@verboo/code 0.15.3 → 0.15.4

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 (2) hide show
  1. package/dist/cli.mjs +516 -61
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -117942,7 +117942,7 @@ function getClaudeCodeUserAgent() {
117942
117942
  return `claude-code/${"99.0.0"}`;
117943
117943
  }
117944
117944
  function getVerbooCodeUserAgent() {
117945
- const version2 = "0.15.3";
117945
+ const version2 = "0.15.4";
117946
117946
  return `verboo-code/${version2}`;
117947
117947
  }
117948
117948
 
@@ -188341,6 +188341,372 @@ var init_contextPartitioning = __esm(() => {
188341
188341
  ];
188342
188342
  });
188343
188343
 
188344
+ // src/utils/messages/toolPairing.ts
188345
+ function getToolUseId(block2) {
188346
+ if (typeof block2 === "object" && block2 !== null && "type" in block2 && block2.type === "tool_use" && "id" in block2 && typeof block2.id === "string") {
188347
+ return block2.id;
188348
+ }
188349
+ return null;
188350
+ }
188351
+ function getToolResultId(block2) {
188352
+ if (typeof block2 === "object" && block2 !== null && "type" in block2 && block2.type === "tool_result" && "tool_use_id" in block2 && typeof block2.tool_use_id === "string") {
188353
+ return block2.tool_use_id;
188354
+ }
188355
+ return null;
188356
+ }
188357
+ function getServerToolUseId(block2) {
188358
+ if (typeof block2 === "object" && block2 !== null && "type" in block2 && (block2.type === "server_tool_use" || block2.type === "mcp_tool_use") && "id" in block2 && typeof block2.id === "string") {
188359
+ return block2.id;
188360
+ }
188361
+ return null;
188362
+ }
188363
+ function getToolUseIdReference(block2) {
188364
+ if (typeof block2 === "object" && block2 !== null && "tool_use_id" in block2 && typeof block2.tool_use_id === "string") {
188365
+ return block2.tool_use_id;
188366
+ }
188367
+ return null;
188368
+ }
188369
+ function getToolResultIdsFromUserMessage(message) {
188370
+ if (!Array.isArray(message.message.content)) {
188371
+ return [];
188372
+ }
188373
+ return message.message.content.map((block2) => getToolResultId(block2)).filter((id) => id !== null);
188374
+ }
188375
+ function isUserOrAssistantMessage(message) {
188376
+ return message.type === "user" || message.type === "assistant";
188377
+ }
188378
+ function getToolUseIdsFromAssistantMessage(message) {
188379
+ if (message.type !== "assistant") {
188380
+ return [];
188381
+ }
188382
+ const content = message.message.content;
188383
+ if (!Array.isArray(content)) {
188384
+ return [];
188385
+ }
188386
+ return content.map((block2) => getToolUseId(block2)).filter((id) => id !== null);
188387
+ }
188388
+ function getToolResultIdsFromMessage(message) {
188389
+ if (message.type !== "user") {
188390
+ return [];
188391
+ }
188392
+ const content = message.message.content;
188393
+ if (!Array.isArray(content)) {
188394
+ return [];
188395
+ }
188396
+ return content.map((block2) => getToolResultId(block2)).filter((id) => id !== null);
188397
+ }
188398
+ function collectToolUseIdsInRange(messages, start, end) {
188399
+ const ids = new Set;
188400
+ for (let i3 = start;i3 < end; i3++) {
188401
+ for (const id of getToolUseIdsFromAssistantMessage(messages[i3])) {
188402
+ ids.add(id);
188403
+ }
188404
+ }
188405
+ return ids;
188406
+ }
188407
+ function collectToolResultIdsInRange(messages, start, end) {
188408
+ const ids = new Set;
188409
+ for (let i3 = start;i3 < end; i3++) {
188410
+ for (const id of getToolResultIdsFromMessage(messages[i3])) {
188411
+ ids.add(id);
188412
+ }
188413
+ }
188414
+ return ids;
188415
+ }
188416
+ function clampRangeIndex(index, min, max2) {
188417
+ if (!Number.isFinite(index))
188418
+ return min;
188419
+ return Math.max(min, Math.min(max2, Math.trunc(index)));
188420
+ }
188421
+ function findToolUseMessageIndex(messages, toolUseId, fromInclusive, toExclusive) {
188422
+ for (let i3 = toExclusive - 1;i3 >= fromInclusive; i3--) {
188423
+ if (getToolUseIdsFromAssistantMessage(messages[i3]).includes(toolUseId)) {
188424
+ return i3;
188425
+ }
188426
+ }
188427
+ return -1;
188428
+ }
188429
+ function findToolResultMessageIndex(messages, toolUseId, fromInclusive, toExclusive) {
188430
+ for (let i3 = fromInclusive;i3 < toExclusive; i3++) {
188431
+ if (getToolResultIdsFromMessage(messages[i3]).includes(toolUseId)) {
188432
+ return i3;
188433
+ }
188434
+ }
188435
+ return -1;
188436
+ }
188437
+ function findEarliestAssistantWithSameMessageId(messages, messageId, fromInclusive, toExclusive) {
188438
+ let result = -1;
188439
+ for (let i3 = fromInclusive;i3 < toExclusive; i3++) {
188440
+ const message = messages[i3];
188441
+ if (message.type === "assistant" && message.message.id === messageId) {
188442
+ result = i3;
188443
+ break;
188444
+ }
188445
+ }
188446
+ return result;
188447
+ }
188448
+ function findLatestAssistantWithSameMessageId(messages, messageId, fromInclusive, toExclusive) {
188449
+ let result = -1;
188450
+ for (let i3 = fromInclusive;i3 < toExclusive; i3++) {
188451
+ const message = messages[i3];
188452
+ if (message.type === "assistant" && message.message.id === messageId) {
188453
+ result = i3;
188454
+ }
188455
+ }
188456
+ return result;
188457
+ }
188458
+ function getPairingIssueKinds(messages) {
188459
+ const pairable = messages.filter(isUserOrAssistantMessage);
188460
+ if (pairable.length === 0)
188461
+ return [];
188462
+ const validation = validateToolResultPairing(pairable);
188463
+ return [...new Set(validation.issues.map((issue2) => issue2.kind))];
188464
+ }
188465
+ function messageHasToolResult(message) {
188466
+ return message ? getToolResultIdsFromMessage(message).length > 0 : false;
188467
+ }
188468
+ function selectToolPairSafeMessageRange(messages, requestedStart, requestedEnd, options2) {
188469
+ const messageList = [...messages];
188470
+ const minStart = clampRangeIndex(options2.minStart ?? 0, 0, messageList.length);
188471
+ const maxEnd = clampRangeIndex(options2.maxEnd ?? messageList.length, minStart, messageList.length);
188472
+ const clampedStart = clampRangeIndex(requestedStart, minStart, maxEnd);
188473
+ const clampedEnd = clampRangeIndex(requestedEnd, clampedStart, maxEnd);
188474
+ const maxExtraMessages = options2.maxExtraMessages === undefined ? messageList.length : Math.max(0, Math.trunc(options2.maxExtraMessages));
188475
+ let expansionMinStart = Math.max(minStart, clampedStart - maxExtraMessages);
188476
+ let expansionMaxEnd = Math.min(maxEnd, clampedEnd + maxExtraMessages);
188477
+ let start = clampedStart;
188478
+ let end = clampedEnd;
188479
+ const requestedMessages = messageList.slice(clampedStart, clampedEnd);
188480
+ const issueKinds = getPairingIssueKinds(requestedMessages);
188481
+ const requestedStartedWithToolResult = messageHasToolResult(messageList[clampedStart]);
188482
+ for (let guard = 0;guard < messageList.length * 2 + 2; guard++) {
188483
+ let changed = false;
188484
+ for (let i3 = start;i3 < end; i3++) {
188485
+ const message = messageList[i3];
188486
+ if (!message)
188487
+ continue;
188488
+ if (message.type !== "assistant")
188489
+ continue;
188490
+ const messageId = message.message.id;
188491
+ if (!messageId)
188492
+ continue;
188493
+ const earlier = findEarliestAssistantWithSameMessageId(messageList, messageId, 0, start);
188494
+ if (earlier !== -1) {
188495
+ if (earlier >= expansionMinStart) {
188496
+ start = earlier;
188497
+ } else {
188498
+ const lastInRange = findLatestAssistantWithSameMessageId(messageList, messageId, start, end);
188499
+ start = lastInRange + 1;
188500
+ expansionMinStart = Math.max(expansionMinStart, start);
188501
+ }
188502
+ changed = true;
188503
+ break;
188504
+ }
188505
+ const later = findLatestAssistantWithSameMessageId(messageList, messageId, end, messageList.length);
188506
+ if (later !== -1) {
188507
+ if (later < expansionMaxEnd) {
188508
+ end = later + 1;
188509
+ } else {
188510
+ const firstInRange = findEarliestAssistantWithSameMessageId(messageList, messageId, start, end);
188511
+ end = firstInRange;
188512
+ expansionMaxEnd = Math.min(expansionMaxEnd, end);
188513
+ }
188514
+ changed = true;
188515
+ break;
188516
+ }
188517
+ }
188518
+ if (changed)
188519
+ continue;
188520
+ const toolUseIds = collectToolUseIdsInRange(messageList, start, end);
188521
+ const toolResultIds = collectToolResultIdsInRange(messageList, start, end);
188522
+ for (let i3 = start;i3 < end; i3++) {
188523
+ const resultIds = getToolResultIdsFromMessage(messageList[i3]);
188524
+ const orphanedResultId = resultIds.find((id) => !toolUseIds.has(id));
188525
+ if (!orphanedResultId)
188526
+ continue;
188527
+ const toolUseIndex = findToolUseMessageIndex(messageList, orphanedResultId, expansionMinStart, start);
188528
+ if (toolUseIndex !== -1) {
188529
+ start = toolUseIndex;
188530
+ changed = true;
188531
+ break;
188532
+ }
188533
+ start = i3 + 1;
188534
+ expansionMinStart = Math.max(expansionMinStart, start);
188535
+ changed = true;
188536
+ break;
188537
+ }
188538
+ if (changed)
188539
+ continue;
188540
+ for (let i3 = start;i3 < end; i3++) {
188541
+ const toolUseIdsForMessage = getToolUseIdsFromAssistantMessage(messageList[i3]);
188542
+ const missingToolUseId = toolUseIdsForMessage.find((id) => !toolResultIds.has(id));
188543
+ if (!missingToolUseId)
188544
+ continue;
188545
+ const toolResultIndex = findToolResultMessageIndex(messageList, missingToolUseId, end, expansionMaxEnd);
188546
+ if (toolResultIndex !== -1) {
188547
+ end = toolResultIndex + 1;
188548
+ changed = true;
188549
+ break;
188550
+ }
188551
+ const hasResultOutsideRange = findToolResultMessageIndex(messageList, missingToolUseId, 0, messageList.length) !== -1;
188552
+ if (options2.allowPendingToolUse && !hasResultOutsideRange)
188553
+ continue;
188554
+ end = i3;
188555
+ expansionMaxEnd = Math.min(expansionMaxEnd, end);
188556
+ changed = true;
188557
+ break;
188558
+ }
188559
+ if (!changed)
188560
+ break;
188561
+ }
188562
+ const selectedMessages = messageList.slice(start, end);
188563
+ const diagnostics = {
188564
+ projectionName: options2.projectionName,
188565
+ querySource: options2.querySource,
188566
+ messageCountBefore: clampedEnd - clampedStart,
188567
+ messageCountAfter: selectedMessages.length,
188568
+ requestedRange: { start: clampedStart, end: clampedEnd },
188569
+ adjustedRange: { start, end },
188570
+ issueKinds,
188571
+ requestedStartedWithToolResult,
188572
+ adjusted: start !== clampedStart || end !== clampedEnd
188573
+ };
188574
+ if (diagnostics.adjusted || issueKinds.length > 0) {
188575
+ logForDebugging(`[messageProjection] tool-pair-safe range projection=${options2.projectionName} ` + `querySource=${options2.querySource ?? "unknown"} ` + `before=${diagnostics.messageCountBefore} after=${diagnostics.messageCountAfter} ` + `requested=${clampedStart}:${clampedEnd} adjusted=${start}:${end} ` + `issueKinds=${issueKinds.join(",") || "none"} ` + `requestedStartedWithToolResult=${requestedStartedWithToolResult}`);
188576
+ }
188577
+ return {
188578
+ messages: selectedMessages,
188579
+ start,
188580
+ end,
188581
+ diagnostics
188582
+ };
188583
+ }
188584
+ function validateToolResultPairing(messages, context = {}) {
188585
+ const issues = [];
188586
+ const seenToolUses = new Map;
188587
+ for (let i3 = 0;i3 < messages.length; i3++) {
188588
+ const msg = messages[i3];
188589
+ if (msg.type === "user") {
188590
+ if (messages[i3 - 1]?.type === "assistant") {
188591
+ continue;
188592
+ }
188593
+ for (const toolUseId of getToolResultIdsFromUserMessage(msg)) {
188594
+ issues.push({
188595
+ kind: "orphaned_tool_result",
188596
+ toolUseId,
188597
+ userIndex: i3
188598
+ });
188599
+ }
188600
+ continue;
188601
+ }
188602
+ const uniqueToolUseIds = new Set;
188603
+ const serverResultIds = new Set;
188604
+ const assistantContent = Array.isArray(msg.message.content) ? msg.message.content : [];
188605
+ for (const block2 of assistantContent) {
188606
+ const toolUseIdReference = getToolUseIdReference(block2);
188607
+ if (toolUseIdReference !== null) {
188608
+ serverResultIds.add(toolUseIdReference);
188609
+ }
188610
+ }
188611
+ for (const block2 of assistantContent) {
188612
+ const toolUseId = getToolUseId(block2);
188613
+ if (toolUseId !== null) {
188614
+ const firstSeen = seenToolUses.get(toolUseId);
188615
+ if (firstSeen) {
188616
+ issues.push({
188617
+ kind: "duplicate_tool_use",
188618
+ toolUseId,
188619
+ assistantIndex: i3,
188620
+ assistantMessageId: msg.message.id,
188621
+ duplicateOfAssistantIndex: firstSeen.assistantIndex,
188622
+ duplicateOfAssistantMessageId: firstSeen.assistantMessageId
188623
+ });
188624
+ } else {
188625
+ seenToolUses.set(toolUseId, {
188626
+ assistantIndex: i3,
188627
+ assistantMessageId: msg.message.id
188628
+ });
188629
+ }
188630
+ uniqueToolUseIds.add(toolUseId);
188631
+ }
188632
+ const serverToolUseId = getServerToolUseId(block2);
188633
+ if (serverToolUseId !== null && !serverResultIds.has(serverToolUseId)) {
188634
+ issues.push({
188635
+ kind: "server_tool_use_without_result",
188636
+ toolUseId: serverToolUseId,
188637
+ assistantIndex: i3,
188638
+ assistantMessageId: msg.message.id
188639
+ });
188640
+ }
188641
+ }
188642
+ const nextMsg = messages[i3 + 1];
188643
+ const toolResultIds = nextMsg?.type === "user" ? getToolResultIdsFromUserMessage(nextMsg) : [];
188644
+ const toolResultIdSet = new Set(toolResultIds);
188645
+ const toolUseIdSet = new Set(uniqueToolUseIds);
188646
+ const seenToolResultIds = new Set;
188647
+ for (const toolResultId of toolResultIds) {
188648
+ if (seenToolResultIds.has(toolResultId)) {
188649
+ issues.push({
188650
+ kind: "duplicate_tool_result",
188651
+ toolUseId: toolResultId,
188652
+ assistantIndex: i3,
188653
+ assistantMessageId: msg.message.id,
188654
+ userIndex: i3 + 1
188655
+ });
188656
+ }
188657
+ seenToolResultIds.add(toolResultId);
188658
+ }
188659
+ for (const toolUseId of toolUseIdSet) {
188660
+ if (!toolResultIdSet.has(toolUseId)) {
188661
+ issues.push({
188662
+ kind: "missing_tool_result",
188663
+ toolUseId,
188664
+ assistantIndex: i3,
188665
+ assistantMessageId: msg.message.id
188666
+ });
188667
+ }
188668
+ }
188669
+ for (const toolResultId of toolResultIdSet) {
188670
+ if (!toolUseIdSet.has(toolResultId)) {
188671
+ issues.push({
188672
+ kind: "orphaned_tool_result",
188673
+ toolUseId: toolResultId,
188674
+ assistantIndex: i3,
188675
+ assistantMessageId: msg.message.id,
188676
+ userIndex: i3 + 1
188677
+ });
188678
+ }
188679
+ }
188680
+ }
188681
+ return {
188682
+ valid: issues.length === 0,
188683
+ context,
188684
+ issues
188685
+ };
188686
+ }
188687
+ function formatToolResultPairingIssue(issue2) {
188688
+ const parts = [`kind=${issue2.kind}`, `tool_use_id=${issue2.toolUseId}`];
188689
+ if (issue2.assistantIndex !== undefined) {
188690
+ parts.push(`assistant_index=${issue2.assistantIndex}`);
188691
+ }
188692
+ if (issue2.assistantMessageId !== undefined) {
188693
+ parts.push(`assistant_message_id=${issue2.assistantMessageId}`);
188694
+ }
188695
+ if (issue2.userIndex !== undefined) {
188696
+ parts.push(`user_index=${issue2.userIndex}`);
188697
+ }
188698
+ if (issue2.duplicateOfAssistantIndex !== undefined) {
188699
+ parts.push(`duplicate_of_assistant_index=${issue2.duplicateOfAssistantIndex}`);
188700
+ }
188701
+ if (issue2.duplicateOfAssistantMessageId !== undefined) {
188702
+ parts.push(`duplicate_of_assistant_message_id=${issue2.duplicateOfAssistantMessageId}`);
188703
+ }
188704
+ return parts.join(",");
188705
+ }
188706
+ var init_toolPairing = __esm(() => {
188707
+ init_debug();
188708
+ });
188709
+
188344
188710
  // src/utils/relevancePruning.ts
