Skip to content

Adopt AI SDK harness#1282

Open
willwashburn wants to merge 4 commits into
mainfrom
codex/ai-sdk-harness-adoption
Open

Adopt AI SDK harness#1282
willwashburn wants to merge 4 commits into
mainfrom
codex/ai-sdk-harness-adoption

Conversation

@willwashburn

@willwashburn willwashburn commented Jul 16, 2026

Copy link
Copy Markdown
Member

Summary

  • add experimental official AI SDK native harness adapters for Claude Code, Codex, OpenCode, Pi, and Deep Agents while keeping shared PTY-capable harnesses PTY-by-default
  • expose native selection through agent-relay node agent spawn|new --backend ai-sdk, with --backend auto|pty preserving the existing PTY rollout and unsupported-harness fallback
  • separate execution naming (pty | native) from normalized observability (AgentEvent), with headless documented as an internal broker process wrapper
  • make canonical lifecycle, activity, agent events, fidelity, and capabilities the Relay observability contract across native and PTY runtimes
  • publish broker-owned activity to Relaycast, add replay and native attach support, and expose SDK reducers/listeners for downstream applications
  • package the native sidecar and official adapters in both the Node distribution and Bun standalone executable
  • require Node 22 across packages and CI
  • add deterministic adapter contracts, 100-cycle fake soaks, PTY reference profiles, real broker/CLI native E2E, Bun standalone native E2E, and durable adversarial review evidence

Rollout boundary

All AI SDK adapters remain experimental. Claude Code, Codex, and OpenCode retain PTY as the default shared path. Pi and Deep Agents are explicit AI SDK-only options. Plan 001 remains IN PROGRESS until authenticated real-provider and cross-platform promotion gates pass.

Native attach supports structured view and line-oriented drive; terminal passthrough, task-exit, and --exit-after-task remain PTY-only.

Hosted high-frequency observability is ordered and bounded but intentionally best-effort during Relaycast outages; it is not a durable audit ledger.

Verification

  • npm test: 107 files passed, 1,320 tests passed, 14 skipped
  • cargo test: 1,024 tests passed, 5 ignored
  • native E2E: Bun standalone CLI -> real broker -> node agent spawn pi --backend ai-sdk -> embedded sidecar/adapter; Node CLI launch; native command/events/release protocol
  • npm run typecheck
  • npm run lint: 0 errors, 39 existing warnings
  • cargo fmt --all -- --check
  • git diff --check
  • scoped Prettier check
  • sequential fresh-context review/fix/signoff loops, final verdict: no findings

No UI surface changed.

@willwashburn
willwashburn requested a review from khaliqgant as a code owner July 16, 2026 06:27
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR establishes Node.js 22 as the runtime baseline and adds AI SDK native harness support through adapter registries, broker-supervised sidecars, versioned protocols, replayable events, observability reducers, CLI attach modes, Relaycast publication, and integration/soak validation.

Changes

AI SDK native harness adoption

Layer / File(s) Summary
Runtime baseline and adoption plan
.github/workflows/*, package.json, packages/*/package.json, plans/*, README.md, CHANGELOG.md
Updates CI, package engines, documentation, and implementation plans for Node.js 22 and AI SDK harness adoption.
Broker protocol and event transport
crates/broker/src/*
Adds native harness configuration, versioned commands/events, per-agent replay history, authenticated history/command APIs, Relaycast event publishing, and PTY observability tracking.
Harness driver contracts
packages/harness-driver/src/*
Adds native protocol types, headless transport selection, event history/subscriptions, buffered broker observation, and native runtime metadata.
AI SDK host and sidecar
packages/harnesses/src/ai-sdk/*
Adds adapter registration, local sandboxing, HarnessV1 lifecycle orchestration, Relay session mapping, native sidecar framing, command deduplication, and cleanup behavior.
Backend selection and CLI attach
packages/harnesses/src/define.ts, packages/harnesses/src/index.ts, packages/cli/src/cli/*
Adds auto/ai-sdk/pty backend routing, native sidecar launches, native attach rendering, drive commands, diagnostics, and sidecar entrypoint dispatch.
Canonical SDK observability
packages/sdk/src/session/*, packages/sdk/src/listeners.ts, packages/sdk/src/agent-relay.ts, packages/sdk/src/messaging/*
Adds observability metadata and capabilities, immutable activity reduction, activity listener selectors, canonical event publication, and Relaycast session-event messaging.
Validation suites
tests/integration/*, packages/*/*.test.ts, vitest.config.ts
Adds adapter contract, sandbox, sidecar, native attach, broker integration, observability parity, real-adapter, soak, and protocol validation coverage.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related issues

Possibly related PRs

Suggested labels: size:XXL

Suggested reviewers: khaliqgant

Poem

A rabbit hops through streams of light,
Native harnesses wake tonight.
Events march on, in ordered rows,
While Node twenty-two gently grows.
Sidecars hum and brokers relay—
Carrots for every test today!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers summary and verification, but it omits the template's Test Plan checklist and Screenshots section. Add a Test Plan section with checked items for tests/manual validation, and include a Screenshots section or note that none apply.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is concise and accurately reflects the main change: adopting AI SDK harnesses.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/ai-sdk-harness-adoption

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.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

38 issues found and verified against the latest diff

Not reviewed (too large): .agentworkforce/trajectories/completed/2026-07/traj_ajse65eu6brc.trace.json (~2,206 lines) - if these are generated or fixture files, add them to ignored paths to exclude them from future reviews.

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="tests/integration/ai-sdk-harnesses/real-adapters.test.ts">

<violation number="1" location="tests/integration/ai-sdk-harnesses/real-adapters.test.ts:64">
P1: When preflight fails or `createHarness()` throws before `host` is assigned, the `finally` block crashes with `TypeError: Cannot read properties of undefined (reading 'catch')` because `host?.destroy()` short-circuits to `undefined`, and `.catch()` is called on that `undefined` value. This either masks the real error or blows up the skip path.</violation>
</file>

<file name=".workflow-artifacts/plan-001/final-signoff-3.md">

<violation number="1" location=".workflow-artifacts/plan-001/final-signoff-3.md:5">
P2: This signoff can be consumed as an approval even though the required settled-tree full-suite gate has not run after the final repairs. Marking the verdict conditional (or withholding approval until the results are recorded) would keep the artifact consistent with its own verification evidence.</violation>
</file>

<file name="packages/sdk/src/session/types.ts">

<violation number="1" location="packages/sdk/src/session/types.ts:521">
P2: A `file.changed` update can pass through the AI SDK mapper at runtime even though `CanonicalAgentSessionEvent` forbids `operation: 'update'`. Preserving `update` in the canonical type or normalizing it to `modify` before publication would prevent this type/runtime contract mismatch.</violation>
</file>

<file name="packages/harnesses/src/define.ts">

<violation number="1" location="packages/harnesses/src/define.ts:137">
P2: Custom PTY harnesses now fail during descriptor creation because observability lookup only recognizes the fixed built-in command names. Keeping `definePtyHarness` generic requires an unavailable/generic PTY profile for unknown commands, or an optional profile lookup, rather than throwing for valid custom definitions.</violation>

<violation number="2" location="packages/harnesses/src/define.ts:364">
P2: Managed PTY factories drop all optional fields from the supplied `ptyDefinition`, so fleet spawns silently lose configured arguments, environment, working directory, session ID, delivery, and metadata. Preserving the `StaticPtyHarnessDefinition` fields in this returned object keeps the declared `ManagedPtyHarness` contract and the existing spawn configuration behavior.</violation>
</file>

<file name=".workflow-artifacts/plan-001/final-signoff.md">

<violation number="1" location=".workflow-artifacts/plan-001/final-signoff.md:11">
P1: Plan 001 is incorrectly rejected for missing Relaycast semantic publication: the broker already forwards canonical semantic frames to Relaycast through `run_hosted_agent_event_publisher`. Please remove or rewrite this P1 finding instead of requiring a repair that is already implemented.</violation>

<violation number="2" location=".workflow-artifacts/plan-001/final-signoff.md:24">
P1: Plan 001 is incorrectly rejected for a dead PTY translator: live PTY spawns already translate broker boundaries into canonical local events, while the broker publishes the same PTY profile through Relaycast. Please remove or rewrite this P1 finding to reflect the implemented path.</violation>
</file>

<file name="packages/harnesses/src/ai-sdk/local-host-sandbox.ts">

<violation number="1" location="packages/harnesses/src/ai-sdk/local-host-sandbox.ts:349">
P2: Removing a leased port with `setPorts([])` leaks its loopback reservation, so the session cannot release that port on stop and the provider keeps holding it. Releasing removed ports before replacing `#ports` would keep port ownership consistent.</violation>
</file>

<file name="plans/001-adopt-ai-sdk-harnesses.md">

