Commit Graph

388 Commits

Author SHA1 Message Date
Levi Neely 5fdd80c26c Implement workflow variants system
- runWorkflow accepts a variant parameter; sources {workflow}-{variant}.conf
  as env vars before exec'ing the script
- Session stores variant; persisted and restored
- session/new accepts variant= parameter
- 'run' ctl command accepts optional variant as second arg
- workflows file now lists variants: name<TAB>default,variant1,...
- review workflow reads AUTHOR_PROFILE/REVIEWER_PROFILE env vars
- Add review-code.conf and review-writing.conf example variants
2026-08-19 17:57:22 +02:00
Levi Neely 86b5039552 peers: clean up peer links when an agent is killed
RemoveAgent now iterates remaining agents and removes any peer link
pointing to the removed agent's name, preventing stale/corrupt state.
2026-08-19 17:23:27 +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
Levi Neely fa99020667 tools: multicall binaries, sandbox fixes
- Multicall pattern for tool families: one binary per family with
  symlinks for each tool name. Reduces tools dir from 156MB to 31MB.
  codeintel (6 tools), filetools (5 tools), lsptools (7 tools).

- Build with -ldflags="-s -w" to strip debug symbols.

- Fix Landlock EINVAL on regular files: filter directory-only access
  rights (READ_DIR, MAKE_*, REMOVE_*) when adding rules for non-
  directory paths.

- Fix toolsrv CWD initialization: pass --cwd flag value to server
  state at startup so {CWD} in sandbox.yaml expands correctly.
2026-08-19 13:51:52 +02:00
Levi Neely b52643314b fix remote toolsrv spawn: use tools/ path and emit ready on stderr 2026-08-19 12:44:03 +02:00
Levi Neely b4baddd826 Memory tools: never expose raw memo commands to agents
- Add MEMO_TOOLS=1 env var to memo script; when set, all printed
  instructions reference native tool names instead of memo paths
