@aigne/core 1.10.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 (47) hide show
  1. package/CHANGELOG.md +13 -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 +1 -0
  6. package/lib/cjs/agents/agent.js +4 -0
  7. package/lib/cjs/agents/ai-agent.d.ts +11 -9
  8. package/lib/cjs/agents/ai-agent.js +17 -11
  9. package/lib/cjs/loader/agent-js.d.ts +2 -2
  10. package/lib/cjs/loader/agent-js.js +4 -5
  11. package/lib/cjs/loader/agent-yaml.d.ts +8 -5
  12. package/lib/cjs/loader/agent-yaml.js +13 -1
  13. package/lib/cjs/loader/index.d.ts +4 -4
  14. package/lib/cjs/loader/index.js +4 -15
  15. package/lib/cjs/models/claude-chat-model.d.ts +3 -1
  16. package/lib/cjs/models/claude-chat-model.js +75 -60
  17. package/lib/cjs/models/openai-chat-model.js +1 -3
  18. package/lib/cjs/utils/camelize.d.ts +13 -0
  19. package/lib/cjs/utils/camelize.js +16 -0
  20. package/lib/cjs/utils/stream-utils.d.ts +3 -1
  21. package/lib/cjs/utils/stream-utils.js +10 -4
  22. package/lib/dts/agents/agent.d.ts +1 -0
  23. package/lib/dts/agents/ai-agent.d.ts +11 -9
  24. package/lib/dts/loader/agent-js.d.ts +2 -2
  25. package/lib/dts/loader/agent-yaml.d.ts +8 -5
  26. package/lib/dts/loader/index.d.ts +4 -4
  27. package/lib/dts/models/claude-chat-model.d.ts +3 -1
  28. package/lib/dts/utils/camelize.d.ts +13 -0
  29. package/lib/dts/utils/stream-utils.d.ts +3 -1
  30. package/lib/esm/agents/agent.d.ts +1 -0
  31. package/lib/esm/agents/agent.js +4 -1
  32. package/lib/esm/agents/ai-agent.d.ts +11 -9
  33. package/lib/esm/agents/ai-agent.js +17 -11
  34. package/lib/esm/loader/agent-js.d.ts +2 -2
  35. package/lib/esm/loader/agent-js.js +4 -5
  36. package/lib/esm/loader/agent-yaml.d.ts +8 -5
  37. package/lib/esm/loader/agent-yaml.js +13 -1
  38. package/lib/esm/loader/index.d.ts +4 -4
  39. package/lib/esm/loader/index.js +4 -15
  40. package/lib/esm/models/claude-chat-model.d.ts +3 -1
  41. package/lib/esm/models/claude-chat-model.js +75 -60
  42. package/lib/esm/models/openai-chat-model.js +1 -3
  43. package/lib/esm/utils/camelize.d.ts +13 -0
  44. package/lib/esm/utils/camelize.js +10 -0
  45. package/lib/esm/utils/stream-utils.d.ts +3 -1
  46. package/lib/esm/utils/stream-utils.js +9 -4
  47. package/package.json +3 -2
@@ -7,8 +7,8 @@ exports.ClaudeChatModel = exports.claudeChatModelOptionsSchema = void 0;
7
7
  const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
8
8
  const zod_1 = require("zod");
9
9
  const json_schema_js_1 = require("../utils/json-schema.js");
10
- const logger_js_1 = require("../utils/logger.js");
11
10
  const model_utils_js_1 = require("../utils/model-utils.js");
11
+ const stream_utils_js_1 = require("../utils/stream-utils.js");
12
12
  const type_utils_js_1 = require("../utils/type-utils.js");
13
13
  const chat_model_js_1 = require("./chat-model.js");
14
14
  const CHAT_MODEL_CLAUDE_DEFAULT_MODEL = "claude-3-7-sonnet-latest";
