| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| import assert from 'node:assert/strict'; |
| import { randomUUID } from 'node:crypto'; |
| import { WORKHUB_COORDINATION_SESSION_ID } from '@maka/core/session'; |
| import type { WorkHubRoutingDecision } from '@maka/core/workhub-routing'; |
| import type { WorkHubAdmittedAction } from '../server/workhub-coordination-action-gate.js'; |
| import type { ConnectionContext } from '../server/operation-dispatcher.js'; |
| import { runtimeInvocationOutcome } from '@maka/core/runtime-invocation'; |
| import { createRunCompositionSnapshot } from '@maka/core/run-composition'; |
| import type { BackendSendInput } from '@maka/core/backend-types'; |
| import type { SessionEvent } from '@maka/core/events'; |
| import { runtimeHandoffPause } from '@maka/core/runtime-handoff'; |
| import { deferred } from '@maka/core/test-only/async-primitives'; |
| import { runtimeInvocationFailureClass } from '@maka/runtime/runtime-event-read-model'; |
| import { parseNoRealConnectionError } from '@maka/core/connection-error-copy'; |
| import { createRequire } from 'node:module'; |
| import { mkdir, mkdtemp, rm, stat, writeFile } from 'node:fs/promises'; |
| import { tmpdir } from 'node:os'; |
| import { join } from 'node:path'; |
| import { DatabaseSync } from 'node:sqlite'; |
| import { test } from 'node:test'; |
| import type { |
| AgentGraphIntentClaim, |
| AgentGraphIntentClaimRequest, |
| } from '@maka/core/agent-graph-control'; |
| import type { HostedUserQuestionSettlement } from '@maka/core/backend-types'; |
| import type { ShellRunRecord } from '@maka/core/shell-run'; |
| import { waitFor as pollFor } from '@maka/core/test-only/async-primitives'; |
| import { |
| AgentGraphCoordinator, |
| agentGraphIdForRootSession, |
| } from '@maka/runtime/stream-graph-coordinator'; |
| import { |
| FAKE_ASK_USER_QUESTION_PROMPT, |
| FAKE_HOLD_OPEN_PROMPT, |
| FakeBackend, |
| } from '@maka/runtime/test-only/fake-backend'; |
| import { LOCAL_READ_AGENT_DEFINITION } from '@maka/runtime/agent-catalog'; |
| import { SessionManager, type BackendFactory } from '@maka/runtime/session-manager'; |
| import { workHubDirectStopAbortSource } from '@maka/runtime/session-manager'; |
| import { fingerprintAgentGraphRunnableIntent } from '@maka/runtime/stream-graph-admission'; |
| import type { AgentGraphRunnableIntent } from '@maka/runtime/stream-graph-readiness'; |
| import { createAgentGraphControlStore } from '@maka/storage/agent-graph-control-store'; |
| import { openInteractiveExecutionStoresForWrite } from '@maka/storage/execution-stores'; |
| import { createSessionStore } from '@maka/storage/session-store'; |
| import { |
| LONG_TERM_MEMORY_DATABASE_NAME, |
| openInteractiveLongTermMemoryStoreForWrite, |
| } from '@maka/storage/long-term-memory-store'; |
| import { |
| resolveStorageRoot, |
| tryAcquireInteractiveRootOwner, |
| type InteractiveRootOwner, |
| } from '@maka/storage/root-authority'; |
| import { openInteractiveUsageStoresForWrite } from '@maka/storage/usage-stores'; |
| import { openInteractiveDailyReviewAuthorityForWrite } from '@maka/storage/daily-review-authority'; |
| import { openInteractiveScheduledTaskStoreForWrite } from '@maka/storage/scheduled-task-store'; |
| import { openInteractiveShellRunStoreForWrite } from '@maka/storage/shell-run-authority'; |
| import { openInteractiveRuntimePolicyStoresForWrite } from '@maka/storage/runtime-policy-stores'; |
| import { |
| HostResidencyRegistry, |
| type HostResidencyKind, |
| } from '../server/host-residency-registry.js'; |
| import { |
| createExecutionRuntimeHostComposition, |
| runtimeHostFilesystemWorkerRuntime, |
| stopOwnedWorkHubRoot, |
| stopReplacedWorkHubRoot, |
| type ExecutionRuntimeHostComposition, |
| } from '../server/execution-composition.js'; |
| import { RuntimeHostKernel, type RuntimeHostCompositionContext } from '../server/host-kernel.js'; |
| import { defineInteractiveRuntimeHostComposition } from '../server/host-composition.js'; |
| import { connectRuntimeHost, RuntimeHostOperationError } from '../client/index.js'; |
| import { RUNTIME_HOST_PROTOCOL_VERSION } from '../protocol/index.js'; |
| import { readLedgerMessages } from './fixtures/ledger-transcript.js'; |
| import { clientCapabilityConnectionIdentity } from './fixtures/client-capability.js'; |
| |
| const require = createRequire(import.meta.url); |
| const FAKE_CONNECTION_ID = 'bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb'; |
| const CONTEXT_OFFLOAD_DATABASE_NAME = 'context-offload.sqlite'; |
| const workHubRoutingDecisions = new WeakMap< |
| ExecutionRuntimeHostComposition, |
| Map<string, WorkHubRoutingDecision> |
| >(); |
| const HANDOFF_TEST_COMPOSITION = createRunCompositionSnapshot({ |
| composerId: 'test.handoff', |
| composerRevision: '1', |
| sourceRevisions: [], |
| baseSystemPromptHash: `sha256:${'0'.repeat(64)}`, |
| toolCatalogHash: `sha256:${'0'.repeat(64)}`, |
| toolAvailabilityHash: `sha256:${'0'.repeat(64)}`, |
| baseProviderOptionsHash: `sha256:${'0'.repeat(64)}`, |
| toolNames: [], |
| contextWindow: null, |
| }); |
| |
| test('idle schedules and armed or paused Goals allow production handoff and recover in the successor', { |
| timeout: 20_000, |
| }, async () => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| const store = await openInteractiveDailyReviewAuthorityForWrite(owner.lease); |
| const snapshot = await store.readConfig(); |
| await store.updateConfig(snapshot.revision, { |
| enabled: true, |
| executeTime: '00:00', |
| modelKey: '', |
| }); |
| const schedules = await openInteractiveScheduledTaskStoreForWrite(owner.lease); |
| await schedules.create( |
| { |
| title: 'Future reminder', |
| intentBody: 'Remind me tomorrow', |
| schedule: { kind: 'once', runAt: Date.now() + 86_400_000 }, |
| effect: { kind: 'notify', channel: 'local' }, |
| createdBy: { kind: 'user' }, |
| }, |
| Date.now(), |
| ); |
| schedules.close(); |
| const residencies = new HostResidencyRegistry(); |
| const { composition, manager } = await createCapturedExecutionComposition(owner, { |
| residencies, |
| }); |
| const expected = [ |
| { label: 'daily-review', count: 1 }, |
| { label: 'goal', count: 2 }, |
| { label: 'scheduled-task', count: 1 }, |
| ]; |
| try { |
| const context = { |
| hostEpoch: 'old-host', |
| connectionId: 'test', |
| principal: 'local_os_user' as const, |
| acquireResidency: () => ({ release() {} }), |
| }; |
| for (const pause of [false, true]) { |
| const session = await manager.createSession({ |
| cwd: root, |
| llmConnectionId: FAKE_CONNECTION_ID, |
| llmConnectionSlug: 'fake', |
| model: 'fake-model', |
| permissionMode: 'ask', |
| }); |
| const armed = await composition.handlers['goal.arm']( |
| { |
| sessionId: session.id, |
| condition: 'Finish later', |
| maxIterations: null, |
| tokenBudget: null, |
| }, |
| context, |
| ); |
| assert.ok(armed.ok); |
| if (pause) { |
| const paused = await composition.handlers['goal.control']( |
| { |
| sessionId: session.id, |
| goalId: armed.result.goal.goalId, |
| expectedRevision: armed.result.goal.revision, |
| action: 'pause', |
| }, |
| context, |
| ); |
| assert.ok(paused.ok); |
| } |
| } |
| await waitFor(async () => residencies.drainCount === 0); |
| assert.deepEqual(residencies.snapshot(), expected); |
| const cancelled = await composition.prepareHandoff!('old-host', new AbortController().signal); |
| assert.ok(cancelled); |
| assert.equal(await cancelled.seal(), true); |
| const cancelledProof = await cancelled.residencies(); |
| assert.ok(cancelledProof); |
| assert.equal(residencies.hasDrainResidenciesExcept(cancelledProof), false); |
| cancelled.cancel(); |
| const prepared = await composition.prepareHandoff!('old-host', new AbortController().signal); |
| assert.ok(prepared); |
| assert.equal(await prepared.seal(), true); |
| const proof = await prepared.residencies(); |
| assert.ok(proof); |
| assert.equal(residencies.hasDrainResidenciesExcept(proof), false); |
| await prepared.detach(); |
| } finally { |
| await composition.close(); |
| } |
| assert.equal(residencies.activeCount, 0); |
| await owner.close(); |
| const successorOwner = await tryAcquireInteractiveRootOwner( |
| await resolveStorageRoot({ path: root, kind: 'interactive' }), |
| ); |
| assert.ok(successorOwner); |
| try { |
| const successor = await createCapturedExecutionComposition(successorOwner, { residencies }); |
| try { |
| await waitFor(async () => residencies.drainCount === 0); |
| assert.deepEqual(residencies.snapshot(), expected); |
| } finally { |
| await successor.composition.close(); |
| } |
| } finally { |
| await successorOwner.close(); |
| } |
| }); |
| }); |
| |
| test('production composition resumes a sealed logical Root after all stores and runtime owners reopen', { |
| timeout: 20_000, |
| }, async () => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| const entered = deferred<void>(); |
| const boundary = deferred<void>(); |
| const requested = deferred<void>(); |
| let dispatches = 0; |
| const backendFactory: BackendFactory = (context) => |
| new (class extends FakeBackend { |
| async prepareRunComposition(input: { runId: string; turnId: string }): Promise<void> { |
| await context.recordRunComposition!(input.runId, HANDOFF_TEST_COMPOSITION); |
| } |
| |
| override async *send(input: BackendSendInput): AsyncIterable<SessionEvent> { |
| assert.ok(input.runId); |
| await this.prepareRunComposition({ runId: input.runId, turnId: input.turnId }); |
| dispatches += 1; |
| if (!input.continuation) { |
| assert.equal(input.maxSteps, 4); |
| entered.resolve(); |
| await boundary.promise; |
| assert.equal(await input.handoffBoundary!(new AbortController().signal, 3), 'pause'); |
| return; |
| } |
| assert.equal(input.maxSteps, 3); |
| yield { |
| type: 'complete', |
| id: 'completed-after-reopen', |
| turnId: input.turnId, |
| ts: Date.now(), |
| stopReason: 'end_turn', |
| }; |
| } |
| })(context); |
| const residencies = new HostResidencyRegistry(); |
| const first = await createCapturedExecutionComposition(owner, { |
| primaryBackendFactory: backendFactory, |
| residencies, |
| }); |
| let successorOwner: InteractiveRootOwner | undefined; |
| let successor: Awaited<ReturnType<typeof createCapturedExecutionComposition>> | undefined; |
| try { |
| const request = first.manager.requestRunHandoff.bind(first.manager); |
| first.manager.requestRunHandoff = (...args) => { |
| const result = request(...args); |
| requested.resolve(); |
| return result; |
| }; |
| const session = await first.manager.createSession({ |
| cwd: root, |
| llmConnectionId: FAKE_CONNECTION_ID, |
| llmConnectionSlug: 'fake', |
| model: 'fake-model', |
| permissionMode: 'ask', |
| }); |
| const started = await first.composition.handlers['turn.start']( |
| { |
| sessionId: session.id, |
| turnId: 'reopen-handoff-turn', |
| content: { text: 'continue after restart' }, |
| maxSteps: 4, |
| }, |
| { |
| hostEpoch: 'execution-composition-test', |
| connectionId: 'client', |
| principal: 'local_os_user', |
| acquireResidency: () => residencies.acquire('test-operation'), |
| }, |
| ); |
| assert.equal(started.ok, true, JSON.stringify(started)); |
| await entered.promise; |
| assert.ok(first.composition.prepareHandoff); |
| const preparing = first.composition.prepareHandoff( |
| 'execution-composition-test', |
| new AbortController().signal, |
| ); |
| await requested.promise; |
| boundary.resolve(); |
| const preparation = await preparing; |
| assert.ok(preparation); |
| assert.equal(await preparation.seal(), true); |
| const transferred = await preparation.residencies(); |
| assert.ok(transferred); |
| assert.equal( |
| residencies.hasDrainResidenciesExcept(transferred), |
| false, |
| JSON.stringify(residencies.snapshot()), |
| ); |
| await preparation.detach(); |
| first.composition.beginDrain(); |
| await first.composition.close(); |
| assert.equal(dispatches, 1); |
| await owner.close(); |
| |
| successorOwner = await tryAcquireInteractiveRootOwner( |
| await resolveStorageRoot({ path: root, kind: 'interactive' }), |
| ); |
| assert.ok(successorOwner); |
| successor = await createCapturedExecutionComposition(successorOwner, { |
| primaryBackendFactory: backendFactory, |
| }); |
| const stores = await openInteractiveExecutionStoresForWrite(successorOwner.lease); |
| await waitFor( |
| async () => |
| (await stores.runtimeEventStore.listSessionInvocations(session.id)).some( |
| (run) => runtimeInvocationOutcome(run) === 'completed', |
| ), |
| 5_000, |
| ); |
| const runs = await stores.runtimeEventStore.listSessionInvocations(session.id); |
| assert.equal(runs.length, 2); |
| assert.equal(new Set(runs.map((run) => run.turnId)).size, 1); |
| assert.equal( |
| runs.filter((run) => run.terminalEvent && runtimeHandoffPause(run.terminalEvent)).length, |
| 1, |
| ); |
| assert.equal(runs.filter((run) => runtimeInvocationOutcome(run) === 'completed').length, 1); |
| assert.equal(dispatches, 2); |
| } finally { |
| boundary.resolve(); |
| first.composition.beginDrain(); |
| await first.composition.close(); |
| successor?.composition.beginDrain(); |
| await successor?.composition.close(); |
| await successorOwner?.close(); |
| } |
| }); |
| }); |
| |
| test('production recovery leaves upgrade residue for explicitly started maintenance', async () => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| const composition = await createExecutionRuntimeHostComposition(compositionContext(owner)); |
| const directory = join(root, 'artifacts', 'retired'); |
| const path = join(directory, 'orphan'); |
| await mkdir(directory, { recursive: true }); |
| await writeFile(path, 'old bytes'); |
| const database = new DatabaseSync(join(root, 'runtime.sqlite')); |
| try { |
| database |
| .prepare('INSERT INTO artifact_upgrade_orphan_paths VALUES (?)') |
| .run('retired/orphan'); |
| await composition.recover(); |
| assert.equal((await stat(path)).size, 9); |
| composition.startMaintenance?.(); |
| await waitFor(async () => { |
| return ( |
| database.prepare('SELECT count(*) AS n FROM artifact_upgrade_orphan_paths').get()?.n === 0 |
| ); |
| }); |
| await assert.rejects(stat(path), { code: 'ENOENT' }); |
| } finally { |
| await composition.close(); |
| database.close(); |
| } |
| }); |
| }); |
| |
| test('filesystem worker follows the candidate executable runtime', () => { |
| assert.equal(runtimeHostFilesystemWorkerRuntime({ electron: '43.1.1' }), 'electron'); |
| assert.equal(runtimeHostFilesystemWorkerRuntime({}), 'node'); |
| }); |
| |
| test('WorkHub recovers a delivered root Stop from its durable cancelled Turn', async () => { |
| let stopCalls = 0; |
| const outcome = await stopOwnedWorkHubRoot( |
| { |
| readRootState: () => ({ kind: 'idle' }), |
| read: async (identity: { sessionId: string; turnId: string; runId: string }) => ({ |
| ...identity, |
| status: 'cancelled', |
| terminalEventId: 'terminal-workhub-stop', |
| abortSource: workHubDirectStopAbortSource('workhub-stop-action'), |
| }), |
| stopRoot: async () => { |
| stopCalls += 1; |
| }, |
| } as unknown as Parameters<typeof stopOwnedWorkHubRoot>[0], |
| { sessionId: 'target-session', turnId: 'target-turn', runId: 'target-run' }, |
| 'workhub-stop-action', |
| ); |
| |
| assert.deepEqual(outcome, { |
| outcome: 'stop_delivered', |
| targetTurnId: 'target-turn', |
| }); |
| assert.equal(stopCalls, 0); |
| }); |
| |
| test('WorkHub never reports a still-running root as already terminal', async () => { |
| // The restart window: the execution is not registered in memory yet, so the |
| // root looks inactive while its durable snapshot is still running. |
| const outcome = await stopOwnedWorkHubRoot( |
| { |
| readRootState: () => ({ kind: 'idle' }), |
| read: async (identity: { sessionId: string; turnId: string; runId: string }) => ({ |
| ...identity, |
| status: 'running', |
| }), |
| stopRoot: async () => assert.fail('an unregistered root cannot be stopped'), |
| } as unknown as Parameters<typeof stopOwnedWorkHubRoot>[0], |
| { sessionId: 'target-session', turnId: 'target-turn', runId: 'target-run' }, |
| 'workhub-stop-action', |
| ); |
| |
| assert.deepEqual(outcome, { outcome: 'recovering', targetTurnId: 'target-turn' }); |
| |
| // A durably terminal snapshot is still the proof `already_terminal` needs. |
| const settled = await stopOwnedWorkHubRoot( |
| { |
| readRootState: () => ({ kind: 'idle' }), |
| read: async (identity: { sessionId: string; turnId: string; runId: string }) => ({ |
| ...identity, |
| status: 'completed', |
| terminalEventId: 'terminal-complete', |
| }), |
| stopRoot: async () => assert.fail('a completed root cannot be stopped'), |
| } as unknown as Parameters<typeof stopOwnedWorkHubRoot>[0], |
| { sessionId: 'target-session', turnId: 'target-turn', runId: 'target-run' }, |
| 'workhub-stop-action', |
| ); |
| |
| assert.deepEqual(settled, { outcome: 'already_terminal', targetTurnId: 'target-turn' }); |
| }); |
| |
| test('WorkHub binds a fresh owning-root Stop to its action identity', async () => { |
| let source: string | undefined; |
| let actionId: string | undefined; |
| const outcome = await stopOwnedWorkHubRoot( |
| { |
| readRootState: () => ({ |
| kind: 'active', |
| sessionId: 'target-session', |
| turnId: 'target-turn', |
| runId: 'target-run', |
| }), |
| read: async (identity: { sessionId: string; turnId: string; runId: string }) => ({ |
| ...identity, |
| status: 'cancelled', |
| terminalEventId: 'terminal-workhub-stop', |
| abortSource: workHubDirectStopAbortSource('workhub-stop-action'), |
| }), |
| stopRoot: async ( |
| _identity: { sessionId: string; turnId: string; runId: string }, |
| input: { |
| source?: 'stop_button' | 'graph_supervisor' | 'workhub_direct_stop'; |
| workHubActionId?: string; |
| }, |
| ) => { |
| source = input.source; |
| actionId = input.workHubActionId; |
| }, |
| } as unknown as Parameters<typeof stopOwnedWorkHubRoot>[0], |
| { sessionId: 'target-session', turnId: 'target-turn', runId: 'target-run' }, |
| 'workhub-stop-action', |
| ); |
| |
| assert.equal(source, 'workhub_direct_stop'); |
| assert.equal(actionId, 'workhub-stop-action'); |
| assert.equal(outcome.outcome, 'stop_delivered'); |
| }); |
| |
| test('WorkHub detects a manual Stop that wins after its active-root check', async () => { |
| let stopCalls = 0; |
| const outcome = await stopOwnedWorkHubRoot( |
| { |
| readRootState: () => ({ |
| kind: 'active', |
| sessionId: 'target-session', |
| turnId: 'target-turn', |
| runId: 'target-run', |
| }), |
| read: async (identity: { sessionId: string; turnId: string; runId: string }) => ({ |
| ...identity, |
| status: 'cancelled', |
| terminalEventId: 'concurrent-manual-stop', |
| abortSource: 'renderer.stop_button', |
| }), |
| stopRoot: async () => { |
| stopCalls += 1; |
| }, |
| } as unknown as Parameters<typeof stopOwnedWorkHubRoot>[0], |
| { sessionId: 'target-session', turnId: 'target-turn', runId: 'target-run' }, |
| 'workhub-stop-action', |
| ); |
| |
| assert.equal(stopCalls, 1); |
| assert.equal(outcome.outcome, 'already_terminal'); |
| }); |
| |
| test('a replacement retirement never records direct-stop provenance', async () => { |
| const stops: Array<Record<string, unknown> | undefined> = []; |
| const outcome = await stopReplacedWorkHubRoot( |
| { |
| readRootState: () => ({ |
| kind: 'active', |
| sessionId: 'target-session', |
| turnId: 'target-turn', |
| runId: 'target-run', |
| }), |
| read: async () => assert.fail('replacement retirement must not re-read stop provenance'), |
| stopRoot: async ( |
| _identity: { sessionId: string; turnId: string; runId: string }, |
| input?: Record<string, unknown>, |
| ) => { |
| stops.push(input); |
| }, |
| } as unknown as Parameters<typeof stopReplacedWorkHubRoot>[0], |
| { sessionId: 'target-session', turnId: 'target-turn', runId: 'target-run' }, |
| ); |
| |
| assert.deepEqual(stops, [undefined]); |
| assert.deepEqual(outcome, { outcome: 'stop_delivered', targetTurnId: 'target-turn' }); |
| }); |
| |
| test('a replacement leaves a root it no longer owns alone', async () => { |
| const outcome = await stopReplacedWorkHubRoot( |
| { |
| readRootState: () => ({ |
| kind: 'active', |
| sessionId: 'target-session', |
| turnId: 'other-turn', |
| runId: 'other-run', |
| }), |
| read: async () => assert.fail('replacement retirement must not re-read stop provenance'), |
| stopRoot: async () => assert.fail('a root owned by another Turn must not be stopped'), |
| } as unknown as Parameters<typeof stopReplacedWorkHubRoot>[0], |
| { sessionId: 'target-session', turnId: 'target-turn', runId: 'target-run' }, |
| ); |
| |
| assert.deepEqual(outcome, { outcome: 'already_terminal', targetTurnId: 'target-turn' }); |
| }); |
| |
| test('production composition owns the long-term memory database lifecycle', async () => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| const databasePath = join(root, LONG_TERM_MEMORY_DATABASE_NAME); |
| await assert.rejects(stat(databasePath), { code: 'ENOENT' }); |
| |
| const composition = await createExecutionRuntimeHostComposition(compositionContext(owner)); |
| const workspaceExecution = composition.workspaceExecution; |
| assert.equal(workspaceExecution.state, 'ready'); |
| const memory = await openInteractiveLongTermMemoryStoreForWrite(owner.lease); |
| assert.equal((await stat(databasePath)).isFile(), true); |
| |
| composition.beginDrain(); |
| assert.equal(workspaceExecution.state, 'draining'); |
| await composition.close(); |
| assert.equal(workspaceExecution.state, 'closed'); |
| await assert.rejects(memory.readItem('after-close'), /closed/); |
| const Database = (require('node:sqlite') as typeof import('node:sqlite')).DatabaseSync; |
| const database = new Database(databasePath); |
| try { |
| const counts = database |
| .prepare( |
| `SELECT |
| (SELECT COUNT(*) FROM memory_items) AS item_count, |
| (SELECT COUNT(*) FROM memory_write_operations) AS operation_count`, |
| ) |
| .get() as { item_count?: unknown; operation_count?: unknown }; |
| assert.equal(counts.item_count, 0); |
| assert.equal(counts.operation_count, 0); |
| } finally { |
| database.close(); |
| } |
| }); |
| }); |
| |
| test('production composition reaches Ready when the optional context Store cannot open', async () => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| const requestFingerprint = `sha256:${'a'.repeat(64)}` as const; |
| const preparingSessionId = 'preparing-context-copy'; |
| const sessionStore = createSessionStore(root); |
| await sessionStore.createStableSession({ |
| sessionId: preparingSessionId, |
| requestFingerprint, |
| input: { |
| cwd: root, |
| llmConnectionId: FAKE_CONNECTION_ID, |
| llmConnectionSlug: 'fake', |
| model: 'fake-model', |
| permissionMode: 'ask', |
| name: 'Preparing context copy', |
| labels: [], |
| parentSessionId: 'source-session', |
| branchOfTurnId: 'source-turn', |
| conversationCopy: { |
| kind: 'branch', |
| sourceSessionId: 'source-session', |
| sourceTurnId: 'source-turn', |
| requestFingerprint, |
| state: 'preparing', |
| }, |
| }, |
| }); |
| await sessionStore.close?.(); |
| await mkdir(join(root, CONTEXT_OFFLOAD_DATABASE_NAME)); |
| const originalConsoleError = console.error; |
| const diagnostics: string[] = []; |
| console.error = (...values: unknown[]) => diagnostics.push(values.map(String).join(' ')); |
| let composition: Awaited<ReturnType<typeof createExecutionRuntimeHostComposition>> | undefined; |
| try { |
| composition = await createExecutionRuntimeHostComposition(compositionContext(owner)); |
| assert.equal(composition.workspaceExecution.state, 'ready'); |
| assert.equal( |
| diagnostics.some((message) => message.includes('optional context-offload Store')), |
| true, |
| ); |
| await composition.recover(); |
| assert.equal( |
| diagnostics.some((message) => |
| message.includes('conversation copy cleanup deferred during recovery'), |
| ), |
| true, |
| ); |
| } finally { |
| console.error = originalConsoleError; |
| if (composition) { |
| await composition.close(); |
| } |
| } |
| const reopened = createSessionStore(root); |
| try { |
| assert.equal( |
| (await reopened.readHeaderSnapshot(preparingSessionId)).conversationCopy?.state, |
| 'preparing', |
| ); |
| } finally { |
| await reopened.close?.(); |
| } |
| }); |
| }); |
| |
| test('production composition closes long-term memory after a later startup failure', async () => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| const stores = await openInteractiveExecutionStoresForWrite(owner.lease); |
| const session = await stores.sessionStore.create({ |
| cwd: root, |
| llmConnectionId: FAKE_CONNECTION_ID, |
| llmConnectionSlug: 'fake', |
| model: 'fake-model', |
| permissionMode: 'ask', |
| }); |
| const memory = await openInteractiveLongTermMemoryStoreForWrite(owner.lease); |
| |
| // Fail the composition after the memory store is opened: beginHostEpoch |
| // runs later in the startup sequence and rejects an invalid host epoch, |
| // so the composition must close every resource it opened, including |
| // long-term memory. |
| await assert.rejects( |
| createExecutionRuntimeHostComposition({ |
| ...compositionContext(owner), |
| hostEpoch: 'invalid host epoch!', |
| }), |
| ); |
| await assert.rejects(memory.readItem('after-failed-start'), /closed/); |
| |
| await owner.close(); |
| const recoveredCapability = await resolveStorageRoot({ path: root, kind: 'interactive' }); |
| const recoveredOwner = await tryAcquireInteractiveRootOwner(recoveredCapability); |
| assert.ok(recoveredOwner); |
| if (!recoveredOwner) return; |
| try { |
| const recovered = await createExecutionRuntimeHostComposition( |
| compositionContext(recoveredOwner), |
| ); |
| await recovered.close(); |
| } finally { |
| await recoveredOwner.close(); |
| } |
| }); |
| }); |
| |
| test('production recovery preserves legacy Automation history and closes an orphaned admission', async () => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| const stores = await openInteractiveExecutionStoresForWrite(owner.lease); |
| const historical = await stores.sessionStore.create({ |
| cwd: root, |
| llmConnectionId: FAKE_CONNECTION_ID, |
| llmConnectionSlug: 'fake', |
| model: 'fake-model', |
| permissionMode: 'ask', |
| }); |
| const pending = await stores.sessionStore.create({ |
| cwd: root, |
| llmConnectionId: FAKE_CONNECTION_ID, |
| llmConnectionSlug: 'fake', |
| model: 'fake-model', |
| permissionMode: 'ask', |
| }); |
| const admitted = await stores.agentRunStore.admitRootTurn({ |
| sessionId: pending.id, |
| turnId: 'legacy-automation-turn', |
| proposedRunId: 'legacy-automation-run', |
| proposedUserMessageId: 'legacy-automation-message', |
| execution: { kind: 'scheduled_task', scheduledTaskId: 'legacy-automation' }, |
| previousRootTurnId: null, |
| normalizedInput: { text: 'Run the legacy Automation' }, |
| sourceMessages: [], |
| admittedAt: 1, |
| }); |
| assert.equal(admitted.kind, 'admitted'); |
| |
| const Database = (require('node:sqlite') as typeof import('node:sqlite')).DatabaseSync; |
| const database = new Database(join(root, 'runtime.sqlite')); |
| database.exec('BEGIN IMMEDIATE'); |
| try { |
| database |
| .prepare(` |
| INSERT INTO session_messages( |
| session_id, sequence, message_id, message_type, message_ts, record_json |
| ) VALUES (?, 0, ?, 'user', 1, ?) |
| `) |
| .run( |
| historical.id, |
| 'historical-automation-message', |
| JSON.stringify({ |
| type: 'user', |
| id: 'historical-automation-message', |
| turnId: 'historical-automation-turn', |
| ts: 1, |
| text: 'Historical Automation prompt', |
| origin: { kind: 'automation', automationId: 'historical-automation' }, |
| }), |
| ); |
| const row = database |
| .prepare(` |
| SELECT record_json |
| FROM core_root_turn_admissions |
| WHERE session_id = ? AND turn_id = 'legacy-automation-turn' |
| `) |
| .get(pending.id) as { record_json: string }; |
| const record = JSON.parse(row.record_json) as Record<string, unknown>; |
| record.execution = { kind: 'automation', automationId: 'legacy-automation' }; |
| database |
| .prepare(` |
| UPDATE core_root_turn_admissions |
| SET record_json = ? |
| WHERE session_id = ? AND turn_id = 'legacy-automation-turn' |
| `) |
| .run(JSON.stringify(record), pending.id); |
| database.exec('COMMIT'); |
| } catch (error) { |
| database.exec('ROLLBACK'); |
| throw error; |
| } |
| database.close(); |
| |
| const composition = await createExecutionRuntimeHostComposition(compositionContext(owner)); |
| try { |
| await composition.recover(); |
| // The legacy transcript itself, as the converter reads it: recovery must |
| // leave a pre-ledger Automation's origin intact for the import that |
| // follows on the Session's first read. |
| const history = await stores.sessionStore.readMessages(historical.id); |
| assert.deepEqual(history[0]?.type === 'user' ? history[0].origin : undefined, { |
| kind: 'legacy_automation', |
| automationId: 'historical-automation', |
| }); |
| const recoveredRun = (await stores.runtimeEventStore.listSessionInvocations(pending.id)).find( |
| (candidate) => candidate.runId === 'legacy-automation-run', |
| ); |
| assert.ok(recoveredRun); |
| assert.equal(recoveredRun && runtimeInvocationOutcome(recoveredRun), 'failed'); |
| assert.deepEqual(recoveredRun?.opening.root, { |
| kind: 'legacy_automation', |
| legacyAutomationId: 'legacy-automation', |
| }); |
| assert.equal(recoveredRun && runtimeInvocationFailureClass(recoveredRun), 'app_restarted'); |
| } finally { |
| await composition.close(); |
| } |
| }); |
| }); |
| |
| test('composition drain preserves usage admission until active Runtime work settles', async () => { |
| await withCompositionRoot(async ({ owner }) => { |
| const composition = await createExecutionRuntimeHostComposition(compositionContext(owner)); |
| const usage = await openInteractiveUsageStoresForWrite(owner.lease); |
| composition.beginDrain(); |
| |
| await usage.telemetry.recordLlmCall(lifecycleUsageRecord()); |
| const persisted = await usage.telemetry.logs({ range: 'all' }, 0, 10); |
| assert.deepEqual( |
| persisted.rows.map((row) => row.id), |
| ['usage_after_composition_drain'], |
| ); |
| |
| await composition.close(); |
| }); |
| }); |
| |
| test('hosted execution settles while its tracked environment resource remains verifiable', async () => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| const policy = await openInteractiveRuntimePolicyStoresForWrite(owner.lease); |
| const created = await policy.connectionCatalog.create({ |
| expectedCatalogRevision: 0, |
| connection: { |
| slug: 'hosted-fake', |
| name: 'Hosted fake', |
| providerType: 'ollama', |
| enabled: true, |
| enabledModelIds: ['fake-model'], |
| }, |
| }); |
| assert.equal(created.kind, 'committed'); |
| if (created.kind !== 'committed') return; |
| const connection = created.snapshot.connections[0]; |
| assert.ok(connection); |
| const fetch = await policy.operations.beginModelFetch(connection.connectionId); |
| assert.equal(fetch.kind, 'ready'); |
| if (fetch.kind !== 'ready') return; |
| const fetched = await policy.operations.completeModelFetch(fetch.ticket, { |
| models: [{ id: 'fake-model' }], |
| source: 'fetched', |
| fetchedAt: Date.now(), |
| }); |
| assert.equal(fetched.kind, 'committed'); |
| if (fetched.kind !== 'committed') return; |
| const defaultTarget = await policy.connectionCatalog.setDefaultTarget({ |
| expectedCatalogRevision: fetched.snapshot.revision, |
| target: { connectionId: connection.connectionId, modelId: 'fake-model' }, |
| }); |
| assert.equal(defaultTarget.kind, 'committed'); |
| |
| const residencies = new HostResidencyRegistry(); |
| let composition: Awaited<ReturnType<typeof createExecutionRuntimeHostComposition>>; |
| const operationContext = { |
| hostEpoch: 'hosted-environment-test', |
| connectionId: 'hosted-environment-test', |
| principal: 'runtime_host' as const, |
| acquireResidency: () => ({ release() {} }), |
| }; |
| composition = await createExecutionRuntimeHostComposition( |
| { |
| owner, |
| hostEpoch: operationContext.hostEpoch, |
| acquireResidency: (label) => residencies.acquire(label), |
| retainUntilProcessExit: () => undefined, |
| requestDrain: () => composition?.beginDrain(), |
| waitForResidencies: () => residencies.waitForEmpty(), |
| waitForResidenciesExcept: (label) => residencies.waitForEmptyExcept(label), |
| }, |
| { bootstrapRuntimePolicy: false }, |
| { |
| primaryBackendFactory: (backendContext) => { |
| const backend = new FakeBackend(backendContext); |
| const send = backend.send.bind(backend); |
| backend.send = async function* (input) { |
| if (input.text === 'leave the environment ready for verification') { |
| const started = await composition.handlers['runtime.resource.start']( |
| { sessionId: backendContext.sessionId, launchId: input.turnId }, |
| operationContext, |
| ); |
| assert.equal(started.ok, true); |
| } |
| yield* send(input); |
| }; |
| return backend; |
| }, |
| }, |
| ); |
| try { |
| await composition.recover(); |
| const executionId = '00000000-0000-4000-8000-000000000111'; |
| const execution = composition.handlers['hosted.execution.start']( |
| { |
| executionId, |
| session: { |
| workspace: { kind: 'host_path', path: root }, |
| modelTarget: { kind: 'default' }, |
| name: 'Hosted environment test', |
| }, |
| content: { text: 'leave the environment ready for verification' }, |
| }, |
| operationContext, |
| ); |
| let settled = false; |
| void execution.then(() => { |
| settled = true; |
| }); |
| try { |
| await waitFor(async () => settled, 5_000); |
| } catch { |
| assert.fail(`Hosted execution did not settle: ${JSON.stringify(residencies.snapshot())}`); |
| } |
| const result = await execution; |
| assert.equal(result.ok, true); |
| if (!result.ok) return; |
| if (result.result.kind !== 'settled') assert.fail(result.result.failureReason); |
| |
| const resources = await composition.handlers['runtime.resource.query']( |
| { kind: 'list_start', sessionId: executionId }, |
| operationContext, |
| ); |
| assert.equal(resources.ok, true); |
| if (!resources.ok || resources.result.kind !== 'page') return; |
| assert.equal( |
| resources.result.resources.some((item) => item.result.status === 'running'), |
| true, |
| ); |
| } finally { |
| composition.beginDrain(); |
| await composition.close(); |
| } |
| }); |
| }); |
| |
| test('production composition commits automatic titles through Host-owned Session effects', async () => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| const { composition, manager } = await createCapturedExecutionComposition(owner); |
| try { |
| const session = await manager.createSession({ |
| cwd: root, |
| llmConnectionId: FAKE_CONNECTION_ID, |
| llmConnectionSlug: 'fake', |
| model: 'fake-model', |
| permissionMode: 'ask', |
| }); |
| const started = await composition.handlers['turn.start']( |
| { |
| sessionId: session.id, |
| turnId: 'turn-title', |
| content: { text: 'Host owns this automatic title' }, |
| }, |
| { |
| hostEpoch: 'execution-composition-test', |
| connectionId: 'title-client', |
| principal: 'local_os_user', |
| acquireResidency: () => ({ release() {} }), |
| }, |
| ); |
| assert.equal(started.ok, true); |
| await waitFor(async () => { |
| const summary = (await manager.listSessions()).find((item) => item.id === session.id); |
| return summary?.name === 'Host owns this automatic title'; |
| }); |
| } finally { |
| await composition.close(); |
| } |
| }); |
| }); |
| |
| test('default production WorkHub selects and delegates through its durable Host interaction', async () => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| const connectionId = await configureFakeDefaultTarget(owner); |
| const { composition, manager } = await createCapturedExecutionComposition(owner, { |
| defaultWorkHubRouting: true, |
| }); |
| const context: ConnectionContext = { |
| hostEpoch: 'execution-composition-test', |
| connectionId: 'selection-client', |
| principal: 'local_os_user', |
| acquireResidency: () => ({ release() {} }), |
| }; |
| const desktop = composition.clientCapabilities!.attachConnection( |
| clientCapabilityConnectionIdentity(context.connectionId), |
| { send: async () => {} }, |
| ); |
| try { |
| const registered = await composition.handlers['client.capability.replace']( |
| { |
| registrationId: randomUUID(), |
| offers: [ |
| { |
| offerId: 'desktop-workhub', |
| version: '0', |
| affinity: 'session', |
| hostPathAccess: 'none', |
| label: 'Desktop WorkHub', |
| tools: ['control', 'tasks'].map((name) => ({ |
| serverId: 'desktop_workhub', |
| name, |
| inputSchema: { type: 'object', additionalProperties: false }, |
| })), |
| }, |
| ], |
| }, |
| context, |
| ); |
| assert.ok(registered.ok, JSON.stringify(registered)); |
| await composition.handlers['workhub.coordination.resolve']({}, context); |
| const alpha = await manager.createSession({ |
| cwd: root, |
| name: 'Release', |
| llmConnectionId: connectionId, |
| llmConnectionSlug: 'fake', |
| model: 'fake-model', |
| permissionMode: 'bypass', |
| }); |
| const beta = await manager.createSession({ |
| cwd: root, |
| name: 'Release', |
| llmConnectionId: connectionId, |
| llmConnectionSlug: 'fake', |
| model: 'fake-model', |
| permissionMode: 'bypass', |
| }); |
| const page = await composition.handlers['workhub.coordination.candidates']({}, context); |
| assert.ok(page.ok); |
| if (!page.ok) return; |
| const turnId = randomUUID(); |
| const started = await composition.handlers['workhub.coordination.answer']( |
| { turnId, text: 'Continue Release; let me choose which work.' }, |
| context, |
| ); |
| assert.ok(started.ok, JSON.stringify(started)); |
| const input = { |
| turnId, |
| actionId: 'selected-release', |
| candidateSetId: page.result.candidateSetId, |
| candidateRefs: page.result.candidates.map((candidate) => candidate.candidateRef), |
| delegationText: 'Report release readiness', |
| }; |
| let selectionOutcome: unknown; |
| const pending = composition.handlers['workhub.coordination.selectAndDelegate']( |
| input, |
| context, |
| ).then((result) => { |
| selectionOutcome = result; |
| return result; |
| }); |
| const stores = await openInteractiveExecutionStoresForWrite(owner.lease); |
| await waitFor(async () => { |
| assert.equal(selectionOutcome, undefined, JSON.stringify(selectionOutcome)); |
| return ( |
| ( |
| await stores.interactionStore.listPending({ |
| sessionId: WORKHUB_COORDINATION_SESSION_ID, |
| }) |
| ).length === 1 |
| ); |
| }); |
| const record = ( |
| await stores.interactionStore.listPending({ sessionId: WORKHUB_COORDINATION_SESSION_ID }) |
| )[0]!; |
| const query = () => |
| composition.handlers['interaction.query']( |
| { sessionId: WORKHUB_COORDINATION_SESSION_ID, interactionId: record.requestId }, |
| context, |
| ); |
| const offered = await query(); |
| assert.ok(offered.ok); |
| if (!offered.ok) return; |
| const interaction = offered.result; |
| assert.equal(interaction.request.kind, 'form'); |
| assert.equal(await stores.sessionStore.readWorkHubAssignment(input.actionId), undefined); |
| assert.equal(interaction.request.kind, 'form'); |
| if ( |
| interaction.request.kind !== 'form' || |
| interaction.request.fields[0]?.kind !== 'single_select' |
| ) |
| return; |
| const selected = interaction.request.fields[0].options.find( |
| (option) => JSON.parse(option.value)[1] === beta.id, |
| )!; |
| // Other candidates can change while the user chooses; identity remains the selected Session. |
| await manager.createSession({ |
| cwd: root, |
| name: 'Unrelated work', |
| llmConnectionId: connectionId, |
| llmConnectionSlug: 'fake', |
| model: 'fake-model', |
| permissionMode: 'bypass', |
| }); |
| const answered = await composition.handlers['interaction.answer']( |
| { |
| sessionId: WORKHUB_COORDINATION_SESSION_ID, |
| interactionId: interaction.interactionId, |
| answer: { kind: 'form', action: 'accept', values: { target: selected.value } }, |
| }, |
| context, |
| ); |
| assert.ok(answered.ok, JSON.stringify(answered)); |
| const delegated = await pending; |
| assert.ok(delegated.ok, JSON.stringify(delegated)); |
| if (!delegated.ok || delegated.result.kind !== 'delegated') return; |
| assert.equal( |
| 'targetSessionId' in delegated.result.result && delegated.result.result.targetSessionId, |
| beta.id, |
| ); |
| assert.notEqual(beta.id, alpha.id); |
| assert.deepEqual( |
| await composition.handlers['workhub.coordination.selectAndDelegate'](input, context), |
| delegated, |
| ); |
| const assignment = await stores.sessionStore.readWorkHubAssignment(input.actionId); |
| assert.equal(assignment?.targetSessionId, beta.id); |
| const targetTurnId = |
| 'targetTurnId' in delegated.result.result |
| ? delegated.result.result.targetTurnId |
| : undefined; |
| assert.ok(targetTurnId); |
| await waitFor(async () => { |
| const turn = await composition.handlers['turn.query']( |
| { sessionId: beta.id, turnId: targetTurnId! }, |
| context, |
| ); |
| return turn.ok && turn.result.status === 'completed'; |
| }); |
| assert.equal((await query()).ok, true); |
| for (const cancel of [true, false]) { |
| const fresh = await composition.handlers['workhub.coordination.candidates']({}, context); |
| assert.ok(fresh.ok); |
| if (!fresh.ok) return; |
| const nextInput = { |
| ...input, |
| actionId: cancel ? 'cancelled-release' : 'stale-release', |
| candidateSetId: fresh.result.candidateSetId, |
| candidateRefs: fresh.result.candidates.map((candidate) => candidate.candidateRef), |
| }; |
| let nextOutcome: unknown; |
| const next = composition.handlers['workhub.coordination.selectAndDelegate']( |
| nextInput, |
| context, |
| ).then((result) => { |
| nextOutcome = result; |
| return result; |
| }); |
| await waitFor(async () => { |
| assert.equal(nextOutcome, undefined, JSON.stringify(nextOutcome)); |
| return ( |
| ( |
| await stores.interactionStore.listPending({ |
| sessionId: WORKHUB_COORDINATION_SESSION_ID, |
| }) |
| ).length === 1 |
| ); |
| }); |
| const offer = ( |
| await stores.interactionStore.listPending({ sessionId: WORKHUB_COORDINATION_SESSION_ID }) |
| )[0]!; |
| assert.equal(offer.request.kind, 'form'); |
| if (offer.request.kind !== 'form' || offer.request.fields[0]?.kind !== 'single_select') |
| return; |
| const option = offer.request.fields[0].options.find( |
| (item) => JSON.parse(item.value)[1] === alpha.id, |
| )!; |
| if (!cancel) { |
| const snapshot = await stores.sessionStore.readCatalogRecord(alpha.id); |
| await stores.sessionStore.setSessionsArchivedVersioned( |
| [{ sessionId: alpha.id, expectedVersion: snapshot.revision }], |
| true, |
| ); |
| } |
| const answer = await composition.handlers['interaction.answer']( |
| { |
| sessionId: WORKHUB_COORDINATION_SESSION_ID, |
| interactionId: offer.requestId, |
| answer: cancel |
| ? { kind: 'form', action: 'cancel' } |
| : { kind: 'form', action: 'accept', values: { target: option.value } }, |
| }, |
| context, |
| ); |
| assert.ok(answer.ok, JSON.stringify(answer)); |
| const result = await next; |
| if (cancel) assert.deepEqual(result, { ok: true, result: { kind: 'cancelled' } }); |
| else { |
| assert.equal(result.ok, false); |
| if (!result.ok) assert.equal(result.error.code, 'candidate_set_stale'); |
| } |
| assert.equal( |
| await stores.sessionStore.readWorkHubAssignment(nextInput.actionId), |
| undefined, |
| ); |
| } |
| } finally { |
| await desktop.close(); |
| await composition.close(); |
| } |
| }); |
| }); |
| |
| test('WorkHub creates new work through the production assignment composition', async () => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| const connectionId = await configureFakeDefaultTarget(owner); |
| const { composition, manager } = await createCapturedExecutionComposition(owner); |
| const context = { |
| hostEpoch: 'execution-composition-test', |
| connectionId: 'workhub-create-client', |
| principal: 'local_os_user' as const, |
| acquireResidency: () => ({ release() {} }), |
| }; |
| try { |
| const resolved = await composition.handlers['workhub.coordination.resolve']({}, context); |
| assert.equal(resolved.ok, true); |
| const created = await actWorkHub( |
| composition, |
| { |
| actionId: 'workhub-create-action', |
| userText: 'Fix login stability', |
| proposal: { disposition: 'create_new', title: 'Login stability' }, |
| create: { workspace: { kind: 'host_path', path: root } }, |
| }, |
| context, |
| ); |
| |
| assert.equal(created.ok, true, JSON.stringify(created)); |
| if (!created.ok || created.result.disposition !== 'create_new') return; |
| const targetSessionId = created.result.targetSessionId; |
| const session = (await manager.listSessions()).find(({ id }) => id === targetSessionId); |
| assert.equal(session?.name, 'Login stability'); |
| assert.equal(session?.llmConnectionId, connectionId); |
| |
| const current = await composition.handlers['workhub.coordination.candidates']({}, context); |
| assert.equal(current.ok, true); |
| if (!current.ok) return; |
| assert.equal( |
| current.result.candidates.find(({ sessionId }) => sessionId === targetSessionId) |
| ?.latestDelegationActionId, |
| 'workhub-create-action', |
| ); |
| const stopped = await actWorkHub( |
| composition, |
| { |
| actionId: 'workhub-create-stop-action', |
| userText: 'Stop Login stability', |
| proposal: { |
| operation: 'stop', |
| expects: { targetSessionId }, |
| }, |
| }, |
| context, |
| ); |
| assert.equal(stopped.ok, true, JSON.stringify(stopped)); |
| if (stopped.ok) assert.equal(stopped.result.disposition, 'stop_work'); |
| } finally { |
| await composition.close(); |
| } |
| }); |
| }); |
| |
| test('WorkHub Resume and Stop follow logical lineage across repeated physical handoffs', async () => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| const connectionId = await configureFakeDefaultTarget(owner); |
| let pauseNext = true; |
| let boundary = deferred<void>(); |
| const primaryBackendFactory: BackendFactory = (backendContext) => |
| new (class extends FakeBackend { |
| async prepareRunComposition(input: { runId: string; turnId: string }): Promise<void> { |
| await backendContext.recordRunComposition!(input.runId, HANDOFF_TEST_COMPOSITION); |
| } |
| |
| override async *send(input: BackendSendInput): AsyncIterable<SessionEvent> { |
| assert.ok(input.runId); |
| await this.prepareRunComposition({ runId: input.runId, turnId: input.turnId }); |
| if (backendContext.header.name === 'Payments' && pauseNext) { |
| pauseNext = false; |
| await boundary.promise; |
| assert.equal(await input.handoffBoundary!(new AbortController().signal, null), 'pause'); |
| return; |
| } |
| yield* super.send(input); |
| } |
| })(backendContext); |
| let { composition, manager } = await createCapturedExecutionComposition(owner, { |
| safeBoundaryResume: true, |
| primaryBackendFactory, |
| }); |
| const context = { |
| hostEpoch: 'execution-composition-test', |
| connectionId: 'workhub-resume-stop-client', |
| principal: 'local_os_user' as const, |
| acquireResidency: () => ({ release() {} }), |
| }; |
| let closed = false; |
| let restartedOwner: InteractiveRootOwner | undefined; |
| let continuation: { turnId: string; runId: string } | undefined; |
| let targetSessionId: string | undefined; |
| const handoffAndReopen = async () => { |
| const requested = deferred<void>(); |
| const request = manager.requestRunHandoff.bind(manager); |
| manager.requestRunHandoff = (...args) => { |
| const result = request(...args); |
| requested.resolve(); |
| return result; |
| }; |
| const preparing = composition.prepareHandoff!( |
| context.hostEpoch, |
| new AbortController().signal, |
| ); |
| await requested.promise; |
| boundary.resolve(); |
| const preparation = await preparing; |
| assert.ok(preparation); |
| assert.equal(await preparation.seal(), true); |
| assert.ok(await preparation.residencies()); |
| await preparation.detach(); |
| composition.beginDrain(); |
| await composition.close(); |
| closed = true; |
| await owner.close(); |
| restartedOwner = await tryAcquireInteractiveRootOwner( |
| await resolveStorageRoot({ path: root, kind: 'interactive' }), |
| ); |
| assert.ok(restartedOwner); |
| owner = restartedOwner; |
| ({ composition, manager } = await createCapturedExecutionComposition(owner, { |
| safeBoundaryResume: true, |
| primaryBackendFactory, |
| })); |
| closed = false; |
| }; |
| try { |
| const target = await manager.createSession({ |
| cwd: root, |
| llmConnectionId: connectionId, |
| llmConnectionSlug: 'fake', |
| model: 'fake-model', |
| permissionMode: 'ask', |
| name: 'Payments', |
| }); |
| targetSessionId = target.id; |
| await composition.handlers['workhub.coordination.resolve']({}, context); |
| const candidates = await composition.handlers['workhub.coordination.candidates']({}, context); |
| assert.equal(candidates.ok, true); |
| if (!candidates.ok) return; |
| const candidate = candidates.result.candidates.find( |
| ({ sessionId }) => sessionId === target.id, |
| ); |
| assert.ok(candidate); |
| if (!candidate) return; |
| |
| const delegated = await actWorkHub( |
| composition, |
| { |
| actionId: 'workhub-resume-stop-delegation', |
| userText: FAKE_HOLD_OPEN_PROMPT, |
| candidateSetId: candidates.result.candidateSetId, |
| proposal: { |
| disposition: 'delegate_existing', |
| candidateRef: candidate.candidateRef, |
| }, |
| }, |
| context, |
| ); |
| assert.equal(delegated.ok, true, JSON.stringify(delegated)); |
| if (!delegated.ok || delegated.result.disposition !== 'delegate_existing') return; |
| const original = await composition.handlers['turn.query']( |
| { sessionId: target.id, turnId: delegated.result.targetTurnId }, |
| context, |
| ); |
| assert.equal(original.ok, true); |
| if (!original.ok) return; |
| await handoffAndReopen(); |
| await composition.handlers['turn.stop']( |
| { sessionId: target.id, turnId: original.result.turnId, runId: original.result.runId }, |
| context, |
| ); |
| |
| pauseNext = true; |
| boundary = deferred<void>(); |
| const resumed = await actWorkHub( |
| composition, |
| { |
| actionId: 'workhub-resume-stop-resume', |
| userText: 'Resume Payments', |
| proposal: { |
| operation: 'resume', |
| resumesActionId: 'workhub-resume-stop-delegation', |
| expects: { targetSessionId: target.id }, |
| }, |
| }, |
| context, |
| ); |
| assert.equal(resumed.ok, true, JSON.stringify(resumed)); |
| if ( |
| !resumed.ok || |
| resumed.result.disposition !== 'resume_work' || |
| !resumed.result.targetTurnId |
| ) |
| return; |
| const resumedTurn = await composition.handlers['turn.query']( |
| { sessionId: target.id, turnId: resumed.result.targetTurnId }, |
| context, |
| ); |
| assert.equal(resumedTurn.ok, true); |
| if (!resumedTurn.ok) return; |
| continuation = { turnId: resumedTurn.result.turnId, runId: resumedTurn.result.runId }; |
| assert.equal(resumedTurn.result.status, 'running'); |
| await handoffAndReopen(); |
| |
| // Lose the response, interrupt the continuation, then discard all |
| // in-memory Gate replay state by reopening the production composition. |
| await composition.handlers['turn.stop']({ sessionId: target.id, ...continuation }, context); |
| await composition.close(); |
| closed = true; |
| await owner.close(); |
| restartedOwner = await tryAcquireInteractiveRootOwner( |
| await resolveStorageRoot({ path: root, kind: 'interactive' }), |
| ); |
| assert.ok(restartedOwner); |
| owner = restartedOwner; |
| ({ composition, manager } = await createCapturedExecutionComposition(owner, { |
| safeBoundaryResume: true, |
| // Keep the resumed target alive until Stop; a normal fake response can |
| // finish between the running-state query and the stop admission. |
| primaryBackendFactory: (backendContext) => |
| new (class extends FakeBackend { |
| override async *send(input: BackendSendInput): AsyncIterable<SessionEvent> { |
| yield* super.send({ ...input, text: FAKE_HOLD_OPEN_PROMPT }); |
| } |
| })(backendContext), |
| })); |
| closed = false; |
| await manager.renameSession(target.id, 'Renamed Payments'); |
| const retry = { |
| actionId: 'workhub-resume-stop-resume', |
| userText: 'Resume Payments', |
| proposal: { |
| operation: 'resume' as const, |
| resumesActionId: 'workhub-resume-stop-delegation', |
| expects: { targetSessionId: target.id }, |
| }, |
| }; |
| const replayed = await actWorkHub(composition, retry, context); |
| assert.deepEqual(replayed, resumed); |
| const fresh = await actWorkHub( |
| composition, |
| { ...retry, actionId: 'workhub-resume-again' }, |
| context, |
| ); |
| assert.equal(fresh.ok, true, JSON.stringify(fresh)); |
| if (!fresh.ok || fresh.result.disposition !== 'resume_work' || !fresh.result.targetTurnId) |
| return; |
| const freshTurn = await composition.handlers['turn.query']( |
| { sessionId: target.id, turnId: fresh.result.targetTurnId }, |
| context, |
| ); |
| assert.equal(freshTurn.ok, true); |
| if (!freshTurn.ok) return; |
| assert.equal(freshTurn.result.status, 'running'); |
| assert.notEqual(freshTurn.result.turnId, continuation.turnId); |
| continuation = { turnId: freshTurn.result.turnId, runId: freshTurn.result.runId }; |
| |
| const stores = await openInteractiveExecutionStoresForWrite(owner.lease); |
| const assignment = await stores.sessionStore.readWorkHubAssignment( |
| 'workhub-resume-stop-delegation', |
| ); |
| assert.ok(assignment); |
| // The existing Desktop card query must resolve the resumed execution, |
| // rather than keep projecting the original interrupted Turn. |
| const feedback = await composition.handlers['turn.message.execution.query']( |
| { |
| sessionId: target.id, |
| messageIds: [assignment.targetMessageId], |
| }, |
| context, |
| ); |
| assert.deepEqual(feedback, { |
| ok: true, |
| result: { |
| resolutions: [ |
| { |
| messageId: assignment.targetMessageId, |
| state: 'owned', |
| ...continuation, |
| }, |
| ], |
| }, |
| }); |
| |
| const stopped = await actWorkHub( |
| composition, |
| { |
| actionId: 'workhub-resume-stop-stop', |
| userText: 'Stop Payments', |
| proposal: { |
| operation: 'stop', |
| expects: { targetSessionId: target.id }, |
| }, |
| }, |
| context, |
| ); |
| assert.deepEqual(stopped, { |
| ok: true, |
| result: { |
| disposition: 'stop_work', |
| outcome: 'stop_delivered', |
| targetSessionId: target.id, |
| targetTurnId: continuation.turnId, |
| }, |
| }); |
| const terminal = await composition.handlers['turn.query']( |
| { sessionId: target.id, turnId: continuation.turnId }, |
| context, |
| ); |
| assert.equal(terminal.ok, true); |
| if (terminal.ok) assert.equal(terminal.result.status, 'cancelled'); |
| } finally { |
| if (!closed && continuation && targetSessionId) { |
| await composition.handlers['turn.stop']( |
| { sessionId: targetSessionId, ...continuation }, |
| context, |
| ); |
| } |
| if (!closed) await composition.close(); |
| await restartedOwner?.close(); |
| } |
| }); |
| }); |
| |
| test('WorkHub does not record resume while safe-boundary resume is disabled', async () => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| const connectionId = await configureFakeDefaultTarget(owner); |
| const { composition, manager } = await createCapturedExecutionComposition(owner, { |
| safeBoundaryResume: false, |
| }); |
| const context = { |
| hostEpoch: 'execution-composition-test', |
| connectionId: 'workhub-disabled-resume-client', |
| principal: 'local_os_user' as const, |
| acquireResidency: () => ({ release() {} }), |
| }; |
| try { |
| const target = await manager.createSession({ |
| cwd: root, |
| llmConnectionId: connectionId, |
| llmConnectionSlug: 'fake', |
| model: 'fake-model', |
| permissionMode: 'ask', |
| name: 'Payments', |
| }); |
| await composition.handlers['workhub.coordination.resolve']({}, context); |
| const candidates = await composition.handlers['workhub.coordination.candidates']({}, context); |
| assert.equal(candidates.ok, true); |
| if (!candidates.ok) return; |
| const candidate = candidates.result.candidates.find( |
| ({ sessionId }) => sessionId === target.id, |
| ); |
| assert.ok(candidate); |
| if (!candidate) return; |
| const delegated = await actWorkHub( |
| composition, |
| { |
| actionId: 'workhub-disabled-resume-delegation', |
| userText: FAKE_HOLD_OPEN_PROMPT, |
| candidateSetId: candidates.result.candidateSetId, |
| proposal: { |
| disposition: 'delegate_existing', |
| candidateRef: candidate.candidateRef, |
| }, |
| }, |
| context, |
| ); |
| assert.equal(delegated.ok, true, JSON.stringify(delegated)); |
| if (!delegated.ok || delegated.result.disposition !== 'delegate_existing') return; |
| const original = await composition.handlers['turn.query']( |
| { sessionId: target.id, turnId: delegated.result.targetTurnId }, |
| context, |
| ); |
| assert.equal(original.ok, true); |
| if (!original.ok) return; |
| await composition.handlers['turn.stop']( |
| { sessionId: target.id, turnId: original.result.turnId, runId: original.result.runId }, |
| context, |
| ); |
| |
| const actionId = 'workhub-disabled-resume'; |
| const resumed = await actWorkHub( |
| composition, |
| { |
| actionId, |
| userText: 'Resume Payments', |
| proposal: { |
| operation: 'resume', |
| resumesActionId: 'workhub-disabled-resume-delegation', |
| expects: { targetSessionId: target.id }, |
| }, |
| }, |
| context, |
| ); |
| assert.deepEqual(resumed, { |
| ok: false, |
| error: { |
| code: 'operation_unavailable', |
| message: 'Safe-boundary resume is disabled for this Runtime Host', |
| }, |
| }); |
| await composition.close(); |
| const stores = await openInteractiveExecutionStoresForWrite(owner.lease); |
| assert.equal(await stores.sessionStore.readWorkHubActionClaim(actionId), undefined); |
| } finally { |
| await composition.close(); |
| } |
| }); |
| }); |
| |
| test('WorkHub correction replaces its link without stopping a shared manual Turn', async () => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| const connectionId = await configureFakeDefaultTarget(owner); |
| const { composition, manager } = await createCapturedExecutionComposition(owner); |
| const context = { |
| hostEpoch: 'execution-composition-test', |
| connectionId: 'workhub-shared-turn-client', |
| principal: 'local_os_user' as const, |
| acquireResidency: () => ({ release() {} }), |
| }; |
| let activeRunId: string | undefined; |
| let sourceId: string | undefined; |
| try { |
| const source = await manager.createSession({ |
| cwd: root, |
| llmConnectionId: connectionId, |
| llmConnectionSlug: 'fake', |
| model: 'fake-model', |
| permissionMode: 'ask', |
| }); |
| sourceId = source.id; |
| const destination = await manager.createSession({ |
| cwd: root, |
| llmConnectionId: connectionId, |
| llmConnectionSlug: 'fake', |
| model: 'fake-model', |
| permissionMode: 'ask', |
| }); |
| const started = await composition.handlers['turn.start']( |
| { |
| sessionId: source.id, |
| turnId: 'manual-active-turn', |
| content: { text: FAKE_HOLD_OPEN_PROMPT }, |
| }, |
| context, |
| ); |
| assert.equal(started.ok, true); |
| if (!started.ok || started.result.kind !== 'started') return; |
| activeRunId = started.result.turn.runId; |
| |
| const resolved = await composition.handlers['workhub.coordination.resolve']({}, context); |
| assert.equal(resolved.ok, true); |
| const candidates = await composition.handlers['workhub.coordination.candidates']({}, context); |
| assert.equal(candidates.ok, true); |
| if (!candidates.ok) return; |
| const sourceCandidate = candidates.result.candidates.find( |
| (candidate) => candidate.sessionId === source.id, |
| ); |
| const destinationCandidate = candidates.result.candidates.find( |
| (candidate) => candidate.sessionId === destination.id, |
| ); |
| assert.ok(sourceCandidate); |
| assert.ok(destinationCandidate); |
| if (!sourceCandidate || !destinationCandidate) return; |
| |
| const delegated = await actWorkHub( |
| composition, |
| { |
| actionId: 'workhub-steering-action', |
| userText: 'Continue this manual work from WorkHub', |
| candidateSetId: candidates.result.candidateSetId, |
| proposal: { |
| disposition: 'delegate_existing', |
| candidateRef: sourceCandidate.candidateRef, |
| }, |
| }, |
| context, |
| ); |
| assert.equal(delegated.ok, true); |
| if (!delegated.ok) return; |
| assert.equal(delegated.result.disposition, 'delegate_existing'); |
| if (delegated.result.disposition !== 'delegate_existing') return; |
| assert.equal(delegated.result.steered, true); |
| |
| const stores = await openInteractiveExecutionStoresForWrite(owner.lease); |
| const assignment = await stores.sessionStore.readWorkHubAssignment('workhub-steering-action'); |
| assert.ok(assignment); |
| if (!assignment) return; |
| await waitFor(async () => { |
| const proof = await composition.handlers['turn.message.execution.query']( |
| { sessionId: source.id, messageIds: [assignment.targetMessageId] }, |
| context, |
| ); |
| return proof.ok && proof.result.resolutions[0]?.state === 'owned'; |
| }); |
| assert.deepEqual( |
| await stores.sessionStore.readActiveWorkHubAssignmentsByTarget([source.id]), |
| [assignment], |
| ); |
| |
| const stopped = await actWorkHub( |
| composition, |
| { |
| actionId: 'workhub-stop-shared-action', |
| userText: `Stop ${sourceCandidate.sessionName}`, |
| proposal: { |
| operation: 'stop', |
| expects: { targetSessionId: source.id }, |
| }, |
| }, |
| context, |
| ); |
| assert.deepEqual(stopped, { |
| ok: true, |
| result: { |
| disposition: 'stop_work', |
| outcome: 'not_owned', |
| targetSessionId: source.id, |
| targetTurnId: 'manual-active-turn', |
| }, |
| }); |
| assert.equal( |
| (await stores.sessionStore.readWorkHubStopResolution(assignment.delegationId))?.outcome, |
| 'not_owned', |
| ); |
| |
| const unrelated = await composition.handlers['turn.message.submit']( |
| { |
| originHostEpoch: context.hostEpoch, |
| sessionId: source.id, |
| messageId: 'unrelated-followup-message', |
| content: { text: 'Keep this unrelated follow-up queued' }, |
| placement: 'next_turn', |
| }, |
| context, |
| ); |
| assert.equal(unrelated.ok, true); |
| if (!unrelated.ok) return; |
| assert.equal(unrelated.result.disposition, 'followup'); |
| |
| const correctionCandidates = await composition.handlers['workhub.coordination.candidates']( |
| {}, |
| context, |
| ); |
| assert.equal(correctionCandidates.ok, true); |
| if (!correctionCandidates.ok) return; |
| const correctionDestination = correctionCandidates.result.candidates.find( |
| (candidate) => candidate.sessionId === destination.id, |
| ); |
| assert.ok(correctionDestination); |
| if (!correctionDestination) return; |
| |
| const correctionInput = { |
| actionId: 'workhub-correction-action', |
| userText: `No, move this to ${correctionDestination.sessionName} instead`, |
| candidateSetId: correctionCandidates.result.candidateSetId, |
| proposal: { |
| operation: 'correct', |
| replacesActionId: assignment.actionId, |
| target: { |
| disposition: 'delegate_existing', |
| candidateRef: correctionDestination.candidateRef, |
| }, |
| }, |
| } as const; |
| const stale = await actWorkHub( |
| composition, |
| { ...correctionInput, candidateSetId: `sha256:${'0'.repeat(64)}` }, |
| context, |
| ); |
| assert.equal(stale.ok, false); |
| if (!stale.ok) assert.equal(stale.error.code, 'candidate_set_stale'); |
| const correction = await actWorkHub(composition, correctionInput, context); |
| assert.equal(correction.ok, true, JSON.stringify(correction)); |
| if (!correction.ok) return; |
| assert.equal(correction.result.disposition, 'replace'); |
| if (correction.result.disposition === 'replace') { |
| assert.equal(correction.result.targetSessionId, destination.id); |
| } |
| |
| const supersession = await stores.sessionStore.readWorkHubSupersession( |
| assignment.delegationId, |
| ); |
| assert.equal(supersession?.replacementDelegationId.startsWith('whd_'), true); |
| |
| const active = await composition.handlers['turn.query']( |
| { sessionId: source.id, turnId: 'manual-active-turn' }, |
| context, |
| ); |
| assert.equal(active.ok, true); |
| if (active.ok) { |
| assert.equal(active.result.status, 'running'); |
| assert.equal(active.result.runId, activeRunId); |
| } |
| const queued = await composition.handlers['turn.message.execution.query']( |
| { sessionId: source.id, messageIds: ['unrelated-followup-message'] }, |
| context, |
| ); |
| assert.equal(queued.ok, true); |
| if (queued.ok) assert.equal(queued.result.resolutions[0]?.state, 'pending'); |
| } finally { |
| if (sourceId && activeRunId) { |
| await composition.handlers['turn.stop']( |
| { sessionId: sourceId, turnId: 'manual-active-turn', runId: activeRunId }, |
| context, |
| ); |
| } |
| await composition.close(); |
| } |
| }); |
| }); |
| |
| test('a legacy fake-backend session is refused with the product reason, not a registry error', async () => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| // Written by an older build: no creation path here can produce `fake`, so |
| // the row is seeded under the writer — which is the only way it was ever |
| // produced — and then read back by a Host that starts up against it, since |
| // activation dispatches straight off the durable header. |
| const legacyId = await seedLegacyFakeBackendSession(root, owner); |
| const { composition } = await createCapturedExecutionComposition(owner); |
| try { |
| const failure = await composition.handlers['turn.start']( |
| { |
| sessionId: legacyId, |
| turnId: 'turn-legacy-fake', |
| content: { text: 'resume a retired local simulation' }, |
| }, |
| { |
| hostEpoch: 'execution-composition-test', |
| connectionId: 'legacy-fake-client', |
| principal: 'local_os_user', |
| acquireResidency: () => ({ release() {} }), |
| }, |
| ).then( |
| (result) => result, |
| (error: unknown) => error, |
| ); |
| const message = failure instanceof Error ? failure.message : JSON.stringify(failure); |
| assert.doesNotMatch(message, /No backend factory registered/); |
| assert.equal(parseNoRealConnectionError(message).reason, 'fake_backend'); |
| } finally { |
| await composition.close(); |
| } |
| }); |
| }); |
| |
| test('production composition orphans ownerless ShellRuns before serving Resource queries', async () => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| const stores = await openInteractiveExecutionStoresForWrite(owner.lease); |
| const session = await stores.sessionStore.create({ |
| cwd: root, |
| llmConnectionId: FAKE_CONNECTION_ID, |
| llmConnectionSlug: 'fake', |
| model: 'fake-model', |
| permissionMode: 'ask', |
| }); |
| const shellRuns = await openInteractiveShellRunStoreForWrite(owner.lease); |
| await shellRuns.createShellRun(shellRunRecord(session.id, 'starting-shell', 'starting')); |
| await shellRuns.createShellRun(shellRunRecord(session.id, 'running-shell', 'running')); |
| |
| const composition = await createExecutionRuntimeHostComposition(compositionContext(owner)); |
| try { |
| await composition.recover(); |
| const outcome = await composition.handlers['runtime.resource.query']( |
| { kind: 'list_start', sessionId: session.id }, |
| { |
| hostEpoch: 'execution-composition-test', |
| connectionId: 'recovery-client', |
| principal: 'local_os_user', |
| acquireResidency: () => ({ release() {} }), |
| }, |
| ); |
| assert.equal(outcome.ok, true); |
| if (!outcome.ok || outcome.result.kind !== 'page') return; |
| assert.equal(outcome.result.resources.length, 2); |
| assert.deepEqual( |
| outcome.result.resources.map((resource) => resource.result.status), |
| ['orphaned', 'orphaned'], |
| ); |
| assert.equal( |
| outcome.result.resources.every( |
| (resource) => |
| resource.result.failureMessage === |
| 'Runtime restarted without a live shell process handle', |
| ), |
| true, |
| ); |
| } finally { |
| await composition.close(); |
| } |
| }); |
| }); |
| |
| test('production Skill catalog resolves a Graph child durable tool surface', async () => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| const stores = await openInteractiveExecutionStoresForWrite(owner.lease); |
| const parent = await stores.sessionStore.create({ |
| cwd: root, |
| llmConnectionId: FAKE_CONNECTION_ID, |
| llmConnectionSlug: 'fake', |
| model: 'fake-model', |
| permissionMode: 'ask', |
| }); |
| const child = await createClaimedGraphChild({ |
| root, |
| parentSessionId: parent.id, |
| suffix: 'c', |
| stores, |
| prompt: 'inspect the child Skill catalog', |
| }); |
| const composition = await createExecutionRuntimeHostComposition(compositionContext(owner)); |
| try { |
| await composition.recover(); |
| const outcome = await composition.handlers['skill.catalog.invocable.query']( |
| { |
| kind: 'start', |
| target: { kind: 'session', sessionId: child.request.targetSessionId }, |
| }, |
| { |
| hostEpoch: 'execution-composition-test', |
| connectionId: 'graph-child-skill-client', |
| principal: 'local_os_user', |
| acquireResidency: () => ({ release() {} }), |
| }, |
| ); |
| assert.equal(outcome.ok, true); |
| if (outcome.ok) assert.equal(outcome.result.kind, 'page'); |
| } finally { |
| await composition.close(); |
| } |
| }); |
| }); |
| |
| test('production Skill catalog reports an archived Session without resolving its live tool surface', async () => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| const stores = await openInteractiveExecutionStoresForWrite(owner.lease); |
| const session = await stores.sessionStore.create({ |
| cwd: root, |
| llmConnectionId: FAKE_CONNECTION_ID, |
| llmConnectionSlug: 'fake', |
| model: 'fake-model', |
| permissionMode: 'ask', |
| }); |
| const snapshot = await stores.sessionStore.readHeaderRecordSnapshot(session.id); |
| await stores.sessionStore.setSessionsArchivedVersioned( |
| [{ sessionId: session.id, expectedVersion: snapshot.revision }], |
| true, |
| ); |
| |
| const composition = await createExecutionRuntimeHostComposition(compositionContext(owner)); |
| try { |
| await composition.recover(); |
| const outcome = await composition.handlers['skill.catalog.invocable.query']( |
| { |
| kind: 'start', |
| target: { kind: 'session', sessionId: session.id }, |
| }, |
| { |
| hostEpoch: 'execution-composition-test', |
| connectionId: 'archived-session-skill-client', |
| principal: 'local_os_user', |
| acquireResidency: () => ({ release() {} }), |
| }, |
| ); |
| assert.deepEqual(outcome, { |
| ok: false, |
| error: { code: 'session_archived', message: 'Session is archived' }, |
| }); |
| } finally { |
| await composition.close(); |
| } |
| }); |
| }); |
| |
| test('production Skill catalog reports a removed Session as not found', async () => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| const stores = await openInteractiveExecutionStoresForWrite(owner.lease); |
| const session = await stores.sessionStore.create({ |
| cwd: root, |
| llmConnectionId: FAKE_CONNECTION_ID, |
| llmConnectionSlug: 'fake', |
| model: 'fake-model', |
| permissionMode: 'ask', |
| }); |
| const snapshot = await stores.sessionStore.readHeaderRecordSnapshot(session.id); |
| await stores.sessionStore.removeSessionsVersioned([ |
| { sessionId: session.id, expectedVersion: snapshot.revision }, |
| ]); |
| |
| const composition = await createExecutionRuntimeHostComposition(compositionContext(owner)); |
| try { |
| await composition.recover(); |
| const outcome = await composition.handlers['skill.catalog.invocable.query']( |
| { |
| kind: 'start', |
| target: { kind: 'session', sessionId: session.id }, |
| }, |
| { |
| hostEpoch: 'execution-composition-test', |
| connectionId: 'removed-session-skill-client', |
| principal: 'local_os_user', |
| acquireResidency: () => ({ release() {} }), |
| }, |
| ); |
| assert.deepEqual(outcome, { |
| ok: false, |
| error: { code: 'not_found', message: 'Session does not exist' }, |
| }); |
| } finally { |
| await composition.close(); |
| } |
| }); |
| }); |
| |
| test('production Skill catalog preserves an archive race during live tool resolution', async () => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| const stores = await openInteractiveExecutionStoresForWrite(owner.lease); |
| const session = await stores.sessionStore.create({ |
| cwd: root, |
| llmConnectionId: FAKE_CONNECTION_ID, |
| llmConnectionSlug: 'fake', |
| model: 'fake-model', |
| permissionMode: 'ask', |
| }); |
| const composition = await createExecutionRuntimeHostComposition(compositionContext(owner)); |
| const originalToolsForSession = AgentGraphCoordinator.prototype.toolsForSession; |
| let archiveInjected = false; |
| try { |
| await composition.recover(); |
| AgentGraphCoordinator.prototype.toolsForSession = async function (sessionId) { |
| if (sessionId === session.id && !archiveInjected) { |
| archiveInjected = true; |
| const snapshot = await stores.sessionStore.readHeaderRecordSnapshot(session.id); |
| await stores.sessionStore.setSessionsArchivedVersioned( |
| [{ sessionId: session.id, expectedVersion: snapshot.revision }], |
| true, |
| ); |
| } |
| return originalToolsForSession.call(this, sessionId); |
| }; |
| |
| const outcome = await composition.handlers['skill.catalog.invocable.query']( |
| { |
| kind: 'start', |
| target: { kind: 'session', sessionId: session.id }, |
| }, |
| { |
| hostEpoch: 'execution-composition-test', |
| connectionId: 'archive-race-skill-client', |
| principal: 'local_os_user', |
| acquireResidency: () => ({ release() {} }), |
| }, |
| ); |
| assert.equal(archiveInjected, true); |
| assert.deepEqual(outcome, { |
| ok: false, |
| error: { code: 'session_archived', message: 'Session is archived' }, |
| }); |
| } finally { |
| AgentGraphCoordinator.prototype.toolsForSession = originalToolsForSession; |
| await composition.close(); |
| } |
| }); |
| }); |
| |
| test('production Skill catalog preserves a removal race during live tool resolution', async () => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| const stores = await openInteractiveExecutionStoresForWrite(owner.lease); |
| const session = await stores.sessionStore.create({ |
| cwd: root, |
| llmConnectionId: FAKE_CONNECTION_ID, |
| llmConnectionSlug: 'fake', |
| model: 'fake-model', |
| permissionMode: 'ask', |
| }); |
| const composition = await createExecutionRuntimeHostComposition(compositionContext(owner)); |
| const originalToolsForSession = AgentGraphCoordinator.prototype.toolsForSession; |
| let removalInjected = false; |
| try { |
| await composition.recover(); |
| AgentGraphCoordinator.prototype.toolsForSession = async function (sessionId) { |
| if (sessionId === session.id && !removalInjected) { |
| removalInjected = true; |
| const snapshot = await stores.sessionStore.readHeaderRecordSnapshot(session.id); |
| await stores.sessionStore.removeSessionsVersioned([ |
| { sessionId: session.id, expectedVersion: snapshot.revision }, |
| ]); |
| } |
| return originalToolsForSession.call(this, sessionId); |
| }; |
| |
| const outcome = await composition.handlers['skill.catalog.invocable.query']( |
| { |
| kind: 'start', |
| target: { kind: 'session', sessionId: session.id }, |
| }, |
| { |
| hostEpoch: 'execution-composition-test', |
| connectionId: 'removal-race-skill-client', |
| principal: 'local_os_user', |
| acquireResidency: () => ({ release() {} }), |
| }, |
| ); |
| assert.equal(removalInjected, true); |
| assert.deepEqual(outcome, { |
| ok: false, |
| error: { code: 'not_found', message: 'Session does not exist' }, |
| }); |
| } finally { |
| AgentGraphCoordinator.prototype.toolsForSession = originalToolsForSession; |
| await composition.close(); |
| } |
| }); |
| }); |
| |
| test('new Full Access Plan Skill previews use the mutating tool surface', async () => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| const skillDirectory = join(root, '.agents', 'skills', 'write-preview'); |
| await mkdir(skillDirectory, { recursive: true }); |
| await writeFile( |
| join(skillDirectory, 'SKILL.md'), |
| [ |
| '---', |
| 'name: Write Preview', |
| 'description: Requires the Write tool.', |
| 'required-tools: [Write]', |
| '---', |
| '# Write Preview', |
| '', |
| ].join('\n'), |
| ); |
| |
| const composition = await createExecutionRuntimeHostComposition(compositionContext(owner)); |
| try { |
| await composition.recover(); |
| const connection = { |
| hostEpoch: 'execution-composition-test', |
| connectionId: 'new-session-skill-client', |
| principal: 'local_os_user' as const, |
| acquireResidency: () => ({ release() {} }), |
| }; |
| const query = (permissionMode: 'ask' | 'bypass') => |
| composition.handlers['skill.catalog.invocable.query']( |
| { |
| kind: 'start', |
| target: { |
| kind: 'new_session', |
| context: { workspace: { kind: 'host_path', path: root } }, |
| collaborationMode: 'plan', |
| permissionMode, |
| }, |
| }, |
| connection, |
| ); |
| |
| const managed = await query('ask'); |
| assert.equal(managed.ok, true); |
| if (!managed.ok || managed.result.kind !== 'page') return; |
| assert.equal( |
| managed.result.items.some((item) => item.id === 'write-preview'), |
| false, |
| ); |
| |
| const fullAccess = await query('bypass'); |
| assert.equal(fullAccess.ok, true); |
| if (!fullAccess.ok || fullAccess.result.kind !== 'page') return; |
| assert.equal( |
| fullAccess.result.items.some((item) => item.id === 'write-preview'), |
| true, |
| ); |
| } finally { |
| await composition.close(); |
| } |
| }); |
| }); |
| |
| test('Skill capability previews keep a bound Session off a same-slug replacement', async () => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| for (const [id, requiredTool] of [ |
| ['web-search-preview', 'WebSearch'], |
| ['web-research-preview', 'web_research'], |
| ] as const) { |
| const skillDirectory = join(root, '.agents', 'skills', id); |
| await mkdir(skillDirectory, { recursive: true }); |
| await writeFile( |
| join(skillDirectory, 'SKILL.md'), |
| [ |
| '---', |
| `name: ${id}`, |
| `description: Requires ${requiredTool}.`, |
| `required-tools: [${requiredTool}]`, |
| '---', |
| `# ${id}`, |
| '', |
| ].join('\n'), |
| ); |
| } |
| |
| const policy = await openInteractiveRuntimePolicyStoresForWrite(owner.lease); |
| const created = await policy.connectionCatalog.create({ |
| expectedCatalogRevision: 0, |
| connection: { |
| slug: 'skill-preview-model', |
| name: 'Skill preview model', |
| providerType: 'ollama', |
| enabled: true, |
| enabledModelIds: ['fake-model'], |
| }, |
| }); |
| assert.equal(created.kind, 'committed'); |
| if (created.kind !== 'committed') return; |
| const connection = created.snapshot.connections[0]; |
| assert.ok(connection); |
| if (!connection) return; |
| const fetch = await policy.operations.beginModelFetch(connection.connectionId); |
| assert.equal(fetch.kind, 'ready'); |
| if (fetch.kind !== 'ready') return; |
| const fetched = await policy.operations.completeModelFetch(fetch.ticket, { |
| models: [{ id: 'fake-model' }], |
| source: 'fetched', |
| fetchedAt: Date.now(), |
| }); |
| assert.equal(fetched.kind, 'committed'); |
| if (fetched.kind !== 'committed') return; |
| const defaultTarget = await policy.connectionCatalog.setDefaultTarget({ |
| expectedCatalogRevision: fetched.snapshot.revision, |
| target: { connectionId: connection.connectionId, modelId: 'fake-model' }, |
| }); |
| assert.equal(defaultTarget.kind, 'committed'); |
| const policySnapshot = await policy.runtimePolicy.getSnapshot(); |
| const webSearchEnabled = await policy.runtimePolicy.mutate({ |
| expectedRevision: policySnapshot.revision, |
| operation: { |
| kind: 'set_web_search', |
| value: { enabled: true, defaultProvider: 'tavily' }, |
| }, |
| }); |
| assert.equal(webSearchEnabled.kind, 'committed'); |
| assert.equal( |
| ( |
| await policy.operations.resolveExecutionConnection({ |
| kind: 'catalog_slug', |
| connectionSlug: connection.slug, |
| }) |
| ).kind, |
| 'ready', |
| ); |
| |
| const stores = await openInteractiveExecutionStoresForWrite(owner.lease); |
| const session = await stores.sessionStore.create({ |
| cwd: root, |
| llmConnectionId: connection.connectionId, |
| llmConnectionSlug: connection.slug, |
| model: 'fake-model', |
| permissionMode: 'bypass', |
| }); |
| const composition = await createExecutionRuntimeHostComposition(compositionContext(owner), { |
| bootstrapRuntimePolicy: false, |
| }); |
| try { |
| await composition.recover(); |
| const connectionContext = { |
| hostEpoch: 'execution-composition-test', |
| connectionId: 'web-search-skill-preview-client', |
| principal: 'local_os_user' as const, |
| acquireResidency: () => ({ release() {} }), |
| }; |
| const query = (target: 'session' | 'new_session') => |
| composition.handlers['skill.catalog.invocable.query']( |
| { |
| kind: 'start', |
| target: |
| target === 'session' |
| ? { kind: 'session', sessionId: session.id } |
| : { |
| kind: 'new_session', |
| context: { workspace: { kind: 'host_path', path: root } }, |
| collaborationMode: 'agent', |
| permissionMode: 'bypass', |
| }, |
| }, |
| connectionContext, |
| ); |
| |
| for (const target of ['session', 'new_session'] as const) { |
| const outcome = await query(target); |
| assert.equal(outcome.ok, true); |
| if (!outcome.ok || outcome.result.kind !== 'page') continue; |
| assert.equal( |
| outcome.result.items.some( |
| (item) => item.id === 'web-search-preview' || item.id === 'web-research-preview', |
| ), |
| false, |
| ); |
| } |
| |
| assert.equal( |
| ( |
| await policy.credentialVault.set({ |
| locator: { scope: 'web_search', provider: 'tavily', kind: 'api_key' }, |
| expected: null, |
| secret: 'replacement-must-not-be-read', |
| }) |
| ).kind, |
| 'committed', |
| ); |
| const beforeRemoval = await policy.connectionCatalog.getSnapshot(); |
| const currentConnection = beforeRemoval.connections.find( |
| (candidate) => candidate.connectionId === connection.connectionId, |
| ); |
| assert.ok(currentConnection); |
| if (!currentConnection) return; |
| assert.equal( |
| ( |
| await policy.connectionCatalog.remove({ |
| expected: { |
| connectionId: currentConnection.connectionId, |
| revision: currentConnection.revision, |
| }, |
| }) |
| ).kind, |
| 'committed', |
| ); |
| const afterRemoval = await policy.connectionCatalog.getSnapshot(); |
| const replacementCreated = await policy.connectionCatalog.create({ |
| expectedCatalogRevision: afterRemoval.revision, |
| connection: { |
| slug: connection.slug, |
| name: 'Same-slug replacement', |
| providerType: 'ollama', |
| enabled: true, |
| enabledModelIds: ['fake-model'], |
| }, |
| }); |
| assert.equal(replacementCreated.kind, 'committed'); |
| if (replacementCreated.kind !== 'committed') return; |
| const replacement = replacementCreated.snapshot.connections[0]; |
| assert.ok(replacement); |
| if (!replacement) return; |
| const replacementFetch = await policy.operations.beginModelFetch(replacement.connectionId); |
| assert.equal(replacementFetch.kind, 'ready'); |
| if (replacementFetch.kind !== 'ready') return; |
| const replacementFetched = await policy.operations.completeModelFetch( |
| replacementFetch.ticket, |
| { |
| models: [{ id: 'fake-model' }], |
| source: 'fetched', |
| fetchedAt: Date.now(), |
| }, |
| ); |
| assert.equal(replacementFetched.kind, 'committed'); |
| if (replacementFetched.kind !== 'committed') return; |
| assert.equal( |
| ( |
| await policy.connectionCatalog.setDefaultTarget({ |
| expectedCatalogRevision: replacementFetched.snapshot.revision, |
| target: { connectionId: replacement.connectionId, modelId: 'fake-model' }, |
| }) |
| ).kind, |
| 'committed', |
| ); |
| |
| const boundSession = await query('session'); |
| assert.equal(boundSession.ok, true); |
| if (boundSession.ok && boundSession.result.kind === 'page') { |
| assert.equal( |
| boundSession.result.items.some( |
| (item) => item.id === 'web-search-preview' || item.id === 'web-research-preview', |
| ), |
| false, |
| ); |
| } |
| const replacementPreview = await query('new_session'); |
| assert.equal(replacementPreview.ok, true); |
| if (replacementPreview.ok && replacementPreview.result.kind === 'page') { |
| assert.equal( |
| replacementPreview.result.items.some( |
| (item) => item.id === 'web-search-preview' || item.id === 'web-research-preview', |
| ), |
| true, |
| ); |
| } |
| } finally { |
| await composition.close(); |
| } |
| }); |
| }); |
| |
| test('production composition validates graph stop before aborting a claimed child', async () => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| const stores = await openInteractiveExecutionStoresForWrite(owner.lease); |
| const claims = createAgentGraphControlStore(root); |
| const parent = await stores.sessionStore.create({ |
| cwd: root, |
| llmConnectionId: FAKE_CONNECTION_ID, |
| llmConnectionSlug: 'fake', |
| model: 'fake-model', |
| permissionMode: 'ask', |
| }); |
| const completedPrompt = 'execute the canonical claimed graph activation'; |
| const completed = await createClaimedGraphChild({ |
| root, |
| parentSessionId: parent.id, |
| suffix: 'a', |
| stores, |
| prompt: completedPrompt, |
| }); |
| const completedClaim = (await claims.claimAgentGraphIntent(completed.request)).claim; |
| const abortedFixture = await createClaimedGraphChild({ |
| root, |
| parentSessionId: parent.id, |
| suffix: 'e', |
| stores, |
| prompt: FAKE_ASK_USER_QUESTION_PROMPT, |
| }); |
| const abortedClaim = (await claims.claimAgentGraphIntent(abortedFixture.request)).claim; |
| claims.close(); |
| const { composition, manager } = await createCapturedExecutionComposition(owner); |
| let journeyError: unknown; |
| try { |
| const first = await manager.runClaimedAgentGraphIntent({ |
| claimStore: claims, |
| intent: completed.intent, |
| graphId: completedClaim.graphId, |
| intentId: completedClaim.intentId, |
| prompt: completedPrompt, |
| }); |
| assert.equal(first.status, 'completed'); |
| |
| const admission = await stores.agentRunStore.readRootTurnAdmission( |
| completedClaim.targetSessionId, |
| completedClaim.targetTurnId, |
| ); |
| assert.ok(admission); |
| assert.ok(admission.userMessageId); |
| assert.deepEqual(admission.execution, graphExecutionDescriptor(completedClaim)); |
| assert.deepEqual(admission.normalizedInput, { text: completedPrompt }); |
| |
| const retry = await manager.runClaimedAgentGraphIntent({ |
| claimStore: claims, |
| intent: completed.intent, |
| graphId: completedClaim.graphId, |
| intentId: completedClaim.intentId, |
| prompt: completedPrompt, |
| }); |
| assert.deepEqual( |
| { |
| claimId: retry.claimId, |
| childSessionId: retry.childSessionId, |
| turnId: retry.turnId, |
| runId: retry.runId, |
| status: retry.status, |
| summary: retry.summary, |
| }, |
| { |
| claimId: first.claimId, |
| childSessionId: first.childSessionId, |
| turnId: first.turnId, |
| runId: first.runId, |
| status: first.status, |
| summary: first.summary, |
| }, |
| ); |
| const retriedAdmission = await stores.agentRunStore.readRootTurnAdmission( |
| completedClaim.targetSessionId, |
| completedClaim.targetTurnId, |
| ); |
| assert.equal(retriedAdmission?.userMessageId, admission.userMessageId); |
| await assertUniqueGraphExecutionFacts(stores, completedClaim, admission.userMessageId); |
| |
| const abort = new AbortController(); |
| let ready!: () => void; |
| const started = new Promise<void>((resolve) => { |
| ready = resolve; |
| }); |
| const aborting = manager.runClaimedAgentGraphIntent({ |
| claimStore: claims, |
| intent: abortedFixture.intent, |
| graphId: abortedClaim.graphId, |
| intentId: abortedClaim.intentId, |
| prompt: FAKE_ASK_USER_QUESTION_PROMPT, |
| abortSignal: abort.signal, |
| onReady: ready, |
| }); |
| await started; |
| const clientContext = { |
| hostEpoch: 'execution-composition-test', |
| connectionId: 'graph-stop-client', |
| principal: 'local_os_user' as const, |
| acquireResidency: () => ({ release() {} }), |
| }; |
| const invalidStop = await composition.handlers['agent.graph.stop']( |
| { |
| rootSessionId: abortedClaim.targetSessionId, |
| expectedGraphId: abortedClaim.graphId, |
| }, |
| clientContext, |
| ); |
| assert.equal(invalidStop.ok, false); |
| if (invalidStop.ok) return; |
| assert.equal(invalidStop.error.code, 'operation_conflict'); |
| const stillActive = await composition.handlers['turn.query']( |
| { |
| sessionId: abortedClaim.targetSessionId, |
| turnId: abortedClaim.targetTurnId, |
| }, |
| clientContext, |
| ); |
| assert.equal(stillActive.ok, true); |
| if (!stillActive.ok) return; |
| assert.equal(['completed', 'failed', 'cancelled'].includes(stillActive.result.status), false); |
| abort.abort(); |
| const aborted = await aborting; |
| assert.equal(aborted.status, 'cancelled'); |
| |
| const abortedAdmission = await stores.agentRunStore.readRootTurnAdmission( |
| abortedClaim.targetSessionId, |
| abortedClaim.targetTurnId, |
| ); |
| assert.ok(abortedAdmission?.userMessageId); |
| assert.deepEqual(abortedAdmission?.execution, graphExecutionDescriptor(abortedClaim)); |
| const abortedRun = ( |
| await stores.runtimeEventStore.listSessionInvocations(abortedClaim.targetSessionId) |
| ).find((candidate) => candidate.runId === abortedClaim.targetRunId); |
| assert.ok(abortedRun); |
| assert.equal(abortedRun && runtimeInvocationOutcome(abortedRun), 'cancelled'); |
| await assertUniqueGraphExecutionFacts( |
| stores, |
| abortedClaim, |
| abortedAdmission.userMessageId, |
| 'cancelled', |
| ); |
| const completedRun = ( |
| await stores.runtimeEventStore.listSessionInvocations(completedClaim.targetSessionId) |
| ).find((candidate) => candidate.runId === completedClaim.targetRunId); |
| assert.ok(completedRun); |
| assert.equal(completedRun && runtimeInvocationOutcome(completedRun), 'completed'); |
| } catch (error) { |
| journeyError = error; |
| throw error; |
| } finally { |
| try { |
| await composition.close(); |
| } catch (closeError) { |
| if (journeyError !== undefined) { |
| throw new AggregateError( |
| [journeyError, closeError], |
| 'Claimed graph journey and composition close both failed', |
| ); |
| } |
| throw closeError; |
| } |
| } |
| }); |
| }); |
| |
| test('interaction fail-stop stops graph operators through the kernel and releases ownership', { |
| timeout: 10_000, |
| }, async (t) => { |
| await withCompositionRoot(async ({ root, owner }) => { |
| const failure = new Error('backend continuation apply failed'); |
| let graph!: AgentGraphCoordinator; |
| const recoverGraph = AgentGraphCoordinator.prototype.recover; |
| t.mock.method( |
| AgentGraphCoordinator.prototype, |
| 'recover', |
| async function (this: AgentGraphCoordinator) { |
| graph = this; |
| return recoverGraph.call(this); |
| }, |
| ); |
| const published = deferred<string>(); |
| const stopped = deferred<void>(); |
| const stopObservations: Array<{ error?: unknown }> = []; |
| let settlement: HostedUserQuestionSettlement | undefined; |
| let retained = false; |
| let retainedAtShutdownRequest = false; |
| let captured!: Awaited<ReturnType<typeof createCapturedExecutionComposition>>; |
| const host = await RuntimeHostKernel.start({ |
| owner, |
| idleGraceMs: 60_000, |
| shutdownGraceMs: 5_000, |
| composition: defineInteractiveRuntimeHostComposition(async (kernelContext) => { |
| captured = await createCapturedExecutionComposition(owner, { |
| context: { |
| ...kernelContext, |
| retainUntilProcessExit: () => { |
| retained = true; |
| kernelContext.retainUntilProcessExit(); |
| }, |
| requestDrain: () => { |
| retainedAtShutdownRequest = retained; |
| kernelContext.requestDrain(); |
| }, |
| }, |
| primaryBackendFactory: (backendContext) => { |
| const backend = new FakeBackend(backendContext); |
| const send = backend.send.bind(backend); |
| backend.send = async function* (input) { |
| const bridge = input.hostedInteraction; |
| assert.ok(bridge); |
| yield* send({ |
| ...input, |
| hostedInteraction: { |
| ...bridge, |
| admitUserQuestionRequest: async (request) => { |
| settlement = request.settlement; |
| await bridge.admitUserQuestionRequest({ |
| ...request, |
| settlement: { |
| ...request.settlement, |
| applyAnswer: async () => { |
| throw failure; |
| }, |
| }, |
| }); |
| published.resolve(request.request.requestId); |
| }, |
| }, |
| }); |
| }; |
| return backend; |
| }, |
| }); |
| return captured.composition; |
| }), |
| }); |
| const closed = host.closed.then( |
| () => undefined, |
| (error: unknown) => error, |
| ); |
| const connected = await connectRuntimeHost({ |
| rootPath: root, |
| protocol: { min: RUNTIME_HOST_PROTOCOL_VERSION, max: RUNTIME_HOST_PROTOCOL_VERSION }, |
| }); |
| assert.equal(connected.kind, 'connected'); |
| if (connected.kind !== 'connected') throw new Error('kernel connection unavailable'); |
| const { manager } = captured; |
| const stores = await openInteractiveExecutionStoresForWrite(owner.lease); |
| try { |
| const session = await manager.createSession({ |
| cwd: root, |
| llmConnectionId: FAKE_CONNECTION_ID, |
| llmConnectionSlug: 'fake', |
| model: 'fake-model', |
| permissionMode: 'ask', |
| }); |
| await graph.toolsForSession(session.id); |
| const turnId = 'interaction-drain-turn'; |
| // Prepare the held-open backend with a fixture residency. The answer below exercises |
| // kernel drain over UDS; poisoned root-execution settlement is a separate close path. |
| const started = await captured.composition.handlers['turn.start']( |
| { |
| sessionId: session.id, |
| turnId, |
| content: { text: FAKE_ASK_USER_QUESTION_PROMPT }, |
| }, |
| { |
| hostEpoch: host.hostEpoch, |
| connectionId: 'interaction-drain-fixture', |
| principal: 'local_os_user', |
| acquireResidency: () => ({ release() {} }), |
| }, |
| ); |
| assert.equal(started.ok, true); |
| const interactionId = await published.promise; |
| const run = (await stores.runtimeEventStore.listSessionInvocations(session.id)).find( |
| (run) => run.turnId === turnId, |
| ); |
| assert.ok(run); |
| const operator = await manager.provisionAgentGraphOperator({ |
| graphId: agentGraphIdForRootSession(session.id), |
| workId: `graph_work_${'a'.repeat(32)}`, |
| operatorId: `graph_operator_${'b'.repeat(32)}`, |
| agentId: LOCAL_READ_AGENT_DEFINITION.id, |
| source: { |
| sessionId: session.id, |
| turnId, |
| runId: run.runId, |
| toolCallId: 'provision-for-drain', |
| }, |
| edges: [], |
| expectedScheduleRevision: 0, |
| }); |
| const stopSession = manager.stopSession.bind(manager); |
| t.mock.method( |
| manager, |
| 'stopSession', |
| async (sessionId: string, input: Parameters<SessionManager['stopSession']>[1]) => { |
| if (sessionId !== operator.header.id) return stopSession(sessionId, input); |
| const observation: (typeof stopObservations)[number] = {}; |
| stopObservations.push(observation); |
| try { |
| await stopSession(sessionId, input); |
| } catch (error) { |
| observation.error = error; |
| throw error; |
| } finally { |
| stopped.resolve(); |
| } |
| }, |
| ); |
| await assert.rejects( |
| connected.connection.request('interaction.answer', { |
| sessionId: session.id, |
| interactionId, |
| answer: { kind: 'question', answers: ['邀请制', '本周', '是'] }, |
| }), |
| (error: unknown) => |
| error instanceof RuntimeHostOperationError && error.code === 'internal_failure', |
| ); |
| await stopped.promise; |
| assert.equal(retained, true); |
| assert.equal(retainedAtShutdownRequest, true); |
| assert.deepEqual(stopObservations, [{}]); |
| } finally { |
| // Release the injected backend waiter; fail-stop intentionally cannot apply its continuation. |
| await settlement?.applyClosure('turn_stopped'); |
| await connected.connection.close(); |
| void host.close().catch(() => undefined); |
| const closeError = await closed; |
| assert.ok( |
| closeError instanceof AggregateError, |
| `Unexpected shutdown result: ${String(closeError)}`, |
| ); |
| const errorTree = (error: unknown): string => |
| error instanceof AggregateError |
| ? [error.message, ...error.errors.map(errorTree)].join('\n') |
| : String(error); |
| // Poisoned compositions can aggregate other close errors; operator stop must not reenter admission. |
| const details = errorTree(closeError); |
| assert.match(details, /Interaction coordinator entered fail-stop/); |
| assert.doesNotMatch( |
| details, |
| /Cannot enter Session admission|termination required|shutdown deadline/i, |
| ); |
| const replacementOwner = await tryAcquireInteractiveRootOwner(owner.capability); |
| assert.ok(replacementOwner, 'kernel released exclusive root ownership'); |
| await replacementOwner.close(); |
| } |
| }); |
| }); |
| |
| function compositionContext(owner: InteractiveRootOwner) { |
| return { |
| owner, |
| hostEpoch: 'execution-composition-test', |
| acquireResidency: () => ({ release() {} }), |
| retainUntilProcessExit: () => undefined, |
| requestDrain: () => undefined, |
| }; |
| } |
| |
| async function configureFakeDefaultTarget(owner: InteractiveRootOwner): Promise<string> { |
| const policy = await openInteractiveRuntimePolicyStoresForWrite(owner.lease); |
| const created = await policy.connectionCatalog.create({ |
| expectedCatalogRevision: 0, |
| connection: { |
| slug: 'fake', |
| name: 'Fake', |
| providerType: 'ollama', |
| enabled: true, |
| enabledModelIds: ['fake-model'], |
| }, |
| }); |
| assert.equal(created.kind, 'committed'); |
| if (created.kind !== 'committed') throw new Error('Fake connection was not committed'); |
| const connection = created.snapshot.connections[0]; |
| assert.ok(connection); |
| if (!connection) throw new Error('Fake connection is unavailable'); |
| const fetch = await policy.operations.beginModelFetch(connection.connectionId); |
| assert.equal(fetch.kind, 'ready'); |
| if (fetch.kind !== 'ready') throw new Error('Fake model fetch did not start'); |
| const fetched = await policy.operations.completeModelFetch(fetch.ticket, { |
| models: [{ id: 'fake-model' }], |
| source: 'fetched', |
| fetchedAt: Date.now(), |
| }); |
| assert.equal(fetched.kind, 'committed'); |
| if (fetched.kind !== 'committed') throw new Error('Fake model catalog was not committed'); |
| const selected = await policy.connectionCatalog.setDefaultTarget({ |
| expectedCatalogRevision: fetched.snapshot.revision, |
| target: { connectionId: connection.connectionId, modelId: 'fake-model' }, |
| }); |
| assert.equal(selected.kind, 'committed'); |
| if (selected.kind !== 'committed') throw new Error('Fake default target was not committed'); |
| return connection.connectionId; |
| } |
| |
| function shellRunRecord( |
| sessionId: string, |
| shellRunId: string, |
| status: 'starting' | 'running', |
| ): ShellRunRecord { |
| return { |
| shellRunId, |
| sessionId, |
| sourceTurnId: `turn-${shellRunId}`, |
| sourceToolCallId: `tool-${shellRunId}`, |
| cwd: '/workspace', |
| command: 'sleep 60', |
| status, |
| startedAt: 1, |
| updatedAt: 1, |
| revision: 1, |
| output: { |
| mode: 'pipes', |
| stdout: '', |
| stderr: '', |
| stdoutTruncated: false, |
| stderrTruncated: false, |
| redacted: false, |
| }, |
| }; |
| } |
| |
| /** |
| * Writes one session whose durable header says `backend: 'fake'`. |
| * |
| * Nothing in this build can write that value, so the row goes in underneath the |
| * session writer: create a normal row through the real store, then rewrite the |
| * persisted backend the way an older build left it on disk. The database |
| * filename is `OPERATIONAL_STATE_DATABASE_NAME` in `@maka/storage`, which the |
| * package does not export. |
| */ |
| async function seedLegacyFakeBackendSession( |
| root: string, |
| owner: InteractiveRootOwner, |
| ): Promise<string> { |
| const stores = await openInteractiveExecutionStoresForWrite(owner.lease); |
| const { id: sessionId } = await stores.sessionStore.create({ |
| cwd: root, |
| llmConnectionSlug: 'fake', |
| model: 'fake-model', |
| permissionMode: 'ask', |
| }); |
| |
| const legacy = new DatabaseSync(join(root, 'runtime.sqlite')); |
| try { |
| const row = legacy |
| .prepare(`SELECT payload_json FROM session_metadata WHERE session_id = ?`) |
| .get(sessionId) as { payload_json: string }; |
| const payload = JSON.parse(row.payload_json) as Record<string, unknown>; |
| payload.backend = 'fake'; |
| legacy |
| .prepare(`UPDATE session_metadata SET payload_json = ?, backend = ? WHERE session_id = ?`) |
| .run(JSON.stringify(payload), 'fake', sessionId); |
| } finally { |
| legacy.close(); |
| } |
| return sessionId; |
| } |
| |
| async function createCapturedExecutionComposition( |
| owner: InteractiveRootOwner, |
| options: { |
| readonly context?: Pick< |
| RuntimeHostCompositionContext, |
| 'retainUntilProcessExit' | 'requestDrain' |
| >; |
| readonly safeBoundaryResume?: boolean; |
| readonly defaultWorkHubRouting?: boolean; |
| readonly primaryBackendFactory?: BackendFactory; |
| readonly residencies?: HostResidencyRegistry; |
| } = {}, |
| ): Promise<{ |
| composition: Awaited<ReturnType<typeof createExecutionRuntimeHostComposition>>; |
| manager: SessionManager; |
| }> { |
| const originalRecover = SessionManager.prototype.recoverInterruptedSessionsStrict; |
| const originalSafeBoundaryResume = process.env.MAKA_RUNTIME_SAFE_BOUNDARY_RESUME; |
| const primaryBackendFactory = |
| options.primaryBackendFactory ?? ((context) => new FakeBackend(context)); |
| const residencies = options.residencies; |
| const routingDecisions = new Map<string, WorkHubRoutingDecision>(); |
| let manager: SessionManager | undefined; |
| SessionManager.prototype.recoverInterruptedSessionsStrict = async function (stores) { |
| manager = this; |
| return originalRecover.call(this, stores); |
| }; |
| try { |
| if (options.safeBoundaryResume === true) process.env.MAKA_RUNTIME_SAFE_BOUNDARY_RESUME = '1'; |
| if (options.safeBoundaryResume === false) delete process.env.MAKA_RUNTIME_SAFE_BOUNDARY_RESUME; |
| // The production composition no longer registers a test backend of its |
| // own; the deterministic one arrives through the same `primaryBackendFactory` |
| // seam the Desktop E2E run uses. |
| const composition = await createExecutionRuntimeHostComposition( |
| { |
| ...compositionContext(owner), |
| ...(residencies |
| ? { |
| acquireResidency: (label: string, kind?: HostResidencyKind) => |
| residencies.acquire(label, kind), |
| } |
| : {}), |
| ...options.context, |
| }, |
| {}, |
| { |
| primaryBackendFactory: (context) => |
| context.sessionId === WORKHUB_COORDINATION_SESSION_ID |
| ? new (class extends FakeBackend { |
| override async *send(input: BackendSendInput): AsyncIterable<SessionEvent> { |
| yield* super.send({ ...input, text: FAKE_HOLD_OPEN_PROMPT }); |
| } |
| })(context) |
| : primaryBackendFactory(context), |
| workHubRoutingModel: options.defaultWorkHubRouting |
| ? undefined |
| : { |
| decide: async ({ turnId }) => { |
| const decision = routingDecisions.get(turnId); |
| if (!decision) |
| throw new Error(`Missing fake WorkHub routing decision for ${turnId}`); |
| return decision; |
| }, |
| }, |
| }, |
| ); |
| await composition.recover(); |
| if (!manager) throw new Error('Production execution composition did not construct Runtime'); |
| workHubRoutingDecisions.set(composition, routingDecisions); |
| return { composition, manager }; |
| } finally { |
| if (originalSafeBoundaryResume === undefined) { |
| delete process.env.MAKA_RUNTIME_SAFE_BOUNDARY_RESUME; |
| } else { |
| process.env.MAKA_RUNTIME_SAFE_BOUNDARY_RESUME = originalSafeBoundaryResume; |
| } |
| SessionManager.prototype.recoverInterruptedSessionsStrict = originalRecover; |
| } |
| } |
| |
| async function createClaimedGraphChild(input: { |
| root: string; |
| parentSessionId: string; |
| suffix: string; |
| stores: Awaited<ReturnType<typeof openInteractiveExecutionStoresForWrite>>; |
| prompt: string; |
| }): Promise<{ request: AgentGraphIntentClaimRequest; intent: AgentGraphRunnableIntent }> { |
| const turnId = `graph-turn-${input.suffix}`; |
| const runId = `graph-run-${input.suffix}`; |
| const child = await input.stores.sessionStore.createSubagent({ |
| cwd: input.root, |
| name: `Graph operator ${input.suffix}`, |
| llmConnectionId: FAKE_CONNECTION_ID, |
| llmConnectionSlug: 'fake', |
| model: 'fake-model', |
| permissionMode: 'explore', |
| collaborationMode: 'agent', |
| orchestrationMode: 'default', |
| subagentParent: { |
| kind: 'subagent', |
| parentSessionId: input.parentSessionId, |
| spawnedBy: { |
| parentRunId: `parent-run-${input.suffix}`, |
| parentTurnId: `parent-turn-${input.suffix}`, |
| toolCallId: `graph-tool-${input.suffix}`, |
| }, |
| lifecycle: 'foreground', |
| }, |
| subagentRuntime: { |
| schemaVersion: 1, |
| definitionVersion: LOCAL_READ_AGENT_DEFINITION.definitionVersion, |
| agentId: LOCAL_READ_AGENT_DEFINITION.id, |
| agentName: LOCAL_READ_AGENT_DEFINITION.name, |
| profile: LOCAL_READ_AGENT_DEFINITION.profile, |
| systemPrompt: LOCAL_READ_AGENT_DEFINITION.systemPrompt, |
| toolNames: [...LOCAL_READ_AGENT_DEFINITION.tools], |
| categoryPolicy: {}, |
| }, |
| subagentSpawn: { |
| schemaVersion: 1, |
| requestFingerprint: input.suffix.repeat(64), |
| initialTurnId: turnId, |
| initialRunId: runId, |
| }, |
| }); |
| assert.equal(child.created, true); |
| const intent: AgentGraphRunnableIntent = { |
| schemaVersion: 1, |
| intentId: `graph_intent_${input.suffix.repeat(32)}`, |
| graphId: `graph-${input.suffix}`, |
| readinessContextFingerprint: `sha256:${nextHex(input.suffix).repeat(64)}`, |
| policyFingerprint: `sha256:${nextHex(nextHex(input.suffix)).repeat(64)}`, |
| readinessId: `readiness-${input.suffix}`, |
| operatorId: LOCAL_READ_AGENT_DEFINITION.id, |
| targetSessionId: child.header.id, |
| policyKind: 'map', |
| triggerRouteIds: [`route-${input.suffix}`], |
| triggerRecordIds: [`record-${input.suffix}`], |
| }; |
| return { |
| intent, |
| request: { |
| schemaVersion: 1, |
| claimId: `graph_claim_${input.suffix.repeat(32)}`, |
| graphId: intent.graphId, |
| intentId: intent.intentId, |
| intentFingerprint: fingerprintAgentGraphRunnableIntent({ |
| intent, |
| executionInput: { prompt: input.prompt }, |
| }), |
| readinessContextFingerprint: intent.readinessContextFingerprint, |
| targetOperatorId: LOCAL_READ_AGENT_DEFINITION.id, |
| targetSessionId: child.header.id, |
| targetTurnId: turnId, |
| targetRunId: runId, |
| }, |
| }; |
| } |
| |
| function graphExecutionDescriptor(claim: AgentGraphIntentClaim) { |
| return { |
| kind: 'claimed_agent_graph_intent' as const, |
| claim, |
| agentId: LOCAL_READ_AGENT_DEFINITION.id, |
| agentName: LOCAL_READ_AGENT_DEFINITION.name, |
| }; |
| } |
| |
| function lifecycleUsageRecord() { |
| return { |
| id: 'usage_after_composition_drain', |
| providerId: 'openai', |
| modelId: 'gpt-5', |
| inputTokens: 10, |
| outputTokens: 20, |
| cacheHitInputTokens: 0, |
| cacheMissInputTokens: 10, |
| cachedInputTokens: 0, |
| cacheWriteInputTokens: 0, |
| reasoningTokens: 0, |
| totalTokens: 30, |
| costUsd: 0.001, |
| latencyMs: 100, |
| status: 'success', |
| date: '2026-07-30', |
| ts: Date.UTC(2026, 6, 30), |
| startedAt: Date.UTC(2026, 6, 30) - 100, |
| } as Parameters< |
| Awaited<ReturnType<typeof openInteractiveUsageStoresForWrite>>['telemetry']['recordLlmCall'] |
| >[0]; |
| } |
| |
| async function assertUniqueGraphExecutionFacts( |
| stores: Awaited<ReturnType<typeof openInteractiveExecutionStoresForWrite>>, |
| claim: AgentGraphIntentClaim, |
| userMessageId: string, |
| expectedOutcome: 'completed' | 'cancelled' = 'completed', |
| ): Promise<void> { |
| const [runs, messages, runtimeEvents] = await Promise.all([ |
| stores.runtimeEventStore.listSessionInvocations(claim.targetSessionId), |
| readLedgerMessages(stores.runtimeEventStore, claim.targetSessionId), |
| stores.runtimeEventStore.readImmutableRuntimeEvents(claim.targetSessionId, claim.targetRunId), |
| ]); |
| assert.deepEqual( |
| runs.filter((run) => run.turnId === claim.targetTurnId).map((run) => run.runId), |
| [claim.targetRunId], |
| ); |
| assert.deepEqual( |
| messages |
| .filter((message) => message.type === 'user' && message.turnId === claim.targetTurnId) |
| .map((message) => message.id), |
| [userMessageId], |
| ); |
| assert.equal( |
| runtimeEvents.filter((event) => event.content?.kind === 'invocation_opened').length, |
| 1, |
| ); |
| assert.equal( |
| runtimeEvents.filter( |
| (event) => event.status === (expectedOutcome === 'cancelled' ? 'aborted' : 'completed'), |
| ).length, |
| 1, |
| ); |
| } |
| |
| function nextHex(value: string): string { |
| const code = Number.parseInt(value, 16); |
| return ((code + 1) % 16).toString(16); |
| } |
| |
| async function withCompositionRoot( |
| run: (fixture: { |
| root: string; |
| owner: NonNullable<Awaited<ReturnType<typeof tryAcquireInteractiveRootOwner>>>; |
| }) => Promise<void>, |
| ): Promise<void> { |
| const base = await mkdtemp(join(tmpdir(), 'maka-execution-composition-')); |
| const root = join(base, 'interactive'); |
| const capability = await resolveStorageRoot({ path: root, kind: 'interactive' }); |
| const owner = await tryAcquireInteractiveRootOwner(capability); |
| assert.ok(owner); |
| if (!owner) throw new Error('Unable to acquire composition test root'); |
| try { |
| await run({ root, owner }); |
| } finally { |
| await owner.close(); |
| await rm(base, { recursive: true, force: true }); |
| } |
| } |
| |
| async function waitFor(predicate: () => Promise<boolean>, timeoutMs = 2_000): Promise<void> { |
| await pollFor(predicate, { timeoutMs, pollMs: 10, message: 'Timed out waiting for condition' }); |
| } |
| |
| /** Runs each task action under a real, admitted coordination Turn. */ |
| async function actWorkHub( |
| composition: Awaited<ReturnType<typeof createExecutionRuntimeHostComposition>>, |
| input: WorkHubAdmittedAction, |
| context: ConnectionContext, |
| ) { |
| const desktop = composition.clientCapabilities!.attachConnection( |
| clientCapabilityConnectionIdentity(context.connectionId), |
| { send: async () => {} }, |
| ); |
| try { |
| const registered = await composition.handlers['client.capability.replace']( |
| { |
| registrationId: randomUUID(), |
| offers: [ |
| { |
| offerId: 'desktop-workhub', |
| version: '0', |
| affinity: 'session', |
| hostPathAccess: 'none', |
| label: 'Desktop WorkHub', |
| tools: ['control', 'tasks'].map((name) => ({ |
| serverId: 'desktop_workhub', |
| name, |
| inputSchema: { type: 'object', additionalProperties: false }, |
| })), |
| }, |
| ], |
| }, |
| context, |
| ); |
| assert.ok(registered.ok, JSON.stringify(registered)); |
| const { userText, attachments, ...action } = input; |
| const turnId = randomUUID(); |
| const decisions = workHubRoutingDecisions.get(composition); |
| assert.ok(decisions, 'Production composition is missing its fake WorkHub routing model'); |
| decisions.set(turnId, routingDecisionForAction(action)); |
| const started = await composition.handlers['workhub.coordination.answer']( |
| { turnId, text: userText, ...(attachments ? { attachments } : {}) }, |
| context, |
| ); |
| assert.ok(started.ok, JSON.stringify(started)); |
| try { |
| return await composition.handlers['workhub.coordination.actFromTurn']( |
| { ...action, turnId }, |
| context, |
| ); |
| } finally { |
| const run = await composition.handlers['turn.query']( |
| { sessionId: WORKHUB_COORDINATION_SESSION_ID, turnId }, |
| context, |
| ); |
| assert.ok(run.ok, JSON.stringify(run)); |
| await composition.handlers['turn.stop']( |
| { sessionId: WORKHUB_COORDINATION_SESSION_ID, turnId, runId: run.result.runId }, |
| context, |
| ); |
| } |
| } finally { |
| await desktop.close(); |
| } |
| } |
| |
| function routingDecisionForAction( |
| action: Omit<WorkHubAdmittedAction, 'userText' | 'attachments'>, |
| ): WorkHubRoutingDecision { |
| if ('operation' in action.proposal) { |
| return { kind: 'linked', operation: action.proposal.operation }; |
| } |
| if (action.proposal.disposition === 'create_new') { |
| return { kind: 'routing', disposition: 'create_new' }; |
| } |
| assert.ok(action.candidateSetId, 'Delegation requires a candidate set'); |
| return { |
| kind: 'routing', |
| disposition: 'delegate_existing', |
| candidateSetId: action.candidateSetId, |
| candidateRef: action.proposal.candidateRef, |
| }; |
| } |