Files
orca/tests/e2e/cross-version-wire/structured-agent-session-surface-manifest.ts
Neil 1c950baf33 refactor(main): group session lifecycle and journal modules by owner (#38638)
* refactor: group structured session modules by owner

* test: retire status history work-count oracle suite

* refactor(main): organize journal storage and projection owners

* Consolidate restart recovery fixture imports

* Consolidate concrete session option model imports
2026-11-06 06:00:08 -08:00

225 lines
7.7 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Adding a manifest entry exercises both skew directions and requires declaring the older peer’s behavior.
import {
attachFingerprintFields,
type AgentSessionAttachParams
} from '../../../src/main/native-chat/agent-session-wire/acquisition/structured-agent-session-attach'
import { computeAgentSessionPayloadFingerprint } from '../../../src/shared/agent-session/lifecycle/agent-session-mutation-envelope'
import {
structuredAgentSessionMessageSendMutation,
structuredAgentSessionSendBody
} from '../../../src/shared/agent-session/requests/structured-agent-session-send-mutation'
import {
SESSION,
WORKSPACE,
THREAD,
NOW,
ATTENTION_READ,
REWIND_METHOD,
ITEM_DETAIL_METHOD
} from './structured-agent-session-surface-calls'
export {
SESSION,
WORKSPACE,
THREAD,
NOW,
ATTENTION_READ,
REWIND_METHOD,
CONVERSATION_OUTLINE_METHOD,
ITEM_DETAIL_METHOD,
STATUS_FEED_METHOD,
TURN_COMPLETION_FEED_METHOD,
STRUCTURED_CALLS
} from './structured-agent-session-surface-calls'
let operations = 0
// Reset ids so one test’s envelopes cannot look like another test’s replays.
export function resetOperationIds(): void {
operations = 0
}
/** `<13-digit ms>-<32 hex>`, the only shape the durable ledger accepts. */
function operationId(): string {
operations += 1
return `${NOW}-${operations.toString(16).padStart(32, '0')}`
}
export function envelope(args: {
method: string
fields: Record<string, unknown>
fence: number | null
}): Record<string, unknown> {
return {
sessionId: SESSION,
clientOperationId: operationId(),
expectedRuntimeFence: args.fence,
payloadFingerprint: computeAgentSessionPayloadFingerprint({
method: args.method,
sessionId: SESSION,
fields: args.fields
})
}
}
export function attachParams(fence: number | null): AgentSessionAttachParams {
const params: AgentSessionAttachParams = {
envelope: {
sessionId: SESSION,
clientOperationId: operationId(),
expectedRuntimeFence: fence,
payloadFingerprint: ''
},
location: {
executionHostId: 'local',
wslDistro: null,
workspaceId: WORKSPACE,
workspaceKind: 'git-worktree'
},
provider: 'codex',
agent: 'codex',
accountHome: { variable: 'CODEX_HOME', path: '/home/dev/.codex' },
runtimeKind: 'native',
providerHandle: { kind: 'codex', threadId: THREAD }
}
return {
...params,
envelope: {
...params.envelope,
payloadFingerprint: computeAgentSessionPayloadFingerprint({
method: 'agentSession.attach',
sessionId: SESSION,
fields: attachFingerprintFields(params)
})
}
}
}
export function createIntentParams(): Record<string, unknown> {
const worktree = `id:${WORKSPACE}`
const fields = { worktree, agent: 'codex' }
return { envelope: envelope({ method: 'agentSession.create', fields, fence: null }), ...fields }
}
// Use the production sender so old hosts receive the exact current fingerprinted wire shape.
export function sendParams(
text: string,
fence: number,
sentDelivery?: 'queue-if-active',
options?: Readonly<Record<string, string>>
): Record<string, unknown> {
return structuredAgentSessionMessageSendMutation({
sessionId: SESSION,
clientOperationId: operationId(),
expectedRuntimeFence: fence,
body: structuredAgentSessionSendBody(text, []),
...(sentDelivery ? { delivery: sentDelivery } : {}),
...(options ? { options } : {})
})
}
/** Schema-valid params per method; values only need to survive validation. */
export function paramsFor(method: string): unknown {
const fence = 1
switch (method) {
case 'agentSession.createSupport':
return { worktree: `id:${WORKSPACE}`, agent: 'codex' }
case 'agentSession.create':
return createIntentParams()
case 'agentSession.ensure':
return attachParams(fence)
case 'agentSession.conversationCommand': {
const fields = { command: 'compact' }
return { envelope: envelope({ method, fields, fence }), ...fields }
}
case 'agentSession.send':
return sendParams('hi', fence)
case REWIND_METHOD: {
const fields = { itemId: 'item-1', expectedEpoch: 'current-epoch' }
return { envelope: envelope({ method, fields, fence }), ...fields }
}
case 'agentSession.cancel':
return {
envelope: envelope({ method: 'agentSession.cancel', fields: { turnId: 'turn-1' }, fence }),
turnId: 'turn-1'
}
case 'agentSession.queuedMessageSend':
case 'agentSession.queuedMessageDelete': {
const fields = { messageId: 'queued-1' }
return { envelope: envelope({ method, fields, fence }), ...fields }
}
case 'agentSession.queuedMessageMove': {
const fields = { messageId: 'queued-1', beforeMessageId: null }
return { envelope: envelope({ method, fields, fence }), ...fields }
}
case 'agentSession.queuedMessagesResume':
return { envelope: envelope({ method, fields: {}, fence }) }
case 'agentSession.queuedMessageUpdate': {
const fields = { messageId: 'queued-1', expectedBodyFingerprint: 'a'.repeat(64), text: 'hi' }
return { envelope: envelope({ method, fields, fence }), ...fields }
}
case 'agentSession.queuedMessageEditHold':
return {
sessionId: SESSION,
messageId: 'queued-1',
editId: 'edit-1',
action: 'acquire',
expectedBodyFingerprint: 'a'.repeat(64)
}
case 'agentSession.respondToApproval':
case 'agentSession.respondToQuestion': {
const fields = { itemId: 'item-1', expectedRevision: 1, optionId: 'allow' }
return { envelope: envelope({ method, fields, fence }), ...fields }
}
case 'agentSession.setOption': {
const fields = { key: 'model', value: 'gpt-5' }
return { envelope: envelope({ method, fields, fence }), ...fields }
}
case 'agentSession.threadGoal': {
const fields = { change: { kind: 'set', objective: 'Ship the parser' } }
return { envelope: envelope({ method, fields, fence }), ...fields }
}
case 'agentSession.history':
return { sessionId: SESSION, direction: 'tail' }
case 'agentSession.continuationContext':
return {
sessionId: SESSION,
workspaceId: WORKSPACE,
expectedCursor: { epoch: 'epoch-a', sequence: 0 }
}
case ITEM_DETAIL_METHOD:
return { sessionId: SESSION, itemId: 'item-1' }
case 'agentSession.sleepWorkspace':
return { workspaceId: WORKSPACE }
case 'agentSession.currentRequests':
return { sessionId: SESSION, version: '00000000-0000-4000-8000-000000000001' }
case 'agentSession.acknowledgeAttention':
return { ...ATTENTION_READ, observedCursor: { ...ATTENTION_READ.observedCursor } }
case 'agentSession.modelCatalog':
return { agent: 'codex', sessionId: SESSION }
case 'agentSession.readVisual':
return { sessionId: SESSION, file: 'usage-chart.html' }
case 'agentSession.rename':
return { sessionId: SESSION, name: 'Release notes' }
case 'agentSession.hold':
case 'agentSession.release':
return { sessionId: SESSION, holderId: 'surface-1' }
case 'agentSession.agents':
case 'agentSession.subscribeAvailability':
case 'agentSession.restartResumable':
case 'agentSession.restartResumableDismiss':
case 'agentSession.restartResume':
case 'agentSession.restartContinue':
// Whole-surface calls: they name no session, and resume/continue narrow by an optional list.
return {}
case 'agentSession.continueInterrupted':
return { sessionId: SESSION, turnItemId: 'legacy:codex:s:turn-1' }
case 'agentSession.cancelUsageLimitContinue':
return { sessionId: SESSION, turnItemId: 'orca:limited-turn', resetsAt: NOW }
default:
return { sessionId: SESSION }
}
}