<violation number="1" location="plans/001-adopt-ai-sdk-harnesses.md:452">
P1: A green real-adapter run can contain no authenticated execution because unavailable CLIs and credentials are skipped by adapter name, so it cannot prove the stated promotion gate. Keep skips for ordinary CI, but make promotion mode fail unless every target adapter has a non-skipped authenticated run.</violation>
</file>

<file name=".workflow-artifacts/plan-001/claude-review-1.md">

<violation number="1" location=".workflow-artifacts/plan-001/claude-review-1.md:15">
P2: This finding would incorrectly block the change: duplicate `deliver_relay` frames are acknowledged twice while `RelayHarnessSession` injects once. The implementation and existing sidecar test already cover the claimed redelivery behavior, so this P1 should be removed or revised.</violation>

<violation number="2" location=".workflow-artifacts/plan-001/claude-review-1.md:35">
P2: Semantic startup history is not erased by `agent_spawned`: the replay buffer resets the previous generation before launch and treats the later broadcast as observational. This P1 is contradicted by the implementation and `semantic_startup_events_before_spawn_broadcast_remain_replayable` test, so it should be removed or revised.</violation>

<violation number="3" location=".workflow-artifacts/plan-001/claude-review-1.md:53">
P2: Semantic sidecars already publish capability discovery, mapped events, and reducer transitions through the broker-facing output. The existing sidecar test covers those outputs, so this P1's reproduction is false and should be removed or revised.</violation>

<violation number="4" location=".workflow-artifacts/plan-001/claude-review-1.md:71">
P2: The public runtime metadata does not advertise the full registry lifecycle: inaccessible operations are explicitly reported as `false`. Therefore the claimed `detach: true`/`stop: true` discovery path is not present; this finding should distinguish internal adapter capabilities from public metadata or be removed.</violation>
</file>

<file name=".workflow-artifacts/plan-001/final-signoff-2.md">

<violation number="1" location=".workflow-artifacts/plan-001/final-signoff-2.md:20">
P1: The signoff’s P1 rejects supported CLI/fleet/direct PTY spawns as unobservable, but the broker already emits canonical PTY events for those paths. This section should be removed or narrowed to wrapper-local translation coverage rather than requiring another broker-owned publisher.</violation>

<violation number="2" location=".workflow-artifacts/plan-001/final-signoff-2.md:34">
P2: The signoff treats loss during a Relaycast outage as a blocker even though this PR explicitly defines hosted high-frequency observability as bounded best-effort, not a durable audit ledger. Unless another public surface promises durability, this should be recorded as accepted contract behavior (with optional drop metrics), not a required persisted outbox repair.</violation>
</file>

<file name="crates/broker/src/runtime/worker_events.rs">

<violation number="1" location="crates/broker/src/runtime/worker_events.rs:208">
P2: PTY workers that become idle before producing a stream never publish the canonical `idle` activity, leaving observers stuck at `starting`. The idle transition should be emitted whenever the current activity is not already idle; emit `turn.settled` only when an active turn exists.</violation>
</file>

<file name="packages/cli/src/cli/commands/local-agent.ts">

<violation number="1" location="packages/cli/src/cli/commands/local-agent.ts:60">
P2: A broker failure while probing the agent type now rejects `runAttach` before `attachView`/`attachDrive` can report the error, causing `local agent attach` to fail as an uncaught promise instead of returning its normal nonzero exit path. Treat probe failures as non-semantic (or handle the rejection) so the existing attach error handling remains effective.</violation>
</file>

<file name="packages/sdk/src/session/activity-reducer.ts">

<violation number="1" location="packages/sdk/src/session/activity-reducer.ts:98">
P2: Parallel same-named tool calls without a stable `callId` or `run` are collapsed into one active entry, so completing one call can make activity stop reporting `using_tool` while the other is still running. The reducer should require or create a per-call correlation key and only remove the matching observation on completion.</violation>

<violation number="2" location="packages/sdk/src/session/activity-reducer.ts:211">
P2: Late events from an earlier turn can corrupt the current activity because text, reasoning, and tool cases never validate the event's provenance against the active `turnId`. Filtering turn-scoped work events to the current turn (and ignoring them after the turn/session is no longer active) would prevent stale stream callbacks from producing false busy states.</violation>
</file>

<file name="packages/sdk/src/agent-relay.ts">

<violation number="1" location="packages/sdk/src/agent-relay.ts:408">
P2: Publishing with a Relaycast agent ID does not reliably target the agent's durable session-event stream because `sessionEvents.emit` is name-keyed. Resolve the agent name before calling the Relaycast API, or change this API to accept an agent name explicitly and keep the local ID separate.</violation>

<violation number="2" location="packages/sdk/src/agent-relay.ts:499">
P2: Agent-scoped clients propagate Relaycast session-event failures, unlike `AgentRelay.publishSessionEvent`, which reports and absorbs them. Applying the same best-effort/error-hook handling here would keep both `AgentRelayAgent` implementations consistent during Relaycast outages.</violation>
</file>

<file name="packages/harnesses/src/ai-sdk/relay-session.ts">

<violation number="1" location="packages/harnesses/src/ai-sdk/relay-session.ts:396">
P2: `next-tool-call` deliveries are executed immediately instead of waiting for the next tool call, so the advertised delivery mode is not honored. Deferring this mode until a `tool.called` event (or removing it from the declared modes) would keep the session contract accurate.</violation>

<violation number="2" location="packages/harnesses/src/ai-sdk/relay-session.ts:399">
P2: Failed deliveries from `startTurn`, `submitUserMessage`, or a full queue are invisible to `onEvent` observers even though `delivery.failed` is declared in `events.emits`. Emitting the failure event for every failed receipt would keep listener/replay consumers consistent with the returned receipt.</violation>
</file>

<file name=".workflow-artifacts/plan-001/final-signoff-resolution.md">

<violation number="1" location=".workflow-artifacts/plan-001/final-signoff-resolution.md:5">
P1: Live harness observability is not published to Relaycast despite this signoff: both semantic sidecar and PTY paths call `emitSessionEvent`, which is local-only, so `messaging.sessionEvents.list` cannot expose those events. Route both paths through the hosted publication/queue path while preserving local listener delivery.</violation>
</file>

<file name="packages/cli/src/cli/lib/attach-semantic.ts">

<violation number="1" location="packages/cli/src/cli/lib/attach-semantic.ts:236">
P2: When the semantic worker exits, `attachSemantic` can hang forever because the live iterator is only stopped by SIGINT, `/detach`, or a closed stream; broker lifecycle exit events are ignored. Handling the worker-exit/error events and stopping the iterator would let `view`/`drive` terminate when the harness is gone.</violation>

<violation number="2" location="packages/cli/src/cli/lib/attach-semantic.ts:251">
P2: After `/detach`, Ctrl+C, or normal completion, this command removes the semantic listener but leaves the broker event WebSocket/reconnect loop alive, which can keep the CLI process running and continue network activity. Disconnecting the event transport during teardown would release the client resources.</violation>
</file>

<file name="crates/broker/src/runtime/event_loop.rs">

<violation number="1" location="crates/broker/src/runtime/event_loop.rs:38">
P2: Workspace-specific observability events can be published to the default Relaycast workspace when their `WorkspaceId` is absent from `clients`, because this fallback treats an unresolved `Some(workspace_id)` like an intentionally default-routed event. Keeping the default fallback only for `None` and dropping/logging unresolved workspace IDs avoids cross-workspace event misattribution.</violation>
</file>

<file name="packages/harness-driver/src/protocol.ts">

<violation number="1" location="packages/harness-driver/src/protocol.ts:635">
P2: Semantic commands and their responses can be represented without the top-level request ID required by the sidecar and broker, causing a command to be ignored or an acknowledgement to be dropped. Mark `request_id` required in both semantic command variants so typed producers cannot construct an unusable frame.</violation>
</file>

<file name="packages/sdk/src/__tests__/activity-reducer.test.ts">

<violation number="1" location="packages/sdk/src/__tests__/activity-reducer.test.ts:43">
P1: Duplicate `text.started` event with the same sequence number (3) will be silently dropped by the reducer's deduplication, so the assertion on `result.transition` will fail: after `reduce()` processes `text.started` with `observation(3)`, `lastSequence` becomes 3, and the subsequent `reduceAgentActivity()` call with the same `observation(3)` returns `{ state: previous }` with an undefined transition instead of the expected `activity.changed`. Remove the redundant first `reduce()` call or use a distinct sequence for one of the two events.</violation>
</file>

<file name="packages/harness-driver/src/broker-driver.ts">

<violation number="1" location="packages/harness-driver/src/broker-driver.ts:68">
P2: High-output PTY workers can grow this buffer without bound when no observer is attached yet: every matching `worker_stream` chunk is retained until `observeBrokerEvents` or `release`. A bounded queue/drop policy would preserve the spawn race fix without turning delayed observation into an unbounded memory sink.</violation>

