Add a pause that holds an agent after its current step
This commit is contained in:
@@ -22,7 +22,7 @@ There is no flag for a system prompt or MCP servers, so byre hands them over as
|
||||
- `plugin.json`: `{"name": "byre"}`.
|
||||
- `rules/AGENTS.md`: always-on guidance. `rules/notes.md` uses `trigger: always_on` frontmatter. The CLI cuts each rule file at 24,000 bytes, so longer guidance or notes must be refused before launch.
|
||||
- `mcp_config.json`: one entry per server, with a Streamable HTTP `url` or a stdio `command` and `args`. The CLI namespaces plugin servers as `<plugin>_<server>`, so byre's own server is `byre_byre`.
|
||||
- `hooks.json`: handlers keyed by hook event, each a command that reads the hook's JSON from stdin and prints its reply. Only flat events (`SessionStart`, `PreInvocation`, `PostInvocation`, `Stop`) fit this shape.
|
||||
- `hooks.json`: handlers keyed by hook event, each a command that reads the hook's JSON from stdin and prints its reply, with a `timeout` in seconds (default 30). Flat events (`SessionStart`, `PreInvocation`, `PostInvocation`, `Stop`) list handlers directly; tool events (`PreToolUse`, `PostToolUse`) wrap them in groups, `[{"matcher": "*", "hooks": [...]}]`, where `matcher` is a regex on the tool name.
|
||||
|
||||
## The session's listener
|
||||
|
||||
@@ -52,7 +52,7 @@ There is no way to switch the model of a running process. Close the idle process
|
||||
|
||||
## Hooks
|
||||
|
||||
Hook input and output are camelCase JSON. byre uses `PreInvocation`, which runs before every model call with `invocationNum` (0 for a turn's first call) and `initialNumSteps`; an output of `{"injectSteps":[{"userMessage":"..."}]}` adds a user message the model reads on that call. The `Stop` hook gets no final message, so byre doesn't use it.
|
||||
Hook input and output are camelCase JSON. byre uses `PreInvocation`, which runs before every model call with `invocationNum` (0 for a turn's first call) and `initialNumSteps`; an output of `{"injectSteps":[{"userMessage":"..."}]}` adds a user message the model reads on that call. byre also uses `PreToolUse` (input `toolCall` with `name` and `args`), whose output needs `decision`: `allow`, or `deny` with a `reason` the agent reads in place of the tool's result. The `Stop` hook gets no final message, so byre doesn't use it.
|
||||
|
||||
## Forking
|
||||
|
||||
|
||||
@@ -38,14 +38,14 @@ Either side sends `{"type":"control_request","request_id":ID,"request":{"subtype
|
||||
|
||||
Host → CLI:
|
||||
|
||||
- `initialize` must be first. It carries hook registrations: `{"hooks":{"Stop":[{"matcher":null,"hookCallbackIds":["hook_0"]}],...}}`.
|
||||
- `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.
|
||||
|
||||
CLI → host:
|
||||
|
||||
- `hook_callback` with `callback_id` and `input` (the hook's input JSON). The response body is the hook output. A Stop hook returning `{"decision":"block","reason":"..."}` keeps the agent going with the reason fed back to it.
|
||||
- `hook_callback` with `callback_id` and `input` (the hook's input JSON). The response body is the hook output. A Stop hook returning `{"decision":"block","reason":"..."}` keeps the agent going with the reason fed back to it. A PreToolUse hook returning `{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"..."}}` skips the call, and the model reads the reason in its place. The model treats that reason as tool output and won't follow instructions in it; an `additionalContext` beside `permissionDecision` reaches it as context it does follow. A hook's callback can take as long as it likes within its timeout; the agent waits.
|
||||
- `mcp_message` with `server_name` and a JSON-RPC `message` for an `sdk`-type MCP server; answer with `{"mcp_response": <JSON-RPC response>}`. Notifications still need a response.
|
||||
- `can_use_tool` only arrives when a permission prompt would show; under `bypassPermissions` it should not.
|
||||
- `control_cancel_request` abandons an in-flight request.
|
||||
|
||||
@@ -33,6 +33,10 @@ A `dynamicTools` entry of type `namespace` holds tools as `function`s with their
|
||||
|
||||
Closing stdin ends the process.
|
||||
|
||||
## Hooks
|
||||
|
||||
The `config` on `thread/start`, `thread/resume` and `thread/fork` takes hooks in Claude Code's shape: `{"hooks":{"PreToolUse":[{"hooks":[{"type":"command","command":...,"timeout":<seconds>}]}]}}`. They are ignored unless `config` also sets `bypass_hook_trust` true: hooks otherwise need trust recorded in `config.toml` (the `--dangerously-bypass-hook-trust` of `codex exec`, which `app-server` lacks as a flag). The command reads the hook's JSON on stdin and prints its reply on stdout; a sync hook holds the turn until it exits, and `hook/started` and `hook/completed` notifications report each run. `PostToolUse` runs after the tool's `item/completed`. A `PreToolUse` reply of `{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":...}}` skips the call, and the model reads "Command blocked by PreToolUse hook:" and the reason in its place; an `additionalContext` beside it reaches the model too. Output that isn't valid JSON fails the hook (`hook returned invalid pre-tool-use JSON output`) and the call runs.
|
||||
|
||||
## Events
|
||||
|
||||
- `turn/started`, `turn/completed` (`turn.status` `completed`, `interrupted` or `failed` with `turn.error`). A failed request to the model also sends an `error` notification first, with `willRetry`.
|
||||
|
||||
Reference in New Issue
Block a user