@corbat-tech/coco 2.23.0 → 2.23.1

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/dist/index.js CHANGED
@@ -13412,6 +13412,7 @@ var OpenAIProvider = class {
13412
13412
  requestParams
13413
13413
  );
13414
13414
  const toolCallBuilders = /* @__PURE__ */ new Map();
13415
+ let lastToolCallKey = null;
13415
13416
  const streamTimeout = this.config.timeout ?? 12e4;
13416
13417
  let lastActivityTime = Date.now();
13417
13418
  const timeoutController = new AbortController();
@@ -13461,9 +13462,9 @@ var OpenAIProvider = class {
13461
13462
  }
13462
13463
  if (delta?.tool_calls) {
13463
13464
  for (const toolCallDelta of delta.tool_calls) {
13464
- const index = toolCallDelta.index ?? toolCallBuilders.size;
13465
- if (!toolCallBuilders.has(index)) {
13466
- toolCallBuilders.set(index, {
13465
+ const key = typeof toolCallDelta.index === "number" ? `index:${toolCallDelta.index}` : typeof toolCallDelta.id === "string" && toolCallDelta.id.length > 0 ? `id:${toolCallDelta.id}` : toolCallBuilders.size === 1 ? Array.from(toolCallBuilders.keys())[0] ?? `fallback:${toolCallBuilders.size}` : lastToolCallKey ?? `fallback:${toolCallBuilders.size}`;
13466
+ if (!toolCallBuilders.has(key)) {
13467
+ toolCallBuilders.set(key, {
13467
13468
  id: toolCallDelta.id ?? "",
13468
13469
  name: toolCallDelta.function?.name ?? "",
13469
13470
  arguments: ""
@@ -13476,7 +13477,8 @@ var OpenAIProvider = class {
13476
13477
  }
13477
13478
  };
13478
13479
  }
13479
- const builder = toolCallBuilders.get(index);
13480
+ const builder = toolCallBuilders.get(key);
13481
+ lastToolCallKey = key;
13480
13482
  if (toolCallDelta.id) {
13481
13483
  builder.id = toolCallDelta.id;
13482
13484
  }
@@ -14064,6 +14066,7 @@ var OpenAIProvider = class {
14064
14066
  requestParams
14065
14067
  );
14066
14068
  const fnCallBuilders = /* @__PURE__ */ new Map();
14069
+ const outputIndexToBuilderKey = /* @__PURE__ */ new Map();
14067
14070
  const streamTimeout = this.config.timeout ?? 12e4;
14068
14071
  let lastActivityTime = Date.now();
14069
14072
  const timeoutController = new AbortController();
@@ -14093,8 +14096,11 @@ var OpenAIProvider = class {
14093
14096
  fnCallBuilders.set(itemKey, {
14094
14097
  callId: fc.call_id,
14095
14098
  name: fc.name,
14096
- arguments: ""
14099
+ arguments: fc.arguments ?? ""
14097
14100
  });
14101
+ if (typeof event.output_index === "number") {
14102
+ outputIndexToBuilderKey.set(event.output_index, itemKey);
14103
+ }
14098
14104
  yield {
14099
14105
  type: "tool_use_start",
14100
14106
  toolCall: { id: fc.call_id, name: fc.name }
@@ -14103,7 +14109,9 @@ var OpenAIProvider = class {
14103
14109
  break;
14104
14110
  case "response.function_call_arguments.delta":
14105
14111
  {
14106
- const builder = fnCallBuilders.get(event.item_id);
14112
+ const builderKey = (event.item_id && fnCallBuilders.has(event.item_id) ? event.item_id : null) ?? (typeof event.output_index === "number" ? outputIndexToBuilderKey.get(event.output_index) ?? null : null) ?? (fnCallBuilders.size === 1 ? Array.from(fnCallBuilders.keys())[0] : null);
14113
+ if (!builderKey) break;
14114
+ const builder = fnCallBuilders.get(builderKey);
14107
14115
  if (builder) {
14108
14116
  builder.arguments += event.delta;
14109
14117
  }
@@ -14111,17 +14119,22 @@ var OpenAIProvider = class {
14111
14119
  break;
14112
14120
  case "response.function_call_arguments.done":
14113
14121
  {
14114
- const builder = fnCallBuilders.get(event.item_id);
14122
+ const builderKey = (event.item_id && fnCallBuilders.has(event.item_id) ? event.item_id : null) ?? (typeof event.output_index === "number" ? outputIndexToBuilderKey.get(event.output_index) ?? null : null) ?? (fnCallBuilders.size === 1 ? Array.from(fnCallBuilders.keys())[0] : null);
14123
+ if (!builderKey) break;
14124
+ const builder = fnCallBuilders.get(builderKey);
14115
14125
  if (builder) {
14116
14126
  yield {
14117
14127
  type: "tool_use_end",
14118
14128
  toolCall: {
14119
14129
  id: builder.callId,
14120
14130
  name: builder.name,
14121
- input: this.parseResponsesArguments(event.arguments)
14131
+ input: this.parseResponsesArguments(event.arguments ?? builder.arguments)
14122
14132
  }
14123
14133
  };
14124
- fnCallBuilders.delete(event.item_id);
14134
+ fnCallBuilders.delete(builderKey);
14135
+ for (const [idx, key] of outputIndexToBuilderKey.entries()) {
14136
+ if (key === builderKey) outputIndexToBuilderKey.delete(idx);
14137
+ }
14125
14138
  }
14126
14139
  }
14127
14140
  break;
@@ -14637,6 +14650,7 @@ var CodexProvider = class {
14637
14650
  let outputTokens = 0;
14638
14651
  const toolCalls = [];
14639
14652
  const fnCallBuilders = /* @__PURE__ */ new Map();
14653
+ const outputIndexToBuilderKey = /* @__PURE__ */ new Map();
14640
14654
  await this.readSSEStream(response, (event) => {
14641
14655
  if (event.id) responseId = event.id;
14642
14656
  switch (event.type) {
@@ -14653,25 +14667,35 @@ var CodexProvider = class {
14653
14667
  fnCallBuilders.set(itemKey, {
14654
14668
  callId: item.call_id,
14655
14669
  name: item.name,
14656
- arguments: ""
14670
+ arguments: item.arguments ?? ""
14657
14671
  });
14672
+ if (typeof event.output_index === "number") {
14673
+ outputIndexToBuilderKey.set(event.output_index, itemKey);
14674
+ }
14658
14675
  }
14659
14676
  break;
14660
14677
  }
14661
14678
  case "response.function_call_arguments.delta": {
14662
- const builder = fnCallBuilders.get(event.item_id);
14679
+ const builderKey = (event.item_id && fnCallBuilders.has(event.item_id) ? event.item_id : null) ?? (typeof event.output_index === "number" ? outputIndexToBuilderKey.get(event.output_index) ?? null : null) ?? (fnCallBuilders.size === 1 ? Array.from(fnCallBuilders.keys())[0] : null);
14680
+ if (!builderKey) break;
14681
+ const builder = fnCallBuilders.get(builderKey);
14663
14682
  if (builder) builder.arguments += event.delta ?? "";
14664
14683
  break;
14665
14684
  }
14666
14685
  case "response.function_call_arguments.done": {
14667
- const builder = fnCallBuilders.get(event.item_id);
14686
+ const builderKey = (event.item_id && fnCallBuilders.has(event.item_id) ? event.item_id : null) ?? (typeof event.output_index === "number" ? outputIndexToBuilderKey.get(event.output_index) ?? null : null) ?? (fnCallBuilders.size === 1 ? Array.from(fnCallBuilders.keys())[0] : null);
14687
+ if (!builderKey) break;
14688
+ const builder = fnCallBuilders.get(builderKey);
14668
14689
  if (builder) {
14669
14690
  toolCalls.push({
14670
14691
  id: builder.callId,
14671
14692
  name: builder.name,
14672
- input: parseArguments(event.arguments)
14693
+ input: parseArguments(event.arguments ?? builder.arguments)
14673
14694
  });
14674
- fnCallBuilders.delete(event.item_id);
14695
+ fnCallBuilders.delete(builderKey);
14696
+ for (const [idx, key] of outputIndexToBuilderKey.entries()) {
14697
+ if (key === builderKey) outputIndexToBuilderKey.delete(idx);
14698
+ }
14675
14699
  }
14676
14700
  break;
14677
14701
  }
@@ -14784,6 +14808,7 @@ var CodexProvider = class {
14784
14808
  const decoder = new TextDecoder();
14785
14809
  let buffer = "";
14786
14810
  const fnCallBuilders = /* @__PURE__ */ new Map();
14811
+ const outputIndexToBuilderKey = /* @__PURE__ */ new Map();
14787
14812
  let lastActivityTime = Date.now();
14788
14813
  const timeoutController = new AbortController();
14789
14814
  const timeoutInterval = setInterval(() => {
@@ -14822,8 +14847,11 @@ var CodexProvider = class {
14822
14847
  fnCallBuilders.set(itemKey, {
14823
14848
  callId: item.call_id,
14824
14849
  name: item.name,
14825
- arguments: ""
14850
+ arguments: item.arguments ?? ""
14826
14851
  });
14852
+ if (typeof event.output_index === "number") {
14853
+ outputIndexToBuilderKey.set(event.output_index, itemKey);
14854
+ }
14827
14855
  yield {
14828
14856
  type: "tool_use_start",
14829
14857
  toolCall: { id: item.call_id, name: item.name }
@@ -14832,14 +14860,18 @@ var CodexProvider = class {
14832
14860
  break;
14833
14861
  }
14834
14862
  case "response.function_call_arguments.delta": {
14835
- const builder = fnCallBuilders.get(event.item_id);
14863
+ const builderKey = (event.item_id && fnCallBuilders.has(event.item_id) ? event.item_id : null) ?? (typeof event.output_index === "number" ? outputIndexToBuilderKey.get(event.output_index) ?? null : null) ?? (fnCallBuilders.size === 1 ? Array.from(fnCallBuilders.keys())[0] : null);
14864
+ if (!builderKey) break;
14865
+ const builder = fnCallBuilders.get(builderKey);
14836
14866
  if (builder) {
14837
14867
  builder.arguments += event.delta ?? "";
14838
14868
  }
14839
14869
  break;
14840
14870
  }
14841
14871
  case "response.function_call_arguments.done": {
14842
- const builder = fnCallBuilders.get(event.item_id);
14872
+ const builderKey = (event.item_id && fnCallBuilders.has(event.item_id) ? event.item_id : null) ?? (typeof event.output_index === "number" ? outputIndexToBuilderKey.get(event.output_index) ?? null : null) ?? (fnCallBuilders.size === 1 ? Array.from(fnCallBuilders.keys())[0] : null);
14873
+ if (!builderKey) break;
14874
+ const builder = fnCallBuilders.get(builderKey);
14843
14875
  if (builder) {
14844
14876
  yield {
14845
14877
  type: "tool_use_end",
@@ -14849,7 +14881,10 @@ var CodexProvider = class {
14849
14881
  input: parseArguments(event.arguments ?? builder.arguments)
14850
14882
  }
14851
14883
  };
14852
- fnCallBuilders.delete(event.item_id);
14884
+ fnCallBuilders.delete(builderKey);
14885
+ for (const [idx, key] of outputIndexToBuilderKey.entries()) {
14886
+ if (key === builderKey) outputIndexToBuilderKey.delete(idx);
14887
+ }
14853
14888
  }
14854
14889
  break;
14855
14890
  }
@@ -15222,8 +15257,8 @@ var GeminiProvider = class {
15222
15257
  const { history, lastMessage } = this.convertMessages(messages);
15223
15258
  const chat = model.startChat({ history });
15224
15259
  const result = await chat.sendMessageStream(lastMessage);
15225
- const emittedToolCalls = /* @__PURE__ */ new Set();
15226
15260
  let streamStopReason;
15261
+ let streamToolCallCounter = 0;
15227
15262
  for await (const chunk of result.stream) {
15228
15263
  const text = chunk.text();
15229
15264
  if (text) {
@@ -15238,30 +15273,23 @@ var GeminiProvider = class {
15238
15273
  for (const part of candidate.content.parts) {
15239
15274
  if ("functionCall" in part && part.functionCall) {
15240
15275
  const funcCall = part.functionCall;
15241
- const sortedArgs = funcCall.args ? Object.keys(funcCall.args).sort().map(
15242
- (k) => `${k}:${JSON.stringify(funcCall.args[k])}`
15243
- ).join(",") : "";
15244
- const callKey = `${funcCall.name}-${sortedArgs}`;
15245
- if (!emittedToolCalls.has(callKey)) {
15246
- emittedToolCalls.add(callKey);
15247
- const toolCall = {
15248
- id: funcCall.name,
15249
- // Gemini uses name as ID
15250
- name: funcCall.name,
15251
- input: funcCall.args ?? {}
15252
- };
15253
- yield {
15254
- type: "tool_use_start",
15255
- toolCall: {
15256
- id: toolCall.id,
15257
- name: toolCall.name
15258
- }
15259
- };
15260
- yield {
15261
- type: "tool_use_end",
15262
- toolCall
15263
- };
15264
- }
15276
+ streamToolCallCounter++;
15277
+ const toolCall = {
15278
+ id: `gemini_call_${streamToolCallCounter}`,
15279
+ name: funcCall.name,
15280
+ input: funcCall.args ?? {}
15281
+ };
15282
+ yield {
15283
+ type: "tool_use_start",
15284
+ toolCall: {
15285
+ id: toolCall.id,
15286
+ name: toolCall.name
15287
+ }
15288
+ };
15289
+ yield {
15290
+ type: "tool_use_end",
15291
+ toolCall
15292
+ };
15265
15293
  }
15266
15294
  }
15267
15295
  }
@@ -15336,13 +15364,13 @@ var GeminiProvider = class {
15336
15364
  * Convert messages to Gemini format
15337
15365
  */
15338
15366
  convertMessages(messages) {
15367
+ const toolNameByUseId = this.buildToolUseNameMap(messages);
15368
+ const conversation = messages.filter((m) => m.role !== "system");
15339
15369
  const history = [];
15340
15370
  let lastUserMessage = "";
15341
- for (const msg of messages) {
15342
- if (msg.role === "system") {
15343
- continue;
15344
- }
15345
- const parts = this.convertContent(msg.content);
15371
+ for (let i = 0; i < conversation.length; i++) {
15372
+ const msg = conversation[i];
15373
+ const isLastMessage = i === conversation.length - 1;
15346
15374
  if (msg.role === "user") {
15347
15375
  if (Array.isArray(msg.content) && msg.content[0]?.type === "tool_result") {
15348
15376
  const functionResponses = [];
@@ -15351,23 +15379,49 @@ var GeminiProvider = class {
15351
15379
  const toolResult = block;
15352
15380
  functionResponses.push({
15353
15381
  functionResponse: {
15354
- name: toolResult.tool_use_id,
15355
- // Gemini uses name, we store it in tool_use_id
15382
+ // Gemini expects the function name in functionResponse.name.
15383
+ // Recover it from prior assistant tool_use blocks when possible.
15384
+ name: toolNameByUseId.get(toolResult.tool_use_id) ?? toolResult.tool_use_id,
15356
15385
  response: { result: toolResult.content }
15357
15386
  }
15358
15387
  });
15359
15388
  }
15360
15389
  }
15361
- history.push({ role: "user", parts: functionResponses });
15390
+ if (isLastMessage) {
15391
+ lastUserMessage = functionResponses;
15392
+ } else {
15393
+ history.push({ role: "user", parts: functionResponses });
15394
+ }
15362
15395
  } else {
15363
- lastUserMessage = parts;
15396
+ const parts = this.convertContent(msg.content);
15397
+ if (isLastMessage) {
15398
+ lastUserMessage = parts;
15399
+ } else {
15400
+ history.push({ role: "user", parts });
15401
+ }
15364
15402
  }
15365
15403
  } else if (msg.role === "assistant") {
15404
+ const parts = this.convertContent(msg.content);
15366
15405
  history.push({ role: "model", parts });
15367
15406
  }
15368
15407
  }
15369
15408
  return { history, lastMessage: lastUserMessage };
15370
15409
  }
15410
+ /**
15411
+ * Build a map from tool_use IDs to function names from assistant history.
15412
+ */
15413
+ buildToolUseNameMap(messages) {
15414
+ const map = /* @__PURE__ */ new Map();
15415
+ for (const msg of messages) {
15416
+ if (msg.role !== "assistant" || !Array.isArray(msg.content)) continue;
15417
+ for (const block of msg.content) {
15418
+ if (block.type === "tool_use") {
15419
+ map.set(block.id, block.name);
15420
+ }
15421
+ }
15422
+ }
15423
+ return map;
15424
+ }
15371
15425
  /**
15372
15426
  * Convert content to Gemini parts
15373
15427
  */
@@ -15444,14 +15498,15 @@ var GeminiProvider = class {
15444
15498
  let textContent = "";
15445
15499
  const toolCalls = [];
15446
15500
  if (candidate?.content?.parts) {
15501
+ let toolIndex = 0;
15447
15502
  for (const part of candidate.content.parts) {
15448
15503
  if ("text" in part && part.text) {
15449
15504
  textContent += part.text;
15450
15505
  }
15451
15506
  if ("functionCall" in part && part.functionCall) {
15507
+ toolIndex++;
15452
15508
  toolCalls.push({
15453
- id: part.functionCall.name,
15454
- // Use name as ID for Gemini
15509
+ id: `gemini_call_${toolIndex}`,
15455
15510
  name: part.functionCall.name,
15456
15511
  input: part.functionCall.args ?? {}
15457
15512
  });