@f5xc-salesdemos/xcsh 18.54.0 → 18.55.0
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/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5xc-salesdemos/xcsh",
|
|
4
|
-
"version": "18.
|
|
4
|
+
"version": "18.55.0",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://github.com/f5xc-salesdemos/xcsh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -48,12 +48,12 @@
|
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@agentclientprotocol/sdk": "0.16.1",
|
|
50
50
|
"@mozilla/readability": "^0.6",
|
|
51
|
-
"@f5xc-salesdemos/xcsh-stats": "18.
|
|
52
|
-
"@f5xc-salesdemos/pi-agent-core": "18.
|
|
53
|
-
"@f5xc-salesdemos/pi-ai": "18.
|
|
54
|
-
"@f5xc-salesdemos/pi-natives": "18.
|
|
55
|
-
"@f5xc-salesdemos/pi-tui": "18.
|
|
56
|
-
"@f5xc-salesdemos/pi-utils": "18.
|
|
51
|
+
"@f5xc-salesdemos/xcsh-stats": "18.55.0",
|
|
52
|
+
"@f5xc-salesdemos/pi-agent-core": "18.55.0",
|
|
53
|
+
"@f5xc-salesdemos/pi-ai": "18.55.0",
|
|
54
|
+
"@f5xc-salesdemos/pi-natives": "18.55.0",
|
|
55
|
+
"@f5xc-salesdemos/pi-tui": "18.55.0",
|
|
56
|
+
"@f5xc-salesdemos/pi-utils": "18.55.0",
|
|
57
57
|
"@sinclair/typebox": "^0.34",
|
|
58
58
|
"@xterm/headless": "^6.0",
|
|
59
59
|
"ajv": "^8.18",
|
|
@@ -17,17 +17,17 @@ export interface BuildInfo {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const BUILD_INFO: BuildInfo = {
|
|
20
|
-
"version": "18.
|
|
21
|
-
"commit": "
|
|
22
|
-
"shortCommit": "
|
|
20
|
+
"version": "18.55.0",
|
|
21
|
+
"commit": "c87217beee0abc34c5d21baa7a6ecbd3e1109630",
|
|
22
|
+
"shortCommit": "c87217b",
|
|
23
23
|
"branch": "main",
|
|
24
|
-
"tag": "v18.
|
|
25
|
-
"commitDate": "2026-05-
|
|
26
|
-
"buildDate": "2026-05-
|
|
24
|
+
"tag": "v18.55.0",
|
|
25
|
+
"commitDate": "2026-05-09T19:47:18Z",
|
|
26
|
+
"buildDate": "2026-05-09T20:10:12.336Z",
|
|
27
27
|
"dirty": false,
|
|
28
28
|
"prNumber": "",
|
|
29
29
|
"repoUrl": "https://github.com/f5xc-salesdemos/xcsh",
|
|
30
30
|
"repoSlug": "f5xc-salesdemos/xcsh",
|
|
31
|
-
"commitUrl": "https://github.com/f5xc-salesdemos/xcsh/commit/
|
|
32
|
-
"releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v18.
|
|
31
|
+
"commitUrl": "https://github.com/f5xc-salesdemos/xcsh/commit/c87217beee0abc34c5d21baa7a6ecbd3e1109630",
|
|
32
|
+
"releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v18.55.0"
|
|
33
33
|
};
|
package/src/session/messages.ts
CHANGED
|
@@ -292,14 +292,14 @@ function repairToolResultOrdering(messages: Message[]): Message[] {
|
|
|
292
292
|
}
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
-
// Track which
|
|
296
|
-
const
|
|
295
|
+
// Track which message indices have been consumed (placed or displaced) by repair
|
|
296
|
+
const consumedIndices = new Set<number>();
|
|
297
297
|
|
|
298
298
|
for (let i = 0; i < messages.length; i++) {
|
|
299
299
|
const msg = messages[i];
|
|
300
300
|
|
|
301
|
-
// Skip toolResult messages that were already placed
|
|
302
|
-
if (msg.role === "toolResult" &&
|
|
301
|
+
// Skip toolResult messages that were already consumed (placed elsewhere or displaced)
|
|
302
|
+
if (msg.role === "toolResult" && consumedIndices.has(i)) {
|
|
303
303
|
continue;
|
|
304
304
|
}
|
|
305
305
|
|
|
@@ -326,7 +326,7 @@ function repairToolResultOrdering(messages: Message[]): Message[] {
|
|
|
326
326
|
if (requiredIds.has(trMsg.toolCallId)) {
|
|
327
327
|
// This tool_result belongs here — place it
|
|
328
328
|
result.push(next);
|
|
329
|
-
|
|
329
|
+
consumedIndices.add(j);
|
|
330
330
|
requiredIds.delete(trMsg.toolCallId);
|
|
331
331
|
if (displaced.length > 0) repaired = true;
|
|
332
332
|
j++;
|
|
@@ -335,7 +335,7 @@ function repairToolResultOrdering(messages: Message[]): Message[] {
|
|
|
335
335
|
}
|
|
336
336
|
// Non-matching message between tool_use and tool_result — displace it
|
|
337
337
|
displaced.push(next);
|
|
338
|
-
|
|
338
|
+
consumedIndices.add(j); // Mark original index as consumed
|
|
339
339
|
j++;
|
|
340
340
|
}
|
|
341
341
|
|
|
@@ -345,9 +345,9 @@ function repairToolResultOrdering(messages: Message[]): Message[] {
|
|
|
345
345
|
// Any remaining required IDs: find them later in the array or synthesize
|
|
346
346
|
for (const id of requiredIds) {
|
|
347
347
|
const found = toolResultsByCallId.get(id);
|
|
348
|
-
if (found && !
|
|
348
|
+
if (found && !consumedIndices.has(found.originalIndex)) {
|
|
349
349
|
result.push(found.message);
|
|
350
|
-
|
|
350
|
+
consumedIndices.add(found.originalIndex);
|
|
351
351
|
repaired = true;
|
|
352
352
|
} else {
|
|
353
353
|
// Missing tool_result entirely — inject synthetic error result
|
|
@@ -370,6 +370,55 @@ function repairToolResultOrdering(messages: Message[]): Message[] {
|
|
|
370
370
|
}
|
|
371
371
|
}
|
|
372
372
|
|
|
373
|
+
// Second pass: repair displaced assistant messages whose tool calls were never processed.
|
|
374
|
+
// When an assistant-with-tool-calls gets displaced (wedged between another assistant's
|
|
375
|
+
// tool_use and its tool_result), the first pass pushes it to result but the outer loop
|
|
376
|
+
// jumps past it — so its own tool_results are never resolved.
|
|
377
|
+
for (let i = 0; i < result.length; i++) {
|
|
378
|
+
const msg = result[i];
|
|
379
|
+
if (msg.role !== "assistant") continue;
|
|
380
|
+
const assistantMsg = msg as AssistantMessage;
|
|
381
|
+
const toolCalls = assistantMsg.content.filter((c): c is ToolCall => c.type === "toolCall");
|
|
382
|
+
if (toolCalls.length === 0) continue;
|
|
383
|
+
|
|
384
|
+
// Check if every tool call has a toolResult immediately following
|
|
385
|
+
const expectedIds = new Set(toolCalls.map(tc => tc.id));
|
|
386
|
+
let j = i + 1;
|
|
387
|
+
while (j < result.length && result[j].role === "toolResult") {
|
|
388
|
+
expectedIds.delete((result[j] as ToolResultMessage).toolCallId);
|
|
389
|
+
j++;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if (expectedIds.size === 0) continue;
|
|
393
|
+
|
|
394
|
+
// For missing tool calls: relocate existing result from later in array, or synthesize
|
|
395
|
+
const toInsert: ToolResultMessage[] = [];
|
|
396
|
+
for (const id of expectedIds) {
|
|
397
|
+
// Check if a toolResult for this ID exists later in result
|
|
398
|
+
const laterIndex = result.findIndex(
|
|
399
|
+
(m, idx) => idx > j && m.role === "toolResult" && (m as ToolResultMessage).toolCallId === id,
|
|
400
|
+
);
|
|
401
|
+
if (laterIndex !== -1) {
|
|
402
|
+
// Relocate the existing result to right after the assistant
|
|
403
|
+
const [relocated] = result.splice(laterIndex, 1);
|
|
404
|
+
toInsert.push(relocated as ToolResultMessage);
|
|
405
|
+
} else {
|
|
406
|
+
const toolCall = toolCalls.find(tc => tc.id === id);
|
|
407
|
+
toInsert.push({
|
|
408
|
+
role: "toolResult",
|
|
409
|
+
toolCallId: id,
|
|
410
|
+
toolName: toolCall?.name ?? "unknown",
|
|
411
|
+
content: [{ type: "text", text: "Tool execution was interrupted (session recovery)." }],
|
|
412
|
+
isError: true,
|
|
413
|
+
timestamp: Date.now(),
|
|
414
|
+
} as ToolResultMessage);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
result.splice(i + 1, 0, ...toInsert);
|
|
418
|
+
i += toInsert.length; // Skip past inserted results
|
|
419
|
+
repaired = true;
|
|
420
|
+
}
|
|
421
|
+
|
|
373
422
|
if (repaired) {
|
|
374
423
|
logger.warn("Repaired tool_use/tool_result ordering in conversation history");
|
|
375
424
|
}
|