Skip to content

feat(workflow): compose finite WebSocket sessions - #27

Merged
copyleftdev merged 2 commits into
mainfrom
agent/websocket-workflows
Aug 8, 2026
Merged

copyleftdev merged 2 commits into
mainfrom
agent/websocket-workflows

Conversation

@copyleftdev

@copyleftdev copyleftdev commented Aug 8, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • embed canonical sealed WebSocket child plans in Arazzo workflow steps
  • aggregate WebSocket risk, exact grants, source fingerprints, and a separately sealed WebSocket policy fingerprint
  • add explicit bounded action-field bindings and selected message/metadata/evidence outputs
  • execute mixed HTTP → WebSocket and WebSocket → WebSocket chains through the canonical planner and executor under one workflow timeout budget
  • document the Arazzo x-kahea-source-kind: websocket-session extension and add deterministic fixtures

Safety and compatibility

  • bindings cannot alter targets, auth references, limits, schemas, action order, or operation identity
  • whole transcripts cannot become implicit workflow values; binary outputs require an evidence handle or base64 selector
  • HTTP-only workflow serialization remains unchanged, as verified by the existing cross-platform golden plan test
  • invocation rejects WebSocket policy drift before transport

Validation

  • scripts/gates.sh
  • all workspace unit, integration, CLI/MCP parity, and doc tests
  • strict Clippy
  • release build and distribution/plugin validation
  • dynamic conformance
  • RustSec audit

Closes #15

Summary by CodeRabbit

  • New Features

    • Added support for workflows combining HTTP steps with local finite WebSocket sessions.
    • Added WebSocket actions, bindings, outputs, retries, evidence capture, policy checks, and timeout controls.
    • Added workflow-wide timeout budgeting across steps and retries.
    • Added CLI and MCP support for planning mixed HTTP/WebSocket workflows.
  • Bug Fixes

    • WebSocket connections now respect invocation timeouts, preventing delayed completion from silent peers.
  • Documentation

    • Expanded workflow guidance and architecture documentation for WebSocket sessions, bindings, evidence, security, and limitations.

@coderabbitai

coderabbitai Bot commented Aug 8, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@copyleftdev, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 18 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0981fa9b-c5f3-4cbb-9b3f-407af805b8cc

📥 Commits

Reviewing files that changed from the base of the PR and between b3961cc and bab44fc.

📒 Files selected for processing (2)
  • crates/kahea-exec/src/websocket.rs
  • crates/kahea-workflow/src/lib.rs
📝 Walkthrough

Walkthrough

Arazzo workflows now support local finite WebSocket session sources beside OpenAPI sources. Plans embed sealed WebSocket child plans, validate bounded bindings and outputs, aggregate grants and risk, enforce policy fingerprints and workflow timeouts, and execute mixed HTTP/WebSocket steps.

Changes

WebSocket workflow integration

