Commit Graph

646 Commits

Author SHA1 Message Date
Levi Neely 939f41013e agent: fix stall state always firing on normal text responses
The "no tools" stall condition (totalToolCalls==0 && hadContent) fired
whenever the bot replied in plain text without calling any tools, which
is the normal completion path. The UI would then see agentStalled before
the done message and never transition back to agentIdle.

Removed the "no tools" stall; only the max-steps limit case is a real
stall worth surfacing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 10:51:10 +02:00
Levi Neely b45f81908e agent: fix compact to proactively summarize older messages
Compact was gated on EvictedMessages(), which only returns messages
that have spilled past the 120k char soft limit. Normal sessions never
hit that threshold, making /compact a permanent no-op.

New approach: compact ALL messages older than the tail window (i.e.
everything computeTailStart puts before the protected tail), regardless
of budget. This makes /compact always useful.

Added OlderMessages(), TailWindow(), and SystemMessages() to
ContextBuilder to support the rewrite cleanly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 10:49:39 +02:00
Levi Neely bc8c6b75b5 session,dedup,compact: persistence, hard errors, summary display, write-then-write
Session persistence:
- Sessions saved to ~/.config/ollie/sessions/{id}.json after each
  completed agent turn and after /compact
- --session <id> flag resumes a saved session, auto-loading its agent
- /sessions command lists saved sessions with agent and goal preview
- /clear and /agent switch generate a new session ID
- Session ID shown at startup

Dedup:
- file_read: overlap check now returns a hard error (was a warning
  prepended to the result); check uses requested range, not actual
  read range, to avoid redundant dispatchFileRead on overlap
- tool calls: duplicate (name, args) now returns a hard error; key
  is only recorded on successful execution

/compact: Compact() now returns the summary text; displayed in the
  UI so the user can verify quality; session saved after compact

Write-then-write:
- After a successful file_write, repopulate fileRanges with the
  written range so a follow-up write to the same region does not
  require a re-read
- Whole-file writes record exact new line count from content;
  range writes record the written [start, end] with totalLines=0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 10:46:01 +02:00
Levi Neely 864d13381a main: fix write guard for new files, rangesCover off-by-one, drop 500-line cap, add /agents
- file_write: allow creating files that don't exist on disk without a
  prior read; the guard only applies to existing files
- rangesCover: initialize cur = ws-1 so coverage check starts at the
  target range, not line 0 (range writes to e.g. lines 50-100 were
  incorrectly blocked even when exactly that range had been read)
- remove fileReadMaxLines (500-line pagination cap); range tracking
  makes the truncation unnecessary
- add /agents command: lists .json configs in agentsDir, marks active
  agent with *
- add main_test.go: table-driven tests for rangesOverlap and rangesCover

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 10:25:02 +02:00
Levi Neely f6f3f60428 clear: reset ctxStats and lastUsage on /clear 2026-04-06 21:46:43 +02:00
Levi Neely 7714243291 prompt,agents: move proactive exploration to system prompt; agent prompts use-case only
"Be proactive / explore first" is generic behavior — moved to systemPromptBase.
Agent prompts now contain only use-case-specific rules (code exploration,
context reads before writing, skill discovery for anvillm-agent).

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-04-06 21:38:15 +02:00
Levi Neely 4ccfcdec4f agents: add code exploration and context rules; scope skill discovery to anvillm
- All four agents: require full source enumeration before explaining code,
  and full context reads before writing or modifying code
- default, default-sp, yolo: remove skill discovery references (anvillm only)
- anvillm-agent: retains skill discovery, adds the same code rules

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-04-06 21:37:04 +02:00
Levi Neely 0a2983b590 prompt: revert code exploration rules from systemPromptBase (moved to agents)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-04-06 21:35:43 +02:00
Levi Neely e4fdf9aaf4 prompt: require full source exploration before answering code questions
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-04-06 21:32:41 +02:00
Levi Neely 1c4c3049ac agent: reduce repetition and blind writes with dedup caches and range tracking
- Revised system prompt with concrete prohibitions against verbosity and
  premature stopping
- Added GenerationParams (max_tokens, temperature, frequency/presence penalty)
  threading from agent config through backend ChatStream calls
- Added stall detection: emits "stalled" role on max-steps hit or zero tool
  calls with content, surfaces as "stalled" in status bar
