@agent-relay/sdk 7.1.0 → 8.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +177 -143
- package/bin/agent-relay-broker-darwin-arm64 +0 -0
- package/bin/agent-relay-broker-darwin-x64 +0 -0
- package/bin/agent-relay-broker-linux-arm64 +0 -0
- package/bin/agent-relay-broker-linux-x64 +0 -0
- package/bin/agent-relay-broker-win32-x64.exe +0 -0
- package/dist/actions/errors.d.ts +18 -0
- package/dist/actions/errors.d.ts.map +1 -0
- package/dist/actions/errors.js +39 -0
- package/dist/actions/errors.js.map +1 -0
- package/dist/actions/index.d.ts +5 -0
- package/dist/actions/index.d.ts.map +1 -0
- package/dist/actions/index.js +5 -0
- package/dist/actions/index.js.map +1 -0
- package/dist/actions/json-schema-lite.d.ts +13 -0
- package/dist/actions/json-schema-lite.d.ts.map +1 -0
- package/dist/actions/json-schema-lite.js +322 -0
- package/dist/actions/json-schema-lite.js.map +1 -0
- package/dist/actions/registry.d.ts +20 -0
- package/dist/actions/registry.d.ts.map +1 -0
- package/dist/actions/registry.js +267 -0
- package/dist/actions/registry.js.map +1 -0
- package/dist/actions/types.d.ts +177 -0
- package/dist/actions/types.d.ts.map +1 -0
- package/dist/{provisioner → actions}/types.js.map +1 -1
- package/dist/agent-relay.d.ts +86 -0
- package/dist/agent-relay.d.ts.map +1 -0
- package/dist/agent-relay.js +197 -0
- package/dist/agent-relay.js.map +1 -0
- package/dist/capabilities.d.ts +6 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +9 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/delivery/index.d.ts +4 -0
- package/dist/delivery/index.d.ts.map +1 -0
- package/dist/delivery/index.js +4 -0
- package/dist/delivery/index.js.map +1 -0
- package/dist/delivery/runner.d.ts +26 -0
- package/dist/delivery/runner.d.ts.map +1 -0
- package/dist/delivery/runner.js +177 -0
- package/dist/delivery/runner.js.map +1 -0
- package/dist/delivery/types.d.ts +45 -0
- package/dist/delivery/types.d.ts.map +1 -0
- package/dist/delivery/types.js +2 -0
- package/dist/delivery/types.js.map +1 -0
- package/dist/facade.d.ts +151 -0
- package/dist/facade.d.ts.map +1 -0
- package/dist/facade.js +280 -0
- package/dist/facade.js.map +1 -0
- package/dist/index.d.ts +9 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -23
- package/dist/index.js.map +1 -1
- package/dist/listeners.d.ts +162 -0
- package/dist/listeners.d.ts.map +1 -0
- package/dist/listeners.js +297 -0
- package/dist/listeners.js.map +1 -0
- package/dist/messaging/index.d.ts +4 -0
- package/dist/messaging/index.d.ts.map +1 -0
- package/dist/messaging/index.js +4 -0
- package/dist/messaging/index.js.map +1 -0
- package/dist/messaging/normalize.d.ts +29 -0
- package/dist/messaging/normalize.d.ts.map +1 -0
- package/dist/messaging/normalize.js +602 -0
- package/dist/messaging/normalize.js.map +1 -0
- package/dist/messaging/relaycast.d.ts +270 -0
- package/dist/messaging/relaycast.d.ts.map +1 -0
- package/dist/messaging/relaycast.js +559 -0
- package/dist/messaging/relaycast.js.map +1 -0
- package/dist/messaging/types.d.ts +672 -0
- package/dist/messaging/types.d.ts.map +1 -0
- package/dist/messaging/types.js +2 -0
- package/dist/messaging/types.js.map +1 -0
- package/dist/relaycast-errors.d.ts +39 -0
- package/dist/relaycast-errors.d.ts.map +1 -0
- package/dist/relaycast-errors.js +111 -0
- package/dist/relaycast-errors.js.map +1 -0
- package/dist/session/index.d.ts +58 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +54 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/types.d.ts +258 -0
- package/dist/session/types.d.ts.map +1 -0
- package/dist/session/types.js +7 -0
- package/dist/session/types.js.map +1 -0
- package/package.json +31 -199
- package/dist/broker-logs.d.ts +0 -80
- package/dist/broker-logs.d.ts.map +0 -1
- package/dist/broker-logs.js +0 -189
- package/dist/broker-logs.js.map +0 -1
- package/dist/broker-path.d.ts +0 -34
- package/dist/broker-path.d.ts.map +0 -1
- package/dist/broker-path.js +0 -267
- package/dist/broker-path.js.map +0 -1
- package/dist/browser.d.ts +0 -16
- package/dist/browser.d.ts.map +0 -1
- package/dist/browser.js +0 -19
- package/dist/browser.js.map +0 -1
- package/dist/cli-registry.d.ts +0 -44
- package/dist/cli-registry.d.ts.map +0 -1
- package/dist/cli-registry.js +0 -104
- package/dist/cli-registry.js.map +0 -1
- package/dist/cli-resolver.d.ts +0 -30
- package/dist/cli-resolver.d.ts.map +0 -1
- package/dist/cli-resolver.js +0 -132
- package/dist/cli-resolver.js.map +0 -1
- package/dist/client.d.ts +0 -278
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js +0 -838
- package/dist/client.js.map +0 -1
- package/dist/communicate/a2a-bridge.d.ts +0 -25
- package/dist/communicate/a2a-bridge.d.ts.map +0 -1
- package/dist/communicate/a2a-bridge.js +0 -89
- package/dist/communicate/a2a-bridge.js.map +0 -1
- package/dist/communicate/a2a-server.d.ts +0 -31
- package/dist/communicate/a2a-server.d.ts.map +0 -1
- package/dist/communicate/a2a-server.js +0 -220
- package/dist/communicate/a2a-server.js.map +0 -1
- package/dist/communicate/a2a-transport.d.ts +0 -48
- package/dist/communicate/a2a-transport.d.ts.map +0 -1
- package/dist/communicate/a2a-transport.js +0 -305
- package/dist/communicate/a2a-transport.js.map +0 -1
- package/dist/communicate/a2a-types.d.ts +0 -107
- package/dist/communicate/a2a-types.d.ts.map +0 -1
- package/dist/communicate/a2a-types.js +0 -209
- package/dist/communicate/a2a-types.js.map +0 -1
- package/dist/communicate/adapters/ai-sdk.d.ts +0 -63
- package/dist/communicate/adapters/ai-sdk.d.ts.map +0 -1
- package/dist/communicate/adapters/ai-sdk.js +0 -114
- package/dist/communicate/adapters/ai-sdk.js.map +0 -1
- package/dist/communicate/adapters/claude-sdk.d.ts +0 -28
- package/dist/communicate/adapters/claude-sdk.d.ts.map +0 -1
- package/dist/communicate/adapters/claude-sdk.js +0 -47
- package/dist/communicate/adapters/claude-sdk.js.map +0 -1
- package/dist/communicate/adapters/crewai.d.ts +0 -42
- package/dist/communicate/adapters/crewai.d.ts.map +0 -1
- package/dist/communicate/adapters/crewai.js +0 -95
- package/dist/communicate/adapters/crewai.js.map +0 -1
- package/dist/communicate/adapters/google-adk.d.ts +0 -53
- package/dist/communicate/adapters/google-adk.d.ts.map +0 -1
- package/dist/communicate/adapters/google-adk.js +0 -77
- package/dist/communicate/adapters/google-adk.js.map +0 -1
- package/dist/communicate/adapters/index.d.ts +0 -3
- package/dist/communicate/adapters/index.d.ts.map +0 -1
- package/dist/communicate/adapters/index.js +0 -3
- package/dist/communicate/adapters/index.js.map +0 -1
- package/dist/communicate/adapters/langgraph.d.ts +0 -40
- package/dist/communicate/adapters/langgraph.d.ts.map +0 -1
- package/dist/communicate/adapters/langgraph.js +0 -77
- package/dist/communicate/adapters/langgraph.js.map +0 -1
- package/dist/communicate/adapters/openai-agents.d.ts +0 -25
- package/dist/communicate/adapters/openai-agents.d.ts.map +0 -1
- package/dist/communicate/adapters/openai-agents.js +0 -70
- package/dist/communicate/adapters/openai-agents.js.map +0 -1
- package/dist/communicate/adapters/pi.d.ts +0 -44
- package/dist/communicate/adapters/pi.d.ts.map +0 -1
- package/dist/communicate/adapters/pi.js +0 -55
- package/dist/communicate/adapters/pi.js.map +0 -1
- package/dist/communicate/core.d.ts +0 -58
- package/dist/communicate/core.d.ts.map +0 -1
- package/dist/communicate/core.js +0 -127
- package/dist/communicate/core.js.map +0 -1
- package/dist/communicate/index.d.ts +0 -20
- package/dist/communicate/index.d.ts.map +0 -1
- package/dist/communicate/index.js +0 -43
- package/dist/communicate/index.js.map +0 -1
- package/dist/communicate/transport.d.ts +0 -35
- package/dist/communicate/transport.d.ts.map +0 -1
- package/dist/communicate/transport.js +0 -279
- package/dist/communicate/transport.js.map +0 -1
- package/dist/communicate/types.d.ts +0 -58
- package/dist/communicate/types.d.ts.map +0 -1
- package/dist/communicate/types.js +0 -66
- package/dist/communicate/types.js.map +0 -1
- package/dist/consensus-helpers.d.ts +0 -103
- package/dist/consensus-helpers.d.ts.map +0 -1
- package/dist/consensus-helpers.js +0 -147
- package/dist/consensus-helpers.js.map +0 -1
- package/dist/consensus.d.ts +0 -72
- package/dist/consensus.d.ts.map +0 -1
- package/dist/consensus.js +0 -378
- package/dist/consensus.js.map +0 -1
- package/dist/event-bus.d.ts +0 -57
- package/dist/event-bus.d.ts.map +0 -1
- package/dist/event-bus.js +0 -76
- package/dist/event-bus.js.map +0 -1
- package/dist/examples/demo.d.ts +0 -2
- package/dist/examples/demo.d.ts.map +0 -1
- package/dist/examples/demo.js +0 -63
- package/dist/examples/demo.js.map +0 -1
- package/dist/examples/example.d.ts +0 -2
- package/dist/examples/example.d.ts.map +0 -1
- package/dist/examples/example.js +0 -77
- package/dist/examples/example.js.map +0 -1
- package/dist/examples/persona-spawn.d.ts +0 -2
- package/dist/examples/persona-spawn.d.ts.map +0 -1
- package/dist/examples/persona-spawn.js +0 -43
- package/dist/examples/persona-spawn.js.map +0 -1
- package/dist/examples/quickstart.d.ts +0 -2
- package/dist/examples/quickstart.d.ts.map +0 -1
- package/dist/examples/quickstart.js +0 -56
- package/dist/examples/quickstart.js.map +0 -1
- package/dist/examples/ralph-loop.d.ts +0 -2
- package/dist/examples/ralph-loop.d.ts.map +0 -1
- package/dist/examples/ralph-loop.js +0 -281
- package/dist/examples/ralph-loop.js.map +0 -1
- package/dist/examples/workflow-superiority.d.ts +0 -32
- package/dist/examples/workflow-superiority.d.ts.map +0 -1
- package/dist/examples/workflow-superiority.js +0 -1421
- package/dist/examples/workflow-superiority.js.map +0 -1
- package/dist/github.d.ts +0 -24
- package/dist/github.d.ts.map +0 -1
- package/dist/github.js +0 -24
- package/dist/github.js.map +0 -1
- package/dist/http.d.ts +0 -38
- package/dist/http.d.ts.map +0 -1
- package/dist/http.js +0 -60
- package/dist/http.js.map +0 -1
- package/dist/lifecycle-hooks.d.ts +0 -141
- package/dist/lifecycle-hooks.d.ts.map +0 -1
- package/dist/lifecycle-hooks.js +0 -29
- package/dist/lifecycle-hooks.js.map +0 -1
- package/dist/logs.d.ts +0 -106
- package/dist/logs.d.ts.map +0 -1
- package/dist/logs.js +0 -291
- package/dist/logs.js.map +0 -1
- package/dist/models.d.ts +0 -9
- package/dist/models.d.ts.map +0 -1
- package/dist/models.js +0 -17
- package/dist/models.js.map +0 -1
- package/dist/personas.d.ts +0 -160
- package/dist/personas.d.ts.map +0 -1
- package/dist/personas.js +0 -401
- package/dist/personas.js.map +0 -1
- package/dist/protocol.d.ts +0 -521
- package/dist/protocol.d.ts.map +0 -1
- package/dist/protocol.js +0 -2
- package/dist/protocol.js.map +0 -1
- package/dist/provisioner/__tests__/audit.test.d.ts +0 -2
- package/dist/provisioner/__tests__/audit.test.d.ts.map +0 -1
- package/dist/provisioner/__tests__/audit.test.js +0 -45
- package/dist/provisioner/__tests__/audit.test.js.map +0 -1
- package/dist/provisioner/__tests__/compiler.test.d.ts +0 -2
- package/dist/provisioner/__tests__/compiler.test.d.ts.map +0 -1
- package/dist/provisioner/__tests__/compiler.test.js +0 -345
- package/dist/provisioner/__tests__/compiler.test.js.map +0 -1
- package/dist/provisioner/__tests__/presets.test.d.ts +0 -2
- package/dist/provisioner/__tests__/presets.test.d.ts.map +0 -1
- package/dist/provisioner/__tests__/presets.test.js +0 -23
- package/dist/provisioner/__tests__/presets.test.js.map +0 -1
- package/dist/provisioner/__tests__/seeder.test.d.ts +0 -2
- package/dist/provisioner/__tests__/seeder.test.d.ts.map +0 -1
- package/dist/provisioner/__tests__/seeder.test.js +0 -224
- package/dist/provisioner/__tests__/seeder.test.js.map +0 -1
- package/dist/provisioner/__tests__/tar-seeder.test.d.ts +0 -2
- package/dist/provisioner/__tests__/tar-seeder.test.d.ts.map +0 -1
- package/dist/provisioner/__tests__/tar-seeder.test.js +0 -191
- package/dist/provisioner/__tests__/tar-seeder.test.js.map +0 -1
- package/dist/provisioner/__tests__/token-factory.test.d.ts +0 -2
- package/dist/provisioner/__tests__/token-factory.test.d.ts.map +0 -1
- package/dist/provisioner/__tests__/token-factory.test.js +0 -139
- package/dist/provisioner/__tests__/token-factory.test.js.map +0 -1
- package/dist/provisioner/__tests__/token.test.d.ts +0 -2
- package/dist/provisioner/__tests__/token.test.d.ts.map +0 -1
- package/dist/provisioner/__tests__/token.test.js +0 -49
- package/dist/provisioner/__tests__/token.test.js.map +0 -1
- package/dist/provisioner/audit.d.ts +0 -19
- package/dist/provisioner/audit.d.ts.map +0 -1
- package/dist/provisioner/audit.js +0 -74
- package/dist/provisioner/audit.js.map +0 -1
- package/dist/provisioner/compiler.d.ts +0 -23
- package/dist/provisioner/compiler.d.ts.map +0 -1
- package/dist/provisioner/compiler.js +0 -355
- package/dist/provisioner/compiler.js.map +0 -1
- package/dist/provisioner/index.d.ts +0 -10
- package/dist/provisioner/index.d.ts.map +0 -1
- package/dist/provisioner/index.js +0 -269
- package/dist/provisioner/index.js.map +0 -1
- package/dist/provisioner/local-jwks.d.ts +0 -25
- package/dist/provisioner/local-jwks.d.ts.map +0 -1
- package/dist/provisioner/local-jwks.js +0 -70
- package/dist/provisioner/local-jwks.js.map +0 -1
- package/dist/provisioner/mount.d.ts +0 -14
- package/dist/provisioner/mount.d.ts.map +0 -1
- package/dist/provisioner/mount.js +0 -329
- package/dist/provisioner/mount.js.map +0 -1
- package/dist/provisioner/seeder.d.ts +0 -17
- package/dist/provisioner/seeder.d.ts.map +0 -1
- package/dist/provisioner/seeder.js +0 -419
- package/dist/provisioner/seeder.js.map +0 -1
- package/dist/provisioner/token.d.ts +0 -41
- package/dist/provisioner/token.d.ts.map +0 -1
- package/dist/provisioner/token.js +0 -77
- package/dist/provisioner/token.js.map +0 -1
- package/dist/provisioner/types.d.ts +0 -134
- package/dist/provisioner/types.d.ts.map +0 -1
- package/dist/pty.d.ts +0 -8
- package/dist/pty.d.ts.map +0 -1
- package/dist/pty.js +0 -26
- package/dist/pty.js.map +0 -1
- package/dist/relay-adapter.d.ts +0 -124
- package/dist/relay-adapter.d.ts.map +0 -1
- package/dist/relay-adapter.js +0 -242
- package/dist/relay-adapter.js.map +0 -1
- package/dist/relay.d.ts +0 -550
- package/dist/relay.d.ts.map +0 -1
- package/dist/relay.js +0 -1682
- package/dist/relay.js.map +0 -1
- package/dist/shadow.d.ts +0 -101
- package/dist/shadow.d.ts.map +0 -1
- package/dist/shadow.js +0 -174
- package/dist/shadow.js.map +0 -1
- package/dist/slack.d.ts +0 -24
- package/dist/slack.d.ts.map +0 -1
- package/dist/slack.js +0 -24
- package/dist/slack.js.map +0 -1
- package/dist/spawn-from-env.d.ts +0 -78
- package/dist/spawn-from-env.d.ts.map +0 -1
- package/dist/spawn-from-env.js +0 -172
- package/dist/spawn-from-env.js.map +0 -1
- package/dist/transport.d.ts +0 -104
- package/dist/transport.d.ts.map +0 -1
- package/dist/transport.js +0 -520
- package/dist/transport.js.map +0 -1
- package/dist/types.d.ts +0 -101
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -5
- package/dist/types.js.map +0 -1
- package/dist/workers.d.ts +0 -39
- package/dist/workers.d.ts.map +0 -1
- package/dist/workers.js +0 -39
- package/dist/workers.js.map +0 -1
- package/dist/workflows/__tests__/budget-enforcement.test.d.ts +0 -2
- package/dist/workflows/__tests__/budget-enforcement.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/budget-enforcement.test.js +0 -411
- package/dist/workflows/__tests__/budget-enforcement.test.js.map +0 -1
- package/dist/workflows/__tests__/budget-tracker.test.d.ts +0 -2
- package/dist/workflows/__tests__/budget-tracker.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/budget-tracker.test.js +0 -99
- package/dist/workflows/__tests__/budget-tracker.test.js.map +0 -1
- package/dist/workflows/__tests__/builder-paths.test.d.ts +0 -2
- package/dist/workflows/__tests__/builder-paths.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/builder-paths.test.js +0 -63
- package/dist/workflows/__tests__/builder-paths.test.js.map +0 -1
- package/dist/workflows/__tests__/channel-messenger.test.d.ts +0 -2
- package/dist/workflows/__tests__/channel-messenger.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/channel-messenger.test.js +0 -123
- package/dist/workflows/__tests__/channel-messenger.test.js.map +0 -1
- package/dist/workflows/__tests__/cli-session-collector.test.d.ts +0 -2
- package/dist/workflows/__tests__/cli-session-collector.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/cli-session-collector.test.js +0 -54
- package/dist/workflows/__tests__/cli-session-collector.test.js.map +0 -1
- package/dist/workflows/__tests__/collectors/claude.test.d.ts +0 -2
- package/dist/workflows/__tests__/collectors/claude.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/collectors/claude.test.js +0 -85
- package/dist/workflows/__tests__/collectors/claude.test.js.map +0 -1
- package/dist/workflows/__tests__/collectors/codex.test.d.ts +0 -2
- package/dist/workflows/__tests__/collectors/codex.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/collectors/codex.test.js +0 -67
- package/dist/workflows/__tests__/collectors/codex.test.js.map +0 -1
- package/dist/workflows/__tests__/collectors/opencode.test.d.ts +0 -2
- package/dist/workflows/__tests__/collectors/opencode.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/collectors/opencode.test.js +0 -119
- package/dist/workflows/__tests__/collectors/opencode.test.js.map +0 -1
- package/dist/workflows/__tests__/e2big-and-verify.test.d.ts +0 -2
- package/dist/workflows/__tests__/e2big-and-verify.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/e2big-and-verify.test.js +0 -62
- package/dist/workflows/__tests__/e2big-and-verify.test.js.map +0 -1
- package/dist/workflows/__tests__/e2e-permissions.test.d.ts +0 -2
- package/dist/workflows/__tests__/e2e-permissions.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/e2e-permissions.test.js +0 -338
- package/dist/workflows/__tests__/e2e-permissions.test.js.map +0 -1
- package/dist/workflows/__tests__/permission-types.test.d.ts +0 -2
- package/dist/workflows/__tests__/permission-types.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/permission-types.test.js +0 -124
- package/dist/workflows/__tests__/permission-types.test.js.map +0 -1
- package/dist/workflows/__tests__/permissions-integration.test.d.ts +0 -2
- package/dist/workflows/__tests__/permissions-integration.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/permissions-integration.test.js +0 -577
- package/dist/workflows/__tests__/permissions-integration.test.js.map +0 -1
- package/dist/workflows/__tests__/process-backend-executor.test.d.ts +0 -2
- package/dist/workflows/__tests__/process-backend-executor.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/process-backend-executor.test.js +0 -83
- package/dist/workflows/__tests__/process-backend-executor.test.js.map +0 -1
- package/dist/workflows/__tests__/proxy-env.test.d.ts +0 -2
- package/dist/workflows/__tests__/proxy-env.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/proxy-env.test.js +0 -135
- package/dist/workflows/__tests__/proxy-env.test.js.map +0 -1
- package/dist/workflows/__tests__/run-script.test.d.ts +0 -2
- package/dist/workflows/__tests__/run-script.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/run-script.test.js +0 -426
- package/dist/workflows/__tests__/run-script.test.js.map +0 -1
- package/dist/workflows/__tests__/run-summary-table.test.d.ts +0 -2
- package/dist/workflows/__tests__/run-summary-table.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/run-summary-table.test.js +0 -131
- package/dist/workflows/__tests__/run-summary-table.test.js.map +0 -1
- package/dist/workflows/__tests__/scrub-pty-chrome.test.d.ts +0 -2
- package/dist/workflows/__tests__/scrub-pty-chrome.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/scrub-pty-chrome.test.js +0 -113
- package/dist/workflows/__tests__/scrub-pty-chrome.test.js.map +0 -1
- package/dist/workflows/__tests__/sibling-links.test.d.ts +0 -2
- package/dist/workflows/__tests__/sibling-links.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/sibling-links.test.js +0 -166
- package/dist/workflows/__tests__/sibling-links.test.js.map +0 -1
- package/dist/workflows/__tests__/step-cwd.test.d.ts +0 -2
- package/dist/workflows/__tests__/step-cwd.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/step-cwd.test.js +0 -42
- package/dist/workflows/__tests__/step-cwd.test.js.map +0 -1
- package/dist/workflows/__tests__/step-executor.test.d.ts +0 -2
- package/dist/workflows/__tests__/step-executor.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/step-executor.test.js +0 -378
- package/dist/workflows/__tests__/step-executor.test.js.map +0 -1
- package/dist/workflows/__tests__/template-resolver.test.d.ts +0 -2
- package/dist/workflows/__tests__/template-resolver.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/template-resolver.test.js +0 -145
- package/dist/workflows/__tests__/template-resolver.test.js.map +0 -1
- package/dist/workflows/__tests__/verification-custom.test.d.ts +0 -2
- package/dist/workflows/__tests__/verification-custom.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/verification-custom.test.js +0 -230
- package/dist/workflows/__tests__/verification-custom.test.js.map +0 -1
- package/dist/workflows/__tests__/verification-traceback.test.d.ts +0 -2
- package/dist/workflows/__tests__/verification-traceback.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/verification-traceback.test.js +0 -442
- package/dist/workflows/__tests__/verification-traceback.test.js.map +0 -1
- package/dist/workflows/__tests__/verification.test.d.ts +0 -2
- package/dist/workflows/__tests__/verification.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/verification.test.js +0 -272
- package/dist/workflows/__tests__/verification.test.js.map +0 -1
- package/dist/workflows/__tests__/workflow-reliability-contract.test.d.ts +0 -2
- package/dist/workflows/__tests__/workflow-reliability-contract.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/workflow-reliability-contract.test.js +0 -536
- package/dist/workflows/__tests__/workflow-reliability-contract.test.js.map +0 -1
- package/dist/workflows/__tests__/workflow-reliability-e2e.test.d.ts +0 -2
- package/dist/workflows/__tests__/workflow-reliability-e2e.test.d.ts.map +0 -1
- package/dist/workflows/__tests__/workflow-reliability-e2e.test.js +0 -199
- package/dist/workflows/__tests__/workflow-reliability-e2e.test.js.map +0 -1
- package/dist/workflows/api-executor.d.ts +0 -16
- package/dist/workflows/api-executor.d.ts.map +0 -1
- package/dist/workflows/api-executor.js +0 -94
- package/dist/workflows/api-executor.js.map +0 -1
- package/dist/workflows/barrier.d.ts +0 -72
- package/dist/workflows/barrier.d.ts.map +0 -1
- package/dist/workflows/barrier.js +0 -162
- package/dist/workflows/barrier.js.map +0 -1
- package/dist/workflows/budget-tracker.d.ts +0 -75
- package/dist/workflows/budget-tracker.d.ts.map +0 -1
- package/dist/workflows/budget-tracker.js +0 -184
- package/dist/workflows/budget-tracker.js.map +0 -1
- package/dist/workflows/builder.d.ts +0 -229
- package/dist/workflows/builder.d.ts.map +0 -1
- package/dist/workflows/builder.js +0 -430
- package/dist/workflows/builder.js.map +0 -1
- package/dist/workflows/channel-messenger.d.ts +0 -28
- package/dist/workflows/channel-messenger.d.ts.map +0 -1
- package/dist/workflows/channel-messenger.js +0 -275
- package/dist/workflows/channel-messenger.js.map +0 -1
- package/dist/workflows/cli-session-collector.d.ts +0 -39
- package/dist/workflows/cli-session-collector.d.ts.map +0 -1
- package/dist/workflows/cli-session-collector.js +0 -23
- package/dist/workflows/cli-session-collector.js.map +0 -1
- package/dist/workflows/cli.d.ts +0 -11
- package/dist/workflows/cli.d.ts.map +0 -1
- package/dist/workflows/cli.js +0 -395
- package/dist/workflows/cli.js.map +0 -1
- package/dist/workflows/cloud-runner.d.ts +0 -15
- package/dist/workflows/cloud-runner.d.ts.map +0 -1
- package/dist/workflows/cloud-runner.js +0 -41
- package/dist/workflows/cloud-runner.js.map +0 -1
- package/dist/workflows/cloud-schedules.d.ts +0 -3
- package/dist/workflows/cloud-schedules.d.ts.map +0 -1
- package/dist/workflows/cloud-schedules.js +0 -2
- package/dist/workflows/cloud-schedules.js.map +0 -1
- package/dist/workflows/collectors/claude.d.ts +0 -6
- package/dist/workflows/collectors/claude.d.ts.map +0 -1
- package/dist/workflows/collectors/claude.js +0 -330
- package/dist/workflows/collectors/claude.js.map +0 -1
- package/dist/workflows/collectors/codex.d.ts +0 -18
- package/dist/workflows/collectors/codex.d.ts.map +0 -1
- package/dist/workflows/collectors/codex.js +0 -265
- package/dist/workflows/collectors/codex.js.map +0 -1
- package/dist/workflows/collectors/opencode.d.ts +0 -6
- package/dist/workflows/collectors/opencode.d.ts.map +0 -1
- package/dist/workflows/collectors/opencode.js +0 -204
- package/dist/workflows/collectors/opencode.js.map +0 -1
- package/dist/workflows/coordinator.d.ts +0 -73
- package/dist/workflows/coordinator.d.ts.map +0 -1
- package/dist/workflows/coordinator.js +0 -647
- package/dist/workflows/coordinator.js.map +0 -1
- package/dist/workflows/custom-steps.d.ts +0 -73
- package/dist/workflows/custom-steps.d.ts.map +0 -1
- package/dist/workflows/custom-steps.js +0 -321
- package/dist/workflows/custom-steps.js.map +0 -1
- package/dist/workflows/default-logger.d.ts +0 -9
- package/dist/workflows/default-logger.d.ts.map +0 -1
- package/dist/workflows/default-logger.js +0 -104
- package/dist/workflows/default-logger.js.map +0 -1
- package/dist/workflows/dry-run-format.d.ts +0 -6
- package/dist/workflows/dry-run-format.d.ts.map +0 -1
- package/dist/workflows/dry-run-format.js +0 -76
- package/dist/workflows/dry-run-format.js.map +0 -1
- package/dist/workflows/file-db.d.ts +0 -85
- package/dist/workflows/file-db.d.ts.map +0 -1
- package/dist/workflows/file-db.js +0 -215
- package/dist/workflows/file-db.js.map +0 -1
- package/dist/workflows/index.d.ts +0 -36
- package/dist/workflows/index.d.ts.map +0 -1
- package/dist/workflows/index.js +0 -33
- package/dist/workflows/index.js.map +0 -1
- package/dist/workflows/listr-renderer.d.ts +0 -26
- package/dist/workflows/listr-renderer.d.ts.map +0 -1
- package/dist/workflows/listr-renderer.js +0 -230
- package/dist/workflows/listr-renderer.js.map +0 -1
- package/dist/workflows/memory-db.d.ts +0 -17
- package/dist/workflows/memory-db.d.ts.map +0 -1
- package/dist/workflows/memory-db.js +0 -33
- package/dist/workflows/memory-db.js.map +0 -1
- package/dist/workflows/process-backend-executor.d.ts +0 -18
- package/dist/workflows/process-backend-executor.d.ts.map +0 -1
- package/dist/workflows/process-backend-executor.js +0 -74
- package/dist/workflows/process-backend-executor.js.map +0 -1
- package/dist/workflows/process-spawner.d.ts +0 -35
- package/dist/workflows/process-spawner.d.ts.map +0 -1
- package/dist/workflows/process-spawner.js +0 -141
- package/dist/workflows/process-spawner.js.map +0 -1
- package/dist/workflows/proxy-env.d.ts +0 -52
- package/dist/workflows/proxy-env.d.ts.map +0 -1
- package/dist/workflows/proxy-env.js +0 -92
- package/dist/workflows/proxy-env.js.map +0 -1
- package/dist/workflows/run-script.d.ts +0 -82
- package/dist/workflows/run-script.d.ts.map +0 -1
- package/dist/workflows/run-script.js +0 -521
- package/dist/workflows/run-script.js.map +0 -1
- package/dist/workflows/run-summary-table.d.ts +0 -5
- package/dist/workflows/run-summary-table.d.ts.map +0 -1
- package/dist/workflows/run-summary-table.js +0 -132
- package/dist/workflows/run-summary-table.js.map +0 -1
- package/dist/workflows/run.d.ts +0 -45
- package/dist/workflows/run.d.ts.map +0 -1
- package/dist/workflows/run.js +0 -37
- package/dist/workflows/run.js.map +0 -1
- package/dist/workflows/runner.d.ts +0 -527
- package/dist/workflows/runner.d.ts.map +0 -1
- package/dist/workflows/runner.js +0 -6266
- package/dist/workflows/runner.js.map +0 -1
- package/dist/workflows/sibling-links.d.ts +0 -100
- package/dist/workflows/sibling-links.d.ts.map +0 -1
- package/dist/workflows/sibling-links.js +0 -205
- package/dist/workflows/sibling-links.js.map +0 -1
- package/dist/workflows/state.d.ts +0 -77
- package/dist/workflows/state.d.ts.map +0 -1
- package/dist/workflows/state.js +0 -140
- package/dist/workflows/state.js.map +0 -1
- package/dist/workflows/step-executor.d.ts +0 -95
- package/dist/workflows/step-executor.d.ts.map +0 -1
- package/dist/workflows/step-executor.js +0 -393
- package/dist/workflows/step-executor.js.map +0 -1
- package/dist/workflows/template-resolver.d.ts +0 -33
- package/dist/workflows/template-resolver.d.ts.map +0 -1
- package/dist/workflows/template-resolver.js +0 -144
- package/dist/workflows/template-resolver.js.map +0 -1
- package/dist/workflows/templates.d.ts +0 -47
- package/dist/workflows/templates.d.ts.map +0 -1
- package/dist/workflows/templates.js +0 -405
- package/dist/workflows/templates.js.map +0 -1
- package/dist/workflows/trajectory.d.ts +0 -87
- package/dist/workflows/trajectory.d.ts.map +0 -1
- package/dist/workflows/trajectory.js +0 -412
- package/dist/workflows/trajectory.js.map +0 -1
- package/dist/workflows/types.d.ts +0 -471
- package/dist/workflows/types.d.ts.map +0 -1
- package/dist/workflows/types.js +0 -37
- package/dist/workflows/types.js.map +0 -1
- package/dist/workflows/validator.d.ts +0 -11
- package/dist/workflows/validator.d.ts.map +0 -1
- package/dist/workflows/validator.js +0 -184
- package/dist/workflows/validator.js.map +0 -1
- package/dist/workflows/verification.d.ts +0 -53
- package/dist/workflows/verification.d.ts.map +0 -1
- package/dist/workflows/verification.js +0 -238
- package/dist/workflows/verification.js.map +0 -1
- /package/dist/{provisioner → actions}/types.js +0 -0
package/dist/relay.js
DELETED
|
@@ -1,1682 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* High-level facade for the Agent Relay SDK.
|
|
3
|
-
*
|
|
4
|
-
* Provides a clean, property-based API on top of the lower-level
|
|
5
|
-
* {@link AgentRelayClient} protocol client.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```ts
|
|
9
|
-
* import { AgentRelay } from "@agent-relay/sdk";
|
|
10
|
-
*
|
|
11
|
-
* const relay = new AgentRelay();
|
|
12
|
-
*
|
|
13
|
-
* relay.addListener('messageReceived', (message) => console.log(message));
|
|
14
|
-
* relay.addListener('agentSpawned', (agent) => console.log("spawned", agent.name));
|
|
15
|
-
*
|
|
16
|
-
* const codex = await relay.codex.spawn();
|
|
17
|
-
* const human = relay.human({ name: "System" });
|
|
18
|
-
* await human.sendMessage({ to: codex.name, text: "Hello!" });
|
|
19
|
-
*
|
|
20
|
-
* const agents = await relay.listAgents();
|
|
21
|
-
* for (const a of agents) await a.release();
|
|
22
|
-
* await relay.shutdown();
|
|
23
|
-
* ```
|
|
24
|
-
*/
|
|
25
|
-
import { randomBytes } from 'node:crypto';
|
|
26
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
27
|
-
import path from 'node:path';
|
|
28
|
-
import { RelayCast } from '@relaycast/sdk';
|
|
29
|
-
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
30
|
-
import { AgentRelayClient } from './client.js';
|
|
31
|
-
import { EventBus } from './event-bus.js';
|
|
32
|
-
import { buildPersonaSpawnSpec, composePersonaTask, loadPersona, materializePersonaConfigFiles, restorePersonaConfigFiles, } from './personas.js';
|
|
33
|
-
import { AgentRelayProtocolError } from './transport.js';
|
|
34
|
-
import { followLogs as followLogsFromFile, getLogs as getLogsFromFile, listLoggedAgents as listLoggedAgentsFromFile, } from './logs.js';
|
|
35
|
-
function isUnsupportedOperation(error) {
|
|
36
|
-
return error instanceof AgentRelayProtocolError && error.code === 'unsupported_operation';
|
|
37
|
-
}
|
|
38
|
-
function buildUnsupportedOperationMessage(from, input) {
|
|
39
|
-
return {
|
|
40
|
-
eventId: 'unsupported_operation',
|
|
41
|
-
from,
|
|
42
|
-
to: input.to,
|
|
43
|
-
text: input.text,
|
|
44
|
-
threadId: input.threadId,
|
|
45
|
-
data: input.data,
|
|
46
|
-
mode: input.mode,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
const WORKSPACE_ID_PREFIX = 'rw_';
|
|
50
|
-
const WORKSPACE_ID_ALPHABET = 'abcdefghijklmnopqrstuvwxyz0123456789';
|
|
51
|
-
function normalizeWorkspaceId(value) {
|
|
52
|
-
const trimmed = value?.trim();
|
|
53
|
-
return trimmed ? trimmed : undefined;
|
|
54
|
-
}
|
|
55
|
-
function generateWorkspaceId() {
|
|
56
|
-
const alphabetLength = WORKSPACE_ID_ALPHABET.length;
|
|
57
|
-
const maxUnbiasedValue = Math.floor(256 / alphabetLength) * alphabetLength;
|
|
58
|
-
let suffix = '';
|
|
59
|
-
while (suffix.length < 8) {
|
|
60
|
-
const bytes = randomBytes(8 - suffix.length);
|
|
61
|
-
for (const byte of bytes) {
|
|
62
|
-
if (byte >= maxUnbiasedValue)
|
|
63
|
-
continue;
|
|
64
|
-
suffix += WORKSPACE_ID_ALPHABET[byte % alphabetLength];
|
|
65
|
-
if (suffix.length === 8)
|
|
66
|
-
break;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
return `${WORKSPACE_ID_PREFIX}${suffix}`;
|
|
70
|
-
}
|
|
71
|
-
function toWorkspaceRegistryEntry(value) {
|
|
72
|
-
if (!value || typeof value !== 'object') {
|
|
73
|
-
return {};
|
|
74
|
-
}
|
|
75
|
-
const record = value;
|
|
76
|
-
const relaycastApiKey = typeof record.relaycastApiKey === 'string' && record.relaycastApiKey.trim()
|
|
77
|
-
? record.relaycastApiKey.trim()
|
|
78
|
-
: undefined;
|
|
79
|
-
const relayfileUrl = typeof record.relayfileUrl === 'string' && record.relayfileUrl.trim()
|
|
80
|
-
? record.relayfileUrl.trim()
|
|
81
|
-
: undefined;
|
|
82
|
-
const createdAt = typeof record.createdAt === 'string' && record.createdAt.trim() ? record.createdAt.trim() : undefined;
|
|
83
|
-
const agents = Array.isArray(record.agents)
|
|
84
|
-
? record.agents
|
|
85
|
-
.filter((agent) => typeof agent === 'string')
|
|
86
|
-
.map((agent) => agent.trim())
|
|
87
|
-
.filter((agent) => agent.length > 0)
|
|
88
|
-
: undefined;
|
|
89
|
-
return {
|
|
90
|
-
...(relaycastApiKey ? { relaycastApiKey } : {}),
|
|
91
|
-
...(relayfileUrl ? { relayfileUrl } : {}),
|
|
92
|
-
...(createdAt ? { createdAt } : {}),
|
|
93
|
-
...(agents && agents.length > 0 ? { agents } : {}),
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
// ── AgentRelay facade ───────────────────────────────────────────────────────
|
|
97
|
-
export class AgentRelay {
|
|
98
|
-
/**
|
|
99
|
-
* Multi-listener event registry. Subscribe via {@link addListener} or
|
|
100
|
-
* `bus.addListener` directly; emit happens internally as broker events
|
|
101
|
-
* arrive and at SDK call sites for the spawn / release lifecycle hooks.
|
|
102
|
-
*
|
|
103
|
-
* The bus is shared with the underlying `AgentRelayClient` (created via
|
|
104
|
-
* {@link ensureStarted}) so listeners registered on either object see
|
|
105
|
-
* the same events.
|
|
106
|
-
*/
|
|
107
|
-
bus = new EventBus();
|
|
108
|
-
addListener(event, handler) {
|
|
109
|
-
return this.bus.addListener(event, handler);
|
|
110
|
-
}
|
|
111
|
-
removeListener(event, handler) {
|
|
112
|
-
this.bus.removeListener(event, handler);
|
|
113
|
-
}
|
|
114
|
-
// ── Public accessors ────────────────────────────────────────────────────
|
|
115
|
-
/** The resolved Relaycast workspace API key (available after first spawn). */
|
|
116
|
-
get workspaceKey() {
|
|
117
|
-
return this.relayApiKey;
|
|
118
|
-
}
|
|
119
|
-
/** Observer URL for the auto-created workspace (available after first spawn). */
|
|
120
|
-
get observerUrl() {
|
|
121
|
-
if (!this.relayApiKey)
|
|
122
|
-
return undefined;
|
|
123
|
-
return `https://agentrelay.com/observer?key=${this.relayApiKey}`;
|
|
124
|
-
}
|
|
125
|
-
// Shorthand spawners
|
|
126
|
-
codex;
|
|
127
|
-
claude;
|
|
128
|
-
gemini;
|
|
129
|
-
opencode;
|
|
130
|
-
clientOptions;
|
|
131
|
-
defaultChannels;
|
|
132
|
-
requestedWorkspaceId;
|
|
133
|
-
workspaceName;
|
|
134
|
-
relaycastBaseUrl;
|
|
135
|
-
defaultPersonaDirs;
|
|
136
|
-
relayApiKey;
|
|
137
|
-
resolvedWorkspaceId;
|
|
138
|
-
client;
|
|
139
|
-
startPromise;
|
|
140
|
-
unsubEvent;
|
|
141
|
-
stderrListeners = new Set();
|
|
142
|
-
knownAgents = new Map();
|
|
143
|
-
readyAgents = new Set();
|
|
144
|
-
messageReadyAgents = new Set();
|
|
145
|
-
exitedAgents = new Set();
|
|
146
|
-
idleAgents = new Set();
|
|
147
|
-
deliveryStates = new Map();
|
|
148
|
-
agentActivityStates = new Map();
|
|
149
|
-
outputListeners = new Map();
|
|
150
|
-
resultContracts = new Map();
|
|
151
|
-
lastAgentResults = new Map();
|
|
152
|
-
resultResolvers = new Map();
|
|
153
|
-
resultResolverSeq = 0;
|
|
154
|
-
exitResolvers = new Map();
|
|
155
|
-
exitResolverSeq = 0;
|
|
156
|
-
idleResolvers = new Map();
|
|
157
|
-
idleResolverSeq = 0;
|
|
158
|
-
constructor(options = {}) {
|
|
159
|
-
const requestedWorkspaceId = normalizeWorkspaceId(options.workspaceId);
|
|
160
|
-
this.defaultChannels = options.channels ?? ['general'];
|
|
161
|
-
this.requestedWorkspaceId = requestedWorkspaceId;
|
|
162
|
-
this.workspaceName = options.workspaceName;
|
|
163
|
-
if (options.workspaceName && !options.workspaceId) {
|
|
164
|
-
console.warn('[AgentRelay] workspaceName without workspaceId is deprecated and will be removed in a future major version. ' +
|
|
165
|
-
'Set workspaceId explicitly to avoid silent behavior changes.');
|
|
166
|
-
}
|
|
167
|
-
this.relaycastBaseUrl = options.relaycastBaseUrl;
|
|
168
|
-
if (options.personaDirs)
|
|
169
|
-
this.defaultPersonaDirs = [...options.personaDirs];
|
|
170
|
-
this.clientOptions = {
|
|
171
|
-
binaryPath: options.binaryPath,
|
|
172
|
-
binaryArgs: options.binaryArgs,
|
|
173
|
-
brokerName: options.brokerName ?? options.workspaceName ?? requestedWorkspaceId,
|
|
174
|
-
channels: this.defaultChannels,
|
|
175
|
-
cwd: options.cwd,
|
|
176
|
-
env: options.env,
|
|
177
|
-
requestTimeoutMs: options.requestTimeoutMs,
|
|
178
|
-
};
|
|
179
|
-
this.codex = this.createSpawner('codex', 'Codex', 'pty');
|
|
180
|
-
this.claude = this.createSpawner('claude', 'Claude', 'pty');
|
|
181
|
-
this.gemini = this.createSpawner('gemini', 'Gemini', 'pty');
|
|
182
|
-
this.opencode = this.createSpawner('opencode', 'OpenCode', 'headless');
|
|
183
|
-
}
|
|
184
|
-
getWorkspaceRegistryPath() {
|
|
185
|
-
return path.join(this.clientOptions.cwd ?? process.cwd(), '.relay', 'workspaces.json');
|
|
186
|
-
}
|
|
187
|
-
readWorkspaceRegistry() {
|
|
188
|
-
const registryPath = this.getWorkspaceRegistryPath();
|
|
189
|
-
if (!existsSync(registryPath)) {
|
|
190
|
-
return {};
|
|
191
|
-
}
|
|
192
|
-
let raw;
|
|
193
|
-
try {
|
|
194
|
-
raw = readFileSync(registryPath, 'utf8').trim();
|
|
195
|
-
}
|
|
196
|
-
catch {
|
|
197
|
-
return {};
|
|
198
|
-
}
|
|
199
|
-
if (!raw) {
|
|
200
|
-
return {};
|
|
201
|
-
}
|
|
202
|
-
let parsed;
|
|
203
|
-
try {
|
|
204
|
-
parsed = JSON.parse(raw);
|
|
205
|
-
}
|
|
206
|
-
catch {
|
|
207
|
-
// Registry file is corrupted (partial write, disk full, concurrent access).
|
|
208
|
-
// Return empty registry so callers can re-create it.
|
|
209
|
-
return {};
|
|
210
|
-
}
|
|
211
|
-
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
212
|
-
return {};
|
|
213
|
-
}
|
|
214
|
-
const registry = {};
|
|
215
|
-
for (const [workspaceId, entry] of Object.entries(parsed)) {
|
|
216
|
-
const normalizedId = normalizeWorkspaceId(workspaceId);
|
|
217
|
-
if (!normalizedId)
|
|
218
|
-
continue;
|
|
219
|
-
registry[normalizedId] = toWorkspaceRegistryEntry(entry);
|
|
220
|
-
}
|
|
221
|
-
return registry;
|
|
222
|
-
}
|
|
223
|
-
writeWorkspaceRegistry(registry) {
|
|
224
|
-
const registryPath = this.getWorkspaceRegistryPath();
|
|
225
|
-
mkdirSync(path.dirname(registryPath), { recursive: true });
|
|
226
|
-
writeFileSync(registryPath, `${JSON.stringify(registry, null, 2)}\n`, { encoding: 'utf8', mode: 0o600 });
|
|
227
|
-
}
|
|
228
|
-
persistWorkspaceMapping(workspaceId, apiKey) {
|
|
229
|
-
const registry = this.readWorkspaceRegistry();
|
|
230
|
-
const existing = registry[workspaceId] ?? {};
|
|
231
|
-
registry[workspaceId] = {
|
|
232
|
-
...existing,
|
|
233
|
-
relaycastApiKey: apiKey,
|
|
234
|
-
relayfileUrl: existing.relayfileUrl,
|
|
235
|
-
createdAt: existing.createdAt ?? new Date().toISOString(),
|
|
236
|
-
agents: existing.agents ?? [],
|
|
237
|
-
};
|
|
238
|
-
this.writeWorkspaceRegistry(registry);
|
|
239
|
-
}
|
|
240
|
-
findMappedWorkspaceIdByApiKey(apiKey) {
|
|
241
|
-
const registry = this.readWorkspaceRegistry();
|
|
242
|
-
for (const [workspaceId, entry] of Object.entries(registry)) {
|
|
243
|
-
if (entry.relaycastApiKey === apiKey) {
|
|
244
|
-
return workspaceId;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
return undefined;
|
|
248
|
-
}
|
|
249
|
-
getResolvedWorkspaceId() {
|
|
250
|
-
return this.resolvedWorkspaceId ?? this.requestedWorkspaceId;
|
|
251
|
-
}
|
|
252
|
-
getRelaycastBaseUrl() {
|
|
253
|
-
return (this.relaycastBaseUrl ??
|
|
254
|
-
this.clientOptions.env?.RELAYCAST_BASE_URL ??
|
|
255
|
-
process.env.RELAYCAST_BASE_URL ??
|
|
256
|
-
'https://api.relaycast.dev');
|
|
257
|
-
}
|
|
258
|
-
applyWorkspaceEnv(workspaceId, apiKey) {
|
|
259
|
-
// `workspaceId` here is the **relaycast** workspace id resolved by this
|
|
260
|
-
// SDK (auto-created or caller-supplied via `new AgentRelay({ workspaceId })`).
|
|
261
|
-
// Do NOT write it into `RELAYFILE_WORKSPACE` — relayfile and relaycast
|
|
262
|
-
// workspaces are independent ids and a relayfile JWT scoped to a
|
|
263
|
-
// different workspace will 403 with "workspace mismatch". Callers that
|
|
264
|
-
// share an id across both services (e.g. the canonical `relay on start`
|
|
265
|
-
// flow) set `RELAYFILE_WORKSPACE` themselves.
|
|
266
|
-
const env = {
|
|
267
|
-
...(this.clientOptions.env ?? process.env),
|
|
268
|
-
RELAY_API_KEY: apiKey,
|
|
269
|
-
RELAY_DEFAULT_WORKSPACE: workspaceId,
|
|
270
|
-
RELAY_WORKSPACE_ID: workspaceId,
|
|
271
|
-
RELAY_WORKSPACES_JSON: JSON.stringify([{ workspace_id: workspaceId, api_key: apiKey }]),
|
|
272
|
-
};
|
|
273
|
-
if (this.relaycastBaseUrl) {
|
|
274
|
-
env.RELAYCAST_BASE_URL = this.relaycastBaseUrl;
|
|
275
|
-
}
|
|
276
|
-
this.clientOptions.env = env;
|
|
277
|
-
}
|
|
278
|
-
async createMappedRelaycastWorkspace(workspaceId) {
|
|
279
|
-
const created = await RelayCast.createWorkspace(this.workspaceName ?? workspaceId, this.getRelaycastBaseUrl());
|
|
280
|
-
const workspace = created;
|
|
281
|
-
const apiKey = workspace.apiKey ?? workspace.api_key;
|
|
282
|
-
if (!apiKey) {
|
|
283
|
-
throw new Error('RelayCast.createWorkspace() did not return an API key');
|
|
284
|
-
}
|
|
285
|
-
return apiKey;
|
|
286
|
-
}
|
|
287
|
-
/**
|
|
288
|
-
* Subscribe to broker stderr output. Listener is wired immediately if the
|
|
289
|
-
* client is already started, otherwise it is attached when the client starts.
|
|
290
|
-
* Returns an unsubscribe function.
|
|
291
|
-
*/
|
|
292
|
-
onBrokerStderr(listener) {
|
|
293
|
-
this.stderrListeners.add(listener);
|
|
294
|
-
return () => {
|
|
295
|
-
this.stderrListeners.delete(listener);
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
// ── Spawning ────────────────────────────────────────────────────────────
|
|
299
|
-
async spawnPty(input) {
|
|
300
|
-
const client = await this.ensureStarted();
|
|
301
|
-
if (!input.channels || input.channels.length === 0) {
|
|
302
|
-
console.warn(`[AgentRelay] spawnPty("${input.name}"): no channels specified, defaulting to "general". ` +
|
|
303
|
-
'Set explicit channels for workflow isolation.');
|
|
304
|
-
}
|
|
305
|
-
const channels = input.channels ?? ['general'];
|
|
306
|
-
const lifecycleContext = {
|
|
307
|
-
name: input.name,
|
|
308
|
-
cli: input.cli,
|
|
309
|
-
channels,
|
|
310
|
-
task: input.task,
|
|
311
|
-
};
|
|
312
|
-
await this.invokeLifecycleHook(input.onStart, lifecycleContext, `spawnPty("${input.name}") onStart`);
|
|
313
|
-
let result;
|
|
314
|
-
const resultContract = this.prepareAgentResultContract(input.result);
|
|
315
|
-
if (resultContract) {
|
|
316
|
-
this.resultContracts.set(input.name, resultContract);
|
|
317
|
-
}
|
|
318
|
-
try {
|
|
319
|
-
result = await client.spawnPty({
|
|
320
|
-
name: input.name,
|
|
321
|
-
cli: input.cli,
|
|
322
|
-
args: input.args,
|
|
323
|
-
channels,
|
|
324
|
-
task: input.task,
|
|
325
|
-
model: input.model,
|
|
326
|
-
cwd: input.cwd,
|
|
327
|
-
team: input.team,
|
|
328
|
-
agentToken: input.agentToken,
|
|
329
|
-
shadowOf: input.shadowOf,
|
|
330
|
-
shadowMode: input.shadowMode,
|
|
331
|
-
idleThresholdSecs: input.idleThresholdSecs,
|
|
332
|
-
restartPolicy: input.restartPolicy,
|
|
333
|
-
skipRelayPrompt: input.skipRelayPrompt,
|
|
334
|
-
agentResultSchema: resultContract?.jsonSchema,
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
|
-
catch (error) {
|
|
338
|
-
if (resultContract) {
|
|
339
|
-
this.resultContracts.delete(input.name);
|
|
340
|
-
}
|
|
341
|
-
await this.invokeLifecycleHook(input.onError, {
|
|
342
|
-
...lifecycleContext,
|
|
343
|
-
error,
|
|
344
|
-
}, `spawnPty("${input.name}") onError`);
|
|
345
|
-
throw error;
|
|
346
|
-
}
|
|
347
|
-
this.resetAgentLifecycleState(result.name);
|
|
348
|
-
if (result.name !== input.name && resultContract) {
|
|
349
|
-
this.resultContracts.delete(input.name);
|
|
350
|
-
this.resultContracts.set(result.name, resultContract);
|
|
351
|
-
}
|
|
352
|
-
const agent = this.makeAgent(result.name, result.runtime, channels);
|
|
353
|
-
this.knownAgents.set(agent.name, agent);
|
|
354
|
-
await this.invokeLifecycleHook(input.onSuccess, {
|
|
355
|
-
...lifecycleContext,
|
|
356
|
-
name: result.name,
|
|
357
|
-
runtime: result.runtime,
|
|
358
|
-
}, `spawnPty("${input.name}") onSuccess`);
|
|
359
|
-
return agent;
|
|
360
|
-
}
|
|
361
|
-
async spawn(name, cli, task, options) {
|
|
362
|
-
return this.spawnPty({
|
|
363
|
-
name,
|
|
364
|
-
cli,
|
|
365
|
-
task,
|
|
366
|
-
args: options?.args,
|
|
367
|
-
channels: options?.channels,
|
|
368
|
-
model: options?.model,
|
|
369
|
-
cwd: options?.cwd,
|
|
370
|
-
team: options?.team,
|
|
371
|
-
agentToken: options?.agentToken,
|
|
372
|
-
shadowOf: options?.shadowOf,
|
|
373
|
-
shadowMode: options?.shadowMode,
|
|
374
|
-
idleThresholdSecs: options?.idleThresholdSecs,
|
|
375
|
-
restartPolicy: options?.restartPolicy,
|
|
376
|
-
skipRelayPrompt: options?.skipRelayPrompt,
|
|
377
|
-
result: options?.result,
|
|
378
|
-
onStart: options?.onStart,
|
|
379
|
-
onSuccess: options?.onSuccess,
|
|
380
|
-
onError: options?.onError,
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
async spawnAndWait(name, cli, task, options) {
|
|
384
|
-
const { timeoutMs, waitForMessage, ...spawnOptions } = options ?? {};
|
|
385
|
-
await this.spawn(name, cli, task, spawnOptions);
|
|
386
|
-
if (waitForMessage) {
|
|
387
|
-
return this.waitForAgentMessage(name, timeoutMs ?? 60_000);
|
|
388
|
-
}
|
|
389
|
-
return this.waitForAgentReady(name, timeoutMs ?? 60_000);
|
|
390
|
-
}
|
|
391
|
-
/**
|
|
392
|
-
* Spawn an agent from a named AgentWorkforce persona.
|
|
393
|
-
*
|
|
394
|
-
* Looks up the persona JSON in the search-dir cascade
|
|
395
|
-
* (`<cwd>/agentworkforce/personas`, `<cwd>/.agentworkforce/workforce/personas`,
|
|
396
|
-
* `~/.agentworkforce/workforce/personas`, plus `AGENT_WORKFORCE_HOME`),
|
|
397
|
-
* resolves the requested tier, and translates it to spawnPty args via
|
|
398
|
-
* `@agentworkforce/harness-kit#buildInteractiveSpec`.
|
|
399
|
-
*
|
|
400
|
-
* For opencode, an `opencode.json` is materialized in the spawn cwd and
|
|
401
|
-
* automatically restored when the agent exits. For codex, the persona's
|
|
402
|
-
* systemPrompt is folded into the initial task (codex has no
|
|
403
|
-
* system-prompt flag). Translation warnings are surfaced via console.warn.
|
|
404
|
-
*
|
|
405
|
-
* @param personaId — id of the persona to load
|
|
406
|
-
* @param options — overrides for tier, search dirs, name, task, and the
|
|
407
|
-
* underlying spawn options
|
|
408
|
-
*/
|
|
409
|
-
async spawnPersona(personaId, options = {}) {
|
|
410
|
-
const personaCwd = options.personaCwd ?? options.cwd ?? process.cwd();
|
|
411
|
-
const searchDirs = options.searchDirs ?? this.defaultPersonaDirs;
|
|
412
|
-
const loadOpts = {
|
|
413
|
-
cwd: personaCwd,
|
|
414
|
-
...(searchDirs ? { searchDirs } : {}),
|
|
415
|
-
...(options.extraDirs ? { extraDirs: options.extraDirs } : {}),
|
|
416
|
-
...(options.tier ? { tier: options.tier } : {}),
|
|
417
|
-
};
|
|
418
|
-
const persona = options.persona ?? loadPersona(personaId, loadOpts);
|
|
419
|
-
const spec = buildPersonaSpawnSpec(persona);
|
|
420
|
-
for (const warning of spec.warnings) {
|
|
421
|
-
console.warn(`[AgentRelay] ${warning}`);
|
|
422
|
-
}
|
|
423
|
-
const spawnCwd = options.cwd ?? process.cwd();
|
|
424
|
-
const writes = spec.configFiles.length > 0 ? materializePersonaConfigFiles(spawnCwd, spec.configFiles) : [];
|
|
425
|
-
const baseArgs = options.args ?? [];
|
|
426
|
-
const mergedArgs = [...spec.args, ...baseArgs];
|
|
427
|
-
const task = composePersonaTask(spec, options.task);
|
|
428
|
-
const spawnName = options.name ?? persona.id;
|
|
429
|
-
let agent;
|
|
430
|
-
try {
|
|
431
|
-
agent = await this.spawnPty({
|
|
432
|
-
name: spawnName,
|
|
433
|
-
cli: spec.cli,
|
|
434
|
-
args: mergedArgs,
|
|
435
|
-
...(task !== undefined ? { task } : {}),
|
|
436
|
-
channels: options.channels,
|
|
437
|
-
model: spec.model,
|
|
438
|
-
cwd: spawnCwd,
|
|
439
|
-
team: options.team,
|
|
440
|
-
agentToken: options.agentToken,
|
|
441
|
-
shadowOf: options.shadowOf,
|
|
442
|
-
shadowMode: options.shadowMode,
|
|
443
|
-
idleThresholdSecs: options.idleThresholdSecs,
|
|
444
|
-
restartPolicy: options.restartPolicy,
|
|
445
|
-
skipRelayPrompt: options.skipRelayPrompt,
|
|
446
|
-
result: options.result,
|
|
447
|
-
onStart: options.onStart,
|
|
448
|
-
onSuccess: options.onSuccess,
|
|
449
|
-
onError: options.onError,
|
|
450
|
-
});
|
|
451
|
-
}
|
|
452
|
-
catch (err) {
|
|
453
|
-
restorePersonaConfigFiles(writes);
|
|
454
|
-
throw err;
|
|
455
|
-
}
|
|
456
|
-
if (writes.length > 0) {
|
|
457
|
-
void agent.waitForExit().finally(() => {
|
|
458
|
-
restorePersonaConfigFiles(writes);
|
|
459
|
-
});
|
|
460
|
-
}
|
|
461
|
-
return agent;
|
|
462
|
-
}
|
|
463
|
-
// ── Human source ────────────────────────────────────────────────────────
|
|
464
|
-
human(opts) {
|
|
465
|
-
return {
|
|
466
|
-
name: opts.name,
|
|
467
|
-
sendMessage: async (input) => {
|
|
468
|
-
const client = await this.ensureStarted();
|
|
469
|
-
let result;
|
|
470
|
-
try {
|
|
471
|
-
result = await client.sendMessage({
|
|
472
|
-
to: input.to,
|
|
473
|
-
text: input.text,
|
|
474
|
-
from: opts.name,
|
|
475
|
-
threadId: input.threadId,
|
|
476
|
-
priority: input.priority,
|
|
477
|
-
data: input.data,
|
|
478
|
-
mode: input.mode,
|
|
479
|
-
});
|
|
480
|
-
}
|
|
481
|
-
catch (error) {
|
|
482
|
-
if (isUnsupportedOperation(error)) {
|
|
483
|
-
return buildUnsupportedOperationMessage(opts.name, input);
|
|
484
|
-
}
|
|
485
|
-
throw error;
|
|
486
|
-
}
|
|
487
|
-
if (result?.event_id === 'unsupported_operation') {
|
|
488
|
-
return buildUnsupportedOperationMessage(opts.name, input);
|
|
489
|
-
}
|
|
490
|
-
const eventId = result?.event_id ?? randomBytes(8).toString('hex');
|
|
491
|
-
const msg = {
|
|
492
|
-
eventId,
|
|
493
|
-
from: opts.name,
|
|
494
|
-
to: input.to,
|
|
495
|
-
text: input.text,
|
|
496
|
-
threadId: input.threadId,
|
|
497
|
-
data: input.data,
|
|
498
|
-
mode: input.mode,
|
|
499
|
-
};
|
|
500
|
-
void this.bus.emit('messageSent', msg);
|
|
501
|
-
return msg;
|
|
502
|
-
},
|
|
503
|
-
};
|
|
504
|
-
}
|
|
505
|
-
system() {
|
|
506
|
-
return this.human({ name: 'system' });
|
|
507
|
-
}
|
|
508
|
-
// ── Messaging ─────────────────────────────────────────────────────────
|
|
509
|
-
/**
|
|
510
|
-
* Broadcast a message to all connected agents.
|
|
511
|
-
* @param text — the message body
|
|
512
|
-
* @param options — optional sender name (defaults to "human:orchestrator")
|
|
513
|
-
*/
|
|
514
|
-
async broadcast(text, options) {
|
|
515
|
-
const from = options?.from ?? 'human:orchestrator';
|
|
516
|
-
return this.human({ name: from }).sendMessage({ to: '*', text });
|
|
517
|
-
}
|
|
518
|
-
async sendAndWaitForDelivery(input, timeoutMs = 30_000) {
|
|
519
|
-
const client = await this.ensureStarted();
|
|
520
|
-
const result = await client.sendMessage(input);
|
|
521
|
-
if (!result.targets.length) {
|
|
522
|
-
return { eventId: result.event_id, status: 'failed', targets: [] };
|
|
523
|
-
}
|
|
524
|
-
return new Promise((resolve) => {
|
|
525
|
-
let resolved = false;
|
|
526
|
-
const ackedTargets = new Set();
|
|
527
|
-
const confirmedTargets = new Set();
|
|
528
|
-
// eslint-disable-next-line prefer-const
|
|
529
|
-
let unsubscribe;
|
|
530
|
-
const timer = setTimeout(() => {
|
|
531
|
-
if (!resolved) {
|
|
532
|
-
resolved = true;
|
|
533
|
-
unsubscribe?.();
|
|
534
|
-
resolve({ eventId: result.event_id, status: 'timeout', targets: result.targets });
|
|
535
|
-
}
|
|
536
|
-
}, timeoutMs);
|
|
537
|
-
unsubscribe = client.onEvent((event) => {
|
|
538
|
-
if (resolved)
|
|
539
|
-
return;
|
|
540
|
-
if (event.kind === 'delivery_ack' &&
|
|
541
|
-
event.event_id === result.event_id &&
|
|
542
|
-
result.targets.includes(event.name)) {
|
|
543
|
-
ackedTargets.add(event.name);
|
|
544
|
-
}
|
|
545
|
-
if (event.kind === 'message_delivery_confirmed' &&
|
|
546
|
-
event.event_id === result.event_id &&
|
|
547
|
-
result.targets.includes(event.name)) {
|
|
548
|
-
confirmedTargets.add(event.name);
|
|
549
|
-
if (confirmedTargets.size >= result.targets.length) {
|
|
550
|
-
resolved = true;
|
|
551
|
-
clearTimeout(timer);
|
|
552
|
-
unsubscribe?.();
|
|
553
|
-
resolve({ eventId: result.event_id, status: 'ack', targets: result.targets });
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
if (event.kind === 'message_delivery_failed' &&
|
|
557
|
-
event.event_id === result.event_id &&
|
|
558
|
-
result.targets.includes(event.name)) {
|
|
559
|
-
resolved = true;
|
|
560
|
-
clearTimeout(timer);
|
|
561
|
-
unsubscribe?.();
|
|
562
|
-
resolve({ eventId: result.event_id, status: 'failed', targets: result.targets });
|
|
563
|
-
}
|
|
564
|
-
});
|
|
565
|
-
});
|
|
566
|
-
}
|
|
567
|
-
// ── Listing ─────────────────────────────────────────────────────────────
|
|
568
|
-
async listAgents() {
|
|
569
|
-
const client = await this.ensureStarted();
|
|
570
|
-
const list = await client.listAgents();
|
|
571
|
-
return list.map((entry) => {
|
|
572
|
-
const existing = this.knownAgents.get(entry.name);
|
|
573
|
-
if (existing)
|
|
574
|
-
return existing;
|
|
575
|
-
const agent = this.makeAgent(entry.name, entry.runtime, entry.channels);
|
|
576
|
-
this.knownAgents.set(agent.name, agent);
|
|
577
|
-
return agent;
|
|
578
|
-
});
|
|
579
|
-
}
|
|
580
|
-
/** Pre-register a batch of agents with Relaycast before steps execute. */
|
|
581
|
-
async preflightAgents(agents) {
|
|
582
|
-
const client = await this.ensureStarted();
|
|
583
|
-
await client.preflight(agents);
|
|
584
|
-
}
|
|
585
|
-
/** List agents with PIDs from the broker (for worker registration). */
|
|
586
|
-
async listAgentsRaw() {
|
|
587
|
-
const client = await this.ensureStarted();
|
|
588
|
-
return client.listAgents();
|
|
589
|
-
}
|
|
590
|
-
// ── Status ────────────────────────────────────────────────────────────
|
|
591
|
-
async getStatus() {
|
|
592
|
-
const client = await this.ensureStarted();
|
|
593
|
-
return client.getStatus();
|
|
594
|
-
}
|
|
595
|
-
async subscribe(opts) {
|
|
596
|
-
const client = await this.ensureStarted();
|
|
597
|
-
await client.subscribeChannels(opts.agent, opts.channels);
|
|
598
|
-
this.addAgentChannels(opts.agent, opts.channels);
|
|
599
|
-
}
|
|
600
|
-
async unsubscribe(opts) {
|
|
601
|
-
const client = await this.ensureStarted();
|
|
602
|
-
await client.unsubscribeChannels(opts.agent, opts.channels);
|
|
603
|
-
this.removeAgentChannels(opts.agent, opts.channels);
|
|
604
|
-
}
|
|
605
|
-
getDeliveryState(eventId) {
|
|
606
|
-
return this.deliveryStates.get(eventId);
|
|
607
|
-
}
|
|
608
|
-
// ── Logs ──────────────────────────────────────────────────────────────
|
|
609
|
-
/**
|
|
610
|
-
* Read the last N lines of an agent's log file.
|
|
611
|
-
*
|
|
612
|
-
* @example
|
|
613
|
-
* ```ts
|
|
614
|
-
* const logs = await relay.getLogs("Worker1", { lines: 100 });
|
|
615
|
-
* if (logs.found) console.log(logs.content);
|
|
616
|
-
* ```
|
|
617
|
-
*/
|
|
618
|
-
async getLogs(agentName, options) {
|
|
619
|
-
const cwd = this.clientOptions.cwd ?? process.cwd();
|
|
620
|
-
const logsDir = path.join(cwd, '.agent-relay', 'team', 'worker-logs');
|
|
621
|
-
return getLogsFromFile(agentName, { logsDir, lines: options?.lines });
|
|
622
|
-
}
|
|
623
|
-
/** List all agents that have log files. */
|
|
624
|
-
async listLoggedAgents() {
|
|
625
|
-
const cwd = this.clientOptions.cwd ?? process.cwd();
|
|
626
|
-
const logsDir = path.join(cwd, '.agent-relay', 'team', 'worker-logs');
|
|
627
|
-
return listLoggedAgentsFromFile(logsDir);
|
|
628
|
-
}
|
|
629
|
-
/**
|
|
630
|
-
* Follow an agent's local log file with history bootstrap + incremental updates.
|
|
631
|
-
*
|
|
632
|
-
* @example
|
|
633
|
-
* ```ts
|
|
634
|
-
* const handle = relay.followLogs("Worker1", {
|
|
635
|
-
* historyLines: 100,
|
|
636
|
-
* onEvent(event) {
|
|
637
|
-
* if (event.type === "log") console.log(event.content);
|
|
638
|
-
* },
|
|
639
|
-
* });
|
|
640
|
-
*
|
|
641
|
-
* // Later:
|
|
642
|
-
* handle.unsubscribe();
|
|
643
|
-
* ```
|
|
644
|
-
*/
|
|
645
|
-
followLogs(agentName, options) {
|
|
646
|
-
const cwd = this.clientOptions.cwd ?? process.cwd();
|
|
647
|
-
const logsDir = path.join(cwd, '.agent-relay', 'team', 'worker-logs');
|
|
648
|
-
return followLogsFromFile(agentName, { ...options, logsDir });
|
|
649
|
-
}
|
|
650
|
-
// ── Wait helpers ──────────────────────────────────────────────────────
|
|
651
|
-
/**
|
|
652
|
-
* Wait for any one of the given agents to exit. Returns the first agent
|
|
653
|
-
* that exits along with its exit reason.
|
|
654
|
-
*
|
|
655
|
-
* @example
|
|
656
|
-
* ```ts
|
|
657
|
-
* const { agent, result } = await AgentRelay.waitForAny([worker1, worker2], 60_000);
|
|
658
|
-
* console.log(`${agent.name} finished: ${result}`);
|
|
659
|
-
* ```
|
|
660
|
-
*/
|
|
661
|
-
static async waitForAny(agents, timeoutMs) {
|
|
662
|
-
if (agents.length === 0) {
|
|
663
|
-
throw new Error('waitForAny requires at least one agent');
|
|
664
|
-
}
|
|
665
|
-
return Promise.race(agents.map(async (agent) => {
|
|
666
|
-
const result = await agent.waitForExit(timeoutMs);
|
|
667
|
-
return { agent, result };
|
|
668
|
-
}));
|
|
669
|
-
}
|
|
670
|
-
/**
|
|
671
|
-
* Resolves when the agent process has started and connected to the broker.
|
|
672
|
-
* The agent's CLI may not yet be ready to receive messages.
|
|
673
|
-
* Use `waitForAgentMessage()` for full readiness.
|
|
674
|
-
*/
|
|
675
|
-
async waitForAgentReady(name, timeoutMs = 60_000) {
|
|
676
|
-
const client = await this.ensureStarted();
|
|
677
|
-
const existing = this.knownAgents.get(name);
|
|
678
|
-
if (existing && this.readyAgents.has(name)) {
|
|
679
|
-
return existing;
|
|
680
|
-
}
|
|
681
|
-
return new Promise((resolve, reject) => {
|
|
682
|
-
let settled = false;
|
|
683
|
-
let timeout;
|
|
684
|
-
const cleanup = () => {
|
|
685
|
-
unsubscribe();
|
|
686
|
-
if (timeout) {
|
|
687
|
-
clearTimeout(timeout);
|
|
688
|
-
timeout = undefined;
|
|
689
|
-
}
|
|
690
|
-
};
|
|
691
|
-
const resolveWith = (agent) => {
|
|
692
|
-
if (settled)
|
|
693
|
-
return;
|
|
694
|
-
settled = true;
|
|
695
|
-
cleanup();
|
|
696
|
-
resolve(agent);
|
|
697
|
-
};
|
|
698
|
-
const rejectWith = (error) => {
|
|
699
|
-
if (settled)
|
|
700
|
-
return;
|
|
701
|
-
settled = true;
|
|
702
|
-
cleanup();
|
|
703
|
-
reject(error);
|
|
704
|
-
};
|
|
705
|
-
const unsubscribe = client.onEvent((event) => {
|
|
706
|
-
if (event.kind !== 'worker_ready' || event.name !== name) {
|
|
707
|
-
return;
|
|
708
|
-
}
|
|
709
|
-
const agent = this.ensureAgentHandle(event.name, event.runtime);
|
|
710
|
-
this.readyAgents.add(event.name);
|
|
711
|
-
this.exitedAgents.delete(event.name);
|
|
712
|
-
resolveWith(agent);
|
|
713
|
-
});
|
|
714
|
-
timeout = setTimeout(() => {
|
|
715
|
-
rejectWith(new Error(`Timed out waiting for worker_ready for '${name}' after ${timeoutMs}ms`));
|
|
716
|
-
}, timeoutMs);
|
|
717
|
-
const known = this.knownAgents.get(name);
|
|
718
|
-
if (known && this.readyAgents.has(name)) {
|
|
719
|
-
resolveWith(known);
|
|
720
|
-
}
|
|
721
|
-
});
|
|
722
|
-
}
|
|
723
|
-
async waitForAgentMessage(name, timeoutMs = 60_000) {
|
|
724
|
-
const client = await this.ensureStarted();
|
|
725
|
-
const existing = this.knownAgents.get(name);
|
|
726
|
-
if (existing && this.messageReadyAgents.has(name)) {
|
|
727
|
-
return existing;
|
|
728
|
-
}
|
|
729
|
-
return new Promise((resolve, reject) => {
|
|
730
|
-
let settled = false;
|
|
731
|
-
let timeout;
|
|
732
|
-
const cleanup = () => {
|
|
733
|
-
unsubscribe();
|
|
734
|
-
if (timeout) {
|
|
735
|
-
clearTimeout(timeout);
|
|
736
|
-
timeout = undefined;
|
|
737
|
-
}
|
|
738
|
-
};
|
|
739
|
-
const resolveWith = (agent) => {
|
|
740
|
-
if (settled)
|
|
741
|
-
return;
|
|
742
|
-
settled = true;
|
|
743
|
-
cleanup();
|
|
744
|
-
resolve(agent);
|
|
745
|
-
};
|
|
746
|
-
const rejectWith = (error) => {
|
|
747
|
-
if (settled)
|
|
748
|
-
return;
|
|
749
|
-
settled = true;
|
|
750
|
-
cleanup();
|
|
751
|
-
reject(error);
|
|
752
|
-
};
|
|
753
|
-
const unsubscribe = client.onEvent((event) => {
|
|
754
|
-
if (event.kind === 'relay_inbound' && event.from === name) {
|
|
755
|
-
this.messageReadyAgents.add(name);
|
|
756
|
-
this.exitedAgents.delete(name);
|
|
757
|
-
resolveWith(this.ensureAgentHandle(name));
|
|
758
|
-
return;
|
|
759
|
-
}
|
|
760
|
-
if (event.kind === 'agent_exited' && event.name === name) {
|
|
761
|
-
rejectWith(new Error(`Agent '${name}' exited before sending its first relay message`));
|
|
762
|
-
return;
|
|
763
|
-
}
|
|
764
|
-
if (event.kind === 'agent_released' && event.name === name) {
|
|
765
|
-
rejectWith(new Error(`Agent '${name}' was released before sending its first relay message`));
|
|
766
|
-
}
|
|
767
|
-
});
|
|
768
|
-
timeout = setTimeout(() => {
|
|
769
|
-
rejectWith(new Error(`Timed out waiting for first relay message from '${name}' after ${timeoutMs}ms`));
|
|
770
|
-
}, timeoutMs);
|
|
771
|
-
const known = this.knownAgents.get(name);
|
|
772
|
-
if (known && this.messageReadyAgents.has(name)) {
|
|
773
|
-
resolveWith(known);
|
|
774
|
-
}
|
|
775
|
-
});
|
|
776
|
-
}
|
|
777
|
-
// ── Lifecycle ───────────────────────────────────────────────────────────
|
|
778
|
-
async shutdown() {
|
|
779
|
-
if (this.unsubEvent) {
|
|
780
|
-
this.unsubEvent();
|
|
781
|
-
this.unsubEvent = undefined;
|
|
782
|
-
}
|
|
783
|
-
let client = this.client;
|
|
784
|
-
if (!client && this.startPromise) {
|
|
785
|
-
try {
|
|
786
|
-
client = await this.startPromise;
|
|
787
|
-
}
|
|
788
|
-
catch {
|
|
789
|
-
client = undefined;
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
if (client) {
|
|
793
|
-
await client.shutdown();
|
|
794
|
-
if (this.client === client) {
|
|
795
|
-
this.client = undefined;
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
this.startPromise = undefined;
|
|
799
|
-
this.knownAgents.clear();
|
|
800
|
-
this.readyAgents.clear();
|
|
801
|
-
this.messageReadyAgents.clear();
|
|
802
|
-
this.exitedAgents.clear();
|
|
803
|
-
this.idleAgents.clear();
|
|
804
|
-
this.deliveryStates.clear();
|
|
805
|
-
this.agentActivityStates.clear();
|
|
806
|
-
this.outputListeners.clear();
|
|
807
|
-
for (const entry of this.exitResolvers.values()) {
|
|
808
|
-
entry.resolve('released');
|
|
809
|
-
}
|
|
810
|
-
this.exitResolvers.clear();
|
|
811
|
-
for (const entry of this.idleResolvers.values()) {
|
|
812
|
-
entry.resolve('exited');
|
|
813
|
-
}
|
|
814
|
-
this.idleResolvers.clear();
|
|
815
|
-
const shutdownError = new Error('AgentRelay shutdown before structured result was submitted');
|
|
816
|
-
for (const waiters of this.resultResolvers.values()) {
|
|
817
|
-
for (const waiter of waiters) {
|
|
818
|
-
waiter.reject(shutdownError);
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
this.resultResolvers.clear();
|
|
822
|
-
this.resultContracts.clear();
|
|
823
|
-
this.lastAgentResults.clear();
|
|
824
|
-
}
|
|
825
|
-
// ── Private helpers ─────────────────────────────────────────────────────
|
|
826
|
-
ensureAgentHandle(name, runtime = 'pty', channels = []) {
|
|
827
|
-
const existing = this.knownAgents.get(name);
|
|
828
|
-
if (existing) {
|
|
829
|
-
return existing;
|
|
830
|
-
}
|
|
831
|
-
const agent = this.makeAgent(name, runtime, channels);
|
|
832
|
-
this.knownAgents.set(name, agent);
|
|
833
|
-
return agent;
|
|
834
|
-
}
|
|
835
|
-
updateDeliveryState(eventId, to, status, updatedAt) {
|
|
836
|
-
this.deliveryStates.set(eventId, { eventId, to, status, updatedAt });
|
|
837
|
-
}
|
|
838
|
-
ensureAgentActivityState(name) {
|
|
839
|
-
const existing = this.agentActivityStates.get(name);
|
|
840
|
-
if (existing) {
|
|
841
|
-
return existing;
|
|
842
|
-
}
|
|
843
|
-
const state = {
|
|
844
|
-
active: false,
|
|
845
|
-
pendingDeliveries: new Map(),
|
|
846
|
-
};
|
|
847
|
-
this.agentActivityStates.set(name, state);
|
|
848
|
-
return state;
|
|
849
|
-
}
|
|
850
|
-
getDeliveryActivityKey(deliveryId, eventId) {
|
|
851
|
-
return deliveryId || eventId;
|
|
852
|
-
}
|
|
853
|
-
markAgentDeliveryPending(name, deliveryId, eventId, reason) {
|
|
854
|
-
const state = this.ensureAgentActivityState(name);
|
|
855
|
-
state.pendingDeliveries.set(this.getDeliveryActivityKey(deliveryId, eventId), eventId);
|
|
856
|
-
this.setAgentActivity(name, state, state.pendingDeliveries.size > 0, reason, eventId);
|
|
857
|
-
}
|
|
858
|
-
closeAgentDelivery(name, reason, eventId, deliveryId) {
|
|
859
|
-
const state = this.agentActivityStates.get(name);
|
|
860
|
-
if (!state)
|
|
861
|
-
return;
|
|
862
|
-
const key = deliveryId && eventId ? this.getDeliveryActivityKey(deliveryId, eventId) : undefined;
|
|
863
|
-
if (key) {
|
|
864
|
-
state.pendingDeliveries.delete(key);
|
|
865
|
-
}
|
|
866
|
-
else if (eventId) {
|
|
867
|
-
const matchingEntry = Array.from(state.pendingDeliveries.entries()).find(([, pendingEventId]) => {
|
|
868
|
-
return pendingEventId === eventId;
|
|
869
|
-
});
|
|
870
|
-
if (matchingEntry) {
|
|
871
|
-
state.pendingDeliveries.delete(matchingEntry[0]);
|
|
872
|
-
}
|
|
873
|
-
else {
|
|
874
|
-
const oldestKey = state.pendingDeliveries.keys().next().value;
|
|
875
|
-
if (oldestKey) {
|
|
876
|
-
state.pendingDeliveries.delete(oldestKey);
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
|
-
}
|
|
880
|
-
this.setAgentActivity(name, state, state.pendingDeliveries.size > 0, reason, eventId);
|
|
881
|
-
}
|
|
882
|
-
clearAgentDeliveries(name, reason, eventId) {
|
|
883
|
-
const state = this.agentActivityStates.get(name);
|
|
884
|
-
if (!state)
|
|
885
|
-
return;
|
|
886
|
-
state.pendingDeliveries.clear();
|
|
887
|
-
this.setAgentActivity(name, state, false, reason, eventId);
|
|
888
|
-
}
|
|
889
|
-
setAgentActivity(name, state, active, reason, eventId) {
|
|
890
|
-
if (state.active === active) {
|
|
891
|
-
return;
|
|
892
|
-
}
|
|
893
|
-
state.active = active;
|
|
894
|
-
void this.bus.emit('agentActivityChanged', {
|
|
895
|
-
name,
|
|
896
|
-
active,
|
|
897
|
-
pendingDeliveries: state.pendingDeliveries.size,
|
|
898
|
-
reason,
|
|
899
|
-
eventId,
|
|
900
|
-
});
|
|
901
|
-
}
|
|
902
|
-
resolveEventTimestamp(candidate) {
|
|
903
|
-
return typeof candidate === 'number' ? candidate : Date.now();
|
|
904
|
-
}
|
|
905
|
-
addAgentChannels(name, channels) {
|
|
906
|
-
const agent = this.knownAgents.get(name);
|
|
907
|
-
if (!agent || channels.length === 0)
|
|
908
|
-
return;
|
|
909
|
-
const next = [...new Set([...agent.channels, ...channels])];
|
|
910
|
-
agent._setChannels(next);
|
|
911
|
-
}
|
|
912
|
-
removeAgentChannels(name, channels) {
|
|
913
|
-
const agent = this.knownAgents.get(name);
|
|
914
|
-
if (!agent || channels.length === 0)
|
|
915
|
-
return;
|
|
916
|
-
const removed = new Set(channels);
|
|
917
|
-
agent._setChannels(agent.channels.filter((channel) => !removed.has(channel)));
|
|
918
|
-
}
|
|
919
|
-
/** Resolve a target to a channel name. If `to` is `#channel`, use that
|
|
920
|
-
* channel. If it's a known agent name, use the agent's first channel.
|
|
921
|
-
* Otherwise fall back to the relay's default channel. */
|
|
922
|
-
resolveChannel(to) {
|
|
923
|
-
if (to.startsWith('#'))
|
|
924
|
-
return to.slice(1);
|
|
925
|
-
const agent = this.knownAgents.get(to);
|
|
926
|
-
if (agent && agent.channels.length > 0)
|
|
927
|
-
return agent.channels[0];
|
|
928
|
-
return this.defaultChannels[0];
|
|
929
|
-
}
|
|
930
|
-
inferOutputMode(callback) {
|
|
931
|
-
const source = callback.toString().trim().replace(/\s+/g, ' ');
|
|
932
|
-
if (source.startsWith('({') || source.startsWith('async ({') || source.startsWith('function ({')) {
|
|
933
|
-
return 'structured';
|
|
934
|
-
}
|
|
935
|
-
return 'chunk';
|
|
936
|
-
}
|
|
937
|
-
dispatchOutput(name, stream, chunk) {
|
|
938
|
-
const listeners = this.outputListeners.get(name);
|
|
939
|
-
if (!listeners)
|
|
940
|
-
return;
|
|
941
|
-
for (const listener of listeners) {
|
|
942
|
-
if (listener.stream !== undefined && listener.stream !== stream)
|
|
943
|
-
continue;
|
|
944
|
-
if (listener.mode === 'structured') {
|
|
945
|
-
listener.callback({ stream, chunk });
|
|
946
|
-
}
|
|
947
|
-
else {
|
|
948
|
-
listener.callback(chunk);
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
}
|
|
952
|
-
/**
|
|
953
|
-
* Ensure a Relaycast workspace API key is available.
|
|
954
|
-
* Resolution order:
|
|
955
|
-
* 1. Already resolved (cached from a previous call)
|
|
956
|
-
* 2. RELAY_API_KEY in options.env
|
|
957
|
-
* 3. RELAY_API_KEY in process.env
|
|
958
|
-
* 4. Auto-create a fresh workspace via the Relaycast REST API
|
|
959
|
-
*/
|
|
960
|
-
async ensureRelaycastApiKey() {
|
|
961
|
-
if (this.relayApiKey) {
|
|
962
|
-
const workspaceId = this.getResolvedWorkspaceId();
|
|
963
|
-
if (workspaceId) {
|
|
964
|
-
this.applyWorkspaceEnv(workspaceId, this.relayApiKey);
|
|
965
|
-
try {
|
|
966
|
-
this.persistWorkspaceMapping(workspaceId, this.relayApiKey);
|
|
967
|
-
}
|
|
968
|
-
catch {
|
|
969
|
-
/* non-critical */
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
else {
|
|
973
|
-
this.wireRelaycastBaseUrl();
|
|
974
|
-
}
|
|
975
|
-
return;
|
|
976
|
-
}
|
|
977
|
-
const envKey = this.clientOptions.env?.RELAY_API_KEY ?? process.env.RELAY_API_KEY;
|
|
978
|
-
const requestedWorkspaceId = this.requestedWorkspaceId;
|
|
979
|
-
if (requestedWorkspaceId) {
|
|
980
|
-
const registry = this.readWorkspaceRegistry();
|
|
981
|
-
const mappedKey = registry[requestedWorkspaceId]?.relaycastApiKey;
|
|
982
|
-
const resolvedKey = mappedKey ?? envKey ?? (await this.createMappedRelaycastWorkspace(requestedWorkspaceId));
|
|
983
|
-
this.relayApiKey = resolvedKey;
|
|
984
|
-
this.resolvedWorkspaceId = requestedWorkspaceId;
|
|
985
|
-
this.applyWorkspaceEnv(requestedWorkspaceId, resolvedKey);
|
|
986
|
-
try {
|
|
987
|
-
this.persistWorkspaceMapping(requestedWorkspaceId, resolvedKey);
|
|
988
|
-
}
|
|
989
|
-
catch {
|
|
990
|
-
/* non-critical */
|
|
991
|
-
}
|
|
992
|
-
return;
|
|
993
|
-
}
|
|
994
|
-
const resolvedWorkspaceId = envKey
|
|
995
|
-
? (this.findMappedWorkspaceIdByApiKey(envKey) ?? generateWorkspaceId())
|
|
996
|
-
: generateWorkspaceId();
|
|
997
|
-
const resolvedKey = envKey ?? (await this.createMappedRelaycastWorkspace(resolvedWorkspaceId));
|
|
998
|
-
this.relayApiKey = resolvedKey;
|
|
999
|
-
this.resolvedWorkspaceId = resolvedWorkspaceId;
|
|
1000
|
-
this.applyWorkspaceEnv(resolvedWorkspaceId, resolvedKey);
|
|
1001
|
-
try {
|
|
1002
|
-
this.persistWorkspaceMapping(resolvedWorkspaceId, resolvedKey);
|
|
1003
|
-
}
|
|
1004
|
-
catch {
|
|
1005
|
-
/* non-critical */
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
/** Inject relaycastBaseUrl into broker env. Explicit option wins over inherited env. */
|
|
1009
|
-
wireRelaycastBaseUrl() {
|
|
1010
|
-
if (this.relaycastBaseUrl && this.clientOptions.env) {
|
|
1011
|
-
this.clientOptions.env.RELAYCAST_BASE_URL = this.relaycastBaseUrl;
|
|
1012
|
-
}
|
|
1013
|
-
}
|
|
1014
|
-
async ensureStarted() {
|
|
1015
|
-
if (this.client)
|
|
1016
|
-
return this.client;
|
|
1017
|
-
if (this.startPromise)
|
|
1018
|
-
return this.startPromise;
|
|
1019
|
-
this.startPromise = this.ensureRelaycastApiKey()
|
|
1020
|
-
.then(() => AgentRelayClient.spawn({
|
|
1021
|
-
...this.clientOptions,
|
|
1022
|
-
eventBus: this.bus,
|
|
1023
|
-
onStderr: (line) => {
|
|
1024
|
-
for (const listener of this.stderrListeners) {
|
|
1025
|
-
try {
|
|
1026
|
-
listener(line);
|
|
1027
|
-
}
|
|
1028
|
-
catch {
|
|
1029
|
-
/* ignore */
|
|
1030
|
-
}
|
|
1031
|
-
}
|
|
1032
|
-
},
|
|
1033
|
-
}))
|
|
1034
|
-
.then((c) => {
|
|
1035
|
-
// Use the workspace key the broker actually connected with.
|
|
1036
|
-
// This ensures SDK and workers are always on the same workspace.
|
|
1037
|
-
if (c.workspaceKey) {
|
|
1038
|
-
this.relayApiKey = c.workspaceKey;
|
|
1039
|
-
const workspaceId = this.getResolvedWorkspaceId();
|
|
1040
|
-
if (workspaceId) {
|
|
1041
|
-
this.applyWorkspaceEnv(workspaceId, c.workspaceKey);
|
|
1042
|
-
try {
|
|
1043
|
-
this.persistWorkspaceMapping(workspaceId, c.workspaceKey);
|
|
1044
|
-
}
|
|
1045
|
-
catch {
|
|
1046
|
-
/* non-critical */
|
|
1047
|
-
}
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
this.wireEvents(c);
|
|
1051
|
-
this.client = c;
|
|
1052
|
-
this.startPromise = undefined;
|
|
1053
|
-
return c;
|
|
1054
|
-
})
|
|
1055
|
-
.catch((err) => {
|
|
1056
|
-
this.client = undefined;
|
|
1057
|
-
this.startPromise = undefined;
|
|
1058
|
-
throw err;
|
|
1059
|
-
});
|
|
1060
|
-
return this.startPromise;
|
|
1061
|
-
}
|
|
1062
|
-
wireEvents(client) {
|
|
1063
|
-
// eslint-disable-next-line complexity
|
|
1064
|
-
this.unsubEvent = client.onEvent((event) => {
|
|
1065
|
-
switch (event.kind) {
|
|
1066
|
-
case 'relay_inbound': {
|
|
1067
|
-
this.closeAgentDelivery(event.from, 'relay_inbound', event.event_id);
|
|
1068
|
-
if (this.knownAgents.has(event.from)) {
|
|
1069
|
-
this.messageReadyAgents.add(event.from);
|
|
1070
|
-
this.exitedAgents.delete(event.from);
|
|
1071
|
-
}
|
|
1072
|
-
this.clearAgentDeliveries(event.from, 'relay_inbound', event.event_id);
|
|
1073
|
-
const msg = {
|
|
1074
|
-
eventId: event.event_id,
|
|
1075
|
-
from: event.from,
|
|
1076
|
-
to: event.target,
|
|
1077
|
-
text: event.body,
|
|
1078
|
-
threadId: event.thread_id,
|
|
1079
|
-
mode: event.injection_mode ?? event.mode,
|
|
1080
|
-
};
|
|
1081
|
-
void this.bus.emit('messageReceived', msg);
|
|
1082
|
-
break;
|
|
1083
|
-
}
|
|
1084
|
-
case 'agent_spawned': {
|
|
1085
|
-
const agent = this.ensureAgentHandle(event.name, event.runtime);
|
|
1086
|
-
this.readyAgents.delete(event.name);
|
|
1087
|
-
this.messageReadyAgents.delete(event.name);
|
|
1088
|
-
this.exitedAgents.delete(event.name);
|
|
1089
|
-
this.idleAgents.delete(event.name);
|
|
1090
|
-
void this.bus.emit('agentSpawned', agent);
|
|
1091
|
-
break;
|
|
1092
|
-
}
|
|
1093
|
-
case 'agent_released': {
|
|
1094
|
-
const agent = this.knownAgents.get(event.name) ?? this.ensureAgentHandle(event.name, 'pty', []);
|
|
1095
|
-
this.clearAgentDeliveries(event.name, 'agent_released');
|
|
1096
|
-
this.exitedAgents.add(event.name);
|
|
1097
|
-
this.readyAgents.delete(event.name);
|
|
1098
|
-
this.messageReadyAgents.delete(event.name);
|
|
1099
|
-
this.idleAgents.delete(event.name);
|
|
1100
|
-
void this.bus.emit('agentReleased', agent);
|
|
1101
|
-
this.knownAgents.delete(event.name);
|
|
1102
|
-
this.outputListeners.delete(event.name);
|
|
1103
|
-
this.resultContracts.delete(event.name);
|
|
1104
|
-
this.exitResolvers.get(event.name)?.resolve('released');
|
|
1105
|
-
this.exitResolvers.delete(event.name);
|
|
1106
|
-
this.idleResolvers.get(event.name)?.resolve('exited');
|
|
1107
|
-
this.idleResolvers.delete(event.name);
|
|
1108
|
-
for (const waiter of this.takeResultResolvers(event.name)) {
|
|
1109
|
-
waiter.reject(new Error(`Agent '${event.name}' was released before submitting a result`));
|
|
1110
|
-
}
|
|
1111
|
-
break;
|
|
1112
|
-
}
|
|
1113
|
-
case 'agent_exited': {
|
|
1114
|
-
const agent = this.knownAgents.get(event.name) ?? this.ensureAgentHandle(event.name, 'pty', []);
|
|
1115
|
-
this.clearAgentDeliveries(event.name, 'agent_exited');
|
|
1116
|
-
this.exitedAgents.add(event.name);
|
|
1117
|
-
this.readyAgents.delete(event.name);
|
|
1118
|
-
this.messageReadyAgents.delete(event.name);
|
|
1119
|
-
this.idleAgents.delete(event.name);
|
|
1120
|
-
// Populate exit info before firing the hook
|
|
1121
|
-
agent.exitCode = event.code;
|
|
1122
|
-
agent.exitSignal = event.signal;
|
|
1123
|
-
if (event.reason !== undefined) {
|
|
1124
|
-
agent.exitReason = event.reason;
|
|
1125
|
-
}
|
|
1126
|
-
void this.bus.emit('agentExited', agent);
|
|
1127
|
-
this.knownAgents.delete(event.name);
|
|
1128
|
-
this.outputListeners.delete(event.name);
|
|
1129
|
-
this.resultContracts.delete(event.name);
|
|
1130
|
-
this.exitResolvers.get(event.name)?.resolve('exited');
|
|
1131
|
-
this.exitResolvers.delete(event.name);
|
|
1132
|
-
this.idleResolvers.get(event.name)?.resolve('exited');
|
|
1133
|
-
this.idleResolvers.delete(event.name);
|
|
1134
|
-
for (const waiter of this.takeResultResolvers(event.name)) {
|
|
1135
|
-
waiter.reject(new Error(`Agent '${event.name}' exited before submitting a result`));
|
|
1136
|
-
}
|
|
1137
|
-
break;
|
|
1138
|
-
}
|
|
1139
|
-
case 'agent_exit': {
|
|
1140
|
-
const agent = this.knownAgents.get(event.name) ?? this.ensureAgentHandle(event.name, 'pty', []);
|
|
1141
|
-
agent.exitReason = event.reason;
|
|
1142
|
-
void this.bus.emit('agentExitRequested', { name: event.name, reason: event.reason });
|
|
1143
|
-
break;
|
|
1144
|
-
}
|
|
1145
|
-
case 'worker_ready': {
|
|
1146
|
-
const agent = this.ensureAgentHandle(event.name, event.runtime);
|
|
1147
|
-
this.readyAgents.add(event.name);
|
|
1148
|
-
this.exitedAgents.delete(event.name);
|
|
1149
|
-
this.idleAgents.delete(event.name);
|
|
1150
|
-
void this.bus.emit('agentReady', agent);
|
|
1151
|
-
break;
|
|
1152
|
-
}
|
|
1153
|
-
case 'channel_subscribed': {
|
|
1154
|
-
this.addAgentChannels(event.name, event.channels);
|
|
1155
|
-
void this.bus.emit('channelSubscribed', { agent: event.name, channels: event.channels });
|
|
1156
|
-
break;
|
|
1157
|
-
}
|
|
1158
|
-
case 'channel_unsubscribed': {
|
|
1159
|
-
this.removeAgentChannels(event.name, event.channels);
|
|
1160
|
-
void this.bus.emit('channelUnsubscribed', { agent: event.name, channels: event.channels });
|
|
1161
|
-
break;
|
|
1162
|
-
}
|
|
1163
|
-
case 'delivery_queued': {
|
|
1164
|
-
this.markAgentDeliveryPending(event.name, event.delivery_id, event.event_id, 'delivery_queued');
|
|
1165
|
-
this.updateDeliveryState(event.event_id, event.name, 'queued', this.resolveEventTimestamp(event.timestamp));
|
|
1166
|
-
break;
|
|
1167
|
-
}
|
|
1168
|
-
case 'delivery_injected': {
|
|
1169
|
-
this.markAgentDeliveryPending(event.name, event.delivery_id, event.event_id, 'delivery_injected');
|
|
1170
|
-
this.updateDeliveryState(event.event_id, event.name, 'injected', this.resolveEventTimestamp(event.timestamp));
|
|
1171
|
-
break;
|
|
1172
|
-
}
|
|
1173
|
-
case 'delivery_active': {
|
|
1174
|
-
this.markAgentDeliveryPending(event.name, event.delivery_id, event.event_id, 'delivery_active');
|
|
1175
|
-
this.updateDeliveryState(event.event_id, event.name, 'active', this.resolveEventTimestamp());
|
|
1176
|
-
break;
|
|
1177
|
-
}
|
|
1178
|
-
case 'delivery_verified': {
|
|
1179
|
-
this.updateDeliveryState(event.event_id, event.name, 'verified', this.resolveEventTimestamp());
|
|
1180
|
-
break;
|
|
1181
|
-
}
|
|
1182
|
-
case 'delivery_ack': {
|
|
1183
|
-
// No-op for activity tracking. delivery_ack can arrive late, after
|
|
1184
|
-
// relay_inbound / idle / exit already cleared activity, so re-adding
|
|
1185
|
-
// pending state here would incorrectly flip the agent back to active.
|
|
1186
|
-
break;
|
|
1187
|
-
}
|
|
1188
|
-
case 'delivery_failed': {
|
|
1189
|
-
this.closeAgentDelivery(event.name, 'delivery_failed', event.event_id, event.delivery_id);
|
|
1190
|
-
this.updateDeliveryState(event.event_id, event.name, 'failed', this.resolveEventTimestamp());
|
|
1191
|
-
break;
|
|
1192
|
-
}
|
|
1193
|
-
case 'message_delivery_confirmed': {
|
|
1194
|
-
this.closeAgentDelivery(event.name, 'message_delivery_confirmed', event.event_id, event.delivery_id);
|
|
1195
|
-
this.updateDeliveryState(event.event_id, event.name, 'verified', this.resolveEventTimestamp());
|
|
1196
|
-
break;
|
|
1197
|
-
}
|
|
1198
|
-
case 'message_delivery_failed': {
|
|
1199
|
-
if (event.event_id) {
|
|
1200
|
-
this.updateDeliveryState(event.event_id, event.name, 'failed', this.resolveEventTimestamp());
|
|
1201
|
-
}
|
|
1202
|
-
if (event.event_id && event.delivery_id) {
|
|
1203
|
-
this.closeAgentDelivery(event.name, 'message_delivery_failed', event.event_id, event.delivery_id);
|
|
1204
|
-
}
|
|
1205
|
-
break;
|
|
1206
|
-
}
|
|
1207
|
-
case 'worker_stream': {
|
|
1208
|
-
// Agent producing output is no longer idle
|
|
1209
|
-
this.idleAgents.delete(event.name);
|
|
1210
|
-
void this.bus.emit('workerOutput', {
|
|
1211
|
-
name: event.name,
|
|
1212
|
-
stream: event.stream,
|
|
1213
|
-
chunk: event.chunk,
|
|
1214
|
-
});
|
|
1215
|
-
// Dispatch to per-agent output listeners
|
|
1216
|
-
this.dispatchOutput(event.name, event.stream, event.chunk);
|
|
1217
|
-
break;
|
|
1218
|
-
}
|
|
1219
|
-
case 'agent_idle': {
|
|
1220
|
-
this.clearAgentDeliveries(event.name, 'agent_idle');
|
|
1221
|
-
this.idleAgents.add(event.name);
|
|
1222
|
-
void this.bus.emit('agentIdle', {
|
|
1223
|
-
name: event.name,
|
|
1224
|
-
idleSecs: event.idle_secs,
|
|
1225
|
-
});
|
|
1226
|
-
// Resolve idle waiters
|
|
1227
|
-
this.idleResolvers.get(event.name)?.resolve('idle');
|
|
1228
|
-
this.idleResolvers.delete(event.name);
|
|
1229
|
-
break;
|
|
1230
|
-
}
|
|
1231
|
-
case 'agent_result': {
|
|
1232
|
-
this.dispatchAgentResult(event.name, {
|
|
1233
|
-
name: event.name,
|
|
1234
|
-
resultId: event.result_id,
|
|
1235
|
-
data: event.data,
|
|
1236
|
-
final: event.final,
|
|
1237
|
-
metadata: event.metadata ?? undefined,
|
|
1238
|
-
});
|
|
1239
|
-
break;
|
|
1240
|
-
}
|
|
1241
|
-
}
|
|
1242
|
-
if (event.kind.startsWith('delivery_') || event.kind.startsWith('message_delivery_')) {
|
|
1243
|
-
void this.bus.emit('deliveryUpdate', event);
|
|
1244
|
-
}
|
|
1245
|
-
});
|
|
1246
|
-
}
|
|
1247
|
-
prepareAgentResultContract(options) {
|
|
1248
|
-
if (!options) {
|
|
1249
|
-
return undefined;
|
|
1250
|
-
}
|
|
1251
|
-
return {
|
|
1252
|
-
schema: options.schema,
|
|
1253
|
-
jsonSchema: options.jsonSchema ?? this.schemaToJsonSchema(options.schema),
|
|
1254
|
-
onResult: options.onResult,
|
|
1255
|
-
};
|
|
1256
|
-
}
|
|
1257
|
-
schemaToJsonSchema(schema) {
|
|
1258
|
-
if (schema && typeof schema === 'object' && this.isZodSchema(schema)) {
|
|
1259
|
-
return zodToJsonSchema(schema, { target: 'jsonSchema7' });
|
|
1260
|
-
}
|
|
1261
|
-
return true;
|
|
1262
|
-
}
|
|
1263
|
-
isZodSchema(schema) {
|
|
1264
|
-
return '_def' in schema && typeof schema.safeParse === 'function';
|
|
1265
|
-
}
|
|
1266
|
-
validateAgentResult(contract, value) {
|
|
1267
|
-
const schema = contract?.schema;
|
|
1268
|
-
if (!schema) {
|
|
1269
|
-
return value;
|
|
1270
|
-
}
|
|
1271
|
-
if (typeof schema === 'function') {
|
|
1272
|
-
return schema(value);
|
|
1273
|
-
}
|
|
1274
|
-
if (typeof schema.safeParse === 'function') {
|
|
1275
|
-
const parsed = schema.safeParse(value);
|
|
1276
|
-
if (parsed.success) {
|
|
1277
|
-
return parsed.data;
|
|
1278
|
-
}
|
|
1279
|
-
throw new Error(`Agent result failed schema validation: ${String(parsed.error)}`);
|
|
1280
|
-
}
|
|
1281
|
-
if (typeof schema.parse === 'function') {
|
|
1282
|
-
return schema.parse(value);
|
|
1283
|
-
}
|
|
1284
|
-
return value;
|
|
1285
|
-
}
|
|
1286
|
-
takeResultResolvers(name) {
|
|
1287
|
-
const waiters = this.resultResolvers.get(name);
|
|
1288
|
-
if (!waiters || waiters.length === 0)
|
|
1289
|
-
return [];
|
|
1290
|
-
this.resultResolvers.delete(name);
|
|
1291
|
-
return waiters;
|
|
1292
|
-
}
|
|
1293
|
-
dispatchAgentResult(name, raw) {
|
|
1294
|
-
const contract = this.resultContracts.get(name);
|
|
1295
|
-
let result;
|
|
1296
|
-
try {
|
|
1297
|
-
const data = this.validateAgentResult(contract, raw.data);
|
|
1298
|
-
result = { ...raw, data };
|
|
1299
|
-
}
|
|
1300
|
-
catch (error) {
|
|
1301
|
-
const err = error instanceof Error ? error : new Error(String(error));
|
|
1302
|
-
for (const waiter of this.takeResultResolvers(name))
|
|
1303
|
-
waiter.reject(err);
|
|
1304
|
-
console.warn(`[AgentRelay] structured result from "${name}" failed validation`, err);
|
|
1305
|
-
return;
|
|
1306
|
-
}
|
|
1307
|
-
void this.bus.emit('agentResult', result);
|
|
1308
|
-
if (contract?.onResult) {
|
|
1309
|
-
Promise.resolve(contract.onResult(result.data, result)).catch((error) => {
|
|
1310
|
-
console.warn(`[AgentRelay] result("${name}") onResult hook threw`, error);
|
|
1311
|
-
});
|
|
1312
|
-
}
|
|
1313
|
-
if (result.final) {
|
|
1314
|
-
this.lastAgentResults.set(name, result);
|
|
1315
|
-
for (const waiter of this.takeResultResolvers(name))
|
|
1316
|
-
waiter.resolve(result);
|
|
1317
|
-
}
|
|
1318
|
-
}
|
|
1319
|
-
waitForAgentResult(name, timeoutMs) {
|
|
1320
|
-
const existing = this.lastAgentResults.get(name);
|
|
1321
|
-
if (existing) {
|
|
1322
|
-
return Promise.resolve(existing);
|
|
1323
|
-
}
|
|
1324
|
-
// Don't register a waiter for an agent we don't know about and haven't
|
|
1325
|
-
// observed a result for — the resolver would never settle.
|
|
1326
|
-
if (!this.knownAgents.has(name) && !this.resultContracts.has(name)) {
|
|
1327
|
-
return Promise.reject(new Error(`Agent '${name}' is not running and has no structured result`));
|
|
1328
|
-
}
|
|
1329
|
-
if (timeoutMs === 0) {
|
|
1330
|
-
return Promise.reject(new Error(`Timed out waiting for structured result from '${name}'`));
|
|
1331
|
-
}
|
|
1332
|
-
return new Promise((resolve, reject) => {
|
|
1333
|
-
let timer;
|
|
1334
|
-
const token = ++this.resultResolverSeq;
|
|
1335
|
-
const waiter = {
|
|
1336
|
-
resolve: (result) => {
|
|
1337
|
-
if (timer)
|
|
1338
|
-
clearTimeout(timer);
|
|
1339
|
-
resolve(result);
|
|
1340
|
-
},
|
|
1341
|
-
reject: (error) => {
|
|
1342
|
-
if (timer)
|
|
1343
|
-
clearTimeout(timer);
|
|
1344
|
-
reject(error);
|
|
1345
|
-
},
|
|
1346
|
-
token,
|
|
1347
|
-
};
|
|
1348
|
-
const existingWaiters = this.resultResolvers.get(name);
|
|
1349
|
-
if (existingWaiters) {
|
|
1350
|
-
existingWaiters.push(waiter);
|
|
1351
|
-
}
|
|
1352
|
-
else {
|
|
1353
|
-
this.resultResolvers.set(name, [waiter]);
|
|
1354
|
-
}
|
|
1355
|
-
if (timeoutMs !== undefined) {
|
|
1356
|
-
timer = setTimeout(() => {
|
|
1357
|
-
const list = this.resultResolvers.get(name);
|
|
1358
|
-
if (list) {
|
|
1359
|
-
const idx = list.findIndex((w) => w.token === token);
|
|
1360
|
-
if (idx >= 0)
|
|
1361
|
-
list.splice(idx, 1);
|
|
1362
|
-
if (list.length === 0)
|
|
1363
|
-
this.resultResolvers.delete(name);
|
|
1364
|
-
}
|
|
1365
|
-
reject(new Error(`Timed out waiting for structured result from '${name}' after ${timeoutMs}ms`));
|
|
1366
|
-
}, timeoutMs);
|
|
1367
|
-
}
|
|
1368
|
-
});
|
|
1369
|
-
}
|
|
1370
|
-
makeAgent(name, runtime, channels) {
|
|
1371
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
1372
|
-
const relay = this;
|
|
1373
|
-
let agentChannels = [...channels];
|
|
1374
|
-
const agent = {
|
|
1375
|
-
name,
|
|
1376
|
-
runtime,
|
|
1377
|
-
get channels() {
|
|
1378
|
-
return [...agentChannels];
|
|
1379
|
-
},
|
|
1380
|
-
get status() {
|
|
1381
|
-
if (relay.exitedAgents.has(name))
|
|
1382
|
-
return 'exited';
|
|
1383
|
-
if (relay.idleAgents.has(name))
|
|
1384
|
-
return 'idle';
|
|
1385
|
-
if (relay.readyAgents.has(name))
|
|
1386
|
-
return 'ready';
|
|
1387
|
-
return 'spawning';
|
|
1388
|
-
},
|
|
1389
|
-
exitCode: undefined,
|
|
1390
|
-
exitSignal: undefined,
|
|
1391
|
-
async release(reasonOrOptions) {
|
|
1392
|
-
const releaseOptions = relay.normalizeReleaseOptions(reasonOrOptions);
|
|
1393
|
-
const releaseContext = {
|
|
1394
|
-
name,
|
|
1395
|
-
reason: releaseOptions.reason,
|
|
1396
|
-
};
|
|
1397
|
-
if (!relay.knownAgents.has(name)) {
|
|
1398
|
-
await relay.invokeLifecycleHook(releaseOptions.onStart, releaseContext, `release("${name}") onStart`);
|
|
1399
|
-
await relay.invokeLifecycleHook(releaseOptions.onSuccess, releaseContext, `release("${name}") onSuccess`);
|
|
1400
|
-
return;
|
|
1401
|
-
}
|
|
1402
|
-
const client = await relay.ensureStarted();
|
|
1403
|
-
await relay.invokeLifecycleHook(releaseOptions.onStart, releaseContext, `release("${name}") onStart`);
|
|
1404
|
-
try {
|
|
1405
|
-
await client.release(name, releaseOptions.reason);
|
|
1406
|
-
await relay.invokeLifecycleHook(releaseOptions.onSuccess, releaseContext, `release("${name}") onSuccess`);
|
|
1407
|
-
}
|
|
1408
|
-
catch (error) {
|
|
1409
|
-
if (error instanceof AgentRelayProtocolError && error.code === 'agent_not_found') {
|
|
1410
|
-
relay.exitedAgents.add(name);
|
|
1411
|
-
relay.readyAgents.delete(name);
|
|
1412
|
-
relay.messageReadyAgents.delete(name);
|
|
1413
|
-
relay.idleAgents.delete(name);
|
|
1414
|
-
relay.knownAgents.delete(name);
|
|
1415
|
-
relay.outputListeners.delete(name);
|
|
1416
|
-
relay.exitResolvers.get(name)?.resolve('released');
|
|
1417
|
-
relay.exitResolvers.delete(name);
|
|
1418
|
-
relay.idleResolvers.get(name)?.resolve('exited');
|
|
1419
|
-
relay.idleResolvers.delete(name);
|
|
1420
|
-
relay.resultContracts.delete(name);
|
|
1421
|
-
relay.lastAgentResults.delete(name);
|
|
1422
|
-
for (const waiter of relay.takeResultResolvers(name)) {
|
|
1423
|
-
waiter.reject(new Error(`Agent '${name}' was released before submitting a result`));
|
|
1424
|
-
}
|
|
1425
|
-
await relay.invokeLifecycleHook(releaseOptions.onSuccess, releaseContext, `release("${name}") onSuccess`);
|
|
1426
|
-
return;
|
|
1427
|
-
}
|
|
1428
|
-
await relay.invokeLifecycleHook(releaseOptions.onError, {
|
|
1429
|
-
...releaseContext,
|
|
1430
|
-
error,
|
|
1431
|
-
}, `release("${name}") onError`);
|
|
1432
|
-
throw error;
|
|
1433
|
-
}
|
|
1434
|
-
},
|
|
1435
|
-
async waitForReady(timeoutMs = 60_000) {
|
|
1436
|
-
await relay.waitForAgentReady(name, timeoutMs);
|
|
1437
|
-
},
|
|
1438
|
-
waitForExit(timeoutMs) {
|
|
1439
|
-
return new Promise((resolve) => {
|
|
1440
|
-
// If already gone, resolve immediately
|
|
1441
|
-
if (!relay.knownAgents.has(name)) {
|
|
1442
|
-
resolve('exited');
|
|
1443
|
-
return;
|
|
1444
|
-
}
|
|
1445
|
-
// Non-blocking poll: timeoutMs === 0 means "check now, return immediately"
|
|
1446
|
-
if (timeoutMs === 0) {
|
|
1447
|
-
resolve('timeout');
|
|
1448
|
-
return;
|
|
1449
|
-
}
|
|
1450
|
-
let timer;
|
|
1451
|
-
const token = ++relay.exitResolverSeq;
|
|
1452
|
-
relay.exitResolvers.set(name, {
|
|
1453
|
-
resolve(reason) {
|
|
1454
|
-
if (timer)
|
|
1455
|
-
clearTimeout(timer);
|
|
1456
|
-
resolve(reason);
|
|
1457
|
-
},
|
|
1458
|
-
token,
|
|
1459
|
-
});
|
|
1460
|
-
if (timeoutMs !== undefined) {
|
|
1461
|
-
timer = setTimeout(() => {
|
|
1462
|
-
// Only delete if this is still our resolver (not one from a later call)
|
|
1463
|
-
const current = relay.exitResolvers.get(name);
|
|
1464
|
-
if (current?.token === token) {
|
|
1465
|
-
relay.exitResolvers.delete(name);
|
|
1466
|
-
}
|
|
1467
|
-
resolve('timeout');
|
|
1468
|
-
}, timeoutMs);
|
|
1469
|
-
}
|
|
1470
|
-
});
|
|
1471
|
-
},
|
|
1472
|
-
waitForIdle(timeoutMs) {
|
|
1473
|
-
return new Promise((resolve) => {
|
|
1474
|
-
if (!relay.knownAgents.has(name)) {
|
|
1475
|
-
resolve('exited');
|
|
1476
|
-
return;
|
|
1477
|
-
}
|
|
1478
|
-
if (timeoutMs === 0) {
|
|
1479
|
-
resolve('timeout');
|
|
1480
|
-
return;
|
|
1481
|
-
}
|
|
1482
|
-
let timer;
|
|
1483
|
-
const token = ++relay.idleResolverSeq;
|
|
1484
|
-
relay.idleResolvers.set(name, {
|
|
1485
|
-
resolve(reason) {
|
|
1486
|
-
if (timer)
|
|
1487
|
-
clearTimeout(timer);
|
|
1488
|
-
resolve(reason);
|
|
1489
|
-
},
|
|
1490
|
-
token,
|
|
1491
|
-
});
|
|
1492
|
-
if (timeoutMs !== undefined) {
|
|
1493
|
-
timer = setTimeout(() => {
|
|
1494
|
-
const current = relay.idleResolvers.get(name);
|
|
1495
|
-
if (current?.token === token) {
|
|
1496
|
-
relay.idleResolvers.delete(name);
|
|
1497
|
-
}
|
|
1498
|
-
resolve('timeout');
|
|
1499
|
-
}, timeoutMs);
|
|
1500
|
-
}
|
|
1501
|
-
});
|
|
1502
|
-
},
|
|
1503
|
-
waitForResult(timeoutMs) {
|
|
1504
|
-
return relay.waitForAgentResult(name, timeoutMs);
|
|
1505
|
-
},
|
|
1506
|
-
async sendMessage(input) {
|
|
1507
|
-
const client = await relay.ensureStarted();
|
|
1508
|
-
let result;
|
|
1509
|
-
try {
|
|
1510
|
-
result = await client.sendMessage({
|
|
1511
|
-
to: input.to,
|
|
1512
|
-
text: input.text,
|
|
1513
|
-
from: name,
|
|
1514
|
-
threadId: input.threadId,
|
|
1515
|
-
priority: input.priority,
|
|
1516
|
-
data: input.data,
|
|
1517
|
-
mode: input.mode,
|
|
1518
|
-
});
|
|
1519
|
-
}
|
|
1520
|
-
catch (error) {
|
|
1521
|
-
if (isUnsupportedOperation(error)) {
|
|
1522
|
-
return buildUnsupportedOperationMessage(name, input);
|
|
1523
|
-
}
|
|
1524
|
-
throw error;
|
|
1525
|
-
}
|
|
1526
|
-
if (result?.event_id === 'unsupported_operation') {
|
|
1527
|
-
return buildUnsupportedOperationMessage(name, input);
|
|
1528
|
-
}
|
|
1529
|
-
const eventId = result?.event_id ?? randomBytes(8).toString('hex');
|
|
1530
|
-
const msg = {
|
|
1531
|
-
eventId,
|
|
1532
|
-
from: name,
|
|
1533
|
-
to: input.to,
|
|
1534
|
-
text: input.text,
|
|
1535
|
-
threadId: input.threadId,
|
|
1536
|
-
data: input.data,
|
|
1537
|
-
mode: input.mode,
|
|
1538
|
-
};
|
|
1539
|
-
void relay.bus.emit('messageSent', msg);
|
|
1540
|
-
return msg;
|
|
1541
|
-
},
|
|
1542
|
-
async subscribe(channelsToAdd) {
|
|
1543
|
-
await relay.subscribe({ agent: name, channels: channelsToAdd });
|
|
1544
|
-
},
|
|
1545
|
-
async unsubscribe(channelsToRemove) {
|
|
1546
|
-
await relay.unsubscribe({ agent: name, channels: channelsToRemove });
|
|
1547
|
-
},
|
|
1548
|
-
onOutput(callback, options) {
|
|
1549
|
-
let listeners = relay.outputListeners.get(name);
|
|
1550
|
-
if (!listeners) {
|
|
1551
|
-
listeners = new Set();
|
|
1552
|
-
relay.outputListeners.set(name, listeners);
|
|
1553
|
-
}
|
|
1554
|
-
const listener = {
|
|
1555
|
-
callback,
|
|
1556
|
-
mode: options?.mode ?? relay.inferOutputMode(callback),
|
|
1557
|
-
stream: options?.stream,
|
|
1558
|
-
};
|
|
1559
|
-
listeners.add(listener);
|
|
1560
|
-
return () => {
|
|
1561
|
-
listeners.delete(listener);
|
|
1562
|
-
if (listeners.size === 0) {
|
|
1563
|
-
relay.outputListeners.delete(name);
|
|
1564
|
-
}
|
|
1565
|
-
};
|
|
1566
|
-
},
|
|
1567
|
-
_setChannels(nextChannels) {
|
|
1568
|
-
agentChannels = [...nextChannels];
|
|
1569
|
-
},
|
|
1570
|
-
};
|
|
1571
|
-
return agent;
|
|
1572
|
-
}
|
|
1573
|
-
createSpawner(cli, defaultName, runtime) {
|
|
1574
|
-
return {
|
|
1575
|
-
spawn: async (options) => {
|
|
1576
|
-
const name = options?.name ?? defaultName;
|
|
1577
|
-
const channels = options?.channels ?? ['general'];
|
|
1578
|
-
const args = options?.args ?? [];
|
|
1579
|
-
const task = options?.task;
|
|
1580
|
-
if (runtime === 'pty') {
|
|
1581
|
-
return this.spawnPty({
|
|
1582
|
-
name,
|
|
1583
|
-
cli,
|
|
1584
|
-
args,
|
|
1585
|
-
channels,
|
|
1586
|
-
task,
|
|
1587
|
-
model: options?.model,
|
|
1588
|
-
cwd: options?.cwd,
|
|
1589
|
-
idleThresholdSecs: options?.idleThresholdSecs,
|
|
1590
|
-
agentToken: options?.agentToken,
|
|
1591
|
-
skipRelayPrompt: options?.skipRelayPrompt,
|
|
1592
|
-
result: options?.result,
|
|
1593
|
-
onStart: options?.onStart,
|
|
1594
|
-
onSuccess: options?.onSuccess,
|
|
1595
|
-
onError: options?.onError,
|
|
1596
|
-
});
|
|
1597
|
-
}
|
|
1598
|
-
const client = await this.ensureStarted();
|
|
1599
|
-
const lifecycleContext = {
|
|
1600
|
-
name,
|
|
1601
|
-
cli,
|
|
1602
|
-
channels,
|
|
1603
|
-
task,
|
|
1604
|
-
};
|
|
1605
|
-
await this.invokeLifecycleHook(options?.onStart, lifecycleContext, `spawn("${name}") onStart`);
|
|
1606
|
-
let result;
|
|
1607
|
-
const resultContract = this.prepareAgentResultContract(options?.result);
|
|
1608
|
-
if (resultContract) {
|
|
1609
|
-
this.resultContracts.set(name, resultContract);
|
|
1610
|
-
}
|
|
1611
|
-
try {
|
|
1612
|
-
result = await client.spawnProvider({
|
|
1613
|
-
name,
|
|
1614
|
-
provider: cli,
|
|
1615
|
-
transport: 'headless',
|
|
1616
|
-
args,
|
|
1617
|
-
channels,
|
|
1618
|
-
task,
|
|
1619
|
-
model: options?.model,
|
|
1620
|
-
cwd: options?.cwd,
|
|
1621
|
-
idleThresholdSecs: options?.idleThresholdSecs,
|
|
1622
|
-
agentToken: options?.agentToken,
|
|
1623
|
-
skipRelayPrompt: options?.skipRelayPrompt,
|
|
1624
|
-
agentResultSchema: resultContract?.jsonSchema,
|
|
1625
|
-
});
|
|
1626
|
-
}
|
|
1627
|
-
catch (error) {
|
|
1628
|
-
if (resultContract) {
|
|
1629
|
-
this.resultContracts.delete(name);
|
|
1630
|
-
}
|
|
1631
|
-
await this.invokeLifecycleHook(options?.onError, {
|
|
1632
|
-
...lifecycleContext,
|
|
1633
|
-
error,
|
|
1634
|
-
}, `spawn("${name}") onError`);
|
|
1635
|
-
throw error;
|
|
1636
|
-
}
|
|
1637
|
-
this.resetAgentLifecycleState(result.name);
|
|
1638
|
-
if (result.name !== name && resultContract) {
|
|
1639
|
-
this.resultContracts.delete(name);
|
|
1640
|
-
this.resultContracts.set(result.name, resultContract);
|
|
1641
|
-
}
|
|
1642
|
-
const agent = this.makeAgent(result.name, result.runtime, channels);
|
|
1643
|
-
this.knownAgents.set(agent.name, agent);
|
|
1644
|
-
await this.invokeLifecycleHook(options?.onSuccess, {
|
|
1645
|
-
...lifecycleContext,
|
|
1646
|
-
name: result.name,
|
|
1647
|
-
runtime: result.runtime,
|
|
1648
|
-
}, `spawn("${name}") onSuccess`);
|
|
1649
|
-
return agent;
|
|
1650
|
-
},
|
|
1651
|
-
};
|
|
1652
|
-
}
|
|
1653
|
-
async invokeLifecycleHook(hook, context, label) {
|
|
1654
|
-
if (!hook) {
|
|
1655
|
-
return;
|
|
1656
|
-
}
|
|
1657
|
-
try {
|
|
1658
|
-
await hook(context);
|
|
1659
|
-
}
|
|
1660
|
-
catch (error) {
|
|
1661
|
-
console.warn(`[AgentRelay] ${label} hook threw`, error);
|
|
1662
|
-
}
|
|
1663
|
-
}
|
|
1664
|
-
resetAgentLifecycleState(name) {
|
|
1665
|
-
this.readyAgents.delete(name);
|
|
1666
|
-
this.messageReadyAgents.delete(name);
|
|
1667
|
-
this.exitedAgents.delete(name);
|
|
1668
|
-
this.idleAgents.delete(name);
|
|
1669
|
-
this.agentActivityStates.delete(name);
|
|
1670
|
-
this.lastAgentResults.delete(name);
|
|
1671
|
-
for (const waiter of this.takeResultResolvers(name)) {
|
|
1672
|
-
waiter.reject(new Error(`Agent '${name}' lifecycle reset before structured result was submitted`));
|
|
1673
|
-
}
|
|
1674
|
-
}
|
|
1675
|
-
normalizeReleaseOptions(reasonOrOptions) {
|
|
1676
|
-
if (typeof reasonOrOptions === 'string' || reasonOrOptions === undefined) {
|
|
1677
|
-
return { reason: reasonOrOptions };
|
|
1678
|
-
}
|
|
1679
|
-
return reasonOrOptions;
|
|
1680
|
-
}
|
|
1681
|
-
}
|
|
1682
|
-
//# sourceMappingURL=relay.js.map
|