sparkecoder 0.1.122 → 0.1.123

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 (109) hide show
  1. package/dist/agent/index.d.ts +3 -3
  2. package/dist/agent/index.js +67 -14
  3. package/dist/agent/index.js.map +1 -1
  4. package/dist/cli.js +124 -24
  5. package/dist/cli.js.map +1 -1
  6. package/dist/db/index.d.ts +2 -2
  7. package/dist/{index-DczYH89U.d.ts → index-Bcz0aCAR.d.ts} +104 -104
  8. package/dist/index.d.ts +5 -5
  9. package/dist/index.js +124 -24
  10. package/dist/index.js.map +1 -1
  11. package/dist/{schema-DxrKyetI.d.ts → schema-BWbWmfDQ.d.ts} +3 -3
  12. package/dist/{search-CVVfuBPZ.d.ts → search-DOzC4ojH.d.ts} +4 -4
  13. package/dist/server/index.js +124 -24
  14. package/dist/server/index.js.map +1 -1
  15. package/dist/tools/index.d.ts +3 -3
  16. package/package.json +1 -1
  17. package/web/.next/BUILD_ID +1 -1
  18. package/web/.next/standalone/web/.next/BUILD_ID +1 -1
  19. package/web/.next/standalone/web/.next/build-manifest.json +2 -2
  20. package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
  21. package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
  22. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
  23. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  24. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  25. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  26. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  27. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  28. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
  29. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +1 -1
  30. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  31. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  32. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  33. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  34. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  35. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  36. package/web/.next/standalone/web/.next/server/app/agents.html +1 -1
  37. package/web/.next/standalone/web/.next/server/app/agents.rsc +1 -1
  38. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents/__PAGE__.segment.rsc +1 -1
  39. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents.segment.rsc +1 -1
  40. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p.segment.rsc +1 -1
  41. package/web/.next/standalone/web/.next/server/app/agents.segments/_full.segment.rsc +1 -1
  42. package/web/.next/standalone/web/.next/server/app/agents.segments/_head.segment.rsc +1 -1
  43. package/web/.next/standalone/web/.next/server/app/agents.segments/_index.segment.rsc +1 -1
  44. package/web/.next/standalone/web/.next/server/app/agents.segments/_tree.segment.rsc +1 -1
  45. package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
  46. package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +1 -1
  47. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +1 -1
  48. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
  49. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +1 -1
  50. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +1 -1
  51. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
  52. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
  53. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
  54. package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
  55. package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +1 -1
  56. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +1 -1
  57. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
  58. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +1 -1
  59. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +1 -1
  60. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
  61. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
  62. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
  63. package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
  64. package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +1 -1
  65. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +1 -1
  66. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
  67. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +1 -1
  68. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +1 -1
  69. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
  70. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
  71. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
  72. package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
  73. package/web/.next/standalone/web/.next/server/app/docs.rsc +1 -1
  74. package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +1 -1
  75. package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
  76. package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +1 -1
  77. package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +1 -1
  78. package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
  79. package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
  80. package/web/.next/standalone/web/.next/server/app/index.html +1 -1
  81. package/web/.next/standalone/web/.next/server/app/index.rsc +1 -1
  82. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +1 -1
  83. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +1 -1
  84. package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +1 -1
  85. package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  86. package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
  87. package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  88. package/web/.next/standalone/web/.next/server/app/settings.html +1 -1
  89. package/web/.next/standalone/web/.next/server/app/settings.rsc +1 -1
  90. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings/__PAGE__.segment.rsc +1 -1
  91. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings.segment.rsc +1 -1
  92. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p.segment.rsc +1 -1
  93. package/web/.next/standalone/web/.next/server/app/settings.segments/_full.segment.rsc +1 -1
  94. package/web/.next/standalone/web/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  95. package/web/.next/standalone/web/.next/server/app/settings.segments/_index.segment.rsc +1 -1
  96. package/web/.next/standalone/web/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
  97. package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
  98. package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
  99. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
  100. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
  101. /package/web/.next/standalone/web/.next/static/{BEIBC9-dP0_AWGmRy97hJ → MP4p8_EldjbZ69dONoEcM}/_buildManifest.js +0 -0
  102. /package/web/.next/standalone/web/.next/static/{BEIBC9-dP0_AWGmRy97hJ → MP4p8_EldjbZ69dONoEcM}/_clientMiddlewareManifest.json +0 -0
  103. /package/web/.next/standalone/web/.next/static/{BEIBC9-dP0_AWGmRy97hJ → MP4p8_EldjbZ69dONoEcM}/_ssgManifest.js +0 -0
  104. /package/web/.next/standalone/web/.next/static/static/{BEIBC9-dP0_AWGmRy97hJ → MP4p8_EldjbZ69dONoEcM}/_buildManifest.js +0 -0
  105. /package/web/.next/standalone/web/.next/static/static/{BEIBC9-dP0_AWGmRy97hJ → MP4p8_EldjbZ69dONoEcM}/_clientMiddlewareManifest.json +0 -0
  106. /package/web/.next/standalone/web/.next/static/static/{BEIBC9-dP0_AWGmRy97hJ → MP4p8_EldjbZ69dONoEcM}/_ssgManifest.js +0 -0
  107. /package/web/.next/static/{BEIBC9-dP0_AWGmRy97hJ → MP4p8_EldjbZ69dONoEcM}/_buildManifest.js +0 -0
  108. /package/web/.next/static/{BEIBC9-dP0_AWGmRy97hJ → MP4p8_EldjbZ69dONoEcM}/_clientMiddlewareManifest.json +0 -0
  109. /package/web/.next/static/{BEIBC9-dP0_AWGmRy97hJ → MP4p8_EldjbZ69dONoEcM}/_ssgManifest.js +0 -0
