feat(harness-driver): add lifecycle-aware SpawnedAgentHandle

Merged
WI
4mo ago
+228-9

User description

What

HarnessDriverClient.spawnPty() / spawnCli() / spawnHeadless() (and spawnClaude/spawnOpencode) now return a SpawnedAgentHandle instead of a bare SpawnAgentResult.

The handle is a structural superset of SpawnAgentResult (it still carries name / runtime / sessionId / pid), so existing callers are unaffected. On top of that it adds the promise-based lifecycle operations consumers previously had to reconstruct by hand from the raw broker event stream:

  • waitForExit(timeoutMs?) → { reason: 'exited' | 'timeout', code?, signal? }
  • waitForIdle(timeoutMs?) → { reason: 'idle' | 'exited' | 'timeout', idleSecs?, exit? }
  • exit / exitCode / exitSignal — synchronous view of a prior exit
  • release(reason?)

Why

Downstream consumers (e.g. the relayflows workflow runner being migrated off the v7 SDK) need an await agent.waitForExit() ergonomic with the process exit code. The v7 SDK Agent provided this; v8's spawnPty() returned a method-less SpawnAgentResult, forcing each consumer to re-implement the event→promise bridge — including the fiddly bits (listener-leak cleanup, exit-code capture from the agent_exited BrokerEvent vs the method-less agentExited payload, and the "already exited before you awaited" replay case).

The driver is the right home for this: it owns the ordered broker event stream and the event history (getLastEvent/queryEvents), so it can implement these replay-correctly — awaiting after a prior exit resolves immediately from history instead of hanging.

Notes

  • Exit code/signal are sourced from the agent_exited BrokerEvent (the named agentExited event payload is a method-less DriverAgent without them).
  • waitForIdle is edge-triggered (resolves on the next idle signal), matching how runners poll-then-nudge.

Verification

  • harness-driver typechecks (tsc --noEmit) and builds.
  • harness-driver test suite passes (26 tests).
  • Direct dependents @agent-relay/harnesses and @agent-relay/sdk typecheck clean (0 errors) against the widened return type.

🤖 Generated with Claude Code


CodeAnt-AI Description

Add lifecycle-aware agent handles and publish harnesses safely

What Changed

  • Spawning an agent now returns a handle that can wait for exit, wait for the next idle signal, read the last exit code or signal, and release the agent.
  • Exit and idle waits now resolve from prior event history too, so they work even if the agent already exited before the wait started.
  • @agent-relay/harnesses is now published to npm, so external users can install the prebuilt PTY harnesses and harness-authoring helpers.
  • Release creation now waits for harness publishing to succeed, so a failed harness publish blocks the release instead of being missed.

Impact

✅ Easier agent shutdown handling
✅ Fewer hangs when checking exited agents
✅ Installable harness package on npm

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.