mirror of
https://github.com/agentclientprotocol/claude-agent-acp.git
synced 2026-10-27 04:30:59 +00:00
feat: publish the predicted follow-up prompt as _meta.promptSuggestions (#1356)
## What
The Claude Code CLI can predict the prompt the user is likely to send
next. This adapter asked for nothing and dropped the `prompt_suggestion`
message. It now asks for the prediction (`promptSuggestions: true`) and
forwards the one prediction of a turn.
ACP has no field for a composer prefill, so the value travels as
```json
{
"sessionUpdate": "session_info_update",
"_meta": { "promptSuggestions": { "suggestions": [{ "text": "Run the tests" }] } }
}
```
The key names no vendor, so another client can read it. AIR already
renders the first non-blank text as gray text in an empty composer,
where Tab fills the composer and sends nothing.
## Behavior
- `suggestions: []` clears the prediction the client holds: at the next
`session/prompt`, because that turn's prediction is spent, and on a
`conversation_reset`, because the transcript it was drawn from is gone.
- A prediction the next prompt outran — the user sent the next prompt
before the adapter read the prediction off the SDK stream — is dropped
instead of published mid-turn.
- A blank prediction never goes on the wire.
- The update is sent only to an AIR client, like the other extension
keys, so non-AIR traffic is unchanged (the key is added to
`AIR_ONLY_META_KEYS`; the `origin/main` scenario baselines stay
byte-identical).
- The CLI predicts nothing on the first turn, after an API error, in
plan mode, and at the usage limit, so a turn without a prediction is
normal. A caller can opt out with
`_meta.claudeCode.options.promptSuggestions: false`.
Documented in `docs/air-extensions.md`.
## Tests
`src/tests/prompt-suggestions.test.ts` covers the wire shape, the
publish after the turn's result, the clear at the next prompt, the
dropped stale prediction, the blank prediction, and a non-AIR client.
`src/tests/create-session-options.test.ts` covers the SDK option and the
caller opt-out.
`npm run check`, `npm run build` and the touched suites are green; the
full `test:run` has pre-existing flakiness on this machine
(session-index watchers, providers) unrelated to this change.
Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Happy <yesreply@happy.engineering>
This commit is contained in:
@@ -20,6 +20,7 @@ It describes only this adapter.
|
||||
- [Session hooks](#session-hooks)
|
||||
- [Permission presentation](#permission-presentation)
|
||||
- [Goal](#goal)
|
||||
- [Predicted follow-up prompt](#predicted-follow-up-prompt)
|
||||
- [Recommended config values](#recommended-config-values)
|
||||
- [Async tasks](#async-tasks)
|
||||
- [Agent file-change report](#agent-file-change-report)
|
||||
@@ -206,6 +207,7 @@ The adapter keeps them where they are.
|
||||
| `steering` | `initialize` response `_meta.steering = {supported: true}` | The agent accepts `_session/steering` for a running turn. |
|
||||
| `quota` | `PromptResponse._meta.quota` | Token usage of the turn, also split by model. |
|
||||
| `authStatus` | `initialize` response `agentCapabilities._meta.authStatus` | The agent pushes `_auth/status_update`. The object carries no payload. |
|
||||
| `promptSuggestions` | `session_info_update._meta.promptSuggestions = {suggestions: [{text}]}`, AIR only | The prompt the agent predicts for the next turn. An empty list clears it. |
|
||||
|
||||
## Auth source display
|
||||
|
||||
@@ -816,6 +818,37 @@ While that command is pending, the adapter ignores late updates for the previous
|
||||
A matching runtime `active_goal` stays authoritative and adds the iteration, reason, and timestamp.
|
||||
A failed command restores the previous state.
|
||||
|
||||
## Predicted follow-up prompt
|
||||
|
||||
After a turn, the Claude Code CLI can predict the prompt the user is likely to send next.
|
||||
The adapter asks for it with the SDK option `promptSuggestions: true` and forwards the one prediction of the turn.
|
||||
|
||||
ACP has no field for a composer prefill, so the prediction travels outside the AIR namespace:
|
||||
|
||||
```json
|
||||
{
|
||||
"sessionUpdate": "session_info_update",
|
||||
"_meta": { "promptSuggestions": { "suggestions": [{ "text": "Run the tests" }] } }
|
||||
}
|
||||
```
|
||||
|
||||
The key names no vendor, so another client can read it.
|
||||
The adapter sends it only to an AIR client; see the [compatibility rule](#compatibility-rule).
|
||||
|
||||
AIR shows the first non-blank `suggestions[].text` as gray text in an empty composer.
|
||||
Tab fills the composer with it and sends nothing.
|
||||
|
||||
`suggestions: []` clears the prediction the client holds. The adapter clears it:
|
||||
|
||||
- when the next `session/prompt` arrives, because that turn's prediction is spent;
|
||||
- on a `conversation_reset`, because the prediction was drawn from the transcript the reset dropped.
|
||||
|
||||
A prediction the next prompt outran — the user sent it before the adapter read the prediction off the SDK stream — is dropped instead of published.
|
||||
|
||||
The CLI predicts nothing on the first turn of a session, after an API error, in plan mode, and at the account's usage limit, so many turns end with no prediction.
|
||||
A client must treat a turn without one as normal.
|
||||
A caller can turn the whole feature off with `_meta.claudeCode.options.promptSuggestions: false` on `session/new`; a user can turn it off in Claude Code settings or with `CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION=false`.
|
||||
|
||||
## Recommended config values
|
||||
|
||||
The `recommendedValue` extension lets a client show concrete model and effort choices without an ambiguous `default` row.
|
||||
|
||||
Reference in New Issue
Block a user