@@ -45,7 +45,7 @@ class ClaudeChatModel extends chat_model_js_1.ChatModel {
45
45
  get modelOptions() {
46
46
  return this.options?.modelOptions;
47
47
  }
48
- async process(input) {
48
+ async process(input, _context, options) {
49
49
  const model = this.options?.model || CHAT_MODEL_CLAUDE_DEFAULT_MODEL;
50
50
  const disableParallelToolUse = input.modelOptions?.parallelToolCalls === false ||
51
51
  this.modelOptions?.parallelToolCalls === false;
@@ -62,6 +62,9 @@ class ClaudeChatModel extends chat_model_js_1.ChatModel {
62
62
  ...body,
63
63
  stream: true,
64
64
  });
65
+ if (options?.streaming && input.responseFormat?.type !== "json_schema") {
66
+ return this.extractResultFromClaudeStream(stream, true);
67
+ }
65
68
  const result = await this.extractResultFromClaudeStream(stream);
66
69
  // Claude doesn't support json_schema response and tool calls in the same request,
67
70
  // so we need to make a separate request for json_schema response when the tool calls is empty
@@ -75,67 +78,79 @@ class ClaudeChatModel extends chat_model_js_1.ChatModel {
75
78
  }
76
79
  return result;
77
80
  }
78
- async extractResultFromClaudeStream(stream) {
81
+ async extractResultFromClaudeStream(stream, streaming) {
79
82
  const logs = [];
80
- try {
81
- let text = "";
82
- const toolCalls = [];
83
- let usage;
84
- let model;
85
- for await (const chunk of stream) {
86
- if (chunk.type === "message_start") {
87
- model ??= chunk.message.model;
88
- const { input_tokens, output_tokens } = chunk.message.usage;
89
- usage = {
90
- inputTokens: input_tokens,
91
- outputTokens: output_tokens,
92
- };
93
- }
94
- if (chunk.type === "message_delta" && usage) {
95
- usage.outputTokens = chunk.usage.output_tokens;
96
- }
97
- logs.push(JSON.stringify(chunk));
98
- // handle streaming text
99
- if (chunk.type === "content_block_delta" && chunk.delta.type === "text_delta") {
100
- text += chunk.delta.text;
83
+ const result = new ReadableStream({
84
+ async start(controller) {
85
+ try {
86
+ const toolCalls = [];
87
+ let usage;
88
+ let model;
89
+ for await (const chunk of stream) {
90
+ if (chunk.type === "message_start") {
91
+ if (!model) {
92
+ model = chunk.message.model;
93
+ controller.enqueue({ delta: { json: { model } } });
94
+ }
95
+ const { input_tokens, output_tokens } = chunk.message.usage;
96
+ usage = {
97
+ inputTokens: input_tokens,
98
+ outputTokens: output_tokens,
99
+ };
100
+ }
101
+ if (chunk.type === "message_delta" && usage) {
102
+ usage.outputTokens = chunk.usage.output_tokens;
103
+ }
104
+ logs.push(JSON.stringify(chunk));
105
+ // handle streaming text
106
+ if (chunk.type === "content_block_delta" && chunk.delta.type === "text_delta") {
107
+ controller.enqueue({ delta: { text: { text: chunk.delta.text } } });
108
+ }
109
+ if (chunk.type === "content_block_start" && chunk.content_block.type === "tool_use") {
110
+ toolCalls[chunk.index] = {
111
+ type: "function",
112
+ id: chunk.content_block.id,
113
+ function: {
114
+ name: chunk.content_block.name,
115
+ arguments: {},
116
+ },
117
+ args: "",
118
+ };
119
+ }
120
+ if (chunk.type === "content_block_delta" && chunk.delta.type === "input_json_delta") {
121
+ const call = toolCalls[chunk.index];
122
+ if (!call)
123
+ throw new Error("Tool call not found");
124
+ call.args += chunk.delta.partial_json;
125
+ }
126
+ }
127
+ controller.enqueue({ delta: { json: { usage } } });
128
+ if (toolCalls.length) {
129
+ controller.enqueue({
130
+ delta: {
131
+ json: {
132
+ toolCalls: toolCalls
133
+ .map(({ args, ...c }) => ({
134
+ ...c,
135
+ function: {
136
+ ...c.function,
137
+ // NOTE: claude may return a blank string for empty object (the tool's input schema is a empty object)
138
+ arguments: args.trim() ? (0, json_schema_js_1.parseJSON)(args) : {},
139
+ },
140
+ }))
141
+ .filter(type_utils_js_1.isNonNullable),
142
+ },
143
+ },
144
+ });
145
+ }
146
+ controller.close();
101
147
  }
102
- if (chunk.type === "content_block_start" && chunk.content_block.type === "tool_use") {
103
- toolCalls[chunk.index] = {
104
- type: "function",
105
- id: chunk.content_block.id,
106
- function: {
107
- name: chunk.content_block.name,
108
- arguments: {},
109
- },
110
- args: "",
111
- };
148
+ catch (error) {
149
+ controller.error(error);
112
150
  }
113
- if (chunk.type === "content_block_delta" && chunk.delta.type === "input_json_delta") {
114
- const call = toolCalls[chunk.index];
115
- if (!call)
116
- throw new Error("Tool call not found");
117
- call.args += chunk.delta.partial_json;
118
- }
119
- }
120
- const result = { usage, model, text };
121
- if (toolCalls.length) {
122
- result.toolCalls = toolCalls
123
- .map(({ args, ...c }) => ({
124
- ...c,
125
- function: {
126
- ...c.function,
127
- // NOTE: claude may return a blank string for empty object (the tool's input schema is a empty object)
128
- arguments: args.trim() ? (0, json_schema_js_1.parseJSON)(args) : {},
129
- },
130
- }))
131
- .filter(type_utils_js_1.isNonNullable);
132
- }
133
- return result;
134
- }
135
- catch (error) {
136
- logger_js_1.logger.core("Failed to process Claude stream", { error, logs });
137
- throw error;
138
- }
151
+ },
152
+ });
153
+ return streaming ? result : await (0, stream_utils_js_1.agentResponseStreamToObject)(result);
139
154
  }
140
155
  async requestStructuredOutput(body, responseFormat) {
141
156
  if (responseFormat?.type !== "json_schema") {
@@ -333,13 +333,11 @@ async function extractResultFromStream(stream, jsonMode, streaming) {
333
333
  },
334
334
  });
335
335
  }
336
+ controller.close();
336
337
  }
337
338
  catch (error) {
338
339
  controller.error(error);
339
340
  }
340
- finally {
341
- controller.close();
342
- }
343
341
  },
344
342
  });
