Skip to content

code-mode: expose create and observe operations#29291

Closed
cconger wants to merge 1 commit into
cconger/code-mode-runtime-compact-03f3-idempotent-createfrom
cconger/code-mode-runtime-compact-03g-create-observe-api
Closed

code-mode: expose create and observe operations#29291
cconger wants to merge 1 commit into
cconger/code-mode-runtime-compact-03f3-idempotent-createfrom
cconger/code-mode-runtime-compact-03g-create-observe-api

Conversation

@cconger

@cconger cconger commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Why

Cell admission and observation need separate protocol operations. Returning a started handle plus a second asynchronous response from one execute request is awkward across IPC and leaves cancellation ownership unclear.

At the wire boundary, each operation also needs its own result union so the serialized type cannot describe outcomes that operation cannot produce. This type narrowing is limited to the protocol/session layer: runtime-owned CellEvent/PausableCellEvent and Core's model/trace RuntimeResponse retain their existing roles.

What

  • Replace session-level execute/wait with wire-facing create_cell(CreateCellRequest) and observe(ObserveRequest) operations.
  • Keep the model-facing tools named exec and wait; only the host/Core session contract changes.
  • Have the host assign and return CellId at admission in this layer.
  • Define flat, explicitly tagged wire unions for operation results.
    • ObserveOutcome: yielded, completed, terminated, or missing.
    • TerminateOutcome: completed, terminated, or missing; yielded is not representable.
    • missing carries only the requested CellId.
  • Convert those wire outcomes into RuntimeResponse after receipt instead of using RuntimeResponse as the session return type.
  • Add a Core guard that terminates a created cell if its initial observation is canceled.
  • Remove the exported pending-observation protocol surface; pausable execution remains a direct runtime API.
  • Add exact serde coverage for requests, the tagged outcome shapes, tool definitions, output items, and image detail.

Host/Core wire sequence

sequenceDiagram
    participant Core
    participant Host
    Core->>Host: create_cell(CreateCellRequest)
    Host-->>Core: CellId
    Core->>Host: observe(ObserveRequest)
    alt cell yields
        Host-->>Core: ObserveOutcome::Yielded
    else cell completes
        Host-->>Core: ObserveOutcome::Completed
    else cell is terminated
        Host-->>Core: ObserveOutcome::Terminated
    else cell is absent
        Host-->>Core: ObserveOutcome::Missing
    end
    opt initial observe is canceled
        Core->>Host: terminate(CellId)
        alt cell completed first
            Host-->>Core: TerminateOutcome::Completed
        else termination wins
            Host-->>Core: TerminateOutcome::Terminated
        else cell is absent
            Host-->>Core: TerminateOutcome::Missing
        end
    end
Loading

All successful payloads above remain wrapped by the session's transport-level Result<T, String>.

Stack boundary

This PR defines the operation split and valid wire outcomes, but does not yet make observation delivery replayable after an ambiguous IPC response. #29397 adds caller-provided request identity and detached, replayable observations.

Validation

  • just test -p codex-code-mode
  • just test -p codex-code-mode-protocol
  • Core regression for cancellation after create and before the initial observation completes.

Stack parent: #29403.

@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03f-create-observe-runtime branch from 67fe0dd to db85bd5 Compare June 21, 2026 05:33
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03g-create-observe-api branch from d573397 to 8fe1bf1 Compare June 21, 2026 05:33
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03g-create-observe-api branch from 8fe1bf1 to b29a55b Compare June 21, 2026 06:24
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03f-create-observe-runtime branch 2 times, most recently from 9ab809d to d969450 Compare June 21, 2026 07:23
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03g-create-observe-api branch from b29a55b to e81e125 Compare June 21, 2026 07:23

#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub enum WaitOutcome {
pub enum CellOutcome {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allows impossible wire states such as MissingCell(Yielded) or Completed(Yielded)
Sounds like a design smell

assert_json_round_trip(
&CellOutcome::LiveCell(result.clone()),
json!({
"LiveCell": {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These exact tests are locking the future wire format to serde's default Rust enum shape ({"LiveCell":{"Result":...}}).
That makes Rust variant names part of the protocol and is awkward to version or implement outside Rust...

@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03g-create-observe-api branch from e81e125 to f3f8aa4 Compare June 21, 2026 19:24
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03f-create-observe-runtime branch from d969450 to 9b1d9b8 Compare June 21, 2026 19:24
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03g-create-observe-api branch from f3f8aa4 to fbf545e Compare June 21, 2026 22:44
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03f-create-observe-runtime branch from 9b1d9b8 to 1ad5213 Compare June 21, 2026 22:44
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03g-create-observe-api branch from fbf545e to bf52c09 Compare June 22, 2026 05:34
@cconger cconger changed the base branch from cconger/code-mode-runtime-compact-03f-create-observe-runtime to cconger/code-mode-runtime-compact-03f3-idempotent-create June 22, 2026 05:34
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03g-create-observe-api branch from bf52c09 to 4232322 Compare June 22, 2026 06:48
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03f3-idempotent-create branch from 4ac6daf to 12e7716 Compare June 22, 2026 06:48
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03g-create-observe-api branch from 4232322 to 5cc94cd Compare June 22, 2026 06:53
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03f3-idempotent-create branch from 12e7716 to bc923b0 Compare June 22, 2026 07:02
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03g-create-observe-api branch 3 times, most recently from b3ba157 to a9ed5af Compare June 22, 2026 07:22
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03g-create-observe-api branch from a9ed5af to 96581e9 Compare June 22, 2026 08:37
) -> CodeModeSessionResultFuture<'a, ObserveOutcome>;

fn terminate<'a>(&'a self, cell_id: CellId) -> CodeModeSessionResultFuture<'a, WaitOutcome>;
fn terminate<'a>(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(found by Codex)
terminate has the same ambiguous-response problem as create/observe, but no request identity or replay. Once the host tombstones the cell, a lost response retries as Missing, dropping the terminal content/outcome. Can we make termination replayable too, or retrieve its terminal result through observe?

}

impl Drop for InitialObservationGuard {
fn drop(&mut self) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This records a cancelled observation as a failed, already-ended runtime before terminate has succeeded

@cconger cconger closed this Jun 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants