@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":"AAIA,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAI1E,OAAO,KAAK,EAMV,WAAW,EASX,WAAW,EAKZ,MAAM,UAAU,CAAA;AAiCjB,OAAO,KAAK,EACV,cAAc,EACd,OAAO,EACP,mBAAmB,EACnB,YAAY,EACZ,aAAa,EACb,mBAAmB,EAEnB,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EAGnB,QAAQ,EACR,eAAe,EACf,WAAW,EAGX,cAAc,EAEf,MAAM,UAAU,CAAA;AA4BjB,KAAK,YAAY,GAAG,cAAc,GAAG,YAAY,GAAG,YAAY,GAAG,oBAAoB,GAAG,OAAO,CAAA;AACjG,KAAK,QAAQ,GAAG,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAA;AAoFtD,KAAK,iBAAiB,GAAG;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC7B,CAAA;AA8FD,eAAO,MAAM,mCAAmC,iDAAiD,CAAA;AACjG,eAAO,MAAM,kCAAkC,gDAAgD,CAAA;AAQ/F,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAEjF;AAED,qBAAa,WAAY,YAAW,OAAO;;
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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);
|