fix(subagent): finalize Codex provider composition

This commit is contained in:
pku-xht
2026-08-04 18:38:05 +08:00
parent 8a24a68333
commit c09b20f96b
31 changed files with 270 additions and 405 deletions
@@ -417,6 +417,25 @@ describe('CodexAppServerWire', () => {
wire.close()
})
it('maps only an explicit context-window failure to max-tokens', async () => {
const { child, wire } = await initializeWire()
const result = wire.runTurn(['task'], new AbortController().signal, () => false)
const turnStart = await child.peer.nextMethod('turn/start')
child.peer.respond(turnStart, { turn: { id: 'turn-1' } })
child.peer.send(
agentMessage('partial answer', null),
turnCompleted('failed', 'turn-1', 'thread-1', {
message: 'too much context',
codexErrorInfo: 'contextWindowExceeded',
}),
)
await expect(result).resolves.toEqual({
output: [{ type: 'text', text: 'partial answer' }],
stopReason: 'max-tokens',
})
wire.close()
})
it('rejects invalid handshake, thread, and turn response shapes', async () => {
{
const child = fakeChild()
@@ -516,7 +535,7 @@ describe('CodexAppServerWire', () => {
wire.close()
})
it('answers all four unattended request classes without granting authority', async () => {
it('answers all five unattended request classes without granting authority', async () => {
const { child, wire } = await initializeWire()
const result = wire.runTurn(['task'], new AbortController().signal, () => false)
const turnStart = await child.peer.nextMethod('turn/start')
@@ -524,10 +543,14 @@ describe('CodexAppServerWire', () => {
child.peer.send({
id: 'command',
method: 'item/commandExecution/requestApproval',
params: { threadId: 'thread-1', turnId: 'turn-1' },
params: {
threadId: 'thread-1',
turnId: 'turn-1',
availableDecisions: ['decline', 'cancel'],
},
})
expect(await child.peer.nextResponse('command')).toMatchObject({
result: { decision: 'decline' },
result: { decision: 'cancel' },
})
child.peer.respond(turnStart, { turn: { id: 'turn-1' } })
@@ -536,6 +559,16 @@ describe('CodexAppServerWire', () => {
{
id: 'file',
method: 'item/fileChange/requestApproval',
params: {
threadId: 'thread-1',
turnId: 'turn-1',
availableDecisions: ['decline'],
},
result: { decision: 'decline' },
},
{
id: 'file-default',
method: 'item/fileChange/requestApproval',
params: { threadId: 'thread-1', turnId: 'turn-1' },
result: { decision: 'decline' },
},
@@ -545,6 +578,12 @@ describe('CodexAppServerWire', () => {
params: { threadId: 'thread-1', turnId: 'turn-1' },
result: { permissions: {}, scope: 'turn' },
},
{
id: 'user-input',
method: 'item/tool/requestUserInput',
params: { threadId: 'thread-1', turnId: 'turn-1', questions: [] },
result: { answers: {} },
},
{
id: 'mcp',
method: 'mcpServer/elicitation/request',
@@ -568,9 +607,27 @@ describe('CodexAppServerWire', () => {
for (const serverRequest of [
{
id: 'unknown',
method: 'item/tool/requestUserInput',
method: 'future/request',
params: { threadId: 'thread-1', turnId: 'turn-1' },
},
{
id: 'approval',
method: 'item/commandExecution/requestApproval',
params: {
threadId: 'thread-1',
turnId: 'turn-1',
availableDecisions: ['accept'],
},
},
{
id: 'malformed-approval',
method: 'item/fileChange/requestApproval',
params: {
threadId: 'thread-1',
turnId: 'turn-1',
availableDecisions: 'decline',
},
},
{
id: 'thread',
method: 'item/fileChange/requestApproval',