Layer / File(s) Summary
Workflow contracts and planning
crates/kahea-core/src/lib.rs, crates/kahea-workflow/src/lib.rs, README.md, docs/architecture/0001-websocket-sessions.md, plugins/kahea/skills/kahea/SKILL.md
Workflow models and planning now represent HTTP or WebSocket transport, embedded child plans, bounded bindings, source metadata, grants, risk, and WebSocket policy fingerprints.
Invocation and bounded execution
crates/kahea-workflow/src/lib.rs, crates/kahea-exec/src/websocket.rs, crates/kahea-workflow/Cargo.toml
Invocation verifies policy fingerprints, dispatches WebSocket steps, applies workflow-wide timeout and retry budgets, materializes bindings, and extracts bounded outputs and evidence.
Validation and integration coverage
fixtures/workflows/*, crates/kahea-workflow/src/lib.rs, crates/kahea/tests/cli.rs, crates/kahea-exec/src/websocket.rs
Fixtures and tests cover mixed planning, grants, policy seals, HTTP-to-WebSocket binding, WebSocket chaining, retries, output extraction, CLI/MCP parity, and timeout enforcement.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ArazzoWorkflow
  participant WorkflowPlanner
  participant WebSocketExecutor
  participant WebSocketPeer
  ArazzoWorkflow->>WorkflowPlanner: plan mixed HTTP and websocket steps
  WorkflowPlanner->>WebSocketExecutor: invoke sealed websocket child plan
  WebSocketExecutor->>WebSocketPeer: execute finite websocket session
  WebSocketPeer-->>WebSocketExecutor: return messages and close data
  WebSocketExecutor-->>ArazzoWorkflow: return bounded outputs and observations
Loading

Possibly related issues

  • Issue 6: The change implements the described WebSocket workflow integration, including sealed plans, grants, bounded outputs, evidence, retries, and policy enforcement.

Possibly related PRs

  • copyleftdev/kahea#19: Defines the WebSocket session contracts used by this workflow integration.
  • copyleftdev/kahea#20: Provides the WebSocketPlan contracts that this change embeds and executes.
  • copyleftdev/kahea#26: Covers the finite WebSocket models and policy handling extended here to mixed Arazzo workflows.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: composing finite WebSocket sessions in workflows.
Linked Issues check ✅ Passed The changes address the linked issue requirements for sealed WebSocket plans, bounded bindings, grants, risk, outputs, timeouts, execution, and deterministic tests.
Out of Scope Changes check ✅ Passed The implementation, documentation, fixtures, dependencies, and tests are directly related to finite WebSocket workflow support.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/websocket-workflows

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@copyleftdev
copyleftdev marked this pull request as ready for review August 8, 2026 21:58

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (2)
crates/kahea-workflow/src/lib.rs (2)

941-961: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Make the close selectors return the same shape when close data is absent.

$websocket.close.code and $websocket.close.reason return Value::Null when observation.close is None. $websocket.close.initiator returns WorkflowError::Invalid in the same state. A workflow that selects the initiator then fails the whole step, while a workflow that selects the code receives null. Return Value::Null for the initiator as well, or fail all three selectors consistently.

♻️ Proposed change
         "$websocket.close.initiator" => {
             return observation
                 .close
                 .as_ref()
                 .map(serde_json::to_value)
                 .transpose()?
                 .map(|close| close["initiator"].clone())
-                .ok_or_else(|| WorkflowError::Invalid("WebSocket close data is absent".into()));
+                .map_or(Ok(Value::Null), Ok);
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/kahea-workflow/src/lib.rs` around lines 941 - 961, Update the
"$websocket.close.initiator" selector to return Value::Null when
observation.close is absent, matching the existing behavior of
"$websocket.close.code" and "$websocket.close.reason"; preserve the current
initiator extraction when close data exists.

1994-2008: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Bound the test peer accept and read calls.

spawn_websocket_peer calls listener.accept() and socket.read() without a timeout. If planning rejects the session or the client never connects, the worker thread blocks and join() at the end of the test hangs instead of failing. The executor tests already solve this with accept_test_connection, which polls a non-blocking listener against a deadline. Apply the same pattern here, and set read and write timeouts on the accepted stream.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/kahea-workflow/src/lib.rs` around lines 1994 - 2008, The
spawn_websocket_peer test helper currently performs unbounded network
operations. Reuse the existing accept_test_connection polling/deadline pattern
for the listener.accept step, and configure read and write timeouts on the
accepted stream before creating the WebSocket; ensure subsequent socket.read and
socket.send operations fail within the test deadline so worker join cannot hang.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/kahea-exec/src/websocket.rs`:
- Around line 430-433: Update the invocation deadline calculation near
total_deadline so overflow from started.checked_add(options.timeout) falls back
to the plan-derived deadline rather than Instant::now(). Ensure total_deadline
does not become immediately expired when options.timeout is extremely large,
while preserving the existing minimum behavior for non-overflowing invocation
deadlines.

In `@crates/kahea-workflow/src/lib.rs`:
- Around line 784-796: Update the WebSocketConnectResult::Denied branch to
record the denial and break immediately, removing the unconditional_retry,
retry-limit, delay, and continue logic from this path. Preserve returning the
original denial result so WebSocket denials remain terminal, matching the HTTP
denial behavior.
- Around line 695-760: In invoke_websocket_workflow_step, after rebuilding
websocket_plan from the bound source, validate that its risk and required_grants
match the sealed step.websocket_plan values, alongside the existing operation
identity check. Return WorkflowError::StepPlan with a clear rejection reason on
any mismatch, before store_websocket_plan or invocation.

---

Nitpick comments:
In `@crates/kahea-workflow/src/lib.rs`:
- Around line 941-961: Update the "$websocket.close.initiator" selector to
return Value::Null when observation.close is absent, matching the existing
behavior of "$websocket.close.code" and "$websocket.close.reason"; preserve the
current initiator extraction when close data exists.
- Around line 1994-2008: The spawn_websocket_peer test helper currently performs
unbounded network operations. Reuse the existing accept_test_connection
polling/deadline pattern for the listener.accept step, and configure read and
write timeouts on the accepted stream before creating the WebSocket; ensure
subsequent socket.read and socket.send operations fail within the test deadline
so worker join cannot hang.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9c2533c7-8142-428f-93cb-f42b551f9435

📥 Commits

Reviewing files that changed from the base of the PR and between 2a86784 and b3961cc.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • README.md
  • crates/kahea-core/src/lib.rs
  • crates/kahea-exec/src/websocket.rs
  • crates/kahea-workflow/Cargo.toml
  • crates/kahea-workflow/src/lib.rs
  • crates/kahea/tests/cli.rs
  • docs/architecture/0001-websocket-sessions.md
  • fixtures/workflows/events.websocket.json
  • fixtures/workflows/mixed.arazzo.yaml
  • plugins/kahea/skills/kahea/SKILL.md

Comment thread crates/kahea-exec/src/websocket.rs Outdated
Comment thread crates/kahea-workflow/src/lib.rs
Comment thread crates/kahea-workflow/src/lib.rs
@copyleftdev
copyleftdev merged commit 3057a37 into main Aug 8, 2026
13 checks passed
@copyleftdev
copyleftdev deleted the agent/websocket-workflows branch August 8, 2026 23:51
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.

websocket: integrate finite sessions into workflows

1 participant