mirror of
https://github.com/stablyai/orca.git
synced 2026-10-22 00:03:47 +00:00
fix(native-chat): retain cold TUI proof authority
This commit is contained in:
@@ -3,12 +3,15 @@ import type { StructuredAgentSessionHandoffTransport } from '../native-chat/agen
|
||||
import { createEphemeralAgentSessionClaimSigner } from './agent-session-claim-identity'
|
||||
import { OrcaRuntimeService } from './orca-runtime'
|
||||
|
||||
const { probeAgentSessionProcessIdentity, readStructuredTuiProcessIdentity } = vi.hoisted(() => ({
|
||||
probeAgentSessionProcessIdentity: vi.fn(),
|
||||
readStructuredTuiProcessIdentity: vi.fn()
|
||||
}))
|
||||
const { probeAgentSessionProcessIdentity, proveCodexTuiRollout, readStructuredTuiProcessIdentity } =
|
||||
vi.hoisted(() => ({
|
||||
probeAgentSessionProcessIdentity: vi.fn(),
|
||||
proveCodexTuiRollout: vi.fn(),
|
||||
readStructuredTuiProcessIdentity: vi.fn()
|
||||
}))
|
||||
|
||||
vi.mock('./structured-tui-process-identity', () => ({ readStructuredTuiProcessIdentity }))
|
||||
vi.mock('../codex/codex-tui-rollout-proof', () => ({ proveCodexTuiRollout }))
|
||||
vi.mock('./agent-session-process-identity-probe', async (importOriginal) => ({
|
||||
...(await importOriginal()),
|
||||
probeAgentSessionProcessIdentity
|
||||
@@ -49,9 +52,17 @@ describe('structured TUI launch tab binding', () => {
|
||||
})
|
||||
const terminalHandle = 'term_cold_owner'
|
||||
const leafId = '23013912-13f8-44e5-818f-d40a1ff4e8c5'
|
||||
const waitForStructuredTuiProof = vi.fn(async () => ({
|
||||
transcriptPath: '/tmp/codex-home/sessions/thread-1.jsonl'
|
||||
}))
|
||||
proveCodexTuiRollout.mockImplementation(
|
||||
async (input: {
|
||||
readOutput(): { text: string; lastOutputAt: number | null }
|
||||
write(data: string): boolean
|
||||
}) => {
|
||||
input.readOutput()
|
||||
expect(input.write('/status')).toBe(true)
|
||||
input.readOutput()
|
||||
return { transcriptPath: '/tmp/codex-home/sessions/thread-1.jsonl' }
|
||||
}
|
||||
)
|
||||
const runtime = new OrcaRuntimeService(undefined, undefined, {
|
||||
agentSessionClaimSigner: signer
|
||||
})
|
||||
@@ -82,6 +93,7 @@ describe('structured TUI launch tab binding', () => {
|
||||
]),
|
||||
write: () => true,
|
||||
kill: () => true,
|
||||
writeAgentSessionProof: vi.fn(() => true),
|
||||
getForegroundProcess: async () => null
|
||||
})
|
||||
const internal = runtime as unknown as {
|
||||
@@ -96,7 +108,6 @@ describe('structured TUI launch tab binding', () => {
|
||||
folderWorkspace: null
|
||||
}>
|
||||
getAgentSessionExecutionNamespace(): typeof namespace
|
||||
waitForStructuredTuiProof: typeof waitForStructuredTuiProof
|
||||
ptysById: Map<
|
||||
string,
|
||||
{ launchToken: string | null; launchAgent: string | null; agentSessionOwners: unknown[] }
|
||||
@@ -113,7 +124,6 @@ describe('structured TUI launch tab binding', () => {
|
||||
folderWorkspace: null
|
||||
}))
|
||||
internal.getAgentSessionExecutionNamespace = () => namespace
|
||||
internal.waitForStructuredTuiProof = waitForStructuredTuiProof
|
||||
probeAgentSessionProcessIdentity.mockResolvedValue({
|
||||
outcome: 'identity-matched',
|
||||
matchedOn: ['process-start-time']
|
||||
@@ -146,13 +156,7 @@ describe('structured TUI launch tab binding', () => {
|
||||
paneKey: `tab-cold-owner:${leafId}`,
|
||||
ptyId: 'pty-cold-owner'
|
||||
})
|
||||
expect(waitForStructuredTuiProof).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
handle: terminalHandle,
|
||||
paneKey: `tab-cold-owner:${leafId}`,
|
||||
spawnToken: 'spawn-token'
|
||||
})
|
||||
)
|
||||
expect(proveCodexTuiRollout).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it('proves the published launch tab before returning its revealed renderer binding', async () => {
|
||||
|
||||
@@ -81,6 +81,7 @@ import type {
|
||||
} from '../native-chat/agent-session-wire/structured-agent-session-handoff-types'
|
||||
import type { AgentSessionRecord } from '../../shared/agent-session-record'
|
||||
import {
|
||||
agentSessionOwnerBindingsEqual,
|
||||
cloneAgentSessionOwnerBinding,
|
||||
scopedAgentSessionClaimsEqual
|
||||
} from '../../shared/claimed-agent-pty-owner-snapshot'
|
||||
@@ -9226,6 +9227,7 @@ export class OrcaRuntimeService {
|
||||
pty.paneKey
|
||||
)
|
||||
let handle = candidate ? this.issueStructuredTuiPtyHandle(candidate) : null
|
||||
let durableOwner: { binding: AgentSessionOwnerBinding; incarnationId: string } | undefined
|
||||
if (!candidate) {
|
||||
const workspace = await this.resolveTerminalWorkspaceLaunchScope(
|
||||
`id:${record.location.workspaceId}`
|
||||
@@ -9273,6 +9275,13 @@ export class OrcaRuntimeService {
|
||||
recovered.owner.surface.leafId
|
||||
)
|
||||
handle = this.issueRecoveredStructuredTuiPtyHandle(candidate, recovered.owner.surface)
|
||||
const recoveredIncarnationId = candidate.incarnationId
|
||||
if (handle && recoveredIncarnationId) {
|
||||
durableOwner = {
|
||||
binding: cloneAgentSessionOwnerBinding(recovered.owner),
|
||||
incarnationId: recoveredIncarnationId
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!candidate?.tabId || !candidate.paneKey || !handle) {
|
||||
throw new Error('The owning agent terminal could not be recovered.')
|
||||
@@ -9283,7 +9292,8 @@ export class OrcaRuntimeService {
|
||||
threadId: head.handle.threadId,
|
||||
spawnToken: identity.spawnToken,
|
||||
codexHome: record.accountHome.path,
|
||||
sessionId: record.sessionId
|
||||
sessionId: record.sessionId,
|
||||
...(durableOwner ? { durableOwner } : {})
|
||||
})
|
||||
return {
|
||||
terminal: {
|
||||
@@ -9470,14 +9480,25 @@ export class OrcaRuntimeService {
|
||||
spawnToken: string
|
||||
codexHome: string
|
||||
sessionId: string
|
||||
durableOwner?: { binding: AgentSessionOwnerBinding; incarnationId: string }
|
||||
}): Promise<{ transcriptPath?: string }> {
|
||||
const readBoundPty = (): RuntimePtyWorktreeRecord => {
|
||||
const pty = this.getLivePtyForHandle(input.handle)?.pty
|
||||
const durableOwner = input.durableOwner
|
||||
const launchIdentityMatches =
|
||||
pty?.launchAgent === 'codex' && pty.launchToken === input.spawnToken
|
||||
const durableIdentityMatches = Boolean(
|
||||
pty &&
|
||||
durableOwner &&
|
||||
pty.incarnationId === durableOwner.incarnationId &&
|
||||
pty.agentSessionOwners.some((owner) =>
|
||||
agentSessionOwnerBindingsEqual(owner, durableOwner.binding)
|
||||
)
|
||||
)
|
||||
if (
|
||||
!pty?.connected ||
|
||||
pty.paneKey !== input.paneKey ||
|
||||
pty.launchAgent !== 'codex' ||
|
||||
pty.launchToken !== input.spawnToken
|
||||
(!launchIdentityMatches && !durableIdentityMatches)
|
||||
) {
|
||||
throw new Error('The resumed terminal lost its launch identity.')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user