@poncho-ai/cli 0.30.7 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +5 -5
- package/CHANGELOG.md +22 -0
- package/dist/{chunk-NPD5GM5C.js → chunk-73C227HM.js} +697 -164
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/dist/{run-interactive-ink-NV6LIQWU.js → run-interactive-ink-OKE5AV3N.js} +1 -1
- package/package.json +4 -4
- package/src/index.ts +645 -96
- package/src/web-ui-client.ts +106 -71
|
@@ -3174,10 +3174,11 @@ var getWebUiClientScript = (markedSource2) => `
|
|
|
3174
3174
|
} else if (willStream) {
|
|
3175
3175
|
setStreaming(true);
|
|
3176
3176
|
} else if (payload.needsContinuation && !payload.conversation.parentConversationId) {
|
|
3177
|
-
console.log("[poncho] Detected orphaned continuation for", conversationId, "\u2014 auto-resuming");
|
|
3177
|
+
console.log("[poncho] Detected orphaned continuation for", conversationId, "\u2014 auto-resuming via /continue");
|
|
3178
3178
|
(async () => {
|
|
3179
3179
|
try {
|
|
3180
3180
|
setStreaming(true);
|
|
3181
|
+
state.activeStreamConversationId = conversationId;
|
|
3181
3182
|
var localMsgs = state.activeMessages || [];
|
|
3182
3183
|
var contAssistant = {
|
|
3183
3184
|
role: "assistant",
|
|
@@ -3194,30 +3195,36 @@ var getWebUiClientScript = (markedSource2) => `
|
|
|
3194
3195
|
state.activeMessages = localMsgs;
|
|
3195
3196
|
state._activeStreamMessages = localMsgs;
|
|
3196
3197
|
renderMessages(localMsgs, true);
|
|
3198
|
+
|
|
3197
3199
|
var contResp = await fetch(
|
|
3198
|
-
"/api/conversations/" + encodeURIComponent(conversationId) + "/
|
|
3200
|
+
"/api/conversations/" + encodeURIComponent(conversationId) + "/continue",
|
|
3199
3201
|
{
|
|
3200
3202
|
method: "POST",
|
|
3201
3203
|
credentials: "include",
|
|
3202
3204
|
headers: { "Content-Type": "application/json", "x-csrf-token": state.csrfToken },
|
|
3203
|
-
body: JSON.stringify({ continuation: true }),
|
|
3204
3205
|
},
|
|
3205
3206
|
);
|
|
3206
3207
|
if (!contResp.ok || !contResp.body) {
|
|
3207
|
-
|
|
3208
|
+
// Server already claimed the continuation (safety net). Poll for completion.
|
|
3209
|
+
await pollUntilRunIdle(conversationId);
|
|
3208
3210
|
setStreaming(false);
|
|
3209
3211
|
renderMessages(localMsgs, false);
|
|
3210
3212
|
return;
|
|
3211
3213
|
}
|
|
3212
|
-
|
|
3214
|
+
|
|
3213
3215
|
var contReader = contResp.body.getReader();
|
|
3214
3216
|
var contDecoder = new TextDecoder();
|
|
3215
3217
|
var contBuffer = "";
|
|
3218
|
+
var gotStreamEnd = false;
|
|
3216
3219
|
while (true) {
|
|
3217
3220
|
var chunk = await contReader.read();
|
|
3218
3221
|
if (chunk.done) break;
|
|
3219
3222
|
contBuffer += contDecoder.decode(chunk.value, { stream: true });
|
|
3220
3223
|
contBuffer = parseSseChunk(contBuffer, function(evtName, evtPayload) {
|
|
3224
|
+
if (evtName === "stream:end") {
|
|
3225
|
+
gotStreamEnd = true;
|
|
3226
|
+
return;
|
|
3227
|
+
}
|
|
3221
3228
|
if (evtName === "model:chunk" && evtPayload.content) {
|
|
3222
3229
|
contAssistant.content = (contAssistant.content || "") + evtPayload.content;
|
|
3223
3230
|
contAssistant._currentText += evtPayload.content;
|
|
@@ -3248,14 +3255,14 @@ var getWebUiClientScript = (markedSource2) => `
|
|
|
3248
3255
|
if (evtName === "run:error") {
|
|
3249
3256
|
contAssistant._error = evtPayload.error?.message || "Something went wrong";
|
|
3250
3257
|
}
|
|
3251
|
-
if (evtName === "run:completed" && evtPayload.result?.continuation === true) {
|
|
3252
|
-
// Another continuation needed \u2014 reload to pick it up
|
|
3253
|
-
loadConversation(conversationId).catch(function() {});
|
|
3254
|
-
}
|
|
3255
3258
|
}
|
|
3256
3259
|
renderMessages(localMsgs, true);
|
|
3257
3260
|
});
|
|
3258
3261
|
}
|
|
3262
|
+
if (gotStreamEnd) {
|
|
3263
|
+
// Safety net already claimed it. Poll for completion.
|
|
3264
|
+
await pollUntilRunIdle(conversationId);
|
|
3265
|
+
}
|
|
3259
3266
|
setStreaming(false);
|
|
3260
3267
|
renderMessages(localMsgs, false);
|
|
3261
3268
|
await loadConversations();
|
|
@@ -4350,59 +4357,30 @@ var getWebUiClientScript = (markedSource2) => `
|
|
|
4350
4357
|
};
|
|
4351
4358
|
let _totalSteps = 0;
|
|
4352
4359
|
let _maxSteps = 0;
|
|
4353
|
-
let _isContinuation = false;
|
|
4354
4360
|
let _receivedTerminalEvent = false;
|
|
4355
|
-
while (true) {
|
|
4356
4361
|
let _shouldContinue = false;
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
headers: { "x-csrf-token": state.csrfToken },
|
|
4376
|
-
body: formData,
|
|
4377
|
-
signal: streamAbortController.signal,
|
|
4378
|
-
};
|
|
4379
|
-
} else {
|
|
4380
|
-
fetchOpts = {
|
|
4381
|
-
method: "POST",
|
|
4382
|
-
credentials: "include",
|
|
4383
|
-
headers: { "Content-Type": "application/json", "x-csrf-token": state.csrfToken },
|
|
4384
|
-
body: JSON.stringify({ message: messageText }),
|
|
4385
|
-
signal: streamAbortController.signal,
|
|
4386
|
-
};
|
|
4387
|
-
}
|
|
4388
|
-
const response = await fetch(
|
|
4389
|
-
"/api/conversations/" + encodeURIComponent(conversationId) + "/messages",
|
|
4390
|
-
fetchOpts,
|
|
4391
|
-
);
|
|
4392
|
-
if (!response.ok || !response.body) {
|
|
4393
|
-
throw new Error("Failed to stream response");
|
|
4394
|
-
}
|
|
4395
|
-
const reader = response.body.getReader();
|
|
4396
|
-
const decoder = new TextDecoder();
|
|
4397
|
-
let buffer = "";
|
|
4398
|
-
while (true) {
|
|
4399
|
-
const { value, done } = await reader.read();
|
|
4400
|
-
if (done) {
|
|
4401
|
-
break;
|
|
4362
|
+
|
|
4363
|
+
// Helper to read an SSE stream from a fetch response
|
|
4364
|
+
const readSseStream = async (response) => {
|
|
4365
|
+
_shouldContinue = false;
|
|
4366
|
+
const reader = response.body.getReader();
|
|
4367
|
+
const decoder = new TextDecoder();
|
|
4368
|
+
let buffer = "";
|
|
4369
|
+
while (true) {
|
|
4370
|
+
const { value, done } = await reader.read();
|
|
4371
|
+
if (done) break;
|
|
4372
|
+
buffer += decoder.decode(value, { stream: true });
|
|
4373
|
+
buffer = parseSseChunk(buffer, (eventName, payload) => {
|
|
4374
|
+
try {
|
|
4375
|
+
handleSseEvent(eventName, payload);
|
|
4376
|
+
} catch (error) {
|
|
4377
|
+
console.error("SSE event handling error:", eventName, error);
|
|
4378
|
+
}
|
|
4379
|
+
});
|
|
4402
4380
|
}
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4381
|
+
};
|
|
4382
|
+
|
|
4383
|
+
const handleSseEvent = (eventName, payload) => {
|
|
4406
4384
|
if (eventName === "model:chunk") {
|
|
4407
4385
|
const chunk = String(payload.content || "");
|
|
4408
4386
|
if (chunk.length > 0) clearResolvedApprovals(assistantMessage);
|
|
@@ -4686,6 +4664,12 @@ var getWebUiClientScript = (markedSource2) => `
|
|
|
4686
4664
|
if (typeof payload.result?.maxSteps === "number") _maxSteps = payload.result.maxSteps;
|
|
4687
4665
|
if (payload.result?.continuation === true && (_maxSteps <= 0 || _totalSteps < _maxSteps)) {
|
|
4688
4666
|
_shouldContinue = true;
|
|
4667
|
+
if (assistantMessage._currentTools.length > 0) {
|
|
4668
|
+
assistantMessage._sections.push({ type: "tools", content: assistantMessage._currentTools });
|
|
4669
|
+
assistantMessage._currentTools = [];
|
|
4670
|
+
}
|
|
4671
|
+
assistantMessage._activeActivities = [];
|
|
4672
|
+
renderIfActiveConversation(true);
|
|
4689
4673
|
} else {
|
|
4690
4674
|
finalizeAssistantMessage();
|
|
4691
4675
|
if (!assistantMessage.content || assistantMessage.content.length === 0) {
|
|
@@ -4709,26 +4693,77 @@ var getWebUiClientScript = (markedSource2) => `
|
|
|
4709
4693
|
assistantMessage._error = errMsg;
|
|
4710
4694
|
renderIfActiveConversation(false);
|
|
4711
4695
|
}
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4696
|
+
if (eventName === "stream:end") {
|
|
4697
|
+
// no-op: server signals empty continuation
|
|
4698
|
+
}
|
|
4699
|
+
};
|
|
4700
|
+
|
|
4701
|
+
// Initial message POST
|
|
4702
|
+
let fetchOpts;
|
|
4703
|
+
if (filesToSend.length > 0) {
|
|
4704
|
+
const formData = new FormData();
|
|
4705
|
+
formData.append("message", messageText);
|
|
4706
|
+
for (const f of filesToSend) {
|
|
4707
|
+
formData.append("files", f, f.name);
|
|
4708
|
+
}
|
|
4709
|
+
fetchOpts = {
|
|
4710
|
+
method: "POST",
|
|
4711
|
+
credentials: "include",
|
|
4712
|
+
headers: { "x-csrf-token": state.csrfToken },
|
|
4713
|
+
body: formData,
|
|
4714
|
+
signal: streamAbortController.signal,
|
|
4715
|
+
};
|
|
4716
|
+
} else {
|
|
4717
|
+
fetchOpts = {
|
|
4718
|
+
method: "POST",
|
|
4719
|
+
credentials: "include",
|
|
4720
|
+
headers: { "Content-Type": "application/json", "x-csrf-token": state.csrfToken },
|
|
4721
|
+
body: JSON.stringify({ message: messageText }),
|
|
4722
|
+
signal: streamAbortController.signal,
|
|
4723
|
+
};
|
|
4716
4724
|
}
|
|
4717
|
-
|
|
4725
|
+
const response = await fetch(
|
|
4726
|
+
"/api/conversations/" + encodeURIComponent(conversationId) + "/messages",
|
|
4727
|
+
fetchOpts,
|
|
4728
|
+
);
|
|
4729
|
+
if (!response.ok || !response.body) {
|
|
4730
|
+
throw new Error("Failed to stream response");
|
|
4731
|
+
}
|
|
4732
|
+
await readSseStream(response);
|
|
4733
|
+
|
|
4734
|
+
// Continuation loop: POST to /continue while the server signals more work
|
|
4735
|
+
while (_shouldContinue) {
|
|
4736
|
+
_shouldContinue = false;
|
|
4737
|
+
_receivedTerminalEvent = false;
|
|
4738
|
+
const contResponse = await fetch(
|
|
4739
|
+
"/api/conversations/" + encodeURIComponent(conversationId) + "/continue",
|
|
4740
|
+
{
|
|
4741
|
+
method: "POST",
|
|
4742
|
+
credentials: "include",
|
|
4743
|
+
headers: { "Content-Type": "application/json", "x-csrf-token": state.csrfToken },
|
|
4744
|
+
signal: streamAbortController.signal,
|
|
4745
|
+
},
|
|
4746
|
+
);
|
|
4747
|
+
if (!contResponse.ok || !contResponse.body) {
|
|
4748
|
+
// Server may have already handled continuation (safety net claimed it).
|
|
4749
|
+
// Fall back to polling for idle state.
|
|
4750
|
+
await pollUntilRunIdle(conversationId);
|
|
4751
|
+
break;
|
|
4752
|
+
}
|
|
4753
|
+
await readSseStream(contResponse);
|
|
4754
|
+
}
|
|
4755
|
+
|
|
4756
|
+
// If stream ended without terminal event and no continuation, check server
|
|
4757
|
+
if (!_receivedTerminalEvent && !_shouldContinue) {
|
|
4718
4758
|
try {
|
|
4719
4759
|
const recoveryPayload = await api("/api/conversations/" + encodeURIComponent(conversationId));
|
|
4720
|
-
if (recoveryPayload.needsContinuation) {
|
|
4721
|
-
|
|
4722
|
-
console.log("[poncho] Stream ended without terminal event, server has continuation \u2014 resuming");
|
|
4760
|
+
if (recoveryPayload.hasActiveRun || recoveryPayload.needsContinuation) {
|
|
4761
|
+
await pollUntilRunIdle(conversationId);
|
|
4723
4762
|
}
|
|
4724
4763
|
} catch (_recoverErr) {
|
|
4725
4764
|
console.warn("[poncho] Recovery check failed after abrupt stream end");
|
|
4726
4765
|
}
|
|
4727
4766
|
}
|
|
4728
|
-
if (!_shouldContinue) break;
|
|
4729
|
-
_receivedTerminalEvent = false;
|
|
4730
|
-
_isContinuation = true;
|
|
4731
|
-
}
|
|
4732
4767
|
// Update active state only if user is still on this conversation.
|
|
4733
4768
|
if (state.activeConversationId === streamConversationId) {
|
|
4734
4769
|
state.activeMessages = localMessages;
|
|
@@ -8604,7 +8639,7 @@ data: ${JSON.stringify(statusPayload)}
|
|
|
8604
8639
|
await resumeRunFromCheckpoint(subagentId, conv, checkpointRef, toolResults);
|
|
8605
8640
|
await handleSubagentCompletion(subagentId);
|
|
8606
8641
|
};
|
|
8607
|
-
const runSubagent = async (childConversationId, parentConversationId, task, ownerId,
|
|
8642
|
+
const runSubagent = async (childConversationId, parentConversationId, task, ownerId, _isContinuation = false) => {
|
|
8608
8643
|
const childHarness = new AgentHarness({
|
|
8609
8644
|
workingDir,
|
|
8610
8645
|
environment: resolveHarnessEnvironment(),
|
|
@@ -8632,9 +8667,9 @@ data: ${JSON.stringify(statusPayload)}
|
|
|
8632
8667
|
if (conversation.subagentMeta?.status === "stopped") return;
|
|
8633
8668
|
conversation.lastActivityAt = Date.now();
|
|
8634
8669
|
await conversationStore.update(conversation);
|
|
8635
|
-
const harnessMessages =
|
|
8670
|
+
const harnessMessages = conversation._harnessMessages?.length ? [...conversation._harnessMessages] : [...conversation.messages];
|
|
8636
8671
|
for await (const event of childHarness.runWithTelemetry({
|
|
8637
|
-
task
|
|
8672
|
+
task,
|
|
8638
8673
|
conversationId: childConversationId,
|
|
8639
8674
|
parameters: {
|
|
8640
8675
|
__activeConversationId: childConversationId,
|
|
@@ -8824,17 +8859,22 @@ data: ${JSON.stringify(statusPayload)}
|
|
|
8824
8859
|
if (currentText.length > 0) sections.push({ type: "text", content: currentText });
|
|
8825
8860
|
const conv = await conversationStore.get(childConversationId);
|
|
8826
8861
|
if (conv) {
|
|
8862
|
+
const hasContent = assistantResponse.length > 0 || toolTimeline.length > 0;
|
|
8863
|
+
if (hasContent) {
|
|
8864
|
+
conv.messages.push({
|
|
8865
|
+
role: "assistant",
|
|
8866
|
+
content: assistantResponse,
|
|
8867
|
+
metadata: toolTimeline.length > 0 || sections.length > 0 ? { toolActivity: toolTimeline, sections: sections.length > 0 ? sections : void 0 } : void 0
|
|
8868
|
+
});
|
|
8869
|
+
}
|
|
8827
8870
|
if (runResult?.continuation && runResult.continuationMessages) {
|
|
8828
8871
|
conv._continuationMessages = runResult.continuationMessages;
|
|
8829
8872
|
} else {
|
|
8830
8873
|
conv._continuationMessages = void 0;
|
|
8831
|
-
|
|
8832
|
-
|
|
8833
|
-
|
|
8834
|
-
|
|
8835
|
-
metadata: toolTimeline.length > 0 || sections.length > 0 ? { toolActivity: toolTimeline, sections: sections.length > 0 ? sections : void 0 } : void 0
|
|
8836
|
-
});
|
|
8837
|
-
}
|
|
8874
|
+
conv._continuationCount = void 0;
|
|
8875
|
+
}
|
|
8876
|
+
if (runResult?.continuationMessages) {
|
|
8877
|
+
conv._harnessMessages = runResult.continuationMessages;
|
|
8838
8878
|
}
|
|
8839
8879
|
conv.lastActivityAt = Date.now();
|
|
8840
8880
|
conv.updatedAt = Date.now();
|
|
@@ -8847,16 +8887,11 @@ data: ${JSON.stringify(statusPayload)}
|
|
|
8847
8887
|
await childHarness.shutdown();
|
|
8848
8888
|
} catch {
|
|
8849
8889
|
}
|
|
8850
|
-
|
|
8851
|
-
|
|
8852
|
-
|
|
8853
|
-
|
|
8854
|
-
|
|
8855
|
-
} else {
|
|
8856
|
-
runSubagent(childConversationId, parentConversationId, task, ownerId, true).catch(
|
|
8857
|
-
(err) => console.error(`[poncho][subagent] Continuation failed:`, err instanceof Error ? err.message : err)
|
|
8858
|
-
);
|
|
8859
|
-
}
|
|
8890
|
+
const work = selfFetchWithRetry(`/api/internal/continue/${encodeURIComponent(childConversationId)}`).catch(
|
|
8891
|
+
(err) => console.error(`[poncho][subagent] Continuation self-fetch failed:`, err instanceof Error ? err.message : err)
|
|
8892
|
+
);
|
|
8893
|
+
doWaitUntil(work);
|
|
8894
|
+
if (!waitUntilHook) await work;
|
|
8860
8895
|
return;
|
|
8861
8896
|
}
|
|
8862
8897
|
conv.subagentMeta = { ...conv.subagentMeta, status: "completed" };
|
|
@@ -9009,11 +9044,12 @@ ${resultBody}`,
|
|
|
9009
9044
|
finished: false
|
|
9010
9045
|
});
|
|
9011
9046
|
}
|
|
9012
|
-
const historyMessages = isContinuationResume && conversation._continuationMessages?.length ? [...conversation._continuationMessages] : [...conversation.messages];
|
|
9047
|
+
const historyMessages = isContinuationResume && conversation._continuationMessages?.length ? [...conversation._continuationMessages] : conversation._harnessMessages?.length ? [...conversation._harnessMessages] : [...conversation.messages];
|
|
9013
9048
|
let assistantResponse = "";
|
|
9014
9049
|
let latestRunId = "";
|
|
9015
|
-
let
|
|
9050
|
+
let runContinuation2 = false;
|
|
9016
9051
|
let runContinuationMessages;
|
|
9052
|
+
let runHarnessMessages;
|
|
9017
9053
|
let runContextTokens = conversation.contextTokens ?? 0;
|
|
9018
9054
|
let runContextWindow = conversation.contextWindow ?? 0;
|
|
9019
9055
|
const toolTimeline = [];
|
|
@@ -9072,8 +9108,11 @@ ${resultBody}`,
|
|
|
9072
9108
|
}
|
|
9073
9109
|
runContextTokens = event.result.contextTokens ?? runContextTokens;
|
|
9074
9110
|
runContextWindow = event.result.contextWindow ?? runContextWindow;
|
|
9111
|
+
if (event.result.continuationMessages) {
|
|
9112
|
+
runHarnessMessages = event.result.continuationMessages;
|
|
9113
|
+
}
|
|
9075
9114
|
if (event.result.continuation) {
|
|
9076
|
-
|
|
9115
|
+
runContinuation2 = true;
|
|
9077
9116
|
if (event.result.continuationMessages) {
|
|
9078
9117
|
runContinuationMessages = event.result.continuationMessages;
|
|
9079
9118
|
}
|
|
@@ -9096,6 +9135,9 @@ ${resultBody}`,
|
|
|
9096
9135
|
metadata: toolTimeline.length > 0 || sections.length > 0 ? { toolActivity: toolTimeline, sections: sections.length > 0 ? sections : void 0 } : void 0
|
|
9097
9136
|
});
|
|
9098
9137
|
}
|
|
9138
|
+
if (runHarnessMessages) {
|
|
9139
|
+
freshConv._harnessMessages = runHarnessMessages;
|
|
9140
|
+
}
|
|
9099
9141
|
freshConv.runtimeRunId = latestRunId || freshConv.runtimeRunId;
|
|
9100
9142
|
freshConv.runningCallbackSince = void 0;
|
|
9101
9143
|
freshConv.runStatus = "idle";
|
|
@@ -9121,7 +9163,7 @@ ${resultBody}`,
|
|
|
9121
9163
|
}
|
|
9122
9164
|
}
|
|
9123
9165
|
}
|
|
9124
|
-
if (
|
|
9166
|
+
if (runContinuation2) {
|
|
9125
9167
|
if (isServerless) {
|
|
9126
9168
|
const work = selfFetchWithRetry(`/api/internal/conversations/${encodeURIComponent(conversationId)}/subagent-callback`).catch(
|
|
9127
9169
|
(err) => console.error(`[poncho][subagent-callback] Continuation self-fetch failed:`, err instanceof Error ? err.message : err)
|
|
@@ -9293,6 +9335,7 @@ ${resultBody}`,
|
|
|
9293
9335
|
let checkpointedRun = false;
|
|
9294
9336
|
let runContextTokens = conversation.contextTokens ?? 0;
|
|
9295
9337
|
let runContextWindow = conversation.contextWindow ?? 0;
|
|
9338
|
+
let resumeHarnessMessages;
|
|
9296
9339
|
const baseMessages = checkpoint.baseMessageCount != null ? conversation.messages.slice(0, checkpoint.baseMessageCount) : [];
|
|
9297
9340
|
const fullCheckpointMessages = [...baseMessages, ...checkpoint.checkpointMessages];
|
|
9298
9341
|
let resumeToolResultMsg;
|
|
@@ -9406,6 +9449,9 @@ ${resultBody}`,
|
|
|
9406
9449
|
}
|
|
9407
9450
|
runContextTokens = event.result.contextTokens ?? runContextTokens;
|
|
9408
9451
|
runContextWindow = event.result.contextWindow ?? runContextWindow;
|
|
9452
|
+
if (event.result.continuationMessages) {
|
|
9453
|
+
resumeHarnessMessages = event.result.continuationMessages;
|
|
9454
|
+
}
|
|
9409
9455
|
}
|
|
9410
9456
|
if (event.type === "run:error") {
|
|
9411
9457
|
assistantResponse = assistantResponse || `[Error: ${event.error.message}]`;
|
|
@@ -9465,6 +9511,9 @@ ${resultBody}`,
|
|
|
9465
9511
|
];
|
|
9466
9512
|
}
|
|
9467
9513
|
}
|
|
9514
|
+
if (resumeHarnessMessages) {
|
|
9515
|
+
conv._harnessMessages = resumeHarnessMessages;
|
|
9516
|
+
}
|
|
9468
9517
|
conv.runtimeRunId = latestRunId || conv.runtimeRunId;
|
|
9469
9518
|
conv.pendingApprovals = [];
|
|
9470
9519
|
conv.runStatus = "idle";
|
|
@@ -9517,7 +9566,7 @@ ${resultBody}`,
|
|
|
9517
9566
|
};
|
|
9518
9567
|
await conversationStore.update(existing);
|
|
9519
9568
|
}
|
|
9520
|
-
return { messages: existing.messages };
|
|
9569
|
+
return { messages: existing._harnessMessages?.length ? existing._harnessMessages : existing.messages };
|
|
9521
9570
|
}
|
|
9522
9571
|
const now = Date.now();
|
|
9523
9572
|
const channelMeta = meta.channelId ? {
|
|
@@ -9566,7 +9615,7 @@ ${resultBody}`,
|
|
|
9566
9615
|
let checkpointedRun = false;
|
|
9567
9616
|
let runContextTokens = 0;
|
|
9568
9617
|
let runContextWindow = 0;
|
|
9569
|
-
let
|
|
9618
|
+
let runContinuation2 = false;
|
|
9570
9619
|
let runContinuationMessages;
|
|
9571
9620
|
let runSteps = 0;
|
|
9572
9621
|
let runMaxSteps;
|
|
@@ -9717,7 +9766,7 @@ ${resultBody}`,
|
|
|
9717
9766
|
if (assistantResponse.length === 0 && event.result.response) {
|
|
9718
9767
|
assistantResponse = event.result.response;
|
|
9719
9768
|
}
|
|
9720
|
-
|
|
9769
|
+
runContinuation2 = event.result.continuation === true;
|
|
9721
9770
|
if (event.result.continuationMessages) {
|
|
9722
9771
|
runContinuationMessages = event.result.continuationMessages;
|
|
9723
9772
|
}
|
|
@@ -9745,12 +9794,15 @@ ${resultBody}`,
|
|
|
9745
9794
|
}
|
|
9746
9795
|
if (!checkpointedRun) {
|
|
9747
9796
|
await updateConversation((c) => {
|
|
9748
|
-
if (runContinuationMessages) {
|
|
9797
|
+
if (runContinuation2 && runContinuationMessages) {
|
|
9749
9798
|
c._continuationMessages = runContinuationMessages;
|
|
9750
9799
|
} else {
|
|
9751
9800
|
c._continuationMessages = void 0;
|
|
9752
9801
|
c.messages = buildMessages();
|
|
9753
9802
|
}
|
|
9803
|
+
if (runContinuationMessages) {
|
|
9804
|
+
c._harnessMessages = runContinuationMessages;
|
|
9805
|
+
}
|
|
9754
9806
|
c.runtimeRunId = latestRunId || c.runtimeRunId;
|
|
9755
9807
|
c.pendingApprovals = [];
|
|
9756
9808
|
c.runStatus = "idle";
|
|
@@ -9767,11 +9819,11 @@ ${resultBody}`,
|
|
|
9767
9819
|
runOwners.delete(latestRunId);
|
|
9768
9820
|
runConversations.delete(latestRunId);
|
|
9769
9821
|
}
|
|
9770
|
-
console.log("[messaging-runner] run complete, response length:", assistantResponse.length,
|
|
9822
|
+
console.log("[messaging-runner] run complete, response length:", assistantResponse.length, runContinuation2 ? "(continuation)" : "");
|
|
9771
9823
|
const response = assistantResponse;
|
|
9772
9824
|
return {
|
|
9773
9825
|
response,
|
|
9774
|
-
continuation:
|
|
9826
|
+
continuation: runContinuation2,
|
|
9775
9827
|
steps: runSteps,
|
|
9776
9828
|
maxSteps: runMaxSteps
|
|
9777
9829
|
};
|
|
@@ -9897,6 +9949,375 @@ ${resultBody}`,
|
|
|
9897
9949
|
const headerValue = getInternalRequestHeader(headers);
|
|
9898
9950
|
return typeof headerValue === "string" && headerValue === internalSecret;
|
|
9899
9951
|
};
|
|
9952
|
+
const MAX_CONTINUATION_COUNT = 20;
|
|
9953
|
+
async function* runContinuation(conversationId) {
|
|
9954
|
+
const conversation = await conversationStore.get(conversationId);
|
|
9955
|
+
if (!conversation) return;
|
|
9956
|
+
if (!conversation._continuationMessages?.length) return;
|
|
9957
|
+
if (conversation.runStatus === "running") return;
|
|
9958
|
+
const count = (conversation._continuationCount ?? 0) + 1;
|
|
9959
|
+
if (count > MAX_CONTINUATION_COUNT) {
|
|
9960
|
+
console.warn(`[poncho][continuation] Max continuation count (${MAX_CONTINUATION_COUNT}) reached for ${conversationId}`);
|
|
9961
|
+
conversation._continuationMessages = void 0;
|
|
9962
|
+
conversation._continuationCount = void 0;
|
|
9963
|
+
await conversationStore.update(conversation);
|
|
9964
|
+
return;
|
|
9965
|
+
}
|
|
9966
|
+
const continuationMessages = [...conversation._continuationMessages];
|
|
9967
|
+
conversation._continuationMessages = void 0;
|
|
9968
|
+
conversation._continuationCount = count;
|
|
9969
|
+
conversation.runStatus = "running";
|
|
9970
|
+
await conversationStore.update(conversation);
|
|
9971
|
+
const abortController = new AbortController();
|
|
9972
|
+
activeConversationRuns.set(conversationId, {
|
|
9973
|
+
ownerId: conversation.ownerId,
|
|
9974
|
+
abortController,
|
|
9975
|
+
runId: null
|
|
9976
|
+
});
|
|
9977
|
+
const prevStream = conversationEventStreams.get(conversationId);
|
|
9978
|
+
if (prevStream) {
|
|
9979
|
+
prevStream.finished = false;
|
|
9980
|
+
prevStream.buffer = [];
|
|
9981
|
+
} else {
|
|
9982
|
+
conversationEventStreams.set(conversationId, {
|
|
9983
|
+
buffer: [],
|
|
9984
|
+
subscribers: /* @__PURE__ */ new Set(),
|
|
9985
|
+
finished: false
|
|
9986
|
+
});
|
|
9987
|
+
}
|
|
9988
|
+
try {
|
|
9989
|
+
if (conversation.parentConversationId) {
|
|
9990
|
+
yield* runSubagentContinuation(conversationId, conversation, continuationMessages);
|
|
9991
|
+
} else {
|
|
9992
|
+
yield* runChatContinuation(conversationId, conversation, continuationMessages);
|
|
9993
|
+
}
|
|
9994
|
+
} finally {
|
|
9995
|
+
activeConversationRuns.delete(conversationId);
|
|
9996
|
+
finishConversationStream(conversationId);
|
|
9997
|
+
}
|
|
9998
|
+
}
|
|
9999
|
+
async function* runChatContinuation(conversationId, conversation, continuationMessages) {
|
|
10000
|
+
let assistantResponse = "";
|
|
10001
|
+
let latestRunId = conversation.runtimeRunId ?? "";
|
|
10002
|
+
const toolTimeline = [];
|
|
10003
|
+
const sections = [];
|
|
10004
|
+
let currentTools = [];
|
|
10005
|
+
let currentText = "";
|
|
10006
|
+
let runContextTokens = conversation.contextTokens ?? 0;
|
|
10007
|
+
let runContextWindow = conversation.contextWindow ?? 0;
|
|
10008
|
+
let nextContinuationMessages;
|
|
10009
|
+
let nextHarnessMessages;
|
|
10010
|
+
for await (const event of harness.runWithTelemetry({
|
|
10011
|
+
conversationId,
|
|
10012
|
+
parameters: {
|
|
10013
|
+
__activeConversationId: conversationId,
|
|
10014
|
+
__ownerId: conversation.ownerId
|
|
10015
|
+
},
|
|
10016
|
+
messages: continuationMessages,
|
|
10017
|
+
abortSignal: activeConversationRuns.get(conversationId)?.abortController.signal
|
|
10018
|
+
})) {
|
|
10019
|
+
if (event.type === "run:started") {
|
|
10020
|
+
latestRunId = event.runId;
|
|
10021
|
+
runOwners.set(event.runId, conversation.ownerId);
|
|
10022
|
+
runConversations.set(event.runId, conversationId);
|
|
10023
|
+
const active = activeConversationRuns.get(conversationId);
|
|
10024
|
+
if (active) active.runId = event.runId;
|
|
10025
|
+
}
|
|
10026
|
+
if (event.type === "model:chunk") {
|
|
10027
|
+
if (currentTools.length > 0) {
|
|
10028
|
+
sections.push({ type: "tools", content: currentTools });
|
|
10029
|
+
currentTools = [];
|
|
10030
|
+
if (assistantResponse.length > 0 && !/\s$/.test(assistantResponse)) {
|
|
10031
|
+
assistantResponse += " ";
|
|
10032
|
+
}
|
|
10033
|
+
}
|
|
10034
|
+
assistantResponse += event.content;
|
|
10035
|
+
currentText += event.content;
|
|
10036
|
+
}
|
|
10037
|
+
if (event.type === "tool:started") {
|
|
10038
|
+
if (currentText.length > 0) {
|
|
10039
|
+
sections.push({ type: "text", content: currentText });
|
|
10040
|
+
currentText = "";
|
|
10041
|
+
}
|
|
10042
|
+
const toolText = `- start \`${event.tool}\``;
|
|
10043
|
+
toolTimeline.push(toolText);
|
|
10044
|
+
currentTools.push(toolText);
|
|
10045
|
+
}
|
|
10046
|
+
if (event.type === "tool:completed") {
|
|
10047
|
+
const toolText = `- done \`${event.tool}\` (${event.duration}ms)`;
|
|
10048
|
+
toolTimeline.push(toolText);
|
|
10049
|
+
currentTools.push(toolText);
|
|
10050
|
+
}
|
|
10051
|
+
if (event.type === "tool:error") {
|
|
10052
|
+
const toolText = `- error \`${event.tool}\`: ${event.error}`;
|
|
10053
|
+
toolTimeline.push(toolText);
|
|
10054
|
+
currentTools.push(toolText);
|
|
10055
|
+
}
|
|
10056
|
+
if (event.type === "run:completed") {
|
|
10057
|
+
runContextTokens = event.result.contextTokens ?? runContextTokens;
|
|
10058
|
+
runContextWindow = event.result.contextWindow ?? runContextWindow;
|
|
10059
|
+
if (event.result.continuation && event.result.continuationMessages) {
|
|
10060
|
+
nextContinuationMessages = event.result.continuationMessages;
|
|
10061
|
+
}
|
|
10062
|
+
if (event.result.continuationMessages) {
|
|
10063
|
+
nextHarnessMessages = event.result.continuationMessages;
|
|
10064
|
+
}
|
|
10065
|
+
if (!assistantResponse && event.result.response) {
|
|
10066
|
+
assistantResponse = event.result.response;
|
|
10067
|
+
}
|
|
10068
|
+
}
|
|
10069
|
+
if (event.type === "run:error") {
|
|
10070
|
+
assistantResponse = assistantResponse || `[Error: ${event.error.message}]`;
|
|
10071
|
+
}
|
|
10072
|
+
await telemetry.emit(event);
|
|
10073
|
+
broadcastEvent(conversationId, event);
|
|
10074
|
+
yield event;
|
|
10075
|
+
}
|
|
10076
|
+
if (currentTools.length > 0) sections.push({ type: "tools", content: currentTools });
|
|
10077
|
+
if (currentText.length > 0) sections.push({ type: "text", content: currentText });
|
|
10078
|
+
const freshConv = await conversationStore.get(conversationId);
|
|
10079
|
+
if (!freshConv) return;
|
|
10080
|
+
const hasContent = assistantResponse.length > 0 || toolTimeline.length > 0;
|
|
10081
|
+
const assistantMetadata = toolTimeline.length > 0 || sections.length > 0 ? {
|
|
10082
|
+
toolActivity: [...toolTimeline],
|
|
10083
|
+
sections: sections.length > 0 ? sections : void 0
|
|
10084
|
+
} : void 0;
|
|
10085
|
+
if (nextContinuationMessages) {
|
|
10086
|
+
if (hasContent) {
|
|
10087
|
+
freshConv.messages = [
|
|
10088
|
+
...freshConv.messages,
|
|
10089
|
+
{ role: "assistant", content: assistantResponse, metadata: assistantMetadata }
|
|
10090
|
+
];
|
|
10091
|
+
}
|
|
10092
|
+
freshConv._continuationMessages = nextContinuationMessages;
|
|
10093
|
+
freshConv._continuationCount = conversation._continuationCount;
|
|
10094
|
+
} else {
|
|
10095
|
+
if (hasContent) {
|
|
10096
|
+
freshConv.messages = [
|
|
10097
|
+
...freshConv.messages,
|
|
10098
|
+
{ role: "assistant", content: assistantResponse, metadata: assistantMetadata }
|
|
10099
|
+
];
|
|
10100
|
+
}
|
|
10101
|
+
freshConv._continuationMessages = void 0;
|
|
10102
|
+
freshConv._continuationCount = void 0;
|
|
10103
|
+
}
|
|
10104
|
+
if (nextHarnessMessages) freshConv._harnessMessages = nextHarnessMessages;
|
|
10105
|
+
freshConv.runtimeRunId = latestRunId || freshConv.runtimeRunId;
|
|
10106
|
+
freshConv.pendingApprovals = [];
|
|
10107
|
+
if (runContextTokens > 0) freshConv.contextTokens = runContextTokens;
|
|
10108
|
+
if (runContextWindow > 0) freshConv.contextWindow = runContextWindow;
|
|
10109
|
+
freshConv.runStatus = "idle";
|
|
10110
|
+
freshConv.updatedAt = Date.now();
|
|
10111
|
+
await conversationStore.update(freshConv);
|
|
10112
|
+
}
|
|
10113
|
+
async function* runSubagentContinuation(conversationId, conversation, continuationMessages) {
|
|
10114
|
+
const parentConversationId = conversation.parentConversationId;
|
|
10115
|
+
const task = conversation.subagentMeta?.task ?? "";
|
|
10116
|
+
const ownerId = conversation.ownerId;
|
|
10117
|
+
const childHarness = new AgentHarness({
|
|
10118
|
+
workingDir,
|
|
10119
|
+
environment: resolveHarnessEnvironment(),
|
|
10120
|
+
uploadStore
|
|
10121
|
+
});
|
|
10122
|
+
await childHarness.initialize();
|
|
10123
|
+
childHarness.unregisterTools(["memory_main_write", "memory_main_edit"]);
|
|
10124
|
+
const childAbortController = activeConversationRuns.get(conversationId)?.abortController ?? new AbortController();
|
|
10125
|
+
activeSubagentRuns.set(conversationId, { abortController: childAbortController, harness: childHarness, parentConversationId });
|
|
10126
|
+
let assistantResponse = "";
|
|
10127
|
+
let latestRunId = "";
|
|
10128
|
+
let runResult;
|
|
10129
|
+
const toolTimeline = [];
|
|
10130
|
+
const sections = [];
|
|
10131
|
+
let currentTools = [];
|
|
10132
|
+
let currentText = "";
|
|
10133
|
+
try {
|
|
10134
|
+
for await (const event of childHarness.runWithTelemetry({
|
|
10135
|
+
conversationId,
|
|
10136
|
+
parameters: {
|
|
10137
|
+
__activeConversationId: conversationId,
|
|
10138
|
+
__ownerId: ownerId
|
|
10139
|
+
},
|
|
10140
|
+
messages: continuationMessages,
|
|
10141
|
+
abortSignal: childAbortController.signal
|
|
10142
|
+
})) {
|
|
10143
|
+
if (event.type === "run:started") {
|
|
10144
|
+
latestRunId = event.runId;
|
|
10145
|
+
const active = activeConversationRuns.get(conversationId);
|
|
10146
|
+
if (active) active.runId = event.runId;
|
|
10147
|
+
}
|
|
10148
|
+
if (event.type === "model:chunk") {
|
|
10149
|
+
if (currentTools.length > 0) {
|
|
10150
|
+
sections.push({ type: "tools", content: currentTools });
|
|
10151
|
+
currentTools = [];
|
|
10152
|
+
if (assistantResponse.length > 0 && !/\s$/.test(assistantResponse)) {
|
|
10153
|
+
assistantResponse += " ";
|
|
10154
|
+
}
|
|
10155
|
+
}
|
|
10156
|
+
assistantResponse += event.content;
|
|
10157
|
+
currentText += event.content;
|
|
10158
|
+
}
|
|
10159
|
+
if (event.type === "tool:started") {
|
|
10160
|
+
if (currentText.length > 0) {
|
|
10161
|
+
sections.push({ type: "text", content: currentText });
|
|
10162
|
+
currentText = "";
|
|
10163
|
+
}
|
|
10164
|
+
const toolText = `- start \`${event.tool}\``;
|
|
10165
|
+
toolTimeline.push(toolText);
|
|
10166
|
+
currentTools.push(toolText);
|
|
10167
|
+
}
|
|
10168
|
+
if (event.type === "tool:completed") {
|
|
10169
|
+
const toolText = `- done \`${event.tool}\` (${event.duration}ms)`;
|
|
10170
|
+
toolTimeline.push(toolText);
|
|
10171
|
+
currentTools.push(toolText);
|
|
10172
|
+
}
|
|
10173
|
+
if (event.type === "tool:error") {
|
|
10174
|
+
const toolText = `- error \`${event.tool}\`: ${event.error}`;
|
|
10175
|
+
toolTimeline.push(toolText);
|
|
10176
|
+
currentTools.push(toolText);
|
|
10177
|
+
}
|
|
10178
|
+
if (event.type === "run:completed") {
|
|
10179
|
+
runResult = {
|
|
10180
|
+
status: event.result.status,
|
|
10181
|
+
response: event.result.response,
|
|
10182
|
+
steps: event.result.steps,
|
|
10183
|
+
duration: event.result.duration,
|
|
10184
|
+
continuation: event.result.continuation,
|
|
10185
|
+
continuationMessages: event.result.continuationMessages
|
|
10186
|
+
};
|
|
10187
|
+
if (!assistantResponse && event.result.response) {
|
|
10188
|
+
assistantResponse = event.result.response;
|
|
10189
|
+
}
|
|
10190
|
+
}
|
|
10191
|
+
if (event.type === "run:error") {
|
|
10192
|
+
assistantResponse = assistantResponse || `[Error: ${event.error.message}]`;
|
|
10193
|
+
}
|
|
10194
|
+
broadcastEvent(conversationId, event);
|
|
10195
|
+
yield event;
|
|
10196
|
+
}
|
|
10197
|
+
if (currentTools.length > 0) sections.push({ type: "tools", content: currentTools });
|
|
10198
|
+
if (currentText.length > 0) sections.push({ type: "text", content: currentText });
|
|
10199
|
+
const conv = await conversationStore.get(conversationId);
|
|
10200
|
+
if (conv) {
|
|
10201
|
+
const hasContent = assistantResponse.length > 0 || toolTimeline.length > 0;
|
|
10202
|
+
if (runResult?.continuation && runResult.continuationMessages) {
|
|
10203
|
+
if (hasContent) {
|
|
10204
|
+
conv.messages.push({
|
|
10205
|
+
role: "assistant",
|
|
10206
|
+
content: assistantResponse,
|
|
10207
|
+
metadata: toolTimeline.length > 0 || sections.length > 0 ? { toolActivity: toolTimeline, sections: sections.length > 0 ? sections : void 0 } : void 0
|
|
10208
|
+
});
|
|
10209
|
+
}
|
|
10210
|
+
conv._continuationMessages = runResult.continuationMessages;
|
|
10211
|
+
conv._continuationCount = conversation._continuationCount;
|
|
10212
|
+
} else {
|
|
10213
|
+
conv._continuationMessages = void 0;
|
|
10214
|
+
conv._continuationCount = void 0;
|
|
10215
|
+
if (hasContent) {
|
|
10216
|
+
conv.messages.push({
|
|
10217
|
+
role: "assistant",
|
|
10218
|
+
content: assistantResponse,
|
|
10219
|
+
metadata: toolTimeline.length > 0 || sections.length > 0 ? { toolActivity: toolTimeline, sections: sections.length > 0 ? sections : void 0 } : void 0
|
|
10220
|
+
});
|
|
10221
|
+
}
|
|
10222
|
+
}
|
|
10223
|
+
if (runResult?.continuationMessages) {
|
|
10224
|
+
conv._harnessMessages = runResult.continuationMessages;
|
|
10225
|
+
}
|
|
10226
|
+
conv.lastActivityAt = Date.now();
|
|
10227
|
+
conv.runStatus = "idle";
|
|
10228
|
+
conv.updatedAt = Date.now();
|
|
10229
|
+
if (runResult?.continuation) {
|
|
10230
|
+
await conversationStore.update(conv);
|
|
10231
|
+
activeSubagentRuns.delete(conversationId);
|
|
10232
|
+
try {
|
|
10233
|
+
await childHarness.shutdown();
|
|
10234
|
+
} catch {
|
|
10235
|
+
}
|
|
10236
|
+
return;
|
|
10237
|
+
}
|
|
10238
|
+
conv.subagentMeta = { ...conv.subagentMeta, status: "completed" };
|
|
10239
|
+
await conversationStore.update(conv);
|
|
10240
|
+
}
|
|
10241
|
+
activeSubagentRuns.delete(conversationId);
|
|
10242
|
+
broadcastEvent(parentConversationId, {
|
|
10243
|
+
type: "subagent:completed",
|
|
10244
|
+
subagentId: conversationId,
|
|
10245
|
+
conversationId
|
|
10246
|
+
});
|
|
10247
|
+
let subagentResponse = runResult?.response ?? assistantResponse;
|
|
10248
|
+
if (!subagentResponse) {
|
|
10249
|
+
const freshSubConv = await conversationStore.get(conversationId);
|
|
10250
|
+
if (freshSubConv) {
|
|
10251
|
+
const lastAssistant = [...freshSubConv.messages].reverse().find((m) => m.role === "assistant");
|
|
10252
|
+
if (lastAssistant) {
|
|
10253
|
+
subagentResponse = typeof lastAssistant.content === "string" ? lastAssistant.content : "";
|
|
10254
|
+
}
|
|
10255
|
+
}
|
|
10256
|
+
}
|
|
10257
|
+
const parentConv = await conversationStore.get(parentConversationId);
|
|
10258
|
+
if (parentConv) {
|
|
10259
|
+
const result = {
|
|
10260
|
+
subagentId: conversationId,
|
|
10261
|
+
task,
|
|
10262
|
+
status: "completed",
|
|
10263
|
+
result: { status: "completed", response: subagentResponse, steps: runResult?.steps ?? 0, tokens: { input: 0, output: 0, cached: 0 }, duration: runResult?.duration ?? 0 },
|
|
10264
|
+
timestamp: Date.now()
|
|
10265
|
+
};
|
|
10266
|
+
await conversationStore.appendSubagentResult(parentConversationId, result);
|
|
10267
|
+
if (isServerless) {
|
|
10268
|
+
selfFetchWithRetry(`/api/internal/conversations/${encodeURIComponent(parentConversationId)}/subagent-callback`).catch(
|
|
10269
|
+
(err) => console.error(`[poncho][subagent] Callback self-fetch failed:`, err instanceof Error ? err.message : err)
|
|
10270
|
+
);
|
|
10271
|
+
} else {
|
|
10272
|
+
processSubagentCallback(parentConversationId).catch(
|
|
10273
|
+
(err) => console.error(`[poncho][subagent] Callback failed:`, err instanceof Error ? err.message : err)
|
|
10274
|
+
);
|
|
10275
|
+
}
|
|
10276
|
+
}
|
|
10277
|
+
try {
|
|
10278
|
+
await childHarness.shutdown();
|
|
10279
|
+
} catch {
|
|
10280
|
+
}
|
|
10281
|
+
} catch (err) {
|
|
10282
|
+
activeSubagentRuns.delete(conversationId);
|
|
10283
|
+
try {
|
|
10284
|
+
await childHarness.shutdown();
|
|
10285
|
+
} catch {
|
|
10286
|
+
}
|
|
10287
|
+
const conv = await conversationStore.get(conversationId);
|
|
10288
|
+
if (conv) {
|
|
10289
|
+
conv.subagentMeta = { ...conv.subagentMeta, status: "error", error: { code: "CONTINUATION_ERROR", message: err instanceof Error ? err.message : String(err) } };
|
|
10290
|
+
conv.runStatus = "idle";
|
|
10291
|
+
conv._continuationMessages = void 0;
|
|
10292
|
+
conv._continuationCount = void 0;
|
|
10293
|
+
conv.updatedAt = Date.now();
|
|
10294
|
+
await conversationStore.update(conv);
|
|
10295
|
+
}
|
|
10296
|
+
broadcastEvent(conversation.parentConversationId, {
|
|
10297
|
+
type: "subagent:completed",
|
|
10298
|
+
subagentId: conversationId,
|
|
10299
|
+
conversationId
|
|
10300
|
+
});
|
|
10301
|
+
const parentConv = await conversationStore.get(conversation.parentConversationId);
|
|
10302
|
+
if (parentConv) {
|
|
10303
|
+
const result = {
|
|
10304
|
+
subagentId: conversationId,
|
|
10305
|
+
task,
|
|
10306
|
+
status: "error",
|
|
10307
|
+
error: { code: "CONTINUATION_ERROR", message: err instanceof Error ? err.message : String(err) },
|
|
10308
|
+
timestamp: Date.now()
|
|
10309
|
+
};
|
|
10310
|
+
await conversationStore.appendSubagentResult(conversation.parentConversationId, result);
|
|
10311
|
+
if (isServerless) {
|
|
10312
|
+
selfFetchWithRetry(`/api/internal/conversations/${encodeURIComponent(conversation.parentConversationId)}/subagent-callback`).catch(() => {
|
|
10313
|
+
});
|
|
10314
|
+
} else {
|
|
10315
|
+
processSubagentCallback(conversation.parentConversationId).catch(() => {
|
|
10316
|
+
});
|
|
10317
|
+
}
|
|
10318
|
+
}
|
|
10319
|
+
}
|
|
10320
|
+
}
|
|
9900
10321
|
const messagingAdapters = /* @__PURE__ */ new Map();
|
|
9901
10322
|
const messagingBridges = [];
|
|
9902
10323
|
if (config?.messaging && config.messaging.length > 0) {
|
|
@@ -10230,9 +10651,8 @@ ${resultBody}`,
|
|
|
10230
10651
|
await resumeSubagentFromCheckpoint(subagentId);
|
|
10231
10652
|
return;
|
|
10232
10653
|
}
|
|
10233
|
-
const
|
|
10234
|
-
|
|
10235
|
-
await runSubagent(subagentId, conv.parentConversationId, task, conv.ownerId, isContinuation);
|
|
10654
|
+
const task = conv.messages.find((m) => m.role === "user")?.content ?? conv.subagentMeta?.task ?? "";
|
|
10655
|
+
await runSubagent(subagentId, conv.parentConversationId, task, conv.ownerId, false);
|
|
10236
10656
|
} catch (err) {
|
|
10237
10657
|
console.error(`[poncho][internal] subagent run error for ${subagentId}:`, err instanceof Error ? err.message : err);
|
|
10238
10658
|
}
|
|
@@ -10250,6 +10670,26 @@ ${resultBody}`,
|
|
|
10250
10670
|
if (!waitUntilHook) await work;
|
|
10251
10671
|
return;
|
|
10252
10672
|
}
|
|
10673
|
+
const continueMatch = pathname.match(/^\/api\/internal\/continue\/([^/]+)$/);
|
|
10674
|
+
if (continueMatch) {
|
|
10675
|
+
const conversationId = decodeURIComponent(continueMatch[1]);
|
|
10676
|
+
writeJson(response, 202, { ok: true });
|
|
10677
|
+
const work = (async () => {
|
|
10678
|
+
try {
|
|
10679
|
+
for await (const _event of runContinuation(conversationId)) {
|
|
10680
|
+
}
|
|
10681
|
+
const conv = await conversationStore.get(conversationId);
|
|
10682
|
+
if (conv?._continuationMessages?.length) {
|
|
10683
|
+
await selfFetchWithRetry(`/api/internal/continue/${encodeURIComponent(conversationId)}`);
|
|
10684
|
+
}
|
|
10685
|
+
} catch (err) {
|
|
10686
|
+
console.error(`[poncho][internal-continue] Error for ${conversationId}:`, err instanceof Error ? err.message : err);
|
|
10687
|
+
}
|
|
10688
|
+
})();
|
|
10689
|
+
doWaitUntil(work);
|
|
10690
|
+
if (!waitUntilHook) await work;
|
|
10691
|
+
return;
|
|
10692
|
+
}
|
|
10253
10693
|
writeJson(response, 404, { error: "Not found" });
|
|
10254
10694
|
return;
|
|
10255
10695
|
}
|
|
@@ -10856,7 +11296,8 @@ data: ${JSON.stringify(frame)}
|
|
|
10856
11296
|
conversation: {
|
|
10857
11297
|
...conversation,
|
|
10858
11298
|
pendingApprovals: storedPending,
|
|
10859
|
-
_continuationMessages: void 0
|
|
11299
|
+
_continuationMessages: void 0,
|
|
11300
|
+
_harnessMessages: void 0
|
|
10860
11301
|
},
|
|
10861
11302
|
subagentPendingApprovals: subagentPending,
|
|
10862
11303
|
hasActiveRun: hasActiveRun || hasPendingCallbackResults,
|
|
@@ -11025,6 +11466,87 @@ data: ${JSON.stringify(frame)}
|
|
|
11025
11466
|
});
|
|
11026
11467
|
return;
|
|
11027
11468
|
}
|
|
11469
|
+
const conversationContinueMatch = pathname.match(/^\/api\/conversations\/([^/]+)\/continue$/);
|
|
11470
|
+
if (conversationContinueMatch && request.method === "POST") {
|
|
11471
|
+
const conversationId = decodeURIComponent(conversationContinueMatch[1] ?? "");
|
|
11472
|
+
const conversation = await conversationStore.get(conversationId);
|
|
11473
|
+
if (!conversation || conversation.ownerId !== ownerId) {
|
|
11474
|
+
writeJson(response, 404, {
|
|
11475
|
+
code: "CONVERSATION_NOT_FOUND",
|
|
11476
|
+
message: "Conversation not found"
|
|
11477
|
+
});
|
|
11478
|
+
return;
|
|
11479
|
+
}
|
|
11480
|
+
if (conversation.parentConversationId) {
|
|
11481
|
+
writeJson(response, 403, {
|
|
11482
|
+
code: "SUBAGENT_READ_ONLY",
|
|
11483
|
+
message: "Subagent conversations are read-only."
|
|
11484
|
+
});
|
|
11485
|
+
return;
|
|
11486
|
+
}
|
|
11487
|
+
response.writeHead(200, {
|
|
11488
|
+
"Content-Type": "text/event-stream",
|
|
11489
|
+
"Cache-Control": "no-cache",
|
|
11490
|
+
Connection: "keep-alive",
|
|
11491
|
+
"X-Accel-Buffering": "no"
|
|
11492
|
+
});
|
|
11493
|
+
const unsubSubagentEvents = onConversationEvent(conversationId, (evt) => {
|
|
11494
|
+
if (evt.type.startsWith("subagent:")) {
|
|
11495
|
+
try {
|
|
11496
|
+
response.write(formatSseEvent(evt));
|
|
11497
|
+
} catch {
|
|
11498
|
+
}
|
|
11499
|
+
}
|
|
11500
|
+
});
|
|
11501
|
+
let eventCount = 0;
|
|
11502
|
+
try {
|
|
11503
|
+
for await (const event of runContinuation(conversationId)) {
|
|
11504
|
+
eventCount++;
|
|
11505
|
+
let sseEvent = event;
|
|
11506
|
+
if (sseEvent.type === "run:completed") {
|
|
11507
|
+
const hasRunningSubagents = Array.from(activeSubagentRuns.values()).some(
|
|
11508
|
+
(r) => r.parentConversationId === conversationId
|
|
11509
|
+
);
|
|
11510
|
+
const stripped = { ...sseEvent, result: { ...sseEvent.result, continuationMessages: void 0 } };
|
|
11511
|
+
sseEvent = hasRunningSubagents ? { ...stripped, pendingSubagents: true } : stripped;
|
|
11512
|
+
}
|
|
11513
|
+
try {
|
|
11514
|
+
response.write(formatSseEvent(sseEvent));
|
|
11515
|
+
} catch {
|
|
11516
|
+
}
|
|
11517
|
+
emitBrowserStatusIfActive(conversationId, event, response);
|
|
11518
|
+
}
|
|
11519
|
+
} catch (err) {
|
|
11520
|
+
const errorEvent = {
|
|
11521
|
+
type: "run:error",
|
|
11522
|
+
runId: "",
|
|
11523
|
+
error: { code: "CONTINUATION_ERROR", message: err instanceof Error ? err.message : String(err) }
|
|
11524
|
+
};
|
|
11525
|
+
try {
|
|
11526
|
+
response.write(formatSseEvent(errorEvent));
|
|
11527
|
+
} catch {
|
|
11528
|
+
}
|
|
11529
|
+
} finally {
|
|
11530
|
+
unsubSubagentEvents();
|
|
11531
|
+
}
|
|
11532
|
+
if (eventCount === 0) {
|
|
11533
|
+
try {
|
|
11534
|
+
response.write("event: stream:end\ndata: {}\n\n");
|
|
11535
|
+
} catch {
|
|
11536
|
+
}
|
|
11537
|
+
} else {
|
|
11538
|
+
const freshConv = await conversationStore.get(conversationId);
|
|
11539
|
+
if (freshConv?._continuationMessages?.length) {
|
|
11540
|
+
doWaitUntil(
|
|
11541
|
+
new Promise((r) => setTimeout(r, 3e3)).then(
|
|
11542
|
+
() => selfFetchWithRetry(`/api/internal/continue/${encodeURIComponent(conversationId)}`)
|
|
11543
|
+
)
|
|
11544
|
+
);
|
|
11545
|
+
}
|
|
11546
|
+
}
|
|
11547
|
+
response.end();
|
|
11548
|
+
return;
|
|
11549
|
+
}
|
|
11028
11550
|
const conversationMessageMatch = pathname.match(/^\/api\/conversations\/([^/]+)\/messages$/);
|
|
11029
11551
|
if (conversationMessageMatch && request.method === "POST") {
|
|
11030
11552
|
const conversationId = decodeURIComponent(conversationMessageMatch[1] ?? "");
|
|
@@ -11046,7 +11568,6 @@ data: ${JSON.stringify(frame)}
|
|
|
11046
11568
|
let messageText = "";
|
|
11047
11569
|
let bodyParameters;
|
|
11048
11570
|
let files = [];
|
|
11049
|
-
let isContinuation = false;
|
|
11050
11571
|
const contentType = request.headers["content-type"] ?? "";
|
|
11051
11572
|
if (contentType.includes("multipart/form-data")) {
|
|
11052
11573
|
const parsed = await parseMultipartRequest(request);
|
|
@@ -11055,11 +11576,7 @@ data: ${JSON.stringify(frame)}
|
|
|
11055
11576
|
files = parsed.files;
|
|
11056
11577
|
} else {
|
|
11057
11578
|
const body = await readRequestBody(request);
|
|
11058
|
-
|
|
11059
|
-
isContinuation = true;
|
|
11060
|
-
} else {
|
|
11061
|
-
messageText = body.message?.trim() ?? "";
|
|
11062
|
-
}
|
|
11579
|
+
messageText = body.message?.trim() ?? "";
|
|
11063
11580
|
bodyParameters = body.parameters;
|
|
11064
11581
|
if (Array.isArray(body.files)) {
|
|
11065
11582
|
files = body.files.filter(
|
|
@@ -11067,7 +11584,7 @@ data: ${JSON.stringify(frame)}
|
|
|
11067
11584
|
);
|
|
11068
11585
|
}
|
|
11069
11586
|
}
|
|
11070
|
-
if (!
|
|
11587
|
+
if (!messageText) {
|
|
11071
11588
|
writeJson(response, 400, {
|
|
11072
11589
|
code: "VALIDATION_ERROR",
|
|
11073
11590
|
message: "message is required"
|
|
@@ -11092,7 +11609,7 @@ data: ${JSON.stringify(frame)}
|
|
|
11092
11609
|
abortController,
|
|
11093
11610
|
runId: null
|
|
11094
11611
|
});
|
|
11095
|
-
if (
|
|
11612
|
+
if (conversation.messages.length === 0 && (conversation.title === "New conversation" || conversation.title.trim().length === 0)) {
|
|
11096
11613
|
conversation.title = inferConversationTitle(messageText);
|
|
11097
11614
|
}
|
|
11098
11615
|
response.writeHead(200, {
|
|
@@ -11101,7 +11618,7 @@ data: ${JSON.stringify(frame)}
|
|
|
11101
11618
|
Connection: "keep-alive",
|
|
11102
11619
|
"X-Accel-Buffering": "no"
|
|
11103
11620
|
});
|
|
11104
|
-
const harnessMessages =
|
|
11621
|
+
const harnessMessages = conversation._harnessMessages?.length ? [...conversation._harnessMessages] : [...conversation.messages];
|
|
11105
11622
|
const historyMessages = [...conversation.messages];
|
|
11106
11623
|
const preRunMessages = [...conversation.messages];
|
|
11107
11624
|
let latestRunId = conversation.runtimeRunId ?? "";
|
|
@@ -11116,8 +11633,9 @@ data: ${JSON.stringify(frame)}
|
|
|
11116
11633
|
let runContextTokens = conversation.contextTokens ?? 0;
|
|
11117
11634
|
let runContextWindow = conversation.contextWindow ?? 0;
|
|
11118
11635
|
let runContinuationMessages;
|
|
11119
|
-
let
|
|
11120
|
-
|
|
11636
|
+
let runHarnessMessages;
|
|
11637
|
+
let userContent = messageText;
|
|
11638
|
+
if (files.length > 0) {
|
|
11121
11639
|
try {
|
|
11122
11640
|
const uploadedParts = await Promise.all(
|
|
11123
11641
|
files.map(async (f) => {
|
|
@@ -11160,9 +11678,10 @@ data: ${JSON.stringify(frame)}
|
|
|
11160
11678
|
}
|
|
11161
11679
|
});
|
|
11162
11680
|
try {
|
|
11163
|
-
|
|
11681
|
+
{
|
|
11164
11682
|
conversation.messages = [...historyMessages, { role: "user", content: userContent }];
|
|
11165
11683
|
conversation.subagentCallbackCount = 0;
|
|
11684
|
+
conversation._continuationCount = void 0;
|
|
11166
11685
|
conversation.updatedAt = Date.now();
|
|
11167
11686
|
conversationStore.update(conversation).catch((err) => {
|
|
11168
11687
|
console.error("[poncho] Failed to persist user turn:", err);
|
|
@@ -11221,7 +11740,7 @@ data: ${JSON.stringify(frame)}
|
|
|
11221
11740
|
return cachedRecallCorpus;
|
|
11222
11741
|
};
|
|
11223
11742
|
for await (const event of harness.runWithTelemetry({
|
|
11224
|
-
task:
|
|
11743
|
+
task: messageText,
|
|
11225
11744
|
conversationId,
|
|
11226
11745
|
parameters: {
|
|
11227
11746
|
...bodyParameters ?? {},
|
|
@@ -11230,7 +11749,7 @@ data: ${JSON.stringify(frame)}
|
|
|
11230
11749
|
__ownerId: ownerId
|
|
11231
11750
|
},
|
|
11232
11751
|
messages: harnessMessages,
|
|
11233
|
-
files:
|
|
11752
|
+
files: files.length > 0 ? files : void 0,
|
|
11234
11753
|
abortSignal: abortController.signal
|
|
11235
11754
|
})) {
|
|
11236
11755
|
if (event.type === "run:started") {
|
|
@@ -11335,15 +11854,34 @@ data: ${JSON.stringify(frame)}
|
|
|
11335
11854
|
}
|
|
11336
11855
|
runContextTokens = event.result.contextTokens ?? runContextTokens;
|
|
11337
11856
|
runContextWindow = event.result.contextWindow ?? runContextWindow;
|
|
11857
|
+
if (event.result.continuationMessages) {
|
|
11858
|
+
runHarnessMessages = event.result.continuationMessages;
|
|
11859
|
+
}
|
|
11338
11860
|
if (event.result.continuation && event.result.continuationMessages) {
|
|
11339
11861
|
runContinuationMessages = event.result.continuationMessages;
|
|
11862
|
+
const intSections = [...sections];
|
|
11863
|
+
if (currentTools.length > 0) intSections.push({ type: "tools", content: [...currentTools] });
|
|
11864
|
+
if (currentText.length > 0) intSections.push({ type: "text", content: currentText });
|
|
11865
|
+
const hasContent = assistantResponse.length > 0 || toolTimeline.length > 0 || intSections.length > 0;
|
|
11866
|
+
const intMetadata = toolTimeline.length > 0 || intSections.length > 0 ? { toolActivity: [...toolTimeline], sections: intSections.length > 0 ? intSections : void 0 } : void 0;
|
|
11867
|
+
conversation.messages = [
|
|
11868
|
+
...historyMessages,
|
|
11869
|
+
...userContent != null ? [{ role: "user", content: userContent }] : [],
|
|
11870
|
+
...hasContent ? [{ role: "assistant", content: assistantResponse, metadata: intMetadata }] : []
|
|
11871
|
+
];
|
|
11340
11872
|
conversation._continuationMessages = runContinuationMessages;
|
|
11873
|
+
conversation._harnessMessages = runContinuationMessages;
|
|
11341
11874
|
conversation.runtimeRunId = latestRunId || conversation.runtimeRunId;
|
|
11342
11875
|
conversation.pendingApprovals = [];
|
|
11343
11876
|
if (runContextTokens > 0) conversation.contextTokens = runContextTokens;
|
|
11344
11877
|
if (runContextWindow > 0) conversation.contextWindow = runContextWindow;
|
|
11345
11878
|
conversation.updatedAt = Date.now();
|
|
11346
11879
|
await conversationStore.update(conversation);
|
|
11880
|
+
doWaitUntil(
|
|
11881
|
+
new Promise((r) => setTimeout(r, 3e3)).then(
|
|
11882
|
+
() => selfFetchWithRetry(`/api/internal/continue/${encodeURIComponent(conversationId)}`)
|
|
11883
|
+
)
|
|
11884
|
+
);
|
|
11347
11885
|
}
|
|
11348
11886
|
}
|
|
11349
11887
|
await telemetry.emit(event);
|
|
@@ -11388,6 +11926,9 @@ data: ${JSON.stringify(frame)}
|
|
|
11388
11926
|
}
|
|
11389
11927
|
] : [...historyMessages, ...userTurn];
|
|
11390
11928
|
conversation._continuationMessages = void 0;
|
|
11929
|
+
if (runHarnessMessages) {
|
|
11930
|
+
conversation._harnessMessages = runHarnessMessages;
|
|
11931
|
+
}
|
|
11391
11932
|
conversation.runtimeRunId = latestRunId || conversation.runtimeRunId;
|
|
11392
11933
|
conversation.pendingApprovals = [];
|
|
11393
11934
|
if (runContextTokens > 0) conversation.contextTokens = runContextTokens;
|
|
@@ -11496,20 +12037,9 @@ data: ${JSON.stringify(frame)}
|
|
|
11496
12037
|
return;
|
|
11497
12038
|
}
|
|
11498
12039
|
const urlObj = new URL(request.url ?? "/", `http://${request.headers.host ?? "localhost"}`);
|
|
11499
|
-
const continueConversationId = urlObj.searchParams.get("continue");
|
|
11500
|
-
const continuationCount = Number(urlObj.searchParams.get("continuation") ?? "0");
|
|
11501
|
-
const maxContinuations = 5;
|
|
11502
|
-
if (continuationCount >= maxContinuations) {
|
|
11503
|
-
writeJson(response, 200, {
|
|
11504
|
-
conversationId: continueConversationId,
|
|
11505
|
-
status: "max_continuations_reached",
|
|
11506
|
-
continuations: continuationCount
|
|
11507
|
-
});
|
|
11508
|
-
return;
|
|
11509
|
-
}
|
|
11510
12040
|
const cronOwnerId = ownerId;
|
|
11511
12041
|
const start = Date.now();
|
|
11512
|
-
if (cronJob.channel
|
|
12042
|
+
if (cronJob.channel) {
|
|
11513
12043
|
const adapter = messagingAdapters.get(cronJob.channel);
|
|
11514
12044
|
if (!adapter) {
|
|
11515
12045
|
writeJson(response, 200, {
|
|
@@ -11544,10 +12074,11 @@ data: ${JSON.stringify(frame)}
|
|
|
11544
12074
|
if (!conv) continue;
|
|
11545
12075
|
const task = `[Scheduled: ${jobName}]
|
|
11546
12076
|
${cronJob.task}`;
|
|
11547
|
-
const historyMessages = [...conv.messages];
|
|
12077
|
+
const historyMessages = conv._harnessMessages?.length ? [...conv._harnessMessages] : [...conv.messages];
|
|
11548
12078
|
try {
|
|
11549
12079
|
let assistantResponse = "";
|
|
11550
12080
|
let steps = 0;
|
|
12081
|
+
let cronHarnessMessages;
|
|
11551
12082
|
for await (const event of harness.runWithTelemetry({
|
|
11552
12083
|
task,
|
|
11553
12084
|
conversationId: conv.conversationId,
|
|
@@ -11562,6 +12093,9 @@ ${cronJob.task}`;
|
|
|
11562
12093
|
if (!assistantResponse && event.result.response) {
|
|
11563
12094
|
assistantResponse = event.result.response;
|
|
11564
12095
|
}
|
|
12096
|
+
if (event.result.continuationMessages) {
|
|
12097
|
+
cronHarnessMessages = event.result.continuationMessages;
|
|
12098
|
+
}
|
|
11565
12099
|
}
|
|
11566
12100
|
await telemetry.emit(event);
|
|
11567
12101
|
}
|
|
@@ -11570,6 +12104,9 @@ ${cronJob.task}`;
|
|
|
11570
12104
|
{ role: "user", content: task },
|
|
11571
12105
|
...assistantResponse ? [{ role: "assistant", content: assistantResponse }] : []
|
|
11572
12106
|
];
|
|
12107
|
+
if (cronHarnessMessages) {
|
|
12108
|
+
conv._harnessMessages = cronHarnessMessages;
|
|
12109
|
+
}
|
|
11573
12110
|
conv.updatedAt = Date.now();
|
|
11574
12111
|
await conversationStore.update(conv);
|
|
11575
12112
|
if (assistantResponse) {
|
|
@@ -11606,29 +12143,12 @@ ${cronJob.task}`;
|
|
|
11606
12143
|
return;
|
|
11607
12144
|
}
|
|
11608
12145
|
try {
|
|
11609
|
-
|
|
11610
|
-
|
|
11611
|
-
|
|
11612
|
-
|
|
11613
|
-
|
|
11614
|
-
|
|
11615
|
-
code: "CONVERSATION_NOT_FOUND",
|
|
11616
|
-
message: "Continuation conversation not found"
|
|
11617
|
-
});
|
|
11618
|
-
return;
|
|
11619
|
-
}
|
|
11620
|
-
historyMessages = conversation._continuationMessages?.length ? [...conversation._continuationMessages] : [...conversation.messages];
|
|
11621
|
-
if (conversation._continuationMessages?.length) {
|
|
11622
|
-
conversation._continuationMessages = void 0;
|
|
11623
|
-
await conversationStore.update(conversation);
|
|
11624
|
-
}
|
|
11625
|
-
} else {
|
|
11626
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
11627
|
-
conversation = await conversationStore.create(
|
|
11628
|
-
cronOwnerId,
|
|
11629
|
-
`[cron] ${jobName} ${timestamp}`
|
|
11630
|
-
);
|
|
11631
|
-
}
|
|
12146
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
12147
|
+
const conversation = await conversationStore.create(
|
|
12148
|
+
cronOwnerId,
|
|
12149
|
+
`[cron] ${jobName} ${timestamp}`
|
|
12150
|
+
);
|
|
12151
|
+
const historyMessages = [];
|
|
11632
12152
|
const convId = conversation.conversationId;
|
|
11633
12153
|
activeConversationRuns.set(convId, {
|
|
11634
12154
|
ownerId: conversation.ownerId,
|
|
@@ -11696,7 +12216,8 @@ ${cronJob.task}`;
|
|
|
11696
12216
|
steps: event.result.steps,
|
|
11697
12217
|
continuation: event.result.continuation,
|
|
11698
12218
|
contextTokens: event.result.contextTokens,
|
|
11699
|
-
contextWindow: event.result.contextWindow
|
|
12219
|
+
contextWindow: event.result.contextWindow,
|
|
12220
|
+
harnessMessages: event.result.continuationMessages
|
|
11700
12221
|
};
|
|
11701
12222
|
if (event.result.continuation && event.result.continuationMessages) {
|
|
11702
12223
|
runContinuationMessages = event.result.continuationMessages;
|
|
@@ -11723,16 +12244,20 @@ ${cronJob.task}`;
|
|
|
11723
12244
|
} : void 0;
|
|
11724
12245
|
const messages = [
|
|
11725
12246
|
...historyMessages,
|
|
11726
|
-
|
|
12247
|
+
{ role: "user", content: cronJob.task },
|
|
11727
12248
|
...hasContent ? [{ role: "assistant", content: assistantResponse, metadata: assistantMetadata }] : []
|
|
11728
12249
|
];
|
|
11729
12250
|
const freshConv = await conversationStore.get(convId);
|
|
11730
12251
|
if (freshConv) {
|
|
12252
|
+
freshConv.messages = messages;
|
|
11731
12253
|
if (runContinuationMessages) {
|
|
11732
12254
|
freshConv._continuationMessages = runContinuationMessages;
|
|
11733
12255
|
} else {
|
|
11734
12256
|
freshConv._continuationMessages = void 0;
|
|
11735
|
-
freshConv.
|
|
12257
|
+
freshConv._continuationCount = void 0;
|
|
12258
|
+
}
|
|
12259
|
+
if (runResult.harnessMessages) {
|
|
12260
|
+
freshConv._harnessMessages = runResult.harnessMessages;
|
|
11736
12261
|
}
|
|
11737
12262
|
freshConv.runtimeRunId = latestRunId || freshConv.runtimeRunId;
|
|
11738
12263
|
if (runResult.contextTokens) freshConv.contextTokens = runResult.contextTokens;
|
|
@@ -11741,15 +12266,13 @@ ${cronJob.task}`;
|
|
|
11741
12266
|
await conversationStore.update(freshConv);
|
|
11742
12267
|
}
|
|
11743
12268
|
if (runResult.continuation) {
|
|
11744
|
-
const
|
|
11745
|
-
const work = selfFetchWithRetry(continuationPath).catch(
|
|
12269
|
+
const work = selfFetchWithRetry(`/api/internal/continue/${encodeURIComponent(convId)}`).catch(
|
|
11746
12270
|
(err) => console.error(`[poncho][cron] Continuation self-fetch failed:`, err instanceof Error ? err.message : err)
|
|
11747
12271
|
);
|
|
11748
12272
|
doWaitUntil(work);
|
|
11749
12273
|
writeJson(response, 200, {
|
|
11750
12274
|
conversationId: convId,
|
|
11751
12275
|
status: "continued",
|
|
11752
|
-
continuations: continuationCount + 1,
|
|
11753
12276
|
duration: Date.now() - start
|
|
11754
12277
|
});
|
|
11755
12278
|
return;
|
|
@@ -11851,6 +12374,7 @@ var startDevServer = async (port, options) => {
|
|
|
11851
12374
|
let steps = 0;
|
|
11852
12375
|
let contextTokens = 0;
|
|
11853
12376
|
let contextWindow = 0;
|
|
12377
|
+
let harnessMessages;
|
|
11854
12378
|
const toolTimeline = [];
|
|
11855
12379
|
const sections = [];
|
|
11856
12380
|
let currentTools = [];
|
|
@@ -11896,6 +12420,9 @@ var startDevServer = async (port, options) => {
|
|
|
11896
12420
|
steps = event.result.steps;
|
|
11897
12421
|
contextTokens = event.result.contextTokens ?? 0;
|
|
11898
12422
|
contextWindow = event.result.contextWindow ?? 0;
|
|
12423
|
+
if (event.result.continuationMessages) {
|
|
12424
|
+
harnessMessages = event.result.continuationMessages;
|
|
12425
|
+
}
|
|
11899
12426
|
if (!assistantResponse && event.result.response) {
|
|
11900
12427
|
assistantResponse = event.result.response;
|
|
11901
12428
|
}
|
|
@@ -11912,7 +12439,7 @@ var startDevServer = async (port, options) => {
|
|
|
11912
12439
|
toolActivity: [...toolTimeline],
|
|
11913
12440
|
sections: sections.length > 0 ? sections : void 0
|
|
11914
12441
|
} : void 0;
|
|
11915
|
-
return { response: assistantResponse, steps, assistantMetadata, hasContent, contextTokens, contextWindow };
|
|
12442
|
+
return { response: assistantResponse, steps, assistantMetadata, hasContent, contextTokens, contextWindow, harnessMessages };
|
|
11916
12443
|
};
|
|
11917
12444
|
const buildCronMessages = (task, historyMessages, result) => [
|
|
11918
12445
|
...historyMessages,
|
|
@@ -11971,7 +12498,7 @@ var startDevServer = async (port, options) => {
|
|
|
11971
12498
|
if (!conversation) continue;
|
|
11972
12499
|
const task = `[Scheduled: ${jobName}]
|
|
11973
12500
|
${config.task}`;
|
|
11974
|
-
const historyMessages = [...conversation.messages];
|
|
12501
|
+
const historyMessages = conversation._harnessMessages?.length ? [...conversation._harnessMessages] : [...conversation.messages];
|
|
11975
12502
|
const convId = conversation.conversationId;
|
|
11976
12503
|
activeRuns?.set(convId, {
|
|
11977
12504
|
ownerId: "local-owner",
|
|
@@ -11991,6 +12518,9 @@ ${config.task}`;
|
|
|
11991
12518
|
const freshConv = await store.get(convId);
|
|
11992
12519
|
if (freshConv) {
|
|
11993
12520
|
freshConv.messages = buildCronMessages(task, historyMessages, result);
|
|
12521
|
+
if (result.harnessMessages) {
|
|
12522
|
+
freshConv._harnessMessages = result.harnessMessages;
|
|
12523
|
+
}
|
|
11994
12524
|
if (result.contextTokens > 0) freshConv.contextTokens = result.contextTokens;
|
|
11995
12525
|
if (result.contextWindow > 0) freshConv.contextWindow = result.contextWindow;
|
|
11996
12526
|
freshConv.updatedAt = Date.now();
|
|
@@ -12062,6 +12592,9 @@ ${config.task}`;
|
|
|
12062
12592
|
const freshConv = await store.get(cronConvId);
|
|
12063
12593
|
if (freshConv) {
|
|
12064
12594
|
freshConv.messages = buildCronMessages(config.task, [], result);
|
|
12595
|
+
if (result.harnessMessages) {
|
|
12596
|
+
freshConv._harnessMessages = result.harnessMessages;
|
|
12597
|
+
}
|
|
12065
12598
|
if (result.contextTokens > 0) freshConv.contextTokens = result.contextTokens;
|
|
12066
12599
|
if (result.contextWindow > 0) freshConv.contextWindow = result.contextWindow;
|
|
12067
12600
|
freshConv.updatedAt = Date.now();
|
|
@@ -12197,7 +12730,7 @@ var runInteractive = async (workingDir, params) => {
|
|
|
12197
12730
|
await harness.initialize();
|
|
12198
12731
|
const identity = await ensureAgentIdentity2(workingDir);
|
|
12199
12732
|
try {
|
|
12200
|
-
const { runInteractiveInk } = await import("./run-interactive-ink-
|
|
12733
|
+
const { runInteractiveInk } = await import("./run-interactive-ink-OKE5AV3N.js");
|
|
12201
12734
|
await runInteractiveInk({
|
|
12202
12735
|
harness,
|
|
12203
12736
|
params,
|