@keo-ai/axiom 0.1.8 → 0.2.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/README.md +57 -3
- package/dist/function_call_loop/loop.d.ts +1 -0
- package/dist/function_call_loop/loop.js +26 -5
- package/dist/function_call_loop/provider.d.ts +1 -0
- package/dist/function_call_loop/provider.js +10 -0
- package/dist/function_call_loop/stream.js +13 -4
- package/dist/function_call_loop/types.d.ts +21 -1
- package/dist/llm_provider/bailian.js +4 -0
- package/dist/llm_provider/index.d.ts +2 -0
- package/dist/llm_provider/types.d.ts +4 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -297,8 +297,12 @@ for await (const chunk of stream) {
|
|
|
297
297
|
case 'turn_start':
|
|
298
298
|
console.log(`\n--- Turn ${chunk.turn} ---`);
|
|
299
299
|
break;
|
|
300
|
+
case 'reasoning':
|
|
301
|
+
// 实时流式输出模型的 reasoning content(思考过程)
|
|
302
|
+
process.stdout.write(chunk.delta);
|
|
303
|
+
break;
|
|
300
304
|
case 'content':
|
|
301
|
-
// 实时流式输出 content
|
|
305
|
+
// 实时流式输出 content(正式回复内容)
|
|
302
306
|
process.stdout.write(chunk.delta);
|
|
303
307
|
break;
|
|
304
308
|
case 'tool_call':
|
|
@@ -341,7 +345,8 @@ console.log('Turns:', result!.turns);
|
|
|
341
345
|
| 事件 | 触发时机 | 包含字段 |
|
|
342
346
|
|---|---|---|
|
|
343
347
|
| `turn_start` | 新一轮开始 | `turn` |
|
|
344
|
-
| `
|
|
348
|
+
| `reasoning` | LLM 输出 reasoning content(推理过程)增量 | `delta`, `turn` |
|
|
349
|
+
| `content` | LLM 输出 content(正式回复)增量 | `delta`, `turn` |
|
|
345
350
|
| `tool_call` | LLM 决定调用 tool(流结束、完整 tool_calls 解析完成) | `toolCalls`, `turn` |
|
|
346
351
|
| `tool_result` | tool 执行完成 | `callId`, `toolName`, `content`, `status`, `turn` |
|
|
347
352
|
| `turn_end` | 一轮结束(tool 全部执行完或 content 直接返回) | `turn` |
|
|
@@ -351,7 +356,7 @@ console.log('Turns:', result!.turns);
|
|
|
351
356
|
| 场景 | 推荐方式 |
|
|
352
357
|
|---|---|
|
|
353
358
|
| 需要实时展示 LLM 输出(打字机效果) | `runLoopStream` |
|
|
354
|
-
|
|
|
359
|
+
| 需要实时展示模型 reasoning(思考)过程 | `runLoopStream`(通过 `reasoning` 事件独立透出) |
|
|
355
360
|
| 后台静默执行,只关心最终结果 | `runLoop` |
|
|
356
361
|
| 低延迟、简单场景 | `runLoop` |
|
|
357
362
|
|
|
@@ -406,6 +411,42 @@ console.log(result.harness);
|
|
|
406
411
|
|
|
407
412
|
**并行隔离原则**:本轮并行执行的多个 tool,各自收到的 Harness 是"本轮并行开始前"的快照,互相看不到同轮其他正在执行的 tool。
|
|
408
413
|
|
|
414
|
+
### Tool 结果分流(ToolResult)
|
|
415
|
+
|
|
416
|
+
当 tool 返回大量结构化数据时,直接 `JSON.stringify` 给 LLM 会导致模型重复复述。此时可以用 `ToolResult` 把结果分成两份:
|
|
417
|
+
|
|
418
|
+
```ts
|
|
419
|
+
const recommendTool = {
|
|
420
|
+
name: 'recommend_conferences',
|
|
421
|
+
description: 'Recommend academic conferences',
|
|
422
|
+
parameters: { /* ... */ },
|
|
423
|
+
execute: async (args) => {
|
|
424
|
+
const raw = await recommendConferences(args);
|
|
425
|
+
return {
|
|
426
|
+
forLLM: `找到 ${raw.results.length} 个相关会议:${raw.results.map(r => r.name).join('、')}`,
|
|
427
|
+
forFrontend: raw,
|
|
428
|
+
};
|
|
429
|
+
},
|
|
430
|
+
};
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
| 字段 | 去向 | 说明 |
|
|
434
|
+
|---|---|---|
|
|
435
|
+
| `forLLM` | `messages[]` → LLM 上下文 | 精简摘要,建议用自然语言 |
|
|
436
|
+
| `forFrontend` | `tool_result` SSE 事件 | 完整原始数据,前端渲染用 |
|
|
437
|
+
|
|
438
|
+
流式消费时前端可以拿到完整数据:
|
|
439
|
+
|
|
440
|
+
```ts
|
|
441
|
+
for await (const chunk of stream) {
|
|
442
|
+
if (chunk.type === 'tool_result' && chunk.frontendData) {
|
|
443
|
+
renderCard(chunk.frontendData); // 前端拿到完整 JSON 渲染卡片
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
**向后兼容**:返回普通值(非 `ToolResult`)时行为完全不变,仍按原有逻辑 `JSON.stringify` 后透给 LLM。
|
|
449
|
+
|
|
409
450
|
### Tool 审批拦截
|
|
410
451
|
|
|
411
452
|
对于敏感操作(转账、删除数据等),可以给 tool 配置 `approval`,Loop 会在执行前暂停并返回 `pendingApproval`:
|
|
@@ -640,6 +681,19 @@ interface LoopResult {
|
|
|
640
681
|
}
|
|
641
682
|
```
|
|
642
683
|
|
|
684
|
+
**Message 中的 reasoningContent**:当使用支持推理的模型(如 DeepSeek-R1、QwQ)时,`messages` 中 `role: 'assistant'` 的条目会包含 `reasoningContent` 字段,记录该轮模型的完整推理过程。该字段会自动保留在对话上下文中,供多轮对话回传。
|
|
685
|
+
|
|
686
|
+
```ts
|
|
687
|
+
const result = await FunctionCallLoop.runLoop(config);
|
|
688
|
+
|
|
689
|
+
for (const msg of result.messages) {
|
|
690
|
+
if (msg.role === 'assistant' && msg.reasoningContent) {
|
|
691
|
+
console.log('[Reasoning]', msg.reasoningContent);
|
|
692
|
+
console.log('[Content]', msg.content);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
```
|
|
696
|
+
|
|
643
697
|
### 错误处理
|
|
644
698
|
|
|
645
699
|
同其他模块:**直接抛异常**。常见场景:
|
|
@@ -92,6 +92,7 @@ function runLoop(config) {
|
|
|
92
92
|
messages.push({
|
|
93
93
|
role: 'assistant',
|
|
94
94
|
content: (_f = llmResponse.content) !== null && _f !== void 0 ? _f : '',
|
|
95
|
+
reasoningContent: llmResponse.reasoningContent,
|
|
95
96
|
});
|
|
96
97
|
return {
|
|
97
98
|
messages,
|
|
@@ -104,6 +105,7 @@ function runLoop(config) {
|
|
|
104
105
|
messages.push({
|
|
105
106
|
role: 'assistant',
|
|
106
107
|
content: (_g = llmResponse.content) !== null && _g !== void 0 ? _g : '',
|
|
108
|
+
reasoningContent: llmResponse.reasoningContent,
|
|
107
109
|
tool_calls: llmResponse.tool_calls,
|
|
108
110
|
});
|
|
109
111
|
// 第七步:并行执行 tool
|
|
@@ -261,6 +263,12 @@ function compressMessages(config, messages, _turn) {
|
|
|
261
263
|
}
|
|
262
264
|
});
|
|
263
265
|
}
|
|
266
|
+
function isToolResult(value) {
|
|
267
|
+
return (typeof value === 'object' &&
|
|
268
|
+
value !== null &&
|
|
269
|
+
'forLLM' in value &&
|
|
270
|
+
typeof value.forLLM === 'string');
|
|
271
|
+
}
|
|
264
272
|
/**
|
|
265
273
|
* 并行执行 tool。
|
|
266
274
|
*/
|
|
@@ -365,14 +373,27 @@ function executeToolsInParallel(config, harness, toolCalls, visibleToolNames, ha
|
|
|
365
373
|
error: finalRecord.error,
|
|
366
374
|
turn,
|
|
367
375
|
};
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
376
|
+
let content;
|
|
377
|
+
let frontendData;
|
|
378
|
+
if (status === 'success') {
|
|
379
|
+
if (isToolResult(result)) {
|
|
380
|
+
content = result.forLLM;
|
|
381
|
+
frontendData = result.forFrontend;
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
content =
|
|
385
|
+
typeof result === 'object' && result !== null
|
|
386
|
+
? JSON.stringify(result)
|
|
387
|
+
: String(result !== null && result !== void 0 ? result : '');
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
content = error !== null && error !== void 0 ? error : 'Execution failed';
|
|
392
|
+
}
|
|
373
393
|
return {
|
|
374
394
|
toolCallId: callId,
|
|
375
395
|
content,
|
|
396
|
+
frontendData,
|
|
376
397
|
record: finalRecord,
|
|
377
398
|
events: [endEvent],
|
|
378
399
|
pendingApproval: typeof result === 'object' &&
|
|
@@ -14,6 +14,7 @@ export interface ProviderOptions {
|
|
|
14
14
|
export declare function createLLMCaller(options: ProviderOptions): {
|
|
15
15
|
call(messages: ReadonlyArray<Message>, tools: ReadonlyArray<ToolDefinition>, callOptions?: LLMCallOptions): Promise<{
|
|
16
16
|
readonly content: string | null;
|
|
17
|
+
readonly reasoningContent?: string;
|
|
17
18
|
readonly tool_calls?: ReadonlyArray<ToolCall>;
|
|
18
19
|
}>;
|
|
19
20
|
/**
|
|
@@ -31,6 +31,7 @@ function toOpenAIMessages(messages) {
|
|
|
31
31
|
return ({
|
|
32
32
|
role: m.role,
|
|
33
33
|
content: m.content,
|
|
34
|
+
reasoning_content: m.reasoningContent,
|
|
34
35
|
tool_calls: (_a = m.tool_calls) === null || _a === void 0 ? void 0 : _a.map((tc) => ({
|
|
35
36
|
id: tc.id,
|
|
36
37
|
type: tc.type,
|
|
@@ -80,6 +81,7 @@ function createLLMCaller(options) {
|
|
|
80
81
|
const choice = data.choices[0];
|
|
81
82
|
return {
|
|
82
83
|
content: choice.message.content,
|
|
84
|
+
reasoningContent: choice.message.reasoning_content,
|
|
83
85
|
tool_calls: (_b = choice.message.tool_calls) === null || _b === void 0 ? void 0 : _b.map((tc) => ({
|
|
84
86
|
id: tc.id,
|
|
85
87
|
type: tc.type,
|
|
@@ -137,6 +139,7 @@ function createLLMCaller(options) {
|
|
|
137
139
|
// 用于增量收集 tool_calls
|
|
138
140
|
const toolCallAccumulators = [];
|
|
139
141
|
let fullContent = '';
|
|
142
|
+
let fullReasoningContent = '';
|
|
140
143
|
let hasYieldedFinish = false;
|
|
141
144
|
try {
|
|
142
145
|
while (true) {
|
|
@@ -164,6 +167,11 @@ function createLLMCaller(options) {
|
|
|
164
167
|
if (!choice)
|
|
165
168
|
continue;
|
|
166
169
|
const delta = choice.delta;
|
|
170
|
+
// 收集 reasoning_content 增量
|
|
171
|
+
if (delta.reasoning_content) {
|
|
172
|
+
fullReasoningContent += delta.reasoning_content;
|
|
173
|
+
yield yield __await({ type: 'reasoning', delta: delta.reasoning_content });
|
|
174
|
+
}
|
|
167
175
|
// 收集 content 增量
|
|
168
176
|
if (delta.content) {
|
|
169
177
|
fullContent += delta.content;
|
|
@@ -209,6 +217,7 @@ function createLLMCaller(options) {
|
|
|
209
217
|
yield yield __await({
|
|
210
218
|
type: 'finish',
|
|
211
219
|
content: fullContent || null,
|
|
220
|
+
reasoningContent: fullReasoningContent || undefined,
|
|
212
221
|
tool_calls: toolCalls.length > 0 ? toolCalls : undefined,
|
|
213
222
|
});
|
|
214
223
|
hasYieldedFinish = true;
|
|
@@ -233,6 +242,7 @@ function createLLMCaller(options) {
|
|
|
233
242
|
yield yield __await({
|
|
234
243
|
type: 'finish',
|
|
235
244
|
content: fullContent || null,
|
|
245
|
+
reasoningContent: fullReasoningContent || undefined,
|
|
236
246
|
tool_calls: toolCalls.length > 0 ? toolCalls : undefined,
|
|
237
247
|
});
|
|
238
248
|
}
|
|
@@ -54,7 +54,7 @@ function buildInitialMessages(config) {
|
|
|
54
54
|
function runLoopStream(config) {
|
|
55
55
|
return __asyncGenerator(this, arguments, function* runLoopStream_1() {
|
|
56
56
|
var _a, e_1, _b, _c;
|
|
57
|
-
var _d, _e, _f, _g, _h, _j;
|
|
57
|
+
var _d, _e, _f, _g, _h, _j, _k;
|
|
58
58
|
const llmCaller = (_d = config.llmCaller) !== null && _d !== void 0 ? _d : (0, provider_1.createLLMCaller)({
|
|
59
59
|
apiKey: (_e = process.env.BAILIAN_API_KEY) !== null && _e !== void 0 ? _e : '',
|
|
60
60
|
baseUrl: (_f = process.env.BAILIAN_BASE_URL) !== null && _f !== void 0 ? _f : DEFAULT_BAILIAN_BASE_URL,
|
|
@@ -108,6 +108,7 @@ function runLoopStream(config) {
|
|
|
108
108
|
const messagesForLLM = yield __await((0, loop_1.compressMessages)(config, messages, turn));
|
|
109
109
|
// 第五步:流式调用 LLM
|
|
110
110
|
let fullContent = '';
|
|
111
|
+
let fullReasoningContent = '';
|
|
111
112
|
let finishChunk = null;
|
|
112
113
|
const stream = llmCaller.stream(messagesForLLM, toolDefinitions, {
|
|
113
114
|
model: config.model,
|
|
@@ -117,14 +118,18 @@ function runLoopStream(config) {
|
|
|
117
118
|
reasoningEffort: config.reasoningEffort,
|
|
118
119
|
});
|
|
119
120
|
try {
|
|
120
|
-
for (var
|
|
121
|
+
for (var _l = true, stream_1 = (e_1 = void 0, __asyncValues(stream)), stream_1_1; stream_1_1 = yield __await(stream_1.next()), _a = stream_1_1.done, !_a; _l = true) {
|
|
121
122
|
_c = stream_1_1.value;
|
|
122
|
-
|
|
123
|
+
_l = false;
|
|
123
124
|
const chunk = _c;
|
|
124
125
|
if (chunk.type === 'content') {
|
|
125
126
|
fullContent += chunk.delta;
|
|
126
127
|
yield yield __await({ type: 'content', delta: chunk.delta, turn });
|
|
127
128
|
}
|
|
129
|
+
else if (chunk.type === 'reasoning') {
|
|
130
|
+
fullReasoningContent += chunk.delta;
|
|
131
|
+
yield yield __await({ type: 'reasoning', delta: chunk.delta, turn });
|
|
132
|
+
}
|
|
128
133
|
else if (chunk.type === 'finish') {
|
|
129
134
|
finishChunk = chunk;
|
|
130
135
|
}
|
|
@@ -133,7 +138,7 @@ function runLoopStream(config) {
|
|
|
133
138
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
134
139
|
finally {
|
|
135
140
|
try {
|
|
136
|
-
if (!
|
|
141
|
+
if (!_l && !_a && (_b = stream_1.return)) yield __await(_b.call(stream_1));
|
|
137
142
|
}
|
|
138
143
|
finally { if (e_1) throw e_1.error; }
|
|
139
144
|
}
|
|
@@ -142,11 +147,13 @@ function runLoopStream(config) {
|
|
|
142
147
|
}
|
|
143
148
|
// 使用 finish chunk 中的 content(优先级更高,可能包含完整格式化内容)
|
|
144
149
|
const assistantContent = (_j = finishChunk.content) !== null && _j !== void 0 ? _j : fullContent;
|
|
150
|
+
const assistantReasoningContent = (_k = finishChunk.reasoningContent) !== null && _k !== void 0 ? _k : (fullReasoningContent || undefined);
|
|
145
151
|
// 第六步:检查 LLM 回复
|
|
146
152
|
if (!finishChunk.tool_calls || finishChunk.tool_calls.length === 0) {
|
|
147
153
|
messages.push({
|
|
148
154
|
role: 'assistant',
|
|
149
155
|
content: assistantContent,
|
|
156
|
+
reasoningContent: assistantReasoningContent,
|
|
150
157
|
});
|
|
151
158
|
yield yield __await({ type: 'turn_end', turn });
|
|
152
159
|
return yield __await({
|
|
@@ -165,6 +172,7 @@ function runLoopStream(config) {
|
|
|
165
172
|
messages.push({
|
|
166
173
|
role: 'assistant',
|
|
167
174
|
content: assistantContent,
|
|
175
|
+
reasoningContent: assistantReasoningContent,
|
|
168
176
|
tool_calls: finishChunk.tool_calls,
|
|
169
177
|
});
|
|
170
178
|
// 第七步:并行执行 tool
|
|
@@ -183,6 +191,7 @@ function runLoopStream(config) {
|
|
|
183
191
|
callId: result.toolCallId,
|
|
184
192
|
toolName: result.record.toolName,
|
|
185
193
|
content: result.content,
|
|
194
|
+
frontendData: result.frontendData,
|
|
186
195
|
status: result.record.status,
|
|
187
196
|
});
|
|
188
197
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
export interface Message {
|
|
6
6
|
readonly role: 'system' | 'user' | 'assistant' | 'tool';
|
|
7
7
|
readonly content: string;
|
|
8
|
+
readonly reasoningContent?: string;
|
|
8
9
|
readonly tool_calls?: ReadonlyArray<ToolCall>;
|
|
9
10
|
readonly tool_call_id?: string;
|
|
10
11
|
}
|
|
@@ -106,6 +107,15 @@ export interface ApprovalConfig {
|
|
|
106
107
|
approved?: boolean;
|
|
107
108
|
}>;
|
|
108
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* Tool 执行结果的分流包装。
|
|
112
|
+
* 当 execute 返回此类型时,forLLM 进入 messages[] 给 LLM 上下文,
|
|
113
|
+
* forFrontend 通过 SSE tool_result 事件透给前端渲染。
|
|
114
|
+
*/
|
|
115
|
+
export interface ToolResult {
|
|
116
|
+
readonly forLLM: string;
|
|
117
|
+
readonly forFrontend?: unknown;
|
|
118
|
+
}
|
|
109
119
|
/**
|
|
110
120
|
* 注册到 Loop 中的 Tool。
|
|
111
121
|
*/
|
|
@@ -114,7 +124,7 @@ export interface Tool {
|
|
|
114
124
|
readonly description: string;
|
|
115
125
|
readonly parameters: unknown;
|
|
116
126
|
readonly discover?: (harness: ReadonlyArray<HarnessRecord>, metadata: unknown) => ToolDiscoverResult | Promise<ToolDiscoverResult>;
|
|
117
|
-
readonly execute: (args: unknown, context: ToolExecuteContext) => unknown | Promise<unknown>;
|
|
127
|
+
readonly execute: (args: unknown, context: ToolExecuteContext) => unknown | ToolResult | Promise<unknown | ToolResult>;
|
|
118
128
|
readonly approval?: ApprovalConfig;
|
|
119
129
|
}
|
|
120
130
|
/**
|
|
@@ -150,9 +160,13 @@ export interface LLMCallOptions {
|
|
|
150
160
|
export type LLMStreamChunk = {
|
|
151
161
|
readonly type: 'content';
|
|
152
162
|
readonly delta: string;
|
|
163
|
+
} | {
|
|
164
|
+
readonly type: 'reasoning';
|
|
165
|
+
readonly delta: string;
|
|
153
166
|
} | {
|
|
154
167
|
readonly type: 'finish';
|
|
155
168
|
readonly content: string | null;
|
|
169
|
+
readonly reasoningContent?: string;
|
|
156
170
|
readonly tool_calls?: ReadonlyArray<ToolCall>;
|
|
157
171
|
};
|
|
158
172
|
/**
|
|
@@ -161,6 +175,7 @@ export type LLMStreamChunk = {
|
|
|
161
175
|
export interface LLMCaller {
|
|
162
176
|
readonly call: (messages: ReadonlyArray<Message>, tools: ReadonlyArray<ToolDefinition>, options?: LLMCallOptions) => Promise<{
|
|
163
177
|
readonly content: string | null;
|
|
178
|
+
readonly reasoningContent?: string;
|
|
164
179
|
readonly tool_calls?: ReadonlyArray<ToolCall>;
|
|
165
180
|
}>;
|
|
166
181
|
readonly stream?: (messages: ReadonlyArray<Message>, tools: ReadonlyArray<ToolDefinition>, options?: LLMCallOptions) => AsyncGenerator<LLMStreamChunk, void, unknown>;
|
|
@@ -225,6 +240,10 @@ export type LoopStreamChunk = {
|
|
|
225
240
|
readonly type: 'content';
|
|
226
241
|
readonly delta: string;
|
|
227
242
|
readonly turn: number;
|
|
243
|
+
} | {
|
|
244
|
+
readonly type: 'reasoning';
|
|
245
|
+
readonly delta: string;
|
|
246
|
+
readonly turn: number;
|
|
228
247
|
} | {
|
|
229
248
|
readonly type: 'tool_call';
|
|
230
249
|
readonly turn: number;
|
|
@@ -235,6 +254,7 @@ export type LoopStreamChunk = {
|
|
|
235
254
|
readonly callId: string;
|
|
236
255
|
readonly toolName: string;
|
|
237
256
|
readonly content: string;
|
|
257
|
+
readonly frontendData?: unknown;
|
|
238
258
|
readonly status: HarnessRecordStatus;
|
|
239
259
|
} | {
|
|
240
260
|
readonly type: 'turn_end';
|
|
@@ -80,6 +80,7 @@ class BailianProvider {
|
|
|
80
80
|
const choice = data.choices[0];
|
|
81
81
|
return {
|
|
82
82
|
content: choice.message.content,
|
|
83
|
+
reasoningContent: choice.message.reasoning_content,
|
|
83
84
|
usage: data.usage
|
|
84
85
|
? {
|
|
85
86
|
promptTokens: data.usage.prompt_tokens,
|
|
@@ -152,6 +153,9 @@ class BailianProvider {
|
|
|
152
153
|
if (!choice)
|
|
153
154
|
continue;
|
|
154
155
|
const delta = choice.delta;
|
|
156
|
+
if (delta.reasoning_content) {
|
|
157
|
+
yield yield __await({ type: 'reasoning', delta: delta.reasoning_content });
|
|
158
|
+
}
|
|
155
159
|
if (delta.content) {
|
|
156
160
|
yield yield __await({ type: 'content', delta: delta.content });
|
|
157
161
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
export interface OpenAIChatMessage {
|
|
6
6
|
role: string;
|
|
7
7
|
content: string | null;
|
|
8
|
+
reasoning_content?: string;
|
|
8
9
|
tool_calls?: Array<{
|
|
9
10
|
id: string;
|
|
10
11
|
type: 'function';
|
|
@@ -42,6 +43,7 @@ export interface OpenAIChatResponse {
|
|
|
42
43
|
choices: Array<{
|
|
43
44
|
message: {
|
|
44
45
|
content: string | null;
|
|
46
|
+
reasoning_content?: string;
|
|
45
47
|
tool_calls?: Array<{
|
|
46
48
|
id: string;
|
|
47
49
|
type: 'function';
|
|
@@ -22,6 +22,7 @@ export interface LLMRequest {
|
|
|
22
22
|
*/
|
|
23
23
|
export interface LLMResponse {
|
|
24
24
|
readonly content: string | null;
|
|
25
|
+
readonly reasoningContent?: string;
|
|
25
26
|
readonly usage?: {
|
|
26
27
|
readonly promptTokens: number;
|
|
27
28
|
readonly completionTokens: number;
|
|
@@ -35,6 +36,9 @@ export interface LLMResponse {
|
|
|
35
36
|
export type StreamChunk = {
|
|
36
37
|
readonly type: 'content';
|
|
37
38
|
readonly delta: string;
|
|
39
|
+
} | {
|
|
40
|
+
readonly type: 'reasoning';
|
|
41
|
+
readonly delta: string;
|
|
38
42
|
} | {
|
|
39
43
|
readonly type: 'finish';
|
|
40
44
|
usage?: LLMResponse['usage'];
|