Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 56 additions & 6 deletions apps/server/src/orchestration-v2/Orchestrator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1528,7 +1528,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?: ProjectionRecordFilter["sinceLastCompaction"],
) =>
projectionStore
.getThreadRecords(
threadId,
Expand Down Expand Up @@ -1557,6 +1560,7 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio
omitSettledSubagentRecords: true,
// Commands act on pending forks and merge-backs only; consumed ones stay unread.
contextTransferStatuses: ["pending"],
...(recent === undefined ? {} : { sinceLastCompaction: recent }),
},
)
.pipe(
Expand Down Expand Up @@ -1645,9 +1649,10 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio
Effect.fnUntraced(function* (
threadId: ThreadId,
events: Ref.Ref<Array<OrchestrationV2DomainEvent>>,
recent?: ProjectionRecordFilter["sinceLastCompaction"],
) {
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;
Expand Down Expand Up @@ -6307,7 +6312,28 @@ 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 reads every run and turn item, but attempts, nodes, messages and provider
// turns only for its recent runs and the runs this command names. An idle compaction reads
// in full: its busy check below looks for a delegated result's message under any old run.
let projection = yield* getProjectionWithPendingEvents(
command.threadId,
events,
command.idleCompaction === undefined
? {
keepRunIds: [
command.manualContinuationOfRunId,
command.restartContinuationOfRunId,
command.usageLimitContinuationOfRunId,
command.steerFollowUpOfRunId,
...(command.dispatchMode.type === "steer_active" ||
command.dispatchMode.type === "restart_active"
? [command.dispatchMode.targetRunId]
: []),
].flatMap((runId) => (runId === undefined ? [] : [runId])),
keepMessageId: command.messageId,
}
: undefined,
);
if (command.steerFollowUpOfRunId !== undefined) {
const source = projection.runs.find((run) => run.id === command.steerFollowUpOfRunId);
if (
Expand Down Expand Up @@ -6344,6 +6370,18 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio
});
return;
}
const activeProviderInstanceId = projection.providerThreads.find(
(candidate) => candidate.id === projection.thread.activeProviderThreadId,
)?.providerInstanceId;
// Another provider is handed what ran since it last saw the thread, which can be older than
// the compaction, so a provider switch reads the whole history.
if (
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);
Expand Down Expand Up @@ -6547,15 +6585,27 @@ 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);
// The recent runs of a compacted thread can hold only a `/compact` while an older prompt
// exists. Every prompt's turn item is loaded; without one, every user message is checked.
const onlyMaintenanceHistory = [
...userMessages,
...projection.turnItems.flatMap((item) => (item.type === "user_message" ? [item] : [])),
].every(isNativeMaintenanceCommand)
? projectionStore
.getThreadRecords(command.threadId, ["messages"], { messageRoles: ["user"] })
.pipe(
Effect.map(({ messages }) => [...messages, ...userMessages]),
Effect.map((all) => all.length > 0 && all.every(isNativeMaintenanceCommand)),
mapDispatchError(command),
)
: Effect.succeed(false);
if (
!isNativeMaintenanceCommand(command) &&
((command.titleSeed !== undefined &&
(yield* projectionStore
.getMessageCount(command.threadId)
.pipe(mapDispatchError(command))) === 0) ||
(command.createdBy === "user" && onlyMaintenanceHistory))
(command.createdBy === "user" && (yield* onlyMaintenanceHistory)))
) {
const now = yield* DateTime.now;
const thread: OrchestrationV2AppThread = {
Expand Down
Loading
Loading