@poncho-ai/harness 0.59.5 → 0.59.6

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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @poncho-ai/harness@0.59.5 build /home/runner/work/poncho-ai/poncho-ai/packages/harness
2
+ > @poncho-ai/harness@0.59.6 build /home/runner/work/poncho-ai/poncho-ai/packages/harness
3
3
  > node scripts/embed-docs.js && tsup src/index.ts --format esm --dts
4
4
 
5
5
  [embed-docs] Generated poncho-docs.ts with 4 topics
@@ -8,9 +8,9 @@
8
8
  CLI tsup v8.5.1
9
9
  CLI Target: es2022
10
10
  ESM Build start
11
- ESM dist/index.js 557.00 KB
12
11
  ESM dist/isolate-F2PPSUL6.js 53.82 KB
13
- ESM ⚡️ Build success in 252ms
12
+ ESM dist/index.js 557.73 KB
13
+ ESM ⚡️ Build success in 256ms
14
14
  DTS Build start
15
- DTS ⚡️ Build success in 7698ms
15
+ DTS ⚡️ Build success in 8276ms
16
16
  DTS dist/index.d.ts 101.66 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @poncho-ai/harness
2
2
 
3
+ ## 0.59.6
4
+
5
+ ### Patch Changes
6
+
7
+ - [`e573f72`](https://github.com/cesr/poncho-ai/commit/e573f72ca31627e48dbdbf296946a72c59a488db) Thanks [@cesr](https://github.com/cesr)! - Preserve the LLM transcript when a turn dies. The errored branch of
8
+ runConversationTurn persisted only the display draft — `_harnessMessages`
9
+ was never updated, so the model's next turn had no memory of the entire
10
+ failed interaction (its user message included), even though the user could
11
+ see it on screen. Both the errored branch and the cancelled-without-
12
+ `run:cancelled.messages` fallback now append a faithful plain-text
13
+ reconstruction (user message + assistant text-so-far + tool activity + an
14
+ interruption note) to the transcript. Plain text on purpose: replaying real
15
+ tool_use blocks would need paired results or the next API call rejects the
16
+ dangling pair.
17
+
3
18
  ## 0.59.5
4
19
 
5
20
  ### Patch Changes
package/dist/index.js CHANGED
@@ -14498,6 +14498,20 @@ var runConversationTurn = async (opts) => {
14498
14498
  };
14499
14499
  } catch (error) {
14500
14500
  flushTurnDraft(draft);
14501
+ const reconstructTranscriptTail = (reason) => {
14502
+ const parts = [];
14503
+ if (draft.assistantResponse.length > 0) parts.push(draft.assistantResponse);
14504
+ if (draft.toolTimeline.length > 0) {
14505
+ parts.push(`Tool activity before interruption:
14506
+ ${draft.toolTimeline.join("\n")}`);
14507
+ }
14508
+ parts.push(`[This turn was interrupted: ${reason}. The work above may be incomplete.]`);
14509
+ return [
14510
+ ...conversation._harnessMessages ?? [],
14511
+ userMessage,
14512
+ { role: "assistant", content: parts.join("\n\n") }
14513
+ ];
14514
+ };
14501
14515
  const aborted = opts.abortSignal?.aborted === true;
14502
14516
  if (aborted || runCancelled) {
14503
14517
  if (draft.assistantResponse.length > 0 || draft.toolTimeline.length > 0 || draft.sections.length > 0) {
@@ -14508,7 +14522,7 @@ var runConversationTurn = async (opts) => {
14508
14522
  latestRunId,
14509
14523
  contextTokens: 0,
14510
14524
  contextWindow: 0,
14511
- harnessMessages: cancelHarnessMessages,
14525
+ harnessMessages: cancelHarnessMessages ?? reconstructTranscriptTail("cancelled"),
14512
14526
  toolResultArchive: opts.harness.getToolResultArchive(opts.conversationId)
14513
14527
  },
14514
14528
  { shouldRebuildCanonical: true }
@@ -14551,6 +14565,9 @@ var runConversationTurn = async (opts) => {
14551
14565
  }
14552
14566
  if (draft.assistantResponse.length > 0 || draft.toolTimeline.length > 0 || draft.sections.length > 0) {
14553
14567
  conversation.messages = buildMessages(false);
14568
+ conversation._harnessMessages = reconstructTranscriptTail(
14569
+ error instanceof Error ? `error \u2014 ${error.message}` : "error"
14570
+ );
14554
14571
  conversation.updatedAt = Date.now();
14555
14572
  await opts.conversationStore.update(conversation);
14556
14573
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poncho-ai/harness",
3
- "version": "0.59.5",
3
+ "version": "0.59.6",
4
4
  "description": "Agent execution runtime - conversation loop, tool dispatch, streaming",
5
5
  "repository": {
6
6
  "type": "git",
@@ -420,6 +420,31 @@ export const runConversationTurn = async (
420
420
  };
421
421
  } catch (error) {
422
422
  flushTurnDraft(draft);
423
+
424
+ // The LLM transcript (`_harnessMessages`) is normally only written at a
425
+ // clean finalize / a cancel that delivered `run:cancelled.messages`. A
426
+ // turn that dies any other way (in-process error, abort that never
427
+ // surfaced the cancel event) would leave the transcript WITHOUT this
428
+ // turn at all — the display shows the partial work but the model has
429
+ // amnesia about the whole interaction on the next turn. Reconstruct a
430
+ // faithful plain-text record from the draft instead: the user message
431
+ // plus an assistant message carrying the text-so-far + tool activity.
432
+ // Plain text on purpose — replaying real tool_use blocks would need
433
+ // paired results or the next API call 400s on the dangling pair.
434
+ const reconstructTranscriptTail = (reason: string): Message[] => {
435
+ const parts: string[] = [];
436
+ if (draft.assistantResponse.length > 0) parts.push(draft.assistantResponse);
437
+ if (draft.toolTimeline.length > 0) {
438
+ parts.push(`Tool activity before interruption:\n${draft.toolTimeline.join("\n")}`);
439
+ }
440
+ parts.push(`[This turn was interrupted: ${reason}. The work above may be incomplete.]`);
441
+ return [
442
+ ...(conversation._harnessMessages ?? []),
443
+ userMessage,
444
+ { role: "assistant" as const, content: parts.join("\n\n") },
445
+ ];
446
+ };
447
+
423
448
  const aborted = opts.abortSignal?.aborted === true;
424
449
  if (aborted || runCancelled) {
425
450
  if (
@@ -434,7 +459,8 @@ export const runConversationTurn = async (
434
459
  latestRunId,
435
460
  contextTokens: 0,
436
461
  contextWindow: 0,
437
- harnessMessages: cancelHarnessMessages,
462
+ harnessMessages:
463
+ cancelHarnessMessages ?? reconstructTranscriptTail("cancelled"),
438
464
  toolResultArchive: opts.harness.getToolResultArchive(opts.conversationId),
439
465
  },
440
466
  { shouldRebuildCanonical: true },
@@ -484,6 +510,12 @@ export const runConversationTurn = async (
484
510
  draft.sections.length > 0
485
511
  ) {
486
512
  conversation.messages = buildMessages(false); // terminal: errored
513
+ // Keep the LLM transcript faithful too (see reconstructTranscriptTail
514
+ // above) — without this, the next turn's model context skipped the
515
+ // whole errored interaction.
516
+ conversation._harnessMessages = reconstructTranscriptTail(
517
+ error instanceof Error ? `error — ${error.message}` : "error",
518
+ );
487
519
  conversation.updatedAt = Date.now();
488
520
  await opts.conversationStore.update(conversation);
489
521
  }