sparkecoder 0.1.122 → 0.1.124
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/agent/index.d.ts +3 -3
- package/dist/agent/index.js +67 -14
- package/dist/agent/index.js.map +1 -1
- package/dist/cli.js +201 -66
- package/dist/cli.js.map +1 -1
- package/dist/db/index.d.ts +2 -2
- package/dist/{index-DczYH89U.d.ts → index-Bcz0aCAR.d.ts} +104 -104
- package/dist/index.d.ts +5 -5
- package/dist/index.js +124 -24
- package/dist/index.js.map +1 -1
- package/dist/{schema-DxrKyetI.d.ts → schema-BWbWmfDQ.d.ts} +3 -3
- package/dist/{search-CVVfuBPZ.d.ts → search-DOzC4ojH.d.ts} +4 -4
- package/dist/server/index.js +124 -24
- package/dist/server/index.js.map +1 -1
- package/dist/skills/default/recording.md +2 -2
- package/dist/tools/index.d.ts +3 -3
- package/package.json +1 -1
- package/src/skills/default/recording.md +2 -2
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/web/.next/build-manifest.json +2 -2
- package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
- package/web/.next/standalone/web/.next/server/app/(main)/agents/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page.js.nft.json +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/settings/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.html +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.rsc +3 -3
- package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents/__PAGE__.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/agents.segments/_full.segment.rsc +3 -3
- package/web/.next/standalone/web/.next/server/app/agents.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.html +1 -1
- package/web/.next/standalone/web/.next/server/app/index.rsc +3 -3
- package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +3 -3
- package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.html +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.rsc +3 -3
- package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings/__PAGE__.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/settings.segments/_full.segment.rsc +3 -3
- package/web/.next/standalone/web/.next/server/app/settings.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_c87abaf4._.js → 2374f_12d55e68._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_1f3f2d00._.js → 2374f_1c0639c2._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_a0d5caeb._.js → 2374f_28cd6777._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_570c34dc._.js → 2374f_5f47a9b7._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_d8122230._.js → 2374f_aa218457._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_9c560f3a._.js → 2374f_f678a96f._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_38945fd9._.js → 2374f_fac4000d._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{[root-of-the-server]__4de426bd._.js → [root-of-the-server]__e5911ea8._.js} +4 -4
- package/web/.next/standalone/web/.next/server/chunks/ssr/{web_62ca4286._.js → web_2966b3a3._.js} +2 -2
- package/web/.next/standalone/web/.next/server/chunks/ssr/web_4fe3c244._.js +1 -1
- package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
- package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
- package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
- package/web/.next/standalone/web/.next/static/chunks/{91988e253d5fa420.js → 4d95c15f712c9e06.js} +5 -5
- package/web/.next/standalone/web/.next/static/chunks/780c93257fac7d43.js +1 -0
- package/web/.next/standalone/web/.next/static/static/chunks/{91988e253d5fa420.js → 4d95c15f712c9e06.js} +5 -5
- package/web/.next/standalone/web/.next/static/static/chunks/780c93257fac7d43.js +1 -0
- package/web/.next/standalone/web/src/components/chat-interface.tsx +112 -1
- package/web/.next/static/chunks/{91988e253d5fa420.js → 4d95c15f712c9e06.js} +5 -5
- package/web/.next/static/chunks/780c93257fac7d43.js +1 -0
- package/web/.next/standalone/web/.next/static/chunks/f0f19357f3fb7cf8.js +0 -1
- package/web/.next/standalone/web/.next/static/static/chunks/f0f19357f3fb7cf8.js +0 -1
- package/web/.next/static/chunks/f0f19357f3fb7cf8.js +0 -1
- /package/web/.next/standalone/web/.next/static/{BEIBC9-dP0_AWGmRy97hJ → cYXZ7UzGc5TttFIXRRcSC}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{BEIBC9-dP0_AWGmRy97hJ → cYXZ7UzGc5TttFIXRRcSC}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/{BEIBC9-dP0_AWGmRy97hJ → cYXZ7UzGc5TttFIXRRcSC}/_ssgManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/static/{BEIBC9-dP0_AWGmRy97hJ → cYXZ7UzGc5TttFIXRRcSC}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/static/{BEIBC9-dP0_AWGmRy97hJ → cYXZ7UzGc5TttFIXRRcSC}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/static/{BEIBC9-dP0_AWGmRy97hJ → cYXZ7UzGc5TttFIXRRcSC}/_ssgManifest.js +0 -0
- /package/web/.next/static/{BEIBC9-dP0_AWGmRy97hJ → cYXZ7UzGc5TttFIXRRcSC}/_buildManifest.js +0 -0
- /package/web/.next/static/{BEIBC9-dP0_AWGmRy97hJ → cYXZ7UzGc5TttFIXRRcSC}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{BEIBC9-dP0_AWGmRy97hJ → cYXZ7UzGc5TttFIXRRcSC}/_ssgManifest.js +0 -0
package/dist/cli.js
CHANGED
|
@@ -8202,6 +8202,55 @@ function wrapToolsNeverThrow(tools) {
|
|
|
8202
8202
|
}
|
|
8203
8203
|
return wrapped;
|
|
8204
8204
|
}
|
|
8205
|
+
function ensureToolResultsFollowCalls(messages) {
|
|
8206
|
+
if (!Array.isArray(messages) || messages.length < 3) return messages;
|
|
8207
|
+
let mutated = false;
|
|
8208
|
+
const result = messages.slice();
|
|
8209
|
+
let i = 0;
|
|
8210
|
+
while (i < result.length) {
|
|
8211
|
+
const msg = result[i];
|
|
8212
|
+
if (msg?.role !== "assistant" || !Array.isArray(msg.content)) {
|
|
8213
|
+
i++;
|
|
8214
|
+
continue;
|
|
8215
|
+
}
|
|
8216
|
+
const callIds = /* @__PURE__ */ new Set();
|
|
8217
|
+
for (const part of msg.content) {
|
|
8218
|
+
if (part?.type === "tool-call" && typeof part.toolCallId === "string") {
|
|
8219
|
+
callIds.add(part.toolCallId);
|
|
8220
|
+
}
|
|
8221
|
+
}
|
|
8222
|
+
if (callIds.size === 0) {
|
|
8223
|
+
i++;
|
|
8224
|
+
continue;
|
|
8225
|
+
}
|
|
8226
|
+
let toolIdx = -1;
|
|
8227
|
+
for (let j = i + 1; j < result.length; j++) {
|
|
8228
|
+
const m = result[j];
|
|
8229
|
+
if (m?.role === "assistant" && Array.isArray(m.content) && m.content.some((p) => p?.type === "tool-call")) {
|
|
8230
|
+
break;
|
|
8231
|
+
}
|
|
8232
|
+
if (m?.role === "tool" && Array.isArray(m.content)) {
|
|
8233
|
+
const answersOne = m.content.some(
|
|
8234
|
+
(p) => p?.type === "tool-result" && typeof p.toolCallId === "string" && callIds.has(p.toolCallId)
|
|
8235
|
+
);
|
|
8236
|
+
if (answersOne) {
|
|
8237
|
+
toolIdx = j;
|
|
8238
|
+
break;
|
|
8239
|
+
}
|
|
8240
|
+
}
|
|
8241
|
+
}
|
|
8242
|
+
if (toolIdx > i + 1) {
|
|
8243
|
+
const [toolMsg] = result.splice(toolIdx, 1);
|
|
8244
|
+
result.splice(i + 1, 0, toolMsg);
|
|
8245
|
+
mutated = true;
|
|
8246
|
+
console.warn(
|
|
8247
|
+
`[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.`
|
|
8248
|
+
);
|
|
8249
|
+
}
|
|
8250
|
+
i++;
|
|
8251
|
+
}
|
|
8252
|
+
return mutated ? result : messages;
|
|
8253
|
+
}
|
|
8205
8254
|
function repairToolPairing(messages) {
|
|
8206
8255
|
const toolCallIds = /* @__PURE__ */ new Set();
|
|
8207
8256
|
const toolResultIds = /* @__PURE__ */ new Set();
|
|
@@ -8321,6 +8370,7 @@ ${summaryContent}`
|
|
|
8321
8370
|
];
|
|
8322
8371
|
}
|
|
8323
8372
|
messages = repairToolPairing(messages);
|
|
8373
|
+
messages = ensureToolResultsFollowCalls(messages);
|
|
8324
8374
|
messages = ensureEndsWithUserOrTool(messages);
|
|
8325
8375
|
return messages;
|
|
8326
8376
|
}
|
|
@@ -8515,7 +8565,7 @@ ${summaryContent}`
|
|
|
8515
8565
|
}
|
|
8516
8566
|
}
|
|
8517
8567
|
async addResponseMessages(messages) {
|
|
8518
|
-
const safe = repairToolPairing(messages);
|
|
8568
|
+
const safe = ensureToolResultsFollowCalls(repairToolPairing(messages));
|
|
8519
8569
|
await messageQueries.addMany(this.sessionId, safe);
|
|
8520
8570
|
try {
|
|
8521
8571
|
const { appendTurn: appendTurn2, flattenContent: flattenContent2 } = await Promise.resolve().then(() => (init_conversation_archive(), conversation_archive_exports));
|
|
@@ -10626,7 +10676,7 @@ ${prompt}` });
|
|
|
10626
10676
|
const config = getConfig();
|
|
10627
10677
|
const userContent = this.buildUserMessageContent(options.prompt, options.attachments);
|
|
10628
10678
|
if (!options.skipSaveUserMessage) {
|
|
10629
|
-
this.context.addUserMessage(userContent);
|
|
10679
|
+
await this.context.addUserMessage(userContent);
|
|
10630
10680
|
}
|
|
10631
10681
|
await sessionQueries.updateStatus(this.session.id, "active");
|
|
10632
10682
|
let systemPrompt = await buildSystemPrompt({
|
|
@@ -10674,9 +10724,10 @@ ${personality.trim()}`;
|
|
|
10674
10724
|
// aborted mid-tool). Repairing in `prepareStep` guarantees no orphan
|
|
10675
10725
|
// ever reaches the model and we never hit AI_MissingToolResultsError.
|
|
10676
10726
|
prepareStep: async ({ messages: stepMessages }) => {
|
|
10677
|
-
const
|
|
10678
|
-
|
|
10679
|
-
|
|
10727
|
+
const paired = repairToolPairing(stepMessages);
|
|
10728
|
+
const ordered = ensureToolResultsFollowCalls(paired);
|
|
10729
|
+
if (ordered === stepMessages) return {};
|
|
10730
|
+
return { messages: ordered };
|
|
10680
10731
|
},
|
|
10681
10732
|
onStepFinish: async (step) => {
|
|
10682
10733
|
options.onStepFinish?.(step);
|
|
@@ -10689,7 +10740,7 @@ ${personality.trim()}`;
|
|
|
10689
10740
|
const result = await stream;
|
|
10690
10741
|
const response = await result.response;
|
|
10691
10742
|
const responseMessages = response.messages;
|
|
10692
|
-
this.context.addResponseMessages(responseMessages);
|
|
10743
|
+
await this.context.addResponseMessages(responseMessages);
|
|
10693
10744
|
};
|
|
10694
10745
|
return {
|
|
10695
10746
|
sessionId: this.session.id,
|
|
@@ -10703,7 +10754,7 @@ ${personality.trim()}`;
|
|
|
10703
10754
|
*/
|
|
10704
10755
|
async run(options) {
|
|
10705
10756
|
const config = getConfig();
|
|
10706
|
-
this.context.addUserMessage(options.prompt);
|
|
10757
|
+
await this.context.addUserMessage(options.prompt);
|
|
10707
10758
|
const systemPrompt = await buildSystemPrompt({
|
|
10708
10759
|
workingDirectory: this.session.workingDirectory,
|
|
10709
10760
|
skillsDirectories: config.resolvedSkillsDirectories,
|
|
@@ -10727,13 +10778,14 @@ ${personality.trim()}`;
|
|
|
10727
10778
|
} : void 0,
|
|
10728
10779
|
// Repair tool pairing before every step (see `stream()` for full rationale).
|
|
10729
10780
|
prepareStep: async ({ messages: stepMessages }) => {
|
|
10730
|
-
const
|
|
10731
|
-
|
|
10732
|
-
|
|
10781
|
+
const paired = repairToolPairing(stepMessages);
|
|
10782
|
+
const ordered = ensureToolResultsFollowCalls(paired);
|
|
10783
|
+
if (ordered === stepMessages) return {};
|
|
10784
|
+
return { messages: ordered };
|
|
10733
10785
|
}
|
|
10734
10786
|
});
|
|
10735
10787
|
const responseMessages = result.response.messages;
|
|
10736
|
-
this.context.addResponseMessages(responseMessages);
|
|
10788
|
+
await this.context.addResponseMessages(responseMessages);
|
|
10737
10789
|
return {
|
|
10738
10790
|
text: result.text,
|
|
10739
10791
|
steps: result.steps
|
|
@@ -10916,9 +10968,10 @@ ${p.text}` : p.text;
|
|
|
10916
10968
|
// See the matching note in `stream()` — repair tool pairing before
|
|
10917
10969
|
// every step so we never feed the model an orphan tool-call.
|
|
10918
10970
|
prepareStep: async ({ messages: stepMessages }) => {
|
|
10919
|
-
const
|
|
10920
|
-
|
|
10921
|
-
|
|
10971
|
+
const paired = repairToolPairing(stepMessages);
|
|
10972
|
+
const ordered = ensureToolResultsFollowCalls(paired);
|
|
10973
|
+
if (ordered === stepMessages) return {};
|
|
10974
|
+
return { messages: ordered };
|
|
10922
10975
|
},
|
|
10923
10976
|
onStepFinish: async (step) => {
|
|
10924
10977
|
options.onStepFinish?.(step);
|
|
@@ -13014,31 +13067,44 @@ async function recoverFromMissingToolResults(sessionId, error) {
|
|
|
13014
13067
|
} catch (err) {
|
|
13015
13068
|
console.warn("[missing-tool-recovery] could not load messages:", err?.message || err);
|
|
13016
13069
|
}
|
|
13017
|
-
const
|
|
13070
|
+
const toolInfoByCallId = /* @__PURE__ */ new Map();
|
|
13071
|
+
const resultMessageIndexByCallId = /* @__PURE__ */ new Map();
|
|
13018
13072
|
const existingResultIds = /* @__PURE__ */ new Set();
|
|
13019
|
-
for (
|
|
13073
|
+
for (let idx = 0; idx < history.length; idx++) {
|
|
13074
|
+
const msg = history[idx];
|
|
13020
13075
|
if (!Array.isArray(msg.content)) continue;
|
|
13021
13076
|
for (const part of msg.content) {
|
|
13022
13077
|
if (part?.type === "tool-call" && typeof part.toolCallId === "string") {
|
|
13023
|
-
if (typeof part.toolName === "string")
|
|
13078
|
+
if (typeof part.toolName === "string") {
|
|
13079
|
+
toolInfoByCallId.set(part.toolCallId, { toolName: part.toolName, callMessageIndex: idx });
|
|
13080
|
+
}
|
|
13024
13081
|
}
|
|
13025
13082
|
if (part?.type === "tool-result" && typeof part.toolCallId === "string") {
|
|
13026
13083
|
existingResultIds.add(part.toolCallId);
|
|
13084
|
+
resultMessageIndexByCallId.set(part.toolCallId, idx);
|
|
13027
13085
|
}
|
|
13028
13086
|
}
|
|
13029
13087
|
}
|
|
13030
|
-
const resolved = toolCallIds.map((id) =>
|
|
13031
|
-
|
|
13032
|
-
|
|
13033
|
-
|
|
13034
|
-
|
|
13088
|
+
const resolved = toolCallIds.map((id) => {
|
|
13089
|
+
const info = toolInfoByCallId.get(id);
|
|
13090
|
+
const resultIdx = resultMessageIndexByCallId.get(id);
|
|
13091
|
+
const wedgedRoles = info && typeof resultIdx === "number" && resultIdx > info.callMessageIndex + 1 ? history.slice(info.callMessageIndex + 1, resultIdx).map((m) => m.role) : void 0;
|
|
13092
|
+
return {
|
|
13093
|
+
toolCallId: id,
|
|
13094
|
+
toolName: info?.toolName ?? "unknown",
|
|
13095
|
+
foundInAssistantMessage: !!info,
|
|
13096
|
+
callMessageIndex: info?.callMessageIndex,
|
|
13097
|
+
resultMessageIndex: resultIdx,
|
|
13098
|
+
wedgedMessageRoles: wedgedRoles
|
|
13099
|
+
};
|
|
13100
|
+
});
|
|
13035
13101
|
const stillOrphaned = toolCallIds.filter((id) => !existingResultIds.has(id));
|
|
13036
13102
|
let syntheticToolMessageSaved = false;
|
|
13037
13103
|
if (stillOrphaned.length > 0) {
|
|
13038
13104
|
const syntheticParts = stillOrphaned.map((id) => ({
|
|
13039
13105
|
type: "tool-result",
|
|
13040
13106
|
toolCallId: id,
|
|
13041
|
-
toolName:
|
|
13107
|
+
toolName: toolInfoByCallId.get(id)?.toolName ?? "unknown",
|
|
13042
13108
|
output: {
|
|
13043
13109
|
type: "text",
|
|
13044
13110
|
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.]"
|
|
@@ -13055,15 +13121,49 @@ async function recoverFromMissingToolResults(sessionId, error) {
|
|
|
13055
13121
|
}
|
|
13056
13122
|
}
|
|
13057
13123
|
const lastFewMessageRoles = history.slice(-6).map((m) => m.role);
|
|
13124
|
+
const first = resolved.find((r) => r.callMessageIndex !== void 0);
|
|
13125
|
+
let contextSnapshot;
|
|
13126
|
+
if (first?.callMessageIndex !== void 0) {
|
|
13127
|
+
const start = Math.max(0, first.callMessageIndex - 1);
|
|
13128
|
+
const end = Math.min(
|
|
13129
|
+
history.length,
|
|
13130
|
+
Math.max(first.callMessageIndex, first.resultMessageIndex ?? first.callMessageIndex) + 2
|
|
13131
|
+
);
|
|
13132
|
+
contextSnapshot = history.slice(start, end).map((m, offset) => ({
|
|
13133
|
+
index: start + offset,
|
|
13134
|
+
role: m.role,
|
|
13135
|
+
summary: summarizeContent(m.content)
|
|
13136
|
+
}));
|
|
13137
|
+
}
|
|
13138
|
+
const anyWedged = resolved.some((r) => r.wedgedMessageRoles && r.wedgedMessageRoles.length > 0);
|
|
13058
13139
|
return {
|
|
13059
13140
|
kind: "missing_tool_results",
|
|
13060
13141
|
toolCallIds,
|
|
13061
13142
|
resolved,
|
|
13062
13143
|
syntheticToolMessageSaved,
|
|
13063
13144
|
lastFewMessageRoles,
|
|
13064
|
-
|
|
13145
|
+
contextSnapshot,
|
|
13146
|
+
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."
|
|
13065
13147
|
};
|
|
13066
13148
|
}
|
|
13149
|
+
function summarizeContent(content) {
|
|
13150
|
+
if (typeof content === "string") {
|
|
13151
|
+
return content.length > 160 ? content.slice(0, 160) + "\u2026" : content;
|
|
13152
|
+
}
|
|
13153
|
+
if (!Array.isArray(content)) return String(content);
|
|
13154
|
+
const parts = content.map((p) => {
|
|
13155
|
+
if (!p || typeof p !== "object") return String(p);
|
|
13156
|
+
if (p.type === "text") {
|
|
13157
|
+
const t = String(p.text ?? "");
|
|
13158
|
+
return `text(${t.length > 80 ? t.slice(0, 80) + "\u2026" : t})`;
|
|
13159
|
+
}
|
|
13160
|
+
if (p.type === "tool-call") return `tool-call(${p.toolName}:${p.toolCallId})`;
|
|
13161
|
+
if (p.type === "tool-result") return `tool-result(${p.toolName ?? "?"}:${p.toolCallId})`;
|
|
13162
|
+
if (p.type === "reasoning") return "reasoning";
|
|
13163
|
+
return p.type ?? "unknown";
|
|
13164
|
+
});
|
|
13165
|
+
return parts.join(", ");
|
|
13166
|
+
}
|
|
13067
13167
|
|
|
13068
13168
|
// src/server/routes/agents.ts
|
|
13069
13169
|
init_agent();
|
|
@@ -16924,7 +17024,7 @@ function generateOpenAPISpec() {
|
|
|
16924
17024
|
init_config();
|
|
16925
17025
|
init_semantic();
|
|
16926
17026
|
init_db();
|
|
16927
|
-
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync8, readFileSync as readFileSync11, existsSync as existsSync23, statSync as statSync4 } from "fs";
|
|
17027
|
+
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync8, readFileSync as readFileSync11, existsSync as existsSync23, statSync as statSync4, unlinkSync as unlinkSync3 } from "fs";
|
|
16928
17028
|
import { resolve as resolve13, join as join18 } from "path";
|
|
16929
17029
|
function getCliVersion() {
|
|
16930
17030
|
const here = dirname11(fileURLToPath5(import.meta.url));
|
|
@@ -18534,7 +18634,9 @@ program.command("request-permissions").description("Open System Settings to the
|
|
|
18534
18634
|
console.log();
|
|
18535
18635
|
});
|
|
18536
18636
|
{
|
|
18537
|
-
let
|
|
18637
|
+
let shellEscape2 = function(str) {
|
|
18638
|
+
return `'${str.replace(/'/g, "'\\''")}'`;
|
|
18639
|
+
}, stateFilePath = function() {
|
|
18538
18640
|
return join18(ensureAppDataDirectory(), "recordings.json");
|
|
18539
18641
|
}, readState = function() {
|
|
18540
18642
|
const p = stateFilePath();
|
|
@@ -18556,21 +18658,81 @@ program.command("request-permissions").description("Open System Settings to the
|
|
|
18556
18658
|
}, pruneDead = function(rows) {
|
|
18557
18659
|
return rows.filter((r) => isAlive(r.pid));
|
|
18558
18660
|
};
|
|
18559
|
-
stateFilePath2 = stateFilePath, readState2 = readState, writeState2 = writeState, isAlive2 = isAlive, pruneDead2 = pruneDead;
|
|
18661
|
+
shellEscape3 = shellEscape2, stateFilePath2 = stateFilePath, readState2 = readState, writeState2 = writeState, isAlive2 = isAlive, pruneDead2 = pruneDead;
|
|
18662
|
+
async function stopRecorderPid(pid) {
|
|
18663
|
+
if (!isAlive(pid)) return;
|
|
18664
|
+
try {
|
|
18665
|
+
process.kill(pid, "SIGINT");
|
|
18666
|
+
} catch {
|
|
18667
|
+
return;
|
|
18668
|
+
}
|
|
18669
|
+
for (let i = 0; i < 40; i++) {
|
|
18670
|
+
if (!isAlive(pid)) break;
|
|
18671
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
18672
|
+
}
|
|
18673
|
+
if (isAlive(pid)) {
|
|
18674
|
+
try {
|
|
18675
|
+
process.kill(pid, "SIGTERM");
|
|
18676
|
+
} catch {
|
|
18677
|
+
}
|
|
18678
|
+
}
|
|
18679
|
+
}
|
|
18680
|
+
async function convertCaptureToMp4(capturePath, mp4Path) {
|
|
18681
|
+
try {
|
|
18682
|
+
const { exec: exec8 } = await import("child_process");
|
|
18683
|
+
const { promisify: promisify8 } = await import("util");
|
|
18684
|
+
const execAsync8 = promisify8(exec8);
|
|
18685
|
+
await execAsync8(
|
|
18686
|
+
`ffmpeg -y -i ${shellEscape2(capturePath)} -c:v libx264 -pix_fmt yuv420p -preset fast -crf 23 -movflags +faststart ${shellEscape2(mp4Path)}`,
|
|
18687
|
+
{ timeout: 12e4, maxBuffer: 10 * 1024 * 1024 }
|
|
18688
|
+
);
|
|
18689
|
+
return existsSync23(mp4Path) && statSync4(mp4Path).size > 0;
|
|
18690
|
+
} catch {
|
|
18691
|
+
return false;
|
|
18692
|
+
}
|
|
18693
|
+
}
|
|
18694
|
+
async function finalizeRecording(row) {
|
|
18695
|
+
await stopRecorderPid(row.pid);
|
|
18696
|
+
let finalPath = row.path;
|
|
18697
|
+
let warning;
|
|
18698
|
+
if (row.capturePath) {
|
|
18699
|
+
for (let i = 0; i < 20; i++) {
|
|
18700
|
+
if (existsSync23(row.capturePath) && statSync4(row.capturePath).size > 0) break;
|
|
18701
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
18702
|
+
}
|
|
18703
|
+
if (existsSync23(row.capturePath)) {
|
|
18704
|
+
const converted = await convertCaptureToMp4(row.capturePath, row.path);
|
|
18705
|
+
if (converted) {
|
|
18706
|
+
try {
|
|
18707
|
+
unlinkSync3(row.capturePath);
|
|
18708
|
+
} catch {
|
|
18709
|
+
}
|
|
18710
|
+
} else {
|
|
18711
|
+
finalPath = row.capturePath;
|
|
18712
|
+
warning = "ffmpeg conversion to mp4 failed; kept .mov capture file";
|
|
18713
|
+
}
|
|
18714
|
+
}
|
|
18715
|
+
}
|
|
18716
|
+
const ok = existsSync23(finalPath);
|
|
18717
|
+
const sizeMb = ok ? Math.round(statSync4(finalPath).size / (1024 * 1024) * 10) / 10 : 0;
|
|
18718
|
+
return { path: finalPath, ok, sizeMb, warning };
|
|
18719
|
+
}
|
|
18560
18720
|
const record = program.command("record").description("Start/stop screen recordings");
|
|
18561
18721
|
record.command("start").description("Start a screen recording (returns id, path, pid as JSON)").option("--name <slug>", "Optional human-readable label for the recording").option("--dir <path>", "Output directory (default: ~/recordings)").action(async (opts) => {
|
|
18562
18722
|
const { homedir: homedir2, platform: osPlatform } = await import("os");
|
|
18563
18723
|
const outDir = opts.dir ? resolve13(opts.dir.replace(/^~/, homedir2())) : join18(homedir2(), "recordings");
|
|
18564
18724
|
mkdirSync11(outDir, { recursive: true });
|
|
18565
18725
|
const id = `rec-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
|
|
18566
|
-
const ext =
|
|
18726
|
+
const ext = "mp4";
|
|
18567
18727
|
const filename = `${id}${opts.name ? `-${String(opts.name).replace(/[^a-z0-9-]+/gi, "-").toLowerCase()}` : ""}.${ext}`;
|
|
18568
18728
|
const path = join18(outDir, filename);
|
|
18569
18729
|
let cmd;
|
|
18570
18730
|
let args;
|
|
18731
|
+
let capturePath;
|
|
18571
18732
|
if (osPlatform() === "darwin") {
|
|
18733
|
+
capturePath = path.replace(/\.mp4$/i, ".mov");
|
|
18572
18734
|
cmd = existsSync23("/usr/sbin/screencapture") ? "/usr/sbin/screencapture" : "screencapture";
|
|
18573
|
-
args = ["-v", "-C", "-k",
|
|
18735
|
+
args = ["-v", "-C", "-k", capturePath];
|
|
18574
18736
|
} else if (osPlatform() === "linux") {
|
|
18575
18737
|
const display = process.env.DISPLAY || ":0.0";
|
|
18576
18738
|
const size = process.env.SPARKECODER_RECORD_SIZE || "1920x1080";
|
|
@@ -18615,6 +18777,7 @@ program.command("request-permissions").description("Open System Settings to the
|
|
|
18615
18777
|
});
|
|
18616
18778
|
await new Promise((r) => setTimeout(r, 600));
|
|
18617
18779
|
if (spawnError || exited || !child.pid) {
|
|
18780
|
+
child.stderr?.destroy();
|
|
18618
18781
|
const diagnosis = [
|
|
18619
18782
|
spawnError && `spawn error: ${spawnError}`,
|
|
18620
18783
|
exited && `recorder exited code=${exitCode} within 600ms`,
|
|
@@ -18633,11 +18796,13 @@ program.command("request-permissions").description("Open System Settings to the
|
|
|
18633
18796
|
}));
|
|
18634
18797
|
process.exit(1);
|
|
18635
18798
|
}
|
|
18799
|
+
child.stderr?.destroy();
|
|
18636
18800
|
child.unref();
|
|
18637
18801
|
const row = {
|
|
18638
18802
|
id,
|
|
18639
18803
|
name: opts.name,
|
|
18640
18804
|
path,
|
|
18805
|
+
capturePath,
|
|
18641
18806
|
pid: child.pid,
|
|
18642
18807
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18643
18808
|
platform: osPlatform()
|
|
@@ -18655,31 +18820,15 @@ program.command("request-permissions").description("Open System Settings to the
|
|
|
18655
18820
|
process.exit(1);
|
|
18656
18821
|
}
|
|
18657
18822
|
const startedAt = new Date(row.startedAt).getTime();
|
|
18658
|
-
|
|
18659
|
-
try {
|
|
18660
|
-
process.kill(row.pid, "SIGINT");
|
|
18661
|
-
} catch {
|
|
18662
|
-
}
|
|
18663
|
-
for (let i = 0; i < 40; i++) {
|
|
18664
|
-
if (!isAlive(row.pid)) break;
|
|
18665
|
-
await new Promise((r) => setTimeout(r, 200));
|
|
18666
|
-
}
|
|
18667
|
-
if (isAlive(row.pid)) {
|
|
18668
|
-
try {
|
|
18669
|
-
process.kill(row.pid, "SIGTERM");
|
|
18670
|
-
} catch {
|
|
18671
|
-
}
|
|
18672
|
-
}
|
|
18673
|
-
}
|
|
18823
|
+
const { path: finalPath, ok, sizeMb, warning } = await finalizeRecording(row);
|
|
18674
18824
|
writeState(rows.filter((r) => r.id !== id));
|
|
18675
|
-
const fileExists = existsSync23(row.path);
|
|
18676
|
-
const sizeMb = fileExists ? Math.round(statSync4(row.path).size / (1024 * 1024) * 10) / 10 : 0;
|
|
18677
18825
|
console.log(JSON.stringify({
|
|
18678
18826
|
id,
|
|
18679
|
-
path:
|
|
18827
|
+
path: finalPath,
|
|
18680
18828
|
durationSec: Math.round((Date.now() - startedAt) / 1e3),
|
|
18681
18829
|
sizeMb,
|
|
18682
|
-
ok
|
|
18830
|
+
ok,
|
|
18831
|
+
...warning ? { warning } : {}
|
|
18683
18832
|
}));
|
|
18684
18833
|
});
|
|
18685
18834
|
record.command("list").description("List active recordings").action(() => {
|
|
@@ -18691,28 +18840,14 @@ program.command("request-permissions").description("Open System Settings to the
|
|
|
18691
18840
|
const rows = readState();
|
|
18692
18841
|
const stopped = [];
|
|
18693
18842
|
for (const r of rows) {
|
|
18694
|
-
|
|
18695
|
-
|
|
18696
|
-
process.kill(r.pid, "SIGINT");
|
|
18697
|
-
} catch {
|
|
18698
|
-
}
|
|
18699
|
-
for (let i = 0; i < 30; i++) {
|
|
18700
|
-
if (!isAlive(r.pid)) break;
|
|
18701
|
-
await new Promise((res) => setTimeout(res, 200));
|
|
18702
|
-
}
|
|
18703
|
-
if (isAlive(r.pid)) {
|
|
18704
|
-
try {
|
|
18705
|
-
process.kill(r.pid, "SIGTERM");
|
|
18706
|
-
} catch {
|
|
18707
|
-
}
|
|
18708
|
-
}
|
|
18709
|
-
}
|
|
18710
|
-
stopped.push({ id: r.id, path: r.path, ok: existsSync23(r.path) });
|
|
18843
|
+
const { path: finalPath, ok, warning } = await finalizeRecording(r);
|
|
18844
|
+
stopped.push({ id: r.id, path: finalPath, ok, ...warning ? { warning } : {} });
|
|
18711
18845
|
}
|
|
18712
18846
|
writeState([]);
|
|
18713
18847
|
console.log(JSON.stringify({ stopped }));
|
|
18714
18848
|
});
|
|
18715
18849
|
}
|
|
18850
|
+
var shellEscape3;
|
|
18716
18851
|
var stateFilePath2;
|
|
18717
18852
|
var readState2;
|
|
18718
18853
|
var writeState2;
|