feat(runtime-host): broker nested capability forms - #4397
Conversation
ed745fb to
032d77f
Compare
36ec70c to
295d562
Compare
032d77f to
d8bae9f
Compare
87d4bd7 to
e07c040
Compare
Astro-Han
left a comment
There was a problem hiding this comment.
PR #4397 — e07c040 — blind review sealed
Summary: Runtime Host brokering for nested capability forms (tail of #4379 stack). Exact head e07c040759c6483ac52e5bb2a6bdefbb8d4a092d frozen, stacked-base CLEAN, 0 checks/0 reviews/0 threads on stacked base. Source is approvable with comments; inherits #4379's 2×P2+1×P3. No simplify finding. Directly affected tests 141/141, Runtime 3121/7/0, Runtime Host 1501/12 (1 transient timing case isolated) all green.
Findings (reproducible production seams):
- P2 — cancellation-before-admission ghost form — if producer
cancellationpublishes before formadmission,withdrawsucceeds early (“no record”), lateradmissionstill publishes and leaves ghost pending form of a failed provider until Run close. Deferred-admission seam: expected 0 pending, actual 1. Fix: share ordered fence between admission/cancellation or re-withdraw after successful admission. - P2 —
HostClientCapabilityCoordinator.close()drops cleanup promise — new asyncreleaseConnection()interaction-cleanuppromise is discarded, only registry mutation awaited; pending form withdrawal slightly slower →broker.close()early withactive invocation. Deferred-withdrawal coordinator seam: expected wait, actual early failure. Fix: collect and await all connection-release promises in coordinator close.
Gating: current-main da84f88de merge tree has only explicitly ignored epoch conflict; stacked-base CLEAN.
Automated review notice: This comment was posted by an automated review agent operated by AstroHan. It is not an independent human review and does not replace one.
简体中文
本条结论来自 @捣蛋鬼 在 exact head e07c040 的独立盲审,已按 @me2seeks 指示排除 compatibility epoch 冲突的计分。编排仅核对 head 未漂移与 CI 状态。
d8bae9f to
1fba905
Compare
e07c040 to
eeb37b8
Compare
|
Fixed both findings across f07fe90 and eeb37b8. Producer cancellation now orders withdrawal after successful Host admission, and connection release/close waits for nested interaction cleanup, including a release that started before coordinator shutdown. While rebasing, I also preserved main's accepted → admitted grant boundary and added a prepared-execution regression so forms are forwarded only after admission (4ac7785). Added deferred-admission and close-barrier coverage. |
1fba905 to
4609622
Compare
eeb37b8 to
6254710
Compare
f1744f3 to
cd16fd6
Compare
6254710 to
5949e03
Compare
|
Rebased onto the updated parent head ( The parent now owns epoch 94 for the provider-neutral form contract, so the nested Client Capability interaction round trip advances to epoch 95; the epoch history comments are retained. A Validation on |
5949e03 to
9ff82bf
Compare
|
Rebased onto the updated parent head ( |
3dd69e7 to
51bacd2
Compare
9ff82bf to
042d203
Compare
|
Rebased onto the updated parent head ( Nested-form fixtures now declare an explicit |
51bacd2 to
9ec0c5f
Compare
042d203 to
62d04e3
Compare
|
Rebased onto the current parent head ( |
9ec0c5f to
0b141e9
Compare
62d04e3 to
3f53e26
Compare
0b141e9 to
94d9d5e
Compare
3f53e26 to
9a870c5
Compare
94d9d5e to
b65d7ff
Compare
9a870c5 to
ea8ad52
Compare
Let an exact hosted Run withdraw one form without closing its surrounding Turn. Commit producer cancellation through the existing InteractionStore authority, preserve an already-claimed Run closure, and compose provider-local cancellation with the Tool invocation signal. Part of #4364. Generated-by: OpenAI Codex
Add strict request/result frames and expose one provider-neutral requestInteraction callback for admitted Client Capability invocations. Keep correlation inside the client channel and publish a new compatibility epoch for peers that understand the round trip.\n\nPart of #4364.\n\nGenerated-by: OpenAI Codex
Route Client Capability interaction requests through the Runtime-owned form callback. Pause provider execution time only while the canonical form is pending, bound result delivery, and rearm a fresh execution timeout after delivery.\n\nClose the exact producer-owned form before settling provider failure, cancellation, or connection loss, while preserving Runtime Host as the only Interaction authority.\n\nPart of #4364.\n\nGenerated-by: OpenAI Codex
The nested capability form sources predate the formatter rules now on main; rebase onto the current parent and reformat so the changed-file biome gate passes again. No semantic change.
Admission now proves every legal answer serializes, so a string field without maxLength is no longer admissible. Bound the fixtures to keep them representative of forms a provider can actually publish.
b65d7ff to
b3b1072
Compare
ea8ad52 to
e27d47d
Compare
M4n5ter
left a comment
There was a problem hiding this comment.
Reviewed at exact commit e27d47d363584428e35e29c81afcf3f675adbf4c.
Nested Client Capability forms now join their exact admission before cancellation can withdraw them, and connection/Host shutdown waits for interaction withdrawal before closing the invocation broker. The current affected builds and lifecycle tests pass, including cancellation-before-admission and delayed-cleanup regressions, and I found no blocking correctness or design issue in this change.
Automated review notice: This comment was posted by an automated review agent operated by M4n5ter. It is not an independent human review and does not replace one.
* feat(runtime): establish durable form interactions Define a bounded provider-neutral primitive form contract and carry its request and acknowledgement facts through the Runtime Event Log. Broker pending forms through the existing InteractionStore authority so schema-invalid answers remain pending, concurrent equivalent answers converge on one canonical outcome, and Turn closure or Host restart closes the exact continuation. Part of #4364. Generated-by: OpenAI Codex * fix(runtime): complete form interaction adapter seam Expose one closed decoder for renderer-to-runtime form responses so surface adapters do not copy protocol validation. Queue the same canonical continuity refresh for form requests that user questions already receive. Refs #4364. Generated-by: OpenAI Codex * fix(runtime): harden structured form boundaries * fix(desktop): accept form interactions in composer region * fix(runtime): complete form interaction lifecycle Generated-by: OpenAI Codex * fix(desktop): keep unsupported forms out of composer queue Generated-by: OpenAI Codex * fix(runtime-host): publish form graph activity Generated-by: OpenAI Codex * style(runtime-host): format form graph regression Generated-by: OpenAI Codex * fix(core): preserve projected form default semantics Generated-by: OpenAI Codex * fix(core): prove the escaped answer envelope at admission Admission reserved the answer envelope with four raw bytes per code point, but enforcement measures post-serialization bytes, where JSON escaping inflates a code point to as much as six. A schema-legal answer of backslashes, newlines, or control characters could pass admission yet be rejected at decode, stranding the pending interaction. Keep the schema semantics — maxLength stays a code-point count and each value stays bounded at INTERACTION_FORM_VALUE_MAX_BYTES raw bytes — and prove serializability at admission: the string envelope is now all control characters (one code point and one raw byte each, six serialized bytes after escaping), and select envelopes pick the serialized-longest option rather than the raw-longest. A form whose limits permit an undeliverable answer is rejected up front instead of stranding the interaction after the user submits. Regressions pin the preserved character semantics (2,048 plain characters or 1,024 backslashes still satisfy a maxLength: 2048 field), admission rejection for limits that cannot guarantee delivery, and escape-heavy answers that decode and deliver for admissible forms. * fix(core): reserve date and date-time envelopes in their legal language A string field without maxLength reserved 2,048 control characters even when the format was date or date-time — an estimate that can never pass the format check yet inflates to 12 KiB, so a form asking for a calendar day was rejected before publication while its whole legal answer is 64 bytes. Compute the worst value inside each format's legal language instead: date is fixed-length over [0-9-], and date-time adds only characters that never JSON-escape, with fractional seconds bounding length at the field caps. Other formats and unconstrained strings keep the six-bytes-per-code-point worst case, since control characters remain legal there. Regressions cover date and date-time fields admitted with no maxLength, their canonical answers decoding, and the fractional-seconds worst case staying deliverable. * feat(runtime-host): broker nested capability forms (#4397) * feat(runtime): withdraw producer-owned forms Let an exact hosted Run withdraw one form without closing its surrounding Turn. Commit producer cancellation through the existing InteractionStore authority, preserve an already-claimed Run closure, and compose provider-local cancellation with the Tool invocation signal. Part of #4364. Generated-by: OpenAI Codex * feat(runtime-host): carry nested capability forms Add strict request/result frames and expose one provider-neutral requestInteraction callback for admitted Client Capability invocations. Keep correlation inside the client channel and publish a new compatibility epoch for peers that understand the round trip.\n\nPart of #4364.\n\nGenerated-by: OpenAI Codex * feat(runtime-host): broker nested capability forms Route Client Capability interaction requests through the Runtime-owned form callback. Pause provider execution time only while the canonical form is pending, bound result delivery, and rearm a fresh execution timeout after delivery.\n\nClose the exact producer-owned form before settling provider failure, cancellation, or connection loss, while preserving Runtime Host as the only Interaction authority.\n\nPart of #4364.\n\nGenerated-by: OpenAI Codex * fix(runtime-host): order nested form cleanup * test(desktop): complete capability interaction fake * fix(runtime-host): forward forms after capability admission * fix(runtime-host): await prior capability releases * style: format nested capability form files The nested capability form sources predate the formatter rules now on main; rebase onto the current parent and reformat so the changed-file biome gate passes again. No semantic change. * test: give nested form fixtures an explicit string bound Admission now proves every legal answer serializes, so a string field without maxLength is no longer admissible. Bound the fixtures to keep them representative of forms a provider can actually publish. * feat(tui): answer structured form interactions (#4392) * feat(tui): answer structured form interactions Review and edit Host-owned forms in the existing TUI interaction queue, preserving optional omission and all six primitive field kinds. Route accepted, declined, and cancelled responses through the generic Runtime Host interaction operation, while non-interactive runs stop the exact Turn instead of dropping the request. Keep requester provenance and sensitive-data guidance visible, validate with the shared Core contract, and retire stale overlays when authoritative transcript state changes. Part of #4364. Generated-by: OpenAI Codex * fix(tui): retain reconnecting form drafts * test(tui): cover form constraint copy variables * style(tui): format form interaction sources The TUI form sources predate the formatter rules now on main; rebase onto the current parent and reformat so the changed-file biome gate passes. Reflow and trailing commas only, no semantic change. * fix(cli): cover the form interaction TUI under copy boundaries
Summary
requestInteraction(form)callback after invocation admissionWhy
#4379 establishes the durable, provider-neutral form interaction contract. Client Capability providers still need a bounded way to pause an admitted tool call, collect structured user input through the active Maka surface, and continue the same invocation.
The Runtime Host remains the only canonical Interaction authority. The Client channel owns only provider-local correlation, while the invocation broker owns the transient execution timer and ensures provider failure, cancellation, release, and connection loss close the nested form before the outer call settles.
This PR is a sibling of the Desktop adapter in #4384 and the TUI adapter in #4392. All three depend directly on #4379; none of the siblings depends on another.
Part of #4364.
Compatibility
Screenshots
No visual changes. Desktop and TUI rendering are covered by the sibling surface PRs #4384 and #4392.
Test plan
npx biome checkon all changed filesnpm run buildGenerated-by: OpenAI Codex