server: remove statewait file, use event stream instead

The event stream with filtering replaces statewait:
- echo filter | rdwrs event

Removed:
- statewait file from agent namespace
- All non-historical references in docs and code

The state file remains for simple polling reads.
This commit is contained in:
Levi Neely 2026-10-06 12:44:02 +02:00
parent 7e7c29c900
commit 86fbc90b43
11 changed files with 17 additions and 21 deletions

View File

@ -69,7 +69,8 @@ session/
├── cfg configuration
├── ctl control commands
├── state current state
├── statewait block until state changes
├── state current state (idle, calling, thinking, paused)
├── status human-readable status
├── prompt submit a prompt
├── peer/ write to peer/{name} to message a peer agent
├── chat conversation history
@ -106,7 +107,7 @@ Persistent memory is provided by [OptMem](https://github.com/VictorTaelin/OptMem
## Frontends
Shell scripts, Acme, KDE components, and other clients create sessions, write prompts, and read files such as `chat`, `statewait`, `context`, and `feed`. They do not embed provider, tool, or agent-loop logic.
Shell scripts, KDE components, and other clients create sessions, write prompts, and read files such as `chat`, `state`, and `feed`. They subscribe to state changes via the `event` stream. They do not embed provider, tool, or agent-loop logic.
See [`doc/architecture-ide.md`](doc/architecture-ide.md) for integrating Ollie with an editor or IDE.

View File

@ -2,7 +2,7 @@
//
// The agent state tracks execution progress: idle, running, completed, error.
// WaitChange blocks until a field changes, enabling 9P clients to observe
// state transitions via statewait.
// state transitions via the event stream.
package agent

View File

@ -27,13 +27,14 @@
//
// prompt - submit prompt (write)
// chat - conversation history (streaming read)
// statewait - block until state changes
// state - current agent state
// status - human-readable status
// plan - agent's plan (survives compaction)
// ctl - agent control commands
//
// # Blocking Reads
//
// Files like statewait and event block until their condition is met.
// Files like event block until their condition is met.
// This is the primary coordination mechanism — clients read these files
// in a loop to react to state changes.
//

View File

@ -883,13 +883,6 @@ func buildAgentChildren(a *agent.Agent, s *session.Session) []virtfs.FsNodeDecl
return []byte(a.State() + "\n"), nil
}),
),
virtfs.FileNode("statewait", 0444,
virtfs.Doc("Blocks until state changes; returns new value"),
virtfs.BlockOnce(func() ([]byte, string, error) {
st := a.State()
return []byte(st + "\n"), st, nil
}, a.SignalCh),
),
virtfs.FileNode("status", 0444,
virtfs.Doc("Human-readable status: current activity and elapsed time"),
virtfs.Read(func() ([]byte, error) {

View File

@ -191,7 +191,7 @@ Use `client_9p` for all 9P operations. Your session ID is `${OLLIE_SESSION_ID}`.
| `fifo` | r/w | Prompt queue. Write: enqueue. Read: dequeue. |
| `chat` | read | Conversation (filtered text, streamable) |
| `chat.raw` | read | Full conversation with block markers |
| `statewait` | read | Blocks until state changes; returns new value |
| `state` | r/w | Current state; subscribe via event stream |
| `cfg` | r/w | Agent config (key=value: backend, model, cwd, temperature, etc.) |
| `ctl` | rdwr | Control: stop, compact, clear, inject, agent, model, tools, tool_load, tool_unload, cwd, name, peeradd, peerdel, peers, proc |
| `peer/` | dir | Peer agent links. Write to `peer/{name}` to send a message to that peer. |

View File

@ -90,7 +90,7 @@ echo "name=coding cwd=$PWD" | ollie-9p write session/myproj/agent/new
| `agent/{aname}/feed` | r/w | Change-detecting input stream. |
| `agent/{aname}/chat` | r | Filtered streaming chat output. |
| `agent/{aname}/chat.raw` | r | Full streaming output with markers. |
| `agent/{aname}/statewait` | r | Blocking state-change read. |
| `agent/{aname}/state` | r | Current agent state (idle, calling, thinking, paused). |
| `agent/{aname}/log` | r | Conversation snapshot. |
| `agent/{aname}/plan` | r/w | Persistent planning scratch space. |
| `agent/{aname}/cfg` | r/w | Agent configuration. |

View File

@ -9,7 +9,8 @@ editor or IDE
├─ file, selection, cursor, project, or diff
└─ 9P client → agent/.../prompt
├─ chat / chat.raw
├─ statewait
├─ state
├─ status
└─ ctl
```
@ -49,7 +50,7 @@ The editor does not need to display agent output or reload files itself. Use the
| Operation | 9P integration |
|---|---|
| Explain file or selection | Write a read-only prompt; read `chat`. |
| Fix, refactor, document, or add tests | Write a mutating prompt; read `statewait`; reload the buffer. |
| Fix, refactor, document, or add tests | Write a mutating prompt; subscribe to state events; reload the buffer on completion. |
| Review a diff | Send the diff as fenced `diff` context. |
| Inline completion | Send a bounded prefix/suffix request to root `generate`. |
| Agent control | Write a command to `ctl`. |

View File

@ -22,7 +22,7 @@ flowchart TB
The daemon constructs an `fs.Tree`. The tree is the session collection; there is no separate manager abstraction. Session operations are package functions over the tree. A session owns its agents, context, cancellation, and lifecycle. An agent owns history and runs the model/tool loop.
The daemon exposes the 9P namespace directly. Reads and writes are the protocol: writing `session/new` creates a session, writing an agent's `prompt` submits work, reading `chat` observes history, and reading `statewait` blocks until a state transition.
The daemon exposes the 9P namespace directly. Reads and writes are the protocol: writing `session/new` creates a session, writing an agent's `prompt` submits work, reading `chat` observes history, and subscribing to the `event` stream monitors state transitions.
### Agent loop
@ -43,7 +43,7 @@ Ollie deliberately does not build the following into the agent runtime:
- **Native MCP client support.** Use executable or metadata-only tools. An external bridge can invoke an MCP client when required.
- **Embedded tool frameworks.** Tools live outside the agent loop; toolsrv owns discovery, loading, execution, sandboxing, and process state. See [`architecture-tools.md`](architecture-tools.md) and [`architecture-toolsrv.md`](architecture-toolsrv.md).
- **Plan-and-execute workflow engines.** Ollie does not own planners, task graphs, schedulers, retries, compensation, or durable workflow state. A system such as [Beads](https://github.com/steveyegge/beads) can expose those capabilities through a tool.
- **External coordination protocols.** Ollie does not expose a workflow engine, actor framework, master coordinator, or public message bus. It does have an internal session event bus for observers. Inter-agent communication uses peer links (`peer/` directory) for topology-controlled messaging within a session. External coordination uses sessions, agents, `prompt`, `chat`, `statewait`, `feed`, and `ctl`.
- **External coordination protocols.** Ollie does not expose a workflow engine, actor framework, master coordinator, or public message bus. It does have an internal session event bus for observers. Inter-agent communication uses peer links (`peer/` directory) for topology-controlled messaging within a session. External coordination uses sessions, agents, `prompt`, `chat`, `event`, `feed`, and `ctl`.
- **Separate frontend control planes.** UIs, editor integrations, shell clients, and automation are 9P clients. They do not maintain a parallel session store or frontend-specific API. See [`architecture-9p.md`](architecture-9p.md).
- **Distributed agent state.** Remote execution moves toolsrv and tool execution, not the agent loop, prompts, history, or model calls. See [`architecture-remote.md`](architecture-remote.md).
- **A competing memory store.** [OptMem](https://github.com/VictorTaelin/OptMem) owns persistent memory; Ollie exposes it through tools.

View File

@ -45,7 +45,7 @@ public:
bool mkdir(const QString &path);
bool rename(const QString &oldPath, const QString &newName);
// Streaming API - for continuous reads (chat, statewait, etc.)
// Streaming API - for continuous reads (chat, event, etc.)
int open(const QString &path); // Returns fid handle, -1 on error
int readFid(int fid, char *buf, int bufLen); // Returns bytes read, 0 on EOF, -1 on error
void closeFid(int fid);

View File

@ -70,7 +70,7 @@ void Lib9pStreamer::Worker::run()
return;
}
if (n == 0) {
// EOF — normal for statewait/event after returning data
// EOF — normal for event stream after returning data
emit finished(true, QString());
return;
}

View File

@ -64,7 +64,7 @@ void Ollie9pClient::setActiveSessionId(const QString &id)
qDebug() << "setActiveSessionId" << id << "prev session" << m_activeSessionId << "prev agent" << m_agentId;
// Session selection must be side-effect free for per-agent streams.
// Even re-selecting the same session should clear agent selection and stop
// statewait/chat so the UI can stay in a pure "session selected" state.
// chat so the UI can stay in a pure "session selected" state.
stopStreams();
m_activeSessionId = id;
m_agentId.clear();