@aigne/core 1.9.0 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/LICENSE +93 -0
  3. package/README.md +89 -0
  4. package/README.zh.md +89 -0
  5. package/lib/cjs/agents/agent.d.ts +30 -3
  6. package/lib/cjs/agents/agent.js +51 -22
  7. package/lib/cjs/agents/ai-agent.d.ts +14 -11
  8. package/lib/cjs/agents/ai-agent.js +36 -17
  9. package/lib/cjs/agents/user-agent.d.ts +3 -3
  10. package/lib/cjs/agents/user-agent.js +14 -8
  11. package/lib/cjs/execution-engine/context.d.ts +18 -7
  12. package/lib/cjs/execution-engine/context.js +76 -28
  13. package/lib/cjs/loader/agent-js.d.ts +2 -2
  14. package/lib/cjs/loader/agent-js.js +4 -5
  15. package/lib/cjs/loader/agent-yaml.d.ts +8 -5
  16. package/lib/cjs/loader/agent-yaml.js +13 -1
  17. package/lib/cjs/loader/index.d.ts +4 -4
  18. package/lib/cjs/loader/index.js +4 -15
  19. package/lib/cjs/models/chat-model.d.ts +4 -0
  20. package/lib/cjs/models/chat-model.js +6 -0
  21. package/lib/cjs/models/claude-chat-model.d.ts +3 -1
  22. package/lib/cjs/models/claude-chat-model.js +75 -60
  23. package/lib/cjs/models/open-router-chat-model.d.ts +1 -0
  24. package/lib/cjs/models/open-router-chat-model.js +1 -0
  25. package/lib/cjs/models/openai-chat-model.d.ts +12 -3
  26. package/lib/cjs/models/openai-chat-model.js +110 -46
  27. package/lib/cjs/utils/camelize.d.ts +13 -0
  28. package/lib/cjs/utils/camelize.js +16 -0
  29. package/lib/cjs/utils/stream-utils.d.ts +17 -0
  30. package/lib/cjs/utils/stream-utils.js +165 -0
  31. package/lib/cjs/utils/type-utils.d.ts +1 -0
  32. package/lib/cjs/utils/type-utils.js +7 -0
  33. package/lib/dts/agents/agent.d.ts +30 -3
  34. package/lib/dts/agents/ai-agent.d.ts +14 -11
  35. package/lib/dts/agents/user-agent.d.ts +3 -3
  36. package/lib/dts/execution-engine/context.d.ts +18 -7
  37. package/lib/dts/loader/agent-js.d.ts +2 -2
  38. package/lib/dts/loader/agent-yaml.d.ts +8 -5
  39. package/lib/dts/loader/index.d.ts +4 -4
  40. package/lib/dts/models/chat-model.d.ts +4 -0
  41. package/lib/dts/models/claude-chat-model.d.ts +3 -1
  42. package/lib/dts/models/open-router-chat-model.d.ts +1 -0
  43. package/lib/dts/models/openai-chat-model.d.ts +12 -3
  44. package/lib/dts/utils/camelize.d.ts +13 -0
  45. package/lib/dts/utils/stream-utils.d.ts +17 -0
  46. package/lib/dts/utils/type-utils.d.ts +1 -0
  47. package/lib/esm/agents/agent.d.ts +30 -3
  48. package/lib/esm/agents/agent.js +51 -23
  49. package/lib/esm/agents/ai-agent.d.ts +14 -11
  50. package/lib/esm/agents/ai-agent.js +37 -18
  51. package/lib/esm/agents/user-agent.d.ts +3 -3
  52. package/lib/esm/agents/user-agent.js +15 -9
  53. package/lib/esm/execution-engine/context.d.ts +18 -7
  54. package/lib/esm/execution-engine/context.js +78 -30
  55. package/lib/esm/loader/agent-js.d.ts +2 -2
  56. package/lib/esm/loader/agent-js.js +4 -5
  57. package/lib/esm/loader/agent-yaml.d.ts +8 -5
  58. package/lib/esm/loader/agent-yaml.js +13 -1
  59. package/lib/esm/loader/index.d.ts +4 -4
  60. package/lib/esm/loader/index.js +4 -15
  61. package/lib/esm/models/chat-model.d.ts +4 -0
  62. package/lib/esm/models/chat-model.js +6 -0
  63. package/lib/esm/models/claude-chat-model.d.ts +3 -1
  64. package/lib/esm/models/claude-chat-model.js +75 -60
  65. package/lib/esm/models/open-router-chat-model.d.ts +1 -0
  66. package/lib/esm/models/open-router-chat-model.js +1 -0
  67. package/lib/esm/models/openai-chat-model.d.ts +12 -3
  68. package/lib/esm/models/openai-chat-model.js +110 -45
  69. package/lib/esm/utils/camelize.d.ts +13 -0
  70. package/lib/esm/utils/camelize.js +10 -0
  71. package/lib/esm/utils/stream-utils.d.ts +17 -0
  72. package/lib/esm/utils/stream-utils.js +149 -0
  73. package/lib/esm/utils/type-utils.d.ts +1 -0
  74. package/lib/esm/utils/type-utils.js +6 -0
  75. package/package.json +4 -2
