Commit Graph

54 Commits

Author SHA1 Message Date
Ollie Agent a4972cd456 Separate chat persistence from live delivery via chat.raw
Streaming partials were appended to log.raw per chunk, each carrying the
full cumulative content, so one response left dozens of partial lines
persisted. GUI clients parsing the snapshot re-rendered the growing block
once per partial (O(N^2)) and replayed all historical partials on every
reconnect, causing intermittent rendering loops.

Partials are no longer persisted: AppendBlock writes only finalized
blocks to log.raw; SetPartial broadcasts the in-flight block without
storing it. New chat.raw StreamRaw file is the authoritative live JSONL
source (finalized history replay, then live deltas); log.raw is a
finalized-only one-shot snapshot. GUI streams chat.raw, never polls
log.raw.
2026-10-10 15:57:48 +02:00
Levi Neely 57c40d541e Migrate chat log to JSONL format
Server changes:
- format/block.go: Block struct with JSONL marshaling, RenderBlock for text
- Deleted format/event.go, format.go, format_test.go (old delimiter format)
- agent/chat.go: Dual logs (rawLog JSONL + textLog rendered text)
- agent/chatlog.go: Streaming via flushPartial/closeBlock, skip internal events
- fs/spec.go: New files log.raw (JSONL), log (text), block (ID lookup)
- Removed chat/chat.raw/chat.search from namespace

GUI changes:
- chatblockmodel: JSONL parsing via QJsonDocument, removed regex state machine
- ollie9pclient: Read from log.raw for replay, removed old streaming code
- Added Context type to block enum, filter context/state/usage from display

Docs updated: AGENTS.md, system_prompt.md, architecture-*.md, scripts/o
2026-10-09 18:52:40 +02:00
Levi Neely c186c87525 Use sha256-based deterministic block IDs
- NextBlockID now uses sha256(sessionID:agentID:counter)[:8] for deterministic,
  collision-resistant block IDs across sessions and agents
- Remove blockCounter reset on Clear() to maintain ID stability
2026-10-09 17:01:22 +02:00
Levi Neely 582f7d1b91 event: emit clear event when agent is cleared
- Add onClear callback to Agent, wired via support.go
- Publish session.{sid}.agent.{aid}.clear event
- GUI listens for agentCleared signal and refreshes chat view
- Works for both GUI clear button and CLI /clear command
2026-10-09 16:31:30 +02:00
Levi Neely 1c863ce9ec gui: add Clear button next to Compact
- Clear button sends /clear command
- /clear now resets history, chat log, and block counter
- Completely fresh start without creating a new session
- Button disabled while agent is running
2026-10-09 16:28:28 +02:00
Levi Neely 46aa901763 server-side block IDs for stable bookmark/plumb targets
- Add blockCounter to Agent, generating sequential hex IDs
- Include #blockId in all block headers: [[[role:name#id]]]
- GUI parses server-provided IDs from headers
- Falls back to client-generated IDs for legacy blocks without server IDs
- Block IDs are now deterministic based on chat history order
2026-10-09 16:12:26 +02:00
Levi Neely f7a52088db per-agent cwd override with session-level inheritance
- Agent cwd is optional; empty = inherit session cwd (the common case)
- Session cwd is required at creation and is the inheritance root
- toolsrv maintains agentCWD map, resolved per call from agent= field
- Override set via agent cfg (cwd=...) or ctl (cwd [<dir>|-])
- Agent.SyncCwdToToolServer re-pushes on every (re)connect
- GUI NewAgentDialog shows '(inherit: <sessionCwd>)' as placeholder
- proc_test.go covers per-agent cwd isolation
- Kate and acme scripts updated for new session/agent creation flow
- AGENTS.md documents the architecture
2026-10-07 15:14:04 +02:00
Levi Neely 1c02b50add proc events, bypass shortcuts, Kate session fix
Backend:
- Add proc.start/proc.exit events for background process lifecycle
- Add proc idx ctl command for machine-readable process listing (TSV)
- Add event.pub file for external event publishing
- Add ListProcsIdx to toolclient and toolsrv
- Fix bypass commands to use Setpgid for process group isolation

GUI:
- Add configurable bypass approval shortcuts (Ctrl+Y/Ctrl+N default)
- Add Keyboard Shortcuts section to Settings dialog
- Store shortcuts in theme.conf

