@desplega.ai/agent-swarm 1.114.0 → 1.115.0
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/{actions-bm8vdxys.js → actions-17ya5wde.js} +6 -6
- package/dist/{app-bhwdxmvp.js → app-4f718yk0.js} +4 -4
- package/dist/{assistant-15mp2apr.js → assistant-ah7csnjz.js} +9 -9
- package/dist/{boot-reembed-awr2179r.js → boot-reembed-4jpxhb25.js} +4 -4
- package/dist/{boot-reembed-b9sbk87z.js → boot-reembed-qata34xa.js} +3 -3
- package/dist/{boot-scrub-logs-c1zsaw9m.js → boot-scrub-logs-tv48nn3z.js} +2 -2
- package/dist/{claude-adapter-2k45y7p7.js → claude-adapter-3csn5bks.js} +2 -2
- package/dist/{cli-zmmp2r79.js → cli-12vb0xg6.js} +13 -2
- package/dist/{cli-jzwtn8rm.js → cli-15y7qhzp.js} +188 -18
- package/dist/{cli-w3nq88yc.js → cli-3samkyap.js} +2 -2
- package/dist/{cli-7rgh0w0k.js → cli-52fg7s7x.js} +10 -3
- package/dist/{cli-5afkmcfj.js → cli-65ekje01.js} +6 -6
- package/dist/{cli-113wmegp.js → cli-6aq8xhvm.js} +1 -1
- package/dist/{cli-byjcad11.js → cli-7xje5amz.js} +1 -1
- package/dist/{cli-0kgcv878.js → cli-86fdnerz.js} +63 -2
- package/dist/{cli-f5pzfvwb.js → cli-b23axgz4.js} +1 -1
- package/dist/{cli-a0t7vapf.js → cli-bc89my0z.js} +1 -1
- package/dist/{cli-q4e2x252.js → cli-beea4a3y.js} +73 -24
- package/dist/{cli-w4wk3kx6.js → cli-cchksf5q.js} +2 -2
- package/dist/{cli-f9n2jg31.js → cli-cmw9rzy5.js} +2 -2
- package/dist/{cli-hvg05qwm.js → cli-cnwssmsr.js} +1 -1
- package/dist/{cli-2t4e4ayk.js → cli-dcca6j8m.js} +46 -5
- package/dist/{cli-tkmm5nf9.js → cli-e61fs2hp.js} +59 -2
- package/dist/{cli-e2xbxmhd.js → cli-hrhye2rm.js} +90 -32
- package/dist/{cli-312v3c41.js → cli-k3y4z3h5.js} +1 -1
- package/dist/{cli-6xd0bvf8.js → cli-ma04faw5.js} +1 -1
- package/dist/{cli-ggy8c7tk.js → cli-mnbgv3w7.js} +1 -1
- package/dist/{cli-hq39e630.js → cli-pet3aev6.js} +95 -10
- package/dist/{cli-a6tzw6vq.js → cli-q1rx7g0d.js} +6 -6
- package/dist/{cli-pnfyyp6h.js → cli-r9f6ngrf.js} +6 -3
- package/dist/{cli-q1z5d5ss.js → cli-shvaxw27.js} +4 -4
- package/dist/{cli-49j095n9.js → cli-t0vqevnm.js} +1 -1
- package/dist/{cli-k6h2zkw3.js → cli-tece6zgm.js} +1 -1
- package/dist/{cli-5ktc9fd4.js → cli-tffvrh6j.js} +1 -1
- package/dist/cli-wh91zby6.js +187222 -0
- package/dist/{cli-r3mtrrzp.js → cli-zsrdty74.js} +12 -12
- package/dist/cli.js +10 -10
- package/dist/{codex-adapter-4z8m9mb5.js → codex-adapter-de3w0nch.js} +2 -2
- package/dist/{codex-session-runner-rbct46dg.js → codex-session-runner-bnw8cysk.js} +2 -2
- package/dist/{commands-zk4d6esf.js → commands-hch4e2k1.js} +2 -2
- package/dist/{db-stn16jp2.js → db-p3h2j06x.js} +12 -2
- package/dist/{handlers-gshprvpf.js → handlers-9er4zx9q.js} +9 -9
- package/dist/{hook-amzx9tap.js → hook-4axs756z.js} +1 -1
- package/dist/{http-6g0hfzax.js → http-809fvtz2.js} +182 -65
- package/dist/{index-ty42rxw9.js → index-47em3d2n.js} +10 -10
- package/dist/{index-jbm7qcqk.js → index-9fqaktjr.js} +8 -8
- package/dist/{index-f03rnnrs.js → index-9ht8gr56.js} +9 -9
- package/dist/{index-df8fmphk.js → index-rm85cfdx.js} +331 -30
- package/dist/{keepalive-pm6g2wpw.js → keepalive-3cps6e3e.js} +4 -4
- package/dist/{lead-h79fzpzw.js → lead-fkk95wgq.js} +24 -24
- package/dist/{maintenance-433zndy1.js → maintenance-fweqh0yj.js} +4 -4
- package/dist/{oauth-refresh-sweep-mjsbmsk2.js → oauth-refresh-sweep-sycqtbph.js} +3 -3
- package/dist/{onboard-vdr9hc3f.js → onboard-cy0rkgvx.js} +2 -2
- package/dist/{opencode-adapter-mqsxr170.js → opencode-adapter-p6bxnbm4.js} +2 -2
- package/dist/{otel-impl-yswd0fty.js → otel-impl-wbns8hf7.js} +1 -1
- package/dist/{pi-mono-adapter-vbrvg1p8.js → pi-mono-adapter-05sck1ds.js} +1 -1
- package/dist/{pricing-refresh-2kk2ap9b.js → pricing-refresh-0hvazmkf.js} +4 -4
- package/dist/{rbac-roles-xdc5208b.js → rbac-roles-kfesjy9y.js} +4 -4
- package/dist/{rbac-roles-2wgh9b5t.js → rbac-roles-mwcwhbxc.js} +11 -4
- package/dist/{seed-pricing-m9h69d2t.js → seed-pricing-h2kdq4cq.js} +3 -3
- package/dist/{setup-eynkvafa.js → setup-8506q97w.js} +2 -2
- package/dist/{worker-136q8dc2.js → worker-4r5c6zyb.js} +24 -24
- package/openapi.json +8 -4
- package/package.json +1 -1
- package/src/be/db.ts +253 -20
- package/src/be/migrations/113_task_routing_affinity.sql +9 -0
- package/src/be/migrations/114_backfill_gpt_5_6_pricing.sql +15 -0
- package/src/be/modelsdev-cache.json +135 -0
- package/src/be/rbac-audit.ts +19 -8
- package/src/be/rbac-roles.ts +8 -1
- package/src/be/script-connections.ts +4 -4
- package/src/be/scripts/typecheck.ts +11 -0
- package/src/be/seed-scripts/catalog/catalog-report.inline.ts +325 -24
- package/src/be/seed-scripts/catalog/catalog-report.ts +325 -24
- package/src/heartbeat/heartbeat.ts +143 -21
- package/src/http/favorites.ts +1 -5
- package/src/http/mcp-servers.ts +38 -0
- package/src/http/poll.ts +7 -2
- package/src/http/scripts.ts +6 -0
- package/src/http/skills.ts +11 -0
- package/src/http/tasks.ts +21 -9
- package/src/providers/codex-models.ts +100 -30
- package/src/providers/modelsdev-reasoning.json +51 -0
- package/src/providers/reasoning-effort.ts +11 -5
- package/src/rbac/admission.ts +26 -2
- package/src/rbac/index.ts +2 -2
- package/src/rbac/legacy-policy.ts +9 -0
- package/src/rbac/permissions.ts +36 -0
- package/src/scripts-runtime/api-client.ts +82 -6
- package/src/scripts-runtime/types/swarm-sdk.d.ts +11 -0
- package/src/server-user.ts +114 -59
- package/src/slack/responses.ts +91 -1
- package/src/slack/watcher.ts +9 -6
- package/src/tasks/worker-follow-up.ts +100 -3
- package/src/tests/codex-adapter.test.ts +46 -23
- package/src/tests/heartbeat.test.ts +48 -3
- package/src/tests/model-control.test.ts +8 -2
- package/src/tests/pool-affinity.test.ts +401 -0
- package/src/tests/rbac-admission-e2e.test.ts +152 -7
- package/src/tests/rbac-admission.test.ts +60 -1
- package/src/tests/rbac-engine.test.ts +9 -0
- package/src/tests/rbac-mcp-admission-e2e.test.ts +362 -0
- package/src/tests/rbac-roles.test.ts +2 -0
- package/src/tests/reasoning-effort.test.ts +15 -2
- package/src/tests/script-apis-mcp.test.ts +37 -13
- package/src/tests/script-connections.test.ts +27 -1
- package/src/tests/scripts-runtime.test.ts +187 -0
- package/src/tests/seed-scripts.test.ts +36 -0
- package/src/tests/slack-inline-output.test.ts +65 -0
- package/src/tests/user-token-rest-auth.test.ts +110 -0
- package/src/tools/script-apis.ts +62 -3
- package/src/tools/send-task.ts +15 -1
- package/src/tools/task-action.ts +34 -2
- package/src/tools/templates.ts +48 -0
- package/src/tools/utils.ts +2 -0
- package/src/types.ts +27 -5
- package/dist/cli-46b6kc7f.js +0 -1698
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
buildModelsDevSeedRows
|
|
3
|
-
} from "./cli-
|
|
3
|
+
} from "./cli-tece6zgm.js";
|
|
4
4
|
import {
|
|
5
5
|
createLogEntry,
|
|
6
6
|
getActivePricingRow,
|
|
7
7
|
getDb,
|
|
8
8
|
init_db,
|
|
9
9
|
insertPricingRow
|
|
10
|
-
} from "./cli-
|
|
10
|
+
} from "./cli-15y7qhzp.js";
|
|
11
11
|
import {
|
|
12
12
|
init_secret_scrubber,
|
|
13
13
|
scrubSecrets
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PermissionVerbSchema
|
|
3
|
-
} from "./cli-
|
|
3
|
+
} from "./cli-86fdnerz.js";
|
|
4
4
|
import {
|
|
5
5
|
getDb,
|
|
6
6
|
init_db
|
|
7
|
-
} from "./cli-
|
|
7
|
+
} from "./cli-15y7qhzp.js";
|
|
8
8
|
|
|
9
9
|
// src/be/rbac-roles.ts
|
|
10
10
|
init_db();
|
|
@@ -24,7 +24,14 @@ var BUILTIN_ROLES = [
|
|
|
24
24
|
description: "Own-task lifecycle: what legacy policy grants user principals.",
|
|
25
25
|
isBuiltin: true,
|
|
26
26
|
grantsAll: false,
|
|
27
|
-
verbs: [
|
|
27
|
+
verbs: [
|
|
28
|
+
"task.create.own",
|
|
29
|
+
"task.read.own",
|
|
30
|
+
"task.cancel.own",
|
|
31
|
+
"task.action.own",
|
|
32
|
+
"task.fs.mutate",
|
|
33
|
+
"favorite.write.own"
|
|
34
|
+
]
|
|
28
35
|
}
|
|
29
36
|
];
|
|
30
37
|
var CREATE_USER_DEFAULT_ROLE_TRIGGER_SQL = `
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createAdditiveBuffer,
|
|
3
3
|
extractSlackMessageText
|
|
4
|
-
} from "./cli-
|
|
4
|
+
} from "./cli-tffvrh6j.js";
|
|
5
5
|
import {
|
|
6
6
|
getSlackApp,
|
|
7
7
|
registerTreeMessage
|
|
8
|
-
} from "./cli-
|
|
8
|
+
} from "./cli-pet3aev6.js";
|
|
9
9
|
import {
|
|
10
10
|
rewriteSlackMentions
|
|
11
|
-
} from "./cli-
|
|
11
|
+
} from "./cli-cchksf5q.js";
|
|
12
12
|
import {
|
|
13
13
|
buildBufferFlushBlocks
|
|
14
|
-
} from "./cli-
|
|
14
|
+
} from "./cli-ma04faw5.js";
|
|
15
15
|
import {
|
|
16
16
|
createTaskWithSiblingAwareness,
|
|
17
17
|
slackContextKey
|
|
18
|
-
} from "./cli-
|
|
18
|
+
} from "./cli-k3y4z3h5.js";
|
|
19
19
|
import {
|
|
20
20
|
getLatestActiveTaskInThread,
|
|
21
21
|
getLeadAgent,
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
init_db,
|
|
24
24
|
init_registry,
|
|
25
25
|
registerTemplate
|
|
26
|
-
} from "./cli-
|
|
26
|
+
} from "./cli-15y7qhzp.js";
|
|
27
27
|
|
|
28
28
|
// src/slack/event-dedup.ts
|
|
29
29
|
var DEFAULT_TTL_MS = 300000;
|
|
@@ -24,6 +24,10 @@ var PERMISSIONS = {
|
|
|
24
24
|
description: "Cancel any task (beyond tasks the caller created).",
|
|
25
25
|
namespace: "task"
|
|
26
26
|
},
|
|
27
|
+
"task.create.own": {
|
|
28
|
+
description: "Create a task the caller owns.",
|
|
29
|
+
namespace: "task"
|
|
30
|
+
},
|
|
27
31
|
"task.read.own": {
|
|
28
32
|
description: "Read details of a task the principal requested.",
|
|
29
33
|
namespace: "task"
|
|
@@ -40,6 +44,10 @@ var PERMISSIONS = {
|
|
|
40
44
|
description: "Mutate a task's filesystem artifacts and attachments.",
|
|
41
45
|
namespace: "task"
|
|
42
46
|
},
|
|
47
|
+
"favorite.write.own": {
|
|
48
|
+
description: "Set a favorite the caller owns.",
|
|
49
|
+
namespace: "favorite"
|
|
50
|
+
},
|
|
43
51
|
"memory.learning.inject": {
|
|
44
52
|
description: "Inject a learning into another agent's memory.",
|
|
45
53
|
namespace: "memory"
|
|
@@ -156,6 +164,10 @@ var PERMISSIONS = {
|
|
|
156
164
|
description: "Update an MCP server the caller does not own.",
|
|
157
165
|
namespace: "mcp-server"
|
|
158
166
|
},
|
|
167
|
+
"mcp-server.read.secrets": {
|
|
168
|
+
description: "Read resolved MCP server secret env/header values.",
|
|
169
|
+
namespace: "mcp-server"
|
|
170
|
+
},
|
|
159
171
|
"mcp-oauth.authorize.any": {
|
|
160
172
|
description: "Start an MCP-server OAuth authorize flow for a caller-supplied user scope.",
|
|
161
173
|
namespace: "mcp-oauth"
|
|
@@ -175,6 +187,30 @@ var PERMISSIONS = {
|
|
|
175
187
|
"script.global.delete": {
|
|
176
188
|
description: "Delete a global-scope script.",
|
|
177
189
|
namespace: "script"
|
|
190
|
+
},
|
|
191
|
+
"script.search": {
|
|
192
|
+
description: "Search reusable scripts visible to the caller.",
|
|
193
|
+
namespace: "script"
|
|
194
|
+
},
|
|
195
|
+
"script.api.read.secrets": {
|
|
196
|
+
description: "Reveal an external script API endpoint bearer token.",
|
|
197
|
+
namespace: "script"
|
|
198
|
+
},
|
|
199
|
+
"script.api.create": {
|
|
200
|
+
description: "Expose a script as an external HTTP API endpoint.",
|
|
201
|
+
namespace: "script"
|
|
202
|
+
},
|
|
203
|
+
"script.api.update": {
|
|
204
|
+
description: "Update an external script API endpoint.",
|
|
205
|
+
namespace: "script"
|
|
206
|
+
},
|
|
207
|
+
"script.api.rotate": {
|
|
208
|
+
description: "Rotate an external script API endpoint bearer token.",
|
|
209
|
+
namespace: "script"
|
|
210
|
+
},
|
|
211
|
+
"script.api.delete": {
|
|
212
|
+
description: "Delete an external script API endpoint.",
|
|
213
|
+
namespace: "script"
|
|
178
214
|
}
|
|
179
215
|
};
|
|
180
216
|
var PERMISSION_VERBS = Object.keys(PERMISSIONS);
|
|
@@ -201,6 +237,22 @@ function decideAdmission(input) {
|
|
|
201
237
|
}
|
|
202
238
|
return { allow: false, reason: "admission: route has no permission verb (operator-only)" };
|
|
203
239
|
}
|
|
240
|
+
function decideToolAdmission(input) {
|
|
241
|
+
if (input.grant.grantsAll) {
|
|
242
|
+
return { allow: true };
|
|
243
|
+
}
|
|
244
|
+
if (input.rbac && "permission" in input.rbac) {
|
|
245
|
+
const verb = input.rbac.permission;
|
|
246
|
+
if (input.grant.verbs.has(verb)) {
|
|
247
|
+
return { allow: true, verb };
|
|
248
|
+
}
|
|
249
|
+
return { allow: false, reason: `admission: missing permission '${verb}'`, verb };
|
|
250
|
+
}
|
|
251
|
+
if (input.readOnly) {
|
|
252
|
+
return { allow: true };
|
|
253
|
+
}
|
|
254
|
+
return { allow: false, reason: "admission: tool has no permission verb (operator-only)" };
|
|
255
|
+
}
|
|
204
256
|
// src/rbac/legacy-policy.ts
|
|
205
257
|
var leadOnly = {
|
|
206
258
|
name: "lead-only",
|
|
@@ -283,10 +335,12 @@ var LEGACY_POLICY = {
|
|
|
283
335
|
"agent.profile.update.any": leadOnly,
|
|
284
336
|
"agent.context.read.any": leadOnly,
|
|
285
337
|
"task.cancel.any": leadOrTaskCreator,
|
|
338
|
+
"task.create.own": anyAuthenticated,
|
|
286
339
|
"task.read.own": requesterOwnsTask,
|
|
287
340
|
"task.cancel.own": requesterOwnsTask,
|
|
288
341
|
"task.action.own": requesterOwnsTask,
|
|
289
342
|
"task.fs.mutate": taskFsMutate,
|
|
343
|
+
"favorite.write.own": anyAuthenticated,
|
|
290
344
|
"memory.learning.inject": leadOnly,
|
|
291
345
|
"memory.delete.any": memoryOwnerOrLeadSwarm,
|
|
292
346
|
"channel.delete": leadOnly,
|
|
@@ -316,11 +370,18 @@ var LEGACY_POLICY = {
|
|
|
316
370
|
"mcp-server.uninstall.any": leadOnly,
|
|
317
371
|
"mcp-server.delete.any": leadOrResourceOwner,
|
|
318
372
|
"mcp-server.update.any": leadOrResourceOwner,
|
|
373
|
+
"mcp-server.read.secrets": leadOnly,
|
|
319
374
|
"mcp-oauth.authorize.any": anyAuthenticated,
|
|
320
375
|
"kv.write.any": leadOrOwnNamespace,
|
|
321
376
|
"page.delete.any": leadOrResourceOwner,
|
|
322
377
|
"script.global.write": leadOnly,
|
|
323
|
-
"script.global.delete": leadOnly
|
|
378
|
+
"script.global.delete": leadOnly,
|
|
379
|
+
"script.search": anyAuthenticated,
|
|
380
|
+
"script.api.read.secrets": leadOnly,
|
|
381
|
+
"script.api.create": leadOnly,
|
|
382
|
+
"script.api.update": leadOnly,
|
|
383
|
+
"script.api.rotate": leadOnly,
|
|
384
|
+
"script.api.delete": leadOnly
|
|
324
385
|
};
|
|
325
386
|
|
|
326
387
|
// src/rbac/can.ts
|
|
@@ -341,4 +402,4 @@ function can(check) {
|
|
|
341
402
|
}
|
|
342
403
|
return decision;
|
|
343
404
|
}
|
|
344
|
-
export { isRbacEnabled, decideAdmission, setAuditSink, clearAuditSink, can, PermissionVerbSchema };
|
|
405
|
+
export { isRbacEnabled, decideAdmission, decideToolAdmission, setAuditSink, clearAuditSink, can, PermissionVerbSchema };
|
|
@@ -7,7 +7,7 @@ var package_default;
|
|
|
7
7
|
var init_package = __esm(() => {
|
|
8
8
|
package_default = {
|
|
9
9
|
name: "@desplega.ai/agent-swarm",
|
|
10
|
-
version: "1.
|
|
10
|
+
version: "1.115.0",
|
|
11
11
|
description: "Multi-agent orchestration for Claude Code, Codex, Gemini CLI, and other AI coding assistants",
|
|
12
12
|
license: "MIT",
|
|
13
13
|
author: "desplega.sh <contact@desplega.sh>",
|
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
|
+
REBOOT_RETRY_PIN_TAG,
|
|
3
|
+
createPoolStarvationDecisionTask,
|
|
2
4
|
createRerouteDecisionTask,
|
|
3
5
|
createResumeFollowUp,
|
|
4
6
|
getNextResumeGeneration,
|
|
7
|
+
getPinCandidateAgent,
|
|
5
8
|
getResumeGeneration,
|
|
6
9
|
repointTrackerSyncBySwarmId
|
|
7
|
-
} from "./cli-
|
|
10
|
+
} from "./cli-dcca6j8m.js";
|
|
8
11
|
import {
|
|
9
12
|
getExecutorRegistry,
|
|
10
13
|
recoverIncompleteRuns
|
|
11
|
-
} from "./cli-
|
|
14
|
+
} from "./cli-q1rx7g0d.js";
|
|
12
15
|
import {
|
|
13
16
|
MAX_EMPTY_POLLS,
|
|
14
17
|
assignUnassignedTaskPending,
|
|
15
18
|
backfillSupersedeTaskResumeTaskId,
|
|
19
|
+
buildRoutingAffinityFromAgent,
|
|
16
20
|
cleanupStaleSessions,
|
|
17
21
|
createTaskExtended,
|
|
18
22
|
deleteActiveSession,
|
|
@@ -28,6 +32,7 @@ import {
|
|
|
28
32
|
getRecentFailedCount,
|
|
29
33
|
getRecentFailedTasks,
|
|
30
34
|
getStalePinnedResumes,
|
|
35
|
+
getStaleUnassignedAffinityTasks,
|
|
31
36
|
getStalledInProgressTasks,
|
|
32
37
|
getTaskById,
|
|
33
38
|
getTaskStats,
|
|
@@ -37,6 +42,8 @@ import {
|
|
|
37
42
|
init_db,
|
|
38
43
|
init_registry,
|
|
39
44
|
init_resolver,
|
|
45
|
+
isAgentEligibleForTask,
|
|
46
|
+
isPoolAffinityEnforcementEnabled,
|
|
40
47
|
registerTemplate,
|
|
41
48
|
releaseStaleMentionProcessing,
|
|
42
49
|
releaseStaleProcessingInbox,
|
|
@@ -44,7 +51,7 @@ import {
|
|
|
44
51
|
resolveTemplate,
|
|
45
52
|
supersedeTask,
|
|
46
53
|
updateAgentStatus
|
|
47
|
-
} from "./cli-
|
|
54
|
+
} from "./cli-15y7qhzp.js";
|
|
48
55
|
|
|
49
56
|
// src/heartbeat/heartbeat.ts
|
|
50
57
|
init_db();
|
|
@@ -155,6 +162,8 @@ var STALL_THRESHOLD_NO_SESSION_MIN = Number(process.env.HEARTBEAT_STALL_NO_SESSI
|
|
|
155
162
|
var STALL_THRESHOLD_STALE_HEARTBEAT_MIN = Number(process.env.HEARTBEAT_STALL_STALE_HB_MIN) || 15;
|
|
156
163
|
var STALE_CLEANUP_THRESHOLD_MINUTES = Number(process.env.HEARTBEAT_STALE_CLEANUP_MIN) || 30;
|
|
157
164
|
var MAX_AUTO_ASSIGN_PER_SWEEP = Number(process.env.HEARTBEAT_MAX_AUTO_ASSIGN) || 5;
|
|
165
|
+
var POOL_SCAN_BATCH_SIZE = Number(process.env.HEARTBEAT_POOL_SCAN_BATCH_SIZE) || 50;
|
|
166
|
+
var POOL_SCAN_CAP = Number(process.env.HEARTBEAT_POOL_SCAN_CAP) || 500;
|
|
158
167
|
var MAX_RESUME_GENERATIONS = Number(process.env.HEARTBEAT_MAX_RESUME_GENERATIONS) || 3;
|
|
159
168
|
var RESUME_BUDGET_EXHAUSTED_REASON = "resume_budget_exhausted";
|
|
160
169
|
var HEARTBEAT_RESUME_PIN_GRACE_MIN = (() => {
|
|
@@ -164,6 +173,7 @@ var HEARTBEAT_RESUME_PIN_GRACE_MIN = (() => {
|
|
|
164
173
|
const parsed = Number(raw);
|
|
165
174
|
return Number.isFinite(parsed) ? parsed : 10;
|
|
166
175
|
})();
|
|
176
|
+
var POOL_AFFINITY_ESCALATION_MIN = Number(process.env.POOL_AFFINITY_ESCALATION_MIN) || 15;
|
|
167
177
|
var HEARTBEAT_CHECKLIST_INTERVAL_MS = Number(process.env.HEARTBEAT_CHECKLIST_INTERVAL_MS) || 30 * 60 * 1000;
|
|
168
178
|
var HEARTBEAT_CHECKLIST_DISABLE = Boolean(process.env.HEARTBEAT_CHECKLIST_DISABLE);
|
|
169
179
|
var heartbeatInterval = null;
|
|
@@ -412,12 +422,28 @@ async function runRebootSweep() {
|
|
|
412
422
|
LIMIT 1`).get(task.id);
|
|
413
423
|
if (!existingRetry) {
|
|
414
424
|
try {
|
|
425
|
+
let preferredAgentId;
|
|
426
|
+
const candidate = getPinCandidateAgent(task.agentId);
|
|
427
|
+
if (candidate) {
|
|
428
|
+
const activeCount = getActiveTaskCount(candidate.id);
|
|
429
|
+
const hasCap = activeCount < (candidate.maxTasks ?? 1);
|
|
430
|
+
if (hasCap) {
|
|
431
|
+
preferredAgentId = candidate.id;
|
|
432
|
+
} else {
|
|
433
|
+
console.warn(`[Heartbeat] Reboot retry for task ${task.id.slice(0, 8)} NOT pinned: agent ${candidate.id.slice(0, 8)} at capacity (${activeCount}/${candidate.maxTasks ?? 1}); falling back to affinity-gated pool`);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
const tags = ["reboot-retry", "auto-generated"];
|
|
437
|
+
if (preferredAgentId !== undefined)
|
|
438
|
+
tags.push(REBOOT_RETRY_PIN_TAG);
|
|
415
439
|
const retryTask = createTaskExtended(task.task, {
|
|
416
440
|
parentTaskId: task.id,
|
|
417
|
-
|
|
441
|
+
agentId: preferredAgentId,
|
|
442
|
+
tags,
|
|
418
443
|
priority: task.priority,
|
|
419
444
|
source: task.source,
|
|
420
|
-
taskType: task.taskType ?? undefined
|
|
445
|
+
taskType: task.taskType ?? undefined,
|
|
446
|
+
routingAffinity: buildRoutingAffinityFromAgent(task.agentId) ?? undefined
|
|
421
447
|
});
|
|
422
448
|
retryTaskId = retryTask.id;
|
|
423
449
|
console.log(`[Heartbeat] Reboot retry created: ${retryTaskId} (parent: ${task.id})`);
|
|
@@ -461,10 +487,6 @@ function autoAssignPoolTasks(findings) {
|
|
|
461
487
|
const idleWorkers = getIdleWorkersWithCapacity().filter((w) => (w.emptyPollCount ?? 0) < MAX_EMPTY_POLLS);
|
|
462
488
|
if (idleWorkers.length === 0)
|
|
463
489
|
return;
|
|
464
|
-
const poolTasks = getUnassignedPoolTasks(MAX_AUTO_ASSIGN_PER_SWEEP);
|
|
465
|
-
if (poolTasks.length === 0)
|
|
466
|
-
return;
|
|
467
|
-
let workerIndex = 0;
|
|
468
490
|
const reservedByWorker = new Map;
|
|
469
491
|
const reservedForWorker = (agentId) => {
|
|
470
492
|
const cached = reservedByWorker.get(agentId);
|
|
@@ -475,24 +497,28 @@ function autoAssignPoolTasks(findings) {
|
|
|
475
497
|
reservedByWorker.set(agentId, reserved);
|
|
476
498
|
return reserved;
|
|
477
499
|
};
|
|
478
|
-
|
|
479
|
-
|
|
500
|
+
let assignedCount = 0;
|
|
501
|
+
let offset = 0;
|
|
502
|
+
while (assignedCount < MAX_AUTO_ASSIGN_PER_SWEEP && offset < POOL_SCAN_CAP) {
|
|
503
|
+
const batch = getUnassignedPoolTasks(POOL_SCAN_BATCH_SIZE, offset);
|
|
504
|
+
if (batch.length === 0)
|
|
480
505
|
break;
|
|
481
|
-
const
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
if (remaining <= 0) {
|
|
493
|
-
workerIndex++;
|
|
506
|
+
for (const task of batch) {
|
|
507
|
+
if (assignedCount >= MAX_AUTO_ASSIGN_PER_SWEEP)
|
|
508
|
+
break;
|
|
509
|
+
const worker = idleWorkers.find((w) => reservedForWorker(w.id) < (w.maxTasks ?? 1) && isAgentEligibleForTask(w, task));
|
|
510
|
+
if (!worker)
|
|
511
|
+
continue;
|
|
512
|
+
const assigned = assignUnassignedTaskPending(task.id, worker.id);
|
|
513
|
+
if (assigned) {
|
|
514
|
+
findings.autoAssigned.push({ taskId: task.id, agentId: worker.id });
|
|
515
|
+
reservedByWorker.set(worker.id, reservedForWorker(worker.id) + 1);
|
|
516
|
+
assignedCount++;
|
|
494
517
|
}
|
|
495
518
|
}
|
|
519
|
+
offset += batch.length;
|
|
520
|
+
if (batch.length < POOL_SCAN_BATCH_SIZE)
|
|
521
|
+
break;
|
|
496
522
|
}
|
|
497
523
|
})();
|
|
498
524
|
}
|
|
@@ -550,12 +576,35 @@ function escalateUnreclaimedResumes(findings) {
|
|
|
550
576
|
console.log(`[Heartbeat] Escalated unreclaimed pinned resume ${resume.id.slice(0, 8)} → Lead reroute-decision ${escalation.decisionTaskId.slice(0, 8)} (original ${original.id.slice(0, 8)})`);
|
|
551
577
|
}
|
|
552
578
|
}
|
|
579
|
+
function escalateStarvedPoolTasks(findings) {
|
|
580
|
+
if (!isPoolAffinityEnforcementEnabled())
|
|
581
|
+
return;
|
|
582
|
+
const cutoff = new Date(Date.now() - POOL_AFFINITY_ESCALATION_MIN * 60 * 1000).toISOString();
|
|
583
|
+
const candidates = getStaleUnassignedAffinityTasks(cutoff);
|
|
584
|
+
if (candidates.length === 0)
|
|
585
|
+
return;
|
|
586
|
+
const registeredAgents = getAllAgents().filter((a) => !a.isLead);
|
|
587
|
+
for (const task of candidates) {
|
|
588
|
+
const hasEligibleAgent = registeredAgents.some((agent) => isAgentEligibleForTask(agent, task));
|
|
589
|
+
if (hasEligibleAgent)
|
|
590
|
+
continue;
|
|
591
|
+
const decision = createPoolStarvationDecisionTask({ original: task });
|
|
592
|
+
if (decision.kind === "created") {
|
|
593
|
+
findings.escalatedReroutes.push({
|
|
594
|
+
originalTaskId: task.id,
|
|
595
|
+
decisionTaskId: decision.task.id
|
|
596
|
+
});
|
|
597
|
+
console.log(`[Heartbeat] Escalated starved pool task ${task.id.slice(0, 8)} → Lead reroute-decision ${decision.task.id.slice(0, 8)} (zero eligible agents)`);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
553
601
|
async function cleanupStaleResources(findings) {
|
|
554
602
|
findings.staleCleanup.sessions = cleanupStaleSessions(STALE_CLEANUP_THRESHOLD_MINUTES);
|
|
555
603
|
findings.staleCleanup.reviewingTasks = releaseStaleReviewingTasks(STALE_CLEANUP_THRESHOLD_MINUTES);
|
|
556
604
|
findings.staleCleanup.mentionProcessing = releaseStaleMentionProcessing(STALE_CLEANUP_THRESHOLD_MINUTES);
|
|
557
605
|
findings.staleCleanup.inboxProcessing = releaseStaleProcessingInbox(STALE_CLEANUP_THRESHOLD_MINUTES);
|
|
558
606
|
escalateUnreclaimedResumes(findings);
|
|
607
|
+
escalateStarvedPoolTasks(findings);
|
|
559
608
|
try {
|
|
560
609
|
findings.staleCleanup.workflowRuns = await recoverIncompleteRuns(getExecutorRegistry());
|
|
561
610
|
} catch {
|
|
@@ -4,12 +4,12 @@ import {
|
|
|
4
4
|
linkIdentity,
|
|
5
5
|
recordUnmappedIdentity,
|
|
6
6
|
resolveIdentity
|
|
7
|
-
} from "./cli-
|
|
7
|
+
} from "./cli-6aq8xhvm.js";
|
|
8
8
|
import {
|
|
9
9
|
getKv,
|
|
10
10
|
init_db,
|
|
11
11
|
upsertKv
|
|
12
|
-
} from "./cli-
|
|
12
|
+
} from "./cli-15y7qhzp.js";
|
|
13
13
|
|
|
14
14
|
// src/slack/enrich.ts
|
|
15
15
|
init_db();
|
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
getEmbeddingProvider,
|
|
5
5
|
init_embedding,
|
|
6
6
|
serializeEmbedding
|
|
7
|
-
} from "./cli-
|
|
7
|
+
} from "./cli-7xje5amz.js";
|
|
8
8
|
import {
|
|
9
9
|
getDb,
|
|
10
10
|
init_db
|
|
11
|
-
} from "./cli-
|
|
11
|
+
} from "./cli-15y7qhzp.js";
|
|
12
12
|
import {
|
|
13
13
|
init_secret_scrubber,
|
|
14
14
|
scrubSecrets
|
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
taskAttachmentDisplayUrl
|
|
3
3
|
} from "./cli-wspgs9bt.js";
|
|
4
4
|
import {
|
|
5
|
+
buildRoutingAffinityFromAgent,
|
|
5
6
|
createTaskExtended,
|
|
6
7
|
getActiveTaskCount,
|
|
7
8
|
getAgentById,
|
|
@@ -17,7 +18,7 @@ import {
|
|
|
17
18
|
init_templates1 as init_templates,
|
|
18
19
|
normalizeDateRequired,
|
|
19
20
|
resolveTemplate
|
|
20
|
-
} from "./cli-
|
|
21
|
+
} from "./cli-15y7qhzp.js";
|
|
21
22
|
|
|
22
23
|
// src/be/db-queries/tracker.ts
|
|
23
24
|
init_date_utils();
|
|
@@ -147,6 +148,13 @@ function isGracefulResumePinEnabled() {
|
|
|
147
148
|
var RESUME_GENERATION_TAG_PREFIX = "resume-generation:";
|
|
148
149
|
var CRASH_RECOVERY_PIN_TAG = "crash-recovery-pin";
|
|
149
150
|
var GRACEFUL_SHUTDOWN_PIN_TAG = "graceful-shutdown-pin";
|
|
151
|
+
var REBOOT_RETRY_PIN_TAG = "reboot-retry-pin";
|
|
152
|
+
function getPinCandidateAgent(agentId) {
|
|
153
|
+
const candidate = getAgentById(agentId);
|
|
154
|
+
if (!candidate || candidate.status === "offline")
|
|
155
|
+
return null;
|
|
156
|
+
return candidate;
|
|
157
|
+
}
|
|
150
158
|
function getResumeGeneration(task) {
|
|
151
159
|
const tag = task.tags.find((value) => value.startsWith(RESUME_GENERATION_TAG_PREFIX));
|
|
152
160
|
if (!tag)
|
|
@@ -247,8 +255,8 @@ function createResumeFollowUp(args) {
|
|
|
247
255
|
}
|
|
248
256
|
let preferredAgentId;
|
|
249
257
|
if (parent.agentId) {
|
|
250
|
-
const candidate =
|
|
251
|
-
if (candidate
|
|
258
|
+
const candidate = getPinCandidateAgent(parent.agentId);
|
|
259
|
+
if (candidate) {
|
|
252
260
|
const lastActivity = candidate.lastActivityAt ? Date.parse(candidate.lastActivityAt) : 0;
|
|
253
261
|
const fresh = Number.isFinite(lastActivity) && Date.now() - lastActivity < WORKER_LIVENESS_WINDOW_SECONDS * 1000;
|
|
254
262
|
const activeCount = getActiveTaskCount(candidate.id);
|
|
@@ -289,6 +297,7 @@ function createResumeFollowUp(args) {
|
|
|
289
297
|
if (args.reason === "graceful_shutdown" && preferredAgentId !== undefined) {
|
|
290
298
|
tags.push(GRACEFUL_SHUTDOWN_PIN_TAG);
|
|
291
299
|
}
|
|
300
|
+
const routingAffinity = parent.agentId ? buildRoutingAffinityFromAgent(parent.agentId) ?? undefined : undefined;
|
|
292
301
|
const created = createTaskExtended(followUpDescription, {
|
|
293
302
|
agentId: preferredAgentId,
|
|
294
303
|
creatorAgentId: parent.creatorAgentId,
|
|
@@ -296,7 +305,8 @@ function createResumeFollowUp(args) {
|
|
|
296
305
|
taskType: "resume",
|
|
297
306
|
tags,
|
|
298
307
|
priority,
|
|
299
|
-
parentTaskId: parent.id
|
|
308
|
+
parentTaskId: parent.id,
|
|
309
|
+
routingAffinity
|
|
300
310
|
});
|
|
301
311
|
const repointed = repointTrackerSyncBySwarmId(parent.id, created.id);
|
|
302
312
|
if (repointed > 0) {
|
|
@@ -338,5 +348,36 @@ function createRerouteDecisionTask(args) {
|
|
|
338
348
|
});
|
|
339
349
|
return { kind: "created", task: created };
|
|
340
350
|
}
|
|
351
|
+
function createPoolStarvationDecisionTask(args) {
|
|
352
|
+
const { original } = args;
|
|
353
|
+
const leadAgent = getLeadAgent();
|
|
354
|
+
if (!leadAgent)
|
|
355
|
+
return { kind: "skipped", reason: "lead_not_found" };
|
|
356
|
+
if (hasNonTerminalRerouteDecisionChild(original.id)) {
|
|
357
|
+
return { kind: "skipped", reason: "duplicate_exists" };
|
|
358
|
+
}
|
|
359
|
+
const affinity = original.routingAffinity;
|
|
360
|
+
const requiredRole = affinity?.role ?? "(none declared)";
|
|
361
|
+
const requiredCapabilities = affinity?.capabilities && affinity.capabilities.length > 0 ? affinity.capabilities.join(", ") : "(none declared)";
|
|
362
|
+
const attachmentsBlock = formatAttachmentsBlock(getTaskAttachments(original.id));
|
|
363
|
+
const decision = resolveTemplate("task.pool.starved.decision", {
|
|
364
|
+
original_task_id: original.id,
|
|
365
|
+
task_desc: original.task.slice(0, 200),
|
|
366
|
+
required_role: requiredRole,
|
|
367
|
+
required_capabilities: requiredCapabilities,
|
|
368
|
+
artifacts_block: attachmentsBlock
|
|
369
|
+
});
|
|
370
|
+
const created = createTaskExtended(decision.text, {
|
|
371
|
+
agentId: leadAgent.id,
|
|
372
|
+
creatorAgentId: original.creatorAgentId,
|
|
373
|
+
source: "system",
|
|
374
|
+
taskType: "reroute-decision",
|
|
375
|
+
tags: ["reroute-decision", "pool-starvation"],
|
|
376
|
+
priority: Math.min(100, (original.priority ?? 50) + 10),
|
|
377
|
+
parentTaskId: original.id,
|
|
378
|
+
inheritParentOutputSchema: false
|
|
379
|
+
});
|
|
380
|
+
return { kind: "created", task: created };
|
|
381
|
+
}
|
|
341
382
|
|
|
342
|
-
export { getTrackerSync, getTrackerSyncByExternalId, createTrackerSyncIfAbsent, updateTrackerSyncSwarmId, repointTrackerSyncBySwarmId, createTrackerSync, updateTrackerSync, deleteTrackerSync, hasTrackerDelivery, markTrackerDelivery, getAllTrackerSyncs, createTrackerAgentMapping, getResumeGeneration, getNextResumeGeneration, createWorkerTaskFollowUp, createResumeFollowUp, createRerouteDecisionTask };
|
|
383
|
+
export { getTrackerSync, getTrackerSyncByExternalId, createTrackerSyncIfAbsent, updateTrackerSyncSwarmId, repointTrackerSyncBySwarmId, createTrackerSync, updateTrackerSync, deleteTrackerSync, hasTrackerDelivery, markTrackerDelivery, getAllTrackerSyncs, createTrackerAgentMapping, REBOOT_RETRY_PIN_TAG, getPinCandidateAgent, getResumeGeneration, getNextResumeGeneration, createWorkerTaskFollowUp, createResumeFollowUp, createRerouteDecisionTask, createPoolStarvationDecisionTask };
|
|
@@ -781,6 +781,57 @@ var modelsdev_reasoning_default = {
|
|
|
781
781
|
]
|
|
782
782
|
}
|
|
783
783
|
]
|
|
784
|
+
},
|
|
785
|
+
"gpt-5.6-sol": {
|
|
786
|
+
id: "gpt-5.6-sol",
|
|
787
|
+
reasoning: true,
|
|
788
|
+
reasoningOptions: [
|
|
789
|
+
{
|
|
790
|
+
type: "effort",
|
|
791
|
+
values: [
|
|
792
|
+
"none",
|
|
793
|
+
"low",
|
|
794
|
+
"medium",
|
|
795
|
+
"high",
|
|
796
|
+
"xhigh",
|
|
797
|
+
"max"
|
|
798
|
+
]
|
|
799
|
+
}
|
|
800
|
+
]
|
|
801
|
+
},
|
|
802
|
+
"gpt-5.6-terra": {
|
|
803
|
+
id: "gpt-5.6-terra",
|
|
804
|
+
reasoning: true,
|
|
805
|
+
reasoningOptions: [
|
|
806
|
+
{
|
|
807
|
+
type: "effort",
|
|
808
|
+
values: [
|
|
809
|
+
"none",
|
|
810
|
+
"low",
|
|
811
|
+
"medium",
|
|
812
|
+
"high",
|
|
813
|
+
"xhigh",
|
|
814
|
+
"max"
|
|
815
|
+
]
|
|
816
|
+
}
|
|
817
|
+
]
|
|
818
|
+
},
|
|
819
|
+
"gpt-5.6-luna": {
|
|
820
|
+
id: "gpt-5.6-luna",
|
|
821
|
+
reasoning: true,
|
|
822
|
+
reasoningOptions: [
|
|
823
|
+
{
|
|
824
|
+
type: "effort",
|
|
825
|
+
values: [
|
|
826
|
+
"none",
|
|
827
|
+
"low",
|
|
828
|
+
"medium",
|
|
829
|
+
"high",
|
|
830
|
+
"xhigh",
|
|
831
|
+
"max"
|
|
832
|
+
]
|
|
833
|
+
}
|
|
834
|
+
]
|
|
784
835
|
}
|
|
785
836
|
},
|
|
786
837
|
openrouter: {
|
|
@@ -4035,7 +4086,7 @@ var modelsdev_reasoning_default = {
|
|
|
4035
4086
|
};
|
|
4036
4087
|
|
|
4037
4088
|
// src/providers/reasoning-effort.ts
|
|
4038
|
-
var REASONING_EFFORT_LEVELS = ["off", "low", "medium", "high", "xhigh"];
|
|
4089
|
+
var REASONING_EFFORT_LEVELS = ["off", "low", "medium", "high", "xhigh", "max"];
|
|
4039
4090
|
var SNAPSHOT = modelsdev_reasoning_default;
|
|
4040
4091
|
var FALLBACK_LEVELS = ["low", "medium", "high"];
|
|
4041
4092
|
var EFFORT_VALUE_MAP = {
|
|
@@ -4043,7 +4094,8 @@ var EFFORT_VALUE_MAP = {
|
|
|
4043
4094
|
low: "low",
|
|
4044
4095
|
medium: "medium",
|
|
4045
4096
|
high: "high",
|
|
4046
|
-
xhigh: "xhigh"
|
|
4097
|
+
xhigh: "xhigh",
|
|
4098
|
+
max: "max"
|
|
4047
4099
|
};
|
|
4048
4100
|
function splitProviderModel(model) {
|
|
4049
4101
|
const slash = model.indexOf("/");
|
|
@@ -4080,6 +4132,9 @@ function applyHarnessOverrides(harness, model, entry, levels) {
|
|
|
4080
4132
|
result = ["off", ...result];
|
|
4081
4133
|
}
|
|
4082
4134
|
}
|
|
4135
|
+
if (harness !== "codex") {
|
|
4136
|
+
result = result.filter((l) => l !== "max");
|
|
4137
|
+
}
|
|
4083
4138
|
if (harness === "codex") {
|
|
4084
4139
|
const isCodexMax = /-codex-max$/.test(model);
|
|
4085
4140
|
const isCodexNonMax = /-codex$/.test(model) && !isCodexMax;
|
|
@@ -4133,6 +4188,8 @@ var ANTHROPIC_BUDGET_TOKENS_BY_LEVEL = {
|
|
|
4133
4188
|
};
|
|
4134
4189
|
function buildOpencodeReasoningOptions(providerId, level) {
|
|
4135
4190
|
if (providerId === "anthropic") {
|
|
4191
|
+
if (level === "max")
|
|
4192
|
+
return { reasoningEffort: level };
|
|
4136
4193
|
return { thinking: { type: "enabled", budgetTokens: ANTHROPIC_BUDGET_TOKENS_BY_LEVEL[level] } };
|
|
4137
4194
|
}
|
|
4138
4195
|
if (providerId === "openrouter") {
|