@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 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(支持 reasoning 内容)
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
- | `content` | LLM 输出 content 增量 | `delta`, `turn` |
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
- | 需要展示模型 reasoning 过程 | `runLoopStream`(content 增量中包含 reasoning |
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 _k = 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; _k = true) {
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
- _k = false;
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 (!_k && !_a && (_b = stream_1.return)) yield __await(_b.call(stream_1));
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'];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keo-ai/axiom",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "基于 LLM 的预测与推理库,支持多 Provider 切换",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",