Codex 的 ID 不是一条不断细分的树,也没有统一生成器。Submission、Turn、Item 和 Call 分别解决投递、工作边界、界面对象和请求相关性;某些路径复用同一个字符串,是协议映射,不是类型等价。
作用域矩阵
| ID | 谁通常生成 | 作用域 | 主要相关对象 |
|---|---|---|---|
| Submission ID | SessionIo / App Server | 一次提交 | Submission 与即时 Event |
| Turn ID | 创建 Turn 的提交 | 当前 Thread 中一次工作 | TurnStarted/Complete/Aborted |
| Item ID | Runtime、模型或投影层 | 一个 TurnItem/ResponseItem | started/delta/completed |
| Call ID | 多数由模型工具调用给出 | 一次调用及其 output/waiter | Tool call、approval、result |
| Process ID | UnifiedExec 分配或调用方提供 | 进程管理器 | write_stdin、poll、terminate |
为什么公开 Turn ID 常等于 Submission ID
SessionIo 默认用 UUIDv7 创建 Submission id。对会创建 Turn 的 UserInput,new_turn_with_sub_id 把这同一个 id 存进 TurnContext 的 sub_id;所有带 TurnContext 发出的 Event 随后使用它。App Server 因而可以把“创建 Turn 的请求 id”稳定暴露为 public turn id。
async def submit_user_input(input):
submission_id = uuid_v7()
await tx.send(Submission(id=submission_id, op=UserInput(input)))
async def handle_user_input(submission):
turn = await new_turn_with_sub_id(submission.id)
assert turn.sub_id == submission.id
await start_task(turn)
但这不是所有 Submission 都是 Turn。审批答复、刷新、Realtime audio 和 Shutdown 也有 submission id,却不创建普通 Turn。反过来,Mailbox 唤醒等内部 Turn 可以用 UUIDv4 或内部生成 id,不一定来自公开 UserInput。
Item ID 与 ResponseItemId
协议投影的 TurnItem 在缺少上游 id 时用 UUIDv7 生成 item id。模型的 ResponseItem 可能携带 provider 给出的 id;Runtime 还提供 ResponseItemId 强类型来校验、保留或生成特定格式的响应项标识。
Item ID 负责把 started、delta、completed 投影成同一个 UI 对象。它不一定等于工具 Call ID。某些命令项为了方便会直接用 call id 作为 item id,但消费者不能把这个实现习惯推广到所有 Item 类型。
Call ID 是相关键,不是全局主键
函数调用、custom tool、MCP 和 hosted tool 的 ResponseItem 带 call_id。Runtime 用它生成对应 output,并索引审批、动态工具或权限请求的 oneshot waiter。
async def dispatch_tool(item, turn_state):
call_id = item.call_id # 通常来自模型响应
waiter = oneshot()
turn_state.approvals[call_id] = waiter.sender
decision = await waiter.receiver
output = await execute_if_allowed(item, decision)
return FunctionCallOutput(call_id=call_id, output=output)
Call ID 的正确要求是在它的相关上下文中不冲突并保持 call/output 配对。代码没有宣称它跨所有 Thread、所有 provider 永久全局唯一,因此存储键至少应包含 Thread/Turn 或明确的调用域。
常见错误
- 用任意 Submission id 查询 Turn:该提交可能只是审批答复。
- 假定 Item id 等于 Call id:普通消息和计划项没有这种关系。
- 用 Call id 直接终止后台进程:UnifiedExec 续写和终止使用 process id。
- 只按 Call id 建全局数据库唯一索引:不同响应域可能产生相同字符串。
- 把内部 synthetic Turn 当成客户端提交:它可能没有对应 public request。
评论
登录后即可评论