Previously loadSandboxConfig was called unconditionally, causing
failures on hosts without ~/.config/ollie/sandbox/ even when yolo
mode was enabled. Move the load inside the !Yolo branch.
Package remote provides a tools.Server implementation that forwards
tool calls to an ollie-remote process over SSH via JSON-RPC.
Key components:
- Dial(): opens SSH, launches ollie-remote, verifies with ping
- Server: implements tools.Server, forwards CallTool over RPC
- Decl(): factory compatible with tools.NewDispatcherFunc
- Config: SSH target, CWD, tools path, yolo flag
Integration: swap execute.Decl() with remote.Decl() in session
creation when remote= config is set.
Add ensureElevateAdapter() which probes the adapter socket and starts
elevate-adapter-start if unreachable. Runs in the execute server
process (outside the sandbox) so the adapter starts unsandboxed.
Track Total, Succeeded, Failed counts and FailedCmds in HookResult.
Add Summary() method producing "(N of X hooks run) (K of X failed: cmd)".
Emit hook summary as info event at all lifecycle hook call sites and
on preTool/postTool failure.
All backend constructors now use SharedClient() which returns an
*http.Client backed by a per-host shared *http.Transport. This enables
HTTP/2 multiplexing: multiple sessions targeting the same API host
share a single TLS connection instead of each maintaining their own.
The pool is keyed by "backend:baseURL" so different endpoints get
separate transports while same-host sessions multiplex.
Route() now queries all configured backends for their model lists,
presents them numbered to the classifier, and parses the number.
No more hardcoded OLLIE_ROUTE_MODEL_FAST/POWER env vars.
The management.*.kiro.dev endpoint was slower/less reliable. Switch to
the same q.<region>.amazonaws.com endpoint that kiro-cli uses, deriving
the region from the profile ARN or runtime endpoint.
Models() now caches at the backend level (shared across sessions) with
a 24h TTL, eliminating repeated expensive HTTP calls to AWS.
The sqliteKiroAuth.load() now caches token reads for 60s, avoiding
shelling out to sqlite3 on every API call (previously 3x per Models
fetch).
Rewrite executeElevated to use the same select/detachCh pattern as
executeWithStdin. When both elevated and detach are set, the process
is immediately backgrounded into the detach registry with streaming
output captured in the ring buffer.
Also adds the detach field to the execute_code JSON schema description.
When detach: true is set on a CodeStep, the process is immediately
backgrounded after start. Its stdout/stderr are captured in a 64KB
ring buffer accessible via GetDetachedOutput. The agent can then
inspect and manage the process via process_list/process_output tools.
After detach, cmd.WaitDelay was still 1s, causing Go exec to
kill the process after context cancellation + 1s delay. Clear
both cmd.Cancel and cmd.WaitDelay in the detach path.
When a detached process exits, its output (last 2KB of ring buffer)
is queued as a prompt wrapped in <detached-process-result> tags.
The agent sees it on its next turn (or immediately if idle via Queue).
- InjectSystemEvent(content) added to Core interface
- SetOnExit(fn) added to execute.Server for external hook wiring
Adds Detach, ListDetached, SignalDetached, GetDetachedOutput,
DismissDetached to the Core interface. Implemented on agent struct
via interface type assertions to the execute server.
Also adds ListDetachedRaw() to execute.Server for cross-package
consumption without import cycles.
Allows the user to detach a running process from the agent mid-execution.
The process continues running; output flows to a 64KB ring buffer.
Detached processes can be listed, signaled (TERM/KILL), and dismissed.
- DetachedProcess struct with ring buffer, signal, output methods
- Server.Detach() signals the currently executing process to detach
- Execute() rewritten: cmd.Start() + select on wait/ctx/detach
- cleanupDetached() on Close() sends SIGTERM to all
- OnDetach/OnExit hooks for integration with D-Bus layer
- Add Backend/Model fields to PersistedSession for full restore metadata
- Add saveToFull() that includes backend/model in persisted state
- Add exported LoadPersistedSession(path) helper
- Add SaveSession(path) to Core interface, implemented on agent struct
- Existing saveTo() preserved as backward-compatible wrapper
- Remove IsSocial guard from sqliteKiroAuth.ProfileARN(); the Kiro API
now requires profileArn on all requests including personal accounts
- Add OLLIE_KIRO_PROFILE_ARN env var for static token auth
- Add repeated error detection (3x identical error triggers corrective nudge)
- Include expected format in tool dispatch error messages
- Switch endpoint from q.*.amazonaws.com to runtime.*.kiro.dev
- Use management.*.kiro.dev for ListModels
- Fix content encoding: plain string instead of json.RawMessage
- Fix tool results: always use text field (upstream rejects bare JSON primitives)
- Normalize tool call arguments (deduplicate keys)
- Expand retry conditions: add 502, 503, 408, InsufficientModelCapacity
- Add SQLite busy-timeout and Go-level retry for lock contention
- Add 30s refresh timeout and fullLoad before refresh
- Add SSO cache fallback for token refresh
- Add jitter to token expiry checks
- Add sqliteHasNewUsableAccessToken for cross-process recovery
- Add envState to current message
- Update user-agent strings to 1.3.15/2.5.1
- Set X-Amzn-Codewhisperer-Optout to true
- Add reasoning/thinking support (additionalModelRequestFields)
- Add counter-thinking tags on user messages before assistants
- Handle reasoningContentEvent in stream
The Kiro/CodeWhisperer API started rejecting tool-use requests from
older API versions (0.1.14474) with InternalServerException. Update
to 0.1.16551 and appVersion 0.12.333 to match kiro-cli.
Also add retry with linear backoff (1-5s) for transient 500 errors
which still occur intermittently even with the correct version.
Moved all 9P FUSE mount code from core to 9p module using lifecycle hooks.
Changes:
- Removed 9P-specific fields (mountProc, mountPath, mountEnabled) from execute.Server
- Removed WithMount(), MountPath(), startMount(), remountIfStale() functions
- Added lifecycle hooks: OnPreDispatch, OnClose, OnEnvSet with corresponding options
- Updated SetEnv(), Close(), and Dispatch() to call hooks instead of hardcoded mount logic
- Fixed tool descriptions to use $OLLIE_TOOLS_PATH instead of 9P-specific $OLLIE/s/$SID/t paths
- Removed unused execute import from agent/commands.go
The core execute server is now harness-agnostic.
SetCWD now replaces old cwd references in the system prompt,
matching the pattern used by SetSessionID. Without this, the
model continued to see the original cwd in its environment
section after a directory change.
- Add ListHandlers map to AgentCoreConfig/agent struct; /skills and /tools
dispatch through it instead of reading local paths directly
- Add ReadPlanStep to AgentCoreConfig; wired by 9p/ directly from sess.plan
- Export NextUncheckedStep([]byte) as pure helper
- Fix prependOlliePath to use OLLIE_CFG_PATH/scripts/x/ instead of $OLLIE/x/
- Add OLLIE_CFG_PATH to EnsureDefaults and managed env var list
- store all tool results verbatim at update time
- stripColdResults now calls LLM to summarize, skips hot tail
- stripCold interface takes ctx+backend
- remove stripColdResults from RestoreSession
DeepSeek requires reasoning_content to be echoed back on assistant
messages. Store reasoning from stream events on Message and serialize
it as reasoning_content in the OpenAI wire format.
TestBuildAnthropicMessages_UserImageBlocks: user message with ContentBlocks
TestBuildAnthropicMessages_ToolImageBlocks: tool result with image blocks
TestBuildAnthropicMessages_UserPlainTextFallback: nil ContentBlocks uses Content
TestEncodeMessages_UserWithImageContentBlocks: OpenAI image_url encoding
TestEncodeMessages_UserWithImageContentBlocks_JSON: wire format verification
Add canonical ContentBlock and ImageSource types to backend.go.
When Message.ContentBlocks is set, it takes precedence over Content.
Anthropic: new anthropicImageSource type, anthropicContentBlocks() helper
converts canonical blocks to wire format. buildAnthropicMessages handles
ContentBlocks on user and tool messages.
OpenAI: new openAIImageURL type, openAIContentBlocks() helper converts
canonical blocks to wire format (image_url with data: URIs).
encodeOpenAIMessages uses ContentBlocks when present.
Retry up to 5 times with exponential backoff (5s, 10s, 20s, 40s, 80s)
when the Kiro backend returns ThrottlingException or HTTP 429.
Previously these errors were sent as a fatal StopReason, causing the
agent loop to abort immediately.
After compaction, the loop was discarding cold+warm zones and only
sending the last 8 messages to the backend. This caused the agent to
lose context after manual or auto compaction.
Remove the recentHistory path entirely: state.history() already
returns the compacted (small) history post-compact. The TaskState
render block remains as additional steering injected after the system
prompt.
Removed: StepContext struct, recentHistory from state interface and
Session.
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).
Copilot API has no /v1 prefix. Add pathPrefix field to OpenAIBackend
(defaults to /v1) and apply extraHeaders in fetchModels. Copilot sets
pathPrefix to / so it hits /models and /chat/completions directly.
LoadFile was setting env vars with literal quotes intact, causing
API keys like OLLIE_GEMINI_KEY to fail auth when loaded from the
env file at olliesrv startup.
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.
- 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