PAF becomes saf/device (history kept), STATE.md dissolves into saf/state.md with the dated era archived, the substrate SAF moves up from souveraine, and every agreement points at saf/INDEX.md and nowhere else. one map, nothing to remember
246 lines
14 KiB
Markdown
246 lines
14 KiB
Markdown
# The agent panel
|
|
|
|
The Panel is Souveraine's close conversation surface on the desktop. It is not
|
|
a generic provider picker laid over somebody else's chat client. The agent in
|
|
its footer is the agent this pane can address; the transcript is the substrate's
|
|
typed conversation; thought, action, itinerary, subconscious work, and context
|
|
pressure remain distinct even when they share a narrow column.
|
|
|
|
The present shell code is split across
|
|
`surfaces/quickshell/services/Souveraine.qml`, the `Ai.qml` compatibility
|
|
adapter, and `modules/souveraine/agent/`. The outer list and composer still live
|
|
in the borrowed `modules/ii/sidebarLeft/AiChat.qml`. That is a migration seam,
|
|
not permission for the borrowed component to become a second owner of state or
|
|
product meaning.
|
|
|
|
## The anatomy
|
|
|
|
The vertical order is deliberate:
|
|
|
|
1. the conversation occupies the primary, scrollable field;
|
|
2. transient subconscious activity may touch the lower edge of that field;
|
|
3. the itinerary remains as a thin persistent ribbon above the composer while
|
|
a route exists;
|
|
4. the composer owns text entry, send/cancel/interject behavior, attachment
|
|
state, and commands;
|
|
5. the footer holds compact controls for the agent and the few secondary
|
|
surfaces that actually work.
|
|
|
|
The agent menu opens from its footer chip. It does not live above the
|
|
conversation as permanent green furniture. The itinerary does remain above the
|
|
composer because it answers a different question: not which process happens to
|
|
be alive, but where the current agent is in the work Casey asked her to carry.
|
|
|
|
Every footer chip must either expose a state the pane owns or perform the act it
|
|
advertises. A decorative tool selector is worse than no selector when tools are
|
|
configured in the agent's sensorium and cannot be switched here. Remove it.
|
|
Commands may still name unavailable work in documentation; they do not earn a
|
|
button on the live surface until their path exists.
|
|
|
|
## One controlled agent, other sessions observed
|
|
|
|
`Souveraine.currentAgentId` is the controlled position. The selector is
|
|
populated from `/v1/agents` through the Souveraine service and may switch only
|
|
between those agents. A running turn pins that selection until it finishes or
|
|
is cancelled, because changing the face while a response is arriving would
|
|
mislabel both transcript and authority.
|
|
|
|
Codex and Claude processes discovered by `AgentSessions` are not models behind
|
|
this pane. Their status may appear under a separate **observed only** heading in
|
|
the opened footer menu, with provider and session label, but those rows do not
|
|
accept selection and never imply that the composer can steer them. Observation
|
|
and control can share a menu only when the boundary is visible in words and in
|
|
behavior.
|
|
|
|
[Agent presence](05-agent-presence.md) owns the collector contract, provider
|
|
health, activity heuristics, and the future path toward one session service.
|
|
This chapter owns only how that projection enters the conversation surface.
|
|
|
|
The Panel eventually needs richer active-agent status: substrate reachability,
|
|
conversation attachment, primary/subconscious phase, queued interjections, and
|
|
the last terminal event. Those facts belong to the Souveraine connection, not
|
|
to heuristics over terminal processes.
|
|
|
|
## A transcript is typed
|
|
|
|
The substrate emits typed segments. The Panel preserves them:
|
|
|
|
- assistant speech is ordinary message content;
|
|
- reasoning is Thinking and renders in `ThinkingCard`;
|
|
- tool invocation and return are one correlated `ToolCard`;
|
|
- interstitial text is visibly provisional rather than final speech;
|
|
- system/interface notices are not forged as the agent's voice.
|
|
|
|
Reasoning may be retained for audit, reflection, and context accounting without
|
|
being replayed to a generic model as `[Reasoning]:` assistant prose. Storage,
|
|
model replay, and visible rendering are three projections of the same typed
|
|
record. None may flatten Thinking into speech merely because a provider lacks a
|
|
native reasoning input block.
|
|
|
|
Tool cards collapse after success, stay open while running or failed, and show
|
|
status without requiring expansion. Their payload is selectable and scrolls
|
|
inside a capped body; a long grep or build result must not be clipped at 240
|
|
pixels or stretch one message across the entire conversation. The inner tool
|
|
body consumes scrolling while it has overflow. Outside it, the transcript
|
|
keeps the wheel.
|
|
|
|
Tool output is evidence. It may be summarized in the header, but the original
|
|
return remains available until transcript retention or compaction explicitly
|
|
changes it.
|
|
|
|
## The itinerary is state, not chat debris
|
|
|
|
`memory/system/dynamic/itinerary.md` is the canonical route. The Panel does not
|
|
parse that file and does not keep a second QML itinerary that dies on reload.
|
|
The authenticated `GET /v1/agents/:id/itinerary` endpoint projects its title,
|
|
current stop, statuses, descriptions, linked todo ids, nature, and energy.
|
|
|
|
An itinerary stream event is an invalidation edge. On set, advance, or clear,
|
|
the service refreshes that projection. Empty is meaningful: it removes the
|
|
ribbon. A shell reload or agent switch asks the substrate again, so current
|
|
work survives the surface without turning surface memory into authority.
|
|
|
|
The compact ribbon shows the title, current stop, phase, progress, and stale
|
|
state. Opening it reveals a bounded scrollable list of stops and the todo
|
|
metadata the substrate supplied. A successful itinerary tool card is hidden
|
|
from the transcript because the persistent ribbon already carries that state;
|
|
an itinerary failure remains visible because failed action is evidence.
|
|
|
|
The itinerary is not the todo ledger. It may reference a todo, but clearing a
|
|
route does not erase a commitment and completing a route does not silently
|
|
invent one.
|
|
|
|
## Conversation life
|
|
|
|
Conversation identity lives on the server. A shell reload may offer the latest
|
|
conversation but must not silently attach it unless the configured policy says
|
|
so. New, resume, list, filter, and fork all act on server conversation ids; a
|
|
local array of bubbles is a projection, never the canonical thread.
|
|
|
|
The complete Panel needs these conversation acts on glass:
|
|
|
|
- a clearly named new conversation;
|
|
- an explicit resume offer with enough metadata to distinguish the thread;
|
|
- a filterable recent-conversation list, with indexed content search as the
|
|
larger corpus demands it;
|
|
- fork from a selected message or turn boundary;
|
|
- visible attachment to a conversation id without exposing token material;
|
|
- honest recovery when the shell reattaches to an active stream.
|
|
|
|
The current adapter carries server resume and active-stream reattachment. The
|
|
footer conversation menu now exposes new, continue, recent-thread browsing,
|
|
and a local id/date filter. Indexed content search and fork remain parity work
|
|
until their owned Panel components and server paths are connected. A slash
|
|
command is not the finished interaction merely because it reaches the same
|
|
function.
|
|
|
|
## Composer and input
|
|
|
|
Send creates a user turn only when no turn is active. During a turn the same
|
|
space must make cancel and queued interjection legible rather than accepting
|
|
text whose delivery phase is unknowable. `202 Accepted` for an interjection
|
|
means queued, not read; the surface keeps that distinction until the next
|
|
round boundary or terminal event.
|
|
|
|
Paste and attachment parity requires a typed input envelope: text, image or
|
|
file identity, media type, size, provenance, and any transformation performed
|
|
before send. The substrate HTTP boundary, provider path, persistence, and TUI
|
|
now accept image blocks. The Panel does not: its QML request still sends a
|
|
plain string and transcript restore reduces an image to `[image]`. A filename
|
|
chip connected only to the old Gemini path is not Souveraine multimodality.
|
|
|
|
Keyboard, touch, and pointer must all reach the same acts. Focus returns to the
|
|
composer after a menu choice; Page Up and Page Down move the transcript; tool
|
|
payload scrolling and text selection do not accidentally send or collapse a
|
|
card. Small icon-only hit targets need tooltips and at least the shell's normal
|
|
touch target.
|
|
|
|
## Command surface audit, 2026-08-17
|
|
|
|
The borrowed composer still advertises illogical-impulse commands. A command
|
|
name surviving in `AiChat.qml` does not mean Souveraine implements the act.
|
|
|
|
| Command | Current truth | Panel direction |
|
|
|---|---|---|
|
|
| `/agent` | real: selects from `/v1/agents`, guarded while a turn runs | keep as the textual form of the footer agent control |
|
|
| `/resume` | real for the selected agent's latest thread; the footer menu also lists and loads recent ids | keep, add `/resume <id>` only if it uses the existing server load path |
|
|
| `/new` | real: clears the projection and detaches so the next send creates a server conversation | keep; the footer conversation control is the discoverable form |
|
|
| `/attach` | stale refusal: image blocks now cross the substrate; QML still sends only text and restores images as a marker | wire a typed image envelope, preview/removal, capability refusal, and image restore |
|
|
| `/btw` | absent in the Panel; the server already exposes conversation fork and the TUI owns the fork lifecycle | build a separate fork stream and bounded visual overlay with dismiss and jump |
|
|
| `/model` | aliases `/agent`; the objects called models are Souveraine agents | remove the alias until a real per-agent model inspection/change API exists |
|
|
| `/tool` | fixed fake vocabulary of one and an explanatory refusal | remove; tools are an agent sensorium, not a composer mode |
|
|
| `/prompt` | prints ownership advice; no prompt files or mutation path are connected | remove as a setter; a future inspector must read the composed server fact |
|
|
| `/key` | prints auth advice and never reads or writes a key | remove; credentials need a secure settings/auth path |
|
|
| `/save` | writes a local JSON bubble snapshot that drops typed segment fidelity | rename as export only if kept; it is not conversation persistence |
|
|
| `/load` | restores that local projection, then starts a fresh live thread on send | remove from the live-thread vocabulary; server resume is the honest act |
|
|
| `/temp` | prints advice because temperature is agent configuration | remove until a typed settings path exists |
|
|
| `/test` | injects a development markdown fixture into the transcript | keep behind development tooling, not in the shipped command list |
|
|
|
|
The short implementation order is attachment, command pruning, then `/btw`.
|
|
Attachment is no longer a substrate project: the missing work is the Panel's
|
|
typed send and render path. Command pruning makes every advertised act true.
|
|
`/btw` is larger because it introduces a second concurrent conversation
|
|
projection; it needs its overlay before the verb is exposed.
|
|
|
|
Ordinary typing during a running turn remains an **interjection** into that
|
|
turn. It is queued and read at a round boundary. `/btw` is a **fork** with its
|
|
own conversation id and stream. Those gestures may look adjacent at the
|
|
composer and must never share state or wording.
|
|
|
|
## Context, reflection, and parity
|
|
|
|
Feature parity means parity with Souveraine's domain, not a pixel copy of the
|
|
TUI and not inherited buttons from ii. Both surfaces should be able to expose:
|
|
|
|
- actual used tokens, model limit, and pressure as separate values;
|
|
- the memory budget and the compaction that changed it;
|
|
- primary completion followed by subconscious activity;
|
|
- reflection/audit records without leaking them into agent speech;
|
|
- the current itinerary and commitment links;
|
|
- correlated tool calls, returns, duration, and failure;
|
|
- server health, cancellation, interjection, and reconnection;
|
|
- conversation creation, discovery, resume, and fork;
|
|
- typed multimodal inputs once the substrate owns them.
|
|
|
|
These may open as drawers, menus, expanded cards, or a dedicated secondary
|
|
Panel. They must consume the same server facts. The TUI is useful evidence of a
|
|
working domain action; it is not a second specification and its screen-local
|
|
state does not become the QML contract.
|
|
|
|
## Ownership migration
|
|
|
|
The borrowed `AiChat.qml` currently owns list lifecycle, focus, and composer
|
|
geometry. Souveraine-owned `AgentMessage`, `ThinkingCard`, `ToolCard`,
|
|
`AgentPaneMenu`, and `ItineraryRibbon` already own the semantics drawn inside
|
|
it. The next structural cut is an owned Panel host and conversation viewport
|
|
that consume the same service without copying the adapter's state.
|
|
|
|
Moving the Panel out of the resident shell is a separate lifetime boundary,
|
|
not a reason to fork its conversation model. [Surface lifetimes](06-surface-lifetimes.md)
|
|
owns that extraction and its memory/fault proof.
|
|
|
|
That cut should be rehearsed beside the live pane, then swapped once. A QML
|
|
write-reload loop over the only working chat surface turns each syntax fault
|
|
into a session-wide interruption and can abandon a live turn. Candidate and
|
|
live panes may share a server and a conversation only if one is read-only;
|
|
they must never become concurrent writers disguised as visual testing.
|
|
|
|
## Proof boundary
|
|
|
|
Panel work has distinct proof layers:
|
|
|
|
1. Source: Rust formatting, QML parsing, lint, manifest coverage, and focused
|
|
projection tests are clean.
|
|
2. CI: Gitea compiles and tests the Rust/QML package path on ArchDev and emits
|
|
the versioned artifact.
|
|
3. Installed: the package or development compose points at the intended source
|
|
revision and QuickShell loads it without binding or component errors.
|
|
4. On glass: the footer menu controls only Souveraine agents; observer rows are
|
|
inert; a long tool body scrolls; set/advance/clear updates the ribbon; a
|
|
failed itinerary remains in chat; switching, resume, cancel, and interject
|
|
have the states their labels claim.
|
|
|
|
A parsed QML file is not on-glass proof. A green Rust job is not an installed
|
|
surface. A hot reload that leaves the previous pane drawn is not success. Keep
|
|
those borders sharp; the Panel is where hidden ambiguity becomes something
|
|
Casey has to touch.
|