Kate:
- Fix 'Start Session Here' - use rdwr for session/new endpoint
2026-10-07 14:22:44 +02:00
Levi Neely a90ca6b57c remove unused feed file and observer agent support
The feed file was documented but never used by any frontend
or script. The observer agent pattern was never adopted.

- Remove feed.go, FeedWrite, ConsumeFeed
- Remove WatchFeed constant
- Remove feed file from 9P namespace
- Remove ConsumeFeed goroutine spawns from session
- Update docs (architecture-9p, architecture-ide, architecture, usage)

The event stream now covers real-time observation patterns better.
2026-10-06 12:55:39 +02:00
Ollie Agent 42cae9ee2e human-friendliness: self-describing ctl, structured errors, status, overview
Make the namespace explain itself instead of requiring prior knowledge.

- ctl is self-describing: reading it (empty write) or writing 'help'
  returns the valid verbs with one-line descriptions; an unknown verb
  errors with the valid list. Refactor dispatch to an ordered []ctlCmd
  carrying descriptions; drop the undocumented '.' alias and the
  drift-prone hardcoded help verb. Keep 'i' (drop 'inject') for fast
  injects. o's ctl usage now reads the live listing.
- Errors carry severity + remediation. backend.ClassifyError maps the
  typed errors to transient/config/fatal with a one-line fix; the error
  event renders [[[error:<severity>]]] and a 'remediation:' line so a
  human knows whether to wait or intervene.
- Add a human status file: 'thinking · 12s', 'calling shell · 3s',
  'idle' — distinct from the machine-facing raw state. Wire the TUI bar
  to it.
- Bare 'o' shows an overview of running sessions/agents with status, so
  you don't need to know any names to get oriented.

Tests: dispatch help/unknown/routing, ClassifyError severity table.
2026-09-07 13:55:45 +02:00
Levi Neely c8ccc2c450 add CONTRIBUTING.md; document Agent struct fields
- CONTRIBUTING.md: development workflow, code style, testing, conventions
- agent.go: add comments to warnedContext, resultCache, chatLog, chatStart,
  chatVers, chatCond, chatSignalCh, plan
2026-08-27 10:13:24 +02:00
Levi Neely 9b7de31a07 add doc.go files; decompose agent package
doc.go:
- agent, backend, session, fs, bypass, toolclient (olliesrv)
- server, sandbox, registry (toolsrv)
- protocol, metadata (toolsrv shared)
- log, util, skills

agent package decomposition:
- chat.go: chat log, streaming, plan methods
- state.go: State, Reply, WaitChange, SignalCh, emit
- peer.go: AddPeer, RemovePeer, Peers
- subagent.go: Depth, IncChildren, DecChildren, ActiveChildren
- agent.go: 881 → 638 lines (core struct, identity, backend, runtime)
2026-08-27 10:03:58 +02:00
Levi Neely 2b59409845 refactor: remove dead code across packages (-220 lines)
Dead code removal based on code review:

fs/spec.go:
- Remove unused Perm* constant aliases

fs/support.go:
- Remove unused agentCwd() function

session/registry.go:
- Remove unused CreateAgent() (callers use CreateAgentWithParams directly)

session/session.go:
- Remove unused sweepStaleTmpDirs() and sweepTmpOnce
- Remove unused Session.LoadTool() (callers use LoadToolOnConn directly)
- Simplify Resume() by removing dead else branch (Pause() always nils Keeper)

toolsrv/server/proc.go:
- Remove unused globalProcCounter
- Remove unused ListProcsWithState()

toolsrv/server/server.go:
- Remove unused Mode* constants

toolsrv/bypass/bypass.go:
- Remove unused PendingCount()

toolsrv/sandbox/config.go:
- Remove unused checkPath() and pathUnder()

backend/new.go:
- Remove unused newBackend() (callers use NewWithName)

agent/loop.go:
- Remove unused contextBudget()

agent/agent.go + turn.go + runtime.go:
- Remove unused startupMessages, StartupMsgs, Runtime.Messages