@@ -2,4 +2,5 @@ import { OpenAIChatModel, type OpenAIChatModelOptions } from "./openai-chat-mode
2
2
  export declare class OpenRouterChatModel extends OpenAIChatModel {
3
3
  constructor(options?: OpenAIChatModelOptions);
4
4
  protected apiKeyEnvName: string;
5
+ protected supportsParallelToolCalls: boolean;
5
6
  }
@@ -13,5 +13,6 @@ class OpenRouterChatModel extends openai_chat_model_js_1.OpenAIChatModel {
13
13
  });
14
14
  }
15
15
  apiKeyEnvName = "OPEN_ROUTER_API_KEY";
16
+ supportsParallelToolCalls = false;
16
17
  }
17
18
  exports.OpenRouterChatModel = OpenRouterChatModel;
@@ -1,8 +1,17 @@
1
1
  import OpenAI from "openai";
2
2
  import type { ChatCompletionMessageParam, ChatCompletionTool } from "openai/resources";
3
- import type { Stream } from "openai/streaming.js";
4
3
  import { z } from "zod";
4
+ import type { AgentCallOptions, AgentResponse } from "../agents/agent.js";
5
+ import type { Context } from "../execution-engine/context.js";
5
6
  import { ChatModel, type ChatModelInput, type ChatModelInputMessage, type ChatModelInputTool, type ChatModelOptions, type ChatModelOutput, type Role } from "./chat-model.js";