- Added per-session file read range tracking: warns on overlapping re-reads,
  blocks file_write unless the target range was previously read
- Added general tool-call dedup: warns on exact (name, args) repeats for
  non-file tools
- Both caches invalidated on /compact and /clear; file read cache invalidated
  per-path on file_write
- Updated all agent configs with documenting defaults for new generation params

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-04-06 21:29:20 +02:00
Levi Neely ea07f6d3a0 mcp,tools,main: shut down MCP servers on agent switch
Client gains a Close() method that closes stdin (giving the subprocess
a clean EOF) then kills and reaps the process. Executor.Close() calls
Close() on all registered clients. agentEnv now carries the mcpExec so
the /agent command can close the outgoing executor before building the
new one.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 20:36:20 +02:00
Levi Neely fd5de0dec3 Enhance anvillm-agent prompt to proactively discover, load, and use skills 2026-04-05 13:59:43 +02:00
Levi Neely 65dc159f71 better agent prompting 2026-04-05 11:54:11 +02:00
Levi Neely 92db8f88cd fix: null content on tool_calls messages; skip empty tool names; rollback on error 2026-04-05 11:53:36 +02:00
Levi Neely 37fc5ee968 fix: account for status bar height when sizing viewport 2026-04-05 11:18:53 +02:00
Levi Neely 1c9d180d35 fix: only rollback session on interrupt, not on every new message 2026-04-04 23:41:56 +02:00
Levi Neely 68bbde568c system prompt: lead with hard no-narration rule in caps 2026-04-04 22:45:42 +02:00
Levi Neely 7e1dc1eb27 fix: clear cancel/doneCh on normal completion to prevent rollback on next turn 2026-04-04 22:43:44 +02:00
Levi Neely ee7117dacf system prompt: no hedging language, use tools to get definite answers 2026-04-04 22:39:41 +02:00
Levi Neely fbbbd66d30 system prompt: no re-reads, no permission-asking, complete tasks in one pass 2026-04-04 22:36:34 +02:00
Levi Neely bd06d83a0e remove tool output truncation; raise context limits 2026-04-04 22:34:43 +02:00
Levi Neely 974b3b7461 increase context limits and replace tool output truncation with retry hint 2026-04-04 22:27:19 +02:00
Levi Neely cb49ac66aa improve tool gating, context visibility, and model guidance
- gate execute_* tools behind trustedTools for consistency
- add /context and /history slash commands
- add few-shot tool call examples to system prompt
- bump fileReadMaxLines 200 -> 500
- update all agent configs with appropriate trustedTools
2026-04-04 22:09:53 +02:00
Levi Neely e48617fc27 implement /compact and /clear commands
- /compact: summarizes evicted context messages via LLM call, replaces
  them with a single summary system message
- /clear: resets session and display
- ContextBuilder.EvictedMessages(): returns messages outside bounded window
- Session.Compact(): drives the summarization and history replacement
2026-04-04 21:51:30 +02:00
Levi Neely 082444dd7e add /clear command; note: /compact requires LLM summarizer (not yet implemented) 2026-04-04 21:48:04 +02:00
Levi Neely f7da39b966 file_write: require reading target lines before writing 2026-04-04 21:40:52 +02:00
Levi Neely cc7a93c87d file_read: truncate at 200 lines with hint to narrow range 2026-04-04 21:38:21 +02:00
Levi Neely b0fa0b6ae4 system prompt: grep before file_read/file_write to scope line ranges 2026-04-04 21:35:26 +02:00
Levi Neely 1b82b59d03 add trustedTools config to bypass file_read/file_write confirmation 2026-04-04 21:33:12 +02:00
Levi Neely f143fde8fd fix confirmation pump; enforce file_read/file_write over shell
- Stop agentCh pump while waiting for user confirmation (prevents
  context cancellation on confirm reply)
- System prompt: hard directive to use file_read/file_write instead
  of shell commands for file operations
- Update tool descriptions to match
2026-04-04 21:27:16 +02:00
Levi Neely cd59dce4ca add user confirmation for file_read/file_write; fix display whitespace
- file_read and file_write require explicit y/n confirmation before executing
- New agentConfirming UI state with confirm [y/n] status bar indicator
- y/yes approves, n/no denies, anything else denies and falls through to
  normal prompt handling