agent/agent_config.go:
- Remove unused Tools *bool field and ToolsEnabled() (tools always enabled)
2026-08-21 16:41:42 +02:00
Levi Neely 8960fb73fd feat: refresh autoLoad tools on agent profile switch
When the 'agent <profile>' ctl command switches profiles, the tool
registry now clears old tools and loads the new profile's autoLoad
list. Previously, switching profiles left the old tools loaded.

Changes:
- registry: add ClearAgent(agentID) to remove all tools for an agent
- server/proc: add ClearAgent wrapper and 'clear <agentID>' ctl command
- toolclient: add ClearTools() method to ToolsrvConn
- agent: SwitchProfile now returns *AgentConfig for tool reload
- fs/spec: agent ctl handler clears and reloads tools after switch
2026-08-21 10:57:59 +02:00
Ollie Agent 19971be343 Support runtime backend switching via ctl 2026-08-19 20:06:20 +02:00
Levi Neely 7055444748 agent peers: bidirectional peer links with topology-controlled messaging
Add peer/ directory to each agent's 9P namespace. Agents communicate
by writing to peer/{name}, which delivers to the target's prompt handler.
Only declared peers can be messaged — the directory is the ACL.

Implementation:
- Agent struct: peers map + AddPeer/RemovePeer/Peers methods
- fs/spec.go: peer/ Each node (write-only entries), peeradd/peerdel/peers ctl commands
- Bidirectional: peeradd A on B also adds B on A
- Peers constrained to same session
- Persisted with session state (PersistedAgent.Peers field)
- peeradd/peerdel trigger immediate session save

Docs updated: system_prompt.md, AGENTS.md, README.md, architecture-9p.md,
architecture-core.md, architecture.md, usage.md.
2026-08-19 17:22:30 +02:00
Ollie Agent af478550a9 Wake OptMem before restored session turns 2026-08-18 14:04:27 +02:00
Ollie Agent c6d9b4aa23 Bound agent prompt queues 2026-08-18 06:58:38 +02:00
Ollie Agent e01d578303 Bound agent chat and summary caches 2026-08-18 06:57:15 +02:00
Ollie Agent 6c1de81cf9 Bound agent result cache 2026-08-18 06:55:25 +02:00
Ollie Agent 16bf2115fa Cancel active agent work during shutdown 2026-08-17 17:57:14 +02:00
Ollie Agent 2352f2483a Close feed consumer resources 2026-08-17 17:42:30 +02:00
Levi Neely 958d3d2ddf workflows: script-based workflows with session-level CWD
- Workflows are executable scripts in data/workflows/
- New 'workflows' 9P file lists available workflows
- Goal file stores text; writing triggers workflow if status allows
- goalstatus file for status read/write, goalwait for blocking
- Session ctl accepts 'run [workflow]' command
- Session now owns CWD; agents inherit via callback
- Conductor workflow: creates agent, primes with instructions, exits
- GUI workflow combo reads from workflows, not agents
- Persistence includes goal, goalstatus, workflow, and session CWD
2026-08-17 12:00:10 +02:00
Levi Neely da0ee4456f sub-agent guardrails: depth, parallelism, timeout
Enforce three limits on sub-agent spawning:
- depth (default 1): sub-agents cannot spawn their own sub-agents
- parallelism (default unlimited): cap concurrent children per parent
- timeout (default 600s): sub-agents are killed after 10 minutes

Top-level agents are never constrained by timeout.

Also: refactored parseAgentNewRequest to return a struct instead of
4 positional values. Added depth/activeChildren fields to Agent.
OLLIE_SUBAGENT_DEPTH env var set on sub-agents.

