@desplega.ai/agent-swarm 2.3.0 → 2.4.1
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/README.md +1 -0
- package/dist/{acp-adapter-v85a2bqy.js → acp-adapter-zvzr538d.js} +9 -9
- package/dist/{actions-zgcxfspj.js → actions-jhtqdw69.js} +21 -19
- package/dist/{amp-adapter-jw9xfz42.js → amp-adapter-bd84rhs2.js} +4 -4
- package/dist/{app-4e1s4675.js → app-kreq1gwg.js} +3 -3
- package/dist/{assistant-v238n9dk.js → assistant-3k22sbsq.js} +23 -21
- package/dist/{boot-reembed-p666cw5n.js → boot-reembed-e53x6b9v.js} +1 -1
- package/dist/{boot-reembed-w6pm64j4.js → boot-reembed-f6z923ny.js} +1 -1
- package/dist/{boot-scrub-sweep-jcyjagn3.js → boot-scrub-sweep-0538vsb7.js} +4 -4
- package/dist/{boot-seeds-gbedmamp.js → boot-seeds-6wxqkfk2.js} +4 -4
- package/dist/{claude-adapter-q7wspzt8.js → claude-adapter-gfts5044.js} +9 -9
- package/dist/{claude-managed-adapter-n7ahjyx6.js → claude-managed-adapter-h2y889ge.js} +3 -3
- package/dist/{claude-managed-setup-wza784fb.js → claude-managed-setup-h00hsgtz.js} +2 -2
- package/dist/{claude-sdk-session-yf400ptr.js → claude-sdk-session-56besmfz.js} +13 -13
- package/dist/{cli-65q70v2v.js → cli-0bh477zn.js} +33 -6
- package/dist/{cli-4ync7m60.js → cli-0ebey9hg.js} +1 -1
- package/dist/{cli-665j3feb.js → cli-0xk505e8.js} +1 -1
- package/dist/{cli-7gh7020n.js → cli-1dmcq2eh.js} +1 -1
- package/dist/{cli-gzvb3d4a.js → cli-1jx0srjt.js} +3 -3
- package/dist/{cli-zj4d6afs.js → cli-1pa3rz69.js} +21 -6
- package/dist/{cli-7ayprxp7.js → cli-2dfbv8qr.js} +8 -0
- package/dist/{cli-30m5q8mc.js → cli-3kh4kpqy.js} +6 -6
- package/dist/{cli-qrwp40st.js → cli-3p8fqcnh.js} +2 -2
- package/dist/{cli-y3dvz6ge.js → cli-3r448dqn.js} +3 -3
- package/dist/{cli-a17tzmn0.js → cli-3tnpj2bh.js} +7 -7
- package/dist/{cli-ea7chd26.js → cli-471qk6s2.js} +93 -46
- package/dist/{cli-a49vpbf3.js → cli-5kqnemen.js} +1 -1
- package/dist/{cli-0rh20bp3.js → cli-6ncjvx55.js} +3 -3
- package/dist/{cli-fb6t92v8.js → cli-6x9ma5w5.js} +1 -1
- package/dist/{cli-k28p6xh7.js → cli-7225gwj7.js} +2 -2
- package/dist/{cli-8cvvytad.js → cli-8nyhf7za.js} +3 -3
- package/dist/{cli-e09hj50q.js → cli-8wkb09q5.js} +11 -11
- package/dist/{cli-j0v75y13.js → cli-a0kcty51.js} +4 -4
- package/dist/{cli-zes4tsbb.js → cli-a4gvwttf.js} +4 -4
- package/dist/{cli-jhp7w1fy.js → cli-a5ebc95n.js} +2 -2
- package/dist/{cli-5d1m1qca.js → cli-ash6xxk7.js} +2 -2
- package/dist/{cli-fp4xbw07.js → cli-axh29tyr.js} +14 -12
- package/dist/{cli-p22zdvnt.js → cli-bn0rewsy.js} +3 -3
- package/dist/{cli-hz64bcnj.js → cli-bn5kevnf.js} +11 -373
- package/dist/{cli-8jtrekpy.js → cli-d2mb5s8a.js} +7 -7
- package/dist/{cli-c5sbmw1v.js → cli-d82btycs.js} +94 -15
- package/dist/{cli-vjfpshn3.js → cli-ejs3m1sx.js} +1 -1
- package/dist/{cli-yv0vgscc.js → cli-fpmsqq59.js} +18 -2
- package/dist/cli-fz9kewbh.js +382 -0
- package/dist/{cli-4s1kqrqg.js → cli-g0hgtz4p.js} +6 -6
- package/dist/{cli-hn3pftj2.js → cli-gf0kfg81.js} +7 -7
- package/dist/{cli-d43xqzbe.js → cli-hqhzg1qq.js} +2 -2
- package/dist/{cli-azs9bhc5.js → cli-j4rqdf2n.js} +2 -2
- package/dist/{cli-wtg6edvd.js → cli-jh0qcrga.js} +1 -1
- package/dist/{cli-kqypty34.js → cli-k9z4zd4p.js} +6 -5
- package/dist/{cli-jhmjwqcg.js → cli-kmqgmcnb.js} +47 -14
- package/dist/{cli-8qsx817b.js → cli-kr2pmfqx.js} +583 -769
- package/dist/{cli-4g629sgr.js → cli-m2qgh5sv.js} +20 -1
- package/dist/{cli-9e9kjqsj.js → cli-mfe7f7b5.js} +2 -2
- package/dist/{cli-x3en6ct3.js → cli-nwyw3zhg.js} +1 -1
- package/dist/{cli-6vcyw6v7.js → cli-nx462e4v.js} +5 -3
- package/dist/{cli-tr24eeny.js → cli-p0rakbrk.js} +9 -9
- package/dist/{cli-4hmaheb6.js → cli-p6argxh9.js} +9 -9
- package/dist/{cli-3avfh5az.js → cli-pemywhfq.js} +2 -2
- package/dist/{cli-etvn5ej2.js → cli-pnp2j5zg.js} +2 -2
- package/dist/{cli-wk8ccrz6.js → cli-pw7v69vp.js} +2 -2
- package/dist/{cli-ka01m5rb.js → cli-rdq7tzwm.js} +17 -14
- package/dist/{cli-re4wkbzx.js → cli-rqqsfz30.js} +677 -104
- package/dist/{cli-xgn4rwyv.js → cli-s48yvzb8.js} +4 -4
- package/dist/{cli-zv4vy2b0.js → cli-s95dknxh.js} +1 -1
- package/dist/{cli-g6p7c2my.js → cli-sjyetj21.js} +2 -2
- package/dist/{cli-rdr166ht.js → cli-smvcw9z5.js} +1 -1
- package/dist/{cli-fhvqt2fp.js → cli-sv5gb0yb.js} +1 -1
- package/dist/{cli-yv3n83x8.js → cli-syhq378v.js} +2 -2
- package/dist/{cli-q1812jbw.js → cli-tbhwrxpt.js} +9 -9
- package/dist/{cli-w7z94e6c.js → cli-tx00c0h6.js} +4 -2
- package/dist/{cli-dxwh4j32.js → cli-vy0fay6k.js} +46 -37
- package/dist/{cli-ptkpaqfy.js → cli-wt645v7q.js} +1 -1
- package/dist/{cli-ppapy34w.js → cli-wxbn3yfx.js} +2 -2
- package/dist/{cli-cby329ny.js → cli-x5mq1fyq.js} +3 -3
- package/dist/{cli-rc3r0bnh.js → cli-xbzvet96.js} +6 -6
- package/dist/{cli-4mkvwgzr.js → cli-xf234ws8.js} +1 -1
- package/dist/{cli-6p7ddg72.js → cli-xftrvxag.js} +5 -5
- package/dist/cli-z071fb95.js +848 -0
- package/dist/{cli-1v8w782f.js → cli-z1ew8vbq.js} +14 -7
- package/dist/{cli-9td5ss65.js → cli-zfg9enh9.js} +3 -3
- package/dist/{cli-yxqag76b.js → cli-zw88zjba.js} +1 -1
- package/dist/cli.js +19 -19
- package/dist/{codex-adapter-nhjj2veb.js → codex-adapter-p6rmm7vv.js} +6 -6
- package/dist/{codex-hook-x6tm6y5m.js → codex-hook-x7nejyrr.js} +8 -5
- package/dist/{codex-login-35p4sk85.js → codex-login-m819c41r.js} +1 -1
- package/dist/{codex-session-runner-6hggrjbx.js → codex-session-runner-8vd5t9t0.js} +7 -7
- package/dist/{commands-mrw1ph2w.js → commands-7ems2p13.js} +2 -2
- package/dist/{controller-pt1zam5w.js → controller-m263fg43.js} +4 -4
- package/dist/{controllers-connect-ymw5541d.js → controllers-connect-bg33ae53.js} +28 -24
- package/dist/{cursor-adapter-cf4zh5x0.js → cursor-adapter-cz6nm6mj.js} +3 -3
- package/dist/{db-hy80219q.js → db-w505dwa8.js} +2 -2
- package/dist/{db-hhpy6m4x.js → db-ys2rbdft.js} +3 -2
- package/dist/{devin-adapter-7egzmt0k.js → devin-adapter-zgqadvnm.js} +1 -1
- package/dist/{dispatcher-6pdjtkr1.js → dispatcher-0s0mckqr.js} +20 -18
- package/dist/{docker-njavd3fb.js → docker-fkgtr75t.js} +2 -2
- package/dist/{dsh-adapter-fbx06re2.js → dsh-adapter-3n3net33.js} +3 -3
- package/dist/{e2b-5r6a5jeb.js → e2b-7am6tmq6.js} +2 -2
- package/dist/{e2b-pw1nvtmh.js → e2b-thdcxtjd.js} +2 -2
- package/dist/{easter-egg-3d-6hg2r942.js → easter-egg-3d-5cgynaja.js} +1 -1
- package/dist/{event-bus-101fenkh.js → event-bus-9vpk8gmq.js} +1 -1
- package/dist/{execute-bcqc69a5.js → execute-t4e6m3rw.js} +1 -1
- package/dist/{external-channel-j6vb6ya1.js → external-channel-5b23fv8z.js} +2 -2
- package/dist/{google-generative-ai-phpmwxvg.js → google-generative-ai-bmq8gkf3.js} +1 -1
- package/dist/{google-vertex-es9ybgdy.js → google-vertex-b1rvp52s.js} +1 -1
- package/dist/{grok-adapter-1193sprp.js → grok-adapter-q9fghe5q.js} +10 -10
- package/dist/handlers-mqrym347.js +39 -0
- package/dist/{heartbeat-h1w1ktce.js → heartbeat-tww6yx1w.js} +23 -21
- package/dist/{hook-ejja4bpe.js → hook-dx0pkvar.js} +16 -9
- package/dist/{hook-skrbja18.js → hook-pvmh9b6m.js} +6 -6
- package/dist/{http-mzh41mfj.js → http-k2ejbt05.js} +975 -292
- package/dist/{index-6rmnn89d.js → index-2z710v4x.js} +10 -10
- package/dist/{index-xmmkyx82.js → index-dgz61nff.js} +20 -18
- package/dist/{index-wgsw9xcz.js → index-g6tbb6ve.js} +1 -1
- package/dist/index-h2ek08d6.js +40 -0
- package/dist/index-pqfwh9nn.js +41 -0
- package/dist/{index-epr2gnbw.js → index-x5aktmp8.js} +1 -1
- package/dist/{index-x0q2a4f9.js → index-ysd45kgc.js} +1 -1
- package/dist/{index-g909y089.js → index-zgvqzjsw.js} +8 -8
- package/dist/{keepalive-4djvbm2j.js → keepalive-nhvpw10z.js} +4 -4
- package/dist/lead-jb6sf69z.js +78 -0
- package/dist/{maintenance-f3xhnjsm.js → maintenance-agakc519.js} +1 -1
- package/dist/{oauth-refresh-sweep-fpd6x6rw.js → oauth-refresh-sweep-4dcbhtn0.js} +3 -3
- package/dist/{onboard-196tjgyn.js → onboard-4n2kwa4v.js} +3 -3
- package/dist/{opencode-adapter-eeesgfqk.js → opencode-adapter-3s7ax02e.js} +7 -7
- package/dist/{otel-impl-g8fh4c21.js → otel-impl-tfa12080.js} +2 -2
- package/dist/{pi-mono-adapter-zasp3ze3.js → pi-mono-adapter-ytp7gz8b.js} +24 -13
- package/dist/{pricing-refresh-sdcf5yaz.js → pricing-refresh-3cqx3f3x.js} +3 -3
- package/dist/{rbac-roles-bsp5657v.js → rbac-roles-9fae5rnv.js} +5 -3
- package/dist/{rbac-roles-2x4g1wb5.js → rbac-roles-y6zbfzve.js} +2 -2
- package/dist/{render-v2-0pyb39bb.js → render-v2-emawjvc4.js} +3 -3
- package/dist/{resume-a86tkj6r.js → resume-zhgts7h7.js} +10 -8
- package/dist/{runtime-ar8310ba.js → runtime-xe3aqy4x.js} +1 -1
- package/dist/session-access-cm823e06.js +25 -0
- package/dist/{setup-ypbzcapd.js → setup-tkp99w1e.js} +1 -1
- package/dist/{virtual-modules-wzk6jf3a.js → virtual-modules-4r3zkc20.js} +2 -2
- package/dist/{work-objects-yjp8de12.js → work-objects-f722h263.js} +23 -21
- package/dist/worker-p7f336rq.js +78 -0
- package/dist/{x-8ewt8gxn.js → x-y45mthwn.js} +2 -2
- package/openapi.json +1086 -305
- package/package.json +2 -2
- package/src/apps/action-caller.ts +6 -0
- package/src/apps/action-runner.ts +146 -0
- package/src/apps/row-store.ts +4 -2
- package/src/apps/script-types.ts +17 -4
- package/src/be/db/active-sessions.ts +5 -0
- package/src/be/db/session-visibility.ts +29 -0
- package/src/be/db/tasks/read.ts +61 -3
- package/src/be/db/tasks/write.ts +15 -6
- package/src/be/db.ts +106 -37
- package/src/be/events.ts +11 -0
- package/src/be/fleet-benchmark-stats.ts +10 -5
- package/src/be/migrations/230_session_shares.sql +23 -0
- package/src/be/models-catalog.ts +4 -0
- package/src/be/onboarding.ts +6 -0
- package/src/be/rbac-roles.ts +2 -0
- package/src/be/scripts/typecheck.ts +13 -0
- package/src/be/session-shares.ts +244 -0
- package/src/be/swarm-config-guard.ts +33 -3
- package/src/be/telemetry-enable.ts +1 -1
- package/src/commands/provider-credentials.ts +12 -2
- package/src/commands/runner.ts +14 -0
- package/src/heartbeat/heartbeat.ts +2 -2
- package/src/hooks/codex-hook.ts +6 -2
- package/src/hooks/hook.ts +7 -0
- package/src/hooks/pr-body-guard.ts +38 -11
- package/src/hooks/pr-room-guard.ts +88 -0
- package/src/http/active-sessions.ts +13 -2
- package/src/http/agents.ts +11 -3
- package/src/http/all-routes.ts +1 -0
- package/src/http/api-keys.ts +3 -1
- package/src/http/approval-requests.ts +2 -1
- package/src/http/apps.ts +118 -190
- package/src/http/config.ts +3 -0
- package/src/http/context.ts +2 -0
- package/src/http/core.ts +39 -2
- package/src/http/events.ts +6 -2
- package/src/http/favorite-owner.ts +1 -1
- package/src/http/fleet-benchmark.ts +79 -30
- package/src/http/fs.ts +38 -3
- package/src/http/global-config.ts +7 -0
- package/src/http/index.ts +3 -1
- package/src/http/memory.ts +3 -1
- package/src/http/ranking.ts +351 -0
- package/src/http/realtime.ts +26 -21
- package/src/http/route-def.ts +77 -11
- package/src/http/script-runs.ts +2 -1
- package/src/http/scripts.ts +8 -0
- package/src/http/session-access.ts +179 -0
- package/src/http/session-data.ts +10 -2
- package/src/http/sessions.ts +212 -12
- package/src/http/stats.ts +7 -3
- package/src/http/tasks.ts +85 -8
- package/src/http/telemetry-ui.ts +1 -1
- package/src/http/used-by.ts +64 -20
- package/src/http/users.ts +2 -2
- package/src/prompts/session-templates.ts +3 -1
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/pi-mono-adapter.ts +15 -0
- package/src/providers/reasoning-effort.ts +2 -1
- package/src/providers/types.ts +2 -0
- package/src/ranking/telemetry-ranking.ts +119 -0
- package/src/ranking/usage.ts +57 -0
- package/src/rbac/admission.ts +22 -7
- package/src/rbac/legacy-policy.ts +2 -0
- package/src/rbac/permissions.ts +9 -0
- package/src/realtime/auth.ts +69 -0
- package/src/realtime/tickets.ts +4 -1
- package/src/realtime/transport.ts +77 -9
- package/src/scripts-runtime/sdk-allowlist.ts +7 -0
- package/src/scripts-runtime/types/stdlib.d.ts +31 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +31 -0
- package/src/server.ts +4 -0
- package/src/slack/blocks.ts +18 -0
- package/src/slack/dm.ts +29 -0
- package/src/telemetry-context.ts +19 -1
- package/src/telemetry-contract/EVENTS.md +45 -8
- package/src/telemetry-contract/SOURCE.json +38 -4
- package/src/telemetry-contract/catalog.json +294 -5
- package/src/telemetry-contract/ranking/fixtures/expected.json +30 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/bad-category.json +11 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/bad-claim.json +11 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/blank-description.json +11 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/blank-name.json +11 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/description-too-long.json +11 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/domain-uppercase.json +11 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/domain-with-scheme.json +11 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/domain-with-www.json +11 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/http-source-url.json +11 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/missing-description.json +10 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/missing-version.json +10 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/name-not-string.json +11 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/name-too-long.json +11 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/not-object.json +1 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/null.json +1 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/other-with-subcategory.json +11 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/oversize.json +1 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/short-claim.json +11 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/subcategory-other-category.json +11 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/trailing-data.json +1 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/unknown-field.json +12 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/unsupported-version.json +11 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/updated-at-not-date.json +11 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/updated-at-offset.json +11 -0
- package/src/telemetry-contract/ranking/fixtures/invalid/wrong-case-field.json +11 -0
- package/src/telemetry-contract/ranking/fixtures/valid/category-without-subcategory.json +11 -0
- package/src/telemetry-contract/ranking/fixtures/valid/full.json +11 -0
- package/src/telemetry-contract/ranking/fixtures/valid/minimal.json +11 -0
- package/src/telemetry-contract/ranking/fixtures/valid/no-claim.json +10 -0
- package/src/telemetry-contract/ranking/fixtures/valid/padded-text.json +11 -0
- package/src/telemetry-contract/ranking/fixtures/valid/unicode-name.json +11 -0
- package/src/telemetry-contract/ranking/listing.v1.schema.json +61 -0
- package/src/telemetry-contract/ranking/taxonomy.json +8 -0
- package/src/telemetry-contract/ranking-taxonomy.gen.ts +11 -0
- package/src/telemetry-contract/types.gen.ts +963 -58
- package/src/telemetry-identity.ts +47 -9
- package/src/telemetry-snapshot.ts +9 -1
- package/src/telemetry-ui-events.ts +9 -2
- package/src/telemetry.ts +40 -5
- package/src/tests/app-action-run-tool.test.ts +178 -0
- package/src/tests/app-row-tools.test.ts +360 -0
- package/src/tests/apps-rbac.test.ts +189 -2
- package/src/tests/apps-script-types.test.ts +16 -3
- package/src/tests/credential-check.test.ts +38 -0
- package/src/tests/db-extraction-contract.test.ts +1 -0
- package/src/tests/db-task-read-contract.test.ts +1 -0
- package/src/tests/docs-index-footprint.test.js +2 -2
- package/src/tests/fleet-benchmark.test.ts +122 -2
- package/src/tests/http-users.test.ts +62 -1
- package/src/tests/model-catalog-table.test.ts +63 -0
- package/src/tests/model-profiles-api.test.ts +19 -7
- package/src/tests/models-catalog.test.ts +50 -0
- package/src/tests/onboarding.test.ts +21 -0
- package/src/tests/org-identity.test.ts +44 -0
- package/src/tests/org-website.test.ts +62 -0
- package/src/tests/pi-mono-adapter.test.ts +23 -0
- package/src/tests/pr-body-leaks.test.ts +4 -0
- package/src/tests/pr-room-guard.test.ts +242 -0
- package/src/tests/ranking-listing.test.ts +97 -0
- package/src/tests/ranking-route.test.ts +321 -0
- package/src/tests/ranking-usage.test.ts +50 -0
- package/src/tests/rbac-admission-e2e.test.ts +8 -0
- package/src/tests/rbac-admission.test.ts +38 -0
- package/src/tests/rbac-charact-http.test.ts +4 -3
- package/src/tests/rbac-engine.test.ts +2 -0
- package/src/tests/rbac-roles.test.ts +2 -0
- package/src/tests/realtime-room-surfaces.test.ts +3 -1
- package/src/tests/realtime-session-join-race.test.ts +142 -0
- package/src/tests/realtime-tickets.test.ts +24 -17
- package/src/tests/realtime-transport.test.ts +91 -0
- package/src/tests/reasoning-effort.test.ts +39 -3
- package/src/tests/runner-harness-telemetry-env.test.ts +56 -1
- package/src/tests/session-route-posture.test.ts +639 -0
- package/src/tests/session-sharing-routes.test.ts +282 -0
- package/src/tests/session-sharing.test.ts +526 -0
- package/src/tests/sessions-detail-batch.test.ts +7 -1
- package/src/tests/slack-tool-blocks.test.ts +101 -0
- package/src/tests/slack-update.test.ts +55 -0
- package/src/tests/slack-user-dm.test.ts +177 -0
- package/src/tests/swarm-tool-result-gate.test.ts +2 -4
- package/src/tests/telemetry-context.test.ts +128 -2
- package/src/tests/telemetry-ui-route.test.ts +123 -0
- package/src/tests/tool-annotations.test.ts +3 -2
- package/src/tests/used-by-route.test.ts +153 -9
- package/src/tests/workflow-agent-task-retry.test.ts +130 -4
- package/src/tests/workflow-wait-recovery.test.ts +116 -4
- package/src/tools/app-action-run.ts +63 -0
- package/src/tools/app-rows.ts +234 -0
- package/src/tools/model-catalog/index.ts +1 -1
- package/src/tools/slack-post.ts +18 -12
- package/src/tools/slack-read.ts +13 -1
- package/src/tools/slack-reply.ts +7 -10
- package/src/tools/slack-start-thread.ts +18 -11
- package/src/tools/slack-update.ts +2 -9
- package/src/tools/tool-config.ts +8 -0
- package/src/tools/utils.ts +1 -1
- package/src/tools/workflows/retry-workflow-run.ts +1 -1
- package/src/types.ts +52 -0
- package/src/utils/company-profile.ts +24 -0
- package/src/utils/org-identity.ts +33 -0
- package/src/utils/org-website.ts +58 -21
- package/src/workflows/recovery.ts +10 -22
- package/src/workflows/resume.ts +16 -0
- package/src/workflows/task-step-routing.ts +47 -7
- package/templates/skills/apps/SKILL.md +58 -2
- package/templates/skills/apps/content.md +58 -2
- package/dist/handlers-tb3xgjnm.js +0 -37
- package/dist/index-nyfcdpky.js +0 -39
- package/dist/index-vjn3wbzf.js +0 -38
- package/dist/lead-61kqp604.js +0 -76
- package/dist/worker-4ptnn1ge.js +0 -76
- package/dist/{cli-n5mrsg0f.js → cli-60cgh1rv.js} +3 -3
|
@@ -13,7 +13,8 @@ import {
|
|
|
13
13
|
} from "../be/db";
|
|
14
14
|
import { ActiveSessionSchema, AgentTaskSchema } from "../types";
|
|
15
15
|
import { isMultiRuntimeEnabled } from "../utils/multi-runtime";
|
|
16
|
-
import { route } from "./route-def";
|
|
16
|
+
import { bodyTask, route } from "./route-def";
|
|
17
|
+
import { readableByFor, resolveSessionActor } from "./session-access";
|
|
17
18
|
import { jsonError } from "./utils";
|
|
18
19
|
|
|
19
20
|
// ─── Route Definitions ───────────────────────────────────────────────────────
|
|
@@ -39,6 +40,7 @@ const createActiveSession = route({
|
|
|
39
40
|
method: "post",
|
|
40
41
|
path: "/api/active-sessions",
|
|
41
42
|
pattern: ["api", "active-sessions"],
|
|
43
|
+
session: bodyTask("taskId"),
|
|
42
44
|
summary: "Create a new active session",
|
|
43
45
|
tags: ["Active Sessions"],
|
|
44
46
|
body: z.object({
|
|
@@ -60,6 +62,7 @@ const deleteSessionByTask = route({
|
|
|
60
62
|
method: "delete",
|
|
61
63
|
path: "/api/active-sessions/by-task/{taskId}",
|
|
62
64
|
pattern: ["api", "active-sessions", "by-task", null],
|
|
65
|
+
session: { taskParam: "taskId" },
|
|
63
66
|
summary: "Delete active session by task ID",
|
|
64
67
|
tags: ["Active Sessions"],
|
|
65
68
|
params: z.object({ taskId: z.string() }),
|
|
@@ -72,6 +75,7 @@ const deleteSessionById = route({
|
|
|
72
75
|
method: "delete",
|
|
73
76
|
path: "/api/active-sessions/{id}",
|
|
74
77
|
pattern: ["api", "active-sessions", null],
|
|
78
|
+
session: { activeSessionParam: "id" },
|
|
75
79
|
summary: "Delete active session by ID",
|
|
76
80
|
tags: ["Active Sessions"],
|
|
77
81
|
params: z.object({ id: z.string() }),
|
|
@@ -84,6 +88,7 @@ const heartbeatSession = route({
|
|
|
84
88
|
method: "put",
|
|
85
89
|
path: "/api/active-sessions/heartbeat/{taskId}",
|
|
86
90
|
pattern: ["api", "active-sessions", "heartbeat", null],
|
|
91
|
+
session: { taskParam: "taskId" },
|
|
87
92
|
summary: "Update heartbeat for an active session",
|
|
88
93
|
tags: ["Active Sessions"],
|
|
89
94
|
params: z.object({ taskId: z.string() }),
|
|
@@ -96,6 +101,7 @@ const updateProviderSession = route({
|
|
|
96
101
|
method: "put",
|
|
97
102
|
path: "/api/active-sessions/provider-session/{taskId}",
|
|
98
103
|
pattern: ["api", "active-sessions", "provider-session", null],
|
|
104
|
+
session: { taskParam: "taskId" },
|
|
99
105
|
summary: "Update provider session ID on an active session",
|
|
100
106
|
tags: ["Active Sessions"],
|
|
101
107
|
params: z.object({ taskId: z.string() }),
|
|
@@ -109,6 +115,7 @@ const cleanupSessions = route({
|
|
|
109
115
|
method: "post",
|
|
110
116
|
path: "/api/active-sessions/cleanup",
|
|
111
117
|
pattern: ["api", "active-sessions", "cleanup"],
|
|
118
|
+
session: { agentWide: "Deletes every session of an agent, or every stale session." },
|
|
112
119
|
summary: "Clean up stale sessions",
|
|
113
120
|
tags: ["Active Sessions"],
|
|
114
121
|
body: z
|
|
@@ -126,6 +133,7 @@ const recoverOrphanedTasks = route({
|
|
|
126
133
|
method: "post",
|
|
127
134
|
path: "/api/active-sessions/recover-orphaned-tasks",
|
|
128
135
|
pattern: ["api", "active-sessions", "recover-orphaned-tasks"],
|
|
136
|
+
session: { none: "Its handler admits only the calling agent, never a user." },
|
|
129
137
|
summary: "Recover orphaned in-progress tasks for an agent",
|
|
130
138
|
tags: ["Active Sessions"],
|
|
131
139
|
body: z.object({
|
|
@@ -153,7 +161,10 @@ export async function handleActiveSessions(
|
|
|
153
161
|
if (listActiveSessions.match(req.method, pathSegments)) {
|
|
154
162
|
const parsed = await listActiveSessions.parse(req, res, pathSegments, queryParams);
|
|
155
163
|
if (!parsed) return true;
|
|
156
|
-
const sessions = await getActiveSessions(
|
|
164
|
+
const sessions = await getActiveSessions(
|
|
165
|
+
parsed.query.agentId || undefined,
|
|
166
|
+
readableByFor(await resolveSessionActor(req, myAgentId)),
|
|
167
|
+
);
|
|
157
168
|
listActiveSessions.respond(res, 200, { sessions });
|
|
158
169
|
return true;
|
|
159
170
|
}
|
package/src/http/agents.ts
CHANGED
|
@@ -90,6 +90,7 @@ import { getRequestAuth } from "../utils/request-auth-context";
|
|
|
90
90
|
import { isRuntimePoolsEnabled } from "../utils/runtime-pools-flag";
|
|
91
91
|
import { scrubSecrets } from "../utils/secret-scrubber";
|
|
92
92
|
import { route, runtimeInstanceHeader } from "./route-def";
|
|
93
|
+
import { readableByFor, resolveSessionActor } from "./session-access";
|
|
93
94
|
import { agentWithCapacity, json, jsonError } from "./utils";
|
|
94
95
|
|
|
95
96
|
function singleHeaderValue(req: IncomingMessage, name: string): string | undefined {
|
|
@@ -844,7 +845,7 @@ export async function handleAgentsRest(
|
|
|
844
845
|
res: ServerResponse,
|
|
845
846
|
pathSegments: string[],
|
|
846
847
|
queryParams: URLSearchParams,
|
|
847
|
-
|
|
848
|
+
myAgentId: string | undefined,
|
|
848
849
|
): Promise<boolean> {
|
|
849
850
|
if (listAgents.match(req.method, pathSegments)) {
|
|
850
851
|
const parsed = await listAgents.parse(req, res, pathSegments, queryParams);
|
|
@@ -853,7 +854,10 @@ export async function handleAgentsRest(
|
|
|
853
854
|
// List responses default to slim (no identity markdown); `?fields=full` restores it.
|
|
854
855
|
const slim = parsed.query.fields !== "full";
|
|
855
856
|
const agents = includeTasks
|
|
856
|
-
? await getAllAgentsWithTasks({
|
|
857
|
+
? await getAllAgentsWithTasks({
|
|
858
|
+
slim,
|
|
859
|
+
readableBy: readableByFor(await resolveSessionActor(req, myAgentId)),
|
|
860
|
+
})
|
|
857
861
|
: await getAllAgents({ slim });
|
|
858
862
|
const [agentsWithCapacity, transports] = await Promise.all([
|
|
859
863
|
Promise.all(agents.map(agentWithCapacity)),
|
|
@@ -1498,6 +1502,7 @@ export async function handleAgentsRest(
|
|
|
1498
1502
|
reportedAt: parsed.body.latest_model?.reportedAt ?? parsed.body.acp!.reportedAt,
|
|
1499
1503
|
reportKind: "post_task" as const,
|
|
1500
1504
|
bedrock: null,
|
|
1505
|
+
opencodeGo: null,
|
|
1501
1506
|
acp: null,
|
|
1502
1507
|
};
|
|
1503
1508
|
finalAgent =
|
|
@@ -1537,7 +1542,10 @@ export async function handleAgentsRest(
|
|
|
1537
1542
|
if (!parsed) return true;
|
|
1538
1543
|
const includeTasks = parsed.query.include === "tasks";
|
|
1539
1544
|
const agent = includeTasks
|
|
1540
|
-
? await getAgentWithTasks(
|
|
1545
|
+
? await getAgentWithTasks(
|
|
1546
|
+
parsed.params.id,
|
|
1547
|
+
readableByFor(await resolveSessionActor(req, myAgentId)),
|
|
1548
|
+
)
|
|
1541
1549
|
: await getAgentById(parsed.params.id);
|
|
1542
1550
|
|
|
1543
1551
|
if (!agent) {
|
package/src/http/all-routes.ts
CHANGED
package/src/http/api-keys.ts
CHANGED
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
SUBSCRIPTION_PLANS,
|
|
21
21
|
SUBSCRIPTION_PLANS_CHECKED_AT,
|
|
22
22
|
} from "../utils/subscription-plans";
|
|
23
|
-
import { route } from "./route-def";
|
|
23
|
+
import { bodyTask, route } from "./route-def";
|
|
24
24
|
import { clearUsageCache } from "./usage-cache";
|
|
25
25
|
import { jsonError } from "./utils";
|
|
26
26
|
|
|
@@ -36,6 +36,7 @@ const reportUsage = route({
|
|
|
36
36
|
method: "post",
|
|
37
37
|
path: "/api/keys/report-usage",
|
|
38
38
|
pattern: ["api", "keys", "report-usage"],
|
|
39
|
+
session: bodyTask("taskId"),
|
|
39
40
|
summary: "Record which API key was used for a task",
|
|
40
41
|
tags: ["API Keys"],
|
|
41
42
|
body: z.object({
|
|
@@ -82,6 +83,7 @@ const reportAuthFailure = route({
|
|
|
82
83
|
method: "post",
|
|
83
84
|
path: "/api/keys/report-auth-failure",
|
|
84
85
|
pattern: ["api", "keys", "report-auth-failure"],
|
|
86
|
+
session: bodyTask("taskId"),
|
|
85
87
|
summary: "Record an auth failure for a pooled key; bench it after 2 in a row",
|
|
86
88
|
tags: ["API Keys"],
|
|
87
89
|
body: z.object({
|
|
@@ -23,7 +23,7 @@ import { getRequestAuth } from "../utils/request-auth-context";
|
|
|
23
23
|
import { cancelApprovalRequest } from "../workflows/approval-cancel";
|
|
24
24
|
import { createApprovalFollowUpTask } from "../workflows/approval-notifications";
|
|
25
25
|
import { workflowEventBus } from "../workflows/event-bus";
|
|
26
|
-
import { route } from "./route-def";
|
|
26
|
+
import { bodyTask, route } from "./route-def";
|
|
27
27
|
import { jsonError } from "./utils";
|
|
28
28
|
|
|
29
29
|
// ─── Route Definitions ───────────────────────────────────────────────────────
|
|
@@ -255,6 +255,7 @@ const createRoute = route({
|
|
|
255
255
|
method: "post",
|
|
256
256
|
path: "/api/approval-requests",
|
|
257
257
|
pattern: ["api", "approval-requests"],
|
|
258
|
+
session: bodyTask("sourceTaskId"),
|
|
258
259
|
summary: "Create a new approval request",
|
|
259
260
|
tags: ["ApprovalRequests"],
|
|
260
261
|
body: z.object({
|
package/src/http/apps.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
2
|
import * as z from "zod";
|
|
3
|
+
import type { AppActionCaller } from "../apps/action-caller";
|
|
4
|
+
import { runAppAction } from "../apps/action-runner";
|
|
3
5
|
import {
|
|
4
6
|
type AppDefinition,
|
|
5
7
|
AppNameSchema,
|
|
@@ -60,14 +62,9 @@ import {
|
|
|
60
62
|
rollbackApp,
|
|
61
63
|
snapshotApp,
|
|
62
64
|
} from "../apps/version";
|
|
63
|
-
import {
|
|
64
|
-
import { getAgentById, getAppVersion, getAppVersions, getLeadAgent } from "../be/db";
|
|
65
|
-
import { getScriptById } from "../be/scripts/db";
|
|
66
|
-
import { getSavedScriptOwnerAgentId, runSavedScriptAsAgent } from "../be/scripts/run-saved";
|
|
67
|
-
import { resolveTemplate } from "../prompts/resolver";
|
|
65
|
+
import { getAgentById, getAppVersion, getAppVersions } from "../be/db";
|
|
68
66
|
import type { RbacPrincipal, RbacResource } from "../rbac";
|
|
69
67
|
import { can } from "../rbac";
|
|
70
|
-
import { createTaskWithSiblingAwareness } from "../tasks/sibling-awareness";
|
|
71
68
|
import { AgentTaskStatusSchema } from "../types";
|
|
72
69
|
import { getRequestAuth } from "../utils/request-auth-context";
|
|
73
70
|
import { scrubObject } from "../utils/secret-scrubber";
|
|
@@ -76,8 +73,8 @@ import { route } from "./route-def";
|
|
|
76
73
|
import { BODY_TOO_LARGE, enforceContentLengthCap, json, jsonError } from "./utils";
|
|
77
74
|
|
|
78
75
|
const MAX_APP_BODY_BYTES = 5 * 1024 * 1024;
|
|
79
|
-
const MAX_APP_ROW_BODY_BYTES = 1 * 1024 * 1024;
|
|
80
|
-
const MAX_APP_BULK_ROWS_BODY_BYTES = 10 * 1024 * 1024;
|
|
76
|
+
export const MAX_APP_ROW_BODY_BYTES = 1 * 1024 * 1024;
|
|
77
|
+
export const MAX_APP_BULK_ROWS_BODY_BYTES = 10 * 1024 * 1024;
|
|
81
78
|
const MAX_USER_CONFIG_BODY_BYTES = 64 * 1024;
|
|
82
79
|
const MAX_USER_CONFIG_VALUES_BYTES = 16 * 1024;
|
|
83
80
|
const DECIMAL_NUMBER_PATTERN = /^[+-]?\d+(?:\.\d+)?$/;
|
|
@@ -660,45 +657,64 @@ const syncAppRoute = route({
|
|
|
660
657
|
});
|
|
661
658
|
|
|
662
659
|
/**
|
|
663
|
-
*
|
|
664
|
-
*
|
|
665
|
-
* (after writing the 403) when the write is denied.
|
|
660
|
+
* Check app permissions and resolve server-verified identity for action input
|
|
661
|
+
* and row provenance. Return null after a 403 response when access is denied.
|
|
666
662
|
*/
|
|
667
|
-
async function
|
|
663
|
+
async function authorizeAppCaller(
|
|
668
664
|
req: IncomingMessage,
|
|
669
665
|
res: ServerResponse,
|
|
670
666
|
myAgentId: string | undefined,
|
|
671
667
|
verb: "app.manage" | "app.use",
|
|
672
668
|
resource: RbacResource,
|
|
673
|
-
): Promise<string | null> {
|
|
669
|
+
): Promise<{ actor: string; caller: AppActionCaller } | null> {
|
|
674
670
|
const auth = getRequestAuth(req);
|
|
675
671
|
let principal: RbacPrincipal;
|
|
676
672
|
let actor: string;
|
|
673
|
+
let caller: AppActionCaller;
|
|
677
674
|
if (auth?.kind === "operator") {
|
|
678
675
|
principal = { kind: "operator" };
|
|
679
|
-
|
|
676
|
+
// Page sessions never act as an agent, even if a header names one.
|
|
677
|
+
const agent = myAgentId && !auth.page ? await getAgentById(myAgentId) : null;
|
|
678
|
+
actor = agent ? `agent:${agent.id}` : "operator";
|
|
679
|
+
caller = agent
|
|
680
|
+
? { kind: "agent", id: agent.id, name: agent.name }
|
|
681
|
+
: { kind: "operator", id: null };
|
|
680
682
|
} else if (auth?.kind === "user") {
|
|
681
683
|
principal = { kind: "user", userId: auth.userId };
|
|
682
684
|
actor = `user:${auth.userId}`;
|
|
683
|
-
|
|
685
|
+
caller = { kind: "user", id: auth.userId, name: auth.user.name };
|
|
686
|
+
} else if (auth?.kind === "guest" || auth?.kind === "controller") {
|
|
684
687
|
principal = { kind: "guest" };
|
|
685
688
|
actor = "guest";
|
|
689
|
+
caller = { kind: "guest", id: null };
|
|
686
690
|
} else {
|
|
687
691
|
const agent = myAgentId ? await getAgentById(myAgentId) : null;
|
|
688
692
|
principal = { kind: "agent", agentId: myAgentId ?? "", isLead: agent?.isLead ?? false };
|
|
689
693
|
actor = myAgentId ? `agent:${myAgentId}` : "agent";
|
|
694
|
+
caller = { kind: "agent", id: myAgentId ?? null, name: agent?.name };
|
|
690
695
|
}
|
|
696
|
+
if (auth?.page) caller.pageId = auth.page.id;
|
|
691
697
|
const decision = can({
|
|
692
698
|
principal,
|
|
693
699
|
verb,
|
|
694
700
|
resource,
|
|
695
701
|
source: "http",
|
|
696
702
|
});
|
|
697
|
-
if (decision.allow) return actor;
|
|
703
|
+
if (decision.allow) return { actor, caller };
|
|
698
704
|
jsonError(res, decision.reason, 403);
|
|
699
705
|
return null;
|
|
700
706
|
}
|
|
701
707
|
|
|
708
|
+
async function authorizeApp(
|
|
709
|
+
req: IncomingMessage,
|
|
710
|
+
res: ServerResponse,
|
|
711
|
+
myAgentId: string | undefined,
|
|
712
|
+
verb: "app.manage" | "app.use",
|
|
713
|
+
resource: RbacResource,
|
|
714
|
+
): Promise<string | null> {
|
|
715
|
+
return (await authorizeAppCaller(req, res, myAgentId, verb, resource))?.actor ?? null;
|
|
716
|
+
}
|
|
717
|
+
|
|
702
718
|
async function authorizeAppManage(
|
|
703
719
|
req: IncomingMessage,
|
|
704
720
|
res: ServerResponse,
|
|
@@ -736,17 +752,6 @@ function definitionNeedsRepair(
|
|
|
736
752
|
return true;
|
|
737
753
|
}
|
|
738
754
|
|
|
739
|
-
/**
|
|
740
|
-
* One `error` string for a sync result, or undefined when every pass succeeded.
|
|
741
|
-
* Each failed pair is named so a multi-pair sync says which one broke; the pass
|
|
742
|
-
* list in `result.passes` carries the rest.
|
|
743
|
-
*/
|
|
744
|
-
function syncPassError(sync: Awaited<ReturnType<typeof runAppSync>>): string | undefined {
|
|
745
|
-
const failed = sync.passes.filter((pass) => pass.error !== undefined);
|
|
746
|
-
if (failed.length === 0) return undefined;
|
|
747
|
-
return failed.map((pass) => `${pass.model}.${pass.source}: ${pass.error}`).join("; ");
|
|
748
|
-
}
|
|
749
|
-
|
|
750
755
|
function snapshotFailure(res: ServerResponse): void {
|
|
751
756
|
jsonError(res, "failed to snapshot app", 500);
|
|
752
757
|
}
|
|
@@ -971,6 +976,10 @@ function rowValue(row: AppRow, column: string): unknown {
|
|
|
971
976
|
return Object.hasOwn(row, column) ? row[column] : undefined;
|
|
972
977
|
}
|
|
973
978
|
|
|
979
|
+
export function rowMatchesFilters(row: AppRow, filters: RowFilter[]): boolean {
|
|
980
|
+
return filters.every((filter) => rowValue(row, filter.column) === filter.value);
|
|
981
|
+
}
|
|
982
|
+
|
|
974
983
|
export function applyQuery(
|
|
975
984
|
rows: AppRow[],
|
|
976
985
|
query: AppQueryDef,
|
|
@@ -999,6 +1008,59 @@ export function applyQuery(
|
|
|
999
1008
|
return selected.slice(0, query.limit ?? 200);
|
|
1000
1009
|
}
|
|
1001
1010
|
|
|
1011
|
+
export async function selectAppRows(
|
|
1012
|
+
appId: string,
|
|
1013
|
+
modelName: string,
|
|
1014
|
+
model: ModelDef,
|
|
1015
|
+
filters: RowFilter[],
|
|
1016
|
+
sortRaw?: string,
|
|
1017
|
+
limit = 200,
|
|
1018
|
+
systemColumns = false,
|
|
1019
|
+
) {
|
|
1020
|
+
// SQL narrows the scan; the `===` re-check keeps the exact filter semantics.
|
|
1021
|
+
const rows = (
|
|
1022
|
+
await listAppRows(
|
|
1023
|
+
appId,
|
|
1024
|
+
modelName,
|
|
1025
|
+
filters.flatMap((filter) =>
|
|
1026
|
+
typeof filter.value === "string" ||
|
|
1027
|
+
typeof filter.value === "number" ||
|
|
1028
|
+
typeof filter.value === "boolean"
|
|
1029
|
+
? [{ column: filter.column, value: filter.value }]
|
|
1030
|
+
: [],
|
|
1031
|
+
),
|
|
1032
|
+
)
|
|
1033
|
+
).filter((row) => rowMatchesFilters(row, filters));
|
|
1034
|
+
|
|
1035
|
+
if (sortRaw) {
|
|
1036
|
+
const [column, dir, extra] = sortRaw.split(":");
|
|
1037
|
+
if (
|
|
1038
|
+
extra !== undefined ||
|
|
1039
|
+
!column ||
|
|
1040
|
+
(dir !== "asc" && dir !== "desc") ||
|
|
1041
|
+
(!SORTABLE_SYSTEM_DATE_COLUMNS.has(column) &&
|
|
1042
|
+
!(systemColumns && Object.hasOwn(SYSTEM_COLUMN_KINDS, column)) &&
|
|
1043
|
+
(!Object.hasOwn(model.columns, column) || model.columns[column]!.hidden === true))
|
|
1044
|
+
) {
|
|
1045
|
+
throw new AppRowValidationError([
|
|
1046
|
+
{ path: "sort", message: "must be <column>:<asc|desc> for a known column" },
|
|
1047
|
+
]);
|
|
1048
|
+
}
|
|
1049
|
+
rows.sort((a, b) => {
|
|
1050
|
+
const result = compareValues(
|
|
1051
|
+
rowValue(a, column),
|
|
1052
|
+
rowValue(b, column),
|
|
1053
|
+
dir,
|
|
1054
|
+
SORTABLE_SYSTEM_DATE_COLUMNS.has(column) ||
|
|
1055
|
+
(Object.hasOwn(model.columns, column) && model.columns[column]!.kind === "date"),
|
|
1056
|
+
);
|
|
1057
|
+
return result;
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
const total = rows.length;
|
|
1061
|
+
return { rows: rows.slice(0, limit), total };
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1002
1064
|
export async function handleApps(
|
|
1003
1065
|
req: IncomingMessage,
|
|
1004
1066
|
res: ServerResponse,
|
|
@@ -1169,55 +1231,23 @@ export async function handleApps(
|
|
|
1169
1231
|
json(res, { error: "invalid row query", issues }, 400);
|
|
1170
1232
|
return true;
|
|
1171
1233
|
}
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1234
|
+
try {
|
|
1235
|
+
listRowsRoute.respond(
|
|
1236
|
+
res,
|
|
1237
|
+
200,
|
|
1238
|
+
await selectAppRows(
|
|
1239
|
+
parsed.params.id,
|
|
1240
|
+
parsed.params.model,
|
|
1241
|
+
resolved.model,
|
|
1242
|
+
filters,
|
|
1243
|
+
parsed.query.sort,
|
|
1244
|
+
parsed.query.limit,
|
|
1183
1245
|
),
|
|
1184
|
-
)
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
const [column, dir, extra] = sortRaw.split(":");
|
|
1189
|
-
if (
|
|
1190
|
-
extra !== undefined ||
|
|
1191
|
-
!column ||
|
|
1192
|
-
(dir !== "asc" && dir !== "desc") ||
|
|
1193
|
-
(!SORTABLE_SYSTEM_DATE_COLUMNS.has(column) &&
|
|
1194
|
-
(!Object.hasOwn(resolved.model.columns, column) ||
|
|
1195
|
-
resolved.model.columns[column]!.hidden === true))
|
|
1196
|
-
) {
|
|
1197
|
-
json(
|
|
1198
|
-
res,
|
|
1199
|
-
{
|
|
1200
|
-
error: "invalid sort",
|
|
1201
|
-
issues: [{ path: "sort", message: "must be <column>:<asc|desc> for a known column" }],
|
|
1202
|
-
},
|
|
1203
|
-
400,
|
|
1204
|
-
);
|
|
1205
|
-
return true;
|
|
1206
|
-
}
|
|
1207
|
-
rows.sort((a, b) => {
|
|
1208
|
-
const result = compareValues(
|
|
1209
|
-
rowValue(a, column),
|
|
1210
|
-
rowValue(b, column),
|
|
1211
|
-
dir,
|
|
1212
|
-
SORTABLE_SYSTEM_DATE_COLUMNS.has(column) ||
|
|
1213
|
-
(Object.hasOwn(resolved.model.columns, column) &&
|
|
1214
|
-
resolved.model.columns[column]!.kind === "date"),
|
|
1215
|
-
);
|
|
1216
|
-
return result;
|
|
1217
|
-
});
|
|
1246
|
+
);
|
|
1247
|
+
} catch (error) {
|
|
1248
|
+
if (!(error instanceof AppRowValidationError)) throw error;
|
|
1249
|
+
json(res, { error: "invalid sort", issues: error.issues }, 400);
|
|
1218
1250
|
}
|
|
1219
|
-
const total = rows.length;
|
|
1220
|
-
listRowsRoute.respond(res, 200, { rows: rows.slice(0, parsed.query.limit ?? 200), total });
|
|
1221
1251
|
return true;
|
|
1222
1252
|
}
|
|
1223
1253
|
|
|
@@ -1326,8 +1356,12 @@ export async function handleApps(
|
|
|
1326
1356
|
if (enforceContentLengthCap(req, res, MAX_APP_ROW_BODY_BYTES) === BODY_TOO_LARGE) return true;
|
|
1327
1357
|
const parsed = await runActionRoute.parse(req, res, pathSegments, queryParams);
|
|
1328
1358
|
if (!parsed) return true;
|
|
1329
|
-
const
|
|
1330
|
-
|
|
1359
|
+
const identity = await authorizeAppCaller(req, res, myAgentId, "app.use", {
|
|
1360
|
+
kind: "app",
|
|
1361
|
+
appId: parsed.params.id,
|
|
1362
|
+
});
|
|
1363
|
+
if (!identity) return true;
|
|
1364
|
+
const { actor, caller } = identity;
|
|
1331
1365
|
|
|
1332
1366
|
const app = await getApp(parsed.params.id);
|
|
1333
1367
|
if (!app) {
|
|
@@ -1335,121 +1369,15 @@ export async function handleApps(
|
|
|
1335
1369
|
return true;
|
|
1336
1370
|
}
|
|
1337
1371
|
if (definitionNeedsRepair(res, app)) return true;
|
|
1338
|
-
const
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
const action = actions[parsed.params.name]!;
|
|
1345
|
-
const input = parsed.body.input ?? {};
|
|
1346
|
-
if (action.kind === "script") {
|
|
1347
|
-
const script = await getScriptById(action.scriptId);
|
|
1348
|
-
if (!script) {
|
|
1349
|
-
json(
|
|
1350
|
-
res,
|
|
1351
|
-
{
|
|
1352
|
-
error: "invalid app action",
|
|
1353
|
-
issues: [
|
|
1354
|
-
{
|
|
1355
|
-
path: `actions.${parsed.params.name}.scriptId`,
|
|
1356
|
-
message: `script "${action.scriptId}" no longer exists`,
|
|
1357
|
-
},
|
|
1358
|
-
],
|
|
1359
|
-
},
|
|
1360
|
-
400,
|
|
1361
|
-
);
|
|
1362
|
-
return true;
|
|
1363
|
-
}
|
|
1364
|
-
|
|
1365
|
-
// Script actions run with the OWNER's bindings by design: wiring a script
|
|
1366
|
-
// into an app is the owner's delegation. parseAppDefinition enforces at
|
|
1367
|
-
// write time that an agent may only wire scripts it owns (or global ones),
|
|
1368
|
-
// so a foreign script id cannot be smuggled in here. Invoker-brokered
|
|
1369
|
-
// credentials remain a possible future tightening.
|
|
1370
|
-
const runAsAgentId = getSavedScriptOwnerAgentId(script);
|
|
1371
|
-
if (!runAsAgentId) {
|
|
1372
|
-
jsonError(res, "agentId is required: this script has no owning agent to run as", 400);
|
|
1373
|
-
return true;
|
|
1374
|
-
}
|
|
1375
|
-
|
|
1376
|
-
const output = await runSavedScriptAsAgent({
|
|
1377
|
-
script,
|
|
1378
|
-
input: { ...action.args, ...input, app: { id: app.id } },
|
|
1379
|
-
agentId: runAsAgentId,
|
|
1380
|
-
});
|
|
1381
|
-
const ok = output.exitCode === 0 && !output.error && !output.runtimeError;
|
|
1382
|
-
const error = ok
|
|
1383
|
-
? undefined
|
|
1384
|
-
: output.runtimeError
|
|
1385
|
-
? `${output.runtimeError.name}: ${output.runtimeError.message}`
|
|
1386
|
-
: (output.error ?? `Script exited with code ${output.exitCode}`);
|
|
1387
|
-
runActionRoute.respond(
|
|
1388
|
-
res,
|
|
1389
|
-
200,
|
|
1390
|
-
scrubObject({
|
|
1391
|
-
ok,
|
|
1392
|
-
result: output.result,
|
|
1393
|
-
stdout: output.stdout,
|
|
1394
|
-
...(error === undefined ? {} : { error }),
|
|
1395
|
-
durationMs: output.durationMs,
|
|
1396
|
-
}),
|
|
1397
|
-
);
|
|
1398
|
-
return true;
|
|
1399
|
-
}
|
|
1400
|
-
|
|
1401
|
-
if (action.kind === "sync") {
|
|
1402
|
-
const startedAt = Date.now();
|
|
1403
|
-
const sync = await runAppSync({
|
|
1404
|
-
appId: app.id,
|
|
1405
|
-
...(action.model === undefined ? {} : { model: action.model }),
|
|
1406
|
-
...(action.source === undefined ? {} : { source: action.source }),
|
|
1407
|
-
invokedBy: actor,
|
|
1408
|
-
});
|
|
1409
|
-
const durationMs = Date.now() - startedAt;
|
|
1410
|
-
if (sync.issues && sync.issues.length > 0) {
|
|
1411
|
-
json(res, { error: "invalid sync action", issues: sync.issues }, 400);
|
|
1412
|
-
return true;
|
|
1413
|
-
}
|
|
1414
|
-
// Deliberately the SCRIPT-action response shape, minus `taskId`:
|
|
1415
|
-
// app-surface.tsx branches on `taskId` first, so omitting it gives the
|
|
1416
|
-
// dashboard running -> ok/error + refetchAll() with zero UI changes.
|
|
1417
|
-
const error = syncPassError(sync);
|
|
1418
|
-
runActionRoute.respond(
|
|
1419
|
-
res,
|
|
1420
|
-
200,
|
|
1421
|
-
scrubObject({
|
|
1422
|
-
ok: sync.ok,
|
|
1423
|
-
result: { passes: sync.passes },
|
|
1424
|
-
...(error === undefined ? {} : { error }),
|
|
1425
|
-
durationMs,
|
|
1426
|
-
}),
|
|
1427
|
-
);
|
|
1428
|
-
return true;
|
|
1429
|
-
}
|
|
1430
|
-
|
|
1431
|
-
const lead = action.agentId ? null : await getLeadAgent();
|
|
1432
|
-
const taskPrompt = resolveTemplate("task.app.action", {
|
|
1433
|
-
prompt: action.prompt,
|
|
1434
|
-
app_id: app.id,
|
|
1435
|
-
action_name: parsed.params.name,
|
|
1436
|
-
input_json: JSON.stringify(input),
|
|
1372
|
+
const output = await runAppAction({
|
|
1373
|
+
app,
|
|
1374
|
+
name: parsed.params.name,
|
|
1375
|
+
input: parsed.body.input,
|
|
1376
|
+
caller,
|
|
1377
|
+
actor,
|
|
1437
1378
|
});
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
{
|
|
1441
|
-
source: "api",
|
|
1442
|
-
agentId: action.agentId ?? lead?.id,
|
|
1443
|
-
routingReason: action.agentId ? "human_pinned" : lead ? "skill" : undefined,
|
|
1444
|
-
routingSource: action.agentId || lead ? "engine_default" : undefined,
|
|
1445
|
-
// App-spawned tasks group under the app's asset namespace so a
|
|
1446
|
-
// swarm-tasks source can pull them back via config.assetKey.
|
|
1447
|
-
key: normalizeAssetKey(`shared/app:${app.id}/action:${parsed.params.name}/`),
|
|
1448
|
-
...(actor.startsWith("user:") ? { requestedByUserId: actor.slice("user:".length) } : {}),
|
|
1449
|
-
},
|
|
1450
|
-
{ origin: "app" },
|
|
1451
|
-
);
|
|
1452
|
-
runActionRoute.respond(res, 200, { ok: true, taskId: task.id, status: task.status });
|
|
1379
|
+
if (output.status === 200) runActionRoute.respond(res, 200, output.body);
|
|
1380
|
+
else json(res, output.body, output.status);
|
|
1453
1381
|
return true;
|
|
1454
1382
|
}
|
|
1455
1383
|
|
package/src/http/config.ts
CHANGED
|
@@ -31,6 +31,7 @@ import { SwarmConfigSchema } from "../types";
|
|
|
31
31
|
import { getRequestAuth, type HttpRequestAuth } from "../utils/request-auth-context";
|
|
32
32
|
import { registerVolatileSecret } from "../utils/secret-scrubber";
|
|
33
33
|
import { reloadGlobalConfigsAndIntegrations, scheduleIntegrationsReload } from "./core";
|
|
34
|
+
import { syncRankingAfterConfigChange } from "./ranking";
|
|
34
35
|
import { route } from "./route-def";
|
|
35
36
|
import { duplicateGuardedQueryKey, jsonError } from "./utils";
|
|
36
37
|
|
|
@@ -527,6 +528,7 @@ export async function handleConfig(
|
|
|
527
528
|
if (scope === "global" && key === "SWARM_ORG_WEBSITE") {
|
|
528
529
|
await fillOrgLogoFromWebsite(String(value));
|
|
529
530
|
}
|
|
531
|
+
if (scope === "global") await syncRankingAfterConfigChange(key, String(value));
|
|
530
532
|
if (scope === "global") {
|
|
531
533
|
scheduleIntegrationsReload();
|
|
532
534
|
}
|
|
@@ -561,6 +563,7 @@ export async function handleConfig(
|
|
|
561
563
|
return true;
|
|
562
564
|
}
|
|
563
565
|
if (existing.scope === "global") {
|
|
566
|
+
await syncRankingAfterConfigChange(existing.key, null);
|
|
564
567
|
scheduleIntegrationsReload();
|
|
565
568
|
}
|
|
566
569
|
if (
|
package/src/http/context.ts
CHANGED
|
@@ -43,6 +43,7 @@ const postContext = route({
|
|
|
43
43
|
method: "post",
|
|
44
44
|
path: "/api/tasks/{id}/context",
|
|
45
45
|
pattern: ["api", "tasks", null, "context"],
|
|
46
|
+
session: { taskParam: "id" },
|
|
46
47
|
summary: "Record a context usage snapshot for a task",
|
|
47
48
|
tags: ["Tasks"],
|
|
48
49
|
params: z.object({ id: z.string() }),
|
|
@@ -72,6 +73,7 @@ const getContext = route({
|
|
|
72
73
|
method: "get",
|
|
73
74
|
path: "/api/tasks/{id}/context",
|
|
74
75
|
pattern: ["api", "tasks", null, "context"],
|
|
76
|
+
session: { taskParam: "id" },
|
|
75
77
|
summary: "Get context usage history for a task",
|
|
76
78
|
tags: ["Tasks"],
|
|
77
79
|
params: z.object({ id: z.string() }),
|