<violation number="2" location="packages/harness-driver/src/broker-driver.ts:192">
P2: One rejected semantic listener silently suppresses all subsequent semantic events until the runtime closes, and `onError` is delayed until shutdown. Handling listener failures per event—like `observeBrokerEvents` does—would notify `onError` and either continue delivery or explicitly close the observer.</violation>

<violation number="3" location="packages/harness-driver/src/broker-driver.ts:197">
P2: A failed semantic-history request leaks both the live semantic subscription and the runtime-exit listener because setup exits before a disposer is returned. Wrapping stream/history setup in cleanup handling would prevent later broker events and reconnects from retaining this observer.</violation>
</file>

<file name=".workflow-artifacts/plan-001/codex-review-1.md">

<violation number="1" location=".workflow-artifacts/plan-001/codex-review-1.md:97">
P2: The executed-evidence conclusion incorrectly says the green suites do not exercise symlink traversal or conflicting idempotency-key reuse, even though both cases have dedicated tests in the repository. Please correct this coverage statement and limit the untested list to the delayed competitor and end-to-end listener scenarios that are actually missing.</violation>
</file>

<file name="packages/harnesses/src/ai-sdk/harness-host.ts">

<violation number="1" location="packages/harnesses/src/ai-sdk/harness-host.ts:369">
P1: An initial `continueFrom` is never actually continued: `start()` passes it to `doStart()` but does not call `doContinueTurn()`, so recovering an in-flight turn through the constructor silently loses the continuation path. The startup flow could invoke the continuation and return its `HarnessTurnHandle`, or reject this option instead of accepting it.</violation>

<violation number="2" location="packages/harnesses/src/ai-sdk/harness-host.ts:535">
P1: A failed `doContinueTurn()` leaves the host stuck in `running` with a stale turn and no control, making the session unusable after a transient adapter error. Handling this call like `doPromptTurn()`—resetting the generation-bound turn state, emitting the error, and restoring an appropriate state—would preserve lifecycle recovery.</violation>

<violation number="3" location="packages/harnesses/src/ai-sdk/harness-host.ts:536">
P1: Continued turns ignore the host-level `abortSignal`, unlike normal prompt turns, so cancellation of the host does not stop an in-flight continuation. Passing the same combined signal used by `startTurn()` would keep both lifecycle paths cancellable.</violation>
</file>

<file name="packages/harness-driver/src/driver-types.ts">

<violation number="1" location="packages/harness-driver/src/driver-types.ts:25">
P2: Action-based `agent.create` calls cannot use the new harness launch contract: `createAgentSchema` rejects `harnessConfig` before the driver receives it. Adding `harnessConfig` to that schema with the runtime-specific shape would allow semantic sidecar spawns through the public action API.</violation>
</file>

<file name="packages/harnesses/src/ai-sdk/sidecar.ts">

<violation number="1" location="packages/harnesses/src/ai-sdk/sidecar.ts:162">
P2: Deferred deliveries that fail after being queued never receive a `delivery_failed` frame, so the broker keeps them pending and may retry or dead-letter them instead of completing the delivery workflow. Handling `delivery.failed` here should clear the pending entry and send the corresponding failure frame.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

}
throw error;
} finally {
await host?.destroy().catch(() => undefined);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: When preflight fails or createHarness() throws before host is assigned, the finally block crashes with TypeError: Cannot read properties of undefined (reading 'catch') because host?.destroy() short-circuits to undefined, and .catch() is called on that undefined value. This either masks the real error or blows up the skip path.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At tests/integration/ai-sdk-harnesses/real-adapters.test.ts, line 64:

<comment>When preflight fails or `createHarness()` throws before `host` is assigned, the `finally` block crashes with `TypeError: Cannot read properties of undefined (reading 'catch')` because `host?.destroy()` short-circuits to `undefined`, and `.catch()` is called on that `undefined` value. This either masks the real error or blows up the skip path.</comment>

<file context>
@@ -0,0 +1,71 @@
+          }
+          throw error;
+        } finally {
+          await host?.destroy().catch(() => undefined);
+          await rm(root, { recursive: true, force: true });
+        }
</file context>


## Findings

### P1 - Semantic events reach the local `AgentRelay` listener hub, but are still not published by Relaycast

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: Plan 001 is incorrectly rejected for missing Relaycast semantic publication: the broker already forwards canonical semantic frames to Relaycast through run_hosted_agent_event_publisher. Please remove or rewrite this P1 finding instead of requiring a repair that is already implemented.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .workflow-artifacts/plan-001/final-signoff.md, line 11:

<comment>Plan 001 is incorrectly rejected for missing Relaycast semantic publication: the broker already forwards canonical semantic frames to Relaycast through `run_hosted_agent_event_publisher`. Please remove or rewrite this P1 finding instead of requiring a repair that is already implemented.</comment>

<file context>
@@ -0,0 +1,81 @@
+
+## Findings
+
+### P1 - Semantic events reach the local `AgentRelay` listener hub, but are still not published by Relaycast
+
+The Codex resolution is only partially true.
</file context>


Required repair: publish the canonical envelopes through the authenticated Relaycast transport with stable public event names and wire round-trip tests, or change the plan/docs/changelog to describe the local broker/SDK observer plane accurately. The Plan 001 done criterion itself currently requires the former.

### P1 - PTY observability is a dead translator, so PTY runtimes emit none of the advertised canonical profile

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: Plan 001 is incorrectly rejected for a dead PTY translator: live PTY spawns already translate broker boundaries into canonical local events, while the broker publishes the same PTY profile through Relaycast. Please remove or rewrite this P1 finding to reflect the implemented path.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .workflow-artifacts/plan-001/final-signoff.md, line 24:

<comment>Plan 001 is incorrectly rejected for a dead PTY translator: live PTY spawns already translate broker boundaries into canonical local events, while the broker publishes the same PTY profile through Relaycast. Please remove or rewrite this P1 finding to reflect the implemented path.</comment>

<file context>
@@ -0,0 +1,81 @@
+
+Required repair: publish the canonical envelopes through the authenticated Relaycast transport with stable public event names and wire round-trip tests, or change the plan/docs/changelog to describe the local broker/SDK observer plane accurately. The Plan 001 done criterion itself currently requires the former.
+
+### P1 - PTY observability is a dead translator, so PTY runtimes emit none of the advertised canonical profile
+
+- `packages/harnesses/src/observability.ts:118-207` defines `createPtyObservabilityTranslator`.
</file context>


## Hosted Relaycast transport

- Canonical semantic sidecar frames are enqueued independently for Relaycast's authenticated `POST /v1/agents/:name/events` SDK surface while remaining available on the local broker stream.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: Live harness observability is not published to Relaycast despite this signoff: both semantic sidecar and PTY paths call emitSessionEvent, which is local-only, so messaging.sessionEvents.list cannot expose those events. Route both paths through the hosted publication/queue path while preserving local listener delivery.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .workflow-artifacts/plan-001/final-signoff-resolution.md, line 5:

<comment>Live harness observability is not published to Relaycast despite this signoff: both semantic sidecar and PTY paths call `emitSessionEvent`, which is local-only, so `messaging.sessionEvents.list` cannot expose those events. Route both paths through the hosted publication/queue path while preserving local listener delivery.</comment>

<file context>
@@ -0,0 +1,37 @@
+
+## Hosted Relaycast transport
+
+- Canonical semantic sidecar frames are enqueued independently for Relaycast's authenticated `POST /v1/agents/:name/events` SDK surface while remaining available on the local broker stream.
+- `AgentRelay.publishSessionEvent` delivers a canonical event to local listeners and Relaycast durable agent-event storage. `messaging.sessionEvents.list` exposes the upstream read surface to other Relay applications.
+- A loopback HTTP round-trip asserts the stable event type and canonical payload sent to Relaycast.
</file context>