- file_read output includes line numbers for precise file_write targeting
- Fix tool output display: remove per-line squashWhitespace (preserves indentation)
- file_write description hints to preserve formatting
2026-04-04 21:19:38 +02:00
Levi Neely efa68f798b ! shell shortcut; fix tool output whitespace; file_write formatting hint 2026-04-04 21:01:59 +02:00
Levi Neely 2445ea0d5e add file_read/file_write tools; refactor dispatch into per-tool functions
- Add file_read: line-range aware file reading (start_line, end_line)
- Add file_write: full overwrite or line-range replacement
- Extract dispatchExecuteCode/Tool/Pipe into separate functions
- Prefer file tools over shell for file operations (system prompt)
2026-04-04 20:56:07 +02:00
Levi Neely 70a50d4ed8 fix interrupt handling: propagate context to subprocess tree
- Pass caller context into Executor.Execute so cancellation reaches
  the subprocess immediately
- Use Setpgid + SIGKILL on process group to kill grandchild processes
- Add context to ToolExecutor signature and thread it through dispatch
- Reset agent state to idle after drainAgent
- Rollback incomplete session turn on interrupt
2026-04-04 18:18:02 +02:00
Levi Neely c2cbc3e806 split execute_code into three tools; improve ollama backend and system prompt
- Split execute_code into execute_code, execute_tool, execute_pipe for
  clearer model comprehension, especially on smaller models
- Ollama: accumulate tool calls across all stream chunks (fixes llama3.1
  which delivers tool calls only on the done event)
- Ollama: add HTTP 429 / RateLimitError handling
- Ollama: map ToolCallID on outbound messages
- System prompt: inject cwd, current time, available tools
- System prompt: clarify tool usage rules
- Fix spurious spaces in streamed output (remove addStreamingContent heuristic)
- Fix tool output display: preserve newlines, add blank line separation
2026-04-04 17:57:55 +02:00
Levi Neely b00d970c74 default agent with superpowers 2026-04-04 12:15:43 +02:00
Levi Neely 500815c4c9 wrong filename 2026-04-04 12:05:30 +02:00
Levi Neely f201a0a737 agent installation; OLLIE_DEFAULT_AGENT 2026-04-04 12:01:57 +02:00
Levi Neely 40abd7a096 config,main: agent configs in ~/.config/ollie/agents/<name>.json
Each agent config (mcpServers, hooks, prompt) lives in its own file.
'prompt' is injected after the system prompt, allowing per-agent
behaviour without touching the minimal base system prompt.

Startup loads agents/default.json, falling back to the legacy
config.json. The /agent [name] command swaps the active agent at
runtime, rebuilding MCP connections, hooks, tools, and the composed
system prompt, and resetting the session. Agent name is shown in the
status bar.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 11:45:11 +02:00
Levi Neely 16c17f79e1 main: replace system prompt with minimal cost/behavior guardrails
Remove use-case-specific instructions (execute_code how-to, planning
workflow, skill discovery) — these dictate behavior inappropriate for a
general-purpose agent and add tokens to every request. Keep only the
terse-output and anti-filler guardrails that directly affect cost and
response quality.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 11:35:26 +02:00
Levi Neely 078428881c agent: revert auto-nudge — model choice is the right fix
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 11:30:57 +02:00
Levi Neely 76c5e696d5 agent: auto-nudge when model narrates intent without acting
When the model emits a text-only turn containing narration phrases
("let me", "i'll", "i will", etc.) with no tool calls, the loop now
injects an ephemeral "Continue. Act now." user message and runs another
step rather than treating the turn as completion. Capped at 2 nudges
per run to prevent infinite loops. UI shows "[nudge: continuing…]" so
the user can see what happened.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 11:28:11 +02:00
Levi Neely ab575ee385 backend,agent,main: retry on HTTP 429 with live countdown
Return RateLimitError from openai backend on HTTP 429, parsing the
Retry-After header (integer seconds or HTTP-date). The agent loop retries
up to 3 times with exponential backoff (5s/10s/20s) when no header is
given, emitting per-second countdown ticks. The status bar renders
"retry {N}s" during the wait.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 11:25:05 +02:00
Levi Neely b3c4ea0ad4 main: restore slash command handling lost during streaming refactor
Re-adds handleCommand (/help, /model, /backend) and wires it into the
enter handler so slash commands are processed without starting an agent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 23:56:49 +02:00
Levi Neely f11d1a4d09 exec: remove unused IsPermissionError
No longer called anywhere after the sandbox fallback was removed from anvillm-mcp.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 21:11:22 +02:00
Levi Neely 5aea341255 context: fix budget accounting, tail counting, and output limits
Five improvements for cost/focus efficiency:

