@poncho-ai/cli 0.32.4 → 0.32.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 +7 -7
- package/CHANGELOG.md +15 -0
- package/dist/{chunk-F6NA3N2R.js → chunk-OJGEUTDF.js} +757 -510
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +81 -3
- package/dist/index.js +3 -1
- package/dist/{run-interactive-ink-GPCI4L6G.js → run-interactive-ink-LAL4PQVD.js} +1 -1
- package/package.json +2 -2
- package/src/index.ts +758 -464
- package/src/web-ui-client.ts +70 -8
- package/test/run-orchestration.test.ts +171 -0
|
@@ -1861,6 +1861,7 @@ var getWebUiClientScript = (markedSource2) => `
|
|
|
1861
1861
|
todoPanelCollapsed: false,
|
|
1862
1862
|
cronSectionCollapsed: true,
|
|
1863
1863
|
cronShowAll: false,
|
|
1864
|
+
subagentPollInFlight: {},
|
|
1864
1865
|
};
|
|
1865
1866
|
|
|
1866
1867
|
const agentInitial = document.body.dataset.agentInitial || "A";
|
|
@@ -2320,11 +2321,20 @@ var getWebUiClientScript = (markedSource2) => `
|
|
|
2320
2321
|
return null;
|
|
2321
2322
|
}
|
|
2322
2323
|
const toolName = item && typeof item.tool === "string" ? item.tool : "tool";
|
|
2324
|
+
const decision =
|
|
2325
|
+
item && typeof item.decision === "string" ? item.decision : null;
|
|
2326
|
+
const isResolved = decision === "approved" || decision === "denied";
|
|
2323
2327
|
return {
|
|
2324
2328
|
approvalId,
|
|
2325
2329
|
tool: toolName,
|
|
2326
2330
|
input: item?.input ?? {},
|
|
2327
|
-
state: "pending",
|
|
2331
|
+
state: isResolved ? "resolved" : "pending",
|
|
2332
|
+
resolvedDecision:
|
|
2333
|
+
decision === "approved"
|
|
2334
|
+
? "approve"
|
|
2335
|
+
: decision === "denied"
|
|
2336
|
+
? "deny"
|
|
2337
|
+
: null,
|
|
2328
2338
|
};
|
|
2329
2339
|
})
|
|
2330
2340
|
.filter(Boolean);
|
|
@@ -3374,8 +3384,8 @@ var getWebUiClientScript = (markedSource2) => `
|
|
|
3374
3384
|
updateContextRing();
|
|
3375
3385
|
renderMessages(state.activeMessages, payload.hasActiveRun);
|
|
3376
3386
|
}
|
|
3377
|
-
if (payload.hasActiveRun) {
|
|
3378
|
-
if (window._connectBrowserStream) window._connectBrowserStream();
|
|
3387
|
+
if (payload.hasActiveRun || payload.hasRunningSubagents) {
|
|
3388
|
+
if (payload.hasActiveRun && window._connectBrowserStream) window._connectBrowserStream();
|
|
3379
3389
|
setTimeout(poll, 2000);
|
|
3380
3390
|
} else {
|
|
3381
3391
|
setStreaming(false);
|
|
@@ -3390,9 +3400,15 @@ var getWebUiClientScript = (markedSource2) => `
|
|
|
3390
3400
|
};
|
|
3391
3401
|
|
|
3392
3402
|
const pollForSubagentResults = (conversationId) => {
|
|
3403
|
+
if (state.subagentPollInFlight[conversationId]) return;
|
|
3404
|
+
state.subagentPollInFlight[conversationId] = true;
|
|
3393
3405
|
let lastMessageCount = state.activeMessages ? state.activeMessages.length : 0;
|
|
3406
|
+
let lastUpdatedAt = 0;
|
|
3394
3407
|
const poll = async () => {
|
|
3395
|
-
if (state.activeConversationId !== conversationId)
|
|
3408
|
+
if (state.activeConversationId !== conversationId) {
|
|
3409
|
+
delete state.subagentPollInFlight[conversationId];
|
|
3410
|
+
return;
|
|
3411
|
+
}
|
|
3396
3412
|
try {
|
|
3397
3413
|
var payload = await api("/api/conversations/" + encodeURIComponent(conversationId));
|
|
3398
3414
|
if (state.activeConversationId !== conversationId) return;
|
|
@@ -3413,13 +3429,17 @@ var getWebUiClientScript = (markedSource2) => `
|
|
|
3413
3429
|
});
|
|
3414
3430
|
});
|
|
3415
3431
|
}
|
|
3416
|
-
|
|
3432
|
+
const conversationUpdatedAt =
|
|
3433
|
+
typeof payload.conversation.updatedAt === "number" ? payload.conversation.updatedAt : 0;
|
|
3434
|
+
if (messages.length > lastMessageCount || conversationUpdatedAt > lastUpdatedAt) {
|
|
3417
3435
|
lastMessageCount = messages.length;
|
|
3436
|
+
lastUpdatedAt = conversationUpdatedAt;
|
|
3418
3437
|
state.activeMessages = hydratePendingApprovals(messages, allPending);
|
|
3419
3438
|
renderMessages(state.activeMessages, payload.hasActiveRun || payload.hasRunningSubagents);
|
|
3420
3439
|
}
|
|
3421
3440
|
if (payload.hasActiveRun) {
|
|
3422
3441
|
// Parent agent started its continuation run \u2014 switch to live stream
|
|
3442
|
+
delete state.subagentPollInFlight[conversationId];
|
|
3423
3443
|
setStreaming(true);
|
|
3424
3444
|
state.activeMessages = hydratePendingApprovals(messages, allPending);
|
|
3425
3445
|
streamConversationEvents(conversationId, { liveOnly: true }).finally(() => {
|
|
@@ -3432,6 +3452,7 @@ var getWebUiClientScript = (markedSource2) => `
|
|
|
3432
3452
|
} else {
|
|
3433
3453
|
renderMessages(state.activeMessages, false);
|
|
3434
3454
|
await loadConversations();
|
|
3455
|
+
delete state.subagentPollInFlight[conversationId];
|
|
3435
3456
|
}
|
|
3436
3457
|
}
|
|
3437
3458
|
} catch {
|
|
@@ -4359,6 +4380,7 @@ var getWebUiClientScript = (markedSource2) => `
|
|
|
4359
4380
|
let _maxSteps = 0;
|
|
4360
4381
|
let _receivedTerminalEvent = false;
|
|
4361
4382
|
let _shouldContinue = false;
|
|
4383
|
+
let _pendingSubagentsConversation = null;
|
|
4362
4384
|
|
|
4363
4385
|
// Helper to read an SSE stream from a fetch response
|
|
4364
4386
|
const readSseStream = async (response) => {
|
|
@@ -4676,7 +4698,7 @@ var getWebUiClientScript = (markedSource2) => `
|
|
|
4676
4698
|
assistantMessage.content = String(payload.result?.response || "");
|
|
4677
4699
|
}
|
|
4678
4700
|
if (payload.pendingSubagents) {
|
|
4679
|
-
|
|
4701
|
+
_pendingSubagentsConversation = conversationId;
|
|
4680
4702
|
}
|
|
4681
4703
|
renderIfActiveConversation(false);
|
|
4682
4704
|
}
|
|
@@ -4804,6 +4826,19 @@ var getWebUiClientScript = (markedSource2) => `
|
|
|
4804
4826
|
}
|
|
4805
4827
|
elements.prompt.focus();
|
|
4806
4828
|
}
|
|
4829
|
+
|
|
4830
|
+
// Subagent callback: after sendMessage fully completes (including
|
|
4831
|
+
// finally cleanup), reload the conversation. loadConversation is
|
|
4832
|
+
// the exact same code path as a manual refresh \u2014 if the callback
|
|
4833
|
+
// is still running it connects to the event stream; if it already
|
|
4834
|
+
// finished it just renders the final persisted state.
|
|
4835
|
+
if (_pendingSubagentsConversation && state.activeConversationId === _pendingSubagentsConversation) {
|
|
4836
|
+
const cbConvId = _pendingSubagentsConversation;
|
|
4837
|
+
await new Promise(r => setTimeout(r, 1200));
|
|
4838
|
+
if (state.activeConversationId === cbConvId && !state.isStreaming) {
|
|
4839
|
+
await loadConversation(cbConvId);
|
|
4840
|
+
}
|
|
4841
|
+
}
|
|
4807
4842
|
};
|
|
4808
4843
|
|
|
4809
4844
|
const requireAuth = async () => {
|
|
@@ -5037,9 +5072,22 @@ var getWebUiClientScript = (markedSource2) => `
|
|
|
5037
5072
|
}));
|
|
5038
5073
|
return api("/api/approvals/" + encodeURIComponent(approvalId), {
|
|
5039
5074
|
method: "POST",
|
|
5040
|
-
body: JSON.stringify({
|
|
5075
|
+
body: JSON.stringify({
|
|
5076
|
+
approved: decision === "approve",
|
|
5077
|
+
conversationId: state.activeConversationId || undefined,
|
|
5078
|
+
}),
|
|
5041
5079
|
}).catch((error) => {
|
|
5042
5080
|
const isStale = error && error.payload && error.payload.code === "APPROVAL_NOT_FOUND";
|
|
5081
|
+
const isNotReady = error && error.payload && error.payload.code === "APPROVAL_NOT_READY";
|
|
5082
|
+
if (isNotReady) {
|
|
5083
|
+
updatePendingApproval(approvalId, (request) => ({
|
|
5084
|
+
...request,
|
|
5085
|
+
state: "pending",
|
|
5086
|
+
pendingDecision: null,
|
|
5087
|
+
resolvedDecision: null,
|
|
5088
|
+
}));
|
|
5089
|
+
return;
|
|
5090
|
+
}
|
|
5043
5091
|
if (isStale) {
|
|
5044
5092
|
updatePendingApproval(approvalId, () => null);
|
|
5045
5093
|
} else {
|
|
@@ -5110,9 +5158,23 @@ var getWebUiClientScript = (markedSource2) => `
|
|
|
5110
5158
|
for (const aid of pending) {
|
|
5111
5159
|
await api("/api/approvals/" + encodeURIComponent(aid), {
|
|
5112
5160
|
method: "POST",
|
|
5113
|
-
body: JSON.stringify({
|
|
5161
|
+
body: JSON.stringify({
|
|
5162
|
+
approved: decision === "approve",
|
|
5163
|
+
conversationId: state.activeConversationId || undefined,
|
|
5164
|
+
}),
|
|
5114
5165
|
}).catch((error) => {
|
|
5115
5166
|
const isStale = error && error.payload && error.payload.code === "APPROVAL_NOT_FOUND";
|
|
5167
|
+
const isNotReady = error && error.payload && error.payload.code === "APPROVAL_NOT_READY";
|
|
5168
|
+
if (isNotReady) {
|
|
5169
|
+
updatePendingApproval(aid, (request) => ({
|
|
5170
|
+
...request,
|
|
5171
|
+
state: "pending",
|
|
5172
|
+
pendingDecision: null,
|
|
5173
|
+
resolvedDecision: null,
|
|
5174
|
+
}));
|
|
5175
|
+
renderMessages(state.activeMessages, state.isStreaming);
|
|
5176
|
+
return;
|
|
5177
|
+
}
|
|
5116
5178
|
if (isStale) {
|
|
5117
5179
|
updatePendingApproval(aid, () => null);
|
|
5118
5180
|
} else {
|
|
@@ -7412,6 +7474,13 @@ var readRequestBody = async (request) => {
|
|
|
7412
7474
|
const body = Buffer.concat(chunks).toString("utf8");
|
|
7413
7475
|
return body.length > 0 ? JSON.parse(body) : {};
|
|
7414
7476
|
};
|
|
7477
|
+
var parseTelegramMessageThreadIdFromPlatformThreadId = (platformThreadId, chatId) => {
|
|
7478
|
+
if (!platformThreadId || !chatId) return void 0;
|
|
7479
|
+
const parts = platformThreadId.split(":");
|
|
7480
|
+
if (parts.length !== 3 || parts[0] !== chatId) return void 0;
|
|
7481
|
+
const threadId = Number(parts[1]);
|
|
7482
|
+
return Number.isInteger(threadId) ? threadId : void 0;
|
|
7483
|
+
};
|
|
7415
7484
|
var MAX_UPLOAD_SIZE = 25 * 1024 * 1024;
|
|
7416
7485
|
var parseMultipartRequest = (request) => new Promise((resolve4, reject) => {
|
|
7417
7486
|
const result = { message: "", files: [] };
|
|
@@ -7546,6 +7615,209 @@ var normalizeMessageForClient = (message) => {
|
|
|
7546
7615
|
}
|
|
7547
7616
|
return message;
|
|
7548
7617
|
};
|
|
7618
|
+
var isMessageArray = (value) => Array.isArray(value) && value.every((entry) => {
|
|
7619
|
+
if (!entry || typeof entry !== "object") return false;
|
|
7620
|
+
const row = entry;
|
|
7621
|
+
const role = row.role;
|
|
7622
|
+
const content = row.content;
|
|
7623
|
+
const roleOk = role === "system" || role === "user" || role === "assistant" || role === "tool";
|
|
7624
|
+
const contentOk = typeof content === "string" || Array.isArray(content);
|
|
7625
|
+
return roleOk && contentOk;
|
|
7626
|
+
});
|
|
7627
|
+
var loadCanonicalHistory = (conversation) => {
|
|
7628
|
+
if (isMessageArray(conversation._harnessMessages) && conversation._harnessMessages.length > 0) {
|
|
7629
|
+
return { messages: [...conversation._harnessMessages], source: "harness" };
|
|
7630
|
+
}
|
|
7631
|
+
return { messages: [...conversation.messages], source: "messages" };
|
|
7632
|
+
};
|
|
7633
|
+
var loadRunHistory = (conversation, options) => {
|
|
7634
|
+
if (options?.preferContinuation && isMessageArray(conversation._continuationMessages) && conversation._continuationMessages.length > 0) {
|
|
7635
|
+
return {
|
|
7636
|
+
messages: [...conversation._continuationMessages],
|
|
7637
|
+
source: "continuation",
|
|
7638
|
+
shouldRebuildCanonical: !isMessageArray(conversation._harnessMessages) || conversation._harnessMessages.length === 0
|
|
7639
|
+
};
|
|
7640
|
+
}
|
|
7641
|
+
const canonical = loadCanonicalHistory(conversation);
|
|
7642
|
+
return {
|
|
7643
|
+
...canonical,
|
|
7644
|
+
shouldRebuildCanonical: canonical.source !== "harness"
|
|
7645
|
+
};
|
|
7646
|
+
};
|
|
7647
|
+
var createTurnDraftState = () => ({
|
|
7648
|
+
assistantResponse: "",
|
|
7649
|
+
toolTimeline: [],
|
|
7650
|
+
sections: [],
|
|
7651
|
+
currentTools: [],
|
|
7652
|
+
currentText: ""
|
|
7653
|
+
});
|
|
7654
|
+
var cloneSections = (sections) => sections.map((section) => ({
|
|
7655
|
+
type: section.type,
|
|
7656
|
+
content: Array.isArray(section.content) ? [...section.content] : section.content
|
|
7657
|
+
}));
|
|
7658
|
+
var flushTurnDraft = (draft) => {
|
|
7659
|
+
if (draft.currentTools.length > 0) {
|
|
7660
|
+
draft.sections.push({ type: "tools", content: draft.currentTools });
|
|
7661
|
+
draft.currentTools = [];
|
|
7662
|
+
}
|
|
7663
|
+
if (draft.currentText.length > 0) {
|
|
7664
|
+
draft.sections.push({ type: "text", content: draft.currentText });
|
|
7665
|
+
draft.currentText = "";
|
|
7666
|
+
}
|
|
7667
|
+
};
|
|
7668
|
+
var recordStandardTurnEvent = (draft, event) => {
|
|
7669
|
+
if (event.type === "model:chunk") {
|
|
7670
|
+
if (draft.currentTools.length > 0) {
|
|
7671
|
+
draft.sections.push({ type: "tools", content: draft.currentTools });
|
|
7672
|
+
draft.currentTools = [];
|
|
7673
|
+
if (draft.assistantResponse.length > 0 && !/\s$/.test(draft.assistantResponse)) {
|
|
7674
|
+
draft.assistantResponse += " ";
|
|
7675
|
+
}
|
|
7676
|
+
}
|
|
7677
|
+
draft.assistantResponse += event.content;
|
|
7678
|
+
draft.currentText += event.content;
|
|
7679
|
+
return;
|
|
7680
|
+
}
|
|
7681
|
+
if (event.type === "tool:started") {
|
|
7682
|
+
if (draft.currentText.length > 0) {
|
|
7683
|
+
draft.sections.push({ type: "text", content: draft.currentText });
|
|
7684
|
+
draft.currentText = "";
|
|
7685
|
+
}
|
|
7686
|
+
const toolText = `- start \`${event.tool}\``;
|
|
7687
|
+
draft.toolTimeline.push(toolText);
|
|
7688
|
+
draft.currentTools.push(toolText);
|
|
7689
|
+
return;
|
|
7690
|
+
}
|
|
7691
|
+
if (event.type === "tool:completed") {
|
|
7692
|
+
const toolText = `- done \`${event.tool}\` (${event.duration}ms)`;
|
|
7693
|
+
draft.toolTimeline.push(toolText);
|
|
7694
|
+
draft.currentTools.push(toolText);
|
|
7695
|
+
return;
|
|
7696
|
+
}
|
|
7697
|
+
if (event.type === "tool:error") {
|
|
7698
|
+
const toolText = `- error \`${event.tool}\`: ${event.error}`;
|
|
7699
|
+
draft.toolTimeline.push(toolText);
|
|
7700
|
+
draft.currentTools.push(toolText);
|
|
7701
|
+
}
|
|
7702
|
+
};
|
|
7703
|
+
var buildAssistantMetadata = (draft, sectionsOverride) => {
|
|
7704
|
+
const sections = sectionsOverride ?? cloneSections(draft.sections);
|
|
7705
|
+
if (draft.toolTimeline.length === 0 && sections.length === 0) return void 0;
|
|
7706
|
+
return {
|
|
7707
|
+
toolActivity: [...draft.toolTimeline],
|
|
7708
|
+
sections: sections.length > 0 ? sections : void 0
|
|
7709
|
+
};
|
|
7710
|
+
};
|
|
7711
|
+
var executeConversationTurn = async ({
|
|
7712
|
+
harness,
|
|
7713
|
+
runInput,
|
|
7714
|
+
initialContextTokens = 0,
|
|
7715
|
+
initialContextWindow = 0,
|
|
7716
|
+
onEvent
|
|
7717
|
+
}) => {
|
|
7718
|
+
const draft = createTurnDraftState();
|
|
7719
|
+
let latestRunId = "";
|
|
7720
|
+
let runCancelled = false;
|
|
7721
|
+
let runContinuation = false;
|
|
7722
|
+
let runContinuationMessages;
|
|
7723
|
+
let runHarnessMessages;
|
|
7724
|
+
let runContextTokens = initialContextTokens;
|
|
7725
|
+
let runContextWindow = initialContextWindow;
|
|
7726
|
+
let runSteps = 0;
|
|
7727
|
+
let runMaxSteps;
|
|
7728
|
+
for await (const event of harness.runWithTelemetry(runInput)) {
|
|
7729
|
+
recordStandardTurnEvent(draft, event);
|
|
7730
|
+
if (event.type === "run:started") {
|
|
7731
|
+
latestRunId = event.runId;
|
|
7732
|
+
}
|
|
7733
|
+
if (event.type === "run:cancelled") {
|
|
7734
|
+
runCancelled = true;
|
|
7735
|
+
}
|
|
7736
|
+
if (event.type === "run:completed") {
|
|
7737
|
+
runContinuation = event.result.continuation === true;
|
|
7738
|
+
runContinuationMessages = event.result.continuationMessages;
|
|
7739
|
+
runHarnessMessages = event.result.continuationMessages;
|
|
7740
|
+
runContextTokens = event.result.contextTokens ?? runContextTokens;
|
|
7741
|
+
runContextWindow = event.result.contextWindow ?? runContextWindow;
|
|
7742
|
+
runSteps = event.result.steps;
|
|
7743
|
+
if (typeof event.result.maxSteps === "number") {
|
|
7744
|
+
runMaxSteps = event.result.maxSteps;
|
|
7745
|
+
}
|
|
7746
|
+
if (draft.assistantResponse.length === 0 && event.result.response) {
|
|
7747
|
+
draft.assistantResponse = event.result.response;
|
|
7748
|
+
}
|
|
7749
|
+
}
|
|
7750
|
+
if (event.type === "run:error") {
|
|
7751
|
+
draft.assistantResponse = draft.assistantResponse || `[Error: ${event.error.message}]`;
|
|
7752
|
+
}
|
|
7753
|
+
if (onEvent) {
|
|
7754
|
+
await onEvent(event, draft);
|
|
7755
|
+
}
|
|
7756
|
+
}
|
|
7757
|
+
return {
|
|
7758
|
+
latestRunId,
|
|
7759
|
+
runCancelled,
|
|
7760
|
+
runContinuation,
|
|
7761
|
+
runContinuationMessages,
|
|
7762
|
+
runHarnessMessages,
|
|
7763
|
+
runContextTokens,
|
|
7764
|
+
runContextWindow,
|
|
7765
|
+
runSteps,
|
|
7766
|
+
runMaxSteps,
|
|
7767
|
+
draft
|
|
7768
|
+
};
|
|
7769
|
+
};
|
|
7770
|
+
var normalizePendingToolCalls = (value) => {
|
|
7771
|
+
if (!Array.isArray(value)) return [];
|
|
7772
|
+
return value.filter((entry) => {
|
|
7773
|
+
if (!entry || typeof entry !== "object") return false;
|
|
7774
|
+
const row = entry;
|
|
7775
|
+
return typeof row.id === "string" && typeof row.name === "string" && typeof row.input === "object" && row.input !== null;
|
|
7776
|
+
}).map((entry) => ({ id: entry.id, name: entry.name, input: entry.input }));
|
|
7777
|
+
};
|
|
7778
|
+
var normalizeApprovalCheckpoint = (approval, fallbackMessages) => ({
|
|
7779
|
+
...approval,
|
|
7780
|
+
checkpointMessages: isMessageArray(approval.checkpointMessages) ? approval.checkpointMessages : [...fallbackMessages],
|
|
7781
|
+
baseMessageCount: typeof approval.baseMessageCount === "number" && approval.baseMessageCount >= 0 ? approval.baseMessageCount : 0,
|
|
7782
|
+
pendingToolCalls: normalizePendingToolCalls(approval.pendingToolCalls)
|
|
7783
|
+
});
|
|
7784
|
+
var buildApprovalCheckpoints = ({
|
|
7785
|
+
approvals,
|
|
7786
|
+
runId,
|
|
7787
|
+
checkpointMessages,
|
|
7788
|
+
baseMessageCount,
|
|
7789
|
+
pendingToolCalls
|
|
7790
|
+
}) => approvals.map((approval) => ({
|
|
7791
|
+
approvalId: approval.approvalId,
|
|
7792
|
+
runId,
|
|
7793
|
+
tool: approval.tool,
|
|
7794
|
+
toolCallId: approval.toolCallId,
|
|
7795
|
+
input: approval.input,
|
|
7796
|
+
checkpointMessages,
|
|
7797
|
+
baseMessageCount,
|
|
7798
|
+
pendingToolCalls
|
|
7799
|
+
}));
|
|
7800
|
+
var resolveRunRequest = (conversation, request) => {
|
|
7801
|
+
const resolved = loadRunHistory(conversation, {
|
|
7802
|
+
preferContinuation: request.preferContinuation
|
|
7803
|
+
});
|
|
7804
|
+
return {
|
|
7805
|
+
source: resolved.source,
|
|
7806
|
+
shouldRebuildCanonical: resolved.shouldRebuildCanonical,
|
|
7807
|
+
messages: resolved.messages.length > 0 ? resolved.messages : request.messages
|
|
7808
|
+
};
|
|
7809
|
+
};
|
|
7810
|
+
var __internalRunOrchestration = {
|
|
7811
|
+
isMessageArray,
|
|
7812
|
+
loadCanonicalHistory,
|
|
7813
|
+
loadRunHistory,
|
|
7814
|
+
normalizeApprovalCheckpoint,
|
|
7815
|
+
buildApprovalCheckpoints,
|
|
7816
|
+
resolveRunRequest,
|
|
7817
|
+
createTurnDraftState,
|
|
7818
|
+
recordStandardTurnEvent,
|
|
7819
|
+
executeConversationTurn
|
|
7820
|
+
};
|
|
7549
7821
|
var AGENT_TEMPLATE = (name, id, options) => `---
|
|
7550
7822
|
name: ${name}
|
|
7551
7823
|
id: ${id}
|
|
@@ -8729,6 +9001,60 @@ data: ${JSON.stringify(statusPayload)}
|
|
|
8729
9001
|
const activeSubagentRuns = /* @__PURE__ */ new Map();
|
|
8730
9002
|
const pendingSubagentApprovals = /* @__PURE__ */ new Map();
|
|
8731
9003
|
const approvalDecisionTracker = /* @__PURE__ */ new Map();
|
|
9004
|
+
const findPendingApproval = async (approvalId, owner) => {
|
|
9005
|
+
const searchedConversationIds = /* @__PURE__ */ new Set();
|
|
9006
|
+
const scan = async (conversations) => {
|
|
9007
|
+
for (const conv of conversations) {
|
|
9008
|
+
if (searchedConversationIds.has(conv.conversationId)) continue;
|
|
9009
|
+
searchedConversationIds.add(conv.conversationId);
|
|
9010
|
+
if (!Array.isArray(conv.pendingApprovals)) continue;
|
|
9011
|
+
const match = conv.pendingApprovals.find((approval) => approval.approvalId === approvalId);
|
|
9012
|
+
if (match) {
|
|
9013
|
+
return { conversation: conv, approval: match };
|
|
9014
|
+
}
|
|
9015
|
+
}
|
|
9016
|
+
return void 0;
|
|
9017
|
+
};
|
|
9018
|
+
const ownerScoped = await scan(await conversationStore.list(owner));
|
|
9019
|
+
if (ownerScoped) return ownerScoped;
|
|
9020
|
+
if (owner === "local-owner") {
|
|
9021
|
+
return await scan(await conversationStore.list());
|
|
9022
|
+
}
|
|
9023
|
+
return void 0;
|
|
9024
|
+
};
|
|
9025
|
+
const hasRunningSubagentsForParent = async (parentConversationId, owner) => {
|
|
9026
|
+
let hasRunning = Array.from(activeSubagentRuns.values()).some(
|
|
9027
|
+
(run) => run.parentConversationId === parentConversationId
|
|
9028
|
+
);
|
|
9029
|
+
if (hasRunning) return true;
|
|
9030
|
+
const summaries = await conversationStore.listSummaries(owner);
|
|
9031
|
+
for (const summary of summaries) {
|
|
9032
|
+
if (summary.parentConversationId !== parentConversationId) continue;
|
|
9033
|
+
const childConversation = await conversationStore.get(summary.conversationId);
|
|
9034
|
+
if (childConversation?.subagentMeta?.status === "running") {
|
|
9035
|
+
hasRunning = true;
|
|
9036
|
+
break;
|
|
9037
|
+
}
|
|
9038
|
+
}
|
|
9039
|
+
return hasRunning;
|
|
9040
|
+
};
|
|
9041
|
+
const hasPendingSubagentWorkForParent = async (parentConversationId, owner) => {
|
|
9042
|
+
if (await hasRunningSubagentsForParent(parentConversationId, owner)) {
|
|
9043
|
+
return true;
|
|
9044
|
+
}
|
|
9045
|
+
if (pendingCallbackNeeded.has(parentConversationId)) {
|
|
9046
|
+
return true;
|
|
9047
|
+
}
|
|
9048
|
+
const parentConversation = await conversationStore.get(parentConversationId);
|
|
9049
|
+
if (!parentConversation) return false;
|
|
9050
|
+
if (Array.isArray(parentConversation.pendingSubagentResults) && parentConversation.pendingSubagentResults.length > 0) {
|
|
9051
|
+
return true;
|
|
9052
|
+
}
|
|
9053
|
+
if (typeof parentConversation.runningCallbackSince === "number" && parentConversation.runningCallbackSince > 0) {
|
|
9054
|
+
return true;
|
|
9055
|
+
}
|
|
9056
|
+
return false;
|
|
9057
|
+
};
|
|
8732
9058
|
const getSubagentDepth = async (conversationId) => {
|
|
8733
9059
|
let depth = 0;
|
|
8734
9060
|
let current = await conversationStore.get(conversationId);
|
|
@@ -8772,7 +9098,9 @@ data: ${JSON.stringify(statusPayload)}
|
|
|
8772
9098
|
const resumeSubagentFromCheckpoint = async (subagentId) => {
|
|
8773
9099
|
const conv = await conversationStore.get(subagentId);
|
|
8774
9100
|
if (!conv || !conv.parentConversationId) return;
|
|
8775
|
-
const allApprovals = conv.pendingApprovals ?? []
|
|
9101
|
+
const allApprovals = (conv.pendingApprovals ?? []).map(
|
|
9102
|
+
(approval) => normalizeApprovalCheckpoint(approval, conv.messages)
|
|
9103
|
+
);
|
|
8776
9104
|
if (allApprovals.length === 0) return;
|
|
8777
9105
|
const allDecided = allApprovals.every((a) => a.decision != null);
|
|
8778
9106
|
if (!allDecided) return;
|
|
@@ -8843,7 +9171,11 @@ data: ${JSON.stringify(statusPayload)}
|
|
|
8843
9171
|
if (conversation.subagentMeta?.status === "stopped") return;
|
|
8844
9172
|
conversation.lastActivityAt = Date.now();
|
|
8845
9173
|
await conversationStore.update(conversation);
|
|
8846
|
-
const
|
|
9174
|
+
const runOutcome = resolveRunRequest(conversation, {
|
|
9175
|
+
conversationId: childConversationId,
|
|
9176
|
+
messages: conversation.messages
|
|
9177
|
+
});
|
|
9178
|
+
const harnessMessages = [...runOutcome.messages];
|
|
8847
9179
|
for await (const event of childHarness.runWithTelemetry({
|
|
8848
9180
|
task,
|
|
8849
9181
|
conversationId: childConversationId,
|
|
@@ -8905,16 +9237,13 @@ data: ${JSON.stringify(statusPayload)}
|
|
|
8905
9237
|
if (event.type === "tool:approval:checkpoint") {
|
|
8906
9238
|
const cpConv = await conversationStore.get(childConversationId);
|
|
8907
9239
|
if (cpConv) {
|
|
8908
|
-
const allCpData =
|
|
8909
|
-
|
|
9240
|
+
const allCpData = buildApprovalCheckpoints({
|
|
9241
|
+
approvals: event.approvals,
|
|
8910
9242
|
runId: latestRunId,
|
|
8911
|
-
tool: a.tool,
|
|
8912
|
-
toolCallId: a.toolCallId,
|
|
8913
|
-
input: a.input,
|
|
8914
9243
|
checkpointMessages: [...harnessMessages, ...event.checkpointMessages],
|
|
8915
9244
|
baseMessageCount: 0,
|
|
8916
9245
|
pendingToolCalls: event.pendingToolCalls
|
|
8917
|
-
})
|
|
9246
|
+
});
|
|
8918
9247
|
cpConv.pendingApprovals = allCpData;
|
|
8919
9248
|
cpConv.updatedAt = Date.now();
|
|
8920
9249
|
await conversationStore.update(cpConv);
|
|
@@ -8929,7 +9258,7 @@ data: ${JSON.stringify(statusPayload)}
|
|
|
8929
9258
|
});
|
|
8930
9259
|
}
|
|
8931
9260
|
});
|
|
8932
|
-
const checkpointRef = allCpData[0];
|
|
9261
|
+
const checkpointRef = normalizeApprovalCheckpoint(allCpData[0], [...harnessMessages]);
|
|
8933
9262
|
const toolContext = {
|
|
8934
9263
|
runId: checkpointRef.runId,
|
|
8935
9264
|
agentId: identity.id,
|
|
@@ -9051,6 +9380,8 @@ data: ${JSON.stringify(statusPayload)}
|
|
|
9051
9380
|
}
|
|
9052
9381
|
if (runResult?.continuationMessages) {
|
|
9053
9382
|
conv._harnessMessages = runResult.continuationMessages;
|
|
9383
|
+
} else if (runOutcome.shouldRebuildCanonical) {
|
|
9384
|
+
conv._harnessMessages = conv.messages;
|
|
9054
9385
|
}
|
|
9055
9386
|
conv._toolResultArchive = childHarness.getToolResultArchive(childConversationId);
|
|
9056
9387
|
conv.lastActivityAt = Date.now();
|
|
@@ -9193,6 +9524,7 @@ ${resultBody}`,
|
|
|
9193
9524
|
metadata: { _subagentCallback: true, subagentId: pr.subagentId, task: pr.task, timestamp: pr.timestamp }
|
|
9194
9525
|
});
|
|
9195
9526
|
}
|
|
9527
|
+
conversation._harnessMessages = [...conversation.messages];
|
|
9196
9528
|
conversation.updatedAt = Date.now();
|
|
9197
9529
|
await conversationStore.update(conversation);
|
|
9198
9530
|
if (callbackCount > MAX_SUBAGENT_CALLBACK_COUNT) {
|
|
@@ -9221,109 +9553,70 @@ ${resultBody}`,
|
|
|
9221
9553
|
finished: false
|
|
9222
9554
|
});
|
|
9223
9555
|
}
|
|
9224
|
-
const
|
|
9225
|
-
|
|
9226
|
-
|
|
9227
|
-
|
|
9228
|
-
|
|
9229
|
-
|
|
9230
|
-
|
|
9231
|
-
|
|
9232
|
-
|
|
9233
|
-
|
|
9234
|
-
let currentTools = [];
|
|
9235
|
-
let currentText = "";
|
|
9556
|
+
const historySelection = resolveRunRequest(conversation, {
|
|
9557
|
+
conversationId,
|
|
9558
|
+
messages: conversation.messages,
|
|
9559
|
+
preferContinuation: isContinuationResume
|
|
9560
|
+
});
|
|
9561
|
+
const historyMessages = [...historySelection.messages];
|
|
9562
|
+
console.info(
|
|
9563
|
+
`[poncho][subagent-callback] conversation="${conversationId}" history_source=${historySelection.source}`
|
|
9564
|
+
);
|
|
9565
|
+
let execution;
|
|
9236
9566
|
try {
|
|
9237
|
-
|
|
9238
|
-
|
|
9239
|
-
|
|
9240
|
-
|
|
9241
|
-
|
|
9242
|
-
|
|
9243
|
-
|
|
9244
|
-
|
|
9245
|
-
|
|
9246
|
-
|
|
9247
|
-
|
|
9248
|
-
|
|
9249
|
-
|
|
9250
|
-
|
|
9251
|
-
|
|
9252
|
-
|
|
9253
|
-
|
|
9254
|
-
|
|
9255
|
-
currentTools = [];
|
|
9256
|
-
if (assistantResponse.length > 0 && !/\s$/.test(assistantResponse)) {
|
|
9257
|
-
assistantResponse += " ";
|
|
9258
|
-
}
|
|
9259
|
-
}
|
|
9260
|
-
assistantResponse += event.content;
|
|
9261
|
-
currentText += event.content;
|
|
9262
|
-
}
|
|
9263
|
-
if (event.type === "tool:started") {
|
|
9264
|
-
if (currentText.length > 0) {
|
|
9265
|
-
sections.push({ type: "text", content: currentText });
|
|
9266
|
-
currentText = "";
|
|
9267
|
-
}
|
|
9268
|
-
const toolText = `- start \`${event.tool}\``;
|
|
9269
|
-
toolTimeline.push(toolText);
|
|
9270
|
-
currentTools.push(toolText);
|
|
9271
|
-
}
|
|
9272
|
-
if (event.type === "tool:completed") {
|
|
9273
|
-
const toolText = `- done \`${event.tool}\` (${event.duration}ms)`;
|
|
9274
|
-
toolTimeline.push(toolText);
|
|
9275
|
-
currentTools.push(toolText);
|
|
9276
|
-
}
|
|
9277
|
-
if (event.type === "tool:error") {
|
|
9278
|
-
const toolText = `- error \`${event.tool}\`: ${event.error}`;
|
|
9279
|
-
toolTimeline.push(toolText);
|
|
9280
|
-
currentTools.push(toolText);
|
|
9281
|
-
}
|
|
9282
|
-
if (event.type === "run:completed") {
|
|
9283
|
-
if (assistantResponse.length === 0 && event.result.response) {
|
|
9284
|
-
assistantResponse = event.result.response;
|
|
9285
|
-
}
|
|
9286
|
-
runContextTokens = event.result.contextTokens ?? runContextTokens;
|
|
9287
|
-
runContextWindow = event.result.contextWindow ?? runContextWindow;
|
|
9288
|
-
if (event.result.continuationMessages) {
|
|
9289
|
-
runHarnessMessages = event.result.continuationMessages;
|
|
9290
|
-
}
|
|
9291
|
-
if (event.result.continuation) {
|
|
9292
|
-
runContinuation2 = true;
|
|
9293
|
-
if (event.result.continuationMessages) {
|
|
9294
|
-
runContinuationMessages = event.result.continuationMessages;
|
|
9295
|
-
}
|
|
9567
|
+
execution = await executeConversationTurn({
|
|
9568
|
+
harness,
|
|
9569
|
+
runInput: {
|
|
9570
|
+
task: void 0,
|
|
9571
|
+
conversationId,
|
|
9572
|
+
parameters: withToolResultArchiveParam({
|
|
9573
|
+
__activeConversationId: conversationId,
|
|
9574
|
+
__ownerId: conversation.ownerId
|
|
9575
|
+
}, conversation),
|
|
9576
|
+
messages: historyMessages,
|
|
9577
|
+
abortSignal: abortController.signal
|
|
9578
|
+
},
|
|
9579
|
+
initialContextTokens: conversation.contextTokens ?? 0,
|
|
9580
|
+
initialContextWindow: conversation.contextWindow ?? 0,
|
|
9581
|
+
onEvent: (event) => {
|
|
9582
|
+
if (event.type === "run:started") {
|
|
9583
|
+
const active = activeConversationRuns.get(conversationId);
|
|
9584
|
+
if (active) active.runId = event.runId;
|
|
9296
9585
|
}
|
|
9586
|
+
broadcastEvent(conversationId, event);
|
|
9297
9587
|
}
|
|
9298
|
-
|
|
9299
|
-
|
|
9300
|
-
|
|
9301
|
-
if (
|
|
9302
|
-
if (runContinuationMessages || assistantResponse.length > 0 || toolTimeline.length > 0) {
|
|
9588
|
+
});
|
|
9589
|
+
flushTurnDraft(execution.draft);
|
|
9590
|
+
const callbackNeedsContinuation = execution.runContinuation && execution.runContinuationMessages;
|
|
9591
|
+
if (callbackNeedsContinuation || execution.draft.assistantResponse.length > 0 || execution.draft.toolTimeline.length > 0) {
|
|
9303
9592
|
const freshConv = await conversationStore.get(conversationId);
|
|
9304
9593
|
if (freshConv) {
|
|
9305
|
-
if (
|
|
9306
|
-
freshConv._continuationMessages = runContinuationMessages;
|
|
9594
|
+
if (callbackNeedsContinuation) {
|
|
9595
|
+
freshConv._continuationMessages = execution.runContinuationMessages;
|
|
9307
9596
|
} else {
|
|
9308
9597
|
freshConv._continuationMessages = void 0;
|
|
9309
9598
|
freshConv.messages.push({
|
|
9310
9599
|
role: "assistant",
|
|
9311
|
-
content: assistantResponse,
|
|
9312
|
-
metadata:
|
|
9600
|
+
content: execution.draft.assistantResponse,
|
|
9601
|
+
metadata: buildAssistantMetadata(execution.draft)
|
|
9313
9602
|
});
|
|
9314
9603
|
}
|
|
9315
|
-
if (runHarnessMessages) {
|
|
9316
|
-
freshConv._harnessMessages = runHarnessMessages;
|
|
9604
|
+
if (callbackNeedsContinuation && execution.runHarnessMessages) {
|
|
9605
|
+
freshConv._harnessMessages = execution.runHarnessMessages;
|
|
9606
|
+
} else if (historySelection.shouldRebuildCanonical) {
|
|
9607
|
+
freshConv._harnessMessages = freshConv.messages;
|
|
9608
|
+
} else {
|
|
9609
|
+
freshConv._harnessMessages = freshConv.messages;
|
|
9317
9610
|
}
|
|
9318
9611
|
freshConv._toolResultArchive = harness.getToolResultArchive(conversationId);
|
|
9319
|
-
freshConv.runtimeRunId = latestRunId || freshConv.runtimeRunId;
|
|
9612
|
+
freshConv.runtimeRunId = execution.latestRunId || freshConv.runtimeRunId;
|
|
9320
9613
|
freshConv.runningCallbackSince = void 0;
|
|
9321
9614
|
freshConv.runStatus = "idle";
|
|
9322
|
-
if (runContextTokens > 0) freshConv.contextTokens = runContextTokens;
|
|
9323
|
-
if (runContextWindow > 0) freshConv.contextWindow = runContextWindow;
|
|
9615
|
+
if (execution.runContextTokens > 0) freshConv.contextTokens = execution.runContextTokens;
|
|
9616
|
+
if (execution.runContextWindow > 0) freshConv.contextWindow = execution.runContextWindow;
|
|
9324
9617
|
freshConv.updatedAt = Date.now();
|
|
9325
9618
|
await conversationStore.update(freshConv);
|
|
9326
|
-
if (freshConv.channelMeta && assistantResponse.length > 0) {
|
|
9619
|
+
if (freshConv.channelMeta && execution.draft.assistantResponse.length > 0) {
|
|
9327
9620
|
const adapter = messagingAdapters.get(freshConv.channelMeta.platform);
|
|
9328
9621
|
if (adapter) {
|
|
9329
9622
|
try {
|
|
@@ -9332,7 +9625,7 @@ ${resultBody}`,
|
|
|
9332
9625
|
channelId: freshConv.channelMeta.channelId,
|
|
9333
9626
|
platformThreadId: freshConv.channelMeta.platformThreadId
|
|
9334
9627
|
},
|
|
9335
|
-
assistantResponse
|
|
9628
|
+
execution.draft.assistantResponse
|
|
9336
9629
|
);
|
|
9337
9630
|
} catch (sendErr) {
|
|
9338
9631
|
console.error(`[poncho][subagent-callback] Messaging notify failed:`, sendErr instanceof Error ? sendErr.message : sendErr);
|
|
@@ -9341,7 +9634,7 @@ ${resultBody}`,
|
|
|
9341
9634
|
}
|
|
9342
9635
|
}
|
|
9343
9636
|
}
|
|
9344
|
-
if (
|
|
9637
|
+
if (execution.runContinuation) {
|
|
9345
9638
|
if (isServerless) {
|
|
9346
9639
|
const work = selfFetchWithRetry(`/api/internal/conversations/${encodeURIComponent(conversationId)}/subagent-callback`).catch(
|
|
9347
9640
|
(err) => console.error(`[poncho][subagent-callback] Continuation self-fetch failed:`, err instanceof Error ? err.message : err)
|
|
@@ -9363,10 +9656,15 @@ ${resultBody}`,
|
|
|
9363
9656
|
}
|
|
9364
9657
|
} finally {
|
|
9365
9658
|
activeConversationRuns.delete(conversationId);
|
|
9366
|
-
finishConversationStream(conversationId);
|
|
9367
9659
|
const hadDeferredTrigger = pendingCallbackNeeded.delete(conversationId);
|
|
9368
9660
|
const freshConv = await conversationStore.get(conversationId);
|
|
9369
9661
|
const hasPendingInStore = !!freshConv?.pendingSubagentResults?.length;
|
|
9662
|
+
const hasRunningCallbackChildren = Array.from(activeSubagentRuns.values()).some(
|
|
9663
|
+
(run) => run.parentConversationId === conversationId
|
|
9664
|
+
);
|
|
9665
|
+
if (!hadDeferredTrigger && !hasPendingInStore && !hasRunningCallbackChildren) {
|
|
9666
|
+
finishConversationStream(conversationId);
|
|
9667
|
+
}
|
|
9370
9668
|
if (hadDeferredTrigger || hasPendingInStore) {
|
|
9371
9669
|
if (isServerless) {
|
|
9372
9670
|
selfFetchWithRetry(`/api/internal/conversations/${encodeURIComponent(conversationId)}/subagent-callback`).catch(
|
|
@@ -9514,8 +9812,9 @@ ${resultBody}`,
|
|
|
9514
9812
|
let runContextTokens = conversation.contextTokens ?? 0;
|
|
9515
9813
|
let runContextWindow = conversation.contextWindow ?? 0;
|
|
9516
9814
|
let resumeHarnessMessages;
|
|
9517
|
-
const
|
|
9518
|
-
const
|
|
9815
|
+
const normalizedCheckpoint = normalizeApprovalCheckpoint(checkpoint, conversation.messages);
|
|
9816
|
+
const baseMessages = normalizedCheckpoint.baseMessageCount != null ? conversation.messages.slice(0, normalizedCheckpoint.baseMessageCount) : [];
|
|
9817
|
+
const fullCheckpointMessages = [...baseMessages, ...normalizedCheckpoint.checkpointMessages];
|
|
9519
9818
|
let resumeToolResultMsg;
|
|
9520
9819
|
const lastCpMsg = fullCheckpointMessages[fullCheckpointMessages.length - 1];
|
|
9521
9820
|
if (lastCpMsg?.role === "assistant") {
|
|
@@ -9596,24 +9895,26 @@ ${resultBody}`,
|
|
|
9596
9895
|
if (event.type === "tool:approval:checkpoint") {
|
|
9597
9896
|
const conv = await conversationStore.get(conversationId);
|
|
9598
9897
|
if (conv) {
|
|
9599
|
-
conv.pendingApprovals =
|
|
9600
|
-
|
|
9898
|
+
conv.pendingApprovals = buildApprovalCheckpoints({
|
|
9899
|
+
approvals: event.approvals,
|
|
9601
9900
|
runId: latestRunId,
|
|
9602
|
-
tool: a.tool,
|
|
9603
|
-
toolCallId: a.toolCallId,
|
|
9604
|
-
input: a.input,
|
|
9605
9901
|
checkpointMessages: [...fullCheckpointWithResults, ...event.checkpointMessages],
|
|
9606
9902
|
baseMessageCount: 0,
|
|
9607
9903
|
pendingToolCalls: event.pendingToolCalls
|
|
9608
|
-
})
|
|
9904
|
+
});
|
|
9609
9905
|
conv.updatedAt = Date.now();
|
|
9610
9906
|
await conversationStore.update(conv);
|
|
9611
9907
|
if (conv.channelMeta?.platform === "telegram") {
|
|
9612
9908
|
const tgAdapter = messagingAdapters.get("telegram");
|
|
9613
9909
|
if (tgAdapter) {
|
|
9910
|
+
const messageThreadId = parseTelegramMessageThreadIdFromPlatformThreadId(
|
|
9911
|
+
conv.channelMeta.platformThreadId,
|
|
9912
|
+
conv.channelMeta.channelId
|
|
9913
|
+
);
|
|
9614
9914
|
void tgAdapter.sendApprovalRequest(
|
|
9615
9915
|
conv.channelMeta.channelId,
|
|
9616
|
-
event.approvals.map((a) => ({ approvalId: a.approvalId, tool: a.tool, input: a.input }))
|
|
9916
|
+
event.approvals.map((a) => ({ approvalId: a.approvalId, tool: a.tool, input: a.input })),
|
|
9917
|
+
{ message_thread_id: messageThreadId }
|
|
9617
9918
|
).catch(() => {
|
|
9618
9919
|
});
|
|
9619
9920
|
}
|
|
@@ -9691,6 +9992,8 @@ ${resultBody}`,
|
|
|
9691
9992
|
}
|
|
9692
9993
|
if (resumeHarnessMessages) {
|
|
9693
9994
|
conv._harnessMessages = resumeHarnessMessages;
|
|
9995
|
+
} else {
|
|
9996
|
+
conv._harnessMessages = conv.messages;
|
|
9694
9997
|
}
|
|
9695
9998
|
conv.runtimeRunId = latestRunId || conv.runtimeRunId;
|
|
9696
9999
|
conv.pendingApprovals = [];
|
|
@@ -9708,7 +10011,6 @@ ${resultBody}`,
|
|
|
9708
10011
|
await conversationStore.update(conv);
|
|
9709
10012
|
}
|
|
9710
10013
|
}
|
|
9711
|
-
finishConversationStream(conversationId);
|
|
9712
10014
|
activeConversationRuns.delete(conversationId);
|
|
9713
10015
|
if (latestRunId) {
|
|
9714
10016
|
runOwners.delete(latestRunId);
|
|
@@ -9717,14 +10019,20 @@ ${resultBody}`,
|
|
|
9717
10019
|
console.log("[resume-run] complete for", conversationId);
|
|
9718
10020
|
const hadDeferred = pendingCallbackNeeded.delete(conversationId);
|
|
9719
10021
|
const postConv = await conversationStore.get(conversationId);
|
|
9720
|
-
|
|
10022
|
+
const needsResumeCallback = hadDeferred || !!postConv?.pendingSubagentResults?.length;
|
|
10023
|
+
const hasRunningResumeChildren = Array.from(activeSubagentRuns.values()).some(
|
|
10024
|
+
(run) => run.parentConversationId === conversationId
|
|
10025
|
+
);
|
|
10026
|
+
if (!needsResumeCallback && !hasRunningResumeChildren) {
|
|
10027
|
+
finishConversationStream(conversationId);
|
|
10028
|
+
}
|
|
10029
|
+
if (needsResumeCallback) {
|
|
9721
10030
|
processSubagentCallback(conversationId, true).catch(
|
|
9722
10031
|
(err) => console.error(`[poncho][subagent-callback] Post-resume callback failed:`, err instanceof Error ? err.message : err)
|
|
9723
10032
|
);
|
|
9724
10033
|
}
|
|
9725
10034
|
};
|
|
9726
10035
|
const messagingRoutes = /* @__PURE__ */ new Map();
|
|
9727
|
-
const messagingRunQueues = /* @__PURE__ */ new Map();
|
|
9728
10036
|
const messagingRouteRegistrar = (method, path, routeHandler) => {
|
|
9729
10037
|
let byMethod = messagingRoutes.get(path);
|
|
9730
10038
|
if (!byMethod) {
|
|
@@ -9745,7 +10053,7 @@ ${resultBody}`,
|
|
|
9745
10053
|
};
|
|
9746
10054
|
await conversationStore.update(existing);
|
|
9747
10055
|
}
|
|
9748
|
-
return { messages: existing.
|
|
10056
|
+
return { messages: loadCanonicalHistory(existing).messages };
|
|
9749
10057
|
}
|
|
9750
10058
|
const now = Date.now();
|
|
9751
10059
|
const channelMeta = meta.channelId ? {
|
|
@@ -9767,159 +10075,116 @@ ${resultBody}`,
|
|
|
9767
10075
|
return { messages: [] };
|
|
9768
10076
|
},
|
|
9769
10077
|
async run(conversationId, input2) {
|
|
9770
|
-
const
|
|
9771
|
-
|
|
9772
|
-
const
|
|
9773
|
-
|
|
10078
|
+
const latestConversation = await conversationStore.get(conversationId);
|
|
10079
|
+
const canonicalHistory = latestConversation ? loadCanonicalHistory(latestConversation) : { messages: [...input2.messages], source: "messages" };
|
|
10080
|
+
const shouldRebuildCanonical = canonicalHistory.source !== "harness";
|
|
10081
|
+
const isContinuation = input2.task == null;
|
|
10082
|
+
console.log(
|
|
10083
|
+
`[messaging-runner] starting run for ${conversationId} ${isContinuation ? "(continuation)" : `task: ${input2.task.slice(0, 80)}`} history_source=${canonicalHistory.source}`
|
|
10084
|
+
);
|
|
10085
|
+
const historyMessages = [...canonicalHistory.messages];
|
|
10086
|
+
const preRunMessages = [...canonicalHistory.messages];
|
|
10087
|
+
const userContent = input2.task;
|
|
10088
|
+
const updateConversation = async (patch) => {
|
|
10089
|
+
const fresh = await conversationStore.get(conversationId);
|
|
10090
|
+
if (!fresh) return;
|
|
10091
|
+
patch(fresh);
|
|
10092
|
+
fresh.updatedAt = Date.now();
|
|
10093
|
+
await conversationStore.update(fresh);
|
|
10094
|
+
};
|
|
10095
|
+
await updateConversation((c) => {
|
|
10096
|
+
if (!isContinuation) {
|
|
10097
|
+
c.messages = [...historyMessages, { role: "user", content: userContent }];
|
|
10098
|
+
}
|
|
10099
|
+
c.runStatus = "running";
|
|
9774
10100
|
});
|
|
9775
|
-
|
|
9776
|
-
|
|
9777
|
-
|
|
9778
|
-
|
|
9779
|
-
|
|
9780
|
-
|
|
9781
|
-
|
|
9782
|
-
|
|
9783
|
-
|
|
9784
|
-
|
|
9785
|
-
const
|
|
9786
|
-
|
|
9787
|
-
|
|
9788
|
-
|
|
9789
|
-
|
|
9790
|
-
|
|
9791
|
-
|
|
9792
|
-
};
|
|
9793
|
-
|
|
9794
|
-
|
|
9795
|
-
|
|
10101
|
+
let latestRunId = "";
|
|
10102
|
+
const draft = createTurnDraftState();
|
|
10103
|
+
let checkpointedRun = false;
|
|
10104
|
+
let runContextTokens = 0;
|
|
10105
|
+
let runContextWindow = 0;
|
|
10106
|
+
let runContinuation2 = false;
|
|
10107
|
+
let runContinuationMessages;
|
|
10108
|
+
let runSteps = 0;
|
|
10109
|
+
let runMaxSteps;
|
|
10110
|
+
const buildMessages = () => {
|
|
10111
|
+
const draftSections = cloneSections(draft.sections);
|
|
10112
|
+
if (draft.currentTools.length > 0) {
|
|
10113
|
+
draftSections.push({ type: "tools", content: [...draft.currentTools] });
|
|
10114
|
+
}
|
|
10115
|
+
if (draft.currentText.length > 0) {
|
|
10116
|
+
draftSections.push({ type: "text", content: draft.currentText });
|
|
10117
|
+
}
|
|
10118
|
+
const userTurn = userContent != null ? [{ role: "user", content: userContent }] : [];
|
|
10119
|
+
const hasDraftContent = draft.assistantResponse.length > 0 || draft.toolTimeline.length > 0 || draftSections.length > 0;
|
|
10120
|
+
if (!hasDraftContent) {
|
|
10121
|
+
return [...historyMessages, ...userTurn];
|
|
10122
|
+
}
|
|
10123
|
+
return [
|
|
10124
|
+
...historyMessages,
|
|
10125
|
+
...userTurn,
|
|
10126
|
+
{
|
|
10127
|
+
role: "assistant",
|
|
10128
|
+
content: draft.assistantResponse,
|
|
10129
|
+
metadata: buildAssistantMetadata(draft, draftSections)
|
|
9796
10130
|
}
|
|
9797
|
-
|
|
10131
|
+
];
|
|
10132
|
+
};
|
|
10133
|
+
const persistDraftAssistantTurn = async () => {
|
|
10134
|
+
if (draft.assistantResponse.length === 0 && draft.toolTimeline.length === 0) return;
|
|
10135
|
+
await updateConversation((c) => {
|
|
10136
|
+
c.messages = buildMessages();
|
|
9798
10137
|
});
|
|
9799
|
-
|
|
9800
|
-
|
|
9801
|
-
|
|
9802
|
-
|
|
9803
|
-
|
|
9804
|
-
|
|
9805
|
-
|
|
9806
|
-
|
|
9807
|
-
|
|
9808
|
-
|
|
9809
|
-
|
|
9810
|
-
|
|
9811
|
-
|
|
9812
|
-
|
|
9813
|
-
|
|
9814
|
-
|
|
9815
|
-
|
|
9816
|
-
|
|
9817
|
-
|
|
9818
|
-
|
|
9819
|
-
|
|
9820
|
-
|
|
9821
|
-
|
|
9822
|
-
|
|
9823
|
-
|
|
9824
|
-
|
|
9825
|
-
const userTurn = userContent != null ? [{ role: "user", content: userContent }] : [];
|
|
9826
|
-
const hasDraftContent = assistantResponse.length > 0 || toolTimeline.length > 0 || draftSections.length > 0;
|
|
9827
|
-
if (!hasDraftContent) {
|
|
9828
|
-
return [...historyMessages, ...userTurn];
|
|
9829
|
-
}
|
|
9830
|
-
return [
|
|
9831
|
-
...historyMessages,
|
|
9832
|
-
...userTurn,
|
|
9833
|
-
{
|
|
9834
|
-
role: "assistant",
|
|
9835
|
-
content: assistantResponse,
|
|
9836
|
-
metadata: toolTimeline.length > 0 || draftSections.length > 0 ? {
|
|
9837
|
-
toolActivity: [...toolTimeline],
|
|
9838
|
-
sections: draftSections.length > 0 ? draftSections : void 0
|
|
9839
|
-
} : void 0
|
|
9840
|
-
}
|
|
9841
|
-
];
|
|
9842
|
-
};
|
|
9843
|
-
const persistDraftAssistantTurn = async () => {
|
|
9844
|
-
if (assistantResponse.length === 0 && toolTimeline.length === 0) return;
|
|
9845
|
-
await updateConversation((c) => {
|
|
9846
|
-
c.messages = buildMessages();
|
|
9847
|
-
});
|
|
9848
|
-
};
|
|
9849
|
-
const runInput = {
|
|
9850
|
-
task: input2.task,
|
|
9851
|
-
conversationId,
|
|
9852
|
-
messages: historyMessages,
|
|
9853
|
-
files: input2.files,
|
|
9854
|
-
parameters: {
|
|
9855
|
-
...input2.metadata ? {
|
|
9856
|
-
__messaging_platform: input2.metadata.platform,
|
|
9857
|
-
__messaging_sender_id: input2.metadata.sender.id,
|
|
9858
|
-
__messaging_sender_name: input2.metadata.sender.name ?? "",
|
|
9859
|
-
__messaging_thread_id: input2.metadata.threadId
|
|
9860
|
-
} : {},
|
|
9861
|
-
__activeConversationId: conversationId
|
|
9862
|
-
}
|
|
9863
|
-
};
|
|
9864
|
-
try {
|
|
9865
|
-
for await (const event of harness.runWithTelemetry(runInput)) {
|
|
10138
|
+
};
|
|
10139
|
+
const runInput = {
|
|
10140
|
+
task: input2.task,
|
|
10141
|
+
conversationId,
|
|
10142
|
+
messages: historyMessages,
|
|
10143
|
+
files: input2.files,
|
|
10144
|
+
parameters: {
|
|
10145
|
+
...input2.metadata ? {
|
|
10146
|
+
__messaging_platform: input2.metadata.platform,
|
|
10147
|
+
__messaging_sender_id: input2.metadata.sender.id,
|
|
10148
|
+
__messaging_sender_name: input2.metadata.sender.name ?? "",
|
|
10149
|
+
__messaging_thread_id: input2.metadata.threadId
|
|
10150
|
+
} : {},
|
|
10151
|
+
__activeConversationId: conversationId
|
|
10152
|
+
}
|
|
10153
|
+
};
|
|
10154
|
+
try {
|
|
10155
|
+
const execution = await executeConversationTurn({
|
|
10156
|
+
harness,
|
|
10157
|
+
runInput,
|
|
10158
|
+
onEvent: async (event, eventDraft) => {
|
|
10159
|
+
draft.assistantResponse = eventDraft.assistantResponse;
|
|
10160
|
+
draft.toolTimeline = eventDraft.toolTimeline;
|
|
10161
|
+
draft.sections = eventDraft.sections;
|
|
10162
|
+
draft.currentTools = eventDraft.currentTools;
|
|
10163
|
+
draft.currentText = eventDraft.currentText;
|
|
9866
10164
|
if (event.type === "run:started") {
|
|
9867
10165
|
latestRunId = event.runId;
|
|
9868
10166
|
runOwners.set(event.runId, "local-owner");
|
|
9869
10167
|
runConversations.set(event.runId, conversationId);
|
|
9870
10168
|
}
|
|
9871
|
-
if (event.type === "model:chunk") {
|
|
9872
|
-
if (currentTools.length > 0) {
|
|
9873
|
-
sections.push({ type: "tools", content: currentTools });
|
|
9874
|
-
currentTools = [];
|
|
9875
|
-
if (assistantResponse.length > 0 && !/\s$/.test(assistantResponse)) {
|
|
9876
|
-
assistantResponse += " ";
|
|
9877
|
-
}
|
|
9878
|
-
}
|
|
9879
|
-
assistantResponse += event.content;
|
|
9880
|
-
currentText += event.content;
|
|
9881
|
-
}
|
|
9882
|
-
if (event.type === "tool:started") {
|
|
9883
|
-
if (currentText.length > 0) {
|
|
9884
|
-
sections.push({ type: "text", content: currentText });
|
|
9885
|
-
currentText = "";
|
|
9886
|
-
}
|
|
9887
|
-
const toolText = `- start \`${event.tool}\``;
|
|
9888
|
-
toolTimeline.push(toolText);
|
|
9889
|
-
currentTools.push(toolText);
|
|
9890
|
-
}
|
|
9891
|
-
if (event.type === "tool:completed") {
|
|
9892
|
-
const toolText = `- done \`${event.tool}\` (${event.duration}ms)`;
|
|
9893
|
-
toolTimeline.push(toolText);
|
|
9894
|
-
currentTools.push(toolText);
|
|
9895
|
-
}
|
|
9896
|
-
if (event.type === "tool:error") {
|
|
9897
|
-
const toolText = `- error \`${event.tool}\`: ${event.error}`;
|
|
9898
|
-
toolTimeline.push(toolText);
|
|
9899
|
-
currentTools.push(toolText);
|
|
9900
|
-
}
|
|
9901
10169
|
if (event.type === "step:completed") {
|
|
9902
10170
|
await persistDraftAssistantTurn();
|
|
9903
10171
|
}
|
|
9904
10172
|
if (event.type === "tool:approval:required") {
|
|
9905
10173
|
const toolText = `- approval required \`${event.tool}\``;
|
|
9906
|
-
toolTimeline.push(toolText);
|
|
9907
|
-
currentTools.push(toolText);
|
|
10174
|
+
draft.toolTimeline.push(toolText);
|
|
10175
|
+
draft.currentTools.push(toolText);
|
|
9908
10176
|
await persistDraftAssistantTurn();
|
|
9909
10177
|
}
|
|
9910
10178
|
if (event.type === "tool:approval:checkpoint") {
|
|
9911
10179
|
await updateConversation((c) => {
|
|
9912
10180
|
c.messages = buildMessages();
|
|
9913
|
-
c.pendingApprovals =
|
|
9914
|
-
|
|
10181
|
+
c.pendingApprovals = buildApprovalCheckpoints({
|
|
10182
|
+
approvals: event.approvals,
|
|
9915
10183
|
runId: latestRunId,
|
|
9916
|
-
tool: a.tool,
|
|
9917
|
-
toolCallId: a.toolCallId,
|
|
9918
|
-
input: a.input,
|
|
9919
10184
|
checkpointMessages: event.checkpointMessages,
|
|
9920
10185
|
baseMessageCount: historyMessages.length,
|
|
9921
10186
|
pendingToolCalls: event.pendingToolCalls
|
|
9922
|
-
})
|
|
10187
|
+
});
|
|
9923
10188
|
});
|
|
9924
10189
|
checkpointedRun = true;
|
|
9925
10190
|
const conv = await conversationStore.get(conversationId);
|
|
@@ -9931,9 +10196,14 @@ ${resultBody}`,
|
|
|
9931
10196
|
tool: a.tool,
|
|
9932
10197
|
input: a.input
|
|
9933
10198
|
}));
|
|
10199
|
+
const messageThreadId = parseTelegramMessageThreadIdFromPlatformThreadId(
|
|
10200
|
+
conv.channelMeta.platformThreadId,
|
|
10201
|
+
conv.channelMeta.channelId
|
|
10202
|
+
);
|
|
9934
10203
|
void tgAdapter.sendApprovalRequest(
|
|
9935
10204
|
conv.channelMeta.channelId,
|
|
9936
|
-
approvals
|
|
10205
|
+
approvals,
|
|
10206
|
+
{ message_thread_id: messageThreadId }
|
|
9937
10207
|
).catch((err) => {
|
|
9938
10208
|
console.error("[messaging-runner] failed to send Telegram approval request:", err instanceof Error ? err.message : err);
|
|
9939
10209
|
});
|
|
@@ -9955,77 +10225,76 @@ ${resultBody}`,
|
|
|
9955
10225
|
});
|
|
9956
10226
|
}
|
|
9957
10227
|
}
|
|
9958
|
-
if (event.type === "run:completed") {
|
|
9959
|
-
if (assistantResponse.length === 0 && event.result.response) {
|
|
9960
|
-
assistantResponse = event.result.response;
|
|
9961
|
-
}
|
|
9962
|
-
runContinuation2 = event.result.continuation === true;
|
|
9963
|
-
if (event.result.continuationMessages) {
|
|
9964
|
-
runContinuationMessages = event.result.continuationMessages;
|
|
9965
|
-
}
|
|
9966
|
-
runSteps = event.result.steps;
|
|
9967
|
-
if (typeof event.result.maxSteps === "number") runMaxSteps = event.result.maxSteps;
|
|
9968
|
-
runContextTokens = event.result.contextTokens ?? runContextTokens;
|
|
9969
|
-
runContextWindow = event.result.contextWindow ?? runContextWindow;
|
|
9970
|
-
}
|
|
9971
|
-
if (event.type === "run:error") {
|
|
9972
|
-
assistantResponse = assistantResponse || `[Error: ${event.error.message}]`;
|
|
9973
|
-
}
|
|
9974
10228
|
broadcastEvent(conversationId, event);
|
|
9975
10229
|
}
|
|
9976
|
-
}
|
|
9977
|
-
|
|
9978
|
-
|
|
9979
|
-
|
|
9980
|
-
|
|
9981
|
-
|
|
9982
|
-
|
|
9983
|
-
|
|
9984
|
-
|
|
9985
|
-
|
|
9986
|
-
|
|
9987
|
-
|
|
9988
|
-
|
|
9989
|
-
|
|
9990
|
-
|
|
9991
|
-
|
|
9992
|
-
|
|
9993
|
-
|
|
9994
|
-
|
|
9995
|
-
|
|
9996
|
-
|
|
9997
|
-
|
|
9998
|
-
|
|
9999
|
-
|
|
10000
|
-
c.
|
|
10001
|
-
|
|
10002
|
-
|
|
10003
|
-
|
|
10004
|
-
|
|
10005
|
-
|
|
10006
|
-
|
|
10007
|
-
|
|
10008
|
-
|
|
10009
|
-
}
|
|
10010
|
-
|
|
10011
|
-
|
|
10012
|
-
|
|
10013
|
-
|
|
10014
|
-
|
|
10015
|
-
|
|
10016
|
-
|
|
10017
|
-
return {
|
|
10018
|
-
response,
|
|
10019
|
-
continuation: runContinuation2,
|
|
10020
|
-
steps: runSteps,
|
|
10021
|
-
maxSteps: runMaxSteps
|
|
10022
|
-
};
|
|
10023
|
-
} finally {
|
|
10024
|
-
releaseQueue?.();
|
|
10025
|
-
if (messagingRunQueues.get(conversationId) === chained) {
|
|
10026
|
-
messagingRunQueues.delete(conversationId);
|
|
10027
|
-
}
|
|
10230
|
+
});
|
|
10231
|
+
runContinuation2 = execution.runContinuation;
|
|
10232
|
+
runContinuationMessages = execution.runContinuationMessages;
|
|
10233
|
+
runSteps = execution.runSteps;
|
|
10234
|
+
runMaxSteps = execution.runMaxSteps;
|
|
10235
|
+
runContextTokens = execution.runContextTokens;
|
|
10236
|
+
runContextWindow = execution.runContextWindow;
|
|
10237
|
+
latestRunId = execution.latestRunId || latestRunId;
|
|
10238
|
+
} catch (err) {
|
|
10239
|
+
console.error("[messaging-runner] run failed:", err instanceof Error ? err.message : err);
|
|
10240
|
+
draft.assistantResponse = draft.assistantResponse || `[Error: ${err instanceof Error ? err.message : "Unknown error"}]`;
|
|
10241
|
+
}
|
|
10242
|
+
flushTurnDraft(draft);
|
|
10243
|
+
if (!checkpointedRun) {
|
|
10244
|
+
await updateConversation((c) => {
|
|
10245
|
+
if (runContinuation2 && runContinuationMessages) {
|
|
10246
|
+
c._continuationMessages = runContinuationMessages;
|
|
10247
|
+
} else {
|
|
10248
|
+
c._continuationMessages = void 0;
|
|
10249
|
+
c.messages = buildMessages();
|
|
10250
|
+
}
|
|
10251
|
+
if (runContinuationMessages) {
|
|
10252
|
+
c._harnessMessages = runContinuationMessages;
|
|
10253
|
+
} else if (shouldRebuildCanonical) {
|
|
10254
|
+
c._harnessMessages = c.messages;
|
|
10255
|
+
} else {
|
|
10256
|
+
c._harnessMessages = c.messages;
|
|
10257
|
+
}
|
|
10258
|
+
c.runtimeRunId = latestRunId || c.runtimeRunId;
|
|
10259
|
+
c.pendingApprovals = [];
|
|
10260
|
+
c.runStatus = "idle";
|
|
10261
|
+
if (runContextTokens > 0) c.contextTokens = runContextTokens;
|
|
10262
|
+
if (runContextWindow > 0) c.contextWindow = runContextWindow;
|
|
10263
|
+
});
|
|
10264
|
+
} else {
|
|
10265
|
+
await updateConversation((c) => {
|
|
10266
|
+
if (shouldRebuildCanonical && !c._harnessMessages?.length) {
|
|
10267
|
+
c._harnessMessages = c.messages;
|
|
10268
|
+
}
|
|
10269
|
+
c.runStatus = "idle";
|
|
10270
|
+
});
|
|
10028
10271
|
}
|
|
10272
|
+
finishConversationStream(conversationId);
|
|
10273
|
+
if (latestRunId) {
|
|
10274
|
+
runOwners.delete(latestRunId);
|
|
10275
|
+
runConversations.delete(latestRunId);
|
|
10276
|
+
}
|
|
10277
|
+
console.log("[messaging-runner] run complete, response length:", draft.assistantResponse.length, runContinuation2 ? "(continuation)" : "");
|
|
10278
|
+
const response = draft.assistantResponse;
|
|
10279
|
+
return {
|
|
10280
|
+
response,
|
|
10281
|
+
continuation: runContinuation2,
|
|
10282
|
+
steps: runSteps,
|
|
10283
|
+
maxSteps: runMaxSteps
|
|
10284
|
+
};
|
|
10285
|
+
},
|
|
10286
|
+
async resetConversation(conversationId) {
|
|
10287
|
+
const existing = await conversationStore.get(conversationId);
|
|
10288
|
+
if (!existing) return;
|
|
10289
|
+
existing.messages = [];
|
|
10290
|
+
existing._harnessMessages = void 0;
|
|
10291
|
+
existing._continuationMessages = void 0;
|
|
10292
|
+
existing._toolResultArchive = void 0;
|
|
10293
|
+
existing.pendingApprovals = void 0;
|
|
10294
|
+
existing.runStatus = void 0;
|
|
10295
|
+
existing.updatedAt = Date.now();
|
|
10296
|
+
await conversationStore.update(existing);
|
|
10297
|
+
console.log(`[messaging-runner] conversation reset: ${conversationId}`);
|
|
10029
10298
|
}
|
|
10030
10299
|
};
|
|
10031
10300
|
let waitUntilHook;
|
|
@@ -10152,6 +10421,7 @@ ${resultBody}`,
|
|
|
10152
10421
|
async function* runContinuation(conversationId) {
|
|
10153
10422
|
const conversation = await conversationStore.get(conversationId);
|
|
10154
10423
|
if (!conversation) return;
|
|
10424
|
+
if (Array.isArray(conversation.pendingApprovals) && conversation.pendingApprovals.length > 0) return;
|
|
10155
10425
|
if (!conversation._continuationMessages?.length) return;
|
|
10156
10426
|
if (conversation.runStatus === "running") return;
|
|
10157
10427
|
const count = (conversation._continuationCount ?? 0) + 1;
|
|
@@ -10300,7 +10570,11 @@ ${resultBody}`,
|
|
|
10300
10570
|
freshConv._continuationMessages = void 0;
|
|
10301
10571
|
freshConv._continuationCount = void 0;
|
|
10302
10572
|
}
|
|
10303
|
-
if (nextHarnessMessages)
|
|
10573
|
+
if (nextHarnessMessages) {
|
|
10574
|
+
freshConv._harnessMessages = nextHarnessMessages;
|
|
10575
|
+
} else {
|
|
10576
|
+
freshConv._harnessMessages = freshConv.messages;
|
|
10577
|
+
}
|
|
10304
10578
|
freshConv._toolResultArchive = harness.getToolResultArchive(conversationId);
|
|
10305
10579
|
freshConv.runtimeRunId = latestRunId || freshConv.runtimeRunId;
|
|
10306
10580
|
freshConv.pendingApprovals = [];
|
|
@@ -10422,6 +10696,8 @@ ${resultBody}`,
|
|
|
10422
10696
|
}
|
|
10423
10697
|
if (runResult?.continuationMessages) {
|
|
10424
10698
|
conv._harnessMessages = runResult.continuationMessages;
|
|
10699
|
+
} else {
|
|
10700
|
+
conv._harnessMessages = conv.messages;
|
|
10425
10701
|
}
|
|
10426
10702
|
conv._toolResultArchive = childHarness.getToolResultArchive(conversationId);
|
|
10427
10703
|
conv.lastActivityAt = Date.now();
|
|
@@ -10614,29 +10890,23 @@ ${resultBody}`,
|
|
|
10614
10890
|
}
|
|
10615
10891
|
return;
|
|
10616
10892
|
}
|
|
10617
|
-
const
|
|
10618
|
-
let foundConversation;
|
|
10619
|
-
let foundApproval;
|
|
10620
|
-
for (const conv of conversations) {
|
|
10621
|
-
if (!Array.isArray(conv.pendingApprovals)) continue;
|
|
10622
|
-
const match = conv.pendingApprovals.find((a) => a.approvalId === approvalId);
|
|
10623
|
-
if (match) {
|
|
10624
|
-
foundConversation = conv;
|
|
10625
|
-
foundApproval = match;
|
|
10626
|
-
break;
|
|
10627
|
-
}
|
|
10628
|
-
}
|
|
10893
|
+
const found = await findPendingApproval(approvalId, "local-owner");
|
|
10894
|
+
let foundConversation = found?.conversation;
|
|
10895
|
+
let foundApproval = found?.approval;
|
|
10629
10896
|
if (!foundConversation || !foundApproval) {
|
|
10630
10897
|
console.warn("[telegram-approval] approval not found:", approvalId);
|
|
10631
10898
|
return;
|
|
10632
10899
|
}
|
|
10900
|
+
foundApproval = normalizeApprovalCheckpoint(foundApproval, foundConversation.messages);
|
|
10633
10901
|
await adapter.updateApprovalMessage(approvalId, approved ? "approved" : "denied", foundApproval.tool);
|
|
10634
10902
|
foundApproval.decision = approved ? "approved" : "denied";
|
|
10635
10903
|
broadcastEvent(
|
|
10636
10904
|
foundConversation.conversationId,
|
|
10637
10905
|
approved ? { type: "tool:approval:granted", approvalId } : { type: "tool:approval:denied", approvalId }
|
|
10638
10906
|
);
|
|
10639
|
-
const allApprovals = foundConversation.pendingApprovals ?? []
|
|
10907
|
+
const allApprovals = (foundConversation.pendingApprovals ?? []).map(
|
|
10908
|
+
(approval) => normalizeApprovalCheckpoint(approval, foundConversation.messages)
|
|
10909
|
+
);
|
|
10640
10910
|
const allDecided = allApprovals.length > 0 && allApprovals.every((a) => a.decision != null);
|
|
10641
10911
|
if (!allDecided) {
|
|
10642
10912
|
await conversationStore.update(foundConversation);
|
|
@@ -10985,6 +11255,9 @@ ${resultBody}`,
|
|
|
10985
11255
|
return;
|
|
10986
11256
|
}
|
|
10987
11257
|
if (requireAuth && session && !hasBearerToken && requiresCsrfValidation && pathname !== "/api/auth/login" && request.headers["x-csrf-token"] !== session?.csrfToken) {
|
|
11258
|
+
console.warn(
|
|
11259
|
+
`[poncho][csrf] blocked request method=${request.method} path="${pathname}" session=${session.sessionId}`
|
|
11260
|
+
);
|
|
10988
11261
|
writeJson(response, 403, {
|
|
10989
11262
|
code: "CSRF_ERROR",
|
|
10990
11263
|
message: "Invalid CSRF token"
|
|
@@ -11180,6 +11453,7 @@ data: ${JSON.stringify(frame)}
|
|
|
11180
11453
|
const approvalId = decodeURIComponent(approvalMatch[1] ?? "");
|
|
11181
11454
|
const body = await readRequestBody(request);
|
|
11182
11455
|
const approved = body.approved === true;
|
|
11456
|
+
const hintedConversationId = typeof body.conversationId === "string" && body.conversationId.trim().length > 0 ? body.conversationId.trim() : void 0;
|
|
11183
11457
|
const pendingSubagent = pendingSubagentApprovals.get(approvalId);
|
|
11184
11458
|
if (pendingSubagent) {
|
|
11185
11459
|
pendingSubagent.checkpoint.decision = approved ? "approved" : "denied";
|
|
@@ -11205,18 +11479,23 @@ data: ${JSON.stringify(frame)}
|
|
|
11205
11479
|
writeJson(response, 200, { ok: true, approvalId, approved });
|
|
11206
11480
|
return;
|
|
11207
11481
|
}
|
|
11208
|
-
const conversations = await conversationStore.list(ownerId);
|
|
11209
11482
|
let foundConversation;
|
|
11210
11483
|
let foundApproval;
|
|
11211
|
-
|
|
11212
|
-
|
|
11213
|
-
|
|
11214
|
-
|
|
11215
|
-
|
|
11216
|
-
|
|
11217
|
-
|
|
11484
|
+
if (hintedConversationId) {
|
|
11485
|
+
const hintedConversation = await conversationStore.get(hintedConversationId);
|
|
11486
|
+
if (hintedConversation && hintedConversation.ownerId === ownerId && Array.isArray(hintedConversation.pendingApprovals)) {
|
|
11487
|
+
const hintedMatch = hintedConversation.pendingApprovals.find((approval) => approval.approvalId === approvalId);
|
|
11488
|
+
if (hintedMatch) {
|
|
11489
|
+
foundConversation = hintedConversation;
|
|
11490
|
+
foundApproval = hintedMatch;
|
|
11491
|
+
}
|
|
11218
11492
|
}
|
|
11219
11493
|
}
|
|
11494
|
+
if (!foundConversation || !foundApproval) {
|
|
11495
|
+
const found = await findPendingApproval(approvalId, ownerId);
|
|
11496
|
+
foundConversation = found?.conversation;
|
|
11497
|
+
foundApproval = found?.approval;
|
|
11498
|
+
}
|
|
11220
11499
|
if (!foundConversation || !foundApproval) {
|
|
11221
11500
|
writeJson(response, 404, {
|
|
11222
11501
|
code: "APPROVAL_NOT_FOUND",
|
|
@@ -11225,37 +11504,32 @@ data: ${JSON.stringify(frame)}
|
|
|
11225
11504
|
return;
|
|
11226
11505
|
}
|
|
11227
11506
|
const conversationId = foundConversation.conversationId;
|
|
11507
|
+
foundApproval = normalizeApprovalCheckpoint(foundApproval, foundConversation.messages);
|
|
11228
11508
|
if (!foundApproval.checkpointMessages || !foundApproval.toolCallId) {
|
|
11229
|
-
|
|
11230
|
-
|
|
11231
|
-
|
|
11232
|
-
code: "APPROVAL_NOT_FOUND",
|
|
11233
|
-
message: "Approval request is no longer active (no checkpoint data)"
|
|
11509
|
+
writeJson(response, 409, {
|
|
11510
|
+
code: "APPROVAL_NOT_READY",
|
|
11511
|
+
message: "Approval checkpoint is not ready yet. Please retry shortly."
|
|
11234
11512
|
});
|
|
11235
11513
|
return;
|
|
11236
11514
|
}
|
|
11237
|
-
|
|
11238
|
-
|
|
11239
|
-
|
|
11240
|
-
|
|
11241
|
-
|
|
11242
|
-
batchDecisions.set(approvalId, approved);
|
|
11243
|
-
foundApproval.decision = approved ? "approved" : "denied";
|
|
11515
|
+
const approvalDecision = approved ? "approved" : "denied";
|
|
11516
|
+
foundConversation.pendingApprovals = (foundConversation.pendingApprovals ?? []).map(
|
|
11517
|
+
(approval) => approval.approvalId === approvalId ? { ...normalizeApprovalCheckpoint(approval, foundConversation.messages), decision: approvalDecision } : normalizeApprovalCheckpoint(approval, foundConversation.messages)
|
|
11518
|
+
);
|
|
11519
|
+
await conversationStore.update(foundConversation);
|
|
11244
11520
|
broadcastEvent(
|
|
11245
11521
|
conversationId,
|
|
11246
11522
|
approved ? { type: "tool:approval:granted", approvalId } : { type: "tool:approval:denied", approvalId }
|
|
11247
11523
|
);
|
|
11248
|
-
const
|
|
11249
|
-
const
|
|
11524
|
+
const refreshedConversation = await conversationStore.get(conversationId);
|
|
11525
|
+
const allApprovals = (refreshedConversation?.pendingApprovals ?? []).map(
|
|
11526
|
+
(approval) => normalizeApprovalCheckpoint(approval, refreshedConversation.messages)
|
|
11527
|
+
);
|
|
11528
|
+
const allDecided = allApprovals.length > 0 && allApprovals.every((a) => a.decision != null);
|
|
11250
11529
|
if (!allDecided) {
|
|
11251
|
-
await conversationStore.update(foundConversation);
|
|
11252
11530
|
writeJson(response, 200, { ok: true, approvalId, approved, batchComplete: false });
|
|
11253
11531
|
return;
|
|
11254
11532
|
}
|
|
11255
|
-
for (const a of allApprovals) {
|
|
11256
|
-
const d = batchDecisions.get(a.approvalId);
|
|
11257
|
-
if (d != null) a.decision = d ? "approved" : "denied";
|
|
11258
|
-
}
|
|
11259
11533
|
approvalDecisionTracker.delete(conversationId);
|
|
11260
11534
|
foundConversation.pendingApprovals = [];
|
|
11261
11535
|
foundConversation.runStatus = "running";
|
|
@@ -11460,7 +11734,8 @@ data: ${JSON.stringify(frame)}
|
|
|
11460
11734
|
approvalId: a.approvalId,
|
|
11461
11735
|
runId: a.runId,
|
|
11462
11736
|
tool: a.tool,
|
|
11463
|
-
input: a.input
|
|
11737
|
+
input: a.input,
|
|
11738
|
+
decision: a.decision
|
|
11464
11739
|
})) : [];
|
|
11465
11740
|
const subagentPending = [];
|
|
11466
11741
|
if (!conversation.parentConversationId) {
|
|
@@ -11477,22 +11752,10 @@ data: ${JSON.stringify(frame)}
|
|
|
11477
11752
|
}
|
|
11478
11753
|
const activeStream = conversationEventStreams.get(conversationId);
|
|
11479
11754
|
const hasActiveRun = !!activeStream && !activeStream.finished || conversation.runStatus === "running";
|
|
11480
|
-
|
|
11481
|
-
(r) => r.parentConversationId === conversationId
|
|
11482
|
-
);
|
|
11483
|
-
if (!hasRunningSubagents && !conversation.parentConversationId) {
|
|
11484
|
-
const summaries = await conversationStore.listSummaries(conversation.ownerId);
|
|
11485
|
-
for (const s of summaries) {
|
|
11486
|
-
if (s.parentConversationId !== conversationId) continue;
|
|
11487
|
-
const c = await conversationStore.get(s.conversationId);
|
|
11488
|
-
if (c?.subagentMeta?.status === "running") {
|
|
11489
|
-
hasRunningSubagents = true;
|
|
11490
|
-
break;
|
|
11491
|
-
}
|
|
11492
|
-
}
|
|
11493
|
-
}
|
|
11755
|
+
const hasRunningSubagents = !conversation.parentConversationId ? await hasRunningSubagentsForParent(conversationId, conversation.ownerId) : false;
|
|
11494
11756
|
const hasPendingCallbackResults = Array.isArray(conversation.pendingSubagentResults) && conversation.pendingSubagentResults.length > 0;
|
|
11495
|
-
const
|
|
11757
|
+
const hasPendingApprovals = Array.isArray(conversation.pendingApprovals) && conversation.pendingApprovals.length > 0;
|
|
11758
|
+
const needsContinuation = !hasActiveRun && Array.isArray(conversation._continuationMessages) && conversation._continuationMessages.length > 0 && !hasPendingApprovals;
|
|
11496
11759
|
writeJson(response, 200, {
|
|
11497
11760
|
conversation: {
|
|
11498
11761
|
...conversation,
|
|
@@ -11706,11 +11969,9 @@ data: ${JSON.stringify(frame)}
|
|
|
11706
11969
|
eventCount++;
|
|
11707
11970
|
let sseEvent = event;
|
|
11708
11971
|
if (sseEvent.type === "run:completed") {
|
|
11709
|
-
const
|
|
11710
|
-
(r) => r.parentConversationId === conversationId
|
|
11711
|
-
);
|
|
11972
|
+
const hasPendingSubagents = await hasPendingSubagentWorkForParent(conversationId, ownerId);
|
|
11712
11973
|
const stripped = { ...sseEvent, result: { ...sseEvent.result, continuationMessages: void 0 } };
|
|
11713
|
-
sseEvent =
|
|
11974
|
+
sseEvent = hasPendingSubagents ? { ...stripped, pendingSubagents: true } : stripped;
|
|
11714
11975
|
}
|
|
11715
11976
|
try {
|
|
11716
11977
|
response.write(formatSseEvent(sseEvent));
|
|
@@ -11738,7 +11999,7 @@ data: ${JSON.stringify(frame)}
|
|
|
11738
11999
|
}
|
|
11739
12000
|
} else {
|
|
11740
12001
|
const freshConv = await conversationStore.get(conversationId);
|
|
11741
|
-
if (freshConv?._continuationMessages?.length) {
|
|
12002
|
+
if (freshConv?._continuationMessages?.length && (!Array.isArray(freshConv.pendingApprovals) || freshConv.pendingApprovals.length === 0)) {
|
|
11742
12003
|
doWaitUntil(
|
|
11743
12004
|
new Promise((r) => setTimeout(r, 3e3)).then(
|
|
11744
12005
|
() => selfFetchWithRetry(`/api/internal/continue/${encodeURIComponent(conversationId)}`)
|
|
@@ -11820,9 +12081,17 @@ data: ${JSON.stringify(frame)}
|
|
|
11820
12081
|
Connection: "keep-alive",
|
|
11821
12082
|
"X-Accel-Buffering": "no"
|
|
11822
12083
|
});
|
|
11823
|
-
const
|
|
12084
|
+
const canonicalHistory = resolveRunRequest(conversation, {
|
|
12085
|
+
conversationId,
|
|
12086
|
+
messages: conversation.messages
|
|
12087
|
+
});
|
|
12088
|
+
const shouldRebuildCanonical = canonicalHistory.shouldRebuildCanonical;
|
|
12089
|
+
const harnessMessages = [...canonicalHistory.messages];
|
|
11824
12090
|
const historyMessages = [...conversation.messages];
|
|
11825
12091
|
const preRunMessages = [...conversation.messages];
|
|
12092
|
+
console.info(
|
|
12093
|
+
`[poncho] conversation="${conversationId}" history_source=${canonicalHistory.source}`
|
|
12094
|
+
);
|
|
11826
12095
|
let latestRunId = conversation.runtimeRunId ?? "";
|
|
11827
12096
|
let assistantResponse = "";
|
|
11828
12097
|
const toolTimeline = [];
|
|
@@ -12017,6 +12286,24 @@ data: ${JSON.stringify(frame)}
|
|
|
12017
12286
|
const toolText = `- approval required \`${event.tool}\``;
|
|
12018
12287
|
toolTimeline.push(toolText);
|
|
12019
12288
|
currentTools.push(toolText);
|
|
12289
|
+
const existingApprovals = Array.isArray(conversation.pendingApprovals) ? conversation.pendingApprovals : [];
|
|
12290
|
+
if (!existingApprovals.some((approval) => approval.approvalId === event.approvalId)) {
|
|
12291
|
+
conversation.pendingApprovals = [
|
|
12292
|
+
...existingApprovals,
|
|
12293
|
+
{
|
|
12294
|
+
approvalId: event.approvalId,
|
|
12295
|
+
runId: latestRunId || conversation.runtimeRunId || "",
|
|
12296
|
+
tool: event.tool,
|
|
12297
|
+
toolCallId: void 0,
|
|
12298
|
+
input: event.input ?? {},
|
|
12299
|
+
checkpointMessages: void 0,
|
|
12300
|
+
baseMessageCount: historyMessages.length,
|
|
12301
|
+
pendingToolCalls: []
|
|
12302
|
+
}
|
|
12303
|
+
];
|
|
12304
|
+
conversation.updatedAt = Date.now();
|
|
12305
|
+
await conversationStore.update(conversation);
|
|
12306
|
+
}
|
|
12020
12307
|
await persistDraftAssistantTurn();
|
|
12021
12308
|
}
|
|
12022
12309
|
if (event.type === "tool:approval:checkpoint") {
|
|
@@ -12036,16 +12323,13 @@ data: ${JSON.stringify(frame)}
|
|
|
12036
12323
|
metadata: toolTimeline.length > 0 || checkpointSections.length > 0 ? { toolActivity: [...toolTimeline], sections: checkpointSections.length > 0 ? checkpointSections : void 0 } : void 0
|
|
12037
12324
|
}] : []
|
|
12038
12325
|
];
|
|
12039
|
-
conversation.pendingApprovals =
|
|
12040
|
-
|
|
12326
|
+
conversation.pendingApprovals = buildApprovalCheckpoints({
|
|
12327
|
+
approvals: event.approvals,
|
|
12041
12328
|
runId: latestRunId,
|
|
12042
|
-
tool: a.tool,
|
|
12043
|
-
toolCallId: a.toolCallId,
|
|
12044
|
-
input: a.input,
|
|
12045
12329
|
checkpointMessages: event.checkpointMessages,
|
|
12046
12330
|
baseMessageCount: historyMessages.length,
|
|
12047
12331
|
pendingToolCalls: event.pendingToolCalls
|
|
12048
|
-
})
|
|
12332
|
+
});
|
|
12049
12333
|
conversation._toolResultArchive = harness.getToolResultArchive(conversationId);
|
|
12050
12334
|
conversation.updatedAt = Date.now();
|
|
12051
12335
|
await conversationStore.update(conversation);
|
|
@@ -12076,26 +12360,28 @@ data: ${JSON.stringify(frame)}
|
|
|
12076
12360
|
conversation._harnessMessages = runContinuationMessages;
|
|
12077
12361
|
conversation._toolResultArchive = harness.getToolResultArchive(conversationId);
|
|
12078
12362
|
conversation.runtimeRunId = latestRunId || conversation.runtimeRunId;
|
|
12079
|
-
|
|
12363
|
+
if (!checkpointedRun) {
|
|
12364
|
+
conversation.pendingApprovals = [];
|
|
12365
|
+
}
|
|
12080
12366
|
if (runContextTokens > 0) conversation.contextTokens = runContextTokens;
|
|
12081
12367
|
if (runContextWindow > 0) conversation.contextWindow = runContextWindow;
|
|
12082
12368
|
conversation.updatedAt = Date.now();
|
|
12083
12369
|
await conversationStore.update(conversation);
|
|
12084
|
-
|
|
12085
|
-
|
|
12086
|
-
() =>
|
|
12087
|
-
|
|
12088
|
-
|
|
12370
|
+
if (!checkpointedRun) {
|
|
12371
|
+
doWaitUntil(
|
|
12372
|
+
new Promise((r) => setTimeout(r, 3e3)).then(
|
|
12373
|
+
() => selfFetchWithRetry(`/api/internal/continue/${encodeURIComponent(conversationId)}`)
|
|
12374
|
+
)
|
|
12375
|
+
);
|
|
12376
|
+
}
|
|
12089
12377
|
}
|
|
12090
12378
|
}
|
|
12091
12379
|
await telemetry.emit(event);
|
|
12092
12380
|
let sseEvent = event.type === "compaction:completed" && event.compactedMessages ? { ...event, compactedMessages: void 0 } : event;
|
|
12093
12381
|
if (sseEvent.type === "run:completed") {
|
|
12094
|
-
const
|
|
12095
|
-
(r) => r.parentConversationId === conversationId
|
|
12096
|
-
);
|
|
12382
|
+
const hasPendingSubagents = await hasPendingSubagentWorkForParent(conversationId, ownerId);
|
|
12097
12383
|
const stripped = { ...sseEvent, result: { ...sseEvent.result, continuationMessages: void 0 } };
|
|
12098
|
-
if (
|
|
12384
|
+
if (hasPendingSubagents) {
|
|
12099
12385
|
sseEvent = { ...stripped, pendingSubagents: true };
|
|
12100
12386
|
} else {
|
|
12101
12387
|
sseEvent = stripped;
|
|
@@ -12132,6 +12418,10 @@ data: ${JSON.stringify(frame)}
|
|
|
12132
12418
|
conversation._continuationMessages = void 0;
|
|
12133
12419
|
if (runHarnessMessages) {
|
|
12134
12420
|
conversation._harnessMessages = runHarnessMessages;
|
|
12421
|
+
} else if (shouldRebuildCanonical) {
|
|
12422
|
+
conversation._harnessMessages = conversation.messages;
|
|
12423
|
+
} else {
|
|
12424
|
+
conversation._harnessMessages = conversation.messages;
|
|
12135
12425
|
}
|
|
12136
12426
|
conversation._toolResultArchive = harness.getToolResultArchive(conversationId);
|
|
12137
12427
|
conversation.runtimeRunId = latestRunId || conversation.runtimeRunId;
|
|
@@ -12166,7 +12456,9 @@ data: ${JSON.stringify(frame)}
|
|
|
12166
12456
|
conversation.updatedAt = Date.now();
|
|
12167
12457
|
await conversationStore.update(conversation);
|
|
12168
12458
|
}
|
|
12169
|
-
|
|
12459
|
+
if (!checkpointedRun) {
|
|
12460
|
+
await clearPendingApprovalsForConversation(conversationId);
|
|
12461
|
+
}
|
|
12170
12462
|
return;
|
|
12171
12463
|
}
|
|
12172
12464
|
try {
|
|
@@ -12211,18 +12503,24 @@ data: ${JSON.stringify(frame)}
|
|
|
12211
12503
|
if (active && active.abortController === abortController) {
|
|
12212
12504
|
activeConversationRuns.delete(conversationId);
|
|
12213
12505
|
}
|
|
12214
|
-
finishConversationStream(conversationId);
|
|
12215
12506
|
if (latestRunId) {
|
|
12216
12507
|
runOwners.delete(latestRunId);
|
|
12217
12508
|
runConversations.delete(latestRunId);
|
|
12218
12509
|
}
|
|
12510
|
+
const hadDeferred = pendingCallbackNeeded.delete(conversationId);
|
|
12511
|
+
const freshConv = await conversationStore.get(conversationId);
|
|
12512
|
+
const needsCallback = hadDeferred || !!freshConv?.pendingSubagentResults?.length;
|
|
12513
|
+
const hasRunningChildren = Array.from(activeSubagentRuns.values()).some(
|
|
12514
|
+
(run) => run.parentConversationId === conversationId
|
|
12515
|
+
);
|
|
12516
|
+
if (!needsCallback && !hasRunningChildren) {
|
|
12517
|
+
finishConversationStream(conversationId);
|
|
12518
|
+
}
|
|
12219
12519
|
try {
|
|
12220
12520
|
response.end();
|
|
12221
12521
|
} catch {
|
|
12222
12522
|
}
|
|
12223
|
-
|
|
12224
|
-
const freshConv = await conversationStore.get(conversationId);
|
|
12225
|
-
if (hadDeferred || freshConv?.pendingSubagentResults?.length) {
|
|
12523
|
+
if (needsCallback) {
|
|
12226
12524
|
processSubagentCallback(conversationId, true).catch(
|
|
12227
12525
|
(err) => console.error(`[poncho][subagent-callback] Post-run callback failed:`, err instanceof Error ? err.message : err)
|
|
12228
12526
|
);
|
|
@@ -12279,43 +12577,41 @@ data: ${JSON.stringify(frame)}
|
|
|
12279
12577
|
if (!conv) continue;
|
|
12280
12578
|
const task = `[Scheduled: ${jobName}]
|
|
12281
12579
|
${cronJob.task}`;
|
|
12282
|
-
const
|
|
12580
|
+
const historySelection = resolveRunRequest(conv, {
|
|
12581
|
+
conversationId: conv.conversationId,
|
|
12582
|
+
messages: conv.messages
|
|
12583
|
+
});
|
|
12584
|
+
const historyMessages = [...historySelection.messages];
|
|
12283
12585
|
try {
|
|
12284
|
-
|
|
12285
|
-
|
|
12286
|
-
|
|
12287
|
-
|
|
12288
|
-
|
|
12289
|
-
|
|
12290
|
-
|
|
12291
|
-
|
|
12292
|
-
|
|
12293
|
-
|
|
12294
|
-
|
|
12295
|
-
|
|
12296
|
-
|
|
12297
|
-
assistantResponse += event.content;
|
|
12298
|
-
}
|
|
12299
|
-
if (event.type === "run:completed") {
|
|
12300
|
-
steps = event.result.steps;
|
|
12301
|
-
if (!assistantResponse && event.result.response) {
|
|
12302
|
-
assistantResponse = event.result.response;
|
|
12303
|
-
}
|
|
12304
|
-
if (event.result.continuationMessages) {
|
|
12305
|
-
cronHarnessMessages = event.result.continuationMessages;
|
|
12306
|
-
}
|
|
12586
|
+
const execution = await executeConversationTurn({
|
|
12587
|
+
harness,
|
|
12588
|
+
runInput: {
|
|
12589
|
+
task,
|
|
12590
|
+
conversationId: conv.conversationId,
|
|
12591
|
+
parameters: withToolResultArchiveParam(
|
|
12592
|
+
{ __activeConversationId: conv.conversationId },
|
|
12593
|
+
conv
|
|
12594
|
+
),
|
|
12595
|
+
messages: historyMessages
|
|
12596
|
+
},
|
|
12597
|
+
onEvent: async (event) => {
|
|
12598
|
+
await telemetry.emit(event);
|
|
12307
12599
|
}
|
|
12308
|
-
|
|
12309
|
-
|
|
12600
|
+
});
|
|
12601
|
+
const assistantResponse = execution.draft.assistantResponse;
|
|
12310
12602
|
conv.messages = [
|
|
12311
12603
|
...historyMessages,
|
|
12312
12604
|
{ role: "user", content: task },
|
|
12313
12605
|
...assistantResponse ? [{ role: "assistant", content: assistantResponse }] : []
|
|
12314
12606
|
];
|
|
12315
|
-
if (
|
|
12316
|
-
conv._harnessMessages =
|
|
12607
|
+
if (execution.runHarnessMessages) {
|
|
12608
|
+
conv._harnessMessages = execution.runHarnessMessages;
|
|
12609
|
+
} else if (historySelection.shouldRebuildCanonical) {
|
|
12610
|
+
conv._harnessMessages = conv.messages;
|
|
12317
12611
|
}
|
|
12318
12612
|
conv._toolResultArchive = harness.getToolResultArchive(conv.conversationId);
|
|
12613
|
+
if (execution.runContextTokens > 0) conv.contextTokens = execution.runContextTokens;
|
|
12614
|
+
if (execution.runContextWindow > 0) conv.contextWindow = execution.runContextWindow;
|
|
12319
12615
|
conv.updatedAt = Date.now();
|
|
12320
12616
|
await conversationStore.update(conv);
|
|
12321
12617
|
if (assistantResponse) {
|
|
@@ -12331,7 +12627,7 @@ ${cronJob.task}`;
|
|
|
12331
12627
|
console.error(`[cron] ${jobName}: send to ${chatId} failed:`, sendError instanceof Error ? sendError.message : sendError);
|
|
12332
12628
|
}
|
|
12333
12629
|
}
|
|
12334
|
-
chatResults.push({ chatId, status: "completed", steps });
|
|
12630
|
+
chatResults.push({ chatId, status: "completed", steps: execution.runSteps });
|
|
12335
12631
|
} catch (runError) {
|
|
12336
12632
|
chatResults.push({ chatId, status: "error" });
|
|
12337
12633
|
console.error(`[cron] ${jobName}: run for chat ${chatId} failed:`, runError instanceof Error ? runError.message : runError);
|
|
@@ -12580,86 +12876,30 @@ var startDevServer = async (port, options) => {
|
|
|
12580
12876
|
const { Cron } = await import("croner");
|
|
12581
12877
|
let activeJobs = [];
|
|
12582
12878
|
const runCronAgent = async (harnessRef, task, conversationId, historyMessages, toolResultArchive, onEvent) => {
|
|
12583
|
-
|
|
12584
|
-
|
|
12585
|
-
|
|
12586
|
-
|
|
12587
|
-
|
|
12588
|
-
|
|
12589
|
-
|
|
12590
|
-
|
|
12591
|
-
|
|
12592
|
-
|
|
12593
|
-
task,
|
|
12594
|
-
conversationId,
|
|
12595
|
-
parameters: {
|
|
12596
|
-
__activeConversationId: conversationId,
|
|
12597
|
-
[TOOL_RESULT_ARCHIVE_PARAM]: toolResultArchive ?? {}
|
|
12879
|
+
const execution = await executeConversationTurn({
|
|
12880
|
+
harness: harnessRef,
|
|
12881
|
+
runInput: {
|
|
12882
|
+
task,
|
|
12883
|
+
conversationId,
|
|
12884
|
+
parameters: {
|
|
12885
|
+
__activeConversationId: conversationId,
|
|
12886
|
+
[TOOL_RESULT_ARCHIVE_PARAM]: toolResultArchive ?? {}
|
|
12887
|
+
},
|
|
12888
|
+
messages: historyMessages
|
|
12598
12889
|
},
|
|
12599
|
-
|
|
12600
|
-
})
|
|
12601
|
-
|
|
12602
|
-
|
|
12603
|
-
|
|
12604
|
-
sections.push({ type: "tools", content: currentTools });
|
|
12605
|
-
currentTools = [];
|
|
12606
|
-
if (assistantResponse.length > 0 && !/\s$/.test(assistantResponse)) {
|
|
12607
|
-
assistantResponse += " ";
|
|
12608
|
-
}
|
|
12609
|
-
}
|
|
12610
|
-
assistantResponse += event.content;
|
|
12611
|
-
currentText += event.content;
|
|
12612
|
-
}
|
|
12613
|
-
if (event.type === "tool:started") {
|
|
12614
|
-
if (currentText.length > 0) {
|
|
12615
|
-
sections.push({ type: "text", content: currentText });
|
|
12616
|
-
currentText = "";
|
|
12617
|
-
}
|
|
12618
|
-
const toolText = `- start \`${event.tool}\``;
|
|
12619
|
-
toolTimeline.push(toolText);
|
|
12620
|
-
currentTools.push(toolText);
|
|
12621
|
-
}
|
|
12622
|
-
if (event.type === "tool:completed") {
|
|
12623
|
-
const toolText = `- done \`${event.tool}\` (${event.duration}ms)`;
|
|
12624
|
-
toolTimeline.push(toolText);
|
|
12625
|
-
currentTools.push(toolText);
|
|
12626
|
-
}
|
|
12627
|
-
if (event.type === "tool:error") {
|
|
12628
|
-
const toolText = `- error \`${event.tool}\`: ${event.error}`;
|
|
12629
|
-
toolTimeline.push(toolText);
|
|
12630
|
-
currentTools.push(toolText);
|
|
12631
|
-
}
|
|
12632
|
-
if (event.type === "run:completed") {
|
|
12633
|
-
steps = event.result.steps;
|
|
12634
|
-
contextTokens = event.result.contextTokens ?? 0;
|
|
12635
|
-
contextWindow = event.result.contextWindow ?? 0;
|
|
12636
|
-
if (event.result.continuationMessages) {
|
|
12637
|
-
harnessMessages = event.result.continuationMessages;
|
|
12638
|
-
}
|
|
12639
|
-
if (!assistantResponse && event.result.response) {
|
|
12640
|
-
assistantResponse = event.result.response;
|
|
12641
|
-
}
|
|
12642
|
-
}
|
|
12643
|
-
}
|
|
12644
|
-
if (currentTools.length > 0) {
|
|
12645
|
-
sections.push({ type: "tools", content: currentTools });
|
|
12646
|
-
}
|
|
12647
|
-
if (currentText.length > 0) {
|
|
12648
|
-
sections.push({ type: "text", content: currentText });
|
|
12649
|
-
}
|
|
12650
|
-
const hasContent = assistantResponse.length > 0 || toolTimeline.length > 0;
|
|
12651
|
-
const assistantMetadata = toolTimeline.length > 0 || sections.length > 0 ? {
|
|
12652
|
-
toolActivity: [...toolTimeline],
|
|
12653
|
-
sections: sections.length > 0 ? sections : void 0
|
|
12654
|
-
} : void 0;
|
|
12890
|
+
onEvent
|
|
12891
|
+
});
|
|
12892
|
+
flushTurnDraft(execution.draft);
|
|
12893
|
+
const hasContent = execution.draft.assistantResponse.length > 0 || execution.draft.toolTimeline.length > 0;
|
|
12894
|
+
const assistantMetadata = buildAssistantMetadata(execution.draft);
|
|
12655
12895
|
return {
|
|
12656
|
-
response: assistantResponse,
|
|
12657
|
-
steps,
|
|
12896
|
+
response: execution.draft.assistantResponse,
|
|
12897
|
+
steps: execution.runSteps,
|
|
12658
12898
|
assistantMetadata,
|
|
12659
12899
|
hasContent,
|
|
12660
|
-
contextTokens,
|
|
12661
|
-
contextWindow,
|
|
12662
|
-
harnessMessages,
|
|
12900
|
+
contextTokens: execution.runContextTokens,
|
|
12901
|
+
contextWindow: execution.runContextWindow,
|
|
12902
|
+
harnessMessages: execution.runHarnessMessages,
|
|
12663
12903
|
toolResultArchive: harnessRef.getToolResultArchive(conversationId)
|
|
12664
12904
|
};
|
|
12665
12905
|
};
|
|
@@ -12720,7 +12960,11 @@ var startDevServer = async (port, options) => {
|
|
|
12720
12960
|
if (!conversation) continue;
|
|
12721
12961
|
const task = `[Scheduled: ${jobName}]
|
|
12722
12962
|
${config.task}`;
|
|
12723
|
-
const
|
|
12963
|
+
const historySelection = resolveRunRequest(conversation, {
|
|
12964
|
+
conversationId: conversation.conversationId,
|
|
12965
|
+
messages: conversation.messages
|
|
12966
|
+
});
|
|
12967
|
+
const historyMessages = [...historySelection.messages];
|
|
12724
12968
|
const convId = conversation.conversationId;
|
|
12725
12969
|
activeRuns?.set(convId, {
|
|
12726
12970
|
ownerId: "local-owner",
|
|
@@ -12743,6 +12987,8 @@ ${config.task}`;
|
|
|
12743
12987
|
freshConv.messages = buildCronMessages(task, historyMessages, result);
|
|
12744
12988
|
if (result.harnessMessages) {
|
|
12745
12989
|
freshConv._harnessMessages = result.harnessMessages;
|
|
12990
|
+
} else if (historySelection.shouldRebuildCanonical) {
|
|
12991
|
+
freshConv._harnessMessages = freshConv.messages;
|
|
12746
12992
|
}
|
|
12747
12993
|
if (result.toolResultArchive) {
|
|
12748
12994
|
freshConv._toolResultArchive = result.toolResultArchive;
|
|
@@ -12960,7 +13206,7 @@ var runInteractive = async (workingDir, params) => {
|
|
|
12960
13206
|
await harness.initialize();
|
|
12961
13207
|
const identity = await ensureAgentIdentity2(workingDir);
|
|
12962
13208
|
try {
|
|
12963
|
-
const { runInteractiveInk } = await import("./run-interactive-ink-
|
|
13209
|
+
const { runInteractiveInk } = await import("./run-interactive-ink-LAL4PQVD.js");
|
|
12964
13210
|
await runInteractiveInk({
|
|
12965
13211
|
harness,
|
|
12966
13212
|
params,
|
|
@@ -13694,6 +13940,7 @@ export {
|
|
|
13694
13940
|
inferConversationTitle,
|
|
13695
13941
|
consumeFirstRunIntro,
|
|
13696
13942
|
resolveHarnessEnvironment,
|
|
13943
|
+
__internalRunOrchestration,
|
|
13697
13944
|
initProject,
|
|
13698
13945
|
updateAgentGuidance,
|
|
13699
13946
|
createRequestHandler,
|