@poncho-ai/harness 0.59.0 → 0.59.2
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 +4 -4
- package/CHANGELOG.md +29 -0
- package/dist/index.js +22 -13
- package/package.json +2 -2
- package/src/orchestrator/run-conversation-turn.ts +21 -8
- package/src/storage/sql-dialect.ts +15 -5
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @poncho-ai/harness@0.59.
|
|
2
|
+
> @poncho-ai/harness@0.59.2 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[32m567.16 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[32m567.57 KB[39m
|
|
13
|
+
[32mESM[39m ⚡️ Build success in 251ms
|
|
14
14
|
[34mDTS[39m Build start
|
|
15
|
-
[32mDTS[39m ⚡️ Build success in
|
|
15
|
+
[32mDTS[39m ⚡️ Build success in 7447ms
|
|
16
16
|
[32mDTS[39m [1mdist/index.d.ts [22m[32m104.68 KB[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# @poncho-ai/harness
|
|
2
2
|
|
|
3
|
+
## 0.59.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`ac0faae`](https://github.com/cesr/poncho-ai/commit/ac0faae54365afda5ef518b0a306a8cde5978ca8) Thanks [@cesr](https://github.com/cesr)! - conversations.rename now does a targeted title-column UPDATE instead of a
|
|
8
|
+
whole-row get→mutate→update. The read-modify-write raced a streaming turn's
|
|
9
|
+
per-step draft persist: a rename landing mid-run wrote the stale blob back
|
|
10
|
+
and silently reverted the turn's persisted progress.
|
|
11
|
+
|
|
12
|
+
## 0.59.1
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- [`299f574`](https://github.com/cesr/poncho-ai/commit/299f574a2f2f0d4873f42bbcffdf604e9cc4c29c) Thanks [@cesr](https://github.com/cesr)! - Mark in-flight assistant drafts with `metadata.incomplete = true`.
|
|
17
|
+
|
|
18
|
+
The orchestrator's per-step draft persist (`persistDraft`) and the
|
|
19
|
+
approval/device checkpoint and continuation writes now stamp the trailing
|
|
20
|
+
assistant message `metadata.incomplete = true`; the three terminal writes
|
|
21
|
+
(normal finalize, cancelled, errored) clear it. This lets a consumer that
|
|
22
|
+
reconciles a persisted snapshot against a live event stream (e.g. a
|
|
23
|
+
WebSocket layer) strip the in-flight draft from the authoritative snapshot
|
|
24
|
+
and rebuild that turn from the event log instead — so the snapshot and the
|
|
25
|
+
replayed events never both carry the in-flight turn, eliminating
|
|
26
|
+
reconnect-time duplication. Additive + backwards-compatible: consumers that
|
|
27
|
+
ignore the flag are unaffected.
|
|
28
|
+
|
|
29
|
+
- Updated dependencies [[`299f574`](https://github.com/cesr/poncho-ai/commit/299f574a2f2f0d4873f42bbcffdf604e9cc4c29c)]:
|
|
30
|
+
- @poncho-ai/sdk@1.15.1
|
|
31
|
+
|
|
3
32
|
## 0.59.0
|
|
4
33
|
|
|
5
34
|
### Minor Changes
|
package/dist/index.js
CHANGED
|
@@ -3966,11 +3966,15 @@ var SqlStorageEngine = class {
|
|
|
3966
3966
|
);
|
|
3967
3967
|
},
|
|
3968
3968
|
rename: async (conversationId, title) => {
|
|
3969
|
-
const
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3969
|
+
const normalized = normalizeTitle2(title);
|
|
3970
|
+
await this.executor.run(
|
|
3971
|
+
rewrite(
|
|
3972
|
+
`UPDATE conversations SET title = $1, updated_at = $2 WHERE id = $3`,
|
|
3973
|
+
this.dialect
|
|
3974
|
+
),
|
|
3975
|
+
[normalized, (/* @__PURE__ */ new Date()).toISOString(), conversationId]
|
|
3976
|
+
);
|
|
3977
|
+
return this.conversations.get(conversationId);
|
|
3974
3978
|
},
|
|
3975
3979
|
delete: async (conversationId) => {
|
|
3976
3980
|
const row = await this.executor.get(
|
|
@@ -14477,7 +14481,7 @@ var runConversationTurn = async (opts) => {
|
|
|
14477
14481
|
let runContinuationMessages;
|
|
14478
14482
|
let cancelHarnessMessages;
|
|
14479
14483
|
let checkpointedRun = false;
|
|
14480
|
-
const buildMessages = () => {
|
|
14484
|
+
const buildMessages = (incomplete = true) => {
|
|
14481
14485
|
const draftSections = cloneSections(draft.sections);
|
|
14482
14486
|
if (draft.currentTools.length > 0) {
|
|
14483
14487
|
draftSections.push({ type: "tools", content: [...draft.currentTools] });
|
|
@@ -14496,10 +14500,15 @@ var runConversationTurn = async (opts) => {
|
|
|
14496
14500
|
{
|
|
14497
14501
|
role: "assistant",
|
|
14498
14502
|
content: draft.assistantResponse,
|
|
14499
|
-
metadata:
|
|
14500
|
-
|
|
14501
|
-
|
|
14502
|
-
|
|
14503
|
+
metadata: {
|
|
14504
|
+
...buildAssistantMetadata(draft, draftSections, {
|
|
14505
|
+
id: assistantId,
|
|
14506
|
+
timestamp: turnTimestamp
|
|
14507
|
+
}),
|
|
14508
|
+
// Only stamp the flag when true; finalize omits it so completed
|
|
14509
|
+
// assistants stay clean (no `incomplete: false` noise on the row).
|
|
14510
|
+
...incomplete ? { incomplete: true } : {}
|
|
14511
|
+
}
|
|
14503
14512
|
}
|
|
14504
14513
|
];
|
|
14505
14514
|
};
|
|
@@ -14721,7 +14730,7 @@ var runConversationTurn = async (opts) => {
|
|
|
14721
14730
|
flushTurnDraft(draft);
|
|
14722
14731
|
latestRunId = execution.latestRunId || latestRunId;
|
|
14723
14732
|
if (!checkpointedRun && !runContinuationMessages) {
|
|
14724
|
-
conversation.messages = buildMessages();
|
|
14733
|
+
conversation.messages = buildMessages(false);
|
|
14725
14734
|
applyTurnMetadata(
|
|
14726
14735
|
conversation,
|
|
14727
14736
|
{
|
|
@@ -14779,7 +14788,7 @@ var runConversationTurn = async (opts) => {
|
|
|
14779
14788
|
const aborted = opts.abortSignal?.aborted === true;
|
|
14780
14789
|
if (aborted || runCancelled) {
|
|
14781
14790
|
if (draft.assistantResponse.length > 0 || draft.toolTimeline.length > 0 || draft.sections.length > 0) {
|
|
14782
|
-
conversation.messages = buildMessages();
|
|
14791
|
+
conversation.messages = buildMessages(false);
|
|
14783
14792
|
applyTurnMetadata(
|
|
14784
14793
|
conversation,
|
|
14785
14794
|
{
|
|
@@ -14828,7 +14837,7 @@ var runConversationTurn = async (opts) => {
|
|
|
14828
14837
|
}
|
|
14829
14838
|
}
|
|
14830
14839
|
if (draft.assistantResponse.length > 0 || draft.toolTimeline.length > 0 || draft.sections.length > 0) {
|
|
14831
|
-
conversation.messages = buildMessages();
|
|
14840
|
+
conversation.messages = buildMessages(false);
|
|
14832
14841
|
conversation.updatedAt = Date.now();
|
|
14833
14842
|
await opts.conversationStore.update(conversation);
|
|
14834
14843
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@poncho-ai/harness",
|
|
3
|
-
"version": "0.59.
|
|
3
|
+
"version": "0.59.2",
|
|
4
4
|
"description": "Agent execution runtime - conversation loop, tool dispatch, streaming",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"mustache": "^4.2.0",
|
|
35
35
|
"yaml": "^2.4.0",
|
|
36
36
|
"zod": "^3.22.0",
|
|
37
|
-
"@poncho-ai/sdk": "1.15.
|
|
37
|
+
"@poncho-ai/sdk": "1.15.1"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
40
|
"esbuild": ">=0.17.0",
|
|
@@ -157,7 +157,15 @@ export const runConversationTurn = async (
|
|
|
157
157
|
let cancelHarnessMessages: Message[] | undefined;
|
|
158
158
|
let checkpointedRun = false;
|
|
159
159
|
|
|
160
|
-
|
|
160
|
+
// `incomplete: true` (the default) marks the trailing assistant message as
|
|
161
|
+
// an in-flight DRAFT — content for a turn that hasn't finished. A consumer
|
|
162
|
+
// (e.g. PonchOS's WS snapshot) uses this to strip the draft from the
|
|
163
|
+
// authoritative snapshot: the in-flight turn is delivered by the event
|
|
164
|
+
// stream instead, so the snapshot and the event log never both carry it
|
|
165
|
+
// (no reconnect duplication). The three TERMINAL writes (normal finalize,
|
|
166
|
+
// cancelled, errored) pass `incomplete: false` — at that point the turn is
|
|
167
|
+
// done and the assistant message is authoritative.
|
|
168
|
+
const buildMessages = (incomplete = true): Message[] => {
|
|
161
169
|
const draftSections = cloneSections(draft.sections);
|
|
162
170
|
if (draft.currentTools.length > 0) {
|
|
163
171
|
draftSections.push({ type: "tools", content: [...draft.currentTools] });
|
|
@@ -179,10 +187,15 @@ export const runConversationTurn = async (
|
|
|
179
187
|
{
|
|
180
188
|
role: "assistant" as const,
|
|
181
189
|
content: draft.assistantResponse,
|
|
182
|
-
metadata:
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
190
|
+
metadata: {
|
|
191
|
+
...buildAssistantMetadata(draft, draftSections, {
|
|
192
|
+
id: assistantId,
|
|
193
|
+
timestamp: turnTimestamp,
|
|
194
|
+
}),
|
|
195
|
+
// Only stamp the flag when true; finalize omits it so completed
|
|
196
|
+
// assistants stay clean (no `incomplete: false` noise on the row).
|
|
197
|
+
...(incomplete ? { incomplete: true } : {}),
|
|
198
|
+
},
|
|
186
199
|
},
|
|
187
200
|
];
|
|
188
201
|
};
|
|
@@ -442,7 +455,7 @@ export const runConversationTurn = async (
|
|
|
442
455
|
latestRunId = execution.latestRunId || latestRunId;
|
|
443
456
|
|
|
444
457
|
if (!checkpointedRun && !runContinuationMessages) {
|
|
445
|
-
conversation.messages = buildMessages();
|
|
458
|
+
conversation.messages = buildMessages(false); // terminal: turn complete
|
|
446
459
|
applyTurnMetadata(
|
|
447
460
|
conversation,
|
|
448
461
|
{
|
|
@@ -515,7 +528,7 @@ export const runConversationTurn = async (
|
|
|
515
528
|
draft.toolTimeline.length > 0 ||
|
|
516
529
|
draft.sections.length > 0
|
|
517
530
|
) {
|
|
518
|
-
conversation.messages = buildMessages();
|
|
531
|
+
conversation.messages = buildMessages(false); // terminal: cancelled
|
|
519
532
|
applyTurnMetadata(
|
|
520
533
|
conversation,
|
|
521
534
|
{
|
|
@@ -571,7 +584,7 @@ export const runConversationTurn = async (
|
|
|
571
584
|
draft.toolTimeline.length > 0 ||
|
|
572
585
|
draft.sections.length > 0
|
|
573
586
|
) {
|
|
574
|
-
conversation.messages = buildMessages();
|
|
587
|
+
conversation.messages = buildMessages(false); // terminal: errored
|
|
575
588
|
conversation.updatedAt = Date.now();
|
|
576
589
|
await opts.conversationStore.update(conversation);
|
|
577
590
|
}
|
|
@@ -557,11 +557,21 @@ export abstract class SqlStorageEngine implements StorageEngine {
|
|
|
557
557
|
conversationId: string,
|
|
558
558
|
title: string,
|
|
559
559
|
): Promise<Conversation | undefined> => {
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
560
|
+
// Targeted column update — deliberately NOT get→mutate→update().
|
|
561
|
+
// The whole-row read-modify-write races a streaming turn's per-step
|
|
562
|
+
// draft persist: rename reads the row at T0, the turn persists step
|
|
563
|
+
// N's draft at T1, rename writes T0's stale blob back at T2 and
|
|
564
|
+
// silently reverts the turn's progress. Title lives in its own
|
|
565
|
+
// column, so touch only that (+ updated_at for sidebar ordering).
|
|
566
|
+
const normalized = normalizeTitle(title);
|
|
567
|
+
await this.executor.run(
|
|
568
|
+
rewrite(
|
|
569
|
+
`UPDATE conversations SET title = $1, updated_at = $2 WHERE id = $3`,
|
|
570
|
+
this.dialect,
|
|
571
|
+
),
|
|
572
|
+
[normalized, new Date().toISOString(), conversationId],
|
|
573
|
+
);
|
|
574
|
+
return this.conversations.get(conversationId);
|
|
565
575
|
},
|
|
566
576
|
|
|
567
577
|
delete: async (conversationId: string): Promise<boolean> => {
|