@codehz/ai 0.2.1 → 0.2.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codehz/ai",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "type": "module",
5
5
  "module": "dist/index.mjs",
6
6
  "exports": {
@@ -458,9 +458,7 @@ export class ChatCompletionsAdapter extends AdapterBase {
458
458
  if (hasMessageStarted) {
459
459
  const message = messageItem([textBlock(accumulatedContent)], { id: currentMessageId });
460
460
  events.push(factory.messageCompleted(currentMessageId));
461
- if (accumulatedContent) {
462
- output.push(message);
463
- }
461
+ output.push(message);
464
462
  }
465
463
 
466
464
  for (const pending of finalizedToolCalls) {
@@ -599,12 +597,6 @@ export class ChatCompletionsAdapter extends AdapterBase {
599
597
  accumulatedContent = "";
600
598
  };
601
599
 
602
- // 处理 role: assistant(首块标识;不要求 content)
603
- if (delta.role === "assistant" && !hasMessageStarted) {
604
- ensureMessageStarted();
605
- yield factory.messageStarted(currentMessageId);
606
- }
607
-
608
600
  // 处理 third-party reasoning delta
609
601
  if (reasoningDeltas.length > 0) {
610
602
  if (!hasReasoningStarted) {
@@ -78,6 +78,8 @@ export interface AggregatorState {
78
78
  completed: boolean;
79
79
  nextSequence?: number;
80
80
  activeItems: Map<string, ActiveItem>;
81
+ itemOrder: string[];
82
+ completedItems: Map<string, OutputItem>;
81
83
 
82
84
  /** adapter 在 response.completed 中提供的 replay */
83
85
  replayFromAdapter?: import("../types/index.js").ReplayItem[];
@@ -96,6 +98,8 @@ export function createAggregatorState(): AggregatorState {
96
98
  started: false,
97
99
  completed: false,
98
100
  activeItems: new Map(),
101
+ itemOrder: [],
102
+ completedItems: new Map(),
99
103
  };
100
104
  }
101
105
 
@@ -178,6 +182,7 @@ function handleMessageStarted(state: AggregatorState, event: AIStreamEvent & { t
178
182
  role: event.item.role,
179
183
  content: [],
180
184
  });
185
+ state.itemOrder.push(id);
181
186
  }
182
187
 
183
188
  function handleMessageDelta(state: AggregatorState, event: AIStreamEvent & { type: "message.delta" }): void {
@@ -189,7 +194,7 @@ function handleMessageCompleted(state: AggregatorState, event: AIStreamEvent & {
189
194
  const active = getActiveItem(state, event.itemId, "message") as ActiveMessage;
190
195
  state.activeItems.delete(event.itemId);
191
196
  const item = finalizeMessage(active);
192
- state.output.push(item);
197
+ state.completedItems.set(event.itemId, item);
193
198
  pushMessageText(state, item);
194
199
  }
195
200
 
@@ -204,6 +209,7 @@ function handleReasoningStarted(state: AggregatorState, event: AIStreamEvent & {
204
209
  visibility: event.item.visibility,
205
210
  content: [],
206
211
  });
212
+ state.itemOrder.push(id);
207
213
  }
208
214
 
209
215
  function handleReasoningDelta(state: AggregatorState, event: AIStreamEvent & { type: "reasoning.delta" }): void {
@@ -217,7 +223,7 @@ function handleReasoningCompleted(
217
223
  ): void {
218
224
  const active = getActiveItem(state, event.itemId, "reasoning") as ActiveReasoning;
219
225
  state.activeItems.delete(event.itemId);
220
- state.output.push(finalizeReasoning(active));
226
+ state.completedItems.set(event.itemId, finalizeReasoning(active));
221
227
  }
222
228
 
223
229
  function handleToolCallStarted(state: AggregatorState, event: AIStreamEvent & { type: "tool_call.started" }): void {
@@ -231,6 +237,7 @@ function handleToolCallStarted(state: AggregatorState, event: AIStreamEvent & {
231
237
  name: event.item.name,
232
238
  argumentsText: "",
233
239
  });
240
+ state.itemOrder.push(id);
234
241
  }
235
242
 
236
243
  function handleToolCallDelta(state: AggregatorState, event: AIStreamEvent & { type: "tool_call.delta" }): void {
@@ -244,7 +251,7 @@ function handleToolCallCompleted(state: AggregatorState, event: AIStreamEvent &
244
251
  const active = getActiveItem(state, event.itemId, "tool_call") as ActiveToolCall;
245
252
  state.activeItems.delete(event.itemId);
246
253
  const item = finalizeToolCall(active);
247
- state.output.push(item);
254
+ state.completedItems.set(event.itemId, item);
248
255
  state.toolCalls.push(item);
249
256
  }
250
257
 
@@ -275,10 +282,17 @@ function buildResponse(state: AggregatorState): AIResponse {
275
282
  metadataSources: backendFromCompleted?.metadataSources,
276
283
  warnings: backendFromCompleted?.warnings,
277
284
  };
285
+ const orderedOutput = state.itemOrder.map((id) => {
286
+ const item = state.completedItems.get(id);
287
+ if (!item) {
288
+ throw streamProtocolError(`Item ${id} was started but not completed`);
289
+ }
290
+ return item;
291
+ });
278
292
 
279
293
  return {
280
294
  id: state.responseId,
281
- output: state.output,
295
+ output: [...orderedOutput, ...state.output],
282
296
  replay: state.replayFromAdapter ?? [],
283
297
  text: state.textParts.join(""),
284
298
  toolCalls: state.toolCalls,