Commit Graph

368 Commits

Author SHA1 Message Date
Levi Neely 35fefefdc7 prompts: clarify background output requires agent idle state
Background process output is only injected when the agent is idle.
If the agent keeps making tool calls, the output won't arrive until
the turn ends.
2026-10-08 18:47:57 +02:00
Levi Neely 414dae05f8 dispatch: include no-wait instruction in system-proc-background
Every background process emission now includes:
'Do NOT sleep, poll, or wait. Continue with other work —
output will be injected automatically when available.'
2026-10-08 11:21:40 +02:00
Levi Neely 8da78f4deb prompts: never sleep/poll/wait for background processes
Add explicit instruction that models must not use sleep, loops,
or any blocking mechanism to wait for background process output.
The system injects updates automatically.
2026-10-08 11:13:54 +02:00
Levi Neely c2df632744 agent/new: parse cwd parameter into CwdOverride
The cwd= parameter in agent/new payloads was not being parsed,
so scripts like ollie-session-here could not set agent cwd on
creation. Now parsed and passed to AgentParams.CwdOverride.
2026-10-07 15:32:53 +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 b9026bb48b fix: allow group access to ctl, plan, fifo for frontend interaction
Changed from 0600 (owner only) to 0660 (owner + group):
- ctl: frontends need to send slash commands
- plan: frontends need to read/write plan
- fifo: frontends need to submit prompts via queue

The agent group includes frontends, so group permissions enable
frontend interaction while still maintaining ownership-based isolation.
2026-10-07 11:01:01 +02:00
Levi Neely d65c06f27b implement namespace-bounded capability model
Per-agent file ownership with Unix permission enforcement:
- Agent directories owned by agent ID (UID), group 'agent' (GID)
- Private files (plan, ctl, fifo): mode 0600 - owner only
- Group-readable (chat, log): mode 0440 - owner + agent group
- World-readable (state, id): mode 0444 - observable by all
- Prompt: mode 0220 - CLI and owner can write

virtfs: fix UID/GID inheritance through nested paths
- Added findChildWithInheritance() to accumulate inherited UID/GID
- Stat now correctly shows agent ID as owner for nested files

server: admin bypass for server owner
- serverAdmin variable captures the Unix user running olliesrv
- Admin bypass includes empty uname, 'admin', or server owner

Documentation updates:
- fs/doc.go: 'The Namespace IS the Security Model'
- registry/doc.go: capability-based tool access
- peer.go: capability-based peer access
- lessons-learned.md: 'Model compliance is not a security boundary'
- architecture-9p.md: per-agent file ownership section

Security evaluation:
- Added experiments/security-eval/ with NERV attack corpus adaptation
- Test scripts for Landlock sandbox validation
- RESULTS.md documenting 0% ASR on hostile operations

This implements the NERV thesis: 'An agent can only access resources
explicitly bound into its namespace.' Enforcement is structural via
file permissions, not behavioral via model compliance.
2026-10-06 17:41:27 +02:00
Levi Neely b25e5e2fc6 bypass: emit resolved event for cross-client coordination
Server emits session.{sid}.agent.{aid}.bypass.resolved with id and
action (approved/denied) when a bypass is resolved by any client.

GUI handles bypass.resolved events to clear the banner and pending
count when CLI or another client resolves a bypass request.

This allows CLI 'o sess approve' to clear the GUI banner automatically.
2026-10-06 14:54:55 +02:00
Levi Neely 6dc9ffe3b1 gui: show bypass banner per-agent, not globally
- Changed event topic: session.{sid}.agent.{aid}.bypass.request
- Added agentId parameter to bypassRequested signal
- Filter bypass events to show only for the active agent
2026-10-06 14:32:30 +02:00
Levi Neely 59d07d3b4a fix bypass event payload truncation at newlines
The shell command in bypass requests contains embedded newlines.
Escape them as \n in the event payload, unescape in GUI.
2026-10-06 14:28:10 +02:00
Levi Neely 7b870443bb remove desktop notification for bypass requests
Bypass approval now flows through:
1. GUI - via event stream and banner
2. CLI - via agent loop (to be implemented)

Removed:
- bypass_notify.go (D-Bus notification)
- BypassNotifyFunc type and all references
- godbus/dbus dependency

