update core submodule (session persistence), sync docs

This commit is contained in:
Levi Neely 2026-05-21 15:08:46 +02:00
parent d08497d287
commit a94454d72b
3 changed files with 69 additions and 25 deletions

2
core

@ -1 +1 @@
Subproject commit 9d4818af8da4ce238181aa83bd9ed0332260f109
Subproject commit 8ae0fad8a302b93d3e13f5b6b6656508f7137b1d

View File

@ -89,7 +89,7 @@ The core is a Go library (`ollie/pkg/`) with no binary. Frontends import it as a
| Package | Purpose |
|---|---|
| `pkg/agent/` | Agent loop, Core interface, Session, TaskState, hooks, prompt resolution |
| `pkg/agent/` | Agent loop, Core interface, Runtime, Session, TaskState, hooks, prompt resolution |
| `pkg/backend/` | Backend interface + implementations (Ollama, OpenAI, Anthropic) |
| `pkg/config/` | Agent config struct and JSON loader |
| `pkg/env/` | Environment variable loading (env file + shell) |
@ -97,6 +97,7 @@ The core is a Go library (`ollie/pkg/`) with no binary. Frontends import it as a
| `pkg/paths/` | Config and data directory resolution |
| `pkg/tools/` | Server and Dispatcher interfaces |
| `pkg/tools/execute/` | The execute.Server (execute_code, call_tool, pipe) |
| `pkg/tools/execute/tool.go` | Named tool script discovery and execution |
| `internal/sandbox/` | Landlock sandbox config and command wrapper |
### Key Interfaces
@ -165,7 +166,7 @@ Safety mechanisms:
`Session` owns the message history as a flat `[]backend.Message` slice. Key behaviors:
- **TaskState**: structured JSON overlay (objective, plan_step, constraints, last_action, next_decision) injected at the top of every turn
- **Compaction**: three-zone strategy when context reaches 75% of model limit:
- **Compaction**: three-zone strategy when context reaches 50% of model limit:
- **Cold zone**: structured task state summary
- **Warm zone**: one-line decision index (10 messages)
- **Hot zone**: last 8 messages verbatim

View File

