@agentica/core 0.44.1 → 0.45.0-dev.20260426

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.
Files changed (68) hide show
  1. package/lib/events/AgenticaCallEvent.d.ts +2 -1
  2. package/lib/events/AgenticaCancelEvent.d.ts +2 -1
  3. package/lib/events/AgenticaExecuteEvent.d.ts +2 -1
  4. package/lib/events/AgenticaSelectEvent.d.ts +2 -1
  5. package/lib/factory/events.d.ts +5 -0
  6. package/lib/factory/events.js +9 -0
  7. package/lib/factory/events.js.map +1 -1
  8. package/lib/factory/histories.js +11 -4
  9. package/lib/factory/histories.js.map +1 -1
  10. package/lib/factory/histories.spec.d.ts +1 -0
  11. package/lib/factory/histories.spec.js +34 -0
  12. package/lib/factory/histories.spec.js.map +1 -0
  13. package/lib/histories/AgenticaCancelHistory.d.ts +2 -1
  14. package/lib/histories/AgenticaExecuteHistory.d.ts +2 -1
  15. package/lib/histories/AgenticaSelectHistory.d.ts +2 -1
  16. package/lib/histories/contents/AgenticaCallReasoningPayload.d.ts +26 -0
  17. package/lib/histories/contents/AgenticaCallReasoningPayload.js +3 -0
  18. package/lib/histories/contents/AgenticaCallReasoningPayload.js.map +1 -0
  19. package/lib/histories/contents/index.d.ts +1 -0
  20. package/lib/histories/contents/index.js +1 -0
  21. package/lib/histories/contents/index.js.map +1 -1
  22. package/lib/index.mjs +136 -49
  23. package/lib/index.mjs.map +1 -1
  24. package/lib/json/IAgenticaEventJson.d.ts +5 -4
  25. package/lib/json/IAgenticaHistoryJson.d.ts +4 -3
  26. package/lib/orchestrate/call.js +27 -11
  27. package/lib/orchestrate/call.js.map +1 -1
  28. package/lib/orchestrate/cancel.js +3 -1
  29. package/lib/orchestrate/cancel.js.map +1 -1
  30. package/lib/orchestrate/internal/cancelFunctionFromContext.js +2 -1
  31. package/lib/orchestrate/internal/cancelFunctionFromContext.js.map +1 -1
  32. package/lib/orchestrate/internal/selectFunctionFromContext.js +2 -1
  33. package/lib/orchestrate/internal/selectFunctionFromContext.js.map +1 -1
  34. package/lib/orchestrate/select.js +3 -1
  35. package/lib/orchestrate/select.js.map +1 -1
  36. package/lib/transformers/transformHistory.js +3 -0
  37. package/lib/transformers/transformHistory.js.map +1 -1
  38. package/lib/utils/ChatGptAssistantMessageUtil.d.ts +10 -0
  39. package/lib/utils/ChatGptAssistantMessageUtil.js +36 -0
  40. package/lib/utils/ChatGptAssistantMessageUtil.js.map +1 -0
  41. package/lib/utils/ChatGptCompletionMessageUtil.js +33 -15
  42. package/lib/utils/ChatGptCompletionMessageUtil.js.map +1 -1
  43. package/lib/utils/ChatGptCompletionMessageUtil.spec.js +27 -0
  44. package/lib/utils/ChatGptCompletionMessageUtil.spec.js.map +1 -1
  45. package/package.json +1 -1
  46. package/src/events/AgenticaCallEvent.ts +2 -1
  47. package/src/events/AgenticaCancelEvent.ts +2 -1
  48. package/src/events/AgenticaExecuteEvent.ts +2 -1
  49. package/src/events/AgenticaSelectEvent.ts +2 -1
  50. package/src/factory/events.ts +14 -0
  51. package/src/factory/histories.spec.ts +34 -0
  52. package/src/factory/histories.ts +16 -4
  53. package/src/histories/AgenticaCancelHistory.ts +2 -1
  54. package/src/histories/AgenticaExecuteHistory.ts +2 -1
  55. package/src/histories/AgenticaSelectHistory.ts +2 -1
  56. package/src/histories/contents/AgenticaCallReasoningPayload.ts +26 -0
  57. package/src/histories/contents/index.ts +1 -0
  58. package/src/json/IAgenticaEventJson.ts +5 -4
  59. package/src/json/IAgenticaHistoryJson.ts +4 -3
  60. package/src/orchestrate/call.ts +28 -4
  61. package/src/orchestrate/cancel.ts +7 -1
  62. package/src/orchestrate/internal/cancelFunctionFromContext.ts +3 -0
  63. package/src/orchestrate/internal/selectFunctionFromContext.ts +3 -0
  64. package/src/orchestrate/select.ts +7 -1
  65. package/src/transformers/transformHistory.ts +3 -0
  66. package/src/utils/ChatGptAssistantMessageUtil.ts +47 -0
  67. package/src/utils/ChatGptCompletionMessageUtil.spec.ts +30 -0
  68. package/src/utils/ChatGptCompletionMessageUtil.ts +31 -15