The bypass event is still published via SetBypassPending.
2026-10-06 14:03:07 +02:00
Levi Neely a4378c1be4 server: also match /event path in read handler 2026-10-06 13:51:25 +02:00
Levi Neely 5077dfea8e server: fix event file fallthrough when fid lookup fails
If fidOK was false for the event file, we fell through to the
default stream handling path which doesn't work for events.
Now we return 'bad fid' error instead of falling through.
2026-10-06 13:50:58 +02:00
Levi Neely d7d9e9654a replace pubsub library with simple fan-out event hub
The pubsub library had issues:
- Published to literal '*' topic (nonsensical)
- Used TrySend which drops events
- Complex hierarchical wildcard publishing

New implementation:
- Simple eventHub with map of subscribers
- PublishEvent fans out to all subscribers (blocking send)
- SubscribeEvents returns channel, cleaned up on ctx cancel
- SubscribeEventsFiltered filters client-side with MatchTopic
- Removed simonfxr/pubsub dependency
2026-10-06 13:43:57 +02:00
Levi Neely 63e7ed5c65 server: clarify event subscription uses 9P client connection context 2026-10-06 13:37:56 +02:00
Levi Neely 43d3051a78 server: fix event subscription context - use connection ctx not request ctx
The subscription was being cancelled after the first read completed
because we used the per-request context. Now using the connection
context so the subscription lives until the fid is clunked or
connection closed.
2026-10-06 13:36:26 +02:00
Levi Neely 79ab165ffd server: fix event dropping - use blocking callback instead of TrySend
The pubsub library's SubscribeChan uses non-blocking TrySend which
drops events when the channel is full. Switch to Subscribe with a
blocking callback to ensure no events are lost.

Also increased channel buffers from 64 to 256.
2026-10-06 13:32:56 +02:00
Levi Neely cd94cdf259 server: event file plain read now uses per-fid subscription
Plain reads (without writing a filter first) now get a per-fid
subscription with '*' filter, identical to 'echo * | rdwrs event'.

This fixes event loss — the old EventStream path overwrote events
when multiple arrived before the reader consumed them.
2026-10-06 13:27:02 +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
Levi Neely 88062d0ed0 server: remove redundant bypasswait file
Bypass requests are delivered via the event stream.
The bypasswait file was unused.
2026-10-06 12:47:57 +02:00
Levi Neely 3b6c78d08d docs: state file is read-only 2026-10-06 12:44:37 +02:00
Levi Neely 86fbc90b43 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.
2026-10-06 12:44:02 +02:00
Levi Neely 772d77940c server: implement filtered event subscriptions
Event file now supports streaming rdwr pattern:
- Read: streams all events (unchanged)
- Write filter, then read: streams only matching events

Filter syntax:
- * matches single segment
- > matches rest of topic
- Examples: session.*.agent.*.state, session.abc.>

Usage: echo filter | rdwrs event

Per-fid subscription state is cleaned up on clunk.
2026-10-06 12:34:14 +02:00
Levi Neely 9a66944859 ollie-9p: add rdwrs command for streaming rdwr
rdwrs writes stdin then streams reads (does not wait for EOF).
Use for event subscription: echo filter | rdwrs event

Also adds prototype in experiments/streamrdwr demonstrating:
- Write topic filter, stream matching events
- Glob-style filtering: * (single segment), > (rest)
2026-10-06 12:31:06 +02:00
Levi Neely 6ea2bc052e server: add non-blocking state file separate from statewait
- state: immediate read of current agent state
- statewait: blocks until state changes

Clearer semantics than overloading statewait with both behaviors.
2026-10-06 12:17:19 +02:00
Levi Neely f86c8d3cdc docs: update all references from eventwait to event 2026-10-06 12:08:35 +02:00
Levi Neely 25d7fbfc5b server: rename eventwait to event 2026-10-06 12:02:37 +02:00
Levi Neely adb08fc51d server: fix eventwait to use Stream instead of BlockOnce
EventValue was storing only the latest event and using hash comparison,
which caused events to be overwritten if they arrived faster than the
client could read them.

Now eventwait uses Stream mode with EventStream which delivers each
event as it arrives. Events won't be lost due to rapid arrival.
2026-10-06 12:01:26 +02:00
Levi Neely f2f1f80e4e gui: integrate bypass requests into chat UI
Server changes:
- Session tracks pending bypass request and exposes methods
- New 9P files: session/{sid}/bypass (read/write), bypasswait (blocking)
- Publish bypass.request events for GUI listeners

GUI changes:
- Handle bypass.request events from eventwait
- Show inline amber banner with command and cwd
- Approve/Deny buttons resolve via 9P

