@agent-relay/factory 0.1.40 → 0.1.41

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.
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/orchestrator/factory.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/orchestrator/factory.ts"],"names":[],"mappings":"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"}
@@ -238,6 +238,7 @@ export class FactoryLoop {
238
238
  #agentExitsInFlight = new Map();
239
239
  #agentLifecycleSignalsInFlight = new Map();
240
240
  #startupAgentAdoptionActive = false;
241
+ #startupRosterExitSignals;
241
242
  // Composite issue + PR identities for which a babysitter has already been spawned, so repeated
242
243
  // webhooks / agent-exit safety nets don't respawn it while multi-repository issues retain one
243
244
  // owner per PR.
@@ -2275,20 +2276,7 @@ export class FactoryLoop {
2275
2276
  // after durable records are restored and is the authoritative signal.
2276
2277
  if (this.#startupAgentAdoptionActive)
2277
2278
  return;
2278
- // Broker replay can deliver an old exit immediately when the listener
2279
- // is installed, before durable agents are restored. Queue a later
2280
- // roster-reconciled exit behind it instead of dropping the newer event.
2281
- const previous = this.#agentExitsInFlight.get(name) ?? Promise.resolve();
2282
- const handling = previous
2283
- .catch(() => undefined)
2284
- .then(async () => await this.#handleAgentExit(name, reason))
2285
- .catch((error) => this.#error(error))
2286
- .finally(() => {
2287
- if (this.#agentExitsInFlight.get(name) === handling) {
2288
- this.#agentExitsInFlight.delete(name);
2289
- }
2290
- });
2291
- this.#agentExitsInFlight.set(name, handling);
2279
+ this.#queueAgentExit(name, reason);
2292
2280
  });
2293
2281
  }
2294
2282
  if (!this.#offDeliveryFailed) {
@@ -2317,6 +2305,23 @@ export class FactoryLoop {
2317
2305
  });
2318
2306
  }
2319
2307
  }
2308
+ #queueAgentExit(name, reason) {
2309
+ this.#startupRosterExitSignals?.add(name);
2310
+ // Broker replay can deliver an old exit immediately when the listener is
2311
+ // installed, before durable agents are restored. Queue a later
2312
+ // roster-reconciled exit behind it instead of dropping the newer event.
2313
+ const previous = this.#agentExitsInFlight.get(name) ?? Promise.resolve();
2314
+ const handling = previous
2315
+ .catch(() => undefined)
2316
+ .then(async () => await this.#handleAgentExit(name, reason))
2317
+ .catch((error) => this.#error(error))
2318
+ .finally(() => {
2319
+ if (this.#agentExitsInFlight.get(name) === handling) {
2320
+ this.#agentExitsInFlight.delete(name);
2321
+ }
2322
+ });
2323
+ this.#agentExitsInFlight.set(name, handling);
2324
+ }
2320
2325
  // Durable backends survive orchestrator restarts: re-adopt the agents recorded
2321
2326
  // in the durable lifecycle store, restore their full batch/spec association,
2322
2327
  // then reconcile once so exits that happened while this process was down are
@@ -2325,6 +2330,7 @@ export class FactoryLoop {
2325
2330
  try {
2326
2331
  const batch = await this.#batch();
2327
2332
  const agents = [];
2333
+ const durableAgentNames = new Set();
2328
2334
  let hasNonterminalDurableLifecycle = false;
2329
2335
  const durableLifecycles = await this.#deduplicateQueuedGithubLifecycleAliases(await this.#state.listDispatchLifecycles(this.#workspaceId));
2330
2336
  this.#logger.info?.('[factory] durable startup adoption loaded', {
@@ -2363,6 +2369,7 @@ export class FactoryLoop {
2363
2369
  const node = agent.tracked.result?.node;
2364
2370
  if (invocationId || node || agent.tracked.result) {
2365
2371
  agents.push({ name: agent.name, invocationId, node });
2372
+ durableAgentNames.add(agent.name);
2366
2373
  }
2367
2374
  }
2368
2375
  }
@@ -2392,7 +2399,27 @@ export class FactoryLoop {
2392
2399
  this.#logger.info?.('[factory] durable startup roster reconciliation started', {
2393
2400
  agents: agents.map((agent) => agent.name),
2394
2401
  });
2395
- await this.#fleet.reconcileTrackedAgents?.();
2402
+ this.#startupRosterExitSignals = new Set();
2403
+ try {
2404
+ await this.#fleet.reconcileTrackedAgents?.();
2405
+ const signalled = this.#startupRosterExitSignals;
2406
+ const online = new Set((await this.#fleet.roster()).agents.map((agent) => agent.name));
2407
+ const missing = [...durableAgentNames]
2408
+ .filter((name) => !online.has(name) && !signalled?.has(name));
2409
+ for (const name of missing) {
2410
+ this.#fleet.markAgentTerminal?.(name, 'reconciled-missing');
2411
+ this.#queueAgentExit(name, 'reconciled-missing');
2412
+ }
2413
+ if (missing.length > 0) {
2414
+ this.#increment('startupRosterMissingExitsSynthesized', missing.length);
2415
+ this.#logger.info?.('[factory] synthesized missing durable startup roster exits', {
2416
+ agents: missing,
2417
+ });
2418
+ }
2419
+ }
2420
+ finally {
2421
+ this.#startupRosterExitSignals = undefined;
2422
+ }
2396
2423
  this.#logger.info?.('[factory] durable startup roster reconciliation completed', {
2397
2424
  pendingExits: [...this.#agentExitsInFlight.keys()].filter((name) => agents.some((agent) => agent.name === name)),
2398
2425
  });
