The inner struct that holds agent-specific state (history, runtime,
backend, tools, hooks) is now called Agent — because that's what it
is. A session owns an Agent; the Agent performs reasoning within
the session's environment.
Extend the core session with fields that are genuinely session
concerns currently duplicated in 9p/session:
- Plan (markdown checklist, survives compaction)
- PrevPrompt (last submitted prompt text)
- Peers (bidirectional session links)
The 9p/session layer can delegate to these in a future change.
Move agent-specific fields into a nested 'reasoning' struct:
- history, runtime, cfg (per-turn params)
- agentName, agentsDir
- baseLayers, promptEnvExtra
- newDispatcher, newBackend
- currentAction, warnedContext, resultCache
The agent struct is now the session host (owns sess + reasoning).
On /agent swap, a new reasoning can be built from the new config
while the session (identity, state, bus, env) remains stable.
The agent struct receiver was historically 's' (from when it was
called 'session'). Now that session is a separate concept, rename
to 'a' to match the type name.
Defines Session (ID, CWD, state, env, bus, FIFO) as the runtime
environment that hosts an agent. This is the foundation for separating
session concerns from agent reasoning concerns.
The Session type in agent/ is purely a conversation accumulator
(message history, token tracking, compaction state). Rename it to
History to free up 'Session' for the runtime environment concept
in the upcoming agent/session split.
- Client sends OLLIE_SESSION_ID in the request JSON payload
- Broker denies requests with no session identity
- Broker denies requests for sessions that don't exist
- Remove dead SO_PEERCRED logic (client is same process, useless)
- Remove allow-unknown bypass from checkTurnLimit
Adds a per-session burst counter that limits elevation requests to 3
per agent turn. Resets on the next user prompt submission.
Rate-limited requests get a distinct error message:
elevate-broker: rate-limited (max 3 per turn)
This guards against runaway agents flooding the notification daemon
(D-Bus is the least robust transport for this).
- executeElevated: add 3-way select (frameCh/ctx.Done/detachCh) so manual
detach works for elevated processes. Previously the default branch called
readFrames synchronously with no way to receive the detach signal.
- README: replace execute_code references with shell, update tool description
to match current single-command interface.
- Add WatchAgent constant to WaitChange fields
- Add WatchAgent case in WaitChange read() function
- Call notifyChange() in /agent command after setting agentName
This enables the D-Bus adapter to detect agent changes and emit
ConfigChanged signals so the GUI can refresh the session list.
Ensures every Server created by the dispatcher factory has registries
wired at construction time, fixing intermittent 'no session registry'
errors from tool_load/skill_load.
Previously, the Output callback set state to 'thinking' on every tool
event (including streaming chunks), so the state flickered immediately
away from 'calling:'. Now:
- Tool events no longer trigger setState('thinking')
- The loop emits a 'state' event with 'thinking' at the top of each
iteration (before calling the backend), which is the correct time
to transition.
- New 'state' event role in Output callback for explicit state transitions.
This keeps the detach button visible in the GUI during tool execution.
Re-adds the detach boolean to the shell tool args. When true, the
process is immediately backgrounded and its PID returned. This was
removed in the simplification commit 2c36c02 but is needed for
long-running commands (builds, servers, etc).
The elevation broker protocol doesn't support stdin piping.
When a promoted tool runs elevated, wrap the command as:
cat <<'OLLIE_EOF' | /path/to/tool
{json}
OLLIE_EOF
This ensures elevated tools receive their JSON args.
- callPromotedTool now pipes raw JSON object to tool stdin instead of
unpacking positional args. Tools parse their own input.
- Default schema changed from positional array to empty object.
- Registry.Discover() skips files without ollie:prompt marker.
- Registry.Summaries() and Loaded() return sorted results (both
tools and skills registries).
New method on the Core interface that appends a lightweight user
message to session history without triggering a model turn. The
agent sees the reaction as context on its next turn.
Used by the 9P react file: echo emoji > s/{id}/react
When tool results are streamed, suffixes appended after execution
(truncation hints, user-interruptions, PostTool context) were only
written to the stored message history but never emitted to the chat
stream. This meant they never appeared in D-Bus signals or the chat
file.
Accumulate suffixes explicitly and emit them as a final event when
streaming was active, guaranteeing they appear at the end of the
tool output in all output paths.
The tool result truncation had two bypasses:
1. Error results were exempt (!isErr condition) — a command returning
output in its error message could flood the context with megabytes
of untruncated data.
2. The streaming callback emitted chunks to the event handler (and
thus D-Bus signals) with no size check, flooding the bus even
when the final stored result would be truncated.
Fix:
- Remove the configurable ToolResultMaxBytes field; use the constant
defaultToolResultMaxBytes (128KB) unconditionally for all results
regardless of success/error status.
- Cap the streaming callback at 128KB so chunks stop being emitted
once the ceiling is reached.
- Cap output embedded in execute server error messages to 8KB as
defense in depth.