1. Budget now accounts for fixed per-request overhead (system prompt +
   tool schemas), which were previously invisible to ContextBuilder and
   could silently exceed intended limits by 30-50%.

2. Tail counting now only counts user and plain-assistant (no tool_calls)
   messages toward TailMessages quota. Processed tool exchanges between
   conversational turns are included but do not crowd out genuine context.
   Trailing in-progress exchanges are always preserved and free.

3. BoundedHistory / BoundedHistoryWithNotice deduplicated into a single
   buildBounded(injectNotice bool) private helper.

4. O(n²) prepend in the greedy inclusion loop replaced with
   append+slices.Reverse.

5. exec.Executor.MaxOutputChars replaces the hardcoded 8000-char const.
   Initialised from OLLIE_TOOL_OUTPUT_CHARS env var, defaults to 8000.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 20:27:16 +02:00
Levi Neely b7d46015d7 agent: simplify loop — Run as function, fix stop condition
- Loop struct and New constructor removed; Run is now a package-level
  function taking (ctx, Config, State)
- Stop condition de-nested: natural stop (no tool calls → MarkComplete
  + break) and step-limit stop (step >= maxSteps-1 → break) are now
  separate, sequential checks instead of a redundant outer/inner pair

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 20:13:14 +02:00
Levi Neely 474eb84e2d agent,backend: drop non-streaming path
Both backends already implement streaming; the non-streaming fallback
was dead code that added complexity.

- Backend interface now requires only ChatStream; the separate
  StreamingBackend interface and Chat method are removed
- Both OpenAIBackend and OllamaBackend lose their Chat methods and the
  stream=bool parameter on their internal doChat helpers
- Loop.Run is simplified: one streaming path, no streamed flag, no
  skippedCalls map, no shouldStop helper, no runStreamStep indirection
- "call" events are now emitted solely in the act phase, not in the
  stream phase, so dedup tracking is no longer needed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 20:11:10 +02:00
Levi Neely f804001d37 main: fix word fusion in streamed output and remap scroll keys
Some backends (DeepInfra, OpenRouter) occasionally emit null or empty
content for whitespace-only tokens, causing adjacent words to fuse
("normaluse" instead of "normal use").  addStreamingContent inserts a
single space at the chunk boundary whenever neither side carries
whitespace.  Safe for LLM streaming because BPE tokens are always
whole — they never split mid-word at the API level.  Rewritten to use
utf8.DecodeLastRuneInString / utf8.DecodeRuneInString instead of raw
byte indexing so multi-byte UTF-8 is handled correctly.

Also remaps viewport scroll keys: half-page to alt+d/alt+u (avoids
conflicting with terminal line-editing on ctrl+d/u) and per-line
scroll to down/up arrows plus alt+n/alt+p (Emacs-style, safe in xterm
and plain tty alike).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 20:06:44 +02:00
Levi Neely 45a32ed4e7 agent: fix conversation history corruption on stream interruption
Two bugs that combined to produce unrecoverable 400 errors from backends:

1. loop.go: runStreamStep returned nil on stream-closed-without-done,
   causing Run to commit a partial assistant message (with no ToolCalls)
   to state even when the backend had already sent tool call frames.
   Now returns a real error so state.Update is never called and the
   session history stays clean for a retry.

2. context.go: BoundedHistory and BoundedHistoryWithNotice could evict
   an assistant[tool_calls] message while its paired tool[result] messages
   remained in the tail window, producing a tool message with no preceding
   assistant — rejected by strict backends (OpenAI, DeepInfra) with a 400.
   Fixed by dropping assistant+tool pairs atomically in the hard-limit loop
   and adding a sanitizeHistory pass that strips any remaining orphaned
   tool messages before the history is returned.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 19:59:45 +02:00