- Set MEMO_TOOLS=1 in all memory tool .meta wrappers
- Add memory_nap tool for compressions
- Add memory_zoom tool for tree navigation
- Add part/T pagination args to memory_wake
- Update system prompt to use memory_zoom tool call
- Fix inject ctl: submit as user message when agent is idle
2026-08-19 10:13:02 +02:00
Levi Neely 9bb2e41e33 Add memory section to system prompt, fix icon resolution
- Add OptMem memory section to system_prompt.md with tool-based API
- Fix KRunner plugin icon: resolve via QStandardPaths instead of theme name
- Fix desktop file icon: use absolute path to bypass stale system icon
2026-08-19 10:02:51 +02:00
Levi Neely 04bef4978c fix tests 2026-08-19 08:50:36 +02:00
Ollie Agent af478550a9 Wake OptMem before restored session turns 2026-08-18 14:04:27 +02:00
Ollie Agent 223a8f1235 remove plumber references 2026-08-18 13:32:43 +02:00
Ollie Agent bf262cba16 manage namespace directory lifecycle 2026-08-18 13:31:52 +02:00
Ollie Agent 7acaebdaaa add generic sandbox interface 2026-08-18 13:22:52 +02:00
Ollie Agent 2ba9ba036c Document native Landlock and persist session yolo 2026-08-18 12:49:25 +02:00
Ollie Agent bdafc30022 replace landrun with native Landlock sandbox 2026-08-18 12:36:27 +02:00
Ollie Agent 45ad8c624e Synchronize toolsrv authentication state 2026-08-18 07:49:59 +02:00
Ollie Agent a8a6bb5204 Complete olliesrv fid synchronization 2026-08-18 07:47:46 +02:00
Ollie Agent cad1c6be9b Synchronize olliesrv fid read state 2026-08-18 07:45:02 +02:00
Ollie Agent 6c476f4fb8 Synchronize toolsrv fid state 2026-08-18 07:41:59 +02:00
Ollie Agent c111cbd0ca Stop persistent loop timers 2026-08-18 07:34:56 +02:00
Ollie Agent e24675b8fa Handle random generation errors 2026-08-18 07:31:52 +02:00
Ollie Agent 2ee9251b5a Clean up toolsrv startup socket failures 2026-08-18 07:29:34 +02:00
Ollie Agent 9bbb6b9152 Make toolsrv socket polling cancellable 2026-08-18 07:27:42 +02:00
Ollie Agent a9f4899ed3 Clean up toolsrv startup errors 2026-08-18 07:22:41 +02:00
Ollie Agent 1b934c43f4 Release empty registry agent state 2026-08-18 07:09:21 +02:00
Ollie Agent 6ef1fe52e0 Make process GC startup idempotent 2026-08-18 07:08:38 +02:00
Ollie Agent a1dc5b990e Bound toolsrv process completion notifications 2026-08-18 07:07:46 +02:00
Ollie Agent 4b86ad94ff Make bypass resolution atomic 2026-08-18 07:04:11 +02:00
Ollie Agent 1284a83b52 Discard cancelled bypass requests 2026-08-18 07:01:48 +02:00
Ollie Agent f41a580dad Tie event subscription to server context 2026-08-18 07:00:31 +02:00
Ollie Agent 7ec8583e06 Honor cancellation during compaction streams 2026-08-18 06:59:35 +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 062642dfd3 Bound parallel tool dispatch 2026-08-18 06:54:48 +02:00
Ollie Agent 6a8e897fa5 Bound asynchronous session work 2026-08-18 06:53:51 +02:00
Ollie Agent 6a4f83b5b2 Bound completed toolsrv process retention 2026-08-18 06:51:43 +02:00
Ollie Agent b6009f0f7a Reserve toolsrv process slots atomically 2026-08-18 06:50:02 +02:00
Ollie Agent 93e7f510b7 Prevent dismissing running processes 2026-08-18 06:45:23 +02:00
Ollie Agent d31d0661bd Drain remote toolsrv stderr until exit 2026-08-18 06:43:14 +02:00
Ollie Agent e24ed79355 Avoid keeper lock during process dialing 2026-08-18 06:41:34 +02:00
Ollie Agent 3c777667ff Fix paused session process lifecycle 2026-08-17 18:31:37 +02:00
Ollie Agent 701e9bcaad Prevent backend stream goroutine leaks 2026-08-17 18:27:35 +02:00
Ollie Agent 49e43248b0 Fix paused session resume lifecycle 2026-08-17 18:23:00 +02:00
Ollie Agent e1136fdb82 Cancel session context during close 2026-08-17 17:59:19 +02:00
Ollie Agent 16bf2115fa Cancel active agent work during shutdown 2026-08-17 17:57:14 +02:00
Ollie Agent 2599ccb4ac Clear stale agent actions on turn exit 2026-08-17 17:52:51 +02:00
Ollie Agent c5a8f18884 Close 9P fids during connection teardown 2026-08-17 17:51:08 +02:00
Ollie Agent 3ad431957c Fix background tool startup signaling 2026-08-17 17:48:23 +02:00
Ollie Agent 4ac3b2135a Reap toolsrv processes on shutdown 2026-08-17 17:45:29 +02:00
Ollie Agent 2352f2483a Close feed consumer resources 2026-08-17 17:42:30 +02:00
Ollie Agent 6131fad5c5 Cancel timed out 9P reads 2026-08-17 17:41:55 +02:00
Ollie Agent c652c562c3 Fix 9P response writer shutdown 2026-08-17 17:39:56 +02:00
Levi Neely 9147fd790a session: expand ~ and env vars in SetCwd 2026-08-17 14:29:02 +02:00
Levi Neely 8a1efe0907 session: require cwd, make agent cwd read-only, sanitize message history
Session creation now requires cwd= parameter (no fallback to daemon cwd).
Agent cwd is read-only — agents inherit from session, cannot override.

Frontends updated:
- NewSessionDialog: added Directory field with Browse button
- NewAgentDialog: removed Directory field
- createAgent(): removed cwd parameter
- Kate plugin: passes cwd when creating kate session
- Dolphin: removed cwd from agent/new call