@@ -4625,11 +4652,17 @@ export class FactoryLoop {
4625
4652
  }
4626
4653
  return;
4627
4654
  }
4628
- if (tracked.result?.locality === 'remote' && tracked.spec.branch) {
4655
+ // A normal remote exit can race branch replication, so leave it in the
4656
+ // publishing retry loop briefly. Startup reconciliation is different:
4657
+ // the live roster has already proved the hydrated session is gone. If
4658
+ // its retained branch still has nothing publishable, restart the saved
4659
+ // worker instead of consuming an implementation slot forever.
4660
+ if (!tracingReconciledExit && tracked.result?.locality === 'remote' && tracked.spec.branch) {
4629
4661
  this.#scheduleDispatchLifecycleRetry(record);
4630
4662
  return;
4631
4663
  }
4632
4664
  }
4665
+ let recovered = false;
4633
4666
  if (tracked.sessionRef) {
4634
4667
  const resumeKey = `${issueKey(record.issue)}:${name}:${tracked.sessionRef}`;
4635
4668
  if (await this.#state.isResumed(this.#workspaceId, resumeKey)) {
@@ -4653,6 +4686,7 @@ export class FactoryLoop {
4653
4686
  try {
4654
4687
  await resume;
4655
4688
  await this.#state.markResumed(this.#workspaceId, resumeKey);
4689
+ recovered = true;
4656
4690
  }
4657
4691
  catch (error) {
4658
4692
  if (isAgentAlreadyExistsError(error)) {
@@ -4703,6 +4737,7 @@ export class FactoryLoop {
4703
4737
  channel: tracked.spec.channel,
4704
4738
  });
4705
4739
  batch.recordSpawn(record, tracked.spec, invocationId, result);
4740
+ recovered = true;
4706
4741
  }
4707
4742
  catch (error) {
4708
4743
  if (!isAgentAlreadyExistsError(error)) {
@@ -4725,6 +4760,10 @@ export class FactoryLoop {
4725
4760
  }
4726
4761
  }
4727
4762
  }
4763
+ if (recovered && tracked.spec.role === 'implementer') {
4764
+ await this.#writeInFlightRegistry();
4765
+ await this.#saveDispatchLifecycle(record, 'running');
4766
+ }
4728
4767
  }
4729
4768
  catch (error) {
4730
4769
  this.#error(error, record.issue);