Desktop notifications still work in parallel for non-GUI usage.
2026-10-06 11:44:15 +02:00
Levi Neely 0c30ec71d2 server: reduce statewait timeout from 5s to 500ms
When reading statewait with the same state value, the server now waits
500ms instead of 5 seconds before returning. This makes state polling
much more responsive.
2026-10-06 11:32:31 +02:00
Levi Neely c9c26d3a3d fix bypass+background hang: signal started immediately
Background procs with bypass were hanging because the caller blocked on
<-startedCh waiting for the process to start, but bypass.Submit blocks
until approval. Now we signal started immediately when entering bypass
path (with Process: nil), so the agent sees the proc ID right away.

Also handle term/kill when proc.proc is nil — cancel the context to stop
the operation (e.g., abort a pending bypass request).
2026-10-06 11:00:23 +02:00
Levi Neely 7ac1b6faf5 fix bypass+background: wire streamOut through bypass path
executeBypassDirect was missing the streamOut parameter, so background
processes running via bypass never had their output written to the proc
buffer. Now both bypass and sandboxed paths receive the streaming writer.
2026-10-06 10:53:06 +02:00
Levi Neely cd76864f19 fix agent profile selection from GUI
Two bugs:
1. GUI sends 'agent=<profile>' but server only recognized 'profile='
   - Added 'agent' as alias for 'profile' in parseAgentNewRequest

2. Model dropdown showed cost columns appended to model names
   - /models format: backend<tab>model[<tab>in<tab>out...]
   - Parser took everything after first tab as model name
   - Now stops at second tab to extract just the model name
2026-10-06 10:42:35 +02:00
Levi Neely f85612a4da session: pause all sessions on shutdown, fix agent config loading
Shutdown changes:
- Shutdown() now calls PauseAll() before closing sessions
- PauseAll() interrupts agents then pauses each session
- Sessions persist their state, allowing resume on next startup

Agent loading fix:
- LoadConfig returns (*AgentConfig, error) instead of *AgentConfig
- Parse errors are no longer silently discarded
- Callers handle nil config gracefully (no nil pointer dereferences)
2026-10-01 13:34:33 +02:00
Levi Neely c1888d31fe agent: increase tool result hard limit from 32KB to 128KB 2026-10-01 09:23:38 +02:00
Ollie Agent 3f9f4753ef session: make session/new get-or-create
CreateEmpty now returns (session, created, error): if a session with the
given name already exists it is returned untouched instead of erroring,
and only a freshly created session receives the provided cwd/workflow/
variant. The o script no longer suppresses errors from session/new, so
real failures surface while re-creating an existing session stays a
no-op success.
2026-09-29 23:01:44 +02:00
Levi Neely 50b02b7a1e sandbox: skip sockets and FIFOs in Landlock rules
Landlock cannot add rules for sockets (S_IFSOCK) or FIFOs (S_IFIFO).
Previously, attempting to add a path like /run/user/1000/wayland-0
would fail with EINVAL.

Now these special file types are detected and skipped gracefully.
2026-09-25 16:33:39 +02:00
Levi Neely f88b5fcc32 kiro: only set additionalModelRequestFields for supported models
The field is rejected by models that don't support thinking/reasoning
configuration. Check model name before setting the field; 'auto' and
unknown models skip it to avoid ValidationException errors.
2026-09-21 14:40:30 +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
Ollie Agent f3933e21e7 backend: make reasoningEffort the primary knob with documented thresholds
reasoningEffort (low|medium|high) is now the single human-facing control
for model deliberation. Backends that speak a discrete level (OpenAI,
OpenRouter, Copilot, Gemini, Kiro) send it verbatim; Anthropic, which
needs a numeric budget, translates via documented thresholds
(low=4096, medium=8192, high=16384). thinkingBudget remains an advanced
explicit override that wins when set.

- Add EffortLow/Medium/High, threshold consts, ValidReasoningEffort,
  EffortThinkingBudget, and GenerationParams.ResolvedThinkingBudget.
- Anthropic: derive budget from effort, grow max_tokens above the budget
  (Anthropic requires budget < max_tokens), and force temperature=1 when
  thinking is enabled (both are Anthropic requirements).
- Validate reasoningEffort at config load so typos fail loudly instead
  of silently no-opping.
- theo: drop explicit thinkingBudget/inflated maxTokens; reasoningEffort
  high now implies the 16384 budget.
- Document thresholds and per-backend behavior in data/agents/README.md;
  fix stale autoLoad/maxSteps references.