@@ -85,7 +85,7 @@ declare const sessions: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
85
85
  tableName: "sessions";
86
86
  dataType: "string";
87
87
  columnType: "SQLiteText";
88
- data: "completed" | "error" | "active" | "waiting";
88
+ data: "error" | "completed" | "active" | "waiting";
89
89
  driverParam: string;
90
90
  notNull: true;
91
91
  hasDefault: true;
@@ -391,7 +391,7 @@ declare const toolExecutions: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
391
391
  tableName: "tool_executions";
392
392
  dataType: "string";
393
393
  columnType: "SQLiteText";
394
- data: "completed" | "error" | "pending" | "approved" | "rejected";
394
+ data: "error" | "completed" | "pending" | "approved" | "rejected";
395
395
  driverParam: string;
396
396
  notNull: true;
397
397
  hasDefault: true;
@@ -814,7 +814,7 @@ declare const terminals: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
814
814
  tableName: "terminals";
815
815
  dataType: "string";
816
816
  columnType: "SQLiteText";
817
- data: "running" | "error" | "stopped";
817
+ data: "error" | "running" | "stopped";
818
818
  driverParam: string;
819
819
  notNull: true;
820
820
  hasDefault: true;
@@ -16,11 +16,11 @@ interface BashToolOptions {
16
16
  declare function createBashTool(options: BashToolOptions): ai.Tool<{
17
17
  background: boolean;
18
18
  id?: string | undefined;
19
- input?: string | undefined;
20
19
  command?: string | undefined;
20
+ input?: string | undefined;
21
21
  kill?: boolean | undefined;
22
22
  tail?: number | undefined;
23
- key?: "Enter" | "Escape" | "Up" | "Down" | "Left" | "Right" | "Tab" | "C-c" | "C-d" | "y" | "n" | undefined;
23
+ key?: "y" | "Enter" | "Escape" | "Up" | "Down" | "Left" | "Right" | "Tab" | "C-c" | "C-d" | "n" | undefined;
24
24
  }, {
25
25
  success: boolean;
26
26
  id: string;
@@ -66,7 +66,7 @@ declare function createBashTool(options: BashToolOptions): ai.Tool<{
66
66
  id: string;
67
67
  output: string;
68
68
  exitCode: number;
69
- status: "running" | "completed" | "error" | "stopped";
69
+ status: "error" | "completed" | "running" | "stopped";
70
70
  message?: undefined;
71
71
  error?: undefined;
72
72
  } | {
@@ -218,8 +218,8 @@ interface SearchToolOptions {
218
218
  * Progress is streamed back to the UI so users can see exploration happening.
219
219
  */
220
220
  declare function createSearchTool(options: SearchToolOptions): ai.Tool<{
221
- query: string;
222
221
  context: string;
222
+ query: string;
223
223
  }, {
224
224
  success: boolean;
225
225
  error: string;
@@ -7459,6 +7459,55 @@ function wrapToolsNeverThrow(tools) {
7459
7459
  }
7460
7460
  return wrapped;
7461
7461
  }
7462
+ function ensureToolResultsFollowCalls(messages) {
7463
+ if (!Array.isArray(messages) || messages.length < 3) return messages;
7464
+ let mutated = false;
7465
+ const result = messages.slice();
7466
+ let i = 0;
7467
+ while (i < result.length) {
7468
+ const msg = result[i];
7469
+ if (msg?.role !== "assistant" || !Array.isArray(msg.content)) {
7470
+ i++;
7471
+ continue;
7472
+ }
7473
+ const callIds = /* @__PURE__ */ new Set();
7474
+ for (const part of msg.content) {
7475
+ if (part?.type === "tool-call" && typeof part.toolCallId === "string") {
7476
+ callIds.add(part.toolCallId);
7477
+ }
7478
+ }
7479
+ if (callIds.size === 0) {
7480
+ i++;
7481
+ continue;
7482
+ }
7483
+ let toolIdx = -1;
7484
+ for (let j = i + 1; j < result.length; j++) {
7485
+ const m = result[j];
7486
+ if (m?.role === "assistant" && Array.isArray(m.content) && m.content.some((p) => p?.type === "tool-call")) {
7487
+ break;
7488
+ }
7489
+ if (m?.role === "tool" && Array.isArray(m.content)) {
7490
+ const answersOne = m.content.some(
7491
+ (p) => p?.type === "tool-result" && typeof p.toolCallId === "string" && callIds.has(p.toolCallId)
7492
+ );
7493
+ if (answersOne) {
7494
+ toolIdx = j;
7495
+ break;
7496
+ }
7497
+ }
7498
+ }
7499
+ if (toolIdx > i + 1) {
7500
+ const [toolMsg] = result.splice(toolIdx, 1);
7501
+ result.splice(i + 1, 0, toolMsg);
7502
+ mutated = true;
7503
+ console.warn(
7504
+ `[tool-repair] Reordered tool-result message from index ${toolIdx} to ${i + 1} to immediately follow assistant tool-call(s) (${[...callIds].join(", ")}). ${toolIdx - i - 1} message(s) were wedged between them.`
7505
+ );
7506
+ }
7507
+ i++;
7508
+ }
7509
+ return mutated ? result : messages;
7510
+ }
7462
7511
  function repairToolPairing(messages) {
7463
7512
  const toolCallIds = /* @__PURE__ */ new Set();
7464
7513
  const toolResultIds = /* @__PURE__ */ new Set();
@@ -7578,6 +7627,7 @@ ${summaryContent}`
7578
7627
  ];
7579
7628
  }
7580
7629
  messages = repairToolPairing(messages);
7630
+ messages = ensureToolResultsFollowCalls(messages);
7581
7631
  messages = ensureEndsWithUserOrTool(messages);
7582
7632
  return messages;
7583
7633
  }
@@ -7772,7 +7822,7 @@ ${summaryContent}`
7772
7822
  }
7773
7823
  }
7774
7824
  async addResponseMessages(messages) {
7775
- const safe = repairToolPairing(messages);
7825
+ const safe = ensureToolResultsFollowCalls(repairToolPairing(messages));
7776
7826
  await messageQueries.addMany(this.sessionId, safe);
7777
7827
  try {
7778
7828
  const { appendTurn: appendTurn2, flattenContent: flattenContent2 } = await Promise.resolve().then(() => (init_conversation_archive(), conversation_archive_exports));
@@ -9883,7 +9933,7 @@ ${prompt}` });
9883
9933
  const config = getConfig();
9884
9934
  const userContent = this.buildUserMessageContent(options.prompt, options.attachments);
9885
9935
  if (!options.skipSaveUserMessage) {
9886
- this.context.addUserMessage(userContent);
9936
+ await this.context.addUserMessage(userContent);
9887
9937
  }
9888
9938
  await sessionQueries.updateStatus(this.session.id, "active");
9889
9939
  let systemPrompt = await buildSystemPrompt({
@@ -9931,9 +9981,10 @@ ${personality.trim()}`;
9931
9981
  // aborted mid-tool). Repairing in `prepareStep` guarantees no orphan
9932
9982
  // ever reaches the model and we never hit AI_MissingToolResultsError.
9933
9983
  prepareStep: async ({ messages: stepMessages }) => {
9934
- const repaired = repairToolPairing(stepMessages);
9935
- if (repaired === stepMessages) return {};
9936
- return { messages: repaired };
9984
+ const paired = repairToolPairing(stepMessages);
9985
+ const ordered = ensureToolResultsFollowCalls(paired);
9986
+ if (ordered === stepMessages) return {};
9987
+ return { messages: ordered };
9937
9988
  },
9938
9989
  onStepFinish: async (step) => {
9939
9990
  options.onStepFinish?.(step);
@@ -9946,7 +9997,7 @@ ${personality.trim()}`;
9946
9997
  const result = await stream;
9947
9998
  const response = await result.response;
9948
9999
  const responseMessages = response.messages;
9949
- this.context.addResponseMessages(responseMessages);
10000
+ await this.context.addResponseMessages(responseMessages);
9950
10001
  };
9951
10002
  return {
9952
10003
  sessionId: this.session.id,
@@ -9960,7 +10011,7 @@ ${personality.trim()}`;
9960
10011
  */
9961
10012
  async run(options) {
9962
10013
  const config = getConfig();
9963
- this.context.addUserMessage(options.prompt);
10014
+ await this.context.addUserMessage(options.prompt);
9964
10015
  const systemPrompt = await buildSystemPrompt({
9965
10016
  workingDirectory: this.session.workingDirectory,
9966
10017
  skillsDirectories: config.resolvedSkillsDirectories,
@@ -9984,13 +10035,14 @@ ${personality.trim()}`;
9984
10035
  } : void 0,
9985
10036
  // Repair tool pairing before every step (see `stream()` for full rationale).
9986
10037
  prepareStep: async ({ messages: stepMessages }) => {
9987
- const repaired = repairToolPairing(stepMessages);
9988
- if (repaired === stepMessages) return {};
9989
- return { messages: repaired };
10038
+ const paired = repairToolPairing(stepMessages);
10039
+ const ordered = ensureToolResultsFollowCalls(paired);
10040
+ if (ordered === stepMessages) return {};
10041
+ return { messages: ordered };
9990
10042
  }
9991
10043
  });
9992
10044
  const responseMessages = result.response.messages;
9993
- this.context.addResponseMessages(responseMessages);
10045
+ await this.context.addResponseMessages(responseMessages);
9994
10046
  return {
9995
10047
  text: result.text,
9996
10048
  steps: result.steps
@@ -10173,9 +10225,10 @@ ${p.text}` : p.text;
10173
10225
  // See the matching note in `stream()` — repair tool pairing before
10174
10226
  // every step so we never feed the model an orphan tool-call.
10175
10227
  prepareStep: async ({ messages: stepMessages }) => {
10176
- const repaired = repairToolPairing(stepMessages);
10177
- if (repaired === stepMessages) return {};
10178
- return { messages: repaired };
10228
+ const paired = repairToolPairing(stepMessages);
10229
+ const ordered = ensureToolResultsFollowCalls(paired);
10230
+ if (ordered === stepMessages) return {};
10231
+ return { messages: ordered };
10179
10232
  },
10180
10233
  onStepFinish: async (step) => {
10181
10234
  options.onStepFinish?.(step);
@@ -12043,31 +12096,44 @@ async function recoverFromMissingToolResults(sessionId, error) {
12043
12096
  } catch (err) {
12044
12097
  console.warn("[missing-tool-recovery] could not load messages:", err?.message || err);
12045
12098
  }
12046
- const toolNameByCallId = /* @__PURE__ */ new Map();
12099
+ const toolInfoByCallId = /* @__PURE__ */ new Map();
12100
+ const resultMessageIndexByCallId = /* @__PURE__ */ new Map();
12047
12101
  const existingResultIds = /* @__PURE__ */ new Set();
12048
- for (const msg of history) {
12102
+ for (let idx = 0; idx < history.length; idx++) {
12103
+ const msg = history[idx];
12049
12104
  if (!Array.isArray(msg.content)) continue;
12050
12105
  for (const part of msg.content) {
12051
12106
  if (part?.type === "tool-call" && typeof part.toolCallId === "string") {
12052
- if (typeof part.toolName === "string") toolNameByCallId.set(part.toolCallId, part.toolName);
12107
+ if (typeof part.toolName === "string") {
12108
+ toolInfoByCallId.set(part.toolCallId, { toolName: part.toolName, callMessageIndex: idx });
12109
+ }
12053
12110
  }
12054
12111
  if (part?.type === "tool-result" && typeof part.toolCallId === "string") {
12055
12112
  existingResultIds.add(part.toolCallId);
12113
+ resultMessageIndexByCallId.set(part.toolCallId, idx);
12056
12114
  }
12057
12115
  }
12058
12116
  }
12059
- const resolved = toolCallIds.map((id) => ({
12060
- toolCallId: id,
12061
- toolName: toolNameByCallId.get(id) ?? "unknown",
12062
- foundInAssistantMessage: toolNameByCallId.has(id)
12063
- }));
12117
+ const resolved = toolCallIds.map((id) => {
12118
+ const info = toolInfoByCallId.get(id);
12119
+ const resultIdx = resultMessageIndexByCallId.get(id);
12120
+ const wedgedRoles = info && typeof resultIdx === "number" && resultIdx > info.callMessageIndex + 1 ? history.slice(info.callMessageIndex + 1, resultIdx).map((m) => m.role) : void 0;
12121
+ return {
12122
+ toolCallId: id,
12123
+ toolName: info?.toolName ?? "unknown",
12124
+ foundInAssistantMessage: !!info,
12125
+ callMessageIndex: info?.callMessageIndex,
12126
+ resultMessageIndex: resultIdx,
12127
+ wedgedMessageRoles: wedgedRoles
12128
+ };
12129
+ });
12064
12130
  const stillOrphaned = toolCallIds.filter((id) => !existingResultIds.has(id));
12065
12131
  let syntheticToolMessageSaved = false;
12066
12132
  if (stillOrphaned.length > 0) {
12067
12133
  const syntheticParts = stillOrphaned.map((id) => ({
12068
12134
  type: "tool-result",
12069
12135
  toolCallId: id,
12070
- toolName: toolNameByCallId.get(id) ?? "unknown",
12136
+ toolName: toolInfoByCallId.get(id)?.toolName ?? "unknown",
12071
12137
  output: {
12072
12138
  type: "text",
12073
12139
  value: "[Auto-recovered: the original tool execution never produced a result (crash, timeout, or message stripped during context compaction). This synthetic placeholder lets the conversation continue.]"
@@ -12084,15 +12150,49 @@ async function recoverFromMissingToolResults(sessionId, error) {
12084
12150
  }
12085
12151
  }
12086
12152
  const lastFewMessageRoles = history.slice(-6).map((m) => m.role);
12153
+ const first = resolved.find((r) => r.callMessageIndex !== void 0);
12154
+ let contextSnapshot;
12155
+ if (first?.callMessageIndex !== void 0) {
12156
+ const start = Math.max(0, first.callMessageIndex - 1);
12157
+ const end = Math.min(
12158
+ history.length,
12159
+ Math.max(first.callMessageIndex, first.resultMessageIndex ?? first.callMessageIndex) + 2
12160
+ );
12161
+ contextSnapshot = history.slice(start, end).map((m, offset) => ({
12162
+ index: start + offset,
12163
+ role: m.role,
12164
+ summary: summarizeContent(m.content)
12165
+ }));
12166
+ }
12167
+ const anyWedged = resolved.some((r) => r.wedgedMessageRoles && r.wedgedMessageRoles.length > 0);
12087
12168
  return {
12088
12169
  kind: "missing_tool_results",
12089
12170
  toolCallIds,
12090
12171
  resolved,
12091
12172
  syntheticToolMessageSaved,
12092
12173
  lastFewMessageRoles,
12093
- hint: syntheticToolMessageSaved ? "Synthetic tool-result(s) saved. Re-send your message to continue." : "Could not auto-recover; please reset the session or revert to the previous checkpoint."
12174
+ contextSnapshot,
12175
+ hint: anyWedged ? "A non-tool message was wedged between the assistant tool-call and its tool-result (likely a Slack/system inbox event that arrived mid-turn). " + (syntheticToolMessageSaved ? "Synthetic tool-result was added as a fallback, but the proper fix (now in place) is the reordering pass that moves tool-results to immediately follow their tool-calls." : "The reordering pass should fix this on the next turn; if not, revert to the previous checkpoint.") : syntheticToolMessageSaved ? "Synthetic tool-result(s) saved. Re-send your message to continue." : "Could not auto-recover; please reset the session or revert to the previous checkpoint."
12094
12176
  };
12095
12177
  }
12178
+ function summarizeContent(content) {
12179
+ if (typeof content === "string") {
12180
+ return content.length > 160 ? content.slice(0, 160) + "\u2026" : content;
12181
+ }
12182
+ if (!Array.isArray(content)) return String(content);
12183
+ const parts = content.map((p) => {
12184
+ if (!p || typeof p !== "object") return String(p);
12185
+ if (p.type === "text") {
12186
+ const t = String(p.text ?? "");
12187
+ return `text(${t.length > 80 ? t.slice(0, 80) + "\u2026" : t})`;
12188
+ }
12189
+ if (p.type === "tool-call") return `tool-call(${p.toolName}:${p.toolCallId})`;
12190
+ if (p.type === "tool-result") return `tool-result(${p.toolName ?? "?"}:${p.toolCallId})`;
12191
+ if (p.type === "reasoning") return "reasoning";
12192
+ return p.type ?? "unknown";
12193
+ });
12194
+ return parts.join(", ");
12195
+ }
12096
12196
 
12097
12197
  // src/server/routes/agents.ts
12098
12198
  init_agent();