agents-relay 2.0.66 → 2.0.67

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/dist/adapters.js CHANGED
@@ -146,7 +146,7 @@ export function parseDriverJson(output) {
146
146
  throw new Error('browser-worker driver returned no submitted receipt');
147
147
  }
148
148
  function browserWorkspaceCli(override = process.env.AGENTS_RELAY_BROWSER_WORKSPACE_COMMAND) {
149
- return override ? { command: override, prefix: [] } : { command: 'npx', prefix: ['browser-workspace'] };
149
+ return override ? { command: override, prefix: [] } : { command: 'uvx', prefix: ['browser-workspace'] };
150
150
  }
151
151
  function browserWorkspaceCommand(cli, args, stdin, signal) {
152
152
  return new Promise((resolve, reject) => {
@@ -110,8 +110,16 @@ export class ReconcilerRuntimeBase {
110
110
  return activeOwner.applyEvent(event);
111
111
  if (event.type === 'task.started')
112
112
  return this.markWorkerStarted(event);
113
- if (['task.completed', 'task.failed', 'task.blocked', 'task.cancelled'].includes(event.type))
114
- return this.applyTerminalEvent(event);
113
+ if (['task.completed', 'task.failed', 'task.blocked', 'task.cancelled'].includes(event.type)) {
114
+ const result = await this.applyTerminalEvent(event);
115
+ if (event.type !== 'task.failed' || event.source?.watchdog !== true || event.data?.workflowEvent !== 'watchdog.failed' || result.reconcile)
116
+ return result;
117
+ // The watchdog has already committed FAILED. The graph owns the recovery
118
+ // action; this correlated event wakes the graph evaluation, not a retry.
119
+ const durable = (await this.store.load(event.job_id)).tasks.find(task => task.id === event.task_id);
120
+ return durable?.state === 'FAILED' && durable.executionHistory?.some(history => history.id === event.data?.executionId)
121
+ ? { applied: true, reconcile: true, reason: 'watchdog.failure-fact' } : result;
122
+ }
115
123
  if (['review.started', 'review.approved', 'review.changes_required', 'review.blocked'].includes(event.type))
116
124
  return this.applyReviewEvent(event);
117
125
  if (event.type === 'job.wake' || event.type === 'github.webhook')
@@ -285,7 +293,7 @@ export class ReconcilerRuntimeBase {
285
293
  return;
286
294
  if (task.adapter !== 'chatgpt' && task.executionId === executionId && live?.executionId === executionId)
287
295
  rearmTerminalEventDeadline(this.terminalTimers, taskId, task.timeoutMs - (Date.now() - live.launchBarrier), this.options.postExitTerminalGraceMs ?? 15_000, () => this.detach(this.timeoutTask(jobId, taskId, executionId), jobId, taskId, 'post-exit terminal event timeout'));
288
- await this.emit(eventFor(jobId, taskId, task.parentTaskId, task.adapter === 'chatgpt' ? 'task.process.async_exited' : 'task.process.exited', live?.execution.processExit ? (live.execution.processExit.exitCode === 0 ? 'succeeded' : 'failed') : (error ? 'failed' : 'succeeded'), result?.summary ?? (live?.execution.processExit?.terminationReason === 'parent-shutdown' ? 'Worker interrupted by daemon shutdown' : error ? 'Worker runtime exited with error' : 'Worker runtime exited'), 'orchestrator', { authoritative: false, waitingForTerminalEvent: true, exitCode: live?.execution.processExit?.exitCode ?? null,
296
+ await this.emit(eventFor(jobId, taskId, task.parentTaskId, task.adapter === 'chatgpt' ? 'task.process.async_exited' : 'task.process.exited', live?.execution.processExit ? (live.execution.processExit.exitCode === 0 ? 'succeeded' : 'failed') : (error ? 'failed' : 'succeeded'), result?.summary ?? (live?.execution.processExit?.terminationReason === 'parent-shutdown' ? 'Worker interrupted by daemon shutdown' : error ? `Worker exited: ${error}${live?.execution.processExit ? ` (exit=${live.execution.processExit.exitCode ?? 'null'}${live.execution.processExit.signal ? ` signal=${live.execution.processExit.signal}` : ''})` : ''}` : 'Worker runtime exited'), 'orchestrator', { authoritative: false, waitingForTerminalEvent: true, exitCode: live?.execution.processExit?.exitCode ?? null,
289
297
  signal: live?.execution.processExit?.signal ?? null, terminationReason: live?.execution.processExit?.terminationReason ?? null, stderr: live?.execution.processExit?.stderr ?? '', processError: error, executionId, pid: live?.execution.pid ?? null }, { id: executionEventSource(jobId, taskId, executionId), agent: 'relay', component: 'agents-relay' }));
290
298
  }
291
299
  async timeoutTask(jobId, taskId, executionId) {
@@ -313,7 +321,7 @@ export class ReconcilerRuntimeBase {
313
321
  this.clearExecution(taskId, executionId);
314
322
  return;
315
323
  }
316
- const event = eventFor(jobId, taskId, transition.task.parentTaskId, 'task.failed', 'failed', transition.task.error ?? failureMessage, 'user', { reason: failureReason, exitCode: exit?.exitCode ?? null, signal: exit?.signal ?? null, timeoutMs: transition.task.timeoutMs, workflowEvent: 'watchdog.failed' }, { agent: 'relay', component: 'agents-relay', watchdog: true });
324
+ const event = eventFor(jobId, taskId, transition.task.parentTaskId, 'task.failed', 'failed', transition.task.error ?? failureMessage, 'user', { reason: failureReason, exitCode: exit?.exitCode ?? null, signal: exit?.signal ?? null, timeoutMs: transition.task.timeoutMs, workflowEvent: 'watchdog.failed', executionId }, { agent: 'relay', component: 'agents-relay', watchdog: true });
317
325
  await this.emit(event);
318
326
  // Provider quota failures are recoverable. Drop the stale selection so the
319
327
  // next launch runs the normal worker/model router with fresh usage data.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agents-relay",
3
- "version": "2.0.66",
3
+ "version": "2.0.67",
4
4
  "description": "Durable async agent jobs coordinated through GitHub pull requests",
5
5
  "type": "module",
6
6
  "bin": {