Deferred: remove maxSteps (replace entirely with timeout).
2026-08-17 09:37:59 +02:00
Ollie Agent e51a1d4ff7 Update architecture documentation and remove obsolete frontends 2026-08-16 19:21:26 +02:00
Ollie Agent 57aa906e5f move toolsrv client into olliesrv 2026-08-16 19:07:25 +02:00
Ollie Agent b321eed99f use 9fans client directly 2026-08-16 19:00:48 +02:00
Ollie Agent 16a2b72051 consolidate 9P clients 2026-08-16 18:56:11 +02:00
Ollie Agent 59c4ed23ac merge paths utilities into util 2026-08-16 18:37:03 +02:00
Ollie Agent 81933e5281 refactor toolsrv into client protocol and metadata packages 2026-08-16 17:22:59 +02:00
Ollie Agent 72209239b0 Add parent IDs for sub-agents 2026-08-16 11:44:06 +02:00
Ollie Agent 8553bc7283 measure provider prompt cache hits 2026-08-15 14:09:00 +02:00
Levi Neely c61fada3e9 extract rebuildAgentRuntime, remove nil guards on things that must not be nil 2026-08-14 08:47:59 +02:00
Levi Neely 785fe0996f fix: rebuild full agent runtime on session resume
Paused sessions restored agents with stub Runtime (nil Backend,
nil Preamble). On resume, now rebuilds the complete runtime:
loads config, builds preamble, creates backend, loads tools.
Added Agent.SetRuntime for this path.
2026-08-14 08:45:54 +02:00
Levi Neely 9246c44c0e agent: remove proc/detach/tool wrapper methods — inline in ctl handler
Removed from Agent: ListProcs, SignalProc, ProcOutput, DismissProc,
Detach, ListDetached, SignalDetached, GetDetachedOutput,
DismissDetached, BgProc type, DetachedInfo type.

The ctl handler now calls toolsrv client methods directly.
RefreshTools replaced by SetToolsPreamble + inline ListTools call.
renderTools exported as RenderTools.
2026-08-13 22:14:37 +02:00
Levi Neely dcd119c853 virtfs: refactor Stream to accept (readFn, signalFn)
Same pattern as BlockOnce: framework handles the blocking loop.
readFn takes a base string, returns (data, nextBase, error).
signal fires when new data may be available.

Chat stream handlers now use Stream(a.ChatRead, a.ChatSignal).
StreamRaw retained for custom handlers.

streamChat() in support.go is now dead code (replaced by ChatRead).
2026-08-13 20:50:27 +02:00
Levi Neely 794673a5d0 virtfs: refactor BlockOnce to accept (readFn, signalFn)
BlockOnce now takes a value-reader and a signal source. The framework
handles the blocking loop: read → compare hash to base → if different
return → else wait on signal or timeout.

On timeout (ctx.Done), returns empty (not error) so clients re-open
cleanly.

BlockOnceRaw retained for queue-style handlers (bypass/pending,
proc/wait) that manage their own blocking.

EventValue adapter wraps a <-chan Event into BlockOnce-compatible
(readFn, signalFn) pair via a thin goroutine.
2026-08-13 20:44:50 +02:00
Levi Neely b5cb8c397d feed: BlockOnce with base init, ConsumeFeed via lib9p client
- BlockOnce handler initializes base to current hash on fresh open,
  then blocks until hash changes. Same pattern as statewait.
- ConsumeFeed is a plain function: dials 9P, reads feed in a loop
  (open → block → data → close → repeat), submits to agent.
- Context cancellation closes the 9P client, unblocking Read().
- Called as go ConsumeFeed(ctx, ag) from AddAgent and session resume.
2026-08-13 20:26:08 +02:00
Levi Neely e2695d6f50 feed: export Feed field, remove wrapper methods, use direct access everywhere 2026-08-13 20:09:28 +02:00
Levi Neely 1537e35685 feed: inline handlers, remove FeedBlockingRead wrapper 2026-08-13 20:06:32 +02:00
Levi Neely 721b49ffa2 feed: use BlockOnce for read side, dedup via base comparison
Feed is now read-write (0666):
- Write: store data, signal via notifyChange
- Read (BlockOnce): block until content hash differs from base

Dedup lives in the read layer (same pattern as statewait). The
internal consumer goroutine and external 9P clients both call
FeedBlockingRead — same codepath, same dedup logic.

Consumer started from AddAgent (if ctx available) and session resume.
2026-08-13 20:05:46 +02:00
Levi Neely dfacdfed94 agent: add feed file — change-detecting streaming input gate
Feed is a write-only file in the agent namespace. Writes are
deduplicated against the previous value; the internal consumer
(blocking on WaitChange/WatchFeed) only wakes when genuinely new
data arrives.

Wiring is external and source-agnostic:
  # human → observer (poll git):
  while :; do git diff HEAD; sleep 5; done | ollie-9p write .../feed
  # agent → observer (stream chat):
  ollie-9p read .../coder/chat | ollie-9p write .../observer/feed

