@aigne/core 1.8.0 → 1.10.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 +24 -0
- package/lib/cjs/agents/agent.d.ts +29 -3
- package/lib/cjs/agents/agent.js +48 -23
- package/lib/cjs/agents/ai-agent.d.ts +3 -2
- package/lib/cjs/agents/ai-agent.js +22 -9
- package/lib/cjs/agents/user-agent.d.ts +3 -3
- package/lib/cjs/agents/user-agent.js +14 -8
- package/lib/cjs/execution-engine/context.d.ts +18 -7
- package/lib/cjs/execution-engine/context.js +76 -28
- package/lib/cjs/loader/index.js +20 -4
- package/lib/cjs/models/chat-model.d.ts +4 -0
- package/lib/cjs/models/chat-model.js +6 -0
- package/lib/cjs/models/deepseek-chat-model.d.ts +7 -0
- package/lib/cjs/models/deepseek-chat-model.js +19 -0
- package/lib/cjs/models/gemini-chat-model.d.ts +8 -0
- package/lib/cjs/models/gemini-chat-model.js +20 -0
- package/lib/cjs/models/ollama-chat-model.d.ts +6 -0
- package/lib/cjs/models/ollama-chat-model.js +18 -0
- package/lib/cjs/models/open-router-chat-model.d.ts +6 -0
- package/lib/cjs/models/open-router-chat-model.js +18 -0
- package/lib/cjs/models/openai-chat-model.d.ts +33 -2
- package/lib/cjs/models/openai-chat-model.js +250 -80
- package/lib/cjs/models/xai-chat-model.d.ts +3 -11
- package/lib/cjs/models/xai-chat-model.js +1 -14
- package/lib/cjs/prompt/prompt-builder.js +3 -0
- package/lib/cjs/utils/prompts.d.ts +1 -0
- package/lib/cjs/utils/prompts.js +13 -0
- package/lib/cjs/utils/stream-utils.d.ts +15 -0
- package/lib/cjs/utils/stream-utils.js +159 -0
- package/lib/cjs/utils/type-utils.d.ts +2 -1
- package/lib/cjs/utils/type-utils.js +8 -1
- package/lib/dts/agents/agent.d.ts +29 -3
- package/lib/dts/agents/ai-agent.d.ts +3 -2
- package/lib/dts/agents/user-agent.d.ts +3 -3
- package/lib/dts/execution-engine/context.d.ts +18 -7
- package/lib/dts/models/chat-model.d.ts +4 -0
- package/lib/dts/models/deepseek-chat-model.d.ts +7 -0
- package/lib/dts/models/gemini-chat-model.d.ts +8 -0
- package/lib/dts/models/ollama-chat-model.d.ts +6 -0
- package/lib/dts/models/open-router-chat-model.d.ts +6 -0
- package/lib/dts/models/openai-chat-model.d.ts +33 -2
- package/lib/dts/models/xai-chat-model.d.ts +3 -11
- package/lib/dts/utils/prompts.d.ts +1 -0
- package/lib/dts/utils/stream-utils.d.ts +15 -0
- package/lib/dts/utils/type-utils.d.ts +2 -1
- package/lib/esm/agents/agent.d.ts +29 -3
- package/lib/esm/agents/agent.js +49 -24
- package/lib/esm/agents/ai-agent.d.ts +3 -2
- package/lib/esm/agents/ai-agent.js +23 -10
- package/lib/esm/agents/user-agent.d.ts +3 -3
- package/lib/esm/agents/user-agent.js +15 -9
- package/lib/esm/execution-engine/context.d.ts +18 -7
- package/lib/esm/execution-engine/context.js +78 -30
- package/lib/esm/loader/index.js +20 -4
- package/lib/esm/models/chat-model.d.ts +4 -0
- package/lib/esm/models/chat-model.js +6 -0
- package/lib/esm/models/deepseek-chat-model.d.ts +7 -0
- package/lib/esm/models/deepseek-chat-model.js +15 -0
- package/lib/esm/models/gemini-chat-model.d.ts +8 -0
- package/lib/esm/models/gemini-chat-model.js +16 -0
- package/lib/esm/models/ollama-chat-model.d.ts +6 -0
- package/lib/esm/models/ollama-chat-model.js +14 -0
- package/lib/esm/models/open-router-chat-model.d.ts +6 -0
- package/lib/esm/models/open-router-chat-model.js +14 -0
- package/lib/esm/models/openai-chat-model.d.ts +33 -2
- package/lib/esm/models/openai-chat-model.js +247 -80
- package/lib/esm/models/xai-chat-model.d.ts +3 -11
- package/lib/esm/models/xai-chat-model.js +1 -11
- package/lib/esm/prompt/prompt-builder.js +3 -0
- package/lib/esm/utils/prompts.d.ts +1 -0
- package/lib/esm/utils/prompts.js +10 -0
- package/lib/esm/utils/stream-utils.d.ts +15 -0
- package/lib/esm/utils/stream-utils.js +144 -0
- package/lib/esm/utils/type-utils.d.ts +2 -1
- package/lib/esm/utils/type-utils.js +7 -1
- package/package.json +2 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { OpenAIChatModel } from "./openai-chat-model.js";
|
|
2
|
+
const OPEN_ROUTER_DEFAULT_CHAT_MODEL = "openai/gpt-4o";
|
|
3
|
+
const OPEN_ROUTER_BASE_URL = "https://openrouter.ai/api/v1";
|
|
4
|
+
export class OpenRouterChatModel extends OpenAIChatModel {
|
|
5
|
+
constructor(options) {
|
|
6
|
+
super({
|
|
7
|
+
...options,
|
|
8
|
+
model: options?.model || OPEN_ROUTER_DEFAULT_CHAT_MODEL,
|
|
9
|
+
baseURL: options?.baseURL || OPEN_ROUTER_BASE_URL,
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
apiKeyEnvName = "OPEN_ROUTER_API_KEY";
|
|
13
|
+
supportsParallelToolCalls = false;
|
|
14
|
+
}
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
import OpenAI from "openai";
|
|
2
|
+
import type { ChatCompletionMessageParam, ChatCompletionTool } from "openai/resources";
|
|
2
3
|
import { z } from "zod";
|
|
3
|
-
import
|
|
4
|
+
import type { AgentCallOptions, AgentResponse } from "../agents/agent.js";
|
|
5
|
+
import type { Context } from "../execution-engine/context.js";
|
|
6
|
+
import { ChatModel, type ChatModelInput, type ChatModelInputMessage, type ChatModelInputTool, type ChatModelOptions, type ChatModelOutput, type Role } from "./chat-model.js";
|
|
7
|
+
export interface OpenAIChatModelCapabilities {
|
|
8
|
+
supportsNativeStructuredOutputs: boolean;
|
|
9
|
+
supportsEndWithSystemMessage: boolean;
|
|
10
|
+
supportsToolsUseWithJsonSchema: boolean;
|
|
11
|
+
supportsParallelToolCalls: boolean;
|
|
12
|
+
supportsToolsEmptyParameters: boolean;
|
|
13
|
+
supportsTemperature: boolean;
|
|
14
|
+
}
|
|
4
15
|
export interface OpenAIChatModelOptions {
|
|
5
16
|
apiKey?: string;
|
|
6
17
|
baseURL?: string;
|
|
@@ -62,7 +73,27 @@ export declare class OpenAIChatModel extends ChatModel {
|
|
|
62
73
|
options?: OpenAIChatModelOptions | undefined;
|
|
63
74
|
constructor(options?: OpenAIChatModelOptions | undefined);
|
|
64
75
|
protected _client?: OpenAI;
|
|
76
|
+
protected apiKeyEnvName: string;
|
|
77
|
+
protected apiKeyDefault: string | undefined;
|
|
78
|
+
protected supportsNativeStructuredOutputs: boolean;
|
|
79
|
+
protected supportsEndWithSystemMessage: boolean;
|
|
80
|
+
protected supportsToolsUseWithJsonSchema: boolean;
|
|
81
|
+
protected supportsParallelToolCalls: boolean;
|
|
82
|
+
protected supportsToolsEmptyParameters: boolean;
|
|
83
|
+
protected supportsTemperature: boolean;
|
|
65
84
|
get client(): OpenAI;
|
|
66
85
|
get modelOptions(): ChatModelOptions | undefined;
|
|
67
|
-
process(input: ChatModelInput): Promise<ChatModelOutput
|
|
86
|
+
process(input: ChatModelInput, _context: Context, options?: AgentCallOptions): Promise<AgentResponse<ChatModelOutput>>;
|
|
87
|
+
private getParallelToolCalls;
|
|
88
|
+
private getRunMessages;
|
|
89
|
+
private getRunResponseFormat;
|
|
90
|
+
private requestStructuredOutput;
|
|
68
91
|
}
|
|
92
|
+
export declare const ROLE_MAP: {
|
|
93
|
+
[key in Role]: ChatCompletionMessageParam["role"];
|
|
94
|
+
};
|
|
95
|
+
export declare function contentsFromInputMessages(messages: ChatModelInputMessage[]): Promise<ChatCompletionMessageParam[]>;
|
|
96
|
+
export declare function toolsFromInputTools(tools?: ChatModelInputTool[], options?: {
|
|
97
|
+
addTypeToEmptyParameters?: boolean;
|
|
98
|
+
}): ChatCompletionTool[] | undefined;
|
|
99
|
+
export declare function jsonSchemaToOpenAIJsonSchema(schema: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -2,9 +2,16 @@ import { nanoid } from "nanoid";
|
|
|
2
2
|
import OpenAI from "openai";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { parseJSON } from "../utils/json-schema.js";
|
|
5
|
+
import { mergeUsage } from "../utils/model-utils.js";
|
|
6
|
+
import { getJsonOutputPrompt } from "../utils/prompts.js";
|
|
7
|
+
import { agentResponseStreamToObject } from "../utils/stream-utils.js";
|
|
5
8
|
import { checkArguments, isNonNullable } from "../utils/type-utils.js";
|
|
6
9
|
import { ChatModel, } from "./chat-model.js";
|
|
7
10
|
const CHAT_MODEL_OPENAI_DEFAULT_MODEL = "gpt-4o-mini";
|
|
11
|
+
const OPENAI_CHAT_MODEL_CAPABILITIES = {
|
|
12
|
+
"o4-mini": { supportsParallelToolCalls: false, supportsTemperature: false },
|
|
13
|
+
"o3-mini": { supportsParallelToolCalls: false, supportsTemperature: false },
|
|
14
|
+
};
|
|
8
15
|
export const openAIChatModelOptionsSchema = z.object({
|
|
9
16
|
apiKey: z.string().optional(),
|
|
10
17
|
baseURL: z.string().optional(),
|
|
@@ -23,16 +30,26 @@ export const openAIChatModelOptionsSchema = z.object({
|
|
|
23
30
|
export class OpenAIChatModel extends ChatModel {
|
|
24
31
|
options;
|
|
25
32
|
constructor(options) {
|
|
26
|
-
if (options)
|
|
27
|
-
checkArguments("OpenAIChatModel", openAIChatModelOptionsSchema, options);
|
|
28
33
|
super();
|
|
29
34
|
this.options = options;
|
|
35
|
+
if (options)
|
|
36
|
+
checkArguments(this.name, openAIChatModelOptionsSchema, options);
|
|
37
|
+
const preset = options?.model ? OPENAI_CHAT_MODEL_CAPABILITIES[options.model] : undefined;
|
|
38
|
+
Object.assign(this, preset);
|
|
30
39
|
}
|
|
31
40
|
_client;
|
|
41
|
+
apiKeyEnvName = "OPENAI_API_KEY";
|
|
42
|
+
apiKeyDefault;
|
|
43
|
+
supportsNativeStructuredOutputs = true;
|
|
44
|
+
supportsEndWithSystemMessage = true;
|
|
45
|
+
supportsToolsUseWithJsonSchema = true;
|
|
46
|
+
supportsParallelToolCalls = true;
|
|
47
|
+
supportsToolsEmptyParameters = true;
|
|
48
|
+
supportsTemperature = true;
|
|
32
49
|
get client() {
|
|
33
|
-
const apiKey = this.options?.apiKey || process.env.
|
|
50
|
+
const apiKey = this.options?.apiKey || process.env[this.apiKeyEnvName] || this.apiKeyDefault;
|
|
34
51
|
if (!apiKey)
|
|
35
|
-
throw new Error(
|
|
52
|
+
throw new Error(`Api Key is required for ${this.name}`);
|
|
36
53
|
this._client ??= new OpenAI({
|
|
37
54
|
baseURL: this.options?.baseURL,
|
|
38
55
|
apiKey,
|
|
@@ -42,92 +59,111 @@ export class OpenAIChatModel extends ChatModel {
|
|
|
42
59
|
get modelOptions() {
|
|
43
60
|
return this.options?.modelOptions;
|
|
44
61
|
}
|
|
45
|
-
async process(input) {
|
|
46
|
-
const
|
|
62
|
+
async process(input, _context, options) {
|
|
63
|
+
const messages = await this.getRunMessages(input);
|
|
64
|
+
const body = {
|
|
47
65
|
model: this.options?.model || CHAT_MODEL_OPENAI_DEFAULT_MODEL,
|
|
48
|
-
temperature:
|
|
66
|
+
temperature: this.supportsTemperature
|
|
67
|
+
? (input.modelOptions?.temperature ?? this.modelOptions?.temperature)
|
|
68
|
+
: undefined,
|
|
49
69
|
top_p: input.modelOptions?.topP ?? this.modelOptions?.topP,
|
|
50
70
|
frequency_penalty: input.modelOptions?.frequencyPenalty ?? this.modelOptions?.frequencyPenalty,
|
|
51
71
|
presence_penalty: input.modelOptions?.presencePenalty ?? this.modelOptions?.presencePenalty,
|
|
52
|
-
messages
|
|
53
|
-
tools: toolsFromInputTools(input.tools),
|
|
54
|
-
tool_choice: input.toolChoice,
|
|
55
|
-
parallel_tool_calls: !input.tools?.length
|
|
56
|
-
? undefined
|
|
57
|
-
: (input.modelOptions?.parallelToolCalls ?? this.modelOptions?.parallelToolCalls),
|
|
58
|
-
response_format: input.responseFormat?.type === "json_schema"
|
|
59
|
-
? {
|
|
60
|
-
type: "json_schema",
|
|
61
|
-
json_schema: {
|
|
62
|
-
...input.responseFormat.jsonSchema,
|
|
63
|
-
schema: jsonSchemaToOpenAIJsonSchema(input.responseFormat.jsonSchema.schema),
|
|
64
|
-
},
|
|
65
|
-
}
|
|
66
|
-
: undefined,
|
|
72
|
+
messages,
|
|
67
73
|
stream_options: {
|
|
68
74
|
include_usage: true,
|
|
69
75
|
},
|
|
70
76
|
stream: true,
|
|
77
|
+
};
|
|
78
|
+
const { jsonMode, responseFormat } = await this.getRunResponseFormat(input);
|
|
79
|
+
const stream = await this.client.chat.completions.create({
|
|
80
|
+
...body,
|
|
81
|
+
tools: toolsFromInputTools(input.tools, {
|
|
82
|
+
addTypeToEmptyParameters: !this.supportsToolsEmptyParameters,
|
|
83
|
+
}),
|
|
84
|
+
tool_choice: input.toolChoice,
|
|
85
|
+
parallel_tool_calls: this.getParallelToolCalls(input),
|
|
86
|
+
response_format: responseFormat,
|
|
71
87
|
});
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
let usage;
|
|
75
|
-
let model;
|
|
76
|
-
for await (const chunk of res) {
|
|
77
|
-
const choice = chunk.choices?.[0];
|
|
78
|
-
model ??= chunk.model;
|
|
79
|
-
if (choice?.delta.tool_calls?.length) {
|
|
80
|
-
for (const call of choice.delta.tool_calls) {
|
|
81
|
-
toolCalls[call.index] ??= {
|
|
82
|
-
id: call.id || nanoid(),
|
|
83
|
-
type: "function",
|
|
84
|
-
function: { name: "", arguments: {} },
|
|
85
|
-
args: "",
|
|
86
|
-
};
|
|
87
|
-
const c = toolCalls[call.index];
|
|
88
|
-
if (!c)
|
|
89
|
-
throw new Error("Tool call not found");
|
|
90
|
-
if (call.type)
|
|
91
|
-
c.type = call.type;
|
|
92
|
-
c.function.name = c.function.name + (call.function?.name || "");
|
|
93
|
-
c.args = c.args.concat(call.function?.arguments || "");
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
if (choice?.delta.content)
|
|
97
|
-
text += choice.delta.content;
|
|
98
|
-
if (chunk.usage) {
|
|
99
|
-
usage = {
|
|
100
|
-
inputTokens: chunk.usage.prompt_tokens,
|
|
101
|
-
outputTokens: chunk.usage.completion_tokens,
|
|
102
|
-
};
|
|
103
|
-
}
|
|
88
|
+
if (options?.streaming && input.responseFormat?.type !== "json_schema") {
|
|
89
|
+
return await extractResultFromStream(stream, false, true);
|
|
104
90
|
}
|
|
105
|
-
const result =
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
91
|
+
const result = await extractResultFromStream(stream, jsonMode);
|
|
92
|
+
if (!this.supportsToolsUseWithJsonSchema &&
|
|
93
|
+
!result.toolCalls?.length &&
|
|
94
|
+
input.responseFormat?.type === "json_schema" &&
|
|
95
|
+
result.text) {
|
|
96
|
+
const output = await this.requestStructuredOutput(body, input.responseFormat);
|
|
97
|
+
return { ...output, usage: mergeUsage(result.usage, output.usage) };
|
|
111
98
|
}
|
|
112
|
-
|
|
113
|
-
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
getParallelToolCalls(input) {
|
|
102
|
+
if (!this.supportsParallelToolCalls)
|
|
103
|
+
return undefined;
|
|
104
|
+
if (!input.tools?.length)
|
|
105
|
+
return undefined;
|
|
106
|
+
return input.modelOptions?.parallelToolCalls ?? this.modelOptions?.parallelToolCalls;
|
|
107
|
+
}
|
|
108
|
+
async getRunMessages(input) {
|
|
109
|
+
const messages = await contentsFromInputMessages(input.messages);
|
|
110
|
+
if (!this.supportsEndWithSystemMessage && messages.at(-1)?.role !== "user") {
|
|
111
|
+
messages.push({ role: "user", content: "" });
|
|
114
112
|
}
|
|
115
|
-
if (
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
113
|
+
if (!this.supportsToolsUseWithJsonSchema && input.tools?.length)
|
|
114
|
+
return messages;
|
|
115
|
+
if (this.supportsNativeStructuredOutputs)
|
|
116
|
+
return messages;
|
|
117
|
+
if (input.responseFormat?.type === "json_schema") {
|
|
118
|
+
messages.unshift({
|
|
119
|
+
role: "system",
|
|
120
|
+
content: getJsonOutputPrompt(input.responseFormat.jsonSchema.schema),
|
|
121
|
+
});
|
|
120
122
|
}
|
|
121
|
-
return
|
|
123
|
+
return messages;
|
|
124
|
+
}
|
|
125
|
+
async getRunResponseFormat(input) {
|
|
126
|
+
if (!this.supportsToolsUseWithJsonSchema && input.tools?.length)
|
|
127
|
+
return { jsonMode: false, responseFormat: undefined };
|
|
128
|
+
if (!this.supportsNativeStructuredOutputs) {
|
|
129
|
+
const jsonMode = input.responseFormat?.type === "json_schema";
|
|
130
|
+
return { jsonMode, responseFormat: jsonMode ? { type: "json_object" } : undefined };
|
|
131
|
+
}
|
|
132
|
+
if (input.responseFormat?.type === "json_schema") {
|
|
133
|
+
return {
|
|
134
|
+
jsonMode: true,
|
|
135
|
+
responseFormat: {
|
|
136
|
+
type: "json_schema",
|
|
137
|
+
json_schema: {
|
|
138
|
+
...input.responseFormat.jsonSchema,
|
|
139
|
+
schema: jsonSchemaToOpenAIJsonSchema(input.responseFormat.jsonSchema.schema),
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
return { jsonMode: false, responseFormat: undefined };
|
|
145
|
+
}
|
|
146
|
+
async requestStructuredOutput(body, responseFormat) {
|
|
147
|
+
if (responseFormat?.type !== "json_schema") {
|
|
148
|
+
throw new Error("Expected json_schema response format");
|
|
149
|
+
}
|
|
150
|
+
const { jsonMode, responseFormat: resolvedResponseFormat } = await this.getRunResponseFormat({
|
|
151
|
+
responseFormat,
|
|
152
|
+
});
|
|
153
|
+
const res = await this.client.chat.completions.create({
|
|
154
|
+
...body,
|
|
155
|
+
response_format: resolvedResponseFormat,
|
|
156
|
+
});
|
|
157
|
+
return extractResultFromStream(res, jsonMode);
|
|
122
158
|
}
|
|
123
159
|
}
|
|
124
|
-
const ROLE_MAP = {
|
|
160
|
+
export const ROLE_MAP = {
|
|
125
161
|
system: "system",
|
|
126
162
|
user: "user",
|
|
127
163
|
agent: "assistant",
|
|
128
164
|
tool: "tool",
|
|
129
165
|
};
|
|
130
|
-
async function contentsFromInputMessages(messages) {
|
|
166
|
+
export async function contentsFromInputMessages(messages) {
|
|
131
167
|
return messages.map((i) => ({
|
|
132
168
|
role: ROLE_MAP[i.role],
|
|
133
169
|
content: typeof i.content === "string"
|
|
@@ -156,19 +192,25 @@ async function contentsFromInputMessages(messages) {
|
|
|
156
192
|
name: i.name,
|
|
157
193
|
}));
|
|
158
194
|
}
|
|
159
|
-
function toolsFromInputTools(tools) {
|
|
195
|
+
export function toolsFromInputTools(tools, options) {
|
|
160
196
|
return tools?.length
|
|
161
|
-
? tools.map((i) =>
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
197
|
+
? tools.map((i) => {
|
|
198
|
+
const parameters = i.function.parameters;
|
|
199
|
+
if (options?.addTypeToEmptyParameters && Object.keys(parameters).length === 0) {
|
|
200
|
+
parameters.type = "object";
|
|
201
|
+
}
|
|
202
|
+
return {
|
|
203
|
+
type: "function",
|
|
204
|
+
function: {
|
|
205
|
+
name: i.function.name,
|
|
206
|
+
description: i.function.description,
|
|
207
|
+
parameters,
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
})
|
|
169
211
|
: undefined;
|
|
170
212
|
}
|
|
171
|
-
function jsonSchemaToOpenAIJsonSchema(schema) {
|
|
213
|
+
export function jsonSchemaToOpenAIJsonSchema(schema) {
|
|
172
214
|
if (schema?.type === "object") {
|
|
173
215
|
const { required, properties } = schema;
|
|
174
216
|
return {
|
|
@@ -193,3 +235,128 @@ function jsonSchemaToOpenAIJsonSchema(schema) {
|
|
|
193
235
|
}
|
|
194
236
|
return schema;
|
|
195
237
|
}
|
|
238
|
+
async function extractResultFromStream(stream, jsonMode, streaming) {
|
|
239
|
+
const result = new ReadableStream({
|
|
240
|
+
async start(controller) {
|
|
241
|
+
try {
|
|
242
|
+
let text = "";
|
|
243
|
+
let refusal = "";
|
|
244
|
+
const toolCalls = [];
|
|
245
|
+
let model;
|
|
246
|
+
for await (const chunk of stream) {
|
|
247
|
+
const choice = chunk.choices?.[0];
|
|
248
|
+
if (!model) {
|
|
249
|
+
model = chunk.model;
|
|
250
|
+
controller.enqueue({
|
|
251
|
+
delta: {
|
|
252
|
+
json: {
|
|
253
|
+
model,
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
if (choice?.delta.tool_calls?.length) {
|
|
259
|
+
for (const call of choice.delta.tool_calls) {
|
|
260
|
+
// Gemini not support tool call delta
|
|
261
|
+
if (call.index !== undefined) {
|
|
262
|
+
handleToolCallDelta(toolCalls, call);
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
handleCompleteToolCall(toolCalls, call);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (choice?.delta.content) {
|
|
270
|
+
text += choice.delta.content;
|
|
271
|
+
if (!jsonMode) {
|
|
272
|
+
controller.enqueue({
|
|
273
|
+
delta: {
|
|
274
|
+
text: {
|
|
275
|
+
text: choice.delta.content,
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if (choice?.delta.refusal) {
|
|
282
|
+
refusal += choice.delta.refusal;
|
|
283
|
+
if (!jsonMode) {
|
|
284
|
+
controller.enqueue({
|
|
285
|
+
delta: {
|
|
286
|
+
text: { text: choice.delta.refusal },
|
|
287
|
+
},
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
if (chunk.usage) {
|
|
292
|
+
controller.enqueue({
|
|
293
|
+
delta: {
|
|
294
|
+
json: {
|
|
295
|
+
usage: {
|
|
296
|
+
inputTokens: chunk.usage.prompt_tokens,
|
|
297
|
+
outputTokens: chunk.usage.completion_tokens,
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
text = text || refusal;
|
|
305
|
+
if (jsonMode && text) {
|
|
306
|
+
controller.enqueue({
|
|
307
|
+
delta: {
|
|
308
|
+
json: {
|
|
309
|
+
json: parseJSON(text),
|
|
310
|
+
},
|
|
311
|
+
},
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
if (toolCalls.length) {
|
|
315
|
+
controller.enqueue({
|
|
316
|
+
delta: {
|
|
317
|
+
json: {
|
|
318
|
+
toolCalls: toolCalls.map(({ args, ...c }) => ({
|
|
319
|
+
...c,
|
|
320
|
+
function: { ...c.function, arguments: parseJSON(args) },
|
|
321
|
+
})),
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
catch (error) {
|
|
328
|
+
controller.error(error);
|
|
329
|
+
}
|
|
330
|
+
finally {
|
|
331
|
+
controller.close();
|
|
332
|
+
}
|
|
333
|
+
},
|
|
334
|
+
});
|
|
335
|
+
return streaming ? result : await agentResponseStreamToObject(result);
|
|
336
|
+
}
|
|
337
|
+
function handleToolCallDelta(toolCalls, call) {
|
|
338
|
+
toolCalls[call.index] ??= {
|
|
339
|
+
id: call.id || nanoid(),
|
|
340
|
+
type: "function",
|
|
341
|
+
function: { name: "", arguments: {} },
|
|
342
|
+
args: "",
|
|
343
|
+
};
|
|
344
|
+
const c = toolCalls[call.index];
|
|
345
|
+
if (!c)
|
|
346
|
+
throw new Error("Tool call not found");
|
|
347
|
+
if (call.type)
|
|
348
|
+
c.type = call.type;
|
|
349
|
+
c.function.name = c.function.name + (call.function?.name || "");
|
|
350
|
+
c.args = c.args.concat(call.function?.arguments || "");
|
|
351
|
+
}
|
|
352
|
+
function handleCompleteToolCall(toolCalls, call) {
|
|
353
|
+
toolCalls.push({
|
|
354
|
+
id: call.id || nanoid(),
|
|
355
|
+
type: "function",
|
|
356
|
+
function: {
|
|
357
|
+
name: call.function?.name || "",
|
|
358
|
+
arguments: parseJSON(call.function?.arguments || "{}"),
|
|
359
|
+
},
|
|
360
|
+
args: call.function?.arguments || "",
|
|
361
|
+
});
|
|
362
|
+
}
|
|
@@ -1,13 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type { ChatModelOptions } from "./chat-model.js";
|
|
3
|
-
import { OpenAIChatModel } from "./openai-chat-model.js";
|
|
4
|
-
export interface XAIChatModelOptions {
|
|
5
|
-
apiKey?: string;
|
|
6
|
-
model?: string;
|
|
7
|
-
modelOptions?: ChatModelOptions;
|
|
8
|
-
baseURL?: string;
|
|
9
|
-
}
|
|
1
|
+
import { OpenAIChatModel, type OpenAIChatModelOptions } from "./openai-chat-model.js";
|
|
10
2
|
export declare class XAIChatModel extends OpenAIChatModel {
|
|
11
|
-
constructor(options?:
|
|
12
|
-
|
|
3
|
+
constructor(options?: OpenAIChatModelOptions);
|
|
4
|
+
protected apiKeyEnvName: string;
|
|
13
5
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import OpenAI from "openai";
|
|
2
1
|
import { OpenAIChatModel } from "./openai-chat-model.js";
|
|
3
2
|
const XAI_DEFAULT_CHAT_MODEL = "grok-2-latest";
|
|
4
3
|
const XAI_BASE_URL = "https://api.x.ai/v1";
|
|
@@ -10,14 +9,5 @@ export class XAIChatModel extends OpenAIChatModel {
|
|
|
10
9
|
baseURL: options?.baseURL || XAI_BASE_URL,
|
|
11
10
|
});
|
|
12
11
|
}
|
|
13
|
-
|
|
14
|
-
const apiKey = this.options?.apiKey || process.env.XAI_API_KEY;
|
|
15
|
-
if (!apiKey)
|
|
16
|
-
throw new Error("Api Key is required for XAIChatModel");
|
|
17
|
-
this._client ??= new OpenAI({
|
|
18
|
-
baseURL: this.options?.baseURL,
|
|
19
|
-
apiKey,
|
|
20
|
-
});
|
|
21
|
-
return this._client;
|
|
22
|
-
}
|
|
12
|
+
apiKeyEnvName = "XAI_API_KEY";
|
|
23
13
|
}
|
|
@@ -127,6 +127,7 @@ export class PromptBuilder {
|
|
|
127
127
|
},
|
|
128
128
|
}));
|
|
129
129
|
let toolChoice;
|
|
130
|
+
const modelOptions = {};
|
|
130
131
|
// use manual choice if configured in the agent
|
|
131
132
|
const manualChoice = options.agent?.toolChoice;
|
|
132
133
|
if (manualChoice) {
|
|
@@ -141,6 +142,7 @@ export class PromptBuilder {
|
|
|
141
142
|
}
|
|
142
143
|
else if (manualChoice === "router") {
|
|
143
144
|
toolChoice = "required";
|
|
145
|
+
modelOptions.parallelToolCalls = false;
|
|
144
146
|
}
|
|
145
147
|
else {
|
|
146
148
|
toolChoice = manualChoice;
|
|
@@ -154,6 +156,7 @@ export class PromptBuilder {
|
|
|
154
156
|
toolAgents: toolAgents.length ? toolAgents : undefined,
|
|
155
157
|
tools: tools.length ? tools : undefined,
|
|
156
158
|
toolChoice,
|
|
159
|
+
modelOptions: Object.keys(modelOptions).length ? modelOptions : undefined,
|
|
157
160
|
};
|
|
158
161
|
}
|
|
159
162
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getJsonOutputPrompt(schema: Record<string, unknown> | string): string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function getJsonOutputPrompt(schema) {
|
|
2
|
+
let prompt = "Provide your output as a JSON containing the following fields:";
|
|
3
|
+
if (typeof schema === "string") {
|
|
4
|
+
prompt += `\n<json_fields>\n${schema}\n</json_fields>`;
|
|
5
|
+
}
|
|
6
|
+
else {
|
|
7
|
+
prompt += `\n<json_fields>\n${JSON.stringify(schema)}\n</json_fields>`;
|
|
8
|
+
}
|
|
9
|
+
return prompt;
|
|
10
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AgentProcessAsyncGenerator, AgentResponseChunk, AgentResponseStream, Message } from "../agents/agent.js";
|
|
2
|
+
import { type PromiseOrValue } from "./type-utils.js";
|
|
3
|
+
export declare function objectToAgentResponseStream<T extends Message>(json: T): AgentResponseStream<T>;
|
|
4
|
+
export declare function mergeAgentResponseChunk<T extends Message>(output: T, chunk: AgentResponseChunk<T>): T;
|
|
5
|
+
export declare function agentResponseStreamToObject<T extends Message>(stream: AgentResponseStream<T> | AgentProcessAsyncGenerator<T>): Promise<T>;
|
|
6
|
+
export declare function asyncGeneratorToReadableStream<T extends Message>(generator: AgentProcessAsyncGenerator<T>): AgentResponseStream<T>;
|
|
7
|
+
export declare function onAgentResponseStreamEnd<T extends Message>(stream: AgentResponseStream<T>, callback: (result: T) => PromiseOrValue<Partial<T> | void>, options?: {
|
|
8
|
+
errorCallback?: (error: Error) => Error;
|
|
9
|
+
processChunk?: (chunk: AgentResponseChunk<T>) => AgentResponseChunk<T>;
|
|
10
|
+
}): ReadableStream<any>;
|
|
11
|
+
export declare function isAsyncGenerator<T extends AsyncGenerator>(value: AsyncGenerator | unknown): value is T;
|
|
12
|
+
export declare function arrayToAgentProcessAsyncGenerator<T extends Message>(chunks: (AgentResponseChunk<T> | Error)[], result?: Partial<T>): AgentProcessAsyncGenerator<T>;
|
|
13
|
+
export declare function arrayToAgentResponseStream<T>(chunks: (AgentResponseChunk<T> | Error)[]): AgentResponseStream<T>;
|
|
14
|
+
export declare function readableStreamToArray<T>(stream: ReadableStream<T>): Promise<T[]>;
|
|
15
|
+
export declare function readableStreamToAsyncIterator<T>(stream: ReadableStream<T>): AsyncIterable<T>;
|