Skip to content

feat: feat(cluster-protocol): add capability-gated read-only agent attach#795

Merged
tomdps merged 1 commit into
devfrom
zeroshot/burning-shift-79
Jul 24, 2026
Merged

feat: feat(cluster-protocol): add capability-gated read-only agent attach#795
tomdps merged 1 commit into
devfrom
zeroshot/burning-shift-79

Conversation

@tomdps

@tomdps tomdps commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Closes #749

@tomdps
tomdps enabled auto-merge July 24, 2026 20:50
@greptile-apps

greptile-apps Bot commented Jul 24, 2026

Copy link
Copy Markdown

Greptile Summary

Adds capability-advertised, read-only agent/attach subscriptions across the protocol, server, client, testkit, and generated protocol artifacts.

  • Defines bounded attach parameters, results, events, and close notifications.
  • Adds in-process and NDJSON clients with shared cursorless subscription handling.
  • Adds server-side admission, streaming, cancellation, overflow, and error mapping.
  • Extends capability vectors, schemas, OpenRPC output, fixtures, and integration tests.

Confidence Score: 3/5

The encoding-failure subscription path needs to notify or disconnect the client before this PR is safe to merge.

An unencodable attachment event stops the server-side forwarding loop without a terminal notification, leaving the client-side subscription registered and waiting indefinitely.

crates/openengine-cluster-server/src/stdio/subscription.rs

Important Files Changed

Filename Overview
crates/openengine-cluster-protocol/src/agent_attach.rs Defines bounded attach wire types and validation consistently with the generated schemas and fixtures.
crates/openengine-cluster-server/src/agent_attach.rs Adds transport-neutral attach establishment and backend delegation with bounded subscription queues.
crates/openengine-cluster-server/src/stdio/agent_attach.rs Adds NDJSON attach dispatch using shared subscription machinery, including an encoding-failure path that terminates without notifying the client.
crates/openengine-cluster-server/src/stdio/subscription.rs Extracts shared cursorless subscription handling but silently exits on event encoding failure without emitting a close notification.
crates/openengine-cluster-client/src/ndjson_subscription.rs Generates common typed NDJSON subscription clients whose streams remain waiting when the server exits without a close notification.
crates/openengine-cluster-client/src/ndjson_agent_attach.rs Instantiates the shared NDJSON subscription client for the new agent/attach method.
crates/openengine-cluster-client/src/lib.rs Generalizes subscription opening so JSON-RPC establishment errors can propagate as typed client errors.
crates/openengine-cluster-server/tests/agent_attach.rs Covers unsupported, unknown, inactive, oversized, cancellation, and capability-related attach behavior, including server survival after an oversized event.

Sequence Diagram

sequenceDiagram
    participant C as Client
    participant T as NDJSON Transport
    participant S as Cluster Server
    participant B as Backend
    C->>T: agent/attach(execution)
    T->>S: JSON-RPC request
    S->>B: agent_attach(context, params, capacity)
    alt unknown or inactive execution
        B-->>S: BackendError
        S-->>T: JSON-RPC error
        T-->>C: Typed RPC error
    else attachment established
        B-->>S: result, event stream, handle
        S-->>T: AgentAttachResult(subscriptionId)
        T-->>C: result and event stream
        loop live attachment events
            B-->>S: Working / Output / Settled
            S-->>T: event notification
            T-->>C: typed event
        end
        C->>T: subscription/cancel
        T->>S: cancel notification
        S->>B: release attachment handle
    end
Loading

Reviews (1): Last reviewed commit: "feat: implement #749 - feat(cluster-prot..." | Re-trigger Greptile

Comment on lines +180 to +188
run_established_subscription(established, channels, move |item| {
let encoded = match item {
BoundedStreamItem::Event(event) => encode_event(encode_subscription_id.clone(), event),
BoundedStreamItem::Closed { reason } => {
encode_closed(encode_subscription_id.clone(), reason)
}
};
encoded.ok()
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Encoding failure leaves stream open

When an attachment event cannot be encoded, converting the error to None ends the server subscription without sending subscription/closed; the client transport retains its registered sender and next() waits indefinitely instead of observing termination.

@tomdps
tomdps added this pull request to the merge queue Jul 24, 2026
Merged via the queue into dev with commit 7d9c440 Jul 24, 2026
6 checks passed
@tomdps
tomdps deleted the zeroshot/burning-shift-79 branch July 24, 2026 21:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant