@desplega.ai/agent-swarm 2.0.0 → 2.1.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/{acp-adapter-sj2g0m84.js → acp-adapter-kr4abrsk.js} +10 -10
- package/dist/{actions-fegk44gr.js → actions-eh4g6w2r.js} +27 -27
- package/dist/{amp-adapter-ad8ft89x.js → amp-adapter-7h7wdt8q.js} +5 -5
- package/dist/{app-kfvgbvzy.js → app-7k8s9w5p.js} +9 -9
- package/dist/{assistant-z7zdy9ja.js → assistant-wswt2y7p.js} +28 -28
- package/dist/{boot-reembed-j8xa181e.js → boot-reembed-9apm9qw6.js} +7 -7
- package/dist/{boot-reembed-5c2z0mbe.js → boot-reembed-whzbdthj.js} +7 -7
- package/dist/{boot-scrub-sweep-hnkn3rgt.js → boot-scrub-sweep-ndzmvmgt.js} +8 -8
- package/dist/{boot-seeds-kwjq4d2z.js → boot-seeds-e9sta0yt.js} +13 -11
- package/dist/{claude-adapter-9vmvpvgd.js → claude-adapter-4mqd3r6r.js} +11 -11
- package/dist/{claude-managed-adapter-k9qae05j.js → claude-managed-adapter-9wswb52m.js} +3 -3
- package/dist/{claude-managed-setup-q54zx5q2.js → claude-managed-setup-tpe1effx.js} +4 -4
- package/dist/{claude-sdk-session-9jye6cxr.js → claude-sdk-session-q49ghmh9.js} +10340 -10197
- package/dist/{cli-ke896fcf.js → cli-01xvj1rq.js} +10 -10
- package/dist/{cli-tr4sxp68.js → cli-035vekcw.js} +2 -2
- package/dist/{cli-z5jjpaxw.js → cli-0pd8hzhc.js} +3 -3
- package/dist/{cli-n5vwg842.js → cli-0veb92a3.js} +6 -1
- package/dist/{cli-wayw93nt.js → cli-10jesr25.js} +3 -3
- package/dist/{cli-se8w6wny.js → cli-1y7yywmj.js} +1 -1
- package/dist/{cli-v1yb0rqb.js → cli-20krdhz5.js} +47 -19
- package/dist/{cli-d5f9ed5c.js → cli-29rja109.js} +39 -20
- package/dist/{cli-apx87jne.js → cli-2pwa0q4d.js} +15 -4
- package/dist/{cli-ee9gtz70.js → cli-4mengw46.js} +348 -25
- package/dist/{cli-03gedhng.js → cli-5twdke5x.js} +6 -6
- package/dist/{cli-6razj6t4.js → cli-711vwbxn.js} +2 -2
- package/dist/{cli-s2sp957d.js → cli-78vv7446.js} +1 -1
- package/dist/{cli-3fbmmawm.js → cli-7n6s5man.js} +4 -4
- package/dist/{cli-hnhtk6cj.js → cli-8wwxw8a3.js} +1 -1
- package/dist/{cli-hnmhtzvh.js → cli-9jzdj90z.js} +2 -0
- package/dist/{cli-skxvvpap.js → cli-cvv9k0hh.js} +28 -25
- package/dist/{cli-74ahz61x.js → cli-d9286m9h.js} +2 -2
- package/dist/{cli-4jxm2qtz.js → cli-gxzkg1de.js} +28 -16
- package/dist/{cli-zkpks3r3.js → cli-h1arqn31.js} +1 -1
- package/dist/{cli-r62a35ea.js → cli-hqr88ew6.js} +1 -1
- package/dist/{cli-ra0xzggj.js → cli-j67mh2vg.js} +2 -2
- package/dist/{cli-29jc5q7w.js → cli-ksphgh48.js} +2 -2
- package/dist/{cli-eejsgvm4.js → cli-mgz4nbgg.js} +4 -4
- package/dist/{cli-vatyhshy.js → cli-mz5as5ha.js} +4 -4
- package/dist/{cli-f7kr7svz.js → cli-n8ndw8j7.js} +2 -2
- package/dist/{cli-1e4b6bzh.js → cli-naqzr17j.js} +7 -7
- package/dist/{cli-q0ke1yww.js → cli-nm1p8jfr.js} +6 -6
- package/dist/{cli-m50t4309.js → cli-p3zbc1rw.js} +5 -5
- package/dist/{cli-cgtksawx.js → cli-pe05f8yk.js} +23 -3
- package/dist/{cli-vdach5a9.js → cli-qmzsbkvy.js} +4 -4
- package/dist/{cli-n3hzg89b.js → cli-qnm4e9e4.js} +57 -579
- package/dist/{cli-s4setq91.js → cli-qqy4q48b.js} +3 -3
- package/dist/{cli-k382tshb.js → cli-r35rw5de.js} +8 -7
- package/dist/{cli-k3dp5tpf.js → cli-r610p9bs.js} +2 -2
- package/dist/{cli-e6mpjhed.js → cli-rc6pf5kv.js} +1 -1
- package/dist/{cli-3dj8k4vy.js → cli-rdxm77k3.js} +1 -1
- package/dist/{cli-tqaazemc.js → cli-s69nfyeh.js} +1 -1
- package/dist/{cli-6jyj59nb.js → cli-sawv63e8.js} +2 -2
- package/dist/{cli-q50942rs.js → cli-sg19gbf0.js} +1 -1
- package/dist/{cli-p1x85d2t.js → cli-shk7r5cs.js} +12 -9
- package/dist/{cli-przpmdgr.js → cli-sksetb2q.js} +11 -1
- package/dist/{cli-d2qr7aj4.js → cli-t02z59f2.js} +1 -1
- package/dist/{cli-j0pfptdp.js → cli-v7g551te.js} +39 -43
- package/dist/{cli-bzszjf2p.js → cli-vgqzp4em.js} +519 -126
- package/dist/cli-wfnemr1t.js +86 -0
- package/dist/{cli-ne236afy.js → cli-wms6x9db.js} +8 -8
- package/dist/{cli-5hkm7whv.js → cli-x1r545x8.js} +1 -1
- package/dist/{cli-kt6zqg0e.js → cli-xczsgshn.js} +2 -2
- package/dist/{cli-ef1hg1wv.js → cli-y3167wt1.js} +430 -238
- package/dist/{cli-tsde1hdr.js → cli-yjmqpxt3.js} +12 -11
- package/dist/{cli-9nfx44eh.js → cli-z780ec7c.js} +1 -1
- package/dist/{cli-r2pnvj8g.js → cli-zm9t2vde.js} +2 -2
- package/dist/cli.js +24 -23
- package/dist/{codex-adapter-y81sssk0.js → codex-adapter-4z16v9n0.js} +8 -8
- package/dist/{codex-login-f2rcfpp9.js → codex-login-pkepy2j1.js} +2 -2
- package/dist/{codex-session-runner-8vx4j6a9.js → codex-session-runner-rvms9y2x.js} +8 -8
- package/dist/{commands-kcpvpcrr.js → commands-2a9rtyat.js} +8 -8
- package/dist/{controller-ywrmt6yd.js → controller-3k3madbn.js} +4 -4
- package/dist/{controllers-connect-kwpvj3rf.js → controllers-connect-v9yn8zb9.js} +30 -30
- package/dist/{cursor-adapter-cehv1qns.js → cursor-adapter-98gbhyzn.js} +4 -4
- package/dist/{db-ww5d7jq3.js → db-eywwsnjw.js} +9 -7
- package/dist/{db-k8ankj20.js → db-ncypk9np.js} +9 -9
- package/dist/{devin-adapter-x1022qb1.js → devin-adapter-zeq8b9gz.js} +2 -2
- package/dist/{dispatcher-e8gq5m68.js → dispatcher-w94kc575.js} +26 -26
- package/dist/{docker-ff6y1190.js → docker-b1e4cqab.js} +2 -2
- package/dist/{dsh-adapter-3epjm3af.js → dsh-adapter-47ztej36.js} +4 -4
- package/dist/{e2b-8ygwhg0f.js → e2b-bbt8ey45.js} +3 -3
- package/dist/{e2b-swhnpw3n.js → e2b-dp804sen.js} +3 -3
- package/dist/{event-bus-6axnngdj.js → event-bus-j2jdg3qb.js} +2 -2
- package/dist/{external-channel-h3359cwn.js → external-channel-zrkg8ar9.js} +8 -8
- package/dist/{grok-adapter-0d4x7gkx.js → grok-adapter-s9ncp9vy.js} +11 -11
- package/dist/{handlers-an1gzv21.js → handlers-kqftvjgw.js} +29 -29
- package/dist/{heartbeat-6dakeb61.js → heartbeat-9q96p8v9.js} +31 -31
- package/dist/{hook-6v6cv6d5.js → hook-56qe10dp.js} +7 -7
- package/dist/{hook-sa5xye4y.js → hook-yy6rw42k.js} +8 -8
- package/dist/{http-r7f3eky0.js → http-r2dnb8f8.js} +963 -75
- package/dist/{index-7ep4gzdk.js → index-3gtmkhc6.js} +26 -26
- package/dist/{index-v1v6n7hg.js → index-3k5hkz7r.js} +31 -31
- package/dist/{index-rmpw9a8q.js → index-5e101240.js} +26 -26
- package/dist/{index-s2wxgzr0.js → index-5wyfjc2c.js} +392 -15
- package/dist/{index-zk96aq1k.js → index-vxvhxxbn.js} +7 -7
- package/dist/{keepalive-be9vwy5h.js → keepalive-psj6j54c.js} +9 -9
- package/dist/{lead-0861cwrf.js → lead-hajz4688.js} +43 -43
- package/dist/{maintenance-mzzgc8bn.js → maintenance-ps02sb5m.js} +7 -7
- package/dist/{node-mn1zs7an.js → node-mwb5r697.js} +1 -1
- package/dist/{oauth-refresh-sweep-cpdnfwdj.js → oauth-refresh-sweep-0284h93b.js} +8 -8
- package/dist/{onboard-fh8qs4r3.js → onboard-rbf6bg01.js} +2 -2
- package/dist/{opencode-adapter-nm42wwj8.js → opencode-adapter-13dcatgq.js} +8 -8
- package/dist/{otel-impl-x6c1c9g4.js → otel-impl-zvqcbhp7.js} +2 -2
- package/dist/{pi-mono-adapter-9n2ya240.js → pi-mono-adapter-xxy47q4v.js} +7 -7
- package/dist/{pricing-refresh-qb0rv0ap.js → pricing-refresh-kefx9v3t.js} +9 -9
- package/dist/{rbac-roles-1gzdwbh1.js → rbac-roles-3m36rxm2.js} +8 -8
- package/dist/{rbac-roles-3mraey52.js → rbac-roles-z76xv0hq.js} +9 -9
- package/dist/{render-v2-agpa45zz.js → render-v2-wz73bs25.js} +9 -9
- package/dist/{resume-x0ydy9s9.js → resume-k4wzge8w.js} +14 -14
- package/dist/{setup-as9ga0d6.js → setup-2fp2pypp.js} +2 -2
- package/dist/{work-objects-y5g1y7ev.js → work-objects-6k0ywz3m.js} +29 -29
- package/dist/{worker-860c3e38.js → worker-5v3rxsdh.js} +43 -43
- package/dist/{x-m477fr0h.js → x-4mtdeym1.js} +2 -2
- package/openapi.json +777 -6
- package/package.json +8 -7
- package/src/agentmail/handlers.ts +21 -11
- package/src/apps/definition.ts +16 -0
- package/src/azure-devops/api.ts +52 -2
- package/src/azure-devops/boards-sync.ts +50 -20
- package/src/azure-devops/index.ts +1 -0
- package/src/azure-devops/outbound.ts +95 -0
- package/src/be/boot-seeds.ts +11 -0
- package/src/be/db/model-profiles.ts +315 -0
- package/src/be/db/tasks/read.ts +7 -0
- package/src/be/db.ts +53 -47
- package/src/be/migrations/219_relabel_pi_context_compactions.sql +22 -0
- package/src/be/migrations/220_model_profiles.sql +137 -0
- package/src/be/model-tier-resolution.ts +145 -11
- package/src/be/model-validation.ts +8 -1
- package/src/be/scripts/typecheck.ts +12 -0
- package/src/be/secret-registry.ts +6 -2
- package/src/be/seed-model-profiles.ts +41 -0
- package/src/be/seed-scripts/catalog/heartbeat-jev-gate.ts +368 -0
- package/src/be/seed-scripts/index.ts +9 -0
- package/src/be/swarm-config-guard.ts +1 -0
- package/src/commands/runner.ts +3 -17
- package/src/extensions/catalog.generated.json +17 -0
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/extensions/loader.ts +10 -5
- package/src/heartbeat/heartbeat.ts +2 -1
- package/src/http/agents.ts +49 -2
- package/src/http/all-routes.ts +1 -0
- package/src/http/apps.ts +30 -3
- package/src/http/config.ts +26 -2
- package/src/http/core.ts +4 -0
- package/src/http/index.ts +11 -1
- package/src/http/model-profiles.ts +303 -0
- package/src/http/pages-public.ts +11 -5
- package/src/http/poll.ts +16 -5
- package/src/http/script-runs.ts +1 -1
- package/src/http/scripts.ts +25 -2
- package/src/http/tasks.ts +18 -0
- package/src/http/webhooks.ts +1 -2
- package/src/pages/feedback-overlay.ts +65 -6
- package/src/providers/acp-targets.ts +1 -1
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/dsh-adapter.ts +1 -1
- package/src/providers/pi-mono-extension.ts +17 -3
- package/src/providers/reasoning-effort.ts +10 -0
- package/src/rbac/legacy-policy.ts +8 -0
- package/src/rbac/permissions.ts +5 -0
- package/src/scheduler/deferred-task-waits.ts +18 -5
- package/src/scheduler/scheduler.ts +7 -1
- package/src/scripts-runtime/executors/quickjs-prelude.ts +75 -6
- package/src/scripts-runtime/executors/quickjs-runner.ts +85 -8
- package/src/scripts-runtime/executors/quickjs-web-shims.ts +1041 -0
- package/src/scripts-runtime/extract-args-schema.ts +9 -8
- package/src/scripts-runtime/quickjs-compat.ts +464 -0
- package/src/scripts-runtime/sdk-allowlist.ts +4 -0
- package/src/scripts-runtime/types/stdlib.d.ts +12 -0
- package/src/scripts-runtime/types/swarm-extension.d.ts +3 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +12 -0
- package/src/server.ts +10 -1
- package/src/slack/blocks.ts +4 -2
- package/src/slack/reaction-shortcode.ts +14 -0
- package/src/slack/render-v2.ts +12 -7
- package/src/slack/responses.ts +5 -4
- package/src/slack/thread-buffer.ts +41 -22
- package/src/tasks/worker-follow-up.ts +11 -2
- package/src/tests/agentmail-filters.test.ts +47 -0
- package/src/tests/apps-spike2.test.ts +35 -0
- package/src/tests/azure-devops-outbound.test.ts +420 -0
- package/src/tests/db-task-read-contract.test.ts +2 -0
- package/src/tests/db-task-write-contract.test.ts +1 -0
- package/src/tests/deferred-task-wake.test.ts +78 -1
- package/src/tests/docs-index-footprint.test.js +2 -2
- package/src/tests/dsh-adapter.test.ts +1 -1
- package/src/tests/env-flag.test.ts +1 -0
- package/src/tests/extensions-catalog.test.ts +1 -0
- package/src/tests/extensions-example-comms-adherence-gate.test.ts +413 -0
- package/src/tests/extensions-loader.test.ts +15 -0
- package/src/tests/heartbeat-jev-gate-credentials.test.ts +168 -0
- package/src/tests/heartbeat-jev-gate.test.ts +385 -0
- package/src/tests/model-profile-backcompat.test.ts +327 -0
- package/src/tests/model-profile-providers.test.ts +302 -0
- package/src/tests/model-profile-runtime-secrets.test.ts +223 -0
- package/src/tests/model-profiles-api.test.ts +614 -0
- package/src/tests/pages-feedback-keys.test.ts +121 -0
- package/src/tests/pages-feedback.test.ts +3 -0
- package/src/tests/pi-context-compaction.test.ts +193 -0
- package/src/tests/profile-claim.test.ts +269 -0
- package/src/tests/quickjs-compat.test.ts +213 -0
- package/src/tests/rbac-engine.test.ts +21 -0
- package/src/tests/script-connections.test.ts +4 -0
- package/src/tests/script-executor-conformance.test.ts +252 -1
- package/src/tests/script-executor-quickjs.test.ts +96 -0
- package/src/tests/script-runs-http.test.ts +89 -0
- package/src/tests/scripts-http.test.ts +16 -0
- package/src/tests/secret-scrubber.test.ts +10 -0
- package/src/tests/seed-model-profiles.test.ts +174 -0
- package/src/tests/seed-scripts.test.ts +2 -2
- package/src/tests/skill-invocations.test.ts +4 -2
- package/src/tests/slack-blocks.test.ts +36 -0
- package/src/tests/slack-inline-output.test.ts +14 -0
- package/src/tests/slack-reaction-config.test.ts +20 -0
- package/src/tests/slack-render-v2.test.ts +37 -0
- package/src/tests/slack-thread-buffer.test.ts +98 -1
- package/src/tests/workflow-llm.test.ts +61 -0
- package/src/tools/model-profiles/list-model-profiles.ts +54 -0
- package/src/tools/request-human-input.ts +11 -3
- package/src/tools/script-apis.ts +5 -1
- package/src/tools/script-upsert.ts +4 -1
- package/src/tools/send-task.ts +24 -1
- package/src/tools/system-one-decide.ts +104 -0
- package/src/tools/task-action.ts +22 -1
- package/src/tools/tool-config.ts +6 -0
- package/src/types.ts +36 -1
- package/src/utils/secret-scrubber.ts +19 -12
- package/src/utils/vcs-repo-match.ts +29 -0
- package/src/workflows/executors/raw-llm.ts +8 -3
- package/src/workflows/executors/system-one-decision.ts +21 -11
- package/src/workflows/executors/workflow-llm.ts +22 -0
- package/src/workflows/index.ts +21 -12
- package/templates/extensions/README.md +1 -0
- package/templates/extensions/comms-adherence-gate/README.md +88 -0
- package/templates/extensions/comms-adherence-gate/hooks.ts +489 -0
- package/templates/extensions/comms-adherence-gate/manifest.json +8 -0
- package/dist/cli-5t4f29ez.js +0 -33
|
@@ -19,12 +19,13 @@ import {
|
|
|
19
19
|
MAX_RATE_LIMIT_RESET_MS
|
|
20
20
|
} from "./cli-2pdaysab.js";
|
|
21
21
|
import {
|
|
22
|
-
reasoningCapability
|
|
23
|
-
|
|
22
|
+
reasoningCapability,
|
|
23
|
+
supportedReasoningLevels
|
|
24
|
+
} from "./cli-0veb92a3.js";
|
|
24
25
|
import {
|
|
25
26
|
ensureAgentFsCredentialsForAgent,
|
|
26
27
|
inviteEmailToSharedOrg
|
|
27
|
-
} from "./cli-
|
|
28
|
+
} from "./cli-zm9t2vde.js";
|
|
28
29
|
import"./cli-6zx22mv6.js";
|
|
29
30
|
import {
|
|
30
31
|
DEFAULT_CONNECTOR_CODE_LABEL,
|
|
@@ -35,16 +36,16 @@ import {
|
|
|
35
36
|
startPoolRouting,
|
|
36
37
|
stopHeartbeat,
|
|
37
38
|
stopPoolRouting
|
|
38
|
-
} from "./cli-
|
|
39
|
+
} from "./cli-yjmqpxt3.js";
|
|
39
40
|
import {
|
|
40
41
|
Anthropic
|
|
41
|
-
} from "./cli-
|
|
42
|
+
} from "./cli-gxzkg1de.js";
|
|
42
43
|
import {
|
|
43
44
|
runtimeSupervisorStatus,
|
|
44
45
|
startRuntimeSupervisor,
|
|
45
46
|
stopRuntimeSupervisor
|
|
46
|
-
} from "./cli-
|
|
47
|
-
import"./cli-
|
|
47
|
+
} from "./cli-01xvj1rq.js";
|
|
48
|
+
import"./cli-n8ndw8j7.js";
|
|
48
49
|
import"./cli-knd276ed.js";
|
|
49
50
|
import {
|
|
50
51
|
AGENT_MAX_TASKS_CONFIG_KEY,
|
|
@@ -202,6 +203,7 @@ import {
|
|
|
202
203
|
initAgentMail,
|
|
203
204
|
initApiTelemetry,
|
|
204
205
|
initAzureDevOps,
|
|
206
|
+
initAzureDevOpsOutbound,
|
|
205
207
|
initGitHub,
|
|
206
208
|
initGitLab,
|
|
207
209
|
initJira,
|
|
@@ -344,13 +346,13 @@ import {
|
|
|
344
346
|
wireHttpSpanLifecycle,
|
|
345
347
|
workflowModelErrors,
|
|
346
348
|
writeUnhandledError
|
|
347
|
-
} from "./cli-
|
|
348
|
-
import"./cli-
|
|
349
|
+
} from "./cli-vgqzp4em.js";
|
|
350
|
+
import"./cli-h1arqn31.js";
|
|
349
351
|
import {
|
|
350
352
|
AMP_ESTIMATE_MODELS,
|
|
351
353
|
ampBillsCacheWrites,
|
|
352
354
|
resolveAmpModel
|
|
353
|
-
} from "./cli-
|
|
355
|
+
} from "./cli-8wwxw8a3.js";
|
|
354
356
|
import {
|
|
355
357
|
RATING_MODEL_MAX_LENGTH,
|
|
356
358
|
REFERENCES_SOURCE_MAX_LENGTH,
|
|
@@ -364,7 +366,7 @@ import {
|
|
|
364
366
|
loadModelsCatalog,
|
|
365
367
|
requestModelCatalogRefresh,
|
|
366
368
|
upsertModelCatalogOverlay
|
|
367
|
-
} from "./cli-
|
|
369
|
+
} from "./cli-0pd8hzhc.js";
|
|
368
370
|
import {
|
|
369
371
|
ConnectionAuthInputSchema,
|
|
370
372
|
MAX_SCRIPT_WALL_CLOCK_MS,
|
|
@@ -381,6 +383,7 @@ import {
|
|
|
381
383
|
buildScriptCredentialBindingsWithFailures,
|
|
382
384
|
callMcpServerTool,
|
|
383
385
|
checkImportAllowlist,
|
|
386
|
+
checkQuickJSCompat,
|
|
384
387
|
collectScriptReferences,
|
|
385
388
|
computeExpiresAt,
|
|
386
389
|
connectionAuthInputFromFlat,
|
|
@@ -421,6 +424,7 @@ import {
|
|
|
421
424
|
oauthAppToProviderConfig,
|
|
422
425
|
parseSkillContent,
|
|
423
426
|
publicEndpointSsrfOptions,
|
|
427
|
+
quickJSCompatWarnings,
|
|
424
428
|
readStreamCapped,
|
|
425
429
|
refreshMcpToken,
|
|
426
430
|
refreshScriptConnection,
|
|
@@ -443,7 +447,7 @@ import {
|
|
|
443
447
|
upsertCredentialBinding,
|
|
444
448
|
upsertMcpOAuthToken,
|
|
445
449
|
upsertScriptConnection
|
|
446
|
-
} from "./cli-
|
|
450
|
+
} from "./cli-4mengw46.js";
|
|
447
451
|
import"./cli-epan13p1.js";
|
|
448
452
|
import {
|
|
449
453
|
detachedProcessGroup,
|
|
@@ -458,11 +462,11 @@ import {
|
|
|
458
462
|
forceRefreshAuthorizationOrThrow,
|
|
459
463
|
forceRefreshTokenOrThrow,
|
|
460
464
|
oauthAppRowToProviderConfig
|
|
461
|
-
} from "./cli-
|
|
462
|
-
import"./cli-
|
|
465
|
+
} from "./cli-711vwbxn.js";
|
|
466
|
+
import"./cli-wfnemr1t.js";
|
|
463
467
|
import {
|
|
464
468
|
normalizeModelKey
|
|
465
|
-
} from "./cli-
|
|
469
|
+
} from "./cli-hqr88ew6.js";
|
|
466
470
|
import"./cli-6cvfxs8r.js";
|
|
467
471
|
import {
|
|
468
472
|
AgentFsProvider,
|
|
@@ -482,14 +486,14 @@ import {
|
|
|
482
486
|
startWorkflowExecution,
|
|
483
487
|
validateJsonSchema,
|
|
484
488
|
workflowSaveWarnings
|
|
485
|
-
} from "./cli-
|
|
489
|
+
} from "./cli-naqzr17j.js";
|
|
486
490
|
import {
|
|
487
491
|
createApprovalFollowUpTask,
|
|
488
492
|
definitionNodeIds,
|
|
489
493
|
generateEdges,
|
|
490
494
|
validateDefinition
|
|
491
|
-
} from "./cli-
|
|
492
|
-
import"./cli-
|
|
495
|
+
} from "./cli-20krdhz5.js";
|
|
496
|
+
import"./cli-1y7yywmj.js";
|
|
493
497
|
import {
|
|
494
498
|
CLIENT_ID,
|
|
495
499
|
MAX_CODEX_OAUTH_SLOT,
|
|
@@ -500,7 +504,7 @@ import {
|
|
|
500
504
|
getAccountId,
|
|
501
505
|
getValidCodexOAuth,
|
|
502
506
|
loadAllCodexOAuthSlots
|
|
503
|
-
} from "./cli-
|
|
507
|
+
} from "./cli-rc6pf5kv.js";
|
|
504
508
|
import"./cli-2x0e561b.js";
|
|
505
509
|
import"./cli-txqb9s38.js";
|
|
506
510
|
import"./cli-h6vtvt5c.js";
|
|
@@ -529,7 +533,7 @@ import {
|
|
|
529
533
|
withRemoteContext,
|
|
530
534
|
withSpan,
|
|
531
535
|
withSpanContext
|
|
532
|
-
} from "./cli-
|
|
536
|
+
} from "./cli-cvv9k0hh.js";
|
|
533
537
|
import"./cli-n2wq4j7m.js";
|
|
534
538
|
import {
|
|
535
539
|
require_content_type
|
|
@@ -538,7 +542,7 @@ import"./cli-3er6gcsn.js";
|
|
|
538
542
|
import"./cli-hjwmhcg1.js";
|
|
539
543
|
import"./cli-rhs9pz33.js";
|
|
540
544
|
import"./cli-9ha6hs2d.js";
|
|
541
|
-
import"./cli-
|
|
545
|
+
import"./cli-r610p9bs.js";
|
|
542
546
|
import {
|
|
543
547
|
InvalidRuntimeTokenError,
|
|
544
548
|
RuntimePoolError,
|
|
@@ -577,8 +581,8 @@ import {
|
|
|
577
581
|
unlinkIdentity,
|
|
578
582
|
updateRuntimeController,
|
|
579
583
|
updateRuntimePool
|
|
580
|
-
} from "./cli-
|
|
581
|
-
import"./cli-
|
|
584
|
+
} from "./cli-mgz4nbgg.js";
|
|
585
|
+
import"./cli-j67mh2vg.js";
|
|
582
586
|
import {
|
|
583
587
|
bedrockProviderModule
|
|
584
588
|
} from "./cli-hvqbtna4.js";
|
|
@@ -605,7 +609,7 @@ import"./cli-pzxba7gw.js";
|
|
|
605
609
|
import {
|
|
606
610
|
getUserGrant,
|
|
607
611
|
init_rbac_roles
|
|
608
|
-
} from "./cli-
|
|
612
|
+
} from "./cli-d9286m9h.js";
|
|
609
613
|
import {
|
|
610
614
|
LEGACY_RULES,
|
|
611
615
|
can,
|
|
@@ -614,7 +618,7 @@ import {
|
|
|
614
618
|
init_rbac,
|
|
615
619
|
isRbacEnabled,
|
|
616
620
|
setAuditSink
|
|
617
|
-
} from "./cli-
|
|
621
|
+
} from "./cli-sksetb2q.js";
|
|
618
622
|
import {
|
|
619
623
|
API_DRAINING_HEADER,
|
|
620
624
|
CANDIDATE_SET_MULTIPLIER,
|
|
@@ -630,6 +634,7 @@ import {
|
|
|
630
634
|
KvTypeCollisionError,
|
|
631
635
|
MAX_DB_RETENTION_DAYS,
|
|
632
636
|
MEMORY_KEY_MAX_LENGTH,
|
|
637
|
+
MODEL_PROFILE_CONFIG_KEY,
|
|
633
638
|
NOT_EXTENSION_AGENT_SQL,
|
|
634
639
|
OpenAI,
|
|
635
640
|
ReservedAgentRoleError,
|
|
@@ -677,6 +682,7 @@ import {
|
|
|
677
682
|
createLogEntry,
|
|
678
683
|
createMcpServer,
|
|
679
684
|
createMetric,
|
|
685
|
+
createModelProfile,
|
|
680
686
|
createOAuthApp,
|
|
681
687
|
createPage,
|
|
682
688
|
createScheduledTask,
|
|
@@ -698,6 +704,7 @@ import {
|
|
|
698
704
|
deleteKv,
|
|
699
705
|
deleteMcpServer,
|
|
700
706
|
deleteMetric,
|
|
707
|
+
deleteModelProfile,
|
|
701
708
|
deleteOAuthTokens,
|
|
702
709
|
deletePage,
|
|
703
710
|
deletePricingRow,
|
|
@@ -772,6 +779,7 @@ import {
|
|
|
772
779
|
getMetric,
|
|
773
780
|
getMetricVersion,
|
|
774
781
|
getMetricVersions,
|
|
782
|
+
getModelProfileByName,
|
|
775
783
|
getOAuthApp,
|
|
776
784
|
getOAuthAppById,
|
|
777
785
|
getOAuthTokens,
|
|
@@ -861,6 +869,7 @@ import {
|
|
|
861
869
|
init_human_free,
|
|
862
870
|
init_key_paths,
|
|
863
871
|
init_memory,
|
|
872
|
+
init_model_profiles,
|
|
864
873
|
init_oauth,
|
|
865
874
|
init_openai,
|
|
866
875
|
init_org_website,
|
|
@@ -909,6 +918,7 @@ import {
|
|
|
909
918
|
listKv,
|
|
910
919
|
listMcpServers,
|
|
911
920
|
listMetricsByAgent,
|
|
921
|
+
listModelProfiles,
|
|
912
922
|
listPagesByAgent,
|
|
913
923
|
listRecentSessions,
|
|
914
924
|
listScriptApisForScript,
|
|
@@ -928,6 +938,8 @@ import {
|
|
|
928
938
|
markSteeringHandled,
|
|
929
939
|
markSteeringUndeliverable,
|
|
930
940
|
maskSecrets,
|
|
941
|
+
modelProfileRefError,
|
|
942
|
+
modelProfileReferences,
|
|
931
943
|
moveAssetKey,
|
|
932
944
|
normalizeDate,
|
|
933
945
|
normalizeOrgWebsite,
|
|
@@ -977,6 +989,7 @@ import {
|
|
|
977
989
|
startTask,
|
|
978
990
|
supersedeTask,
|
|
979
991
|
sweepExpiredKv,
|
|
992
|
+
taskProfileError,
|
|
980
993
|
telemetry,
|
|
981
994
|
touchScratchScriptLastUsed,
|
|
982
995
|
trackRelayed,
|
|
@@ -995,6 +1008,7 @@ import {
|
|
|
995
1008
|
updateAgentStatusFromCapacity,
|
|
996
1009
|
updateAuthorizationIdentity,
|
|
997
1010
|
updateMetric,
|
|
1011
|
+
updateModelProfile,
|
|
998
1012
|
updateOAuthAppById,
|
|
999
1013
|
updatePage,
|
|
1000
1014
|
updateScheduledTask,
|
|
@@ -1023,8 +1037,8 @@ import {
|
|
|
1023
1037
|
validateConfigValue,
|
|
1024
1038
|
validateExportToEnv,
|
|
1025
1039
|
withFavoriteFlags
|
|
1026
|
-
} from "./cli-
|
|
1027
|
-
import"./cli-
|
|
1040
|
+
} from "./cli-y3167wt1.js";
|
|
1041
|
+
import"./cli-9jzdj90z.js";
|
|
1028
1042
|
import {
|
|
1029
1043
|
ActiveSessionSchema,
|
|
1030
1044
|
AgentAcpStatusSchema,
|
|
@@ -1083,6 +1097,8 @@ import {
|
|
|
1083
1097
|
MetricSchema,
|
|
1084
1098
|
MetricVersionSchema,
|
|
1085
1099
|
MetricWidgetSchema,
|
|
1100
|
+
ModelProfileNameSchema,
|
|
1101
|
+
ModelProfileSchema,
|
|
1086
1102
|
ModelTierSchema,
|
|
1087
1103
|
OnUnsupportedSchema,
|
|
1088
1104
|
PageAuthModeSchema,
|
|
@@ -1159,12 +1175,12 @@ import {
|
|
|
1159
1175
|
isSafeBundlePath,
|
|
1160
1176
|
isTerminalTaskStatus,
|
|
1161
1177
|
splitLegacyModelAlias
|
|
1162
|
-
} from "./cli-
|
|
1178
|
+
} from "./cli-pe05f8yk.js";
|
|
1163
1179
|
import {
|
|
1164
1180
|
IDENTITY_FIELD_BUDGETS,
|
|
1165
1181
|
IdentityFieldBudgetError,
|
|
1166
1182
|
init_identity_field_budget
|
|
1167
|
-
} from "./cli-
|
|
1183
|
+
} from "./cli-78vv7446.js";
|
|
1168
1184
|
import {
|
|
1169
1185
|
getSlackConfiguration,
|
|
1170
1186
|
init_config
|
|
@@ -1173,7 +1189,7 @@ import {
|
|
|
1173
1189
|
init_steering_enabled,
|
|
1174
1190
|
isSteeringEnabled
|
|
1175
1191
|
} from "./cli-7mm2r1kp.js";
|
|
1176
|
-
import"./cli-
|
|
1192
|
+
import"./cli-x1r545x8.js";
|
|
1177
1193
|
import"./cli-mvzyxwg3.js";
|
|
1178
1194
|
import {
|
|
1179
1195
|
getAllTemplateDefinitions,
|
|
@@ -1222,17 +1238,17 @@ import {
|
|
|
1222
1238
|
import {
|
|
1223
1239
|
init_package,
|
|
1224
1240
|
package_default
|
|
1225
|
-
} from "./cli-
|
|
1241
|
+
} from "./cli-r35rw5de.js";
|
|
1226
1242
|
import {
|
|
1227
1243
|
init_event_bus,
|
|
1228
1244
|
workflowEventBus
|
|
1229
|
-
} from "./cli-
|
|
1245
|
+
} from "./cli-z780ec7c.js";
|
|
1230
1246
|
import {
|
|
1231
1247
|
init_bus,
|
|
1232
1248
|
realtimeBus
|
|
1233
1249
|
} from "./cli-zf8jjwex.js";
|
|
1234
1250
|
import"./cli-h8w3fg83.js";
|
|
1235
|
-
import"./cli-
|
|
1251
|
+
import"./cli-t02z59f2.js";
|
|
1236
1252
|
import {
|
|
1237
1253
|
MAX_PROFILE_FILE_LENGTH,
|
|
1238
1254
|
agentFsFileRoute,
|
|
@@ -1248,7 +1264,7 @@ import {
|
|
|
1248
1264
|
parseEnvFlag
|
|
1249
1265
|
} from "./cli-ej6gbxfb.js";
|
|
1250
1266
|
import"./cli-1srmzpr3.js";
|
|
1251
|
-
import"./cli-
|
|
1267
|
+
import"./cli-s69nfyeh.js";
|
|
1252
1268
|
import {
|
|
1253
1269
|
getApiKey,
|
|
1254
1270
|
init_api_key
|
|
@@ -1259,7 +1275,7 @@ import {
|
|
|
1259
1275
|
registerVolatileSecret,
|
|
1260
1276
|
scrubObject,
|
|
1261
1277
|
scrubSecrets
|
|
1262
|
-
} from "./cli-
|
|
1278
|
+
} from "./cli-shk7r5cs.js";
|
|
1263
1279
|
import {
|
|
1264
1280
|
init_src,
|
|
1265
1281
|
isAlias
|
|
@@ -4048,6 +4064,7 @@ async function handleActiveSessions(req, res, pathSegments, queryParams, myAgent
|
|
|
4048
4064
|
init_src();
|
|
4049
4065
|
init_zod();
|
|
4050
4066
|
init_db3();
|
|
4067
|
+
init_model_profiles();
|
|
4051
4068
|
init_db2();
|
|
4052
4069
|
init_telemetry();
|
|
4053
4070
|
init_types();
|
|
@@ -4195,7 +4212,7 @@ var updateAgentRuntimeRoute = route({
|
|
|
4195
4212
|
path: "/api/agents/{id}/runtime",
|
|
4196
4213
|
pattern: ["api", "agents", null, "runtime"],
|
|
4197
4214
|
summary: "Update an agent's runtime harness and default model",
|
|
4198
|
-
description: "Updates `agents.harness_provider` and agent-scoped runtime config. The settings apply to future provider sessions. For `model`, `reasoning_effort`, and `claude.transport`: omit the field to leave it unchanged, send `null` to clear the corresponding override, or send a value to set it. A `model` the model catalog does not list is a 400 unless `allow_custom_model` is true. A `latest:` alias is not accepted here (aliases resolve for a task's model and for `MODEL_TIER_*` values); `reasoning_effort` must be one the harness and model support.",
|
|
4215
|
+
description: "Updates `agents.harness_provider` and agent-scoped runtime config. The settings apply to future provider sessions. For `model`, `reasoning_effort`, and `claude.transport`: omit the field to leave it unchanged, send `null` to clear the corresponding override, or send a value to set it. A `model` the model catalog does not list is a 400 unless `allow_custom_model` is true. A `latest:` alias is not accepted here (aliases resolve for a task's model and for `MODEL_TIER_*` values); `reasoning_effort` must be one the harness and model support. `profile` sets the agent's default model profile (same tri-state): it must exist and run on `harness_provider`, and it cannot be sent with `model`. Sending `model`, or changing the model or effort override by any path, clears the default profile.",
|
|
4199
4216
|
tags: ["Agents"],
|
|
4200
4217
|
params: exports_external.object({ id: exports_external.string() }),
|
|
4201
4218
|
query: exports_external.object({ repoId: exports_external.string().optional() }),
|
|
@@ -4204,6 +4221,7 @@ var updateAgentRuntimeRoute = route({
|
|
|
4204
4221
|
model: exports_external.string().trim().min(1).nullable().optional(),
|
|
4205
4222
|
allow_custom_model: exports_external.boolean().optional().default(false),
|
|
4206
4223
|
reasoning_effort: ReasoningEffortSchema.nullable().optional(),
|
|
4224
|
+
profile: exports_external.string().trim().min(1).nullable().optional(),
|
|
4207
4225
|
acp: AcpRuntimeConfigSchema.optional(),
|
|
4208
4226
|
claude: ClaudeRuntimeConfigSchema.optional()
|
|
4209
4227
|
}),
|
|
@@ -4848,7 +4866,22 @@ async function handleAgentsRest(req, res, pathSegments, queryParams, _myAgentId)
|
|
|
4848
4866
|
const parsed = await updateAgentRuntimeRoute.parse(req, res, pathSegments, queryParams);
|
|
4849
4867
|
if (!parsed)
|
|
4850
4868
|
return true;
|
|
4851
|
-
const { harness_provider, model, allow_custom_model, reasoning_effort, acp, claude } = parsed.body;
|
|
4869
|
+
const { harness_provider, model, allow_custom_model, reasoning_effort, profile, acp, claude } = parsed.body;
|
|
4870
|
+
if (typeof profile === "string") {
|
|
4871
|
+
if (model !== undefined) {
|
|
4872
|
+
jsonError(res, "Send `profile` or `model`, not both", 400);
|
|
4873
|
+
return true;
|
|
4874
|
+
}
|
|
4875
|
+
const picked = await getModelProfileByName(profile);
|
|
4876
|
+
if (!picked) {
|
|
4877
|
+
jsonError(res, `Unknown model profile "${profile}"`, 400);
|
|
4878
|
+
return true;
|
|
4879
|
+
}
|
|
4880
|
+
if (picked.harness !== harness_provider) {
|
|
4881
|
+
jsonError(res, `Model profile "${profile}" runs on the ${picked.harness} harness, not ${harness_provider}`, 400);
|
|
4882
|
+
return true;
|
|
4883
|
+
}
|
|
4884
|
+
}
|
|
4852
4885
|
if (acp && harness_provider !== "acp") {
|
|
4853
4886
|
jsonError(res, "ACP configuration requires harness_provider=acp", 400);
|
|
4854
4887
|
return true;
|
|
@@ -4925,6 +4958,18 @@ async function handleAgentsRest(req, res, pathSegments, queryParams, _myAgentId)
|
|
|
4925
4958
|
description: "Set via PATCH /api/agents/{id}/runtime"
|
|
4926
4959
|
});
|
|
4927
4960
|
}
|
|
4961
|
+
if (model !== undefined || profile === null) {
|
|
4962
|
+
await deleteSwarmConfigByKey("agent", parsed.params.id, MODEL_PROFILE_CONFIG_KEY);
|
|
4963
|
+
} else if (profile !== undefined) {
|
|
4964
|
+
await upsertSwarmConfig({
|
|
4965
|
+
scope: "agent",
|
|
4966
|
+
scopeId: parsed.params.id,
|
|
4967
|
+
key: MODEL_PROFILE_CONFIG_KEY,
|
|
4968
|
+
value: profile,
|
|
4969
|
+
description: "Default model profile, set via PATCH /api/agents/{id}/runtime",
|
|
4970
|
+
exportToEnv: false
|
|
4971
|
+
});
|
|
4972
|
+
}
|
|
4928
4973
|
if (claude?.transport === null) {
|
|
4929
4974
|
await deleteSwarmConfigByKey("agent", parsed.params.id, "CLAUDE_TRANSPORT");
|
|
4930
4975
|
} else if (claude?.transport !== undefined) {
|
|
@@ -5011,6 +5056,10 @@ async function handleAgentsRest(req, res, pathSegments, queryParams, _myAgentId)
|
|
|
5011
5056
|
jsonError(res, error.message, 400);
|
|
5012
5057
|
return true;
|
|
5013
5058
|
}
|
|
5059
|
+
if (modelProfileRefError(error) === "missing") {
|
|
5060
|
+
jsonError(res, `Unknown model profile "${profile}"`, 400);
|
|
5061
|
+
return true;
|
|
5062
|
+
}
|
|
5014
5063
|
throw error;
|
|
5015
5064
|
}
|
|
5016
5065
|
if (!agent) {
|
|
@@ -7511,6 +7560,7 @@ init_secret_scrubber();
|
|
|
7511
7560
|
// src/http/config.ts
|
|
7512
7561
|
init_zod();
|
|
7513
7562
|
init_db3();
|
|
7563
|
+
init_model_profiles();
|
|
7514
7564
|
|
|
7515
7565
|
// src/be/org-profile.ts
|
|
7516
7566
|
init_org_website();
|
|
@@ -7553,6 +7603,16 @@ function singleHeader(req, name) {
|
|
|
7553
7603
|
const raw = req.headers[name];
|
|
7554
7604
|
return Array.isArray(raw) ? raw[0] : raw;
|
|
7555
7605
|
}
|
|
7606
|
+
function readsRepoSecrets(auth, agent) {
|
|
7607
|
+
if (auth?.kind !== "agent" || !auth.runtimeId)
|
|
7608
|
+
return true;
|
|
7609
|
+
return can({
|
|
7610
|
+
principal: { kind: "agent", agentId: auth.agentId, isLead: agent?.isLead ?? false },
|
|
7611
|
+
verb: "config.read.secrets",
|
|
7612
|
+
resource: { kind: "none" },
|
|
7613
|
+
source: "http"
|
|
7614
|
+
}).allow;
|
|
7615
|
+
}
|
|
7556
7616
|
async function requestSecretReadScope(req, resolvedScope) {
|
|
7557
7617
|
const auth = getRequestAuth(req);
|
|
7558
7618
|
if (auth?.kind === "operator")
|
|
@@ -7908,7 +7968,11 @@ async function handleConfig(req, res, pathSegments, queryParams) {
|
|
|
7908
7968
|
}
|
|
7909
7969
|
const result = includeSecrets || !config.isSecret ? config : maskSecrets([config])[0];
|
|
7910
7970
|
upsertConfig.respond(res, 200, result);
|
|
7911
|
-
} catch (
|
|
7971
|
+
} catch (error) {
|
|
7972
|
+
if (modelProfileRefError(error) === "missing") {
|
|
7973
|
+
jsonError(res, `Unknown model profile "${String(value)}"`, 400);
|
|
7974
|
+
return true;
|
|
7975
|
+
}
|
|
7912
7976
|
jsonError(res, "Failed to upsert config", 500);
|
|
7913
7977
|
}
|
|
7914
7978
|
return true;
|
|
@@ -9118,6 +9182,7 @@ declare module "swarm-extension" {
|
|
|
9118
9182
|
model?: string | undefined;
|
|
9119
9183
|
modelTier?: "smol" | "regular" | "smart" | "ultra" | undefined;
|
|
9120
9184
|
effort?: "off" | "low" | "medium" | "high" | "xhigh" | "max" | undefined;
|
|
9185
|
+
profile?: string | undefined;
|
|
9121
9186
|
scheduleId?: string | undefined;
|
|
9122
9187
|
workflowRunId?: string | undefined;
|
|
9123
9188
|
workflowRunStepId?: string | undefined;
|
|
@@ -9252,6 +9317,8 @@ declare module "swarm-extension" {
|
|
|
9252
9317
|
modelSource?: string | undefined;
|
|
9253
9318
|
modelAlias?: string | undefined;
|
|
9254
9319
|
resolvedEffort?: "off" | "low" | "medium" | "high" | "xhigh" | "max" | undefined;
|
|
9320
|
+
profile?: string | undefined;
|
|
9321
|
+
resolvedProfile?: string | undefined;
|
|
9255
9322
|
scheduleId?: string | undefined;
|
|
9256
9323
|
workflowRunId?: string | null | undefined;
|
|
9257
9324
|
workflowRunStepId?: string | null | undefined;
|
|
@@ -9931,6 +9998,512 @@ void _configIsValid;
|
|
|
9931
9998
|
|
|
9932
9999
|
// src/extensions/catalog.generated.json
|
|
9933
10000
|
var catalog_generated_default = {
|
|
10001
|
+
"comms-adherence-gate": {
|
|
10002
|
+
manifestFile: "manifest.json",
|
|
10003
|
+
manifest: {
|
|
10004
|
+
$schema: "../manifest.schema.json",
|
|
10005
|
+
name: "comms-adherence-gate",
|
|
10006
|
+
description: "Judges every Slack-facing store-progress completion against the requester's comms preferences and latest request with Jev (TypeSafe or OpenRouter), and in enforce blocks a non-adherent completion once per task",
|
|
10007
|
+
version: "1.5.0",
|
|
10008
|
+
runtime: "api",
|
|
10009
|
+
assets: {
|
|
10010
|
+
hooks: "hooks.ts"
|
|
10011
|
+
}
|
|
10012
|
+
},
|
|
10013
|
+
files: {
|
|
10014
|
+
"hooks.ts": `import { type ApiCtx, block, type SwarmExtension } from "swarm-extension";
|
|
10015
|
+
import { z } from "zod";
|
|
10016
|
+
|
|
10017
|
+
/**
|
|
10018
|
+
* comms-adherence-gate
|
|
10019
|
+
*
|
|
10020
|
+
* When an agent calls \`store-progress\` with status "completed" on a task that
|
|
10021
|
+
* reaches a human in Slack, judge the \`output\` against the requesting user's
|
|
10022
|
+
* stored comms preferences (users.metadata.$.comms) with Jev, and against what
|
|
10023
|
+
* that user actually asked for in their latest message. An explicit request
|
|
10024
|
+
* ("tell me a long joke", "explain in detail") outranks the stored default, so
|
|
10025
|
+
* a requested long answer is not a verbosity failure.
|
|
10026
|
+
*
|
|
10027
|
+
* Transport (config.provider): Jev is served by TypeSafe directly and by
|
|
10028
|
+
* OpenRouter's Decisions endpoint. Both take the same {model, state, questions}
|
|
10029
|
+
* body and return the same \`answers\` shape. \`auto\` uses TYPESAFE_API_KEY when
|
|
10030
|
+
* set, else OPENROUTER_API_KEY.
|
|
10031
|
+
*
|
|
10032
|
+
* modes (config.mode):
|
|
10033
|
+
* off -> never evaluate
|
|
10034
|
+
* shadow -> evaluate + record, never block (default)
|
|
10035
|
+
* enforce -> record, and block the completion up to maxBlocksPerTask times
|
|
10036
|
+
* per task with actionable feedback
|
|
10037
|
+
*
|
|
10038
|
+
* Fails OPEN on every error: a judge outage must never wall the swarm.
|
|
10039
|
+
* Every verdict lands in KV namespace \`ext:comms-gate\`.
|
|
10040
|
+
*/
|
|
10041
|
+
|
|
10042
|
+
export const config = z.object({
|
|
10043
|
+
mode: z.enum(["off", "shadow", "enforce"]).default("shadow"),
|
|
10044
|
+
/** A dimension scoring below this fails. */
|
|
10045
|
+
threshold: z.number().min(0).max(1).default(0.5),
|
|
10046
|
+
timeoutMs: z.number().int().positive().default(4000),
|
|
10047
|
+
maxBlocksPerTask: z.number().int().min(0).default(1),
|
|
10048
|
+
provider: z.enum(["auto", "typesafe", "openrouter"]).default("auto"),
|
|
10049
|
+
/** Jev model on the TypeSafe transport. */
|
|
10050
|
+
model: z.string().default("jev-latest"),
|
|
10051
|
+
/** Jev model on the OpenRouter transport. */
|
|
10052
|
+
openrouterModel: z.string().default("typesafe/jev-1.13"),
|
|
10053
|
+
/** Explicit TypeSafe key; otherwise TYPESAFE_API_KEY from the API process env. */
|
|
10054
|
+
apiKey: z.string().optional(),
|
|
10055
|
+
});
|
|
10056
|
+
|
|
10057
|
+
type Cfg = z.infer<typeof config>;
|
|
10058
|
+
type Swarm = ApiCtx["swarm"];
|
|
10059
|
+
|
|
10060
|
+
const NS = "ext:comms-gate";
|
|
10061
|
+
const TYPESAFE_ENDPOINT = "https://api.typesafe.ai/v1/systemone";
|
|
10062
|
+
const OPENROUTER_ENDPOINT = "https://openrouter.ai/api/alpha/decisions";
|
|
10063
|
+
const UUID_RE = /^[0-9a-fA-F-]{36}$/;
|
|
10064
|
+
// The dispatcher cancels a handler after 5 s; leave room for the DB read and KV writes.
|
|
10065
|
+
const MAX_TIMEOUT_MS = 4000;
|
|
10066
|
+
|
|
10067
|
+
export const cfgOf = (raw: unknown): Cfg => {
|
|
10068
|
+
const parsed = config.safeParse(raw ?? {});
|
|
10069
|
+
return parsed.success ? parsed.data : config.parse({});
|
|
10070
|
+
};
|
|
10071
|
+
|
|
10072
|
+
// kv keys accept [a-zA-Z0-9._:/%-]
|
|
10073
|
+
const safeKey = (raw: string | undefined | null): string =>
|
|
10074
|
+
(raw && raw.length > 0 ? raw : "unknown").replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 120);
|
|
10075
|
+
|
|
10076
|
+
/** SDK envelopes: {success, data:{...}} or the bare payload. */
|
|
10077
|
+
type Envelope = {
|
|
10078
|
+
data?: { rows?: unknown[]; value?: unknown };
|
|
10079
|
+
rows?: unknown[];
|
|
10080
|
+
value?: unknown;
|
|
10081
|
+
} | null;
|
|
10082
|
+
|
|
10083
|
+
const cell = (row: unknown, i: number, key: string): unknown =>
|
|
10084
|
+
Array.isArray(row) ? row[i] : (row as Record<string, unknown>)?.[key];
|
|
10085
|
+
|
|
10086
|
+
/**
|
|
10087
|
+
* The newest human message sits at the END of a Slack task: the
|
|
10088
|
+
* \`<thread_context>\` blob comes first and can run to thousands of chars, so a
|
|
10089
|
+
* leading slice of \`agent_tasks.task\` shows the judge everything except the
|
|
10090
|
+
* actual request. Take the tail, then the part after the last \`</thread_context>\`.
|
|
10091
|
+
*/
|
|
10092
|
+
const CTX_END = "</thread_context>";
|
|
10093
|
+
export const latestAsk = (tail: string): string => {
|
|
10094
|
+
const end = tail.lastIndexOf(CTX_END);
|
|
10095
|
+
let out = (end >= 0 ? tail.slice(end + CTX_END.length) : tail)
|
|
10096
|
+
.replace(/\\[Thread follow-up[^\\]]*\\]/g, "")
|
|
10097
|
+
.trim();
|
|
10098
|
+
// Some tasks end with the context block; fall back to the last messages in it.
|
|
10099
|
+
if (out.length < 8) out = (end >= 0 ? tail.slice(0, end) : tail).trim().slice(-800);
|
|
10100
|
+
return out.slice(0, 900);
|
|
10101
|
+
};
|
|
10102
|
+
|
|
10103
|
+
// Preferences are the DEFAULT. A direct request outranks them.
|
|
10104
|
+
const JUDGING_RULES = [
|
|
10105
|
+
"The requester's explicit instruction in latest_request OUTRANKS requester_preferences. Preferences describe the DEFAULT; they never override a direct request.",
|
|
10106
|
+
"If latest_request asks for something long, detailed, creative, a story, a joke, a full explanation or a document, then length and structure serving that request are CORRECT and must NOT be penalized.",
|
|
10107
|
+
"Judge whether agent_message serves what latest_request actually asked for, written in the requester's manner. Do not judge it against the default preference when the request overrides it.",
|
|
10108
|
+
];
|
|
10109
|
+
|
|
10110
|
+
type Prefs = { verbosity?: unknown; tone?: unknown; language?: unknown } & Record<string, unknown>;
|
|
10111
|
+
|
|
10112
|
+
/** One \`noul\` question per stated preference the gate knows how to judge. */
|
|
10113
|
+
export const buildQuestions = (prefs: Prefs): Record<string, unknown> => {
|
|
10114
|
+
const questions: Record<string, unknown> = {};
|
|
10115
|
+
if (prefs.verbosity) {
|
|
10116
|
+
questions.verbosity = {
|
|
10117
|
+
type: "noul",
|
|
10118
|
+
instructions:
|
|
10119
|
+
"Does agent_message respect the requester's verbosity preference, AS OVERRIDDEN by any explicit instruction in latest_request? Apply judging_rules.",
|
|
10120
|
+
criteria: {
|
|
10121
|
+
true: "Length and structure fit what latest_request asked for (or the stated preference when the request does not override it), and it leads with the result.",
|
|
10122
|
+
false:
|
|
10123
|
+
"Too long for what was asked, or it opens with preamble, recaps the request, narrates the process, or ends with an offer to elaborate. Length explicitly requested in latest_request is NOT a failure.",
|
|
10124
|
+
},
|
|
10125
|
+
};
|
|
10126
|
+
}
|
|
10127
|
+
if (prefs.tone) {
|
|
10128
|
+
questions.tone = {
|
|
10129
|
+
type: "noul",
|
|
10130
|
+
instructions:
|
|
10131
|
+
"Does agent_message match the requester's stated tone preference, as overridden by any explicit instruction in latest_request? Apply judging_rules.",
|
|
10132
|
+
criteria: {
|
|
10133
|
+
true: "The tone matches what the requester asked for.",
|
|
10134
|
+
false:
|
|
10135
|
+
"The tone conflicts with it (for example hedging, flattery or filler when the requester asked for direct and plain). A voice appropriate to an explicitly requested creative or narrative form is NOT a failure.",
|
|
10136
|
+
},
|
|
10137
|
+
};
|
|
10138
|
+
}
|
|
10139
|
+
if (prefs.language) {
|
|
10140
|
+
questions.language = {
|
|
10141
|
+
type: "noul",
|
|
10142
|
+
instructions: "Is agent_message written in the requester's stated language?",
|
|
10143
|
+
criteria: {
|
|
10144
|
+
true: "Written in the stated language.",
|
|
10145
|
+
false: "Written in a different language.",
|
|
10146
|
+
},
|
|
10147
|
+
};
|
|
10148
|
+
}
|
|
10149
|
+
return questions;
|
|
10150
|
+
};
|
|
10151
|
+
|
|
10152
|
+
const secretCache = new Map<string, { value: string; at: number }>();
|
|
10153
|
+
const KEY_TTL_MS = 5 * 60 * 1000;
|
|
10154
|
+
const usable = (v: string): boolean => Boolean(v) && !v.startsWith("[REDACTED");
|
|
10155
|
+
const envOf = (name: string): string => String(process.env[name] ?? "");
|
|
10156
|
+
|
|
10157
|
+
/**
|
|
10158
|
+
* Resolve a secret: explicit value, then the API process env. The API process loads
|
|
10159
|
+
* global swarm_config rows into process.env at boot and on config reload.
|
|
10160
|
+
* ctx.swarm.config_get cannot serve it: the SDK scrubs secrets to "[REDACTED:<name>]".
|
|
10161
|
+
*/
|
|
10162
|
+
const secret = (name: string, explicit?: string): string => {
|
|
10163
|
+
const cached = secretCache.get(name);
|
|
10164
|
+
if (cached && Date.now() - cached.at < KEY_TTL_MS) return cached.value;
|
|
10165
|
+
const value = [String(explicit ?? ""), envOf(name)].find(usable) ?? "";
|
|
10166
|
+
if (usable(value)) secretCache.set(name, { value, at: Date.now() });
|
|
10167
|
+
return value;
|
|
10168
|
+
};
|
|
10169
|
+
|
|
10170
|
+
/** Test hook: forget cached secrets. */
|
|
10171
|
+
export const resetKeyCache = (): void => {
|
|
10172
|
+
secretCache.clear();
|
|
10173
|
+
};
|
|
10174
|
+
|
|
10175
|
+
export type JevTransport = {
|
|
10176
|
+
provider: "typesafe" | "openrouter";
|
|
10177
|
+
endpoint: string;
|
|
10178
|
+
key: string;
|
|
10179
|
+
model: string;
|
|
10180
|
+
};
|
|
10181
|
+
|
|
10182
|
+
/**
|
|
10183
|
+
* Pick the Jev transport. \`auto\` prefers TypeSafe and falls back to OpenRouter.
|
|
10184
|
+
* Throws when the chosen provider has no usable key; the handler fails open.
|
|
10185
|
+
*/
|
|
10186
|
+
export const resolveTransport = (cfg: Cfg): JevTransport => {
|
|
10187
|
+
const typesafe = (): JevTransport | null => {
|
|
10188
|
+
const key = secret("TYPESAFE_API_KEY", cfg.apiKey);
|
|
10189
|
+
return usable(key)
|
|
10190
|
+
? { provider: "typesafe", endpoint: TYPESAFE_ENDPOINT, key, model: cfg.model }
|
|
10191
|
+
: null;
|
|
10192
|
+
};
|
|
10193
|
+
const openrouter = (): JevTransport | null => {
|
|
10194
|
+
const key = secret("OPENROUTER_API_KEY");
|
|
10195
|
+
return usable(key)
|
|
10196
|
+
? { provider: "openrouter", endpoint: OPENROUTER_ENDPOINT, key, model: cfg.openrouterModel }
|
|
10197
|
+
: null;
|
|
10198
|
+
};
|
|
10199
|
+
const transport =
|
|
10200
|
+
cfg.provider === "typesafe"
|
|
10201
|
+
? typesafe()
|
|
10202
|
+
: cfg.provider === "openrouter"
|
|
10203
|
+
? openrouter()
|
|
10204
|
+
: (typesafe() ?? openrouter());
|
|
10205
|
+
if (transport) return transport;
|
|
10206
|
+
throw new Error(
|
|
10207
|
+
cfg.provider === "typesafe"
|
|
10208
|
+
? "no TYPESAFE_API_KEY"
|
|
10209
|
+
: cfg.provider === "openrouter"
|
|
10210
|
+
? "no OPENROUTER_API_KEY"
|
|
10211
|
+
: "no TYPESAFE_API_KEY or OPENROUTER_API_KEY",
|
|
10212
|
+
);
|
|
10213
|
+
};
|
|
10214
|
+
|
|
10215
|
+
/** One Jev call; returns the \`noul\` score per question. Throws on any failure. */
|
|
10216
|
+
export const askJev = async (
|
|
10217
|
+
state: Record<string, unknown>,
|
|
10218
|
+
questions: Record<string, unknown>,
|
|
10219
|
+
transport: JevTransport,
|
|
10220
|
+
cfg: Cfg,
|
|
10221
|
+
outer?: AbortSignal,
|
|
10222
|
+
): Promise<{ scores: Record<string, number>; latencyMs: number }> => {
|
|
10223
|
+
const controller = new AbortController();
|
|
10224
|
+
const timer = setTimeout(() => controller.abort(), Math.min(cfg.timeoutMs, MAX_TIMEOUT_MS));
|
|
10225
|
+
const onOuterAbort = () => controller.abort();
|
|
10226
|
+
outer?.addEventListener("abort", onOuterAbort);
|
|
10227
|
+
const t0 = Date.now();
|
|
10228
|
+
try {
|
|
10229
|
+
const res = await fetch(transport.endpoint, {
|
|
10230
|
+
method: "POST",
|
|
10231
|
+
headers: { "Content-Type": "application/json", Authorization: \`Bearer \${transport.key}\` },
|
|
10232
|
+
body: JSON.stringify({ state, model: transport.model, questions }),
|
|
10233
|
+
signal: controller.signal,
|
|
10234
|
+
});
|
|
10235
|
+
if (!res.ok) throw new Error(\`\${transport.provider} \${res.status}\`);
|
|
10236
|
+
const body = (await res.json()) as { answers?: Record<string, { noul?: unknown }> } | null;
|
|
10237
|
+
const answers = body?.answers;
|
|
10238
|
+
if (!answers || typeof answers !== "object") throw new Error("no answers in response");
|
|
10239
|
+
const scores: Record<string, number> = {};
|
|
10240
|
+
for (const [id, a] of Object.entries(answers)) {
|
|
10241
|
+
if (typeof a?.noul === "number") scores[id] = a.noul;
|
|
10242
|
+
}
|
|
10243
|
+
if (Object.keys(scores).length === 0) throw new Error("no scores in response");
|
|
10244
|
+
return { scores, latencyMs: Date.now() - t0 };
|
|
10245
|
+
} finally {
|
|
10246
|
+
clearTimeout(timer);
|
|
10247
|
+
outer?.removeEventListener("abort", onOuterAbort);
|
|
10248
|
+
}
|
|
10249
|
+
};
|
|
10250
|
+
|
|
10251
|
+
const SELFTEST = "comms-gate-selftest";
|
|
10252
|
+
const SELFTEST_PREFS = {
|
|
10253
|
+
tone: "direct, plain, no hedging",
|
|
10254
|
+
language: "English",
|
|
10255
|
+
verbosity:
|
|
10256
|
+
"very terse - answer in the first sentence, ~400 chars max. No preamble, no recap, no closing offer.",
|
|
10257
|
+
};
|
|
10258
|
+
const SELFTEST_BAD =
|
|
10259
|
+
"Great question! Let me walk you through what I did here. First I looked at the task, then I reviewed the relevant files, and after careful consideration I decided to go with option B. I hope this helps - let me know if you would like me to elaborate further on any of the above!";
|
|
10260
|
+
const SELFTEST_GOOD =
|
|
10261
|
+
"Went with option B: it is the only one that keeps the migration reversible. PR #123.";
|
|
10262
|
+
|
|
10263
|
+
/**
|
|
10264
|
+
* Run the judge on a known-bad (positive control, must score below threshold) and a
|
|
10265
|
+
* known-good (negative control, must score at or above it) message and record both
|
|
10266
|
+
* under \`selftest:last\`. Proves key, egress and KV from inside the API runtime
|
|
10267
|
+
* without touching real traffic.
|
|
10268
|
+
*/
|
|
10269
|
+
const selfTest = async (swarm: Swarm, cfg: Cfg, signal?: AbortSignal): Promise<void> => {
|
|
10270
|
+
const started = Date.now();
|
|
10271
|
+
try {
|
|
10272
|
+
const transport = resolveTransport(cfg);
|
|
10273
|
+
const questions = { verbosity: buildQuestions(SELFTEST_PREFS).verbosity };
|
|
10274
|
+
const judge = (message: string) =>
|
|
10275
|
+
askJev(
|
|
10276
|
+
{ requester_preferences: SELFTEST_PREFS, agent_message: message },
|
|
10277
|
+
questions,
|
|
10278
|
+
transport,
|
|
10279
|
+
cfg,
|
|
10280
|
+
signal,
|
|
10281
|
+
).then((r) => r.scores.verbosity ?? null);
|
|
10282
|
+
const [bad, good] = await Promise.all([judge(SELFTEST_BAD), judge(SELFTEST_GOOD)]);
|
|
10283
|
+
await swarm.kv_set({
|
|
10284
|
+
namespace: NS,
|
|
10285
|
+
key: "selftest:last",
|
|
10286
|
+
value: {
|
|
10287
|
+
at: new Date().toISOString(),
|
|
10288
|
+
provider: transport.provider,
|
|
10289
|
+
threshold: cfg.threshold,
|
|
10290
|
+
positiveControlBadScore: bad,
|
|
10291
|
+
negativeControlGoodScore: good,
|
|
10292
|
+
controlsOk:
|
|
10293
|
+
typeof bad === "number" &&
|
|
10294
|
+
typeof good === "number" &&
|
|
10295
|
+
bad < cfg.threshold &&
|
|
10296
|
+
good >= cfg.threshold,
|
|
10297
|
+
latencyMs: Date.now() - started,
|
|
10298
|
+
},
|
|
10299
|
+
});
|
|
10300
|
+
} catch (err) {
|
|
10301
|
+
await swarm
|
|
10302
|
+
.kv_set({
|
|
10303
|
+
namespace: NS,
|
|
10304
|
+
key: "selftest:last",
|
|
10305
|
+
value: {
|
|
10306
|
+
at: new Date().toISOString(),
|
|
10307
|
+
error: String(err).slice(0, 400),
|
|
10308
|
+
latencyMs: Date.now() - started,
|
|
10309
|
+
},
|
|
10310
|
+
})
|
|
10311
|
+
.catch(() => {});
|
|
10312
|
+
}
|
|
10313
|
+
};
|
|
10314
|
+
|
|
10315
|
+
const TASK_SQL = \`SELECT t.source, t.slackThreadTs, t.agentId, t.requestedByUserId,
|
|
10316
|
+
json_extract(u.metadata, '$.comms') AS comms, u.name,
|
|
10317
|
+
substr(t.task, 1, 400) AS askHead,
|
|
10318
|
+
substr(t.task, -1400) AS askTail
|
|
10319
|
+
FROM agent_tasks t
|
|
10320
|
+
LEFT JOIN users u ON u.id = t.requestedByUserId
|
|
10321
|
+
WHERE t.id = ?\`;
|
|
10322
|
+
|
|
10323
|
+
const LEAD_SQL = "SELECT isLead FROM agents WHERE id = ?";
|
|
10324
|
+
|
|
10325
|
+
/**
|
|
10326
|
+
* Mirrors the \`task.progress.write\` rule store-progress enforces
|
|
10327
|
+
* (src/rbac/legacy-policy.ts): the caller owns the task, the task is
|
|
10328
|
+
* unassigned, or the caller is a lead. Lead status comes from the caller's
|
|
10329
|
+
* agents row, never from tool args. Extension callers return before this.
|
|
10330
|
+
*/
|
|
10331
|
+
const mayWriteProgress = async (
|
|
10332
|
+
swarm: Swarm,
|
|
10333
|
+
callerId: string | undefined,
|
|
10334
|
+
taskAgentId: string,
|
|
10335
|
+
): Promise<boolean> => {
|
|
10336
|
+
if (!callerId) return false;
|
|
10337
|
+
if (!taskAgentId || taskAgentId === callerId) return true;
|
|
10338
|
+
const q = (await swarm.db_query({ sql: LEAD_SQL, params: [callerId] })) as Envelope;
|
|
10339
|
+
const row = (q?.data?.rows ?? q?.rows ?? [])[0];
|
|
10340
|
+
return Number(cell(row, 0, "isLead") ?? 0) === 1;
|
|
10341
|
+
};
|
|
10342
|
+
|
|
10343
|
+
const extension: SwarmExtension = (api) => {
|
|
10344
|
+
api.on("pre.tool.call", async (event, ctx) => {
|
|
10345
|
+
if (event.tool !== "store-progress") return;
|
|
10346
|
+
if (event.requestInfo?.callOrigin === "extension") return;
|
|
10347
|
+
|
|
10348
|
+
const cfg = cfgOf(ctx.config);
|
|
10349
|
+
if (cfg.mode === "off") return;
|
|
10350
|
+
|
|
10351
|
+
const args = (event.args ?? {}) as Record<string, unknown>;
|
|
10352
|
+
|
|
10353
|
+
// Self-test hatch: a progress call whose text starts with the sentinel runs
|
|
10354
|
+
// the controls and records them under \`selftest:last\`.
|
|
10355
|
+
if (args.status !== "completed") {
|
|
10356
|
+
if (typeof args.progress === "string" && args.progress.startsWith(SELFTEST)) {
|
|
10357
|
+
await selfTest(ctx.swarm, cfg, ctx.signal);
|
|
10358
|
+
}
|
|
10359
|
+
return;
|
|
10360
|
+
}
|
|
10361
|
+
|
|
10362
|
+
const output = typeof args.output === "string" ? args.output.trim() : "";
|
|
10363
|
+
if (!output) return;
|
|
10364
|
+
|
|
10365
|
+
const taskId = String(args.taskId ?? event.requestInfo?.sourceTaskId ?? "");
|
|
10366
|
+
if (!UUID_RE.test(taskId)) return;
|
|
10367
|
+
|
|
10368
|
+
try {
|
|
10369
|
+
const q = (await ctx.swarm.db_query({ sql: TASK_SQL, params: [taskId] })) as Envelope;
|
|
10370
|
+
const row = (q?.data?.rows ?? q?.rows ?? [])[0];
|
|
10371
|
+
if (!row) return;
|
|
10372
|
+
|
|
10373
|
+
const source = String(cell(row, 0, "source") ?? "");
|
|
10374
|
+
const slackThreadTs = cell(row, 1, "slackThreadTs");
|
|
10375
|
+
const agentId = String(cell(row, 2, "agentId") ?? "");
|
|
10376
|
+
const requesterId = String(cell(row, 3, "requestedByUserId") ?? "");
|
|
10377
|
+
const commsRaw = cell(row, 4, "comms");
|
|
10378
|
+
const requesterName = String(cell(row, 5, "name") ?? requesterId);
|
|
10379
|
+
const threadOpening = String(cell(row, 6, "askHead") ?? "");
|
|
10380
|
+
const ask = latestAsk(String(cell(row, 7, "askTail") ?? ""));
|
|
10381
|
+
|
|
10382
|
+
// Judge only a completion store-progress will accept, so no agent can ship
|
|
10383
|
+
// another task's thread and preferences to the external judge.
|
|
10384
|
+
if (!(await mayWriteProgress(ctx.swarm, event.requestInfo?.agentId, agentId))) return;
|
|
10385
|
+
|
|
10386
|
+
// Only where the text actually reaches a human in Slack.
|
|
10387
|
+
if (source !== "slack" && !slackThreadTs) return;
|
|
10388
|
+
if (!commsRaw) return; // no stated preferences -> nothing to judge against
|
|
10389
|
+
const prefs = (typeof commsRaw === "string" ? JSON.parse(commsRaw) : commsRaw) as Prefs;
|
|
10390
|
+
if (!prefs || typeof prefs !== "object") return;
|
|
10391
|
+
|
|
10392
|
+
const questions = buildQuestions(prefs);
|
|
10393
|
+
if (Object.keys(questions).length === 0) return;
|
|
10394
|
+
|
|
10395
|
+
const transport = resolveTransport(cfg);
|
|
10396
|
+
const { scores, latencyMs } = await askJev(
|
|
10397
|
+
{
|
|
10398
|
+
role: "You audit an AI agent's final message to the human who requested the work.",
|
|
10399
|
+
requester: requesterName,
|
|
10400
|
+
requester_preferences: prefs,
|
|
10401
|
+
latest_request: ask,
|
|
10402
|
+
thread_opening: threadOpening,
|
|
10403
|
+
judging_rules: JUDGING_RULES,
|
|
10404
|
+
agent_message: output,
|
|
10405
|
+
},
|
|
10406
|
+
questions,
|
|
10407
|
+
transport,
|
|
10408
|
+
cfg,
|
|
10409
|
+
ctx.signal,
|
|
10410
|
+
);
|
|
10411
|
+
|
|
10412
|
+
const failed = Object.entries(scores)
|
|
10413
|
+
.filter(([, v]) => v < cfg.threshold)
|
|
10414
|
+
.map(([k]) => k);
|
|
10415
|
+
|
|
10416
|
+
const verdict = {
|
|
10417
|
+
at: new Date().toISOString(),
|
|
10418
|
+
taskId,
|
|
10419
|
+
agentId,
|
|
10420
|
+
source,
|
|
10421
|
+
requester: requesterName,
|
|
10422
|
+
requesterId,
|
|
10423
|
+
provider: transport.provider,
|
|
10424
|
+
scores,
|
|
10425
|
+
failed,
|
|
10426
|
+
threshold: cfg.threshold,
|
|
10427
|
+
mode: cfg.mode,
|
|
10428
|
+
latencyMs,
|
|
10429
|
+
preferences: prefs,
|
|
10430
|
+
askPreview: ask.slice(0, 400),
|
|
10431
|
+
outputPreview: output.slice(0, 700),
|
|
10432
|
+
};
|
|
10433
|
+
|
|
10434
|
+
await ctx.swarm.kv_incr({ namespace: NS, key: "total" });
|
|
10435
|
+
await ctx.swarm.kv_set({ namespace: NS, key: "last", value: verdict });
|
|
10436
|
+
|
|
10437
|
+
if (failed.length === 0) {
|
|
10438
|
+
await ctx.swarm.kv_incr({ namespace: NS, key: "pass" });
|
|
10439
|
+
return;
|
|
10440
|
+
}
|
|
10441
|
+
|
|
10442
|
+
await ctx.swarm.kv_incr({ namespace: NS, key: "fail" });
|
|
10443
|
+
for (const dim of failed) {
|
|
10444
|
+
await ctx.swarm.kv_incr({ namespace: NS, key: \`dim:\${safeKey(dim)}\` });
|
|
10445
|
+
}
|
|
10446
|
+
|
|
10447
|
+
const blocksKey = \`blocks:\${safeKey(taskId)}\`;
|
|
10448
|
+
// kv_get answers {success, data:{value}}, and {success:false} when absent.
|
|
10449
|
+
const prior = (await ctx.swarm.kv_get({ namespace: NS, key: blocksKey })) as Envelope;
|
|
10450
|
+
const priorBlocks = Number(prior?.data?.value ?? prior?.value ?? 0) || 0;
|
|
10451
|
+
const willBlock = cfg.mode === "enforce" && priorBlocks < cfg.maxBlocksPerTask;
|
|
10452
|
+
|
|
10453
|
+
await ctx.swarm.kv_set({
|
|
10454
|
+
namespace: NS,
|
|
10455
|
+
key: \`fail:\${Date.now()}:\${safeKey(taskId)}\`,
|
|
10456
|
+
value: { ...verdict, action: willBlock ? "blocked" : "recorded" },
|
|
10457
|
+
});
|
|
10458
|
+
|
|
10459
|
+
if (!willBlock) {
|
|
10460
|
+
await ctx.swarm.kv_incr({
|
|
10461
|
+
namespace: NS,
|
|
10462
|
+
key: cfg.mode === "enforce" ? "escaped" : "shadowed",
|
|
10463
|
+
});
|
|
10464
|
+
return;
|
|
10465
|
+
}
|
|
10466
|
+
|
|
10467
|
+
await ctx.swarm.kv_incr({ namespace: NS, key: "blocked" });
|
|
10468
|
+
await ctx.swarm.kv_incr({ namespace: NS, key: blocksKey });
|
|
10469
|
+
|
|
10470
|
+
const detail = failed
|
|
10471
|
+
.map(
|
|
10472
|
+
(d) =>
|
|
10473
|
+
\`\${d} (\${scores[d]!.toFixed(2)} vs \${cfg.threshold}) — requested: \${String(prefs[d] ?? "").slice(0, 220)}\`,
|
|
10474
|
+
)
|
|
10475
|
+
.join("\\n");
|
|
10476
|
+
|
|
10477
|
+
return block(
|
|
10478
|
+
[
|
|
10479
|
+
\`Comms gate: this output does not match \${requesterName}'s stated preferences.\`,
|
|
10480
|
+
detail,
|
|
10481
|
+
"Rewrite the output to match and call store-progress again. Do not change the facts, only how they are said.",
|
|
10482
|
+
].join("\\n"),
|
|
10483
|
+
);
|
|
10484
|
+
} catch (err) {
|
|
10485
|
+
// Fail open, always.
|
|
10486
|
+
try {
|
|
10487
|
+
await ctx.swarm.kv_incr({ namespace: NS, key: "error" });
|
|
10488
|
+
await ctx.swarm.kv_set({
|
|
10489
|
+
namespace: NS,
|
|
10490
|
+
key: "error:last",
|
|
10491
|
+
value: { at: new Date().toISOString(), taskId, error: String(err).slice(0, 400) },
|
|
10492
|
+
});
|
|
10493
|
+
} catch {
|
|
10494
|
+
/* ignore */
|
|
10495
|
+
}
|
|
10496
|
+
ctx.log.warn("comms-adherence-gate: failing open", { error: String(err) });
|
|
10497
|
+
return;
|
|
10498
|
+
}
|
|
10499
|
+
});
|
|
10500
|
+
};
|
|
10501
|
+
|
|
10502
|
+
export default extension;
|
|
10503
|
+
`
|
|
10504
|
+
},
|
|
10505
|
+
readme: '# comms-adherence-gate\n\nAgents finish Slack tasks with a final message a human reads. This extension judges that message against the requester\'s stated comms preferences and their latest request with Jev, [TypeSafe](https://typesafe.ai)\'s decision model. In `enforce` it blocks a non-adherent completion once and tells the agent what to fix.\n\nInstall config:\n\n```json\n{ "mode": "shadow" }\n```\n\nStart in `shadow`, read the verdicts in KV for a few days, then switch to `enforce`.\n\n## Modes\n\n| `mode` | Effect |\n|---|---|\n| `off` | Never evaluates. |\n| `shadow` (default) | Asks Jev and records the verdict. Never blocks. |\n| `enforce` | Asks Jev, records the verdict, and blocks the `store-progress` call when a dimension fails, at most `maxBlocksPerTask` times per task. The agent gets the failed dimensions, their scores and the stated preference, and calls again. |\n\n## What it gates\n\nHook: `pre.tool.call` on `store-progress` with `status: "completed"` and a non-empty `output`. Calls made by extensions are skipped. The task must:\n\n1. Come from Slack (`source = "slack"` or a `slackThreadTs`). Other tasks pass without a Jev call.\n2. Have a requester with stated preferences in `users.metadata.comms`. A requester with none passes. Set them with the `manage-user` tool.\n\n## Decision\n\nThe gate reads the task row and asks one `noul` question per stated preference it knows: `verbosity`, `tone`, `language`. Any other key in `comms` is context only.\n\nJev sees the preferences, the requester\'s latest message (the text after the last `</thread_context>`, from the last 1,400 characters of the task), the first 400 characters of the task, and the output. Its judging rules say an explicit request outranks the stored default. A requested long answer, story or document is not a verbosity failure.\n\nA dimension fails when its score is below `threshold`. Any failed dimension fails the output.\n\n## Jev transport\n\nJev is reachable two ways. Both take the same request and return the same answer.\n\n| `provider` | Endpoint | Key | Model |\n|---|---|---|---|\n| `typesafe` | `POST https://api.typesafe.ai/v1/systemone` | `TYPESAFE_API_KEY` (or `apiKey`) | `model`, default `jev-latest` |\n| `openrouter` | `POST https://openrouter.ai/api/alpha/decisions` | `OPENROUTER_API_KEY` | `openrouterModel`, default `typesafe/jev-1.13` |\n| `auto` (default) | TypeSafe when its key is set, else OpenRouter | | |\n\nEach verdict row records the `provider` that answered.\n\n## Fail open\n\nEvery error lets the completion through: a missing key, an HTTP error, a network error, a timeout, a malformed answer, or a failed DB read. The handler never throws, so an outage cannot auto-disable the extension. Each failure bumps the `error` counter and overwrites `error:last`.\n\n## Self-test\n\nCall `store-progress` with a non-completed status and `progress` starting with `comms-gate-selftest`. The gate judges a known-bad and a known-good message against a terse preference and writes `selftest:last`: both scores, the threshold, the provider, and `controlsOk` (bad below threshold and good at or above it). Real traffic is untouched.\n\n## Config\n\n| Key | Default | Notes |\n|---|---|---|\n| `mode` | `shadow` | `off`, `shadow`, or `enforce` |\n| `threshold` | `0.5` | A dimension scoring below this fails |\n| `timeoutMs` | `4000` | Jev call timeout, capped at 4000 (the dispatcher cancels a handler at 5 s) |\n| `maxBlocksPerTask` | `1` | Blocks per task in `enforce`; after that the gate records and lets it through |\n| `provider` | `auto` | `auto`, `typesafe`, or `openrouter`. See [Jev transport](#jev-transport) |\n| `model` | `jev-latest` | Jev model on TypeSafe |\n| `openrouterModel` | `typesafe/jev-1.13` | Jev model on OpenRouter |\n| `apiKey` | unset | Explicit TypeSafe key. Prefer the `TYPESAFE_API_KEY` secret below |\n\n## Required secrets\n\nRead from the API process environment at call time. Set them as global `swarm_config` secrets: the API process loads global rows into `process.env` at boot and on config reload.\n\n- `TYPESAFE_API_KEY` or `OPENROUTER_API_KEY`: one is required for any evaluation. Under `auto`, TypeSafe wins when both are set. Without either, every completion fails open.\n\nNo key is written to config, KV, logs, or a block reason.\n\n## KV namespace `ext:comms-gate`\n\n- `last`: the latest verdict, with `scores`, `failed`, `provider`, `latencyMs`, the preferences, a 400-character `askPreview` and a 700-character `outputPreview`.\n- `fail:<epochMs>:<taskId>`: one row per failed verdict, with `action` (`blocked` or `recorded`).\n- `blocks:<taskId>`: blocks issued for that task.\n- `error:last`, `selftest:last`.\n- Counters: `total`, `pass`, `fail`, `blocked`, `escaped` (enforce, block budget spent), `shadowed`, `error`, and `dim:<dimension>`.\n\n## Known limits\n\n- Only the last 1,400 characters of the task are searched for the latest request. A very long final message is cut to its last 900 characters.\n- The block budget is per task, so a retried completion after a block goes through once the budget is spent, even if it still fails.\n'
|
|
10506
|
+
},
|
|
9934
10507
|
"deploy-awareness": {
|
|
9935
10508
|
manifestFile: "manifest.json",
|
|
9936
10509
|
manifest: {
|
|
@@ -18907,6 +19480,237 @@ async function handleMetrics(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
18907
19480
|
return false;
|
|
18908
19481
|
}
|
|
18909
19482
|
|
|
19483
|
+
// src/http/model-profiles.ts
|
|
19484
|
+
init_src();
|
|
19485
|
+
init_zod();
|
|
19486
|
+
init_model_profiles();
|
|
19487
|
+
init_rbac();
|
|
19488
|
+
init_types();
|
|
19489
|
+
var listProfiles = route({
|
|
19490
|
+
method: "get",
|
|
19491
|
+
path: "/api/model-profiles",
|
|
19492
|
+
pattern: ["api", "model-profiles"],
|
|
19493
|
+
summary: "List model profiles",
|
|
19494
|
+
description: "Every model profile, ordered by harness then name. Filter by `harness` to see what an agent on that harness can run.",
|
|
19495
|
+
tags: ["Models"],
|
|
19496
|
+
query: exports_external.object({ harness: ProviderNameSchema.optional() }),
|
|
19497
|
+
responses: {
|
|
19498
|
+
200: {
|
|
19499
|
+
description: "Model profiles",
|
|
19500
|
+
schema: exports_external.object({ profiles: exports_external.array(ModelProfileSchema) })
|
|
19501
|
+
}
|
|
19502
|
+
}
|
|
19503
|
+
});
|
|
19504
|
+
var getProfile = route({
|
|
19505
|
+
method: "get",
|
|
19506
|
+
path: "/api/model-profiles/{name}",
|
|
19507
|
+
pattern: ["api", "model-profiles", null],
|
|
19508
|
+
summary: "Get one model profile",
|
|
19509
|
+
tags: ["Models"],
|
|
19510
|
+
params: exports_external.object({ name: exports_external.string() }),
|
|
19511
|
+
responses: {
|
|
19512
|
+
200: { description: "The model profile", schema: ModelProfileSchema },
|
|
19513
|
+
404: { description: "No profile with that name" }
|
|
19514
|
+
}
|
|
19515
|
+
});
|
|
19516
|
+
var createProfile = route({
|
|
19517
|
+
method: "post",
|
|
19518
|
+
path: "/api/model-profiles",
|
|
19519
|
+
pattern: ["api", "model-profiles"],
|
|
19520
|
+
summary: "Create a model profile",
|
|
19521
|
+
description: "A profile runs on one harness. `model` must run on that harness and be in the model catalog unless `allowCustomModel` is true (a gateway id, a fresh launch); a `latest:` alias is accepted and resolves at claim. `effort` must be a level the harness and model support. Operator only (the shared API key).",
|
|
19522
|
+
tags: ["Models"],
|
|
19523
|
+
rbac: { permission: "models.profiles.write" },
|
|
19524
|
+
body: exports_external.object({
|
|
19525
|
+
name: ModelProfileNameSchema,
|
|
19526
|
+
harness: ProviderNameSchema,
|
|
19527
|
+
model: exports_external.string().trim().min(1),
|
|
19528
|
+
effort: ReasoningEffortSchema.nullable().optional(),
|
|
19529
|
+
allowCustomModel: exports_external.boolean().optional().default(false),
|
|
19530
|
+
description: exports_external.string().trim().max(500).nullable().optional()
|
|
19531
|
+
}),
|
|
19532
|
+
responses: {
|
|
19533
|
+
201: { description: "Profile created", schema: ModelProfileSchema },
|
|
19534
|
+
400: { description: "Validation error" },
|
|
19535
|
+
403: { description: "Forbidden" },
|
|
19536
|
+
409: { description: "A profile with that name exists" }
|
|
19537
|
+
}
|
|
19538
|
+
});
|
|
19539
|
+
var updateProfile = route({
|
|
19540
|
+
method: "patch",
|
|
19541
|
+
path: "/api/model-profiles/{name}",
|
|
19542
|
+
pattern: ["api", "model-profiles", null],
|
|
19543
|
+
summary: "Update a model profile",
|
|
19544
|
+
description: "Changes the model, effort, custom-model flag or description; the name and harness are fixed. Omit a field to keep it; `effort: null` clears it. Applies to tasks claimed after the change. Operator only (the shared API key).",
|
|
19545
|
+
tags: ["Models"],
|
|
19546
|
+
rbac: { permission: "models.profiles.write" },
|
|
19547
|
+
params: exports_external.object({ name: exports_external.string() }),
|
|
19548
|
+
body: exports_external.object({
|
|
19549
|
+
model: exports_external.string().trim().min(1).optional(),
|
|
19550
|
+
effort: ReasoningEffortSchema.nullable().optional(),
|
|
19551
|
+
allowCustomModel: exports_external.boolean().optional(),
|
|
19552
|
+
description: exports_external.string().trim().max(500).nullable().optional()
|
|
19553
|
+
}),
|
|
19554
|
+
responses: {
|
|
19555
|
+
200: { description: "Profile updated", schema: ModelProfileSchema },
|
|
19556
|
+
400: { description: "Validation error" },
|
|
19557
|
+
403: { description: "Forbidden" },
|
|
19558
|
+
404: { description: "No profile with that name" }
|
|
19559
|
+
}
|
|
19560
|
+
});
|
|
19561
|
+
var deleteProfile = route({
|
|
19562
|
+
method: "delete",
|
|
19563
|
+
path: "/api/model-profiles/{name}",
|
|
19564
|
+
pattern: ["api", "model-profiles", null],
|
|
19565
|
+
summary: "Delete a model profile",
|
|
19566
|
+
description: "Refused (409) for a shipped `<harness>-<tier>` seed (edit it instead; it would come back at the next boot), and while an agent has the profile as its default or a task holds it (unfinished, or superseded and still owed its resume). Operator only (the shared API key).",
|
|
19567
|
+
tags: ["Models"],
|
|
19568
|
+
rbac: { permission: "models.profiles.write" },
|
|
19569
|
+
params: exports_external.object({ name: exports_external.string() }),
|
|
19570
|
+
responses: {
|
|
19571
|
+
200: { description: "Profile deleted", schema: exports_external.object({ deleted: exports_external.literal(true) }) },
|
|
19572
|
+
403: { description: "Forbidden" },
|
|
19573
|
+
404: { description: "No profile with that name" },
|
|
19574
|
+
409: { description: "The profile is a seed or still in use" }
|
|
19575
|
+
}
|
|
19576
|
+
});
|
|
19577
|
+
async function profileValueError(input) {
|
|
19578
|
+
const modelError = await explicitModelError({
|
|
19579
|
+
model: input.model,
|
|
19580
|
+
allowCustomModel: input.allowCustomModel,
|
|
19581
|
+
harnessProvider: input.harness
|
|
19582
|
+
});
|
|
19583
|
+
if (modelError)
|
|
19584
|
+
return modelError;
|
|
19585
|
+
if (input.effort && !isAlias(input.model) && !supportedReasoningLevels(input.harness, input.model).includes(input.effort)) {
|
|
19586
|
+
return `Effort "${input.effort}" is not supported by ${input.model} on ${input.harness}.`;
|
|
19587
|
+
}
|
|
19588
|
+
return null;
|
|
19589
|
+
}
|
|
19590
|
+
async function canWriteProfiles(req, res, myAgentId) {
|
|
19591
|
+
const decision = can({
|
|
19592
|
+
principal: await agentFirstPrincipal(req, myAgentId),
|
|
19593
|
+
verb: "models.profiles.write",
|
|
19594
|
+
resource: { kind: "none" },
|
|
19595
|
+
source: "http"
|
|
19596
|
+
});
|
|
19597
|
+
if (!decision.allow) {
|
|
19598
|
+
jsonError(res, "Writing model profiles requires the operator", 403);
|
|
19599
|
+
return false;
|
|
19600
|
+
}
|
|
19601
|
+
return true;
|
|
19602
|
+
}
|
|
19603
|
+
async function handleModelProfiles(req, res, pathSegments, queryParams, myAgentId) {
|
|
19604
|
+
if (listProfiles.match(req.method, pathSegments)) {
|
|
19605
|
+
const parsed = await listProfiles.parse(req, res, pathSegments, queryParams);
|
|
19606
|
+
if (!parsed)
|
|
19607
|
+
return true;
|
|
19608
|
+
listProfiles.respond(res, 200, {
|
|
19609
|
+
profiles: await listModelProfiles({ harness: parsed.query.harness })
|
|
19610
|
+
});
|
|
19611
|
+
return true;
|
|
19612
|
+
}
|
|
19613
|
+
if (getProfile.match(req.method, pathSegments)) {
|
|
19614
|
+
const parsed = await getProfile.parse(req, res, pathSegments, queryParams);
|
|
19615
|
+
if (!parsed)
|
|
19616
|
+
return true;
|
|
19617
|
+
const profile = await getModelProfileByName(parsed.params.name);
|
|
19618
|
+
if (!profile) {
|
|
19619
|
+
jsonError(res, "Model profile not found", 404);
|
|
19620
|
+
return true;
|
|
19621
|
+
}
|
|
19622
|
+
getProfile.respond(res, 200, profile);
|
|
19623
|
+
return true;
|
|
19624
|
+
}
|
|
19625
|
+
if (createProfile.match(req.method, pathSegments)) {
|
|
19626
|
+
const parsed = await createProfile.parse(req, res, pathSegments, queryParams);
|
|
19627
|
+
if (!parsed)
|
|
19628
|
+
return true;
|
|
19629
|
+
if (!await canWriteProfiles(req, res, myAgentId))
|
|
19630
|
+
return true;
|
|
19631
|
+
const body = parsed.body;
|
|
19632
|
+
const error = await profileValueError({ ...body, effort: body.effort ?? null });
|
|
19633
|
+
if (error) {
|
|
19634
|
+
jsonError(res, error, 400);
|
|
19635
|
+
return true;
|
|
19636
|
+
}
|
|
19637
|
+
const created = await createModelProfile(body, {
|
|
19638
|
+
userId: await resolveHttpAuditUserId(req, myAgentId)
|
|
19639
|
+
});
|
|
19640
|
+
if (!created) {
|
|
19641
|
+
jsonError(res, `Model profile "${body.name}" already exists`, 409);
|
|
19642
|
+
return true;
|
|
19643
|
+
}
|
|
19644
|
+
createProfile.respond(res, 201, created);
|
|
19645
|
+
return true;
|
|
19646
|
+
}
|
|
19647
|
+
if (updateProfile.match(req.method, pathSegments)) {
|
|
19648
|
+
const parsed = await updateProfile.parse(req, res, pathSegments, queryParams);
|
|
19649
|
+
if (!parsed)
|
|
19650
|
+
return true;
|
|
19651
|
+
if (!await canWriteProfiles(req, res, myAgentId))
|
|
19652
|
+
return true;
|
|
19653
|
+
const current = await getModelProfileByName(parsed.params.name);
|
|
19654
|
+
if (!current) {
|
|
19655
|
+
jsonError(res, "Model profile not found", 404);
|
|
19656
|
+
return true;
|
|
19657
|
+
}
|
|
19658
|
+
const body = parsed.body;
|
|
19659
|
+
const error = await profileValueError({
|
|
19660
|
+
harness: current.harness,
|
|
19661
|
+
model: body.model ?? current.model,
|
|
19662
|
+
effort: body.effort === undefined ? current.effort : body.effort,
|
|
19663
|
+
allowCustomModel: body.allowCustomModel ?? current.allowCustomModel
|
|
19664
|
+
});
|
|
19665
|
+
if (error) {
|
|
19666
|
+
jsonError(res, error, 400);
|
|
19667
|
+
return true;
|
|
19668
|
+
}
|
|
19669
|
+
const updated = await updateModelProfile(current.name, body, {
|
|
19670
|
+
userId: await resolveHttpAuditUserId(req, myAgentId)
|
|
19671
|
+
});
|
|
19672
|
+
if (!updated) {
|
|
19673
|
+
jsonError(res, "Model profile not found", 404);
|
|
19674
|
+
return true;
|
|
19675
|
+
}
|
|
19676
|
+
updateProfile.respond(res, 200, updated);
|
|
19677
|
+
return true;
|
|
19678
|
+
}
|
|
19679
|
+
if (deleteProfile.match(req.method, pathSegments)) {
|
|
19680
|
+
const parsed = await deleteProfile.parse(req, res, pathSegments, queryParams);
|
|
19681
|
+
if (!parsed)
|
|
19682
|
+
return true;
|
|
19683
|
+
if (!await canWriteProfiles(req, res, myAgentId))
|
|
19684
|
+
return true;
|
|
19685
|
+
const current = await getModelProfileByName(parsed.params.name);
|
|
19686
|
+
if (!current) {
|
|
19687
|
+
jsonError(res, "Model profile not found", 404);
|
|
19688
|
+
return true;
|
|
19689
|
+
}
|
|
19690
|
+
if (current.seededFrom?.startsWith("tier:")) {
|
|
19691
|
+
jsonError(res, `"${current.name}" is a shipped tier profile and comes back at the next boot; edit it instead.`, 409);
|
|
19692
|
+
return true;
|
|
19693
|
+
}
|
|
19694
|
+
const refs = await modelProfileReferences(current.name);
|
|
19695
|
+
if (refs.agentIds.length > 0 || refs.openTaskCount > 0) {
|
|
19696
|
+
jsonError(res, `"${current.name}" is in use: default of ${refs.agentIds.length} agent(s), held by ${refs.openTaskCount} unfinished or awaiting-resume task(s).`, 409);
|
|
19697
|
+
return true;
|
|
19698
|
+
}
|
|
19699
|
+
const outcome = await deleteModelProfile(current.name);
|
|
19700
|
+
if (outcome === "in-use") {
|
|
19701
|
+
jsonError(res, `"${current.name}" is in use by a task or an agent default created just now.`, 409);
|
|
19702
|
+
return true;
|
|
19703
|
+
}
|
|
19704
|
+
if (outcome === "missing") {
|
|
19705
|
+
jsonError(res, "Model profile not found", 404);
|
|
19706
|
+
return true;
|
|
19707
|
+
}
|
|
19708
|
+
deleteProfile.respond(res, 200, { deleted: true });
|
|
19709
|
+
return true;
|
|
19710
|
+
}
|
|
19711
|
+
return false;
|
|
19712
|
+
}
|
|
19713
|
+
|
|
18910
19714
|
// src/http/models-catalog.ts
|
|
18911
19715
|
init_zod();
|
|
18912
19716
|
init_db3();
|
|
@@ -20793,6 +21597,7 @@ init_request_auth_context();
|
|
|
20793
21597
|
// src/http/tasks.ts
|
|
20794
21598
|
init_zod();
|
|
20795
21599
|
init_db3();
|
|
21600
|
+
init_model_profiles();
|
|
20796
21601
|
init_steering();
|
|
20797
21602
|
init_users();
|
|
20798
21603
|
init_rbac();
|
|
@@ -20989,6 +21794,7 @@ var createTask = route({
|
|
|
20989
21794
|
modelTier: ModelTierSchema.optional(),
|
|
20990
21795
|
allowCustomModel: exports_external.boolean().optional(),
|
|
20991
21796
|
effort: ReasoningEffortSchema.optional(),
|
|
21797
|
+
profile: exports_external.string().trim().min(1).optional(),
|
|
20992
21798
|
draft: exports_external.boolean().optional()
|
|
20993
21799
|
}).superRefine((body, ctx) => {
|
|
20994
21800
|
if ((body.agentId !== undefined || body.offeredTo !== undefined) && !body.routingReason) {
|
|
@@ -21530,6 +22336,15 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
21530
22336
|
jsonError(res, modelError, 400);
|
|
21531
22337
|
return true;
|
|
21532
22338
|
}
|
|
22339
|
+
const profileError = await taskProfileError({
|
|
22340
|
+
profile: parsed.body.profile,
|
|
22341
|
+
...splitLegacyModelAlias({ model: parsed.body.model, modelTier: parsed.body.modelTier }),
|
|
22342
|
+
agentId: defaultAgentId
|
|
22343
|
+
});
|
|
22344
|
+
if (profileError) {
|
|
22345
|
+
jsonError(res, profileError, 400);
|
|
22346
|
+
return true;
|
|
22347
|
+
}
|
|
21533
22348
|
const parentTask = parsed.body.parentTaskId ? await getTaskById(parsed.body.parentTaskId) : null;
|
|
21534
22349
|
const principal = await resolveTaskWritePrincipal(req, myAgentId);
|
|
21535
22350
|
if (parentTask && !can({
|
|
@@ -21587,7 +22402,8 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
21587
22402
|
model: parsed.body.model,
|
|
21588
22403
|
modelTier: parsed.body.modelTier
|
|
21589
22404
|
}),
|
|
21590
|
-
effort: parsed.body.effort
|
|
22405
|
+
effort: parsed.body.effort,
|
|
22406
|
+
profile: parsed.body.profile
|
|
21591
22407
|
}, { origin: "rest", allowCustomModel: parsed.body.allowCustomModel });
|
|
21592
22408
|
ensure({
|
|
21593
22409
|
id: "created",
|
|
@@ -21614,6 +22430,10 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
21614
22430
|
jsonError(res, error.message, 400);
|
|
21615
22431
|
return true;
|
|
21616
22432
|
}
|
|
22433
|
+
if (modelProfileRefError(error) === "missing") {
|
|
22434
|
+
jsonError(res, `Unknown model profile "${parsed.body.profile}"`, 400);
|
|
22435
|
+
return true;
|
|
22436
|
+
}
|
|
21617
22437
|
console.error("[HTTP] Failed to create task:", error);
|
|
21618
22438
|
jsonError(res, "Failed to create task", 500);
|
|
21619
22439
|
}
|
|
@@ -23813,6 +24633,33 @@ function isPageFeedbackRequested(queryParams) {
|
|
|
23813
24633
|
const value = (queryParams.get(PAGE_FEEDBACK_PARAM) ?? "").toLowerCase();
|
|
23814
24634
|
return value !== "0" && value !== "false";
|
|
23815
24635
|
}
|
|
24636
|
+
var FEEDBACK_KEY_GUARD_JS = `
|
|
24637
|
+
(function () {
|
|
24638
|
+
if (window.__swarmFeedbackKeys) return;
|
|
24639
|
+
var keys = window.__swarmFeedbackKeys = { host: null, handle: null };
|
|
24640
|
+
var owned = {};
|
|
24641
|
+
function id(e) { return e.code || e.key; }
|
|
24642
|
+
function fromOverlay(e) {
|
|
24643
|
+
return !!keys.host && typeof e.composedPath === 'function' && e.composedPath().indexOf(keys.host) !== -1;
|
|
24644
|
+
}
|
|
24645
|
+
function guard(e) {
|
|
24646
|
+
var k = id(e);
|
|
24647
|
+
var mine = fromOverlay(e);
|
|
24648
|
+
if (!mine && !owned[k]) return;
|
|
24649
|
+
if (e.type === 'keydown') {
|
|
24650
|
+
if (mine) owned[k] = true;
|
|
24651
|
+
else if (!e.repeat) { delete owned[k]; return; }
|
|
24652
|
+
}
|
|
24653
|
+
if (e.type === 'keyup') delete owned[k];
|
|
24654
|
+
e.stopImmediatePropagation();
|
|
24655
|
+
if (mine && keys.handle) keys.handle(e);
|
|
24656
|
+
}
|
|
24657
|
+
['keydown', 'keypress', 'keyup'].forEach(function (type) {
|
|
24658
|
+
window.addEventListener(type, guard, true);
|
|
24659
|
+
});
|
|
24660
|
+
window.addEventListener('blur', function () { owned = {}; });
|
|
24661
|
+
})();
|
|
24662
|
+
`;
|
|
23816
24663
|
var FEEDBACK_OVERLAY_JS = `
|
|
23817
24664
|
(function () {
|
|
23818
24665
|
var cfg = window.__swarmFeedback;
|
|
@@ -23923,6 +24770,7 @@ var FEEDBACK_OVERLAY_JS = `
|
|
|
23923
24770
|
var panel = document.createElement('div');
|
|
23924
24771
|
panel.className = 'panel';
|
|
23925
24772
|
var composer = null;
|
|
24773
|
+
var composerInput = null;
|
|
23926
24774
|
root.appendChild(hl);
|
|
23927
24775
|
root.appendChild(markers);
|
|
23928
24776
|
root.appendChild(panel);
|
|
@@ -23995,11 +24843,25 @@ var FEEDBACK_OVERLAY_JS = `
|
|
|
23995
24843
|
}
|
|
23996
24844
|
render();
|
|
23997
24845
|
}
|
|
23998
|
-
|
|
23999
|
-
if (e.key !== 'Escape') return;
|
|
24846
|
+
function onEscape() {
|
|
24000
24847
|
if (state.draft) { closeComposer(); return; }
|
|
24001
24848
|
if (state.selecting) setSelecting(false);
|
|
24849
|
+
}
|
|
24850
|
+
// Escape pressed on the page while selecting. Keys typed in the overlay never
|
|
24851
|
+
// get here: the key guard stops them and calls onOverlayKey instead.
|
|
24852
|
+
document.addEventListener('keydown', function (e) {
|
|
24853
|
+
if (e.key === 'Escape') onEscape();
|
|
24002
24854
|
}, true);
|
|
24855
|
+
function onOverlayKey(e) {
|
|
24856
|
+
if (e.type !== 'keydown') return;
|
|
24857
|
+
if (e.key === 'Escape') { onEscape(); return; }
|
|
24858
|
+
if (e.key === 'Enter' && (e.metaKey || e.ctrlKey) && composerInput && e.composedPath()[0] === composerInput) {
|
|
24859
|
+
e.preventDefault();
|
|
24860
|
+
commitDraft(composerInput.value);
|
|
24861
|
+
}
|
|
24862
|
+
}
|
|
24863
|
+
window.__swarmFeedbackKeys.host = host;
|
|
24864
|
+
window.__swarmFeedbackKeys.handle = onOverlayKey;
|
|
24003
24865
|
|
|
24004
24866
|
// ─── Composer ──────────────────────────────────────────────────────────
|
|
24005
24867
|
function openComposer(target) {
|
|
@@ -24018,9 +24880,7 @@ var FEEDBACK_OVERLAY_JS = `
|
|
|
24018
24880
|
add.type = 'button';
|
|
24019
24881
|
cancel.addEventListener('click', closeComposer);
|
|
24020
24882
|
add.addEventListener('click', function () { commitDraft(input.value); });
|
|
24021
|
-
|
|
24022
|
-
if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) { e.preventDefault(); commitDraft(input.value); }
|
|
24023
|
-
});
|
|
24883
|
+
composerInput = input;
|
|
24024
24884
|
row.appendChild(cancel);
|
|
24025
24885
|
row.appendChild(add);
|
|
24026
24886
|
composer.appendChild(row);
|
|
@@ -24041,6 +24901,7 @@ var FEEDBACK_OVERLAY_JS = `
|
|
|
24041
24901
|
function closeComposer() {
|
|
24042
24902
|
if (composer) composer.remove();
|
|
24043
24903
|
composer = null;
|
|
24904
|
+
composerInput = null;
|
|
24044
24905
|
state.draft = null;
|
|
24045
24906
|
hideHighlight();
|
|
24046
24907
|
}
|
|
@@ -24306,7 +25167,10 @@ var FEEDBACK_OVERLAY_JS = `
|
|
|
24306
25167
|
`;
|
|
24307
25168
|
function feedbackOverlayScripts(pageId) {
|
|
24308
25169
|
const config = JSON.stringify({ pageId }).replace(/</g, "\\u003c");
|
|
24309
|
-
return `<script>window.__swarmFeedback = ${config};</script><script>${FEEDBACK_OVERLAY_JS}</script>`;
|
|
25170
|
+
return `<script>window.__swarmFeedback = ${config};</script><script>${FEEDBACK_KEY_GUARD_JS}${FEEDBACK_OVERLAY_JS}</script>`;
|
|
25171
|
+
}
|
|
25172
|
+
function feedbackKeyGuardScript() {
|
|
25173
|
+
return `<script>${FEEDBACK_KEY_GUARD_JS}</script>`;
|
|
24310
25174
|
}
|
|
24311
25175
|
|
|
24312
25176
|
// src/http/pages-public.ts
|
|
@@ -24414,8 +25278,8 @@ var PAGE_HEAD_DEFAULTS = `<base target="_blank">
|
|
|
24414
25278
|
.swarm-card, swarm-diff { break-inside: avoid; }
|
|
24415
25279
|
}
|
|
24416
25280
|
</style>`;
|
|
24417
|
-
function injectBrowserSdk(html) {
|
|
24418
|
-
const injection = `${PAGE_HEAD_DEFAULTS}<script>${BROWSER_SDK_JS}</script><script>${SWARM_UI_JS}</script>`;
|
|
25281
|
+
function injectBrowserSdk(html, headFirst = "") {
|
|
25282
|
+
const injection = `${headFirst}${PAGE_HEAD_DEFAULTS}<script>${BROWSER_SDK_JS}</script><script>${SWARM_UI_JS}</script>`;
|
|
24419
25283
|
const headOpenMatch = html.match(/<head\b[^>]*>/i);
|
|
24420
25284
|
if (headOpenMatch) {
|
|
24421
25285
|
const idx = headOpenMatch.index + headOpenMatch[0].length;
|
|
@@ -24718,7 +25582,8 @@ async function handlePagesPublic(req, res, pathSegments, queryParams) {
|
|
|
24718
25582
|
res.end();
|
|
24719
25583
|
return true;
|
|
24720
25584
|
}
|
|
24721
|
-
const
|
|
25585
|
+
const feedback = isPageFeedbackRequested(queryParams);
|
|
25586
|
+
const html = injectBrowserSdk(page.body, feedback ? feedbackKeyGuardScript() : "") + (wantsPrint ? PRINT_AUTOTRIGGER_SCRIPT : "") + (feedback ? feedbackOverlayScripts(page.id) : "");
|
|
24722
25587
|
const headers2 = {
|
|
24723
25588
|
"Content-Type": "text/html; charset=utf-8",
|
|
24724
25589
|
"Cache-Control": "no-store",
|
|
@@ -24850,6 +25715,7 @@ async function fetchAllBotChannels(client) {
|
|
|
24850
25715
|
// src/http/poll.ts
|
|
24851
25716
|
init_telemetry_trigger();
|
|
24852
25717
|
init_types();
|
|
25718
|
+
init_request_auth_context();
|
|
24853
25719
|
init_runtime_pools_flag();
|
|
24854
25720
|
function buildBudgetRefusedTrigger(refusal) {
|
|
24855
25721
|
const trigger = {
|
|
@@ -24946,18 +25812,21 @@ async function attachmentsForTrigger(taskId) {
|
|
|
24946
25812
|
sizeBytes: a.sizeBytes
|
|
24947
25813
|
}));
|
|
24948
25814
|
}
|
|
24949
|
-
async function claimModelFields(task, agent) {
|
|
25815
|
+
async function claimModelFields(task, agent, auth) {
|
|
24950
25816
|
const pin = taskModelPin(task);
|
|
24951
25817
|
const cleared = {
|
|
24952
25818
|
model: pin,
|
|
24953
25819
|
resolvedModel: undefined,
|
|
24954
25820
|
modelSource: undefined,
|
|
24955
|
-
modelAlias: undefined
|
|
25821
|
+
modelAlias: undefined,
|
|
25822
|
+
resolvedProfile: undefined
|
|
24956
25823
|
};
|
|
24957
25824
|
try {
|
|
24958
25825
|
return {
|
|
24959
25826
|
...cleared,
|
|
24960
|
-
...await recordClaimModelResolution({ ...task, model: pin }, agent
|
|
25827
|
+
...await recordClaimModelResolution({ ...task, model: pin }, agent, {
|
|
25828
|
+
includeRepoSecrets: readsRepoSecrets(auth, agent)
|
|
25829
|
+
})
|
|
24961
25830
|
};
|
|
24962
25831
|
} catch (error) {
|
|
24963
25832
|
console.warn(`[/api/poll] model resolution failed for task ${task.id}:`, error);
|
|
@@ -25135,7 +26004,7 @@ async function handlePoll(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
25135
26004
|
triggerSurface: assignedTriggerSurface,
|
|
25136
26005
|
task: {
|
|
25137
26006
|
...pendingTask,
|
|
25138
|
-
...await claimModelFields(pendingTask, agent),
|
|
26007
|
+
...await claimModelFields(pendingTask, agent, getRequestAuth(req)),
|
|
25139
26008
|
status: "in_progress",
|
|
25140
26009
|
attachments: await attachmentsForTrigger(pendingTask.id)
|
|
25141
26010
|
},
|
|
@@ -25226,7 +26095,7 @@ async function handlePoll(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
25226
26095
|
triggerSurface: claimedTriggerSurface,
|
|
25227
26096
|
task: {
|
|
25228
26097
|
...claimed,
|
|
25229
|
-
...await claimModelFields(claimed, agent),
|
|
26098
|
+
...await claimModelFields(claimed, agent, getRequestAuth(req)),
|
|
25230
26099
|
attachments: await attachmentsForTrigger(claimed.id)
|
|
25231
26100
|
},
|
|
25232
26101
|
...claimedRequestedBy && { requestedBy: claimedRequestedBy }
|
|
@@ -30132,7 +31001,7 @@ async function handleScriptRuns(req, res, pathSegments, queryParams, agentId) {
|
|
|
30132
31001
|
return true;
|
|
30133
31002
|
const result = await executeRawLlm(parsed.body);
|
|
30134
31003
|
if (result.status === "failed") {
|
|
30135
|
-
|
|
31004
|
+
jsonError(res, result.error, 500);
|
|
30136
31005
|
return true;
|
|
30137
31006
|
}
|
|
30138
31007
|
rawLlmRoute.respond(res, 200, result.output);
|
|
@@ -30336,7 +31205,8 @@ var upsertRoute2 = route({
|
|
|
30336
31205
|
schema: exports_external.object({
|
|
30337
31206
|
name: exports_external.string(),
|
|
30338
31207
|
version: exports_external.number(),
|
|
30339
|
-
contentDeduped: exports_external.boolean()
|
|
31208
|
+
contentDeduped: exports_external.boolean(),
|
|
31209
|
+
warnings: exports_external.array(exports_external.string()).optional().describe("Advisory quickjs-executor compatibility findings. Never blocks the save.")
|
|
30340
31210
|
})
|
|
30341
31211
|
},
|
|
30342
31212
|
400: { description: "Validation or typecheck failure" },
|
|
@@ -30496,7 +31366,12 @@ var createScriptApiRoute = route({
|
|
|
30496
31366
|
params: idParamsSchema4,
|
|
30497
31367
|
body: createScriptApiBodySchema,
|
|
30498
31368
|
responses: {
|
|
30499
|
-
201: {
|
|
31369
|
+
201: {
|
|
31370
|
+
description: "Endpoint created",
|
|
31371
|
+
schema: scriptApiWithSecretSchema.extend({
|
|
31372
|
+
warnings: exports_external.array(exports_external.string()).optional().describe("Advisory quickjs-executor compatibility findings for the script.")
|
|
31373
|
+
})
|
|
31374
|
+
},
|
|
30500
31375
|
400: { description: "Validation error or script has no owning agent" },
|
|
30501
31376
|
404: { description: "Script not found" }
|
|
30502
31377
|
},
|
|
@@ -30705,10 +31580,12 @@ async function handleScripts(req, res, pathSegments, queryParams, agentId) {
|
|
|
30705
31580
|
isPromotion: Boolean(existingAgentScript)
|
|
30706
31581
|
});
|
|
30707
31582
|
}
|
|
31583
|
+
const warnings = quickJSCompatWarnings(checkQuickJSCompat(parsed.body.source, { fsMode: parsed.body.fsMode }));
|
|
30708
31584
|
upsertRoute2.respond(res, 200, {
|
|
30709
31585
|
name: result.script.name,
|
|
30710
31586
|
version: result.script.version,
|
|
30711
|
-
contentDeduped: result.contentDeduped
|
|
31587
|
+
contentDeduped: result.contentDeduped,
|
|
31588
|
+
...warnings.length > 0 ? { warnings } : {}
|
|
30712
31589
|
});
|
|
30713
31590
|
return true;
|
|
30714
31591
|
}
|
|
@@ -31005,7 +31882,11 @@ async function handleScripts(req, res, pathSegments, queryParams, agentId) {
|
|
|
31005
31882
|
label: parsed.body.label ?? null,
|
|
31006
31883
|
createdBy: await resolveHttpAuditUserId(req, agentId)
|
|
31007
31884
|
});
|
|
31008
|
-
|
|
31885
|
+
const warnings = quickJSCompatWarnings(checkQuickJSCompat(script.source, { fsMode: script.fsMode }));
|
|
31886
|
+
createScriptApiRoute.respond(res, 201, {
|
|
31887
|
+
...endpoint,
|
|
31888
|
+
...warnings.length > 0 ? { warnings } : {}
|
|
31889
|
+
});
|
|
31009
31890
|
return true;
|
|
31010
31891
|
}
|
|
31011
31892
|
if (listScriptApisRoute.match(req.method, pathSegments)) {
|
|
@@ -36037,8 +36918,7 @@ async function handleWebhooks(req, res, pathSegments) {
|
|
|
36037
36918
|
}
|
|
36038
36919
|
agentmailWebhook.respond(res, 200, { received: true });
|
|
36039
36920
|
if (payload.message && !isInboxAllowed(payload.message.inbox_id, process.env.AGENTMAIL_INBOX_DOMAIN_FILTER)) {
|
|
36040
|
-
|
|
36041
|
-
console.log(`[AgentMail] Ignoring event for inbox domain "${domain}" (not in AGENTMAIL_INBOX_DOMAIN_FILTER)`);
|
|
36921
|
+
console.log(`[AgentMail] Ignoring event for inbox "${payload.message.inbox_id}" (not in AGENTMAIL_INBOX_DOMAIN_FILTER)`);
|
|
36042
36922
|
return true;
|
|
36043
36923
|
}
|
|
36044
36924
|
if (payload.message && !isSenderAllowed(payload.message.from_, process.env.AGENTMAIL_SENDER_DOMAIN_FILTER)) {
|
|
@@ -37401,6 +38281,7 @@ var httpServer = createHttpServer(async (req, res) => {
|
|
|
37401
38281
|
() => handleDbQuery(req, res, pathSegments, queryParams),
|
|
37402
38282
|
() => handleMetrics(req, res, pathSegments, queryParams, myAgentId),
|
|
37403
38283
|
() => handleModelsCatalog(req, res, pathSegments, queryParams),
|
|
38284
|
+
() => handleModelProfiles(req, res, pathSegments, queryParams, myAgentId),
|
|
37404
38285
|
() => handleRepos(req, res, pathSegments, queryParams, myAgentId),
|
|
37405
38286
|
() => handleSkills(req, res, pathSegments, queryParams, myAgentId),
|
|
37406
38287
|
() => handleScriptConnections(req, res, pathSegments, queryParams, myAgentId),
|
|
@@ -37461,7 +38342,7 @@ var httpServer = createHttpServer(async (req, res) => {
|
|
|
37461
38342
|
});
|
|
37462
38343
|
});
|
|
37463
38344
|
var detachRealtime = attachRealtimeTransport(httpServer);
|
|
37464
|
-
var { attachControllerTransport } = await import("./controllers-connect-
|
|
38345
|
+
var { attachControllerTransport } = await import("./controllers-connect-v9yn8zb9.js");
|
|
37465
38346
|
var detachControllers = attachControllerTransport(httpServer);
|
|
37466
38347
|
var stopWorkerNudges = startWorkerNudgeListener();
|
|
37467
38348
|
var stopRoomDeletion = realtimeBus.subscribe("room:namespace-deleted", (namespace) => {
|
|
@@ -37490,7 +38371,7 @@ async function shutdown() {
|
|
|
37490
38371
|
sessionsProcessed: getServerSessionsProcessed()
|
|
37491
38372
|
});
|
|
37492
38373
|
if (hasCapability("scheduling")) {
|
|
37493
|
-
const { stopScheduler } = await import("./index-
|
|
38374
|
+
const { stopScheduler } = await import("./index-3gtmkhc6.js");
|
|
37494
38375
|
stopScheduler();
|
|
37495
38376
|
}
|
|
37496
38377
|
stopHeartbeat();
|
|
@@ -37502,7 +38383,7 @@ async function shutdown() {
|
|
|
37502
38383
|
await stopSlackApp();
|
|
37503
38384
|
await stopChatSdk();
|
|
37504
38385
|
if (process.env.OAUTH_KEEPALIVE_DISABLE !== "true") {
|
|
37505
|
-
const { stopOAuthKeepalive } = await import("./keepalive-
|
|
38386
|
+
const { stopOAuthKeepalive } = await import("./keepalive-psj6j54c.js");
|
|
37506
38387
|
await stopOAuthKeepalive();
|
|
37507
38388
|
}
|
|
37508
38389
|
stopOAuthPendingGc();
|
|
@@ -37582,15 +38463,21 @@ try {
|
|
|
37582
38463
|
console.warn("[startup] CAPABILITIES upgrade seed failed (non-fatal):", err);
|
|
37583
38464
|
}
|
|
37584
38465
|
try {
|
|
37585
|
-
const { ensurePricingSeeded } = await import("./boot-seeds-
|
|
38466
|
+
const { ensurePricingSeeded } = await import("./boot-seeds-e9sta0yt.js");
|
|
37586
38467
|
ensurePricingSeeded();
|
|
37587
|
-
const { startPricingRefreshLoop } = await import("./pricing-refresh-
|
|
38468
|
+
const { startPricingRefreshLoop } = await import("./pricing-refresh-kefx9v3t.js");
|
|
37588
38469
|
startPricingRefreshLoop();
|
|
37589
38470
|
} catch (err) {
|
|
37590
38471
|
console.error("[startup] Failed to seed pricing rows:", err);
|
|
37591
38472
|
}
|
|
37592
38473
|
try {
|
|
37593
|
-
const {
|
|
38474
|
+
const { ensureModelProfilesSeeded } = await import("./boot-seeds-e9sta0yt.js");
|
|
38475
|
+
await ensureModelProfilesSeeded();
|
|
38476
|
+
} catch (err) {
|
|
38477
|
+
console.error("[startup] Failed to seed model profiles:", err);
|
|
38478
|
+
}
|
|
38479
|
+
try {
|
|
38480
|
+
const { ensureRbacSeeded } = await import("./boot-seeds-e9sta0yt.js");
|
|
37594
38481
|
ensureRbacSeeded();
|
|
37595
38482
|
} catch (err) {
|
|
37596
38483
|
console.error("[startup] Failed to sync RBAC seed rows:", err);
|
|
@@ -37598,7 +38485,7 @@ try {
|
|
|
37598
38485
|
throw err;
|
|
37599
38486
|
}
|
|
37600
38487
|
try {
|
|
37601
|
-
const { runAllSeeders } = await import("./index-
|
|
38488
|
+
const { runAllSeeders } = await import("./index-5wyfjc2c.js");
|
|
37602
38489
|
await runAllSeeders({ scriptEmbeddingMode: "skip" });
|
|
37603
38490
|
} catch (err) {
|
|
37604
38491
|
console.error("[startup] Failed to seed built-in entities:", err);
|
|
@@ -37653,45 +38540,46 @@ httpServer.listen(port, async () => {
|
|
|
37653
38540
|
initGitHub();
|
|
37654
38541
|
initGitLab();
|
|
37655
38542
|
initAzureDevOps();
|
|
38543
|
+
initAzureDevOpsOutbound();
|
|
37656
38544
|
initAgentMail();
|
|
37657
38545
|
await initLinear();
|
|
37658
38546
|
await initJira();
|
|
37659
38547
|
await initWorkflows();
|
|
37660
38548
|
await startScriptRunSupervisor(getMcpBaseUrl());
|
|
37661
38549
|
if (hasCapability("scheduling")) {
|
|
37662
|
-
const { startScheduler } = await import("./index-
|
|
37663
|
-
const { getExecutorRegistry: getExecutorRegistry2 } = await import("./index-
|
|
38550
|
+
const { startScheduler } = await import("./index-3gtmkhc6.js");
|
|
38551
|
+
const { getExecutorRegistry: getExecutorRegistry2 } = await import("./index-5e101240.js");
|
|
37664
38552
|
const intervalMs = Number(process.env.SCHEDULER_INTERVAL_MS) || 1e4;
|
|
37665
38553
|
startScheduler(getExecutorRegistry2(), intervalMs, {
|
|
37666
38554
|
runId: globalState.__runId
|
|
37667
38555
|
});
|
|
37668
38556
|
}
|
|
37669
38557
|
if (!isEnvFlagEnabled("HEARTBEAT_DISABLE", false)) {
|
|
37670
|
-
const { startHeartbeat } = await import("./index-
|
|
38558
|
+
const { startHeartbeat } = await import("./index-3k5hkz7r.js");
|
|
37671
38559
|
const heartbeatMs = Number(process.env.HEARTBEAT_INTERVAL_MS) || 90000;
|
|
37672
38560
|
startHeartbeat(heartbeatMs);
|
|
37673
38561
|
}
|
|
37674
38562
|
startPoolRouting();
|
|
37675
38563
|
startRuntimeSupervisor();
|
|
37676
38564
|
if (process.env.OAUTH_KEEPALIVE_DISABLE !== "true") {
|
|
37677
|
-
const { startOAuthKeepalive } = await import("./keepalive-
|
|
38565
|
+
const { startOAuthKeepalive } = await import("./keepalive-psj6j54c.js");
|
|
37678
38566
|
startOAuthKeepalive();
|
|
37679
38567
|
}
|
|
37680
38568
|
if (process.env.OAUTH_REFRESH_SWEEP_DISABLE !== "true") {
|
|
37681
|
-
const { startOAuthRefreshSweep } = await import("./oauth-refresh-sweep-
|
|
38569
|
+
const { startOAuthRefreshSweep } = await import("./oauth-refresh-sweep-0284h93b.js");
|
|
37682
38570
|
startOAuthRefreshSweep();
|
|
37683
38571
|
}
|
|
37684
38572
|
startOAuthPendingGc();
|
|
37685
38573
|
await startMemoryGc();
|
|
37686
38574
|
await startDbRetention();
|
|
37687
38575
|
startHumanFreeDrain();
|
|
37688
|
-
import("./boot-reembed-
|
|
38576
|
+
import("./boot-reembed-whzbdthj.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
|
|
37689
38577
|
console.error("[boot-reembed] startup backfill failed (non-fatal):", err);
|
|
37690
38578
|
});
|
|
37691
|
-
import("./boot-reembed-
|
|
38579
|
+
import("./boot-reembed-9apm9qw6.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
|
|
37692
38580
|
console.error("[boot-reembed-scripts] startup backfill failed (non-fatal):", err);
|
|
37693
38581
|
});
|
|
37694
|
-
import("./boot-scrub-sweep-
|
|
38582
|
+
import("./boot-scrub-sweep-ndzmvmgt.js").then(({ runBootScrubSweep }) => runBootScrubSweep()).catch((err) => {
|
|
37695
38583
|
console.error("[boot-scrub-sweep] startup scrub failed (non-fatal):", err);
|
|
37696
38584
|
});
|
|
37697
38585
|
}).on("error", (err) => {
|