Message history sanitization (backend.SanitizeMessages):
- Removes dangling tool calls (assistant with ToolCalls but missing results)
- Removes orphan tool results (tool message without preceding call)
- Applied before sub-agent context inheritance
- Applied before session persistence save
- Applied after compaction (defensive)

Includes unit tests for all sanitization cases.
2026-08-17 14:15:55 +02:00
Levi Neely 025c351dcb Fix ollie-9p UNAME fallback, goal file permissions
- ollie-9p: Fall back to USER when OLLIE_UNAME not set (remove fatal error)
- goal/goalstatus: Use mode 0666 (world readable/writable) while keeping GID agent
2026-08-17 13:46:44 +02:00
Levi Neely a17dd683df Split session/idx and agent/idx, fix sub-agent tree display
Server:
- session/idx now outputs: session-id, session-name, paused, connected, remote, cwd
- session/{s}/agent/idx now outputs: session-id, agent-id, agent-name, parent-id, depth, state
- Add error if parent agent not found during sub-agent spawn

GUI:
- refreshSessions() reads session index, then agent/idx per session
- Auto-select first top-level agent (depth 0) instead of first in list
- SessionModel tracks agent expansion separately from session expansion
- Agents with children show expand/collapse arrows and are collapsible
- Add hasChildren role to SessionModel

Tools:
- subagent_spawn now passes parent= argument for proper depth tracking
- Remove hardcoded max_depth=5, use server default of 1
- Makefile installs shell script tools from data/tools/

KRunner:
- Update to parse new session/idx format
2026-08-17 13:03:26 +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 743e40c2f8 selectable workflow in new session 2026-08-17 10:52:53 +02:00
Levi Neely 2cde59ac3b session-level goals: goal file + goalwait + conductor workflow
Write to session/{s}/goal to set a session-level objective.
A conductor agent is spawned automatically in the background,
decomposes the goal, spawns sub-agents, and reports completion.

- goal file: write sets goal + starts conductor; read returns status
- goalwait file: blocks until goal status changes (BlockOnce)
- Conductor writes status=complete/blocked back to goal when done
- Session.Goal() / SetGoal() / GoalSignal() on Session struct
2026-08-17 10:15:00 +02:00
Levi Neely 74ba5ae7ac remove maxSteps and ResetsCounter entirely
The step budget mechanism is gone. Agents run until they finish,
are interrupted by the user, or (for sub-agents) hit the timeout.

No replacement. The human is the kill switch.
2026-08-17 09:48:58 +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
Levi Neely ecb9406413 agent/new: fork_at= parameter for historical context forking
Sub-agents can now inherit parent context truncated at a specific
user turn: fork_at=5 means 'fork from the state after the 5th
user message.' Enables backtracking without losing unsummarized
context from before a failed approach.

