Commit Graph

211 Commits

Author SHA1 Message Date
Levi Neely 9d6800a51c agent: parse text-based tool calls instead of failing
Models that don't support native function calling emit tool calls as
plain text. Instead of treating this as ToolUnsupportedError, parse the
text and execute the tool calls normally.

Handles both direct JSON and shorthand (key=value) formats with relaxed
JSON support (unquoted keys).
2026-05-23 11:46:49 +02:00
Levi Neely 47f8eed119 agent: remove unsandboxed ! shell escape
The ! prefix allowed arbitrary command execution without sandbox
protection. Since agents share the same Submit path as users, this
was a sandbox bypass vector. Remove it entirely; users who need
shell access can use execute_code (sandboxed) or run commands
directly in their terminal.
2026-05-21 15:18:02 +02:00
Levi Neely 8ae0fad8a3 session persistence: /save, /resume, cwd-scoped /sessions
- Add CWD field to PersistedSession for per-directory filtering
- /sessions now shows only sessions matching current cwd (-a for all)
- /save <name> creates a named checkpoint
- /resume <id> restores a saved session (messages + task state)
- Autosave (already existed) now persists cwd with each save
2026-05-21 15:08:16 +02:00
Levi Neely 9d4818af8d refactor agent core: extract runtime, simplify commands 2026-05-21 14:42:45 +02:00
Levi Neely 82ac183357 add OLLIE_DEFAULT_AGENT support and update agent commands 2026-05-21 12:33:18 +02:00
Levi Neely fa9c98fb05 agent: add exec event role for ! command output
Shell command output uses a dedicated "exec" role instead of "info",
formatted with ``` fences in the chat log.
2026-05-20 16:49:41 +02:00
Levi Neely 1479aea274 agent: publish events on pubsub bus, self-drain queue
- Add pubsub.Bus to agent; all events published on "event" topic
- Remove EventHandler param from Submit (and internal methods)
- Queue() self-drains via goroutine when agent is idle
- /i submits directly when idle, injects when running
2026-05-20 16:45:32 +02:00
Levi Neely 5099ccf51d /agent: preserve session ID when switching agents 2026-05-20 10:57:04 +02:00
Levi Neely 82df12e293 add test for SetSessionID preamble update 2026-05-20 10:50:20 +02:00
Levi Neely 09a9364b6f SetSessionID: update session ID in system prompt on rename 2026-05-20 10:47:56 +02:00
Levi Neely ccacdc4ec8 fix: clear OLLIE env in tests to prevent FUSE mount hangs 2026-05-19 15:20:31 +02:00
Levi Neely 1e96d4c7f4 agent: separate uname (principal) from session ID
Session identity is now a numeric UID (starting at 10000) assigned at
creation and never changed. Session names can be renamed freely without
affecting the 9P identity.

- AgentCoreConfig.Uname carries the principal
- pushSessionEnv sets OLLIE_UNAME on the execute server
- startMount gated by WithMount() option (not env var)
- Close() uses context timeout to avoid hanging on fusermount
2026-05-19 15:06:16 +02:00
Levi Neely e20f9a7a06 execute: per-session FUSE mount for 9P identity
The execute server now starts ollie-9p-mount when OLLIE_SESSION_ID is
set, giving each agent session its own FUSE proxy that attaches to
olliesrv with Uname=session_id. Tools see the full namespace through
$OLLIE but all 9P operations carry the session's identity.

Close() tears down the mount on session destroy.
2026-05-19 14:10:09 +02:00
Levi Neely 5efed7040d fix: inject OLLIE_SESSION_ID into prompt resolution subprocesses
resolveExecPrompt spawns x/prime which uses envsubst to expand
${OLLIE_SESSION_ID} in the system prompt template. The variable was
never in the process environment at resolution time — it was only
set on the execute server after the prompt was already rendered.

Add env []string parameter to resolvePrompt/resolveExecPrompt and
BuildAgentEnv so callers can inject session-scoped vars into the
subprocess environment. Generate session ID before BuildAgentEnv in
the agent-switch path so it is available at prompt resolution time.
2026-05-18 12:31:35 +02:00
Levi Neely 1207e26a07 remove trustedTools and Confirm callback; trust is implicit via allowExecutors 2026-05-17 15:21:26 +02:00
Levi Neely 93c0b374d5 truncation: avoid mid-rune cut with ToValidUTF8 2026-05-17 12:59:49 +02:00
Levi Neely 7237980ff5 truncation: raise hard ceiling to 128KB, include tool name in message 2026-05-17 12:51:43 +02:00
Levi Neely 011843a59d loop: per-step budgets — replan gate (8 rounds) and stall detection (5 rounds) 2026-05-17 12:13:26 +02:00
Levi Neely 8be8b9c42d task state: read PlanStep from plan file (ground truth) with text fallback 2026-05-17 11:09:44 +02:00
Levi Neely 837c95c483 state: expose estimateTokens/stripCold on interface; remove type assertion 2026-05-17 11:06:45 +02:00
Levi Neely 62774e60a6 session: strip cold results at restore time to eliminate resume hot spot 2026-05-17 11:05:27 +02:00
Levi Neely d1ac24fb1d loop: auto-infer TaskState from actual tool results each round 2026-05-17 11:04:55 +02:00
Levi Neely 1cf171adae loop: proactive cold stripping at 50% context budget before backend call 2026-05-17 11:01:21 +02:00
Levi Neely 779b99fd9b tool results: tier classification (hot/warm/cold) with immediate cold summarization 2026-05-17 10:59:17 +02:00
Levi Neely da36db8f2b loop: introduce StepContext — per-turn context object assembled once 2026-05-17 10:54:10 +02:00
Levi Neely fa88c89369 compact: tiered compaction — cold (summary), warm (decision index), hot (verbatim tail) 2026-05-17 10:52:48 +02:00
Levi Neely ea4a3084e0 session: add Checkpoint for typed subflow handoff 2026-05-17 10:15:24 +02:00
Levi Neely b5b2ee43ec loop: replace plan file re-injection with structured TaskState re-injection 2026-05-17 10:14:44 +02:00
Levi Neely 283a2e24d8 state: extend interface with recentHistory/taskState; loop uses selective context 2026-05-17 10:10:33 +02:00
Levi Neely 54351e8c85 compact: structured TaskState compaction with recent message tail 2026-05-17 10:08:33 +02:00
Levi Neely b775e5df7a agent: add TaskState — persisted structured overlay injected at each turn 2026-05-17 10:06:21 +02:00
Levi Neely 45959cb79d agent: apply config backend/model when switching agents via /agent 2026-05-17 00:19:55 +02:00
Levi Neely 22d72f143d fix: wire allowExecutors/allowTools in BuildAgentEnv; add missing IncrToolCallCount field 2026-05-17 00:05:34 +02:00
Levi Neely 3867d52689 add generation params: top_p, top_k, min_p, top_a, repetition_penalty, max_completion_tokens, response_format, reasoning_effort, include_reasoning, stop, verbosity 2026-05-16 23:54:04 +02:00
Levi Neely 6dfae368d0 fix: wire PlanFile, add missing rate-limit constants, simplify test helpers, fix regex
- Wire PlanFile from $OLLIE/s/{id}/plan into agentConfig so plan
  re-injection is no longer dead code
- Add missing failureWindow/maxFailures/blockDuration constants
- Replace hand-rolled contains() with strings.Contains
- Fix rm -rf .. regex to match end-of-string and whitespace
- Add TestPlanReinjection covering periodic plan re-surfacing
- Add loop_maxsteps_helpers_test.go with mockResponse/newState/sequentialStream
2026-05-16 23:54:04 +02:00
Levi Neely 2101a2c023 agent: add MaxSteps override in AgentCoreConfig and /maxsteps command
- AgentCoreConfig.MaxSteps: when non-zero, overrides the value loaded
  from the agent JSON (cfg.Env.maxSteps). Zero means "use the agent
  JSON value, or unlimited if absent". Callers (9p frontend, httpgw,
  CLI) can now inject a per-session limit at construction time without
  touching any agent config file.

- /maxsteps [n] command: shows the current limit (0 = unlimited) or
  sets it live during a session. Follows the same pattern as /model.
  Added to /help listing.
2026-05-16 18:56:39 +00:00
Levi Neely d8467a4f16 agent: add ToolCallCount to Core interface; wire tcct accumulator
Adds a monotonically increasing tool-call counter (tcct) to the agent.

- atomic.Int64 toolCallCount on the agent struct
- ToolCallCount() int64 on the Core interface
- IncrToolCallCount func() int64 on agentConfig, wired in executeTurn
- Incremented in execOne after the pre-tool hook returns (blocked calls
  don't count) and before cfg.Exec is called (timeout/error still counts)

The counter never resets. Consumers use modulo arithmetic:
  tcct % 10 == 0  ->  fires every 10 actual executions

The primary consumer is ollie-9p, which exposes tcct as a read-only
9P file that pre_tool / post_tool hooks can inspect via cat.
2026-05-15 20:16:43 +00:00
Levi Neely 4fdf5e042d loop: re-surface plan file every 10 tool rounds; nudge includes plan reminder 2026-05-15 19:48:13 +00:00
Levi Neely 0d9405f9bc core: read MaxSteps from config into agentConfig 2026-05-15 19:33:44 +00:00
Levi Neely c20a5203ca agent: add MaxSteps soft guardrail to agentConfig and loop 2026-05-15 19:25:10 +00:00
Levi Neely b6308f1a13 agent: log prompt resolution errors to stderr 2026-05-11 14:13:44 +02:00
Levi Neely 76697ab597 fix TestCommand_Agents_Empty: set OLLIE_AGENTS_PATH 2026-05-08 13:02:03 +02:00
Levi Neely a2b6adb6cf env: add OLLIE_AGENTS_PATH with colon-separated multi-dir resolution 2026-05-08 13:01:04 +02:00
Levi Neely 0041fc77ec add OLLIE_PROMPTS_PATH env var and PromptsDirs helper 2026-05-08 11:59:16 +02:00
Levi Neely 1279f10218 fix: remove cancelled tool calls from assistant messages
After interrupt, tool results with cancelled status are removed but
the assistant message kept its ToolCalls referencing them, causing
'Improperly formed request' errors.

Now also strips cancelled tool call IDs from assistant messages.
Only removes the assistant message entirely if it has zero remaining
tool calls AND no text content.
2026-05-04 16:54:04 +02:00
Levi Neely e6233626bc speed up agent tests
- Add configurable retryBaseDelay and streamDropBaseDelay for tests
- Fix hook kill: don't wait for done channel after Kill() since child
  processes may keep stdout/stderr pipes open
- Update tests to use short delays

Tests now run in ~0.4s instead of ~59s.
2026-05-04 11:58:01 +02:00
Levi Neely a9c7600d6e prompt: remove newline heuristic from exec prompt
All array entries in prompt config are now shell commands.
Removes the special case that treated entries with newlines as literal text.
2026-05-04 11:33:16 +02:00
Levi Neely f9b2b50274 agent: preserve completed work on interrupt/error
- On interrupt or error, keep user message, assistant response, and
  completed tool results (success or error)
- Only remove cancelled/interrupted tool results
- Use deep copy for message snapshots to prevent aliasing bugs
- Snapshot now only used for context overflow retry
2026-05-04 10:23:56 +02:00
Levi Neely 6422c365b7 agent: deduplicate identical tool calls within parallel batches
Identical read-safe tool calls in the same batch now execute only
once. Duplicates get the result copied with the correct ToolCallID.
Fixes a race where concurrent goroutines both missed the cache
before either could store, causing double execution.
2026-05-03 21:27:46 +02:00
Levi Neely 3c5d92b461 agent: roll back session on interrupt, clean error message
On user interrupt (stop/CTRL+C), the session history now rolls back
to the pre-turn snapshot instead of keeping partial/cancelled tool
results in the model's context. This prevents raw errors like
'context canceled' from poisoning subsequent turns.

Tool results interrupted by cancellation now report 'tool execution
interrupted by user' instead of the raw Go error chain.
2026-05-03 21:10:28 +02:00