agent-relay 2.1.4 → 2.1.6

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.
Files changed (132) hide show
  1. package/README.md +85 -236
  2. package/dist/index.cjs +281 -24
  3. package/package.json +19 -19
  4. package/packages/api-types/package.json +1 -1
  5. package/packages/benchmark/package.json +4 -4
  6. package/packages/bridge/dist/spawner.d.ts.map +1 -1
  7. package/packages/bridge/dist/spawner.js +39 -5
  8. package/packages/bridge/dist/spawner.js.map +1 -1
  9. package/packages/bridge/package.json +8 -8
  10. package/packages/bridge/src/spawner.ts +40 -5
  11. package/packages/cli-tester/package.json +1 -1
  12. package/packages/config/package.json +2 -2
  13. package/packages/continuity/package.json +2 -2
  14. package/packages/daemon/dist/server.d.ts +5 -0
  15. package/packages/daemon/dist/server.d.ts.map +1 -1
  16. package/packages/daemon/dist/server.js +31 -0
  17. package/packages/daemon/dist/server.js.map +1 -1
  18. package/packages/daemon/package.json +12 -12
  19. package/packages/daemon/src/server.ts +37 -0
  20. package/packages/hooks/package.json +4 -4
  21. package/packages/mcp/dist/cloud.d.ts +7 -114
  22. package/packages/mcp/dist/cloud.d.ts.map +1 -1
  23. package/packages/mcp/dist/cloud.js +21 -431
  24. package/packages/mcp/dist/cloud.js.map +1 -1
  25. package/packages/mcp/dist/errors.d.ts +4 -22
  26. package/packages/mcp/dist/errors.d.ts.map +1 -1
  27. package/packages/mcp/dist/errors.js +4 -43
  28. package/packages/mcp/dist/errors.js.map +1 -1
  29. package/packages/mcp/dist/hybrid-client.d.ts.map +1 -1
  30. package/packages/mcp/dist/hybrid-client.js +7 -1
  31. package/packages/mcp/dist/hybrid-client.js.map +1 -1
  32. package/packages/mcp/package.json +4 -3
  33. package/packages/mcp/src/cloud.ts +29 -511
  34. package/packages/mcp/src/errors.ts +12 -49
  35. package/packages/mcp/src/hybrid-client.ts +8 -1
  36. package/packages/mcp/tests/discover.test.ts +72 -11
  37. package/packages/memory/package.json +2 -2
  38. package/packages/policy/package.json +2 -2
  39. package/packages/protocol/dist/types.d.ts +17 -1
  40. package/packages/protocol/dist/types.d.ts.map +1 -1
  41. package/packages/protocol/package.json +1 -1
  42. package/packages/protocol/src/types.ts +23 -0
  43. package/packages/resiliency/package.json +1 -1
  44. package/packages/sdk/dist/browser-client.d.ts +212 -0
  45. package/packages/sdk/dist/browser-client.d.ts.map +1 -0
  46. package/packages/sdk/dist/browser-client.js +750 -0
  47. package/packages/sdk/dist/browser-client.js.map +1 -0
  48. package/packages/sdk/dist/browser-framing.d.ts +46 -0
  49. package/packages/sdk/dist/browser-framing.d.ts.map +1 -0
  50. package/packages/sdk/dist/browser-framing.js +122 -0
  51. package/packages/sdk/dist/browser-framing.js.map +1 -0
  52. package/packages/sdk/dist/client.d.ts +129 -2
  53. package/packages/sdk/dist/client.d.ts.map +1 -1
  54. package/packages/sdk/dist/client.js +312 -2
  55. package/packages/sdk/dist/client.js.map +1 -1
  56. package/packages/sdk/dist/discovery.d.ts +10 -0
  57. package/packages/sdk/dist/discovery.d.ts.map +1 -0
  58. package/packages/sdk/dist/discovery.js +22 -0
  59. package/packages/sdk/dist/discovery.js.map +1 -0
  60. package/packages/sdk/dist/errors.d.ts +9 -0
  61. package/packages/sdk/dist/errors.d.ts.map +1 -0
  62. package/packages/sdk/dist/errors.js +9 -0
  63. package/packages/sdk/dist/errors.js.map +1 -0
  64. package/packages/sdk/dist/index.d.ts +18 -2
  65. package/packages/sdk/dist/index.d.ts.map +1 -1
  66. package/packages/sdk/dist/index.js +27 -1
  67. package/packages/sdk/dist/index.js.map +1 -1
  68. package/packages/sdk/dist/transports/index.d.ts +92 -0
  69. package/packages/sdk/dist/transports/index.d.ts.map +1 -0
  70. package/packages/sdk/dist/transports/index.js +129 -0
  71. package/packages/sdk/dist/transports/index.js.map +1 -0
  72. package/packages/sdk/dist/transports/socket-transport.d.ts +30 -0
  73. package/packages/sdk/dist/transports/socket-transport.d.ts.map +1 -0
  74. package/packages/sdk/dist/transports/socket-transport.js +94 -0
  75. package/packages/sdk/dist/transports/socket-transport.js.map +1 -0
  76. package/packages/sdk/dist/transports/types.d.ts +69 -0
  77. package/packages/sdk/dist/transports/types.d.ts.map +1 -0
  78. package/packages/sdk/dist/transports/types.js +10 -0
  79. package/packages/sdk/dist/transports/types.js.map +1 -0
  80. package/packages/sdk/dist/transports/websocket-transport.d.ts +55 -0
  81. package/packages/sdk/dist/transports/websocket-transport.d.ts.map +1 -0
  82. package/packages/sdk/dist/transports/websocket-transport.js +180 -0
  83. package/packages/sdk/dist/transports/websocket-transport.js.map +1 -0
  84. package/packages/sdk/package.json +28 -4
  85. package/packages/sdk/src/browser-client.ts +985 -0
  86. package/packages/sdk/src/browser-framing.test.ts +115 -0
  87. package/packages/sdk/src/browser-framing.ts +150 -0
  88. package/packages/sdk/src/client.test.ts +425 -0
  89. package/packages/sdk/src/client.ts +397 -3
  90. package/packages/sdk/src/discovery.ts +38 -0
  91. package/packages/sdk/src/errors.ts +17 -0
  92. package/packages/sdk/src/index.ts +82 -1
  93. package/packages/sdk/src/transports/index.ts +197 -0
  94. package/packages/sdk/src/transports/socket-transport.ts +115 -0
  95. package/packages/sdk/src/transports/types.ts +77 -0
  96. package/packages/sdk/src/transports/websocket-transport.ts +245 -0
  97. package/packages/sdk/tsconfig.json +1 -1
  98. package/packages/spawner/package.json +1 -1
  99. package/packages/state/package.json +1 -1
  100. package/packages/storage/package.json +2 -2
  101. package/packages/storage/src/jsonl-adapter.test.ts +8 -3
  102. package/packages/telemetry/package.json +1 -1
  103. package/packages/trajectory/package.json +2 -2
  104. package/packages/user-directory/package.json +2 -2
  105. package/packages/utils/dist/cjs/discovery.js +328 -0
  106. package/packages/utils/dist/cjs/errors.js +81 -0
  107. package/packages/utils/dist/discovery.d.ts +123 -0
  108. package/packages/utils/dist/discovery.d.ts.map +1 -0
  109. package/packages/utils/dist/discovery.js +439 -0
  110. package/packages/utils/dist/discovery.js.map +1 -0
  111. package/packages/utils/dist/errors.d.ts +29 -0
  112. package/packages/utils/dist/errors.d.ts.map +1 -0
  113. package/packages/utils/dist/errors.js +50 -0
  114. package/packages/utils/dist/errors.js.map +1 -0
  115. package/packages/utils/package.json +15 -2
  116. package/packages/utils/src/consolidation.test.ts +125 -0
  117. package/packages/utils/src/discovery.test.ts +196 -0
  118. package/packages/utils/src/discovery.ts +524 -0
  119. package/packages/utils/src/errors.test.ts +83 -0
  120. package/packages/utils/src/errors.ts +56 -0
  121. package/packages/wrapper/dist/opencode-wrapper.d.ts +6 -2
  122. package/packages/wrapper/dist/opencode-wrapper.d.ts.map +1 -1
  123. package/packages/wrapper/dist/opencode-wrapper.js +34 -10
  124. package/packages/wrapper/dist/opencode-wrapper.js.map +1 -1
  125. package/packages/wrapper/dist/relay-pty-orchestrator.d.ts +22 -2
  126. package/packages/wrapper/dist/relay-pty-orchestrator.d.ts.map +1 -1
  127. package/packages/wrapper/dist/relay-pty-orchestrator.js +174 -4
  128. package/packages/wrapper/dist/relay-pty-orchestrator.js.map +1 -1
  129. package/packages/wrapper/package.json +6 -6
  130. package/packages/wrapper/src/opencode-wrapper.ts +37 -9
  131. package/packages/wrapper/src/relay-pty-orchestrator.ts +197 -4
  132. package/relay-snippets/agent-relay-snippet.md +17 -5