345
343
  return streaming ? result : await (0, stream_utils_js_1.agentResponseStreamToObject)(result);
@@ -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();
@@ -1,4 +1,5 @@
1
- import type { AgentProcessAsyncGenerator, AgentResponseChunk, AgentResponseStream, Message } from "../agents/agent.js";
1
+ import { type AgentProcessAsyncGenerator, type AgentResponseChunk, type AgentResponseStream, type Message } from "../agents/agent.js";
2
+ import type { MESSAGE_KEY } from "../prompt/prompt-builder.js";
2
3
  import { type PromiseOrValue } from "./type-utils.js";
3
4
  export declare function objectToAgentResponseStream<T extends Message>(json: T): AgentResponseStream<T>;
4
5
  export declare function mergeAgentResponseChunk<T extends Message>(output: T, chunk: AgentResponseChunk<T>): T;
@@ -13,3 +14,4 @@ export declare function arrayToAgentProcessAsyncGenerator<T extends Message>(chu
13
14
  export declare function arrayToAgentResponseStream<T>(chunks: (AgentResponseChunk<T> | Error)[]): AgentResponseStream<T>;
14
15
  export declare function readableStreamToArray<T>(stream: ReadableStream<T>): Promise<T[]>;
15
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>;
@@ -13,7 +13,9 @@ exports.arrayToAgentProcessAsyncGenerator = arrayToAgentProcessAsyncGenerator;
13
13
  exports.arrayToAgentResponseStream = arrayToAgentResponseStream;
14
14
  exports.readableStreamToArray = readableStreamToArray;
15
15
  exports.readableStreamToAsyncIterator = readableStreamToAsyncIterator;
16
+ exports.stringToAgentResponseStream = stringToAgentResponseStream;
16
17
  const fast_deep_equal_1 = __importDefault(require("fast-deep-equal"));
18
+ const agent_js_1 = require("../agents/agent.js");
17
19
  const type_utils_js_1 = require("./type-utils.js");
18
20
  function objectToAgentResponseStream(json) {
19
21
  return new ReadableStream({
@@ -78,13 +80,11 @@ function asyncGeneratorToReadableStream(generator) {
78
80
  if (chunk.done)
79
81
  break;
80
82
  }
83
+ controller.close();
81
84
  }
82
85
  catch (error) {
83
86
  controller.error(error);
84
87
  }
85
- finally {
86
- controller.close();
87
- }
88
88
  },
89
89
  });
