@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
package/src/extensions/loader.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { tmpdir } from "node:os";
|
|
2
|
-
import { resolve } from "node:path";
|
|
2
|
+
import { dirname, isAbsolute, relative, resolve, sep } from "node:path";
|
|
3
3
|
import { pathToFileURL } from "node:url";
|
|
4
4
|
import type { z } from "zod";
|
|
5
5
|
import { insertExtensionRun, setExtensionState } from "../be/extensions/db";
|
|
@@ -122,12 +122,18 @@ export async function removeExtensionTmpRoot(): Promise<void> {
|
|
|
122
122
|
|
|
123
123
|
export async function loadExtension(input: LoadableExtension): Promise<LoadedExtension> {
|
|
124
124
|
const { record } = input;
|
|
125
|
-
const directory =
|
|
125
|
+
const directory = resolve(EXTENSIONS_TMP_ROOT, record.name, record.contentHash);
|
|
126
126
|
|
|
127
127
|
try {
|
|
128
128
|
const bundlePath = (path: string): string => {
|
|
129
129
|
const filePath = resolve(directory, path);
|
|
130
|
-
|
|
130
|
+
const relativePath = relative(directory, filePath);
|
|
131
|
+
if (
|
|
132
|
+
!isSafeBundlePath(path) ||
|
|
133
|
+
relativePath === ".." ||
|
|
134
|
+
relativePath.startsWith(`..${sep}`) ||
|
|
135
|
+
isAbsolute(relativePath)
|
|
136
|
+
) {
|
|
131
137
|
throw new Error(`Unsafe bundle file path: ${JSON.stringify(path)}`);
|
|
132
138
|
}
|
|
133
139
|
return filePath;
|
|
@@ -138,8 +144,7 @@ export async function loadExtension(input: LoadableExtension): Promise<LoadedExt
|
|
|
138
144
|
);
|
|
139
145
|
await Bun.$`mkdir -p ${directory}`.quiet();
|
|
140
146
|
for (const [filePath, content] of files) {
|
|
141
|
-
|
|
142
|
-
await Bun.$`mkdir -p ${parent}`.quiet();
|
|
147
|
+
await Bun.$`mkdir -p ${dirname(filePath)}`.quiet();
|
|
143
148
|
await Bun.write(filePath, content);
|
|
144
149
|
}
|
|
145
150
|
await writeRuntimeShims(directory);
|
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
releaseStaleOfferedTasksForOfflineAgents,
|
|
44
44
|
releaseStaleProcessingInbox,
|
|
45
45
|
releaseStaleReviewingTasks,
|
|
46
|
+
SUPERSEDED_RESUME_REPAIR_WINDOW_MS,
|
|
46
47
|
settleSupersededTaskDependents,
|
|
47
48
|
supersedeTask,
|
|
48
49
|
updateAgentStatus,
|
|
@@ -588,7 +589,7 @@ async function detectAndRemediateStalledTasks(findings: HeartbeatFindings): Prom
|
|
|
588
589
|
|
|
589
590
|
/** Repair window: skip in-flight supersedes, stop at a day of history. */
|
|
590
591
|
const ORPHAN_SUPERSEDE_MIN_AGE_MS = 60 * 1000;
|
|
591
|
-
const ORPHAN_SUPERSEDE_MAX_AGE_MS =
|
|
592
|
+
const ORPHAN_SUPERSEDE_MAX_AGE_MS = SUPERSEDED_RESUME_REPAIR_WINDOW_MS;
|
|
592
593
|
|
|
593
594
|
/**
|
|
594
595
|
* Supersede and resume creation are separate writes. If the API process dies
|
package/src/http/agents.ts
CHANGED
|
@@ -28,6 +28,11 @@ import {
|
|
|
28
28
|
updateAgentStatus,
|
|
29
29
|
upsertSwarmConfig,
|
|
30
30
|
} from "../be/db";
|
|
31
|
+
import {
|
|
32
|
+
getModelProfileByName,
|
|
33
|
+
MODEL_PROFILE_CONFIG_KEY,
|
|
34
|
+
modelProfileRefError,
|
|
35
|
+
} from "../be/db/model-profiles";
|
|
31
36
|
import { createEvent } from "../be/events";
|
|
32
37
|
import { setAgentHarnessCliVersion } from "../be/harness-model-support";
|
|
33
38
|
import {
|
|
@@ -278,7 +283,7 @@ const updateAgentRuntimeRoute = route({
|
|
|
278
283
|
pattern: ["api", "agents", null, "runtime"],
|
|
279
284
|
summary: "Update an agent's runtime harness and default model",
|
|
280
285
|
description:
|
|
281
|
-
"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.",
|
|
286
|
+
"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.",
|
|
282
287
|
tags: ["Agents"],
|
|
283
288
|
params: z.object({ id: z.string() }),
|
|
284
289
|
query: z.object({ repoId: z.string().optional() }),
|
|
@@ -287,6 +292,7 @@ const updateAgentRuntimeRoute = route({
|
|
|
287
292
|
model: z.string().trim().min(1).nullable().optional(),
|
|
288
293
|
allow_custom_model: z.boolean().optional().default(false),
|
|
289
294
|
reasoning_effort: ReasoningEffortSchema.nullable().optional(),
|
|
295
|
+
profile: z.string().trim().min(1).nullable().optional(),
|
|
290
296
|
acp: AcpRuntimeConfigSchema.optional(),
|
|
291
297
|
claude: ClaudeRuntimeConfigSchema.optional(),
|
|
292
298
|
}),
|
|
@@ -1129,9 +1135,29 @@ export async function handleAgentsRest(
|
|
|
1129
1135
|
if (updateAgentRuntimeRoute.match(req.method, pathSegments)) {
|
|
1130
1136
|
const parsed = await updateAgentRuntimeRoute.parse(req, res, pathSegments, queryParams);
|
|
1131
1137
|
if (!parsed) return true;
|
|
1132
|
-
const { harness_provider, model, allow_custom_model, reasoning_effort, acp, claude } =
|
|
1138
|
+
const { harness_provider, model, allow_custom_model, reasoning_effort, profile, acp, claude } =
|
|
1133
1139
|
parsed.body;
|
|
1134
1140
|
|
|
1141
|
+
if (typeof profile === "string") {
|
|
1142
|
+
if (model !== undefined) {
|
|
1143
|
+
jsonError(res, "Send `profile` or `model`, not both", 400);
|
|
1144
|
+
return true;
|
|
1145
|
+
}
|
|
1146
|
+
const picked = await getModelProfileByName(profile);
|
|
1147
|
+
if (!picked) {
|
|
1148
|
+
jsonError(res, `Unknown model profile "${profile}"`, 400);
|
|
1149
|
+
return true;
|
|
1150
|
+
}
|
|
1151
|
+
if (picked.harness !== harness_provider) {
|
|
1152
|
+
jsonError(
|
|
1153
|
+
res,
|
|
1154
|
+
`Model profile "${profile}" runs on the ${picked.harness} harness, not ${harness_provider}`,
|
|
1155
|
+
400,
|
|
1156
|
+
);
|
|
1157
|
+
return true;
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1135
1161
|
if (acp && harness_provider !== "acp") {
|
|
1136
1162
|
jsonError(res, "ACP configuration requires harness_provider=acp", 400);
|
|
1137
1163
|
return true;
|
|
@@ -1250,6 +1276,22 @@ export async function handleAgentsRest(
|
|
|
1250
1276
|
});
|
|
1251
1277
|
}
|
|
1252
1278
|
|
|
1279
|
+
// Written after the overrides above: changing either of them clears
|
|
1280
|
+
// MODEL_PROFILE, so a stale default never beats a fresh override.
|
|
1281
|
+
if (model !== undefined || profile === null) {
|
|
1282
|
+
await deleteSwarmConfigByKey("agent", parsed.params.id, MODEL_PROFILE_CONFIG_KEY);
|
|
1283
|
+
} else if (profile !== undefined) {
|
|
1284
|
+
await upsertSwarmConfig({
|
|
1285
|
+
scope: "agent",
|
|
1286
|
+
scopeId: parsed.params.id,
|
|
1287
|
+
key: MODEL_PROFILE_CONFIG_KEY,
|
|
1288
|
+
value: profile,
|
|
1289
|
+
description: "Default model profile, set via PATCH /api/agents/{id}/runtime",
|
|
1290
|
+
// Read by the API at claim only; workers never need it in their env.
|
|
1291
|
+
exportToEnv: false,
|
|
1292
|
+
});
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1253
1295
|
if (claude?.transport === null) {
|
|
1254
1296
|
await deleteSwarmConfigByKey("agent", parsed.params.id, "CLAUDE_TRANSPORT");
|
|
1255
1297
|
} else if (claude?.transport !== undefined) {
|
|
@@ -1341,6 +1383,11 @@ export async function handleAgentsRest(
|
|
|
1341
1383
|
jsonError(res, error.message, 400);
|
|
1342
1384
|
return true;
|
|
1343
1385
|
}
|
|
1386
|
+
// The profile was deleted between the check above and this write.
|
|
1387
|
+
if (modelProfileRefError(error) === "missing") {
|
|
1388
|
+
jsonError(res, `Unknown model profile "${profile}"`, 400);
|
|
1389
|
+
return true;
|
|
1390
|
+
}
|
|
1344
1391
|
throw error;
|
|
1345
1392
|
}
|
|
1346
1393
|
|
package/src/http/all-routes.ts
CHANGED
package/src/http/apps.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
parseAppDefinition,
|
|
13
13
|
SORTABLE_SYSTEM_DATE_COLUMNS,
|
|
14
14
|
SYSTEM_COLUMN_KINDS,
|
|
15
|
+
scriptCompatWarnings,
|
|
15
16
|
} from "../apps/definition";
|
|
16
17
|
import {
|
|
17
18
|
type AppRow,
|
|
@@ -227,9 +228,14 @@ const AppUserConfigFieldSchema = z.object({
|
|
|
227
228
|
/** Mirrors an app definition's `userConfig` declaration map. */
|
|
228
229
|
const AppUserConfigSchema = z.record(AppNameSchema, AppUserConfigFieldSchema);
|
|
229
230
|
|
|
231
|
+
const compatWarningsSchema = z
|
|
232
|
+
.array(z.string())
|
|
233
|
+
.optional()
|
|
234
|
+
.describe("Advisory quickjs-executor compatibility findings for the app's scripts.");
|
|
230
235
|
const appWriteResponseSchema = z.object({
|
|
231
236
|
app: AppRecordSchema,
|
|
232
237
|
migration: AppMigrationReportSchema,
|
|
238
|
+
warnings: compatWarningsSchema,
|
|
233
239
|
});
|
|
234
240
|
const userConfigBodySchema = z.object({ values: z.record(z.string(), z.unknown()) }).strict();
|
|
235
241
|
|
|
@@ -307,7 +313,10 @@ const createAppRoute = route({
|
|
|
307
313
|
forceElementBreak: ForceElementBreakSchema.optional(),
|
|
308
314
|
}),
|
|
309
315
|
responses: {
|
|
310
|
-
201: {
|
|
316
|
+
201: {
|
|
317
|
+
description: "Created app",
|
|
318
|
+
schema: z.object({ app: AppRecordSchema, warnings: compatWarningsSchema }),
|
|
319
|
+
},
|
|
311
320
|
400: { description: "Invalid app definition" },
|
|
312
321
|
403: { description: "Permission denied" },
|
|
313
322
|
},
|
|
@@ -1020,12 +1029,14 @@ export async function handleApps(
|
|
|
1020
1029
|
invalidDefinition(res, definition.issues);
|
|
1021
1030
|
return true;
|
|
1022
1031
|
}
|
|
1032
|
+
const warnings = await scriptCompatWarnings(definition.definition);
|
|
1023
1033
|
createAppRoute.respond(res, 201, {
|
|
1024
1034
|
app: await createApp({
|
|
1025
1035
|
name: parsed.body.name,
|
|
1026
1036
|
description: parsed.body.description,
|
|
1027
1037
|
definition: definition.definition,
|
|
1028
1038
|
}),
|
|
1039
|
+
...(warnings.length > 0 ? { warnings } : {}),
|
|
1029
1040
|
});
|
|
1030
1041
|
return true;
|
|
1031
1042
|
}
|
|
@@ -1482,6 +1493,7 @@ export async function handleApps(
|
|
|
1482
1493
|
}
|
|
1483
1494
|
let app: Awaited<ReturnType<typeof updateApp>> = null;
|
|
1484
1495
|
let migration!: AppMigrationReport;
|
|
1496
|
+
let writtenDefinition: unknown;
|
|
1485
1497
|
let responseHandled = false;
|
|
1486
1498
|
try {
|
|
1487
1499
|
await withAppDefinitionLock(parsed.params.id, async () => {
|
|
@@ -1513,6 +1525,7 @@ export async function handleApps(
|
|
|
1513
1525
|
responseHandled = true;
|
|
1514
1526
|
return;
|
|
1515
1527
|
}
|
|
1528
|
+
if (parsed.body.definition !== undefined) writtenDefinition = definition.definition;
|
|
1516
1529
|
const migrated = await migrateAppSchema({
|
|
1517
1530
|
appId: parsed.params.id,
|
|
1518
1531
|
previousDefinition: existing.definition,
|
|
@@ -1553,7 +1566,13 @@ export async function handleApps(
|
|
|
1553
1566
|
jsonError(res, "app not found", 404);
|
|
1554
1567
|
return true;
|
|
1555
1568
|
}
|
|
1556
|
-
|
|
1569
|
+
const warnings =
|
|
1570
|
+
writtenDefinition === undefined ? [] : await scriptCompatWarnings(writtenDefinition);
|
|
1571
|
+
patchAppRoute.respond(res, 200, {
|
|
1572
|
+
app,
|
|
1573
|
+
migration,
|
|
1574
|
+
...(warnings.length > 0 ? { warnings } : {}),
|
|
1575
|
+
});
|
|
1557
1576
|
return true;
|
|
1558
1577
|
}
|
|
1559
1578
|
|
|
@@ -1568,6 +1587,7 @@ export async function handleApps(
|
|
|
1568
1587
|
}
|
|
1569
1588
|
let app: Awaited<ReturnType<typeof updateApp>> = null;
|
|
1570
1589
|
let migration!: AppMigrationReport;
|
|
1590
|
+
let writtenDefinition: unknown;
|
|
1571
1591
|
let responseHandled = false;
|
|
1572
1592
|
try {
|
|
1573
1593
|
await withAppDefinitionLock(parsed.params.id, async () => {
|
|
@@ -1597,6 +1617,7 @@ export async function handleApps(
|
|
|
1597
1617
|
return;
|
|
1598
1618
|
}
|
|
1599
1619
|
const nextDefinition = definition ?? existing.definition;
|
|
1620
|
+
writtenDefinition = definition;
|
|
1600
1621
|
const migrated = await migrateAppSchema({
|
|
1601
1622
|
appId: parsed.params.id,
|
|
1602
1623
|
previousDefinition: appDefinitionNeedsRepair(existing) ? undefined : existing.definition,
|
|
@@ -1637,7 +1658,13 @@ export async function handleApps(
|
|
|
1637
1658
|
jsonError(res, "app not found", 404);
|
|
1638
1659
|
return true;
|
|
1639
1660
|
}
|
|
1640
|
-
|
|
1661
|
+
const warnings =
|
|
1662
|
+
writtenDefinition === undefined ? [] : await scriptCompatWarnings(writtenDefinition);
|
|
1663
|
+
updateAppRoute.respond(res, 200, {
|
|
1664
|
+
app,
|
|
1665
|
+
migration,
|
|
1666
|
+
...(warnings.length > 0 ? { warnings } : {}),
|
|
1667
|
+
});
|
|
1641
1668
|
return true;
|
|
1642
1669
|
}
|
|
1643
1670
|
|
package/src/http/config.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
getSwarmConfigs,
|
|
10
10
|
maskSecrets,
|
|
11
11
|
} from "../be/db";
|
|
12
|
+
import { modelProfileRefError } from "../be/db/model-profiles";
|
|
12
13
|
import {
|
|
13
14
|
AGENT_MAX_TASKS_CONFIG_KEY,
|
|
14
15
|
resetAgentMaxTasksMirror,
|
|
@@ -27,7 +28,7 @@ import {
|
|
|
27
28
|
} from "../be/swarm-config-guard";
|
|
28
29
|
import { can, isRbacEnabled, type PermissionVerb } from "../rbac";
|
|
29
30
|
import { SwarmConfigSchema } from "../types";
|
|
30
|
-
import { getRequestAuth } from "../utils/request-auth-context";
|
|
31
|
+
import { getRequestAuth, type HttpRequestAuth } from "../utils/request-auth-context";
|
|
31
32
|
import { registerVolatileSecret } from "../utils/secret-scrubber";
|
|
32
33
|
import { reloadGlobalConfigsAndIntegrations, scheduleIntegrationsReload } from "./core";
|
|
33
34
|
import { route } from "./route-def";
|
|
@@ -48,6 +49,25 @@ function singleHeader(req: IncomingMessage, name: string): string | undefined {
|
|
|
48
49
|
return Array.isArray(raw) ? raw[0] : raw;
|
|
49
50
|
}
|
|
50
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Whether this caller's `/api/config/resolved` carries secret repo rows (the
|
|
54
|
+
* `includeRepoSecrets` of {@link resolveSecretsRead}): a runtime-token agent
|
|
55
|
+
* gets them only with `config.read.secrets`. Claim uses it so an agent's
|
|
56
|
+
* default profile yields only to repo rows that worker's env really gets.
|
|
57
|
+
*/
|
|
58
|
+
export function readsRepoSecrets(
|
|
59
|
+
auth: HttpRequestAuth | null,
|
|
60
|
+
agent: { isLead?: boolean } | null | undefined,
|
|
61
|
+
): boolean {
|
|
62
|
+
if (auth?.kind !== "agent" || !auth.runtimeId) return true;
|
|
63
|
+
return can({
|
|
64
|
+
principal: { kind: "agent", agentId: auth.agentId, isLead: agent?.isLead ?? false },
|
|
65
|
+
verb: "config.read.secrets",
|
|
66
|
+
resource: { kind: "none" },
|
|
67
|
+
source: "http",
|
|
68
|
+
}).allow;
|
|
69
|
+
}
|
|
70
|
+
|
|
51
71
|
async function requestSecretReadScope(
|
|
52
72
|
req: IncomingMessage,
|
|
53
73
|
resolvedScope?: { agentId?: string; repoId?: string },
|
|
@@ -512,7 +532,11 @@ export async function handleConfig(
|
|
|
512
532
|
}
|
|
513
533
|
const result = includeSecrets || !config.isSecret ? config : maskSecrets([config])[0]!;
|
|
514
534
|
upsertConfig.respond(res, 200, result);
|
|
515
|
-
} catch (
|
|
535
|
+
} catch (error) {
|
|
536
|
+
if (modelProfileRefError(error) === "missing") {
|
|
537
|
+
jsonError(res, `Unknown model profile "${String(value)}"`, 400);
|
|
538
|
+
return true;
|
|
539
|
+
}
|
|
516
540
|
jsonError(res, "Failed to upsert config", 500);
|
|
517
541
|
}
|
|
518
542
|
return true;
|
package/src/http/core.ts
CHANGED
|
@@ -3,9 +3,11 @@ import { z } from "zod";
|
|
|
3
3
|
import { initAgentMail, resetAgentMail } from "../agentmail";
|
|
4
4
|
import {
|
|
5
5
|
initAzureDevOps,
|
|
6
|
+
initAzureDevOpsOutbound,
|
|
6
7
|
isAzureDevOpsEnabled,
|
|
7
8
|
resetAzureDevOps,
|
|
8
9
|
resetAzureDevOpsBotIdCache,
|
|
10
|
+
teardownAzureDevOpsOutbound,
|
|
9
11
|
} from "../azure-devops";
|
|
10
12
|
import {
|
|
11
13
|
getAgentById,
|
|
@@ -235,6 +237,8 @@ async function reloadGlobalConfigsAndIntegrationsInner(): Promise<ReloadConfigRe
|
|
|
235
237
|
resetAzureDevOpsBotIdCache();
|
|
236
238
|
initAzureDevOps();
|
|
237
239
|
if (isAzureDevOpsEnabled()) integrations.push("azure-devops");
|
|
240
|
+
teardownAzureDevOpsOutbound();
|
|
241
|
+
if (isAzureDevOpsEnabled()) initAzureDevOpsOutbound();
|
|
238
242
|
|
|
239
243
|
resetLinear();
|
|
240
244
|
if (await initLinear()) integrations.push("linear");
|
package/src/http/index.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
import type { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
8
8
|
import { getEnabledCapabilities, hasCapability } from "@/server";
|
|
9
9
|
import { initAgentMail } from "../agentmail";
|
|
10
|
-
import { initAzureDevOps } from "../azure-devops";
|
|
10
|
+
import { initAzureDevOps, initAzureDevOpsOutbound } from "../azure-devops";
|
|
11
11
|
import { drainApi, isApiDraining } from "../be/api-drain";
|
|
12
12
|
import {
|
|
13
13
|
closeDb,
|
|
@@ -104,6 +104,7 @@ import { handleMcpServers } from "./mcp-servers";
|
|
|
104
104
|
import { closeIdleMcpUserTransports, handleMcpUser } from "./mcp-user";
|
|
105
105
|
import { handleMemory, startMemoryGc, stopMemoryGc } from "./memory";
|
|
106
106
|
import { handleMetrics } from "./metrics";
|
|
107
|
+
import { handleModelProfiles } from "./model-profiles";
|
|
107
108
|
import { handleModelsCatalog } from "./models-catalog";
|
|
108
109
|
import { handleOAuthCallback, startOAuthPendingGc, stopOAuthPendingGc } from "./oauth-callback";
|
|
109
110
|
import { handleGenericOAuth } from "./oauth-generic";
|
|
@@ -376,6 +377,7 @@ const httpServer = createHttpServer(async (req, res) => {
|
|
|
376
377
|
() => handleDbQuery(req, res, pathSegments, queryParams),
|
|
377
378
|
() => handleMetrics(req, res, pathSegments, queryParams, myAgentId),
|
|
378
379
|
() => handleModelsCatalog(req, res, pathSegments, queryParams),
|
|
380
|
+
() => handleModelProfiles(req, res, pathSegments, queryParams, myAgentId),
|
|
379
381
|
() => handleRepos(req, res, pathSegments, queryParams, myAgentId),
|
|
380
382
|
() => handleSkills(req, res, pathSegments, queryParams, myAgentId),
|
|
381
383
|
() => handleScriptConnections(req, res, pathSegments, queryParams, myAgentId),
|
|
@@ -665,6 +667,13 @@ try {
|
|
|
665
667
|
console.error("[startup] Failed to seed pricing rows:", err);
|
|
666
668
|
}
|
|
667
669
|
|
|
670
|
+
try {
|
|
671
|
+
const { ensureModelProfilesSeeded } = await import("../be/boot-seeds");
|
|
672
|
+
await ensureModelProfilesSeeded();
|
|
673
|
+
} catch (err) {
|
|
674
|
+
console.error("[startup] Failed to seed model profiles:", err);
|
|
675
|
+
}
|
|
676
|
+
|
|
668
677
|
try {
|
|
669
678
|
const { ensureRbacSeeded } = await import("../be/boot-seeds");
|
|
670
679
|
ensureRbacSeeded();
|
|
@@ -785,6 +794,7 @@ httpServer
|
|
|
785
794
|
|
|
786
795
|
// Initialize Azure DevOps service-hook handler (if configured)
|
|
787
796
|
initAzureDevOps();
|
|
797
|
+
initAzureDevOpsOutbound();
|
|
788
798
|
|
|
789
799
|
// Initialize AgentMail webhook handler (if configured)
|
|
790
800
|
initAgentMail();
|