@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.
- package/CHANGELOG.md +13 -0
- package/LICENSE +93 -0
- package/README.md +89 -0
- package/README.zh.md +89 -0
- package/lib/cjs/agents/agent.d.ts +1 -0
- package/lib/cjs/agents/agent.js +4 -0
- package/lib/cjs/agents/ai-agent.d.ts +11 -9
- package/lib/cjs/agents/ai-agent.js +17 -11
- 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 +13 -1
- package/lib/cjs/loader/index.d.ts +4 -4
- package/lib/cjs/loader/index.js +4 -15
- 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.js +1 -3
- package/lib/cjs/utils/camelize.d.ts +13 -0
- package/lib/cjs/utils/camelize.js +16 -0
- package/lib/cjs/utils/stream-utils.d.ts +3 -1
- package/lib/cjs/utils/stream-utils.js +10 -4
- package/lib/dts/agents/agent.d.ts +1 -0
- package/lib/dts/agents/ai-agent.d.ts +11 -9
- 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 +4 -4
- package/lib/dts/models/claude-chat-model.d.ts +3 -1
- package/lib/dts/utils/camelize.d.ts +13 -0
- package/lib/dts/utils/stream-utils.d.ts +3 -1
- package/lib/esm/agents/agent.d.ts +1 -0
- package/lib/esm/agents/agent.js +4 -1
- package/lib/esm/agents/ai-agent.d.ts +11 -9
- package/lib/esm/agents/ai-agent.js +17 -11
- 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 +13 -1
- package/lib/esm/loader/index.d.ts +4 -4
- package/lib/esm/loader/index.js +4 -15
- 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.js +1 -3
- package/lib/esm/utils/camelize.d.ts +13 -0
- package/lib/esm/utils/camelize.js +10 -0
- package/lib/esm/utils/stream-utils.d.ts +3 -1
- package/lib/esm/utils/stream-utils.js +9 -4
- package/package.json +3 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsonSchemaToZod } from "@aigne/json-schema-to-zod";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
import { customCamelize } from "../utils/camelize.js";
|
|
3
4
|
import { tryOrThrow } from "../utils/type-utils.js";
|
|
4
5
|
import { inputOutputSchema } from "./schema.js";
|
|
5
6
|
const agentJsFileSchema = z.object({
|
|
@@ -21,11 +22,9 @@ export async function loadAgentFromJsFile(path) {
|
|
|
21
22
|
if (typeof agent !== "function") {
|
|
22
23
|
throw new Error(`Agent file ${path} must export a default function, but got ${typeof agent}`);
|
|
23
24
|
}
|
|
24
|
-
return tryOrThrow(() => agentJsFileSchema.parse({
|
|
25
|
+
return tryOrThrow(() => customCamelize(agentJsFileSchema.parse({
|
|
26
|
+
...agent,
|
|
25
27
|
name: agent.agent_name || agent.name,
|
|
26
|
-
description: agent.description,
|
|
27
|
-
input_schema: agent.input_schema,
|
|
28
|
-
output_schema: agent.output_schema,
|
|
29
28
|
fn: agent,
|
|
30
|
-
}), (error) => new Error(`Failed to parse agent from ${path}: ${error.message}`));
|
|
29
|
+
}), { shallowKeys: ["input_schema", "output_schema"] }), (error) => new Error(`Failed to parse agent from ${path}: ${error.message}`));
|
|
31
30
|
}
|
|
@@ -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
|
-
|
|
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
|
-
|
|
14
|
-
|
|
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
|
-
|
|
22
|
+
outputKey?: string | undefined;
|
|
20
23
|
} | {
|
|
21
24
|
type: "mcp";
|
|
22
25
|
url?: string | undefined;
|
|
@@ -2,6 +2,7 @@ import { readFile } from "node:fs/promises";
|
|
|
2
2
|
import { jsonSchemaToZod } from "@aigne/json-schema-to-zod";
|
|
3
3
|
import { parse } from "yaml";
|
|
4
4
|
import { z } from "zod";
|
|
5
|
+
import { customCamelize } from "../utils/camelize.js";
|
|
5
6
|
import { tryOrThrow } from "../utils/type-utils.js";
|
|
6
7
|
import { inputOutputSchema } from "./schema.js";
|
|
7
8
|
const agentFileSchema = z.discriminatedUnion("type", [
|
|
@@ -34,6 +35,15 @@ const agentFileSchema = z.discriminatedUnion("type", [
|
|
|
34
35
|
.union([z.literal("auto"), z.literal("none"), z.literal("required"), z.literal("router")])
|
|
35
36
|
.nullish()
|
|
36
37
|
.transform((v) => v ?? undefined),
|
|
38
|
+
memory: z
|
|
39
|
+
.union([
|
|
40
|
+
z.boolean(),
|
|
41
|
+
z.object({
|
|
42
|
+
subscribe_topic: z.array(z.string()),
|
|
43
|
+
}),
|
|
44
|
+
])
|
|
45
|
+
.nullish()
|
|
46
|
+
.transform((v) => v || undefined),
|
|
37
47
|
}),
|
|
38
48
|
z.object({
|
|
39
49
|
type: z.literal("mcp"),
|
|
@@ -54,6 +64,8 @@ const agentFileSchema = z.discriminatedUnion("type", [
|
|
|
54
64
|
export async function loadAgentFromYamlFile(path) {
|
|
55
65
|
const raw = await tryOrThrow(() => readFile(path, "utf8"), (error) => new Error(`Failed to load agent definition from ${path}: ${error.message}`));
|
|
56
66
|
const json = await tryOrThrow(() => parse(raw), (error) => new Error(`Failed to parse agent definition from ${path}: ${error.message}`));
|
|
57
|
-
const agent = tryOrThrow(() => agentFileSchema.parse({ ...json, type: json.type ?? "ai" }),
|
|
67
|
+
const agent = tryOrThrow(() => customCamelize(agentFileSchema.parse({ ...json, type: json.type ?? "ai" }), {
|
|
68
|
+
shallowKeys: ["input_schema", "output_schema"],
|
|
69
|
+
}), (error) => new Error(`Failed to validate agent definition from ${path}: ${error.message}`));
|
|
58
70
|
return agent;
|
|
59
71
|
}
|
|
@@ -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;
|
package/lib/esm/loader/index.js
CHANGED
|
@@ -33,26 +33,15 @@ export async function load(options) {
|
|
|
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
|
+
tools: agent.tools &&
|
|
44
|
+
(await Promise.all(agent.tools.map((filename) => loadAgent(join(dirname(path), filename))))),
|
|
56
45
|
});
|
|
57
46
|
}
|
|
58
47
|
if (agent.type === "mcp") {
|
|
@@ -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
|
}
|
|
@@ -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") {
|
|
@@ -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);
|
|
@@ -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();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type
|
|
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>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import equal from "fast-deep-equal";
|
|
2
|
+
import { isEmptyChunk, } from "../agents/agent.js";
|
|
2
3
|
import { omitBy } from "./type-utils.js";
|
|
3
4
|
export function objectToAgentResponseStream(json) {
|
|
4
5
|
return new ReadableStream({
|
|
@@ -63,13 +64,11 @@ export function asyncGeneratorToReadableStream(generator) {
|
|
|
63
64
|
if (chunk.done)
|
|
64
65
|
break;
|
|
65
66
|
}
|
|
67
|
+
controller.close();
|
|
66
68
|
}
|
|
67
69
|
catch (error) {
|
|
68
70
|
controller.error(error);
|
|
69
71
|
}
|
|
70
|
-
finally {
|
|
71
|
-
controller.close();
|
|
72
|
-
}
|
|
73
72
|
},
|
|
74
73
|
});
|
|
75
74
|
}
|
|
@@ -80,7 +79,8 @@ export function onAgentResponseStreamEnd(stream, callback, options) {
|
|
|
80
79
|
const json = {};
|
|
81
80
|
for await (const value of readableStreamToAsyncIterator(stream)) {
|
|
82
81
|
const chunk = options?.processChunk ? options.processChunk(value) : value;
|
|
83
|
-
|
|
82
|
+
if (!isEmptyChunk(chunk))
|
|
83
|
+
controller.enqueue(chunk);
|
|
84
84
|
mergeAgentResponseChunk(json, value);
|
|
85
85
|
}
|
|
86
86
|
const result = await callback(json);
|
|
@@ -142,3 +142,8 @@ export async function* readableStreamToAsyncIterator(stream) {
|
|
|
142
142
|
yield value;
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
|
+
export function stringToAgentResponseStream(str, key = "text") {
|
|
146
|
+
const segmenter = new Intl.Segmenter(undefined, { granularity: "word" });
|
|
147
|
+
const segments = segmenter.segment(str);
|
|
148
|
+
return arrayToAgentResponseStream(Array.from(segments).map((segment) => ({ delta: { text: { [key]: segment.segment } } })));
|
|
149
|
+
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
4
4
|
"description": "AIGNE core library for building AI-powered applications",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
8
8
|
"author": "Arcblock <blocklet@arcblock.io> https://github.com/blocklet",
|
|
9
9
|
"homepage": "https://github.com/AIGNE-io/aigne-framework",
|
|
10
|
-
"license": "
|
|
10
|
+
"license": "Elastic-2.0",
|
|
11
11
|
"repository": {
|
|
12
12
|
"type": "git",
|
|
13
13
|
"url": "git+https://github.com/AIGNE-io/aigne-framework"
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
"@aigne/json-schema-to-zod": "^1.3.3",
|
|
66
66
|
"@modelcontextprotocol/sdk": "^1.9.0",
|
|
67
67
|
"@types/debug": "^4.1.12",
|
|
68
|
+
"camelize-ts": "^3.0.0",
|
|
68
69
|
"debug": "^4.4.0",
|
|
69
70
|
"fast-deep-equal": "^3.1.3",
|
|
70
71
|
"inquirer": "^12.5.2",
|