app-server: Replay pending item requests on thread/resume (#12560)

Replay pending client requests after `thread/resume` and emit resolved
notifications when those requests clear so approval/input UI state stays
in sync after reconnects and across subscribed clients.

Affected RPCs:
- `item/commandExecution/requestApproval`
- `item/fileChange/requestApproval`
- `item/tool/requestUserInput`

Motivation:
- Resumed clients need to see pending approval/input requests that were
already outstanding before the reconnect.
- Clients also need an explicit signal when a pending request resolves
or is cleared so stale UI can be removed on turn start, completion, or
interruption.

Implementation notes:
- Use pending client requests from `OutgoingMessageSender` in order to
replay them after `thread/resume` attaches the connection, using
original request ids.
- Emit `serverRequest/resolved` when pending requests are answered
or cleared by lifecycle cleanup.
- Update the app-server protocol schema, generated TypeScript bindings,
and README docs for the replay/resolution flow.

High-level test plan:
- Added automated coverage for replaying pending command execution and
file change approval requests on `thread/resume`.
- Added automated coverage for resolved notifications in command
approval, file change approval, request_user_input, turn start, and turn
interrupt flows.
- Verified schema/docs updates in the relevant protocol and app-server
tests.

Manual testing:
- Tested reconnect/resume with multiple connections.
- Confirmed state stayed in sync between connections.
This commit is contained in:
Ruslan Nigmatullin
2026-02-27 12:45:59 -08:00
committed by GitHub
parent 66b0adb34c
commit 69d7a456bb
22 changed files with 1416 additions and 207 deletions

View File

@@ -1422,6 +1422,32 @@
],
"type": "object"
},
"RequestId": {
"anyOf": [
{
"type": "string"
},
{
"format": "int64",
"type": "integer"
}
]
},
"ServerRequestResolvedNotification": {
"properties": {
"requestId": {
"$ref": "#/definitions/RequestId"
},
"threadId": {
"type": "string"
}
},
"required": [
"requestId",
"threadId"
],
"type": "object"
},
"SessionSource": {
"oneOf": [
{
@@ -3422,6 +3448,26 @@
"title": "Item/fileChange/outputDeltaNotification",
"type": "object"
},
{
"properties": {
"method": {
"enum": [
"serverRequest/resolved"
],
"title": "ServerRequest/resolvedNotificationMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/ServerRequestResolvedNotification"
}
},
"required": [
"method",
"params"
],
"title": "ServerRequest/resolvedNotification",
"type": "object"
},
{
"properties": {
"method": {