Skip to content

Commit f4ca416

Browse files
committed
docs: document v0.36.0/v0.36.1 — parallel tool execution + batch approval gate
- CHANGELOG.md: v0.36.0 (parallel exec) + v0.36.1 (Phase 1.5 batch gate) - API.md: document MaxToolParallel, Approver fields on Config - CONFIG.md: add max_tool_parallel reference, env var, sample JSON - AGENTS.md: add parallel exec + batch gate to conventions and gotchas
1 parent e71dedf commit f4ca416

4 files changed

Lines changed: 87 additions & 1 deletion

File tree

AGENTS.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ docs/ Documentation (CLI, API, CONFIG, MCP, MEMORY, etc.
6060
- **Config structs:** JSON tags for serialization. `*bool` for optional tristate fields (nil = not set).
6161
- **Security:** Symlinked AGENTS.md is refused. Shell commands are classified into 8 risk classes. Sandbox mode uses Docker with no network and read-only mounts.
6262
- **Model profiles:** Added in `odek.go`'s `KnownProfiles` var. Longest-prefix matching.
63+
- **Parallel tool execution:** When the LLM returns multiple `tool_calls` in one response, they execute concurrently via goroutines with a channel semaphore (default cap: 4). Results are collected in original call order.
64+
- **Batch approval gate:** When an approver is set and > 1 tool calls per iteration, a single batch approval prompt fires before Phase 2. If approved, `SetTrustAll(true)` is called on the approver to bypass individual tool-level prompts.
6365

6466
## How to Update/Maintain This Project
6567

@@ -156,3 +158,6 @@ Edit `odek.go`, add to `KnownProfiles`:
156158
- Session files are JSON in `~/.odek/sessions/` — corrupt data is handled gracefully with fallback scan.
157159
- The Telegram bot uses long-polling (no webhooks), built on stdlib `net/http`.
158160
- `delegate_tasks` sub-agents have a 120s default timeout. Override via `subagent.timeout_seconds` config.
161+
- **Parallel tool tests** use `timedTool` with configurable delays — always run with `-race` to catch data races on the results slice.
162+
- **Batch approval gate** (`Phase 1.5`) checks `e.approver != nil && len(result.ToolCalls) > 1` — single-tool responses skip the gate. When adding a new approver implementation, implement `SetTrustAll(bool)` to benefit from batch trust cascade.
163+
- **SetTrustAll** is bounded by `defer` — it's enabled before Phase 2 and disabled when `runLoop` returns. The mockApprover's `trustAll` field will be `false` after `Run()` returns because the deferred `SetTrustAll(false)` runs first.

docs/API.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,24 @@ type Config struct {
156156
// Memory system configuration (facts, buffer, episodes).
157157
// Default: memory.DefaultMemoryConfig()
158158
MemoryConfig memory.MemoryConfig
159+
160+
// PromptCaching enables prompt caching markers for supported
161+
// providers (Anthropic, DeepSeek, OpenAI). When enabled, the
162+
// system prompt and first user message are annotated for cache.
163+
// Default: false (no cache markers)
164+
PromptCaching bool
165+
166+
// MaxToolParallel controls tool call concurrency per iteration.
167+
// When the LLM emits multiple tool calls in one response, they
168+
// execute concurrently — this caps the max simultaneous goroutines.
169+
// 0 = use default (4). I/O-bound tools benefit most.
170+
MaxToolParallel int
171+
172+
// Approver gates dangerous tool operations. When set and the LLM
173+
// returns multiple tool calls in one iteration, a single batch
174+
// approval prompt is shown instead of N individual prompts.
175+
// If denied, no tools run for that iteration.
176+
Approver danger.Approver
159177
}
160178
```
161179

docs/CHANGELOG.md

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,55 @@
11
# Changelog
22

3-
## v0.34.0 (2026-05-23) — secrets.env Auto-Load + File Attachments
3+
## v0.36.1 (2026-05-23) — Phase 1.5: Batch Approval Gate
4+
5+
### Parallel Approval Fix
6+
- When the LLM returns **multiple tool calls** in one iteration and an **approver is set**, the engine now shows a **single batch approval prompt** instead of N concurrent inline keyboards
7+
- If denied, all tools are rejected with `"error: batch approval denied"` without executing anything
8+
- If approved, `SetTrustAll(true)` is called on the approver so individual tool-level `PromptCommand` calls auto-pass during that iteration
9+
- Single tool calls (≤1 per iteration) skip the batch gate entirely — no behavior change
10+
11+
### New Method: `SetTrustAll(bool)`
12+
Added to all three approver implementations:
13+
- **`TTYApprover`** — skips `/dev/tty` prompt when enabled
14+
- **`TelegramApprover`** — skips inline keyboard prompt when enabled
15+
- **`wsApprover`** — skips WebSocket approval when enabled
16+
17+
### API: `Config.Approver`
18+
- New `Approver danger.Approver` field on `odek.Config`
19+
- Wired through `odek.New()``loop.Engine.SetApprover()`
20+
- Telegram handler passes per-chat `TelegramApprover` to the agent config
21+
22+
### Test Coverage
23+
- 3 batch approval tests: denied, approved, single-tool skip
24+
- All tests pass with `-race`
25+
26+
---
27+
28+
## v0.36.0 (2026-05-23) — Parallel Tool Execution
29+
30+
### Parallel Execution
31+
- When the LLM returns multiple tool calls in one response, tools now execute **concurrently** in goroutines (was: sequential)
32+
- **Bounded semaphore** — at most `max_tool_parallel` goroutines run simultaneously (default: 4)
33+
- I/O-bound tools (read_file, search_files, shell, web_search) benefit most — latency drops from `sum(latencies)` to `max(latency)`
34+
- Configurable via `max_tool_parallel` in config or `ODEK_MAX_TOOL_PARALLEL` env var
35+
36+
### Three-Phase Implementation
37+
1. **Phase 1 (sync)** — fire all `tool_call` events + narrator/rendering so the user sees progress immediately
38+
2. **Phase 2 (parallel)** — N goroutines execute tools concurrently via channel semaphore
39+
3. **Phase 3 (sync)** — drain semaphore, compress large outputs, append results in **original call order**
40+
41+
### Config
42+
- `MaxToolParallel int` on `loop.Engine` and `odek.Config` (0 = default 4)
43+
- `max_tool_parallel` in FileConfig (`internal/config/loader.go`)
44+
- Wired through CLI, Telegram, and serve entry points
45+
46+
### Test Coverage
47+
- 6 parallelism tests: latency (4×100ms → ~100ms vs 400ms), ordering, semaphore cap (6 tools, cap=2), default cap, error resilience, single tool
48+
- All tests pass with `-race`
49+
50+
---
51+
52+
## v0.35.1 (2026-05-23) — secrets.env Auto-Load + File Attachments
453

554
### Secrets Management
655
- **`~/.odek/secrets.env` auto-loaded** as Layer 0 in the config priority chain — parsed before any config file or env var lookup

docs/CONFIG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Shared across all projects:
3838
"interaction_mode": "engaging",
3939
"no_color": false,
4040
"no_agents": false,
41+
"max_tool_parallel": 4,
4142
"system": ""
4243
}
4344
```
@@ -107,11 +108,24 @@ Every config knob has a `ODEK_*` counterpart:
107108
| `ODEK_SANDBOX_MEMORY` | `--sandbox-memory` | string |
108109
| `ODEK_SANDBOX_CPUS` | `--sandbox-cpus` | string |
109110
| `ODEK_SANDBOX_USER` | `--sandbox-user` | string |
111+
| `ODEK_MAX_TOOL_PARALLEL` | `max_tool_parallel` | int |
110112

111113
## API key fallback order
112114

113115
`ODEK_API_KEY``DEEPSEEK_API_KEY``OPENAI_API_KEY`
114116

117+
## Parallel tool execution
118+
119+
When a model emits multiple tool calls in one response (`tool_calls` array with N entries), odek executes them **concurrently** in goroutines bounded by a semaphore.
120+
121+
| Field | Default | Env var | Description |
122+
|-------|---------|---------|-------------|
123+
| `max_tool_parallel` | `4` | `ODEK_MAX_TOOL_PARALLEL` | Max concurrent tool calls per iteration. 0 = default 4. Set to 1 for sequential execution. |
124+
125+
I/O-bound tools (read_file, search_files, shell) benefit most — latency drops from `sum(latencies)` to `max(latency)`.
126+
127+
**Approval gate:** When an approver is configured and the LLM returns multiple tool calls, a single batch approval prompt is shown before any tool executes. If approved, all tools run in parallel. If denied, no tools run.
128+
115129
## Skills configuration
116130

117131
The `skills` section controls the skill system:

0 commit comments

Comments
 (0)