Without fork_at (or fork_at=0), full history is inherited as before.
2026-08-17 09:04:57 +02:00
Ollie Agent 9789eb56ff show agent reasoning output 2026-08-17 00:08:27 +02:00
Ollie Agent 5d834934de sandbox update 2026-08-16 21:23:15 +02:00
Ollie Agent 45ff8a2864 Remove legacy backend environment configuration 2026-08-16 19:48:52 +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 aca5546ea5 refactor environment utilities and file tools 2026-08-16 18:20:50 +02:00
Ollie Agent 81933e5281 refactor toolsrv into client protocol and metadata packages 2026-08-16 17:22:59 +02:00
Ollie Agent e972b5666a add metrics queries and agent-scoped plans 2026-08-16 17:00:11 +02:00
Ollie Agent 9409920c61 Propagate parent ID for spawned sub-agents 2026-08-16 11:44:39 +02:00
Ollie Agent 72209239b0 Add parent IDs for sub-agents 2026-08-16 11:44:06 +02:00
Ollie Agent ab9fd60901 Document sub-agent context isolation 2026-08-16 11:39:21 +02:00
Ollie Agent e1ac2df3fb Lower tool output cap and add Markdown parsing 2026-08-16 11:31:31 +02:00
Ollie Agent f82b36ea80 Integrate OptMem memory backend 2026-08-16 11:10:50 +02:00
Ollie Agent 929b94e34d Clarify workspace path placeholders 2026-08-16 10:30:56 +02:00
Ollie Agent 741ac689f8 Persist and expose aggregate usage metrics 2026-08-15 20:12:21 +02:00
Ollie Agent a945445c1f Expose cache metrics in agent stats 2026-08-15 20:04:34 +02:00
Ollie Agent 45746a3164 Expose agent stats through ctl 2026-08-15 19:58:54 +02:00
Ollie Agent 9330632402 Use compaction model context limit 2026-08-15 14:13:44 +02:00
Ollie Agent 8553bc7283 measure provider prompt cache hits 2026-08-15 14:09:00 +02:00
Ollie Agent 64b76d9bf0 stabilize provider prompt prefix 2026-08-15 13:57:31 +02:00
Ollie Agent 5dbfa3060f include tool semantics in summary cache 2026-08-15 13:46:29 +02:00
Ollie Agent 82ab9dd2e3 version summary cache keys 2026-08-15 13:43:04 +02:00
Ollie Agent 60c4541fa4 normalize summary cache keys 2026-08-15 13:42:11 +02:00
Ollie Agent adf7242774 reduce cold results locally 2026-08-15 13:33:26 +02:00
Ollie Agent 32180bee4d defer cold summaries until needed 2026-08-15 13:27:16 +02:00
Ollie Agent f167168df3 incrementalize cold summaries 2026-08-15 13:13:22 +02:00
Ollie Agent 25d502cfc2 cache cold result summaries 2026-08-15 13:10:15 +02:00
Ollie Agent b6584d35e7 cancellation persistence fix 2026-08-15 12:59:21 +02:00
Ollie Agent f38b130111 explicit summary state on stripCold 2026-08-15 12:55:04 +02:00
Ollie Agent f4cb1ea290 validate cold history summaries 2026-08-15 12:42:28 +02:00
Ollie Agent 329edc3218 account for stripCold in cost 2026-08-15 12:37:13 +02:00
Ollie Agent e4c24e8a5f fix cancellation and configure compaction model 2026-08-15 12:29:55 +02:00
Ollie Agent 93f021f068 feat: add userPrompts config field for active global rules
- Add UserPrompts Prompt field to AgentConfig (same JSON format as prompt).
- Resolve userPrompts via resolvePrompt() in BuildRuntime, store in Runtime.UserPrompt.
- Prepend resolved user prompts to every user message at executeTurn start.
- Document userPrompts in data/agents/README.md.
2026-08-15 11:52:21 +02:00
Ollie Agent f61a93e426 refactor: move stripCold to executeTurn, replace clone with rollback pointer
- Remove per-step stripCold from run(); call once per turn in executeTurn
  after accumulator reset and before preamble injection.
- Replace expensive deep-clone snapshot with pre-turn length truncation.
- Delete unused cloneMessages() helper.
2026-08-15 11:30:19 +02:00
Ollie Agent e0f846bd31 fix: batch preamble injection and stripCold into single LLM calls
- Remove per-step preamble prepending in loop.go; inject once at turn start
  in turn.go instead of re-sending thousands of tokens every tool step.
- Re-inject preamble after overflow retry compaction where it was lost.
- Replace stripCold() N sequential LLM calls with one batched call that
  summarizes all cold-zone tool results via a single JSON response.
2026-08-15 11:16:49 +02:00
Levi Neely 617bb5586a subagent: inherit parent context via parent= parameter
Sub-agents now clone the parent agent's conversation history into
their initial context. The tool script passes parent=$OLLIE_UNAME
automatically. Mechanically identical to session restore — uses
RestoreHistoryFromMessages on the parent's Messages().
2026-08-14 15:12:16 +02:00
Levi Neely a8d087a080 system prompt: document sub-agent mechanism
Add Sub-Agents section explaining agent/new with prompt= key.
Include examples for single and parallel sub-agent spawning.
Update 9P namespace table to show agent/new as rdwr.
2026-08-14 14:52:53 +02:00
Levi Neely 250ad4b233 agent/new: sub-agent support via rdwr with prompt=
Writing to session/{s}/agent/new with a prompt= key now blocks
until the agent completes its task, then returns the reply and
destroys the transient agent. Without prompt=, behaves as before
(creates agent, returns ID).