it('follows the reference lifecycle and waits for turn settlement before becoming idle', () => {
let state = createAgentActivityState();

let result = reduceAgentActivity(state, {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: Duplicate text.started event with the same sequence number (3) will be silently dropped by the reducer's deduplication, so the assertion on result.transition will fail: after reduce() processes text.started with observation(3), lastSequence becomes 3, and the subsequent reduceAgentActivity() call with the same observation(3) returns { state: previous } with an undefined transition instead of the expected activity.changed. Remove the redundant first reduce() call or use a distinct sequence for one of the two events.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/sdk/src/__tests__/activity-reducer.test.ts, line 43:

<comment>Duplicate `text.started` event with the same sequence number (3) will be silently dropped by the reducer's deduplication, so the assertion on `result.transition` will fail: after `reduce()` processes `text.started` with `observation(3)`, `lastSequence` becomes 3, and the subsequent `reduceAgentActivity()` call with the same `observation(3)` returns `{ state: previous }` with an undefined transition instead of the expected `activity.changed`. Remove the redundant first `reduce()` call or use a distinct sequence for one of the two events.</comment>

<file context>
@@ -0,0 +1,307 @@
+  it('follows the reference lifecycle and waits for turn settlement before becoming idle', () => {
+    let state = createAgentActivityState();
+
+    let result = reduceAgentActivity(state, {
+      type: 'session.starting',
+      observability: observation(1),
</file context>

if (ports.some((port) => !this.#ports.includes(port))) {
throw new Error('Local sandbox ports are exclusively allocated by the provider');
}
this.#ports = [...ports];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: Removing a leased port with setPorts([]) leaks its loopback reservation, so the session cannot release that port on stop and the provider keeps holding it. Releasing removed ports before replacing #ports would keep port ownership consistent.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/harnesses/src/ai-sdk/local-host-sandbox.ts, line 349:

<comment>Removing a leased port with `setPorts([])` leaks its loopback reservation, so the session cannot release that port on stop and the provider keeps holding it. Releasing removed ports before replacing `#ports` would keep port ownership consistent.</comment>

<file context>
@@ -0,0 +1,551 @@
+    if (ports.some((port) => !this.#ports.includes(port))) {
+      throw new Error('Local sandbox ports are exclusively allocated by the provider');
+    }
+    this.#ports = [...ports];
+  }
+
</file context>

return attachDrive(name, options);
}
export function runAttach(name: string, mode: AttachMode, options: SemanticAttachOptions): Promise<number> {
return isSemanticHarness(name, options).then((semantic) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: A broker failure while probing the agent type now rejects runAttach before attachView/attachDrive can report the error, causing local agent attach to fail as an uncaught promise instead of returning its normal nonzero exit path. Treat probe failures as non-semantic (or handle the rejection) so the existing attach error handling remains effective.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cli/src/cli/commands/local-agent.ts, line 60:

<comment>A broker failure while probing the agent type now rejects `runAttach` before `attachView`/`attachDrive` can report the error, causing `local agent attach` to fail as an uncaught promise instead of returning its normal nonzero exit path. Treat probe failures as non-semantic (or handle the rejection) so the existing attach error handling remains effective.</comment>

<file context>
@@ -55,32 +56,27 @@ export type AttachMode = 'drive' | 'view' | 'passthrough';
-      return attachDrive(name, options);
-  }
+export function runAttach(name: string, mode: AttachMode, options: SemanticAttachOptions): Promise<number> {
+  return isSemanticHarness(name, options).then((semantic) => {
+    if (semantic) return attachSemantic(name, mode, options);
+    switch (mode) {
</file context>
Suggested change
return isSemanticHarness(name, options).then((semantic) => {
return isSemanticHarness(name, options).catch(() => false).then((semantic) => {

emitSessionEvent: (agentId, event) => hub.emitSessionEvent(agentId, event),
publishSessionEvent: async (agentId, event) => {
hub.emitSessionEvent(agentId, event);
await messaging.sessionEvents?.emit(agentId, event);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: Agent-scoped clients propagate Relaycast session-event failures, unlike AgentRelay.publishSessionEvent, which reports and absorbs them. Applying the same best-effort/error-hook handling here would keep both AgentRelayAgent implementations consistent during Relaycast outages.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/sdk/src/agent-relay.ts, line 499:

<comment>Agent-scoped clients propagate Relaycast session-event failures, unlike `AgentRelay.publishSessionEvent`, which reports and absorbs them. Applying the same best-effort/error-hook handling here would keep both `AgentRelayAgent` implementations consistent during Relaycast outages.</comment>

<file context>
@@ -480,6 +494,10 @@ export function agentRelayAgent(
     emitSessionEvent: (agentId, event) => hub.emitSessionEvent(agentId, event),
+    publishSessionEvent: async (agentId, event) => {
+      hub.emitSessionEvent(agentId, event);
+      await messaging.sessionEvents?.emit(agentId, event);
+    },
   };
</file context>

this.host.hasActiveTurn && (context.mode === 'next-message' || context.mode === 'on-idle');
if (shouldQueue) {
if (this.#queue.length >= this.#maxQueueSize) {
return this.#remember(key, {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: Failed deliveries from startTurn, submitUserMessage, or a full queue are invisible to onEvent observers even though delivery.failed is declared in events.emits. Emitting the failure event for every failed receipt would keep listener/replay consumers consistent with the returned receipt.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/harnesses/src/ai-sdk/relay-session.ts, line 399:

<comment>Failed deliveries from `startTurn`, `submitUserMessage`, or a full queue are invisible to `onEvent` observers even though `delivery.failed` is declared in `events.emits`. Emitting the failure event for every failed receipt would keep listener/replay consumers consistent with the returned receipt.</comment>

<file context>
@@ -0,0 +1,438 @@
+        this.host.hasActiveTurn && (context.mode === 'next-message' || context.mode === 'on-idle');
+      if (shouldQueue) {
+        if (this.#queue.length >= this.#maxQueueSize) {
+          return this.#remember(key, {
+            status: 'failed',
+            deliveryId: context.id,
</file context>

const unsubscribe = client.onEvent((event) => {
if (!('name' in event) || event.name !== name) return;
if (live) live(event);
else pending.push(event);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: High-output PTY workers can grow this buffer without bound when no observer is attached yet: every matching worker_stream chunk is retained until observeBrokerEvents or release. A bounded queue/drop policy would preserve the spawn race fix without turning delayed observation into an unbounded memory sink.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/harness-driver/src/broker-driver.ts, line 68:

<comment>High-output PTY workers can grow this buffer without bound when no observer is attached yet: every matching `worker_stream` chunk is retained until `observeBrokerEvents` or `release`. A bounded queue/drop policy would preserve the spawn race fix without turning delayed observation into an unbounded memory sink.</comment>

<file context>
@@ -38,12 +44,37 @@ export class BrokerDriver implements AgentDriver {
+    const unsubscribe = client.onEvent((event) => {
+      if (!('name' in event) || event.name !== name) return;
+      if (live) live(event);
+      else pending.push(event);
+    });
+    return {
</file context>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/verify-publish.yml (1)

420-423: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove Node 20 from verify-docker matrix.

The summary output for Node 20 was removed, but the verify-docker strategy matrix at line 365 still includes '20' (node: ['20', '22']). This means the job will still run for Node 20, but the result will be confusingly aggregated under "Node 22" in the markdown summary.

Please remove '20' from the verify-docker matrix to fully align with the Node 22 migration plan.

🤖 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 @.github/workflows/verify-publish.yml around lines 420 - 423, Update the
verify-docker strategy matrix to remove Node 20, leaving only Node 22 so the
workflow execution matches the Docker test summary and migration plan.
🟠 Major comments (21)
tests/integration/ai-sdk-harnesses/real-adapters.test.ts-10-10 (1)

10-10: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Do not convert arbitrary adapter failures into skips.

Matching generic text such as not found, unavailable, or pnpm can classify model-resolution, packaging, and adapter regressions as environmental skips. Restrict skipping to typed credential or missing-executable failures and rethrow ambiguous errors.

Also applies to: 55-61

🤖 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 `@tests/integration/ai-sdk-harnesses/real-adapters.test.ts` at line 10,
Restrict AUTH_OR_CLI_ERROR and the related skip handling in the adapter test to
explicit credential/authentication failures or missing-executable errors,
removing broad matches such as “not found,” “unavailable,” and “pnpm.” Ensure
ambiguous adapter, model-resolution, packaging, and regression errors are
rethrown instead of converted into skips.
tests/integration/ai-sdk-harnesses/adapter-contract.test.ts-23-155 (1)

23-155: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

The deterministic acceptance suites do not exercise registered adapter implementations.

Both suites substitute FakeHarnessController, so adapter-specific failures cannot affect their results.

  • tests/integration/ai-sdk-harnesses/adapter-contract.test.ts#L23-L155: instantiate adapter-backed deterministic fixtures rather than mirroring registry declarations in a generic fake.
  • tests/integration/ai-sdk-harnesses/soak-contract.test.ts#L44-L180: collect metrics from those adapter-backed fixtures, or rename the evidence as a shared-host fake soak.
🤖 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 `@tests/integration/ai-sdk-harnesses/adapter-contract.test.ts` around lines 23
- 155, Replace the FakeHarnessController-based fixtures with adapter-backed
deterministic fixtures so registered implementations are actually exercised. In
tests/integration/ai-sdk-harnesses/adapter-contract.test.ts:23-155, update the
adapter-contract setup around aiSdkAdapterRegistry and host; in
tests/integration/ai-sdk-harnesses/soak-contract.test.ts:44-180, collect soak
metrics from those same adapter-backed fixtures, or explicitly rename the suite
to describe a shared-host fake soak if it remains fake.
packages/sdk/src/agent-relay.ts-121-121 (1)

121-121: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Keep the listener ID and Relaycast agent name distinct.

publishSessionEvent(agentId, ...) uses the same value for local ID-based dispatch and agents.events.emit(name, ...). Since agent IDs and names are distinct, events can be persisted against the wrong identifier or fail entirely. Accept both identity fields or resolve the storage name separately; the test currently masks this by passing "Worker" as the ID.

Also applies to: 405-408, 497-499

🤖 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 `@packages/sdk/src/agent-relay.ts` at line 121, Update publishSessionEvent and
its implementations/call sites to keep the local agentId separate from the
Relaycast agent name used by agents.events.emit. Accept or resolve both identity
values, use agentId for listener dispatch and persistence, and use the Relaycast
name for emission; update the affected tests so they pass distinct identifiers.
packages/sdk/src/session/activity-reducer.ts-152-157 (1)

152-157: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Advance the sequence watermark for ignored activity transitions.

Line 153 ignores activity.changed before recording its sequence. If sequence 10 is ignored and sequence 9 arrives afterward, sequence 9 is incorrectly processed as current, violating replay/out-of-order deduplication.

Proposed fix
   const observation = observed(event);
-  if (!observation || event.type === 'activity.changed') return { state: previous };
+  if (!observation) return { state: previous };
   if (observation.sequence <= previous.lastSequence) return { state: previous };
+  if (event.type === 'activity.changed') {
+    return {
+      state: { ...previous, lastSequence: observation.sequence },
+    };
+  }

   const state = cloneState(previous);

Add a regression test with an ignored transition followed by a lower-sequence lifecycle event.

🤖 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 `@packages/sdk/src/session/activity-reducer.ts` around lines 152 - 157, Update
the reducer logic around observed and activity.changed events so ignored
activity transitions still advance the sequence watermark before returning the
unchanged activity state. Preserve deduplication for sequences at or below the
updated watermark, and add a regression test covering an ignored higher-sequence
transition followed by a lower-sequence lifecycle event.
packages/sdk/src/agent-relay.ts-497-500 (1)

497-500: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Match the class’s best-effort publication behavior.

This facade rejects when Relaycast is unavailable, while AgentRelay.publishSessionEvent reports and swallows the same failure. Wrap this emission and route errors through options?.onError so callers do not receive implementation-dependent outage behavior.

Proposed parity fix
     publishSessionEvent: async (agentId, event) => {
       hub.emitSessionEvent(agentId, event);
-      await messaging.sessionEvents?.emit(agentId, event);
+      try {
+        await messaging.sessionEvents?.emit(agentId, event);
+      } catch (error) {
+        options?.onError?.(error, {
+          source: 'listener',
+          selector: event.type,
+          operation: 'publish_session_event',
+        });
+      }
     },
🤖 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 `@packages/sdk/src/agent-relay.ts` around lines 497 - 500, Update
publishSessionEvent to use best-effort error handling: wrap the hub and optional
messaging session-event emissions in a try/catch, and route any failure through
options?.onError without rejecting to callers. Preserve the existing emission
order and successful behavior.
packages/sdk/src/listeners.ts-531-541 (1)

531-541: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Type canonical selectors from AgentEvent, not the legacy session union.

The current map exposes AgentSessionEvent variants, so handlers such as tool.called, file.changed, and error still see optional observability and legacy fields despite using canonical selectors. Build the mapped envelope from AgentEvent, and normalize or reject legacy events before dispatch.

Proposed type correction
 import type {
   AgentActivity,
+  AgentEvent,
   AgentEventType,
   AgentSessionEvent,
 } from './session/index.js';

 export type RelayCanonicalSessionEventMap = {
-  [TType in CanonicalSessionSelector]: RelaySessionEvent<TType>;
+  [TType in CanonicalSessionSelector]: {
+    type: TType;
+    agentId: string;
+    event: Extract<AgentEvent, { type: TType }>;
+  };
 };
🤖 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 `@packages/sdk/src/listeners.ts` around lines 531 - 541, Update
RelaySessionEvent and RelayCanonicalSessionEventMap to derive event payloads
from the canonical AgentEvent union rather than AgentSessionEvent, so canonical
selectors such as tool.called, file.changed, and error expose only canonical
fields. Normalize or reject legacy session events before dispatch so handlers
cannot receive AgentSessionEvent variants through the canonical map.
packages/harnesses/src/define.ts-236-236 (1)

236-236: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject unsupported AI SDK selection from new() too.

Line 236 silently returns a PTY descriptor for calls such as gemini.new({ backend: 'ai-sdk' }), while create() correctly rejects the same explicit request. Keep both public entry points consistent.

Proposed fix
-    new: (input) => build(input),
+    new: (input = {}) => {
+      if (input.backend === 'ai-sdk') {
+        throw new Error(`No AI SDK harness adapter is registered for ${definition.command}`);
+      }
+      return build(input);
+    },
🤖 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 `@packages/harnesses/src/define.ts` at line 236, Update the `new` entry point
to reject an explicit unsupported `backend: 'ai-sdk'` request, matching the
validation behavior of `create()`, while preserving normal PTY descriptor
construction for supported backends.
packages/harnesses/src/ai-sdk/relay-session.ts-58-94 (1)

58-94: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Advertise the emitted session.released event.

release() emits session.released, but capabilities.events.emits omits it. This makes the published event contract inaccurate.

Also applies to: 429-435

🤖 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 `@packages/harnesses/src/ai-sdk/relay-session.ts` around lines 58 - 94, Add
'session.released' to the AI_SDK_EVENT_TYPES array used by
capabilities.events.emits, ensuring the advertised event contract matches the
event emitted by release().
packages/harnesses/src/ai-sdk/local-host-sandbox.ts-345-350 (1)

345-350: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Release removed ports and make released ports reusable.

setPorts() drops removed leases without releasing them, while #releasePorts() never deletes ports from #usedPorts. Long-running session churn leaks reservations and eventually exhausts eligible ephemeral ports.

Proposed fix
 async setPorts(ports: readonly number[]) {
   if (ports.some((port) => !this.#ports.includes(port))) {
     throw new Error('Local sandbox ports are exclusively allocated by the provider');
   }
+  await this.#releasePorts(this.#ports.filter((port) => !ports.includes(port)));
   this.#ports = [...ports];
 }

 async `#releasePorts`(ports: readonly number[]): Promise<void> {
   for (const port of ports) {
     await this.#handoffPort(port);
     this.#ports.delete(port);
+    this.#usedPorts.delete(port);
   }
 }

Also applies to: 442-447

🤖 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 `@packages/harnesses/src/ai-sdk/local-host-sandbox.ts` around lines 345 - 350,
Update setPorts and `#releasePorts` to release ports removed from the current
allocation and delete every released port from `#usedPorts`, while preserving
validation that all requested ports are provider-allocated. Ensure released
ports become eligible for reuse during later allocations.
packages/harnesses/src/ai-sdk/relay-session.ts-289-297 (1)

289-297: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Do not advertise next-tool-call until its semantics are implemented.

During an active turn, this mode falls through to #accept() and injects immediately. Either defer it until a tool-call boundary or remove it from the capabilities list.

Also applies to: 395-397

🤖 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 `@packages/harnesses/src/ai-sdk/relay-session.ts` around lines 289 - 297,
Remove next-tool-call from the advertised delivery modes in the RelaySession
capabilities configuration. Until its boundary semantics are implemented in the
delivery handling path, keep only the currently supported modes and preserve the
existing capability structure.
packages/harnesses/src/ai-sdk/harness-host.ts-301-312 (1)

301-312: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Serialize normalized event delivery.

Stream callbacks invoke #emit concurrently. Later raw events can therefore be published before activity transitions derived from earlier events, violating observable event order. Queue listener dispatch inside #emit.

Also applies to: 417-419, 537-539

🤖 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 `@packages/harnesses/src/ai-sdk/harness-host.ts` around lines 301 - 312, Update
`#emit` to serialize normalized event delivery through a shared promise chain or
equivalent dispatch queue, ensuring each event’s listener notifications complete
before the next event is published. Preserve the existing listener snapshot,
Promise.allSettled behavior, sequencing, and turn metadata, and apply the same
queued dispatch behavior to the related `#emit` call sites.
packages/harnesses/src/ai-sdk/relay-session.ts-429-435 (1)

429-435: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Finalize deferred deliveries before clearing the queue.

Release silently discards queued messages whose callers received deferred receipts. Replace each receipt with a terminal failure and emit delivery.failed before destroying the host.

🤖 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 `@packages/harnesses/src/ai-sdk/relay-session.ts` around lines 429 - 435,
Update release in the session class to finalize every queued deferred delivery
before clearing `#queue`: replace each receipt with a terminal failure and emit
the corresponding delivery.failed event, then clear the queue and continue
destroying the host and emitting session.released. Preserve the existing
released guard and serialized execution.
packages/harnesses/src/ai-sdk/harness-host.ts-530-540 (1)

530-540: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Rollback the host state when continuation setup fails.

If doContinueTurn() rejects, the host remains running with no control object, blocking subsequent lifecycle operations. Clear the turn fields and restore suspended or transition to failed in a catch block.

🤖 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 `@packages/harnesses/src/ai-sdk/harness-host.ts` around lines 530 - 540, Update
the continuation setup around doContinueTurn in the session resume flow to catch
rejected promises and roll back the host state instead of leaving it running
without a control object. In the catch path, clear the active turn fields and
restore suspended state or transition to failed according to the existing
lifecycle conventions, while preserving the successful control assignment and
event flow.
packages/harnesses/src/ai-sdk/sidecar.ts-176-177 (1)

176-177: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Guarantee host cleanup with try/finally.

Any readline or output-write failure exits before Lines 371–372. Because sandbox children are detached process groups, this can leave adapter processes and port reservations alive.

Also applies to: 371-372

🤖 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 `@packages/harnesses/src/ai-sdk/sidecar.ts` around lines 176 - 177, Wrap the
line-processing and output-writing flow around createInterface and the `for
await (const line of lines)` loop in a try/finally block. Ensure the existing
host cleanup at lines 371–372 runs from the finally block even when readline
iteration or output writes throw, while preserving the current processing
behavior on success.
packages/harnesses/src/ai-sdk/harness-host.ts-273-279 (1)

273-279: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Settle every promise-capable callback invocation. Both hooks allow asynchronous callbacks but discard their results, allowing rejected writes or listeners to become unhandled rejections.

  • packages/harnesses/src/ai-sdk/harness-host.ts#L273-L279: await, enqueue, or explicitly catch options.onDiagnostic.
  • packages/harnesses/src/ai-sdk/relay-session.ts#L311-L323: dispatch the initial capabilities event through the settled #emit path.
🤖 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 `@packages/harnesses/src/ai-sdk/harness-host.ts` around lines 273 - 279, Settle
the asynchronous diagnostic callback in the observability report wrapper by
awaiting, enqueueing, or explicitly catching options.onDiagnostic rather than
discarding its promise; preserve the existing report and `#emit` behavior. In
packages/harnesses/src/ai-sdk/relay-session.ts lines 311-323, route the initial
capabilities event through the settled `#emit` path so any asynchronous listener
or write rejection is handled.
packages/harnesses/src/ai-sdk/sidecar.ts-389-394 (1)

389-394: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Enforce the Node 22 baseline inside the shared sidecar entrypoint.

Both the CLI __ai-sdk-sidecar branch and sidecar-main.ts invoke this function without passing through runCli() and its version assertion. Add the check here so every sidecar launch fails clearly on unsupported runtimes.

🤖 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 `@packages/harnesses/src/ai-sdk/sidecar.ts` around lines 389 - 394, Update
runAiSdkSidecarMain to enforce the Node 22 runtime baseline before loading
configuration or starting the sidecar. Reuse the existing version assertion used
by runCli(), ensuring unsupported runtimes fail with the same clear error
regardless of how the shared entrypoint is invoked.
crates/broker/src/protocol.rs-586-598 (1)

586-598: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Preserve instructions in the typed native-command protocol.

The HTTP endpoint accepts and forwards instructions, but this enum omits it. Any typed round-trip will silently discard that field, breaking compact-command instructions.

Proposed fix
     NativeHarnessCommand {
         protocol_version: u32,
         kind: String,
         idempotency_key: String,
         #[serde(default, skip_serializing_if = "Option::is_none")]
         text: Option<String>,
         #[serde(default, skip_serializing_if = "Option::is_none")]
         mode: Option<String>,
         #[serde(default, skip_serializing_if = "Option::is_none")]
         approval_id: Option<String>,
+        #[serde(default, skip_serializing_if = "Option::is_none")]
+        instructions: Option<String>,
     },
         let command = BrokerToWorker::NativeHarnessCommand {
             protocol_version: 1,
-            kind: "submit_user_message".into(),
+            kind: "compact".into(),
             idempotency_key: "input-1".into(),
-            text: Some("continue".into()),
-            mode: Some("active".into()),
+            text: None,
+            mode: None,
             approval_id: None,
+            instructions: Some("Preserve open tasks".into()),
         };

Also applies to: 747-761

🤖 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/broker/src/protocol.rs` around lines 586 - 598, Add an optional
serde-compatible instructions field to the NativeHarnessCommand variant,
matching the HTTP payload’s field name and the existing optional
text/mode/approval_id fields. Ensure typed serialization and deserialization
preserve instructions during round-trips.
packages/harness-driver/src/protocol.ts-145-153 (1)

145-153: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Align the command frame across TypeScript, Rust, and the sidecar.

The Rust round-trip frame has neither instructions nor request_id, while this contract advertises compact guidance and the sidecar requires request_id. Guidance may be dropped and uncorrelated commands rejected. Update all protocol definitions and add a cross-language compact-command test.

Also applies to: 634-638

🤖 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 `@packages/harness-driver/src/protocol.ts` around lines 145 - 153, Align
NativeHarnessCommand and its Rust and sidecar equivalents by adding the missing
request_id and optional compact-only instructions fields with matching
serialization names and optionality. Update command handling so both fields
survive round trips and request_id is accepted where required, then add a
cross-language test covering a compact command with instructions and correlation
via request_id.
packages/harness-driver/src/broker-driver.ts-190-197 (1)

190-197: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Recover the delivery chain after listener failures.

A rejected listener leaves delivery rejected, so every later event skips the listener while the stream continues consuming events.

Proposed fix
-      delivery = delivery.then(() => listener(event));
+      delivery = delivery
+        .then(() => listener(event))
+        .catch(async (error) => onError?.(error));
🤖 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 `@packages/harness-driver/src/broker-driver.ts` around lines 190 - 197, Update
the publish function’s delivery chaining so a listener rejection does not leave
delivery permanently rejected. Ensure each subsequent event still invokes
listener(event), while preserving event ordering and the existing highWater and
terminalSeen behavior.
packages/harness-driver/src/broker-driver.ts-59-59 (1)

59-59: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Do not classify every headless runtime as native.

Non-native headless workers also use this transport, but their history endpoint returns unsupported_runtime. Pass the actual harness runtime discriminator instead.

Proposed fix
-    return this.runtimeHandle(client, result, transport === 'headless', buffered);
+    return this.runtimeHandle(
+      client,
+      result,
+      input.harnessConfig?.runtime === 'native',
+      buffered
+    );
🤖 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 `@packages/harness-driver/src/broker-driver.ts` at line 59, Update the call to
runtimeHandle in the broker driver so its native-runtime discriminator reflects
the actual harness runtime rather than treating every transport === 'headless'
case as native. Preserve the existing client, result, and buffered arguments,
and use the available runtime discriminator that distinguishes native from
non-native headless workers.
packages/harness-driver/src/broker-driver.ts-198-199 (1)

198-199: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Fail and clean up when history seeding is incomplete.

A rejected history request leaves both subscriptions active, while history.gap === true silently produces an incomplete event timeline. Dispose the iterator/runtime listener and surface either condition before replaying events.

Proposed fix
-    const history = await client.getAgentEventHistory(name, 0);
+    let history: AgentEventHistoryResponse;
+    try {
+      history = await client.getAgentEventHistory(name, 0);
+      if (history.gap) {
+        throw new Error(`agent event history for ${JSON.stringify(name)} contains a replay gap`);
+      }
+    } catch (error) {
+      stopped = true;
+      stopOnRuntimeExit();
+      await iterator.return?.();
+      throw error;
+    }
     for (const event of history.events) publish(event);
🤖 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 `@packages/harness-driver/src/broker-driver.ts` around lines 198 - 199, Update
the history seeding flow around client.getAgentEventHistory and the event replay
loop to detect a rejected history request or history.gap === true before
publishing events. On either condition, dispose both the iterator and runtime
listener, then surface the failure instead of replaying an incomplete timeline;
preserve normal replay when history is complete.
🟡 Minor comments (2)
tests/integration/ai-sdk-harnesses/pty-reference-profile.test.ts-41-66 (1)

41-66: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert every reference event family, not a partial subset.

toMatchObject and the omitted model, warnings, and diagnostics entries allow this “every reference gap” test to pass when those families are missing from the report.

Proposed fix
-    expect(comparison.agentEventFamilies).toMatchObject({
+    expect(comparison.agentEventFamilies).toEqual({
       lifecycle: { reference: ['exact'], candidate: ['exact'] },
       turns: { reference: ['exact'], candidate: ['inferred'] },
       text: { reference: ['exact'], candidate: ['unavailable'] },
       reasoning: { reference: ['exact'], candidate: ['unavailable'] },
       tools: { reference: ['exact'], candidate: ['unavailable'] },
       tool_approvals: { reference: ['exact'], candidate: ['unavailable'] },
       files: { reference: ['exact'], candidate: ['unavailable'] },
       compaction: { reference: ['exact'], candidate: ['unavailable'] },
+      model: { reference: ['exact'], candidate: ['unavailable'] },
+      warnings: { reference: ['exact'], candidate: ['unavailable'] },
       usage: { reference: ['exact'], candidate: ['unavailable'] },
+      diagnostics: { reference: ['exact'], candidate: ['unavailable'] },
       errors: { reference: ['exact'], candidate: ['exact'] },
     });
🤖 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 `@tests/integration/ai-sdk-harnesses/pty-reference-profile.test.ts` around
lines 41 - 66, Update the comparison assertions in the test so they require the
complete activities and agentEventFamilies reports rather than permitting
partial matches. Include the omitted model, warnings, and diagnostics reference
entries, and use strict equality assertions so missing or extra event families
cause the test to fail.
packages/cli/src/cli/lib/client-factory.test.ts-157-163 (1)

157-163: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use a real Bun executable path here. process.argv[0] is a path, not the literal bun, so this fixture should mirror the compiled-binary argv shape (/path/to/bun) to exercise the sidecar detection path instead of masking it.

🤖 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 `@packages/cli/src/cli/lib/client-factory.test.ts` around lines 157 - 163,
Update the nativeSidecarLaunch test fixture to use a realistic Bun executable
path (such as an absolute path) as process.argv[0] instead of the literal "bun",
while preserving the compiled Bun argv shape and existing expected launch
result.
🤖 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.

Outside diff comments:
In @.github/workflows/verify-publish.yml:
- Around line 420-423: Update the verify-docker strategy matrix to remove Node
20, leaving only Node 22 so the workflow execution matches the Docker test
summary and migration plan.

---

Major comments:
In `@crates/broker/src/protocol.rs`:
- Around line 586-598: Add an optional serde-compatible instructions field to
the NativeHarnessCommand variant, matching the HTTP payload’s field name and the
existing optional text/mode/approval_id fields. Ensure typed serialization and
deserialization preserve instructions during round-trips.

In `@packages/harness-driver/src/broker-driver.ts`:
- Around line 190-197: Update the publish function’s delivery chaining so a
listener rejection does not leave delivery permanently rejected. Ensure each
subsequent event still invokes listener(event), while preserving event ordering
and the existing highWater and terminalSeen behavior.
- Line 59: Update the call to runtimeHandle in the broker driver so its
native-runtime discriminator reflects the actual harness runtime rather than
treating every transport === 'headless' case as native. Preserve the existing
client, result, and buffered arguments, and use the available runtime
discriminator that distinguishes native from non-native headless workers.
- Around line 198-199: Update the history seeding flow around
client.getAgentEventHistory and the event replay loop to detect a rejected
history request or history.gap === true before publishing events. On either
condition, dispose both the iterator and runtime listener, then surface the
failure instead of replaying an incomplete timeline; preserve normal replay when
history is complete.

In `@packages/harness-driver/src/protocol.ts`:
- Around line 145-153: Align NativeHarnessCommand and its Rust and sidecar
equivalents by adding the missing request_id and optional compact-only
instructions fields with matching serialization names and optionality. Update
command handling so both fields survive round trips and request_id is accepted
where required, then add a cross-language test covering a compact command with
instructions and correlation via request_id.

In `@packages/harnesses/src/ai-sdk/harness-host.ts`:
- Around line 301-312: Update `#emit` to serialize normalized event delivery
through a shared promise chain or equivalent dispatch queue, ensuring each
event’s listener notifications complete before the next event is published.
Preserve the existing listener snapshot, Promise.allSettled behavior,
sequencing, and turn metadata, and apply the same queued dispatch behavior to
the related `#emit` call sites.
- Around line 530-540: Update the continuation setup around doContinueTurn in
the session resume flow to catch rejected promises and roll back the host state
instead of leaving it running without a control object. In the catch path, clear
the active turn fields and restore suspended state or transition to failed
according to the existing lifecycle conventions, while preserving the successful
control assignment and event flow.
- Around line 273-279: Settle the asynchronous diagnostic callback in the
observability report wrapper by awaiting, enqueueing, or explicitly catching
options.onDiagnostic rather than discarding its promise; preserve the existing
report and `#emit` behavior. In packages/harnesses/src/ai-sdk/relay-session.ts
lines 311-323, route the initial capabilities event through the settled `#emit`
path so any asynchronous listener or write rejection is handled.

In `@packages/harnesses/src/ai-sdk/local-host-sandbox.ts`:
- Around line 345-350: Update setPorts and `#releasePorts` to release ports
removed from the current allocation and delete every released port from
`#usedPorts`, while preserving validation that all requested ports are
provider-allocated. Ensure released ports become eligible for reuse during later
allocations.

In `@packages/harnesses/src/ai-sdk/relay-session.ts`:
- Around line 58-94: Add 'session.released' to the AI_SDK_EVENT_TYPES array used
by capabilities.events.emits, ensuring the advertised event contract matches the
event emitted by release().
- Around line 289-297: Remove next-tool-call from the advertised delivery modes
in the RelaySession capabilities configuration. Until its boundary semantics are
implemented in the delivery handling path, keep only the currently supported
modes and preserve the existing capability structure.
- Around line 429-435: Update release in the session class to finalize every
queued deferred delivery before clearing `#queue`: replace each receipt with a
terminal failure and emit the corresponding delivery.failed event, then clear
the queue and continue destroying the host and emitting session.released.
Preserve the existing released guard and serialized execution.

In `@packages/harnesses/src/ai-sdk/sidecar.ts`:
- Around line 176-177: Wrap the line-processing and output-writing flow around
createInterface and the `for await (const line of lines)` loop in a try/finally
block. Ensure the existing host cleanup at lines 371–372 runs from the finally
block even when readline iteration or output writes throw, while preserving the
current processing behavior on success.
- Around line 389-394: Update runAiSdkSidecarMain to enforce the Node 22 runtime
baseline before loading configuration or starting the sidecar. Reuse the
existing version assertion used by runCli(), ensuring unsupported runtimes fail
with the same clear error regardless of how the shared entrypoint is invoked.

In `@packages/harnesses/src/define.ts`:
- Line 236: Update the `new` entry point to reject an explicit unsupported
`backend: 'ai-sdk'` request, matching the validation behavior of `create()`,
while preserving normal PTY descriptor construction for supported backends.

In `@packages/sdk/src/agent-relay.ts`:
- Line 121: Update publishSessionEvent and its implementations/call sites to
keep the local agentId separate from the Relaycast agent name used by
agents.events.emit. Accept or resolve both identity values, use agentId for
listener dispatch and persistence, and use the Relaycast name for emission;
update the affected tests so they pass distinct identifiers.
- Around line 497-500: Update publishSessionEvent to use best-effort error
handling: wrap the hub and optional messaging session-event emissions in a
try/catch, and route any failure through options?.onError without rejecting to
callers. Preserve the existing emission order and successful behavior.

In `@packages/sdk/src/listeners.ts`:
- Around line 531-541: Update RelaySessionEvent and
RelayCanonicalSessionEventMap to derive event payloads from the canonical
AgentEvent union rather than AgentSessionEvent, so canonical selectors such as
tool.called, file.changed, and error expose only canonical fields. Normalize or
reject legacy session events before dispatch so handlers cannot receive
AgentSessionEvent variants through the canonical map.

In `@packages/sdk/src/session/activity-reducer.ts`:
- Around line 152-157: Update the reducer logic around observed and
activity.changed events so ignored activity transitions still advance the
sequence watermark before returning the unchanged activity state. Preserve
deduplication for sequences at or below the updated watermark, and add a
regression test covering an ignored higher-sequence transition followed by a
lower-sequence lifecycle event.

In `@tests/integration/ai-sdk-harnesses/adapter-contract.test.ts`:
- Around line 23-155: Replace the FakeHarnessController-based fixtures with
adapter-backed deterministic fixtures so registered implementations are actually
exercised. In
tests/integration/ai-sdk-harnesses/adapter-contract.test.ts:23-155, update the
adapter-contract setup around aiSdkAdapterRegistry and host; in
tests/integration/ai-sdk-harnesses/soak-contract.test.ts:44-180, collect soak
metrics from those same adapter-backed fixtures, or explicitly rename the suite
to describe a shared-host fake soak if it remains fake.

In `@tests/integration/ai-sdk-harnesses/real-adapters.test.ts`:
- Line 10: Restrict AUTH_OR_CLI_ERROR and the related skip handling in the
adapter test to explicit credential/authentication failures or
missing-executable errors, removing broad matches such as “not found,”
“unavailable,” and “pnpm.” Ensure ambiguous adapter, model-resolution,
packaging, and regression errors are rethrown instead of converted into skips.

---

Minor comments:
In `@packages/cli/src/cli/lib/client-factory.test.ts`:
- Around line 157-163: Update the nativeSidecarLaunch test fixture to use a
realistic Bun executable path (such as an absolute path) as process.argv[0]
instead of the literal "bun", while preserving the compiled Bun argv shape and
existing expected launch result.

In `@tests/integration/ai-sdk-harnesses/pty-reference-profile.test.ts`:
- Around line 41-66: Update the comparison assertions in the test so they
require the complete activities and agentEventFamilies reports rather than
permitting partial matches. Include the omitted model, warnings, and diagnostics
reference entries, and use strict equality assertions so missing or extra event
families cause the test to fail.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 56c5b3e9-c62c-4ae8-8102-62412e18991c

📥 Commits

Reviewing files that changed from the base of the PR and between 06ba42d and 7448b24.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (139)
  • .agentworkforce/trajectories/completed/2026-07/traj_20khcr8z0v13/summary.md
  • .agentworkforce/trajectories/completed/2026-07/traj_20khcr8z0v13/trajectory.json
  • .agentworkforce/trajectories/completed/2026-07/traj_681sx2jr2m46/summary.md
  • .agentworkforce/trajectories/completed/2026-07/traj_681sx2jr2m46/trajectory.json
  • .agentworkforce/trajectories/completed/2026-07/traj_8rr4e8wisgh3/summary.md
  • .agentworkforce/trajectories/completed/2026-07/traj_8rr4e8wisgh3/trajectory.json
  • .agentworkforce/trajectories/completed/2026-07/traj_ajse65eu6brc.trace.json
  • .agentworkforce/trajectories/completed/2026-07/traj_ajse65eu6brc/summary.md
  • .agentworkforce/trajectories/completed/2026-07/traj_ajse65eu6brc/trajectory.json
  • .agentworkforce/trajectories/completed/2026-07/traj_b8i9trq4ou7i/summary.md
  • .agentworkforce/trajectories/completed/2026-07/traj_b8i9trq4ou7i/trajectory.json
  • .agentworkforce/trajectories/completed/2026-07/traj_bvv35fxv38pq/summary.md
  • .agentworkforce/trajectories/completed/2026-07/traj_bvv35fxv38pq/trajectory.json
  • .agentworkforce/trajectories/completed/2026-07/traj_cyut1lxn0261/summary.md
  • .agentworkforce/trajectories/completed/2026-07/traj_cyut1lxn0261/trajectory.json
  • .agentworkforce/trajectories/completed/2026-07/traj_id1ypo49qd36/summary.md
  • .agentworkforce/trajectories/completed/2026-07/traj_id1ypo49qd36/trajectory.json
  • .agentworkforce/trajectories/completed/2026-07/traj_mpf6nswkfvex/summary.md
  • .agentworkforce/trajectories/completed/2026-07/traj_mpf6nswkfvex/trajectory.json
  • .github/workflows/codegen-models.yml
  • .github/workflows/e2e-tests.yml
  • .github/workflows/fleet-e2e.yml
  • .github/workflows/node-compat.yml
  • .github/workflows/prettier-fmt-fix.yml
  • .github/workflows/prod-smoke.yml
  • .github/workflows/stress-tests.yml
  • .github/workflows/test-install.yml
  • .github/workflows/test.yml
  • .github/workflows/update-cli-versions.yml
  • .github/workflows/verify-publish.yml
  • .workflow-artifacts/plan-001/claude-review-1-resolution.md
  • .workflow-artifacts/plan-001/claude-review-1.md
  • .workflow-artifacts/plan-001/codex-review-1-resolution.md
  • .workflow-artifacts/plan-001/codex-review-1.md
  • .workflow-artifacts/plan-001/final-signoff-2.md
  • .workflow-artifacts/plan-001/final-signoff-3.md
  • .workflow-artifacts/plan-001/final-signoff-resolution.md
  • .workflow-artifacts/plan-001/final-signoff.md
  • .workflow-artifacts/plan-001/self-reflection.md
  • CHANGELOG.md
  • README.md
  • crates/broker/src/listen_api.rs
  • crates/broker/src/protocol.rs
  • crates/broker/src/relaycast/ws.rs
  • crates/broker/src/replay_buffer.rs
  • crates/broker/src/runtime/api.rs
  • crates/broker/src/runtime/event_loop.rs
  • crates/broker/src/runtime/fleet.rs
  • crates/broker/src/runtime/init.rs
  • crates/broker/src/runtime/maintenance.rs
  • crates/broker/src/runtime/mod.rs
  • crates/broker/src/runtime/relaycast_events.rs
  • crates/broker/src/runtime/spawn_spec.rs
  • crates/broker/src/runtime/tests.rs
  • crates/broker/src/runtime/worker_events.rs
  • crates/broker/src/worker.rs
  • package.json
  • packages/brand/package.json
  • packages/broker-darwin-arm64/package.json
  • packages/broker-darwin-x64/package.json
  • packages/broker-linux-arm64/package.json
  • packages/broker-linux-x64/package.json
  • packages/broker-win32-x64/package.json
  • packages/cli/README.md
  • packages/cli/package.json
  • packages/cli/src/cli/bootstrap.ts
  • packages/cli/src/cli/commands/local-agent.test.ts
  • packages/cli/src/cli/commands/local-agent.ts
  • packages/cli/src/cli/entrypoint.test.ts
  • packages/cli/src/cli/index.ts
  • packages/cli/src/cli/lib/attach-native.test.ts
  • packages/cli/src/cli/lib/attach-native.ts
  • packages/cli/src/cli/lib/client-factory.test.ts
  • packages/cli/src/cli/lib/client-factory.ts
  • packages/cli/src/cli/lib/fleet-sidecar.test.ts
  • packages/cli/src/cli/lib/node-version.test.ts
  • packages/cli/src/cli/lib/node-version.ts
  • packages/cloud/package.json
  • packages/config/package.json
  • packages/evals/package.json
  • packages/fleet/package.json
  • packages/harness-driver/package.json
  • packages/harness-driver/src/broker-driver.ts
  • packages/harness-driver/src/client.ts
  • packages/harness-driver/src/driver-types.ts
  • packages/harness-driver/src/harness.ts
  • packages/harness-driver/src/native-client.test.ts
  • packages/harness-driver/src/protocol.ts
  • packages/harness-driver/src/spawn-request.ts
  • packages/harness-driver/src/types.ts
  • packages/harnesses/README.md
  • packages/harnesses/package.json
  • packages/harnesses/src/ai-sdk/adapter-registry.test.ts
  • packages/harnesses/src/ai-sdk/adapter-registry.ts
  • packages/harnesses/src/ai-sdk/harness-host.test.ts
  • packages/harnesses/src/ai-sdk/harness-host.ts
  • packages/harnesses/src/ai-sdk/index.ts
  • packages/harnesses/src/ai-sdk/local-host-sandbox.test.ts
  • packages/harnesses/src/ai-sdk/local-host-sandbox.ts
  • packages/harnesses/src/ai-sdk/relay-session.test.ts
  • packages/harnesses/src/ai-sdk/relay-session.ts
  • packages/harnesses/src/ai-sdk/sidecar-main.ts
  • packages/harnesses/src/ai-sdk/sidecar.test.ts
  • packages/harnesses/src/ai-sdk/sidecar.ts
  • packages/harnesses/src/define-spawn.test.ts
  • packages/harnesses/src/define.ts
  • packages/harnesses/src/index.ts
  • packages/harnesses/src/observability.test.ts
  • packages/harnesses/src/observability.ts
  • packages/integration-prompts/package.json
  • packages/policy/package.json
  • packages/sdk/package.json
  • packages/sdk/src/__tests__/activity-reducer.test.ts
  • packages/sdk/src/__tests__/listeners.test-d.ts
  • packages/sdk/src/__tests__/listeners.test.ts
  • packages/sdk/src/__tests__/messaging.test.ts
  • packages/sdk/src/agent-relay.ts
  • packages/sdk/src/listeners.ts
  • packages/sdk/src/messaging/relaycast-client.ts
  • packages/sdk/src/messaging/relaycast.ts
  • packages/sdk/src/messaging/types.ts
  • packages/sdk/src/session/activity-reducer.ts
  • packages/sdk/src/session/index.ts
  • packages/sdk/src/session/types.ts
  • packages/utils/package.json
  • plans/001-adopt-ai-sdk-harnesses.md
  • plans/README.md
  • tests/e2e/fleet/harness.ts
  • tests/integration/ai-sdk-harnesses/adapter-contract.test.ts
  • tests/integration/ai-sdk-harnesses/fakes.ts
  • tests/integration/ai-sdk-harnesses/native-attach-order.test.ts
  • tests/integration/ai-sdk-harnesses/observability-contract.test.ts
  • tests/integration/ai-sdk-harnesses/profile-report.ts
  • tests/integration/ai-sdk-harnesses/pty-reference-profile.test.ts
  • tests/integration/ai-sdk-harnesses/real-adapters.test.ts
  • tests/integration/ai-sdk-harnesses/soak-contract.test.ts
  • tests/integration/broker/fixtures/native-sidecar.ts
  • tests/integration/broker/native-harness.test.ts
  • vitest.config.ts

@willwashburn willwashburn changed the title Adopt AI SDK harness observability benchmark Adopt AI SDK harness Jul 17, 2026
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