@poncho-ai/harness 0.59.2 → 0.59.4
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 +30 -0
- package/dist/index.d.ts +45 -118
- package/dist/index.js +34 -327
- package/package.json +2 -2
- package/src/harness.ts +7 -2
- package/src/index.ts +3 -11
- package/src/orchestrator/entries-dual-write.ts +20 -209
- package/src/orchestrator/index.ts +1 -6
- package/src/orchestrator/orchestrator.ts +22 -115
- package/src/orchestrator/run-conversation-turn.ts +7 -108
- package/src/state.ts +3 -1
- package/src/storage/entries.ts +47 -182
- package/src/storage/memory-engine.ts +2 -2
- package/src/storage/sql-dialect.ts +18 -8
- package/test/entries-dual-write.test.ts +21 -144
- package/test/entries-store.test.ts +43 -53
- package/test/entries.test.ts +37 -105
package/dist/index.js
CHANGED
|
@@ -2780,55 +2780,6 @@ import { randomUUID as randomUUID3 } from "crypto";
|
|
|
2780
2780
|
// src/storage/entries.ts
|
|
2781
2781
|
import { createLogger as createLogger2 } from "@poncho-ai/sdk";
|
|
2782
2782
|
var entriesReadLog = createLogger2("entries-read");
|
|
2783
|
-
function buildLlmContext(entries) {
|
|
2784
|
-
let latestCompaction;
|
|
2785
|
-
for (const e of entries) {
|
|
2786
|
-
if (e.type === "compaction" && (!latestCompaction || e.seq > latestCompaction.seq)) {
|
|
2787
|
-
latestCompaction = e;
|
|
2788
|
-
}
|
|
2789
|
-
}
|
|
2790
|
-
const harnessMsgs = entries.filter(
|
|
2791
|
-
(e) => e.type === "harness_message"
|
|
2792
|
-
);
|
|
2793
|
-
if (latestCompaction) {
|
|
2794
|
-
const kept = harnessMsgs.filter((e) => e.seq >= latestCompaction.firstKeptSeq).map((e) => e.message);
|
|
2795
|
-
return [latestCompaction.summaryMessage, ...kept];
|
|
2796
|
-
}
|
|
2797
|
-
return harnessMsgs.map((e) => e.message);
|
|
2798
|
-
}
|
|
2799
|
-
function buildDisplaySnapshot(entries, tailN) {
|
|
2800
|
-
const amendmentsByTarget = /* @__PURE__ */ new Map();
|
|
2801
|
-
for (const e of entries) {
|
|
2802
|
-
if (e.type === "assistant_amendment") {
|
|
2803
|
-
const list = amendmentsByTarget.get(e.targetEntryId) ?? [];
|
|
2804
|
-
list.push(e);
|
|
2805
|
-
amendmentsByTarget.set(e.targetEntryId, list);
|
|
2806
|
-
}
|
|
2807
|
-
}
|
|
2808
|
-
const built = [];
|
|
2809
|
-
for (const e of entries) {
|
|
2810
|
-
if (e.type === "user_message") {
|
|
2811
|
-
if (e.hidden) continue;
|
|
2812
|
-
built.push({ seq: e.seq, message: e.message });
|
|
2813
|
-
} else if (e.type === "assistant_message") {
|
|
2814
|
-
let content = typeof e.message.content === "string" ? e.message.content : "";
|
|
2815
|
-
const amendments = amendmentsByTarget.get(e.id);
|
|
2816
|
-
if (amendments) {
|
|
2817
|
-
for (const a of amendments.sort((x, y) => x.seq - y.seq)) {
|
|
2818
|
-
if (a.appendText) content += a.appendText;
|
|
2819
|
-
}
|
|
2820
|
-
}
|
|
2821
|
-
built.push({ seq: e.seq, message: { ...e.message, content } });
|
|
2822
|
-
}
|
|
2823
|
-
}
|
|
2824
|
-
const total = built.length;
|
|
2825
|
-
const tail = tailN >= total ? built : built.slice(total - tailN);
|
|
2826
|
-
return {
|
|
2827
|
-
messages: tail.map((b) => b.message),
|
|
2828
|
-
totalMessages: total,
|
|
2829
|
-
headSeq: tail.length > 0 ? tail[0].seq : null
|
|
2830
|
-
};
|
|
2831
|
-
}
|
|
2832
2783
|
function getPendingSubagentResults(entries) {
|
|
2833
2784
|
const consumed = /* @__PURE__ */ new Set();
|
|
2834
2785
|
for (const e of entries) {
|
|
@@ -2908,7 +2859,7 @@ var InMemoryEngine = class {
|
|
|
2908
2859
|
if (!c) return void 0;
|
|
2909
2860
|
return rebuildConversationFromEntries(
|
|
2910
2861
|
{ ...c },
|
|
2911
|
-
(id) => this.conversations.readEntries(id)
|
|
2862
|
+
(id) => this.conversations.readEntries(id, { types: ["subagent_result", "callback_started"] })
|
|
2912
2863
|
);
|
|
2913
2864
|
},
|
|
2914
2865
|
// In-memory storage has no separate archive blob, so both variants
|
|
@@ -2918,7 +2869,7 @@ var InMemoryEngine = class {
|
|
|
2918
2869
|
if (!c) return void 0;
|
|
2919
2870
|
return rebuildConversationFromEntries(
|
|
2920
2871
|
{ ...c },
|
|
2921
|
-
(id) => this.conversations.readEntries(id)
|
|
2872
|
+
(id) => this.conversations.readEntries(id, { types: ["subagent_result", "callback_started"] })
|
|
2922
2873
|
);
|
|
2923
2874
|
},
|
|
2924
2875
|
getStatusSnapshot: async (conversationId) => {
|
|
@@ -3797,7 +3748,7 @@ var SqlStorageEngine = class {
|
|
|
3797
3748
|
}
|
|
3798
3749
|
return rebuildConversationFromEntries(
|
|
3799
3750
|
conv,
|
|
3800
|
-
(id) => this.conversations.readEntries(id)
|
|
3751
|
+
(id) => this.conversations.readEntries(id, { types: ["subagent_result", "callback_started"] })
|
|
3801
3752
|
);
|
|
3802
3753
|
},
|
|
3803
3754
|
getStatusSnapshot: async (conversationId) => {
|
|
@@ -3850,7 +3801,7 @@ var SqlStorageEngine = class {
|
|
|
3850
3801
|
}
|
|
3851
3802
|
return rebuildConversationFromEntries(
|
|
3852
3803
|
conv,
|
|
3853
|
-
(id) => this.conversations.readEntries(id)
|
|
3804
|
+
(id) => this.conversations.readEntries(id, { types: ["subagent_result", "callback_started"] })
|
|
3854
3805
|
);
|
|
3855
3806
|
},
|
|
3856
3807
|
create: async (ownerId, title, tenantId, init) => {
|
|
@@ -3967,12 +3918,13 @@ var SqlStorageEngine = class {
|
|
|
3967
3918
|
},
|
|
3968
3919
|
rename: async (conversationId, title) => {
|
|
3969
3920
|
const normalized = normalizeTitle2(title);
|
|
3921
|
+
const dataExpr = this.dialect.tag === "sqlite" ? `json_set(data, '$.title', $2)` : `jsonb_set(data, '{title}', to_jsonb($2::text))`;
|
|
3970
3922
|
await this.executor.run(
|
|
3971
3923
|
rewrite(
|
|
3972
|
-
`UPDATE conversations SET title = $1, updated_at = $
|
|
3924
|
+
`UPDATE conversations SET title = $1, data = ${dataExpr}, updated_at = $3 WHERE id = $4`,
|
|
3973
3925
|
this.dialect
|
|
3974
3926
|
),
|
|
3975
|
-
[normalized, (/* @__PURE__ */ new Date()).toISOString(), conversationId]
|
|
3927
|
+
[normalized, normalized, (/* @__PURE__ */ new Date()).toISOString(), conversationId]
|
|
3976
3928
|
);
|
|
3977
3929
|
return this.conversations.get(conversationId);
|
|
3978
3930
|
},
|
|
@@ -10767,7 +10719,7 @@ ${this.skillFingerprint}`;
|
|
|
10767
10719
|
}
|
|
10768
10720
|
return pushEvent({ type: "run:cancelled", runId, messages: trimToValidPrefix(snapshot) });
|
|
10769
10721
|
};
|
|
10770
|
-
const resolvedModelName = agent.frontmatter.model?.name ?? "claude-opus-4-5";
|
|
10722
|
+
const resolvedModelName = input.model ?? agent.frontmatter.model?.name ?? "claude-opus-4-5";
|
|
10771
10723
|
const contextWindow = agent.frontmatter.model?.contextWindow ?? getModelContextWindow(resolvedModelName);
|
|
10772
10724
|
yield pushEvent({
|
|
10773
10725
|
type: "run:started",
|
|
@@ -11134,7 +11086,7 @@ ${textContent}` };
|
|
|
11134
11086
|
}
|
|
11135
11087
|
return [];
|
|
11136
11088
|
};
|
|
11137
|
-
const modelName = agent.frontmatter.model?.name ?? "claude-opus-4-5";
|
|
11089
|
+
const modelName = input.model ?? agent.frontmatter.model?.name ?? "claude-opus-4-5";
|
|
11138
11090
|
if (step === 1) {
|
|
11139
11091
|
modelLog.item(`${modelName} (provider=${agent.frontmatter.model?.provider ?? "anthropic"})`);
|
|
11140
11092
|
}
|
|
@@ -12249,7 +12201,10 @@ var InMemoryConversationStore = class {
|
|
|
12249
12201
|
this.purgeExpired();
|
|
12250
12202
|
const c = this.conversations.get(conversationId);
|
|
12251
12203
|
if (!c) return void 0;
|
|
12252
|
-
return rebuildConversationFromEntries(
|
|
12204
|
+
return rebuildConversationFromEntries(
|
|
12205
|
+
{ ...c },
|
|
12206
|
+
(id) => this.readEntries(id, { types: ["subagent_result", "callback_started"] })
|
|
12207
|
+
);
|
|
12253
12208
|
}
|
|
12254
12209
|
// In-memory stores already hold the full conversation object, so there's
|
|
12255
12210
|
// no separate archive blob to load. Both variants return the same data.
|
|
@@ -12708,12 +12663,10 @@ var CALLBACK_LOCK_STALE_MS = 5 * 60 * 1e3;
|
|
|
12708
12663
|
var STALE_SUBAGENT_THRESHOLD_MS = 5 * 60 * 1e3;
|
|
12709
12664
|
|
|
12710
12665
|
// src/orchestrator/orchestrator.ts
|
|
12711
|
-
import { createLogger as createLogger8, getTextContent as
|
|
12666
|
+
import { createLogger as createLogger8, getTextContent as getTextContent3 } from "@poncho-ai/sdk";
|
|
12712
12667
|
|
|
12713
12668
|
// src/orchestrator/entries-dual-write.ts
|
|
12714
12669
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
12715
|
-
import { getTextContent as getTextContent3 } from "@poncho-ai/sdk";
|
|
12716
|
-
var entriesParityEnabled = () => process.env.PONCHO_VERIFY_ENTRIES === "1";
|
|
12717
12670
|
var appendEntriesSafe = async (store, conversation, entries, log2) => {
|
|
12718
12671
|
if (entries.length === 0) return [];
|
|
12719
12672
|
try {
|
|
@@ -12728,123 +12681,21 @@ var appendEntriesSafe = async (store, conversation, entries, log2) => {
|
|
|
12728
12681
|
);
|
|
12729
12682
|
} catch (err) {
|
|
12730
12683
|
log2.error(
|
|
12731
|
-
`[entries-
|
|
12684
|
+
`[entries-queue] append failed for ${conversation.conversationId}: ${err instanceof Error ? err.message : String(err)}`
|
|
12732
12685
|
);
|
|
12733
12686
|
return [];
|
|
12734
12687
|
}
|
|
12735
12688
|
};
|
|
12736
|
-
var userMessageEntry = (message, turnId, opts) => ({
|
|
12737
|
-
type: "user_message",
|
|
12738
|
-
message,
|
|
12739
|
-
turnId,
|
|
12740
|
-
...opts?.hidden ? { hidden: true } : {}
|
|
12741
|
-
});
|
|
12742
|
-
var assistantMessageEntry = (message, turnId, runId) => ({
|
|
12743
|
-
type: "assistant_message",
|
|
12744
|
-
message,
|
|
12745
|
-
turnId,
|
|
12746
|
-
runId
|
|
12747
|
-
});
|
|
12748
|
-
var harnessMessageEntries = (messages, turnId) => messages.map((message) => ({ type: "harness_message", message, turnId }));
|
|
12749
|
-
var compactionEntry = (summaryMessage, firstKeptSeq, opts) => ({
|
|
12750
|
-
type: "compaction",
|
|
12751
|
-
summaryMessage,
|
|
12752
|
-
firstKeptSeq,
|
|
12753
|
-
...opts?.tokensBefore !== void 0 ? { tokensBefore: opts.tokensBefore } : {},
|
|
12754
|
-
...opts?.tokensAfter !== void 0 ? { tokensAfter: opts.tokensAfter } : {}
|
|
12755
|
-
});
|
|
12756
12689
|
var subagentResultEntry = (result) => ({ type: "subagent_result", result });
|
|
12757
12690
|
var callbackStartedEntry = (consumedSeqs) => ({
|
|
12758
12691
|
type: "callback_started",
|
|
12759
12692
|
consumedSeqs
|
|
12760
12693
|
});
|
|
12761
|
-
var assistantAmendmentEntry = (targetEntryId, appendText) => ({
|
|
12762
|
-
type: "assistant_amendment",
|
|
12763
|
-
targetEntryId,
|
|
12764
|
-
...appendText ? { appendText } : {}
|
|
12765
|
-
});
|
|
12766
|
-
var newHarnessMessagesThisTurn = (prev, next) => {
|
|
12767
|
-
const prevArr = prev ?? [];
|
|
12768
|
-
const nextArr = next ?? [];
|
|
12769
|
-
if (nextArr.length === 0) return { messages: [], approximate: false };
|
|
12770
|
-
if (prevArr.length === 0) return { messages: nextArr, approximate: false };
|
|
12771
|
-
if (nextArr.length >= prevArr.length) {
|
|
12772
|
-
return { messages: nextArr.slice(prevArr.length), approximate: false };
|
|
12773
|
-
}
|
|
12774
|
-
return { messages: nextArr, approximate: true };
|
|
12775
|
-
};
|
|
12776
|
-
var projectText = (m) => {
|
|
12777
|
-
const role = m.role;
|
|
12778
|
-
const text = getTextContent3(m).replace(/\s+/g, " ").trim();
|
|
12779
|
-
return `${role}:${text}`;
|
|
12780
|
-
};
|
|
12781
|
-
var projectAll = (msgs) => msgs.map(projectText);
|
|
12782
|
-
var countMismatch = (label, a, b) => a === b ? null : `${label} length ${a} (entries) vs ${b} (blob)`;
|
|
12783
|
-
var verifyEntriesParity = async (store, conversationId, blob, log2) => {
|
|
12784
|
-
if (!entriesParityEnabled()) return;
|
|
12785
|
-
try {
|
|
12786
|
-
const entries = await store.readEntries(conversationId);
|
|
12787
|
-
const mismatches = [];
|
|
12788
|
-
if (blob.harnessMessages) {
|
|
12789
|
-
const llm = buildLlmContext(entries);
|
|
12790
|
-
const lenMismatch = countMismatch(
|
|
12791
|
-
"llmContext",
|
|
12792
|
-
llm.length,
|
|
12793
|
-
blob.harnessMessages.length
|
|
12794
|
-
);
|
|
12795
|
-
if (lenMismatch) mismatches.push(lenMismatch);
|
|
12796
|
-
const entriesProj = projectAll(llm);
|
|
12797
|
-
const blobProj = projectAll(blob.harnessMessages);
|
|
12798
|
-
const tail = Math.min(entriesProj.length, blobProj.length, 5);
|
|
12799
|
-
for (let i = 1; i <= tail; i++) {
|
|
12800
|
-
const ep = entriesProj[entriesProj.length - i];
|
|
12801
|
-
const bp = blobProj[blobProj.length - i];
|
|
12802
|
-
if (ep !== bp) {
|
|
12803
|
-
mismatches.push(
|
|
12804
|
-
`llmContext tail[-${i}] differs: entries=${JSON.stringify(ep).slice(0, 120)} blob=${JSON.stringify(bp).slice(0, 120)}`
|
|
12805
|
-
);
|
|
12806
|
-
}
|
|
12807
|
-
}
|
|
12808
|
-
}
|
|
12809
|
-
if (blob.displayMessages) {
|
|
12810
|
-
const snap = buildDisplaySnapshot(entries, Number.MAX_SAFE_INTEGER);
|
|
12811
|
-
const lenMismatch = countMismatch(
|
|
12812
|
-
"display",
|
|
12813
|
-
snap.totalMessages,
|
|
12814
|
-
blob.displayMessages.length
|
|
12815
|
-
);
|
|
12816
|
-
if (lenMismatch) mismatches.push(lenMismatch);
|
|
12817
|
-
const entriesProj = projectAll(snap.messages);
|
|
12818
|
-
const blobProj = projectAll(blob.displayMessages);
|
|
12819
|
-
const tail = Math.min(entriesProj.length, blobProj.length, 5);
|
|
12820
|
-
for (let i = 1; i <= tail; i++) {
|
|
12821
|
-
const ep = entriesProj[entriesProj.length - i];
|
|
12822
|
-
const bp = blobProj[blobProj.length - i];
|
|
12823
|
-
if (ep !== bp) {
|
|
12824
|
-
mismatches.push(
|
|
12825
|
-
`display tail[-${i}] differs: entries=${JSON.stringify(ep).slice(0, 120)} blob=${JSON.stringify(bp).slice(0, 120)}`
|
|
12826
|
-
);
|
|
12827
|
-
}
|
|
12828
|
-
}
|
|
12829
|
-
}
|
|
12830
|
-
if (mismatches.length > 0) {
|
|
12831
|
-
log2.warn(
|
|
12832
|
-
`[entries-parity] ${conversationId} MISMATCH (${mismatches.length}): ${mismatches.join(" | ")}`
|
|
12833
|
-
);
|
|
12834
|
-
} else {
|
|
12835
|
-
log2.info(`[entries-parity] ${conversationId} OK`);
|
|
12836
|
-
}
|
|
12837
|
-
} catch (err) {
|
|
12838
|
-
log2.error(
|
|
12839
|
-
`[entries-parity] ${conversationId} checker threw (ignored): ${err instanceof Error ? err.message : String(err)}`
|
|
12840
|
-
);
|
|
12841
|
-
}
|
|
12842
|
-
};
|
|
12843
12694
|
|
|
12844
12695
|
// src/orchestrator/orchestrator.ts
|
|
12845
|
-
var
|
|
12696
|
+
var entriesQueueLog = createLogger8("orchestrator:entries");
|
|
12846
12697
|
var assistantMessageText = (message) => {
|
|
12847
|
-
const raw =
|
|
12698
|
+
const raw = getTextContent3(message).trim();
|
|
12848
12699
|
if (raw.startsWith("{") && raw.includes('"tool_calls"')) {
|
|
12849
12700
|
try {
|
|
12850
12701
|
const parsed = JSON.parse(raw);
|
|
@@ -13153,8 +13004,6 @@ var AgentOrchestrator = class {
|
|
|
13153
13004
|
if (!checkpointedRun) {
|
|
13154
13005
|
const conv = await this.conversationStore.get(conversationId);
|
|
13155
13006
|
if (conv) {
|
|
13156
|
-
let amendmentText;
|
|
13157
|
-
let pushedAssistant;
|
|
13158
13007
|
const hasAssistantContent = draft.assistantResponse.length > 0 || draft.toolTimeline.length > 0 || draft.sections.length > 0;
|
|
13159
13008
|
if (hasAssistantContent) {
|
|
13160
13009
|
const prevMessages = conv.messages;
|
|
@@ -13182,14 +13031,15 @@ var AgentOrchestrator = class {
|
|
|
13182
13031
|
}
|
|
13183
13032
|
}
|
|
13184
13033
|
];
|
|
13185
|
-
amendmentText = draft.assistantResponse;
|
|
13186
13034
|
} else {
|
|
13187
|
-
|
|
13188
|
-
|
|
13189
|
-
|
|
13190
|
-
|
|
13191
|
-
|
|
13192
|
-
|
|
13035
|
+
conv.messages = [
|
|
13036
|
+
...prevMessages,
|
|
13037
|
+
{
|
|
13038
|
+
role: "assistant",
|
|
13039
|
+
content: draft.assistantResponse,
|
|
13040
|
+
metadata: buildAssistantMetadata(draft)
|
|
13041
|
+
}
|
|
13042
|
+
];
|
|
13193
13043
|
}
|
|
13194
13044
|
}
|
|
13195
13045
|
applyTurnMetadata(conv, {
|
|
@@ -13199,54 +13049,6 @@ var AgentOrchestrator = class {
|
|
|
13199
13049
|
harnessMessages: execution?.runHarnessMessages
|
|
13200
13050
|
}, { shouldRebuildCanonical: true });
|
|
13201
13051
|
await this.conversationStore.update(conv);
|
|
13202
|
-
if (amendmentText !== void 0 || pushedAssistant) {
|
|
13203
|
-
const finalConv = conv;
|
|
13204
|
-
const amendText = amendmentText;
|
|
13205
|
-
const pushed = pushedAssistant;
|
|
13206
|
-
void (async () => {
|
|
13207
|
-
try {
|
|
13208
|
-
if (pushed) {
|
|
13209
|
-
await appendEntriesSafe(
|
|
13210
|
-
this.conversationStore,
|
|
13211
|
-
finalConv,
|
|
13212
|
-
[assistantMessageEntry(pushed, `resume-${conversationId}`, latestRunId)],
|
|
13213
|
-
dualWriteLog
|
|
13214
|
-
);
|
|
13215
|
-
} else if (amendText !== void 0) {
|
|
13216
|
-
const existing = await this.conversationStore.readEntries(
|
|
13217
|
-
conversationId,
|
|
13218
|
-
{ types: ["assistant_message"] }
|
|
13219
|
-
);
|
|
13220
|
-
const target = existing[existing.length - 1];
|
|
13221
|
-
if (target) {
|
|
13222
|
-
await appendEntriesSafe(
|
|
13223
|
-
this.conversationStore,
|
|
13224
|
-
finalConv,
|
|
13225
|
-
[assistantAmendmentEntry(target.id, amendText)],
|
|
13226
|
-
dualWriteLog
|
|
13227
|
-
);
|
|
13228
|
-
} else {
|
|
13229
|
-
dualWriteLog.warn(
|
|
13230
|
-
`[entries-dual-write] resume amendment for ${conversationId}: no assistant_message entry to target; skipped`
|
|
13231
|
-
);
|
|
13232
|
-
}
|
|
13233
|
-
}
|
|
13234
|
-
await verifyEntriesParity(
|
|
13235
|
-
this.conversationStore,
|
|
13236
|
-
conversationId,
|
|
13237
|
-
{
|
|
13238
|
-
harnessMessages: finalConv._harnessMessages,
|
|
13239
|
-
displayMessages: finalConv.messages
|
|
13240
|
-
},
|
|
13241
|
-
dualWriteLog
|
|
13242
|
-
);
|
|
13243
|
-
} catch (err) {
|
|
13244
|
-
dualWriteLog.error(
|
|
13245
|
-
`[entries-dual-write] resume finalize append failed for ${conversationId}: ${err instanceof Error ? err.message : String(err)}`
|
|
13246
|
-
);
|
|
13247
|
-
}
|
|
13248
|
-
})();
|
|
13249
|
-
}
|
|
13250
13052
|
}
|
|
13251
13053
|
} else {
|
|
13252
13054
|
const conv = await this.conversationStore.get(conversationId);
|
|
@@ -13782,7 +13584,6 @@ ${resultBody}`,
|
|
|
13782
13584
|
conversation.updatedAt = Date.now();
|
|
13783
13585
|
await this.conversationStore.update(conversation);
|
|
13784
13586
|
if (pendingResults.length > 0) {
|
|
13785
|
-
const turnId = `callback-${callbackCount}-${conversation.conversationId}`;
|
|
13786
13587
|
void (async () => {
|
|
13787
13588
|
try {
|
|
13788
13589
|
const resultEntries = await this.conversationStore.readEntries(
|
|
@@ -13796,17 +13597,12 @@ ${resultBody}`,
|
|
|
13796
13597
|
await appendEntriesSafe(
|
|
13797
13598
|
this.conversationStore,
|
|
13798
13599
|
conversation,
|
|
13799
|
-
[
|
|
13800
|
-
|
|
13801
|
-
...injectedCallbackMessages.map(
|
|
13802
|
-
(m) => userMessageEntry(m, turnId, { hidden: true })
|
|
13803
|
-
)
|
|
13804
|
-
],
|
|
13805
|
-
dualWriteLog
|
|
13600
|
+
[callbackStartedEntry(consumedSeqs)],
|
|
13601
|
+
entriesQueueLog
|
|
13806
13602
|
);
|
|
13807
13603
|
} catch (err) {
|
|
13808
|
-
|
|
13809
|
-
`[entries-
|
|
13604
|
+
entriesQueueLog.error(
|
|
13605
|
+
`[entries-queue] callback_started append failed for ${conversation.conversationId}: ${err instanceof Error ? err.message : String(err)}`
|
|
13810
13606
|
);
|
|
13811
13607
|
}
|
|
13812
13608
|
})();
|
|
@@ -13892,25 +13688,6 @@ ${resultBody}`,
|
|
|
13892
13688
|
}, { shouldRebuildCanonical: true, clearApprovals: false });
|
|
13893
13689
|
freshConv.runningCallbackSince = void 0;
|
|
13894
13690
|
await this.conversationStore.update(freshConv);
|
|
13895
|
-
if (callbackAssistantMsg) {
|
|
13896
|
-
const finalMsg = callbackAssistantMsg;
|
|
13897
|
-
void appendEntriesSafe(
|
|
13898
|
-
this.conversationStore,
|
|
13899
|
-
freshConv,
|
|
13900
|
-
[assistantMessageEntry(finalMsg, `callback-${conversationId}`, execution.latestRunId)],
|
|
13901
|
-
dualWriteLog
|
|
13902
|
-
).then(
|
|
13903
|
-
() => verifyEntriesParity(
|
|
13904
|
-
this.conversationStore,
|
|
13905
|
-
conversationId,
|
|
13906
|
-
{
|
|
13907
|
-
harnessMessages: freshConv._harnessMessages,
|
|
13908
|
-
displayMessages: freshConv.messages
|
|
13909
|
-
},
|
|
13910
|
-
dualWriteLog
|
|
13911
|
-
)
|
|
13912
|
-
);
|
|
13913
|
-
}
|
|
13914
13691
|
if (freshConv.channelMeta && execution.draft.assistantResponse.length > 0) {
|
|
13915
13692
|
this.hooks?.onMessagingNotify?.(conversationId, execution.draft.assistantResponse);
|
|
13916
13693
|
}
|
|
@@ -14323,11 +14100,11 @@ ${resultBody}`,
|
|
|
14323
14100
|
this.conversationStore,
|
|
14324
14101
|
parent,
|
|
14325
14102
|
[subagentResultEntry(result)],
|
|
14326
|
-
|
|
14103
|
+
entriesQueueLog
|
|
14327
14104
|
);
|
|
14328
14105
|
} catch (err) {
|
|
14329
|
-
|
|
14330
|
-
`[entries-
|
|
14106
|
+
entriesQueueLog.error(
|
|
14107
|
+
`[entries-queue] subagent_result append failed for ${parentConversationId}: ${err instanceof Error ? err.message : String(err)}`
|
|
14331
14108
|
);
|
|
14332
14109
|
}
|
|
14333
14110
|
})();
|
|
@@ -14518,8 +14295,6 @@ var runConversationTurn = async (opts) => {
|
|
|
14518
14295
|
conversation.updatedAt = Date.now();
|
|
14519
14296
|
await opts.conversationStore.update(conversation);
|
|
14520
14297
|
};
|
|
14521
|
-
const preTurnHarnessMessages = conversation._harnessMessages ? [...conversation._harnessMessages] : void 0;
|
|
14522
|
-
const turnId = assistantId;
|
|
14523
14298
|
conversation.messages = [...historyMessages, userMessage];
|
|
14524
14299
|
conversation.subagentCallbackCount = 0;
|
|
14525
14300
|
conversation._continuationCount = void 0;
|
|
@@ -14529,12 +14304,6 @@ var runConversationTurn = async (opts) => {
|
|
|
14529
14304
|
`failed to persist user turn: ${err instanceof Error ? err.message : String(err)}`
|
|
14530
14305
|
);
|
|
14531
14306
|
});
|
|
14532
|
-
void appendEntriesSafe(
|
|
14533
|
-
opts.conversationStore,
|
|
14534
|
-
conversation,
|
|
14535
|
-
[userMessageEntry(userMessage, turnId)],
|
|
14536
|
-
log
|
|
14537
|
-
);
|
|
14538
14307
|
try {
|
|
14539
14308
|
const execution = await executeConversationTurn({
|
|
14540
14309
|
harness: opts.harness,
|
|
@@ -14554,7 +14323,8 @@ var runConversationTurn = async (opts) => {
|
|
|
14554
14323
|
files: opts.files && opts.files.length > 0 ? opts.files : void 0,
|
|
14555
14324
|
abortSignal: opts.abortSignal,
|
|
14556
14325
|
disablePromptCache: opts.disablePromptCache,
|
|
14557
|
-
suppressTelemetry: opts.suppressTelemetry
|
|
14326
|
+
suppressTelemetry: opts.suppressTelemetry,
|
|
14327
|
+
model: opts.model
|
|
14558
14328
|
},
|
|
14559
14329
|
initialContextTokens: conversation.contextTokens ?? 0,
|
|
14560
14330
|
initialContextWindow: conversation.contextWindow ?? 0,
|
|
@@ -14582,34 +14352,6 @@ var runConversationTurn = async (opts) => {
|
|
|
14582
14352
|
...existingHistory,
|
|
14583
14353
|
...preRunMessages.slice(0, removedCount)
|
|
14584
14354
|
];
|
|
14585
|
-
const summaryMessage = event.compactedMessages[0];
|
|
14586
|
-
const keptCount = Math.max(0, event.compactedMessages.length - 1);
|
|
14587
|
-
if (summaryMessage) {
|
|
14588
|
-
void (async () => {
|
|
14589
|
-
try {
|
|
14590
|
-
const existing = await opts.conversationStore.readEntries(
|
|
14591
|
-
opts.conversationId,
|
|
14592
|
-
{ types: ["harness_message"] }
|
|
14593
|
-
);
|
|
14594
|
-
const harnessSeqs = existing.map((e) => e.seq);
|
|
14595
|
-
const firstKeptSeq = harnessSeqs.length >= keptCount && keptCount > 0 ? harnessSeqs[harnessSeqs.length - keptCount] : (harnessSeqs[harnessSeqs.length - 1] ?? 0) + 1;
|
|
14596
|
-
await appendEntriesSafe(
|
|
14597
|
-
opts.conversationStore,
|
|
14598
|
-
conversation,
|
|
14599
|
-
[
|
|
14600
|
-
compactionEntry(summaryMessage, firstKeptSeq, {
|
|
14601
|
-
tokensBefore: conversation.contextTokens
|
|
14602
|
-
})
|
|
14603
|
-
],
|
|
14604
|
-
log
|
|
14605
|
-
);
|
|
14606
|
-
} catch (err) {
|
|
14607
|
-
log.error(
|
|
14608
|
-
`[entries-dual-write] compaction append failed: ${err instanceof Error ? err.message : String(err)}`
|
|
14609
|
-
);
|
|
14610
|
-
}
|
|
14611
|
-
})();
|
|
14612
|
-
}
|
|
14613
14355
|
}
|
|
14614
14356
|
}
|
|
14615
14357
|
if (event.type === "step:completed") {
|
|
@@ -14743,36 +14485,6 @@ var runConversationTurn = async (opts) => {
|
|
|
14743
14485
|
{ shouldRebuildCanonical }
|
|
14744
14486
|
);
|
|
14745
14487
|
await opts.conversationStore.update(conversation);
|
|
14746
|
-
const finalAssistant = conversation.messages[conversation.messages.length - 1];
|
|
14747
|
-
const { messages: newHarness, approximate } = newHarnessMessagesThisTurn(
|
|
14748
|
-
preTurnHarnessMessages,
|
|
14749
|
-
conversation._harnessMessages
|
|
14750
|
-
);
|
|
14751
|
-
if (approximate) {
|
|
14752
|
-
log.warn(
|
|
14753
|
-
`[entries-dual-write] ${opts.conversationId} harness-message diff approximate (blob array shrank this turn \u2014 likely compaction); appended full context`
|
|
14754
|
-
);
|
|
14755
|
-
}
|
|
14756
|
-
const finalizeEntries = [
|
|
14757
|
-
...harnessMessageEntries(newHarness, turnId),
|
|
14758
|
-
...finalAssistant && finalAssistant.role === "assistant" ? [assistantMessageEntry(finalAssistant, turnId, latestRunId)] : []
|
|
14759
|
-
];
|
|
14760
|
-
void appendEntriesSafe(
|
|
14761
|
-
opts.conversationStore,
|
|
14762
|
-
conversation,
|
|
14763
|
-
finalizeEntries,
|
|
14764
|
-
log
|
|
14765
|
-
).then(
|
|
14766
|
-
() => verifyEntriesParity(
|
|
14767
|
-
opts.conversationStore,
|
|
14768
|
-
opts.conversationId,
|
|
14769
|
-
{
|
|
14770
|
-
harnessMessages: conversation._harnessMessages,
|
|
14771
|
-
displayMessages: conversation.messages
|
|
14772
|
-
},
|
|
14773
|
-
log
|
|
14774
|
-
)
|
|
14775
|
-
);
|
|
14776
14488
|
}
|
|
14777
14489
|
return {
|
|
14778
14490
|
latestRunId,
|
|
@@ -14895,8 +14607,6 @@ export {
|
|
|
14895
14607
|
buildAgentDirectoryName,
|
|
14896
14608
|
buildApprovalCheckpoints,
|
|
14897
14609
|
buildAssistantMetadata,
|
|
14898
|
-
buildDisplaySnapshot,
|
|
14899
|
-
buildLlmContext,
|
|
14900
14610
|
buildSkillContextWindow,
|
|
14901
14611
|
buildToolCompletedText,
|
|
14902
14612
|
cloneSections,
|
|
@@ -14933,7 +14643,6 @@ export {
|
|
|
14933
14643
|
deleteOpenAICodexSession,
|
|
14934
14644
|
deriveUploadKey,
|
|
14935
14645
|
ensureAgentIdentity,
|
|
14936
|
-
entriesParityEnabled,
|
|
14937
14646
|
estimateTokens,
|
|
14938
14647
|
estimateTotalTokens,
|
|
14939
14648
|
executeConversationTurn,
|
|
@@ -14959,7 +14668,6 @@ export {
|
|
|
14959
14668
|
loadSkillMetadataFromDirs,
|
|
14960
14669
|
loadVfsSkillMetadata,
|
|
14961
14670
|
mergeSkills,
|
|
14962
|
-
newHarnessMessagesThisTurn,
|
|
14963
14671
|
normalizeApprovalCheckpoint,
|
|
14964
14672
|
normalizeOtlp,
|
|
14965
14673
|
normalizeScriptPolicyPath,
|
|
@@ -14983,7 +14691,6 @@ export {
|
|
|
14983
14691
|
runConversationTurn,
|
|
14984
14692
|
slugifyStorageComponent,
|
|
14985
14693
|
startOpenAICodexDeviceAuth,
|
|
14986
|
-
verifyEntriesParity,
|
|
14987
14694
|
verifyTenantToken,
|
|
14988
14695
|
withToolResultArchiveParam,
|
|
14989
14696
|
writeOpenAICodexSession
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@poncho-ai/harness",
|
|
3
|
-
"version": "0.59.
|
|
3
|
+
"version": "0.59.4",
|
|
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.2"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
40
|
"esbuild": ">=0.17.0",
|
package/src/harness.ts
CHANGED
|
@@ -2376,7 +2376,7 @@ Code is wrapped in an async IIFE — use \`return\` to return a value to the too
|
|
|
2376
2376
|
return pushEvent({ type: "run:cancelled", runId, messages: trimToValidPrefix(snapshot) });
|
|
2377
2377
|
};
|
|
2378
2378
|
|
|
2379
|
-
const resolvedModelName = agent.frontmatter.model?.name ?? "claude-opus-4-5";
|
|
2379
|
+
const resolvedModelName = input.model ?? agent.frontmatter.model?.name ?? "claude-opus-4-5";
|
|
2380
2380
|
const contextWindow =
|
|
2381
2381
|
agent.frontmatter.model?.contextWindow ?? getModelContextWindow(resolvedModelName);
|
|
2382
2382
|
|
|
@@ -2836,7 +2836,12 @@ Code is wrapped in an async IIFE — use \`return\` to return a value to the too
|
|
|
2836
2836
|
return [];
|
|
2837
2837
|
};
|
|
2838
2838
|
|
|
2839
|
-
|
|
2839
|
+
// Per-run override wins over frontmatter. Reading frontmatter here is
|
|
2840
|
+
// what made model selection racy: the field is re-read every step, so
|
|
2841
|
+
// a concurrent run's setHarnessModel-style mutation flipped this
|
|
2842
|
+
// run's model mid-turn (and a model switch drops the whole per-model
|
|
2843
|
+
// Anthropic prompt cache).
|
|
2844
|
+
const modelName = input.model ?? agent.frontmatter.model?.name ?? "claude-opus-4-5";
|
|
2840
2845
|
if (step === 1) {
|
|
2841
2846
|
modelLog.item(`${modelName} (provider=${agent.frontmatter.model?.provider ?? "anthropic"})`);
|
|
2842
2847
|
}
|
package/src/index.ts
CHANGED
|
@@ -21,23 +21,15 @@ export * from "./telemetry.js";
|
|
|
21
21
|
export * from "./secrets-store.js";
|
|
22
22
|
export * from "./storage/index.js";
|
|
23
23
|
export * from "./storage/store-adapters.js";
|
|
24
|
-
//
|
|
25
|
-
// appendEntries/readEntries are reachable on the
|
|
26
|
-
// StorageEngine.conversations surfaces
|
|
24
|
+
// Subagent delivery queue (append-only conversation_entries): types + the
|
|
25
|
+
// pending-results rebuild. appendEntries/readEntries are reachable on the
|
|
26
|
+
// ConversationStore / StorageEngine.conversations surfaces exported above.
|
|
27
27
|
export {
|
|
28
|
-
buildLlmContext,
|
|
29
|
-
buildDisplaySnapshot,
|
|
30
28
|
getPendingSubagentResults,
|
|
31
29
|
type ConversationEntry,
|
|
32
30
|
type NewConversationEntry,
|
|
33
|
-
type UserMessageEntry,
|
|
34
|
-
type AssistantMessageEntry,
|
|
35
|
-
type AssistantAmendmentEntry,
|
|
36
|
-
type HarnessMessageEntry,
|
|
37
|
-
type CompactionEntry,
|
|
38
31
|
type SubagentResultEntry,
|
|
39
32
|
type CallbackStartedEntry,
|
|
40
|
-
type DisplaySnapshot,
|
|
41
33
|
} from "./storage/entries.js";
|
|
42
34
|
export {
|
|
43
35
|
PonchoFsAdapter,
|