188345
188711
  function extractKeywords(text) {
188346
188712
  const words = text.toLowerCase().split(/\s+/);
@@ -188427,8 +188793,13 @@ function pruneByRelevance(messages, options2) {
188427
188793
  if (messages.length <= preserveRecent) {
188428
188794
  return messages;
188429
188795
  }
188430
- const recentMessages = messages.slice(-preserveRecent);
188431
- const olderMessages = messages.slice(0, -preserveRecent);
188796
+ const requestedRecentStart = Math.max(0, messages.length - preserveRecent);
188797
+ const recentRange = selectToolPairSafeMessageRange(messages, requestedRecentStart, messages.length, {
188798
+ projectionName: "relevance_pruning_recent",
188799
+ querySource: "compact"
188800
+ });
188801
+ const recentMessages = recentRange.messages;
188802
+ const olderMessages = messages.slice(0, recentRange.start);
188432
188803
  const olderGroups = groupMessagesByApiRound(olderMessages);
188433
188804
  const scored = [];
188434
188805
  for (const group of olderGroups) {
@@ -188458,6 +188829,7 @@ function pruneByRelevance(messages, options2) {
188458
188829
  var STOP_WORDS;
188459
188830
  var init_relevancePruning = __esm(() => {
188460
188831
  init_tokenEstimation();
188832
+ init_toolPairing();
188461
188833
  STOP_WORDS = new Set([
188462
188834
  "the",
188463
188835
  "and",
@@ -385171,6 +385543,39 @@ function getNextImagePasteId(messages) {
385171
385543
  }
385172
385544
  return maxId + 1;
385173
385545
  }
385546
+ function messageContainsToolResult(message, toolUseId) {
385547
+ return message.type === "user" && Array.isArray(message.message.content) && message.message.content.some((block2) => block2.type === "tool_result" && block2.tool_use_id === toolUseId);
385548
+ }
385549
+ function createMissingToolResultMessage(toolUseId, assistantMessage2) {
385550
+ const errorMessage2 = "Tool execution ended without returning a result. The tool was not run again.";
385551
+ return {
385552
+ message: createUserMessage({
385553
+ content: [
385554
+ {
385555
+ type: "tool_result",
385556
+ content: `<tool_use_error>${errorMessage2}</tool_use_error>`,
385557
+ is_error: true,
385558
+ tool_use_id: toolUseId
385559
+ }
385560
+ ],
385561
+ toolUseResult: errorMessage2,
385562
+ sourceToolAssistantUUID: assistantMessage2.uuid
385563
+ })
385564
+ };
385565
+ }
385566
+ async function* ensureTerminalToolResult(updates, toolUseId, assistantMessage2, onMissing = () => {}) {
385567
+ let hasTerminalToolResult = false;
385568
+ for await (const update of updates) {
385569
+ if (messageContainsToolResult(update.message, toolUseId)) {
385570
+ hasTerminalToolResult = true;
385571
+ }
385572
+ yield update;
385573
+ }
385574
+ if (!hasTerminalToolResult) {
385575
+ onMissing();
385576
+ yield createMissingToolResultMessage(toolUseId, assistantMessage2);
385577
+ }
385578
+ }
385174
385579
  function findMcpServerConnection(toolName, mcpClients) {
385175
385580
  if (!toolName.startsWith("mcp__")) {
385176
385581
  return;
@@ -385246,6 +385651,7 @@ async function* runToolUse(toolUse, assistantMessage2, canUseTool, toolUseContex
385246
385651
  return;
385247
385652
  }
385248
385653
  const toolInput = toolUse.input;
385654
+ let hasTerminalToolResult = false;
385249
385655
  try {
385250
385656
  if (toolUseContext.abortController.signal.aborted) {
385251
385657
  logEvent("tengu_tool_use_cancelled", {
@@ -385282,7 +385688,21 @@ async function* runToolUse(toolUse, assistantMessage2, canUseTool, toolUseContex
385282
385688
  toolUseId: toolUse.id,
385283
385689
  inputKeys: Object.keys(toolInput ?? {})
385284
385690
  }), { level: "debug" });
385285
- for await (const update of streamedCheckPermissionsAndCallTool(tool, toolUse.id, toolInput, toolUseContext, canUseTool, assistantMessage2, messageId, requestId, mcpServerType, mcpServerBaseUrl)) {
385691
+ const toolUpdates = streamedCheckPermissionsAndCallTool(tool, toolUse.id, toolInput, toolUseContext, canUseTool, assistantMessage2, messageId, requestId, mcpServerType, mcpServerBaseUrl);
385692
+ for await (const update of ensureTerminalToolResult(toolUpdates, toolUse.id, assistantMessage2, () => {
385693
+ const sanitizedToolName = sanitizeToolNameForAnalytics(tool.name);
385694
+ logEvent("tengu_tool_result_missing_at_execution", {
385695
+ toolName: sanitizedToolName,
385696
+ toolUseID: toolUse.id,
385697
+ model: toolUseContext.options.mainLoopModel,
385698
+ querySource: toolUseContext.options.querySource ?? "unknown",
385699
+ isMcp: tool.isMcp ?? false
385700
+ });
385701
+ logError2(new Error(`runToolUse: ${sanitizedToolName} completed without a tool_result`));
385702
+ })) {
385703
+ if (messageContainsToolResult(update.message, toolUse.id)) {
385704
+ hasTerminalToolResult = true;
385705
+ }
385286
385706
  yield update;
385287
385707
  }
385288
385708
  logForDebugging(JSON.stringify({
@@ -385295,20 +385715,22 @@ async function* runToolUse(toolUse, assistantMessage2, canUseTool, toolUseContex
385295
385715
  const errorMessage2 = error42 instanceof Error ? error42.message : String(error42);
385296
385716
  const toolInfo = tool ? ` (${tool.name})` : "";
385297
385717
  const detailedError = `Error calling tool${toolInfo}: ${errorMessage2}`;
385298
- yield {
385299
- message: createUserMessage({
385300
- content: [
385301
- {
385302
- type: "tool_result",
385303
- content: `<tool_use_error>${detailedError}</tool_use_error>`,
385304
- is_error: true,
385305
- tool_use_id: toolUse.id
385306
- }
385307
- ],
385308
- toolUseResult: detailedError,
385309
- sourceToolAssistantUUID: assistantMessage2.uuid
385310
- })
385311
- };
385718
+ if (!hasTerminalToolResult) {
385719
+ yield {
385720
+ message: createUserMessage({
385721
+ content: [
385722
+ {
385723
+ type: "tool_result",
385724
+ content: `<tool_use_error>${detailedError}</tool_use_error>`,
385725
+ is_error: true,
385726
+ tool_use_id: toolUse.id
385727
+ }
385728
+ ],
385729
+ toolUseResult: detailedError,
385730
+ sourceToolAssistantUUID: assistantMessage2.uuid
385731
+ })
385732
+ };
385733
+ }
385312
385734
  }
385313
385735
  }
385314
385736
  function streamedCheckPermissionsAndCallTool(tool, toolUseID, input, toolUseContext, canUseTool, assistantMessage2, messageId, requestId, mcpServerType, mcpServerBaseUrl) {
@@ -389080,7 +389502,7 @@ function getAnthropicEnvMetadata() {
389080
389502
  function getBuildAgeMinutes() {
389081
389503
  if (false)
389082
389504
  ;
389083
- const buildTime = new Date("2026-08-07T00:37:19.823Z").getTime();
389505
+ const buildTime = new Date("2026-08-08T14:50:13.943Z").getTime();
389084
389506
  if (isNaN(buildTime))
389085
389507
  return;
389086
389508
  return Math.floor((Date.now() - buildTime) / 60000);
@@ -390421,8 +390843,14 @@ async function partialCompactConversation(allMessages, pivotIndex, context, cach
390421
390843
  logMemoryDiagnostics("compact-start", memoryDiagExtra);
390422
390844
  maybeLogMemoryHighWatermark("compact-start", memoryDiagExtra);
390423
390845
  try {
390424
- const messagesToSummarize = direction === "up_to" ? allMessages.slice(0, pivotIndex) : allMessages.slice(pivotIndex);
390425
- const messagesToKeep = direction === "up_to" ? allMessages.slice(pivotIndex).filter((m) => m.type !== "progress" && !isCompactBoundaryMessage(m) && !(m.type === "user" && m.isCompactSummary)) : allMessages.slice(0, pivotIndex).filter((m) => m.type !== "progress");
390846
+ const requestedStart = direction === "up_to" ? 0 : pivotIndex;
390847
+ const requestedEnd = direction === "up_to" ? pivotIndex : allMessages.length;
390848
+ const summarizeRange = selectToolPairSafeMessageRange(allMessages, requestedStart, requestedEnd, {
390849
+ projectionName: "partial_compact",
390850
+ querySource: "compact"
390851
+ });
390852
+ const messagesToSummarize = summarizeRange.messages;
390853
+ const messagesToKeep = direction === "up_to" ? allMessages.slice(summarizeRange.end).filter((m) => m.type !== "progress" && !isCompactBoundaryMessage(m) && !(m.type === "user" && m.isCompactSummary)) : allMessages.slice(0, summarizeRange.start).filter((m) => m.type !== "progress");
390426
390854
  if (messagesToSummarize.length === 0) {
390427
390855
  throw new Error(direction === "up_to" ? "Nothing to summarize before the selected message." : "Nothing to summarize after the selected message.");
390428
390856
  }
@@ -405047,7 +405475,7 @@ function createToolUseSummaryMessage(summary, precedingToolUseIds) {
405047
405475
  timestamp: new Date().toISOString()
405048
405476
  };
405049
405477
  }
405050
- function ensureToolResultPairing(messages) {
405478
+ function ensureToolResultPairing(messages, context = {}) {
405051
405479
  const result = [];
405052
405480
  let repaired = false;
405053
405481
  const allSeenToolUseIds = new Set;
@@ -405187,6 +405615,7 @@ function ensureToolResultPairing(messages) {
405187
405615
  }
405188
405616
  }
405189
405617
  if (repaired) {
405618
+ const validation = validateToolResultPairing(messages, context);
405190
405619
  const messageTypes = messages.map((m, idx) => {
405191
405620
  if (m.type === "assistant") {
405192
405621
  const toolUses = m.message.content.filter((b) => b.type === "tool_use").map((b) => b.id);
@@ -405209,14 +405638,26 @@ function ensureToolResultPairing(messages) {
405209
405638
  return `[${idx}] ${m.type}`;
405210
405639
  });
405211
405640
  if (getStrictToolResultPairing()) {
405212
- throw new Error(`ensureToolResultPairing: tool_use/tool_result pairing mismatch detected (strict mode). ` + `Refusing to repair — would inject synthetic placeholders into model context. ` + `Message structure: ${messageTypes.join("; ")}. See inc-4977.`);
405641
+ throw new Error(`ensureToolResultPairing: tool_use/tool_result pairing mismatch detected (strict mode). ` + `Refusing to repair — would inject synthetic placeholders into model context. ` + `Phase: ${validation.context.phase ?? "unknown"}. ` + `Issues: ${validation.issues.map(formatToolResultPairingIssue).join("; ") || "none"}. ` + `Message structure: ${messageTypes.join("; ")}. See inc-4977.`);
405213
405642
  }
405643
+ const issueKinds = [
405644
+ ...new Set(validation.issues.map((issue2) => issue2.kind))
405645
+ ].join(",");
405646
+ const issueSummary = validation.issues.map(formatToolResultPairingIssue).join("; ") || "none";
405647
+ const diagnosticContext = `Phase: ${validation.context.phase ?? "unknown"}. ` + `Query source: ${validation.context.querySource ?? "unknown"}. ` + `Provider: ${validation.context.provider ?? "unknown"}. ` + `Model: ${validation.context.model ?? "unknown"}. ` + `Issues: ${issueSummary}.`;
405214
405648
  logEvent("tengu_tool_result_pairing_repaired", {
405215
405649
  messageCount: messages.length,
405216
405650
  repairedMessageCount: result.length,
405651
+ issueCount: validation.issues.length,
405652
+ phase: validation.context.phase ?? "unknown",
405653
+ querySource: validation.context.querySource ?? "unknown",
405654
+ agentId: validation.context.agentId ?? "none",
405655
+ model: validation.context.model ?? "unknown",
405656
+ provider: validation.context.provider ?? "unknown",
405657
+ issueKinds: issueKinds || "none",
405217
405658
  messageTypes: messageTypes.join("; ")
405218
405659
  });
405219
- logError2(new Error(`ensureToolResultPairing: repaired missing tool_result blocks (${messages.length} -> ${result.length} messages). Message structure: ${messageTypes.join("; ")}`));
405660
+ logError2(new Error(`ensureToolResultPairing: repaired missing tool_result blocks (${messages.length} -> ${result.length} messages). ${diagnosticContext} Message structure: ${messageTypes.join("; ")}`));
405220
405661
  }
405221
405662
  return result;
405222
405663
  }
@@ -405340,11 +405781,13 @@ var init_messages3 = __esm(() => {
405340
405781
  init_imageValidation();
405341
405782
  init_json();
405342
405783
  init_log3();
405784
+ init_toolPairing();
405343
405785
  init_permissionRuleParser();
405344
405786
  init_planModeV2();
405345
405787
  init_stringUtils();
405346
405788
  init_tasks();
405347
405789
  init_toolSearch();
405790
+ init_toolPairing();
405348
405791
  DENIAL_WORKAROUND_GUIDANCE = `IMPORTANT: You *may* attempt to accomplish this action using other tools that might naturally be used to accomplish this goal, ` + `e.g. using head instead of cat. But you *should not* attempt to work around this denial in malicious ways, ` + `e.g. do not use your ability to run tests to execute non-test actions. ` + `You should only try to work around this restriction in reasonable ways that do not attempt to bypass the intent behind this denial. ` + `If you believe this capability is essential to complete the user's request, STOP and explain to the user ` + `what you were trying to do and why you need this permission. Let the user decide how to proceed.`;
405349
405792
  SYNTHETIC_MESSAGES = new Set([
405350
405793
  INTERRUPT_MESSAGE,
@@ -417485,7 +417928,13 @@ async function* queryModel(messages, systemPrompt, thinkingConfig, tools, signal
417485
417928
  }
417486
417929
  });
417487
417930
  }
417488
- messagesForAPI = ensureToolResultPairing(messagesForAPI);
417931
+ messagesForAPI = ensureToolResultPairing(messagesForAPI, {
417932
+ phase: "api_before_repair",
417933
+ querySource: options2.querySource,
417934
+ agentId: options2.agentId,
417935
+ model: options2.model,
417936
+ provider: getAPIProvider()
417937
+ });
417489
417938
  if (!betas.includes(ADVISOR_BETA_HEADER)) {
417490
417939
  messagesForAPI = stripAdvisorBlocks(messagesForAPI);
417491
417940
  }
@@ -430741,7 +431190,7 @@ function buildPrimarySection() {
430741
431190
  });
430742
431191
  return [{
430743
431192
  label: "Version",
430744
- value: "0.15.3"
431193
+ value: "0.15.4"
430745
431194
  }, {
430746
431195
  label: "Session name",
430747
431196
  value: nameValue
@@ -444627,7 +445076,7 @@ function getReleaseTagUrl(version2 = publicBuildVersion) {
444627
445076
  return `${VERBOO_RELEASES_URL}/tag/v${normalizePublicVersion(version2)}`;
444628
445077
  }
444629
445078
  function getPublicBuildVersion() {
444630
- return "0.15.3";
445079
+ return "0.15.4";
444631
445080
  }
444632
445081
  var import_semver10, VERBOO_RELEASES_URL = "https://github.com/verbeux-ai/code/releases", fallbackBuildVersion, publicBuildVersion;
444633
445082
  var init_version = __esm(() => {
@@ -496020,7 +496469,7 @@ var init_bridge_kick = __esm(() => {
496020
496469
  var call66 = async () => {
496021
496470
  return {
496022
496471
  type: "text",
496023
- value: `${"99.0.0"} (built ${"2026-08-07T00:37:19.823Z"})`
496472
+ value: `${"99.0.0"} (built ${"2026-08-08T14:50:13.943Z"})`
496024
496473
  };
496025
496474
  }, version2, version_default;
496026
496475
  var init_version2 = __esm(() => {
@@ -520286,7 +520735,7 @@ function printStartupScreen(modelOverride) {
520286
520735
  const home = process.env.HOME || process.env.USERPROFILE || "";
520287
520736
  const cwd2 = process.cwd();
520288
520737
  const displayCwd = home && cwd2.startsWith(home) ? `~${cwd2.slice(home.length)}` : cwd2;
520289
- const version3 = "0.15.3";
520738
+ const version3 = "0.15.4";
520290
520739
  const columns = process.stdout.columns ?? STARTUP_LOGO_MIN_COLUMNS;
520291
520740
  process.stdout.write(renderStartupScreen(p, version3, displayCwd, columns));
520292
520741
  }
@@ -539530,7 +539979,7 @@ var init_routerRateLimitHook = __esm(() => {
539530
539979
  function getSemverPart(version3) {
539531
539980
  return `${import_semver13.major(version3, { loose: true })}.${import_semver13.minor(version3, { loose: true })}.${import_semver13.patch(version3, { loose: true })}`;
539532
539981
  }
539533
- function useUpdateNotification(updatedVersion, initialVersion = "0.15.3") {
539982
+ function useUpdateNotification(updatedVersion, initialVersion = "0.15.4") {
539534
539983
  const [lastNotifiedSemver, setLastNotifiedSemver] = import_react227.useState(() => getSemverPart(initialVersion));
539535
539984
  const [pendingNotification2, setPendingNotification] = import_react227.useState(null);
539536
539985
  if (updatedVersion) {
@@ -539570,7 +540019,7 @@ function AutoUpdater({
539570
540019
  return;
539571
540020
  }
539572
540021
  if (false) {}
539573
- const currentVersion = "0.15.3";
540022
+ const currentVersion = "0.15.4";
539574
540023
  const channel2 = getInitialSettings()?.autoUpdatesChannel ?? "latest";
539575
540024
  let latestVersion = await getLatestVersion(channel2);
539576
540025
  const isDisabled = isAutoUpdaterDisabled();
@@ -539923,17 +540372,17 @@ function PackageManagerAutoUpdater(t0) {
539923
540372
  const maxVersion = await getMaxVersion();
539924
540373
  if (maxVersion && latest && gt(latest, maxVersion)) {
539925
540374
  logForDebugging(`PackageManagerAutoUpdater: maxVersion ${maxVersion} is set, capping update from ${latest} to ${maxVersion}`);
539926
- if (gte("0.15.3", maxVersion)) {
539927
- logForDebugging(`PackageManagerAutoUpdater: current version ${"0.15.3"} is already at or above maxVersion ${maxVersion}, skipping update`);
540375
+ if (gte("0.15.4", maxVersion)) {
540376
+ logForDebugging(`PackageManagerAutoUpdater: current version ${"0.15.4"} is already at or above maxVersion ${maxVersion}, skipping update`);
539928
540377
  setUpdateAvailable(false);
539929
540378
  return;
539930
540379
  }
539931
540380
  latest = maxVersion;
539932
540381
  }
539933
- const hasUpdate = latest && !gte("0.15.3", latest) && !shouldSkipVersion(latest);
540382
+ const hasUpdate = latest && !gte("0.15.4", latest) && !shouldSkipVersion(latest);
539934
540383
  setUpdateAvailable(!!hasUpdate);
539935
540384
  if (hasUpdate) {
539936
- logForDebugging(`PackageManagerAutoUpdater: Update available ${"0.15.3"} -> ${latest}`);
540385
+ logForDebugging(`PackageManagerAutoUpdater: Update available ${"0.15.4"} -> ${latest}`);
539937
540386
  }
539938
540387
  };
539939
540388
  $2[0] = t1;
@@ -539967,7 +540416,7 @@ function PackageManagerAutoUpdater(t0) {
539967
540416
  wrap: "truncate",
539968
540417
  children: [
539969
540418
  "currentVersion: ",
539970
- "0.15.3"
540419
+ "0.15.4"
539971
540420
  ]
539972
540421
  });
539973
540422
  $2[3] = verbose;
@@ -555985,10 +556434,10 @@ async function autoUpdateCliInBackground() {
555985
556434
  return;
555986
556435
  const channel2 = getInitialSettings()?.autoUpdatesChannel ?? "latest";
555987
556436
  const latest = await getLatestVersion(channel2);
555988
- if (!latest || gte("0.15.3", latest))
556437
+ if (!latest || gte("0.15.4", latest))
555989
556438
  return;
555990
556439
  writeToStdout(`
555991
- Nova versão disponível: ${latest} (atual: ${"0.15.3"})
556440
+ Nova versão disponível: ${latest} (atual: ${"0.15.4"})
555992
556441
  `);
555993
556442
  writeToStdout(`Atualizando automaticamente...
555994
556443
  `);
@@ -561921,7 +562370,13 @@ async function generateAwaySummary(messages, signal) {
561921
562370
  }
561922
562371
  try {
561923
562372
  const memory2 = await getSessionMemoryContent();
561924
- const recent = messages.slice(-RECENT_MESSAGE_WINDOW);
562373
+ const requestedStart = Math.max(0, messages.length - RECENT_MESSAGE_WINDOW);
562374
+ const recentRange = selectToolPairSafeMessageRange(messages, requestedStart, messages.length, {
562375
+ projectionName: "away_summary",
562376
+ querySource: "away_summary",
562377
+ maxExtraMessages: RECENT_MESSAGE_WINDOW
562378
+ });
562379
+ const recent = [...recentRange.messages];
561925
562380
  recent.push(createUserMessage({ content: buildAwaySummaryPrompt(memory2) }));
561926
562381
  const response = await queryModelWithoutStreaming({
561927
562382
  messages: recent,
@@ -574201,7 +574656,7 @@ function WelcomeV2() {
574201
574656
  dimColor: true,
574202
574657
  children: [
574203
574658
  "v",
574204
- "0.15.3",
574659
+ "0.15.4",
574205
574660
  " "
574206
574661
  ]
574207
574662
  })
@@ -574388,7 +574843,7 @@ function WelcomeV2() {
574388
574843
  dimColor: true,
574389
574844
  children: [
574390
574845
  "v",
574391
- "0.15.3",
574846
+ "0.15.4",
574392
574847
  " "
574393
574848
  ]
574394
574849
  })
@@ -574604,7 +575059,7 @@ function AppleTerminalWelcomeV2(t0) {
574604
575059
  dimColor: true,
574605
575060
  children: [
574606
575061
  "v",
574607
- "0.15.3",
575062
+ "0.15.4",
574608
575063
  " "
574609
575064
  ]
574610
575065
  });
@@ -574813,7 +575268,7 @@ function AppleTerminalWelcomeV2(t0) {
574813
575268
  dimColor: true,
574814
575269
  children: [
574815
575270
  "v",
574816
- "0.15.3",
575271
+ "0.15.4",
574817
575272
  " "
574818
575273
  ]
574819
575274
  });
@@ -593269,7 +593724,7 @@ __export(exports_update, {
593269
593724
  });
593270
593725
  async function update() {
593271
593726
  logEvent("tengu_update_check", {});
593272
- writeToStdout(`Current version: ${"0.15.3"}
593727
+ writeToStdout(`Current version: ${"0.15.4"}
593273
593728
  `);
593274
593729
  const channel2 = getInitialSettings()?.autoUpdatesChannel ?? "latest";
593275
593730
  writeToStdout(`Checking for updates to ${channel2} version...
@@ -593354,8 +593809,8 @@ async function update() {
593354
593809
  writeToStdout(`Verboo Code is managed by Homebrew.
593355
593810
  `);
593356
593811
  const latest = await getLatestVersion(channel2);
593357
- if (latest && !gte("0.15.3", latest)) {
593358
- writeToStdout(`Update available: ${"0.15.3"} → ${latest}
593812
+ if (latest && !gte("0.15.4", latest)) {
593813
+ writeToStdout(`Update available: ${"0.15.4"} → ${latest}
593359
593814
  `);
593360
593815
  writeToStdout(`
593361
593816
  `);
@@ -593371,8 +593826,8 @@ async function update() {
593371
593826
  writeToStdout(`Verboo Code is managed by winget.
593372
593827
  `);
593373
593828
  const latest = await getLatestVersion(channel2);
593374
- if (latest && !gte("0.15.3", latest)) {
593375
- writeToStdout(`Update available: ${"0.15.3"} → ${latest}
593829
+ if (latest && !gte("0.15.4", latest)) {
593830
+ writeToStdout(`Update available: ${"0.15.4"} → ${latest}
593376
593831
  `);
593377
593832
  writeToStdout(`
593378
593833
  `);
@@ -593388,8 +593843,8 @@ async function update() {
593388
593843
  writeToStdout(`Verboo Code is managed by apk.
593389
593844
  `);
593390
593845
  const latest = await getLatestVersion(channel2);
593391
- if (latest && !gte("0.15.3", latest)) {
593392
- writeToStdout(`Update available: ${"0.15.3"} → ${latest}
593846
+ if (latest && !gte("0.15.4", latest)) {
593847
+ writeToStdout(`Update available: ${"0.15.4"} → ${latest}
593393
593848
  `);
593394
593849
  writeToStdout(`
593395
593850
  `);
@@ -593442,11 +593897,11 @@ async function update() {
593442
593897
  `);
593443
593898
  await gracefulShutdown(1);
593444
593899
  }
593445
- if (result.latestVersion === "0.15.3") {
593446
- writeToStdout(source_default.green(`Verboo Code is up to date (${"0.15.3"})`) + `
593900
+ if (result.latestVersion === "0.15.4") {
593901
+ writeToStdout(source_default.green(`Verboo Code is up to date (${"0.15.4"})`) + `
593447
593902
  `);
593448
593903
  } else {
593449
- writeToStdout(source_default.green(`Successfully updated from ${"0.15.3"} to version ${result.latestVersion}`) + `
593904
+ writeToStdout(source_default.green(`Successfully updated from ${"0.15.4"} to version ${result.latestVersion}`) + `
593450
593905
  `);
593451
593906
  await regenerateCompletionCache();
593452
593907
  }
@@ -593506,12 +593961,12 @@ async function update() {
593506
593961
  `);
593507
593962
  await gracefulShutdown(1);
593508
593963
  }
593509
- if (latestVersion === "0.15.3") {
593510
- writeToStdout(source_default.green(`Verboo Code is up to date (${"0.15.3"})`) + `
593964
+ if (latestVersion === "0.15.4") {
593965
+ writeToStdout(source_default.green(`Verboo Code is up to date (${"0.15.4"})`) + `
593511
593966
  `);
593512
593967
  await gracefulShutdown(0);
593513
593968
  }
593514
- writeToStdout(`New version available: ${latestVersion} (current: ${"0.15.3"})
593969
+ writeToStdout(`New version available: ${latestVersion} (current: ${"0.15.4"})
593515
593970
  `);
593516
593971
  writeToStdout(`Installing update...
593517
593972
  `);
@@ -593556,7 +594011,7 @@ async function update() {
593556
594011
  logForDebugging(`update: Installation status: ${status2}`);
593557
594012
  switch (status2) {
593558
594013
  case "success":
593559
- writeToStdout(source_default.green(`Successfully updated from ${"0.15.3"} to version ${latestVersion}`) + `
594014
+ writeToStdout(source_default.green(`Successfully updated from ${"0.15.4"} to version ${latestVersion}`) + `
593560
594015
  `);
593561
594016
  await regenerateCompletionCache();
593562
594017
  break;
@@ -594875,7 +595330,7 @@ ${customInstructions}` : customInstructions;
594875
595330
  is_native_binary: isInBundledMode()
594876
595331
  });
594877
595332
  logMemoryDiagnostics("start", {
594878
- version: "0.15.3",
595333
+ version: "0.15.4",
594879
595334
  debug: debug2,
594880
595335
  debugToStderr,
594881
595336
  print: print ?? false,
@@ -595686,7 +596141,7 @@ Usage: verboo --remote "your task description"`, () => gracefulShutdown(1));
595686
596141
  pendingHookMessages
595687
596142
  }, renderAndRun);
595688
596143
  }
595689
- }).version(`0.15.3 (${cliDesc})`, "-v, --version", "Output the version number");
596144
+ }).version(`0.15.4 (${cliDesc})`, "-v, --version", "Output the version number");
595690
596145
  program2.option("-w, --worktree [name]", "Create a new git worktree for this session (optionally specify a name)");
595691
596146
  program2.option("--tmux", "Create a tmux session for the worktree (requires --worktree). Uses iTerm2 native panes when available; use --tmux=classic for traditional tmux.");
595692
596147
  if (canUserConfigureAdvisor()) {
@@ -596267,7 +596722,7 @@ if (false) {}
596267
596722
  async function main2() {
596268
596723
  const args = process.argv.slice(2);
596269
596724
  if (args.length === 1 && (args[0] === "--version" || args[0] === "-v" || args[0] === "-V")) {
596270
- console.log(`${"0.15.3"} (Verboo Code)`);
596725
+ console.log(`${"0.15.4"} (Verboo Code)`);
596271
596726
  return;
596272
596727
  }
596273
596728
  if (!IS_VERBOO_CLI && args.includes("--provider")) {
@@ -596441,4 +596896,4 @@ async function main2() {
596441
596896
  }
596442
596897
  main2();
596443
596898
 
596444
- //# debugId=AD4F17ADE1D4CF4564756E2164756E21
596899
+ //# debugId=914D44FF804D587164756E2164756E21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verboo/code",
3
- "version": "0.15.3",
3
+ "version": "0.15.4",
4
4
  "description": "Verboo Code — coding agent for the Verboo platform",
5
5
  "type": "module",
6
6
  "bin": {