agents-relay 2.0.103 → 2.0.104
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/planner.js +1 -1
- package/dist/pool.js +2 -2
- package/dist/unblock.js +9 -0
- package/dist/workflow/planner-orchestration-v2.js +2 -2
- package/package.json +1 -1
package/dist/planner.js
CHANGED
|
@@ -25,7 +25,7 @@ function plannerTrigger(job, manual = false) {
|
|
|
25
25
|
const unblocked = job.tasks.filter(task => ['DRAFT', 'QUEUED', 'UNBLOCKED'].includes(task.state) && task.unblock && !consumed.has(task.id));
|
|
26
26
|
const hasUnblock = unblocked.length > 0 || Boolean(job.changeCycle && !job.changeCycle.consumedByPlannerTaskId);
|
|
27
27
|
const decision = dispatchPlannerTrigger({
|
|
28
|
-
manualPlan: manual,
|
|
28
|
+
manualPlan: manual && !hasUnblock,
|
|
29
29
|
hasUnblock,
|
|
30
30
|
scheduledRun: Boolean(job.schedule?.currentRunSlot),
|
|
31
31
|
initialPlan: (job.plans?.length ?? 0) === 0 && !job.tasks.some(task => task.kind === 'planner'),
|
package/dist/pool.js
CHANGED
|
@@ -5,7 +5,7 @@ import { scheduleBucket } from './scheduler.js';
|
|
|
5
5
|
import { ReconcileCoordinator } from './reconcile-coordinator.js';
|
|
6
6
|
import { errorMessage, observability, withObservabilityCorrelation } from './observability.js';
|
|
7
7
|
import { jobHasActiveExecution } from './job-execution-slot.js';
|
|
8
|
-
import {
|
|
8
|
+
import { unblockNeedsNewPlan } from './unblock.js';
|
|
9
9
|
const RANK = { P0: 0, P1: 1, P2: 2, P3: 3 };
|
|
10
10
|
export function compareJobPriority(a, b) { return RANK[a.priority ?? 'P2'] - RANK[b.priority ?? 'P2'] || a.createdAt.localeCompare(b.createdAt) || a.id.localeCompare(b.id); }
|
|
11
11
|
export function runnableManagedJobs(items) { return items.filter(item => item.job.state === 'ACTIVE').map(item => item.job).sort(compareJobPriority); }
|
|
@@ -13,7 +13,7 @@ export function needsLifecycleReconciliation(job, now = Date.now()) {
|
|
|
13
13
|
// DRAFT create-only Jobs stay dormant until a caller explicitly creates work.
|
|
14
14
|
if (job.tasks.length === 0)
|
|
15
15
|
return false;
|
|
16
|
-
if (job.executionMode === 'autonomous' &&
|
|
16
|
+
if (job.executionMode === 'autonomous' && unblockNeedsNewPlan(job))
|
|
17
17
|
return true;
|
|
18
18
|
if (job.tasks.some(task => (task.state === 'QUEUED' && task.executionId === null)
|
|
19
19
|
|| (task.state === 'RUNNING' && task.adapter === 'orchestrator' && task.executionId === null)
|
package/dist/unblock.js
CHANGED
|
@@ -45,6 +45,15 @@ export function unconsumedUnblockTrigger(job) {
|
|
|
45
45
|
unblockSource: records[0].source,
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
|
+
/** A failed Planner round keeps the unblock pending, but must not spin up endless rounds. */
|
|
49
|
+
export function unblockNeedsNewPlan(job) {
|
|
50
|
+
const pending = unconsumedUnblockTrigger(job);
|
|
51
|
+
if (!pending)
|
|
52
|
+
return false;
|
|
53
|
+
const latest = job.plans?.at(-1);
|
|
54
|
+
return !(latest?.status === 'FAILED' && latest.trigger.source === 'unblock'
|
|
55
|
+
&& latest.trigger.taskIds?.some(id => pending.taskIds?.includes(id)));
|
|
56
|
+
}
|
|
48
57
|
export async function unblockAutonomousTasks(options) {
|
|
49
58
|
const { store, job, trigger } = options;
|
|
50
59
|
const tasks = options.tasks.filter(isEffectivelyBlocked);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { GraphRuntime } from './graph-v2.js';
|
|
3
3
|
import { dispatchWorkflowGraph, dispatchWorkflowGraphSync } from './dispatcher.js';
|
|
4
|
-
import { isEffectivelyBlocked, unconsumedUnblockTrigger } from '../unblock.js';
|
|
4
|
+
import { isEffectivelyBlocked, unblockNeedsNewPlan, unconsumedUnblockTrigger } from '../unblock.js';
|
|
5
5
|
const source = readFileSync(new URL('../../workflow/planner-orchestration.mmd', import.meta.url), 'utf8');
|
|
6
6
|
const boolGuard = (name) => (facts) => facts.durableFacts[name] === true;
|
|
7
7
|
export const plannerOrchestrationV2 = new GraphRuntime(source, {
|
|
@@ -50,7 +50,7 @@ export function plannerOrchestrationFacts(job, recoverablePendingPlan) {
|
|
|
50
50
|
legacyPlanningPending: job.initialPlanning?.status === 'pending',
|
|
51
51
|
recoverablePendingPlan,
|
|
52
52
|
hasSeedWork: !((job.plans?.length ?? 0) === 0 && job.tasks.filter(task => task.kind !== 'planner').length === 0),
|
|
53
|
-
noActivePlanner: !scopedPlans.some(plan => plan.status === 'PLANNING'),
|
|
53
|
+
noActivePlanner: unblockNeedsNewPlan(job) || !unconsumedUnblockTrigger(job) ? !scopedPlans.some(plan => plan.status === 'PLANNING') : false,
|
|
54
54
|
noBlockedWork: Boolean(unconsumedUnblockTrigger(job)) || !scopedTasks.some(task => task.kind !== 'planner' && isEffectivelyBlocked(task)),
|
|
55
55
|
noActiveImplementation: !scopedTasks.some(task => task.kind !== 'planner' && (['QUEUED', 'RUNNING'].includes(task.state) || (task.state === 'DRAFT' && !task.unblock))),
|
|
56
56
|
resolutionOwnedByTroubleshooter: scopedTasks.some(task => task.kind !== 'planner' && task.resolution?.owner === 'troubleshooter' && ['active', 'waiting'].includes(task.resolution.state)),
|