Files
orca/tests/e2e/cross-version-wire/cross-version-agent-session-send.unit.test.ts
Neil 89f9ce08de refactor(shared): organize session contracts and projections (#36979)
* refactor(shared): organize session contracts and projections

* chore: tighten dropped-path flaky pattern allowance

* docs: preserve current agent instructions with valid formatting
2026-11-01 03:14:46 -08:00

119 lines
5.1 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.
// Run current outbox-built sends against a real release; both schema admission and operation fingerprints must preserve the user’s message.
import { beforeAll, describe, expect, it } from 'vitest'
import { AGENT_SESSION_SEND_OPTIONS_RUNTIME_CAPABILITY } from '../../../src/shared/agent-session/agent-session-create-capabilities'
import { resolveBaselineReleaseRef } from './release-checkout'
import { installableHost, structuredHostStub } from './structured-agent-session-host-fixture'
import {
resetOperationIds,
sendParams,
SESSION,
WORKSPACE
} from './structured-agent-session-surface-manifest'
import {
loadAgentSessionWireBuild,
WORKING_TREE,
type AgentSessionWireBuild,
type RpcReply,
type SentMessage
} from './versioned-agent-session-wire'
// The first published release whose host advertises `agent-session.send-options.v1` (#27826).
const SEND_OPTIONS_RELEASE_REF = 'v1.4.228'
const SUITE_TIMEOUT_MS = 180_000
let current: AgentSessionWireBuild
let baseline: AgentSessionWireBuild
beforeAll(async () => {
current = await loadAgentSessionWireBuild(WORKING_TREE)
baseline = await loadAgentSessionWireBuild(resolveBaselineReleaseRef())
}, SUITE_TIMEOUT_MS)
async function send(build: AgentSessionWireBuild, params: unknown): Promise<RpcReply[]> {
const replies: RpcReply[] = []
await build
// Releases before the setting gate was dropped admit structured calls only with it on.
.createDispatcher({
getRuntimeId: () => 'runtime-1',
getClientSettings: () => ({ experimentalStructuredNativeChat: true })
})
.dispatchStreaming(
{ id: 'request-send', authToken: 'cross-version-token', method: 'agentSession.send', params },
(raw) => replies.push(JSON.parse(raw)),
{ clientKind: 'runtime', clientCapabilities: current.capabilities }
)
return replies
}
describe('a current client sending a message', () => {
it.each([
['a plain message', undefined],
// `delivery` joins the operation fingerprint, so a builder that drops it is refused by a host
// that digests it.
['a message held as a draft while a turn runs', 'queue-if-active' as const]
])('is accepted for %s, under the fingerprint each build re-derives', async (_case, delivery) => {
// Anti-vacuous: the release must have the method, or there is no older host to send to.
expect(baseline.methodNames).toContain('agentSession.send')
for (const build of [current, baseline]) {
resetOperationIds()
const hostCalls = structuredHostStub(SESSION, WORKSPACE)
await build.installStructuredHost(installableHost(hostCalls))
try {
const replies = await send(build, sendParams('hi', 1, delivery))
expect(replies, `${build.label}: ${JSON.stringify(replies)}`).toMatchObject([{ ok: true }])
expect(hostCalls.send, `${build.label}: the send reached the host`).toHaveBeenCalledTimes(1)
const sent: SentMessage = hostCalls.send.mock.calls[0]?.[1]
expect(sent.delivery, `${build.label}: delivery reached the host`).toBe(delivery)
// Past the fingerprint check, admission stops at the journal this harness never opens.
expect(await build.admitSend(sent), `${build.label}: send admission`).toMatchObject({
ok: false,
refusal: { details: { reason: 'sessionNotAttached' } }
})
// Negative control: proves the fingerprint check ran before admission reached the journal.
const wrong = { ...sent.envelope, payloadFingerprint: '0'.repeat(64) }
expect(await build.admitSend({ ...sent, envelope: wrong }), build.label).toMatchObject({
refusal: { details: { reason: 'fingerprintMismatch' } }
})
} finally {
await build.installStructuredHost(null)
}
}
})
})
describe('a current client sending a message with its choices', () => {
it(
'is accepted, and the choices reach the host, on a host that advertises them',
async () => {
const release = await loadAgentSessionWireBuild(SEND_OPTIONS_RELEASE_REF)
const options = { model: 'sonnet', effort: 'high' }
for (const build of [current, release]) {
expect(build.capabilities, build.label).toContain(
AGENT_SESSION_SEND_OPTIONS_RUNTIME_CAPABILITY
)
resetOperationIds()
const hostCalls = structuredHostStub(SESSION, WORKSPACE)
await build.installStructuredHost(installableHost(hostCalls))
try {
const replies = await send(build, sendParams('hi', 1, undefined, options))
expect(replies, `${build.label}: ${JSON.stringify(replies)}`).toMatchObject([
{ ok: true }
])
const sent: SentMessage = hostCalls.send.mock.calls[0]?.[1]
expect(sent.options, `${build.label}: choices reached the host`).toEqual(options)
// `options` joins the operation fingerprint on both builds, so admission gets past it.
expect(await build.admitSend(sent), `${build.label}: send admission`).toMatchObject({
ok: false,
refusal: { details: { reason: 'sessionNotAttached' } }
})
} finally {
await build.installStructuredHost(null)
}
}
},
SUITE_TIMEOUT_MS
)
})