@poncho-ai/cli 0.32.4 → 0.32.5
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 +6 -0
- package/dist/{chunk-F6NA3N2R.js → chunk-LVWNWMNE.js} +744 -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-VGKSZJDO.js} +1 -1
- package/package.json +3 -3
- package/src/index.ts +745 -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,63 @@ ${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
|
-
if (!checkpointedRun) {
|
|
9989
|
-
await updateConversation((c) => {
|
|
9990
|
-
if (runContinuation2 && runContinuationMessages) {
|
|
9991
|
-
c._continuationMessages = runContinuationMessages;
|
|
9992
|
-
} else {
|
|
9993
|
-
c._continuationMessages = void 0;
|
|
9994
|
-
c.messages = buildMessages();
|
|
9995
|
-
}
|
|
9996
|
-
if (runContinuationMessages) {
|
|
9997
|
-
c._harnessMessages = runContinuationMessages;
|
|
9998
|
-
}
|
|
9999
|
-
c.runtimeRunId = latestRunId || c.runtimeRunId;
|
|
10000
|
-
c.pendingApprovals = [];
|
|
10001
|
-
c.runStatus = "idle";
|
|
10002
|
-
if (runContextTokens > 0) c.contextTokens = runContextTokens;
|
|
10003
|
-
if (runContextWindow > 0) c.contextWindow = runContextWindow;
|
|
10004
|
-
});
|
|
10005
|
-
} else {
|
|
10006
|
-
await updateConversation((c) => {
|
|
10007
|
-
c.runStatus = "idle";
|
|
10008
|
-
});
|
|
10009
|
-
}
|
|
10010
|
-
finishConversationStream(conversationId);
|
|
10011
|
-
if (latestRunId) {
|
|
10012
|
-
runOwners.delete(latestRunId);
|
|
10013
|
-
runConversations.delete(latestRunId);
|
|
10014
|
-
}
|
|
10015
|
-
console.log("[messaging-runner] run complete, response length:", assistantResponse.length, runContinuation2 ? "(continuation)" : "");
|
|
10016
|
-
const response = assistantResponse;
|
|
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"}]`;
|
|
10028
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
|
+
});
|
|
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
|
+
};
|
|
10029
10285
|
}
|
|
10030
10286
|
};
|
|
10031
10287
|
let waitUntilHook;
|
|
@@ -10152,6 +10408,7 @@ ${resultBody}`,
|
|
|
10152
10408
|
async function* runContinuation(conversationId) {
|
|
10153
10409
|
const conversation = await conversationStore.get(conversationId);
|
|
10154
10410
|
if (!conversation) return;
|
|
10411
|
+
if (Array.isArray(conversation.pendingApprovals) && conversation.pendingApprovals.length > 0) return;
|
|
10155
10412
|
if (!conversation._continuationMessages?.length) return;
|
|
10156
10413
|
if (conversation.runStatus === "running") return;
|
|
10157
10414
|
const count = (conversation._continuationCount ?? 0) + 1;
|
|
@@ -10300,7 +10557,11 @@ ${resultBody}`,
|
|
|
10300
10557
|
freshConv._continuationMessages = void 0;
|
|
10301
10558
|
freshConv._continuationCount = void 0;
|
|
10302
10559
|
}
|
|
10303
|
-
if (nextHarnessMessages)
|
|
10560
|
+
if (nextHarnessMessages) {
|
|
10561
|
+
freshConv._harnessMessages = nextHarnessMessages;
|
|
10562
|
+
} else {
|
|
10563
|
+
freshConv._harnessMessages = freshConv.messages;
|
|
10564
|
+
}
|
|
10304
10565
|
freshConv._toolResultArchive = harness.getToolResultArchive(conversationId);
|
|
10305
10566
|
freshConv.runtimeRunId = latestRunId || freshConv.runtimeRunId;
|
|
10306
10567
|
freshConv.pendingApprovals = [];
|
|
@@ -10422,6 +10683,8 @@ ${resultBody}`,
|
|
|
10422
10683
|
}
|
|
10423
10684
|
if (runResult?.continuationMessages) {
|
|
10424
10685
|
conv._harnessMessages = runResult.continuationMessages;
|
|
10686
|
+
} else {
|
|
10687
|
+
conv._harnessMessages = conv.messages;
|
|
10425
10688
|
}
|
|
10426
10689
|
conv._toolResultArchive = childHarness.getToolResultArchive(conversationId);
|
|
10427
10690
|
conv.lastActivityAt = Date.now();
|
|
@@ -10614,29 +10877,23 @@ ${resultBody}`,
|
|
|
10614
10877
|
}
|
|
10615
10878
|
return;
|
|
10616
10879
|
}
|
|
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
|
-
}
|
|
10880
|
+
const found = await findPendingApproval(approvalId, "local-owner");
|
|
10881
|
+
let foundConversation = found?.conversation;
|
|
10882
|
+
let foundApproval = found?.approval;
|
|
10629
10883
|
if (!foundConversation || !foundApproval) {
|
|
10630
10884
|
console.warn("[telegram-approval] approval not found:", approvalId);
|
|
10631
10885
|
return;
|
|
10632
10886
|
}
|
|
10887
|
+
foundApproval = normalizeApprovalCheckpoint(foundApproval, foundConversation.messages);
|
|
10633
10888
|
await adapter.updateApprovalMessage(approvalId, approved ? "approved" : "denied", foundApproval.tool);
|
|
10634
10889
|
foundApproval.decision = approved ? "approved" : "denied";
|
|
10635
10890
|
broadcastEvent(
|
|
10636
10891
|
foundConversation.conversationId,
|
|
10637
10892
|
approved ? { type: "tool:approval:granted", approvalId } : { type: "tool:approval:denied", approvalId }
|
|
10638
10893
|
);
|
|
10639
|
-
const allApprovals = foundConversation.pendingApprovals ?? []
|
|
10894
|
+
const allApprovals = (foundConversation.pendingApprovals ?? []).map(
|
|
10895
|
+
(approval) => normalizeApprovalCheckpoint(approval, foundConversation.messages)
|
|
10896
|
+
);
|
|
10640
10897
|
const allDecided = allApprovals.length > 0 && allApprovals.every((a) => a.decision != null);
|
|
10641
10898
|
if (!allDecided) {
|
|
10642
10899
|
await conversationStore.update(foundConversation);
|
|
@@ -10985,6 +11242,9 @@ ${resultBody}`,
|
|
|
10985
11242
|
return;
|
|
10986
11243
|
}
|
|
10987
11244
|
if (requireAuth && session && !hasBearerToken && requiresCsrfValidation && pathname !== "/api/auth/login" && request.headers["x-csrf-token"] !== session?.csrfToken) {
|
|
11245
|
+
console.warn(
|
|
11246
|
+
`[poncho][csrf] blocked request method=${request.method} path="${pathname}" session=${session.sessionId}`
|
|
11247
|
+
);
|
|
10988
11248
|
writeJson(response, 403, {
|
|
10989
11249
|
code: "CSRF_ERROR",
|
|
10990
11250
|
message: "Invalid CSRF token"
|
|
@@ -11180,6 +11440,7 @@ data: ${JSON.stringify(frame)}
|
|
|
11180
11440
|
const approvalId = decodeURIComponent(approvalMatch[1] ?? "");
|
|
11181
11441
|
const body = await readRequestBody(request);
|
|
11182
11442
|
const approved = body.approved === true;
|
|
11443
|
+
const hintedConversationId = typeof body.conversationId === "string" && body.conversationId.trim().length > 0 ? body.conversationId.trim() : void 0;
|
|
11183
11444
|
const pendingSubagent = pendingSubagentApprovals.get(approvalId);
|
|
11184
11445
|
if (pendingSubagent) {
|
|
11185
11446
|
pendingSubagent.checkpoint.decision = approved ? "approved" : "denied";
|
|
@@ -11205,18 +11466,23 @@ data: ${JSON.stringify(frame)}
|
|
|
11205
11466
|
writeJson(response, 200, { ok: true, approvalId, approved });
|
|
11206
11467
|
return;
|
|
11207
11468
|
}
|
|
11208
|
-
const conversations = await conversationStore.list(ownerId);
|
|
11209
11469
|
let foundConversation;
|
|
11210
11470
|
let foundApproval;
|
|
11211
|
-
|
|
11212
|
-
|
|
11213
|
-
|
|
11214
|
-
|
|
11215
|
-
|
|
11216
|
-
|
|
11217
|
-
|
|
11471
|
+
if (hintedConversationId) {
|
|
11472
|
+
const hintedConversation = await conversationStore.get(hintedConversationId);
|
|
11473
|
+
if (hintedConversation && hintedConversation.ownerId === ownerId && Array.isArray(hintedConversation.pendingApprovals)) {
|
|
11474
|
+
const hintedMatch = hintedConversation.pendingApprovals.find((approval) => approval.approvalId === approvalId);
|
|
11475
|
+
if (hintedMatch) {
|
|
11476
|
+
foundConversation = hintedConversation;
|
|
11477
|
+
foundApproval = hintedMatch;
|
|
11478
|
+
}
|
|
11218
11479
|
}
|
|
11219
11480
|
}
|
|
11481
|
+
if (!foundConversation || !foundApproval) {
|
|
11482
|
+
const found = await findPendingApproval(approvalId, ownerId);
|
|
11483
|
+
foundConversation = found?.conversation;
|
|
11484
|
+
foundApproval = found?.approval;
|
|
11485
|
+
}
|
|
11220
11486
|
if (!foundConversation || !foundApproval) {
|
|
11221
11487
|
writeJson(response, 404, {
|
|
11222
11488
|
code: "APPROVAL_NOT_FOUND",
|
|
@@ -11225,37 +11491,32 @@ data: ${JSON.stringify(frame)}
|
|
|
11225
11491
|
return;
|
|
11226
11492
|
}
|
|
11227
11493
|
const conversationId = foundConversation.conversationId;
|
|
11494
|
+
foundApproval = normalizeApprovalCheckpoint(foundApproval, foundConversation.messages);
|
|
11228
11495
|
if (!foundApproval.checkpointMessages || !foundApproval.toolCallId) {
|
|
11229
|
-
|
|
11230
|
-
|
|
11231
|
-
|
|
11232
|
-
code: "APPROVAL_NOT_FOUND",
|
|
11233
|
-
message: "Approval request is no longer active (no checkpoint data)"
|
|
11496
|
+
writeJson(response, 409, {
|
|
11497
|
+
code: "APPROVAL_NOT_READY",
|
|
11498
|
+
message: "Approval checkpoint is not ready yet. Please retry shortly."
|
|
11234
11499
|
});
|
|
11235
11500
|
return;
|
|
11236
11501
|
}
|
|
11237
|
-
|
|
11238
|
-
|
|
11239
|
-
|
|
11240
|
-
|
|
11241
|
-
|
|
11242
|
-
batchDecisions.set(approvalId, approved);
|
|
11243
|
-
foundApproval.decision = approved ? "approved" : "denied";
|
|
11502
|
+
const approvalDecision = approved ? "approved" : "denied";
|
|
11503
|
+
foundConversation.pendingApprovals = (foundConversation.pendingApprovals ?? []).map(
|
|
11504
|
+
(approval) => approval.approvalId === approvalId ? { ...normalizeApprovalCheckpoint(approval, foundConversation.messages), decision: approvalDecision } : normalizeApprovalCheckpoint(approval, foundConversation.messages)
|
|
11505
|
+
);
|
|
11506
|
+
await conversationStore.update(foundConversation);
|
|
11244
11507
|
broadcastEvent(
|
|
11245
11508
|
conversationId,
|
|
11246
11509
|
approved ? { type: "tool:approval:granted", approvalId } : { type: "tool:approval:denied", approvalId }
|
|
11247
11510
|
);
|
|
11248
|
-
const
|
|
11249
|
-
const
|
|
11511
|
+
const refreshedConversation = await conversationStore.get(conversationId);
|
|
11512
|
+
const allApprovals = (refreshedConversation?.pendingApprovals ?? []).map(
|
|
11513
|
+
(approval) => normalizeApprovalCheckpoint(approval, refreshedConversation.messages)
|
|
11514
|
+
);
|
|
11515
|
+
const allDecided = allApprovals.length > 0 && allApprovals.every((a) => a.decision != null);
|
|
11250
11516
|
if (!allDecided) {
|
|
11251
|
-
await conversationStore.update(foundConversation);
|
|
11252
11517
|
writeJson(response, 200, { ok: true, approvalId, approved, batchComplete: false });
|
|
11253
11518
|
return;
|
|
11254
11519
|
}
|
|
11255
|
-
for (const a of allApprovals) {
|
|
11256
|
-
const d = batchDecisions.get(a.approvalId);
|
|
11257
|
-
if (d != null) a.decision = d ? "approved" : "denied";
|
|
11258
|
-
}
|
|
11259
11520
|
approvalDecisionTracker.delete(conversationId);
|
|
11260
11521
|
foundConversation.pendingApprovals = [];
|
|
11261
11522
|
foundConversation.runStatus = "running";
|
|
@@ -11460,7 +11721,8 @@ data: ${JSON.stringify(frame)}
|
|
|
11460
11721
|
approvalId: a.approvalId,
|
|
11461
11722
|
runId: a.runId,
|
|
11462
11723
|
tool: a.tool,
|
|
11463
|
-
input: a.input
|
|
11724
|
+
input: a.input,
|
|
11725
|
+
decision: a.decision
|
|
11464
11726
|
})) : [];
|
|
11465
11727
|
const subagentPending = [];
|
|
11466
11728
|
if (!conversation.parentConversationId) {
|
|
@@ -11477,22 +11739,10 @@ data: ${JSON.stringify(frame)}
|
|
|
11477
11739
|
}
|
|
11478
11740
|
const activeStream = conversationEventStreams.get(conversationId);
|
|
11479
11741
|
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
|
-
}
|
|
11742
|
+
const hasRunningSubagents = !conversation.parentConversationId ? await hasRunningSubagentsForParent(conversationId, conversation.ownerId) : false;
|
|
11494
11743
|
const hasPendingCallbackResults = Array.isArray(conversation.pendingSubagentResults) && conversation.pendingSubagentResults.length > 0;
|
|
11495
|
-
const
|
|
11744
|
+
const hasPendingApprovals = Array.isArray(conversation.pendingApprovals) && conversation.pendingApprovals.length > 0;
|
|
11745
|
+
const needsContinuation = !hasActiveRun && Array.isArray(conversation._continuationMessages) && conversation._continuationMessages.length > 0 && !hasPendingApprovals;
|
|
11496
11746
|
writeJson(response, 200, {
|
|
11497
11747
|
conversation: {
|
|
11498
11748
|
...conversation,
|
|
@@ -11706,11 +11956,9 @@ data: ${JSON.stringify(frame)}
|
|
|
11706
11956
|
eventCount++;
|
|
11707
11957
|
let sseEvent = event;
|
|
11708
11958
|
if (sseEvent.type === "run:completed") {
|
|
11709
|
-
const
|
|
11710
|
-
(r) => r.parentConversationId === conversationId
|
|
11711
|
-
);
|
|
11959
|
+
const hasPendingSubagents = await hasPendingSubagentWorkForParent(conversationId, ownerId);
|
|
11712
11960
|
const stripped = { ...sseEvent, result: { ...sseEvent.result, continuationMessages: void 0 } };
|
|
11713
|
-
sseEvent =
|
|
11961
|
+
sseEvent = hasPendingSubagents ? { ...stripped, pendingSubagents: true } : stripped;
|
|
11714
11962
|
}
|
|
11715
11963
|
try {
|
|
11716
11964
|
response.write(formatSseEvent(sseEvent));
|
|
@@ -11738,7 +11986,7 @@ data: ${JSON.stringify(frame)}
|
|
|
11738
11986
|
}
|
|
11739
11987
|
} else {
|
|
11740
11988
|
const freshConv = await conversationStore.get(conversationId);
|
|
11741
|
-
if (freshConv?._continuationMessages?.length) {
|
|
11989
|
+
if (freshConv?._continuationMessages?.length && (!Array.isArray(freshConv.pendingApprovals) || freshConv.pendingApprovals.length === 0)) {
|
|
11742
11990
|
doWaitUntil(
|
|
11743
11991
|
new Promise((r) => setTimeout(r, 3e3)).then(
|
|
11744
11992
|
() => selfFetchWithRetry(`/api/internal/continue/${encodeURIComponent(conversationId)}`)
|
|
@@ -11820,9 +12068,17 @@ data: ${JSON.stringify(frame)}
|
|
|
11820
12068
|
Connection: "keep-alive",
|
|
11821
12069
|
"X-Accel-Buffering": "no"
|
|
11822
12070
|
});
|
|
11823
|
-
const
|
|
12071
|
+
const canonicalHistory = resolveRunRequest(conversation, {
|
|
12072
|
+
conversationId,
|
|
12073
|
+
messages: conversation.messages
|
|
12074
|
+
});
|
|
12075
|
+
const shouldRebuildCanonical = canonicalHistory.shouldRebuildCanonical;
|
|
12076
|
+
const harnessMessages = [...canonicalHistory.messages];
|
|
11824
12077
|
const historyMessages = [...conversation.messages];
|
|
11825
12078
|
const preRunMessages = [...conversation.messages];
|
|
12079
|
+
console.info(
|
|
12080
|
+
`[poncho] conversation="${conversationId}" history_source=${canonicalHistory.source}`
|
|
12081
|
+
);
|
|
11826
12082
|
let latestRunId = conversation.runtimeRunId ?? "";
|
|
11827
12083
|
let assistantResponse = "";
|
|
11828
12084
|
const toolTimeline = [];
|
|
@@ -12017,6 +12273,24 @@ data: ${JSON.stringify(frame)}
|
|
|
12017
12273
|
const toolText = `- approval required \`${event.tool}\``;
|
|
12018
12274
|
toolTimeline.push(toolText);
|
|
12019
12275
|
currentTools.push(toolText);
|
|
12276
|
+
const existingApprovals = Array.isArray(conversation.pendingApprovals) ? conversation.pendingApprovals : [];
|
|
12277
|
+
if (!existingApprovals.some((approval) => approval.approvalId === event.approvalId)) {
|
|
12278
|
+
conversation.pendingApprovals = [
|
|
12279
|
+
...existingApprovals,
|
|
12280
|
+
{
|
|
12281
|
+
approvalId: event.approvalId,
|
|
12282
|
+
runId: latestRunId || conversation.runtimeRunId || "",
|
|
12283
|
+
tool: event.tool,
|
|
12284
|
+
toolCallId: void 0,
|
|
12285
|
+
input: event.input ?? {},
|
|
12286
|
+
checkpointMessages: void 0,
|
|
12287
|
+
baseMessageCount: historyMessages.length,
|
|
12288
|
+
pendingToolCalls: []
|
|
12289
|
+
}
|
|
12290
|
+
];
|
|
12291
|
+
conversation.updatedAt = Date.now();
|
|
12292
|
+
await conversationStore.update(conversation);
|
|
12293
|
+
}
|
|
12020
12294
|
await persistDraftAssistantTurn();
|
|
12021
12295
|
}
|
|
12022
12296
|
if (event.type === "tool:approval:checkpoint") {
|
|
@@ -12036,16 +12310,13 @@ data: ${JSON.stringify(frame)}
|
|
|
12036
12310
|
metadata: toolTimeline.length > 0 || checkpointSections.length > 0 ? { toolActivity: [...toolTimeline], sections: checkpointSections.length > 0 ? checkpointSections : void 0 } : void 0
|
|
12037
12311
|
}] : []
|
|
12038
12312
|
];
|
|
12039
|
-
conversation.pendingApprovals =
|
|
12040
|
-
|
|
12313
|
+
conversation.pendingApprovals = buildApprovalCheckpoints({
|
|
12314
|
+
approvals: event.approvals,
|
|
12041
12315
|
runId: latestRunId,
|
|
12042
|
-
tool: a.tool,
|
|
12043
|
-
toolCallId: a.toolCallId,
|
|
12044
|
-
input: a.input,
|
|
12045
12316
|
checkpointMessages: event.checkpointMessages,
|
|
12046
12317
|
baseMessageCount: historyMessages.length,
|
|
12047
12318
|
pendingToolCalls: event.pendingToolCalls
|
|
12048
|
-
})
|
|
12319
|
+
});
|
|
12049
12320
|
conversation._toolResultArchive = harness.getToolResultArchive(conversationId);
|
|
12050
12321
|
conversation.updatedAt = Date.now();
|
|
12051
12322
|
await conversationStore.update(conversation);
|
|
@@ -12076,26 +12347,28 @@ data: ${JSON.stringify(frame)}
|
|
|
12076
12347
|
conversation._harnessMessages = runContinuationMessages;
|
|
12077
12348
|
conversation._toolResultArchive = harness.getToolResultArchive(conversationId);
|
|
12078
12349
|
conversation.runtimeRunId = latestRunId || conversation.runtimeRunId;
|
|
12079
|
-
|
|
12350
|
+
if (!checkpointedRun) {
|
|
12351
|
+
conversation.pendingApprovals = [];
|
|
12352
|
+
}
|
|
12080
12353
|
if (runContextTokens > 0) conversation.contextTokens = runContextTokens;
|
|
12081
12354
|
if (runContextWindow > 0) conversation.contextWindow = runContextWindow;
|
|
12082
12355
|
conversation.updatedAt = Date.now();
|
|
12083
12356
|
await conversationStore.update(conversation);
|
|
12084
|
-
|
|
12085
|
-
|
|
12086
|
-
() =>
|
|
12087
|
-
|
|
12088
|
-
|
|
12357
|
+
if (!checkpointedRun) {
|
|
12358
|
+
doWaitUntil(
|
|
12359
|
+
new Promise((r) => setTimeout(r, 3e3)).then(
|
|
12360
|
+
() => selfFetchWithRetry(`/api/internal/continue/${encodeURIComponent(conversationId)}`)
|
|
12361
|
+
)
|
|
12362
|
+
);
|
|
12363
|
+
}
|
|
12089
12364
|
}
|
|
12090
12365
|
}
|
|
12091
12366
|
await telemetry.emit(event);
|
|
12092
12367
|
let sseEvent = event.type === "compaction:completed" && event.compactedMessages ? { ...event, compactedMessages: void 0 } : event;
|
|
12093
12368
|
if (sseEvent.type === "run:completed") {
|
|
12094
|
-
const
|
|
12095
|
-
(r) => r.parentConversationId === conversationId
|
|
12096
|
-
);
|
|
12369
|
+
const hasPendingSubagents = await hasPendingSubagentWorkForParent(conversationId, ownerId);
|
|
12097
12370
|
const stripped = { ...sseEvent, result: { ...sseEvent.result, continuationMessages: void 0 } };
|
|
12098
|
-
if (
|
|
12371
|
+
if (hasPendingSubagents) {
|
|
12099
12372
|
sseEvent = { ...stripped, pendingSubagents: true };
|
|
12100
12373
|
} else {
|
|
12101
12374
|
sseEvent = stripped;
|
|
@@ -12132,6 +12405,10 @@ data: ${JSON.stringify(frame)}
|
|
|
12132
12405
|
conversation._continuationMessages = void 0;
|
|
12133
12406
|
if (runHarnessMessages) {
|
|
12134
12407
|
conversation._harnessMessages = runHarnessMessages;
|
|
12408
|
+
} else if (shouldRebuildCanonical) {
|
|
12409
|
+
conversation._harnessMessages = conversation.messages;
|
|
12410
|
+
} else {
|
|
12411
|
+
conversation._harnessMessages = conversation.messages;
|
|
12135
12412
|
}
|
|
12136
12413
|
conversation._toolResultArchive = harness.getToolResultArchive(conversationId);
|
|
12137
12414
|
conversation.runtimeRunId = latestRunId || conversation.runtimeRunId;
|
|
@@ -12166,7 +12443,9 @@ data: ${JSON.stringify(frame)}
|
|
|
12166
12443
|
conversation.updatedAt = Date.now();
|
|
12167
12444
|
await conversationStore.update(conversation);
|
|
12168
12445
|
}
|
|
12169
|
-
|
|
12446
|
+
if (!checkpointedRun) {
|
|
12447
|
+
await clearPendingApprovalsForConversation(conversationId);
|
|
12448
|
+
}
|
|
12170
12449
|
return;
|
|
12171
12450
|
}
|
|
12172
12451
|
try {
|
|
@@ -12211,18 +12490,24 @@ data: ${JSON.stringify(frame)}
|
|
|
12211
12490
|
if (active && active.abortController === abortController) {
|
|
12212
12491
|
activeConversationRuns.delete(conversationId);
|
|
12213
12492
|
}
|
|
12214
|
-
finishConversationStream(conversationId);
|
|
12215
12493
|
if (latestRunId) {
|
|
12216
12494
|
runOwners.delete(latestRunId);
|
|
12217
12495
|
runConversations.delete(latestRunId);
|
|
12218
12496
|
}
|
|
12497
|
+
const hadDeferred = pendingCallbackNeeded.delete(conversationId);
|
|
12498
|
+
const freshConv = await conversationStore.get(conversationId);
|
|
12499
|
+
const needsCallback = hadDeferred || !!freshConv?.pendingSubagentResults?.length;
|
|
12500
|
+
const hasRunningChildren = Array.from(activeSubagentRuns.values()).some(
|
|
12501
|
+
(run) => run.parentConversationId === conversationId
|
|
12502
|
+
);
|
|
12503
|
+
if (!needsCallback && !hasRunningChildren) {
|
|
12504
|
+
finishConversationStream(conversationId);
|
|
12505
|
+
}
|
|
12219
12506
|
try {
|
|
12220
12507
|
response.end();
|
|
12221
12508
|
} catch {
|
|
12222
12509
|
}
|
|
12223
|
-
|
|
12224
|
-
const freshConv = await conversationStore.get(conversationId);
|
|
12225
|
-
if (hadDeferred || freshConv?.pendingSubagentResults?.length) {
|
|
12510
|
+
if (needsCallback) {
|
|
12226
12511
|
processSubagentCallback(conversationId, true).catch(
|
|
12227
12512
|
(err) => console.error(`[poncho][subagent-callback] Post-run callback failed:`, err instanceof Error ? err.message : err)
|
|
12228
12513
|
);
|
|
@@ -12279,43 +12564,41 @@ data: ${JSON.stringify(frame)}
|
|
|
12279
12564
|
if (!conv) continue;
|
|
12280
12565
|
const task = `[Scheduled: ${jobName}]
|
|
12281
12566
|
${cronJob.task}`;
|
|
12282
|
-
const
|
|
12567
|
+
const historySelection = resolveRunRequest(conv, {
|
|
12568
|
+
conversationId: conv.conversationId,
|
|
12569
|
+
messages: conv.messages
|
|
12570
|
+
});
|
|
12571
|
+
const historyMessages = [...historySelection.messages];
|
|
12283
12572
|
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
|
-
}
|
|
12573
|
+
const execution = await executeConversationTurn({
|
|
12574
|
+
harness,
|
|
12575
|
+
runInput: {
|
|
12576
|
+
task,
|
|
12577
|
+
conversationId: conv.conversationId,
|
|
12578
|
+
parameters: withToolResultArchiveParam(
|
|
12579
|
+
{ __activeConversationId: conv.conversationId },
|
|
12580
|
+
conv
|
|
12581
|
+
),
|
|
12582
|
+
messages: historyMessages
|
|
12583
|
+
},
|
|
12584
|
+
onEvent: async (event) => {
|
|
12585
|
+
await telemetry.emit(event);
|
|
12307
12586
|
}
|
|
12308
|
-
|
|
12309
|
-
|
|
12587
|
+
});
|
|
12588
|
+
const assistantResponse = execution.draft.assistantResponse;
|
|
12310
12589
|
conv.messages = [
|
|
12311
12590
|
...historyMessages,
|
|
12312
12591
|
{ role: "user", content: task },
|
|
12313
12592
|
...assistantResponse ? [{ role: "assistant", content: assistantResponse }] : []
|
|
12314
12593
|
];
|
|
12315
|
-
if (
|
|
12316
|
-
conv._harnessMessages =
|
|
12594
|
+
if (execution.runHarnessMessages) {
|
|
12595
|
+
conv._harnessMessages = execution.runHarnessMessages;
|
|
12596
|
+
} else if (historySelection.shouldRebuildCanonical) {
|
|
12597
|
+
conv._harnessMessages = conv.messages;
|
|
12317
12598
|
}
|
|
12318
12599
|
conv._toolResultArchive = harness.getToolResultArchive(conv.conversationId);
|
|
12600
|
+
if (execution.runContextTokens > 0) conv.contextTokens = execution.runContextTokens;
|
|
12601
|
+
if (execution.runContextWindow > 0) conv.contextWindow = execution.runContextWindow;
|
|
12319
12602
|
conv.updatedAt = Date.now();
|
|
12320
12603
|
await conversationStore.update(conv);
|
|
12321
12604
|
if (assistantResponse) {
|
|
@@ -12331,7 +12614,7 @@ ${cronJob.task}`;
|
|
|
12331
12614
|
console.error(`[cron] ${jobName}: send to ${chatId} failed:`, sendError instanceof Error ? sendError.message : sendError);
|
|
12332
12615
|
}
|
|
12333
12616
|
}
|
|
12334
|
-
chatResults.push({ chatId, status: "completed", steps });
|
|
12617
|
+
chatResults.push({ chatId, status: "completed", steps: execution.runSteps });
|
|
12335
12618
|
} catch (runError) {
|
|
12336
12619
|
chatResults.push({ chatId, status: "error" });
|
|
12337
12620
|
console.error(`[cron] ${jobName}: run for chat ${chatId} failed:`, runError instanceof Error ? runError.message : runError);
|
|
@@ -12580,86 +12863,30 @@ var startDevServer = async (port, options) => {
|
|
|
12580
12863
|
const { Cron } = await import("croner");
|
|
12581
12864
|
let activeJobs = [];
|
|
12582
12865
|
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 ?? {}
|
|
12866
|
+
const execution = await executeConversationTurn({
|
|
12867
|
+
harness: harnessRef,
|
|
12868
|
+
runInput: {
|
|
12869
|
+
task,
|
|
12870
|
+
conversationId,
|
|
12871
|
+
parameters: {
|
|
12872
|
+
__activeConversationId: conversationId,
|
|
12873
|
+
[TOOL_RESULT_ARCHIVE_PARAM]: toolResultArchive ?? {}
|
|
12874
|
+
},
|
|
12875
|
+
messages: historyMessages
|
|
12598
12876
|
},
|
|
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;
|
|
12877
|
+
onEvent
|
|
12878
|
+
});
|
|
12879
|
+
flushTurnDraft(execution.draft);
|
|
12880
|
+
const hasContent = execution.draft.assistantResponse.length > 0 || execution.draft.toolTimeline.length > 0;
|
|
12881
|
+
const assistantMetadata = buildAssistantMetadata(execution.draft);
|
|
12655
12882
|
return {
|
|
12656
|
-
response: assistantResponse,
|
|
12657
|
-
steps,
|
|
12883
|
+
response: execution.draft.assistantResponse,
|
|
12884
|
+
steps: execution.runSteps,
|
|
12658
12885
|
assistantMetadata,
|
|
12659
12886
|
hasContent,
|
|
12660
|
-
contextTokens,
|
|
12661
|
-
contextWindow,
|
|
12662
|
-
harnessMessages,
|
|
12887
|
+
contextTokens: execution.runContextTokens,
|
|
12888
|
+
contextWindow: execution.runContextWindow,
|
|
12889
|
+
harnessMessages: execution.runHarnessMessages,
|
|
12663
12890
|
toolResultArchive: harnessRef.getToolResultArchive(conversationId)
|
|
12664
12891
|
};
|
|
12665
12892
|
};
|
|
@@ -12720,7 +12947,11 @@ var startDevServer = async (port, options) => {
|
|
|
12720
12947
|
if (!conversation) continue;
|
|
12721
12948
|
const task = `[Scheduled: ${jobName}]
|
|
12722
12949
|
${config.task}`;
|
|
12723
|
-
const
|
|
12950
|
+
const historySelection = resolveRunRequest(conversation, {
|
|
12951
|
+
conversationId: conversation.conversationId,
|
|
12952
|
+
messages: conversation.messages
|
|
12953
|
+
});
|
|
12954
|
+
const historyMessages = [...historySelection.messages];
|
|
12724
12955
|
const convId = conversation.conversationId;
|
|
12725
12956
|
activeRuns?.set(convId, {
|
|
12726
12957
|
ownerId: "local-owner",
|
|
@@ -12743,6 +12974,8 @@ ${config.task}`;
|
|
|
12743
12974
|
freshConv.messages = buildCronMessages(task, historyMessages, result);
|
|
12744
12975
|
if (result.harnessMessages) {
|
|
12745
12976
|
freshConv._harnessMessages = result.harnessMessages;
|
|
12977
|
+
} else if (historySelection.shouldRebuildCanonical) {
|
|
12978
|
+
freshConv._harnessMessages = freshConv.messages;
|
|
12746
12979
|
}
|
|
12747
12980
|
if (result.toolResultArchive) {
|
|
12748
12981
|
freshConv._toolResultArchive = result.toolResultArchive;
|
|
@@ -12960,7 +13193,7 @@ var runInteractive = async (workingDir, params) => {
|
|
|
12960
13193
|
await harness.initialize();
|
|
12961
13194
|
const identity = await ensureAgentIdentity2(workingDir);
|
|
12962
13195
|
try {
|
|
12963
|
-
const { runInteractiveInk } = await import("./run-interactive-ink-
|
|
13196
|
+
const { runInteractiveInk } = await import("./run-interactive-ink-VGKSZJDO.js");
|
|
12964
13197
|
await runInteractiveInk({
|
|
12965
13198
|
harness,
|
|
12966
13199
|
params,
|
|
@@ -13694,6 +13927,7 @@ export {
|
|
|
13694
13927
|
inferConversationTitle,
|
|
13695
13928
|
consumeFirstRunIntro,
|
|
13696
13929
|
resolveHarnessEnvironment,
|
|
13930
|
+
__internalRunOrchestration,
|
|
13697
13931
|
initProject,
|
|
13698
13932
|
updateAgentGuidance,
|
|
13699
13933
|
createRequestHandler,
|