@keo-ai/axiom 0.1.8 → 0.1.9
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 +21 -3
- package/dist/function_call_loop/loop.js +2 -0
- 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 +12 -4
- package/dist/function_call_loop/types.d.ts +10 -0
- 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
|
|
|
@@ -640,6 +645,19 @@ interface LoopResult {
|
|
|
640
645
|
}
|
|
641
646
|
```
|
|
642
647
|
|
|
648
|
+
**Message 中的 reasoningContent**:当使用支持推理的模型(如 DeepSeek-R1、QwQ)时,`messages` 中 `role: 'assistant'` 的条目会包含 `reasoningContent` 字段,记录该轮模型的完整推理过程。该字段会自动保留在对话上下文中,供多轮对话回传。
|
|
649
|
+
|
|
650
|
+
```ts
|
|
651
|
+
const result = await FunctionCallLoop.runLoop(config);
|
|
652
|
+
|
|
653
|
+
for (const msg of result.messages) {
|
|
654
|
+
if (msg.role === 'assistant' && msg.reasoningContent) {
|
|
655
|
+
console.log('[Reasoning]', msg.reasoningContent);
|
|
656
|
+
console.log('[Content]', msg.content);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
```
|
|
660
|
+
|
|
643
661
|
### 错误处理
|
|
644
662
|
|
|
645
663
|
同其他模块:**直接抛异常**。常见场景:
|
|
@@ -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
|
|
@@ -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
|
|
@@ -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
|
}
|
|
@@ -150,9 +151,13 @@ export interface LLMCallOptions {
|
|
|
150
151
|
export type LLMStreamChunk = {
|
|
151
152
|
readonly type: 'content';
|
|
152
153
|
readonly delta: string;
|
|
154
|
+
} | {
|
|
155
|
+
readonly type: 'reasoning';
|
|
156
|
+
readonly delta: string;
|
|
153
157
|
} | {
|
|
154
158
|
readonly type: 'finish';
|
|
155
159
|
readonly content: string | null;
|
|
160
|
+
readonly reasoningContent?: string;
|
|
156
161
|
readonly tool_calls?: ReadonlyArray<ToolCall>;
|
|
157
162
|
};
|
|
158
163
|
/**
|
|
@@ -161,6 +166,7 @@ export type LLMStreamChunk = {
|
|
|
161
166
|
export interface LLMCaller {
|
|
162
167
|
readonly call: (messages: ReadonlyArray<Message>, tools: ReadonlyArray<ToolDefinition>, options?: LLMCallOptions) => Promise<{
|
|
163
168
|
readonly content: string | null;
|
|
169
|
+
readonly reasoningContent?: string;
|
|
164
170
|
readonly tool_calls?: ReadonlyArray<ToolCall>;
|
|
165
171
|
}>;
|
|
166
172
|
readonly stream?: (messages: ReadonlyArray<Message>, tools: ReadonlyArray<ToolDefinition>, options?: LLMCallOptions) => AsyncGenerator<LLMStreamChunk, void, unknown>;
|
|
@@ -225,6 +231,10 @@ export type LoopStreamChunk = {
|
|
|
225
231
|
readonly type: 'content';
|
|
226
232
|
readonly delta: string;
|
|
227
233
|
readonly turn: number;
|
|
234
|
+
} | {
|
|
235
|
+
readonly type: 'reasoning';
|
|
236
|
+
readonly delta: string;
|
|
237
|
+
readonly turn: number;
|
|
228
238
|
} | {
|
|
229
239
|
readonly type: 'tool_call';
|
|
230
240
|
readonly turn: number;
|
|
@@ -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'];
|