mirror of
https://github.com/stablyai/orca.git
synced 2026-11-15 18:37:24 +00:00
test: remove simulated mobile and worker observation pipelines
This commit is contained in:
@@ -480,7 +480,6 @@
|
||||
1 test-no-wall-clock:src/main/runtime/rpc/methods/agent-launch/agent-launch-replay.test.ts
|
||||
1 test-no-wall-clock:src/main/runtime/rpc/methods/orchestration/federation/federation-output.test.ts
|
||||
2 test-no-wall-clock:src/main/runtime/rpc/methods/orchestration/worker/observation/fleet-status-observed-identity.test.ts
|
||||
1 test-no-wall-clock:src/main/runtime/rpc/methods/orchestration/worker/observation/worker-interactive-wait.test.ts
|
||||
1 test-no-wall-clock:src/main/runtime/rpc/methods/orchestration/worker/output/worker-output.test.ts
|
||||
2 test-no-wall-clock:src/main/runtime/rpc/server/remote-runtime-request-connection.integration.test.ts
|
||||
2 test-no-wall-clock:src/main/runtime/rpc/server/runtime-rpc-pairing-mode-persistence.test.ts
|
||||
|
||||
@@ -2979,7 +2979,6 @@
|
||||
"src/main/runtime/push/notifications/mobile-notification-replay.test.ts": 43,
|
||||
"src/main/runtime/rpc/server/pairing/mobile-pairing-userdata-path.test.ts": 171,
|
||||
"src/main/runtime/terminal/layout/mobile-presence-lock.test.ts": 25928,
|
||||
"src/main/runtime/terminal/lifecycle/mobile-session-dead-pty.test.ts": 4708,
|
||||
"src/main/runtime/session-tabs/headless-editor-tabs.test.ts": 57,
|
||||
"src/main/runtime/session-lifecycle/publication/mobile-session-tabs-agent-status-heartbeat.test.ts": 65,
|
||||
"src/main/runtime/terminal/surface/mobile-session-terminal-persistence-retirement.test.ts": 278,
|
||||
@@ -3270,7 +3269,6 @@
|
||||
"src/main/runtime/rpc/methods/orchestration/worker/release/worker-auto-release-turns.test.ts": 3578,
|
||||
"src/main/runtime/rpc/methods/orchestration/worker/release/worker-auto-release.test.ts": 4863,
|
||||
"src/main/runtime/rpc/methods/orchestration/worker/follow-up/worker-follow-up.test.ts": 4916,
|
||||
"src/main/runtime/rpc/methods/orchestration/worker/observation/worker-interactive-wait.test.ts": 5579,
|
||||
"src/main/runtime/rpc/methods/orchestration/worker/fleet/worker-list-pagination.test.ts": 4740,
|
||||
"src/main/runtime/rpc/methods/orchestration/worker/output/worker-output.test.ts": 541,
|
||||
"src/main/runtime/rpc/methods/orchestration/worker/release/worker-release-authority-contracts.test.ts": 3949,
|
||||
|
||||
-134
@@ -1,134 +0,0 @@
|
||||
// Drive real detector/plumbing through RPC to distinguish workers waiting on human prompts (STA-3714, STA-4513).
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { join } from 'node:path'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { OrcaRuntimeService } from '../../../../../orca-runtime'
|
||||
import { OrchestrationDb } from '../../../../../orchestration/db/orchestration-db'
|
||||
import '../../../../../orchestration/db/contract-constants'
|
||||
import '../../../../../orchestration/db/messages/mailbox-routing-page'
|
||||
import '../../../../../orchestration/db/dispatch-row-writer'
|
||||
import '../../../../../orchestration/db/attempt-outcome-projection'
|
||||
import { ORCHESTRATION_METHODS } from '../../orchestration'
|
||||
import { createRootDispatch } from '../../../../../orchestration/db/root-dispatch-test-fixture'
|
||||
|
||||
vi.mock('electron', () => ({
|
||||
BrowserWindow: { fromId: vi.fn(() => null) },
|
||||
webContents: { fromId: vi.fn(() => null) },
|
||||
ipcMain: { on: vi.fn(), removeListener: vi.fn() },
|
||||
app: { getPath: vi.fn(() => '/tmp') }
|
||||
}))
|
||||
|
||||
const LEAF_ID = '22222222-2222-4222-8222-222222222222'
|
||||
const TAB_ID = 'tab-worker'
|
||||
const WORKTREE_ID = 'wt-worker'
|
||||
const PTY_ID = 'pty-worker'
|
||||
|
||||
// Captured verbatim from cursor-agent 2026.08.11-e8db854 driven through Orca.
|
||||
function fixture(name: string): string {
|
||||
return readFileSync(join(__dirname, '../../../../../__fixtures__', `${name}.txt`), 'utf8')
|
||||
}
|
||||
|
||||
function workerShowMethod() {
|
||||
const method = ORCHESTRATION_METHODS.find(
|
||||
(candidate) => candidate.name === 'orchestration.workerShow'
|
||||
)
|
||||
if (!method) {
|
||||
throw new Error('Missing method orchestration.workerShow')
|
||||
}
|
||||
return method
|
||||
}
|
||||
|
||||
describe('worker-show interactive wait (STA-3714, STA-4513)', () => {
|
||||
let db: OrchestrationDb | undefined
|
||||
|
||||
afterEach(() => db?.close())
|
||||
|
||||
async function showWorkerPaneServing(paneOutput: string, opts?: { breakIdentity?: boolean }) {
|
||||
const runtime = new OrcaRuntimeService(null)
|
||||
const internals = runtime as unknown as {
|
||||
resolveTerminalWorkspaceLaunchScope: (selector: string) => Promise<unknown>
|
||||
}
|
||||
vi.spyOn(internals, 'resolveTerminalWorkspaceLaunchScope').mockResolvedValue({
|
||||
id: WORKTREE_ID,
|
||||
path: '/repo/app',
|
||||
connectionId: null,
|
||||
repo: null,
|
||||
folderWorkspace: null
|
||||
})
|
||||
runtime.setPtyController({
|
||||
spawn: vi.fn().mockResolvedValue({ id: PTY_ID, incarnationId: 'inc-1' }),
|
||||
write: () => true,
|
||||
kill: () => true,
|
||||
getForegroundProcess: async () => 'cursor-agent'
|
||||
})
|
||||
const terminal = await runtime.createTerminal(`id:${WORKTREE_ID}`, {
|
||||
tabId: TAB_ID,
|
||||
leafId: LEAF_ID,
|
||||
title: 'worker'
|
||||
})
|
||||
runtime.attachWindow(1)
|
||||
runtime.syncWindowGraph(1, {
|
||||
tabs: [
|
||||
{
|
||||
tabId: TAB_ID,
|
||||
worktreeId: WORKTREE_ID,
|
||||
title: 'worker',
|
||||
activeLeafId: LEAF_ID,
|
||||
layout: null
|
||||
}
|
||||
],
|
||||
leaves: [
|
||||
{
|
||||
tabId: TAB_ID,
|
||||
worktreeId: WORKTREE_ID,
|
||||
leafId: LEAF_ID,
|
||||
paneRuntimeId: 1,
|
||||
ptyId: PTY_ID,
|
||||
// cursor-agent's spinner title, identical whether it runs or waits.
|
||||
paneTitle: '⠇ Cursor Agent'
|
||||
}
|
||||
]
|
||||
})
|
||||
runtime.onPtyData(PTY_ID, paneOutput, Date.now())
|
||||
|
||||
db = new OrchestrationDb(':memory:')
|
||||
runtime.setOrchestrationDb(db)
|
||||
const run = db.createRun({
|
||||
objective: 'supervise lanes',
|
||||
coordinatorHandle: 'term_coord',
|
||||
coordinatorPaneKey: 'tab_coord:leaf_coord'
|
||||
})
|
||||
const task = db.createTask({ spec: 'run the suite', runId: run.id })
|
||||
const paneKey = runtime.getTerminalPaneKey(terminal.handle)
|
||||
const incarnation = runtime.getTerminalProcessIncarnation(terminal.handle)
|
||||
if (!paneKey || !incarnation) {
|
||||
throw new Error('Runtime did not expose the worker pane identity.')
|
||||
}
|
||||
const dispatch = createRootDispatch(
|
||||
db,
|
||||
task.id,
|
||||
terminal.handle,
|
||||
paneKey,
|
||||
'launch-hash', // A dispatch recorded against a process that has since been replaced.
|
||||
opts?.breakIdentity === true ? `${incarnation}:replaced` : incarnation
|
||||
)
|
||||
|
||||
const method = workerShowMethod()
|
||||
return method.handler(method.params?.parse({ dispatch: dispatch.id }), { runtime })
|
||||
}
|
||||
|
||||
it('names the pending prompt on the observation a coordinator polls', async () => {
|
||||
const result = await showWorkerPaneServing(fixture('cursor-agent-approval-prompt'))
|
||||
|
||||
expect(result).toMatchObject({
|
||||
observation: {
|
||||
exactWorker: true,
|
||||
agentWait: {
|
||||
source: 'prompt-text',
|
||||
reason: 'agent-approval-prompt',
|
||||
since: expect.any(Number)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,232 +0,0 @@
|
||||
import { expect, it, vi } from 'vitest'
|
||||
import { rmSync } from 'node:fs'
|
||||
import { DaemonPtyAdapter } from '../../../daemon/providers/adapter/daemon-pty-adapter'
|
||||
import { DaemonPtyRouter } from '../../../daemon/providers/routing/daemon-pty-router'
|
||||
import { DegradedDaemonPtyProvider } from '../../../daemon/providers/routing/degraded-daemon-pty-provider'
|
||||
import { LocalPtyProvider } from '../../../providers/local-pty/local-pty-provider'
|
||||
import {
|
||||
createMockSubprocess,
|
||||
startDaemonAdapterHarness,
|
||||
waitFor
|
||||
} from '../../../daemon/providers/adapter/testing/daemon-pty-adapter-test-harness'
|
||||
import type { IPtyProvider } from '../../../providers/pty/provider-contract'
|
||||
import { PtyWriteUnavailableError } from '../../../providers/pty/write-unavailable-error'
|
||||
|
||||
await import('../../orca-runtime-tests/runtime-test-module-registration.spec')
|
||||
await import('../../orca-runtime-tests/orca-runtime-test-lifecycle.spec')
|
||||
await import('../../orca-runtime-tests/runtime-test-module-registration.spec')
|
||||
const { OrcaRuntimeService } = await import('../../orca-runtime')
|
||||
const {
|
||||
HEADLESS_LEAF_ID,
|
||||
TEST_WORKTREE_ID,
|
||||
TEST_WORKTREE_PATH,
|
||||
makeRuntimeStoreWithWorkspaceSession,
|
||||
makeWorkspaceSessionWithHeadlessTerminal
|
||||
} = await import('../../orca-runtime-tests/orca-runtime-test-fixtures.spec')
|
||||
|
||||
const providerSession = { key: 'session_id' as const, id: 'codex-conversation' }
|
||||
|
||||
function mobileChat(provider: IPtyProvider) {
|
||||
const { runtimeStore } = makeRuntimeStoreWithWorkspaceSession(
|
||||
makeWorkspaceSessionWithHeadlessTerminal()
|
||||
)
|
||||
const runtime = new OrcaRuntimeService(runtimeStore)
|
||||
const spawn = vi.fn()
|
||||
const write = vi.fn(() => true)
|
||||
runtime.setPtyController({
|
||||
spawn,
|
||||
write,
|
||||
kill: () => true,
|
||||
getForegroundProcess: async () => null,
|
||||
hasPty: (id) => provider.hasPty?.(id) ?? null,
|
||||
getPtyAvailability: (id) => provider.getPtyAvailability?.(id) ?? null,
|
||||
listProcesses: () => provider.listProcesses()
|
||||
})
|
||||
runtime.attachWindow(1)
|
||||
let snapshotVersion = 0
|
||||
const publish = (ptyId: string) =>
|
||||
runtime.syncWindowGraph(1, {
|
||||
tabs: [
|
||||
{
|
||||
tabId: 'host-tab',
|
||||
worktreeId: TEST_WORKTREE_ID,
|
||||
title: 'Codex',
|
||||
activeLeafId: HEADLESS_LEAF_ID,
|
||||
layout: null
|
||||
}
|
||||
],
|
||||
leaves: [
|
||||
{
|
||||
tabId: 'host-tab',
|
||||
worktreeId: TEST_WORKTREE_ID,
|
||||
leafId: HEADLESS_LEAF_ID,
|
||||
paneRuntimeId: 1,
|
||||
ptyId,
|
||||
paneTitle: 'Codex'
|
||||
}
|
||||
],
|
||||
mobileSessionTabs: [
|
||||
{
|
||||
worktree: TEST_WORKTREE_ID,
|
||||
publicationEpoch: 'renderer',
|
||||
snapshotVersion: ++snapshotVersion,
|
||||
activeGroupId: null,
|
||||
activeTabId: 'host-tab',
|
||||
activeTabType: 'terminal',
|
||||
tabs: [
|
||||
{
|
||||
type: 'terminal',
|
||||
id: `host-tab::${HEADLESS_LEAF_ID}`,
|
||||
parentTabId: 'host-tab',
|
||||
leafId: HEADLESS_LEAF_ID,
|
||||
ptyId,
|
||||
title: 'Codex',
|
||||
isActive: true,
|
||||
agentStatus: {
|
||||
agentType: 'codex',
|
||||
state: 'waiting',
|
||||
prompt: '',
|
||||
updatedAt: 1,
|
||||
stateStartedAt: 1,
|
||||
stateHistory: [],
|
||||
paneKey: `host-tab:${HEADLESS_LEAF_ID}`,
|
||||
providerSession
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
})
|
||||
const read = () => runtime.listMobileSessionTabs(`id:${TEST_WORKTREE_ID}`)
|
||||
const published = () => runtime['getMobileSessionTabsForWorktree'](TEST_WORKTREE_ID)
|
||||
return { runtime, publish, read, published, spawn, write }
|
||||
}
|
||||
|
||||
it.each(['direct', 'router', 'degraded'] as const)(
|
||||
'keeps an unattached retained conversation ready, then withholds a gone PTY through %s',
|
||||
async (route) => {
|
||||
const subprocesses: ReturnType<typeof createMockSubprocess>[] = []
|
||||
const harness = await startDaemonAdapterHarness(() => {
|
||||
const subprocess = createMockSubprocess()
|
||||
subprocesses.push(subprocess)
|
||||
return subprocess
|
||||
})
|
||||
const owner = new DaemonPtyAdapter(harness)
|
||||
try {
|
||||
await harness.adapter.spawn({
|
||||
sessionId: 'persisted-pty',
|
||||
cwd: TEST_WORKTREE_PATH,
|
||||
cols: 80,
|
||||
rows: 24
|
||||
})
|
||||
harness.adapter.dispose()
|
||||
const provider =
|
||||
route === 'direct'
|
||||
? owner
|
||||
: route === 'router'
|
||||
? new DaemonPtyRouter({ current: owner, legacy: [] })
|
||||
: new DegradedDaemonPtyProvider({
|
||||
current: owner,
|
||||
legacy: [],
|
||||
fallback: new LocalPtyProvider()
|
||||
})
|
||||
const chat = mobileChat(provider)
|
||||
chat.publish('persisted-pty')
|
||||
const before = await chat.read()
|
||||
expect(owner.hasPty('persisted-pty')).toBe(false)
|
||||
expect(before.tabs[0]).toMatchObject({ status: 'ready', terminal: expect.any(String) })
|
||||
const original = before.tabs[0]
|
||||
if (original?.type !== 'terminal') {
|
||||
throw new Error('Expected the retained terminal')
|
||||
}
|
||||
|
||||
await owner.attach('persisted-pty')
|
||||
expect((await chat.read()).tabs[0]).toHaveProperty('terminal', original.terminal)
|
||||
expect(subprocesses).toHaveLength(1)
|
||||
subprocesses[0]?._simulateExit(0)
|
||||
await waitFor(() => !owner.hasPty('persisted-pty'))
|
||||
expect((await chat.read()).tabs[0]).toMatchObject({
|
||||
status: 'pending-handle',
|
||||
terminal: null
|
||||
})
|
||||
chat.publish('persisted-pty')
|
||||
expect(chat.published().tabs[0]).toMatchObject({ status: 'pending-handle', terminal: null })
|
||||
|
||||
await owner.spawn({
|
||||
sessionId: 'replacement-pty',
|
||||
cwd: TEST_WORKTREE_PATH,
|
||||
cols: 80,
|
||||
rows: 24
|
||||
})
|
||||
chat.publish('replacement-pty')
|
||||
const restored = (await chat.read()).tabs[0]
|
||||
expect(restored).toMatchObject({
|
||||
id: original.id,
|
||||
status: 'ready',
|
||||
terminal: expect.any(String),
|
||||
agentStatus: expect.objectContaining({ providerSession })
|
||||
})
|
||||
expect(restored).not.toHaveProperty('terminal', original.terminal)
|
||||
expect(chat.spawn).not.toHaveBeenCalled()
|
||||
expect(chat.write).not.toHaveBeenCalled()
|
||||
expect(subprocesses.every((subprocess) => subprocess.write.mock.calls.length === 0)).toBe(
|
||||
true
|
||||
)
|
||||
} finally {
|
||||
owner.dispose()
|
||||
harness.adapter.dispose()
|
||||
await harness.server.shutdown()
|
||||
rmSync(harness.dir, { recursive: true, force: true })
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
it('withholds an attached PTY during endpoint recovery and restores its same conversation without replay', async () => {
|
||||
const subprocess = createMockSubprocess()
|
||||
const harness = await startDaemonAdapterHarness(() => subprocess)
|
||||
const respawn = vi.fn(async () => {})
|
||||
const owner = new DaemonPtyAdapter({ ...harness, respawn })
|
||||
try {
|
||||
await owner.spawn({ sessionId: 'persisted-pty', cwd: TEST_WORKTREE_PATH, cols: 80, rows: 24 })
|
||||
const chat = mobileChat(owner)
|
||||
chat.publish('persisted-pty')
|
||||
const original = (await chat.read()).tabs[0]
|
||||
if (original?.type !== 'terminal') {
|
||||
throw new Error('Expected the attached terminal')
|
||||
}
|
||||
expect(original.status).toBe('ready')
|
||||
const unavailable = new Promise<void>((resolve) => owner.onWriteUnavailable(() => resolve()))
|
||||
owner['client'].disconnect()
|
||||
expect(() => owner.write('persisted-pty', 'refused')).toThrow(PtyWriteUnavailableError)
|
||||
await unavailable
|
||||
expect(owner.hasPty('persisted-pty')).toBe(true)
|
||||
expect(chat.published().tabs[0]).toMatchObject({ status: 'pending-handle', terminal: null })
|
||||
|
||||
// Successful inventory reconnects transport but does not clear the remount fence.
|
||||
expect((await chat.read()).tabs[0]).toMatchObject({ status: 'pending-handle', terminal: null })
|
||||
await owner.attach('persisted-pty')
|
||||
expect((await chat.read()).tabs[0]).toMatchObject({
|
||||
id: original.id,
|
||||
status: 'ready',
|
||||
terminal: original.terminal,
|
||||
agentStatus: expect.objectContaining({ providerSession })
|
||||
})
|
||||
expect(subprocess.write).not.toHaveBeenCalled()
|
||||
expect(chat.spawn).not.toHaveBeenCalled()
|
||||
expect(chat.write).not.toHaveBeenCalled()
|
||||
expect(respawn).not.toHaveBeenCalled()
|
||||
|
||||
respawn.mockRejectedValue(new Error('daemon remains unavailable'))
|
||||
await harness.server.shutdown()
|
||||
await waitFor(() => owner.getDaemonIdentity() === null)
|
||||
expect((await chat.read()).tabs[0]).toMatchObject({ status: 'pending-handle', terminal: null })
|
||||
expect(owner.hasPty('persisted-pty')).toBe(true)
|
||||
expect(subprocess.write).not.toHaveBeenCalled()
|
||||
expect(chat.spawn).not.toHaveBeenCalled()
|
||||
} finally {
|
||||
owner.dispose()
|
||||
harness.adapter.dispose()
|
||||
await harness.server.shutdown()
|
||||
rmSync(harness.dir, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user