- The composer's primary button keeps master's rule that hides a denied
action and draws the sending state inside it; a sending prompt stays
interruptible through master's stopAction.
- The ui-conversation README pairing is recorded again for the merged
sections.
The default per-image limit is 50 MiB and the default per-side limit is
65,535 pixels, but the admission summaries in the attachment subsystem
page and the attachment-local README still named 20 MiB and 8192 pixels.
The session-controller note on the /api/file byte limit and the tool-fs
note on read_image source caps also named the old 20 MiB maxImageBytes
default.
Brings in master a8d675ecc92, which reverts the agent controller of #6418,
together with the composer's image upload on add.
The agent-controller message delivery Agent Note follows master's deletion.
The ui-conversation README keeps the read-only sending paragraph and takes
the image upload sentences. Service orchestration keeps both new sendSession
cases, and the refused-send reference case takes master's newSession
submission fact. README pairings are recorded again.
An ordinary Session's composer now uploads each image draft through the
background upload queue as soon as it is added. The raw upload route stages
the body as a prompt image when the request names its media type: the Host
reads at most the per-image byte limit, then validates, normalizes, and
stores the image as prompt admission would. The prompt cites the receipt in
a file part; prompt admission resolves it to the stored image, applies the
image-input check, and counts stored images toward maxImagesPerMessage.
Send waits for every image receipt, and a failed image upload turns its
thumbnail into a retry control. Commands and subagent continuations keep
encoding images inline.
The Host's Inbox projection can reach the client before the prompt receipt.
Until the receipt published the echo, QueueDock showed the message as a
queued row, and in "On next message" mode the conversation followed the
grown tail and then folded back.
An Inbox row carrying the request id proves that the Host accepted the
prompt. The Session now publishes the echo and leaves the blank layout at
whichever of the receipt or the row arrives first, and calls the new
onAccept callback in that update. The composer settles inside that callback,
before the echo renders, so the fold starts from the shrunk composer instead
of depending on microtask order.
The Agent controller now finishes disposal only after every delivery it
stopped has settled, and a sender that cancels stops waiting at once, also
while its message waits behind a held one; the message keeps its place and
is dropped at its turn.
An image prompt takes the Session's image admission turn when its
preparation starts, in the Agent's delivery order, and keeps it until the
prompt settles. Image and text prompts therefore enter the inbox in arrival
order, and a model selection waits only for the image prompt being
admitted, not for one still queued.
The core page documents the delivery types, and the architecture overview
lists the controller and its admission event.
The composer keeps a sent message, its references, and its attachments
read-only in a sending phase until session/prompt resolves, so an
admission listener can hold or refuse a prompt before it appears as sent.
The Session publishes the local echo and leaves the blank layout only
after acceptance; a refusal or failure keeps the draft, and
session/prompt-rejected with presented: true adds no toast.
This carries the client half of deepseek-harness/deepseek-harness#6178.
Add @deepseek-ai/dsh-agent-controller, composed in the base bundle, as the
entry through which a sender delivers a message from outside an Agent into
its inbox. deliver() runs the sender's content preparation in the Agent's
delivery order, asks the agent-controller/admission waterfall for a
decision, rechecks cancellation and registration, and appends the message
with followup() or steer(). dsh-agent and agent-loop are unchanged.
The Web session/prompt Remote delivers through it: the image model check,
upload receipt resolution, and attachment storage run as prepare, the
receipt binding runs as beforeInsert, and refusals map to
session/prompt-rejected. The Web client keeps its existing echo.
This replaces the Host half of deepseek-harness/deepseek-harness#6178,
whose admission stage lived in dsh-agent.
session.create resolved the requested preset before queueing on the named
identity, so a later request whose preset resolved first could run first, and
an undeclared preset masked the directory conflict the README promises.
Queue first, check the named Session's directory and ownership, then resolve
the preset inside the queue, and report the preset each request left the
Session running instead of reading it after the queue moved on. The no-roster
conflict message now names its actual cause.
A request without the file's current version gets an uncached 302 to
api/file?path=…&v=<fs version>, served private, immutable. Each newly
mounted Markdown image still requests a unique URL, while the Host
decides whether the browser may reuse cached bytes.
Delete @deepseek-ai/dsh-invariants, every package's ./invariant companion
and its tests, the invariant gates and Vitest setup, the scoped-event
resolver generator, and the INVARIANT-coded listener rethrow paths.
Update docs, READMEs, Agent Notes, and add an upgrade guide.