@poncho-ai/cli 0.30.0 → 0.30.1
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 +6 -6
- package/CHANGELOG.md +13 -0
- package/dist/{chunk-5OLH7U3C.js → chunk-UYZOJWGL.js} +487 -180
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.js +1 -1
- package/dist/{run-interactive-ink-EMTC7MK7.js → run-interactive-ink-ZSIGWFLZ.js} +1 -1
- package/package.json +4 -4
- package/src/index.ts +249 -82
- package/src/web-ui-client.ts +130 -9
- package/src/web-ui-styles.ts +50 -0
|
@@ -442,6 +442,41 @@ var WEB_UI_STYLES = `
|
|
|
442
442
|
.conversation-item .delete-btn.confirming:hover {
|
|
443
443
|
color: var(--error-alt);
|
|
444
444
|
}
|
|
445
|
+
.cron-section-header {
|
|
446
|
+
display: flex;
|
|
447
|
+
align-items: center;
|
|
448
|
+
gap: 6px;
|
|
449
|
+
padding: 8px 10px 4px;
|
|
450
|
+
cursor: pointer;
|
|
451
|
+
font-size: 11px;
|
|
452
|
+
font-weight: 600;
|
|
453
|
+
color: var(--fg-7);
|
|
454
|
+
text-transform: uppercase;
|
|
455
|
+
letter-spacing: 0.04em;
|
|
456
|
+
user-select: none;
|
|
457
|
+
transition: color 0.15s;
|
|
458
|
+
}
|
|
459
|
+
.cron-section-header:hover { color: var(--fg-5); }
|
|
460
|
+
.cron-section-caret {
|
|
461
|
+
display: inline-flex;
|
|
462
|
+
transition: transform 0.15s;
|
|
463
|
+
}
|
|
464
|
+
.cron-section-caret.open { transform: rotate(90deg); }
|
|
465
|
+
.cron-section-count {
|
|
466
|
+
font-weight: 400;
|
|
467
|
+
color: var(--fg-8);
|
|
468
|
+
font-size: 11px;
|
|
469
|
+
}
|
|
470
|
+
.cron-view-more {
|
|
471
|
+
padding: 6px 10px;
|
|
472
|
+
font-size: 12px;
|
|
473
|
+
color: var(--fg-7);
|
|
474
|
+
cursor: pointer;
|
|
475
|
+
text-align: center;
|
|
476
|
+
transition: color 0.15s;
|
|
477
|
+
user-select: none;
|
|
478
|
+
}
|
|
479
|
+
.cron-view-more:hover { color: var(--fg-3); }
|
|
445
480
|
.sidebar-footer {
|
|
446
481
|
margin-top: auto;
|
|
447
482
|
padding-top: 8px;
|
|
@@ -1613,6 +1648,8 @@ var WEB_UI_STYLES = `
|
|
|
1613
1648
|
line-height: 1.45;
|
|
1614
1649
|
color: var(--fg-tool-code);
|
|
1615
1650
|
width: 100%;
|
|
1651
|
+
min-width: 0;
|
|
1652
|
+
overflow: hidden;
|
|
1616
1653
|
}
|
|
1617
1654
|
.subagent-result-summary {
|
|
1618
1655
|
list-style: none;
|
|
@@ -1657,6 +1694,19 @@ var WEB_UI_STYLES = `
|
|
|
1657
1694
|
display: grid;
|
|
1658
1695
|
gap: 6px;
|
|
1659
1696
|
padding: 0 12px 10px;
|
|
1697
|
+
min-width: 0;
|
|
1698
|
+
overflow-x: auto;
|
|
1699
|
+
overflow-wrap: break-word;
|
|
1700
|
+
word-break: break-word;
|
|
1701
|
+
}
|
|
1702
|
+
.subagent-result-body pre {
|
|
1703
|
+
max-width: 100%;
|
|
1704
|
+
overflow-x: auto;
|
|
1705
|
+
}
|
|
1706
|
+
.subagent-result-body table {
|
|
1707
|
+
max-width: 100%;
|
|
1708
|
+
overflow-x: auto;
|
|
1709
|
+
display: block;
|
|
1660
1710
|
}
|
|
1661
1711
|
|
|
1662
1712
|
/* Todo panel \u2014 inside composer-inner, above the input shell */
|
|
@@ -1809,6 +1859,8 @@ var getWebUiClientScript = (markedSource2) => `
|
|
|
1809
1859
|
parentConversationId: null,
|
|
1810
1860
|
todos: [],
|
|
1811
1861
|
todoPanelCollapsed: false,
|
|
1862
|
+
cronSectionCollapsed: true,
|
|
1863
|
+
cronShowAll: false,
|
|
1812
1864
|
};
|
|
1813
1865
|
|
|
1814
1866
|
const agentInitial = document.body.dataset.agentInitial || "A";
|
|
@@ -2552,11 +2604,86 @@ var getWebUiClientScript = (markedSource2) => `
|
|
|
2552
2604
|
}
|
|
2553
2605
|
};
|
|
2554
2606
|
|
|
2607
|
+
const cronCaretSvg = '<svg viewBox="0 0 12 12" fill="none" width="10" height="10"><path d="M4.5 2.75L8 6L4.5 9.25" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>';
|
|
2608
|
+
|
|
2609
|
+
const parseCronTitle = (title) => {
|
|
2610
|
+
const rest = title.replace(/^[cron]s*/, "");
|
|
2611
|
+
const isoMatch = rest.match(/s(d{4}-d{2}-d{2}T[d:.]+Z?)$/);
|
|
2612
|
+
if (isoMatch) {
|
|
2613
|
+
return { jobName: rest.slice(0, isoMatch.index).trim(), timestamp: isoMatch[1] };
|
|
2614
|
+
}
|
|
2615
|
+
return { jobName: rest, timestamp: "" };
|
|
2616
|
+
};
|
|
2617
|
+
|
|
2618
|
+
const formatCronTimestamp = (isoStr) => {
|
|
2619
|
+
if (!isoStr) return "";
|
|
2620
|
+
try {
|
|
2621
|
+
const d = new Date(isoStr);
|
|
2622
|
+
if (isNaN(d.getTime())) return isoStr;
|
|
2623
|
+
return d.toLocaleString(undefined, { month: "short", day: "numeric", hour: "numeric", minute: "2-digit" });
|
|
2624
|
+
} catch { return isoStr; }
|
|
2625
|
+
};
|
|
2626
|
+
|
|
2627
|
+
const CRON_PAGE_SIZE = 20;
|
|
2628
|
+
|
|
2629
|
+
const appendCronSection = (cronConvs, needsDivider) => {
|
|
2630
|
+
if (needsDivider) {
|
|
2631
|
+
const divider = document.createElement("div");
|
|
2632
|
+
divider.className = "sidebar-section-divider";
|
|
2633
|
+
elements.list.appendChild(divider);
|
|
2634
|
+
}
|
|
2635
|
+
|
|
2636
|
+
cronConvs.sort((a, b) => (b.updatedAt || b.createdAt || 0) - (a.updatedAt || a.createdAt || 0));
|
|
2637
|
+
|
|
2638
|
+
const isOpen = !state.cronSectionCollapsed;
|
|
2639
|
+
const header = document.createElement("div");
|
|
2640
|
+
header.className = "cron-section-header";
|
|
2641
|
+
header.innerHTML =
|
|
2642
|
+
'<span class="cron-section-caret' + (isOpen ? ' open' : '') + '">' + cronCaretSvg + '</span>' +
|
|
2643
|
+
'<span>Cron jobs</span>' +
|
|
2644
|
+
'<span class="cron-section-count">' + cronConvs.length + '</span>';
|
|
2645
|
+
header.onclick = () => {
|
|
2646
|
+
state.cronSectionCollapsed = !state.cronSectionCollapsed;
|
|
2647
|
+
state.cronShowAll = false;
|
|
2648
|
+
renderConversationList();
|
|
2649
|
+
};
|
|
2650
|
+
elements.list.appendChild(header);
|
|
2651
|
+
|
|
2652
|
+
if (state.cronSectionCollapsed) return;
|
|
2653
|
+
|
|
2654
|
+
const limit = state.cronShowAll ? cronConvs.length : CRON_PAGE_SIZE;
|
|
2655
|
+
const visible = cronConvs.slice(0, limit);
|
|
2656
|
+
|
|
2657
|
+
for (const c of visible) {
|
|
2658
|
+
const { jobName, timestamp } = parseCronTitle(c.title);
|
|
2659
|
+
const fmtTime = formatCronTimestamp(timestamp);
|
|
2660
|
+
const displayTitle = fmtTime ? jobName + " \\u00b7 " + fmtTime : c.title;
|
|
2661
|
+
elements.list.appendChild(buildConversationItem(Object.assign({}, c, { title: displayTitle })));
|
|
2662
|
+
appendSubagentsIfActive(c.conversationId);
|
|
2663
|
+
}
|
|
2664
|
+
|
|
2665
|
+
if (!state.cronShowAll && cronConvs.length > CRON_PAGE_SIZE) {
|
|
2666
|
+
const remaining = cronConvs.length - CRON_PAGE_SIZE;
|
|
2667
|
+
const viewMore = document.createElement("div");
|
|
2668
|
+
viewMore.className = "cron-view-more";
|
|
2669
|
+
viewMore.textContent = "View " + remaining + " more\\u2026";
|
|
2670
|
+
viewMore.onclick = () => {
|
|
2671
|
+
state.cronShowAll = true;
|
|
2672
|
+
renderConversationList();
|
|
2673
|
+
};
|
|
2674
|
+
elements.list.appendChild(viewMore);
|
|
2675
|
+
}
|
|
2676
|
+
};
|
|
2677
|
+
|
|
2555
2678
|
const renderConversationList = () => {
|
|
2556
2679
|
elements.list.innerHTML = "";
|
|
2557
2680
|
const pending = state.conversations.filter(c => c.hasPendingApprovals);
|
|
2558
2681
|
const rest = state.conversations.filter(c => !c.hasPendingApprovals);
|
|
2559
2682
|
|
|
2683
|
+
const isCron = (c) => c.title && c.title.startsWith("[cron]");
|
|
2684
|
+
const cronConvs = rest.filter(isCron);
|
|
2685
|
+
const nonCron = rest.filter(c => !isCron(c));
|
|
2686
|
+
|
|
2560
2687
|
if (pending.length > 0) {
|
|
2561
2688
|
const label = document.createElement("div");
|
|
2562
2689
|
label.className = "sidebar-section-label";
|
|
@@ -2575,7 +2702,7 @@ var getWebUiClientScript = (markedSource2) => `
|
|
|
2575
2702
|
const latest = [];
|
|
2576
2703
|
const previous7 = [];
|
|
2577
2704
|
const older = [];
|
|
2578
|
-
for (const c of
|
|
2705
|
+
for (const c of nonCron) {
|
|
2579
2706
|
const ts = c.updatedAt || c.createdAt || 0;
|
|
2580
2707
|
if (ts >= startOfToday) {
|
|
2581
2708
|
latest.push(c);
|
|
@@ -2587,6 +2714,12 @@ var getWebUiClientScript = (markedSource2) => `
|
|
|
2587
2714
|
}
|
|
2588
2715
|
|
|
2589
2716
|
let sectionRendered = pending.length > 0;
|
|
2717
|
+
|
|
2718
|
+
if (cronConvs.length > 0) {
|
|
2719
|
+
appendCronSection(cronConvs, sectionRendered);
|
|
2720
|
+
sectionRendered = true;
|
|
2721
|
+
}
|
|
2722
|
+
|
|
2590
2723
|
const appendSection = (items, labelText) => {
|
|
2591
2724
|
if (items.length === 0) return;
|
|
2592
2725
|
if (sectionRendered) {
|
|
@@ -4756,7 +4889,7 @@ var getWebUiClientScript = (markedSource2) => `
|
|
|
4756
4889
|
state: "resolved",
|
|
4757
4890
|
resolvedDecision: decision,
|
|
4758
4891
|
}));
|
|
4759
|
-
api("/api/approvals/" + encodeURIComponent(approvalId), {
|
|
4892
|
+
return api("/api/approvals/" + encodeURIComponent(approvalId), {
|
|
4760
4893
|
method: "POST",
|
|
4761
4894
|
body: JSON.stringify({ approved: decision === "approve" }),
|
|
4762
4895
|
}).catch((error) => {
|
|
@@ -4804,16 +4937,54 @@ var getWebUiClientScript = (markedSource2) => `
|
|
|
4804
4937
|
if (pending.length === 0) return;
|
|
4805
4938
|
const wasStreaming = state.isStreaming;
|
|
4806
4939
|
if (!wasStreaming) setStreaming(true);
|
|
4807
|
-
|
|
4940
|
+
// Mark all items as resolved in the UI immediately
|
|
4941
|
+
for (const aid of pending) {
|
|
4942
|
+
state.approvalRequestsInFlight[aid] = true;
|
|
4943
|
+
updatePendingApproval(aid, (request) => ({
|
|
4944
|
+
...request,
|
|
4945
|
+
state: "resolved",
|
|
4946
|
+
resolvedDecision: decision,
|
|
4947
|
+
}));
|
|
4948
|
+
}
|
|
4808
4949
|
renderMessages(state.activeMessages, state.isStreaming);
|
|
4809
4950
|
loadConversations();
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4951
|
+
const streamCid = !wasStreaming && state.activeConversationId
|
|
4952
|
+
? state.activeConversationId
|
|
4953
|
+
: null;
|
|
4954
|
+
if (streamCid) {
|
|
4955
|
+
streamConversationEvents(streamCid, { liveOnly: true }).finally(() => {
|
|
4956
|
+
if (state.activeConversationId === streamCid) {
|
|
4957
|
+
pollUntilRunIdle(streamCid);
|
|
4958
|
+
}
|
|
4959
|
+
});
|
|
4816
4960
|
}
|
|
4961
|
+
// Send API calls sequentially so each store write completes
|
|
4962
|
+
// before the next read (avoids last-writer-wins in serverless).
|
|
4963
|
+
void (async () => {
|
|
4964
|
+
for (const aid of pending) {
|
|
4965
|
+
await api("/api/approvals/" + encodeURIComponent(aid), {
|
|
4966
|
+
method: "POST",
|
|
4967
|
+
body: JSON.stringify({ approved: decision === "approve" }),
|
|
4968
|
+
}).catch((error) => {
|
|
4969
|
+
const isStale = error && error.payload && error.payload.code === "APPROVAL_NOT_FOUND";
|
|
4970
|
+
if (isStale) {
|
|
4971
|
+
updatePendingApproval(aid, () => null);
|
|
4972
|
+
} else {
|
|
4973
|
+
const errMsg = error instanceof Error ? error.message : String(error);
|
|
4974
|
+
updatePendingApproval(aid, (request) => ({
|
|
4975
|
+
...request,
|
|
4976
|
+
state: "pending",
|
|
4977
|
+
pendingDecision: null,
|
|
4978
|
+
resolvedDecision: null,
|
|
4979
|
+
_error: errMsg,
|
|
4980
|
+
}));
|
|
4981
|
+
}
|
|
4982
|
+
renderMessages(state.activeMessages, state.isStreaming);
|
|
4983
|
+
}).finally(() => {
|
|
4984
|
+
delete state.approvalRequestsInFlight[aid];
|
|
4985
|
+
});
|
|
4986
|
+
}
|
|
4987
|
+
})();
|
|
4817
4988
|
return;
|
|
4818
4989
|
}
|
|
4819
4990
|
|
|
@@ -8229,6 +8400,7 @@ data: ${JSON.stringify(statusPayload)}
|
|
|
8229
8400
|
const MAX_CONCURRENT_SUBAGENTS = 5;
|
|
8230
8401
|
const activeSubagentRuns = /* @__PURE__ */ new Map();
|
|
8231
8402
|
const pendingSubagentApprovals = /* @__PURE__ */ new Map();
|
|
8403
|
+
const approvalDecisionTracker = /* @__PURE__ */ new Map();
|
|
8232
8404
|
const getSubagentDepth = async (conversationId) => {
|
|
8233
8405
|
let depth = 0;
|
|
8234
8406
|
let current = await conversationStore.get(conversationId);
|
|
@@ -8646,8 +8818,10 @@ data: ${JSON.stringify(statusPayload)}
|
|
|
8646
8818
|
}
|
|
8647
8819
|
};
|
|
8648
8820
|
const MAX_SUBAGENT_CALLBACK_COUNT = 20;
|
|
8821
|
+
const pendingCallbackNeeded = /* @__PURE__ */ new Set();
|
|
8649
8822
|
const triggerParentCallback = async (parentConversationId) => {
|
|
8650
8823
|
if (activeConversationRuns.has(parentConversationId)) {
|
|
8824
|
+
pendingCallbackNeeded.add(parentConversationId);
|
|
8651
8825
|
return;
|
|
8652
8826
|
}
|
|
8653
8827
|
if (isServerless) {
|
|
@@ -8659,12 +8833,12 @@ data: ${JSON.stringify(statusPayload)}
|
|
|
8659
8833
|
await processSubagentCallback(parentConversationId);
|
|
8660
8834
|
};
|
|
8661
8835
|
const CALLBACK_LOCK_STALE_MS = 5 * 60 * 1e3;
|
|
8662
|
-
const processSubagentCallback = async (conversationId) => {
|
|
8836
|
+
const processSubagentCallback = async (conversationId, skipLockCheck = false) => {
|
|
8663
8837
|
const conversation = await conversationStore.get(conversationId);
|
|
8664
8838
|
if (!conversation) return;
|
|
8665
8839
|
const pendingResults = conversation.pendingSubagentResults ?? [];
|
|
8666
8840
|
if (pendingResults.length === 0) return;
|
|
8667
|
-
if (conversation.runningCallbackSince) {
|
|
8841
|
+
if (!skipLockCheck && conversation.runningCallbackSince) {
|
|
8668
8842
|
const elapsed = Date.now() - conversation.runningCallbackSince;
|
|
8669
8843
|
if (elapsed < CALLBACK_LOCK_STALE_MS) {
|
|
8670
8844
|
return;
|
|
@@ -8702,11 +8876,24 @@ ${resultBody}`,
|
|
|
8702
8876
|
abortController,
|
|
8703
8877
|
runId: null
|
|
8704
8878
|
});
|
|
8879
|
+
const prevStream = conversationEventStreams.get(conversationId);
|
|
8880
|
+
if (prevStream) {
|
|
8881
|
+
prevStream.finished = false;
|
|
8882
|
+
prevStream.buffer = [];
|
|
8883
|
+
} else {
|
|
8884
|
+
conversationEventStreams.set(conversationId, {
|
|
8885
|
+
buffer: [],
|
|
8886
|
+
subscribers: /* @__PURE__ */ new Set(),
|
|
8887
|
+
finished: false
|
|
8888
|
+
});
|
|
8889
|
+
}
|
|
8705
8890
|
const historyMessages = [...conversation.messages];
|
|
8706
8891
|
let assistantResponse = "";
|
|
8707
8892
|
let latestRunId = "";
|
|
8708
8893
|
let runContinuation = false;
|
|
8709
8894
|
let runContinuationMessages;
|
|
8895
|
+
let runContextTokens = conversation.contextTokens ?? 0;
|
|
8896
|
+
let runContextWindow = conversation.contextWindow ?? 0;
|
|
8710
8897
|
const toolTimeline = [];
|
|
8711
8898
|
const sections = [];
|
|
8712
8899
|
let currentTools = [];
|
|
@@ -8761,6 +8948,8 @@ ${resultBody}`,
|
|
|
8761
8948
|
if (assistantResponse.length === 0 && event.result.response) {
|
|
8762
8949
|
assistantResponse = event.result.response;
|
|
8763
8950
|
}
|
|
8951
|
+
runContextTokens = event.result.contextTokens ?? runContextTokens;
|
|
8952
|
+
runContextWindow = event.result.contextWindow ?? runContextWindow;
|
|
8764
8953
|
if (event.result.continuation) {
|
|
8765
8954
|
runContinuation = true;
|
|
8766
8955
|
if (event.result.continuationMessages) {
|
|
@@ -8787,6 +8976,8 @@ ${resultBody}`,
|
|
|
8787
8976
|
}
|
|
8788
8977
|
freshConv.runtimeRunId = latestRunId || freshConv.runtimeRunId;
|
|
8789
8978
|
freshConv.runningCallbackSince = void 0;
|
|
8979
|
+
if (runContextTokens > 0) freshConv.contextTokens = runContextTokens;
|
|
8980
|
+
if (runContextWindow > 0) freshConv.contextWindow = runContextWindow;
|
|
8790
8981
|
freshConv.updatedAt = Date.now();
|
|
8791
8982
|
await conversationStore.update(freshConv);
|
|
8792
8983
|
if (freshConv.channelMeta && assistantResponse.length > 0) {
|
|
@@ -8824,23 +9015,32 @@ ${resultBody}`,
|
|
|
8824
9015
|
} finally {
|
|
8825
9016
|
activeConversationRuns.delete(conversationId);
|
|
8826
9017
|
finishConversationStream(conversationId);
|
|
9018
|
+
const hadDeferredTrigger = pendingCallbackNeeded.delete(conversationId);
|
|
8827
9019
|
const freshConv = await conversationStore.get(conversationId);
|
|
8828
|
-
|
|
8829
|
-
|
|
8830
|
-
freshConv.runningCallbackSince = void 0;
|
|
8831
|
-
await conversationStore.update(freshConv);
|
|
8832
|
-
}
|
|
8833
|
-
}
|
|
8834
|
-
if (freshConv?.pendingSubagentResults?.length) {
|
|
9020
|
+
const hasPendingInStore = !!freshConv?.pendingSubagentResults?.length;
|
|
9021
|
+
if (hadDeferredTrigger || hasPendingInStore) {
|
|
8835
9022
|
if (isServerless) {
|
|
8836
9023
|
selfFetchWithRetry(`/api/internal/conversations/${encodeURIComponent(conversationId)}/subagent-callback`).catch(
|
|
8837
9024
|
(err) => console.error(`[poncho][subagent-callback] Recursive callback self-fetch failed:`, err instanceof Error ? err.message : err)
|
|
8838
9025
|
);
|
|
8839
9026
|
} else {
|
|
8840
|
-
processSubagentCallback(conversationId).catch(
|
|
9027
|
+
processSubagentCallback(conversationId, true).catch(
|
|
8841
9028
|
(err) => console.error(`[poncho][subagent-callback] Recursive callback failed:`, err instanceof Error ? err.message : err)
|
|
8842
9029
|
);
|
|
8843
9030
|
}
|
|
9031
|
+
} else if (freshConv?.runningCallbackSince) {
|
|
9032
|
+
const afterClear = await conversationStore.clearCallbackLock(conversationId);
|
|
9033
|
+
if (afterClear?.pendingSubagentResults?.length) {
|
|
9034
|
+
if (isServerless) {
|
|
9035
|
+
selfFetchWithRetry(`/api/internal/conversations/${encodeURIComponent(conversationId)}/subagent-callback`).catch(
|
|
9036
|
+
(err) => console.error(`[poncho][subagent-callback] Post-clear callback self-fetch failed:`, err instanceof Error ? err.message : err)
|
|
9037
|
+
);
|
|
9038
|
+
} else {
|
|
9039
|
+
processSubagentCallback(conversationId, true).catch(
|
|
9040
|
+
(err) => console.error(`[poncho][subagent-callback] Post-clear callback failed:`, err instanceof Error ? err.message : err)
|
|
9041
|
+
);
|
|
9042
|
+
}
|
|
9043
|
+
}
|
|
8844
9044
|
}
|
|
8845
9045
|
}
|
|
8846
9046
|
};
|
|
@@ -9007,14 +9207,6 @@ ${resultBody}`,
|
|
|
9007
9207
|
if (active && active.abortController === abortController) {
|
|
9008
9208
|
active.runId = event.runId;
|
|
9009
9209
|
}
|
|
9010
|
-
if (typeof event.contextWindow === "number" && event.contextWindow > 0) {
|
|
9011
|
-
runContextWindow = event.contextWindow;
|
|
9012
|
-
}
|
|
9013
|
-
}
|
|
9014
|
-
if (event.type === "model:response") {
|
|
9015
|
-
if (typeof event.usage?.input === "number") {
|
|
9016
|
-
runContextTokens = event.usage.input;
|
|
9017
|
-
}
|
|
9018
9210
|
}
|
|
9019
9211
|
if (event.type === "model:chunk") {
|
|
9020
9212
|
if (currentTools.length > 0) {
|
|
@@ -9079,8 +9271,12 @@ ${resultBody}`,
|
|
|
9079
9271
|
}
|
|
9080
9272
|
checkpointedRun = true;
|
|
9081
9273
|
}
|
|
9082
|
-
if (event.type === "run:completed"
|
|
9083
|
-
assistantResponse
|
|
9274
|
+
if (event.type === "run:completed") {
|
|
9275
|
+
if (assistantResponse.length === 0 && event.result.response) {
|
|
9276
|
+
assistantResponse = event.result.response;
|
|
9277
|
+
}
|
|
9278
|
+
runContextTokens = event.result.contextTokens ?? runContextTokens;
|
|
9279
|
+
runContextWindow = event.result.contextWindow ?? runContextWindow;
|
|
9084
9280
|
}
|
|
9085
9281
|
if (event.type === "run:error") {
|
|
9086
9282
|
assistantResponse = assistantResponse || `[Error: ${event.error.message}]`;
|
|
@@ -9163,6 +9359,13 @@ ${resultBody}`,
|
|
|
9163
9359
|
runConversations.delete(latestRunId);
|
|
9164
9360
|
}
|
|
9165
9361
|
console.log("[resume-run] complete for", conversationId);
|
|
9362
|
+
const hadDeferred = pendingCallbackNeeded.delete(conversationId);
|
|
9363
|
+
const postConv = await conversationStore.get(conversationId);
|
|
9364
|
+
if (hadDeferred || postConv?.pendingSubagentResults?.length) {
|
|
9365
|
+
processSubagentCallback(conversationId, true).catch(
|
|
9366
|
+
(err) => console.error(`[poncho][subagent-callback] Post-resume callback failed:`, err instanceof Error ? err.message : err)
|
|
9367
|
+
);
|
|
9368
|
+
}
|
|
9166
9369
|
};
|
|
9167
9370
|
const messagingRoutes = /* @__PURE__ */ new Map();
|
|
9168
9371
|
const messagingRouteRegistrar = (method, path, routeHandler) => {
|
|
@@ -9293,14 +9496,6 @@ ${resultBody}`,
|
|
|
9293
9496
|
latestRunId = event.runId;
|
|
9294
9497
|
runOwners.set(event.runId, "local-owner");
|
|
9295
9498
|
runConversations.set(event.runId, conversationId);
|
|
9296
|
-
if (typeof event.contextWindow === "number" && event.contextWindow > 0) {
|
|
9297
|
-
runContextWindow = event.contextWindow;
|
|
9298
|
-
}
|
|
9299
|
-
}
|
|
9300
|
-
if (event.type === "model:response") {
|
|
9301
|
-
if (typeof event.usage?.input === "number") {
|
|
9302
|
-
runContextTokens = event.usage.input;
|
|
9303
|
-
}
|
|
9304
9499
|
}
|
|
9305
9500
|
if (event.type === "model:chunk") {
|
|
9306
9501
|
if (currentTools.length > 0) {
|
|
@@ -9399,6 +9594,8 @@ ${resultBody}`,
|
|
|
9399
9594
|
}
|
|
9400
9595
|
runSteps = event.result.steps;
|
|
9401
9596
|
if (typeof event.result.maxSteps === "number") runMaxSteps = event.result.maxSteps;
|
|
9597
|
+
runContextTokens = event.result.contextTokens ?? runContextTokens;
|
|
9598
|
+
runContextWindow = event.result.contextWindow ?? runContextWindow;
|
|
9402
9599
|
}
|
|
9403
9600
|
if (event.type === "run:error") {
|
|
9404
9601
|
assistantResponse = assistantResponse || `[Error: ${event.error.message}]`;
|
|
@@ -10187,18 +10384,29 @@ data: ${JSON.stringify(frame)}
|
|
|
10187
10384
|
});
|
|
10188
10385
|
return;
|
|
10189
10386
|
}
|
|
10387
|
+
let batchDecisions = approvalDecisionTracker.get(conversationId);
|
|
10388
|
+
if (!batchDecisions) {
|
|
10389
|
+
batchDecisions = /* @__PURE__ */ new Map();
|
|
10390
|
+
approvalDecisionTracker.set(conversationId, batchDecisions);
|
|
10391
|
+
}
|
|
10392
|
+
batchDecisions.set(approvalId, approved);
|
|
10190
10393
|
foundApproval.decision = approved ? "approved" : "denied";
|
|
10191
10394
|
broadcastEvent(
|
|
10192
10395
|
conversationId,
|
|
10193
10396
|
approved ? { type: "tool:approval:granted", approvalId } : { type: "tool:approval:denied", approvalId }
|
|
10194
10397
|
);
|
|
10195
10398
|
const allApprovals = foundConversation.pendingApprovals ?? [];
|
|
10196
|
-
const allDecided = allApprovals.length > 0 && allApprovals.every((a) => a.
|
|
10399
|
+
const allDecided = allApprovals.length > 0 && allApprovals.every((a) => batchDecisions.has(a.approvalId));
|
|
10197
10400
|
if (!allDecided) {
|
|
10198
10401
|
await conversationStore.update(foundConversation);
|
|
10199
10402
|
writeJson(response, 200, { ok: true, approvalId, approved, batchComplete: false });
|
|
10200
10403
|
return;
|
|
10201
10404
|
}
|
|
10405
|
+
for (const a of allApprovals) {
|
|
10406
|
+
const d = batchDecisions.get(a.approvalId);
|
|
10407
|
+
if (d != null) a.decision = d ? "approved" : "denied";
|
|
10408
|
+
}
|
|
10409
|
+
approvalDecisionTracker.delete(conversationId);
|
|
10202
10410
|
foundConversation.pendingApprovals = [];
|
|
10203
10411
|
foundConversation.runStatus = "running";
|
|
10204
10412
|
await conversationStore.update(foundConversation);
|
|
@@ -10820,14 +11028,6 @@ data: ${JSON.stringify(frame)}
|
|
|
10820
11028
|
if (active && active.abortController === abortController) {
|
|
10821
11029
|
active.runId = event.runId;
|
|
10822
11030
|
}
|
|
10823
|
-
if (typeof event.contextWindow === "number" && event.contextWindow > 0) {
|
|
10824
|
-
runContextWindow = event.contextWindow;
|
|
10825
|
-
}
|
|
10826
|
-
}
|
|
10827
|
-
if (event.type === "model:response") {
|
|
10828
|
-
if (typeof event.usage?.input === "number") {
|
|
10829
|
-
runContextTokens = event.usage.input;
|
|
10830
|
-
}
|
|
10831
11031
|
}
|
|
10832
11032
|
if (event.type === "run:cancelled") {
|
|
10833
11033
|
runCancelled = true;
|
|
@@ -10920,6 +11120,8 @@ data: ${JSON.stringify(frame)}
|
|
|
10920
11120
|
if (assistantResponse.length === 0 && event.result.response) {
|
|
10921
11121
|
assistantResponse = event.result.response;
|
|
10922
11122
|
}
|
|
11123
|
+
runContextTokens = event.result.contextTokens ?? runContextTokens;
|
|
11124
|
+
runContextWindow = event.result.contextWindow ?? runContextWindow;
|
|
10923
11125
|
if (event.result.continuation && event.result.continuationMessages) {
|
|
10924
11126
|
runContinuationMessages = event.result.continuationMessages;
|
|
10925
11127
|
conversation._continuationMessages = runContinuationMessages;
|
|
@@ -11059,9 +11261,10 @@ data: ${JSON.stringify(frame)}
|
|
|
11059
11261
|
response.end();
|
|
11060
11262
|
} catch {
|
|
11061
11263
|
}
|
|
11264
|
+
const hadDeferred = pendingCallbackNeeded.delete(conversationId);
|
|
11062
11265
|
const freshConv = await conversationStore.get(conversationId);
|
|
11063
|
-
if (freshConv?.pendingSubagentResults?.length) {
|
|
11064
|
-
processSubagentCallback(conversationId).catch(
|
|
11266
|
+
if (hadDeferred || freshConv?.pendingSubagentResults?.length) {
|
|
11267
|
+
processSubagentCallback(conversationId, true).catch(
|
|
11065
11268
|
(err) => console.error(`[poncho][subagent-callback] Post-run callback failed:`, err instanceof Error ? err.message : err)
|
|
11066
11269
|
);
|
|
11067
11270
|
}
|
|
@@ -11209,125 +11412,157 @@ ${cronJob.task}`;
|
|
|
11209
11412
|
`[cron] ${jobName} ${timestamp}`
|
|
11210
11413
|
);
|
|
11211
11414
|
}
|
|
11212
|
-
const
|
|
11213
|
-
|
|
11214
|
-
|
|
11215
|
-
|
|
11216
|
-
|
|
11217
|
-
|
|
11218
|
-
|
|
11219
|
-
|
|
11220
|
-
|
|
11221
|
-
|
|
11222
|
-
|
|
11223
|
-
|
|
11224
|
-
|
|
11225
|
-
|
|
11226
|
-
|
|
11227
|
-
|
|
11228
|
-
|
|
11229
|
-
|
|
11230
|
-
|
|
11231
|
-
|
|
11232
|
-
|
|
11233
|
-
|
|
11234
|
-
|
|
11235
|
-
|
|
11236
|
-
|
|
11237
|
-
|
|
11238
|
-
|
|
11239
|
-
|
|
11240
|
-
|
|
11415
|
+
const convId = conversation.conversationId;
|
|
11416
|
+
activeConversationRuns.set(convId, {
|
|
11417
|
+
ownerId: conversation.ownerId,
|
|
11418
|
+
abortController: new AbortController(),
|
|
11419
|
+
runId: null
|
|
11420
|
+
});
|
|
11421
|
+
try {
|
|
11422
|
+
const abortController = new AbortController();
|
|
11423
|
+
let assistantResponse = "";
|
|
11424
|
+
let latestRunId = "";
|
|
11425
|
+
const toolTimeline = [];
|
|
11426
|
+
const sections = [];
|
|
11427
|
+
let currentTools = [];
|
|
11428
|
+
let currentText = "";
|
|
11429
|
+
let runResult = {
|
|
11430
|
+
status: "completed",
|
|
11431
|
+
steps: 0
|
|
11432
|
+
};
|
|
11433
|
+
const platformMaxDurationSec = Number(process.env.PONCHO_MAX_DURATION) || 0;
|
|
11434
|
+
const softDeadlineMs = platformMaxDurationSec > 0 ? platformMaxDurationSec * 800 : 0;
|
|
11435
|
+
for await (const event of harness.runWithTelemetry({
|
|
11436
|
+
task: cronJob.task,
|
|
11437
|
+
conversationId: convId,
|
|
11438
|
+
parameters: { __activeConversationId: convId },
|
|
11439
|
+
messages: historyMessages,
|
|
11440
|
+
abortSignal: abortController.signal
|
|
11441
|
+
})) {
|
|
11442
|
+
if (event.type === "run:started") {
|
|
11443
|
+
latestRunId = event.runId;
|
|
11444
|
+
}
|
|
11445
|
+
if (event.type === "model:chunk") {
|
|
11446
|
+
if (currentTools.length > 0) {
|
|
11447
|
+
sections.push({ type: "tools", content: currentTools });
|
|
11448
|
+
currentTools = [];
|
|
11449
|
+
if (assistantResponse.length > 0 && !/\s$/.test(assistantResponse)) {
|
|
11450
|
+
assistantResponse += " ";
|
|
11451
|
+
}
|
|
11241
11452
|
}
|
|
11453
|
+
assistantResponse += event.content;
|
|
11454
|
+
currentText += event.content;
|
|
11242
11455
|
}
|
|
11243
|
-
|
|
11244
|
-
|
|
11245
|
-
|
|
11246
|
-
|
|
11247
|
-
|
|
11248
|
-
|
|
11249
|
-
|
|
11456
|
+
if (event.type === "tool:started") {
|
|
11457
|
+
if (currentText.length > 0) {
|
|
11458
|
+
sections.push({ type: "text", content: currentText });
|
|
11459
|
+
currentText = "";
|
|
11460
|
+
}
|
|
11461
|
+
const toolText = `- start \`${event.tool}\``;
|
|
11462
|
+
toolTimeline.push(toolText);
|
|
11463
|
+
currentTools.push(toolText);
|
|
11250
11464
|
}
|
|
11251
|
-
|
|
11252
|
-
|
|
11253
|
-
|
|
11465
|
+
if (event.type === "tool:completed") {
|
|
11466
|
+
const toolText = `- done \`${event.tool}\` (${event.duration}ms)`;
|
|
11467
|
+
toolTimeline.push(toolText);
|
|
11468
|
+
currentTools.push(toolText);
|
|
11469
|
+
}
|
|
11470
|
+
if (event.type === "tool:error") {
|
|
11471
|
+
const toolText = `- error \`${event.tool}\`: ${event.error}`;
|
|
11472
|
+
toolTimeline.push(toolText);
|
|
11473
|
+
currentTools.push(toolText);
|
|
11474
|
+
}
|
|
11475
|
+
if (event.type === "run:completed") {
|
|
11476
|
+
runResult = {
|
|
11477
|
+
status: event.result.status,
|
|
11478
|
+
steps: event.result.steps,
|
|
11479
|
+
continuation: event.result.continuation,
|
|
11480
|
+
contextTokens: event.result.contextTokens,
|
|
11481
|
+
contextWindow: event.result.contextWindow
|
|
11482
|
+
};
|
|
11483
|
+
if (!assistantResponse && event.result.response) {
|
|
11484
|
+
assistantResponse = event.result.response;
|
|
11485
|
+
}
|
|
11486
|
+
}
|
|
11487
|
+
broadcastEvent(convId, event);
|
|
11488
|
+
await telemetry.emit(event);
|
|
11254
11489
|
}
|
|
11255
|
-
|
|
11256
|
-
|
|
11257
|
-
|
|
11258
|
-
currentTools.push(toolText);
|
|
11490
|
+
finishConversationStream(convId);
|
|
11491
|
+
if (currentTools.length > 0) {
|
|
11492
|
+
sections.push({ type: "tools", content: currentTools });
|
|
11259
11493
|
}
|
|
11260
|
-
if (
|
|
11261
|
-
|
|
11262
|
-
|
|
11263
|
-
currentTools.push(toolText);
|
|
11494
|
+
if (currentText.length > 0) {
|
|
11495
|
+
sections.push({ type: "text", content: currentText });
|
|
11496
|
+
currentText = "";
|
|
11264
11497
|
}
|
|
11265
|
-
|
|
11266
|
-
|
|
11267
|
-
|
|
11268
|
-
|
|
11269
|
-
|
|
11270
|
-
|
|
11271
|
-
|
|
11272
|
-
|
|
11498
|
+
const hasContent = assistantResponse.length > 0 || toolTimeline.length > 0;
|
|
11499
|
+
const assistantMetadata = toolTimeline.length > 0 || sections.length > 0 ? {
|
|
11500
|
+
toolActivity: [...toolTimeline],
|
|
11501
|
+
sections: sections.length > 0 ? sections : void 0
|
|
11502
|
+
} : void 0;
|
|
11503
|
+
const messages = [
|
|
11504
|
+
...historyMessages,
|
|
11505
|
+
...continueConversationId ? [] : [{ role: "user", content: cronJob.task }],
|
|
11506
|
+
...hasContent ? [{ role: "assistant", content: assistantResponse, metadata: assistantMetadata }] : []
|
|
11507
|
+
];
|
|
11508
|
+
const freshConv = await conversationStore.get(convId);
|
|
11509
|
+
if (freshConv) {
|
|
11510
|
+
freshConv.messages = messages;
|
|
11511
|
+
freshConv.runtimeRunId = latestRunId || freshConv.runtimeRunId;
|
|
11512
|
+
if (runResult.contextTokens) freshConv.contextTokens = runResult.contextTokens;
|
|
11513
|
+
if (runResult.contextWindow) freshConv.contextWindow = runResult.contextWindow;
|
|
11514
|
+
freshConv.updatedAt = Date.now();
|
|
11515
|
+
await conversationStore.update(freshConv);
|
|
11516
|
+
}
|
|
11517
|
+
if (runResult.continuation && softDeadlineMs > 0) {
|
|
11518
|
+
const selfUrl = `http://${request.headers.host ?? "localhost"}${pathname}?continue=${encodeURIComponent(convId)}&continuation=${continuationCount + 1}`;
|
|
11519
|
+
try {
|
|
11520
|
+
const selfRes = await fetch(selfUrl, {
|
|
11521
|
+
method: "GET",
|
|
11522
|
+
headers: request.headers.authorization ? { authorization: request.headers.authorization } : {}
|
|
11523
|
+
});
|
|
11524
|
+
const selfBody = await selfRes.json();
|
|
11525
|
+
writeJson(response, 200, {
|
|
11526
|
+
conversationId: convId,
|
|
11527
|
+
status: "continued",
|
|
11528
|
+
continuations: continuationCount + 1,
|
|
11529
|
+
finalResult: selfBody,
|
|
11530
|
+
duration: Date.now() - start
|
|
11531
|
+
});
|
|
11532
|
+
} catch (continueError) {
|
|
11533
|
+
writeJson(response, 200, {
|
|
11534
|
+
conversationId: convId,
|
|
11535
|
+
status: "continuation_failed",
|
|
11536
|
+
error: continueError instanceof Error ? continueError.message : "Unknown error",
|
|
11537
|
+
duration: Date.now() - start,
|
|
11538
|
+
steps: runResult.steps
|
|
11539
|
+
});
|
|
11273
11540
|
}
|
|
11541
|
+
return;
|
|
11274
11542
|
}
|
|
11275
|
-
|
|
11276
|
-
|
|
11277
|
-
|
|
11278
|
-
|
|
11279
|
-
|
|
11280
|
-
|
|
11281
|
-
|
|
11282
|
-
|
|
11283
|
-
|
|
11284
|
-
|
|
11285
|
-
|
|
11286
|
-
|
|
11287
|
-
|
|
11288
|
-
|
|
11289
|
-
|
|
11290
|
-
|
|
11291
|
-
|
|
11292
|
-
|
|
11293
|
-
|
|
11294
|
-
|
|
11295
|
-
|
|
11296
|
-
conversation.updatedAt = Date.now();
|
|
11297
|
-
await conversationStore.update(conversation);
|
|
11298
|
-
if (runResult.continuation && softDeadlineMs > 0) {
|
|
11299
|
-
const selfUrl = `http://${request.headers.host ?? "localhost"}${pathname}?continue=${encodeURIComponent(conversation.conversationId)}&continuation=${continuationCount + 1}`;
|
|
11300
|
-
try {
|
|
11301
|
-
const selfRes = await fetch(selfUrl, {
|
|
11302
|
-
method: "GET",
|
|
11303
|
-
headers: request.headers.authorization ? { authorization: request.headers.authorization } : {}
|
|
11304
|
-
});
|
|
11305
|
-
const selfBody = await selfRes.json();
|
|
11306
|
-
writeJson(response, 200, {
|
|
11307
|
-
conversationId: conversation.conversationId,
|
|
11308
|
-
status: "continued",
|
|
11309
|
-
continuations: continuationCount + 1,
|
|
11310
|
-
finalResult: selfBody,
|
|
11311
|
-
duration: Date.now() - start
|
|
11312
|
-
});
|
|
11313
|
-
} catch (continueError) {
|
|
11314
|
-
writeJson(response, 200, {
|
|
11315
|
-
conversationId: conversation.conversationId,
|
|
11316
|
-
status: "continuation_failed",
|
|
11317
|
-
error: continueError instanceof Error ? continueError.message : "Unknown error",
|
|
11318
|
-
duration: Date.now() - start,
|
|
11319
|
-
steps: runResult.steps
|
|
11320
|
-
});
|
|
11543
|
+
writeJson(response, 200, {
|
|
11544
|
+
conversationId: convId,
|
|
11545
|
+
status: runResult.status,
|
|
11546
|
+
response: assistantResponse.slice(0, 500),
|
|
11547
|
+
duration: Date.now() - start,
|
|
11548
|
+
steps: runResult.steps
|
|
11549
|
+
});
|
|
11550
|
+
} finally {
|
|
11551
|
+
activeConversationRuns.delete(convId);
|
|
11552
|
+
const hadDeferred = pendingCallbackNeeded.delete(convId);
|
|
11553
|
+
const checkConv = await conversationStore.get(convId);
|
|
11554
|
+
if (hadDeferred || checkConv?.pendingSubagentResults?.length) {
|
|
11555
|
+
if (isServerless) {
|
|
11556
|
+
selfFetchWithRetry(`/api/internal/conversations/${encodeURIComponent(convId)}/subagent-callback`).catch(
|
|
11557
|
+
(err) => console.error(`[cron] subagent callback self-fetch failed:`, err instanceof Error ? err.message : err)
|
|
11558
|
+
);
|
|
11559
|
+
} else {
|
|
11560
|
+
processSubagentCallback(convId, true).catch(
|
|
11561
|
+
(err) => console.error(`[cron] subagent callback failed:`, err instanceof Error ? err.message : err)
|
|
11562
|
+
);
|
|
11563
|
+
}
|
|
11321
11564
|
}
|
|
11322
|
-
return;
|
|
11323
11565
|
}
|
|
11324
|
-
writeJson(response, 200, {
|
|
11325
|
-
conversationId: conversation.conversationId,
|
|
11326
|
-
status: runResult.status,
|
|
11327
|
-
response: assistantResponse.slice(0, 500),
|
|
11328
|
-
duration: Date.now() - start,
|
|
11329
|
-
steps: runResult.steps
|
|
11330
|
-
});
|
|
11331
11566
|
} catch (error) {
|
|
11332
11567
|
writeJson(response, 500, {
|
|
11333
11568
|
code: "CRON_RUN_ERROR",
|
|
@@ -11342,6 +11577,11 @@ ${cronJob.task}`;
|
|
|
11342
11577
|
handler._cronJobs = cronJobs;
|
|
11343
11578
|
handler._conversationStore = conversationStore;
|
|
11344
11579
|
handler._messagingAdapters = messagingAdapters;
|
|
11580
|
+
handler._activeConversationRuns = activeConversationRuns;
|
|
11581
|
+
handler._pendingCallbackNeeded = pendingCallbackNeeded;
|
|
11582
|
+
handler._processSubagentCallback = processSubagentCallback;
|
|
11583
|
+
handler._broadcastEvent = broadcastEvent;
|
|
11584
|
+
handler._finishConversationStream = finishConversationStream;
|
|
11345
11585
|
const STALE_SUBAGENT_THRESHOLD_MS = 5 * 60 * 1e3;
|
|
11346
11586
|
try {
|
|
11347
11587
|
const allSummaries = await conversationStore.listSummaries();
|
|
@@ -11392,9 +11632,11 @@ var startDevServer = async (port, options) => {
|
|
|
11392
11632
|
await checkVercelCronDrift(workingDir);
|
|
11393
11633
|
const { Cron } = await import("croner");
|
|
11394
11634
|
let activeJobs = [];
|
|
11395
|
-
const runCronAgent = async (harnessRef, task, conversationId, historyMessages) => {
|
|
11635
|
+
const runCronAgent = async (harnessRef, task, conversationId, historyMessages, onEvent) => {
|
|
11396
11636
|
let assistantResponse = "";
|
|
11397
11637
|
let steps = 0;
|
|
11638
|
+
let contextTokens = 0;
|
|
11639
|
+
let contextWindow = 0;
|
|
11398
11640
|
const toolTimeline = [];
|
|
11399
11641
|
const sections = [];
|
|
11400
11642
|
let currentTools = [];
|
|
@@ -11405,6 +11647,7 @@ var startDevServer = async (port, options) => {
|
|
|
11405
11647
|
parameters: { __activeConversationId: conversationId },
|
|
11406
11648
|
messages: historyMessages
|
|
11407
11649
|
})) {
|
|
11650
|
+
onEvent?.(event);
|
|
11408
11651
|
if (event.type === "model:chunk") {
|
|
11409
11652
|
if (currentTools.length > 0) {
|
|
11410
11653
|
sections.push({ type: "tools", content: currentTools });
|
|
@@ -11437,6 +11680,8 @@ var startDevServer = async (port, options) => {
|
|
|
11437
11680
|
}
|
|
11438
11681
|
if (event.type === "run:completed") {
|
|
11439
11682
|
steps = event.result.steps;
|
|
11683
|
+
contextTokens = event.result.contextTokens ?? 0;
|
|
11684
|
+
contextWindow = event.result.contextWindow ?? 0;
|
|
11440
11685
|
if (!assistantResponse && event.result.response) {
|
|
11441
11686
|
assistantResponse = event.result.response;
|
|
11442
11687
|
}
|
|
@@ -11453,7 +11698,7 @@ var startDevServer = async (port, options) => {
|
|
|
11453
11698
|
toolActivity: [...toolTimeline],
|
|
11454
11699
|
sections: sections.length > 0 ? sections : void 0
|
|
11455
11700
|
} : void 0;
|
|
11456
|
-
return { response: assistantResponse, steps, assistantMetadata, hasContent };
|
|
11701
|
+
return { response: assistantResponse, steps, assistantMetadata, hasContent, contextTokens, contextWindow };
|
|
11457
11702
|
};
|
|
11458
11703
|
const buildCronMessages = (task, historyMessages, result) => [
|
|
11459
11704
|
...historyMessages,
|
|
@@ -11470,6 +11715,9 @@ var startDevServer = async (port, options) => {
|
|
|
11470
11715
|
const harnessRef = handler._harness;
|
|
11471
11716
|
const store = handler._conversationStore;
|
|
11472
11717
|
const adapters = handler._messagingAdapters;
|
|
11718
|
+
const activeRuns = handler._activeConversationRuns;
|
|
11719
|
+
const deferredCallbacks = handler._pendingCallbackNeeded;
|
|
11720
|
+
const runCallback = handler._processSubagentCallback;
|
|
11473
11721
|
if (!harnessRef || !store) return;
|
|
11474
11722
|
for (const [jobName, config] of entries) {
|
|
11475
11723
|
const job = new Cron(
|
|
@@ -11510,24 +11758,43 @@ var startDevServer = async (port, options) => {
|
|
|
11510
11758
|
const task = `[Scheduled: ${jobName}]
|
|
11511
11759
|
${config.task}`;
|
|
11512
11760
|
const historyMessages = [...conversation.messages];
|
|
11761
|
+
const convId = conversation.conversationId;
|
|
11762
|
+
activeRuns?.set(convId, {
|
|
11763
|
+
ownerId: "local-owner",
|
|
11764
|
+
abortController: new AbortController(),
|
|
11765
|
+
runId: null
|
|
11766
|
+
});
|
|
11513
11767
|
try {
|
|
11514
|
-
const
|
|
11515
|
-
|
|
11516
|
-
|
|
11517
|
-
|
|
11518
|
-
|
|
11519
|
-
|
|
11520
|
-
|
|
11521
|
-
|
|
11522
|
-
|
|
11523
|
-
|
|
11524
|
-
|
|
11525
|
-
|
|
11526
|
-
|
|
11527
|
-
|
|
11528
|
-
|
|
11529
|
-
|
|
11768
|
+
const broadcastCh = handler._broadcastEvent;
|
|
11769
|
+
const result = await runCronAgent(
|
|
11770
|
+
harnessRef,
|
|
11771
|
+
task,
|
|
11772
|
+
convId,
|
|
11773
|
+
historyMessages,
|
|
11774
|
+
broadcastCh ? (ev) => broadcastCh(convId, ev) : void 0
|
|
11775
|
+
);
|
|
11776
|
+
handler._finishConversationStream?.(convId);
|
|
11777
|
+
const freshConv = await store.get(convId);
|
|
11778
|
+
if (freshConv) {
|
|
11779
|
+
freshConv.messages = buildCronMessages(task, historyMessages, result);
|
|
11780
|
+
if (result.contextTokens > 0) freshConv.contextTokens = result.contextTokens;
|
|
11781
|
+
if (result.contextWindow > 0) freshConv.contextWindow = result.contextWindow;
|
|
11782
|
+
freshConv.updatedAt = Date.now();
|
|
11783
|
+
await store.update(freshConv);
|
|
11784
|
+
if (result.response) {
|
|
11785
|
+
try {
|
|
11786
|
+
await adapter.sendReply(
|
|
11787
|
+
{
|
|
11788
|
+
channelId: chatId,
|
|
11789
|
+
platformThreadId: freshConv.channelMeta?.platformThreadId ?? chatId
|
|
11790
|
+
},
|
|
11791
|
+
result.response
|
|
11792
|
+
);
|
|
11793
|
+
} catch (sendError) {
|
|
11794
|
+
const sendMsg = sendError instanceof Error ? sendError.message : String(sendError);
|
|
11795
|
+
process.stderr.write(`[cron] ${jobName}: send to ${chatId} failed: ${sendMsg}
|
|
11530
11796
|
`);
|
|
11797
|
+
}
|
|
11531
11798
|
}
|
|
11532
11799
|
}
|
|
11533
11800
|
totalChats++;
|
|
@@ -11535,6 +11802,15 @@ ${config.task}`;
|
|
|
11535
11802
|
const runMsg = runError instanceof Error ? runError.message : String(runError);
|
|
11536
11803
|
process.stderr.write(`[cron] ${jobName}: run for chat ${chatId} failed: ${runMsg}
|
|
11537
11804
|
`);
|
|
11805
|
+
} finally {
|
|
11806
|
+
activeRuns?.delete(convId);
|
|
11807
|
+
const hadDeferred = deferredCallbacks?.delete(convId) ?? false;
|
|
11808
|
+
const checkConv = await store.get(convId);
|
|
11809
|
+
if (hadDeferred || checkConv?.pendingSubagentResults?.length) {
|
|
11810
|
+
runCallback?.(convId, true).catch(
|
|
11811
|
+
(err) => console.error(`[cron] ${jobName}: subagent callback for ${chatId} failed:`, err instanceof Error ? err.message : err)
|
|
11812
|
+
);
|
|
11813
|
+
}
|
|
11538
11814
|
}
|
|
11539
11815
|
}
|
|
11540
11816
|
const elapsed = ((Date.now() - start) / 1e3).toFixed(1);
|
|
@@ -11548,15 +11824,35 @@ ${config.task}`;
|
|
|
11548
11824
|
}
|
|
11549
11825
|
return;
|
|
11550
11826
|
}
|
|
11827
|
+
let cronConvId;
|
|
11551
11828
|
try {
|
|
11552
11829
|
const conversation = await store.create(
|
|
11553
11830
|
"local-owner",
|
|
11554
11831
|
`[cron] ${jobName} ${timestamp}`
|
|
11555
11832
|
);
|
|
11556
|
-
|
|
11557
|
-
|
|
11558
|
-
|
|
11559
|
-
|
|
11833
|
+
cronConvId = conversation.conversationId;
|
|
11834
|
+
activeRuns?.set(cronConvId, {
|
|
11835
|
+
ownerId: "local-owner",
|
|
11836
|
+
abortController: new AbortController(),
|
|
11837
|
+
runId: null
|
|
11838
|
+
});
|
|
11839
|
+
const broadcast = handler._broadcastEvent;
|
|
11840
|
+
const result = await runCronAgent(
|
|
11841
|
+
harnessRef,
|
|
11842
|
+
config.task,
|
|
11843
|
+
cronConvId,
|
|
11844
|
+
[],
|
|
11845
|
+
broadcast ? (ev) => broadcast(cronConvId, ev) : void 0
|
|
11846
|
+
);
|
|
11847
|
+
handler._finishConversationStream?.(cronConvId);
|
|
11848
|
+
const freshConv = await store.get(cronConvId);
|
|
11849
|
+
if (freshConv) {
|
|
11850
|
+
freshConv.messages = buildCronMessages(config.task, [], result);
|
|
11851
|
+
if (result.contextTokens > 0) freshConv.contextTokens = result.contextTokens;
|
|
11852
|
+
if (result.contextWindow > 0) freshConv.contextWindow = result.contextWindow;
|
|
11853
|
+
freshConv.updatedAt = Date.now();
|
|
11854
|
+
await store.update(freshConv);
|
|
11855
|
+
}
|
|
11560
11856
|
const elapsed = ((Date.now() - start) / 1e3).toFixed(1);
|
|
11561
11857
|
process.stdout.write(
|
|
11562
11858
|
`[cron] ${jobName} completed in ${elapsed}s (${result.steps} steps)
|
|
@@ -11569,6 +11865,17 @@ ${config.task}`;
|
|
|
11569
11865
|
`[cron] ${jobName} failed after ${elapsed}s: ${msg}
|
|
11570
11866
|
`
|
|
11571
11867
|
);
|
|
11868
|
+
} finally {
|
|
11869
|
+
if (cronConvId) {
|
|
11870
|
+
activeRuns?.delete(cronConvId);
|
|
11871
|
+
const hadDeferred = deferredCallbacks?.delete(cronConvId) ?? false;
|
|
11872
|
+
const checkConv = await store.get(cronConvId);
|
|
11873
|
+
if (hadDeferred || checkConv?.pendingSubagentResults?.length) {
|
|
11874
|
+
runCallback?.(cronConvId, true).catch(
|
|
11875
|
+
(err) => console.error(`[cron] ${jobName}: subagent callback failed:`, err instanceof Error ? err.message : err)
|
|
11876
|
+
);
|
|
11877
|
+
}
|
|
11878
|
+
}
|
|
11572
11879
|
}
|
|
11573
11880
|
}
|
|
11574
11881
|
);
|
|
@@ -11676,7 +11983,7 @@ var runInteractive = async (workingDir, params) => {
|
|
|
11676
11983
|
await harness.initialize();
|
|
11677
11984
|
const identity = await ensureAgentIdentity2(workingDir);
|
|
11678
11985
|
try {
|
|
11679
|
-
const { runInteractiveInk } = await import("./run-interactive-ink-
|
|
11986
|
+
const { runInteractiveInk } = await import("./run-interactive-ink-ZSIGWFLZ.js");
|
|
11680
11987
|
await runInteractiveInk({
|
|
11681
11988
|
harness,
|
|
11682
11989
|
params,
|