- 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
- 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.
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.
- steps: independent, run in parallel when annotated safe, outputs
concatenated. No stdout chaining.
- pipe: explicit pipeline, sequential, stdout of each stage feeds
stdin of the next.
steps and pipe are mutually exclusive in a single execute_code call.
steps is always a pipe (sequential, stdout chains to next stdin).
Concurrent fan-out requires explicit use of the parallel field.
The ollie:parallel annotation still drives agent-level tool call
parallelism via IsParallelRead, but no longer hijacks pipe semantics.
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.
- 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.
- 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
WrapCommand now returns an error instead of silently falling back to
unsandboxed execution when landrun is not in PATH. execute_code
propagates this as a hard failure.
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.
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.
When tools is false in agent config, BuildAgentEnv skips ListTools
entirely so no tool schemas are sent to the backend. Models without
tool support now work cleanly.