@corbat-tech/coco 2.5.2 → 2.5.3

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
@@ -11790,6 +11790,20 @@ var AnthropicProvider = class {
11790
11790
  if (event.type === "content_block_start") {
11791
11791
  const contentBlock = event.content_block;
11792
11792
  if (contentBlock.type === "tool_use") {
11793
+ if (currentToolCall) {
11794
+ getLogger().warn(
11795
+ `[Anthropic] content_block_stop missing for tool '${currentToolCall.name}' \u2014 finalizing early to prevent data bleed.`
11796
+ );
11797
+ try {
11798
+ currentToolCall.input = currentToolInputJson ? JSON.parse(currentToolInputJson) : {};
11799
+ } catch {
11800
+ currentToolCall.input = {};
11801
+ }
11802
+ yield {
11803
+ type: "tool_use_end",
11804
+ toolCall: { ...currentToolCall }
11805
+ };
11806
+ }
11793
11807
  currentToolCall = {
11794
11808
  id: contentBlock.id,
11795
11809
  name: contentBlock.name
@@ -12383,6 +12397,30 @@ var OpenAIProvider = class {
12383
12397
  }
12384
12398
  };
12385
12399
  const timeoutInterval = setInterval(checkTimeout, 5e3);
12400
+ const providerName = this.name;
12401
+ const parseArguments = (builder) => {
12402
+ let input = {};
12403
+ try {
12404
+ input = builder.arguments ? JSON.parse(builder.arguments) : {};
12405
+ } catch (error) {
12406
+ console.warn(
12407
+ `[${providerName}] Failed to parse tool call arguments for ${builder.name}: ${builder.arguments?.slice(0, 300)}`
12408
+ );
12409
+ try {
12410
+ if (builder.arguments) {
12411
+ const repaired = jsonrepair(builder.arguments);
12412
+ input = JSON.parse(repaired);
12413
+ console.log(`[${providerName}] \u2713 Successfully repaired JSON for ${builder.name}`);
12414
+ }
12415
+ } catch {
12416
+ console.error(
12417
+ `[${providerName}] Cannot repair JSON for ${builder.name}, using empty object`
12418
+ );
12419
+ console.error(`[${providerName}] Original error:`, error);
12420
+ }
12421
+ }
12422
+ return input;
12423
+ };
12386
12424
  try {
12387
12425
  for await (const chunk of stream) {
12388
12426
  const delta = chunk.choices[0]?.delta;
@@ -12394,7 +12432,7 @@ var OpenAIProvider = class {
12394
12432
  }
12395
12433
  if (delta?.tool_calls) {
12396
12434
  for (const toolCallDelta of delta.tool_calls) {
12397
- const index = toolCallDelta.index;
12435
+ const index = toolCallDelta.index ?? toolCallBuilders.size;
12398
12436
  if (!toolCallBuilders.has(index)) {
12399
12437
  toolCallBuilders.set(index, {
12400
12438
  id: toolCallDelta.id ?? "",
@@ -12429,34 +12467,28 @@ var OpenAIProvider = class {
12429
12467
  }
12430
12468
  }
12431
12469
  }
12432
- }
12433
- for (const [, builder] of toolCallBuilders) {
12434
- let input = {};
12435
- try {
12436
- input = builder.arguments ? JSON.parse(builder.arguments) : {};
12437
- } catch (error) {
12438
- console.warn(
12439
- `[${this.name}] Failed to parse tool call arguments for ${builder.name}: ${builder.arguments?.slice(0, 300)}`
12440
- );
12441
- try {
12442
- if (builder.arguments) {
12443
- const repaired = jsonrepair(builder.arguments);
12444
- input = JSON.parse(repaired);
12445
- console.log(`[${this.name}] \u2713 Successfully repaired JSON for ${builder.name}`);
12446
- }
12447
- } catch {
12448
- console.error(
12449
- `[${this.name}] Cannot repair JSON for ${builder.name}, using empty object`
12450
- );
12451
- console.error(`[${this.name}] Original error:`, error);
12470
+ const finishReason = chunk.choices[0]?.finish_reason;
12471
+ if (finishReason && toolCallBuilders.size > 0) {
12472
+ for (const [, builder] of toolCallBuilders) {
12473
+ yield {
12474
+ type: "tool_use_end",
12475
+ toolCall: {
12476
+ id: builder.id,
12477
+ name: builder.name,
12478
+ input: parseArguments(builder)
12479
+ }
12480
+ };
12452
12481
  }
12482
+ toolCallBuilders.clear();
12453
12483
  }
12484
+ }
12485
+ for (const [, builder] of toolCallBuilders) {
12454
12486
  yield {
12455
12487
  type: "tool_use_end",
12456
12488
  toolCall: {
12457
12489
  id: builder.id,
12458
12490
  name: builder.name,
12459
- input
12491
+ input: parseArguments(builder)
12460
12492
  }
12461
12493
  };
12462
12494
  }
@@ -12625,7 +12657,8 @@ var OpenAIProvider = class {
12625
12657
  if (msg.role === "system") {
12626
12658
  result.push({ role: "system", content: this.contentToString(msg.content) });
12627
12659
  } else if (msg.role === "user") {
12628
- if (Array.isArray(msg.content) && msg.content[0]?.type === "tool_result") {
12660
+ if (Array.isArray(msg.content) && msg.content.some((b) => b.type === "tool_result")) {
12661
+ const textParts = [];
12629
12662
  for (const block of msg.content) {
12630
12663
  if (block.type === "tool_result") {
12631
12664
  const toolResult = block;
@@ -12634,8 +12667,16 @@ var OpenAIProvider = class {
12634
12667
  tool_call_id: toolResult.tool_use_id,
12635
12668
  content: toolResult.content
12636
12669
  });
12670
+ } else if (block.type === "text") {
12671
+ textParts.push(block.text);
12637
12672
  }
12638
12673
  }
12674
+ if (textParts.length > 0) {
12675
+ console.warn(
12676
+ `[${this.name}] User message has mixed tool_result and text blocks \u2014 text emitted as a separate user message.`
12677
+ );
12678
+ result.push({ role: "user", content: textParts.join("") });
12679
+ }
12639
12680
  } else if (Array.isArray(msg.content) && msg.content.some((b) => b.type === "image")) {
12640
12681
  const parts = [];
12641
12682
  for (const block of msg.content) {
@@ -12680,6 +12721,10 @@ var OpenAIProvider = class {
12680
12721
  arguments: JSON.stringify(block.input)
12681
12722
  }
12682
12723
  });
12724
+ } else {
12725
+ console.warn(
12726
+ `[${this.name}] Unexpected block type '${block.type}' in assistant message \u2014 dropping. This may indicate a message history corruption.`
12727
+ );
12683
12728
  }
12684
12729
  }
12685
12730
  if (textParts.length > 0) {
@@ -15156,7 +15201,7 @@ function escapeRegex(str) {
15156
15201
  }
15157
15202
  var DEFAULT_TIMEOUT_MS = 12e4;
15158
15203
  var MAX_OUTPUT_SIZE = 1024 * 1024;
15159
- var DANGEROUS_PATTERNS = [
15204
+ var DANGEROUS_PATTERNS_FULL = [
15160
15205
  /\brm\s+-rf\s+\/(?!\w)/,
15161
15206
  // rm -rf / (root)
15162
15207
  /\bsudo\s+rm\s+-rf/,
@@ -15169,14 +15214,6 @@ var DANGEROUS_PATTERNS = [
15169
15214
  // Format filesystem
15170
15215
  /\bformat\s+/,
15171
15216
  // Windows format
15172
- /`[^`]+`/,
15173
- // Backtick command substitution
15174
- /\$\([^)]+\)/,
15175
- // $() command substitution
15176
- /\beval\s+/,
15177
- // eval command
15178
- /\bsource\s+/,
15179
- // source command (can execute arbitrary scripts)
15180
15217
  />\s*\/etc\//,
15181
15218
  // Write to /etc
15182
15219
  />\s*\/root\//,
@@ -15190,6 +15227,25 @@ var DANGEROUS_PATTERNS = [
15190
15227
  /\bwget\s+.*\|\s*(ba)?sh/
15191
15228
  // wget | sh pattern
15192
15229
  ];
15230
+ var DANGEROUS_PATTERNS_SHELL_ONLY = [
15231
+ /`[^`]+`/,
15232
+ // Backtick command substitution
15233
+ /\$\([^)]+\)/,
15234
+ // $() command substitution
15235
+ /\beval\s+/,
15236
+ // eval command (shell eval, not JS eval())
15237
+ /\bsource\s+/
15238
+ // source command (can execute arbitrary scripts)
15239
+ ];
15240
+ function getShellCommandPart(command) {
15241
+ const firstNewline = command.indexOf("\n");
15242
+ if (firstNewline === -1) return command;
15243
+ const firstLine = command.slice(0, firstNewline);
15244
+ if (/<<-?\s*['"]?\w/.test(firstLine)) {
15245
+ return firstLine;
15246
+ }
15247
+ return command;
15248
+ }
15193
15249
  var SAFE_ENV_VARS = /* @__PURE__ */ new Set([
15194
15250
  // System info (non-sensitive)
15195
15251
  "PATH",
@@ -15256,13 +15312,21 @@ Examples:
15256
15312
  env: z.record(z.string(), z.string()).optional().describe("Environment variables")
15257
15313
  }),
15258
15314
  async execute({ command, cwd, timeout, env: env2 }) {
15259
- for (const pattern of DANGEROUS_PATTERNS) {
15315
+ const shellPart = getShellCommandPart(command);
15316
+ for (const pattern of DANGEROUS_PATTERNS_FULL) {
15260
15317
  if (pattern.test(command)) {
15261
15318
  throw new ToolError(`Potentially dangerous command blocked: ${command.slice(0, 100)}`, {
15262
15319
  tool: "bash_exec"
15263
15320
  });
15264
15321
  }
15265
15322
  }
15323
+ for (const pattern of DANGEROUS_PATTERNS_SHELL_ONLY) {
15324
+ if (pattern.test(shellPart)) {
15325
+ throw new ToolError(`Potentially dangerous command blocked: ${command.slice(0, 100)}`, {
15326
+ tool: "bash_exec"
15327
+ });
15328
+ }
15329
+ }
15266
15330
  const startTime = performance.now();
15267
15331
  const timeoutMs = timeout ?? DEFAULT_TIMEOUT_MS;
15268
15332
  const { CommandHeartbeat: CommandHeartbeat2 } = await Promise.resolve().then(() => (init_heartbeat(), heartbeat_exports));
@@ -15344,13 +15408,21 @@ Examples:
15344
15408
  env: z.record(z.string(), z.string()).optional().describe("Environment variables")
15345
15409
  }),
15346
15410
  async execute({ command, cwd, env: env2 }) {
15347
- for (const pattern of DANGEROUS_PATTERNS) {
15411
+ const shellPart = getShellCommandPart(command);
15412
+ for (const pattern of DANGEROUS_PATTERNS_FULL) {
15348
15413
  if (pattern.test(command)) {
15349
15414
  throw new ToolError(`Potentially dangerous command blocked: ${command.slice(0, 100)}`, {
15350
15415
  tool: "bash_background"
15351
15416
  });
15352
15417
  }
15353
15418
  }
15419
+ for (const pattern of DANGEROUS_PATTERNS_SHELL_ONLY) {
15420
+ if (pattern.test(shellPart)) {
15421
+ throw new ToolError(`Potentially dangerous command blocked: ${command.slice(0, 100)}`, {
15422
+ tool: "bash_background"
15423
+ });
15424
+ }
15425
+ }
15354
15426
  try {
15355
15427
  const filteredEnv = {};
15356
15428
  for (const [key, value] of Object.entries(process.env)) {
@@ -20932,7 +21004,7 @@ Examples:
20932
21004
  });
20933
21005
  var imageTools = [readImageTool];
20934
21006
  var path31 = await import('path');
20935
- var DANGEROUS_PATTERNS2 = [
21007
+ var DANGEROUS_PATTERNS = [
20936
21008
  /\bDROP\s+(?:TABLE|DATABASE|INDEX|VIEW)\b/i,
20937
21009
  /\bTRUNCATE\b/i,
20938
21010
  /\bALTER\s+TABLE\b/i,
@@ -20942,7 +21014,7 @@ var DANGEROUS_PATTERNS2 = [
20942
21014
  /\bCREATE\s+(?:TABLE|DATABASE|INDEX)\b/i
20943
21015
  ];
20944
21016
  function isDangerousSql(sql2) {
20945
- return DANGEROUS_PATTERNS2.some((pattern) => pattern.test(sql2));
21017
+ return DANGEROUS_PATTERNS.some((pattern) => pattern.test(sql2));
20946
21018
  }
20947
21019
  var sqlQueryTool = defineTool({
20948
21020
  name: "sql_query",