Spaces:
Sleeping
Sleeping
| import { InMemoryStudioEventBus } from '../../../events/event-bus' | |
| import { logPlotStudioTiming, readRunElapsedMs } from '../../../observability/plot-studio-timing' | |
| import { extractLatestAssistantText, cancelRunState, failRunState, finalizeRunState } from '../session-runner-helpers' | |
| import type { | |
| StudioAssistantMessage, | |
| StudioEventBus, | |
| StudioRun, | |
| StudioSession | |
| } from '../../../domain/types' | |
| import type { StudioSessionRunnerDependencies } from './dependency-center' | |
| import type { StudioSubagentRunResult } from '../../tools/tool-runtime-context' | |
| export async function handleCancelledRun( | |
| deps: StudioSessionRunnerDependencies, | |
| input: { | |
| session: StudioSession | |
| run: StudioRun | |
| reason: string | |
| }, | |
| ): Promise<never> { | |
| const cancelledRun = cancelRunState(input.run, input.reason) | |
| await deps.runStore?.update(input.run.id, cancelledRun) | |
| ;(deps.sharedEventBus ?? new InMemoryStudioEventBus()).publish({ | |
| type: 'run_updated', | |
| run: cancelledRun | |
| }) | |
| logPlotStudioTiming(input.session.studioKind, 'run.failed', { | |
| sessionId: input.session.id, | |
| runId: input.run.id, | |
| error: input.reason, | |
| cancelled: true, | |
| runElapsedMs: readRunElapsedMs(cancelledRun), | |
| }, 'warn') | |
| throw new Error(input.reason) | |
| } | |
| export async function finalizeSuccessfulRun( | |
| deps: StudioSessionRunnerDependencies, | |
| input: { | |
| session: StudioSession | |
| run: StudioRun | |
| assistantMessage: StudioAssistantMessage | |
| outcome: 'continue' | 'stop' | 'compact' | |
| eventBus: StudioEventBus | |
| }, | |
| ): Promise<StudioSubagentRunResult & { run: StudioRun; assistantMessage: StudioAssistantMessage }> { | |
| const finishedRun = finalizeRunState({ run: input.run, outcome: input.outcome }) | |
| await deps.runStore?.update(input.run.id, finishedRun) | |
| input.eventBus.publish({ | |
| type: 'run_updated', | |
| run: finishedRun | |
| }) | |
| const finalAssistantMessage = await findLatestAssistantMessage( | |
| deps, | |
| input.session.id, | |
| input.assistantMessage, | |
| ) | |
| logPlotStudioTiming(input.session.studioKind, 'run.completed', { | |
| sessionId: input.session.id, | |
| runId: input.run.id, | |
| outcome: input.outcome, | |
| eventCount: input.eventBus.list().length, | |
| runElapsedMs: readRunElapsedMs(finishedRun), | |
| }) | |
| return { | |
| run: finishedRun, | |
| assistantMessage: finalAssistantMessage, | |
| text: extractLatestAssistantText(finalAssistantMessage.parts) | |
| } | |
| } | |
| export async function handleFailedRun( | |
| deps: StudioSessionRunnerDependencies, | |
| input: { | |
| session: StudioSession | |
| run: StudioRun | |
| error: unknown | |
| }, | |
| ): Promise<never> { | |
| const message = input.error instanceof Error ? input.error.message : String(input.error) | |
| const failedRun = failRunState(input.run, message) | |
| await deps.runStore?.update(input.run.id, failedRun) | |
| ;(deps.sharedEventBus ?? new InMemoryStudioEventBus()).publish({ | |
| type: 'run_updated', | |
| run: failedRun | |
| }) | |
| logPlotStudioTiming(input.session.studioKind, 'run.failed', { | |
| sessionId: input.session.id, | |
| runId: input.run.id, | |
| error: message, | |
| runElapsedMs: readRunElapsedMs(failedRun), | |
| }, 'warn') | |
| throw input.error | |
| } | |
| async function findLatestAssistantMessage( | |
| deps: StudioSessionRunnerDependencies, | |
| sessionId: string, | |
| fallback: StudioAssistantMessage, | |
| ): Promise<StudioAssistantMessage> { | |
| const messages = await deps.messageStore.listBySessionId(sessionId) | |
| const latestAssistantMessage = [...messages] | |
| .reverse() | |
| .find((message): message is StudioAssistantMessage => message.role === 'assistant') | |
| return latestAssistantMessage ?? fallback | |
| } | |