Also:
- Move ParsePayload/UnescapeValue to shared ollie/toolsrv package
- Remove duplicate implementations from cmd/toolsrv/internal/server
- Add session.CreateAgentWithParams for direct AgentParams usage
- Eliminate flattenParams/unescapeValue redundancy in fs package
2026-08-14 14:48:12 +02:00
Levi Neely ab4668cb3f virtfs: rename Request to Rdwr
Read, Write, and Rdwr are the three atomic 9P operations:
- Read: non-blocking read
- Write: non-blocking write (fire-and-forget)
- Rdwr: atomic write-then-read (blocking, produces result)

BlockOnce and Stream are special cases of Read.
Rdwr is its own primitive — not a variant of either.
2026-08-14 14:42:19 +02:00
Levi Neely 5dcde264e6 toolsrv: add path-based lock table for cross-agent serialization
All foreground tool calls now acquire a lock based on the tool's
declared scope and file path before execution:

  - scope "read":  no lock (reads never conflict)
  - scope "write": exclusive lock on the file path
  - scope "global": exclusive global lock (serializes with everything)

This ensures writes to the same path serialize regardless of which
agent initiated the call, enabling safe parallel sub-agents within
a session without explicit coordination.

Cross-session serialization (shared toolsrv per host) is left as
future work.
2026-08-14 14:27:21 +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 a8fd7a658f fix: nil Preamble on restored paused sessions
The persist path created agents with &Runtime{} (nil Preamble).
If a prompt arrived before resume rebuilt the runtime, Preamble.Set
panicked. Initialize with an empty Preamble.
2026-08-14 08:42:03 +02:00
Levi Neely dc26871bdc proc/list: use fixed-width columns instead of tabs 2026-08-13 22:28:33 +02:00
Levi Neely 0fed1aa124 proc/list: include command in output 2026-08-13 22:24:50 +02:00
Levi Neely d64f6c1d76 proc: rename ListDetachedRaw→ListProcs, use proc/list rdwr (agent-filtered)
ListProcs now does rdwr to toolsrv proc/list with the agent ID.
Returns pre-formatted text. Ctl proc handler uses it directly.
Removed all ListDetachedRaw map-parsing logic.
2026-08-13 22:22: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 c767ee10c9 ctl proc top: include STATUS column 2026-08-13 22:09:09 +02:00
Levi Neely de33f954e2 toolsrv: proc/list now rdwr with agent filtering
Write agent ID to filter, or empty for all. Returns pid\tstate\ttool.
Added ListProcsForAgent to State.
2026-08-13 22:08:15 +02:00
Levi Neely 48add8f7bb remove proc/ directory from agent namespace (processes live in toolsrv) 2026-08-13 22:01:06 +02:00
Levi Neely 6e5b1aa5f0 system prompt: remove proc/ from agent table (managed via ctl) 2026-08-13 21:59:34 +02:00
Levi Neely 6d4e7e237d system prompt: remove tools file from table (it's a ctl command, not a file) 2026-08-13 21:59:04 +02:00
Levi Neely fd4a3afa4f move tool catalog to toolsrv: add /all file, tools_all ctl command
- Remove /tools from olliesrv root (toolsrv owns all tool state)
- Add /all file to toolsrv namespace (lists all available tools on disk)
- Add ListAllTools() to toolsrv client library
- Add tools_all ctl command to agent (reads from toolsrv/all)
- Update system prompt with tools_all usage
2026-08-13 21:58:08 +02:00
Levi Neely a1e78bca80 remove tool_load: use ctl directly
tool_load was a built-in intercept in the agent loop — the only
'tool' that didn't run in toolsrv. Removed entirely:
- Intercept in loop.go (25 lines)
- Script + .meta in data/tools/
- autoLoad references in agent configs

Loading tools is now exclusively via ctl (which already existed):
  echo 'tool_load X' | ollie-9p write .../ctl

System prompt updated to show the ctl pattern.
2026-08-13 21:44:46 +02:00
Levi Neely 324247b6a5 fs: remove dead streamChat and mergeCtx 2026-08-13 21:09:53 +02:00
Levi Neely 4bb08e860b toolsrv: fix shutdown ordering — close conn before draining
On context cancellation, close the connection first to unblock
ReadFcall. Then wait for in-flight handlers, drain the response
channel, and wait for the writer to finish. No writes hit a
closed socket.
2026-08-13 21:08:01 +02:00
Levi Neely d9026499fd toolsrv: suppress write errors during shutdown 2026-08-13 21:04:19 +02:00
Levi Neely bcaac146d2 server: on BlockOnce timeout, fall back to non-blocking Read
Frontends rely on getting the current state on timeout (heartbeat).
When BlockOnce returns empty (5s timeout), the server now calls the
plain Read handler as fallback. Files without a Read handler (like
feed) return nothing — consumer unaffected.
2026-08-13 20:59:05 +02:00
Levi Neely dd0021fd9a fix: restore sessions after 9P listener is ready
ConsumeFeed dials the 9P socket. Moving session restore to after
the listener starts ensures the socket exists when feed consumers
connect.
2026-08-13 20:55:02 +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 5459e7fa2a fix: XDG default fallback in prompt resolver; deduplicate tool headers
- envLookup: provide XDG spec defaults (XDG_CONFIG_HOME, XDG_DATA_HOME,
  XDG_CACHE_HOME) when env vars are unset, so agent profile prompts
  resolve correctly on systems without explicit XDG vars.
- renderTools: skip generated '## name' header when the tool's prompt
  text already starts with a markdown header, eliminating duplicates.
2026-08-13 15:45:35 +02:00
Levi Neely 6a19c135eb prompts: drop tool path from system prompt, use absolute path in copilot example 2026-08-13 12:04:52 +02:00
Levi Neely 83b0b59a0a prompts: remove /home/user path examples that bias tilde expansion
- file_grep.meta: replace /home/user/project with /abs/path
- system_prompt.md: use $XDG_CONFIG_HOME instead of ~
- agent-copilot.md: use relative path in code block example
2026-08-13 12:02:27 +02:00
Levi Neely 1ac50d97e1 agent: drain FIFO after interrupted/failed turns
Fix holes where queued prompts were orphaned:
- After turn loop exits (interrupt, toolsrv unavailable), drain remaining FIFO items
- On panic recovery, pop next FIFO item and re-submit in a new goroutine
- fifo file write triggers Submit when agent is idle
2026-08-13 11:59:11 +02:00
Levi Neely 9b98a958cc fix: treat meta cmd as shell command string, prepend tools dir to PATH
- ResolveTool now returns cmd field as-is instead of trying to resolve
  it as a binary path. This allows meta-only tools to use full shell
  command strings with env vars, pipes, and subshells.

- Prepend ~/.config/ollie/tools to PATH when executing tools so cmd
  fields can reference other tools by name.
2026-08-12 18:44:16 +02:00
Levi Neely 23f3a6092b refactor: eliminate TurnCtx, make loop functions Agent methods
- Delete TurnCtx struct (was progressively populated with optional nil fields)
- Convert run(), streamResponse(), execToolCalls(), execBatch(), execOne(),
  trackErrors(), retryCountdown() to Agent methods
- Extract autoCompact() and popInject() as Agent methods
- turn.go now installs a turn-scoped output handler wrapper instead of
  building TurnCtx closures
- context.Context is now passed as plain context.Context, not smuggled
  with unrelated state

Add history compaction tests:
- TestBuildCompactedHistory_OrphanedToolWalkback: verifies walk-back logic
  prevents orphaned tool messages at hot zone boundary
- TestBuildCompactedHistory_NoOrphanAtBoundary: verifies tool messages
  always have preceding assistant with tool_calls
2026-08-12 18:06:19 +02:00
Levi Neely 0a4149218a fix: set agent ID on toolsrv connection after resume 2026-08-12 17:10:22 +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 85435447bf fix: clean shutdown without connection errors
- Use read deadline + context check instead of forcibly closing connections
- ReadBypassPending now takes context and exits cleanly on cancellation
- Remove forced conn.Close() loop from Kill() - context cancellation suffices
2026-08-12 12:40:40 +02:00
Levi Neely 9057d36f05 docs: clarify tool usage in system prompt, add cancellation flow doc
- Explicitly tell model not to invoke tool scripts via filesystem path
- Add concrete examples of native tool calls vs shell
- Document context cancellation flow from interrupt to process kill
2026-08-12 12:20:34 +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
Levi Neely edd5ade471 refactor: simplify bypass - toolsrv is the broker, olliesrv is just a client
- Remove olliesrv's bypass broker machinery (pendingCh, EvaluateRequest, etc)
- Session bypass loop now just reads from toolsrv's bypass/pending and notifies
- Notification handler writes directly to toolsrv's bypass/resolve (fire and forget)
- Remove bypass/ directory from olliesrv's 9P namespace
- Remove session/*/bypass file (policy can be added back to toolsrv later if needed)

The flow is now:
1. toolsrv blocks tool execution, exposes request via bypass/pending
2. olliesrv reads from toolsrv, shows D-Bus notification
3. User clicks approve/deny, olliesrv writes to toolsrv's bypass/resolve
4. toolsrv unblocks and executes (or denies)
2026-08-12 11:01:29 +02:00
Levi Neely 46bd0dd999 fix: toolsrv 9P server now handles BlockOnce/Stream reads correctly
- Added BlockingReadMode() and StreamMode() handling to toolsrv's handleRead()
- Made NextPending() context-aware in both toolsrv and olliesrv bypass packages
- This fixes the bypass approval flow via 9P - reads now properly block until
  a request is available and respect context cancellation
2026-08-12 10:49:08 +02:00
Levi Neely d59f49ee54 feat: context cancellation for tool calls
Wire context cancellation through the toolsrv 9P server so that
canceling a CallTool context properly terminates the running tool.

Changes:
- virtfs: Add Close() to File interface with CloseFn for Request handlers
- toolsrv/p9.go: Handle requests concurrently to allow Tclunk during
  blocking Twrite; call entry.Close() in handleClunk
- toolsrv/internal/server/proc.go: Check ctx.Done() while waiting for
  tool completion in NewProc
- Integration tests for context cancellation chain

The cancellation chain: client cancels ctx → fid.Close() → Tclunk →
handleClunk calls entry.Close() → closeFn cancels reqCtx → NewProc
sees ctx.Done() and returns ctx.Err()
2026-08-12 10:00:44 +02:00
Levi Neely 31681cb4e7 Add context cancellation to bypass.Submit
bypass.Submit now takes a context and returns early when cancelled.
This allows the stop command to properly cancel pending bypass requests
that haven't been approved or denied yet.

The full context chain is now:
1. stop command -> Interrupt -> cancel actCtx
2. actCtx cancellation -> closes CallTool fid
3. toolsrv proc/new sees closed fid -> propagates ctx cancellation
4. ExecuteTool -> executeBypassDirect -> bypass.Submit
5. bypass.Submit returns ctx.Err() when context is cancelled
2026-08-12 09:32:21 +02:00
Levi Neely 5dc7cdc2ea Make Request() always context-aware
Remove RequestCtx variant - all Request handlers now take context.
This is required for proper cancellation of blocking operations
like tool execution when the client disconnects or stop is called.
2026-08-12 09:30:39 +02:00
Levi Neely 861cb47d13 Add RequestCtx for context-aware request handlers
- Add RequestCtx field to FsNodeDecl for handlers that need context
- Add RequestCtx() helper function in virtfs/decl.go
- Update builder.go to handle RequestCtx in validation and Open
- Use RequestCtx in toolsrv proc/new and proc/new.bg handlers

This allows the context to be cancelled when the 9P fid is closed,
enabling proper stop/interrupt of running tool calls.
2026-08-12 09:26:02 +02:00