Repository navigation
perf(server): new prompts in a compacted thread read only what follows it #33000
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9e0d6ec
676afc4
e7b5c1d
13e718b
72bd82b
8f7ed10
6d1e4e0
1be76cf
860ff72
4dcd26f
decbfb4
2d7f3df
7836410
79ed278
e5473e9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -1298,7 +1298,10 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio | |||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| // Runs in every command transaction; avoid reading thousands of finished leaf nodes. | ||||||||||||||||||||||||||||||||||
| const readCommandProjection = (threadId: ThreadId) => | ||||||||||||||||||||||||||||||||||
| const readCommandProjection = ( | ||||||||||||||||||||||||||||||||||
| threadId: ThreadId, | ||||||||||||||||||||||||||||||||||
| recent?: { keepRunIds: ReadonlyArray<RunId> }, | ||||||||||||||||||||||||||||||||||
| ) => | ||||||||||||||||||||||||||||||||||
| projectionStore | ||||||||||||||||||||||||||||||||||
| .getThreadRecords( | ||||||||||||||||||||||||||||||||||
| threadId, | ||||||||||||||||||||||||||||||||||
|
|
@@ -1323,6 +1326,7 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio | |||||||||||||||||||||||||||||||||
| // Commands here read only undelivered or active tasks; a dispatcher thread keeps | ||||||||||||||||||||||||||||||||||
| // thousands of delivered ones, each carrying its full prompt. | ||||||||||||||||||||||||||||||||||
| omitSettledSubagents: true, | ||||||||||||||||||||||||||||||||||
| ...(recent === undefined ? {} : { sinceLastCompaction: recent }), | ||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| .pipe( | ||||||||||||||||||||||||||||||||||
|
|
@@ -1411,9 +1415,10 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio | |||||||||||||||||||||||||||||||||
| Effect.fnUntraced(function* ( | ||||||||||||||||||||||||||||||||||
| threadId: ThreadId, | ||||||||||||||||||||||||||||||||||
| events: Ref.Ref<Array<OrchestrationV2DomainEvent>>, | ||||||||||||||||||||||||||||||||||
| recent?: { keepRunIds: ReadonlyArray<RunId> }, | ||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||
| const pending = (yield* Ref.get(events)).filter((event) => event.threadId === threadId); | ||||||||||||||||||||||||||||||||||
| const stored = yield* Effect.option(readCommandProjection(threadId)); | ||||||||||||||||||||||||||||||||||
| const stored = yield* Effect.option(readCommandProjection(threadId, recent)); | ||||||||||||||||||||||||||||||||||
| let projection: OrchestrationV2ThreadProjection; | ||||||||||||||||||||||||||||||||||
| if (Option.isSome(stored)) { | ||||||||||||||||||||||||||||||||||
| projection = stored.value; | ||||||||||||||||||||||||||||||||||
|
|
@@ -5845,7 +5850,31 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio | |||||||||||||||||||||||||||||||||
| events: Ref.Ref<Array<OrchestrationV2DomainEvent>>, | ||||||||||||||||||||||||||||||||||
| effects: Ref.Ref<Array<PendingOrchestrationEffectV2>>, | ||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||
| let projection = yield* getProjectionWithPendingEvents(command.threadId, events); | ||||||||||||||||||||||||||||||||||
| // A compacted thread needs only its recent runs, plus any older run the command names. | ||||||||||||||||||||||||||||||||||
| let projection = yield* getProjectionWithPendingEvents(command.threadId, events, { | ||||||||||||||||||||||||||||||||||
| keepRunIds: [ | ||||||||||||||||||||||||||||||||||
| command.manualContinuationOfRunId, | ||||||||||||||||||||||||||||||||||
| command.restartContinuationOfRunId, | ||||||||||||||||||||||||||||||||||
| command.usageLimitContinuationOfRunId, | ||||||||||||||||||||||||||||||||||
| command.delegatedCompletion?.parentRunId, | ||||||||||||||||||||||||||||||||||
| ...(command.dispatchMode.type === "steer_active" || | ||||||||||||||||||||||||||||||||||
| command.dispatchMode.type === "restart_active" | ||||||||||||||||||||||||||||||||||
| ? [command.dispatchMode.targetRunId] | ||||||||||||||||||||||||||||||||||
| : []), | ||||||||||||||||||||||||||||||||||
| ].flatMap((runId) => (runId === undefined ? [] : [runId])), | ||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+5856
to
+5865
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟠 High An explicit steer or restart targeting a run older than the compaction window now fails as “not found” instead of starting a new turn:
Suggested change
🤖 Copy this AI Prompt to have your agent fix this:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Confirmed: an explicit
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I'm unable to act on this request because you do not have permissions within this repository. |
||||||||||||||||||||||||||||||||||
| const activeProviderInstanceId = projection.providerThreads.find( | ||||||||||||||||||||||||||||||||||
| (candidate) => candidate.id === projection.thread.activeProviderThreadId, | ||||||||||||||||||||||||||||||||||
| )?.providerInstanceId; | ||||||||||||||||||||||||||||||||||
| // A fresh session or another provider is handed the whole history, so it reads all of it. | ||||||||||||||||||||||||||||||||||
| if ( | ||||||||||||||||||||||||||||||||||
| command.freshContext === true || | ||||||||||||||||||||||||||||||||||
| (activeProviderInstanceId !== undefined && | ||||||||||||||||||||||||||||||||||
| activeProviderInstanceId !== | ||||||||||||||||||||||||||||||||||
| (command.modelSelection ?? projection.thread.modelSelection).instanceId) | ||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||
| projection = yield* getProjectionWithPendingEvents(command.threadId, events); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| if (command.manualContinuationOfRunId !== undefined) { | ||||||||||||||||||||||||||||||||||
| const source = projection.runs.find((run) => run.id === command.manualContinuationOfRunId); | ||||||||||||||||||||||||||||||||||
| const limited = latestRootProviderFailure(source ?? null, projection.turnItems); | ||||||||||||||||||||||||||||||||||
|
|
@@ -6018,16 +6047,16 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio | |||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
| projection = applyToProjection(projection, event); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| const userMessages = projection.messages.filter((message) => message.role === "user"); | ||||||||||||||||||||||||||||||||||
| const onlyMaintenanceHistory = | ||||||||||||||||||||||||||||||||||
| userMessages.length > 0 && userMessages.every(isNativeMaintenanceCommand); | ||||||||||||||||||||||||||||||||||
| if ( | ||||||||||||||||||||||||||||||||||
| !isNativeMaintenanceCommand(command) && | ||||||||||||||||||||||||||||||||||
| ((command.titleSeed !== undefined && | ||||||||||||||||||||||||||||||||||
| (yield* projectionStore | ||||||||||||||||||||||||||||||||||
| .getMessageCount(command.threadId) | ||||||||||||||||||||||||||||||||||
| .pipe(mapDispatchError(command))) === 0) || | ||||||||||||||||||||||||||||||||||
| (command.createdBy === "user" && onlyMaintenanceHistory)) | ||||||||||||||||||||||||||||||||||
| (command.createdBy === "user" && | ||||||||||||||||||||||||||||||||||
| (yield* projectionStore | ||||||||||||||||||||||||||||||||||
| .hasOnlyMaintenanceUserMessages(command.threadId) | ||||||||||||||||||||||||||||||||||
| .pipe(mapDispatchError(command))))) | ||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||
| const now = yield* DateTime.now; | ||||||||||||||||||||||||||||||||||
| const thread: OrchestrationV2AppThread = { | ||||||||||||||||||||||||||||||||||
|
|
@@ -13008,21 +13037,19 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio | |||||||||||||||||||||||||||||||||
| turnItems: childResult.turnItems, | ||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||
| const parentThreadId = childControls.thread.lineage.parentThreadId; | ||||||||||||||||||||||||||||||||||
| const parentProjection = yield* projectionStore.getThreadRecords( | ||||||||||||||||||||||||||||||||||
| // A dispatcher parent holds thousands of tasks, runs and prompts, so read only this task's | ||||||||||||||||||||||||||||||||||
| // records and the delivery cohort the completion plan joins. | ||||||||||||||||||||||||||||||||||
| const taskRecords = yield* projectionStore.getThreadRecords( | ||||||||||||||||||||||||||||||||||
| parentThreadId, | ||||||||||||||||||||||||||||||||||
| [ | ||||||||||||||||||||||||||||||||||
| "runs", | ||||||||||||||||||||||||||||||||||
| "messages", | ||||||||||||||||||||||||||||||||||
| "subagents", | ||||||||||||||||||||||||||||||||||
| "providerThreads", | ||||||||||||||||||||||||||||||||||
| "providerTurns", | ||||||||||||||||||||||||||||||||||
| "nodes", | ||||||||||||||||||||||||||||||||||
| "turnItems", | ||||||||||||||||||||||||||||||||||
| "contextTransfers", | ||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||
| { turnItemTypes: ["subagent"], messageRoles: ["user"] }, | ||||||||||||||||||||||||||||||||||
| ["subagents", "nodes", "turnItems"], | ||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||
| subagentIds: [options.task.id], | ||||||||||||||||||||||||||||||||||
| nodeIds: [options.task.id], | ||||||||||||||||||||||||||||||||||
| turnItemNodeIds: [options.task.id], | ||||||||||||||||||||||||||||||||||
| turnItemTypes: ["subagent"], | ||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| const task = parentProjection.subagents.find( | ||||||||||||||||||||||||||||||||||
| const task = taskRecords.subagents.find( | ||||||||||||||||||||||||||||||||||
| (candidate) => | ||||||||||||||||||||||||||||||||||
| candidate.id === options.task.id && | ||||||||||||||||||||||||||||||||||
| candidate.origin === "app_owned" && | ||||||||||||||||||||||||||||||||||
|
|
@@ -13031,7 +13058,11 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio | |||||||||||||||||||||||||||||||||
| if (task === undefined) { | ||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| const existingResultTransfer = parentProjection.contextTransfers.find( | ||||||||||||||||||||||||||||||||||
| // The result transfer runs from the child, so the child's side lists it too. | ||||||||||||||||||||||||||||||||||
| const { contextTransfers } = yield* projectionStore.getThreadRecords(childThreadId, [ | ||||||||||||||||||||||||||||||||||
| "contextTransfers", | ||||||||||||||||||||||||||||||||||
| ]); | ||||||||||||||||||||||||||||||||||
| const existingResultTransfer = contextTransfers.find( | ||||||||||||||||||||||||||||||||||
| (transfer) => | ||||||||||||||||||||||||||||||||||
| transfer.type === "subagent_result" && | ||||||||||||||||||||||||||||||||||
| transfer.sourceThreadId === childThreadId && | ||||||||||||||||||||||||||||||||||
|
|
@@ -13045,12 +13076,37 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio | |||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| const now = yield* DateTime.now; | ||||||||||||||||||||||||||||||||||
| const result = subagentResultForRun(childProjection, { ...childRun, status: outcome }); | ||||||||||||||||||||||||||||||||||
| const parentRun = | ||||||||||||||||||||||||||||||||||
| task.runId === null | ||||||||||||||||||||||||||||||||||
| const taskRunRecords = yield* projectionStore.getThreadRecords(parentThreadId, ["runs"], { | ||||||||||||||||||||||||||||||||||
| runIds: task.runId === null ? [] : [task.runId], | ||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
| const parentRun = taskRunRecords.runs.find((candidate) => candidate.id === task.runId); | ||||||||||||||||||||||||||||||||||
| const delivery = parentRun?.delegatedCompletion?.delivery; | ||||||||||||||||||||||||||||||||||
| const deliveryRecords = | ||||||||||||||||||||||||||||||||||
| delivery == null | ||||||||||||||||||||||||||||||||||
| ? undefined | ||||||||||||||||||||||||||||||||||
| : yield* projectionStore.getThreadRecords(parentThreadId, ["messages", "subagents"], { | ||||||||||||||||||||||||||||||||||
| messageIds: [delivery.messageId], | ||||||||||||||||||||||||||||||||||
| subagentIds: [...new Set([...delivery.taskIds, task.id])], | ||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
| const deliveryRunId = deliveryRecords?.messages[0]?.runId ?? null; | ||||||||||||||||||||||||||||||||||
| const deliveryRun = | ||||||||||||||||||||||||||||||||||
| deliveryRunId === null || deliveryRunId === parentRun?.id | ||||||||||||||||||||||||||||||||||
| ? undefined | ||||||||||||||||||||||||||||||||||
| : parentProjection.runs.find((candidate) => candidate.id === task.runId); | ||||||||||||||||||||||||||||||||||
| const parentNode = parentProjection.nodes.find((candidate) => candidate.id === task.id); | ||||||||||||||||||||||||||||||||||
| const parentTurnItem = parentProjection.turnItems.find( | ||||||||||||||||||||||||||||||||||
| : (yield* projectionStore.getThreadRecords(parentThreadId, ["runs"], { | ||||||||||||||||||||||||||||||||||
| runIds: [deliveryRunId], | ||||||||||||||||||||||||||||||||||
| })).runs[0]; | ||||||||||||||||||||||||||||||||||
| const parentProjection = { | ||||||||||||||||||||||||||||||||||
| thread: taskRecords.thread, | ||||||||||||||||||||||||||||||||||
| runs: [ | ||||||||||||||||||||||||||||||||||
| ...(parentRun === undefined ? [] : [parentRun]), | ||||||||||||||||||||||||||||||||||
| ...(deliveryRun ? [deliveryRun] : []), | ||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||
| messages: deliveryRecords?.messages ?? [], | ||||||||||||||||||||||||||||||||||
| subagents: deliveryRecords?.subagents ?? [task], | ||||||||||||||||||||||||||||||||||
| providerTurns: [], | ||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||
| const parentNode = taskRecords.nodes.find((candidate) => candidate.id === task.id); | ||||||||||||||||||||||||||||||||||
| const parentTurnItem = taskRecords.turnItems.find( | ||||||||||||||||||||||||||||||||||
| (candidate) => candidate.type === "subagent" && candidate.subagentId === task.id, | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| const updatedTask: OrchestrationV2Subagent = { | ||||||||||||||||||||||||||||||||||
|
|
@@ -13183,8 +13239,11 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio | |||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||
| const progress = delegatedTaskProgress(childControls); | ||||||||||||||||||||||||||||||||||
| const parent = yield* projectionStore.getThreadRecords(parentThreadId, [ | ||||||||||||||||||||||||||||||||||
| "subagents", | ||||||||||||||||||||||||||||||||||
| // A dispatcher parent holds thousands of tasks and transfers; this child owns a few of each. | ||||||||||||||||||||||||||||||||||
| const parent = yield* projectionStore.getThreadRecords(parentThreadId, ["subagents"], { | ||||||||||||||||||||||||||||||||||
| subagentChildThreadId: childThreadId, | ||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
| const { contextTransfers } = yield* projectionStore.getThreadRecords(childThreadId, [ | ||||||||||||||||||||||||||||||||||
| "contextTransfers", | ||||||||||||||||||||||||||||||||||
| ]); | ||||||||||||||||||||||||||||||||||
| for (const task of parent.subagents) { | ||||||||||||||||||||||||||||||||||
|
|
@@ -13194,9 +13253,11 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio | |||||||||||||||||||||||||||||||||
| (task.id === childControls.thread.forkedFrom.nodeId && | ||||||||||||||||||||||||||||||||||
| progress.state !== "result_available") || | ||||||||||||||||||||||||||||||||||
| (task.result !== null && | ||||||||||||||||||||||||||||||||||
| parent.contextTransfers.some( | ||||||||||||||||||||||||||||||||||
| contextTransfers.some( | ||||||||||||||||||||||||||||||||||
| (transfer) => | ||||||||||||||||||||||||||||||||||
| transfer.type === "subagent_result" && transfer.sourceThreadId === childThreadId, | ||||||||||||||||||||||||||||||||||
| transfer.type === "subagent_result" && | ||||||||||||||||||||||||||||||||||
| transfer.sourceThreadId === childThreadId && | ||||||||||||||||||||||||||||||||||
| transfer.targetThreadId === parentThreadId, | ||||||||||||||||||||||||||||||||||
| )) | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 Medium
orchestration-v2/Orchestrator.ts:5624After consecutive
/compactruns, the truncated projection drops the last ordinary prompt run, so the next prompt with a different model gets nomodelSwitcheven though the full history records a model change from that prompt.modelSwitchSinceexcludes compaction messages, leaving no baseline in the retained runs; preserve the last timeline-visible run as well as the compaction predecessor.🤖 Copy this AI Prompt to have your agent fix this:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Confirmed: with a
/compactrun directly before the compaction, the window had no run whose prompt the timeline shows, somodelSwitchSincelost its baseline. Fixed in 7836410: the window now starts at the last prompt before the latest compaction that is not itself a/compactrun (and not queued or rolled back). The compacted-thread case inProjectionStore.test.tsnow has a second compaction behind a/compactrun and expects the window to start at the prompt before it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I'm unable to act on this request because you do not have permissions within this repository.