mirror of
https://github.com/wu736139669/hapi.git
synced 2026-10-08 19:19:42 +00:00
542 lines
22 KiB
TypeScript
542 lines
22 KiB
TypeScript
import type { FixtureCase } from '../fixtureTypes'
|
|
import { T0, wireMessage } from './support'
|
|
|
|
/**
|
|
* Generic agent family: content.type === 'codex' (AGENT_MESSAGE_PAYLOAD_TYPE,
|
|
* used by Codex/Cursor/OpenCode/Pi/…). Text and reasoning arrive as cumulative
|
|
* stream snapshots keyed by data.id.
|
|
*/
|
|
export const codexCases: FixtureCase[] = [
|
|
...([true, false] as const).map((available): FixtureCase => {
|
|
const callId = 'codex-proposed-plan:root:turn:plan-item'
|
|
const data = [
|
|
{ type: 'message', message: 'Proposal preface', id: 'codex:root:turn:before:agent_message' },
|
|
{ type: 'tool-call', name: 'ExitPlanMode', callId, input: { plan: '# Shared plan\n\n1. Inspect\n2. Implement' }, id: 'codex:root:turn:plan-item:proposed_plan' },
|
|
{ type: 'tool-call-result', callId, output: null, id: 'codex:root:turn:plan-item:proposed_plan:result' },
|
|
...(!available ? [{ type: 'message', message: 'Implementation started', id: 'codex:root:next:message:agent_message' }] : [])
|
|
]
|
|
return {
|
|
name: available ? 'codex-shared-plan-available' : 'codex-shared-plan-historical',
|
|
description: 'Shared Codex proposals remain completed content without a synthetic permission. The current plan id only enables Web client actions; native continuation preserves the card.',
|
|
messages: data.map((entry, index) => wireMessage({ id: `shared-plan-${index}`, seq: index + 1, createdAt: T0 + index * 1000,
|
|
content: { role: 'agent', content: { type: 'codex', data: entry } }
|
|
})),
|
|
agentState: { codexPlanProposalId: available ? callId : null }
|
|
}
|
|
}),
|
|
...(['ExitPlanMode', 'exit_plan_mode'] as const).map((name, index): FixtureCase => {
|
|
const plan = '# 实施计划\n\n1. Inspect **input.plan**\n2. Render Markdown\n\n```swift\nlet ready = true\n```\n'
|
|
const callId = `codex-proposed-plan:plan-${index}`
|
|
const pending = index === 1
|
|
const data = [
|
|
{ type: 'tool-call', name: 'Read', callId: 'read-before', input: { file_path: '/repo/README.md' } },
|
|
{ type: 'tool-call-result', callId: 'read-before', output: 'Readme' },
|
|
{ type: 'tool-call', name, callId, input: { plan }, id: `plan-${index}` },
|
|
...(!pending ? [{ type: 'tool-call-result', callId, output: null, id: `plan-${index}:result` }] : []),
|
|
{ type: 'tool-call', name: 'Read', callId: 'read-after', input: { file_path: '/repo/package.json' } },
|
|
{ type: 'tool-call-result', callId: 'read-after', output: '{}' }
|
|
]
|
|
return {
|
|
name: pending ? 'codex-plan-proposal-pending' : 'codex-plan-proposal-completed',
|
|
description: 'Proposal Markdown lives in input.plan. Keep it standalone between ordinary tools; null output completes a proposal without inventing approval. The lowercase alias also accepts a pending permission.',
|
|
messages: data.map((entry, seq) => wireMessage({
|
|
id: `proposal-${index}-${seq}`, seq: seq + 1, createdAt: T0 + seq * 1000,
|
|
content: { role: 'agent', content: { type: 'codex', data: entry } }
|
|
})),
|
|
...(pending ? { agentState: { requests: {
|
|
'plan-approval': { tool: name, toolCallId: callId, arguments: { plan }, createdAt: T0 + 2000 }
|
|
} } } : {})
|
|
}
|
|
}),
|
|
{
|
|
name: 'codex-message-stream-snapshot',
|
|
description: 'Codex family: two message payloads sharing a stream id (data.id) are cumulative snapshots. Expects a single agent-text block keyed by that stable stream id, carrying the final snapshot text.',
|
|
messages: [
|
|
wireMessage({
|
|
id: 'msg-codex-051',
|
|
seq: 1,
|
|
createdAt: T0,
|
|
content: {
|
|
role: 'agent',
|
|
content: {
|
|
type: 'codex',
|
|
data: {
|
|
type: 'message',
|
|
id: 'item_7',
|
|
message: 'Tracking down the failing pagination'
|
|
}
|
|
}
|
|
}
|
|
}),
|
|
wireMessage({
|
|
id: 'msg-codex-052',
|
|
seq: 2,
|
|
createdAt: T0 + 900,
|
|
content: {
|
|
role: 'agent',
|
|
content: {
|
|
type: 'codex',
|
|
data: {
|
|
type: 'message',
|
|
id: 'item_7',
|
|
message: 'Tracking down the failing pagination test: the cursor math drops the epoch check when seq wraps.'
|
|
}
|
|
}
|
|
}
|
|
})
|
|
]
|
|
},
|
|
{
|
|
name: 'codex-reasoning',
|
|
description: 'Codex family: reasoning payload becomes an agent-reasoning block keyed by its stream id (data.id).',
|
|
messages: [
|
|
wireMessage({
|
|
id: 'msg-codex-061',
|
|
seq: 1,
|
|
createdAt: T0,
|
|
content: {
|
|
role: 'agent',
|
|
content: {
|
|
type: 'codex',
|
|
data: {
|
|
type: 'reasoning',
|
|
id: 'rs_0af3d219',
|
|
message: '**Weighing pagination approaches**\n\nThe epoch guard only fires when the server resets, so the client must drop its window on mismatch.'
|
|
}
|
|
}
|
|
}
|
|
})
|
|
]
|
|
},
|
|
{
|
|
name: 'codex-blank-stream-ids',
|
|
description: 'Codex family: blank (empty or whitespace-only) data.id values are not stream identities (shared/src/messages.ts trims before accepting) — each payload keeps its own row-derived block id instead of collapsing onto a shared blank identity.',
|
|
messages: [
|
|
wireMessage({
|
|
id: 'msg-codex-065',
|
|
seq: 1,
|
|
createdAt: T0,
|
|
content: {
|
|
role: 'agent',
|
|
content: {
|
|
type: 'codex',
|
|
data: {
|
|
type: 'reasoning',
|
|
id: '',
|
|
message: 'blank id one'
|
|
}
|
|
}
|
|
}
|
|
}),
|
|
wireMessage({
|
|
id: 'msg-codex-066',
|
|
seq: 2,
|
|
createdAt: T0 + 100,
|
|
content: {
|
|
role: 'agent',
|
|
content: {
|
|
type: 'codex',
|
|
data: {
|
|
type: 'reasoning',
|
|
id: ' ',
|
|
message: 'blank id two'
|
|
}
|
|
}
|
|
}
|
|
}),
|
|
wireMessage({
|
|
id: 'msg-codex-067',
|
|
seq: 3,
|
|
createdAt: T0 + 200,
|
|
content: {
|
|
role: 'agent',
|
|
content: {
|
|
type: 'codex',
|
|
data: {
|
|
type: 'message',
|
|
id: '',
|
|
message: 'blank id text one'
|
|
}
|
|
}
|
|
}
|
|
}),
|
|
wireMessage({
|
|
id: 'msg-codex-068',
|
|
seq: 4,
|
|
createdAt: T0 + 300,
|
|
content: {
|
|
role: 'agent',
|
|
content: {
|
|
type: 'codex',
|
|
data: {
|
|
type: 'message',
|
|
id: ' ',
|
|
message: 'blank id text two'
|
|
}
|
|
}
|
|
}
|
|
})
|
|
]
|
|
},
|
|
{
|
|
name: 'codex-error-event',
|
|
description: 'Codex family: an error payload becomes an agent-event block with {type: error, message} carried verbatim.',
|
|
messages: [
|
|
wireMessage({
|
|
id: 'msg-user-501',
|
|
seq: 1,
|
|
createdAt: T0,
|
|
content: {
|
|
role: 'user',
|
|
content: { type: 'text', text: 'Continue the review.' }
|
|
}
|
|
}),
|
|
wireMessage({
|
|
id: 'msg-codex-502',
|
|
seq: 2,
|
|
createdAt: T0 + 2_700,
|
|
content: {
|
|
role: 'agent',
|
|
content: {
|
|
type: 'codex',
|
|
data: {
|
|
type: 'error',
|
|
message: 'Codex backend disconnected: stream closed before the turn completed'
|
|
}
|
|
}
|
|
}
|
|
})
|
|
]
|
|
},
|
|
{
|
|
name: 'codex-context-compacted',
|
|
description: 'Codex family: context_compacted maps to an agent-event of type compact with trigger and preTokens (accepting the snake_case pre_tokens wire key).',
|
|
messages: [
|
|
wireMessage({
|
|
id: 'msg-user-511',
|
|
seq: 1,
|
|
createdAt: T0,
|
|
content: {
|
|
role: 'user',
|
|
content: { type: 'text', text: 'Carry on.' }
|
|
}
|
|
}),
|
|
wireMessage({
|
|
id: 'msg-codex-512',
|
|
seq: 2,
|
|
createdAt: T0 + 3_100,
|
|
content: {
|
|
role: 'agent',
|
|
content: {
|
|
type: 'codex',
|
|
data: {
|
|
type: 'context_compacted',
|
|
trigger: 'auto',
|
|
pre_tokens: 186211,
|
|
thread_id: 'thread-42'
|
|
}
|
|
}
|
|
}
|
|
})
|
|
]
|
|
},
|
|
{
|
|
name: 'codex-generated-image',
|
|
description: 'Codex family: generated-image becomes a generated-image block keeping {imageId, fileName, mimeType}; the wire source (inline media provenance) and sourceImageId are web rendering concerns and are dropped by the projection.',
|
|
messages: [
|
|
wireMessage({
|
|
id: 'msg-codex-521',
|
|
seq: 1,
|
|
createdAt: T0,
|
|
content: {
|
|
role: 'agent',
|
|
content: {
|
|
type: 'codex',
|
|
data: {
|
|
type: 'generated-image',
|
|
imageId: 'img-01J9ZD8KM4TQ',
|
|
sourceImageId: 'ig_58210',
|
|
fileName: 'latency-chart.png',
|
|
mimeType: 'image/png',
|
|
id: 'aed0f1b2-5fb6-4c2d-8e9d-e2f3a4b5c521',
|
|
source: {
|
|
ingress: 'tool_result',
|
|
flavor: 'codex',
|
|
toolCallId: 'call_img_58210'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
})
|
|
]
|
|
},
|
|
{
|
|
name: 'codex-review-verdict',
|
|
description: 'Codex family: a message whose text is codex review JSON (findings + overall_correctness/…) parses into a codex-review block with the normalized review object (camelCase fields, code_location flattened to filePath/lineStart/lineEnd).',
|
|
messages: [
|
|
wireMessage({
|
|
id: 'msg-codex-531',
|
|
seq: 1,
|
|
createdAt: T0,
|
|
content: {
|
|
role: 'agent',
|
|
content: {
|
|
type: 'codex',
|
|
data: {
|
|
type: 'message',
|
|
id: '550e8400-e29b-41d4-a716-446655440531',
|
|
message: '{"findings":[{"title":"[P2] Remove retained sessions when sockets disconnect","body":"Retained sockets survive disconnects.","confidence_score":0.82,"priority":2,"code_location":{"absolute_file_path":"/repo/hub/src/pairing/manager.ts","line_range":{"start":1614,"end":1619}}}],"overall_correctness":"patch is incorrect","overall_explanation":"The message-sending feature retains long-lived sockets but does not fully manage their lifecycle.","overall_confidence_score":0.8}'
|
|
}
|
|
}
|
|
}
|
|
})
|
|
]
|
|
},
|
|
{
|
|
name: 'codex-thread-goal-updated',
|
|
description: 'Codex family: thread_goal_updated normalizes to a thread-goal-updated event which is SILENT in the timeline (filtered as a goal-state signal) — expected blocks contain only the user text. latestGoal is derived state outside the normative projection.',
|
|
messages: [
|
|
wireMessage({
|
|
id: 'msg-user-541',
|
|
seq: 1,
|
|
createdAt: T0,
|
|
content: {
|
|
role: 'user',
|
|
content: { type: 'text', text: '/goal Ship the pagination fix' }
|
|
}
|
|
}),
|
|
wireMessage({
|
|
id: 'msg-codex-542',
|
|
seq: 2,
|
|
createdAt: T0 + 1_300,
|
|
content: {
|
|
role: 'agent',
|
|
content: {
|
|
type: 'codex',
|
|
data: {
|
|
type: 'thread_goal_updated',
|
|
thread_id: 'thread-42',
|
|
turn_id: 'turn-7',
|
|
goal: {
|
|
threadId: 'thread-42',
|
|
objective: 'Ship the pagination fix',
|
|
status: 'active',
|
|
tokenBudget: 200000,
|
|
tokensUsed: 8016,
|
|
timeUsedSeconds: 42,
|
|
createdAt: 1755000001300,
|
|
updatedAt: 1755000001300
|
|
}
|
|
}
|
|
}
|
|
}
|
|
})
|
|
]
|
|
},
|
|
{
|
|
name: 'codex-thread-goal-cleared',
|
|
description: 'Codex family: thread_goal_cleared normalizes to a thread-goal-cleared event which is SILENT in the timeline — expected blocks contain only the user text.',
|
|
messages: [
|
|
wireMessage({
|
|
id: 'msg-user-551',
|
|
seq: 1,
|
|
createdAt: T0,
|
|
content: {
|
|
role: 'user',
|
|
content: { type: 'text', text: '/goal clear' }
|
|
}
|
|
}),
|
|
wireMessage({
|
|
id: 'msg-codex-552',
|
|
seq: 2,
|
|
createdAt: T0 + 1_100,
|
|
content: {
|
|
role: 'agent',
|
|
content: {
|
|
type: 'codex',
|
|
data: {
|
|
type: 'thread_goal_cleared',
|
|
thread_id: 'thread-42'
|
|
}
|
|
}
|
|
}
|
|
})
|
|
]
|
|
},
|
|
{
|
|
name: 'codex-tool-call-result-pair',
|
|
description: 'Codex family: a tool-call (callId + name + structured input) paired with its tool-call-result (output object) merges into one completed tool-call block; input and output are carried verbatim (command as argv array, output as {exit_code, stdout, …}).',
|
|
messages: [
|
|
wireMessage({
|
|
id: 'msg-user-561',
|
|
seq: 1,
|
|
createdAt: T0,
|
|
content: {
|
|
role: 'user',
|
|
content: { type: 'text', text: 'Run the test suite.' }
|
|
}
|
|
}),
|
|
wireMessage({
|
|
id: 'msg-codex-562',
|
|
seq: 2,
|
|
createdAt: T0 + 1_800,
|
|
content: {
|
|
role: 'agent',
|
|
content: {
|
|
type: 'codex',
|
|
data: {
|
|
type: 'tool-call',
|
|
name: 'CodexBash',
|
|
callId: 'call_9f2d81aa04',
|
|
input: {
|
|
command: ['bash', '-lc', 'bun test'],
|
|
cwd: '/repo'
|
|
},
|
|
id: 'bfe1a2c3-6ac7-4d3e-9fae-f3a4b5c6d562'
|
|
}
|
|
}
|
|
}
|
|
}),
|
|
wireMessage({
|
|
id: 'msg-codex-563',
|
|
seq: 3,
|
|
createdAt: T0 + 9_400,
|
|
content: {
|
|
role: 'agent',
|
|
content: {
|
|
type: 'codex',
|
|
data: {
|
|
type: 'tool-call-result',
|
|
callId: 'call_9f2d81aa04',
|
|
output: {
|
|
exit_code: 0,
|
|
stdout: '420 pass\n0 fail\nRan 420 tests across 37 files. [4.21s]',
|
|
duration_seconds: 4.21
|
|
},
|
|
is_error: false,
|
|
id: 'c0f2b3d4-7bd8-4e4f-8ab0-a4b5c6d7e563'
|
|
}
|
|
}
|
|
}
|
|
})
|
|
]
|
|
},
|
|
{
|
|
name: 'codex-exploration-tool-group',
|
|
description: 'Codex exploration grouping family: consecutive CodexBash calls whose command_actions are all read/listFiles/search (and command_source is not userShell) collapse into one tool-group in visibleBlocks — a family boundary distinct from the default read/search grouping.',
|
|
messages: [
|
|
wireMessage({
|
|
id: 'msg-user-571',
|
|
seq: 1,
|
|
createdAt: T0,
|
|
content: {
|
|
role: 'user',
|
|
content: { type: 'text', text: 'Where is the pagination cursor built?' }
|
|
}
|
|
}),
|
|
wireMessage({
|
|
id: 'msg-codex-572',
|
|
seq: 2,
|
|
createdAt: T0 + 1_500,
|
|
content: {
|
|
role: 'agent',
|
|
content: {
|
|
type: 'codex',
|
|
data: {
|
|
type: 'tool-call',
|
|
name: 'CodexBash',
|
|
callId: 'call_expl_read01',
|
|
input: {
|
|
command: ['bash', '-lc', 'cat package.json'],
|
|
cwd: '/repo',
|
|
command_source: 'agent',
|
|
command_actions: [
|
|
{
|
|
type: 'read',
|
|
command: 'cat package.json',
|
|
name: 'package.json',
|
|
path: '/repo/package.json'
|
|
}
|
|
]
|
|
},
|
|
id: 'd1a3c4e5-8ce9-4f5a-9bc1-b5c6d7e8f572'
|
|
}
|
|
}
|
|
}
|
|
}),
|
|
wireMessage({
|
|
id: 'msg-codex-573',
|
|
seq: 3,
|
|
createdAt: T0 + 2_400,
|
|
content: {
|
|
role: 'agent',
|
|
content: {
|
|
type: 'codex',
|
|
data: {
|
|
type: 'tool-call-result',
|
|
callId: 'call_expl_read01',
|
|
output: {
|
|
exit_code: 0,
|
|
stdout: '{\n "name": "hapi",\n "workspaces": ["cli", "hub", "web", "shared"]\n}'
|
|
},
|
|
is_error: false,
|
|
id: 'e2b4d5f6-9dfa-4a6b-8cd2-c6d7e8f9a573'
|
|
}
|
|
}
|
|
}
|
|
}),
|
|
wireMessage({
|
|
id: 'msg-codex-574',
|
|
seq: 4,
|
|
createdAt: T0 + 3_300,
|
|
content: {
|
|
role: 'agent',
|
|
content: {
|
|
type: 'codex',
|
|
data: {
|
|
type: 'tool-call',
|
|
name: 'CodexBash',
|
|
callId: 'call_expl_search01',
|
|
input: {
|
|
command: ['bash', '-lc', 'rg buildCursor web/src'],
|
|
cwd: '/repo',
|
|
command_source: 'agent',
|
|
command_actions: [
|
|
{
|
|
type: 'search',
|
|
command: 'rg buildCursor web/src',
|
|
query: 'buildCursor',
|
|
path: 'web/src'
|
|
}
|
|
]
|
|
},
|
|
id: 'f3c5e6a7-0eab-4b7c-9de3-d7e8f9a0b574'
|
|
}
|
|
}
|
|
}
|
|
}),
|
|
wireMessage({
|
|
id: 'msg-codex-575',
|
|
seq: 5,
|
|
createdAt: T0 + 4_100,
|
|
content: {
|
|
role: 'agent',
|
|
content: {
|
|
type: 'codex',
|
|
data: {
|
|
type: 'tool-call-result',
|
|
callId: 'call_expl_search01',
|
|
output: {
|
|
exit_code: 0,
|
|
stdout: 'web/src/lib/message-window-store.ts:412:function buildCursor(page) {'
|
|
},
|
|
is_error: false,
|
|
id: 'a4d6f7b8-1fbc-4c8d-8ef4-e8f9a0b1c575'
|
|
}
|
|
}
|
|
}
|
|
})
|
|
]
|
|
}
|
|
]
|