@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.
- package/.turbo/turbo-build.log +6 -6
- package/CHANGELOG.md +6 -0
- package/dist/{chunk-IDGGF5WH.js → chunk-QAUWCAWU.js} +485 -810
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +1 -1
- package/dist/{run-interactive-ink-R4PHKIQR.js → run-interactive-ink-VS35YSBB.js} +1 -1
- package/package.json +3 -3
- package/src/index.ts +586 -923
- package/src/init-onboarding.ts +2 -7
package/src/index.ts
CHANGED
|
@@ -303,15 +303,21 @@ const parseParams = (values: string[]): Record<string, string> => {
|
|
|
303
303
|
return params;
|
|
304
304
|
};
|
|
305
305
|
|
|
306
|
-
const normalizeMessageForClient = (message: Message): Message => {
|
|
306
|
+
const normalizeMessageForClient = (message: Message): Message | null => {
|
|
307
|
+
// Hide tool-role and system-role messages from the web UI — they are
|
|
308
|
+
// internal harness bookkeeping that leaks into conv.messages when
|
|
309
|
+
// _harnessMessages are used as canonical history.
|
|
310
|
+
if (message.role === "tool" || message.role === "system") {
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
307
313
|
if (message.role !== "assistant" || typeof message.content !== "string") {
|
|
308
314
|
return message;
|
|
309
315
|
}
|
|
310
316
|
try {
|
|
311
317
|
const parsed = JSON.parse(message.content) as Record<string, unknown>;
|
|
312
|
-
const text = typeof parsed.text === "string" ? parsed.text : undefined;
|
|
313
318
|
const toolCalls = Array.isArray(parsed.tool_calls) ? parsed.tool_calls : undefined;
|
|
314
|
-
if (
|
|
319
|
+
if (toolCalls) {
|
|
320
|
+
const text = typeof parsed.text === "string" ? parsed.text : "";
|
|
315
321
|
const meta = { ...(message.metadata ?? {}) } as Record<string, unknown>;
|
|
316
322
|
if (!meta.sections && toolCalls.length > 0) {
|
|
317
323
|
const toolLabels = toolCalls.map((tc: Record<string, unknown>) => {
|
|
@@ -491,12 +497,14 @@ const buildAssistantMetadata = (
|
|
|
491
497
|
const executeConversationTurn = async ({
|
|
492
498
|
harness,
|
|
493
499
|
runInput,
|
|
500
|
+
events,
|
|
494
501
|
initialContextTokens = 0,
|
|
495
502
|
initialContextWindow = 0,
|
|
496
503
|
onEvent,
|
|
497
504
|
}: {
|
|
498
505
|
harness: AgentHarness;
|
|
499
|
-
runInput
|
|
506
|
+
runInput?: Parameters<AgentHarness["runWithTelemetry"]>[0];
|
|
507
|
+
events?: AsyncIterable<AgentEvent>;
|
|
500
508
|
initialContextTokens?: number;
|
|
501
509
|
initialContextWindow?: number;
|
|
502
510
|
onEvent?: (event: AgentEvent, draft: TurnDraftState) => void | Promise<void>;
|
|
@@ -512,7 +520,8 @@ const executeConversationTurn = async ({
|
|
|
512
520
|
let runSteps = 0;
|
|
513
521
|
let runMaxSteps: number | undefined;
|
|
514
522
|
|
|
515
|
-
|
|
523
|
+
const source = events ?? harness.runWithTelemetry(runInput!);
|
|
524
|
+
for await (const event of source) {
|
|
516
525
|
recordStandardTurnEvent(draft, event);
|
|
517
526
|
if (event.type === "run:started") {
|
|
518
527
|
latestRunId = event.runId;
|
|
@@ -634,6 +643,142 @@ export const __internalRunOrchestration = {
|
|
|
634
643
|
executeConversationTurn,
|
|
635
644
|
};
|
|
636
645
|
|
|
646
|
+
// ── Shared turn metadata helper ──────────────────────────────────
|
|
647
|
+
// Standardises post-run metadata persistence across all execution paths.
|
|
648
|
+
|
|
649
|
+
type TurnResultMetadata = {
|
|
650
|
+
latestRunId: string;
|
|
651
|
+
contextTokens: number;
|
|
652
|
+
contextWindow: number;
|
|
653
|
+
continuation?: boolean;
|
|
654
|
+
continuationMessages?: Message[];
|
|
655
|
+
harnessMessages?: Message[];
|
|
656
|
+
toolResultArchive?: Conversation["_toolResultArchive"];
|
|
657
|
+
};
|
|
658
|
+
|
|
659
|
+
const applyTurnMetadata = (
|
|
660
|
+
conv: Conversation,
|
|
661
|
+
meta: TurnResultMetadata,
|
|
662
|
+
opts: {
|
|
663
|
+
clearContinuation?: boolean;
|
|
664
|
+
clearApprovals?: boolean;
|
|
665
|
+
setIdle?: boolean;
|
|
666
|
+
shouldRebuildCanonical?: boolean;
|
|
667
|
+
} = {},
|
|
668
|
+
): void => {
|
|
669
|
+
const {
|
|
670
|
+
clearContinuation = true,
|
|
671
|
+
clearApprovals = true,
|
|
672
|
+
setIdle = true,
|
|
673
|
+
shouldRebuildCanonical = false,
|
|
674
|
+
} = opts;
|
|
675
|
+
|
|
676
|
+
if (meta.continuation && meta.continuationMessages) {
|
|
677
|
+
conv._continuationMessages = meta.continuationMessages;
|
|
678
|
+
} else if (clearContinuation) {
|
|
679
|
+
conv._continuationMessages = undefined;
|
|
680
|
+
conv._continuationCount = undefined;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
if (meta.harnessMessages) {
|
|
684
|
+
conv._harnessMessages = meta.harnessMessages;
|
|
685
|
+
} else if (shouldRebuildCanonical) {
|
|
686
|
+
conv._harnessMessages = conv.messages;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
if (meta.toolResultArchive !== undefined) {
|
|
690
|
+
conv._toolResultArchive = meta.toolResultArchive;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
conv.runtimeRunId = meta.latestRunId || conv.runtimeRunId;
|
|
694
|
+
|
|
695
|
+
if (clearApprovals) conv.pendingApprovals = [];
|
|
696
|
+
if (setIdle) conv.runStatus = "idle";
|
|
697
|
+
|
|
698
|
+
if (meta.contextTokens > 0) conv.contextTokens = meta.contextTokens;
|
|
699
|
+
if (meta.contextWindow > 0) conv.contextWindow = meta.contextWindow;
|
|
700
|
+
|
|
701
|
+
conv.updatedAt = Date.now();
|
|
702
|
+
};
|
|
703
|
+
|
|
704
|
+
// ── Shared cron helpers ──────────────────────────────────────────
|
|
705
|
+
// Used by both the HTTP /api/cron endpoint and the local-dev scheduler.
|
|
706
|
+
|
|
707
|
+
type CronRunResult = {
|
|
708
|
+
response: string;
|
|
709
|
+
steps: number;
|
|
710
|
+
assistantMetadata?: Message["metadata"];
|
|
711
|
+
hasContent: boolean;
|
|
712
|
+
contextTokens: number;
|
|
713
|
+
contextWindow: number;
|
|
714
|
+
harnessMessages?: Message[];
|
|
715
|
+
toolResultArchive?: Conversation["_toolResultArchive"];
|
|
716
|
+
latestRunId: string;
|
|
717
|
+
continuation: boolean;
|
|
718
|
+
continuationMessages?: Message[];
|
|
719
|
+
};
|
|
720
|
+
|
|
721
|
+
const runCronAgent = async (
|
|
722
|
+
harnessRef: AgentHarness,
|
|
723
|
+
task: string,
|
|
724
|
+
conversationId: string,
|
|
725
|
+
historyMessages: Message[],
|
|
726
|
+
toolResultArchive?: Conversation["_toolResultArchive"],
|
|
727
|
+
onEvent?: (event: AgentEvent) => void | Promise<void>,
|
|
728
|
+
): Promise<CronRunResult> => {
|
|
729
|
+
const execution = await executeConversationTurn({
|
|
730
|
+
harness: harnessRef,
|
|
731
|
+
runInput: {
|
|
732
|
+
task,
|
|
733
|
+
conversationId,
|
|
734
|
+
parameters: {
|
|
735
|
+
__activeConversationId: conversationId,
|
|
736
|
+
[TOOL_RESULT_ARCHIVE_PARAM]: toolResultArchive ?? {},
|
|
737
|
+
},
|
|
738
|
+
messages: historyMessages,
|
|
739
|
+
},
|
|
740
|
+
onEvent,
|
|
741
|
+
});
|
|
742
|
+
flushTurnDraft(execution.draft);
|
|
743
|
+
const hasContent = execution.draft.assistantResponse.length > 0 || execution.draft.toolTimeline.length > 0;
|
|
744
|
+
const assistantMetadata = buildAssistantMetadata(execution.draft);
|
|
745
|
+
return {
|
|
746
|
+
response: execution.draft.assistantResponse,
|
|
747
|
+
steps: execution.runSteps,
|
|
748
|
+
assistantMetadata,
|
|
749
|
+
hasContent,
|
|
750
|
+
contextTokens: execution.runContextTokens,
|
|
751
|
+
contextWindow: execution.runContextWindow,
|
|
752
|
+
harnessMessages: execution.runHarnessMessages,
|
|
753
|
+
toolResultArchive: harnessRef.getToolResultArchive(conversationId),
|
|
754
|
+
latestRunId: execution.latestRunId,
|
|
755
|
+
continuation: execution.runContinuation,
|
|
756
|
+
continuationMessages: execution.runContinuationMessages,
|
|
757
|
+
};
|
|
758
|
+
};
|
|
759
|
+
|
|
760
|
+
const buildCronMessages = (
|
|
761
|
+
task: string,
|
|
762
|
+
historyMessages: Message[],
|
|
763
|
+
result: CronRunResult,
|
|
764
|
+
): Message[] => [
|
|
765
|
+
...historyMessages,
|
|
766
|
+
{ role: "user" as const, content: task },
|
|
767
|
+
...(result.hasContent
|
|
768
|
+
? [{ role: "assistant" as const, content: result.response, metadata: result.assistantMetadata }]
|
|
769
|
+
: []),
|
|
770
|
+
];
|
|
771
|
+
|
|
772
|
+
/** Append a cron turn to a freshly-fetched conversation (avoids overwriting concurrent writes). */
|
|
773
|
+
const appendCronTurn = (conv: Conversation, task: string, result: CronRunResult): void => {
|
|
774
|
+
conv.messages.push(
|
|
775
|
+
{ role: "user" as const, content: task },
|
|
776
|
+
...(result.hasContent
|
|
777
|
+
? [{ role: "assistant" as const, content: result.response, metadata: result.assistantMetadata }]
|
|
778
|
+
: []),
|
|
779
|
+
);
|
|
780
|
+
};
|
|
781
|
+
|
|
637
782
|
const AGENT_TEMPLATE = (
|
|
638
783
|
name: string,
|
|
639
784
|
id: string,
|
|
@@ -2701,30 +2846,23 @@ export const createRequestHandler = async (options?: {
|
|
|
2701
2846
|
if (callbackNeedsContinuation || execution.draft.assistantResponse.length > 0 || execution.draft.toolTimeline.length > 0) {
|
|
2702
2847
|
const freshConv = await conversationStore.get(conversationId);
|
|
2703
2848
|
if (freshConv) {
|
|
2704
|
-
if (callbackNeedsContinuation) {
|
|
2705
|
-
freshConv._continuationMessages = execution.runContinuationMessages;
|
|
2706
|
-
} else {
|
|
2707
|
-
freshConv._continuationMessages = undefined;
|
|
2849
|
+
if (!callbackNeedsContinuation) {
|
|
2708
2850
|
freshConv.messages.push({
|
|
2709
2851
|
role: "assistant",
|
|
2710
2852
|
content: execution.draft.assistantResponse,
|
|
2711
2853
|
metadata: buildAssistantMetadata(execution.draft),
|
|
2712
2854
|
});
|
|
2713
2855
|
}
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2856
|
+
applyTurnMetadata(freshConv, {
|
|
2857
|
+
latestRunId: execution.latestRunId,
|
|
2858
|
+
contextTokens: execution.runContextTokens,
|
|
2859
|
+
contextWindow: execution.runContextWindow,
|
|
2860
|
+
continuation: !!callbackNeedsContinuation,
|
|
2861
|
+
continuationMessages: execution.runContinuationMessages,
|
|
2862
|
+
harnessMessages: callbackNeedsContinuation ? execution.runHarnessMessages : undefined,
|
|
2863
|
+
toolResultArchive: harness.getToolResultArchive(conversationId),
|
|
2864
|
+
}, { shouldRebuildCanonical: true, clearApprovals: false });
|
|
2723
2865
|
freshConv.runningCallbackSince = undefined;
|
|
2724
|
-
freshConv.runStatus = "idle";
|
|
2725
|
-
if (execution.runContextTokens > 0) freshConv.contextTokens = execution.runContextTokens;
|
|
2726
|
-
if (execution.runContextWindow > 0) freshConv.contextWindow = execution.runContextWindow;
|
|
2727
|
-
freshConv.updatedAt = Date.now();
|
|
2728
2866
|
await conversationStore.update(freshConv);
|
|
2729
2867
|
|
|
2730
2868
|
// Proactive messaging notification if conversation has a messaging channel
|
|
@@ -2955,15 +3093,7 @@ export const createRequestHandler = async (options?: {
|
|
|
2955
3093
|
runId: null,
|
|
2956
3094
|
});
|
|
2957
3095
|
let latestRunId = conversation.runtimeRunId ?? "";
|
|
2958
|
-
let assistantResponse = "";
|
|
2959
|
-
const toolTimeline: string[] = [];
|
|
2960
|
-
const sections: Array<{ type: "text" | "tools"; content: string | string[] }> = [];
|
|
2961
|
-
let currentText = "";
|
|
2962
|
-
let currentTools: string[] = [];
|
|
2963
3096
|
let checkpointedRun = false;
|
|
2964
|
-
let runContextTokens = conversation.contextTokens ?? 0;
|
|
2965
|
-
let runContextWindow = conversation.contextWindow ?? 0;
|
|
2966
|
-
let resumeHarnessMessages: Message[] | undefined;
|
|
2967
3097
|
|
|
2968
3098
|
const normalizedCheckpoint = normalizeApprovalCheckpoint(checkpoint, conversation.messages);
|
|
2969
3099
|
const baseMessages = normalizedCheckpoint.baseMessageCount != null
|
|
@@ -3006,136 +3136,103 @@ export const createRequestHandler = async (options?: {
|
|
|
3006
3136
|
? [...fullCheckpointMessages, resumeToolResultMsg]
|
|
3007
3137
|
: fullCheckpointMessages;
|
|
3008
3138
|
|
|
3139
|
+
let draftRef: TurnDraftState | undefined;
|
|
3140
|
+
let execution: ExecuteTurnResult | undefined;
|
|
3141
|
+
|
|
3009
3142
|
try {
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
if (assistantResponse.length > 0 && !/\s$/.test(assistantResponse)) {
|
|
3030
|
-
assistantResponse += " ";
|
|
3143
|
+
execution = await executeConversationTurn({
|
|
3144
|
+
harness,
|
|
3145
|
+
events: harness.continueFromToolResult({
|
|
3146
|
+
messages: fullCheckpointMessages,
|
|
3147
|
+
toolResults,
|
|
3148
|
+
conversationId,
|
|
3149
|
+
abortSignal: abortController.signal,
|
|
3150
|
+
}),
|
|
3151
|
+
initialContextTokens: conversation.contextTokens ?? 0,
|
|
3152
|
+
initialContextWindow: conversation.contextWindow ?? 0,
|
|
3153
|
+
onEvent: async (event, draft) => {
|
|
3154
|
+
draftRef = draft;
|
|
3155
|
+
if (event.type === "run:started") {
|
|
3156
|
+
latestRunId = event.runId;
|
|
3157
|
+
runOwners.set(event.runId, conversation.ownerId);
|
|
3158
|
+
runConversations.set(event.runId, conversationId);
|
|
3159
|
+
const active = activeConversationRuns.get(conversationId);
|
|
3160
|
+
if (active && active.abortController === abortController) {
|
|
3161
|
+
active.runId = event.runId;
|
|
3031
3162
|
}
|
|
3032
3163
|
}
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
if (currentText.length > 0) {
|
|
3038
|
-
sections.push({ type: "text", content: currentText });
|
|
3039
|
-
currentText = "";
|
|
3164
|
+
if (event.type === "tool:approval:required") {
|
|
3165
|
+
const toolText = `- approval required \`${event.tool}\``;
|
|
3166
|
+
draft.toolTimeline.push(toolText);
|
|
3167
|
+
draft.currentTools.push(toolText);
|
|
3040
3168
|
}
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
currentTools.push(toolText);
|
|
3054
|
-
}
|
|
3055
|
-
if (event.type === "tool:approval:required") {
|
|
3056
|
-
const toolText = `- approval required \`${event.tool}\``;
|
|
3057
|
-
toolTimeline.push(toolText);
|
|
3058
|
-
currentTools.push(toolText);
|
|
3059
|
-
}
|
|
3060
|
-
if (event.type === "tool:approval:checkpoint") {
|
|
3061
|
-
const conv = await conversationStore.get(conversationId);
|
|
3062
|
-
if (conv) {
|
|
3063
|
-
conv.pendingApprovals = buildApprovalCheckpoints({
|
|
3064
|
-
approvals: event.approvals,
|
|
3065
|
-
runId: latestRunId,
|
|
3066
|
-
checkpointMessages: [...fullCheckpointWithResults, ...event.checkpointMessages],
|
|
3067
|
-
baseMessageCount: 0,
|
|
3068
|
-
pendingToolCalls: event.pendingToolCalls,
|
|
3069
|
-
});
|
|
3070
|
-
conv.updatedAt = Date.now();
|
|
3071
|
-
await conversationStore.update(conv);
|
|
3169
|
+
if (event.type === "tool:approval:checkpoint") {
|
|
3170
|
+
const conv = await conversationStore.get(conversationId);
|
|
3171
|
+
if (conv) {
|
|
3172
|
+
conv.pendingApprovals = buildApprovalCheckpoints({
|
|
3173
|
+
approvals: event.approvals,
|
|
3174
|
+
runId: latestRunId,
|
|
3175
|
+
checkpointMessages: [...fullCheckpointWithResults, ...event.checkpointMessages],
|
|
3176
|
+
baseMessageCount: 0,
|
|
3177
|
+
pendingToolCalls: event.pendingToolCalls,
|
|
3178
|
+
});
|
|
3179
|
+
conv.updatedAt = Date.now();
|
|
3180
|
+
await conversationStore.update(conv);
|
|
3072
3181
|
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3182
|
+
if (conv.channelMeta?.platform === "telegram") {
|
|
3183
|
+
const tgAdapter = messagingAdapters.get("telegram") as TelegramAdapter | undefined;
|
|
3184
|
+
if (tgAdapter) {
|
|
3185
|
+
const messageThreadId = parseTelegramMessageThreadIdFromPlatformThreadId(
|
|
3186
|
+
conv.channelMeta.platformThreadId,
|
|
3187
|
+
conv.channelMeta.channelId,
|
|
3188
|
+
);
|
|
3189
|
+
void tgAdapter.sendApprovalRequest(
|
|
3190
|
+
conv.channelMeta.channelId,
|
|
3191
|
+
event.approvals.map(a => ({ approvalId: a.approvalId, tool: a.tool, input: a.input })),
|
|
3192
|
+
{ message_thread_id: messageThreadId },
|
|
3193
|
+
).catch(() => {});
|
|
3194
|
+
}
|
|
3085
3195
|
}
|
|
3086
3196
|
}
|
|
3197
|
+
checkpointedRun = true;
|
|
3087
3198
|
}
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
runContextWindow = event.result.contextWindow ?? runContextWindow;
|
|
3096
|
-
if (event.result.continuationMessages) {
|
|
3097
|
-
resumeHarnessMessages = event.result.continuationMessages;
|
|
3098
|
-
}
|
|
3099
|
-
}
|
|
3100
|
-
if (event.type === "run:error") {
|
|
3101
|
-
assistantResponse = assistantResponse || `[Error: ${event.error.message}]`;
|
|
3102
|
-
}
|
|
3103
|
-
await telemetry.emit(event);
|
|
3104
|
-
broadcastEvent(conversationId, event);
|
|
3105
|
-
emitBrowserStatusIfActive(conversationId, event);
|
|
3106
|
-
}
|
|
3199
|
+
await telemetry.emit(event);
|
|
3200
|
+
broadcastEvent(conversationId, event);
|
|
3201
|
+
emitBrowserStatusIfActive(conversationId, event);
|
|
3202
|
+
},
|
|
3203
|
+
});
|
|
3204
|
+
flushTurnDraft(execution.draft);
|
|
3205
|
+
latestRunId = execution.latestRunId || latestRunId;
|
|
3107
3206
|
} catch (err) {
|
|
3108
3207
|
console.error("[resume-run] error:", err instanceof Error ? err.message : err);
|
|
3109
|
-
|
|
3208
|
+
if (draftRef) {
|
|
3209
|
+
draftRef.assistantResponse = draftRef.assistantResponse || `[Error: ${err instanceof Error ? err.message : "Unknown error"}]`;
|
|
3210
|
+
flushTurnDraft(draftRef);
|
|
3211
|
+
}
|
|
3110
3212
|
}
|
|
3111
3213
|
|
|
3112
|
-
|
|
3113
|
-
sections.push({ type: "tools", content: currentTools });
|
|
3114
|
-
}
|
|
3115
|
-
if (currentText.length > 0) {
|
|
3116
|
-
sections.push({ type: "text", content: currentText });
|
|
3117
|
-
}
|
|
3214
|
+
const draft = execution?.draft ?? draftRef ?? createTurnDraftState();
|
|
3118
3215
|
|
|
3119
3216
|
if (!checkpointedRun) {
|
|
3120
3217
|
const conv = await conversationStore.get(conversationId);
|
|
3121
3218
|
if (conv) {
|
|
3122
|
-
const prevMessages = conv.messages;
|
|
3123
3219
|
const hasAssistantContent =
|
|
3124
|
-
assistantResponse.length > 0 || toolTimeline.length > 0 || sections.length > 0;
|
|
3220
|
+
draft.assistantResponse.length > 0 || draft.toolTimeline.length > 0 || draft.sections.length > 0;
|
|
3125
3221
|
if (hasAssistantContent) {
|
|
3222
|
+
const prevMessages = conv.messages;
|
|
3126
3223
|
const lastMsg = prevMessages[prevMessages.length - 1];
|
|
3127
3224
|
if (lastMsg && lastMsg.role === "assistant" && lastMsg.metadata) {
|
|
3128
3225
|
const existingToolActivity = (lastMsg.metadata as Record<string, unknown>).toolActivity;
|
|
3129
3226
|
const existingSections = (lastMsg.metadata as Record<string, unknown>).sections;
|
|
3130
3227
|
const mergedTimeline = [
|
|
3131
3228
|
...(Array.isArray(existingToolActivity) ? existingToolActivity as string[] : []),
|
|
3132
|
-
...toolTimeline,
|
|
3229
|
+
...draft.toolTimeline,
|
|
3133
3230
|
];
|
|
3134
3231
|
const mergedSections = [
|
|
3135
3232
|
...(Array.isArray(existingSections) ? existingSections as Array<{ type: "text" | "tools"; content: string | string[] }> : []),
|
|
3136
|
-
...sections,
|
|
3233
|
+
...draft.sections,
|
|
3137
3234
|
];
|
|
3138
|
-
const mergedText = (typeof lastMsg.content === "string" ? lastMsg.content : "") + assistantResponse;
|
|
3235
|
+
const mergedText = (typeof lastMsg.content === "string" ? lastMsg.content : "") + draft.assistantResponse;
|
|
3139
3236
|
conv.messages = [
|
|
3140
3237
|
...prevMessages.slice(0, -1),
|
|
3141
3238
|
{
|
|
@@ -3152,25 +3249,18 @@ export const createRequestHandler = async (options?: {
|
|
|
3152
3249
|
...prevMessages,
|
|
3153
3250
|
{
|
|
3154
3251
|
role: "assistant" as const,
|
|
3155
|
-
content: assistantResponse,
|
|
3156
|
-
metadata: (
|
|
3157
|
-
? { toolActivity: toolTimeline, sections: sections.length > 0 ? sections : undefined }
|
|
3158
|
-
: undefined) as Message["metadata"],
|
|
3252
|
+
content: draft.assistantResponse,
|
|
3253
|
+
metadata: buildAssistantMetadata(draft),
|
|
3159
3254
|
},
|
|
3160
3255
|
];
|
|
3161
3256
|
}
|
|
3162
3257
|
}
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
conv.pendingApprovals = [];
|
|
3170
|
-
conv.runStatus = "idle";
|
|
3171
|
-
if (runContextTokens > 0) conv.contextTokens = runContextTokens;
|
|
3172
|
-
if (runContextWindow > 0) conv.contextWindow = runContextWindow;
|
|
3173
|
-
conv.updatedAt = Date.now();
|
|
3258
|
+
applyTurnMetadata(conv, {
|
|
3259
|
+
latestRunId,
|
|
3260
|
+
contextTokens: execution?.runContextTokens ?? 0,
|
|
3261
|
+
contextWindow: execution?.runContextWindow ?? 0,
|
|
3262
|
+
harnessMessages: execution?.runHarnessMessages,
|
|
3263
|
+
}, { shouldRebuildCanonical: true });
|
|
3174
3264
|
await conversationStore.update(conv);
|
|
3175
3265
|
}
|
|
3176
3266
|
} else {
|
|
@@ -3341,7 +3431,7 @@ export const createRequestHandler = async (options?: {
|
|
|
3341
3431
|
conversationId,
|
|
3342
3432
|
messages: historyMessages,
|
|
3343
3433
|
files: input.files,
|
|
3344
|
-
parameters: {
|
|
3434
|
+
parameters: withToolResultArchiveParam({
|
|
3345
3435
|
...(input.metadata ? {
|
|
3346
3436
|
__messaging_platform: input.metadata.platform,
|
|
3347
3437
|
__messaging_sender_id: input.metadata.sender.id,
|
|
@@ -3349,7 +3439,7 @@ export const createRequestHandler = async (options?: {
|
|
|
3349
3439
|
__messaging_thread_id: input.metadata.threadId,
|
|
3350
3440
|
} : {}),
|
|
3351
3441
|
__activeConversationId: conversationId,
|
|
3352
|
-
},
|
|
3442
|
+
}, latestConversation ?? { _toolResultArchive: {} } as Conversation),
|
|
3353
3443
|
};
|
|
3354
3444
|
|
|
3355
3445
|
try {
|
|
@@ -3448,31 +3538,31 @@ export const createRequestHandler = async (options?: {
|
|
|
3448
3538
|
|
|
3449
3539
|
if (!checkpointedRun) {
|
|
3450
3540
|
await updateConversation((c) => {
|
|
3451
|
-
if (runContinuation && runContinuationMessages) {
|
|
3452
|
-
c._continuationMessages = runContinuationMessages;
|
|
3453
|
-
} else {
|
|
3454
|
-
c._continuationMessages = undefined;
|
|
3541
|
+
if (!(runContinuation && runContinuationMessages)) {
|
|
3455
3542
|
c.messages = buildMessages();
|
|
3456
3543
|
}
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
c.runStatus = "idle";
|
|
3467
|
-
if (runContextTokens > 0) c.contextTokens = runContextTokens;
|
|
3468
|
-
if (runContextWindow > 0) c.contextWindow = runContextWindow;
|
|
3544
|
+
applyTurnMetadata(c, {
|
|
3545
|
+
latestRunId,
|
|
3546
|
+
contextTokens: runContextTokens,
|
|
3547
|
+
contextWindow: runContextWindow,
|
|
3548
|
+
continuation: runContinuation,
|
|
3549
|
+
continuationMessages: runContinuationMessages,
|
|
3550
|
+
harnessMessages: runContinuationMessages,
|
|
3551
|
+
toolResultArchive: harness.getToolResultArchive(conversationId),
|
|
3552
|
+
}, { shouldRebuildCanonical: true });
|
|
3469
3553
|
});
|
|
3470
3554
|
} else {
|
|
3471
3555
|
await updateConversation((c) => {
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3556
|
+
applyTurnMetadata(c, {
|
|
3557
|
+
latestRunId: "",
|
|
3558
|
+
contextTokens: 0,
|
|
3559
|
+
contextWindow: 0,
|
|
3560
|
+
toolResultArchive: harness.getToolResultArchive(conversationId),
|
|
3561
|
+
}, {
|
|
3562
|
+
clearContinuation: false,
|
|
3563
|
+
clearApprovals: false,
|
|
3564
|
+
shouldRebuildCanonical: shouldRebuildCanonical && !c._harnessMessages?.length,
|
|
3565
|
+
});
|
|
3476
3566
|
});
|
|
3477
3567
|
}
|
|
3478
3568
|
finishConversationStream(conversationId);
|
|
@@ -3648,9 +3738,10 @@ export const createRequestHandler = async (options?: {
|
|
|
3648
3738
|
// ── Unified continuation ──────────────────────────────────────────────
|
|
3649
3739
|
const MAX_CONTINUATION_COUNT = 20;
|
|
3650
3740
|
|
|
3651
|
-
async function
|
|
3741
|
+
async function runContinuation(
|
|
3652
3742
|
conversationId: string,
|
|
3653
|
-
|
|
3743
|
+
onYield?: (event: AgentEvent) => void | Promise<void>,
|
|
3744
|
+
): Promise<void> {
|
|
3654
3745
|
const conversation = await conversationStore.get(conversationId);
|
|
3655
3746
|
if (!conversation) return;
|
|
3656
3747
|
if (Array.isArray(conversation.pendingApprovals) && conversation.pendingApprovals.length > 0) return;
|
|
@@ -3693,9 +3784,11 @@ export const createRequestHandler = async (options?: {
|
|
|
3693
3784
|
|
|
3694
3785
|
try {
|
|
3695
3786
|
if (conversation.parentConversationId) {
|
|
3696
|
-
|
|
3787
|
+
for await (const event of runSubagentContinuation(conversationId, conversation, continuationMessages)) {
|
|
3788
|
+
if (onYield) await onYield(event);
|
|
3789
|
+
}
|
|
3697
3790
|
} else {
|
|
3698
|
-
|
|
3791
|
+
await runChatContinuation(conversationId, conversation, continuationMessages, onYield);
|
|
3699
3792
|
}
|
|
3700
3793
|
} finally {
|
|
3701
3794
|
activeConversationRuns.delete(conversationId);
|
|
@@ -3703,136 +3796,66 @@ export const createRequestHandler = async (options?: {
|
|
|
3703
3796
|
}
|
|
3704
3797
|
}
|
|
3705
3798
|
|
|
3706
|
-
async function
|
|
3799
|
+
async function runChatContinuation(
|
|
3707
3800
|
conversationId: string,
|
|
3708
3801
|
conversation: Conversation,
|
|
3709
3802
|
continuationMessages: Message[],
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
if (event.type === "run:started") {
|
|
3732
|
-
latestRunId = event.runId;
|
|
3733
|
-
runOwners.set(event.runId, conversation.ownerId);
|
|
3734
|
-
runConversations.set(event.runId, conversationId);
|
|
3735
|
-
const active = activeConversationRuns.get(conversationId);
|
|
3736
|
-
if (active) active.runId = event.runId;
|
|
3737
|
-
}
|
|
3738
|
-
if (event.type === "model:chunk") {
|
|
3739
|
-
if (currentTools.length > 0) {
|
|
3740
|
-
sections.push({ type: "tools", content: currentTools });
|
|
3741
|
-
currentTools = [];
|
|
3742
|
-
if (assistantResponse.length > 0 && !/\s$/.test(assistantResponse)) {
|
|
3743
|
-
assistantResponse += " ";
|
|
3744
|
-
}
|
|
3745
|
-
}
|
|
3746
|
-
assistantResponse += event.content;
|
|
3747
|
-
currentText += event.content;
|
|
3748
|
-
}
|
|
3749
|
-
if (event.type === "tool:started") {
|
|
3750
|
-
if (currentText.length > 0) {
|
|
3751
|
-
sections.push({ type: "text", content: currentText });
|
|
3752
|
-
currentText = "";
|
|
3753
|
-
}
|
|
3754
|
-
const toolText = `- start \`${event.tool}\``;
|
|
3755
|
-
toolTimeline.push(toolText);
|
|
3756
|
-
currentTools.push(toolText);
|
|
3757
|
-
}
|
|
3758
|
-
if (event.type === "tool:completed") {
|
|
3759
|
-
const toolText = `- done \`${event.tool}\` (${event.duration}ms)`;
|
|
3760
|
-
toolTimeline.push(toolText);
|
|
3761
|
-
currentTools.push(toolText);
|
|
3762
|
-
}
|
|
3763
|
-
if (event.type === "tool:error") {
|
|
3764
|
-
const toolText = `- error \`${event.tool}\`: ${event.error}`;
|
|
3765
|
-
toolTimeline.push(toolText);
|
|
3766
|
-
currentTools.push(toolText);
|
|
3767
|
-
}
|
|
3768
|
-
if (event.type === "run:completed") {
|
|
3769
|
-
runContextTokens = event.result.contextTokens ?? runContextTokens;
|
|
3770
|
-
runContextWindow = event.result.contextWindow ?? runContextWindow;
|
|
3771
|
-
if (event.result.continuation && event.result.continuationMessages) {
|
|
3772
|
-
nextContinuationMessages = event.result.continuationMessages;
|
|
3773
|
-
}
|
|
3774
|
-
if (event.result.continuationMessages) {
|
|
3775
|
-
nextHarnessMessages = event.result.continuationMessages;
|
|
3776
|
-
}
|
|
3777
|
-
if (!assistantResponse && event.result.response) {
|
|
3778
|
-
assistantResponse = event.result.response;
|
|
3803
|
+
onYield?: (event: AgentEvent) => void | Promise<void>,
|
|
3804
|
+
): Promise<void> {
|
|
3805
|
+
const execution = await executeConversationTurn({
|
|
3806
|
+
harness,
|
|
3807
|
+
runInput: {
|
|
3808
|
+
conversationId,
|
|
3809
|
+
parameters: withToolResultArchiveParam({
|
|
3810
|
+
__activeConversationId: conversationId,
|
|
3811
|
+
__ownerId: conversation.ownerId,
|
|
3812
|
+
}, conversation),
|
|
3813
|
+
messages: continuationMessages,
|
|
3814
|
+
abortSignal: activeConversationRuns.get(conversationId)?.abortController.signal,
|
|
3815
|
+
},
|
|
3816
|
+
initialContextTokens: conversation.contextTokens ?? 0,
|
|
3817
|
+
initialContextWindow: conversation.contextWindow ?? 0,
|
|
3818
|
+
onEvent: async (event) => {
|
|
3819
|
+
if (event.type === "run:started") {
|
|
3820
|
+
runOwners.set(event.runId, conversation.ownerId);
|
|
3821
|
+
runConversations.set(event.runId, conversationId);
|
|
3822
|
+
const active = activeConversationRuns.get(conversationId);
|
|
3823
|
+
if (active) active.runId = event.runId;
|
|
3779
3824
|
}
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
}
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
yield event;
|
|
3787
|
-
}
|
|
3788
|
-
|
|
3789
|
-
if (currentTools.length > 0) sections.push({ type: "tools", content: currentTools });
|
|
3790
|
-
if (currentText.length > 0) sections.push({ type: "text", content: currentText });
|
|
3825
|
+
await telemetry.emit(event);
|
|
3826
|
+
broadcastEvent(conversationId, event);
|
|
3827
|
+
if (onYield) await onYield(event);
|
|
3828
|
+
},
|
|
3829
|
+
});
|
|
3830
|
+
flushTurnDraft(execution.draft);
|
|
3791
3831
|
|
|
3792
3832
|
const freshConv = await conversationStore.get(conversationId);
|
|
3793
3833
|
if (!freshConv) return;
|
|
3794
3834
|
|
|
3795
|
-
const hasContent = assistantResponse.length > 0 || toolTimeline.length > 0;
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3835
|
+
const hasContent = execution.draft.assistantResponse.length > 0 || execution.draft.toolTimeline.length > 0;
|
|
3836
|
+
if (hasContent) {
|
|
3837
|
+
freshConv.messages = [
|
|
3838
|
+
...freshConv.messages,
|
|
3839
|
+
{
|
|
3840
|
+
role: "assistant" as const,
|
|
3841
|
+
content: execution.draft.assistantResponse,
|
|
3842
|
+
metadata: buildAssistantMetadata(execution.draft),
|
|
3843
|
+
},
|
|
3844
|
+
];
|
|
3845
|
+
}
|
|
3803
3846
|
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3847
|
+
applyTurnMetadata(freshConv, {
|
|
3848
|
+
latestRunId: execution.latestRunId,
|
|
3849
|
+
contextTokens: execution.runContextTokens,
|
|
3850
|
+
contextWindow: execution.runContextWindow,
|
|
3851
|
+
continuation: execution.runContinuation,
|
|
3852
|
+
continuationMessages: execution.runContinuationMessages,
|
|
3853
|
+
harnessMessages: execution.runHarnessMessages,
|
|
3854
|
+
toolResultArchive: harness.getToolResultArchive(conversationId),
|
|
3855
|
+
}, { shouldRebuildCanonical: true });
|
|
3856
|
+
if (execution.runContinuation) {
|
|
3812
3857
|
freshConv._continuationCount = conversation._continuationCount;
|
|
3813
|
-
} else {
|
|
3814
|
-
if (hasContent) {
|
|
3815
|
-
freshConv.messages = [
|
|
3816
|
-
...freshConv.messages,
|
|
3817
|
-
{ role: "assistant", content: assistantResponse, metadata: assistantMetadata },
|
|
3818
|
-
];
|
|
3819
|
-
}
|
|
3820
|
-
freshConv._continuationMessages = undefined;
|
|
3821
|
-
freshConv._continuationCount = undefined;
|
|
3822
3858
|
}
|
|
3823
|
-
|
|
3824
|
-
if (nextHarnessMessages) {
|
|
3825
|
-
freshConv._harnessMessages = nextHarnessMessages;
|
|
3826
|
-
} else {
|
|
3827
|
-
freshConv._harnessMessages = freshConv.messages;
|
|
3828
|
-
}
|
|
3829
|
-
freshConv._toolResultArchive = harness.getToolResultArchive(conversationId);
|
|
3830
|
-
freshConv.runtimeRunId = latestRunId || freshConv.runtimeRunId;
|
|
3831
|
-
freshConv.pendingApprovals = [];
|
|
3832
|
-
if (runContextTokens > 0) freshConv.contextTokens = runContextTokens;
|
|
3833
|
-
if (runContextWindow > 0) freshConv.contextWindow = runContextWindow;
|
|
3834
|
-
freshConv.runStatus = "idle";
|
|
3835
|
-
freshConv.updatedAt = Date.now();
|
|
3836
3859
|
await conversationStore.update(freshConv);
|
|
3837
3860
|
}
|
|
3838
3861
|
|
|
@@ -4471,9 +4494,7 @@ export const createRequestHandler = async (options?: {
|
|
|
4471
4494
|
writeJson(response, 202, { ok: true });
|
|
4472
4495
|
const work = (async () => {
|
|
4473
4496
|
try {
|
|
4474
|
-
|
|
4475
|
-
// Events are already broadcast inside runContinuation
|
|
4476
|
-
}
|
|
4497
|
+
await runContinuation(conversationId);
|
|
4477
4498
|
// Chain: if another continuation is needed, fire next self-fetch
|
|
4478
4499
|
const conv = await conversationStore.get(conversationId);
|
|
4479
4500
|
if (conv?._continuationMessages?.length) {
|
|
@@ -5202,7 +5223,7 @@ export const createRequestHandler = async (options?: {
|
|
|
5202
5223
|
writeJson(response, 200, {
|
|
5203
5224
|
conversation: {
|
|
5204
5225
|
...conversation,
|
|
5205
|
-
messages: conversation.messages.map(normalizeMessageForClient),
|
|
5226
|
+
messages: conversation.messages.map(normalizeMessageForClient).filter((m): m is Message => m !== null),
|
|
5206
5227
|
pendingApprovals: storedPending,
|
|
5207
5228
|
_continuationMessages: undefined,
|
|
5208
5229
|
_harnessMessages: undefined,
|
|
@@ -5406,7 +5427,7 @@ export const createRequestHandler = async (options?: {
|
|
|
5406
5427
|
|
|
5407
5428
|
let eventCount = 0;
|
|
5408
5429
|
try {
|
|
5409
|
-
|
|
5430
|
+
await runContinuation(conversationId, async (event) => {
|
|
5410
5431
|
eventCount++;
|
|
5411
5432
|
let sseEvent: AgentEvent = event;
|
|
5412
5433
|
if (sseEvent.type === "run:completed") {
|
|
@@ -5420,7 +5441,7 @@ export const createRequestHandler = async (options?: {
|
|
|
5420
5441
|
// Client disconnected — continue processing so the run completes
|
|
5421
5442
|
}
|
|
5422
5443
|
emitBrowserStatusIfActive(conversationId, event, response);
|
|
5423
|
-
}
|
|
5444
|
+
});
|
|
5424
5445
|
} catch (err) {
|
|
5425
5446
|
const errorEvent: AgentEvent = {
|
|
5426
5447
|
type: "run:error",
|
|
@@ -5546,18 +5567,6 @@ export const createRequestHandler = async (options?: {
|
|
|
5546
5567
|
`[poncho] conversation="${conversationId}" history_source=${canonicalHistory.source}`,
|
|
5547
5568
|
);
|
|
5548
5569
|
let latestRunId = conversation.runtimeRunId ?? "";
|
|
5549
|
-
let assistantResponse = "";
|
|
5550
|
-
const toolTimeline: string[] = [];
|
|
5551
|
-
const sections: Array<{ type: "text" | "tools"; content: string | string[] }> = [];
|
|
5552
|
-
let currentText = "";
|
|
5553
|
-
let currentTools: string[] = [];
|
|
5554
|
-
let runCancelled = false;
|
|
5555
|
-
let checkpointedRun = false;
|
|
5556
|
-
let didCompact = false;
|
|
5557
|
-
let runContextTokens = conversation.contextTokens ?? 0;
|
|
5558
|
-
let runContextWindow = conversation.contextWindow ?? 0;
|
|
5559
|
-
let runContinuationMessages: Message[] | undefined;
|
|
5560
|
-
let runHarnessMessages: Message[] | undefined;
|
|
5561
5570
|
let userContent: Message["content"] | undefined = messageText;
|
|
5562
5571
|
if (files.length > 0) {
|
|
5563
5572
|
try {
|
|
@@ -5593,14 +5602,51 @@ export const createRequestHandler = async (options?: {
|
|
|
5593
5602
|
return;
|
|
5594
5603
|
}
|
|
5595
5604
|
}
|
|
5596
|
-
// Forward subagent lifecycle events to the response so the client can update the sidebar.
|
|
5597
|
-
// These events are broadcast via broadcastEvent but not emitted by the harness run loop.
|
|
5598
5605
|
const unsubSubagentEvents = onConversationEvent(conversationId, (evt) => {
|
|
5599
5606
|
if (evt.type.startsWith("subagent:")) {
|
|
5600
5607
|
try { response.write(formatSseEvent(evt)); } catch {}
|
|
5601
5608
|
}
|
|
5602
5609
|
});
|
|
5603
5610
|
|
|
5611
|
+
const draft = createTurnDraftState();
|
|
5612
|
+
let checkpointedRun = false;
|
|
5613
|
+
let runCancelled = false;
|
|
5614
|
+
let runContinuationMessages: Message[] | undefined;
|
|
5615
|
+
|
|
5616
|
+
const buildMessages = (): Message[] => {
|
|
5617
|
+
const draftSections = cloneSections(draft.sections);
|
|
5618
|
+
if (draft.currentTools.length > 0) {
|
|
5619
|
+
draftSections.push({ type: "tools", content: [...draft.currentTools] });
|
|
5620
|
+
}
|
|
5621
|
+
if (draft.currentText.length > 0) {
|
|
5622
|
+
draftSections.push({ type: "text", content: draft.currentText });
|
|
5623
|
+
}
|
|
5624
|
+
const userTurn: Message[] = userContent != null
|
|
5625
|
+
? [{ role: "user" as const, content: userContent }]
|
|
5626
|
+
: [];
|
|
5627
|
+
const hasDraftContent =
|
|
5628
|
+
draft.assistantResponse.length > 0 || draft.toolTimeline.length > 0 || draftSections.length > 0;
|
|
5629
|
+
if (!hasDraftContent) {
|
|
5630
|
+
return [...historyMessages, ...userTurn];
|
|
5631
|
+
}
|
|
5632
|
+
return [
|
|
5633
|
+
...historyMessages,
|
|
5634
|
+
...userTurn,
|
|
5635
|
+
{
|
|
5636
|
+
role: "assistant" as const,
|
|
5637
|
+
content: draft.assistantResponse,
|
|
5638
|
+
metadata: buildAssistantMetadata(draft, draftSections),
|
|
5639
|
+
},
|
|
5640
|
+
];
|
|
5641
|
+
};
|
|
5642
|
+
|
|
5643
|
+
const persistDraftAssistantTurn = async (): Promise<void> => {
|
|
5644
|
+
if (draft.assistantResponse.length === 0 && draft.toolTimeline.length === 0) return;
|
|
5645
|
+
conversation.messages = buildMessages();
|
|
5646
|
+
conversation.updatedAt = Date.now();
|
|
5647
|
+
await conversationStore.update(conversation);
|
|
5648
|
+
};
|
|
5649
|
+
|
|
5604
5650
|
try {
|
|
5605
5651
|
{
|
|
5606
5652
|
conversation.messages = [...historyMessages, { role: "user", content: userContent! }];
|
|
@@ -5612,43 +5658,6 @@ export const createRequestHandler = async (options?: {
|
|
|
5612
5658
|
});
|
|
5613
5659
|
}
|
|
5614
5660
|
|
|
5615
|
-
const persistDraftAssistantTurn = async (): Promise<void> => {
|
|
5616
|
-
const draftSections: Array<{ type: "text" | "tools"; content: string | string[] }> = [
|
|
5617
|
-
...sections.map((section) => ({
|
|
5618
|
-
type: section.type,
|
|
5619
|
-
content: Array.isArray(section.content) ? [...section.content] : section.content,
|
|
5620
|
-
})),
|
|
5621
|
-
];
|
|
5622
|
-
if (currentTools.length > 0) {
|
|
5623
|
-
draftSections.push({ type: "tools", content: [...currentTools] });
|
|
5624
|
-
}
|
|
5625
|
-
if (currentText.length > 0) {
|
|
5626
|
-
draftSections.push({ type: "text", content: currentText });
|
|
5627
|
-
}
|
|
5628
|
-
const hasDraftContent =
|
|
5629
|
-
assistantResponse.length > 0 || toolTimeline.length > 0 || draftSections.length > 0;
|
|
5630
|
-
if (!hasDraftContent) {
|
|
5631
|
-
return;
|
|
5632
|
-
}
|
|
5633
|
-
conversation.messages = [
|
|
5634
|
-
...historyMessages,
|
|
5635
|
-
...(userContent != null ? [{ role: "user" as const, content: userContent }] : []),
|
|
5636
|
-
{
|
|
5637
|
-
role: "assistant",
|
|
5638
|
-
content: assistantResponse,
|
|
5639
|
-
metadata:
|
|
5640
|
-
toolTimeline.length > 0 || draftSections.length > 0
|
|
5641
|
-
? ({
|
|
5642
|
-
toolActivity: [...toolTimeline],
|
|
5643
|
-
sections: draftSections.length > 0 ? draftSections : undefined,
|
|
5644
|
-
} as Message["metadata"])
|
|
5645
|
-
: undefined,
|
|
5646
|
-
},
|
|
5647
|
-
];
|
|
5648
|
-
conversation.updatedAt = Date.now();
|
|
5649
|
-
await conversationStore.update(conversation);
|
|
5650
|
-
};
|
|
5651
|
-
|
|
5652
5661
|
let cachedRecallCorpus: unknown[] | undefined;
|
|
5653
5662
|
const lazyRecallCorpus = async () => {
|
|
5654
5663
|
if (cachedRecallCorpus) return cachedRecallCorpus;
|
|
@@ -5682,281 +5691,168 @@ export const createRequestHandler = async (options?: {
|
|
|
5682
5691
|
return cachedRecallCorpus;
|
|
5683
5692
|
};
|
|
5684
5693
|
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
runCancelled = true;
|
|
5709
|
-
}
|
|
5710
|
-
if (event.type === "model:chunk") {
|
|
5711
|
-
if (currentTools.length > 0) {
|
|
5712
|
-
sections.push({ type: "tools", content: currentTools });
|
|
5713
|
-
currentTools = [];
|
|
5714
|
-
if (assistantResponse.length > 0 && !/\s$/.test(assistantResponse)) {
|
|
5715
|
-
assistantResponse += " ";
|
|
5716
|
-
}
|
|
5717
|
-
}
|
|
5718
|
-
assistantResponse += event.content;
|
|
5719
|
-
currentText += event.content;
|
|
5720
|
-
}
|
|
5721
|
-
if (event.type === "tool:started") {
|
|
5722
|
-
// If we have text accumulated, push it as a text section
|
|
5723
|
-
if (currentText.length > 0) {
|
|
5724
|
-
sections.push({ type: "text", content: currentText });
|
|
5725
|
-
currentText = "";
|
|
5726
|
-
}
|
|
5727
|
-
const toolText = `- start \`${event.tool}\``;
|
|
5728
|
-
toolTimeline.push(toolText);
|
|
5729
|
-
currentTools.push(toolText);
|
|
5730
|
-
}
|
|
5731
|
-
if (event.type === "tool:completed") {
|
|
5732
|
-
const toolText = `- done \`${event.tool}\` (${event.duration}ms)`;
|
|
5733
|
-
toolTimeline.push(toolText);
|
|
5734
|
-
currentTools.push(toolText);
|
|
5735
|
-
}
|
|
5736
|
-
if (event.type === "tool:error") {
|
|
5737
|
-
const toolText = `- error \`${event.tool}\`: ${event.error}`;
|
|
5738
|
-
toolTimeline.push(toolText);
|
|
5739
|
-
currentTools.push(toolText);
|
|
5740
|
-
}
|
|
5741
|
-
if (event.type === "compaction:completed") {
|
|
5742
|
-
didCompact = true;
|
|
5743
|
-
if (event.compactedMessages) {
|
|
5744
|
-
historyMessages.length = 0;
|
|
5745
|
-
historyMessages.push(...event.compactedMessages);
|
|
5694
|
+
const execution = await executeConversationTurn({
|
|
5695
|
+
harness,
|
|
5696
|
+
runInput: {
|
|
5697
|
+
task: messageText,
|
|
5698
|
+
conversationId,
|
|
5699
|
+
parameters: withToolResultArchiveParam({
|
|
5700
|
+
...(bodyParameters ?? {}),
|
|
5701
|
+
__conversationRecallCorpus: lazyRecallCorpus,
|
|
5702
|
+
__activeConversationId: conversationId,
|
|
5703
|
+
__ownerId: ownerId,
|
|
5704
|
+
}, conversation),
|
|
5705
|
+
messages: harnessMessages,
|
|
5706
|
+
files: files.length > 0 ? files : undefined,
|
|
5707
|
+
abortSignal: abortController.signal,
|
|
5708
|
+
},
|
|
5709
|
+
initialContextTokens: conversation.contextTokens ?? 0,
|
|
5710
|
+
initialContextWindow: conversation.contextWindow ?? 0,
|
|
5711
|
+
onEvent: async (event, eventDraft) => {
|
|
5712
|
+
draft.assistantResponse = eventDraft.assistantResponse;
|
|
5713
|
+
draft.toolTimeline = eventDraft.toolTimeline;
|
|
5714
|
+
draft.sections = eventDraft.sections;
|
|
5715
|
+
draft.currentTools = eventDraft.currentTools;
|
|
5716
|
+
draft.currentText = eventDraft.currentText;
|
|
5746
5717
|
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
}
|
|
5756
|
-
if (event.type === "step:completed") {
|
|
5757
|
-
await persistDraftAssistantTurn();
|
|
5758
|
-
}
|
|
5759
|
-
if (event.type === "tool:approval:required") {
|
|
5760
|
-
const toolText = `- approval required \`${event.tool}\``;
|
|
5761
|
-
toolTimeline.push(toolText);
|
|
5762
|
-
currentTools.push(toolText);
|
|
5763
|
-
const existingApprovals = Array.isArray(conversation.pendingApprovals)
|
|
5764
|
-
? conversation.pendingApprovals
|
|
5765
|
-
: [];
|
|
5766
|
-
if (!existingApprovals.some((approval) => approval.approvalId === event.approvalId)) {
|
|
5767
|
-
conversation.pendingApprovals = [
|
|
5768
|
-
...existingApprovals,
|
|
5769
|
-
{
|
|
5770
|
-
approvalId: event.approvalId,
|
|
5771
|
-
runId: latestRunId || conversation.runtimeRunId || "",
|
|
5772
|
-
tool: event.tool,
|
|
5773
|
-
toolCallId: undefined,
|
|
5774
|
-
input: (event.input ?? {}) as Record<string, unknown>,
|
|
5775
|
-
checkpointMessages: undefined,
|
|
5776
|
-
baseMessageCount: historyMessages.length,
|
|
5777
|
-
pendingToolCalls: [],
|
|
5778
|
-
},
|
|
5779
|
-
];
|
|
5780
|
-
conversation.updatedAt = Date.now();
|
|
5781
|
-
await conversationStore.update(conversation);
|
|
5718
|
+
if (event.type === "run:started") {
|
|
5719
|
+
latestRunId = event.runId;
|
|
5720
|
+
runOwners.set(event.runId, ownerId);
|
|
5721
|
+
runConversations.set(event.runId, conversationId);
|
|
5722
|
+
const active = activeConversationRuns.get(conversationId);
|
|
5723
|
+
if (active && active.abortController === abortController) {
|
|
5724
|
+
active.runId = event.runId;
|
|
5725
|
+
}
|
|
5782
5726
|
}
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
if (event.type === "tool:approval:checkpoint") {
|
|
5786
|
-
const checkpointSections = [...sections];
|
|
5787
|
-
if (currentTools.length > 0) {
|
|
5788
|
-
checkpointSections.push({ type: "tools", content: [...currentTools] });
|
|
5727
|
+
if (event.type === "run:cancelled") {
|
|
5728
|
+
runCancelled = true;
|
|
5789
5729
|
}
|
|
5790
|
-
if (
|
|
5791
|
-
|
|
5730
|
+
if (event.type === "compaction:completed") {
|
|
5731
|
+
if (event.compactedMessages) {
|
|
5732
|
+
historyMessages.length = 0;
|
|
5733
|
+
historyMessages.push(...event.compactedMessages);
|
|
5734
|
+
|
|
5735
|
+
const preservedFromHistory = historyMessages.length - 1;
|
|
5736
|
+
const removedCount = preRunMessages.length - Math.max(0, preservedFromHistory);
|
|
5737
|
+
const existingHistory = conversation.compactedHistory ?? [];
|
|
5738
|
+
conversation.compactedHistory = [
|
|
5739
|
+
...existingHistory,
|
|
5740
|
+
...preRunMessages.slice(0, removedCount),
|
|
5741
|
+
];
|
|
5742
|
+
}
|
|
5792
5743
|
}
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
...(userContent != null ? [{ role: "user" as const, content: userContent }] : []),
|
|
5796
|
-
...(assistantResponse.length > 0 || toolTimeline.length > 0 || checkpointSections.length > 0
|
|
5797
|
-
? [{
|
|
5798
|
-
role: "assistant" as const,
|
|
5799
|
-
content: assistantResponse,
|
|
5800
|
-
metadata: (toolTimeline.length > 0 || checkpointSections.length > 0
|
|
5801
|
-
? { toolActivity: [...toolTimeline], sections: checkpointSections.length > 0 ? checkpointSections : undefined }
|
|
5802
|
-
: undefined) as Message["metadata"],
|
|
5803
|
-
}]
|
|
5804
|
-
: []),
|
|
5805
|
-
];
|
|
5806
|
-
conversation.pendingApprovals = buildApprovalCheckpoints({
|
|
5807
|
-
approvals: event.approvals,
|
|
5808
|
-
runId: latestRunId,
|
|
5809
|
-
checkpointMessages: event.checkpointMessages,
|
|
5810
|
-
baseMessageCount: historyMessages.length,
|
|
5811
|
-
pendingToolCalls: event.pendingToolCalls,
|
|
5812
|
-
});
|
|
5813
|
-
conversation._toolResultArchive = harness.getToolResultArchive(conversationId);
|
|
5814
|
-
conversation.updatedAt = Date.now();
|
|
5815
|
-
await conversationStore.update(conversation);
|
|
5816
|
-
checkpointedRun = true;
|
|
5817
|
-
}
|
|
5818
|
-
if (event.type === "run:completed") {
|
|
5819
|
-
if (assistantResponse.length === 0 && event.result.response) {
|
|
5820
|
-
assistantResponse = event.result.response;
|
|
5744
|
+
if (event.type === "step:completed") {
|
|
5745
|
+
await persistDraftAssistantTurn();
|
|
5821
5746
|
}
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
|
|
5747
|
+
if (event.type === "tool:approval:required") {
|
|
5748
|
+
const toolText = `- approval required \`${event.tool}\``;
|
|
5749
|
+
draft.toolTimeline.push(toolText);
|
|
5750
|
+
draft.currentTools.push(toolText);
|
|
5751
|
+
const existingApprovals = Array.isArray(conversation.pendingApprovals)
|
|
5752
|
+
? conversation.pendingApprovals
|
|
5753
|
+
: [];
|
|
5754
|
+
if (!existingApprovals.some((approval) => approval.approvalId === event.approvalId)) {
|
|
5755
|
+
conversation.pendingApprovals = [
|
|
5756
|
+
...existingApprovals,
|
|
5757
|
+
{
|
|
5758
|
+
approvalId: event.approvalId,
|
|
5759
|
+
runId: latestRunId || conversation.runtimeRunId || "",
|
|
5760
|
+
tool: event.tool,
|
|
5761
|
+
toolCallId: undefined,
|
|
5762
|
+
input: (event.input ?? {}) as Record<string, unknown>,
|
|
5763
|
+
checkpointMessages: undefined,
|
|
5764
|
+
baseMessageCount: historyMessages.length,
|
|
5765
|
+
pendingToolCalls: [],
|
|
5766
|
+
},
|
|
5767
|
+
];
|
|
5768
|
+
conversation.updatedAt = Date.now();
|
|
5769
|
+
await conversationStore.update(conversation);
|
|
5770
|
+
}
|
|
5771
|
+
await persistDraftAssistantTurn();
|
|
5826
5772
|
}
|
|
5827
|
-
if (event.
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
const intMetadata = toolTimeline.length > 0 || intSections.length > 0
|
|
5837
|
-
? ({ toolActivity: [...toolTimeline], sections: intSections.length > 0 ? intSections : undefined } as Message["metadata"])
|
|
5838
|
-
: undefined;
|
|
5839
|
-
conversation.messages = [
|
|
5840
|
-
...historyMessages,
|
|
5841
|
-
...(userContent != null ? [{ role: "user" as const, content: userContent }] : []),
|
|
5842
|
-
...(hasContent ? [{ role: "assistant" as const, content: assistantResponse, metadata: intMetadata }] : []),
|
|
5843
|
-
];
|
|
5844
|
-
conversation._continuationMessages = runContinuationMessages;
|
|
5845
|
-
conversation._harnessMessages = runContinuationMessages;
|
|
5773
|
+
if (event.type === "tool:approval:checkpoint") {
|
|
5774
|
+
conversation.messages = buildMessages();
|
|
5775
|
+
conversation.pendingApprovals = buildApprovalCheckpoints({
|
|
5776
|
+
approvals: event.approvals,
|
|
5777
|
+
runId: latestRunId,
|
|
5778
|
+
checkpointMessages: event.checkpointMessages,
|
|
5779
|
+
baseMessageCount: historyMessages.length,
|
|
5780
|
+
pendingToolCalls: event.pendingToolCalls,
|
|
5781
|
+
});
|
|
5846
5782
|
conversation._toolResultArchive = harness.getToolResultArchive(conversationId);
|
|
5847
|
-
conversation.runtimeRunId = latestRunId || conversation.runtimeRunId;
|
|
5848
|
-
if (!checkpointedRun) {
|
|
5849
|
-
conversation.pendingApprovals = [];
|
|
5850
|
-
}
|
|
5851
|
-
if (runContextTokens > 0) conversation.contextTokens = runContextTokens;
|
|
5852
|
-
if (runContextWindow > 0) conversation.contextWindow = runContextWindow;
|
|
5853
5783
|
conversation.updatedAt = Date.now();
|
|
5854
5784
|
await conversationStore.update(conversation);
|
|
5785
|
+
checkpointedRun = true;
|
|
5786
|
+
}
|
|
5787
|
+
if (event.type === "run:completed") {
|
|
5788
|
+
if (event.result.continuation && event.result.continuationMessages) {
|
|
5789
|
+
runContinuationMessages = event.result.continuationMessages;
|
|
5790
|
+
|
|
5791
|
+
conversation.messages = buildMessages();
|
|
5792
|
+
conversation._continuationMessages = runContinuationMessages;
|
|
5793
|
+
conversation._harnessMessages = runContinuationMessages;
|
|
5794
|
+
conversation._toolResultArchive = harness.getToolResultArchive(conversationId);
|
|
5795
|
+
conversation.runtimeRunId = latestRunId || conversation.runtimeRunId;
|
|
5796
|
+
if (!checkpointedRun) {
|
|
5797
|
+
conversation.pendingApprovals = [];
|
|
5798
|
+
}
|
|
5799
|
+
if ((event.result.contextTokens ?? 0) > 0) conversation.contextTokens = event.result.contextTokens!;
|
|
5800
|
+
if ((event.result.contextWindow ?? 0) > 0) conversation.contextWindow = event.result.contextWindow!;
|
|
5801
|
+
conversation.updatedAt = Date.now();
|
|
5802
|
+
await conversationStore.update(conversation);
|
|
5803
|
+
|
|
5804
|
+
if (!checkpointedRun) {
|
|
5805
|
+
doWaitUntil(
|
|
5806
|
+
new Promise(r => setTimeout(r, 3000)).then(() =>
|
|
5807
|
+
selfFetchWithRetry(`/api/internal/continue/${encodeURIComponent(conversationId)}`),
|
|
5808
|
+
),
|
|
5809
|
+
);
|
|
5810
|
+
}
|
|
5811
|
+
}
|
|
5812
|
+
}
|
|
5855
5813
|
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5814
|
+
await telemetry.emit(event);
|
|
5815
|
+
let sseEvent: AgentEvent = event.type === "compaction:completed" && event.compactedMessages
|
|
5816
|
+
? { ...event, compactedMessages: undefined }
|
|
5817
|
+
: event;
|
|
5818
|
+
if (sseEvent.type === "run:completed") {
|
|
5819
|
+
const hasPendingSubagents = await hasPendingSubagentWorkForParent(conversationId, ownerId);
|
|
5820
|
+
const stripped = { ...sseEvent, result: { ...sseEvent.result, continuationMessages: undefined } };
|
|
5821
|
+
if (hasPendingSubagents) {
|
|
5822
|
+
sseEvent = { ...stripped, pendingSubagents: true };
|
|
5823
|
+
} else {
|
|
5824
|
+
sseEvent = stripped;
|
|
5864
5825
|
}
|
|
5865
5826
|
}
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
if (sseEvent.type === "run:completed") {
|
|
5872
|
-
const hasPendingSubagents = await hasPendingSubagentWorkForParent(conversationId, ownerId);
|
|
5873
|
-
const stripped = { ...sseEvent, result: { ...sseEvent.result, continuationMessages: undefined } };
|
|
5874
|
-
if (hasPendingSubagents) {
|
|
5875
|
-
sseEvent = { ...stripped, pendingSubagents: true };
|
|
5876
|
-
} else {
|
|
5877
|
-
sseEvent = stripped;
|
|
5827
|
+
broadcastEvent(conversationId, sseEvent);
|
|
5828
|
+
try {
|
|
5829
|
+
response.write(formatSseEvent(sseEvent));
|
|
5830
|
+
} catch {
|
|
5831
|
+
// Client disconnected — continue processing so the run completes.
|
|
5878
5832
|
}
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
}
|
|
5887
|
-
emitBrowserStatusIfActive(conversationId, event, response);
|
|
5888
|
-
}
|
|
5889
|
-
// Finalize sections
|
|
5890
|
-
if (currentTools.length > 0) {
|
|
5891
|
-
sections.push({ type: "tools", content: currentTools });
|
|
5892
|
-
}
|
|
5893
|
-
if (currentText.length > 0) {
|
|
5894
|
-
sections.push({ type: "text", content: currentText });
|
|
5895
|
-
}
|
|
5833
|
+
emitBrowserStatusIfActive(conversationId, event, response);
|
|
5834
|
+
},
|
|
5835
|
+
});
|
|
5836
|
+
|
|
5837
|
+
flushTurnDraft(draft);
|
|
5838
|
+
latestRunId = execution.latestRunId || latestRunId;
|
|
5839
|
+
|
|
5896
5840
|
if (!checkpointedRun && !runContinuationMessages) {
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
:
|
|
5902
|
-
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
...userTurn,
|
|
5906
|
-
{
|
|
5907
|
-
role: "assistant",
|
|
5908
|
-
content: assistantResponse,
|
|
5909
|
-
metadata:
|
|
5910
|
-
toolTimeline.length > 0 || sections.length > 0
|
|
5911
|
-
? ({
|
|
5912
|
-
toolActivity: toolTimeline,
|
|
5913
|
-
sections: sections.length > 0 ? sections : undefined,
|
|
5914
|
-
} as Message["metadata"])
|
|
5915
|
-
: undefined,
|
|
5916
|
-
},
|
|
5917
|
-
]
|
|
5918
|
-
: [...historyMessages, ...userTurn];
|
|
5919
|
-
conversation._continuationMessages = undefined;
|
|
5920
|
-
if (runHarnessMessages) {
|
|
5921
|
-
conversation._harnessMessages = runHarnessMessages;
|
|
5922
|
-
} else if (shouldRebuildCanonical) {
|
|
5923
|
-
conversation._harnessMessages = conversation.messages;
|
|
5924
|
-
} else {
|
|
5925
|
-
conversation._harnessMessages = conversation.messages;
|
|
5926
|
-
}
|
|
5927
|
-
conversation._toolResultArchive = harness.getToolResultArchive(conversationId);
|
|
5928
|
-
conversation.runtimeRunId = latestRunId || conversation.runtimeRunId;
|
|
5929
|
-
conversation.pendingApprovals = [];
|
|
5930
|
-
if (runContextTokens > 0) conversation.contextTokens = runContextTokens;
|
|
5931
|
-
if (runContextWindow > 0) conversation.contextWindow = runContextWindow;
|
|
5932
|
-
conversation.updatedAt = Date.now();
|
|
5841
|
+
conversation.messages = buildMessages();
|
|
5842
|
+
applyTurnMetadata(conversation, {
|
|
5843
|
+
latestRunId,
|
|
5844
|
+
contextTokens: execution.runContextTokens,
|
|
5845
|
+
contextWindow: execution.runContextWindow,
|
|
5846
|
+
harnessMessages: execution.runHarnessMessages,
|
|
5847
|
+
toolResultArchive: harness.getToolResultArchive(conversationId),
|
|
5848
|
+
}, { shouldRebuildCanonical });
|
|
5933
5849
|
await conversationStore.update(conversation);
|
|
5934
5850
|
}
|
|
5935
5851
|
} catch (error) {
|
|
5852
|
+
flushTurnDraft(draft);
|
|
5936
5853
|
if (abortController.signal.aborted || runCancelled) {
|
|
5937
|
-
|
|
5938
|
-
|
|
5939
|
-
fallbackSections.push({ type: "tools", content: [...currentTools] });
|
|
5940
|
-
}
|
|
5941
|
-
if (currentText.length > 0) {
|
|
5942
|
-
fallbackSections.push({ type: "text", content: currentText });
|
|
5943
|
-
}
|
|
5944
|
-
if (assistantResponse.length > 0 || toolTimeline.length > 0 || fallbackSections.length > 0) {
|
|
5945
|
-
conversation.messages = [
|
|
5946
|
-
...historyMessages,
|
|
5947
|
-
...(userContent != null ? [{ role: "user" as const, content: userContent }] : []),
|
|
5948
|
-
{
|
|
5949
|
-
role: "assistant",
|
|
5950
|
-
content: assistantResponse,
|
|
5951
|
-
metadata:
|
|
5952
|
-
toolTimeline.length > 0 || fallbackSections.length > 0
|
|
5953
|
-
? ({
|
|
5954
|
-
toolActivity: [...toolTimeline],
|
|
5955
|
-
sections: fallbackSections.length > 0 ? fallbackSections : undefined,
|
|
5956
|
-
} as Message["metadata"])
|
|
5957
|
-
: undefined,
|
|
5958
|
-
},
|
|
5959
|
-
];
|
|
5854
|
+
if (draft.assistantResponse.length > 0 || draft.toolTimeline.length > 0 || draft.sections.length > 0) {
|
|
5855
|
+
conversation.messages = buildMessages();
|
|
5960
5856
|
conversation.updatedAt = Date.now();
|
|
5961
5857
|
await conversationStore.update(conversation);
|
|
5962
5858
|
}
|
|
@@ -5977,29 +5873,8 @@ export const createRequestHandler = async (options?: {
|
|
|
5977
5873
|
}),
|
|
5978
5874
|
);
|
|
5979
5875
|
} catch {
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
fallbackSections.push({ type: "tools", content: [...currentTools] });
|
|
5983
|
-
}
|
|
5984
|
-
if (currentText.length > 0) {
|
|
5985
|
-
fallbackSections.push({ type: "text", content: currentText });
|
|
5986
|
-
}
|
|
5987
|
-
if (assistantResponse.length > 0 || toolTimeline.length > 0 || fallbackSections.length > 0) {
|
|
5988
|
-
conversation.messages = [
|
|
5989
|
-
...historyMessages,
|
|
5990
|
-
...(userContent != null ? [{ role: "user" as const, content: userContent }] : []),
|
|
5991
|
-
{
|
|
5992
|
-
role: "assistant",
|
|
5993
|
-
content: assistantResponse,
|
|
5994
|
-
metadata:
|
|
5995
|
-
toolTimeline.length > 0 || fallbackSections.length > 0
|
|
5996
|
-
? ({
|
|
5997
|
-
toolActivity: [...toolTimeline],
|
|
5998
|
-
sections: fallbackSections.length > 0 ? fallbackSections : undefined,
|
|
5999
|
-
} as Message["metadata"])
|
|
6000
|
-
: undefined,
|
|
6001
|
-
},
|
|
6002
|
-
];
|
|
5876
|
+
if (draft.assistantResponse.length > 0 || draft.toolTimeline.length > 0 || draft.sections.length > 0) {
|
|
5877
|
+
conversation.messages = buildMessages();
|
|
6003
5878
|
conversation.updatedAt = Date.now();
|
|
6004
5879
|
await conversationStore.update(conversation);
|
|
6005
5880
|
}
|
|
@@ -6015,10 +5890,6 @@ export const createRequestHandler = async (options?: {
|
|
|
6015
5890
|
runConversations.delete(latestRunId);
|
|
6016
5891
|
}
|
|
6017
5892
|
|
|
6018
|
-
// Determine if subagent work is pending before deciding to close the
|
|
6019
|
-
// event stream. When a callback is about to run, the stream stays open
|
|
6020
|
-
// so clients that subscribe to /events receive callback-run events in
|
|
6021
|
-
// real-time — the same delivery path used for every other run.
|
|
6022
5893
|
const hadDeferred = pendingCallbackNeeded.delete(conversationId);
|
|
6023
5894
|
const freshConv = await conversationStore.get(conversationId);
|
|
6024
5895
|
const needsCallback = hadDeferred || !!freshConv?.pendingSubagentResults?.length;
|
|
@@ -6106,53 +5977,37 @@ export const createRequestHandler = async (options?: {
|
|
|
6106
5977
|
});
|
|
6107
5978
|
const historyMessages = [...historySelection.messages];
|
|
6108
5979
|
try {
|
|
6109
|
-
const
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
}
|
|
6123
|
-
|
|
6124
|
-
const assistantResponse = execution.draft.assistantResponse;
|
|
6125
|
-
|
|
6126
|
-
conv.messages = [
|
|
6127
|
-
...historyMessages,
|
|
6128
|
-
{ role: "user" as const, content: task },
|
|
6129
|
-
...(assistantResponse ? [{ role: "assistant" as const, content: assistantResponse }] : []),
|
|
6130
|
-
];
|
|
6131
|
-
if (execution.runHarnessMessages) {
|
|
6132
|
-
conv._harnessMessages = execution.runHarnessMessages;
|
|
6133
|
-
} else if (historySelection.shouldRebuildCanonical) {
|
|
6134
|
-
conv._harnessMessages = conv.messages;
|
|
5980
|
+
const result = await runCronAgent(harness, task, conv.conversationId, historyMessages,
|
|
5981
|
+
conv._toolResultArchive,
|
|
5982
|
+
async (event) => { await telemetry.emit(event); },
|
|
5983
|
+
);
|
|
5984
|
+
|
|
5985
|
+
const freshConv = await conversationStore.get(conv.conversationId);
|
|
5986
|
+
if (freshConv) {
|
|
5987
|
+
appendCronTurn(freshConv, task, result);
|
|
5988
|
+
applyTurnMetadata(freshConv, result, {
|
|
5989
|
+
clearContinuation: false,
|
|
5990
|
+
clearApprovals: false,
|
|
5991
|
+
setIdle: false,
|
|
5992
|
+
shouldRebuildCanonical: historySelection.shouldRebuildCanonical,
|
|
5993
|
+
});
|
|
5994
|
+
await conversationStore.update(freshConv);
|
|
6135
5995
|
}
|
|
6136
|
-
conv._toolResultArchive = harness.getToolResultArchive(conv.conversationId);
|
|
6137
|
-
if (execution.runContextTokens > 0) conv.contextTokens = execution.runContextTokens;
|
|
6138
|
-
if (execution.runContextWindow > 0) conv.contextWindow = execution.runContextWindow;
|
|
6139
|
-
conv.updatedAt = Date.now();
|
|
6140
|
-
await conversationStore.update(conv);
|
|
6141
5996
|
|
|
6142
|
-
if (
|
|
5997
|
+
if (result.response) {
|
|
6143
5998
|
try {
|
|
6144
5999
|
await adapter.sendReply(
|
|
6145
6000
|
{
|
|
6146
6001
|
channelId: chatId,
|
|
6147
|
-
platformThreadId: conv.channelMeta?.platformThreadId ?? chatId,
|
|
6002
|
+
platformThreadId: (freshConv ?? conv).channelMeta?.platformThreadId ?? chatId,
|
|
6148
6003
|
},
|
|
6149
|
-
|
|
6004
|
+
result.response,
|
|
6150
6005
|
);
|
|
6151
6006
|
} catch (sendError) {
|
|
6152
6007
|
console.error(`[cron] ${jobName}: send to ${chatId} failed:`, sendError instanceof Error ? sendError.message : sendError);
|
|
6153
6008
|
}
|
|
6154
6009
|
}
|
|
6155
|
-
chatResults.push({ chatId, status: "completed", steps:
|
|
6010
|
+
chatResults.push({ chatId, status: "completed", steps: result.steps });
|
|
6156
6011
|
} catch (runError) {
|
|
6157
6012
|
chatResults.push({ chatId, status: "error" });
|
|
6158
6013
|
console.error(`[cron] ${jobName}: run for chat ${chatId} failed:`, runError instanceof Error ? runError.message : runError);
|
|
@@ -6180,7 +6035,6 @@ export const createRequestHandler = async (options?: {
|
|
|
6180
6035
|
cronOwnerId,
|
|
6181
6036
|
`[cron] ${jobName} ${timestamp}`,
|
|
6182
6037
|
);
|
|
6183
|
-
const historyMessages: Message[] = [];
|
|
6184
6038
|
|
|
6185
6039
|
const convId = conversation.conversationId;
|
|
6186
6040
|
activeConversationRuns.set(convId, {
|
|
@@ -6190,152 +6044,45 @@ export const createRequestHandler = async (options?: {
|
|
|
6190
6044
|
});
|
|
6191
6045
|
|
|
6192
6046
|
try {
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
for await (const event of harness.runWithTelemetry({
|
|
6212
|
-
task: cronJob.task,
|
|
6213
|
-
conversationId: convId,
|
|
6214
|
-
parameters: withToolResultArchiveParam({ __activeConversationId: convId }, conversation),
|
|
6215
|
-
messages: historyMessages,
|
|
6216
|
-
abortSignal: abortController.signal,
|
|
6217
|
-
})) {
|
|
6218
|
-
if (event.type === "run:started") {
|
|
6219
|
-
latestRunId = event.runId;
|
|
6220
|
-
}
|
|
6221
|
-
if (event.type === "model:chunk") {
|
|
6222
|
-
if (currentTools.length > 0) {
|
|
6223
|
-
sections.push({ type: "tools", content: currentTools });
|
|
6224
|
-
currentTools = [];
|
|
6225
|
-
if (assistantResponse.length > 0 && !/\s$/.test(assistantResponse)) {
|
|
6226
|
-
assistantResponse += " ";
|
|
6227
|
-
}
|
|
6228
|
-
}
|
|
6229
|
-
assistantResponse += event.content;
|
|
6230
|
-
currentText += event.content;
|
|
6231
|
-
}
|
|
6232
|
-
if (event.type === "tool:started") {
|
|
6233
|
-
if (currentText.length > 0) {
|
|
6234
|
-
sections.push({ type: "text", content: currentText });
|
|
6235
|
-
currentText = "";
|
|
6236
|
-
}
|
|
6237
|
-
const toolText = `- start \`${event.tool}\``;
|
|
6238
|
-
toolTimeline.push(toolText);
|
|
6239
|
-
currentTools.push(toolText);
|
|
6240
|
-
}
|
|
6241
|
-
if (event.type === "tool:completed") {
|
|
6242
|
-
const toolText = `- done \`${event.tool}\` (${event.duration}ms)`;
|
|
6243
|
-
toolTimeline.push(toolText);
|
|
6244
|
-
currentTools.push(toolText);
|
|
6245
|
-
}
|
|
6246
|
-
if (event.type === "tool:error") {
|
|
6247
|
-
const toolText = `- error \`${event.tool}\`: ${event.error}`;
|
|
6248
|
-
toolTimeline.push(toolText);
|
|
6249
|
-
currentTools.push(toolText);
|
|
6250
|
-
}
|
|
6251
|
-
if (event.type === "run:completed") {
|
|
6252
|
-
runResult = {
|
|
6253
|
-
status: event.result.status,
|
|
6254
|
-
steps: event.result.steps,
|
|
6255
|
-
continuation: event.result.continuation,
|
|
6256
|
-
contextTokens: event.result.contextTokens,
|
|
6257
|
-
contextWindow: event.result.contextWindow,
|
|
6258
|
-
harnessMessages: event.result.continuationMessages,
|
|
6259
|
-
};
|
|
6260
|
-
if (event.result.continuation && event.result.continuationMessages) {
|
|
6261
|
-
runContinuationMessages = event.result.continuationMessages;
|
|
6262
|
-
}
|
|
6263
|
-
if (!assistantResponse && event.result.response) {
|
|
6264
|
-
assistantResponse = event.result.response;
|
|
6265
|
-
}
|
|
6047
|
+
const result = await runCronAgent(harness, cronJob.task, convId, [],
|
|
6048
|
+
conversation._toolResultArchive,
|
|
6049
|
+
async (event) => {
|
|
6050
|
+
broadcastEvent(convId, event);
|
|
6051
|
+
await telemetry.emit(event);
|
|
6052
|
+
},
|
|
6053
|
+
);
|
|
6054
|
+
finishConversationStream(convId);
|
|
6055
|
+
|
|
6056
|
+
const freshConv = await conversationStore.get(convId);
|
|
6057
|
+
if (freshConv) {
|
|
6058
|
+
freshConv.messages = buildCronMessages(cronJob.task, [], result);
|
|
6059
|
+
applyTurnMetadata(freshConv, result, {
|
|
6060
|
+
clearApprovals: false,
|
|
6061
|
+
setIdle: false,
|
|
6062
|
+
});
|
|
6063
|
+
await conversationStore.update(freshConv);
|
|
6266
6064
|
}
|
|
6267
|
-
broadcastEvent(convId, event);
|
|
6268
|
-
await telemetry.emit(event);
|
|
6269
|
-
}
|
|
6270
6065
|
|
|
6271
|
-
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
|
-
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
// pendingSubagentResults appended during the run.
|
|
6283
|
-
const hasContent = assistantResponse.length > 0 || toolTimeline.length > 0;
|
|
6284
|
-
const assistantMetadata =
|
|
6285
|
-
toolTimeline.length > 0 || sections.length > 0
|
|
6286
|
-
? ({
|
|
6287
|
-
toolActivity: [...toolTimeline],
|
|
6288
|
-
sections: sections.length > 0 ? sections : undefined,
|
|
6289
|
-
} as Message["metadata"])
|
|
6290
|
-
: undefined;
|
|
6291
|
-
const messages: Message[] = [
|
|
6292
|
-
...historyMessages,
|
|
6293
|
-
{ role: "user" as const, content: cronJob.task },
|
|
6294
|
-
...(hasContent
|
|
6295
|
-
? [{ role: "assistant" as const, content: assistantResponse, metadata: assistantMetadata }]
|
|
6296
|
-
: []),
|
|
6297
|
-
];
|
|
6298
|
-
const freshConv = await conversationStore.get(convId);
|
|
6299
|
-
if (freshConv) {
|
|
6300
|
-
// Always persist intermediate messages so clients see progress
|
|
6301
|
-
freshConv.messages = messages;
|
|
6302
|
-
if (runContinuationMessages) {
|
|
6303
|
-
freshConv._continuationMessages = runContinuationMessages;
|
|
6304
|
-
} else {
|
|
6305
|
-
freshConv._continuationMessages = undefined;
|
|
6306
|
-
freshConv._continuationCount = undefined;
|
|
6307
|
-
}
|
|
6308
|
-
if (runResult.harnessMessages) {
|
|
6309
|
-
freshConv._harnessMessages = runResult.harnessMessages;
|
|
6066
|
+
if (result.continuation) {
|
|
6067
|
+
const work = selfFetchWithRetry(`/api/internal/continue/${encodeURIComponent(convId)}`).catch(err =>
|
|
6068
|
+
console.error(`[poncho][cron] Continuation self-fetch failed:`, err instanceof Error ? err.message : err),
|
|
6069
|
+
);
|
|
6070
|
+
doWaitUntil(work);
|
|
6071
|
+
writeJson(response, 200, {
|
|
6072
|
+
conversationId: convId,
|
|
6073
|
+
status: "continued",
|
|
6074
|
+
duration: Date.now() - start,
|
|
6075
|
+
});
|
|
6076
|
+
return;
|
|
6310
6077
|
}
|
|
6311
|
-
freshConv._toolResultArchive = harness.getToolResultArchive(convId);
|
|
6312
|
-
freshConv.runtimeRunId = latestRunId || freshConv.runtimeRunId;
|
|
6313
|
-
if (runResult.contextTokens) freshConv.contextTokens = runResult.contextTokens;
|
|
6314
|
-
if (runResult.contextWindow) freshConv.contextWindow = runResult.contextWindow;
|
|
6315
|
-
freshConv.updatedAt = Date.now();
|
|
6316
|
-
await conversationStore.update(freshConv);
|
|
6317
|
-
}
|
|
6318
6078
|
|
|
6319
|
-
if (runResult.continuation) {
|
|
6320
|
-
const work = selfFetchWithRetry(`/api/internal/continue/${encodeURIComponent(convId)}`).catch(err =>
|
|
6321
|
-
console.error(`[poncho][cron] Continuation self-fetch failed:`, err instanceof Error ? err.message : err),
|
|
6322
|
-
);
|
|
6323
|
-
doWaitUntil(work);
|
|
6324
6079
|
writeJson(response, 200, {
|
|
6325
6080
|
conversationId: convId,
|
|
6326
|
-
status: "
|
|
6081
|
+
status: "completed",
|
|
6082
|
+
response: result.response.slice(0, 500),
|
|
6327
6083
|
duration: Date.now() - start,
|
|
6084
|
+
steps: result.steps,
|
|
6328
6085
|
});
|
|
6329
|
-
return;
|
|
6330
|
-
}
|
|
6331
|
-
|
|
6332
|
-
writeJson(response, 200, {
|
|
6333
|
-
conversationId: convId,
|
|
6334
|
-
status: runResult.status,
|
|
6335
|
-
response: assistantResponse.slice(0, 500),
|
|
6336
|
-
duration: Date.now() - start,
|
|
6337
|
-
steps: runResult.steps,
|
|
6338
|
-
});
|
|
6339
6086
|
} finally {
|
|
6340
6087
|
activeConversationRuns.delete(convId);
|
|
6341
6088
|
const hadDeferred = pendingCallbackNeeded.delete(convId);
|
|
@@ -6417,26 +6164,19 @@ export const createRequestHandler = async (options?: {
|
|
|
6417
6164
|
if (channelMeta) {
|
|
6418
6165
|
const adapter = messagingAdapters.get(channelMeta.platform);
|
|
6419
6166
|
if (adapter && originConv) {
|
|
6420
|
-
const
|
|
6421
|
-
|
|
6422
|
-
|
|
6423
|
-
|
|
6424
|
-
|
|
6425
|
-
|
|
6426
|
-
messages: historyMessages,
|
|
6427
|
-
})) {
|
|
6428
|
-
if (event.type === "model:chunk") {
|
|
6429
|
-
assistantResponse += event.content;
|
|
6430
|
-
}
|
|
6431
|
-
}
|
|
6432
|
-
if (assistantResponse) {
|
|
6167
|
+
const result = await runCronAgent(
|
|
6168
|
+
harness, framedMessage, originConv.conversationId,
|
|
6169
|
+
originConv.messages ?? [],
|
|
6170
|
+
originConv._toolResultArchive,
|
|
6171
|
+
);
|
|
6172
|
+
if (result.response) {
|
|
6433
6173
|
try {
|
|
6434
6174
|
await adapter.sendReply(
|
|
6435
6175
|
{
|
|
6436
6176
|
channelId: channelMeta.channelId,
|
|
6437
6177
|
platformThreadId: channelMeta.platformThreadId ?? channelMeta.channelId,
|
|
6438
6178
|
},
|
|
6439
|
-
|
|
6179
|
+
result.response,
|
|
6440
6180
|
);
|
|
6441
6181
|
} catch (sendError) {
|
|
6442
6182
|
console.error(`[reminder] Send to ${channelMeta.platform} failed:`, sendError instanceof Error ? sendError.message : sendError);
|
|
@@ -6444,12 +6184,12 @@ export const createRequestHandler = async (options?: {
|
|
|
6444
6184
|
}
|
|
6445
6185
|
const freshConv = await conversationStore.get(originConv.conversationId);
|
|
6446
6186
|
if (freshConv) {
|
|
6447
|
-
freshConv
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6187
|
+
appendCronTurn(freshConv, framedMessage, result);
|
|
6188
|
+
applyTurnMetadata(freshConv, result, {
|
|
6189
|
+
clearContinuation: false,
|
|
6190
|
+
clearApprovals: false,
|
|
6191
|
+
setIdle: false,
|
|
6192
|
+
});
|
|
6453
6193
|
await conversationStore.update(freshConv);
|
|
6454
6194
|
}
|
|
6455
6195
|
}
|
|
@@ -6460,24 +6200,15 @@ export const createRequestHandler = async (options?: {
|
|
|
6460
6200
|
`[reminder] ${reminder.task.slice(0, 80)} ${timestamp}`,
|
|
6461
6201
|
);
|
|
6462
6202
|
const convId = conversation.conversationId;
|
|
6463
|
-
|
|
6464
|
-
for await (const event of harness.runWithTelemetry({
|
|
6465
|
-
task: framedMessage,
|
|
6466
|
-
conversationId: convId,
|
|
6467
|
-
parameters: { __activeConversationId: convId },
|
|
6468
|
-
messages: [],
|
|
6469
|
-
})) {
|
|
6470
|
-
if (event.type === "model:chunk") {
|
|
6471
|
-
assistantResponse += event.content;
|
|
6472
|
-
}
|
|
6473
|
-
}
|
|
6203
|
+
const result = await runCronAgent(harness, framedMessage, convId, []);
|
|
6474
6204
|
const freshConv = await conversationStore.get(convId);
|
|
6475
6205
|
if (freshConv) {
|
|
6476
|
-
freshConv.messages = [
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
6206
|
+
freshConv.messages = buildCronMessages(framedMessage, [], result);
|
|
6207
|
+
applyTurnMetadata(freshConv, result, {
|
|
6208
|
+
clearContinuation: false,
|
|
6209
|
+
clearApprovals: false,
|
|
6210
|
+
setIdle: false,
|
|
6211
|
+
});
|
|
6481
6212
|
await conversationStore.update(freshConv);
|
|
6482
6213
|
}
|
|
6483
6214
|
}
|
|
@@ -6568,65 +6299,6 @@ export const startDevServer = async (
|
|
|
6568
6299
|
type CronJob = InstanceType<typeof Cron>;
|
|
6569
6300
|
let activeJobs: CronJob[] = [];
|
|
6570
6301
|
|
|
6571
|
-
type CronRunResult = {
|
|
6572
|
-
response: string;
|
|
6573
|
-
steps: number;
|
|
6574
|
-
assistantMetadata?: Message["metadata"];
|
|
6575
|
-
hasContent: boolean;
|
|
6576
|
-
contextTokens: number;
|
|
6577
|
-
contextWindow: number;
|
|
6578
|
-
harnessMessages?: Message[];
|
|
6579
|
-
toolResultArchive?: Conversation["_toolResultArchive"];
|
|
6580
|
-
};
|
|
6581
|
-
|
|
6582
|
-
const runCronAgent = async (
|
|
6583
|
-
harnessRef: AgentHarness,
|
|
6584
|
-
task: string,
|
|
6585
|
-
conversationId: string,
|
|
6586
|
-
historyMessages: Message[],
|
|
6587
|
-
toolResultArchive?: Conversation["_toolResultArchive"],
|
|
6588
|
-
onEvent?: (event: AgentEvent) => void | Promise<void>,
|
|
6589
|
-
): Promise<CronRunResult> => {
|
|
6590
|
-
const execution = await executeConversationTurn({
|
|
6591
|
-
harness: harnessRef,
|
|
6592
|
-
runInput: {
|
|
6593
|
-
task,
|
|
6594
|
-
conversationId,
|
|
6595
|
-
parameters: {
|
|
6596
|
-
__activeConversationId: conversationId,
|
|
6597
|
-
[TOOL_RESULT_ARCHIVE_PARAM]: toolResultArchive ?? {},
|
|
6598
|
-
},
|
|
6599
|
-
messages: historyMessages,
|
|
6600
|
-
},
|
|
6601
|
-
onEvent,
|
|
6602
|
-
});
|
|
6603
|
-
flushTurnDraft(execution.draft);
|
|
6604
|
-
const hasContent = execution.draft.assistantResponse.length > 0 || execution.draft.toolTimeline.length > 0;
|
|
6605
|
-
const assistantMetadata = buildAssistantMetadata(execution.draft);
|
|
6606
|
-
return {
|
|
6607
|
-
response: execution.draft.assistantResponse,
|
|
6608
|
-
steps: execution.runSteps,
|
|
6609
|
-
assistantMetadata,
|
|
6610
|
-
hasContent,
|
|
6611
|
-
contextTokens: execution.runContextTokens,
|
|
6612
|
-
contextWindow: execution.runContextWindow,
|
|
6613
|
-
harnessMessages: execution.runHarnessMessages,
|
|
6614
|
-
toolResultArchive: harnessRef.getToolResultArchive(conversationId),
|
|
6615
|
-
};
|
|
6616
|
-
};
|
|
6617
|
-
|
|
6618
|
-
const buildCronMessages = (
|
|
6619
|
-
task: string,
|
|
6620
|
-
historyMessages: Message[],
|
|
6621
|
-
result: CronRunResult,
|
|
6622
|
-
): Message[] => [
|
|
6623
|
-
...historyMessages,
|
|
6624
|
-
{ role: "user" as const, content: task },
|
|
6625
|
-
...(result.hasContent
|
|
6626
|
-
? [{ role: "assistant" as const, content: result.response, metadata: result.assistantMetadata }]
|
|
6627
|
-
: []),
|
|
6628
|
-
];
|
|
6629
|
-
|
|
6630
6302
|
const scheduleCronJobs = (jobs: Record<string, CronJobConfig>): void => {
|
|
6631
6303
|
for (const job of activeJobs) {
|
|
6632
6304
|
job.stop();
|
|
@@ -6704,18 +6376,13 @@ export const startDevServer = async (
|
|
|
6704
6376
|
|
|
6705
6377
|
const freshConv = await store.get(convId);
|
|
6706
6378
|
if (freshConv) {
|
|
6707
|
-
freshConv
|
|
6708
|
-
|
|
6709
|
-
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
|
|
6713
|
-
|
|
6714
|
-
freshConv._toolResultArchive = result.toolResultArchive;
|
|
6715
|
-
}
|
|
6716
|
-
if (result.contextTokens > 0) freshConv.contextTokens = result.contextTokens;
|
|
6717
|
-
if (result.contextWindow > 0) freshConv.contextWindow = result.contextWindow;
|
|
6718
|
-
freshConv.updatedAt = Date.now();
|
|
6379
|
+
appendCronTurn(freshConv, task, result);
|
|
6380
|
+
applyTurnMetadata(freshConv, result, {
|
|
6381
|
+
clearContinuation: false,
|
|
6382
|
+
clearApprovals: false,
|
|
6383
|
+
setIdle: false,
|
|
6384
|
+
shouldRebuildCanonical: historySelection.shouldRebuildCanonical,
|
|
6385
|
+
});
|
|
6719
6386
|
await store.update(freshConv);
|
|
6720
6387
|
|
|
6721
6388
|
if (result.response) {
|
|
@@ -6780,15 +6447,11 @@ export const startDevServer = async (
|
|
|
6780
6447
|
const freshConv = await store.get(cronConvId);
|
|
6781
6448
|
if (freshConv) {
|
|
6782
6449
|
freshConv.messages = buildCronMessages(config.task, [], result);
|
|
6783
|
-
|
|
6784
|
-
|
|
6785
|
-
|
|
6786
|
-
|
|
6787
|
-
|
|
6788
|
-
}
|
|
6789
|
-
if (result.contextTokens > 0) freshConv.contextTokens = result.contextTokens;
|
|
6790
|
-
if (result.contextWindow > 0) freshConv.contextWindow = result.contextWindow;
|
|
6791
|
-
freshConv.updatedAt = Date.now();
|
|
6450
|
+
applyTurnMetadata(freshConv, result, {
|
|
6451
|
+
clearContinuation: false,
|
|
6452
|
+
clearApprovals: false,
|
|
6453
|
+
setIdle: false,
|
|
6454
|
+
});
|
|
6792
6455
|
await store.update(freshConv);
|
|
6793
6456
|
}
|
|
6794
6457
|
const elapsed = ((Date.now() - start) / 1000).toFixed(1);
|