# Agent Note: Web 图片准入的原子性

Status: implemented

[English](2026-07-29-atomic-web-image-admission.md) | 中文

## 问题

包含图片的提示词准入与 `session.selectModel` 都会在跨越异步模型查询与附件查询的过程中读取会话模态状态。如果没有统一的顺序边界，包含图片的提示词可能在支持图片的目标上通过校验，并发的选择操作却设置了纯文本目标；选择操作也可能在提示词已从 inbox 出队、但其持久消息事件尚未发布时漏掉该提示词。扫描不可变事件日志可以避免第二种竞态，但即使压缩（compaction）已经从当前模型历史中移除图片，仍会永久阻止选择纯文本目标。

## 决策

每个活跃 Web agent（智能体）都有一条私有 promise 链，由包含图片的提示词准入与模型选择共享。操作失败会照常传递给调用方，且不会使该链失效。纯文本提示词绕过该链，因为它们不会改变模态约束。

待发布集合会在排队条目出队时记录它，而 steering 条目在入队时即被记录（steering 条目从不进入排队 UI 镜像），并各自保留到匹配的 `user/message` 或 `steering/message` 事件发布。若准入结束时未发布事件，转为空闲状态会移除这些条目；inbox 丢弃会移除列出的工作项，会话 dispose（资源释放）则会移除所有剩余条目。模型选择会检查该集合、排队 UI 镜像以及 `Session.deriveMessages()`；后者表示压缩后模型当前可见的历史。

提供方适配器仍是最终的强制检查边界。宿主的顺序控制仅用于避免其可变路由与待发布图片状态在请求组装前彼此矛盾。

## 曾考虑的替代方案

**扫描每个不可变会话事件。** 这能捕获已发布的图片，但会把经压缩移除的内容视为永久对模型可见，从而阻止之后合法切换到纯文本路由。

**在 inbox 出队时退役待处理镜像。** 出队早于持久消息追加，因此恰好会留下一个时间区间，让模型选择既看不到待处理状态，也看不到已发布状态。

**序列化每个提示词和会话变更。** 纯文本提示词和无关的会话操作无法引入图片要求。更宽的锁会增加延迟与所有权复杂度，却不会再消除任何模态竞态。

## 后果

包含图片的提示词准入与并发模型选择之间具有确定的先后顺序，纯文本目标无法使已获准入但尚未发布的图片搁浅。模型选择可能等待正在进行的图片准入完成，而无关提示词仍按现有方式并发处理。当没有图片等待发布，且派生历史经过压缩后也不再含图片时，纯文本目标可以变得有效。
