@aigne/core 1.3.1 → 1.4.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.
- package/CHANGELOG.md +12 -0
- package/lib/cjs/agents/agent.d.ts +7 -4
- package/lib/cjs/agents/agent.js +25 -8
- package/lib/cjs/index.d.ts +2 -0
- package/lib/cjs/index.js +2 -0
- package/lib/cjs/models/chat-model.d.ts +1 -0
- package/lib/cjs/models/chat-model.js +1 -0
- package/lib/cjs/models/claude-chat-model.d.ts +9 -9
- package/lib/cjs/models/claude-chat-model.js +60 -41
- package/lib/cjs/models/openai-chat-model.d.ts +10 -9
- package/lib/cjs/models/openai-chat-model.js +19 -10
- package/lib/cjs/models/xai-chat-model.d.ts +12 -0
- package/lib/cjs/models/xai-chat-model.js +18 -0
- package/lib/cjs/package.json +1 -0
- package/lib/cjs/prompt/prompt-builder.d.ts +2 -2
- package/lib/cjs/utils/json-schema.d.ts +9 -1
- package/lib/cjs/utils/json-schema.js +14 -0
- package/lib/cjs/utils/run-chat-loop.js +10 -5
- package/lib/dts/agents/agent.d.ts +7 -4
- package/lib/dts/index.d.ts +2 -0
- package/lib/dts/models/chat-model.d.ts +1 -0
- package/lib/dts/models/claude-chat-model.d.ts +9 -9
- package/lib/dts/models/openai-chat-model.d.ts +10 -9
- package/lib/dts/models/xai-chat-model.d.ts +12 -0
- package/lib/dts/prompt/prompt-builder.d.ts +2 -2
- package/lib/dts/utils/json-schema.d.ts +9 -1
- package/lib/esm/agents/agent.d.ts +7 -4
- package/lib/esm/agents/agent.js +25 -8
- package/lib/esm/index.d.ts +2 -0
- package/lib/esm/index.js +2 -0
- package/lib/esm/models/chat-model.d.ts +1 -0
- package/lib/esm/models/chat-model.js +1 -0
- package/lib/esm/models/claude-chat-model.d.ts +9 -9
- package/lib/esm/models/claude-chat-model.js +60 -41
- package/lib/esm/models/openai-chat-model.d.ts +10 -9
- package/lib/esm/models/openai-chat-model.js +19 -10
- package/lib/esm/models/xai-chat-model.d.ts +12 -0
- package/lib/esm/models/xai-chat-model.js +14 -0
- package/lib/esm/package.json +1 -0
- package/lib/esm/prompt/prompt-builder.d.ts +2 -2
- package/lib/esm/utils/json-schema.d.ts +9 -1
- package/lib/esm/utils/json-schema.js +13 -0
- package/lib/esm/utils/run-chat-loop.js +10 -5
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -22,6 +22,18 @@
|
|
|
22
22
|
* rename @aigne/core-next to @aigne/core ([3a81009](https://github.com/AIGNE-io/aigne-framework/commit/3a8100962c81813217b687ae28e8de604419c622))
|
|
23
23
|
* use text resource from MCP correctly ([8b9eba8](https://github.com/AIGNE-io/aigne-framework/commit/8b9eba83352ec096a2a5d4f410d4c4bde7420bce))
|
|
24
24
|
|
|
25
|
+
## [1.4.0](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.3.1...core-v1.4.0) (2025-03-26)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
### Features
|
|
29
|
+
|
|
30
|
+
* **core:** add xAI chat model adapter ([#34](https://github.com/AIGNE-io/aigne-framework/issues/34)) ([b228d22](https://github.com/AIGNE-io/aigne-framework/commit/b228d22b550535ab8e511f13de9e4a65dd73e3c0))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
### Bug Fixes
|
|
34
|
+
|
|
35
|
+
* **orchestrator:** refactor and enhance orchestrator with step synthesis ([#31](https://github.com/AIGNE-io/aigne-framework/issues/31)) ([ba9fca0](https://github.com/AIGNE-io/aigne-framework/commit/ba9fca04fad71d49c8f4f52172b56668a94ea714))
|
|
36
|
+
|
|
25
37
|
## [1.3.1](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.3.0...core-v1.3.1) (2025-03-25)
|
|
26
38
|
|
|
27
39
|
|
|
@@ -11,8 +11,8 @@ export interface AgentOptions<I extends Message = Message, O extends Message = M
|
|
|
11
11
|
publishTopic?: PublishTopic<O>;
|
|
12
12
|
name?: string;
|
|
13
13
|
description?: string;
|
|
14
|
-
inputSchema?:
|
|
15
|
-
outputSchema?:
|
|
14
|
+
inputSchema?: AgentInputOutputSchema<I>;
|
|
15
|
+
outputSchema?: AgentInputOutputSchema<O>;
|
|
16
16
|
includeInputInOutput?: boolean;
|
|
17
17
|
tools?: (Agent | FunctionAgentFn)[];
|
|
18
18
|
disableLogging?: boolean;
|
|
@@ -27,8 +27,10 @@ export declare abstract class Agent<I extends Message = Message, O extends Messa
|
|
|
27
27
|
*/
|
|
28
28
|
get topic(): string;
|
|
29
29
|
readonly description?: string;
|
|
30
|
-
readonly
|
|
31
|
-
readonly
|
|
30
|
+
private readonly _inputSchema?;
|
|
31
|
+
private readonly _outputSchema?;
|
|
32
|
+
get inputSchema(): ZodType<I>;
|
|
33
|
+
get outputSchema(): ZodType<O>;
|
|
32
34
|
readonly includeInputInOutput?: boolean;
|
|
33
35
|
readonly subscribeTopic?: SubscribeTopic;
|
|
34
36
|
readonly publishTopic?: PublishTopic<Message>;
|
|
@@ -49,6 +51,7 @@ export declare abstract class Agent<I extends Message = Message, O extends Messa
|
|
|
49
51
|
abstract process(input: I, context?: Context): Promise<O | TransferAgentOutput>;
|
|
50
52
|
shutdown(): Promise<void>;
|
|
51
53
|
}
|
|
54
|
+
export type AgentInputOutputSchema<I extends Message = Message> = ZodType<I> | ((agent: Agent) => ZodType<I>);
|
|
52
55
|
export interface FunctionAgentOptions<I extends Message = Message, O extends Message = Message> extends AgentOptions<I, O> {
|
|
53
56
|
fn?: FunctionAgentFn<I, O>;
|
|
54
57
|
}
|
package/lib/cjs/agents/agent.js
CHANGED
|
@@ -11,12 +11,12 @@ class Agent {
|
|
|
11
11
|
constructor({ inputSchema, outputSchema, ...options }) {
|
|
12
12
|
this.name = options.name || this.constructor.name;
|
|
13
13
|
this.description = options.description;
|
|
14
|
-
if (
|
|
15
|
-
(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
this.
|
|
19
|
-
this.
|
|
14
|
+
if (inputSchema)
|
|
15
|
+
checkAgentInputOutputSchema(inputSchema);
|
|
16
|
+
if (outputSchema)
|
|
17
|
+
checkAgentInputOutputSchema(outputSchema);
|
|
18
|
+
this._inputSchema = inputSchema;
|
|
19
|
+
this._outputSchema = outputSchema;
|
|
20
20
|
this.includeInputInOutput = options.includeInputInOutput;
|
|
21
21
|
this.subscribeTopic = options.subscribeTopic;
|
|
22
22
|
this.publishTopic = options.publishTopic;
|
|
@@ -41,8 +41,20 @@ class Agent {
|
|
|
41
41
|
return `$agent_${this.name}`;
|
|
42
42
|
}
|
|
43
43
|
description;
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
_inputSchema;
|
|
45
|
+
_outputSchema;
|
|
46
|
+
get inputSchema() {
|
|
47
|
+
const s = this._inputSchema;
|
|
48
|
+
const schema = typeof s === "function" ? s(this) : s || zod_1.z.object({});
|
|
49
|
+
checkAgentInputOutputSchema(schema);
|
|
50
|
+
return schema.passthrough();
|
|
51
|
+
}
|
|
52
|
+
get outputSchema() {
|
|
53
|
+
const s = this._outputSchema;
|
|
54
|
+
const schema = typeof s === "function" ? s(this) : s || zod_1.z.object({});
|
|
55
|
+
checkAgentInputOutputSchema(schema);
|
|
56
|
+
return schema.passthrough();
|
|
57
|
+
}
|
|
46
58
|
includeInputInOutput;
|
|
47
59
|
subscribeTopic;
|
|
48
60
|
publishTopic;
|
|
@@ -98,6 +110,11 @@ class Agent {
|
|
|
98
110
|
}
|
|
99
111
|
}
|
|
100
112
|
exports.Agent = Agent;
|
|
113
|
+
function checkAgentInputOutputSchema(schema) {
|
|
114
|
+
if (!(schema instanceof zod_1.ZodObject) && typeof schema !== "function") {
|
|
115
|
+
throw new Error("schema must be a zod object or function return a zod object ");
|
|
116
|
+
}
|
|
117
|
+
}
|
|
101
118
|
class FunctionAgent extends Agent {
|
|
102
119
|
static from(options) {
|
|
103
120
|
return typeof options === "function" ? functionToAgent(options) : new FunctionAgent(options);
|
package/lib/cjs/index.d.ts
CHANGED
|
@@ -8,7 +8,9 @@ export * from "./execution-engine/index.js";
|
|
|
8
8
|
export * from "./models/chat-model.js";
|
|
9
9
|
export * from "./models/claude-chat-model.js";
|
|
10
10
|
export * from "./models/openai-chat-model.js";
|
|
11
|
+
export * from "./models/xai-chat-model.js";
|
|
11
12
|
export * from "./prompt/prompt-builder.js";
|
|
12
13
|
export * from "./prompt/template.js";
|
|
14
|
+
export * from "./utils/json-schema.js";
|
|
13
15
|
export * from "./utils/logger.js";
|
|
14
16
|
export * from "./utils/run-chat-loop.js";
|
package/lib/cjs/index.js
CHANGED
|
@@ -24,7 +24,9 @@ __exportStar(require("./execution-engine/index.js"), exports);
|
|
|
24
24
|
__exportStar(require("./models/chat-model.js"), exports);
|
|
25
25
|
__exportStar(require("./models/claude-chat-model.js"), exports);
|
|
26
26
|
__exportStar(require("./models/openai-chat-model.js"), exports);
|
|
27
|
+
__exportStar(require("./models/xai-chat-model.js"), exports);
|
|
27
28
|
__exportStar(require("./prompt/prompt-builder.js"), exports);
|
|
28
29
|
__exportStar(require("./prompt/template.js"), exports);
|
|
30
|
+
__exportStar(require("./utils/json-schema.js"), exports);
|
|
29
31
|
__exportStar(require("./utils/logger.js"), exports);
|
|
30
32
|
__exportStar(require("./utils/run-chat-loop.js"), exports);
|
|
@@ -68,6 +68,7 @@ const chatModelOptionsSchema = zod_1.z.object({
|
|
|
68
68
|
topP: zod_1.z.number().optional(),
|
|
69
69
|
frequencyPenalty: zod_1.z.number().optional(),
|
|
70
70
|
presencePenalty: zod_1.z.number().optional(),
|
|
71
|
+
parallelToolCalls: zod_1.z.boolean().optional().default(true),
|
|
71
72
|
});
|
|
72
73
|
const chatModelInputSchema = zod_1.z.object({
|
|
73
74
|
messages: zod_1.z.array(chatModelInputMessageSchema),
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import Anthropic from "@anthropic-ai/sdk";
|
|
2
|
-
import { ChatModel, type ChatModelInput, type ChatModelOutput } from "./chat-model.js";
|
|
2
|
+
import { ChatModel, type ChatModelInput, type ChatModelOptions, type ChatModelOutput } from "./chat-model.js";
|
|
3
|
+
export interface ClaudeChatModelOptions {
|
|
4
|
+
apiKey?: string;
|
|
5
|
+
model?: string;
|
|
6
|
+
modelOptions?: ChatModelOptions;
|
|
7
|
+
}
|
|
3
8
|
export declare class ClaudeChatModel extends ChatModel {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
model?: string;
|
|
7
|
-
} | undefined;
|
|
8
|
-
constructor(config?: {
|
|
9
|
-
apiKey?: string;
|
|
10
|
-
model?: string;
|
|
11
|
-
} | undefined);
|
|
9
|
+
options?: ClaudeChatModelOptions | undefined;
|
|
10
|
+
constructor(options?: ClaudeChatModelOptions | undefined);
|
|
12
11
|
private _client?;
|
|
13
12
|
get client(): Anthropic;
|
|
13
|
+
get modelOptions(): ChatModelOptions | undefined;
|
|
14
14
|
process(input: ChatModelInput): Promise<ChatModelOutput>;
|
|
15
15
|
private extractResultFromClaudeStream;
|
|
16
16
|
private requestStructuredOutput;
|
|
@@ -7,32 +7,38 @@ exports.ClaudeChatModel = void 0;
|
|
|
7
7
|
const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
|
|
8
8
|
const lodash_es_1 = require("lodash-es");
|
|
9
9
|
const json_schema_js_1 = require("../utils/json-schema.js");
|
|
10
|
+
const logger_js_1 = require("../utils/logger.js");
|
|
10
11
|
const type_utils_js_1 = require("../utils/type-utils.js");
|
|
11
12
|
const chat_model_js_1 = require("./chat-model.js");
|
|
12
13
|
const CHAT_MODEL_CLAUDE_DEFAULT_MODEL = "claude-3-7-sonnet-latest";
|
|
13
14
|
class ClaudeChatModel extends chat_model_js_1.ChatModel {
|
|
14
|
-
|
|
15
|
-
constructor(
|
|
15
|
+
options;
|
|
16
|
+
constructor(options) {
|
|
16
17
|
super();
|
|
17
|
-
this.
|
|
18
|
+
this.options = options;
|
|
18
19
|
}
|
|
19
20
|
_client;
|
|
20
21
|
get client() {
|
|
21
|
-
if (!this.
|
|
22
|
+
if (!this.options?.apiKey)
|
|
22
23
|
throw new Error("Api Key is required for ClaudeChatModel");
|
|
23
|
-
this._client ??= new sdk_1.default({ apiKey: this.
|
|
24
|
+
this._client ??= new sdk_1.default({ apiKey: this.options.apiKey });
|
|
24
25
|
return this._client;
|
|
25
26
|
}
|
|
27
|
+
get modelOptions() {
|
|
28
|
+
return this.options?.modelOptions;
|
|
29
|
+
}
|
|
26
30
|
async process(input) {
|
|
27
|
-
const model = this.
|
|
31
|
+
const model = this.options?.model || CHAT_MODEL_CLAUDE_DEFAULT_MODEL;
|
|
32
|
+
const disableParallelToolUse = input.modelOptions?.parallelToolCalls === false ||
|
|
33
|
+
this.modelOptions?.parallelToolCalls === false;
|
|
28
34
|
const body = {
|
|
29
35
|
model,
|
|
30
|
-
temperature: input.modelOptions?.temperature,
|
|
31
|
-
top_p: input.modelOptions?.topP,
|
|
36
|
+
temperature: input.modelOptions?.temperature ?? this.modelOptions?.temperature,
|
|
37
|
+
top_p: input.modelOptions?.topP ?? this.modelOptions?.topP,
|
|
32
38
|
// TODO: make dynamic based on model https://docs.anthropic.com/en/docs/about-claude/models/all-models
|
|
33
39
|
max_tokens: /claude-3-[5|7]/.test(model) ? 8192 : 4096,
|
|
34
40
|
...convertMessages(input),
|
|
35
|
-
...convertTools(input),
|
|
41
|
+
...convertTools({ ...input, disableParallelToolUse }),
|
|
36
42
|
};
|
|
37
43
|
const stream = this.client.messages.stream({
|
|
38
44
|
...body,
|
|
@@ -47,41 +53,53 @@ class ClaudeChatModel extends chat_model_js_1.ChatModel {
|
|
|
47
53
|
return result;
|
|
48
54
|
}
|
|
49
55
|
async extractResultFromClaudeStream(stream) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
const logs = [];
|
|
57
|
+
try {
|
|
58
|
+
let text = "";
|
|
59
|
+
const toolCalls = [];
|
|
60
|
+
for await (const chunk of stream) {
|
|
61
|
+
logs.push(JSON.stringify(chunk));
|
|
62
|
+
// handle streaming text
|
|
63
|
+
if (chunk.type === "content_block_delta" && chunk.delta.type === "text_delta") {
|
|
64
|
+
text += chunk.delta.text;
|
|
65
|
+
}
|
|
66
|
+
if (chunk.type === "content_block_start" && chunk.content_block.type === "tool_use") {
|
|
67
|
+
toolCalls[chunk.index] = {
|
|
68
|
+
type: "function",
|
|
69
|
+
id: chunk.content_block.id,
|
|
70
|
+
function: {
|
|
71
|
+
name: chunk.content_block.name,
|
|
72
|
+
arguments: {},
|
|
73
|
+
},
|
|
74
|
+
args: "",
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
if (chunk.type === "content_block_delta" && chunk.delta.type === "input_json_delta") {
|
|
78
|
+
const call = toolCalls[chunk.index];
|
|
79
|
+
if (!call)
|
|
80
|
+
throw new Error("Tool call not found");
|
|
81
|
+
call.args += chunk.delta.partial_json;
|
|
82
|
+
}
|
|
56
83
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
84
|
+
const result = { text };
|
|
85
|
+
if (toolCalls.length) {
|
|
86
|
+
result.toolCalls = toolCalls
|
|
87
|
+
.map(({ args, ...c }) => ({
|
|
88
|
+
...c,
|
|
61
89
|
function: {
|
|
62
|
-
|
|
63
|
-
|
|
90
|
+
...c.function,
|
|
91
|
+
// NOTE: claude may return a blank string for empty object (the tool's input schema is a empty object)
|
|
92
|
+
arguments: args.trim() ? (0, json_schema_js_1.parseJSON)(args) : {},
|
|
64
93
|
},
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
if (chunk.type === "content_block_delta" && chunk.delta.type === "input_json_delta") {
|
|
69
|
-
const call = toolCalls[chunk.index];
|
|
70
|
-
if (!call)
|
|
71
|
-
throw new Error("Tool call not found");
|
|
72
|
-
call.args += chunk.delta.partial_json;
|
|
94
|
+
}))
|
|
95
|
+
.filter(type_utils_js_1.isNonNullable);
|
|
73
96
|
}
|
|
97
|
+
return result;
|
|
74
98
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
.map(({ args, ...c }) => ({
|
|
79
|
-
...c,
|
|
80
|
-
function: { ...c.function, arguments: (0, json_schema_js_1.parseJSON)(args) },
|
|
81
|
-
}))
|
|
82
|
-
.filter(type_utils_js_1.isNonNullable);
|
|
99
|
+
catch (error) {
|
|
100
|
+
logger_js_1.logger.debug("Failed to process Claude stream", { error, logs });
|
|
101
|
+
throw error;
|
|
83
102
|
}
|
|
84
|
-
return result;
|
|
85
103
|
}
|
|
86
104
|
async requestStructuredOutput(body, responseFormat) {
|
|
87
105
|
if (responseFormat?.type !== "json_schema") {
|
|
@@ -178,19 +196,20 @@ function convertContent(content) {
|
|
|
178
196
|
}
|
|
179
197
|
throw new Error("Invalid chat message content");
|
|
180
198
|
}
|
|
181
|
-
function convertTools({ tools, toolChoice, }) {
|
|
199
|
+
function convertTools({ tools, toolChoice, disableParallelToolUse, }) {
|
|
182
200
|
let choice;
|
|
183
201
|
if (typeof toolChoice === "object" && "type" in toolChoice && toolChoice.type === "function") {
|
|
184
202
|
choice = {
|
|
185
203
|
type: "tool",
|
|
186
204
|
name: toolChoice.function.name,
|
|
205
|
+
disable_parallel_tool_use: disableParallelToolUse,
|
|
187
206
|
};
|
|
188
207
|
}
|
|
189
208
|
else if (toolChoice === "required") {
|
|
190
|
-
choice = { type: "any" };
|
|
209
|
+
choice = { type: "any", disable_parallel_tool_use: disableParallelToolUse };
|
|
191
210
|
}
|
|
192
211
|
else if (toolChoice === "auto") {
|
|
193
|
-
choice = { type: "auto" };
|
|
212
|
+
choice = { type: "auto", disable_parallel_tool_use: disableParallelToolUse };
|
|
194
213
|
}
|
|
195
214
|
else if (toolChoice === "none") {
|
|
196
215
|
choice = { type: "none" };
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { ChatModel, type ChatModelInput, type ChatModelOutput } from "./chat-model.js";
|
|
1
|
+
import { ChatModel, type ChatModelInput, type ChatModelOptions, type ChatModelOutput } from "./chat-model.js";
|
|
2
|
+
export interface OpenAIChatModelOptions {
|
|
3
|
+
apiKey?: string;
|
|
4
|
+
baseURL?: string;
|
|
5
|
+
model?: string;
|
|
6
|
+
modelOptions?: ChatModelOptions;
|
|
7
|
+
}
|
|
2
8
|
export declare class OpenAIChatModel extends ChatModel {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
model?: string;
|
|
6
|
-
} | undefined;
|
|
7
|
-
constructor(config?: {
|
|
8
|
-
apiKey?: string;
|
|
9
|
-
model?: string;
|
|
10
|
-
} | undefined);
|
|
9
|
+
options?: OpenAIChatModelOptions | undefined;
|
|
10
|
+
constructor(options?: OpenAIChatModelOptions | undefined);
|
|
11
11
|
private _client?;
|
|
12
12
|
private get client();
|
|
13
|
+
get modelOptions(): ChatModelOptions | undefined;
|
|
13
14
|
process(input: ChatModelInput): Promise<ChatModelOutput>;
|
|
14
15
|
}
|
|
@@ -11,28 +11,37 @@ const type_utils_js_1 = require("../utils/type-utils.js");
|
|
|
11
11
|
const chat_model_js_1 = require("./chat-model.js");
|
|
12
12
|
const CHAT_MODEL_OPENAI_DEFAULT_MODEL = "gpt-4o-mini";
|
|
13
13
|
class OpenAIChatModel extends chat_model_js_1.ChatModel {
|
|
14
|
-
|
|
15
|
-
constructor(
|
|
14
|
+
options;
|
|
15
|
+
constructor(options) {
|
|
16
16
|
super();
|
|
17
|
-
this.
|
|
17
|
+
this.options = options;
|
|
18
18
|
}
|
|
19
19
|
_client;
|
|
20
20
|
get client() {
|
|
21
|
-
if (!this.
|
|
21
|
+
if (!this.options?.apiKey)
|
|
22
22
|
throw new Error("Api Key is required for OpenAIChatModel");
|
|
23
|
-
this._client ??= new openai_1.default({
|
|
23
|
+
this._client ??= new openai_1.default({
|
|
24
|
+
baseURL: this.options.baseURL,
|
|
25
|
+
apiKey: this.options.apiKey,
|
|
26
|
+
});
|
|
24
27
|
return this._client;
|
|
25
28
|
}
|
|
29
|
+
get modelOptions() {
|
|
30
|
+
return this.options?.modelOptions;
|
|
31
|
+
}
|
|
26
32
|
async process(input) {
|
|
27
33
|
const res = await this.client.chat.completions.create({
|
|
28
|
-
model: this.
|
|
29
|
-
temperature: input.modelOptions?.temperature,
|
|
30
|
-
top_p: input.modelOptions?.topP,
|
|
31
|
-
frequency_penalty: input.modelOptions?.frequencyPenalty,
|
|
32
|
-
presence_penalty: input.modelOptions?.presencePenalty,
|
|
34
|
+
model: this.options?.model || CHAT_MODEL_OPENAI_DEFAULT_MODEL,
|
|
35
|
+
temperature: input.modelOptions?.temperature ?? this.modelOptions?.temperature,
|
|
36
|
+
top_p: input.modelOptions?.topP ?? this.modelOptions?.topP,
|
|
37
|
+
frequency_penalty: input.modelOptions?.frequencyPenalty ?? this.modelOptions?.frequencyPenalty,
|
|
38
|
+
presence_penalty: input.modelOptions?.presencePenalty ?? this.modelOptions?.presencePenalty,
|
|
33
39
|
messages: await contentsFromInputMessages(input.messages),
|
|
34
40
|
tools: toolsFromInputTools(input.tools),
|
|
35
41
|
tool_choice: input.toolChoice,
|
|
42
|
+
parallel_tool_calls: !input.tools?.length
|
|
43
|
+
? undefined
|
|
44
|
+
: (input.modelOptions?.parallelToolCalls ?? this.modelOptions?.parallelToolCalls),
|
|
36
45
|
response_format: input.responseFormat?.type === "json_schema"
|
|
37
46
|
? {
|
|
38
47
|
type: "json_schema",
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ChatModelOptions } from "./chat-model.js";
|
|
2
|
+
import { OpenAIChatModel } from "./openai-chat-model.js";
|
|
3
|
+
export interface XAIChatModelOptions {
|
|
4
|
+
apiKey?: string;
|
|
5
|
+
model?: string;
|
|
6
|
+
modelOptions?: ChatModelOptions;
|
|
7
|
+
baseURL?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class XAIChatModel extends OpenAIChatModel {
|
|
10
|
+
options?: XAIChatModelOptions | undefined;
|
|
11
|
+
constructor(options?: XAIChatModelOptions | undefined);
|
|
12
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.XAIChatModel = void 0;
|
|
4
|
+
const openai_chat_model_js_1 = require("./openai-chat-model.js");
|
|
5
|
+
const XAI_DEFAULT_CHAT_MODEL = "grok-2-latest";
|
|
6
|
+
const XAI_BASE_URL = "https://api.x.ai/v1";
|
|
7
|
+
class XAIChatModel extends openai_chat_model_js_1.OpenAIChatModel {
|
|
8
|
+
options;
|
|
9
|
+
constructor(options) {
|
|
10
|
+
super({
|
|
11
|
+
...options,
|
|
12
|
+
model: options?.model || XAI_DEFAULT_CHAT_MODEL,
|
|
13
|
+
baseURL: options?.baseURL || XAI_BASE_URL,
|
|
14
|
+
});
|
|
15
|
+
this.options = options;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.XAIChatModel = XAIChatModel;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type": "commonjs"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { GetPromptResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
-
import { Agent, type
|
|
2
|
+
import { Agent, type Message } from "../agents/agent.js";
|
|
3
3
|
import type { AIAgent } from "../agents/ai-agent.js";
|
|
4
4
|
import type { AgentMemory } from "../agents/memory.js";
|
|
5
5
|
import type { Context } from "../execution-engine/context.js";
|
|
@@ -18,7 +18,7 @@ export interface PromptBuilderBuildOptions {
|
|
|
18
18
|
agent?: AIAgent;
|
|
19
19
|
input?: Message;
|
|
20
20
|
model?: ChatModel;
|
|
21
|
-
outputSchema?:
|
|
21
|
+
outputSchema?: Agent["outputSchema"];
|
|
22
22
|
}
|
|
23
23
|
export declare class PromptBuilder {
|
|
24
24
|
static from(instructions: string): PromptBuilder;
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import type { ZodType } from "zod";
|
|
1
|
+
import type { ZodType, z } from "zod";
|
|
2
2
|
import type { Message } from "../agents/agent.js";
|
|
3
3
|
export declare function outputSchemaToResponseFormatSchema(agentOutput: ZodType<Message>): Record<string, unknown>;
|
|
4
4
|
export declare function parseJSON(json: string): any;
|
|
5
|
+
/**
|
|
6
|
+
* Ensure that the union array has at least 1 item.
|
|
7
|
+
* NOTE: the zod union requires at least 2 items (just type definition, not runtime behavior)
|
|
8
|
+
* so we need to ensure that the union has at least 1 item.
|
|
9
|
+
* @param union - The union array
|
|
10
|
+
* @returns The union array with at least 1 item (but the type is at least 2 items for z.union)
|
|
11
|
+
*/
|
|
12
|
+
export declare function ensureZodUnionArray<T extends z.ZodType>(union: T[]): [T, T, ...T[]];
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.outputSchemaToResponseFormatSchema = outputSchemaToResponseFormatSchema;
|
|
4
4
|
exports.parseJSON = parseJSON;
|
|
5
|
+
exports.ensureZodUnionArray = ensureZodUnionArray;
|
|
5
6
|
const lodash_es_1 = require("lodash-es");
|
|
6
7
|
const zod_to_json_schema_1 = require("zod-to-json-schema");
|
|
7
8
|
const logger_js_1 = require("./logger.js");
|
|
@@ -32,3 +33,16 @@ function parseJSON(json) {
|
|
|
32
33
|
throw new Error(`Failed to parse JSON ${error.message}`);
|
|
33
34
|
}
|
|
34
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Ensure that the union array has at least 1 item.
|
|
38
|
+
* NOTE: the zod union requires at least 2 items (just type definition, not runtime behavior)
|
|
39
|
+
* so we need to ensure that the union has at least 1 item.
|
|
40
|
+
* @param union - The union array
|
|
41
|
+
* @returns The union array with at least 1 item (but the type is at least 2 items for z.union)
|
|
42
|
+
*/
|
|
43
|
+
function ensureZodUnionArray(union) {
|
|
44
|
+
if (!(union.length >= 1)) {
|
|
45
|
+
throw new Error(`Union must have at least 1 item, but got ${union.length}`);
|
|
46
|
+
}
|
|
47
|
+
return union;
|
|
48
|
+
}
|
|
@@ -57,11 +57,16 @@ async function runChatLoopInTerminal(userAgent, { log = console.log.bind(console
|
|
|
57
57
|
isLoopExited = true;
|
|
58
58
|
}
|
|
59
59
|
async function callAgent(agent, input, options) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
options
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
try {
|
|
61
|
+
const response = await logger_js_1.logger.spinner(agent.call(options.inputKey && typeof input === "string" ? { [options.inputKey]: input } : input), "🤖");
|
|
62
|
+
if (options?.onResponse)
|
|
63
|
+
options.onResponse(response);
|
|
64
|
+
else
|
|
65
|
+
options.log(response);
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
options.log(`ERROR: ${error.message}`);
|
|
69
|
+
}
|
|
65
70
|
}
|
|
66
71
|
const COMMANDS = {
|
|
67
72
|
"/exit": () => ({ exit: true }),
|
|
@@ -11,8 +11,8 @@ export interface AgentOptions<I extends Message = Message, O extends Message = M
|
|
|
11
11
|
publishTopic?: PublishTopic<O>;
|
|
12
12
|
name?: string;
|
|
13
13
|
description?: string;
|
|
14
|
-
inputSchema?:
|
|
15
|
-
outputSchema?:
|
|
14
|
+
inputSchema?: AgentInputOutputSchema<I>;
|
|
15
|
+
outputSchema?: AgentInputOutputSchema<O>;
|
|
16
16
|
includeInputInOutput?: boolean;
|
|
17
17
|
tools?: (Agent | FunctionAgentFn)[];
|
|
18
18
|
disableLogging?: boolean;
|
|
@@ -27,8 +27,10 @@ export declare abstract class Agent<I extends Message = Message, O extends Messa
|
|
|
27
27
|
*/
|
|
28
28
|
get topic(): string;
|
|
29
29
|
readonly description?: string;
|
|
30
|
-
readonly
|
|
31
|
-
readonly
|
|
30
|
+
private readonly _inputSchema?;
|
|
31
|
+
private readonly _outputSchema?;
|
|
32
|
+
get inputSchema(): ZodType<I>;
|
|
33
|
+
get outputSchema(): ZodType<O>;
|
|
32
34
|
readonly includeInputInOutput?: boolean;
|
|
33
35
|
readonly subscribeTopic?: SubscribeTopic;
|
|
34
36
|
readonly publishTopic?: PublishTopic<Message>;
|
|
@@ -49,6 +51,7 @@ export declare abstract class Agent<I extends Message = Message, O extends Messa
|
|
|
49
51
|
abstract process(input: I, context?: Context): Promise<O | TransferAgentOutput>;
|
|
50
52
|
shutdown(): Promise<void>;
|
|
51
53
|
}
|
|
54
|
+
export type AgentInputOutputSchema<I extends Message = Message> = ZodType<I> | ((agent: Agent) => ZodType<I>);
|
|
52
55
|
export interface FunctionAgentOptions<I extends Message = Message, O extends Message = Message> extends AgentOptions<I, O> {
|
|
53
56
|
fn?: FunctionAgentFn<I, O>;
|
|
54
57
|
}
|
package/lib/dts/index.d.ts
CHANGED
|
@@ -8,7 +8,9 @@ export * from "./execution-engine/index.js";
|
|
|
8
8
|
export * from "./models/chat-model.js";
|
|
9
9
|
export * from "./models/claude-chat-model.js";
|
|
10
10
|
export * from "./models/openai-chat-model.js";
|
|
11
|
+
export * from "./models/xai-chat-model.js";
|
|
11
12
|
export * from "./prompt/prompt-builder.js";
|
|
12
13
|
export * from "./prompt/template.js";
|
|
14
|
+
export * from "./utils/json-schema.js";
|
|
13
15
|
export * from "./utils/logger.js";
|
|
14
16
|
export * from "./utils/run-chat-loop.js";
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import Anthropic from "@anthropic-ai/sdk";
|
|
2
|
-
import { ChatModel, type ChatModelInput, type ChatModelOutput } from "./chat-model.js";
|
|
2
|
+
import { ChatModel, type ChatModelInput, type ChatModelOptions, type ChatModelOutput } from "./chat-model.js";
|
|
3
|
+
export interface ClaudeChatModelOptions {
|
|
4
|
+
apiKey?: string;
|
|
5
|
+
model?: string;
|
|
6
|
+
modelOptions?: ChatModelOptions;
|
|
7
|
+
}
|
|
3
8
|
export declare class ClaudeChatModel extends ChatModel {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
model?: string;
|
|
7
|
-
} | undefined;
|
|
8
|
-
constructor(config?: {
|
|
9
|
-
apiKey?: string;
|
|
10
|
-
model?: string;
|
|
11
|
-
} | undefined);
|
|
9
|
+
options?: ClaudeChatModelOptions | undefined;
|
|
10
|
+
constructor(options?: ClaudeChatModelOptions | undefined);
|
|
12
11
|
private _client?;
|
|
13
12
|
get client(): Anthropic;
|
|
13
|
+
get modelOptions(): ChatModelOptions | undefined;
|
|
14
14
|
process(input: ChatModelInput): Promise<ChatModelOutput>;
|
|
15
15
|
private extractResultFromClaudeStream;
|
|
16
16
|
private requestStructuredOutput;
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { ChatModel, type ChatModelInput, type ChatModelOutput } from "./chat-model.js";
|
|
1
|
+
import { ChatModel, type ChatModelInput, type ChatModelOptions, type ChatModelOutput } from "./chat-model.js";
|
|
2
|
+
export interface OpenAIChatModelOptions {
|
|
3
|
+
apiKey?: string;
|
|
4
|
+
baseURL?: string;
|
|
5
|
+
model?: string;
|
|
6
|
+
modelOptions?: ChatModelOptions;
|
|
7
|
+
}
|
|
2
8
|
export declare class OpenAIChatModel extends ChatModel {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
model?: string;
|
|
6
|
-
} | undefined;
|
|
7
|
-
constructor(config?: {
|
|
8
|
-
apiKey?: string;
|
|
9
|
-
model?: string;
|
|
10
|
-
} | undefined);
|
|
9
|
+
options?: OpenAIChatModelOptions | undefined;
|
|
10
|
+
constructor(options?: OpenAIChatModelOptions | undefined);
|
|
11
11
|
private _client?;
|
|
12
12
|
private get client();
|
|
13
|
+
get modelOptions(): ChatModelOptions | undefined;
|
|
13
14
|
process(input: ChatModelInput): Promise<ChatModelOutput>;
|
|
14
15
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ChatModelOptions } from "./chat-model.js";
|
|
2
|
+
import { OpenAIChatModel } from "./openai-chat-model.js";
|
|
3
|
+
export interface XAIChatModelOptions {
|
|
4
|
+
apiKey?: string;
|
|
5
|
+
model?: string;
|
|
6
|
+
modelOptions?: ChatModelOptions;
|
|
7
|
+
baseURL?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class XAIChatModel extends OpenAIChatModel {
|
|
10
|
+
options?: XAIChatModelOptions | undefined;
|
|
11
|
+
constructor(options?: XAIChatModelOptions | undefined);
|
|
12
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { GetPromptResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
-
import { Agent, type
|
|
2
|
+
import { Agent, type Message } from "../agents/agent.js";
|
|
3
3
|
import type { AIAgent } from "../agents/ai-agent.js";
|
|
4
4
|
import type { AgentMemory } from "../agents/memory.js";
|
|
5
5
|
import type { Context } from "../execution-engine/context.js";
|
|
@@ -18,7 +18,7 @@ export interface PromptBuilderBuildOptions {
|
|
|
18
18
|
agent?: AIAgent;
|
|
19
19
|
input?: Message;
|
|
20
20
|
model?: ChatModel;
|
|
21
|
-
outputSchema?:
|
|
21
|
+
outputSchema?: Agent["outputSchema"];
|
|
22
22
|
}
|
|
23
23
|
export declare class PromptBuilder {
|
|
24
24
|
static from(instructions: string): PromptBuilder;
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import type { ZodType } from "zod";
|
|
1
|
+
import type { ZodType, z } from "zod";
|
|
2
2
|
import type { Message } from "../agents/agent.js";
|
|
3
3
|
export declare function outputSchemaToResponseFormatSchema(agentOutput: ZodType<Message>): Record<string, unknown>;
|
|
4
4
|
export declare function parseJSON(json: string): any;
|
|
5
|
+
/**
|
|
6
|
+
* Ensure that the union array has at least 1 item.
|
|
7
|
+
* NOTE: the zod union requires at least 2 items (just type definition, not runtime behavior)
|
|
8
|
+
* so we need to ensure that the union has at least 1 item.
|
|
9
|
+
* @param union - The union array
|
|
10
|
+
* @returns The union array with at least 1 item (but the type is at least 2 items for z.union)
|
|
11
|
+
*/
|
|
12
|
+
export declare function ensureZodUnionArray<T extends z.ZodType>(union: T[]): [T, T, ...T[]];
|
|
@@ -11,8 +11,8 @@ export interface AgentOptions<I extends Message = Message, O extends Message = M
|
|
|
11
11
|
publishTopic?: PublishTopic<O>;
|
|
12
12
|
name?: string;
|
|
13
13
|
description?: string;
|
|
14
|
-
inputSchema?:
|
|
15
|
-
outputSchema?:
|
|
14
|
+
inputSchema?: AgentInputOutputSchema<I>;
|
|
15
|
+
outputSchema?: AgentInputOutputSchema<O>;
|
|
16
16
|
includeInputInOutput?: boolean;
|
|
17
17
|
tools?: (Agent | FunctionAgentFn)[];
|
|
18
18
|
disableLogging?: boolean;
|
|
@@ -27,8 +27,10 @@ export declare abstract class Agent<I extends Message = Message, O extends Messa
|
|
|
27
27
|
*/
|
|
28
28
|
get topic(): string;
|
|
29
29
|
readonly description?: string;
|
|
30
|
-
readonly
|
|
31
|
-
readonly
|
|
30
|
+
private readonly _inputSchema?;
|
|
31
|
+
private readonly _outputSchema?;
|
|
32
|
+
get inputSchema(): ZodType<I>;
|
|
33
|
+
get outputSchema(): ZodType<O>;
|
|
32
34
|
readonly includeInputInOutput?: boolean;
|
|
33
35
|
readonly subscribeTopic?: SubscribeTopic;
|
|
34
36
|
readonly publishTopic?: PublishTopic<Message>;
|
|
@@ -49,6 +51,7 @@ export declare abstract class Agent<I extends Message = Message, O extends Messa
|
|
|
49
51
|
abstract process(input: I, context?: Context): Promise<O | TransferAgentOutput>;
|
|
50
52
|
shutdown(): Promise<void>;
|
|
51
53
|
}
|
|
54
|
+
export type AgentInputOutputSchema<I extends Message = Message> = ZodType<I> | ((agent: Agent) => ZodType<I>);
|
|
52
55
|
export interface FunctionAgentOptions<I extends Message = Message, O extends Message = Message> extends AgentOptions<I, O> {
|
|
53
56
|
fn?: FunctionAgentFn<I, O>;
|
|
54
57
|
}
|
package/lib/esm/agents/agent.js
CHANGED
|
@@ -8,12 +8,12 @@ export class Agent {
|
|
|
8
8
|
constructor({ inputSchema, outputSchema, ...options }) {
|
|
9
9
|
this.name = options.name || this.constructor.name;
|
|
10
10
|
this.description = options.description;
|
|
11
|
-
if (
|
|
12
|
-
(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
this.
|
|
16
|
-
this.
|
|
11
|
+
if (inputSchema)
|
|
12
|
+
checkAgentInputOutputSchema(inputSchema);
|
|
13
|
+
if (outputSchema)
|
|
14
|
+
checkAgentInputOutputSchema(outputSchema);
|
|
15
|
+
this._inputSchema = inputSchema;
|
|
16
|
+
this._outputSchema = outputSchema;
|
|
17
17
|
this.includeInputInOutput = options.includeInputInOutput;
|
|
18
18
|
this.subscribeTopic = options.subscribeTopic;
|
|
19
19
|
this.publishTopic = options.publishTopic;
|
|
@@ -38,8 +38,20 @@ export class Agent {
|
|
|
38
38
|
return `$agent_${this.name}`;
|
|
39
39
|
}
|
|
40
40
|
description;
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
_inputSchema;
|
|
42
|
+
_outputSchema;
|
|
43
|
+
get inputSchema() {
|
|
44
|
+
const s = this._inputSchema;
|
|
45
|
+
const schema = typeof s === "function" ? s(this) : s || z.object({});
|
|
46
|
+
checkAgentInputOutputSchema(schema);
|
|
47
|
+
return schema.passthrough();
|
|
48
|
+
}
|
|
49
|
+
get outputSchema() {
|
|
50
|
+
const s = this._outputSchema;
|
|
51
|
+
const schema = typeof s === "function" ? s(this) : s || z.object({});
|
|
52
|
+
checkAgentInputOutputSchema(schema);
|
|
53
|
+
return schema.passthrough();
|
|
54
|
+
}
|
|
43
55
|
includeInputInOutput;
|
|
44
56
|
subscribeTopic;
|
|
45
57
|
publishTopic;
|
|
@@ -94,6 +106,11 @@ export class Agent {
|
|
|
94
106
|
this.memory?.detach();
|
|
95
107
|
}
|
|
96
108
|
}
|
|
109
|
+
function checkAgentInputOutputSchema(schema) {
|
|
110
|
+
if (!(schema instanceof ZodObject) && typeof schema !== "function") {
|
|
111
|
+
throw new Error("schema must be a zod object or function return a zod object ");
|
|
112
|
+
}
|
|
113
|
+
}
|
|
97
114
|
export class FunctionAgent extends Agent {
|
|
98
115
|
static from(options) {
|
|
99
116
|
return typeof options === "function" ? functionToAgent(options) : new FunctionAgent(options);
|
package/lib/esm/index.d.ts
CHANGED
|
@@ -8,7 +8,9 @@ export * from "./execution-engine/index.js";
|
|
|
8
8
|
export * from "./models/chat-model.js";
|
|
9
9
|
export * from "./models/claude-chat-model.js";
|
|
10
10
|
export * from "./models/openai-chat-model.js";
|
|
11
|
+
export * from "./models/xai-chat-model.js";
|
|
11
12
|
export * from "./prompt/prompt-builder.js";
|
|
12
13
|
export * from "./prompt/template.js";
|
|
14
|
+
export * from "./utils/json-schema.js";
|
|
13
15
|
export * from "./utils/logger.js";
|
|
14
16
|
export * from "./utils/run-chat-loop.js";
|
package/lib/esm/index.js
CHANGED
|
@@ -8,7 +8,9 @@ export * from "./execution-engine/index.js";
|
|
|
8
8
|
export * from "./models/chat-model.js";
|
|
9
9
|
export * from "./models/claude-chat-model.js";
|
|
10
10
|
export * from "./models/openai-chat-model.js";
|
|
11
|
+
export * from "./models/xai-chat-model.js";
|
|
11
12
|
export * from "./prompt/prompt-builder.js";
|
|
12
13
|
export * from "./prompt/template.js";
|
|
14
|
+
export * from "./utils/json-schema.js";
|
|
13
15
|
export * from "./utils/logger.js";
|
|
14
16
|
export * from "./utils/run-chat-loop.js";
|
|
@@ -64,6 +64,7 @@ const chatModelOptionsSchema = z.object({
|
|
|
64
64
|
topP: z.number().optional(),
|
|
65
65
|
frequencyPenalty: z.number().optional(),
|
|
66
66
|
presencePenalty: z.number().optional(),
|
|
67
|
+
parallelToolCalls: z.boolean().optional().default(true),
|
|
67
68
|
});
|
|
68
69
|
const chatModelInputSchema = z.object({
|
|
69
70
|
messages: z.array(chatModelInputMessageSchema),
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import Anthropic from "@anthropic-ai/sdk";
|
|
2
|
-
import { ChatModel, type ChatModelInput, type ChatModelOutput } from "./chat-model.js";
|
|
2
|
+
import { ChatModel, type ChatModelInput, type ChatModelOptions, type ChatModelOutput } from "./chat-model.js";
|
|
3
|
+
export interface ClaudeChatModelOptions {
|
|
4
|
+
apiKey?: string;
|
|
5
|
+
model?: string;
|
|
6
|
+
modelOptions?: ChatModelOptions;
|
|
7
|
+
}
|
|
3
8
|
export declare class ClaudeChatModel extends ChatModel {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
model?: string;
|
|
7
|
-
} | undefined;
|
|
8
|
-
constructor(config?: {
|
|
9
|
-
apiKey?: string;
|
|
10
|
-
model?: string;
|
|
11
|
-
} | undefined);
|
|
9
|
+
options?: ClaudeChatModelOptions | undefined;
|
|
10
|
+
constructor(options?: ClaudeChatModelOptions | undefined);
|
|
12
11
|
private _client?;
|
|
13
12
|
get client(): Anthropic;
|
|
13
|
+
get modelOptions(): ChatModelOptions | undefined;
|
|
14
14
|
process(input: ChatModelInput): Promise<ChatModelOutput>;
|
|
15
15
|
private extractResultFromClaudeStream;
|
|
16
16
|
private requestStructuredOutput;
|
|
@@ -1,32 +1,38 @@
|
|
|
1
1
|
import Anthropic from "@anthropic-ai/sdk";
|
|
2
2
|
import { isEmpty } from "lodash-es";
|
|
3
3
|
import { parseJSON } from "../utils/json-schema.js";
|
|
4
|
+
import { logger } from "../utils/logger.js";
|
|
4
5
|
import { isNonNullable } from "../utils/type-utils.js";
|
|
5
6
|
import { ChatModel, } from "./chat-model.js";
|
|
6
7
|
const CHAT_MODEL_CLAUDE_DEFAULT_MODEL = "claude-3-7-sonnet-latest";
|
|
7
8
|
export class ClaudeChatModel extends ChatModel {
|
|
8
|
-
|
|
9
|
-
constructor(
|
|
9
|
+
options;
|
|
10
|
+
constructor(options) {
|
|
10
11
|
super();
|
|
11
|
-
this.
|
|
12
|
+
this.options = options;
|
|
12
13
|
}
|
|
13
14
|
_client;
|
|
14
15
|
get client() {
|
|
15
|
-
if (!this.
|
|
16
|
+
if (!this.options?.apiKey)
|
|
16
17
|
throw new Error("Api Key is required for ClaudeChatModel");
|
|
17
|
-
this._client ??= new Anthropic({ apiKey: this.
|
|
18
|
+
this._client ??= new Anthropic({ apiKey: this.options.apiKey });
|
|
18
19
|
return this._client;
|
|
19
20
|
}
|
|
21
|
+
get modelOptions() {
|
|
22
|
+
return this.options?.modelOptions;
|
|
23
|
+
}
|
|
20
24
|
async process(input) {
|
|
21
|
-
const model = this.
|
|
25
|
+
const model = this.options?.model || CHAT_MODEL_CLAUDE_DEFAULT_MODEL;
|
|
26
|
+
const disableParallelToolUse = input.modelOptions?.parallelToolCalls === false ||
|
|
27
|
+
this.modelOptions?.parallelToolCalls === false;
|
|
22
28
|
const body = {
|
|
23
29
|
model,
|
|
24
|
-
temperature: input.modelOptions?.temperature,
|
|
25
|
-
top_p: input.modelOptions?.topP,
|
|
30
|
+
temperature: input.modelOptions?.temperature ?? this.modelOptions?.temperature,
|
|
31
|
+
top_p: input.modelOptions?.topP ?? this.modelOptions?.topP,
|
|
26
32
|
// TODO: make dynamic based on model https://docs.anthropic.com/en/docs/about-claude/models/all-models
|
|
27
33
|
max_tokens: /claude-3-[5|7]/.test(model) ? 8192 : 4096,
|
|
28
34
|
...convertMessages(input),
|
|
29
|
-
...convertTools(input),
|
|
35
|
+
...convertTools({ ...input, disableParallelToolUse }),
|
|
30
36
|
};
|
|
31
37
|
const stream = this.client.messages.stream({
|
|
32
38
|
...body,
|
|
@@ -41,41 +47,53 @@ export class ClaudeChatModel extends ChatModel {
|
|
|
41
47
|
return result;
|
|
42
48
|
}
|
|
43
49
|
async extractResultFromClaudeStream(stream) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
const logs = [];
|
|
51
|
+
try {
|
|
52
|
+
let text = "";
|
|
53
|
+
const toolCalls = [];
|
|
54
|
+
for await (const chunk of stream) {
|
|
55
|
+
logs.push(JSON.stringify(chunk));
|
|
56
|
+
// handle streaming text
|
|
57
|
+
if (chunk.type === "content_block_delta" && chunk.delta.type === "text_delta") {
|
|
58
|
+
text += chunk.delta.text;
|
|
59
|
+
}
|
|
60
|
+
if (chunk.type === "content_block_start" && chunk.content_block.type === "tool_use") {
|
|
61
|
+
toolCalls[chunk.index] = {
|
|
62
|
+
type: "function",
|
|
63
|
+
id: chunk.content_block.id,
|
|
64
|
+
function: {
|
|
65
|
+
name: chunk.content_block.name,
|
|
66
|
+
arguments: {},
|
|
67
|
+
},
|
|
68
|
+
args: "",
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
if (chunk.type === "content_block_delta" && chunk.delta.type === "input_json_delta") {
|
|
72
|
+
const call = toolCalls[chunk.index];
|
|
73
|
+
if (!call)
|
|
74
|
+
throw new Error("Tool call not found");
|
|
75
|
+
call.args += chunk.delta.partial_json;
|
|
76
|
+
}
|
|
50
77
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
78
|
+
const result = { text };
|
|
79
|
+
if (toolCalls.length) {
|
|
80
|
+
result.toolCalls = toolCalls
|
|
81
|
+
.map(({ args, ...c }) => ({
|
|
82
|
+
...c,
|
|
55
83
|
function: {
|
|
56
|
-
|
|
57
|
-
|
|
84
|
+
...c.function,
|
|
85
|
+
// NOTE: claude may return a blank string for empty object (the tool's input schema is a empty object)
|
|
86
|
+
arguments: args.trim() ? parseJSON(args) : {},
|
|
58
87
|
},
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
if (chunk.type === "content_block_delta" && chunk.delta.type === "input_json_delta") {
|
|
63
|
-
const call = toolCalls[chunk.index];
|
|
64
|
-
if (!call)
|
|
65
|
-
throw new Error("Tool call not found");
|
|
66
|
-
call.args += chunk.delta.partial_json;
|
|
88
|
+
}))
|
|
89
|
+
.filter(isNonNullable);
|
|
67
90
|
}
|
|
91
|
+
return result;
|
|
68
92
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
.map(({ args, ...c }) => ({
|
|
73
|
-
...c,
|
|
74
|
-
function: { ...c.function, arguments: parseJSON(args) },
|
|
75
|
-
}))
|
|
76
|
-
.filter(isNonNullable);
|
|
93
|
+
catch (error) {
|
|
94
|
+
logger.debug("Failed to process Claude stream", { error, logs });
|
|
95
|
+
throw error;
|
|
77
96
|
}
|
|
78
|
-
return result;
|
|
79
97
|
}
|
|
80
98
|
async requestStructuredOutput(body, responseFormat) {
|
|
81
99
|
if (responseFormat?.type !== "json_schema") {
|
|
@@ -171,19 +189,20 @@ function convertContent(content) {
|
|
|
171
189
|
}
|
|
172
190
|
throw new Error("Invalid chat message content");
|
|
173
191
|
}
|
|
174
|
-
function convertTools({ tools, toolChoice, }) {
|
|
192
|
+
function convertTools({ tools, toolChoice, disableParallelToolUse, }) {
|
|
175
193
|
let choice;
|
|
176
194
|
if (typeof toolChoice === "object" && "type" in toolChoice && toolChoice.type === "function") {
|
|
177
195
|
choice = {
|
|
178
196
|
type: "tool",
|
|
179
197
|
name: toolChoice.function.name,
|
|
198
|
+
disable_parallel_tool_use: disableParallelToolUse,
|
|
180
199
|
};
|
|
181
200
|
}
|
|
182
201
|
else if (toolChoice === "required") {
|
|
183
|
-
choice = { type: "any" };
|
|
202
|
+
choice = { type: "any", disable_parallel_tool_use: disableParallelToolUse };
|
|
184
203
|
}
|
|
185
204
|
else if (toolChoice === "auto") {
|
|
186
|
-
choice = { type: "auto" };
|
|
205
|
+
choice = { type: "auto", disable_parallel_tool_use: disableParallelToolUse };
|
|
187
206
|
}
|
|
188
207
|
else if (toolChoice === "none") {
|
|
189
208
|
choice = { type: "none" };
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { ChatModel, type ChatModelInput, type ChatModelOutput } from "./chat-model.js";
|
|
1
|
+
import { ChatModel, type ChatModelInput, type ChatModelOptions, type ChatModelOutput } from "./chat-model.js";
|
|
2
|
+
export interface OpenAIChatModelOptions {
|
|
3
|
+
apiKey?: string;
|
|
4
|
+
baseURL?: string;
|
|
5
|
+
model?: string;
|
|
6
|
+
modelOptions?: ChatModelOptions;
|
|
7
|
+
}
|
|
2
8
|
export declare class OpenAIChatModel extends ChatModel {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
model?: string;
|
|
6
|
-
} | undefined;
|
|
7
|
-
constructor(config?: {
|
|
8
|
-
apiKey?: string;
|
|
9
|
-
model?: string;
|
|
10
|
-
} | undefined);
|
|
9
|
+
options?: OpenAIChatModelOptions | undefined;
|
|
10
|
+
constructor(options?: OpenAIChatModelOptions | undefined);
|
|
11
11
|
private _client?;
|
|
12
12
|
private get client();
|
|
13
|
+
get modelOptions(): ChatModelOptions | undefined;
|
|
13
14
|
process(input: ChatModelInput): Promise<ChatModelOutput>;
|
|
14
15
|
}
|
|
@@ -5,28 +5,37 @@ import { isNonNullable } from "../utils/type-utils.js";
|
|
|
5
5
|
import { ChatModel, } from "./chat-model.js";
|
|
6
6
|
const CHAT_MODEL_OPENAI_DEFAULT_MODEL = "gpt-4o-mini";
|
|
7
7
|
export class OpenAIChatModel extends ChatModel {
|
|
8
|
-
|
|
9
|
-
constructor(
|
|
8
|
+
options;
|
|
9
|
+
constructor(options) {
|
|
10
10
|
super();
|
|
11
|
-
this.
|
|
11
|
+
this.options = options;
|
|
12
12
|
}
|
|
13
13
|
_client;
|
|
14
14
|
get client() {
|
|
15
|
-
if (!this.
|
|
15
|
+
if (!this.options?.apiKey)
|
|
16
16
|
throw new Error("Api Key is required for OpenAIChatModel");
|
|
17
|
-
this._client ??= new OpenAI({
|
|
17
|
+
this._client ??= new OpenAI({
|
|
18
|
+
baseURL: this.options.baseURL,
|
|
19
|
+
apiKey: this.options.apiKey,
|
|
20
|
+
});
|
|
18
21
|
return this._client;
|
|
19
22
|
}
|
|
23
|
+
get modelOptions() {
|
|
24
|
+
return this.options?.modelOptions;
|
|
25
|
+
}
|
|
20
26
|
async process(input) {
|
|
21
27
|
const res = await this.client.chat.completions.create({
|
|
22
|
-
model: this.
|
|
23
|
-
temperature: input.modelOptions?.temperature,
|
|
24
|
-
top_p: input.modelOptions?.topP,
|
|
25
|
-
frequency_penalty: input.modelOptions?.frequencyPenalty,
|
|
26
|
-
presence_penalty: input.modelOptions?.presencePenalty,
|
|
28
|
+
model: this.options?.model || CHAT_MODEL_OPENAI_DEFAULT_MODEL,
|
|
29
|
+
temperature: input.modelOptions?.temperature ?? this.modelOptions?.temperature,
|
|
30
|
+
top_p: input.modelOptions?.topP ?? this.modelOptions?.topP,
|
|
31
|
+
frequency_penalty: input.modelOptions?.frequencyPenalty ?? this.modelOptions?.frequencyPenalty,
|
|
32
|
+
presence_penalty: input.modelOptions?.presencePenalty ?? this.modelOptions?.presencePenalty,
|
|
27
33
|
messages: await contentsFromInputMessages(input.messages),
|
|
28
34
|
tools: toolsFromInputTools(input.tools),
|
|
29
35
|
tool_choice: input.toolChoice,
|
|
36
|
+
parallel_tool_calls: !input.tools?.length
|
|
37
|
+
? undefined
|
|
38
|
+
: (input.modelOptions?.parallelToolCalls ?? this.modelOptions?.parallelToolCalls),
|
|
30
39
|
response_format: input.responseFormat?.type === "json_schema"
|
|
31
40
|
? {
|
|
32
41
|
type: "json_schema",
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ChatModelOptions } from "./chat-model.js";
|
|
2
|
+
import { OpenAIChatModel } from "./openai-chat-model.js";
|
|
3
|
+
export interface XAIChatModelOptions {
|
|
4
|
+
apiKey?: string;
|
|
5
|
+
model?: string;
|
|
6
|
+
modelOptions?: ChatModelOptions;
|
|
7
|
+
baseURL?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class XAIChatModel extends OpenAIChatModel {
|
|
10
|
+
options?: XAIChatModelOptions | undefined;
|
|
11
|
+
constructor(options?: XAIChatModelOptions | undefined);
|
|
12
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { OpenAIChatModel } from "./openai-chat-model.js";
|
|
2
|
+
const XAI_DEFAULT_CHAT_MODEL = "grok-2-latest";
|
|
3
|
+
const XAI_BASE_URL = "https://api.x.ai/v1";
|
|
4
|
+
export class XAIChatModel extends OpenAIChatModel {
|
|
5
|
+
options;
|
|
6
|
+
constructor(options) {
|
|
7
|
+
super({
|
|
8
|
+
...options,
|
|
9
|
+
model: options?.model || XAI_DEFAULT_CHAT_MODEL,
|
|
10
|
+
baseURL: options?.baseURL || XAI_BASE_URL,
|
|
11
|
+
});
|
|
12
|
+
this.options = options;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type": "module"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { GetPromptResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
-
import { Agent, type
|
|
2
|
+
import { Agent, type Message } from "../agents/agent.js";
|
|
3
3
|
import type { AIAgent } from "../agents/ai-agent.js";
|
|
4
4
|
import type { AgentMemory } from "../agents/memory.js";
|
|
5
5
|
import type { Context } from "../execution-engine/context.js";
|
|
@@ -18,7 +18,7 @@ export interface PromptBuilderBuildOptions {
|
|
|
18
18
|
agent?: AIAgent;
|
|
19
19
|
input?: Message;
|
|
20
20
|
model?: ChatModel;
|
|
21
|
-
outputSchema?:
|
|
21
|
+
outputSchema?: Agent["outputSchema"];
|
|
22
22
|
}
|
|
23
23
|
export declare class PromptBuilder {
|
|
24
24
|
static from(instructions: string): PromptBuilder;
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import type { ZodType } from "zod";
|
|
1
|
+
import type { ZodType, z } from "zod";
|
|
2
2
|
import type { Message } from "../agents/agent.js";
|
|
3
3
|
export declare function outputSchemaToResponseFormatSchema(agentOutput: ZodType<Message>): Record<string, unknown>;
|
|
4
4
|
export declare function parseJSON(json: string): any;
|
|
5
|
+
/**
|
|
6
|
+
* Ensure that the union array has at least 1 item.
|
|
7
|
+
* NOTE: the zod union requires at least 2 items (just type definition, not runtime behavior)
|
|
8
|
+
* so we need to ensure that the union has at least 1 item.
|
|
9
|
+
* @param union - The union array
|
|
10
|
+
* @returns The union array with at least 1 item (but the type is at least 2 items for z.union)
|
|
11
|
+
*/
|
|
12
|
+
export declare function ensureZodUnionArray<T extends z.ZodType>(union: T[]): [T, T, ...T[]];
|
|
@@ -28,3 +28,16 @@ export function parseJSON(json) {
|
|
|
28
28
|
throw new Error(`Failed to parse JSON ${error.message}`);
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Ensure that the union array has at least 1 item.
|
|
33
|
+
* NOTE: the zod union requires at least 2 items (just type definition, not runtime behavior)
|
|
34
|
+
* so we need to ensure that the union has at least 1 item.
|
|
35
|
+
* @param union - The union array
|
|
36
|
+
* @returns The union array with at least 1 item (but the type is at least 2 items for z.union)
|
|
37
|
+
*/
|
|
38
|
+
export function ensureZodUnionArray(union) {
|
|
39
|
+
if (!(union.length >= 1)) {
|
|
40
|
+
throw new Error(`Union must have at least 1 item, but got ${union.length}`);
|
|
41
|
+
}
|
|
42
|
+
return union;
|
|
43
|
+
}
|
|
@@ -51,11 +51,16 @@ export async function runChatLoopInTerminal(userAgent, { log = console.log.bind(
|
|
|
51
51
|
isLoopExited = true;
|
|
52
52
|
}
|
|
53
53
|
async function callAgent(agent, input, options) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
options
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
try {
|
|
55
|
+
const response = await logger.spinner(agent.call(options.inputKey && typeof input === "string" ? { [options.inputKey]: input } : input), "🤖");
|
|
56
|
+
if (options?.onResponse)
|
|
57
|
+
options.onResponse(response);
|
|
58
|
+
else
|
|
59
|
+
options.log(response);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
options.log(`ERROR: ${error.message}`);
|
|
63
|
+
}
|
|
59
64
|
}
|
|
60
65
|
const COMMANDS = {
|
|
61
66
|
"/exit": () => ({ exit: true }),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "AIGNE core library for building AI-powered applications",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
"build": "tsc --build scripts/tsconfig.build.json",
|
|
66
66
|
"clean": "rimraf lib coverage",
|
|
67
67
|
"test": "bun test",
|
|
68
|
-
"test:coverage": "bun test --coverage --coverage-reporter=lcov --coverage-reporter=text"
|
|
68
|
+
"test:coverage": "bun test --coverage --coverage-reporter=lcov --coverage-reporter=text",
|
|
69
|
+
"postbuild": "echo '{\"type\": \"module\"}' > lib/esm/package.json && echo '{\"type\": \"commonjs\"}' > lib/cjs/package.json"
|
|
69
70
|
}
|
|
70
71
|
}
|