Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions config/gemini-flex.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
models:
default: openrouter/google/gemini-3.1-flash-lite
providers:
openrouter:
type: openai-compatible
baseURL: https://openrouter.ai/api/v1
apiKeyEnv: OPENROUTER_API_KEY
supportsStructuredOutputs: true
service_tier: flex
38 changes: 36 additions & 2 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,10 +229,15 @@ The core runtime should expose a small command/event boundary:
client command
-> runtime command handler
-> KB-aware agent loop
-> typed runtime events
-> typed runtime event stream
-> TUI, CLI, GUI, IDE, or session log consumer
```

For chat turns, `submitMessageStream(...)` is the primary in-process contract:
clients consume an `AsyncIterable` of runtime events as the model and tools
progress. `submitMessage(...)` remains as a compatibility collector for callers
that still need the completed event array or the older callback shape.

Initial command types:

- submit a user message,
Expand All @@ -251,12 +256,41 @@ Initial event types:
- user choice requested,
- turn finished or failed.

This is enough structure to keep rendering code out of the runtime and runtime policy out of rendering code.
This is enough structure to keep rendering code out of the runtime and runtime policy out of rendering code. Stream consumers should persist or render events as they arrive; they should not own the agent loop.

Do not add a big global event bus in V0. A global bus can make small apps feel clean at first, but it hides ownership when every module can publish anything. Start with typed runtime events and explicit subscribers. The session event log should be the durable event stream; the in-process event path should stay narrow and boring.

If plugins, background jobs, or multiple clients need fan-out later, add a scoped event hub around the runtime/session boundary. Keep events named, versioned, and tied to the session log shape.

## Agent Profiles And Tool Permissions

Runtime turns execute under an agent profile. The primary profile uses the normal
model slot and can see the full registered tool set. Subagent profiles can add
prompt instructions, choose a model slot, and narrow the tool set.

Tool permissions are enforced twice:

- prompt/model schema filtering hides denied tools from the model-facing tool list;
- execution-time checks reject denied tools even if a model emits one anyway.

Permission composition is monotonic for subagents: a child profile can reduce
the parent permission view, but parent-denied tools remain denied and cannot be
reintroduced by the child profile.

The `task` tool is the first subagent entrypoint. It creates a real child
session, runs the delegated prompt under a subagent profile, forwards child
runtime events to the parent stream, and returns one bounded result to the
parent model.

Tool definitions can opt into parallel scheduling with metadata:

- `parallelSafe` marks tools that may run alongside other safe tools.
- `mutatesWorkspace` and `requiresExclusiveWorkspace` keep write, Git mutation, command, and unknown tools sequential by default.
- `resourceKeys(args)` gives future schedulers a stable conflict key, such as a file path or Git scope.

Only explicitly read-only tools are marked parallel-safe initially. Unknown or
unmarked tools remain sequential.

## Future GUI / IDE Path

The TUI should be only one client of the same KB-aware runtime.
Expand Down
5 changes: 5 additions & 0 deletions docs/MODEL_CONFIG.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ For agent turns, Topchester tries native OpenAI-compatible tool calls first. If

OpenRouter requests that try native tools include internal routing hints so OpenRouter should pick an upstream that can accept tool parameters. This is automatic for providers named like `openrouter` or using an OpenRouter base URL.

Topchester also adds default `HTTP-Referer` and `X-Title` attribution headers for OpenRouter providers unless the config sets those header names explicitly.

Advanced debugging overrides are available but should stay out of normal examples:

```jsonc
Expand All @@ -143,6 +145,7 @@ Advanced debugging overrides are available but should stay out of normal example
"type": "openai-compatible",
"baseURL": "https://openrouter.ai/api/v1",
"apiKeyEnv": "OPENROUTER_API_KEY",
"service_tier": "flex",
"toolProtocol": "text-json",
"openRouterToolRouting": "off",
},
Expand All @@ -151,6 +154,8 @@ Advanced debugging overrides are available but should stay out of normal example
}
```

`service_tier` is passed through to compatible OpenRouter requests. Supported request values are `flex` and `priority`.

`toolProtocol` values:

- `auto` — default; try native tools, then text fallbacks.
Expand Down
33 changes: 32 additions & 1 deletion docs/SESSIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,37 @@ Early event kinds:
- `message` — user, agent, or system-visible chat row.
- `status` — transient or persisted state changes.
- `tool_call` — command/tool request.
- `tool_result` — command/tool result.
- `task_plan` — visible session-only task plan state.
- `choice` — visible user choice prompt.
- `subagent_started` — parent log reference to a child session starting.
- `subagent_event` — parent log reference to a forwarded child runtime event.
- `subagent_completed` — parent log reference to a child session completing.
- `subagent_failed` — parent log reference to a child session failing.

`metadata.json` includes the root session identity and, for child sessions, the
parent link:

```json
{
"version": 1,
"sessionId": "019e0000-0000-7000-8000-000000000000",
"rootSessionId": "019e0000-0000-7000-8000-000000000000",
"parentSessionId": "019e0000-0000-7000-8000-000000000000",
"parentToolCallId": "task-call-1",
"source": "subagent",
"agentProfileId": "explore",
"title": "Inspect runtime"
}
```

For existing sessions that do not have tree fields, loaders treat `source` as
`user` and `rootSessionId` as the session's own `sessionId`. That keeps older
project-local sessions readable without rewriting their JSONL.

Child sessions are stored as normal session folders under the same project-local
session root. Creating a child session writes the child's own `metadata.json`
with `source: "subagent"` and appends a `subagent_started` reference to the
parent `events.jsonl`. Child events stay in the child session's log, so replay
can load a parent alone, list its direct children, or expand the full tree.

Keep model-facing chat roles separate from UI/runtime events. The TUI can show both, but model context should only include what the agent runtime intentionally selects.
2 changes: 2 additions & 0 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ Current behavior:
- The coding loop can use workspace-scoped file tools: `read_file`, `list_files`, `grep`, `find_file`, `edit_file`, `write_file`, and `inspect_command`.
- The coding loop can use structured Git tools: `git_status`, `git_diff`, `git_log`, `git_add`, and `git_commit`.
- The coding loop can use `plan_todo` to keep a visible session-only task plan during non-trivial multi-step work. Completed-only `plan_todo` text emitted with a final answer is ignored when no visible plan is open, so accidental closed-plan updates do not render as raw chat text.
- The coding loop can use `task` to delegate focused read-only exploration or isolated analysis to a child agent session. The parent receives a bounded task result while child events are persisted in the child session log and forwarded as runtime events.
- `git_status`, `git_diff`, and `git_log` are the preferred path for Git state, diffs, and recent history. `inspect_command` can still inspect read-only Git commands, but it is an orientation fallback rather than the normal Git workflow.
- `git_add` stages only explicit paths whose current status was acknowledged. It rejects broad pathspecs such as `.` and does not stage unrelated files by default.
- `git_commit` commits only when staged paths exactly match `expected_staged_paths`. The model prompt still tells the agent not to stage or commit unless the user explicitly asks.
Expand Down Expand Up @@ -109,6 +110,7 @@ Current behavior:
- Emits startup KB status before the prompt runs.
- Persists user messages and runtime events to the session log.
- Persists `plan_todo` task-plan events to the session log. Resume restores the latest visible plan without adding task-plan rows to future model context.
- Persists child `task` sessions separately under the same project-local session root and records parent-child links in session metadata.
- Includes a per-run `runId` in structured logs when `TOPCHESTER_LOG_LEVEL` enables logging.
- Routes slash-command prompts such as `/kb status` through the same command dispatcher used by the TUI.
- Does not open the interactive TUI.
Expand Down
7 changes: 6 additions & 1 deletion docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ models:

## Example 4: Custom OpenRouter Settings

Use this when you want a custom environment variable name, headers, or tool behavior.
Use this when you want a custom environment variable name, extra headers, or tool behavior.

```yaml
models:
Expand Down Expand Up @@ -184,6 +184,7 @@ models:
apiKeyEnv: MY_PROVIDER_API_KEY
apiKey: optional-inline-key
supportsStructuredOutputs: true
service_tier: flex
toolProtocol: auto
openRouterToolRouting: auto
headers:
Expand All @@ -192,6 +193,10 @@ models:

Prefer `apiKeyEnv` over `apiKey` so secrets stay out of config files.

Topchester adds default `HTTP-Referer` and `X-Title` headers for OpenRouter providers unless the config sets those header names explicitly.

`service_tier` is passed through to compatible OpenRouter requests. Use `flex` for lower cost with higher latency, or `priority` for faster service at higher cost.

`toolProtocol` can be:

- `auto`: try native tools, then text fallbacks.
Expand Down
Loading