agents-relay 1.0.117 → 1.0.119

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
@@ -6,10 +6,10 @@ export function buildCodexArgs(route, input) {
6
6
  const args = ['exec', '--json'];
7
7
  if (route.profile)
8
8
  args.push('-p', route.profile);
9
+ else if (route.provider)
10
+ args.push('-p', route.provider);
9
11
  if (route.model)
10
12
  args.push('-m', route.model);
11
- if (route.provider)
12
- args.push('-c', `model_provider=${route.provider}`);
13
13
  if (route.reasoning)
14
14
  args.push('-c', `model_reasoning_effort=${route.reasoning}`);
15
15
  if (route.cwd)
@@ -7,6 +7,7 @@ import { workflowEffectFailureEvent } from './workflow/contracts.js';
7
7
  export function executionEventSource(jobId, taskId, executionId) { return `job/${jobId}/task/${taskId}/execution/${executionId}`; }
8
8
  function eventSourceId(event) { return typeof event.source?.id === 'string' ? event.source.id : undefined; }
9
9
  const terminalExecutionClaims = new Set();
10
+ const activeExecutionOwners = new Map();
10
11
  function claimTerminalExecution(sourceId) {
11
12
  terminalExecutionClaims.add(sourceId);
12
13
  const cleanup = setTimeout(() => terminalExecutionClaims.delete(sourceId), 60000);
@@ -61,6 +62,12 @@ export class ReconcilerRuntimeBase {
61
62
  }
62
63
  }
63
64
  async handleEvent(event) {
65
+ const sourceId = eventSourceId(event);
66
+ const activeOwner = sourceId ? activeExecutionOwners.get(sourceId) : undefined;
67
+ if (activeOwner && activeOwner !== this) {
68
+ await activeOwner.handleEvent(event);
69
+ return;
70
+ }
64
71
  if (event.type === 'task.started') {
65
72
  await this.markWorkerStarted(event);
66
73
  return;
@@ -87,10 +94,13 @@ export class ReconcilerRuntimeBase {
87
94
  return async () => { };
88
95
  }
89
96
  }
90
- async idle() { while (this.live.size > 0 || this.plannerLive.size > 0 || this.continuationLive.size > 0 || this.reconciling)
97
+ async idle() { while ([...this.live.values()].some(item => !item.processSettled) || this.plannerLive.size > 0 || this.continuationLive.size > 0 || this.reconciling)
91
98
  await new Promise(resolve => setTimeout(resolve, 25)); }
92
99
  async close() {
93
100
  for (const live of this.live.values()) {
101
+ const sourceId = executionEventSource(live.jobId, live.taskId, live.executionId);
102
+ if (activeExecutionOwners.get(sourceId) === this)
103
+ activeExecutionOwners.delete(sourceId);
94
104
  live.controller.abort();
95
105
  live.execution.cancel();
96
106
  }
@@ -144,10 +154,19 @@ export class ReconcilerRuntimeBase {
144
154
  clearTimeout(timer); await unsubscribe(); };
145
155
  return { ack, stop };
146
156
  }
157
+ registerExecutionOwner(jobId, taskId, executionId) {
158
+ activeExecutionOwners.set(executionEventSource(jobId, taskId, executionId), this);
159
+ }
147
160
  clearExecution(taskId, executionId) {
148
161
  const live = this.live.get(taskId);
149
- if (!executionId || live?.executionId === executionId)
162
+ if (!executionId || live?.executionId === executionId) {
163
+ if (live) {
164
+ const sourceId = executionEventSource(live.jobId, live.taskId, live.executionId);
165
+ if (activeExecutionOwners.get(sourceId) === this)
166
+ activeExecutionOwners.delete(sourceId);
167
+ }
150
168
  this.live.delete(taskId);
169
+ }
151
170
  const timer = this.terminalTimers.get(taskId);
152
171
  if (timer)
153
172
  clearTimeout(timer);
@@ -228,7 +247,7 @@ export class ReconcilerRuntimeBase {
228
247
  const live = this.live.get(taskId);
229
248
  const liveWorkerStarted = live?.executionId === executionId && live.workerStarted;
230
249
  if (live?.executionId === executionId)
231
- this.live.delete(taskId);
250
+ live.processSettled = true;
232
251
  const job = await this.store.load(jobId);
233
252
  const task = job.tasks.find(item => item.id === taskId);
234
253
  const workerStarted = liveWorkerStarted || task?.state === 'RUNNING';
@@ -249,6 +268,12 @@ export class ReconcilerRuntimeBase {
249
268
  async failUnexpectedExit(jobId, taskId, executionId, workerStarted) {
250
269
  if (terminalExecutionClaimed(jobId, taskId, executionId))
251
270
  return;
271
+ const current = await this.store.load(jobId);
272
+ const currentTask = current.tasks.find(item => item.id === taskId);
273
+ if (!currentTask || currentTask.executionId !== executionId || ['SUCCEEDED', 'FAILED', 'BLOCKED', 'CANCELLED'].includes(currentTask.state)) {
274
+ this.clearExecution(taskId, executionId);
275
+ return;
276
+ }
252
277
  const reason = workerStarted ? 'worker_exit_without_terminal_event' : 'worker_exit_before_start';
253
278
  const message = workerStarted
254
279
  ? `Worker ${taskId} exited after task.started without publishing a terminal task event`
@@ -419,7 +419,8 @@ export class Reconciler extends ReconcilerReviewBase {
419
419
  void (execution.launched ?? Promise.resolve()).then(() => this.emit(eventFor(job.id, task.id, task.parentTaskId, 'task.process.launched', 'running', `Task ${task.id} process launched`, 'user', { adapter: adapter.id, model: task.routing?.model }, { agent: 'relay', component: 'agents-relay' }))).catch(error => this.failLaunch(job.id, task.id, durableExecutionId, error instanceof Error ? error.message : String(error), 'launch'));
420
420
  if (startAckSetup)
421
421
  void startAckSetup.ack.finally(() => { void startAckSetup.stop(); }).catch(() => { });
422
- this.live.set(task.id, { jobId: job.id, taskId: task.id, executionId: durableExecutionId, execution, controller, launchBarrier: Date.now(), workerStarted: false });
422
+ this.live.set(task.id, { jobId: job.id, taskId: task.id, executionId: durableExecutionId, execution, controller, launchBarrier: Date.now(), workerStarted: false, processSettled: false });
423
+ this.registerExecutionOwner(job.id, task.id, durableExecutionId);
423
424
  const terminalTimer = setTimeout(() => {
424
425
  this.detach(this.timeoutTask(job.id, task.id, durableExecutionId), job.id, task.id, 'worker terminal-event timeout');
425
426
  }, Math.max(1, task.timeoutMs));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agents-relay",
3
- "version": "1.0.117",
3
+ "version": "1.0.119",
4
4
  "description": "Durable async agent jobs coordinated through GitHub pull requests",
5
5
  "type": "module",
6
6
  "bin": {