@aigne/core 1.10.0 → 1.12.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 +28 -0
- package/LICENSE +93 -0
- package/README.md +90 -0
- package/README.zh.md +90 -0
- package/lib/cjs/agents/agent.d.ts +21 -20
- package/lib/cjs/agents/agent.js +29 -26
- package/lib/cjs/agents/ai-agent.d.ts +9 -8
- package/lib/cjs/agents/ai-agent.js +20 -14
- package/lib/cjs/agents/mcp-agent.d.ts +10 -4
- package/lib/cjs/agents/mcp-agent.js +12 -6
- package/lib/cjs/agents/memory.d.ts +1 -1
- package/lib/cjs/agents/team-agent.d.ts +28 -0
- package/lib/cjs/agents/team-agent.js +93 -0
- package/lib/cjs/agents/user-agent.d.ts +9 -10
- package/lib/cjs/agents/user-agent.js +10 -13
- package/lib/{esm/execution-engine/execution-engine.d.ts → cjs/aigne/aigne.d.ts} +9 -12
- package/lib/cjs/{execution-engine/execution-engine.js → aigne/aigne.js} +19 -19
- package/lib/cjs/{execution-engine → aigne}/context.d.ts +31 -32
- package/lib/cjs/{execution-engine → aigne}/context.js +30 -40
- package/lib/cjs/aigne/index.d.ts +4 -0
- package/lib/cjs/{execution-engine → aigne}/index.js +2 -2
- package/lib/cjs/{execution-engine → aigne}/usage.d.ts +1 -1
- package/lib/cjs/client/client.d.ts +19 -0
- package/lib/cjs/client/client.js +49 -0
- package/lib/cjs/index.d.ts +2 -1
- package/lib/cjs/index.js +2 -1
- package/lib/cjs/loader/agent-js.d.ts +2 -2
- package/lib/cjs/loader/agent-js.js +4 -5
- package/lib/cjs/loader/agent-yaml.d.ts +8 -5
- package/lib/cjs/loader/agent-yaml.js +21 -2
- package/lib/cjs/loader/index.d.ts +5 -5
- package/lib/cjs/loader/index.js +8 -19
- package/lib/cjs/models/chat-model.d.ts +1 -1
- package/lib/cjs/models/claude-chat-model.d.ts +3 -1
- package/lib/cjs/models/claude-chat-model.js +75 -60
- package/lib/cjs/models/openai-chat-model.d.ts +3 -3
- package/lib/cjs/models/openai-chat-model.js +1 -3
- package/lib/cjs/prompt/prompt-builder.d.ts +1 -1
- package/lib/cjs/prompt/prompt-builder.js +3 -3
- package/lib/cjs/server/error.d.ts +4 -0
- package/lib/cjs/server/error.js +11 -0
- package/lib/cjs/server/server.d.ts +54 -0
- package/lib/cjs/server/server.js +130 -0
- package/lib/cjs/utils/camelize.d.ts +13 -0
- package/lib/cjs/utils/camelize.js +16 -0
- package/lib/cjs/utils/event-stream.d.ts +11 -0
- package/lib/cjs/utils/event-stream.js +91 -0
- package/lib/cjs/utils/mcp-utils.js +4 -1
- package/lib/cjs/utils/stream-utils.d.ts +10 -3
- package/lib/cjs/utils/stream-utils.js +51 -36
- package/lib/cjs/utils/type-utils.d.ts +4 -2
- package/lib/cjs/utils/type-utils.js +10 -2
- package/lib/dts/agents/agent.d.ts +21 -20
- package/lib/dts/agents/ai-agent.d.ts +9 -8
- package/lib/dts/agents/mcp-agent.d.ts +10 -4
- package/lib/dts/agents/memory.d.ts +1 -1
- package/lib/dts/agents/team-agent.d.ts +28 -0
- package/lib/dts/agents/user-agent.d.ts +9 -10
- package/lib/dts/{execution-engine/execution-engine.d.ts → aigne/aigne.d.ts} +9 -12
- package/lib/dts/{execution-engine → aigne}/context.d.ts +31 -32
- package/lib/dts/aigne/index.d.ts +4 -0
- package/lib/dts/{execution-engine → aigne}/usage.d.ts +1 -1
- package/lib/dts/client/client.d.ts +19 -0
- package/lib/dts/index.d.ts +2 -1
- package/lib/dts/loader/agent-js.d.ts +2 -2
- package/lib/dts/loader/agent-yaml.d.ts +8 -5
- package/lib/dts/loader/index.d.ts +5 -5
- package/lib/dts/models/chat-model.d.ts +1 -1
- package/lib/dts/models/claude-chat-model.d.ts +3 -1
- package/lib/dts/models/openai-chat-model.d.ts +3 -3
- package/lib/dts/prompt/prompt-builder.d.ts +1 -1
- package/lib/dts/server/error.d.ts +4 -0
- package/lib/dts/server/server.d.ts +54 -0
- package/lib/dts/utils/camelize.d.ts +13 -0
- package/lib/dts/utils/event-stream.d.ts +11 -0
- package/lib/dts/utils/stream-utils.d.ts +10 -3
- package/lib/dts/utils/type-utils.d.ts +4 -2
- package/lib/esm/agents/agent.d.ts +21 -20
- package/lib/esm/agents/agent.js +29 -27
- package/lib/esm/agents/ai-agent.d.ts +9 -8
- package/lib/esm/agents/ai-agent.js +20 -14
- package/lib/esm/agents/mcp-agent.d.ts +10 -4
- package/lib/esm/agents/mcp-agent.js +12 -6
- package/lib/esm/agents/memory.d.ts +1 -1
- package/lib/esm/agents/team-agent.d.ts +28 -0
- package/lib/esm/agents/team-agent.js +89 -0
- package/lib/esm/agents/user-agent.d.ts +9 -10
- package/lib/esm/agents/user-agent.js +11 -14
- package/lib/{cjs/execution-engine/execution-engine.d.ts → esm/aigne/aigne.d.ts} +9 -12
- package/lib/esm/{execution-engine/execution-engine.js → aigne/aigne.js} +18 -18
- package/lib/esm/{execution-engine → aigne}/context.d.ts +31 -32
- package/lib/esm/{execution-engine → aigne}/context.js +28 -38
- package/lib/esm/aigne/index.d.ts +4 -0
- package/lib/esm/aigne/index.js +4 -0
- package/lib/esm/{execution-engine → aigne}/usage.d.ts +1 -1
- package/lib/esm/client/client.d.ts +19 -0
- package/lib/esm/client/client.js +45 -0
- package/lib/esm/index.d.ts +2 -1
- package/lib/esm/index.js +2 -1
- package/lib/esm/loader/agent-js.d.ts +2 -2
- package/lib/esm/loader/agent-js.js +4 -5
- package/lib/esm/loader/agent-yaml.d.ts +8 -5
- package/lib/esm/loader/agent-yaml.js +21 -2
- package/lib/esm/loader/index.d.ts +5 -5
- package/lib/esm/loader/index.js +8 -19
- package/lib/esm/models/chat-model.d.ts +1 -1
- package/lib/esm/models/claude-chat-model.d.ts +3 -1
- package/lib/esm/models/claude-chat-model.js +75 -60
- package/lib/esm/models/openai-chat-model.d.ts +3 -3
- package/lib/esm/models/openai-chat-model.js +1 -3
- package/lib/esm/prompt/prompt-builder.d.ts +1 -1
- package/lib/esm/prompt/prompt-builder.js +3 -3
- package/lib/esm/server/error.d.ts +4 -0
- package/lib/esm/server/error.js +7 -0
- package/lib/esm/server/server.d.ts +54 -0
- package/lib/esm/server/server.js +123 -0
- package/lib/esm/utils/camelize.d.ts +13 -0
- package/lib/esm/utils/camelize.js +10 -0
- package/lib/esm/utils/event-stream.d.ts +11 -0
- package/lib/esm/utils/event-stream.js +85 -0
- package/lib/esm/utils/mcp-utils.js +4 -1
- package/lib/esm/utils/stream-utils.d.ts +10 -3
- package/lib/esm/utils/stream-utils.js +49 -35
- package/lib/esm/utils/type-utils.d.ts +4 -2
- package/lib/esm/utils/type-utils.js +9 -2
- package/package.json +15 -5
- package/lib/cjs/execution-engine/index.d.ts +0 -4
- package/lib/cjs/execution-engine/utils.d.ts +0 -4
- package/lib/cjs/execution-engine/utils.js +0 -34
- package/lib/dts/execution-engine/index.d.ts +0 -4
- package/lib/dts/execution-engine/utils.d.ts +0 -4
- package/lib/esm/execution-engine/index.d.ts +0 -4
- package/lib/esm/execution-engine/index.js +0 -4
- package/lib/esm/execution-engine/utils.d.ts +0 -4
- package/lib/esm/execution-engine/utils.js +0 -30
- /package/lib/cjs/{execution-engine → aigne}/message-queue.d.ts +0 -0
- /package/lib/cjs/{execution-engine → aigne}/message-queue.js +0 -0
- /package/lib/cjs/{execution-engine → aigne}/usage.js +0 -0
- /package/lib/dts/{execution-engine → aigne}/message-queue.d.ts +0 -0
- /package/lib/esm/{execution-engine → aigne}/message-queue.d.ts +0 -0
- /package/lib/esm/{execution-engine → aigne}/message-queue.js +0 -0
- /package/lib/esm/{execution-engine → aigne}/usage.js +0 -0
|
@@ -7,7 +7,7 @@ export interface LoadOptions {
|
|
|
7
7
|
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
|
+
skills: Agent<import("../agents/agent.js").Message, import("../agents/agent.js").Message>[];
|
|
11
11
|
description?: string | null | undefined;
|
|
12
12
|
name?: string | null | undefined;
|
|
13
13
|
chat_model?: {
|
|
@@ -61,11 +61,11 @@ declare const aigneFileSchema: z.ZodObject<{
|
|
|
61
61
|
presence_penalty?: number | null | undefined;
|
|
62
62
|
} | null | undefined>;
|
|
63
63
|
agents: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
|
|
64
|
-
|
|
64
|
+
skills: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
|
|
65
65
|
}, "strip", z.ZodTypeAny, {
|
|
66
66
|
description?: string | null | undefined;
|
|
67
|
-
tools?: string[] | null | undefined;
|
|
68
67
|
name?: string | null | undefined;
|
|
68
|
+
skills?: string[] | null | undefined;
|
|
69
69
|
chat_model?: {
|
|
70
70
|
name?: string | null | undefined;
|
|
71
71
|
temperature?: number | null | undefined;
|
|
@@ -77,8 +77,8 @@ declare const aigneFileSchema: z.ZodObject<{
|
|
|
77
77
|
agents?: string[] | null | undefined;
|
|
78
78
|
}, {
|
|
79
79
|
description?: string | null | undefined;
|
|
80
|
-
tools?: string[] | null | undefined;
|
|
81
80
|
name?: string | null | undefined;
|
|
81
|
+
skills?: string[] | null | undefined;
|
|
82
82
|
chat_model?: string | {
|
|
83
83
|
name?: string | null | undefined;
|
|
84
84
|
temperature?: number | null | undefined;
|
|
@@ -91,8 +91,8 @@ declare const aigneFileSchema: z.ZodObject<{
|
|
|
91
91
|
}>;
|
|
92
92
|
export declare function loadAIGNEFile(path: string): Promise<{
|
|
93
93
|
description?: string | null | undefined;
|
|
94
|
-
tools?: string[] | null | undefined;
|
|
95
94
|
name?: string | null | undefined;
|
|
95
|
+
skills?: string[] | null | undefined;
|
|
96
96
|
chat_model?: {
|
|
97
97
|
name?: string | null | undefined;
|
|
98
98
|
temperature?: number | null | undefined;
|
package/lib/esm/loader/index.js
CHANGED
|
@@ -22,37 +22,26 @@ export async function load(options) {
|
|
|
22
22
|
const rootDir = dirname(aigneFilePath);
|
|
23
23
|
const aigne = await loadAIGNEFile(aigneFilePath);
|
|
24
24
|
const agents = await Promise.all((aigne.agents ?? []).map((filename) => loadAgent(join(rootDir, filename))));
|
|
25
|
-
const
|
|
25
|
+
const skills = await Promise.all((aigne.skills ?? []).map((filename) => loadAgent(join(rootDir, filename))));
|
|
26
26
|
return {
|
|
27
27
|
...aigne,
|
|
28
28
|
model: await loadModel(aigne.chat_model),
|
|
29
29
|
agents,
|
|
30
|
-
|
|
30
|
+
skills,
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
export async function loadAgent(path) {
|
|
34
34
|
if (extname(path) === ".js") {
|
|
35
35
|
const agent = await loadAgentFromJsFile(path);
|
|
36
|
-
return FunctionAgent.from(
|
|
37
|
-
name: agent.name,
|
|
38
|
-
description: agent.description,
|
|
39
|
-
inputSchema: agent.input_schema,
|
|
40
|
-
outputSchema: agent.output_schema,
|
|
41
|
-
fn: agent.fn,
|
|
42
|
-
});
|
|
36
|
+
return FunctionAgent.from(agent);
|
|
43
37
|
}
|
|
44
38
|
if (extname(path) === ".yaml" || extname(path) === ".yml") {
|
|
45
39
|
const agent = await loadAgentFromYamlFile(path);
|
|
46
40
|
if (agent.type === "ai") {
|
|
47
41
|
return AIAgent.from({
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
inputSchema: agent.input_schema,
|
|
52
|
-
outputSchema: agent.output_schema,
|
|
53
|
-
outputKey: agent.output_key,
|
|
54
|
-
tools: await Promise.all((agent.tools ?? []).map((filename) => loadAgent(join(dirname(path), filename)))),
|
|
55
|
-
toolChoice: agent.tool_choice,
|
|
42
|
+
...agent,
|
|
43
|
+
skills: agent.skills &&
|
|
44
|
+
(await Promise.all(agent.skills.map((filename) => loadAgent(join(dirname(path), filename))))),
|
|
56
45
|
});
|
|
57
46
|
}
|
|
58
47
|
if (agent.type === "mcp") {
|
|
@@ -117,12 +106,12 @@ const aigneFileSchema = z.object({
|
|
|
117
106
|
.nullish()
|
|
118
107
|
.transform((v) => (typeof v === "string" ? { name: v } : v)),
|
|
119
108
|
agents: z.array(z.string()).nullish(),
|
|
120
|
-
|
|
109
|
+
skills: z.array(z.string()).nullish(),
|
|
121
110
|
});
|
|
122
111
|
export async function loadAIGNEFile(path) {
|
|
123
112
|
const raw = await tryOrThrow(() => readFile(path, "utf8"), (error) => new Error(`Failed to load aigne.yaml from ${path}: ${error.message}`));
|
|
124
113
|
const json = await tryOrThrow(() => parse(raw), (error) => new Error(`Failed to parse aigne.yaml from ${path}: ${error.message}`));
|
|
125
|
-
const agent = tryOrThrow(() => aigneFileSchema.parse(json), (error) => new Error(`Failed to validate aigne.yaml from ${path}: ${error.message}`));
|
|
114
|
+
const agent = tryOrThrow(() => aigneFileSchema.parse({ ...json, skills: json.skills ?? json.tools }), (error) => new Error(`Failed to validate aigne.yaml from ${path}: ${error.message}`));
|
|
126
115
|
return agent;
|
|
127
116
|
}
|
|
128
117
|
async function getAIGNEFilePath(path) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Agent, type Message } from "../agents/agent.js";
|
|
2
|
-
import type { Context } from "../
|
|
2
|
+
import type { Context } from "../aigne/context.js";
|
|
3
3
|
export declare abstract class ChatModel extends Agent<ChatModelInput, ChatModelOutput> {
|
|
4
4
|
constructor();
|
|
5
5
|
protected supportsParallelToolCalls: boolean;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import Anthropic from "@anthropic-ai/sdk";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
import type { AgentInvokeOptions, AgentResponse } from "../agents/agent.js";
|
|
4
|
+
import type { Context } from "../aigne/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?: AgentInvokeOptions): Promise<AgentResponse<ChatModelOutput>>;
|
|
64
66
|
private extractResultFromClaudeStream;
|
|
65
67
|
private requestStructuredOutput;
|
|
66
68
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import Anthropic from "@anthropic-ai/sdk";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { parseJSON } from "../utils/json-schema.js";
|
|
4
|
-
import { logger } from "../utils/logger.js";
|
|
5
4
|
import { mergeUsage } from "../utils/model-utils.js";
|
|
5
|
+
import { agentResponseStreamToObject } from "../utils/stream-utils.js";
|
|
6
6
|
import { checkArguments, isEmpty, isNonNullable } from "../utils/type-utils.js";
|
|
7
7
|
import { ChatModel, } from "./chat-model.js";
|
|
8
8
|
const CHAT_MODEL_CLAUDE_DEFAULT_MODEL = "claude-3-7-sonnet-latest";
|
|
@@ -39,7 +39,7 @@ export class ClaudeChatModel extends ChatModel {
|
|
|
39
39
|
get modelOptions() {
|
|
40
40
|
return this.options?.modelOptions;
|
|
41
41
|
}
|
|
42
|
-
async process(input) {
|
|
42
|
+
async process(input, _context, options) {
|
|
43
43
|
const model = this.options?.model || CHAT_MODEL_CLAUDE_DEFAULT_MODEL;
|
|
44
44
|
const disableParallelToolUse = input.modelOptions?.parallelToolCalls === false ||
|
|
45
45
|
this.modelOptions?.parallelToolCalls === false;
|
|
@@ -56,6 +56,9 @@ export class ClaudeChatModel extends ChatModel {
|
|
|
56
56
|
...body,
|
|
57
57
|
stream: true,
|
|
58
58
|
});
|
|
59
|
+
if (options?.streaming && input.responseFormat?.type !== "json_schema") {
|
|
60
|
+
return this.extractResultFromClaudeStream(stream, true);
|
|
61
|
+
}
|
|
59
62
|
const result = await this.extractResultFromClaudeStream(stream);
|
|
60
63
|
// Claude doesn't support json_schema response and tool calls in the same request,
|
|
61
64
|
// so we need to make a separate request for json_schema response when the tool calls is empty
|
|
@@ -69,67 +72,79 @@ export class ClaudeChatModel extends ChatModel {
|
|
|
69
72
|
}
|
|
70
73
|
return result;
|
|
71
74
|
}
|
|
72
|
-
async extractResultFromClaudeStream(stream) {
|
|
75
|
+
async extractResultFromClaudeStream(stream, streaming) {
|
|
73
76
|
const logs = [];
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
77
|
+
const result = new ReadableStream({
|
|
78
|
+
async start(controller) {
|
|
79
|
+
try {
|
|
80
|
+
const toolCalls = [];
|
|
81
|
+
let usage;
|
|
82
|
+
let model;
|
|
83
|
+
for await (const chunk of stream) {
|
|
84
|
+
if (chunk.type === "message_start") {
|
|
85
|
+
if (!model) {
|
|
86
|
+
model = chunk.message.model;
|
|
87
|
+
controller.enqueue({ delta: { json: { model } } });
|
|
88
|
+
}
|
|
89
|
+
const { input_tokens, output_tokens } = chunk.message.usage;
|
|
90
|
+
usage = {
|
|
91
|
+
inputTokens: input_tokens,
|
|
92
|
+
outputTokens: output_tokens,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
if (chunk.type === "message_delta" && usage) {
|
|
96
|
+
usage.outputTokens = chunk.usage.output_tokens;
|
|
97
|
+
}
|
|
98
|
+
logs.push(JSON.stringify(chunk));
|
|
99
|
+
// handle streaming text
|
|
100
|
+
if (chunk.type === "content_block_delta" && chunk.delta.type === "text_delta") {
|
|
101
|
+
controller.enqueue({ delta: { text: { text: chunk.delta.text } } });
|
|
102
|
+
}
|
|
103
|
+
if (chunk.type === "content_block_start" && chunk.content_block.type === "tool_use") {
|
|
104
|
+
toolCalls[chunk.index] = {
|
|
105
|
+
type: "function",
|
|
106
|
+
id: chunk.content_block.id,
|
|
107
|
+
function: {
|
|
108
|
+
name: chunk.content_block.name,
|
|
109
|
+
arguments: {},
|
|
110
|
+
},
|
|
111
|
+
args: "",
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
if (chunk.type === "content_block_delta" && chunk.delta.type === "input_json_delta") {
|
|
115
|
+
const call = toolCalls[chunk.index];
|
|
116
|
+
if (!call)
|
|
117
|
+
throw new Error("Tool call not found");
|
|
118
|
+
call.args += chunk.delta.partial_json;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
controller.enqueue({ delta: { json: { usage } } });
|
|
122
|
+
if (toolCalls.length) {
|
|
123
|
+
controller.enqueue({
|
|
124
|
+
delta: {
|
|
125
|
+
json: {
|
|
126
|
+
toolCalls: toolCalls
|
|
127
|
+
.map(({ args, ...c }) => ({
|
|
128
|
+
...c,
|
|
129
|
+
function: {
|
|
130
|
+
...c.function,
|
|
131
|
+
// NOTE: claude may return a blank string for empty object (the tool's input schema is a empty object)
|
|
132
|
+
arguments: args.trim() ? parseJSON(args) : {},
|
|
133
|
+
},
|
|
134
|
+
}))
|
|
135
|
+
.filter(isNonNullable),
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
controller.close();
|
|
95
141
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
type: "function",
|
|
99
|
-
id: chunk.content_block.id,
|
|
100
|
-
function: {
|
|
101
|
-
name: chunk.content_block.name,
|
|
102
|
-
arguments: {},
|
|
103
|
-
},
|
|
104
|
-
args: "",
|
|
105
|
-
};
|
|
142
|
+
catch (error) {
|
|
143
|
+
controller.error(error);
|
|
106
144
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
throw new Error("Tool call not found");
|
|
111
|
-
call.args += chunk.delta.partial_json;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
const result = { usage, model, text };
|
|
115
|
-
if (toolCalls.length) {
|
|
116
|
-
result.toolCalls = toolCalls
|
|
117
|
-
.map(({ args, ...c }) => ({
|
|
118
|
-
...c,
|
|
119
|
-
function: {
|
|
120
|
-
...c.function,
|
|
121
|
-
// NOTE: claude may return a blank string for empty object (the tool's input schema is a empty object)
|
|
122
|
-
arguments: args.trim() ? parseJSON(args) : {},
|
|
123
|
-
},
|
|
124
|
-
}))
|
|
125
|
-
.filter(isNonNullable);
|
|
126
|
-
}
|
|
127
|
-
return result;
|
|
128
|
-
}
|
|
129
|
-
catch (error) {
|
|
130
|
-
logger.core("Failed to process Claude stream", { error, logs });
|
|
131
|
-
throw error;
|
|
132
|
-
}
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
return streaming ? result : await agentResponseStreamToObject(result);
|
|
133
148
|
}
|
|
134
149
|
async requestStructuredOutput(body, responseFormat) {
|
|
135
150
|
if (responseFormat?.type !== "json_schema") {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import OpenAI from "openai";
|
|
2
2
|
import type { ChatCompletionMessageParam, ChatCompletionTool } from "openai/resources";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
-
import type {
|
|
5
|
-
import type { Context } from "../
|
|
4
|
+
import type { AgentInvokeOptions, AgentResponse } from "../agents/agent.js";
|
|
5
|
+
import type { Context } from "../aigne/context.js";
|
|
6
6
|
import { ChatModel, type ChatModelInput, type ChatModelInputMessage, type ChatModelInputTool, type ChatModelOptions, type ChatModelOutput, type Role } from "./chat-model.js";
|
|
7
7
|
export interface OpenAIChatModelCapabilities {
|
|
8
8
|
supportsNativeStructuredOutputs: boolean;
|
|
@@ -83,7 +83,7 @@ export declare class OpenAIChatModel extends ChatModel {
|
|
|
83
83
|
protected supportsTemperature: boolean;
|
|
84
84
|
get client(): OpenAI;
|
|
85
85
|
get modelOptions(): ChatModelOptions | undefined;
|
|
86
|
-
process(input: ChatModelInput, _context: Context, options?:
|
|
86
|
+
process(input: ChatModelInput, _context: Context, options?: AgentInvokeOptions): Promise<AgentResponse<ChatModelOutput>>;
|
|
87
87
|
private getParallelToolCalls;
|
|
88
88
|
private getRunMessages;
|
|
89
89
|
private getRunResponseFormat;
|
|
@@ -323,13 +323,11 @@ async function extractResultFromStream(stream, jsonMode, streaming) {
|
|
|
323
323
|
},
|
|
324
324
|
});
|
|
325
325
|
}
|
|
326
|
+
controller.close();
|
|
326
327
|
}
|
|
327
328
|
catch (error) {
|
|
328
329
|
controller.error(error);
|
|
329
330
|
}
|
|
330
|
-
finally {
|
|
331
|
-
controller.close();
|
|
332
|
-
}
|
|
333
331
|
},
|
|
334
332
|
});
|
|
335
333
|
return streaming ? result : await agentResponseStreamToObject(result);
|
|
@@ -2,7 +2,7 @@ import type { GetPromptResult } from "@modelcontextprotocol/sdk/types.js";
|
|
|
2
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
|
-
import type { Context } from "../
|
|
5
|
+
import type { Context } from "../aigne/context.js";
|
|
6
6
|
import type { ChatModel, ChatModelInput } from "../models/chat-model.js";
|
|
7
7
|
import { ChatMessagesTemplate } from "./template.js";
|
|
8
8
|
export declare const MESSAGE_KEY = "$message";
|
|
@@ -112,10 +112,10 @@ export class PromptBuilder {
|
|
|
112
112
|
: undefined;
|
|
113
113
|
}
|
|
114
114
|
buildTools(options) {
|
|
115
|
-
const toolAgents = (options.context?.
|
|
116
|
-
.concat(options.agent?.
|
|
115
|
+
const toolAgents = (options.context?.skills ?? [])
|
|
116
|
+
.concat(options.agent?.skills ?? [])
|
|
117
117
|
// TODO: support nested tools?
|
|
118
|
-
.flatMap((i) => (i.
|
|
118
|
+
.flatMap((i) => (i.isInvokable ? i.skills.concat(i) : i.skills));
|
|
119
119
|
const tools = toolAgents.map((i) => ({
|
|
120
120
|
type: "function",
|
|
121
121
|
function: {
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import type { AIGNE } from "../aigne/aigne.js";
|
|
4
|
+
export declare const invokePayloadSchema: z.ZodObject<{
|
|
5
|
+
agent: z.ZodString;
|
|
6
|
+
input: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
7
|
+
options: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
8
|
+
streaming: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
|
|
9
|
+
}, "strip", z.ZodTypeAny, {
|
|
10
|
+
streaming?: boolean | null | undefined;
|
|
11
|
+
}, {
|
|
12
|
+
streaming?: boolean | null | undefined;
|
|
13
|
+
}>>>;
|
|
14
|
+
}, "strip", z.ZodTypeAny, {
|
|
15
|
+
agent: string;
|
|
16
|
+
input: Record<string, unknown>;
|
|
17
|
+
options?: {
|
|
18
|
+
streaming?: boolean | null | undefined;
|
|
19
|
+
} | null | undefined;
|
|
20
|
+
}, {
|
|
21
|
+
agent: string;
|
|
22
|
+
input: Record<string, unknown>;
|
|
23
|
+
options?: {
|
|
24
|
+
streaming?: boolean | null | undefined;
|
|
25
|
+
} | null | undefined;
|
|
26
|
+
}>;
|
|
27
|
+
export interface AIGNEServerOptions {
|
|
28
|
+
/**
|
|
29
|
+
* Maximum body size for the request.
|
|
30
|
+
* Only used when the request is a Node.js IncomingMessage and no `body` property is present.
|
|
31
|
+
* @default "4mb"
|
|
32
|
+
*/
|
|
33
|
+
maximumBodySize?: string;
|
|
34
|
+
}
|
|
35
|
+
export declare class AIGNEServer {
|
|
36
|
+
engine: AIGNE;
|
|
37
|
+
options?: AIGNEServerOptions | undefined;
|
|
38
|
+
constructor(engine: AIGNE, options?: AIGNEServerOptions | undefined);
|
|
39
|
+
/**
|
|
40
|
+
* Invoke the agent with the given input.
|
|
41
|
+
* @param request - The request object, which can be a parsed JSON object, a Fetch API Request object, or a Node.js IncomingMessage object.
|
|
42
|
+
* @returns The web standard response, you can return it directly in supported frameworks like hono.
|
|
43
|
+
*/
|
|
44
|
+
invoke(request: Record<string, unknown> | Request | IncomingMessage): Promise<Response>;
|
|
45
|
+
/**
|
|
46
|
+
* Invoke the agent with the given input, and write the SSE response to the Node.js ServerResponse.
|
|
47
|
+
* @param request - The request object, which can be a parsed JSON object, a Fetch API Request object, or a Node.js IncomingMessage object.
|
|
48
|
+
* @param response - The Node.js ServerResponse object to write the SSE response to.
|
|
49
|
+
*/
|
|
50
|
+
invoke(request: Record<string, unknown> | Request | IncomingMessage, response: ServerResponse): Promise<void>;
|
|
51
|
+
_invoke(request: Record<string, unknown> | Request | IncomingMessage): Promise<Response>;
|
|
52
|
+
_prepareInput(request: Record<string, unknown> | Request | IncomingMessage): Promise<Record<string, unknown>>;
|
|
53
|
+
_writeResponse(response: Response, res: ServerResponse): Promise<void>;
|
|
54
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
+
import contentType from "content-type";
|
|
3
|
+
import getRawBody from "raw-body";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { AgentResponseStreamSSE } from "../utils/event-stream.js";
|
|
6
|
+
import { readableStreamToAsyncIterator } from "../utils/stream-utils.js";
|
|
7
|
+
import { checkArguments, isRecord, tryOrThrow } from "../utils/type-utils.js";
|
|
8
|
+
import { ServerError } from "./error.js";
|
|
9
|
+
const DEFAULT_MAXIMUM_BODY_SIZE = "4mb";
|
|
10
|
+
export const invokePayloadSchema = z.object({
|
|
11
|
+
agent: z.string(),
|
|
12
|
+
input: z.record(z.string(), z.unknown()),
|
|
13
|
+
options: z
|
|
14
|
+
.object({
|
|
15
|
+
streaming: z.boolean().nullish(),
|
|
16
|
+
})
|
|
17
|
+
.nullish(),
|
|
18
|
+
});
|
|
19
|
+
export class AIGNEServer {
|
|
20
|
+
engine;
|
|
21
|
+
options;
|
|
22
|
+
constructor(engine, options) {
|
|
23
|
+
this.engine = engine;
|
|
24
|
+
this.options = options;
|
|
25
|
+
}
|
|
26
|
+
async invoke(request, response) {
|
|
27
|
+
const result = await this._invoke(request);
|
|
28
|
+
if (response instanceof ServerResponse) {
|
|
29
|
+
await this._writeResponse(result, response);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
async _invoke(request) {
|
|
35
|
+
const { engine } = this;
|
|
36
|
+
try {
|
|
37
|
+
const payload = await this._prepareInput(request);
|
|
38
|
+
const { agent: agentName, input, options, } = tryOrThrow(() => checkArguments(`Invoke agent ${payload.agent}`, invokePayloadSchema, payload), (error) => new ServerError(400, error.message));
|
|
39
|
+
const agent = engine.agents[agentName];
|
|
40
|
+
if (!agent)
|
|
41
|
+
throw new ServerError(404, `Agent ${agentName} not found`);
|
|
42
|
+
if (!options?.streaming) {
|
|
43
|
+
const result = await engine.invoke(agent, input);
|
|
44
|
+
return new Response(JSON.stringify(result), {
|
|
45
|
+
headers: { "Content-Type": "application/json" },
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
const stream = await engine.invoke(agent, input, { streaming: true });
|
|
49
|
+
return new Response(new AgentResponseStreamSSE(stream), {
|
|
50
|
+
headers: {
|
|
51
|
+
"Content-Type": "text/event-stream",
|
|
52
|
+
"Cache-Control": "no-cache",
|
|
53
|
+
"X-Accel-Buffering": "no",
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
return new Response(JSON.stringify({ error: { message: error.message } }), {
|
|
59
|
+
status: error instanceof ServerError ? error.status : 500,
|
|
60
|
+
headers: { "Content-Type": "application/json" },
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async _prepareInput(request) {
|
|
65
|
+
const contentTypeError = new ServerError(415, "Unsupported Media Type: Content-Type must be application/json");
|
|
66
|
+
if (request instanceof IncomingMessage) {
|
|
67
|
+
// Support for express with json() middleware
|
|
68
|
+
if ("body" in request && typeof request.body === "object") {
|
|
69
|
+
if (!isRecord(request.body))
|
|
70
|
+
throw contentTypeError;
|
|
71
|
+
return request.body;
|
|
72
|
+
}
|
|
73
|
+
// Support vanilla nodejs http server
|
|
74
|
+
const maximumBodySize = this.options?.maximumBodySize || DEFAULT_MAXIMUM_BODY_SIZE;
|
|
75
|
+
const ct = request.headers["content-type"];
|
|
76
|
+
if (!ct || !ct.includes("application/json"))
|
|
77
|
+
throw contentTypeError;
|
|
78
|
+
const parsedCt = contentType.parse(ct);
|
|
79
|
+
const raw = await getRawBody(request, {
|
|
80
|
+
limit: maximumBodySize,
|
|
81
|
+
encoding: parsedCt.parameters.charset ?? "utf-8",
|
|
82
|
+
});
|
|
83
|
+
return tryOrThrow(() => JSON.parse(raw.toString()), (error) => new ServerError(400, `Parse request body to json error: ${error.message}`));
|
|
84
|
+
}
|
|
85
|
+
if (request instanceof Request) {
|
|
86
|
+
if (!request.headers.get("content-type")?.includes("application/json")) {
|
|
87
|
+
throw contentTypeError;
|
|
88
|
+
}
|
|
89
|
+
return await request.json();
|
|
90
|
+
}
|
|
91
|
+
if (!isRecord(request))
|
|
92
|
+
throw contentTypeError;
|
|
93
|
+
return request;
|
|
94
|
+
}
|
|
95
|
+
async _writeResponse(response, res) {
|
|
96
|
+
try {
|
|
97
|
+
res.writeHead(response.status, response.headers.toJSON());
|
|
98
|
+
res.flushHeaders();
|
|
99
|
+
if (!response.body)
|
|
100
|
+
throw new Error("Response body is empty");
|
|
101
|
+
for await (const chunk of readableStreamToAsyncIterator(response.body)) {
|
|
102
|
+
res.write(chunk);
|
|
103
|
+
// Support for express with compression middleware
|
|
104
|
+
if ("flush" in res && typeof res.flush === "function") {
|
|
105
|
+
res.flush();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
if (!res.headersSent) {
|
|
111
|
+
res.writeHead(error instanceof ServerError ? error.status : 500, {
|
|
112
|
+
"Content-Type": "application/json",
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
if (res.writable) {
|
|
116
|
+
res.write(JSON.stringify({ error: { message: error.message } }));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
res.end();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -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,10 @@
|
|
|
1
|
+
import camelize from "camelize-ts";
|
|
2
|
+
export function customCamelize(obj, { shallowKeys = [] } = {}) {
|
|
3
|
+
const shallow = Object.fromEntries(shallowKeys?.filter((key) => key in obj).map((key) => [key, obj[key]]) ?? []);
|
|
4
|
+
const deep = Object.fromEntries(Object.entries(obj).filter(([key]) => !shallowKeys?.includes(key)));
|
|
5
|
+
return {
|
|
6
|
+
...camelize(shallow, true),
|
|
7
|
+
...camelize(deep),
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
const _unique = Symbol();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AgentResponseChunk, AgentResponseStream, Message } from "../agents/agent.js";
|
|
2
|
+
export declare class EventStreamParser<T> extends TransformStream<string, T | Error> {
|
|
3
|
+
constructor();
|
|
4
|
+
}
|
|
5
|
+
export declare class AgentResponseStreamParser<O extends Message> extends TransformStream<AgentResponseChunk<O> | Error, AgentResponseChunk<O>> {
|
|
6
|
+
private json;
|
|
7
|
+
constructor();
|
|
8
|
+
}
|
|
9
|
+
export declare class AgentResponseStreamSSE<O extends Message> extends ReadableStream<string> {
|
|
10
|
+
constructor(stream: AgentResponseStream<O>);
|
|
11
|
+
}
|