package/dist/index.cjs CHANGED
@@ -28161,7 +28161,6 @@ var require_type_overrides = __commonJS({
28161
28161
  var require_pg_connection_string = __commonJS({
28162
28162
  "node_modules/pg-connection-string/index.js"(exports2, module2) {
28163
28163
  "use strict";
28164
- var { emitWarning } = require("process");
28165
28164
  function parse4(str, options = {}) {
28166
28165
  if (str.charAt(0) === "/") {
28167
28166
  const config3 = str.split(" ");
@@ -28324,9 +28323,9 @@ var require_pg_connection_string = __commonJS({
28324
28323
  return toClientConfig(parse4(str));
28325
28324
  }
28326
28325
  function deprecatedSslModeWarning(sslmode) {
28327
- if (!deprecatedSslModeWarning.warned) {
28326
+ if (!deprecatedSslModeWarning.warned && typeof process !== "undefined" && process.emitWarning) {
28328
28327
  deprecatedSslModeWarning.warned = true;
28329
- emitWarning(`SECURITY WARNING: The SSL modes 'prefer', 'require', and 'verify-ca' are treated as aliases for 'verify-full'.
28328
+ process.emitWarning(`SECURITY WARNING: The SSL modes 'prefer', 'require', and 'verify-ca' are treated as aliases for 'verify-full'.
28330
28329
  In the next major version (pg-connection-string v3.0.0 and pg v9.0.0), these modes will adopt standard libpq semantics, which have weaker security guarantees.
28331
28330
 
28332
28331
  To prepare for this change:
@@ -30352,7 +30351,7 @@ var require_client = __commonJS({
30352
30351
  if (error2) {
30353
30352
  reject(error2);
30354
30353
  } else {
30355
- resolve5();
30354
+ resolve5(this);
30356
30355
  }
30357
30356
  });
30358
30357
  });
@@ -30519,16 +30518,40 @@ var require_client = __commonJS({
30519
30518
  activeQuery.handleError(msg, this.connection);
30520
30519
  }
30521
30520
  _handleRowDescription(msg) {
30522
- this._getActiveQuery().handleRowDescription(msg);
30521
+ const activeQuery = this._getActiveQuery();
30522
+ if (activeQuery == null) {
30523
+ const error2 = new Error("Received unexpected rowDescription message from backend.");
30524
+ this._handleErrorEvent(error2);
30525
+ return;
30526
+ }
30527
+ activeQuery.handleRowDescription(msg);
30523
30528
  }
30524
30529
  _handleDataRow(msg) {
30525
- this._getActiveQuery().handleDataRow(msg);
30530
+ const activeQuery = this._getActiveQuery();
30531
+ if (activeQuery == null) {
30532
+ const error2 = new Error("Received unexpected dataRow message from backend.");
30533
+ this._handleErrorEvent(error2);
30534
+ return;
30535
+ }
30536
+ activeQuery.handleDataRow(msg);
30526
30537
  }
30527
30538
  _handlePortalSuspended(msg) {
30528
- this._getActiveQuery().handlePortalSuspended(this.connection);
30539
+ const activeQuery = this._getActiveQuery();
30540
+ if (activeQuery == null) {
30541
+ const error2 = new Error("Received unexpected portalSuspended message from backend.");
30542
+ this._handleErrorEvent(error2);
30543
+ return;
30544
+ }
30545
+ activeQuery.handlePortalSuspended(this.connection);
30529
30546
  }
30530
30547
  _handleEmptyQuery(msg) {
30531
- this._getActiveQuery().handleEmptyQuery(this.connection);
30548
+ const activeQuery = this._getActiveQuery();
30549
+ if (activeQuery == null) {
30550
+ const error2 = new Error("Received unexpected emptyQuery message from backend.");
30551
+ this._handleErrorEvent(error2);
30552
+ return;
30553
+ }
30554
+ activeQuery.handleEmptyQuery(this.connection);
30532
30555
  }
30533
30556
  _handleCommandComplete(msg) {
30534
30557
  const activeQuery = this._getActiveQuery();
@@ -30551,10 +30574,22 @@ var require_client = __commonJS({
30551
30574
  }
30552
30575
  }
30553
30576
  _handleCopyInResponse(msg) {
30554
- this._getActiveQuery().handleCopyInResponse(this.connection);
30577
+ const activeQuery = this._getActiveQuery();
30578
+ if (activeQuery == null) {
30579
+ const error2 = new Error("Received unexpected copyInResponse message from backend.");
30580
+ this._handleErrorEvent(error2);
30581
+ return;
30582
+ }
30583
+ activeQuery.handleCopyInResponse(this.connection);
30555
30584
  }
30556
30585
  _handleCopyData(msg) {
30557
- this._getActiveQuery().handleCopyData(msg, this.connection);
30586
+ const activeQuery = this._getActiveQuery();
30587
+ if (activeQuery == null) {
30588
+ const error2 = new Error("Received unexpected copyData message from backend.");
30589
+ this._handleErrorEvent(error2);
30590
+ return;
30591
+ }
30592
+ activeQuery.handleCopyData(msg, this.connection);
30558
30593
  }
30559
30594
  _handleNotification(msg) {
30560
30595
  this.emit("notification", msg);
@@ -31368,7 +31403,7 @@ var require_client2 = __commonJS({
31368
31403
  });
31369
31404
  self2.emit("connect");
31370
31405
  self2._pulseQueryQueue(true);
31371
- cb();
31406
+ cb(null, this);
31372
31407
  });
31373
31408
  });
31374
31409
  };
@@ -31382,7 +31417,7 @@ var require_client2 = __commonJS({
31382
31417
  if (error2) {
31383
31418
  reject(error2);
31384
31419
  } else {
31385
- resolve5();
31420
+ resolve5(this);
31386
31421
  }
31387
31422
  });
31388
31423
  });
@@ -46309,6 +46344,54 @@ var __filename2 = (0, import_node_url2.fileURLToPath)(import_meta_url);
46309
46344
  var __dirname2 = (0, import_node_path11.dirname)(__filename2);
46310
46345
  var MAX_SOCKET_PATH_LENGTH = 107;
46311
46346
  var MAX_OUTPUT_BUFFER_SIZE = 10 * 1024 * 1024;
46347
+ var ACTIVITY_VERIFICATION = {
46348
+ /** Time to wait for activity patterns after injection (ms) */
46349
+ TIMEOUT_MS: 5e3,
46350
+ /** How often to check for activity patterns (ms) */
46351
+ POLL_INTERVAL_MS: 200,
46352
+ /** Maximum retries when no activity is detected */
46353
+ MAX_RETRIES: 3,
46354
+ /** Delay between retries (ms) */
46355
+ RETRY_DELAY_MS: 500,
46356
+ /**
46357
+ * Patterns indicating the task was received and displayed.
46358
+ * These are the primary verification patterns.
46359
+ */
46360
+ TASK_RECEIVED_PATTERNS: [
46361
+ /\[Pasted text #\d+/,
46362
+ // Claude Code shows "[Pasted text #1 +95 lines]"
46363
+ /› Relay message from/,
46364
+ // Codex shows "› Relay message from"
46365
+ /Relay message from \w+ \[[\w-]+\]/
46366
+ // Droid/Gemini shows "Relay message from Agent [id]:"
46367
+ ],
46368
+ /**
46369
+ * Patterns indicating the CLI is thinking/processing.
46370
+ * Secondary verification - proves the CLI is active.
46371
+ */
46372
+ THINKING_PATTERNS: [
46373
+ /\(.*esc to (?:interrupt|stop)\)/i,
46374
+ // All CLIs: "(esc to interrupt)" or "(Press ESC to stop)"
46375
+ /[✻✶✳✢·✽⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏]/,
46376
+ // Spinner characters (Claude + Droid)
46377
+ /Thinking\.\.\./,
46378
+ // Droid: "Thinking..."
46379
+ /Working/,
46380
+ // Codex: "Working"
46381
+ /Forming|Noodling|Manifesting/i
46382
+ // Claude Code thinking states
46383
+ ],
46384
+ /**
46385
+ * Patterns indicating tool execution started.
46386
+ * Tertiary verification - proves the CLI is working.
46387
+ */
46388
+ TOOL_EXECUTION_PATTERNS: [
46389
+ /⏺\s*(Bash|Read|Write|Edit|Glob|Grep|Task|WebFetch)/,
46390
+ // Claude Code tool markers
46391
+ /•\s*Running/
46392
+ // Codex: "• Running: command"
46393
+ ]
46394
+ };
46312
46395
  function hashWorkspaceId(workspaceId) {
46313
46396
  return (0, import_node_crypto9.createHash)("sha256").update(workspaceId).digest("hex").slice(0, 12);
46314
46397
  }
@@ -46331,6 +46414,7 @@ var RelayPtyOrchestrator = class extends BaseWrapper {
46331
46414
  outputBuffer = "";
46332
46415
  rawBuffer = "";
46333
46416
  lastParsedLength = 0;
46417
+ bufferTrimCount = 0;
46334
46418
  // Interactive mode (show output to terminal)
46335
46419
  isInteractive = false;
46336
46420
  // Injection state
@@ -46879,13 +46963,19 @@ Stderr: ${stderrBuffer.slice(0, 500)}` : "";
46879
46963
  this.rawBuffer += data;
46880
46964
  this.outputBuffer += data;
46881
46965
  this.hasReceivedOutput = true;
46966
+ let buffersTrimmed = false;
46882
46967
  if (this.rawBuffer.length > MAX_OUTPUT_BUFFER_SIZE) {
46883
46968
  const trimAmount = this.rawBuffer.length - MAX_OUTPUT_BUFFER_SIZE;
46884
46969
  this.rawBuffer = this.rawBuffer.slice(-MAX_OUTPUT_BUFFER_SIZE);
46885
46970
  this.lastParsedLength = Math.max(0, this.lastParsedLength - trimAmount);
46971
+ buffersTrimmed = true;
46886
46972
  }
46887
46973
  if (this.outputBuffer.length > MAX_OUTPUT_BUFFER_SIZE) {
46888
46974
  this.outputBuffer = this.outputBuffer.slice(-MAX_OUTPUT_BUFFER_SIZE);
46975
+ buffersTrimmed = true;
46976
+ }
46977
+ if (buffersTrimmed) {
46978
+ this.bufferTrimCount += 1;
46889
46979
  }
46890
46980
  this.feedIdleDetectorOutput(data);
46891
46981
  const indicator = this.formatUnreadIndicator();
@@ -48129,14 +48219,103 @@ Then output: \`->relay-file:spawn\`
48129
48219
  this.relayPtyProcess.stdin.write(buffer);
48130
48220
  }
48131
48221
  /**
48132
- * Inject a task using the socket-based injection system with verification.
48222
+ * Verify that the CLI shows activity after task injection.
48223
+ * Checks output for patterns indicating the task was received and processing started.
48224
+ *
48225
+ * This catches the race condition where PTY write succeeds but CLI wasn't ready
48226
+ * (the T-003 failure scenario where CLI showed bell characters instead of processing).
48227
+ *
48228
+ * @param outputBefore The output buffer content before injection
48229
+ * @returns Promise resolving to true if activity detected, false otherwise
48230
+ */
48231
+ async verifyActivityAfterInjection(outputBefore) {
48232
+ const startTime = Date.now();
48233
+ const { TIMEOUT_MS, POLL_INTERVAL_MS, TASK_RECEIVED_PATTERNS, THINKING_PATTERNS, TOOL_EXECUTION_PATTERNS } = ACTIVITY_VERIFICATION;
48234
+ const trimCountBefore = this.bufferTrimCount;
48235
+ while (Date.now() - startTime < TIMEOUT_MS) {
48236
+ if (this.bufferTrimCount !== trimCountBefore) {
48237
+ this.log(` Activity verified: output buffer trimmed during verification (large output)`);
48238
+ return true;
48239
+ }
48240
+ const currentOutput = this.outputBuffer;
48241
+ const newOutput = currentOutput.slice(outputBefore.length);
48242
+ if (newOutput.length > 0) {
48243
+ const belCount = (newOutput.match(/\x07/g) || []).length;
48244
+ if (belCount > 10) {
48245
+ this.logError(` Input rejected: CLI produced ${belCount} BEL characters`);
48246
+ return false;
48247
+ }
48248
+ for (const pattern of TASK_RECEIVED_PATTERNS) {
48249
+ if (pattern.test(newOutput)) {
48250
+ this.log(` Activity verified: task received pattern matched`);
48251
+ return true;
48252
+ }
48253
+ }
48254
+ for (const pattern of THINKING_PATTERNS) {
48255
+ if (pattern.test(newOutput)) {
48256
+ this.log(` Activity verified: thinking pattern matched`);
48257
+ return true;
48258
+ }
48259
+ }
48260
+ for (const pattern of TOOL_EXECUTION_PATTERNS) {
48261
+ if (pattern.test(newOutput)) {
48262
+ this.log(` Activity verified: tool execution pattern matched`);
48263
+ return true;
48264
+ }
48265
+ }
48266
+ const meaningfulOutput = newOutput.replace(/[\x00-\x1f]/g, "");
48267
+ if (meaningfulOutput.length > 100) {
48268
+ this.log(` Activity verified: significant output growth (${meaningfulOutput.length} meaningful chars)`);
48269
+ return true;
48270
+ }
48271
+ }
48272
+ await sleep(POLL_INTERVAL_MS);
48273
+ }
48274
+ this.log(` No activity detected within ${TIMEOUT_MS}ms`);
48275
+ return false;
48276
+ }
48277
+ /**
48278
+ * Inject a task using the socket-based injection system with activity verification.
48133
48279
  * This is the preferred method for spawned agent task delivery.
48134
48280
  *
48281
+ * After socket confirms delivery, verifies the CLI shows activity (task received,
48282
+ * thinking indicators, or tool execution). Retries if no activity is detected.
48283
+ *
48135
48284
  * @param task The task text to inject
48136
48285
  * @param from The sender name (default: "spawner")
48137
- * @returns Promise resolving to true if injection succeeded, false otherwise
48286
+ * @returns Promise resolving to true if task was delivered AND activity verified, false otherwise
48138
48287
  */
48139
48288
  async injectTask(task, from = "spawner") {
48289
+ const { MAX_RETRIES, RETRY_DELAY_MS } = ACTIVITY_VERIFICATION;
48290
+ const STABILIZATION_DELAY_MS = 1500;
48291
+ this.log(` Waiting ${STABILIZATION_DELAY_MS}ms for CLI stabilization before task injection`);
48292
+ await sleep(STABILIZATION_DELAY_MS);
48293
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
48294
+ if (attempt > 0) {
48295
+ this.log(` Retry ${attempt}/${MAX_RETRIES} - waiting ${RETRY_DELAY_MS}ms before retry`);
48296
+ await sleep(RETRY_DELAY_MS);
48297
+ }
48298
+ const outputBefore = this.outputBuffer;
48299
+ const delivered = await this.performTaskInjection(task, from);
48300
+ if (!delivered) {
48301
+ this.logError(` Task delivery failed on attempt ${attempt + 1}`);
48302
+ continue;
48303
+ }
48304
+ const activityVerified = await this.verifyActivityAfterInjection(outputBefore);
48305
+ if (activityVerified) {
48306
+ this.log(` Task delivered and activity verified successfully`);
48307
+ return true;
48308
+ }
48309
+ this.logError(` Task delivered but no activity detected (attempt ${attempt + 1})`);
48310
+ }
48311
+ this.logError(` Task injection failed after ${MAX_RETRIES + 1} attempts - no CLI activity detected`);
48312
+ return false;
48313
+ }
48314
+ /**
48315
+ * Perform a single task injection attempt (without retry logic).
48316
+ * @returns true if the injection was sent successfully, false otherwise
48317
+ */
48318
+ async performTaskInjection(task, from) {
48140
48319
  if (!this.socket || !this.socketConnected) {
48141
48320
  this.log(` Socket not connected for task injection, falling back to stdin write`);
48142
48321
  try {
@@ -48389,6 +48568,12 @@ var openCodeApi = new OpenCodeApi();
48389
48568
 
48390
48569
  // packages/wrapper/dist/opencode-wrapper.js
48391
48570
  var import_node_child_process4 = require("node:child_process");
48571
+ var TASK_INJECTION = {
48572
+ /** Maximum retries when injection fails */
48573
+ MAX_RETRIES: 3,
48574
+ /** Delay between retries (ms) */
48575
+ RETRY_DELAY_MS: 500
48576
+ };
48392
48577
  var OpenCodeWrapper = class extends BaseWrapper {
48393
48578
  config;
48394
48579
  // OpenCode API client
@@ -48644,19 +48829,32 @@ var OpenCodeWrapper = class extends BaseWrapper {
48644
48829
  }
48645
48830
  }
48646
48831
  /**
48647
- * Inject a task into the agent
48832
+ * Inject a task into the agent with retry logic.
48833
+ *
48834
+ * Retries on transient failures to match RelayPtyOrchestrator behavior.
48835
+ * This ensures consistent reliability across all wrapper types.
48836
+ *
48648
48837
  * @param task - The task description to inject
48649
48838
  * @param _from - The sender name (used for formatting)
48650
- * @returns true if injection succeeded
48839
+ * @returns true if injection succeeded, false otherwise
48651
48840
  */
48652
48841
  async injectTask(task, _from) {
48653
- try {
48654
- await this.performInjection(task);
48655
- return true;
48656
- } catch (error2) {
48657
- console.error("[OpenCodeWrapper] Task injection failed:", error2);
48658
- return false;
48842
+ const { MAX_RETRIES, RETRY_DELAY_MS } = TASK_INJECTION;
48843
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
48844
+ if (attempt > 0) {
48845
+ console.log(`[OpenCodeWrapper] Retry ${attempt}/${MAX_RETRIES} - waiting ${RETRY_DELAY_MS}ms before retry`);
48846
+ await sleep(RETRY_DELAY_MS);
48847
+ }
48848
+ try {
48849
+ await this.performInjection(task);
48850
+ console.log(`[OpenCodeWrapper] Task delivered successfully${attempt > 0 ? ` (attempt ${attempt + 1})` : ""}`);
48851
+ return true;
48852
+ } catch (error2) {
48853
+ console.error(`[OpenCodeWrapper] Task delivery failed (attempt ${attempt + 1}/${MAX_RETRIES + 1}):`, error2);
48854
+ }
48659
48855
  }
48856
+ console.error(`[OpenCodeWrapper] Task injection failed after ${MAX_RETRIES + 1} attempts`);
48857
+ return false;
48660
48858
  }
48661
48859
  /**
48662
48860
  * Get output lines (for compatibility with spawner)
@@ -65364,8 +65562,9 @@ ${relayInstructions}`;
65364
65562
  }
65365
65563
  if (task && task.trim()) {
65366
65564
  const ready = await openCodeWrapper.waitUntilReadyForMessages(2e4, 100);
65565
+ let taskSent = false;
65367
65566
  if (ready) {
65368
- const taskSent = await openCodeWrapper.injectTask(task, spawnerName || "spawner");
65567
+ taskSent = await openCodeWrapper.injectTask(task, spawnerName || "spawner");
65369
65568
  if (!taskSent) {
65370
65569
  log3.warn(`Failed to inject task for ${name} via OpenCodeWrapper`);
65371
65570
  } else if (debug) {
@@ -65374,6 +65573,25 @@ ${relayInstructions}`;
65374
65573
  } else {
65375
65574
  log3.warn(`OpenCodeWrapper ${name} not ready for task injection`);
65376
65575
  }
65576
+ if (!taskSent) {
65577
+ const tracedError = createTraceableError("Task injection failed", {
65578
+ agentName: name,
65579
+ cli,
65580
+ taskLength: task.length,
65581
+ ready
65582
+ });
65583
+ log3.error(`CRITICAL: ${tracedError.logMessage}`);
65584
+ await openCodeWrapper.stop();
65585
+ if (this.onClearSpawning) {
65586
+ this.onClearSpawning(name);
65587
+ }
65588
+ return {
65589
+ success: false,
65590
+ name,
65591
+ error: tracedError.userMessage,
65592
+ errorId: tracedError.errorId
65593
+ };
65594
+ }
65377
65595
  }
65378
65596
  const workerInfo2 = {
65379
65597
  name,
@@ -65514,7 +65732,7 @@ ${relayInstructions}`;
65514
65732
  log3.debug(`Task injected to ${name} (attempt ${attempt})`);
65515
65733
  break;
65516
65734
  } else {
65517
- throw new Error("Task injection returned false");
65735
+ throw new Error("Task injection returned false - delivery failed");
65518
65736
  }
65519
65737
  } catch (err) {
65520
65738
  log3.debug(`Attempt ${attempt}/${maxRetries}: Error injecting task for ${name}: ${err.message}`);
@@ -65531,6 +65749,17 @@ ${relayInstructions}`;
65531
65749
  taskLength: task.length
65532
65750
  });
65533
65751
  log3.error(`CRITICAL: ${tracedError.logMessage}`);
65752
+ await pty.stop();
65753
+ this.activeWorkers.delete(name);
65754
+ if (this.onClearSpawning) {
65755
+ this.onClearSpawning(name);
65756
+ }
65757
+ return {
65758
+ success: false,
65759
+ name,
65760
+ error: tracedError.userMessage,
65761
+ errorId: tracedError.errorId
65762
+ };
65534
65763
  }
65535
65764
  }
65536
65765
  const workerInfo = {
@@ -73037,6 +73266,9 @@ var Daemon = class _Daemon {
73037
73266
  }
73038
73267
  this.notifyCloudSync();
73039
73268
  this.writeConnectedAgentsFile();
73269
+ if (connection.agentName) {
73270
+ this.broadcastAgentReady(connection);
73271
+ }
73040
73272
  };
73041
73273
  connection.onClose = () => {
73042
73274
  daemonLog.debug("Connection closed", { agent: connection.agentName ?? connection.id });
@@ -73610,6 +73842,31 @@ var Daemon = class _Daemon {
73610
73842
  broadcastSystemMessage(message, data) {
73611
73843
  this.router.broadcastSystemMessage(message, data);
73612
73844
  }
73845
+ /**
73846
+ * Broadcast AGENT_READY event when an agent completes connection.
73847
+ * This allows spawning clients to know when their spawned agent is ready to receive messages.
73848
+ */
73849
+ broadcastAgentReady(connection) {
73850
+ const payload = {
73851
+ name: connection.agentName,
73852
+ cli: connection.cli,
73853
+ task: connection.task,
73854
+ connectedAt: Date.now()
73855
+ };
73856
+ const envelope = {
73857
+ v: PROTOCOL_VERSION,
73858
+ type: "AGENT_READY",
73859
+ id: generateId2(),
73860
+ ts: Date.now(),
73861
+ payload
73862
+ };
73863
+ for (const conn of this.connections) {
73864
+ if (conn.id !== connection.id && conn.state === "ACTIVE") {
73865
+ conn.send(envelope);
73866
+ }
73867
+ }
73868
+ daemonLog.info("Broadcast AGENT_READY", { agent: connection.agentName });
73869
+ }
73613
73870
  /**
73614
73871
  * Get connection count.
73615
73872
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-relay",
3
- "version": "2.1.4",
3
+ "version": "2.1.6",
4
4
  "description": "Real-time agent-to-agent communication system",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -130,25 +130,25 @@
130
130
  },
131
131
  "homepage": "https://github.com/AgentWorkforce/relay#readme",
132
132
  "dependencies": {
133
- "@agent-relay/bridge": "2.1.4",
134
- "@agent-relay/config": "2.1.4",
135
- "@agent-relay/continuity": "2.1.4",
136
- "@agent-relay/daemon": "2.1.4",
137
- "@agent-relay/hooks": "2.1.4",
138
- "@agent-relay/mcp": "2.1.4",
139
- "@agent-relay/protocol": "2.1.4",
140
- "@agent-relay/resiliency": "2.1.4",
141
- "@agent-relay/sdk": "2.1.4",
142
- "@agent-relay/spawner": "2.1.4",
143
- "@agent-relay/state": "2.1.4",
144
- "@agent-relay/storage": "2.1.4",
145
- "@agent-relay/telemetry": "2.1.4",
146
- "@agent-relay/trajectory": "2.1.4",
147
- "@agent-relay/user-directory": "2.1.4",
148
- "@agent-relay/utils": "2.1.4",
149
- "@agent-relay/wrapper": "2.1.4",
133
+ "@agent-relay/bridge": "2.1.6",
134
+ "@agent-relay/config": "2.1.6",
135
+ "@agent-relay/continuity": "2.1.6",
136
+ "@agent-relay/daemon": "2.1.6",
137
+ "@agent-relay/hooks": "2.1.6",
138
+ "@agent-relay/mcp": "2.1.6",
139
+ "@agent-relay/protocol": "2.1.6",
140
+ "@agent-relay/resiliency": "2.1.6",
141
+ "@agent-relay/sdk": "2.1.6",
142
+ "@agent-relay/spawner": "2.1.6",
143
+ "@agent-relay/state": "2.1.6",
144
+ "@agent-relay/storage": "2.1.6",
145
+ "@agent-relay/telemetry": "2.1.6",
146
+ "@agent-relay/trajectory": "2.1.6",
147
+ "@agent-relay/user-directory": "2.1.6",
148
+ "@agent-relay/utils": "2.1.6",
149
+ "@agent-relay/wrapper": "2.1.6",
150
150
  "@modelcontextprotocol/sdk": "^1.0.0",
151
- "agent-trajectories": "^0.2.3",
151
+ "agent-trajectories": "^0.3.0",
152
152
  "chokidar": "^5.0.0",
153
153
  "commander": "^12.1.0",
154
154
  "compare-versions": "^6.1.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/api-types",
3
- "version": "2.1.4",
3
+ "version": "2.1.6",
4
4
  "description": "Shared API types and Zod schemas for Agent Relay",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/benchmark",
3
- "version": "2.1.4",
3
+ "version": "2.1.6",
4
4
  "description": "Performance benchmarking for agent swarms, sub-agents, and single agents using Harbor",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -54,9 +54,9 @@
54
54
  "directory": "packages/benchmark"
55
55
  },
56
56
  "dependencies": {
57
- "@agent-relay/sdk": "2.1.4",
58
- "@agent-relay/protocol": "2.1.4",
59
- "@agent-relay/spawner": "2.1.4",
57
+ "@agent-relay/sdk": "2.1.6",
58
+ "@agent-relay/protocol": "2.1.6",
59
+ "@agent-relay/spawner": "2.1.6",
60
60
  "commander": "^12.1.0",
61
61
  "yaml": "^2.3.4"
62
62
  },
@@ -1 +1 @@
1
- {"version":3,"file":"spawner.d.ts","sourceRoot":"","sources":["../src/spawner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"spawner.d.ts","sourceRoot":"","sources":["../src/spawner.ts"],"names":[],"mappings":"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"}
@@ -962,8 +962,9 @@ export class AgentSpawner {
962
962
  // Send task to the newly spawned agent if provided
963
963
  if (task && task.trim()) {
964
964
  const ready = await openCodeWrapper.waitUntilReadyForMessages(20000, 100);
965
+ let taskSent = false;
965
966
  if (ready) {
966
- const taskSent = await openCodeWrapper.injectTask(task, spawnerName || 'spawner');
967
+ taskSent = await openCodeWrapper.injectTask(task, spawnerName || 'spawner');
967
968
  if (!taskSent) {
968
969
  log.warn(`Failed to inject task for ${name} via OpenCodeWrapper`);
969
970
  }
@@ -974,6 +975,27 @@ export class AgentSpawner {
974
975
  else {
975
976
  log.warn(`OpenCodeWrapper ${name} not ready for task injection`);
976
977
  }
978
+ // If task injection failed, kill the agent and return error
979
+ // An agent without its task is useless and will just sit idle
980
+ if (!taskSent) {
981
+ const tracedError = createTraceableError('Task injection failed', {
982
+ agentName: name,
983
+ cli,
984
+ taskLength: task.length,
985
+ ready,
986
+ });
987
+ log.error(`CRITICAL: ${tracedError.logMessage}`);
988
+ await openCodeWrapper.stop();
989
+ if (this.onClearSpawning) {
990
+ this.onClearSpawning(name);
991
+ }
992
+ return {
993
+ success: false,
994
+ name,
995
+ error: tracedError.userMessage,
996
+ errorId: tracedError.errorId,
997
+ };
998
+ }
977
999
  }
978
1000
  // Track the worker (cast to AgentWrapper for type compatibility)
979
1001
  const workerInfo = {
@@ -1133,7 +1155,7 @@ export class AgentSpawner {
1133
1155
  // Fallback for older wrapper types
1134
1156
  await pty.waitUntilCliReady(15000, 100);
1135
1157
  }
1136
- // Inject task via socket (with verification and retries)
1158
+ // Inject task via socket (relay-pty confirms write)
1137
1159
  const success = await pty.injectTask(task, spawnerName || 'spawner');
1138
1160
  if (success) {
1139
1161
  taskSent = true;
@@ -1142,7 +1164,8 @@ export class AgentSpawner {
1142
1164
  break;
1143
1165
  }
1144
1166
  else {
1145
- throw new Error('Task injection returned false');
1167
+ // Delivery failed - safe to retry
1168
+ throw new Error('Task injection returned false - delivery failed');
1146
1169
  }
1147
1170
  }
1148
1171
  catch (err) {
@@ -1162,8 +1185,19 @@ export class AgentSpawner {
1162
1185
  taskLength: task.length,
1163
1186
  });
1164
1187
  log.error(`CRITICAL: ${tracedError.logMessage}`);
1165
- // Note: We don't return an error here because the agent is running,
1166
- // but we track the errorId so support can investigate if user reports it
1188
+ // Kill the agent since it's useless without its task - it will just sit idle
1189
+ // Return an error so the caller knows the spawn effectively failed
1190
+ await pty.stop();
1191
+ this.activeWorkers.delete(name);
1192
+ if (this.onClearSpawning) {
1193
+ this.onClearSpawning(name);
1194
+ }
1195
+ return {
1196
+ success: false,
1197
+ name,
1198
+ error: tracedError.userMessage,
1199
+ errorId: tracedError.errorId,
1200
+ };
1167
1201
  }
1168
1202
  }
1169
1203
  // Track the worker