- Add unit tests for the mapping and Anthropic thinking behavior.
2026-09-07 13:34:58 +02:00
Ollie Agent 6c7e5864c4 agents: set reasoningEffort per profile; rename thinkingBudget tag
Reasoning effort is part of an agent's behavior definition, so set it
on all 14 profiles keyed to role (planning/review high, general medium,
lightweight assist low). Also rename the ThinkingBudget json tag from
the confusing bare "reasoning" to "thinkingBudget", distinct from the
reasoningEffort string knob. No config migration needed — no profile or
backends.conf used the old "reasoning" key.
2026-09-07 13:27:33 +02:00
Ollie Agent 9395a0e07b config: rename agent autoLoad field to tools
The autoLoad name implied an automatic tool-loading path that no longer
exists; tools now come only from agent config plus the /tool_load ctl
command. Rename the AgentConfig.AutoLoad field (json autoLoad) to Tools
(json tools), rename LoadAutoLoadTools to LoadTools, and update all 14
agent JSON profiles and the tool-not-loaded error message.
2026-09-07 13:23:17 +02:00
Ollie Agent eff0880737 backend: test that no tools loaded omits tools field
Regression guard for tool-free model compatibility: an agent with an
empty tool set must produce requests with no "tools"/"tool_choice"
field. Covers OpenAI, OpenRouter, Ollama, and Anthropic.
2026-09-07 13:19:35 +02:00
Ollie Agent 2e30b0ddab fs: show OpenRouter cache pricing for selected models 2026-09-05 11:56:04 +02:00
Ollie Agent 3ca84487c5 toolsrv: neutralize repo-controlled core.fsmonitor in tool env
GitSpawn class (Sep 2026): a repo's .git/config can set core.fsmonitor to
a command that executes on any git index refresh, silently and as the
user. Ollie never spawns git in its own plumbing (repo detection is
os.Stat), but model-run git inside a malicious repo would fire it.

- exec: force core.fsmonitor=false via GIT_CONFIG_* in sandboxed tool env
- turn: wrap repo AGENTS.md in <context> markers (untrusted data,
  filtered by KDE chat rendering)
- AGENTS.md: document the no-git-in-plumbing invariant (lesson 16)
2026-09-05 11:42:38 +02:00
Levi Neely 065e399444 models: add pricing info with cache rates and static estimates
Add per-model pricing to /models output. Format:
  backend<tab>model[<tab>in<tab>out<tab>cache_read<tab>cache_write]

Pricing sources:
- Anthropic: hardcoded from official pricing, includes cache rates
- OpenRouter: parsed from API response pricing field
- Other backends: static lookup table fallback, marked with (e)

Changes:
- backend: Add ModelPricing/ModelInfo types, ModelLister interface,
  static price table (Claude, GPT, Gemini, DeepSeek), LookupStaticPricing()
- openai: Parse pricing from API, implement ModelsInfo()
- anthropic: Implement ModelsInfo() with hardcoded cache rates
- fs/cache: Use ModelsInfo when available, fall back to static lookup,
  format prices per 1M tokens with (e) suffix for estimates
- agent/cost: Use shared LookupStaticPricing instead of duplicate table
2026-09-04 13:26:48 +02:00
Levi Neely 765e8b9d05 add file-level doc comments and improve AGENTS.md navigation
Agent package files now have descriptive header comments explaining
their purpose:
- dispatch.go: tool execution, batching, conflict detection
- turn.go: turn orchestration and Submit entry point
- state.go: agent state machine and notifications
- history.go: message history and token tracking
- compact.go: context compaction and cold summarization
- cache.go: tool result caching with staleness detection
- retry.go: error tracking and transient retry logic
- runtime.go: preamble assembly and tool schema management
- text_parse.go: text-based tool call parsing
- chatlog.go: chat output formatting
- chat.go: chat log storage and streaming
- workflow.go: workflow classification for discovery
- skill_match.go: semantic skill discovery
- tool_match.go: semantic tool discovery
- commands.go: slash command interception
- feed.go: feed value storage with dedup
- fifo.go: buffered prompt queue
- peer.go: peer agent management
- subagent.go: sub-agent depth and child tracking
- cost.go: cost calculation and audit logging
- prompt_resolver.go: prompt file resolution
- local_summary.go: non-LLM text summarization
- agent_config.go: configuration types

AGENTS.md improvements:
- Add 'Where to Start' section with entry points by concern
- Expand Key Files table with cache, retry, text_parse, tool_match,
  skill_match, chatlog, local_summary, workflow, and proc files
2026-08-27 10:23:26 +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 785c27c450 extract compaction logic from history.go
compact.go (379 lines): compact(), buildCompactedHistory(), summarizeMessage(),
  flattenToolMessages(), cacheSummary(), pendingColdSummaryStats(), stripCold(),
  resolveCompactionModel()

history.go (636 → 279 lines): core History struct, message operations,
  usage tracking
2026-08-27 10:11:54 +02:00