@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
|
@@ -7,9 +7,12 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Precedence (first hit wins):
|
|
9
9
|
* 1. task `model` → modelSource "model"
|
|
10
|
-
* 2.
|
|
11
|
-
* 3.
|
|
12
|
-
* 4.
|
|
10
|
+
* 2. task `profile` → "profile:task"
|
|
11
|
+
* 3. the claiming worker's MODEL_TIER_* → "worker-env" (agents.modelTierOverrides)
|
|
12
|
+
* 4. swarm_config MODEL_TIER_<PROV>_<TIER> → "tier-config"
|
|
13
|
+
* 5. DEFAULT_MODEL_TIER_MAP → "tier-default"
|
|
14
|
+
* 6. the agent's default profile → "profile:agent-default" (no model, no tier,
|
|
15
|
+
* no repo-scoped MODEL_OVERRIDE on the task's repo)
|
|
13
16
|
*
|
|
14
17
|
* Any layer may hold a `latest:` alias. An alias that resolves to nothing
|
|
15
18
|
* (empty catalog, everything filtered) falls through to the next layer.
|
|
@@ -45,8 +48,14 @@ import {
|
|
|
45
48
|
type ProviderName,
|
|
46
49
|
ProviderNameSchema,
|
|
47
50
|
parseModelTier,
|
|
51
|
+
type ReasoningEffort,
|
|
48
52
|
} from "../types";
|
|
49
53
|
import { getDbClient } from "./db";
|
|
54
|
+
import {
|
|
55
|
+
getAgentDefaultProfileName,
|
|
56
|
+
getModelProfileByName,
|
|
57
|
+
repoModelOverrideKeys,
|
|
58
|
+
} from "./db/model-profiles";
|
|
50
59
|
import {
|
|
51
60
|
CLI_PINNED_HARNESSES,
|
|
52
61
|
fallbackForUnsupportedModel,
|
|
@@ -74,7 +83,9 @@ export type ModelSource =
|
|
|
74
83
|
| "tier-config"
|
|
75
84
|
| "tier-default"
|
|
76
85
|
| "fallback:cli-unsupported"
|
|
77
|
-
| "fallback:cli-unsupported:model"
|
|
86
|
+
| "fallback:cli-unsupported:model"
|
|
87
|
+
| "profile:task"
|
|
88
|
+
| "profile:agent-default";
|
|
78
89
|
|
|
79
90
|
export interface TaskModelResolution {
|
|
80
91
|
resolvedModel: string;
|
|
@@ -490,15 +501,21 @@ async function applyCliSupport(
|
|
|
490
501
|
if (!fallback) return resolution;
|
|
491
502
|
noticeCliUnsupported(harness, cliVersion, resolution.resolvedModel, fallback);
|
|
492
503
|
// Keep the winning layer in the source: a fallback from the task's own `latest:` alias is
|
|
493
|
-
// still a task-level pin (a resume carries it), one from a tier layer is not.
|
|
494
|
-
|
|
495
|
-
|
|
504
|
+
// still a task-level pin (a resume carries it), one from a tier layer is not. A profile keeps
|
|
505
|
+
// its own source; `resolvedProfile` still names it and `resolvedModel` shows the swap.
|
|
506
|
+
const modelSource = resolution.modelSource.startsWith("profile:")
|
|
507
|
+
? resolution.modelSource
|
|
508
|
+
: resolution.modelSource === "model"
|
|
496
509
|
? "fallback:cli-unsupported:model"
|
|
497
510
|
: "fallback:cli-unsupported";
|
|
498
511
|
return { ...resolution, resolvedModel: fallback, modelSource };
|
|
499
512
|
}
|
|
500
513
|
|
|
501
514
|
export type ClaimModelFields = Partial<TaskModelResolution> & {
|
|
515
|
+
/** The profile claim applied (`agent_tasks.resolvedProfile`). */
|
|
516
|
+
resolvedProfile?: string;
|
|
517
|
+
/** The profile's effort, when it has one and the task set none; the worker spawns with it. */
|
|
518
|
+
effort?: ReasoningEffort;
|
|
502
519
|
/**
|
|
503
520
|
* Set when the task's explicit model is rejected by this worker's CLI, or belongs to another
|
|
504
521
|
* harness family (`[model-harness-mismatch]`); the worker fails the task without a spawn.
|
|
@@ -506,6 +523,55 @@ export type ClaimModelFields = Partial<TaskModelResolution> & {
|
|
|
506
523
|
modelUnsupported?: string;
|
|
507
524
|
};
|
|
508
525
|
|
|
526
|
+
/**
|
|
527
|
+
* Resolve a model profile for a claim. Null when the profile does not apply:
|
|
528
|
+
* an agent default that is missing or on another harness falls through to the
|
|
529
|
+
* tier chain. For a task's own `profile` both are a hard stop.
|
|
530
|
+
*/
|
|
531
|
+
async function resolveClaimProfile(
|
|
532
|
+
name: string,
|
|
533
|
+
source: "profile:task" | "profile:agent-default",
|
|
534
|
+
harness: ProviderName | null,
|
|
535
|
+
): Promise<
|
|
536
|
+
| { profile: { name: string; effort: ReasoningEffort | null }; resolution: TaskModelResolution }
|
|
537
|
+
| { modelUnsupported: string }
|
|
538
|
+
| null
|
|
539
|
+
> {
|
|
540
|
+
const isTask = source === "profile:task";
|
|
541
|
+
const profile = await getModelProfileByName(name);
|
|
542
|
+
if (!profile) {
|
|
543
|
+
return isTask
|
|
544
|
+
? { modelUnsupported: `[model-profile-missing] Model profile "${name}" no longer exists.` }
|
|
545
|
+
: null;
|
|
546
|
+
}
|
|
547
|
+
if (profile.harness !== harness) {
|
|
548
|
+
if (!isTask) return null;
|
|
549
|
+
return {
|
|
550
|
+
modelUnsupported: `[model-harness-mismatch] Model profile "${name}" runs on the ${profile.harness} harness, not on the ${harness ?? "unknown"} harness of this worker. Re-create the task with a ${harness ?? "matching"} profile.`,
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
let resolution: TaskModelResolution = {
|
|
554
|
+
resolvedModel: profile.model,
|
|
555
|
+
modelSource: source,
|
|
556
|
+
modelAlias: null,
|
|
557
|
+
};
|
|
558
|
+
if (isAlias(profile.model)) {
|
|
559
|
+
const resolved = await resolveLatestAlias(profile.model);
|
|
560
|
+
if (!resolved) {
|
|
561
|
+
if (!isTask) return null;
|
|
562
|
+
return {
|
|
563
|
+
modelUnsupported: `[model-profile-unresolved] Model profile "${name}" names ${profile.model}, which resolves to no usable model.`,
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
resolution = {
|
|
567
|
+
resolvedModel: resolved,
|
|
568
|
+
modelSource: source,
|
|
569
|
+
modelAlias: profile.model.trim().toLowerCase(),
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
return { profile: { name: profile.name, effort: profile.effort }, resolution };
|
|
573
|
+
}
|
|
574
|
+
|
|
509
575
|
/**
|
|
510
576
|
* Resolve and record the model for a task the given agent is claiming. Runs
|
|
511
577
|
* inside the claim transaction. Returns the fields to merge into the trigger.
|
|
@@ -513,10 +579,77 @@ export type ClaimModelFields = Partial<TaskModelResolution> & {
|
|
|
513
579
|
* previous session reported into the column.
|
|
514
580
|
*/
|
|
515
581
|
export async function recordClaimModelResolution(
|
|
516
|
-
task: {
|
|
582
|
+
task: {
|
|
583
|
+
id: string;
|
|
584
|
+
model?: string | null;
|
|
585
|
+
modelTier?: string | null;
|
|
586
|
+
profile?: string | null;
|
|
587
|
+
effort?: string | null;
|
|
588
|
+
vcsRepo?: string | null;
|
|
589
|
+
},
|
|
517
590
|
agent: { id: string; harnessProvider?: ProviderName | null; provider?: ProviderName | null },
|
|
591
|
+
/**
|
|
592
|
+
* Whether the claiming worker's config read includes secret repo rows
|
|
593
|
+
* (`readsRepoSecrets`). A secret repo override it never receives cannot
|
|
594
|
+
* beat its default profile. Defaults to true (an operator-key worker).
|
|
595
|
+
*/
|
|
596
|
+
{ includeRepoSecrets = true }: { includeRepoSecrets?: boolean } = {},
|
|
518
597
|
): Promise<ClaimModelFields> {
|
|
519
598
|
const harnessProvider = agent.harnessProvider ?? agent.provider ?? null;
|
|
599
|
+
|
|
600
|
+
if (!task.model?.trim()) {
|
|
601
|
+
const taskProfile = task.profile?.trim();
|
|
602
|
+
const agentDefault =
|
|
603
|
+
taskProfile || parseModelTier(task.modelTier)
|
|
604
|
+
? null
|
|
605
|
+
: await getAgentDefaultProfileName(agent.id);
|
|
606
|
+
// The agent default is agent-scoped config: a repo-scoped MODEL_OVERRIDE or
|
|
607
|
+
// REASONING_EFFORT_OVERRIDE on the task's repo still beats it on that axis
|
|
608
|
+
// (repo > agent), as it beats the agent's own override in the worker env.
|
|
609
|
+
// A task's own profile is the creator's pick and beats repo config.
|
|
610
|
+
const repoKeys = agentDefault
|
|
611
|
+
? await repoModelOverrideKeys(task.vcsRepo, { includeSecrets: includeRepoSecrets })
|
|
612
|
+
: new Set<string>();
|
|
613
|
+
const defaultProfile = repoKeys.has("MODEL_OVERRIDE") ? null : agentDefault;
|
|
614
|
+
const picked = taskProfile
|
|
615
|
+
? await resolveClaimProfile(taskProfile, "profile:task", harnessProvider)
|
|
616
|
+
: defaultProfile
|
|
617
|
+
? await resolveClaimProfile(defaultProfile, "profile:agent-default", harnessProvider)
|
|
618
|
+
: null;
|
|
619
|
+
if (picked && "modelUnsupported" in picked)
|
|
620
|
+
return { modelUnsupported: picked.modelUnsupported };
|
|
621
|
+
if (picked) {
|
|
622
|
+
const checked = await applyCliSupport(
|
|
623
|
+
picked.resolution,
|
|
624
|
+
harnessProvider,
|
|
625
|
+
await getAgentHarnessCliVersion(agent.id),
|
|
626
|
+
);
|
|
627
|
+
// Profiles never fail fast on the CLI check (only a raw task pin does), so this is a resolution.
|
|
628
|
+
const resolution = "unsupported" in checked ? picked.resolution : checked;
|
|
629
|
+
await getDbClient().run(
|
|
630
|
+
"UPDATE agent_tasks SET resolvedModel = ?, modelSource = ?, modelAlias = ?, resolvedProfile = ? WHERE id = ?",
|
|
631
|
+
[
|
|
632
|
+
resolution.resolvedModel,
|
|
633
|
+
resolution.modelSource,
|
|
634
|
+
resolution.modelAlias,
|
|
635
|
+
picked.profile.name,
|
|
636
|
+
task.id,
|
|
637
|
+
],
|
|
638
|
+
);
|
|
639
|
+
return {
|
|
640
|
+
resolvedModel: resolution.resolvedModel,
|
|
641
|
+
modelSource: resolution.modelSource,
|
|
642
|
+
...(resolution.modelAlias ? { modelAlias: resolution.modelAlias } : {}),
|
|
643
|
+
resolvedProfile: picked.profile.name,
|
|
644
|
+
// A task's own effort stays the pin; the profile's fills only an unset one,
|
|
645
|
+
// and an agent default's yields to the repo's effort override.
|
|
646
|
+
...(!task.effort && picked.profile.effort && !repoKeys.has("REASONING_EFFORT_OVERRIDE")
|
|
647
|
+
? { effort: picked.profile.effort }
|
|
648
|
+
: {}),
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
520
653
|
const resolved = await resolveTaskModel({
|
|
521
654
|
model: task.model,
|
|
522
655
|
modelTier: task.modelTier,
|
|
@@ -527,8 +660,9 @@ export async function recordClaimModelResolution(
|
|
|
527
660
|
// A re-claimed row keeps the claim record of its previous run; drop it so
|
|
528
661
|
// the trigger and the row do not replay that run's model.
|
|
529
662
|
await getDbClient().run(
|
|
530
|
-
`UPDATE agent_tasks SET resolvedModel = NULL, modelSource = NULL, modelAlias = NULL
|
|
531
|
-
WHERE id = ? AND (resolvedModel IS NOT NULL OR modelSource IS NOT NULL OR modelAlias IS NOT NULL
|
|
663
|
+
`UPDATE agent_tasks SET resolvedModel = NULL, modelSource = NULL, modelAlias = NULL, resolvedProfile = NULL
|
|
664
|
+
WHERE id = ? AND (resolvedModel IS NOT NULL OR modelSource IS NOT NULL OR modelAlias IS NOT NULL
|
|
665
|
+
OR resolvedProfile IS NOT NULL)`,
|
|
532
666
|
[task.id],
|
|
533
667
|
);
|
|
534
668
|
return {};
|
|
@@ -544,7 +678,7 @@ export async function recordClaimModelResolution(
|
|
|
544
678
|
}
|
|
545
679
|
const resolution = checked;
|
|
546
680
|
await getDbClient().run(
|
|
547
|
-
"UPDATE agent_tasks SET resolvedModel = ?, modelSource = ?, modelAlias =
|
|
681
|
+
"UPDATE agent_tasks SET resolvedModel = ?, modelSource = ?, modelAlias = ?, resolvedProfile = NULL WHERE id = ?",
|
|
548
682
|
[resolution.resolvedModel, resolution.modelSource, resolution.modelAlias, task.id],
|
|
549
683
|
);
|
|
550
684
|
return resolution.modelAlias
|
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
import { type TaskModelPinFields, taskModelPin } from "../tasks/model-pin";
|
|
33
33
|
import { ampModelError, ampPinCatalogError, ampPinProviderError } from "../utils/amp-models";
|
|
34
34
|
import { getAgentById, getAllAgents } from "./db";
|
|
35
|
+
import { getModelProfileByName } from "./db/model-profiles";
|
|
35
36
|
import { loadModelsCatalog } from "./model-catalog-store";
|
|
36
37
|
import { resolveLatestAlias } from "./model-tier-resolution";
|
|
37
38
|
|
|
@@ -100,9 +101,15 @@ export async function harnessModelErrorFor(
|
|
|
100
101
|
* stays sync and catalog-free; this runs next to it.
|
|
101
102
|
*/
|
|
102
103
|
export async function poolTaskRunsOnHarness(
|
|
103
|
-
task: TaskModelPinFields | null | undefined,
|
|
104
|
+
task: (TaskModelPinFields & { profile?: string | null }) | null | undefined,
|
|
104
105
|
harness: string | null | undefined,
|
|
105
106
|
): Promise<boolean> {
|
|
107
|
+
// A task's model profile runs on one harness only; other workers leave it in the pool.
|
|
108
|
+
const profileName = task?.profile?.trim();
|
|
109
|
+
if (profileName) {
|
|
110
|
+
const profile = await getModelProfileByName(profileName);
|
|
111
|
+
return !profile || !harness || profile.harness === harness;
|
|
112
|
+
}
|
|
106
113
|
// Only the task's own pin restricts harnesses; a model a previous run
|
|
107
114
|
// reported into `model` does not.
|
|
108
115
|
const model = taskModelPin(task ?? {})?.trim();
|
|
@@ -232,6 +232,8 @@ export interface SwarmSdk {
|
|
|
232
232
|
// --- config ---
|
|
233
233
|
config_get(args?: { agentId?: string; repoId?: string; key?: string; includeSecrets?: boolean }): Promise<unknown>;
|
|
234
234
|
config_list(args?: { scope?: "global" | "agent" | "repo"; scopeId?: string; key?: string; includeSecrets?: boolean }): Promise<unknown>;
|
|
235
|
+
// --- model profiles ---
|
|
236
|
+
modelProfile_list(args?: { harness?: string }): Promise<unknown>;
|
|
235
237
|
// --- slack ---
|
|
236
238
|
slack_read(args?: { inboxMessageId?: string; taskId?: string; channelId?: string; threadTs?: string; limit?: number; includeFiles?: boolean }): Promise<unknown>;
|
|
237
239
|
slack_listChannels(args?: { types?: Array<"public" | "private" | "dm" | "mpim">; limit?: number }): Promise<unknown>;
|
|
@@ -439,6 +441,16 @@ export interface SwarmSdk {
|
|
|
439
441
|
// --- human input ---
|
|
440
442
|
request_humanInput(args: Record<string, unknown>): Promise<unknown>;
|
|
441
443
|
approval_cancel(args: { requestId: string; reason?: string }): Promise<unknown>;
|
|
444
|
+
|
|
445
|
+
// --- decisions ---
|
|
446
|
+
systemOne_decide(args: {
|
|
447
|
+
provider?: "typesafe" | "openrouter" | "laya" | "openai" | "cloudflare";
|
|
448
|
+
model?: string;
|
|
449
|
+
state: string | string[] | Record<string, unknown>;
|
|
450
|
+
questions: Record<string, Record<string, unknown>>;
|
|
451
|
+
timeoutMs?: number;
|
|
452
|
+
maxRetries?: number;
|
|
453
|
+
}): Promise<unknown>;
|
|
442
454
|
}
|
|
443
455
|
|
|
444
456
|
export interface ScriptStdlib {
|
|
@@ -77,8 +77,12 @@ export function encodedForms(value: string): string[] {
|
|
|
77
77
|
/** Register a stored secret value, plus its encoded forms, with the scrubber. */
|
|
78
78
|
export function registerStoredSecret(value: string | null | undefined, name: string): void {
|
|
79
79
|
if (!value) return;
|
|
80
|
-
|
|
81
|
-
for (const
|
|
80
|
+
// Config values are hydrated verbatim but consumed trimmed.
|
|
81
|
+
for (const candidate of new Set([value, value.trim()])) {
|
|
82
|
+
if (!candidate) continue;
|
|
83
|
+
registerVolatileSecret(candidate, name);
|
|
84
|
+
for (const form of encodedForms(candidate)) registerVolatileSecret(form, name);
|
|
85
|
+
}
|
|
82
86
|
}
|
|
83
87
|
|
|
84
88
|
export interface SecretRegistryLoadResult {
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boot seed for the shipped model profiles: one `<harness>-<tier>` profile per
|
|
3
|
+
* harness and tier, a 1:1 copy of `DEFAULT_MODEL_TIER_MAP` (runbooks/model-tiers.md
|
|
4
|
+
* § Model profiles). A global `MODEL_TIER_<HARNESS>_<TIER>` row, when one exists,
|
|
5
|
+
* overrides the seed's model at seeding time. Seeds use the harness default
|
|
6
|
+
* route, no effort and no fallbacks.
|
|
7
|
+
*
|
|
8
|
+
* Idempotent: an existing name is never overwritten, so an operator's edit to a
|
|
9
|
+
* seed survives every boot. Harnesses with no portable tier mapping (acp) get
|
|
10
|
+
* no seeds.
|
|
11
|
+
*/
|
|
12
|
+
import { DEFAULT_MODEL_TIER_MAP, MODEL_TIERS, ProviderNameSchema } from "../types";
|
|
13
|
+
import { createModelProfile } from "./db/model-profiles";
|
|
14
|
+
import { getDbClient } from "./db/runtime";
|
|
15
|
+
import { tierConfigKey } from "./model-tier-keys";
|
|
16
|
+
|
|
17
|
+
export async function seedModelProfiles(): Promise<number> {
|
|
18
|
+
let inserted = 0;
|
|
19
|
+
for (const harness of ProviderNameSchema.options) {
|
|
20
|
+
for (const tier of MODEL_TIERS) {
|
|
21
|
+
const fallback = DEFAULT_MODEL_TIER_MAP[harness]?.[tier];
|
|
22
|
+
if (!fallback) continue;
|
|
23
|
+
const configured = await getDbClient().get<{ value: string }>(
|
|
24
|
+
"SELECT value FROM swarm_config WHERE scope = 'global' AND scopeId IS NULL AND key = ? AND isSecret = 0",
|
|
25
|
+
[tierConfigKey(harness, tier)],
|
|
26
|
+
);
|
|
27
|
+
const created = await createModelProfile({
|
|
28
|
+
name: `${harness}-${tier}`,
|
|
29
|
+
harness,
|
|
30
|
+
model: configured?.value.trim() || fallback,
|
|
31
|
+
effort: null,
|
|
32
|
+
// Tier values are free-form today (a `latest:` alias, a gateway id); keep that.
|
|
33
|
+
allowCustomModel: true,
|
|
34
|
+
description: `The ${tier} tier on ${harness}, seeded from the tier map.`,
|
|
35
|
+
seededFrom: `tier:${tier}`,
|
|
36
|
+
});
|
|
37
|
+
if (created) inserted++;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return inserted;
|
|
41
|
+
}
|