Support configuring effort alongside model

This commit is contained in:
Ian Gulliver
2026-10-23 08:40:00 -07:00
parent 6bbae3fffe
commit d6d9dd86d9
40 changed files with 805 additions and 541 deletions
+2 -2
View File
@@ -7,7 +7,7 @@ How `internal/antigravity` drives the Antigravity CLI, `agy` (`brew install --ca
```
agy --input-format stream-json --output-format stream-json \
--dangerously-skip-permissions --add-dir <session dir> \
[--model M] [--conversation ID] --print ""
[--model M] [--effort E] [--conversation ID] --print ""
```
- `--print ""` puts the CLI in print mode; with `--input-format stream-json` it reads one message per line from stdin and runs a turn for each, in one conversation, until stdin closes. A bare `-p` takes the next flag as its prompt, so the empty prompt is passed explicitly.
@@ -48,7 +48,7 @@ Stdout, one JSON object per line, each `{"event": E, E: {...}}`:
SIGINT ends the running turn: the CLI prints `error: interrupted` on stderr, sends a `result` with `status` `ERROR` and `error` `interrupted`, and exits. A tool step cut off this way gets no `DONE` update. Resume with `--conversation` after the old process exits to keep using the conversation.
There is no way to switch the model of a running process. Close the idle process's stdin, wait for it to exit, and restart with the new `--model` and the same `--conversation`.
There is no way to switch the model or effort of a running process. Close the idle process's stdin, wait for it to exit, and restart with the new `--model` and `--effort` and the same `--conversation`.
## Hooks
+3 -2
View File
@@ -10,7 +10,7 @@ claude --output-format stream-json --input-format stream-json --verbose \
--permission-mode bypassPermissions --allow-dangerously-skip-permissions \
--settings '{"attribution":{"commit":"","pr":""}}' \
--mcp-config '{"mcpServers":{"byre":{"type":"sdk","name":"byre","alwaysLoad":true}}}' \
[--model M] [--session-id=ID] [--resume=SESSION_ID] [--resume-session-at=UUID] [--fork-session]
[--model M] [--effort E] [--session-id=ID] [--resume=SESSION_ID] [--resume-session-at=UUID] [--fork-session]
```
- No `--print`; stream-json input implies non-interactive.
@@ -41,7 +41,8 @@ Host → CLI:
- `initialize` must be first. It carries hook registrations: `{"hooks":{"Stop":[{"matcher":null,"hookCallbackIds":["hook_0"],"timeout":<seconds>}],...}}`. Without `timeout` the CLI abandons a hook callback after its default; the timer is a JavaScript `setTimeout`, so values past about 24 days (2^31 ms) fire at once.
- `interrupt` ends the current turn; the turn's `result` follows almost immediately and a running Bash tool is killed. The session stays usable.
- `set_model` (`{"subtype":"set_model","model":M}`) switches the running process's model for later turns.
- `set_permission_mode`, `mcp_status`, `get_context_usage`, `rewind_files`, `stop_task` exist and are not used yet.
- `apply_flag_settings` (`{"subtype":"apply_flag_settings","settings":{"effortLevel":E}}`) switches its effort; `null` returns to the default. It answers success for any value, an unknown level included.
- `set_max_thinking_tokens`, `set_permission_mode`, `mcp_status`, `get_context_usage`, `rewind_files`, `stop_task` exist and are not used yet.
CLI → host:
+1 -1
View File
@@ -22,7 +22,7 @@ Shell commands inherit the app-server's environment. NDJSON both ways on stdio.
1. `initialize` with `clientInfo` and `capabilities.experimentalApi` true (dynamic tools need it: without it `thread/start` with `dynamicTools` fails with `thread/start.dynamicTools requires experimentalApi capability`), then the `initialized` notification.
2. `thread/start` (`cwd`, `model`, `approvalPolicy` `never`, `sandbox` `danger-full-access`, `developerInstructions` for byre's guidance, `dynamicTools` for the tool schemas), or `thread/resume` with `threadId` and the same settings but no tools, or `thread/fork` (`threadId`, `lastTurnId`, the last turn the fork keeps; the turn must not be in progress) with the same settings. The server picks the thread id, returned as `thread.id`; resuming keeps it, forking makes a new one. A thread's dynamic tools are stored with it, so resumed and forked threads keep them.
3. `turn/start` with `threadId` and `input`, a list of `UserInput`: `{"type":"text","text":...}`, and for each image `{"type":"image","url":"data:<type>;base64,..."}` before the text. Additional turn context uses `additionalContext`, for example `{"byre":{"kind":"application","value":...}}`. `model` on it switches the model for that turn and every later one; `thread/read` reports the thread's current `model`. The response carries the new turn; `turn/started` follows.
3. `turn/start` with `threadId` and `input`, a list of `UserInput`: `{"type":"text","text":...}`, and for each image `{"type":"image","url":"data:<type>;base64,..."}` before the text. Additional turn context uses `additionalContext`, for example `{"byre":{"kind":"application","value":...}}`. `model` on it switches the model for that turn and every later one, and `effort` the reasoning effort the same way; an absent `effort` keeps the thread's, so returning a running thread to the model's default means sending that default explicitly: `model/list` (`includeHidden`, paged by `nextCursor`) gives each model's `defaultReasoningEffort`. `thread/read` reports the thread's current `model`. The effort a thread starts or resumes with is `model_reasoning_effort` in `config`, which the `thread/start` response echoes as `reasoningEffort` (absent for the model's default). Valid efforts are whatever the model advertises (typically `low` to `xhigh`). The response carries the new turn; `turn/started` follows.
4. `turn/steer` with `threadId`, `expectedTurnId` (the active turn) and `input` adds input to the running turn; the model reads it at its next step without the turn ending.
5. `turn/interrupt` with `threadId` and the active `turnId` ends the turn: `turn/completed` arrives with `status` `interrupted` within milliseconds, a running command is killed, and the thread stays usable.
6. `thread/compact/start` runs compaction as a turn of its own: `turn/started`, an item of type `contextCompaction`, `turn/completed`. The thread keeps its id and remembers the conversation in summary.