@@ -1,6 +1,7 @@
1
1
  import type { tags } from "typia";
2
2
 
3
3
  import type { AgenticaUserMessageContent } from "../histories";
4
+ import type { AgenticaCallReasoningPayload } from "../histories/contents/AgenticaCallReasoningPayload";
4
5
 
5
6
  import type { IAgenticaOperationJson } from "./IAgenticaOperationJson";
6
7
  import type { IAgenticaOperationSelectionJson } from "./IAgenticaOperationSelectionJson";
@@ -78,7 +79,7 @@ export namespace IAgenticaHistoryJson {
78
79
  *
79
80
  * Selection prompt about candidate functions to call.
80
81
  */
81
- export interface ISelect extends IBase<"select"> {
82
+ export interface ISelect extends IBase<"select">, AgenticaCallReasoningPayload {
82
83
  /**
83
84
  * Operations that have been selected.
84
85
  */
@@ -90,7 +91,7 @@ export namespace IAgenticaHistoryJson {
90
91
  *
91
92
  * Cancellation prompt about the candidate functions to be discarded.
92
93
  */
93
- export interface ICancel extends IBase<"cancel"> {
94
+ export interface ICancel extends IBase<"cancel">, AgenticaCallReasoningPayload {
94
95
  /**
95
96
  * Operations that have been cancelled.
96
97
  */
@@ -102,7 +103,7 @@ export namespace IAgenticaHistoryJson {
102
103
  *
103
104
  * Execution prompt about the LLM function calling.
104
105
  */
105
- export interface IExecute extends IBase<"execute"> {
106
+ export interface IExecute extends IBase<"execute">, AgenticaCallReasoningPayload {
106
107
  /**
107
108
  * Target operation to call.
108
109
  */
@@ -14,6 +14,7 @@ import type { AgenticaAssistantMessageEvent, AgenticaValidateEvent } from "../ev
14
14
  import type { AgenticaCallEvent } from "../events/AgenticaCallEvent";
15
15
  import type { AgenticaExecuteEvent } from "../events/AgenticaExecuteEvent";
16
16
  import type { AgenticaJsonParseErrorEvent } from "../events/AgenticaJsonParseErrorEvent";
17
+ import type { AgenticaCallReasoningPayload } from "../histories/contents/AgenticaCallReasoningPayload";
17
18
  import type { MicroAgenticaHistory } from "../histories/MicroAgenticaHistory";
18
19
 
19
20
  import { AgenticaConstant } from "../constants/AgenticaConstant";
@@ -26,6 +27,7 @@ import { createAssistantMessageEvent, createCallEvent, createExecuteEvent, creat
26
27
  import { decodeHistory, decodeUserMessageContent } from "../factory/histories";
27
28
  import { __get_retry } from "../utils/__retry";
28
29
  import { AssistantMessageEmptyError, AssistantMessageEmptyWithReasoningError } from "../utils/AssistantMessageEmptyError";
30
+ import { ChatGptAssistantMessageUtil } from "../utils/ChatGptAssistantMessageUtil";
29
31
  import { ChatGptCompletionMessageUtil } from "../utils/ChatGptCompletionMessageUtil";
30
32
  import { reduceStreamingWithDispatch } from "../utils/ChatGptCompletionStreamingUtil";
31
33
  import { StreamUtil, toAsyncGenerator } from "../utils/StreamUtil";
@@ -133,6 +135,10 @@ export async function call(
133
135
 
134
136
  const retry: number = ctx.config?.retry ?? AgenticaConstant.RETRY;
135
137
  for (const choice of (completion.choices ?? [])) {
138
+ const assistant = ChatGptAssistantMessageUtil.collect(choice.message);
139
+ const reasoning: AgenticaCallReasoningPayload | undefined = assistant === undefined
140
+ ? undefined
141
+ : { assistant };
136
142
  for (const tc of choice.message.tool_calls ?? []) {
137
143
  if (tc.type === "function") {
138
144
  const operation: AgenticaOperation | undefined = operations.find(
@@ -145,6 +151,7 @@ export async function call(
145
151
  ctx,
146
152
  operation,
147
153
  tc,
154
+ reasoning,
148
155
  [],
149
156
  retry,
150
157
  );
@@ -166,6 +173,7 @@ async function predicate(
166
173
  ctx: AgenticaContext | MicroAgenticaContext,
167
174
  operation: AgenticaOperation,
168
175
  toolCall: OpenAI.ChatCompletionMessageFunctionToolCall,
176
+ reasoning: AgenticaCallReasoningPayload | undefined,
169
177
  previousValidationErrors: AgenticaValidateEvent[],
170
178
  life: number,
171
179
  ): Promise<AgenticaExecuteEvent> {
@@ -174,11 +182,12 @@ async function predicate(
174
182
  = parseArguments(
175
183
  operation,
176
184
  toolCall,
185
+ reasoning,
177
186
  life,
178
187
  );
179
188
  await ctx.dispatch(call);
180
189
  if (call.type === "jsonParseError") {
181
- return correctJsonError(ctx, toolCall, call, previousValidationErrors, life - 1);
190
+ return correctJsonError(ctx, toolCall, reasoning, call, previousValidationErrors, life - 1);
182
191
  }
183
192
 
184
193
  // CHECK TYPE VALIDATION
@@ -224,11 +233,13 @@ async function correctTypeError(
224
233
  errors: validateEvent.result.errors,
225
234
  }),
226
235
  success: false,
236
+ assistant: callEvent.assistant,
227
237
  }),
228
238
  operation: callEvent.operation,
229
239
  toolCall: {
230
240
  id: callEvent.id,
231
241
  arguments: JSON.stringify(callEvent.arguments),
242
+ assistant: callEvent.assistant,
232
243
  result: [
233
244
  "🚨 VALIDATION FAILURE: Your function arguments do not conform to the required schema.",
234
245
  "",
@@ -269,6 +280,7 @@ async function correctTypeError(
269
280
  async function correctJsonError(
270
281
  ctx: AgenticaContext | MicroAgenticaContext,
271
282
  toolCall: OpenAI.ChatCompletionMessageFunctionToolCall,
283
+ reasoning: AgenticaCallReasoningPayload | undefined,
272
284
  parseErrorEvent: AgenticaJsonParseErrorEvent,
273
285
  previousValidationErrors: AgenticaValidateEvent[],
274
286
  life: number,
@@ -280,11 +292,13 @@ async function correctJsonError(
280
292
  arguments: {},
281
293
  value: new AgenticaJsonParseError(parseErrorEvent.failure),
282
294
  success: false,
295
+ assistant: reasoning?.assistant,
283
296
  }),
284
297
  operation: parseErrorEvent.operation,
285
298
  toolCall: {
286
299
  id: parseErrorEvent.id,
287
300
  arguments: parseErrorEvent.failure.input,
301
+ assistant: reasoning?.assistant,
288
302
  result: dedent`
289
303
  Invalid JSON format.
290
304
 
@@ -316,6 +330,7 @@ async function correctJsonError(
316
330
  function parseArguments(
317
331
  operation: AgenticaOperation,
318
332
  toolCall: OpenAI.ChatCompletionMessageFunctionToolCall,
333
+ reasoning: AgenticaCallReasoningPayload | undefined,
319
334
  life: number,
320
335
  ): AgenticaCallEvent | AgenticaJsonParseErrorEvent {
321
336
  const result: IJsonParseResult<Record<string, unknown>> = operation.function.parse(
@@ -333,6 +348,7 @@ function parseArguments(
333
348
  id: toolCall.id,
334
349
  operation,
335
350
  arguments: result.data,
351
+ assistant: reasoning?.assistant,
336
352
  });
337
353
  }
338
354
 
@@ -344,6 +360,7 @@ async function correctError(
344
360
  toolCall: {
345
361
  id: string;
346
362
  arguments: string;
363
+ assistant?: AgenticaCallReasoningPayload["assistant"];
347
364
  result: string;
348
365
  };
349
366
  systemPrompt: string;
@@ -371,7 +388,7 @@ async function correctError(
371
388
  ctx.config?.systemPrompt?.execute?.(ctx.histories as MicroAgenticaHistory[])
372
389
  ?? AgenticaSystemPrompt.EXECUTE,
373
390
  },
374
- {
391
+ ChatGptAssistantMessageUtil.assign({
375
392
  role: "assistant",
376
393
  tool_calls: [
377
394
  {
@@ -383,7 +400,7 @@ async function correctError(
383
400
  },
384
401
  } satisfies OpenAI.ChatCompletionMessageFunctionToolCall,
385
402
  ],
386
- } satisfies OpenAI.ChatCompletionAssistantMessageParam,
403
+ } satisfies OpenAI.ChatCompletionAssistantMessageParam, props.toolCall.assistant),
387
404
  {
388
405
  role: "tool",
389
406
  content: props.toolCall.result,
@@ -425,7 +442,8 @@ async function correctError(
425
442
  return ChatGptCompletionMessageUtil.merge(await StreamUtil.readAll(result.value));
426
443
  })();
427
444
 
428
- const toolCall: OpenAI.ChatCompletionMessageFunctionToolCall | undefined = completion.choices?.[0]?.message.tool_calls?.filter(
445
+ const choice = completion.choices?.[0];
446
+ const toolCall: OpenAI.ChatCompletionMessageFunctionToolCall | undefined = choice?.message.tool_calls?.filter(
429
447
  tc => tc.type === "function",
430
448
  ).find(
431
449
  s => s.function.name === props.operation.name,
@@ -437,10 +455,14 @@ async function correctError(
437
455
  life: props.life - 1,
438
456
  });
439
457
  }
458
+ const assistant = choice === undefined
459
+ ? undefined
460
+ : ChatGptAssistantMessageUtil.collect(choice.message);
440
461
  return predicate(
441
462
  ctx,
442
463
  props.operation,
443
464
  toolCall,
465
+ assistant === undefined ? undefined : { assistant },
444
466
  props.previousValidationErrors,
445
467
  props.life,
446
468
  );
@@ -473,6 +495,7 @@ async function executeFunction(
473
495
  arguments: call.arguments,
474
496
  value,
475
497
  success: true,
498
+ assistant: call.assistant,
476
499
  });
477
500
  }
478
501
  catch (error) {
@@ -489,6 +512,7 @@ async function executeFunction(
489
512
  }
490
513
  : error,
491
514
  success: false,
515
+ assistant: call.assistant,
492
516
  });
493
517
  }
494
518
  }
@@ -15,6 +15,7 @@ import { AgenticaConstant } from "../constants/AgenticaConstant";
15
15
  import { AgenticaDefaultPrompt } from "../constants/AgenticaDefaultPrompt";
16
16
  import { AgenticaSystemPrompt } from "../constants/AgenticaSystemPrompt";
17
17
  import { decodeHistory, decodeUserMessageContent } from "../factory/histories";
18
+ import { ChatGptAssistantMessageUtil } from "../utils/ChatGptAssistantMessageUtil";
18
19
  import { ChatGptCompletionMessageUtil } from "../utils/ChatGptCompletionMessageUtil";
19
20
  import { StreamUtil } from "../utils/StreamUtil";
20
21
 
@@ -205,6 +206,7 @@ async function step(
205
206
  // PROCESS COMPLETION
206
207
  // ----
207
208
  for (const choice of (completion.choices ?? [])) {
209
+ const assistant = ChatGptAssistantMessageUtil.collect(choice.message);
208
210
  // TOOL CALLING HANDLER
209
211
  if (choice.message.tool_calls != null) {
210
212
  for (const tc of choice.message.tool_calls) {
@@ -224,7 +226,11 @@ async function step(
224
226
  }
225
227
 
226
228
  for (const reference of input.functions) {
227
- cancelFunctionFromContext(ctx, reference);
229
+ cancelFunctionFromContext(
230
+ ctx,
231
+ reference,
232
+ assistant === undefined ? undefined : { assistant },
233
+ );
228
234
  }
229
235
  }
230
236
  }
@@ -2,6 +2,7 @@ import type { AgenticaContext } from "../../context/AgenticaContext";
2
2
  import type { AgenticaOperationSelection } from "../../context/AgenticaOperationSelection";
3
3
  import type { __IChatFunctionReference } from "../../context/internal/__IChatFunctionReference";
4
4
  import type { AgenticaCancelEvent } from "../../events";
5
+ import type { AgenticaCallReasoningPayload } from "../../histories/contents/AgenticaCallReasoningPayload";
5
6
 
6
7
  import { createCancelEvent } from "../../factory/events";
7
8
  import { createOperationSelection } from "../../factory/operations";
@@ -12,6 +13,7 @@ import { createOperationSelection } from "../../factory/operations";
12
13
  export function cancelFunctionFromContext(
13
14
  ctx: AgenticaContext,
14
15
  reference: __IChatFunctionReference,
16
+ reasoning?: AgenticaCallReasoningPayload,
15
17
  ): void {
16
18
  const index: number = ctx.stack.findIndex(
17
19
  item => item.operation.name === reference.name,
@@ -28,6 +30,7 @@ export function cancelFunctionFromContext(
28
30
  operation: item.operation,
29
31
  reason: reference.reason,
30
32
  }),
33
+ assistant: reasoning?.assistant,
31
34
  });
32
35
  void ctx.dispatch(event).catch(() => {});
33
36
  }
@@ -3,6 +3,7 @@ import type { AgenticaOperation } from "../../context/AgenticaOperation";
3
3
  import type { AgenticaOperationSelection } from "../../context/AgenticaOperationSelection";
4
4
  import type { __IChatFunctionReference } from "../../context/internal/__IChatFunctionReference";
5
5
  import type { AgenticaSelectEvent } from "../../events/AgenticaSelectEvent";
6
+ import type { AgenticaCallReasoningPayload } from "../../histories/contents/AgenticaCallReasoningPayload";
6
7
 
7
8
  import { createSelectEvent } from "../../factory/events";
8
9
  import { createOperationSelection } from "../../factory/operations";
@@ -13,6 +14,7 @@ import { createOperationSelection } from "../../factory/operations";
13
14
  export function selectFunctionFromContext(
14
15
  ctx: AgenticaContext,
15
16
  reference: __IChatFunctionReference,
17
+ reasoning?: AgenticaCallReasoningPayload,
16
18
  ): void {
17
19
  const operation: AgenticaOperation | undefined
18
20
  = ctx.operations.flat.get(reference.name);
@@ -29,6 +31,7 @@ export function selectFunctionFromContext(
29
31
 
30
32
  const event: AgenticaSelectEvent = createSelectEvent({
31
33
  selection,
34
+ assistant: reasoning?.assistant,
32
35
  });
33
36
  void ctx.dispatch(event).catch(() => {});
34
37
  }
@@ -18,6 +18,7 @@ import { createAssistantMessageEvent } from "../factory/events";
18
18
  import { decodeHistory, decodeUserMessageContent } from "../factory/histories";
19
19
  import { __get_retry } from "../utils/__retry";
20
20
  import { AssistantMessageEmptyError, AssistantMessageEmptyWithReasoningError } from "../utils/AssistantMessageEmptyError";
21
+ import { ChatGptAssistantMessageUtil } from "../utils/ChatGptAssistantMessageUtil";
21
22
  import { reduceStreamingWithDispatch } from "../utils/ChatGptCompletionStreamingUtil";
22
23
  import { toAsyncGenerator } from "../utils/StreamUtil";
23
24
 
@@ -261,6 +262,7 @@ async function step(
261
262
  // PROCESS COMPLETION
262
263
  // ----
263
264
  for (const choice of (completion.choices ?? [])) {
265
+ const assistant = ChatGptAssistantMessageUtil.collect(choice.message);
264
266
  // FUNCTION CALLING
265
267
  if (choice.message.tool_calls != null) {
266
268
  for (const tc of choice.message.tool_calls) {
@@ -279,7 +281,11 @@ async function step(
279
281
  continue;
280
282
  }
281
283
  for (const reference of input.functions) {
282
- selectFunctionFromContext(ctx, reference);
284
+ selectFunctionFromContext(
285
+ ctx,
286
+ reference,
287
+ assistant === undefined ? undefined : { assistant },
288
+ );
283
289
  }
284
290
  }
285
291
  }
@@ -95,6 +95,7 @@ function transformSelect(props: {
95
95
  }),
96
96
  reason: props.history.selection.reason,
97
97
  }),
98
+ assistant: props.history.assistant,
98
99
  });
99
100
  }
100
101
 
@@ -112,6 +113,7 @@ function transformCancel(props: {
112
113
  }),
113
114
  reason: props.history.selection.reason,
114
115
  }),
116
+ assistant: props.history.assistant,
115
117
  });
116
118
  }
117
119
 
@@ -133,6 +135,7 @@ function transformExecute(props: {
133
135
  */
134
136
  value: props.history.value as Record<string, unknown>,
135
137
  success: props.history.success,
138
+ assistant: props.history.assistant,
136
139
  });
137
140
  }
138
141
 
@@ -0,0 +1,47 @@
1
+ import type OpenAI from "openai";
2
+
3
+ function isRecord(value: unknown): value is Record<string, unknown> {
4
+ return value != null && typeof value === "object" && Array.isArray(value) === false;
5
+ }
6
+
7
+ function collect(source: unknown): Record<string, unknown> | undefined {
8
+ if (isRecord(source) === false) {
9
+ return undefined;
10
+ }
11
+ const output: Record<string, unknown> = {};
12
+ for (const [key, value] of Object.entries(source)) {
13
+ if (key.startsWith("reasoning") && value !== undefined) {
14
+ output[key] = value;
15
+ }
16
+ }
17
+ return Object.keys(output).length === 0
18
+ ? undefined
19
+ : output;
20
+ }
21
+
22
+ function assign<Message extends OpenAI.ChatCompletionAssistantMessageParam>(
23
+ message: Message,
24
+ payload: Record<string, unknown> | undefined,
25
+ ): Message {
26
+ const collected = collect(payload);
27
+ if (collected === undefined) {
28
+ return message;
29
+ }
30
+ return {
31
+ ...message,
32
+ ...collected,
33
+ };
34
+ }
35
+
36
+ function assignFrom<Message extends OpenAI.ChatCompletionAssistantMessageParam>(
37
+ message: Message,
38
+ source: unknown,
39
+ ): Message {
40
+ return assign(message, collect(source));
41
+ }
42
+
43
+ export const ChatGptAssistantMessageUtil = {
44
+ assign,
45
+ assignFrom,
46
+ collect,
47
+ };
@@ -264,6 +264,36 @@ describe("chatGptCompletionMessageUtil", () => {
264
264
  const result = ChatGptCompletionMessageUtil.mergeChoice(acc, cur);
265
265
  expect(result.message.refusal).toBe("I cannot do that");
266
266
  });
267
+
268
+ it("should merge reasoning payloads", () => {
269
+ const acc: ChatCompletion.Choice = {
270
+ index: 0,
271
+ message: {
272
+ role: "assistant",
273
+ content: null,
274
+ reasoning: "think",
275
+ reasoning_content: "deep",
276
+ reasoning_details: [{ index: 0 }],
277
+ } as any,
278
+ } as any;
279
+
280
+ const cur: ChatCompletionChunk.Choice = {
281
+ index: 0,
282
+ delta: {
283
+ reasoning: " more",
284
+ reasoning_content: " seek",
285
+ reasoning_details: [{ index: 1 }],
286
+ } as any,
287
+ } as any;
288
+
289
+ const result = ChatGptCompletionMessageUtil.mergeChoice(acc, cur);
290
+ expect((result.message as { reasoning?: string }).reasoning).toBe("think more");
291
+ expect((result.message as { reasoning_content?: string }).reasoning_content).toBe("deep seek");
292
+ expect((result.message as { reasoning_details?: unknown[] }).reasoning_details).toEqual([
293
+ { index: 0 },
294
+ { index: 1 },
295
+ ]);
296
+ });
267
297
  });
268
298
 
269
299
  describe("mergeToolCalls", () => {
@@ -11,6 +11,7 @@ import { dedent, LlmJson } from "@typia/utils";
11
11
 
12
12
  // import typia from "typia";
13
13
  import { ByteArrayUtil } from "./ByteArrayUtil";
14
+ import { ChatGptAssistantMessageUtil } from "./ChatGptAssistantMessageUtil";
14
15
  import { ChatGptTokenUsageAggregator } from "./ChatGptTokenUsageAggregator";
15
16
 
16
17
  function transformCompletionChunk(source: string | Uint8Array): ChatCompletionChunk {
@@ -54,7 +55,7 @@ function accumulate(origin: ChatCompletion, chunk: ChatCompletionChunk): ChatCom
54
55
  ?? (null as unknown as ChatCompletion.Choice["finish_reason"]),
55
56
 
56
57
  logprobs: choice.logprobs ?? null,
57
- message: {
58
+ message: ChatGptAssistantMessageUtil.assignFrom({
58
59
  tool_calls: choice.delta.tool_calls !== undefined
59
60
  ? choice.delta.tool_calls.reduce((acc, cur) => {
60
61
  acc[cur.index] = {
@@ -71,11 +72,7 @@ function accumulate(origin: ChatCompletion, chunk: ChatCompletionChunk): ChatCom
71
72
  content: choice.delta.content ?? null,
72
73
  refusal: choice.delta.refusal ?? null,
73
74
  role: "assistant",
74
- ...({
75
- // for open router
76
- reasoning: (choice.delta as { reasoning?: string }).reasoning ?? null,
77
- }),
78
- } satisfies ChatCompletionMessage,
75
+ } satisfies ChatCompletionMessage, choice.delta),
79
76
  };
80
77
  });
81
78
 
@@ -154,15 +151,7 @@ function mergeChoice(acc: ChatCompletion.Choice, cur: ChatCompletionChunk.Choice
154
151
  }
155
152
  }
156
153
 
157
- // for open router
158
- if ((cur.delta as { reasoning?: string }).reasoning != null) {
159
- if ((acc.message as { reasoning?: string }).reasoning == null) {
160
- (acc.message as { reasoning?: string }).reasoning = (cur.delta as { reasoning?: string }).reasoning;
161
- }
162
- else {
163
- (acc.message as unknown as { reasoning: string }).reasoning += (cur.delta as { reasoning: string }).reasoning;
164
- }
165
- }
154
+ mergeAssistantMessagePayload(acc.message, cur.delta);
166
155
 
167
156
  if (cur.delta.tool_calls != null) {
168
157
  acc.message.tool_calls ??= [];
@@ -201,6 +190,33 @@ function mergeToolCalls(acc: ChatCompletionMessageFunctionToolCall, cur: ChatCom
201
190
  return acc;
202
191
  }
203
192
 
193
+ function mergeAssistantMessagePayload(
194
+ message: ChatCompletionMessage,
195
+ delta: ChatCompletionChunk.Choice.Delta,
196
+ ): void {
197
+ const target = message as unknown as Record<string, unknown>;
198
+ const source = delta as Record<string, unknown>;
199
+ for (const [key, value] of Object.entries(source)) {
200
+ if (key.startsWith("reasoning") === false || value === undefined) {
201
+ continue;
202
+ }
203
+ if (typeof value === "string") {
204
+ target[key] = typeof target[key] === "string"
205
+ ? `${target[key]}${value}`
206
+ : value;
207
+ }
208
+ else if (Array.isArray(value)) {
209
+ target[key] = [
210
+ ...(Array.isArray(target[key]) ? target[key] : []),
211
+ ...value,
212
+ ];
213
+ }
214
+ else {
215
+ target[key] = value;
216
+ }
217
+ }
218
+ }
219
+
204
220
  export const ChatGptCompletionMessageUtil = {
205
221
  transformCompletionChunk,
206
222
  accumulate,