@poncho-ai/harness 0.59.4 → 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.
- package/.turbo/turbo-build.log +5 -5
- package/CHANGELOG.md +21 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +20 -2
- package/package.json +1 -1
- package/src/harness.ts +6 -0
- package/src/orchestrator/run-conversation-turn.ts +33 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @poncho-ai/harness@0.59.
|
|
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
|
[34mCLI[39m tsup v8.5.1
|
|
9
9
|
[34mCLI[39m Target: es2022
|
|
10
10
|
[34mESM[39m Build start
|
|
11
|
-
[32mESM[39m [1mdist/index.js [22m[32m556.98 KB[39m
|
|
12
11
|
[32mESM[39m [1mdist/isolate-F2PPSUL6.js [22m[32m53.82 KB[39m
|
|
13
|
-
[32mESM[39m
|
|
12
|
+
[32mESM[39m [1mdist/index.js [22m[32m557.73 KB[39m
|
|
13
|
+
[32mESM[39m ⚡️ Build success in 256ms
|
|
14
14
|
[34mDTS[39m Build start
|
|
15
|
-
[32mDTS[39m ⚡️ Build success in
|
|
16
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[32m101.
|
|
15
|
+
[32mDTS[39m ⚡️ Build success in 8276ms
|
|
16
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m101.66 KB[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
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
|
+
|
|
18
|
+
## 0.59.5
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- [`d14c390`](https://github.com/cesr/poncho-ai/commit/d14c390ce6830f7446ea7a4e934d2cb76833c455) Thanks [@cesr](https://github.com/cesr)! - `continueFromToolResult` accepts and forwards the per-run `model` override, so approval-checkpoint continuations run on the same model as the checkpointed run instead of re-reading the (possibly concurrently-mutated) agent frontmatter.
|
|
23
|
+
|
|
3
24
|
## 0.59.4
|
|
4
25
|
|
|
5
26
|
### Patch Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -1582,6 +1582,11 @@ declare class AgentHarness {
|
|
|
1582
1582
|
/** Emit no telemetry for the continuation run (e.g. resuming an
|
|
1583
1583
|
* incognito turn after an approval). */
|
|
1584
1584
|
suppressTelemetry?: boolean;
|
|
1585
|
+
/** Per-run model override for the continuation run — same semantics as
|
|
1586
|
+
* `RunInput.model`. Forward the model the checkpointed run was using,
|
|
1587
|
+
* otherwise the continuation falls back to the agent definition's
|
|
1588
|
+
* (possibly concurrently-mutated) frontmatter model. */
|
|
1589
|
+
model?: string;
|
|
1585
1590
|
}): AsyncGenerator<AgentEvent>;
|
|
1586
1591
|
runToCompletion(input: RunInput): Promise<HarnessRunOutput>;
|
|
1587
1592
|
}
|
package/dist/index.js
CHANGED
|
@@ -11921,7 +11921,8 @@ ${this.skillFingerprint}`;
|
|
|
11921
11921
|
tenantId: input.tenantId,
|
|
11922
11922
|
parameters: input.parameters,
|
|
11923
11923
|
abortSignal: input.abortSignal,
|
|
11924
|
-
suppressTelemetry: input.suppressTelemetry
|
|
11924
|
+
suppressTelemetry: input.suppressTelemetry,
|
|
11925
|
+
model: input.model
|
|
11925
11926
|
});
|
|
11926
11927
|
}
|
|
11927
11928
|
async runToCompletion(input) {
|
|
@@ -14497,6 +14498,20 @@ var runConversationTurn = async (opts) => {
|
|
|
14497
14498
|
};
|
|
14498
14499
|
} catch (error) {
|
|
14499
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
|
+
};
|
|
14500
14515
|
const aborted = opts.abortSignal?.aborted === true;
|
|
14501
14516
|
if (aborted || runCancelled) {
|
|
14502
14517
|
if (draft.assistantResponse.length > 0 || draft.toolTimeline.length > 0 || draft.sections.length > 0) {
|
|
@@ -14507,7 +14522,7 @@ var runConversationTurn = async (opts) => {
|
|
|
14507
14522
|
latestRunId,
|
|
14508
14523
|
contextTokens: 0,
|
|
14509
14524
|
contextWindow: 0,
|
|
14510
|
-
harnessMessages: cancelHarnessMessages,
|
|
14525
|
+
harnessMessages: cancelHarnessMessages ?? reconstructTranscriptTail("cancelled"),
|
|
14511
14526
|
toolResultArchive: opts.harness.getToolResultArchive(opts.conversationId)
|
|
14512
14527
|
},
|
|
14513
14528
|
{ shouldRebuildCanonical: true }
|
|
@@ -14550,6 +14565,9 @@ var runConversationTurn = async (opts) => {
|
|
|
14550
14565
|
}
|
|
14551
14566
|
if (draft.assistantResponse.length > 0 || draft.toolTimeline.length > 0 || draft.sections.length > 0) {
|
|
14552
14567
|
conversation.messages = buildMessages(false);
|
|
14568
|
+
conversation._harnessMessages = reconstructTranscriptTail(
|
|
14569
|
+
error instanceof Error ? `error \u2014 ${error.message}` : "error"
|
|
14570
|
+
);
|
|
14553
14571
|
conversation.updatedAt = Date.now();
|
|
14554
14572
|
await opts.conversationStore.update(conversation);
|
|
14555
14573
|
}
|
package/package.json
CHANGED
package/src/harness.ts
CHANGED
|
@@ -3841,6 +3841,11 @@ Code is wrapped in an async IIFE — use \`return\` to return a value to the too
|
|
|
3841
3841
|
/** Emit no telemetry for the continuation run (e.g. resuming an
|
|
3842
3842
|
* incognito turn after an approval). */
|
|
3843
3843
|
suppressTelemetry?: boolean;
|
|
3844
|
+
/** Per-run model override for the continuation run — same semantics as
|
|
3845
|
+
* `RunInput.model`. Forward the model the checkpointed run was using,
|
|
3846
|
+
* otherwise the continuation falls back to the agent definition's
|
|
3847
|
+
* (possibly concurrently-mutated) frontmatter model. */
|
|
3848
|
+
model?: string;
|
|
3844
3849
|
}): AsyncGenerator<AgentEvent> {
|
|
3845
3850
|
const messages = [...input.messages];
|
|
3846
3851
|
const lastMsg = messages[messages.length - 1];
|
|
@@ -3900,6 +3905,7 @@ Code is wrapped in an async IIFE — use \`return\` to return a value to the too
|
|
|
3900
3905
|
parameters: input.parameters,
|
|
3901
3906
|
abortSignal: input.abortSignal,
|
|
3902
3907
|
suppressTelemetry: input.suppressTelemetry,
|
|
3908
|
+
model: input.model,
|
|
3903
3909
|
});
|
|
3904
3910
|
}
|
|
3905
3911
|
|
|
@@ -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:
|
|
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
|
}
|