90
90
  }
@@ -95,7 +95,8 @@ function onAgentResponseStreamEnd(stream, callback, options) {
95
95
  const json = {};
96
96
  for await (const value of readableStreamToAsyncIterator(stream)) {
97
97
  const chunk = options?.processChunk ? options.processChunk(value) : value;
98
- controller.enqueue(chunk);
98
+ if (!(0, agent_js_1.isEmptyChunk)(chunk))
99
+ controller.enqueue(chunk);
99
100
  mergeAgentResponseChunk(json, value);
100
101
  }
101
102
  const result = await callback(json);
@@ -157,3 +158,8 @@ async function* readableStreamToAsyncIterator(stream) {
157
158
  yield value;
158
159
  }
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
+ }
@@ -72,6 +72,7 @@ export declare abstract class Agent<I extends Message = Message, O extends Messa
72
72
  export type AgentResponse<T> = T | AgentResponseStream<T>;
73
73
  export type AgentResponseStream<T> = ReadableStream<AgentResponseChunk<T>>;
74
74
  export type AgentResponseChunk<T> = AgentResponseDelta<T>;
75
+ export declare function isEmptyChunk<T>(chunk: AgentResponseChunk<T>): boolean;
75
76
  export interface AgentResponseDelta<T> {
76
77
  delta: {
77
78
  text?: Partial<{
@@ -1,6 +1,7 @@
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
6
  import { Agent, type AgentOptions, type AgentProcessAsyncGenerator, type Message } from "./agent.js";
6
7
  import { type TransferAgentOutput } from "./types.js";
@@ -28,35 +29,35 @@ export declare const aiAgentOptionsSchema: z.ZodObject<{
28
29
  disableLogging: z.ZodOptional<z.ZodBoolean>;
29
30
  memory: z.ZodOptional<z.ZodUnion<[z.ZodBoolean, z.ZodAny, z.ZodAny]>>;
30
31
  }, "strip", z.ZodTypeAny, {
31
- description?: string | undefined;
32
- memory?: any;
33
- includeInputInOutput?: boolean | undefined;
34
- subscribeTopic?: string | string[] | undefined;
35
- publishTopic?: string | string[] | ((...args: unknown[]) => unknown) | undefined;
36
32
  tools?: (Agent<Message, Message> | ((...args: unknown[]) => unknown))[] | undefined;
37
33
  toolChoice?: Agent<Message, Message> | "auto" | "none" | "required" | "router" | undefined;
38
34
  name?: string | undefined;
35
+ description?: string | undefined;
39
36
  model?: ChatModel | undefined;
40
37
  instructions?: string | PromptBuilder | undefined;
41
38
  outputKey?: string | undefined;
42
39
  enableHistory?: boolean | undefined;
43
40
  maxHistoryMessages?: number | undefined;
44
- disableLogging?: boolean | undefined;
45
- }, {
46
- description?: string | undefined;
47
- memory?: any;
48
41
  includeInputInOutput?: boolean | undefined;
49
42
  subscribeTopic?: string | string[] | undefined;
50
43
  publishTopic?: string | string[] | ((...args: unknown[]) => unknown) | undefined;
44
+ disableLogging?: boolean | undefined;
45
+ memory?: any;
46
+ }, {
51
47
  tools?: (Agent<Message, Message> | ((...args: unknown[]) => unknown))[] | undefined;
52
48
  toolChoice?: Agent<Message, Message> | "auto" | "none" | "required" | "router" | undefined;
53
49
  name?: string | undefined;
50
+ description?: string | undefined;
54
51
  model?: ChatModel | undefined;
55
52
  instructions?: string | PromptBuilder | undefined;
56
53
  outputKey?: string | undefined;
57
54
  enableHistory?: boolean | undefined;
58
55
  maxHistoryMessages?: number | undefined;
56
+ includeInputInOutput?: boolean | undefined;
57
+ subscribeTopic?: string | string[] | undefined;
58
+ publishTopic?: string | string[] | ((...args: unknown[]) => unknown) | undefined;
59
59
  disableLogging?: boolean | undefined;
60
+ memory?: any;
60
61
  }>;
61
62
  export declare class AIAgent<I extends Message = Message, O extends Message = Message> extends Agent<I, O> {
62
63
  static from<I extends Message, O extends Message>(options: AIAgentOptions<I, O>): AIAgent<I, O>;
@@ -66,4 +67,5 @@ export declare class AIAgent<I extends Message = Message, O extends Message = Me
66
67
  outputKey?: string;
67
68
  toolChoice?: AIAgentToolChoice;
68
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>;
69
71
  }
@@ -4,12 +4,12 @@ export declare function loadAgentFromJsFile(path: string): Promise<{
4
4
  name: string;
5
5
  fn: (args_0: Message) => Message;
6
6
  description?: string | undefined;
7
- input_schema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
7
+ inputSchema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
8
8
  [x: string]: any;
9
9
  }, {
10
10
  [x: string]: any;
11
11
  }> | undefined;
12
- output_schema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
12
+ outputSchema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
13
13
  [x: string]: any;
14
14
  }, {
15
15
  [x: string]: any;
@@ -2,21 +2,24 @@ import { type ZodObject, type ZodType, z } from "zod";
2
2
  export declare function loadAgentFromYamlFile(path: string): Promise<{
3
3
  type: "ai";
4
4
  name: string;
5
- description?: string | undefined;
6
5
  tools?: string[] | undefined;
6
+ description?: string | undefined;
7
7
  instructions?: string | undefined;
8
- input_schema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
8
+ memory?: true | {
9
+ subscribeTopic: string[];
10
+ } | undefined;
11
+ inputSchema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
9
12
  [x: string]: any;
10
13
  }, {
11
14
  [x: string]: any;
12
15
  }> | undefined;
13
- tool_choice?: "auto" | "none" | "required" | "router" | undefined;
14
- output_schema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
16
+ toolChoice?: "auto" | "none" | "required" | "router" | undefined;
17
+ outputSchema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
15
18
  [x: string]: any;
16
19
  }, {
17
20
  [x: string]: any;
18
21
  }> | undefined;
19
- output_key?: string | undefined;
22
+ outputKey?: string | undefined;
20
23
  } | {
21
24
  type: "mcp";
22
25
  url?: string | undefined;
@@ -8,8 +8,8 @@ export declare function load(options: LoadOptions): Promise<{
8
8
  model: ChatModel | undefined;
9
9
  agents: Agent<import("../agents/agent.js").Message, import("../agents/agent.js").Message>[];
10
10
  tools: Agent<import("../agents/agent.js").Message, import("../agents/agent.js").Message>[];
11
- description?: string | null | undefined;
12
11
  name?: string | null | undefined;
12
+ description?: string | null | undefined;
13
13
  chat_model?: {
14
14
  name?: string | null | undefined;
15
15
  temperature?: number | null | undefined;
@@ -63,9 +63,9 @@ declare const aigneFileSchema: z.ZodObject<{
63
63
  agents: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
64
64
  tools: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
65
65
  }, "strip", z.ZodTypeAny, {
66
- description?: string | null | undefined;
67
66
  tools?: string[] | null | undefined;
68
67
  name?: string | null | undefined;
68
+ description?: string | null | undefined;
69
69
  chat_model?: {
70
70
  name?: string | null | undefined;
71
71
  temperature?: number | null | undefined;
@@ -76,9 +76,9 @@ declare const aigneFileSchema: z.ZodObject<{
76
76
  } | null | undefined;
77
77
  agents?: string[] | null | undefined;
78
78
  }, {
79
- description?: string | null | undefined;
80
79
  tools?: string[] | null | undefined;
81
80
  name?: string | null | undefined;
81
+ description?: string | null | undefined;
82
82
  chat_model?: string | {
83
83
  name?: string | null | undefined;
84
84
  temperature?: number | null | undefined;
@@ -90,9 +90,9 @@ declare const aigneFileSchema: z.ZodObject<{
90
90
  agents?: string[] | null | undefined;
91
91
  }>;
92
92
  export declare function loadAIGNEFile(path: string): Promise<{
93
- description?: string | null | undefined;
94
93
  tools?: string[] | null | undefined;
95
94
  name?: string | null | undefined;
95
+ description?: string | null | undefined;
96
96
  chat_model?: {
97
97
  name?: string | null | undefined;
98
98
  temperature?: number | null | undefined;
@@ -1,5 +1,7 @@
1
1
  import Anthropic from "@anthropic-ai/sdk";
2
2
  import { z } from "zod";
3
+ import type { AgentCallOptions, AgentResponse } from "../agents/agent.js";
4
+ import type { Context } from "../execution-engine/context.js";
3
5
  import { ChatModel, type ChatModelInput, type ChatModelOptions, type ChatModelOutput } from "./chat-model.js";
4
6
  export interface ClaudeChatModelOptions {
5
7
  apiKey?: string;
@@ -60,7 +62,7 @@ export declare class ClaudeChatModel extends ChatModel {
60
62
  protected _client?: Anthropic;
61
63
  get client(): Anthropic;
62
64
  get modelOptions(): ChatModelOptions | undefined;
63
- process(input: ChatModelInput): Promise<ChatModelOutput>;
65
+ process(input: ChatModelInput, _context: Context, options?: AgentCallOptions): Promise<AgentResponse<ChatModelOutput>>;
64
66
  private extractResultFromClaudeStream;
65
67
  private requestStructuredOutput;
66
68
  }
@@ -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 {};
@@ -1,4 +1,5 @@
1
- import type { AgentProcessAsyncGenerator, AgentResponseChunk, AgentResponseStream, Message } from "../agents/agent.js";
1
+ import { type AgentProcessAsyncGenerator, type AgentResponseChunk, type AgentResponseStream, type Message } from "../agents/agent.js";
2
+ import type { MESSAGE_KEY } from "../prompt/prompt-builder.js";
2
3
  import { type PromiseOrValue } from "./type-utils.js";
3
4
  export declare function objectToAgentResponseStream<T extends Message>(json: T): AgentResponseStream<T>;
4
5
  export declare function mergeAgentResponseChunk<T extends Message>(output: T, chunk: AgentResponseChunk<T>): T;
@@ -13,3 +14,4 @@ export declare function arrayToAgentProcessAsyncGenerator<T extends Message>(chu
13
14
  export declare function arrayToAgentResponseStream<T>(chunks: (AgentResponseChunk<T> | Error)[]): AgentResponseStream<T>;
14
15
  export declare function readableStreamToArray<T>(stream: ReadableStream<T>): Promise<T[]>;
15
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>;
@@ -72,6 +72,7 @@ export declare abstract class Agent<I extends Message = Message, O extends Messa
72
72
  export type AgentResponse<T> = T | AgentResponseStream<T>;
73
73
  export type AgentResponseStream<T> = ReadableStream<AgentResponseChunk<T>>;
74
74
  export type AgentResponseChunk<T> = AgentResponseDelta<T>;
75
+ export declare function isEmptyChunk<T>(chunk: AgentResponseChunk<T>): boolean;
75
76
  export interface AgentResponseDelta<T> {
76
77
  delta: {
77
78
  text?: Partial<{
@@ -3,7 +3,7 @@ import { ZodObject, z } from "zod";
3
3
  import { createMessage } from "../prompt/prompt-builder.js";
4
4
  import { logger } from "../utils/logger.js";
5
5
  import { agentResponseStreamToObject, asyncGeneratorToReadableStream, isAsyncGenerator, objectToAgentResponseStream, onAgentResponseStreamEnd, } from "../utils/stream-utils.js";
6
- import { checkArguments, createAccessorArray, orArrayToArray, } from "../utils/type-utils.js";
6
+ import { checkArguments, createAccessorArray, isEmpty, orArrayToArray, } from "../utils/type-utils.js";
7
7
  import { AgentMemory } from "./memory.js";
8
8
  import { replaceTransferAgentToName, transferToAgentOutput, } from "./types.js";
9
9
  export class Agent {
@@ -177,6 +177,9 @@ export class Agent {
177
177
  return this.name;
178
178
  }
179
179
  }
180
+ export function isEmptyChunk(chunk) {
181
+ return isEmpty(chunk.delta.json) && isEmpty(chunk.delta.text);
182
+ }
180
183
  function checkAgentInputOutputSchema(schema) {
181
184
  if (!(schema instanceof ZodObject) && typeof schema !== "function") {
182
185
  throw new Error("schema must be a zod object or function return a zod object ");
@@ -1,6 +1,7 @@
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
6
  import { Agent, type AgentOptions, type AgentProcessAsyncGenerator, type Message } from "./agent.js";
6
7
  import { type TransferAgentOutput } from "./types.js";
@@ -28,35 +29,35 @@ export declare const aiAgentOptionsSchema: z.ZodObject<{
28
29
  disableLogging: z.ZodOptional<z.ZodBoolean>;
29
30
  memory: z.ZodOptional<z.ZodUnion<[z.ZodBoolean, z.ZodAny, z.ZodAny]>>;
30
31
  }, "strip", z.ZodTypeAny, {
31
- description?: string | undefined;
32
- memory?: any;
33
- includeInputInOutput?: boolean | undefined;
34
- subscribeTopic?: string | string[] | undefined;
35
- publishTopic?: string | string[] | ((...args: unknown[]) => unknown) | undefined;
36
32
  tools?: (Agent<Message, Message> | ((...args: unknown[]) => unknown))[] | undefined;
37
33
  toolChoice?: Agent<Message, Message> | "auto" | "none" | "required" | "router" | undefined;
38
34
  name?: string | undefined;
35
+ description?: string | undefined;
39
36
  model?: ChatModel | undefined;
40
37
  instructions?: string | PromptBuilder | undefined;
41
38
  outputKey?: string | undefined;
42
39
  enableHistory?: boolean | undefined;
43
40
  maxHistoryMessages?: number | undefined;
44
- disableLogging?: boolean | undefined;
45
- }, {
46
- description?: string | undefined;
47
- memory?: any;
48
41
  includeInputInOutput?: boolean | undefined;
49
42
  subscribeTopic?: string | string[] | undefined;
50
43
  publishTopic?: string | string[] | ((...args: unknown[]) => unknown) | undefined;
44
+ disableLogging?: boolean | undefined;
45
+ memory?: any;
46
+ }, {
51
47
  tools?: (Agent<Message, Message> | ((...args: unknown[]) => unknown))[] | undefined;
52
48
  toolChoice?: Agent<Message, Message> | "auto" | "none" | "required" | "router" | undefined;
53
49
  name?: string | undefined;
50
+ description?: string | undefined;
54
51
  model?: ChatModel | undefined;
55
52
  instructions?: string | PromptBuilder | undefined;
56
53
  outputKey?: string | undefined;
57
54
  enableHistory?: boolean | undefined;
58
55
  maxHistoryMessages?: number | undefined;
56
+ includeInputInOutput?: boolean | undefined;
57
+ subscribeTopic?: string | string[] | undefined;
58
+ publishTopic?: string | string[] | ((...args: unknown[]) => unknown) | undefined;
59
59
  disableLogging?: boolean | undefined;
60
+ memory?: any;
60
61
  }>;
61
62
  export declare class AIAgent<I extends Message = Message, O extends Message = Message> extends Agent<I, O> {
62
63
  static from<I extends Message, O extends Message>(options: AIAgentOptions<I, O>): AIAgent<I, O>;
@@ -66,4 +67,5 @@ export declare class AIAgent<I extends Message = Message, O extends Message = Me
66
67
  outputKey?: string;
67
68
  toolChoice?: AIAgentToolChoice;
68
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>;
69
71
  }
@@ -52,18 +52,22 @@ export class AIAgent extends Agent {
52
52
  const model = context.model ?? this.model;
53
53
  if (!model)
54
54
  throw new Error("model is required to run AIAgent");
55
- const { toolAgents, messages, ...modelInput } = await this.instructions.build({
55
+ const { toolAgents, ...modelInput } = await this.instructions.build({
56
56
  agent: this,
57
57
  input,
58
58
  model,
59
59
  context,
60
60
  });
61
61
  const toolsMap = new Map(toolAgents?.map((i) => [i.name, i]));
62
+ if (this.toolChoice === "router") {
63
+ yield* this.processRouter(input, model, modelInput, context, toolsMap);
64
+ return;
65
+ }
62
66
  const toolCallMessages = [];
63
67
  const outputKey = this.outputKey || MESSAGE_KEY;
64
68
  for (;;) {
65
69
  const modelOutput = {};
66
- const stream = await context.call(model, { ...modelInput, messages: messages.concat(toolCallMessages) }, { streaming: true });
70
+ const stream = await context.call(model, { ...modelInput, messages: modelInput.messages.concat(toolCallMessages) }, { streaming: true });
67
71
  for await (const value of readableStreamToAsyncIterator(stream)) {
68
72
  if (value.delta.text?.text) {
69
73
  yield { delta: { text: { [outputKey]: value.delta.text.text } } };
@@ -91,15 +95,6 @@ export class AIAgent extends Agent {
91
95
  // Continue LLM function calling loop if any tools were executed
92
96
  if (executedToolCalls.length) {
93
97
  toolCallMessages.push(AgentMessageTemplate.from(undefined, executedToolCalls.map(({ call }) => call)).format(), ...executedToolCalls.map(({ call, output }) => ToolMessageTemplate.from(output, call.id).format()));
94
- // Return the output of the first tool if the toolChoice is "router"
95
- if (this.toolChoice === "router") {
96
- const output = executedToolCalls[0]?.output;
97
- const { supportsParallelToolCalls } = model.getModelCapabilities();
98
- if (!output || (supportsParallelToolCalls && executedToolCalls.length !== 1)) {
99
- throw new Error("Router toolChoice requires exactly one tool to be executed");
100
- }
101
- return output;
102
- }
103
98
  continue;
104
99
  }
105
100
  }
@@ -116,4 +111,15 @@ export class AIAgent extends Agent {
116
111
  return;
117
112
  }
118
113
  }
114
+ async *processRouter(input, model, modelInput, context, toolsMap) {
115
+ const { toolCalls: [call] = [], } = await context.call(model, modelInput);
116
+ if (!call) {
117
+ throw new Error("Router toolChoice requires exactly one tool to be executed");
118
+ }
119
+ const tool = toolsMap.get(call.function.name);
120
+ if (!tool)
121
+ throw new Error(`Tool not found: ${call.function.name}`);
122
+ const stream = await context.call(tool, { ...call.function.arguments, ...input }, { streaming: true });
123
+ yield* readableStreamToAsyncIterator(stream);
124
+ }
119
125
  }
@@ -4,12 +4,12 @@ export declare function loadAgentFromJsFile(path: string): Promise<{
4
4
  name: string;
5
5
  fn: (args_0: Message) => Message;
6
6
  description?: string | undefined;
7
- input_schema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
7
+ inputSchema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
8
8
  [x: string]: any;
9
9
  }, {
10
10
  [x: string]: any;
11
11
  }> | undefined;
12
- output_schema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
12
+ outputSchema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
13
13
  [x: string]: any;
14
14
  }, {
15
15
  [x: string]: any;