7
+ export interface OpenAIChatModelCapabilities {
8
+ supportsNativeStructuredOutputs: boolean;
9
+ supportsEndWithSystemMessage: boolean;
10
+ supportsToolsUseWithJsonSchema: boolean;
11
+ supportsParallelToolCalls: boolean;
12
+ supportsToolsEmptyParameters: boolean;
13
+ supportsTemperature: boolean;
14
+ }
6
15
  export interface OpenAIChatModelOptions {
7
16
  apiKey?: string;
8
17
  baseURL?: string;
@@ -71,9 +80,10 @@ export declare class OpenAIChatModel extends ChatModel {
71
80
  protected supportsToolsUseWithJsonSchema: boolean;
72
81
  protected supportsParallelToolCalls: boolean;
73
82
  protected supportsToolsEmptyParameters: boolean;
83
+ protected supportsTemperature: boolean;
74
84
  get client(): OpenAI;
75
85
  get modelOptions(): ChatModelOptions | undefined;
76
- process(input: ChatModelInput): Promise<ChatModelOutput>;
86
+ process(input: ChatModelInput, _context: Context, options?: AgentCallOptions): Promise<AgentResponse<ChatModelOutput>>;
77
87
  private getParallelToolCalls;
78
88
  private getRunMessages;
79
89
  private getRunResponseFormat;
@@ -87,4 +97,3 @@ export declare function toolsFromInputTools(tools?: ChatModelInputTool[], option
87
97
  addTypeToEmptyParameters?: boolean;
88
98
  }): ChatCompletionTool[] | undefined;
89
99
  export declare function jsonSchemaToOpenAIJsonSchema(schema: Record<string, unknown>): Record<string, unknown>;
90
- export declare function extractResultFromStream(stream: Stream<OpenAI.Chat.Completions.ChatCompletionChunk>, jsonMode?: boolean): Promise<ChatModelOutput>;
@@ -7,16 +7,20 @@ exports.ROLE_MAP = exports.OpenAIChatModel = exports.openAIChatModelOptionsSchem
7
7
  exports.contentsFromInputMessages = contentsFromInputMessages;
8
8
  exports.toolsFromInputTools = toolsFromInputTools;
9
9
  exports.jsonSchemaToOpenAIJsonSchema = jsonSchemaToOpenAIJsonSchema;
10
- exports.extractResultFromStream = extractResultFromStream;
11
10
  const nanoid_1 = require("nanoid");
12
11
  const openai_1 = __importDefault(require("openai"));
13
12
  const zod_1 = require("zod");
14
13
  const json_schema_js_1 = require("../utils/json-schema.js");
15
14
  const model_utils_js_1 = require("../utils/model-utils.js");
16
15
  const prompts_js_1 = require("../utils/prompts.js");
16
+ const stream_utils_js_1 = require("../utils/stream-utils.js");
17
17
  const type_utils_js_1 = require("../utils/type-utils.js");
18
18
  const chat_model_js_1 = require("./chat-model.js");
19
19
  const CHAT_MODEL_OPENAI_DEFAULT_MODEL = "gpt-4o-mini";
20
+ const OPENAI_CHAT_MODEL_CAPABILITIES = {
21
+ "o4-mini": { supportsParallelToolCalls: false, supportsTemperature: false },
22
+ "o3-mini": { supportsParallelToolCalls: false, supportsTemperature: false },
23
+ };
20
24
  exports.openAIChatModelOptionsSchema = zod_1.z.object({
21
25
  apiKey: zod_1.z.string().optional(),
22
26
  baseURL: zod_1.z.string().optional(),
@@ -39,6 +43,8 @@ class OpenAIChatModel extends chat_model_js_1.ChatModel {
39
43
  this.options = options;
40
44
  if (options)
41
45
  (0, type_utils_js_1.checkArguments)(this.name, exports.openAIChatModelOptionsSchema, options);
46
+ const preset = options?.model ? OPENAI_CHAT_MODEL_CAPABILITIES[options.model] : undefined;
47
+ Object.assign(this, preset);
42
48
  }
43
49
  _client;
44
50
  apiKeyEnvName = "OPENAI_API_KEY";
@@ -48,6 +54,7 @@ class OpenAIChatModel extends chat_model_js_1.ChatModel {
48
54
  supportsToolsUseWithJsonSchema = true;
49
55
  supportsParallelToolCalls = true;
50
56
  supportsToolsEmptyParameters = true;
57
+ supportsTemperature = true;
51
58
  get client() {
52
59
  const apiKey = this.options?.apiKey || process.env[this.apiKeyEnvName] || this.apiKeyDefault;
53
60
  if (!apiKey)
@@ -61,14 +68,17 @@ class OpenAIChatModel extends chat_model_js_1.ChatModel {
61
68
  get modelOptions() {
62
69
  return this.options?.modelOptions;
63
70
  }
64
- async process(input) {
71
+ async process(input, _context, options) {
72
+ const messages = await this.getRunMessages(input);
65
73
  const body = {
66
74
  model: this.options?.model || CHAT_MODEL_OPENAI_DEFAULT_MODEL,
67
- temperature: input.modelOptions?.temperature ?? this.modelOptions?.temperature,
75
+ temperature: this.supportsTemperature
76
+ ? (input.modelOptions?.temperature ?? this.modelOptions?.temperature)
77
+ : undefined,
68
78
  top_p: input.modelOptions?.topP ?? this.modelOptions?.topP,
69
79
  frequency_penalty: input.modelOptions?.frequencyPenalty ?? this.modelOptions?.frequencyPenalty,
70
80
  presence_penalty: input.modelOptions?.presencePenalty ?? this.modelOptions?.presencePenalty,
71
- messages: await this.getRunMessages(input),
81
+ messages,
72
82
  stream_options: {
73
83
  include_usage: true,
74
84
  },
@@ -84,6 +94,9 @@ class OpenAIChatModel extends chat_model_js_1.ChatModel {
84
94
  parallel_tool_calls: this.getParallelToolCalls(input),
85
95
  response_format: responseFormat,
86
96
  });
97
+ if (options?.streaming && input.responseFormat?.type !== "json_schema") {
98
+ return await extractResultFromStream(stream, false, true);
99
+ }
87
100
  const result = await extractResultFromStream(stream, jsonMode);
88
101
  if (!this.supportsToolsUseWithJsonSchema &&
89
102
  !result.toolCalls?.length &&
@@ -232,51 +245,102 @@ function jsonSchemaToOpenAIJsonSchema(schema) {
232
245
  }
233
246
  return schema;
234
247
  }
235
- async function extractResultFromStream(stream, jsonMode = false) {
236
- let text = "";
237
- const toolCalls = [];
238
- let usage;
239
- let model;
240
- for await (const chunk of stream) {
241
- const choice = chunk.choices?.[0];
242
- model ??= chunk.model;
243
- if (choice?.delta.tool_calls?.length) {
244
- for (const call of choice.delta.tool_calls) {
245
- // Gemini not support tool call delta
246
- if (call.index !== undefined) {
247
- handleToolCallDelta(toolCalls, call);
248
+ async function extractResultFromStream(stream, jsonMode, streaming) {
249
+ const result = new ReadableStream({
250
+ async start(controller) {
251
+ try {
252
+ let text = "";
253
+ let refusal = "";
254
+ const toolCalls = [];
255
+ let model;
256
+ for await (const chunk of stream) {
257
+ const choice = chunk.choices?.[0];
258
+ if (!model) {
259
+ model = chunk.model;
260
+ controller.enqueue({
261
+ delta: {
262
+ json: {
263
+ model,
264
+ },
265
+ },
266
+ });
267
+ }
268
+ if (choice?.delta.tool_calls?.length) {
269
+ for (const call of choice.delta.tool_calls) {
270
+ // Gemini not support tool call delta
271
+ if (call.index !== undefined) {
272
+ handleToolCallDelta(toolCalls, call);
273
+ }
274
+ else {
275
+ handleCompleteToolCall(toolCalls, call);
276
+ }
277
+ }
278
+ }
279
+ if (choice?.delta.content) {
280
+ text += choice.delta.content;
281
+ if (!jsonMode) {
282
+ controller.enqueue({
283
+ delta: {
284
+ text: {
285
+ text: choice.delta.content,
286
+ },
287
+ },
288
+ });
289
+ }
290
+ }
291
+ if (choice?.delta.refusal) {
292
+ refusal += choice.delta.refusal;
293
+ if (!jsonMode) {
294
+ controller.enqueue({
295
+ delta: {
296
+ text: { text: choice.delta.refusal },
297
+ },
298
+ });
299
+ }
300
+ }
301
+ if (chunk.usage) {
302
+ controller.enqueue({
303
+ delta: {
304
+ json: {
305
+ usage: {
306
+ inputTokens: chunk.usage.prompt_tokens,
307
+ outputTokens: chunk.usage.completion_tokens,
308
+ },
309
+ },
310
+ },
311
+ });
312
+ }
248
313
  }
249
- else {
250
- handleCompleteToolCall(toolCalls, call);
314
+ text = text || refusal;
315
+ if (jsonMode && text) {
316
+ controller.enqueue({
317
+ delta: {
318
+ json: {
319
+ json: (0, json_schema_js_1.parseJSON)(text),
320
+ },
321
+ },
322
+ });
251
323
  }
324
+ if (toolCalls.length) {
325
+ controller.enqueue({
326
+ delta: {
327
+ json: {
328
+ toolCalls: toolCalls.map(({ args, ...c }) => ({
329
+ ...c,
330
+ function: { ...c.function, arguments: (0, json_schema_js_1.parseJSON)(args) },
331
+ })),
332
+ },
333
+ },
334
+ });
335
+ }
336
+ controller.close();
252
337
  }
253
- }
254
- if (choice?.delta.content)
255
- text += choice.delta.content;
256
- if (chunk.usage) {
257
- usage = {
258
- inputTokens: chunk.usage.prompt_tokens,
259
- outputTokens: chunk.usage.completion_tokens,
260
- };
261
- }
262
- }
263
- const result = {
264
- usage,
265
- model,
266
- };
267
- if (jsonMode && text) {
268
- result.json = (0, json_schema_js_1.parseJSON)(text);
269
- }
270
- else {
271
- result.text = text;
272
- }
273
- if (toolCalls.length) {
274
- result.toolCalls = toolCalls.map(({ args, ...c }) => ({
275
- ...c,
276
- function: { ...c.function, arguments: (0, json_schema_js_1.parseJSON)(args) },
277
- }));
278
- }
279
- return result;
338
+ catch (error) {
339
+ controller.error(error);
340
+ }
341
+ },
342
+ });
343
+ return streaming ? result : await (0, stream_utils_js_1.agentResponseStreamToObject)(result);
280
344
  }
281
345
  function handleToolCallDelta(toolCalls, call) {
282
346
  toolCalls[call.index] ??= {
@@ -0,0 +1,13 @@
1
+ export declare function customCamelize<T extends Record<string, unknown>, K extends KeyofUnion<T> = never>(obj: T, { shallowKeys }?: {
2
+ shallowKeys?: K[];
3
+ }): CustomCamelize<T, K>;
4
+ type KeyofUnion<U> = U extends Record<string, unknown> ? keyof U : never;
5
+ type CamelCase<S extends string> = S extends `${infer P1}_${infer P2}${infer P3}` ? `${P1}${Uppercase<P2>}${CamelCase<P3>}` : S;
6
+ declare const _unique: unique symbol;
7
+ type _never = typeof _unique;
8
+ type ExtractTypeFromUnion<T, U> = Extract<T, U> extends never ? _never : Extract<T, U> extends Array<infer E> ? Array<E> : U;
9
+ type ExtractTypeWithConstFromUnion<T, U> = Exclude<T, Exclude<T, U>>;
10
+ export type CustomCamelize<T, ShallowKeys extends KeyofUnion<T> | undefined = undefined> = ExtractTypeFromUnion<T, never> extends never ? never : ExtractTypeFromUnion<T, Date> extends Date ? ExtractTypeWithConstFromUnion<T, Date> | CustomCamelize<Exclude<T, Date>> : ExtractTypeFromUnion<T, RegExp> extends RegExp ? ExtractTypeWithConstFromUnion<T, RegExp> | CustomCamelize<Exclude<T, RegExp>> : ExtractTypeFromUnion<T, Array<unknown>> extends Array<infer U> ? Array<CustomCamelize<U>> | CustomCamelize<Exclude<T, Array<U>>> : ExtractTypeFromUnion<T, Function> extends Function ? ExtractTypeWithConstFromUnion<T, Function> | CustomCamelize<Exclude<T, Function>> : ExtractTypeFromUnion<T, object> extends object ? {
11
+ [K in keyof T as Uncapitalize<CamelCase<string & K>>]: K extends Exclude<ShallowKeys, undefined> ? T[K] : CustomCamelize<T[K]>;
12
+ } : T;
13
+ export {};
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.customCamelize = customCamelize;
7
+ const camelize_ts_1 = __importDefault(require("camelize-ts"));
8
+ function customCamelize(obj, { shallowKeys = [] } = {}) {
9
+ const shallow = Object.fromEntries(shallowKeys?.filter((key) => key in obj).map((key) => [key, obj[key]]) ?? []);
10
+ const deep = Object.fromEntries(Object.entries(obj).filter(([key]) => !shallowKeys?.includes(key)));
11
+ return {
12
+ ...(0, camelize_ts_1.default)(shallow, true),
13
+ ...(0, camelize_ts_1.default)(deep),
14
+ };
15
+ }
16
+ const _unique = Symbol();
@@ -0,0 +1,17 @@
1
+ import { type AgentProcessAsyncGenerator, type AgentResponseChunk, type AgentResponseStream, type Message } from "../agents/agent.js";
2
+ import type { MESSAGE_KEY } from "../prompt/prompt-builder.js";
3
+ import { type PromiseOrValue } from "./type-utils.js";
4
+ export declare function objectToAgentResponseStream<T extends Message>(json: T): AgentResponseStream<T>;
5
+ export declare function mergeAgentResponseChunk<T extends Message>(output: T, chunk: AgentResponseChunk<T>): T;
6
+ export declare function agentResponseStreamToObject<T extends Message>(stream: AgentResponseStream<T> | AgentProcessAsyncGenerator<T>): Promise<T>;
7
+ export declare function asyncGeneratorToReadableStream<T extends Message>(generator: AgentProcessAsyncGenerator<T>): AgentResponseStream<T>;
8
+ export declare function onAgentResponseStreamEnd<T extends Message>(stream: AgentResponseStream<T>, callback: (result: T) => PromiseOrValue<Partial<T> | void>, options?: {
9
+ errorCallback?: (error: Error) => Error;
10
+ processChunk?: (chunk: AgentResponseChunk<T>) => AgentResponseChunk<T>;
11
+ }): ReadableStream<any>;
12
+ export declare function isAsyncGenerator<T extends AsyncGenerator>(value: AsyncGenerator | unknown): value is T;
13
+ export declare function arrayToAgentProcessAsyncGenerator<T extends Message>(chunks: (AgentResponseChunk<T> | Error)[], result?: Partial<T>): AgentProcessAsyncGenerator<T>;
14
+ export declare function arrayToAgentResponseStream<T>(chunks: (AgentResponseChunk<T> | Error)[]): AgentResponseStream<T>;
15
+ export declare function readableStreamToArray<T>(stream: ReadableStream<T>): Promise<T[]>;
16
+ export declare function readableStreamToAsyncIterator<T>(stream: ReadableStream<T>): AsyncIterable<T>;
17
+ export declare function stringToAgentResponseStream(str: string, key?: "text" | typeof MESSAGE_KEY | string): AgentResponseStream<Message>;
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.objectToAgentResponseStream = objectToAgentResponseStream;
7
+ exports.mergeAgentResponseChunk = mergeAgentResponseChunk;
8
+ exports.agentResponseStreamToObject = agentResponseStreamToObject;
9
+ exports.asyncGeneratorToReadableStream = asyncGeneratorToReadableStream;
10
+ exports.onAgentResponseStreamEnd = onAgentResponseStreamEnd;
11
+ exports.isAsyncGenerator = isAsyncGenerator;
12
+ exports.arrayToAgentProcessAsyncGenerator = arrayToAgentProcessAsyncGenerator;
13
+ exports.arrayToAgentResponseStream = arrayToAgentResponseStream;
14
+ exports.readableStreamToArray = readableStreamToArray;
15
+ exports.readableStreamToAsyncIterator = readableStreamToAsyncIterator;
16
+ exports.stringToAgentResponseStream = stringToAgentResponseStream;
17
+ const fast_deep_equal_1 = __importDefault(require("fast-deep-equal"));
18
+ const agent_js_1 = require("../agents/agent.js");
19
+ const type_utils_js_1 = require("./type-utils.js");
20
+ function objectToAgentResponseStream(json) {
21
+ return new ReadableStream({
22
+ start(controller) {
23
+ controller.enqueue({ delta: { json } });
24
+ controller.close();
25
+ },
26
+ });
27
+ }
28
+ function mergeAgentResponseChunk(output, chunk) {
29
+ if (chunk.delta.text) {
30
+ for (const [key, text] of Object.entries(chunk.delta.text)) {
31
+ const original = output[key];
32
+ const t = (original || "") + (text || "");
33
+ if (t)
34
+ Object.assign(output, { [key]: t });
35
+ }
36
+ }
37
+ if (chunk.delta.json) {
38
+ Object.assign(output, (0, type_utils_js_1.omitBy)(chunk.delta.json, (v) => v === undefined));
39
+ }
40
+ return output;
41
+ }
42
+ async function agentResponseStreamToObject(stream) {
43
+ const json = {};
44
+ if (stream instanceof ReadableStream) {
45
+ for await (const value of readableStreamToAsyncIterator(stream)) {
46
+ mergeAgentResponseChunk(json, value);
47
+ }
48
+ }
49
+ else {
50
+ for (;;) {
51
+ const chunk = await stream.next();
52
+ if (chunk.value) {
53
+ if (chunk.done) {
54
+ Object.assign(json, chunk.value);
55
+ }
56
+ else {
57
+ mergeAgentResponseChunk(json, chunk.value);
58
+ }
59
+ }
60
+ if (chunk.done)
61
+ break;
62
+ }
63
+ }
64
+ return json;
65
+ }
66
+ function asyncGeneratorToReadableStream(generator) {
67
+ return new ReadableStream({
68
+ async start(controller) {
69
+ try {
70
+ for (;;) {
71
+ const chunk = await generator.next();
72
+ if (chunk.value) {
73
+ if (chunk.done) {
74
+ controller.enqueue({ delta: { json: chunk.value } });
75
+ }
76
+ else {
77
+ controller.enqueue(chunk.value);
78
+ }
79
+ }
80
+ if (chunk.done)
81
+ break;
82
+ }
83
+ controller.close();
84
+ }
85
+ catch (error) {
86
+ controller.error(error);
87
+ }
88
+ },
89
+ });
90
+ }
91
+ function onAgentResponseStreamEnd(stream, callback, options) {
92
+ return new ReadableStream({
93
+ async start(controller) {
94
+ try {
95
+ const json = {};
96
+ for await (const value of readableStreamToAsyncIterator(stream)) {
97
+ const chunk = options?.processChunk ? options.processChunk(value) : value;
98
+ if (!(0, agent_js_1.isEmptyChunk)(chunk))
99
+ controller.enqueue(chunk);
100
+ mergeAgentResponseChunk(json, value);
101
+ }
102
+ const result = await callback(json);
103
+ if (result && !(0, fast_deep_equal_1.default)(result, json)) {
104
+ let chunk = { delta: { json: result } };
105
+ if (options?.processChunk)
106
+ chunk = options.processChunk(chunk);
107
+ controller.enqueue(chunk);
108
+ }
109
+ }
110
+ catch (error) {
111
+ controller.error(options?.errorCallback?.(error) ?? error);
112
+ }
113
+ finally {
114
+ controller.close();
115
+ }
116
+ },
117
+ });
118
+ }
119
+ function isAsyncGenerator(value) {
120
+ return typeof value === "object" && value !== null && Symbol.asyncIterator in value;
121
+ }
122
+ async function* arrayToAgentProcessAsyncGenerator(chunks, result) {
123
+ for (const chunk of chunks) {
124
+ if (chunk instanceof Error)
125
+ throw chunk;
126
+ yield chunk;
127
+ }
128
+ if (result !== undefined)
129
+ return result;
130
+ }
131
+ function arrayToAgentResponseStream(chunks) {
132
+ return new ReadableStream({
133
+ start(controller) {
134
+ for (const chunk of chunks) {
135
+ if (chunk instanceof Error) {
136
+ controller.error(chunk);
137
+ return;
138
+ }
139
+ controller.enqueue(chunk);
140
+ }
141
+ controller.close();
142
+ },
143
+ });
144
+ }
145
+ async function readableStreamToArray(stream) {
146
+ const result = [];
147
+ for await (const value of readableStreamToAsyncIterator(stream)) {
148
+ result.push(value);
149
+ }
150
+ return result;
151
+ }
152
+ async function* readableStreamToAsyncIterator(stream) {
153
+ const reader = stream.getReader();
154
+ while (true) {
155
+ const { value, done } = await reader.read();
156
+ if (done)
157
+ break;
158
+ yield value;
159
+ }
160
+ }
161
+ function stringToAgentResponseStream(str, key = "text") {
162
+ const segmenter = new Intl.Segmenter(undefined, { granularity: "word" });
163
+ const segments = segmenter.segment(str);
164
+ return arrayToAgentResponseStream(Array.from(segments).map((segment) => ({ delta: { text: { [key]: segment.segment } } })));
165
+ }
@@ -7,6 +7,7 @@ export declare function isEmpty(obj: unknown): boolean;
7
7
  export declare function isNonNullable<T>(value: T): value is NonNullable<T>;
8
8
  export declare function isNotEmpty<T>(arr: T[]): arr is [T, ...T[]];
9
9
  export declare function duplicates<T>(arr: T[], key?: (item: T) => unknown): T[];
10
+ export declare function omitBy<T extends Record<string, unknown>, K extends keyof T>(obj: T, predicate: (value: T[K], key: K) => boolean): Partial<T>;
10
11
  export declare function orArrayToArray<T>(value?: T | T[]): T[];
11
12
  export declare function createAccessorArray<T>(array: T[], accessor: (array: T[], name: string) => T | undefined): T[] & {
12
13
  [key: string]: T;
@@ -5,6 +5,7 @@ exports.isEmpty = isEmpty;
5
5
  exports.isNonNullable = isNonNullable;
6
6
  exports.isNotEmpty = isNotEmpty;
7
7
  exports.duplicates = duplicates;
8
+ exports.omitBy = omitBy;
8
9
  exports.orArrayToArray = orArrayToArray;
9
10
  exports.createAccessorArray = createAccessorArray;
10
11
  exports.checkArguments = checkArguments;
@@ -42,6 +43,12 @@ function duplicates(arr, key = (item) => item) {
42
43
  }
43
44
  return Array.from(duplicates);
44
45
  }
46
+ function omitBy(obj, predicate) {
47
+ return Object.fromEntries(Object.entries(obj).filter(([key, value]) => {
48
+ const k = key;
49
+ return !predicate(value, k);
50
+ }));
51
+ }
45
52
  function orArrayToArray(value) {
46
53
  if (isNil(value))
47
54
  return [];
@@ -19,6 +19,9 @@ export interface AgentOptions<I extends Message = Message, O extends Message = M
19
19
  disableEvents?: boolean;
20
20
  memory?: AgentMemory | AgentMemoryOptions | true;
21
21
  }
22
+ export interface AgentCallOptions {
23
+ streaming?: boolean;
24
+ }
22
25
  export declare abstract class Agent<I extends Message = Message, O extends Message = Message> {
23
26
  constructor({ inputSchema, outputSchema, ...options }: AgentOptions<I, O>);
24
27
  readonly memory?: AgentMemory;
@@ -50,14 +53,38 @@ export declare abstract class Agent<I extends Message = Message, O extends Messa
50
53
  get isCallable(): boolean;
51
54
  private checkContextStatus;
52
55
  private newDefaultContext;
53
- call(input: I | string, context?: Context): Promise<O>;
56
+ call(input: I | string, context: Context | undefined, options: AgentCallOptions & {
57
+ streaming: true;
58
+ }): Promise<AgentResponseStream<O>>;
59
+ call(input: I | string, context?: Context, options?: AgentCallOptions & {
60
+ streaming?: false;
61
+ }): Promise<O>;
62
+ call(input: I | string, context?: Context, options?: AgentCallOptions): Promise<AgentResponse<O>>;
63
+ private processAgentOutput;
64
+ private processAgentError;
54
65
  protected checkUsageAgentCalls(context: Context): void;
55
66
  protected preprocess(_: I, context: Context): void;
56
67
  protected postprocess(input: I, output: O, context: Context): void;
57
- abstract process(input: I, context: Context): Promise<O | TransferAgentOutput>;
68
+ abstract process(input: I, context: Context, options?: AgentCallOptions): AgentProcessResult<O | TransferAgentOutput>;
58
69
  shutdown(): Promise<void>;
59
70
  [inspect.custom](): string;
60
71
  }
72
+ export type AgentResponse<T> = T | AgentResponseStream<T>;
73
+ export type AgentResponseStream<T> = ReadableStream<AgentResponseChunk<T>>;
74
+ export type AgentResponseChunk<T> = AgentResponseDelta<T>;
75
+ export declare function isEmptyChunk<T>(chunk: AgentResponseChunk<T>): boolean;
76
+ export interface AgentResponseDelta<T> {
77
+ delta: {
78
+ text?: Partial<{
79
+ [key in keyof T as Extract<T[key], string> extends string ? key : never]: string;
80
+ }> | {
81
+ [key: string]: string;
82
+ };
83
+ json?: Partial<T>;
84
+ };
85
+ }
86
+ export type AgentProcessAsyncGenerator<O extends Message> = AsyncGenerator<AgentResponseChunk<O>, Partial<O> | undefined | void>;
87
+ export type AgentProcessResult<O extends Message> = Promise<AgentResponse<O>> | AgentProcessAsyncGenerator<O>;
61
88
  export type AgentInputOutputSchema<I extends Message = Message> = ZodType<I> | ((agent: Agent) => ZodType<I>);
62
89
  export interface FunctionAgentOptions<I extends Message = Message, O extends Message = Message> extends AgentOptions<I, O> {
63
90
  fn?: FunctionAgentFn<I, O>;
@@ -66,6 +93,6 @@ export declare class FunctionAgent<I extends Message = Message, O extends Messag
66
93
  static from<I extends Message, O extends Message>(options: FunctionAgentOptions<I, O> | FunctionAgentFn<I, O>): FunctionAgent<I, O>;
67
94
  constructor(options: FunctionAgentOptions<I, O>);
68
95
  fn: FunctionAgentFn<I, O>;
69
- process(input: I, context: Context): Promise<TransferAgentOutput | O>;
96
+ process(input: I, context: Context, options?: AgentCallOptions): Promise<AgentResponse<O | TransferAgentOutput>>;
70
97
  }
71
98
  export type FunctionAgentFn<I extends Message = Message, O extends Message = Message> = (input: I, context: Context) => O | Promise<O> | Agent | Promise<Agent>;
@@ -1,8 +1,10 @@
1
1
  import { z } from "zod";
2
2
  import type { Context } from "../execution-engine/context.js";
3
3
  import { ChatModel } from "../models/chat-model.js";
4
+ import type { ChatModelInput } from "../models/chat-model.js";
4
5
  import { PromptBuilder } from "../prompt/prompt-builder.js";
5
- import { Agent, type AgentOptions, type Message } from "./agent.js";
6
+ import { Agent, type AgentOptions, type AgentProcessAsyncGenerator, type Message } from "./agent.js";
7
+ import { type TransferAgentOutput } from "./types.js";
6
8
  export interface AIAgentOptions<I extends Message = Message, O extends Message = Message> extends AgentOptions<I, O> {
7
9
  model?: ChatModel;
8
10
  instructions?: string | PromptBuilder;
@@ -27,35 +29,35 @@ export declare const aiAgentOptionsSchema: z.ZodObject<{
27
29
  disableLogging: z.ZodOptional<z.ZodBoolean>;
28
30
  memory: z.ZodOptional<z.ZodUnion<[z.ZodBoolean, z.ZodAny, z.ZodAny]>>;
29
31
  }, "strip", z.ZodTypeAny, {
30
- description?: string | undefined;
31
- memory?: any;
32
- includeInputInOutput?: boolean | undefined;
33
- subscribeTopic?: string | string[] | undefined;
34
- publishTopic?: string | string[] | ((...args: unknown[]) => unknown) | undefined;
35
32
  tools?: (Agent<Message, Message> | ((...args: unknown[]) => unknown))[] | undefined;
36
33
  toolChoice?: Agent<Message, Message> | "auto" | "none" | "required" | "router" | undefined;
37
34
  name?: string | undefined;
35
+ description?: string | undefined;
38
36
  model?: ChatModel | undefined;
39
37
  instructions?: string | PromptBuilder | undefined;
40
38
  outputKey?: string | undefined;
41
39
  enableHistory?: boolean | undefined;
42
40
  maxHistoryMessages?: number | undefined;
43
- disableLogging?: boolean | undefined;
44
- }, {
45
- description?: string | undefined;
46
- memory?: any;
47
41
  includeInputInOutput?: boolean | undefined;
48
42
  subscribeTopic?: string | string[] | undefined;
49
43
  publishTopic?: string | string[] | ((...args: unknown[]) => unknown) | undefined;
44
+ disableLogging?: boolean | undefined;
45
+ memory?: any;
46
+ }, {
50
47
  tools?: (Agent<Message, Message> | ((...args: unknown[]) => unknown))[] | undefined;
51
48
  toolChoice?: Agent<Message, Message> | "auto" | "none" | "required" | "router" | undefined;
52
49
  name?: string | undefined;
50
+ description?: string | undefined;
53
51
  model?: ChatModel | undefined;
54
52
  instructions?: string | PromptBuilder | undefined;
55
53
  outputKey?: string | undefined;
56
54
  enableHistory?: boolean | undefined;
57
55
  maxHistoryMessages?: number | undefined;
56
+ includeInputInOutput?: boolean | undefined;
57
+ subscribeTopic?: string | string[] | undefined;
58
+ publishTopic?: string | string[] | ((...args: unknown[]) => unknown) | undefined;
58
59
  disableLogging?: boolean | undefined;
60
+ memory?: any;
59
61
  }>;
60
62
  export declare class AIAgent<I extends Message = Message, O extends Message = Message> extends Agent<I, O> {
61
63
  static from<I extends Message, O extends Message>(options: AIAgentOptions<I, O>): AIAgent<I, O>;
@@ -64,5 +66,6 @@ export declare class AIAgent<I extends Message = Message, O extends Message = Me
64
66
  instructions: PromptBuilder;
65
67
  outputKey?: string;
66
68
  toolChoice?: AIAgentToolChoice;
67
- process(input: I, context: Context): Promise<import("./types.js").TransferAgentOutput | O>;
69
+ process(input: I, context: Context): AgentProcessAsyncGenerator<O | TransferAgentOutput>;
70
+ processRouter(input: I, model: ChatModel, modelInput: ChatModelInput, context: Context, toolsMap: Map<string, Agent>): AgentProcessAsyncGenerator<O | TransferAgentOutput>;
68
71
  }
@@ -2,7 +2,7 @@ import { ReadableStream } from "node:stream/web";
2
2
  import { type Context, type Runnable } from "../execution-engine/context.js";
3
3
  import type { MessagePayload } from "../execution-engine/message-queue.js";
4
4
  import { type PromiseOrValue } from "../utils/type-utils.js";
5
- import { Agent, type AgentOptions, type Message } from "./agent.js";
5
+ import { Agent, type AgentOptions, type AgentProcessAsyncGenerator, type Message } from "./agent.js";
6
6
  export interface UserAgentOptions<I extends Message = Message, O extends Message = Message> extends AgentOptions<I, O> {
7
7
  context: Context;
8
8
  process?: (input: I, context: Context) => PromiseOrValue<O>;
@@ -14,8 +14,8 @@ export declare class UserAgent<I extends Message = Message, O extends Message =
14
14
  context: Context;
15
15
  private _process?;
16
16
  private activeAgent?;
17
- call(input: string | I, context?: Context): Promise<O>;
18
- process(input: I, context: Context): Promise<O>;
17
+ call: Agent<I, O>["call"];
18
+ process(input: I, context: Context): AgentProcessAsyncGenerator<O>;
19
19
  publish: Context["publish"];
20
20
  subscribe: Context["subscribe"];
21
21
  unsubscribe: Context["unsubscribe"];