@poncho-ai/cli 0.33.1 → 0.33.2

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.
@@ -7175,12 +7175,8 @@ var collectEnvFileLines = (answers) => {
7175
7175
  }
7176
7176
  const telemetryEnabled = Boolean(answers["telemetry.enabled"] ?? true);
7177
7177
  if (telemetryEnabled) {
7178
- lines.push("# Telemetry (optional)");
7179
- lines.push("# Latitude telemetry setup: https://docs.latitude.so/");
7180
- lines.push("# If not using Latitude yet, you can leave these empty.");
7181
- lines.push("LATITUDE_API_KEY=");
7182
- lines.push("LATITUDE_PROJECT_ID=");
7183
- lines.push("LATITUDE_PATH=");
7178
+ lines.push("# Telemetry (optional) \u2014 set an OTLP endpoint to export traces");
7179
+ lines.push("# OTEL_EXPORTER_OTLP_ENDPOINT=");
7184
7180
  lines.push("");
7185
7181
  }
7186
7182
  while (lines.length > 0 && lines[lines.length - 1] === "") {
@@ -7599,14 +7595,17 @@ var parseParams = (values) => {
7599
7595
  return params;
7600
7596
  };
7601
7597
  var normalizeMessageForClient = (message) => {
7598
+ if (message.role === "tool" || message.role === "system") {
7599
+ return null;
7600
+ }
7602
7601
  if (message.role !== "assistant" || typeof message.content !== "string") {
7603
7602
  return message;
7604
7603
  }
7605
7604
  try {
7606
7605
  const parsed = JSON.parse(message.content);
7607
- const text = typeof parsed.text === "string" ? parsed.text : void 0;
7608
7606
  const toolCalls = Array.isArray(parsed.tool_calls) ? parsed.tool_calls : void 0;
7609
- if (typeof text === "string" && toolCalls) {
7607
+ if (toolCalls) {
7608
+ const text = typeof parsed.text === "string" ? parsed.text : "";
7610
7609
  const meta = { ...message.metadata ?? {} };
7611
7610
  if (!meta.sections && toolCalls.length > 0) {
7612
7611
  const toolLabels = toolCalls.map((tc) => {
@@ -7724,6 +7723,7 @@ var buildAssistantMetadata = (draft, sectionsOverride) => {
7724
7723
  var executeConversationTurn = async ({
7725
7724
  harness,
7726
7725
  runInput,
7726
+ events,
7727
7727
  initialContextTokens = 0,
7728
7728
  initialContextWindow = 0,
7729
7729
  onEvent
@@ -7738,7 +7738,8 @@ var executeConversationTurn = async ({
7738
7738
  let runContextWindow = initialContextWindow;
7739
7739
  let runSteps = 0;
7740
7740
  let runMaxSteps;
7741
- for await (const event of harness.runWithTelemetry(runInput)) {
7741
+ const source = events ?? harness.runWithTelemetry(runInput);
7742
+ for await (const event of source) {
7742
7743
  recordStandardTurnEvent(draft, event);
7743
7744
  if (event.type === "run:started") {
7744
7745
  latestRunId = event.runId;
@@ -7831,6 +7832,76 @@ var __internalRunOrchestration = {
7831
7832
  recordStandardTurnEvent,
7832
7833
  executeConversationTurn
7833
7834
  };
7835
+ var applyTurnMetadata = (conv, meta, opts = {}) => {
7836
+ const {
7837
+ clearContinuation = true,
7838
+ clearApprovals = true,
7839
+ setIdle = true,
7840
+ shouldRebuildCanonical = false
7841
+ } = opts;
7842
+ if (meta.continuation && meta.continuationMessages) {
7843
+ conv._continuationMessages = meta.continuationMessages;
7844
+ } else if (clearContinuation) {
7845
+ conv._continuationMessages = void 0;
7846
+ conv._continuationCount = void 0;
7847
+ }
7848
+ if (meta.harnessMessages) {
7849
+ conv._harnessMessages = meta.harnessMessages;
7850
+ } else if (shouldRebuildCanonical) {
7851
+ conv._harnessMessages = conv.messages;
7852
+ }
7853
+ if (meta.toolResultArchive !== void 0) {
7854
+ conv._toolResultArchive = meta.toolResultArchive;
7855
+ }
7856
+ conv.runtimeRunId = meta.latestRunId || conv.runtimeRunId;
7857
+ if (clearApprovals) conv.pendingApprovals = [];
7858
+ if (setIdle) conv.runStatus = "idle";
7859
+ if (meta.contextTokens > 0) conv.contextTokens = meta.contextTokens;
7860
+ if (meta.contextWindow > 0) conv.contextWindow = meta.contextWindow;
7861
+ conv.updatedAt = Date.now();
7862
+ };
7863
+ var runCronAgent = async (harnessRef, task, conversationId, historyMessages, toolResultArchive, onEvent) => {
7864
+ const execution = await executeConversationTurn({
7865
+ harness: harnessRef,
7866
+ runInput: {
7867
+ task,
7868
+ conversationId,
7869
+ parameters: {
7870
+ __activeConversationId: conversationId,
7871
+ [TOOL_RESULT_ARCHIVE_PARAM]: toolResultArchive ?? {}
7872
+ },
7873
+ messages: historyMessages
7874
+ },
7875
+ onEvent
7876
+ });
7877
+ flushTurnDraft(execution.draft);
7878
+ const hasContent = execution.draft.assistantResponse.length > 0 || execution.draft.toolTimeline.length > 0;
7879
+ const assistantMetadata = buildAssistantMetadata(execution.draft);
7880
+ return {
7881
+ response: execution.draft.assistantResponse,
7882
+ steps: execution.runSteps,
7883
+ assistantMetadata,
7884
+ hasContent,
7885
+ contextTokens: execution.runContextTokens,
7886
+ contextWindow: execution.runContextWindow,
7887
+ harnessMessages: execution.runHarnessMessages,
7888
+ toolResultArchive: harnessRef.getToolResultArchive(conversationId),
7889
+ latestRunId: execution.latestRunId,
7890
+ continuation: execution.runContinuation,
7891
+ continuationMessages: execution.runContinuationMessages
7892
+ };
7893
+ };
7894
+ var buildCronMessages = (task, historyMessages, result) => [
7895
+ ...historyMessages,
7896
+ { role: "user", content: task },
7897
+ ...result.hasContent ? [{ role: "assistant", content: result.response, metadata: result.assistantMetadata }] : []
7898
+ ];
7899
+ var appendCronTurn = (conv, task, result) => {
7900
+ conv.messages.push(
7901
+ { role: "user", content: task },
7902
+ ...result.hasContent ? [{ role: "assistant", content: result.response, metadata: result.assistantMetadata }] : []
7903
+ );
7904
+ };
7834
7905
  var AGENT_TEMPLATE = (name, id, options) => `---
7835
7906
  name: ${name}
7836
7907
  id: ${id}
@@ -9651,30 +9722,23 @@ ${resultBody}`,
9651
9722
  if (callbackNeedsContinuation || execution.draft.assistantResponse.length > 0 || execution.draft.toolTimeline.length > 0) {
9652
9723
  const freshConv = await conversationStore.get(conversationId);
9653
9724
  if (freshConv) {
9654
- if (callbackNeedsContinuation) {
9655
- freshConv._continuationMessages = execution.runContinuationMessages;
9656
- } else {
9657
- freshConv._continuationMessages = void 0;
9725
+ if (!callbackNeedsContinuation) {
9658
9726
  freshConv.messages.push({
9659
9727
  role: "assistant",
9660
9728
  content: execution.draft.assistantResponse,
9661
9729
  metadata: buildAssistantMetadata(execution.draft)
9662
9730
  });
9663
9731
  }
9664
- if (callbackNeedsContinuation && execution.runHarnessMessages) {
9665
- freshConv._harnessMessages = execution.runHarnessMessages;
9666
- } else if (historySelection.shouldRebuildCanonical) {
9667
- freshConv._harnessMessages = freshConv.messages;
9668
- } else {
9669
- freshConv._harnessMessages = freshConv.messages;
9670
- }
9671
- freshConv._toolResultArchive = harness.getToolResultArchive(conversationId);
9672
- freshConv.runtimeRunId = execution.latestRunId || freshConv.runtimeRunId;
9732
+ applyTurnMetadata(freshConv, {
9733
+ latestRunId: execution.latestRunId,
9734
+ contextTokens: execution.runContextTokens,
9735
+ contextWindow: execution.runContextWindow,
9736
+ continuation: !!callbackNeedsContinuation,
9737
+ continuationMessages: execution.runContinuationMessages,
9738
+ harnessMessages: callbackNeedsContinuation ? execution.runHarnessMessages : void 0,
9739
+ toolResultArchive: harness.getToolResultArchive(conversationId)
9740
+ }, { shouldRebuildCanonical: true, clearApprovals: false });
9673
9741
  freshConv.runningCallbackSince = void 0;
9674
- freshConv.runStatus = "idle";
9675
- if (execution.runContextTokens > 0) freshConv.contextTokens = execution.runContextTokens;
9676
- if (execution.runContextWindow > 0) freshConv.contextWindow = execution.runContextWindow;
9677
- freshConv.updatedAt = Date.now();
9678
9742
  await conversationStore.update(freshConv);
9679
9743
  if (freshConv.channelMeta && execution.draft.assistantResponse.length > 0) {
9680
9744
  const adapter = messagingAdapters.get(freshConv.channelMeta.platform);
@@ -9863,15 +9927,7 @@ ${resultBody}`,
9863
9927
  runId: null
9864
9928
  });
9865
9929
  let latestRunId = conversation.runtimeRunId ?? "";
9866
- let assistantResponse = "";
9867
- const toolTimeline = [];
9868
- const sections = [];
9869
- let currentText = "";
9870
- let currentTools = [];
9871
9930
  let checkpointedRun = false;
9872
- let runContextTokens = conversation.contextTokens ?? 0;
9873
- let runContextWindow = conversation.contextWindow ?? 0;
9874
- let resumeHarnessMessages;
9875
9931
  const normalizedCheckpoint = normalizeApprovalCheckpoint(checkpoint, conversation.messages);
9876
9932
  const baseMessages = normalizedCheckpoint.baseMessageCount != null ? conversation.messages.slice(0, normalizedCheckpoint.baseMessageCount) : [];
9877
9933
  const fullCheckpointMessages = [...baseMessages, ...normalizedCheckpoint.checkpointMessages];
@@ -9901,133 +9957,99 @@ ${resultBody}`,
9901
9957
  }
9902
9958
  }
9903
9959
  const fullCheckpointWithResults = resumeToolResultMsg ? [...fullCheckpointMessages, resumeToolResultMsg] : fullCheckpointMessages;
9960
+ let draftRef;
9961
+ let execution;
9904
9962
  try {
9905
- for await (const event of harness.continueFromToolResult({
9906
- messages: fullCheckpointMessages,
9907
- toolResults,
9908
- conversationId,
9909
- abortSignal: abortController.signal
9910
- })) {
9911
- if (event.type === "run:started") {
9912
- latestRunId = event.runId;
9913
- runOwners.set(event.runId, conversation.ownerId);
9914
- runConversations.set(event.runId, conversationId);
9915
- const active = activeConversationRuns.get(conversationId);
9916
- if (active && active.abortController === abortController) {
9917
- active.runId = event.runId;
9918
- }
9919
- }
9920
- if (event.type === "model:chunk") {
9921
- if (currentTools.length > 0) {
9922
- sections.push({ type: "tools", content: currentTools });
9923
- currentTools = [];
9924
- if (assistantResponse.length > 0 && !/\s$/.test(assistantResponse)) {
9925
- assistantResponse += " ";
9963
+ execution = await executeConversationTurn({
9964
+ harness,
9965
+ events: harness.continueFromToolResult({
9966
+ messages: fullCheckpointMessages,
9967
+ toolResults,
9968
+ conversationId,
9969
+ abortSignal: abortController.signal
9970
+ }),
9971
+ initialContextTokens: conversation.contextTokens ?? 0,
9972
+ initialContextWindow: conversation.contextWindow ?? 0,
9973
+ onEvent: async (event, draft2) => {
9974
+ draftRef = draft2;
9975
+ if (event.type === "run:started") {
9976
+ latestRunId = event.runId;
9977
+ runOwners.set(event.runId, conversation.ownerId);
9978
+ runConversations.set(event.runId, conversationId);
9979
+ const active = activeConversationRuns.get(conversationId);
9980
+ if (active && active.abortController === abortController) {
9981
+ active.runId = event.runId;
9926
9982
  }
9927
9983
  }
9928
- assistantResponse += event.content;
9929
- currentText += event.content;
9930
- }
9931
- if (event.type === "tool:started") {
9932
- if (currentText.length > 0) {
9933
- sections.push({ type: "text", content: currentText });
9934
- currentText = "";
9984
+ if (event.type === "tool:approval:required") {
9985
+ const toolText = `- approval required \`${event.tool}\``;
9986
+ draft2.toolTimeline.push(toolText);
9987
+ draft2.currentTools.push(toolText);
9935
9988
  }
9936
- const toolText = `- start \`${event.tool}\``;
9937
- toolTimeline.push(toolText);
9938
- currentTools.push(toolText);
9939
- }
9940
- if (event.type === "tool:completed") {
9941
- const toolText = `- done \`${event.tool}\` (${event.duration}ms)`;
9942
- toolTimeline.push(toolText);
9943
- currentTools.push(toolText);
9944
- }
9945
- if (event.type === "tool:error") {
9946
- const toolText = `- error \`${event.tool}\`: ${event.error}`;
9947
- toolTimeline.push(toolText);
9948
- currentTools.push(toolText);
9949
- }
9950
- if (event.type === "tool:approval:required") {
9951
- const toolText = `- approval required \`${event.tool}\``;
9952
- toolTimeline.push(toolText);
9953
- currentTools.push(toolText);
9954
- }
9955
- if (event.type === "tool:approval:checkpoint") {
9956
- const conv = await conversationStore.get(conversationId);
9957
- if (conv) {
9958
- conv.pendingApprovals = buildApprovalCheckpoints({
9959
- approvals: event.approvals,
9960
- runId: latestRunId,
9961
- checkpointMessages: [...fullCheckpointWithResults, ...event.checkpointMessages],
9962
- baseMessageCount: 0,
9963
- pendingToolCalls: event.pendingToolCalls
9964
- });
9965
- conv.updatedAt = Date.now();
9966
- await conversationStore.update(conv);
9967
- if (conv.channelMeta?.platform === "telegram") {
9968
- const tgAdapter = messagingAdapters.get("telegram");
9969
- if (tgAdapter) {
9970
- const messageThreadId = parseTelegramMessageThreadIdFromPlatformThreadId(
9971
- conv.channelMeta.platformThreadId,
9972
- conv.channelMeta.channelId
9973
- );
9974
- void tgAdapter.sendApprovalRequest(
9975
- conv.channelMeta.channelId,
9976
- event.approvals.map((a) => ({ approvalId: a.approvalId, tool: a.tool, input: a.input })),
9977
- { message_thread_id: messageThreadId }
9978
- ).catch(() => {
9979
- });
9989
+ if (event.type === "tool:approval:checkpoint") {
9990
+ const conv = await conversationStore.get(conversationId);
9991
+ if (conv) {
9992
+ conv.pendingApprovals = buildApprovalCheckpoints({
9993
+ approvals: event.approvals,
9994
+ runId: latestRunId,
9995
+ checkpointMessages: [...fullCheckpointWithResults, ...event.checkpointMessages],
9996
+ baseMessageCount: 0,
9997
+ pendingToolCalls: event.pendingToolCalls
9998
+ });
9999
+ conv.updatedAt = Date.now();
10000
+ await conversationStore.update(conv);
10001
+ if (conv.channelMeta?.platform === "telegram") {
10002
+ const tgAdapter = messagingAdapters.get("telegram");
10003
+ if (tgAdapter) {
10004
+ const messageThreadId = parseTelegramMessageThreadIdFromPlatformThreadId(
10005
+ conv.channelMeta.platformThreadId,
10006
+ conv.channelMeta.channelId
10007
+ );
10008
+ void tgAdapter.sendApprovalRequest(
10009
+ conv.channelMeta.channelId,
10010
+ event.approvals.map((a) => ({ approvalId: a.approvalId, tool: a.tool, input: a.input })),
10011
+ { message_thread_id: messageThreadId }
10012
+ ).catch(() => {
10013
+ });
10014
+ }
9980
10015
  }
9981
10016
  }
10017
+ checkpointedRun = true;
9982
10018
  }
9983
- checkpointedRun = true;
9984
- }
9985
- if (event.type === "run:completed") {
9986
- if (assistantResponse.length === 0 && event.result.response) {
9987
- assistantResponse = event.result.response;
9988
- }
9989
- runContextTokens = event.result.contextTokens ?? runContextTokens;
9990
- runContextWindow = event.result.contextWindow ?? runContextWindow;
9991
- if (event.result.continuationMessages) {
9992
- resumeHarnessMessages = event.result.continuationMessages;
9993
- }
9994
- }
9995
- if (event.type === "run:error") {
9996
- assistantResponse = assistantResponse || `[Error: ${event.error.message}]`;
10019
+ await telemetry.emit(event);
10020
+ broadcastEvent(conversationId, event);
10021
+ emitBrowserStatusIfActive(conversationId, event);
9997
10022
  }
9998
- await telemetry.emit(event);
9999
- broadcastEvent(conversationId, event);
10000
- emitBrowserStatusIfActive(conversationId, event);
10001
- }
10023
+ });
10024
+ flushTurnDraft(execution.draft);
10025
+ latestRunId = execution.latestRunId || latestRunId;
10002
10026
  } catch (err) {
10003
10027
  console.error("[resume-run] error:", err instanceof Error ? err.message : err);
10004
- assistantResponse = assistantResponse || `[Error: ${err instanceof Error ? err.message : "Unknown error"}]`;
10005
- }
10006
- if (currentTools.length > 0) {
10007
- sections.push({ type: "tools", content: currentTools });
10008
- }
10009
- if (currentText.length > 0) {
10010
- sections.push({ type: "text", content: currentText });
10028
+ if (draftRef) {
10029
+ draftRef.assistantResponse = draftRef.assistantResponse || `[Error: ${err instanceof Error ? err.message : "Unknown error"}]`;
10030
+ flushTurnDraft(draftRef);
10031
+ }
10011
10032
  }
10033
+ const draft = execution?.draft ?? draftRef ?? createTurnDraftState();
10012
10034
  if (!checkpointedRun) {
10013
10035
  const conv = await conversationStore.get(conversationId);
10014
10036
  if (conv) {
10015
- const prevMessages = conv.messages;
10016
- const hasAssistantContent = assistantResponse.length > 0 || toolTimeline.length > 0 || sections.length > 0;
10037
+ const hasAssistantContent = draft.assistantResponse.length > 0 || draft.toolTimeline.length > 0 || draft.sections.length > 0;
10017
10038
  if (hasAssistantContent) {
10039
+ const prevMessages = conv.messages;
10018
10040
  const lastMsg = prevMessages[prevMessages.length - 1];
10019
10041
  if (lastMsg && lastMsg.role === "assistant" && lastMsg.metadata) {
10020
10042
  const existingToolActivity = lastMsg.metadata.toolActivity;
10021
10043
  const existingSections = lastMsg.metadata.sections;
10022
10044
  const mergedTimeline = [
10023
10045
  ...Array.isArray(existingToolActivity) ? existingToolActivity : [],
10024
- ...toolTimeline
10046
+ ...draft.toolTimeline
10025
10047
  ];
10026
10048
  const mergedSections = [
10027
10049
  ...Array.isArray(existingSections) ? existingSections : [],
10028
- ...sections
10050
+ ...draft.sections
10029
10051
  ];
10030
- const mergedText = (typeof lastMsg.content === "string" ? lastMsg.content : "") + assistantResponse;
10052
+ const mergedText = (typeof lastMsg.content === "string" ? lastMsg.content : "") + draft.assistantResponse;
10031
10053
  conv.messages = [
10032
10054
  ...prevMessages.slice(0, -1),
10033
10055
  {
@@ -10044,23 +10066,18 @@ ${resultBody}`,
10044
10066
  ...prevMessages,
10045
10067
  {
10046
10068
  role: "assistant",
10047
- content: assistantResponse,
10048
- metadata: toolTimeline.length > 0 || sections.length > 0 ? { toolActivity: toolTimeline, sections: sections.length > 0 ? sections : void 0 } : void 0
10069
+ content: draft.assistantResponse,
10070
+ metadata: buildAssistantMetadata(draft)
10049
10071
  }
10050
10072
  ];
10051
10073
  }
10052
10074
  }
10053
- if (resumeHarnessMessages) {
10054
- conv._harnessMessages = resumeHarnessMessages;
10055
- } else {
10056
- conv._harnessMessages = conv.messages;
10057
- }
10058
- conv.runtimeRunId = latestRunId || conv.runtimeRunId;
10059
- conv.pendingApprovals = [];
10060
- conv.runStatus = "idle";
10061
- if (runContextTokens > 0) conv.contextTokens = runContextTokens;
10062
- if (runContextWindow > 0) conv.contextWindow = runContextWindow;
10063
- conv.updatedAt = Date.now();
10075
+ applyTurnMetadata(conv, {
10076
+ latestRunId,
10077
+ contextTokens: execution?.runContextTokens ?? 0,
10078
+ contextWindow: execution?.runContextWindow ?? 0,
10079
+ harnessMessages: execution?.runHarnessMessages
10080
+ }, { shouldRebuildCanonical: true });
10064
10081
  await conversationStore.update(conv);
10065
10082
  }
10066
10083
  } else {
@@ -10201,7 +10218,7 @@ ${resultBody}`,
10201
10218
  conversationId,
10202
10219
  messages: historyMessages,
10203
10220
  files: input2.files,
10204
- parameters: {
10221
+ parameters: withToolResultArchiveParam({
10205
10222
  ...input2.metadata ? {
10206
10223
  __messaging_platform: input2.metadata.platform,
10207
10224
  __messaging_sender_id: input2.metadata.sender.id,
@@ -10209,7 +10226,7 @@ ${resultBody}`,
10209
10226
  __messaging_thread_id: input2.metadata.threadId
10210
10227
  } : {},
10211
10228
  __activeConversationId: conversationId
10212
- }
10229
+ }, latestConversation ?? { _toolResultArchive: {} })
10213
10230
  };
10214
10231
  try {
10215
10232
  const execution = await executeConversationTurn({
@@ -10302,31 +10319,31 @@ ${resultBody}`,
10302
10319
  flushTurnDraft(draft);
10303
10320
  if (!checkpointedRun) {
10304
10321
  await updateConversation((c) => {
10305
- if (runContinuation2 && runContinuationMessages) {
10306
- c._continuationMessages = runContinuationMessages;
10307
- } else {
10308
- c._continuationMessages = void 0;
10322
+ if (!(runContinuation2 && runContinuationMessages)) {
10309
10323
  c.messages = buildMessages();
10310
10324
  }
10311
- if (runContinuationMessages) {
10312
- c._harnessMessages = runContinuationMessages;
10313
- } else if (shouldRebuildCanonical) {
10314
- c._harnessMessages = c.messages;
10315
- } else {
10316
- c._harnessMessages = c.messages;
10317
- }
10318
- c.runtimeRunId = latestRunId || c.runtimeRunId;
10319
- c.pendingApprovals = [];
10320
- c.runStatus = "idle";
10321
- if (runContextTokens > 0) c.contextTokens = runContextTokens;
10322
- if (runContextWindow > 0) c.contextWindow = runContextWindow;
10325
+ applyTurnMetadata(c, {
10326
+ latestRunId,
10327
+ contextTokens: runContextTokens,
10328
+ contextWindow: runContextWindow,
10329
+ continuation: runContinuation2,
10330
+ continuationMessages: runContinuationMessages,
10331
+ harnessMessages: runContinuationMessages,
10332
+ toolResultArchive: harness.getToolResultArchive(conversationId)
10333
+ }, { shouldRebuildCanonical: true });
10323
10334
  });
10324
10335
  } else {
10325
10336
  await updateConversation((c) => {
10326
- if (shouldRebuildCanonical && !c._harnessMessages?.length) {
10327
- c._harnessMessages = c.messages;
10328
- }
10329
- c.runStatus = "idle";
10337
+ applyTurnMetadata(c, {
10338
+ latestRunId: "",
10339
+ contextTokens: 0,
10340
+ contextWindow: 0,
10341
+ toolResultArchive: harness.getToolResultArchive(conversationId)
10342
+ }, {
10343
+ clearContinuation: false,
10344
+ clearApprovals: false,
10345
+ shouldRebuildCanonical: shouldRebuildCanonical && !c._harnessMessages?.length
10346
+ });
10330
10347
  });
10331
10348
  }
10332
10349
  finishConversationStream(conversationId);
@@ -10477,7 +10494,7 @@ ${resultBody}`,
10477
10494
  return typeof headerValue === "string" && headerValue === internalSecret;
10478
10495
  };
10479
10496
  const MAX_CONTINUATION_COUNT = 20;
10480
- async function* runContinuation(conversationId) {
10497
+ async function runContinuation(conversationId, onYield) {
10481
10498
  const conversation = await conversationStore.get(conversationId);
10482
10499
  if (!conversation) return;
10483
10500
  if (Array.isArray(conversation.pendingApprovals) && conversation.pendingApprovals.length > 0) return;
@@ -10515,132 +10532,69 @@ ${resultBody}`,
10515
10532
  }
10516
10533
  try {
10517
10534
  if (conversation.parentConversationId) {
10518
- yield* runSubagentContinuation(conversationId, conversation, continuationMessages);
10535
+ for await (const event of runSubagentContinuation(conversationId, conversation, continuationMessages)) {
10536
+ if (onYield) await onYield(event);
10537
+ }
10519
10538
  } else {
10520
- yield* runChatContinuation(conversationId, conversation, continuationMessages);
10539
+ await runChatContinuation(conversationId, conversation, continuationMessages, onYield);
10521
10540
  }
10522
10541
  } finally {
10523
10542
  activeConversationRuns.delete(conversationId);
10524
10543
  finishConversationStream(conversationId);
10525
10544
  }
10526
10545
  }
10527
- async function* runChatContinuation(conversationId, conversation, continuationMessages) {
10528
- let assistantResponse = "";
10529
- let latestRunId = conversation.runtimeRunId ?? "";
10530
- const toolTimeline = [];
10531
- const sections = [];
10532
- let currentTools = [];
10533
- let currentText = "";
10534
- let runContextTokens = conversation.contextTokens ?? 0;
10535
- let runContextWindow = conversation.contextWindow ?? 0;
10536
- let nextContinuationMessages;
10537
- let nextHarnessMessages;
10538
- for await (const event of harness.runWithTelemetry({
10539
- conversationId,
10540
- parameters: withToolResultArchiveParam({
10541
- __activeConversationId: conversationId,
10542
- __ownerId: conversation.ownerId
10543
- }, conversation),
10544
- messages: continuationMessages,
10545
- abortSignal: activeConversationRuns.get(conversationId)?.abortController.signal
10546
- })) {
10547
- if (event.type === "run:started") {
10548
- latestRunId = event.runId;
10549
- runOwners.set(event.runId, conversation.ownerId);
10550
- runConversations.set(event.runId, conversationId);
10551
- const active = activeConversationRuns.get(conversationId);
10552
- if (active) active.runId = event.runId;
10553
- }
10554
- if (event.type === "model:chunk") {
10555
- if (currentTools.length > 0) {
10556
- sections.push({ type: "tools", content: currentTools });
10557
- currentTools = [];
10558
- if (assistantResponse.length > 0 && !/\s$/.test(assistantResponse)) {
10559
- assistantResponse += " ";
10560
- }
10561
- }
10562
- assistantResponse += event.content;
10563
- currentText += event.content;
10564
- }
10565
- if (event.type === "tool:started") {
10566
- if (currentText.length > 0) {
10567
- sections.push({ type: "text", content: currentText });
10568
- currentText = "";
10569
- }
10570
- const toolText = `- start \`${event.tool}\``;
10571
- toolTimeline.push(toolText);
10572
- currentTools.push(toolText);
10573
- }
10574
- if (event.type === "tool:completed") {
10575
- const toolText = `- done \`${event.tool}\` (${event.duration}ms)`;
10576
- toolTimeline.push(toolText);
10577
- currentTools.push(toolText);
10578
- }
10579
- if (event.type === "tool:error") {
10580
- const toolText = `- error \`${event.tool}\`: ${event.error}`;
10581
- toolTimeline.push(toolText);
10582
- currentTools.push(toolText);
10583
- }
10584
- if (event.type === "run:completed") {
10585
- runContextTokens = event.result.contextTokens ?? runContextTokens;
10586
- runContextWindow = event.result.contextWindow ?? runContextWindow;
10587
- if (event.result.continuation && event.result.continuationMessages) {
10588
- nextContinuationMessages = event.result.continuationMessages;
10589
- }
10590
- if (event.result.continuationMessages) {
10591
- nextHarnessMessages = event.result.continuationMessages;
10592
- }
10593
- if (!assistantResponse && event.result.response) {
10594
- assistantResponse = event.result.response;
10546
+ async function runChatContinuation(conversationId, conversation, continuationMessages, onYield) {
10547
+ const execution = await executeConversationTurn({
10548
+ harness,
10549
+ runInput: {
10550
+ conversationId,
10551
+ parameters: withToolResultArchiveParam({
10552
+ __activeConversationId: conversationId,
10553
+ __ownerId: conversation.ownerId
10554
+ }, conversation),
10555
+ messages: continuationMessages,
10556
+ abortSignal: activeConversationRuns.get(conversationId)?.abortController.signal
10557
+ },
10558
+ initialContextTokens: conversation.contextTokens ?? 0,
10559
+ initialContextWindow: conversation.contextWindow ?? 0,
10560
+ onEvent: async (event) => {
10561
+ if (event.type === "run:started") {
10562
+ runOwners.set(event.runId, conversation.ownerId);
10563
+ runConversations.set(event.runId, conversationId);
10564
+ const active = activeConversationRuns.get(conversationId);
10565
+ if (active) active.runId = event.runId;
10595
10566
  }
10567
+ await telemetry.emit(event);
10568
+ broadcastEvent(conversationId, event);
10569
+ if (onYield) await onYield(event);
10596
10570
  }
10597
- if (event.type === "run:error") {
10598
- assistantResponse = assistantResponse || `[Error: ${event.error.message}]`;
10599
- }
10600
- await telemetry.emit(event);
10601
- broadcastEvent(conversationId, event);
10602
- yield event;
10603
- }
10604
- if (currentTools.length > 0) sections.push({ type: "tools", content: currentTools });
10605
- if (currentText.length > 0) sections.push({ type: "text", content: currentText });
10571
+ });
10572
+ flushTurnDraft(execution.draft);
10606
10573
  const freshConv = await conversationStore.get(conversationId);
10607
10574
  if (!freshConv) return;
10608
- const hasContent = assistantResponse.length > 0 || toolTimeline.length > 0;
10609
- const assistantMetadata = toolTimeline.length > 0 || sections.length > 0 ? {
10610
- toolActivity: [...toolTimeline],
10611
- sections: sections.length > 0 ? sections : void 0
10612
- } : void 0;
10613
- if (nextContinuationMessages) {
10614
- if (hasContent) {
10615
- freshConv.messages = [
10616
- ...freshConv.messages,
10617
- { role: "assistant", content: assistantResponse, metadata: assistantMetadata }
10618
- ];
10619
- }
10620
- freshConv._continuationMessages = nextContinuationMessages;
10575
+ const hasContent = execution.draft.assistantResponse.length > 0 || execution.draft.toolTimeline.length > 0;
10576
+ if (hasContent) {
10577
+ freshConv.messages = [
10578
+ ...freshConv.messages,
10579
+ {
10580
+ role: "assistant",
10581
+ content: execution.draft.assistantResponse,
10582
+ metadata: buildAssistantMetadata(execution.draft)
10583
+ }
10584
+ ];
10585
+ }
10586
+ applyTurnMetadata(freshConv, {
10587
+ latestRunId: execution.latestRunId,
10588
+ contextTokens: execution.runContextTokens,
10589
+ contextWindow: execution.runContextWindow,
10590
+ continuation: execution.runContinuation,
10591
+ continuationMessages: execution.runContinuationMessages,
10592
+ harnessMessages: execution.runHarnessMessages,
10593
+ toolResultArchive: harness.getToolResultArchive(conversationId)
10594
+ }, { shouldRebuildCanonical: true });
10595
+ if (execution.runContinuation) {
10621
10596
  freshConv._continuationCount = conversation._continuationCount;
10622
- } else {
10623
- if (hasContent) {
10624
- freshConv.messages = [
10625
- ...freshConv.messages,
10626
- { role: "assistant", content: assistantResponse, metadata: assistantMetadata }
10627
- ];
10628
- }
10629
- freshConv._continuationMessages = void 0;
10630
- freshConv._continuationCount = void 0;
10631
10597
  }
10632
- if (nextHarnessMessages) {
10633
- freshConv._harnessMessages = nextHarnessMessages;
10634
- } else {
10635
- freshConv._harnessMessages = freshConv.messages;
10636
- }
10637
- freshConv._toolResultArchive = harness.getToolResultArchive(conversationId);
10638
- freshConv.runtimeRunId = latestRunId || freshConv.runtimeRunId;
10639
- freshConv.pendingApprovals = [];
10640
- if (runContextTokens > 0) freshConv.contextTokens = runContextTokens;
10641
- if (runContextWindow > 0) freshConv.contextWindow = runContextWindow;
10642
- freshConv.runStatus = "idle";
10643
- freshConv.updatedAt = Date.now();
10644
10598
  await conversationStore.update(freshConv);
10645
10599
  }
10646
10600
  async function* runSubagentContinuation(conversationId, conversation, continuationMessages) {
@@ -11206,8 +11160,7 @@ ${resultBody}`,
11206
11160
  writeJson(response, 202, { ok: true });
11207
11161
  const work = (async () => {
11208
11162
  try {
11209
- for await (const _event of runContinuation(conversationId)) {
11210
- }
11163
+ await runContinuation(conversationId);
11211
11164
  const conv = await conversationStore.get(conversationId);
11212
11165
  if (conv?._continuationMessages?.length) {
11213
11166
  await selfFetchWithRetry(`/api/internal/continue/${encodeURIComponent(conversationId)}`);
@@ -11818,7 +11771,7 @@ data: ${JSON.stringify(frame)}
11818
11771
  writeJson(response, 200, {
11819
11772
  conversation: {
11820
11773
  ...conversation,
11821
- messages: conversation.messages.map(normalizeMessageForClient),
11774
+ messages: conversation.messages.map(normalizeMessageForClient).filter((m) => m !== null),
11822
11775
  pendingApprovals: storedPending,
11823
11776
  _continuationMessages: void 0,
11824
11777
  _harnessMessages: void 0
@@ -12024,7 +11977,7 @@ data: ${JSON.stringify(frame)}
12024
11977
  });
12025
11978
  let eventCount = 0;
12026
11979
  try {
12027
- for await (const event of runContinuation(conversationId)) {
11980
+ await runContinuation(conversationId, async (event) => {
12028
11981
  eventCount++;
12029
11982
  let sseEvent = event;
12030
11983
  if (sseEvent.type === "run:completed") {
@@ -12037,7 +11990,7 @@ data: ${JSON.stringify(frame)}
12037
11990
  } catch {
12038
11991
  }
12039
11992
  emitBrowserStatusIfActive(conversationId, event, response);
12040
- }
11993
+ });
12041
11994
  } catch (err) {
12042
11995
  const errorEvent = {
12043
11996
  type: "run:error",
@@ -12152,18 +12105,6 @@ data: ${JSON.stringify(frame)}
12152
12105
  `[poncho] conversation="${conversationId}" history_source=${canonicalHistory.source}`
12153
12106
  );
12154
12107
  let latestRunId = conversation.runtimeRunId ?? "";
12155
- let assistantResponse = "";
12156
- const toolTimeline = [];
12157
- const sections = [];
12158
- let currentText = "";
12159
- let currentTools = [];
12160
- let runCancelled = false;
12161
- let checkpointedRun = false;
12162
- let didCompact = false;
12163
- let runContextTokens = conversation.contextTokens ?? 0;
12164
- let runContextWindow = conversation.contextWindow ?? 0;
12165
- let runContinuationMessages;
12166
- let runHarnessMessages;
12167
12108
  let userContent = messageText;
12168
12109
  if (files.length > 0) {
12169
12110
  try {
@@ -12207,6 +12148,39 @@ data: ${JSON.stringify(frame)}
12207
12148
  }
12208
12149
  }
12209
12150
  });
12151
+ const draft = createTurnDraftState();
12152
+ let checkpointedRun = false;
12153
+ let runCancelled = false;
12154
+ let runContinuationMessages;
12155
+ const buildMessages = () => {
12156
+ const draftSections = cloneSections(draft.sections);
12157
+ if (draft.currentTools.length > 0) {
12158
+ draftSections.push({ type: "tools", content: [...draft.currentTools] });
12159
+ }
12160
+ if (draft.currentText.length > 0) {
12161
+ draftSections.push({ type: "text", content: draft.currentText });
12162
+ }
12163
+ const userTurn = userContent != null ? [{ role: "user", content: userContent }] : [];
12164
+ const hasDraftContent = draft.assistantResponse.length > 0 || draft.toolTimeline.length > 0 || draftSections.length > 0;
12165
+ if (!hasDraftContent) {
12166
+ return [...historyMessages, ...userTurn];
12167
+ }
12168
+ return [
12169
+ ...historyMessages,
12170
+ ...userTurn,
12171
+ {
12172
+ role: "assistant",
12173
+ content: draft.assistantResponse,
12174
+ metadata: buildAssistantMetadata(draft, draftSections)
12175
+ }
12176
+ ];
12177
+ };
12178
+ const persistDraftAssistantTurn = async () => {
12179
+ if (draft.assistantResponse.length === 0 && draft.toolTimeline.length === 0) return;
12180
+ conversation.messages = buildMessages();
12181
+ conversation.updatedAt = Date.now();
12182
+ await conversationStore.update(conversation);
12183
+ };
12210
12184
  try {
12211
12185
  {
12212
12186
  conversation.messages = [...historyMessages, { role: "user", content: userContent }];
@@ -12217,38 +12191,6 @@ data: ${JSON.stringify(frame)}
12217
12191
  console.error("[poncho] Failed to persist user turn:", err);
12218
12192
  });
12219
12193
  }
12220
- const persistDraftAssistantTurn = async () => {
12221
- const draftSections = [
12222
- ...sections.map((section) => ({
12223
- type: section.type,
12224
- content: Array.isArray(section.content) ? [...section.content] : section.content
12225
- }))
12226
- ];
12227
- if (currentTools.length > 0) {
12228
- draftSections.push({ type: "tools", content: [...currentTools] });
12229
- }
12230
- if (currentText.length > 0) {
12231
- draftSections.push({ type: "text", content: currentText });
12232
- }
12233
- const hasDraftContent = assistantResponse.length > 0 || toolTimeline.length > 0 || draftSections.length > 0;
12234
- if (!hasDraftContent) {
12235
- return;
12236
- }
12237
- conversation.messages = [
12238
- ...historyMessages,
12239
- ...userContent != null ? [{ role: "user", content: userContent }] : [],
12240
- {
12241
- role: "assistant",
12242
- content: assistantResponse,
12243
- metadata: toolTimeline.length > 0 || draftSections.length > 0 ? {
12244
- toolActivity: [...toolTimeline],
12245
- sections: draftSections.length > 0 ? draftSections : void 0
12246
- } : void 0
12247
- }
12248
- ];
12249
- conversation.updatedAt = Date.now();
12250
- await conversationStore.update(conversation);
12251
- };
12252
12194
  let cachedRecallCorpus;
12253
12195
  const lazyRecallCorpus = async () => {
12254
12196
  if (cachedRecallCorpus) return cachedRecallCorpus;
@@ -12269,249 +12211,156 @@ data: ${JSON.stringify(frame)}
12269
12211
  console.info(`[poncho] recall corpus fetched lazily (${cachedRecallCorpus.length} items, ${(performance.now() - _rc0).toFixed(1)}ms)`);
12270
12212
  return cachedRecallCorpus;
12271
12213
  };
12272
- for await (const event of harness.runWithTelemetry({
12273
- task: messageText,
12274
- conversationId,
12275
- parameters: withToolResultArchiveParam({
12276
- ...bodyParameters ?? {},
12277
- __conversationRecallCorpus: lazyRecallCorpus,
12278
- __activeConversationId: conversationId,
12279
- __ownerId: ownerId
12280
- }, conversation),
12281
- messages: harnessMessages,
12282
- files: files.length > 0 ? files : void 0,
12283
- abortSignal: abortController.signal
12284
- })) {
12285
- if (event.type === "run:started") {
12286
- latestRunId = event.runId;
12287
- runOwners.set(event.runId, ownerId);
12288
- runConversations.set(event.runId, conversationId);
12289
- const active = activeConversationRuns.get(conversationId);
12290
- if (active && active.abortController === abortController) {
12291
- active.runId = event.runId;
12292
- }
12293
- }
12294
- if (event.type === "run:cancelled") {
12295
- runCancelled = true;
12296
- }
12297
- if (event.type === "model:chunk") {
12298
- if (currentTools.length > 0) {
12299
- sections.push({ type: "tools", content: currentTools });
12300
- currentTools = [];
12301
- if (assistantResponse.length > 0 && !/\s$/.test(assistantResponse)) {
12302
- assistantResponse += " ";
12214
+ const execution = await executeConversationTurn({
12215
+ harness,
12216
+ runInput: {
12217
+ task: messageText,
12218
+ conversationId,
12219
+ parameters: withToolResultArchiveParam({
12220
+ ...bodyParameters ?? {},
12221
+ __conversationRecallCorpus: lazyRecallCorpus,
12222
+ __activeConversationId: conversationId,
12223
+ __ownerId: ownerId
12224
+ }, conversation),
12225
+ messages: harnessMessages,
12226
+ files: files.length > 0 ? files : void 0,
12227
+ abortSignal: abortController.signal
12228
+ },
12229
+ initialContextTokens: conversation.contextTokens ?? 0,
12230
+ initialContextWindow: conversation.contextWindow ?? 0,
12231
+ onEvent: async (event, eventDraft) => {
12232
+ draft.assistantResponse = eventDraft.assistantResponse;
12233
+ draft.toolTimeline = eventDraft.toolTimeline;
12234
+ draft.sections = eventDraft.sections;
12235
+ draft.currentTools = eventDraft.currentTools;
12236
+ draft.currentText = eventDraft.currentText;
12237
+ if (event.type === "run:started") {
12238
+ latestRunId = event.runId;
12239
+ runOwners.set(event.runId, ownerId);
12240
+ runConversations.set(event.runId, conversationId);
12241
+ const active = activeConversationRuns.get(conversationId);
12242
+ if (active && active.abortController === abortController) {
12243
+ active.runId = event.runId;
12303
12244
  }
12304
12245
  }
12305
- assistantResponse += event.content;
12306
- currentText += event.content;
12307
- }
12308
- if (event.type === "tool:started") {
12309
- if (currentText.length > 0) {
12310
- sections.push({ type: "text", content: currentText });
12311
- currentText = "";
12312
- }
12313
- const toolText = `- start \`${event.tool}\``;
12314
- toolTimeline.push(toolText);
12315
- currentTools.push(toolText);
12316
- }
12317
- if (event.type === "tool:completed") {
12318
- const toolText = `- done \`${event.tool}\` (${event.duration}ms)`;
12319
- toolTimeline.push(toolText);
12320
- currentTools.push(toolText);
12321
- }
12322
- if (event.type === "tool:error") {
12323
- const toolText = `- error \`${event.tool}\`: ${event.error}`;
12324
- toolTimeline.push(toolText);
12325
- currentTools.push(toolText);
12326
- }
12327
- if (event.type === "compaction:completed") {
12328
- didCompact = true;
12329
- if (event.compactedMessages) {
12330
- historyMessages.length = 0;
12331
- historyMessages.push(...event.compactedMessages);
12332
- const preservedFromHistory = historyMessages.length - 1;
12333
- const removedCount = preRunMessages.length - Math.max(0, preservedFromHistory);
12334
- const existingHistory = conversation.compactedHistory ?? [];
12335
- conversation.compactedHistory = [
12336
- ...existingHistory,
12337
- ...preRunMessages.slice(0, removedCount)
12338
- ];
12339
- }
12340
- }
12341
- if (event.type === "step:completed") {
12342
- await persistDraftAssistantTurn();
12343
- }
12344
- if (event.type === "tool:approval:required") {
12345
- const toolText = `- approval required \`${event.tool}\``;
12346
- toolTimeline.push(toolText);
12347
- currentTools.push(toolText);
12348
- const existingApprovals = Array.isArray(conversation.pendingApprovals) ? conversation.pendingApprovals : [];
12349
- if (!existingApprovals.some((approval) => approval.approvalId === event.approvalId)) {
12350
- conversation.pendingApprovals = [
12351
- ...existingApprovals,
12352
- {
12353
- approvalId: event.approvalId,
12354
- runId: latestRunId || conversation.runtimeRunId || "",
12355
- tool: event.tool,
12356
- toolCallId: void 0,
12357
- input: event.input ?? {},
12358
- checkpointMessages: void 0,
12359
- baseMessageCount: historyMessages.length,
12360
- pendingToolCalls: []
12361
- }
12362
- ];
12363
- conversation.updatedAt = Date.now();
12364
- await conversationStore.update(conversation);
12365
- }
12366
- await persistDraftAssistantTurn();
12367
- }
12368
- if (event.type === "tool:approval:checkpoint") {
12369
- const checkpointSections = [...sections];
12370
- if (currentTools.length > 0) {
12371
- checkpointSections.push({ type: "tools", content: [...currentTools] });
12246
+ if (event.type === "run:cancelled") {
12247
+ runCancelled = true;
12372
12248
  }
12373
- if (currentText.length > 0) {
12374
- checkpointSections.push({ type: "text", content: currentText });
12249
+ if (event.type === "compaction:completed") {
12250
+ if (event.compactedMessages) {
12251
+ historyMessages.length = 0;
12252
+ historyMessages.push(...event.compactedMessages);
12253
+ const preservedFromHistory = historyMessages.length - 1;
12254
+ const removedCount = preRunMessages.length - Math.max(0, preservedFromHistory);
12255
+ const existingHistory = conversation.compactedHistory ?? [];
12256
+ conversation.compactedHistory = [
12257
+ ...existingHistory,
12258
+ ...preRunMessages.slice(0, removedCount)
12259
+ ];
12260
+ }
12375
12261
  }
12376
- conversation.messages = [
12377
- ...historyMessages,
12378
- ...userContent != null ? [{ role: "user", content: userContent }] : [],
12379
- ...assistantResponse.length > 0 || toolTimeline.length > 0 || checkpointSections.length > 0 ? [{
12380
- role: "assistant",
12381
- content: assistantResponse,
12382
- metadata: toolTimeline.length > 0 || checkpointSections.length > 0 ? { toolActivity: [...toolTimeline], sections: checkpointSections.length > 0 ? checkpointSections : void 0 } : void 0
12383
- }] : []
12384
- ];
12385
- conversation.pendingApprovals = buildApprovalCheckpoints({
12386
- approvals: event.approvals,
12387
- runId: latestRunId,
12388
- checkpointMessages: event.checkpointMessages,
12389
- baseMessageCount: historyMessages.length,
12390
- pendingToolCalls: event.pendingToolCalls
12391
- });
12392
- conversation._toolResultArchive = harness.getToolResultArchive(conversationId);
12393
- conversation.updatedAt = Date.now();
12394
- await conversationStore.update(conversation);
12395
- checkpointedRun = true;
12396
- }
12397
- if (event.type === "run:completed") {
12398
- if (assistantResponse.length === 0 && event.result.response) {
12399
- assistantResponse = event.result.response;
12262
+ if (event.type === "step:completed") {
12263
+ await persistDraftAssistantTurn();
12400
12264
  }
12401
- runContextTokens = event.result.contextTokens ?? runContextTokens;
12402
- runContextWindow = event.result.contextWindow ?? runContextWindow;
12403
- if (event.result.continuationMessages) {
12404
- runHarnessMessages = event.result.continuationMessages;
12265
+ if (event.type === "tool:approval:required") {
12266
+ const toolText = `- approval required \`${event.tool}\``;
12267
+ draft.toolTimeline.push(toolText);
12268
+ draft.currentTools.push(toolText);
12269
+ const existingApprovals = Array.isArray(conversation.pendingApprovals) ? conversation.pendingApprovals : [];
12270
+ if (!existingApprovals.some((approval) => approval.approvalId === event.approvalId)) {
12271
+ conversation.pendingApprovals = [
12272
+ ...existingApprovals,
12273
+ {
12274
+ approvalId: event.approvalId,
12275
+ runId: latestRunId || conversation.runtimeRunId || "",
12276
+ tool: event.tool,
12277
+ toolCallId: void 0,
12278
+ input: event.input ?? {},
12279
+ checkpointMessages: void 0,
12280
+ baseMessageCount: historyMessages.length,
12281
+ pendingToolCalls: []
12282
+ }
12283
+ ];
12284
+ conversation.updatedAt = Date.now();
12285
+ await conversationStore.update(conversation);
12286
+ }
12287
+ await persistDraftAssistantTurn();
12405
12288
  }
12406
- if (event.result.continuation && event.result.continuationMessages) {
12407
- runContinuationMessages = event.result.continuationMessages;
12408
- const intSections = [...sections];
12409
- if (currentTools.length > 0) intSections.push({ type: "tools", content: [...currentTools] });
12410
- if (currentText.length > 0) intSections.push({ type: "text", content: currentText });
12411
- const hasContent = assistantResponse.length > 0 || toolTimeline.length > 0 || intSections.length > 0;
12412
- const intMetadata = toolTimeline.length > 0 || intSections.length > 0 ? { toolActivity: [...toolTimeline], sections: intSections.length > 0 ? intSections : void 0 } : void 0;
12413
- conversation.messages = [
12414
- ...historyMessages,
12415
- ...userContent != null ? [{ role: "user", content: userContent }] : [],
12416
- ...hasContent ? [{ role: "assistant", content: assistantResponse, metadata: intMetadata }] : []
12417
- ];
12418
- conversation._continuationMessages = runContinuationMessages;
12419
- conversation._harnessMessages = runContinuationMessages;
12289
+ if (event.type === "tool:approval:checkpoint") {
12290
+ conversation.messages = buildMessages();
12291
+ conversation.pendingApprovals = buildApprovalCheckpoints({
12292
+ approvals: event.approvals,
12293
+ runId: latestRunId,
12294
+ checkpointMessages: event.checkpointMessages,
12295
+ baseMessageCount: historyMessages.length,
12296
+ pendingToolCalls: event.pendingToolCalls
12297
+ });
12420
12298
  conversation._toolResultArchive = harness.getToolResultArchive(conversationId);
12421
- conversation.runtimeRunId = latestRunId || conversation.runtimeRunId;
12422
- if (!checkpointedRun) {
12423
- conversation.pendingApprovals = [];
12424
- }
12425
- if (runContextTokens > 0) conversation.contextTokens = runContextTokens;
12426
- if (runContextWindow > 0) conversation.contextWindow = runContextWindow;
12427
12299
  conversation.updatedAt = Date.now();
12428
12300
  await conversationStore.update(conversation);
12429
- if (!checkpointedRun) {
12430
- doWaitUntil(
12431
- new Promise((r) => setTimeout(r, 3e3)).then(
12432
- () => selfFetchWithRetry(`/api/internal/continue/${encodeURIComponent(conversationId)}`)
12433
- )
12434
- );
12301
+ checkpointedRun = true;
12302
+ }
12303
+ if (event.type === "run:completed") {
12304
+ if (event.result.continuation && event.result.continuationMessages) {
12305
+ runContinuationMessages = event.result.continuationMessages;
12306
+ conversation.messages = buildMessages();
12307
+ conversation._continuationMessages = runContinuationMessages;
12308
+ conversation._harnessMessages = runContinuationMessages;
12309
+ conversation._toolResultArchive = harness.getToolResultArchive(conversationId);
12310
+ conversation.runtimeRunId = latestRunId || conversation.runtimeRunId;
12311
+ if (!checkpointedRun) {
12312
+ conversation.pendingApprovals = [];
12313
+ }
12314
+ if ((event.result.contextTokens ?? 0) > 0) conversation.contextTokens = event.result.contextTokens;
12315
+ if ((event.result.contextWindow ?? 0) > 0) conversation.contextWindow = event.result.contextWindow;
12316
+ conversation.updatedAt = Date.now();
12317
+ await conversationStore.update(conversation);
12318
+ if (!checkpointedRun) {
12319
+ doWaitUntil(
12320
+ new Promise((r) => setTimeout(r, 3e3)).then(
12321
+ () => selfFetchWithRetry(`/api/internal/continue/${encodeURIComponent(conversationId)}`)
12322
+ )
12323
+ );
12324
+ }
12435
12325
  }
12436
12326
  }
12437
- }
12438
- await telemetry.emit(event);
12439
- let sseEvent = event.type === "compaction:completed" && event.compactedMessages ? { ...event, compactedMessages: void 0 } : event;
12440
- if (sseEvent.type === "run:completed") {
12441
- const hasPendingSubagents = await hasPendingSubagentWorkForParent(conversationId, ownerId);
12442
- const stripped = { ...sseEvent, result: { ...sseEvent.result, continuationMessages: void 0 } };
12443
- if (hasPendingSubagents) {
12444
- sseEvent = { ...stripped, pendingSubagents: true };
12445
- } else {
12446
- sseEvent = stripped;
12327
+ await telemetry.emit(event);
12328
+ let sseEvent = event.type === "compaction:completed" && event.compactedMessages ? { ...event, compactedMessages: void 0 } : event;
12329
+ if (sseEvent.type === "run:completed") {
12330
+ const hasPendingSubagents = await hasPendingSubagentWorkForParent(conversationId, ownerId);
12331
+ const stripped = { ...sseEvent, result: { ...sseEvent.result, continuationMessages: void 0 } };
12332
+ if (hasPendingSubagents) {
12333
+ sseEvent = { ...stripped, pendingSubagents: true };
12334
+ } else {
12335
+ sseEvent = stripped;
12336
+ }
12447
12337
  }
12448
- }
12449
- broadcastEvent(conversationId, sseEvent);
12450
- try {
12451
- response.write(formatSseEvent(sseEvent));
12452
- } catch {
12453
- }
12454
- emitBrowserStatusIfActive(conversationId, event, response);
12455
- }
12456
- if (currentTools.length > 0) {
12457
- sections.push({ type: "tools", content: currentTools });
12458
- }
12459
- if (currentText.length > 0) {
12460
- sections.push({ type: "text", content: currentText });
12461
- }
12462
- if (!checkpointedRun && !runContinuationMessages) {
12463
- const hasAssistantContent = assistantResponse.length > 0 || toolTimeline.length > 0 || sections.length > 0;
12464
- const userTurn = userContent != null ? [{ role: "user", content: userContent }] : [];
12465
- conversation.messages = hasAssistantContent ? [
12466
- ...historyMessages,
12467
- ...userTurn,
12468
- {
12469
- role: "assistant",
12470
- content: assistantResponse,
12471
- metadata: toolTimeline.length > 0 || sections.length > 0 ? {
12472
- toolActivity: toolTimeline,
12473
- sections: sections.length > 0 ? sections : void 0
12474
- } : void 0
12338
+ broadcastEvent(conversationId, sseEvent);
12339
+ try {
12340
+ response.write(formatSseEvent(sseEvent));
12341
+ } catch {
12475
12342
  }
12476
- ] : [...historyMessages, ...userTurn];
12477
- conversation._continuationMessages = void 0;
12478
- if (runHarnessMessages) {
12479
- conversation._harnessMessages = runHarnessMessages;
12480
- } else if (shouldRebuildCanonical) {
12481
- conversation._harnessMessages = conversation.messages;
12482
- } else {
12483
- conversation._harnessMessages = conversation.messages;
12343
+ emitBrowserStatusIfActive(conversationId, event, response);
12484
12344
  }
12485
- conversation._toolResultArchive = harness.getToolResultArchive(conversationId);
12486
- conversation.runtimeRunId = latestRunId || conversation.runtimeRunId;
12487
- conversation.pendingApprovals = [];
12488
- if (runContextTokens > 0) conversation.contextTokens = runContextTokens;
12489
- if (runContextWindow > 0) conversation.contextWindow = runContextWindow;
12490
- conversation.updatedAt = Date.now();
12345
+ });
12346
+ flushTurnDraft(draft);
12347
+ latestRunId = execution.latestRunId || latestRunId;
12348
+ if (!checkpointedRun && !runContinuationMessages) {
12349
+ conversation.messages = buildMessages();
12350
+ applyTurnMetadata(conversation, {
12351
+ latestRunId,
12352
+ contextTokens: execution.runContextTokens,
12353
+ contextWindow: execution.runContextWindow,
12354
+ harnessMessages: execution.runHarnessMessages,
12355
+ toolResultArchive: harness.getToolResultArchive(conversationId)
12356
+ }, { shouldRebuildCanonical });
12491
12357
  await conversationStore.update(conversation);
12492
12358
  }
12493
12359
  } catch (error) {
12360
+ flushTurnDraft(draft);
12494
12361
  if (abortController.signal.aborted || runCancelled) {
12495
- const fallbackSections = [...sections];
12496
- if (currentTools.length > 0) {
12497
- fallbackSections.push({ type: "tools", content: [...currentTools] });
12498
- }
12499
- if (currentText.length > 0) {
12500
- fallbackSections.push({ type: "text", content: currentText });
12501
- }
12502
- if (assistantResponse.length > 0 || toolTimeline.length > 0 || fallbackSections.length > 0) {
12503
- conversation.messages = [
12504
- ...historyMessages,
12505
- ...userContent != null ? [{ role: "user", content: userContent }] : [],
12506
- {
12507
- role: "assistant",
12508
- content: assistantResponse,
12509
- metadata: toolTimeline.length > 0 || fallbackSections.length > 0 ? {
12510
- toolActivity: [...toolTimeline],
12511
- sections: fallbackSections.length > 0 ? fallbackSections : void 0
12512
- } : void 0
12513
- }
12514
- ];
12362
+ if (draft.assistantResponse.length > 0 || draft.toolTimeline.length > 0 || draft.sections.length > 0) {
12363
+ conversation.messages = buildMessages();
12515
12364
  conversation.updatedAt = Date.now();
12516
12365
  await conversationStore.update(conversation);
12517
12366
  }
@@ -12532,26 +12381,8 @@ data: ${JSON.stringify(frame)}
12532
12381
  })
12533
12382
  );
12534
12383
  } catch {
12535
- const fallbackSections = [...sections];
12536
- if (currentTools.length > 0) {
12537
- fallbackSections.push({ type: "tools", content: [...currentTools] });
12538
- }
12539
- if (currentText.length > 0) {
12540
- fallbackSections.push({ type: "text", content: currentText });
12541
- }
12542
- if (assistantResponse.length > 0 || toolTimeline.length > 0 || fallbackSections.length > 0) {
12543
- conversation.messages = [
12544
- ...historyMessages,
12545
- ...userContent != null ? [{ role: "user", content: userContent }] : [],
12546
- {
12547
- role: "assistant",
12548
- content: assistantResponse,
12549
- metadata: toolTimeline.length > 0 || fallbackSections.length > 0 ? {
12550
- toolActivity: [...toolTimeline],
12551
- sections: fallbackSections.length > 0 ? fallbackSections : void 0
12552
- } : void 0
12553
- }
12554
- ];
12384
+ if (draft.assistantResponse.length > 0 || draft.toolTimeline.length > 0 || draft.sections.length > 0) {
12385
+ conversation.messages = buildMessages();
12555
12386
  conversation.updatedAt = Date.now();
12556
12387
  await conversationStore.update(conversation);
12557
12388
  }
@@ -12642,51 +12473,41 @@ ${cronJob.task}`;
12642
12473
  });
12643
12474
  const historyMessages = [...historySelection.messages];
12644
12475
  try {
12645
- const execution = await executeConversationTurn({
12476
+ const result = await runCronAgent(
12646
12477
  harness,
12647
- runInput: {
12648
- task,
12649
- conversationId: conv.conversationId,
12650
- parameters: withToolResultArchiveParam(
12651
- { __activeConversationId: conv.conversationId },
12652
- conv
12653
- ),
12654
- messages: historyMessages
12655
- },
12656
- onEvent: async (event) => {
12478
+ task,
12479
+ conv.conversationId,
12480
+ historyMessages,
12481
+ conv._toolResultArchive,
12482
+ async (event) => {
12657
12483
  await telemetry.emit(event);
12658
12484
  }
12659
- });
12660
- const assistantResponse = execution.draft.assistantResponse;
12661
- conv.messages = [
12662
- ...historyMessages,
12663
- { role: "user", content: task },
12664
- ...assistantResponse ? [{ role: "assistant", content: assistantResponse }] : []
12665
- ];
12666
- if (execution.runHarnessMessages) {
12667
- conv._harnessMessages = execution.runHarnessMessages;
12668
- } else if (historySelection.shouldRebuildCanonical) {
12669
- conv._harnessMessages = conv.messages;
12485
+ );
12486
+ const freshConv = await conversationStore.get(conv.conversationId);
12487
+ if (freshConv) {
12488
+ appendCronTurn(freshConv, task, result);
12489
+ applyTurnMetadata(freshConv, result, {
12490
+ clearContinuation: false,
12491
+ clearApprovals: false,
12492
+ setIdle: false,
12493
+ shouldRebuildCanonical: historySelection.shouldRebuildCanonical
12494
+ });
12495
+ await conversationStore.update(freshConv);
12670
12496
  }
12671
- conv._toolResultArchive = harness.getToolResultArchive(conv.conversationId);
12672
- if (execution.runContextTokens > 0) conv.contextTokens = execution.runContextTokens;
12673
- if (execution.runContextWindow > 0) conv.contextWindow = execution.runContextWindow;
12674
- conv.updatedAt = Date.now();
12675
- await conversationStore.update(conv);
12676
- if (assistantResponse) {
12497
+ if (result.response) {
12677
12498
  try {
12678
12499
  await adapter.sendReply(
12679
12500
  {
12680
12501
  channelId: chatId,
12681
- platformThreadId: conv.channelMeta?.platformThreadId ?? chatId
12502
+ platformThreadId: (freshConv ?? conv).channelMeta?.platformThreadId ?? chatId
12682
12503
  },
12683
- assistantResponse
12504
+ result.response
12684
12505
  );
12685
12506
  } catch (sendError) {
12686
12507
  console.error(`[cron] ${jobName}: send to ${chatId} failed:`, sendError instanceof Error ? sendError.message : sendError);
12687
12508
  }
12688
12509
  }
12689
- chatResults.push({ chatId, status: "completed", steps: execution.runSteps });
12510
+ chatResults.push({ chatId, status: "completed", steps: result.steps });
12690
12511
  } catch (runError) {
12691
12512
  chatResults.push({ chatId, status: "error" });
12692
12513
  console.error(`[cron] ${jobName}: run for chat ${chatId} failed:`, runError instanceof Error ? runError.message : runError);
@@ -12712,7 +12533,6 @@ ${cronJob.task}`;
12712
12533
  cronOwnerId,
12713
12534
  `[cron] ${jobName} ${timestamp}`
12714
12535
  );
12715
- const historyMessages = [];
12716
12536
  const convId = conversation.conversationId;
12717
12537
  activeConversationRuns.set(convId, {
12718
12538
  ownerId: conversation.ownerId,
@@ -12720,117 +12540,28 @@ ${cronJob.task}`;
12720
12540
  runId: null
12721
12541
  });
12722
12542
  try {
12723
- const abortController = new AbortController();
12724
- let assistantResponse = "";
12725
- let latestRunId = "";
12726
- let runContinuationMessages;
12727
- const toolTimeline = [];
12728
- const sections = [];
12729
- let currentTools = [];
12730
- let currentText = "";
12731
- let runResult = {
12732
- status: "completed",
12733
- steps: 0
12734
- };
12735
- const platformMaxDurationSec = Number(process.env.PONCHO_MAX_DURATION) || 0;
12736
- const softDeadlineMs = platformMaxDurationSec > 0 ? platformMaxDurationSec * 800 : 0;
12737
- for await (const event of harness.runWithTelemetry({
12738
- task: cronJob.task,
12739
- conversationId: convId,
12740
- parameters: withToolResultArchiveParam({ __activeConversationId: convId }, conversation),
12741
- messages: historyMessages,
12742
- abortSignal: abortController.signal
12743
- })) {
12744
- if (event.type === "run:started") {
12745
- latestRunId = event.runId;
12746
- }
12747
- if (event.type === "model:chunk") {
12748
- if (currentTools.length > 0) {
12749
- sections.push({ type: "tools", content: currentTools });
12750
- currentTools = [];
12751
- if (assistantResponse.length > 0 && !/\s$/.test(assistantResponse)) {
12752
- assistantResponse += " ";
12753
- }
12754
- }
12755
- assistantResponse += event.content;
12756
- currentText += event.content;
12757
- }
12758
- if (event.type === "tool:started") {
12759
- if (currentText.length > 0) {
12760
- sections.push({ type: "text", content: currentText });
12761
- currentText = "";
12762
- }
12763
- const toolText = `- start \`${event.tool}\``;
12764
- toolTimeline.push(toolText);
12765
- currentTools.push(toolText);
12766
- }
12767
- if (event.type === "tool:completed") {
12768
- const toolText = `- done \`${event.tool}\` (${event.duration}ms)`;
12769
- toolTimeline.push(toolText);
12770
- currentTools.push(toolText);
12543
+ const result = await runCronAgent(
12544
+ harness,
12545
+ cronJob.task,
12546
+ convId,
12547
+ [],
12548
+ conversation._toolResultArchive,
12549
+ async (event) => {
12550
+ broadcastEvent(convId, event);
12551
+ await telemetry.emit(event);
12771
12552
  }
12772
- if (event.type === "tool:error") {
12773
- const toolText = `- error \`${event.tool}\`: ${event.error}`;
12774
- toolTimeline.push(toolText);
12775
- currentTools.push(toolText);
12776
- }
12777
- if (event.type === "run:completed") {
12778
- runResult = {
12779
- status: event.result.status,
12780
- steps: event.result.steps,
12781
- continuation: event.result.continuation,
12782
- contextTokens: event.result.contextTokens,
12783
- contextWindow: event.result.contextWindow,
12784
- harnessMessages: event.result.continuationMessages
12785
- };
12786
- if (event.result.continuation && event.result.continuationMessages) {
12787
- runContinuationMessages = event.result.continuationMessages;
12788
- }
12789
- if (!assistantResponse && event.result.response) {
12790
- assistantResponse = event.result.response;
12791
- }
12792
- }
12793
- broadcastEvent(convId, event);
12794
- await telemetry.emit(event);
12795
- }
12553
+ );
12796
12554
  finishConversationStream(convId);
12797
- if (currentTools.length > 0) {
12798
- sections.push({ type: "tools", content: currentTools });
12799
- }
12800
- if (currentText.length > 0) {
12801
- sections.push({ type: "text", content: currentText });
12802
- currentText = "";
12803
- }
12804
- const hasContent = assistantResponse.length > 0 || toolTimeline.length > 0;
12805
- const assistantMetadata = toolTimeline.length > 0 || sections.length > 0 ? {
12806
- toolActivity: [...toolTimeline],
12807
- sections: sections.length > 0 ? sections : void 0
12808
- } : void 0;
12809
- const messages = [
12810
- ...historyMessages,
12811
- { role: "user", content: cronJob.task },
12812
- ...hasContent ? [{ role: "assistant", content: assistantResponse, metadata: assistantMetadata }] : []
12813
- ];
12814
12555
  const freshConv = await conversationStore.get(convId);
12815
12556
  if (freshConv) {
12816
- freshConv.messages = messages;
12817
- if (runContinuationMessages) {
12818
- freshConv._continuationMessages = runContinuationMessages;
12819
- } else {
12820
- freshConv._continuationMessages = void 0;
12821
- freshConv._continuationCount = void 0;
12822
- }
12823
- if (runResult.harnessMessages) {
12824
- freshConv._harnessMessages = runResult.harnessMessages;
12825
- }
12826
- freshConv._toolResultArchive = harness.getToolResultArchive(convId);
12827
- freshConv.runtimeRunId = latestRunId || freshConv.runtimeRunId;
12828
- if (runResult.contextTokens) freshConv.contextTokens = runResult.contextTokens;
12829
- if (runResult.contextWindow) freshConv.contextWindow = runResult.contextWindow;
12830
- freshConv.updatedAt = Date.now();
12557
+ freshConv.messages = buildCronMessages(cronJob.task, [], result);
12558
+ applyTurnMetadata(freshConv, result, {
12559
+ clearApprovals: false,
12560
+ setIdle: false
12561
+ });
12831
12562
  await conversationStore.update(freshConv);
12832
12563
  }
12833
- if (runResult.continuation) {
12564
+ if (result.continuation) {
12834
12565
  const work = selfFetchWithRetry(`/api/internal/continue/${encodeURIComponent(convId)}`).catch(
12835
12566
  (err) => console.error(`[poncho][cron] Continuation self-fetch failed:`, err instanceof Error ? err.message : err)
12836
12567
  );
@@ -12844,10 +12575,10 @@ ${cronJob.task}`;
12844
12575
  }
12845
12576
  writeJson(response, 200, {
12846
12577
  conversationId: convId,
12847
- status: runResult.status,
12848
- response: assistantResponse.slice(0, 500),
12578
+ status: "completed",
12579
+ response: result.response.slice(0, 500),
12849
12580
  duration: Date.now() - start,
12850
- steps: runResult.steps
12581
+ steps: result.steps
12851
12582
  });
12852
12583
  } finally {
12853
12584
  activeConversationRuns.delete(convId);
@@ -12909,26 +12640,21 @@ Scheduled for: ${new Date(reminder.scheduledAt).toISOString()}`;
12909
12640
  if (channelMeta) {
12910
12641
  const adapter = messagingAdapters.get(channelMeta.platform);
12911
12642
  if (adapter && originConv) {
12912
- const historyMessages = originConv.messages ?? [];
12913
- let assistantResponse = "";
12914
- for await (const event of harness.runWithTelemetry({
12915
- task: framedMessage,
12916
- conversationId: originConv.conversationId,
12917
- parameters: { __activeConversationId: originConv.conversationId },
12918
- messages: historyMessages
12919
- })) {
12920
- if (event.type === "model:chunk") {
12921
- assistantResponse += event.content;
12922
- }
12923
- }
12924
- if (assistantResponse) {
12643
+ const result = await runCronAgent(
12644
+ harness,
12645
+ framedMessage,
12646
+ originConv.conversationId,
12647
+ originConv.messages ?? [],
12648
+ originConv._toolResultArchive
12649
+ );
12650
+ if (result.response) {
12925
12651
  try {
12926
12652
  await adapter.sendReply(
12927
12653
  {
12928
12654
  channelId: channelMeta.channelId,
12929
12655
  platformThreadId: channelMeta.platformThreadId ?? channelMeta.channelId
12930
12656
  },
12931
- assistantResponse
12657
+ result.response
12932
12658
  );
12933
12659
  } catch (sendError) {
12934
12660
  console.error(`[reminder] Send to ${channelMeta.platform} failed:`, sendError instanceof Error ? sendError.message : sendError);
@@ -12936,12 +12662,12 @@ Scheduled for: ${new Date(reminder.scheduledAt).toISOString()}`;
12936
12662
  }
12937
12663
  const freshConv = await conversationStore.get(originConv.conversationId);
12938
12664
  if (freshConv) {
12939
- freshConv.messages = [
12940
- ...historyMessages,
12941
- { role: "user", content: framedMessage },
12942
- ...assistantResponse ? [{ role: "assistant", content: assistantResponse }] : []
12943
- ];
12944
- freshConv.updatedAt = Date.now();
12665
+ appendCronTurn(freshConv, framedMessage, result);
12666
+ applyTurnMetadata(freshConv, result, {
12667
+ clearContinuation: false,
12668
+ clearApprovals: false,
12669
+ setIdle: false
12670
+ });
12945
12671
  await conversationStore.update(freshConv);
12946
12672
  }
12947
12673
  }
@@ -12952,24 +12678,15 @@ Scheduled for: ${new Date(reminder.scheduledAt).toISOString()}`;
12952
12678
  `[reminder] ${reminder.task.slice(0, 80)} ${timestamp}`
12953
12679
  );
12954
12680
  const convId = conversation.conversationId;
12955
- let assistantResponse = "";
12956
- for await (const event of harness.runWithTelemetry({
12957
- task: framedMessage,
12958
- conversationId: convId,
12959
- parameters: { __activeConversationId: convId },
12960
- messages: []
12961
- })) {
12962
- if (event.type === "model:chunk") {
12963
- assistantResponse += event.content;
12964
- }
12965
- }
12681
+ const result = await runCronAgent(harness, framedMessage, convId, []);
12966
12682
  const freshConv = await conversationStore.get(convId);
12967
12683
  if (freshConv) {
12968
- freshConv.messages = [
12969
- { role: "user", content: framedMessage },
12970
- ...assistantResponse ? [{ role: "assistant", content: assistantResponse }] : []
12971
- ];
12972
- freshConv.updatedAt = Date.now();
12684
+ freshConv.messages = buildCronMessages(framedMessage, [], result);
12685
+ applyTurnMetadata(freshConv, result, {
12686
+ clearContinuation: false,
12687
+ clearApprovals: false,
12688
+ setIdle: false
12689
+ });
12973
12690
  await conversationStore.update(freshConv);
12974
12691
  }
12975
12692
  }
@@ -13044,39 +12761,6 @@ var startDevServer = async (port, options) => {
13044
12761
  await checkVercelCronDrift(workingDir);
13045
12762
  const { Cron } = await import("croner");
13046
12763
  let activeJobs = [];
13047
- const runCronAgent = async (harnessRef, task, conversationId, historyMessages, toolResultArchive, onEvent) => {
13048
- const execution = await executeConversationTurn({
13049
- harness: harnessRef,
13050
- runInput: {
13051
- task,
13052
- conversationId,
13053
- parameters: {
13054
- __activeConversationId: conversationId,
13055
- [TOOL_RESULT_ARCHIVE_PARAM]: toolResultArchive ?? {}
13056
- },
13057
- messages: historyMessages
13058
- },
13059
- onEvent
13060
- });
13061
- flushTurnDraft(execution.draft);
13062
- const hasContent = execution.draft.assistantResponse.length > 0 || execution.draft.toolTimeline.length > 0;
13063
- const assistantMetadata = buildAssistantMetadata(execution.draft);
13064
- return {
13065
- response: execution.draft.assistantResponse,
13066
- steps: execution.runSteps,
13067
- assistantMetadata,
13068
- hasContent,
13069
- contextTokens: execution.runContextTokens,
13070
- contextWindow: execution.runContextWindow,
13071
- harnessMessages: execution.runHarnessMessages,
13072
- toolResultArchive: harnessRef.getToolResultArchive(conversationId)
13073
- };
13074
- };
13075
- const buildCronMessages = (task, historyMessages, result) => [
13076
- ...historyMessages,
13077
- { role: "user", content: task },
13078
- ...result.hasContent ? [{ role: "assistant", content: result.response, metadata: result.assistantMetadata }] : []
13079
- ];
13080
12764
  const scheduleCronJobs = (jobs) => {
13081
12765
  for (const job of activeJobs) {
13082
12766
  job.stop();
@@ -13153,18 +12837,13 @@ ${config.task}`;
13153
12837
  handler._finishConversationStream?.(convId);
13154
12838
  const freshConv = await store.get(convId);
13155
12839
  if (freshConv) {
13156
- freshConv.messages = buildCronMessages(task, historyMessages, result);
13157
- if (result.harnessMessages) {
13158
- freshConv._harnessMessages = result.harnessMessages;
13159
- } else if (historySelection.shouldRebuildCanonical) {
13160
- freshConv._harnessMessages = freshConv.messages;
13161
- }
13162
- if (result.toolResultArchive) {
13163
- freshConv._toolResultArchive = result.toolResultArchive;
13164
- }
13165
- if (result.contextTokens > 0) freshConv.contextTokens = result.contextTokens;
13166
- if (result.contextWindow > 0) freshConv.contextWindow = result.contextWindow;
13167
- freshConv.updatedAt = Date.now();
12840
+ appendCronTurn(freshConv, task, result);
12841
+ applyTurnMetadata(freshConv, result, {
12842
+ clearContinuation: false,
12843
+ clearApprovals: false,
12844
+ setIdle: false,
12845
+ shouldRebuildCanonical: historySelection.shouldRebuildCanonical
12846
+ });
13168
12847
  await store.update(freshConv);
13169
12848
  if (result.response) {
13170
12849
  try {
@@ -13234,15 +12913,11 @@ ${config.task}`;
13234
12913
  const freshConv = await store.get(cronConvId);
13235
12914
  if (freshConv) {
13236
12915
  freshConv.messages = buildCronMessages(config.task, [], result);
13237
- if (result.harnessMessages) {
13238
- freshConv._harnessMessages = result.harnessMessages;
13239
- }
13240
- if (result.toolResultArchive) {
13241
- freshConv._toolResultArchive = result.toolResultArchive;
13242
- }
13243
- if (result.contextTokens > 0) freshConv.contextTokens = result.contextTokens;
13244
- if (result.contextWindow > 0) freshConv.contextWindow = result.contextWindow;
13245
- freshConv.updatedAt = Date.now();
12916
+ applyTurnMetadata(freshConv, result, {
12917
+ clearContinuation: false,
12918
+ clearApprovals: false,
12919
+ setIdle: false
12920
+ });
13246
12921
  await store.update(freshConv);
13247
12922
  }
13248
12923
  const elapsed = ((Date.now() - start) / 1e3).toFixed(1);
@@ -13396,7 +13071,7 @@ var runInteractive = async (workingDir, params) => {
13396
13071
  await harness.initialize();
13397
13072
  const identity = await ensureAgentIdentity2(workingDir);
13398
13073
  try {
13399
- const { runInteractiveInk } = await import("./run-interactive-ink-R4PHKIQR.js");
13074
+ const { runInteractiveInk } = await import("./run-interactive-ink-VS35YSBB.js");
13400
13075
  await runInteractiveInk({
13401
13076
  harness,
13402
13077
  params,