@ -9,7 +9,8 @@ core/
├── pkg/
│ ├── agent/ The agent engine
│ │ ├── types.go Core interface, Event, PromptFIFO
│ │ ├── core.go AgentCoreConfig, agent struct, NewAgentCore, BuildAgentEnv
│ │ ├── runtime.go Runtime struct (swappable per-agent config)
│ │ ├── core.go AgentCoreConfig, agent struct, NewAgentCore, BuildRuntime
│ │ ├── loop.go The agent loop (run function)
│ │ ├── session.go Session, TaskState, compaction, persistence
│ │ ├── state.go state interface, ResultTier, toolResult
@ -31,6 +32,7 @@ core/
│ └── execute/ The execute.Server
│ ├── server.go Server struct, Decl factory, ListTools, options
│ ├── code.go Step resolution, validation, dispatch routing
│ ├── tool.go Named tool script discovery and execution
│ ├── pipe.go Pipeline stage execution, parallel fan-out
│ ├── flock.go Advisory locking, parallelism classification
│ └── tier.go Result tier classification (hot/warm/cold)
@ -104,37 +106,65 @@ The full construction config:
| `Uname` | Immutable 9P user principal |
| `CWD` | Working directory for tools and prompt |
| `Session` | Pre-existing session to restore (nil = new) |
| `Env` | Pre-built AgentEnv (tools, hooks, prompt, params) |
| `Runtime` | Pre-built *Runtime (tools, hooks, prompt, params) |
| `NewDispatcher` | Factory for fresh Dispatcher on agent switch |
| `NewBackend` | Factory for backend by name |
| `Log` | Logger instance |
| `MaxSteps` | Override agent config's maxSteps |
### BuildAgentEnv
### Runtime
`BuildAgentEnv(cfg, dispatcher, cwd, env)` wires everything together:
The `Runtime` struct holds all per-agent configuration that changes on an `/agent` switch but remains stable across turns. The agent struct stores a pointer to the active Runtime; switching agents replaces it atomically.
```go
type Runtime struct {
Backend backend.Backend
Dispatcher tools.Dispatcher
Hooks Hooks
Preamble string // compiled system prompt
Tools []backend.Tool
Exec toolExecutor
ClassifyTool toolClassifier
ClassifyTier func(string) ResultTier
GenParams backend.GenerationParams
MaxSteps int
ToolResultMaxBytes int // 0 means use default (128KB)
CfgBackend string // backend override from agent JSON
CfgModel string // model override from agent JSON
Messages []string // non-fatal warnings from construction
}
```
### BuildRuntime
`BuildRuntime(cfg, dispatcher, cwd, env)` wires everything together:
1. Lists all tools from the dispatcher
2. Resolves the system prompt by executing the config's `prompt` commands
3. Extracts generation parameters from the config
4. Builds the tool executor closure (routes calls through the dispatcher)
5. Extracts parallelism and tier classifiers from the execute server
6. Returns an `AgentEnv` struct ready for `NewAgentCore`
6. Applies tool/executor restrictions if configured
7. Returns a `*Runtime` struct ready for `NewAgentCore`
### NewAgentCore
Creates the `agent` struct:
Creates the `agent` struct from `AgentCoreConfig`:
1. Sweeps stale tmpdirs from previous crashes
2. Creates `/tmp/ollie/{sessionID}` for this session
3. Sets up the plan file reader (reads `s/{id}/plan` for the next unchecked step)
4. Wires the `turnError` hook with a detached context
5. Pushes `OLLIE_SESSION_ID` and `OLLIE_UNAME` into the execute server env
6. Sets the flock directory for parallel coordination
2. Stores the provided `Runtime` (or creates an empty one)
3. Sets the backend model if `ModelName` is specified
4. Creates `/tmp/ollie/{sessionID}` for this session
5. Sets up the plan file reader (reads `s/{id}/plan` for the next unchecked step)
6. Wires the `turnError` hook with a detached context
7. Pushes `OLLIE_SESSION_ID` and `OLLIE_UNAME` into the execute server env
8. Sets the flock directory for parallel coordination
## The Agent Loop (`pkg/agent/loop.go`)
The `run()` function is the core execution engine. It takes an `agentConfig` and a `state` interface, and loops until the model stops calling tools.
The `agentConfig` struct bundles per-turn dependencies: `Backend`, `Tools`, `Exec` (tool executor closure), `ClassifyTool`/`ClassifyTier` (parallelism and retention classifiers), `ToolResultMaxBytes`, `Output` (event handler), `preamble`, `GenerationParams`, and lifecycle callbacks: `PopInject`, `AutoCompact`, `SaveSession`, `PreTool`, `PostTool`, `TurnError`, `MaxSteps`, `ReadPlanStep`, and `IncrToolCallCount`.
### Per-Iteration Flow
```
@ -208,6 +238,8 @@ After each tool round, `inferTaskStateUpdate` updates the structured overlay:
`Session` holds a flat `[]backend.Message` slice. No rolling window — grows until compaction.
**Checkpoint**: `Session.Checkpoint(ts TaskState)` forks the session — returns a new Session that inherits the given TaskState but starts with a clean message history. Used for narrow-context sub-agents that know what to do without inheriting parent message noise.
Token tracking per session:
- `TotalInputTokens`, `TotalOutputTokens`, `TotalRequests`
- `TotalCachedInputTokens`, `TotalCacheCreationTokens`
@ -216,7 +248,7 @@ Token tracking per session:
### Compaction
Triggered when estimated tokens reach 75% of model context length.
Triggered when estimated tokens reach 50% of model context length.
**Three-zone strategy:**
@ -289,27 +321,38 @@ Multiple commands per hook run sequentially. If any exits 2, execution stops imm
| Prefix | Dispatch |
|---|---|
| `!<cmd>` | Shell command in session CWD |
| `/backend <name>` | Switch LLM backend |
| `/model <name>` | Switch model |
| `/agent <name>` | Switch agent config (rebuilds dispatcher) |
| `/compact` | Manual compaction |
| `/context` | Show message breakdown |
| `/usage` | Show token counts |
| `/cost` | Show cost |
| `/backend [name]` | Show or switch LLM backend |
| `/model [name]` | Show or switch model |
| `/models` | List available models |
| `/agent [name]` | Show or switch agent config (rebuilds Runtime) |
| `/agents` | List available agents |
| `/maxsteps [n]` | Get/set max steps |
| `/maxsteps [n]` | Get/set max steps (0 = unlimited) |
| `/compact` | Manual compaction |
| `/context` | Show context size and message breakdown |
| `/usage` | Show token usage and context percentage |
| `/cost` | Show last turn and session cost |
| `/history` | Dump bounded message history |
| `/sessions` | List saved sessions |
| `/clear` | Clear session (reset context) |
| `/kill` | Kill session |
| `/rn <name>` | Rename session |
| `/cwd [path]` | Show or change working directory |
| `/skills` | List available skills |
| `/tools` | List available tools |
| `/sp` | Show rendered system prompt |
| `/i <prompt>` | Inject into running turn |
| `/irw <prompt>` | Inject-rewrite |
| `/queued [pop\|clear]` | Manage queued prompts |
| `/help` | Show command help |
### Agent Switching
When `/agent <name>` is issued:
1. Load the new agent config JSON
2. Create a fresh dispatcher via `newDispatcher()`
3. Call `BuildAgentEnv` with the new config
3. Call `BuildRuntime` with the new config
4. If the config specifies a backend/model, switch those too
5. Replace dispatcher, hooks, prompt, tools, params on the agent struct
5. Replace the entire `Runtime` pointer on the agent struct
6. Clear the session (fresh context for the new persona)
## Tool System (`pkg/tools/`)