Uses the agent's existing signalCh/notifyChange plumbing — no new
channel infrastructure. Consumer goroutine spawned at agent creation
(AddAgent) and session resume, tied to session context.
2026-08-13 20:02:06 +02:00
Levi Neely bc7f51a9dc refactor: push proc completion from toolsrv to agent prompt
- toolsrv pushes <system-proc-complete> to agent prompt when bg proc exits
- Remove bgTracker and CollectInterrupts from olliesrv
- Add Cmd, AgentID, SessionID fields to Proc
- Add OnProcExit callback to State
- Add command field to Proc.Stat() output
2026-08-12 16:39:43 +02:00
Levi Neely 6eb3bf960b refactor: query toolsrv directly for proc list
- ListProcs() now queries toolsrv directly instead of local tracker
- Remove ownership verification from SignalProc/ProcOutput/DismissProc
- Clean up stale procs from local tracker when they disappear from toolsrv
- Document local tracker quirk in TODO.md for future cleanup
2026-08-12 16:06:22 +02:00
Levi Neely 1d5e9c4f8d fix: background proc output capture and status display
- Detach background proc context from request context so processes survive
  after the 9P request returns (fixes premature SIGTERM)
- Add /proc/list file to toolsrv showing all procs with state
- Show status (running/exited (N)) in agent proc list
- Keep exited procs in tracker until explicitly dismissed
- Skip 'list' entry in ListDetachedRaw
2026-08-12 14:10:08 +02:00
Levi Neely aedfdec564 fix: set agent ID on tool server after /agent switch
SwitchProfile creates a new tool server connection but wasn't calling
SetAgentID on it, causing 'agent ID required' errors when listing tools.
2026-08-12 11:08:37 +02:00
Ollie Agent 47b460b2da fs: eliminate AgentLog, SessionNode, RootState
State now lives where it belongs:
- Chat log/plan/condvar → agent.Agent (new chatlog.go)
- Models cache → session.Session
- Event handler → agent.Agent.initChatHandler() (self-wiring)
- Message replay → agent.Agent.ReplayMessages()

The fs package is now a pure presentation layer: spec.go (namespace),
support.go (shared utils), newroot.go (entry point), cache.go (ModelCache).
No wrapper types, no parallel registries.

Deleted: AgentLog, SessionNode, RootState, lifecycle.go, agent_log.go,
session_node.go. Removed replay_test.go (needs rewrite against agent pkg).
2026-08-11 21:50:18 +02:00
Ollie Agent 31d3466b3b agent: add chat log fields and methods
Moved log buffer, plan, mutex, and condvar onto agent.Agent directly.
These were previously on the fs package's AgentLog type. The fs package
will be migrated to use these in the next commit.

New methods: AppendChat, EnsureTrailingNewline, ChatMu, ChatCond,
ChatLog, Plan, SetPlan.
2026-08-11 21:41:12 +02:00
Ollie Agent de5456e4aa toolsrv: fix per-agent tool registry to actually work
The registry was keyed by agent ID but read it from a shared env map
(st.env["OLLIE_UNAME"]) that all agents overwrote — making it
effectively per-session with a race condition.

Fix: pass agent ID explicitly through the protocol at every call site.

- ctl protocol: 'load <agentID> <tool>', 'unload <agentID> <tool>'
- tools file: rdwr (Request) — write agent ID, read filtered list
- proc/new payload: 'agent=<id>' field required
- Client: SetAgentID() stores identity, included in all operations
- Empty agent ID is a hard error everywhere
- Setting OLLIE_UNAME via env ctl is blocked (prevents reintroduction)
2026-08-11 16:26:12 +02:00
Ollie Agent 686a560e84 agent: toolsrv is sole owner of tool state
Remove all cached tool state from agent:
- Remove toolRegistryRevision from Runtime
- Remove wireToolsChanged (OnToolsChanged callback)
- Remove toolsNeedRefresh (revision-based cache invalidation)
- Remove refreshToolListing (redundant with RefreshTools)

Tools are now fetched fresh from toolsrv at the start of every turn.
The preamble tools section is also rebuilt at turn start. No local
caching means tool_load/unload take effect immediately on the next
turn and /tools always shows the live state from toolsrv.
2026-08-11 10:59:31 +02:00