@desplega.ai/agent-swarm 2.3.0 → 2.4.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/README.md +1 -0
- package/dist/{acp-adapter-v85a2bqy.js → acp-adapter-kedstxx6.js} +6 -6
- package/dist/{actions-zgcxfspj.js → actions-vget6r1k.js} +18 -16
- package/dist/{amp-adapter-jw9xfz42.js → amp-adapter-xeb5mktv.js} +2 -2
- package/dist/{app-4e1s4675.js → app-mqap8t8m.js} +3 -3
- package/dist/{assistant-v238n9dk.js → assistant-h0gv97mv.js} +20 -18
- package/dist/{boot-reembed-p666cw5n.js → boot-reembed-qr8a894z.js} +1 -1
- package/dist/{boot-reembed-w6pm64j4.js → boot-reembed-rj85jjhw.js} +1 -1
- package/dist/{boot-scrub-sweep-jcyjagn3.js → boot-scrub-sweep-eyfvn6v9.js} +3 -3
- package/dist/{boot-seeds-gbedmamp.js → boot-seeds-xs9a8dx1.js} +4 -4
- package/dist/{claude-adapter-q7wspzt8.js → claude-adapter-bm23cye7.js} +5 -5
- package/dist/{claude-managed-adapter-n7ahjyx6.js → claude-managed-adapter-1mwrsm9d.js} +2 -2
- package/dist/{claude-managed-setup-wza784fb.js → claude-managed-setup-gkfgks4j.js} +1 -1
- package/dist/{claude-sdk-session-yf400ptr.js → claude-sdk-session-apb4ypz3.js} +5 -5
- package/dist/cli-02vhhssk.js +848 -0
- package/dist/{cli-4ync7m60.js → cli-0ebey9hg.js} +1 -1
- package/dist/{cli-665j3feb.js → cli-0xk505e8.js} +1 -1
- package/dist/{cli-30m5q8mc.js → cli-1cevz46c.js} +5 -5
- package/dist/{cli-gzvb3d4a.js → cli-1jx0srjt.js} +3 -3
- package/dist/{cli-zj4d6afs.js → cli-1pa3rz69.js} +21 -6
- package/dist/{cli-fhvqt2fp.js → cli-2rwet3r7.js} +1 -1
- package/dist/{cli-azs9bhc5.js → cli-3wjs22x3.js} +2 -2
- package/dist/{cli-dxwh4j32.js → cli-4fhyq711.js} +45 -36
- package/dist/{cli-yv3n83x8.js → cli-5ff2sjyt.js} +1 -1
- package/dist/{cli-6vcyw6v7.js → cli-5s5hx57y.js} +5 -3
- package/dist/{cli-hz64bcnj.js → cli-6ftrrwm1.js} +9 -371
- package/dist/{cli-zes4tsbb.js → cli-8b9wvjps.js} +1 -1
- package/dist/cli-8cxkw1f5.js +382 -0
- package/dist/{cli-4s1kqrqg.js → cli-8rwvksbc.js} +2 -2
- package/dist/{cli-e09hj50q.js → cli-8wkb09q5.js} +11 -11
- package/dist/{cli-yv0vgscc.js → cli-a1esmmee.js} +13 -2
- package/dist/{cli-4hmaheb6.js → cli-avmqhatn.js} +7 -7
- package/dist/{cli-g6p7c2my.js → cli-b80a1100.js} +1 -1
- package/dist/{cli-tr24eeny.js → cli-bfc3k1x5.js} +3 -3
- package/dist/{cli-ka01m5rb.js → cli-bhwa8rzc.js} +13 -11
- package/dist/{cli-8cvvytad.js → cli-bn26xbcs.js} +2 -2
- package/dist/{cli-k28p6xh7.js → cli-c8fwpgqb.js} +1 -1
- package/dist/{cli-rc3r0bnh.js → cli-ccn0eybf.js} +1 -1
- package/dist/{cli-9td5ss65.js → cli-dsgj3e7a.js} +2 -2
- package/dist/{cli-a17tzmn0.js → cli-ecshf504.js} +2 -2
- package/dist/{cli-d43xqzbe.js → cli-eqgfs202.js} +1 -1
- package/dist/{cli-ppapy34w.js → cli-f3nx1h8z.js} +2 -2
- package/dist/{cli-ea7chd26.js → cli-ffbrkh1r.js} +74 -35
- package/dist/{cli-xgn4rwyv.js → cli-kk2r80n5.js} +4 -4
- package/dist/{cli-hn3pftj2.js → cli-kz116kvw.js} +3 -3
- package/dist/{cli-1v8w782f.js → cli-mvg2hf8p.js} +4 -4
- package/dist/{cli-5d1m1qca.js → cli-mz1ezzzh.js} +1 -1
- package/dist/{cli-jhmjwqcg.js → cli-nme7wery.js} +6 -6
- package/dist/{cli-65q70v2v.js → cli-nrrg0fvy.js} +18 -4
- package/dist/{cli-8jtrekpy.js → cli-p1m2b6gc.js} +7 -7
- package/dist/{cli-re4wkbzx.js → cli-rg7ntypm.js} +328 -47
- package/dist/{cli-fp4xbw07.js → cli-rsd7ga7v.js} +10 -8
- package/dist/{cli-etvn5ej2.js → cli-sppc0cmw.js} +1 -1
- package/dist/{cli-qrwp40st.js → cli-tg9ksbn8.js} +1 -1
- package/dist/{cli-6p7ddg72.js → cli-tgvpmnwz.js} +2 -2
- package/dist/{cli-q1812jbw.js → cli-tj4j2ts4.js} +6 -6
- package/dist/{cli-kqypty34.js → cli-ttaz6c7m.js} +2 -2
- package/dist/{cli-w7z94e6c.js → cli-tx00c0h6.js} +4 -2
- package/dist/{cli-4g629sgr.js → cli-wrv09v7q.js} +20 -1
- package/dist/{cli-cby329ny.js → cli-wyrr38xm.js} +2 -2
- package/dist/{cli-y3dvz6ge.js → cli-x1p5dhq2.js} +3 -3
- package/dist/{cli-8qsx817b.js → cli-x719j3vs.js} +219 -629
- package/dist/{cli-9e9kjqsj.js → cli-xfe63zx3.js} +1 -1
- package/dist/{cli-wtg6edvd.js → cli-ywyrffff.js} +1 -1
- package/dist/{cli-0rh20bp3.js → cli-zvze9rbm.js} +1 -1
- package/dist/cli.js +14 -14
- package/dist/{codex-adapter-nhjj2veb.js → codex-adapter-pp2gq8gr.js} +3 -3
- package/dist/{codex-hook-x6tm6y5m.js → codex-hook-qwzccd64.js} +1 -1
- package/dist/{codex-session-runner-6hggrjbx.js → codex-session-runner-0vzn09t8.js} +3 -3
- package/dist/{commands-mrw1ph2w.js → commands-psqhkttb.js} +2 -2
- package/dist/{controller-pt1zam5w.js → controller-t20vz2k8.js} +2 -2
- package/dist/{controllers-connect-ymw5541d.js → controllers-connect-gkxmqw9d.js} +24 -20
- package/dist/{cursor-adapter-cf4zh5x0.js → cursor-adapter-3v542qe5.js} +1 -1
- package/dist/{db-hy80219q.js → db-2xbyenjr.js} +2 -2
- package/dist/{db-hhpy6m4x.js → db-nc1rd869.js} +3 -2
- package/dist/{dispatcher-6pdjtkr1.js → dispatcher-ewceb8ts.js} +17 -15
- package/dist/{dsh-adapter-fbx06re2.js → dsh-adapter-75xwh78t.js} +1 -1
- package/dist/{easter-egg-3d-6hg2r942.js → easter-egg-3d-xsc47jwf.js} +1 -1
- package/dist/{execute-bcqc69a5.js → execute-gzmw1mnw.js} +1 -1
- package/dist/{external-channel-j6vb6ya1.js → external-channel-a5dsmxn4.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-vj88xr23.js} +7 -7
- package/dist/handlers-zbs90bny.js +39 -0
- package/dist/{heartbeat-h1w1ktce.js → heartbeat-t2m9r3wa.js} +20 -18
- package/dist/{hook-skrbja18.js → hook-8femx1bg.js} +4 -4
- package/dist/{hook-ejja4bpe.js → hook-xa677f8r.js} +5 -5
- package/dist/{http-mzh41mfj.js → http-xpmmq028.js} +868 -253
- package/dist/{index-vjn3wbzf.js → index-8pwc1jc8.js} +17 -15
- package/dist/{index-epr2gnbw.js → index-cdzyfrsp.js} +1 -1
- package/dist/{index-xmmkyx82.js → index-dg2tmj99.js} +17 -15
- package/dist/index-nxa6me0q.js +41 -0
- package/dist/{index-6rmnn89d.js → index-s7ckdajq.js} +9 -9
- package/dist/{index-wgsw9xcz.js → index-syztqdt6.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-3nr4st3r.js} +3 -3
- package/dist/{lead-61kqp604.js → lead-td8h2sfn.js} +33 -31
- package/dist/{maintenance-f3xhnjsm.js → maintenance-verwpe2c.js} +1 -1
- package/dist/{oauth-refresh-sweep-fpd6x6rw.js → oauth-refresh-sweep-9q2t0y3q.js} +2 -2
- package/dist/{onboard-196tjgyn.js → onboard-aytqedmq.js} +2 -2
- package/dist/{opencode-adapter-eeesgfqk.js → opencode-adapter-f4hryjny.js} +4 -4
- package/dist/{otel-impl-g8fh4c21.js → otel-impl-hckw4wt1.js} +1 -1
- package/dist/{pi-mono-adapter-zasp3ze3.js → pi-mono-adapter-hxby0ce1.js} +6 -6
- package/dist/{pricing-refresh-sdcf5yaz.js → pricing-refresh-5nvme3sm.js} +3 -3
- package/dist/{rbac-roles-bsp5657v.js → rbac-roles-pd8c26m1.js} +5 -3
- package/dist/{rbac-roles-2x4g1wb5.js → rbac-roles-vbpy21mg.js} +2 -2
- package/dist/{render-v2-0pyb39bb.js → render-v2-7nqgvk2q.js} +3 -3
- package/dist/{resume-a86tkj6r.js → resume-b6djcj3c.js} +6 -6
- package/dist/{runtime-ar8310ba.js → runtime-txrxc9za.js} +1 -1
- package/dist/session-access-fc3f9y12.js +25 -0
- package/dist/{setup-ypbzcapd.js → setup-n39szm6b.js} +1 -1
- package/dist/{virtual-modules-wzk6jf3a.js → virtual-modules-wyp2k6z3.js} +2 -2
- package/dist/{work-objects-yjp8de12.js → work-objects-jem2fre0.js} +20 -18
- package/dist/{worker-4ptnn1ge.js → worker-wr6xgfr2.js} +33 -31
- package/openapi.json +844 -110
- package/package.json +1 -1
- package/src/apps/action-caller.ts +6 -0
- package/src/apps/script-types.ts +16 -3
- 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 +92 -33
- package/src/be/events.ts +11 -0
- package/src/be/migrations/230_session_shares.sql +23 -0
- package/src/be/rbac-roles.ts +2 -0
- package/src/be/session-shares.ts +244 -0
- package/src/be/swarm-config-guard.ts +23 -2
- package/src/commands/runner.ts +11 -0
- package/src/http/active-sessions.ts +13 -2
- package/src/http/agents.ts +10 -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 +36 -11
- 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/fs.ts +38 -3
- package/src/http/index.ts +3 -1
- package/src/http/memory.ts +3 -1
- package/src/http/ranking.ts +367 -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 +83 -7
- package/src/http/used-by.ts +11 -3
- package/src/prompts/session-templates.ts +3 -1
- package/src/providers/amp-adapter.ts +1 -1
- package/src/ranking/telemetry-ranking.ts +147 -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/slack/blocks.ts +18 -0
- package/src/slack/dm.ts +29 -0
- package/src/telemetry-contract/EVENTS.md +3 -0
- package/src/telemetry-contract/SOURCE.json +37 -4
- package/src/telemetry-contract/catalog.json +69 -0
- 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/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 +708 -1
- package/src/telemetry.ts +26 -2
- package/src/tests/apps-rbac.test.ts +189 -2
- package/src/tests/apps-script-types.test.ts +16 -3
- package/src/tests/check-pr-body.test.ts +23 -0
- package/src/tests/check-ranking-entry.test.ts +146 -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/org-identity.test.ts +44 -0
- package/src/tests/ranking-listing.test.ts +112 -0
- package/src/tests/ranking-route.test.ts +319 -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/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/used-by-route.test.ts +10 -0
- 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/types.ts +35 -0
- package/src/utils/org-identity.ts +33 -0
- package/templates/skills/apps/SKILL.md +17 -0
- package/templates/skills/apps/content.md +17 -0
- package/dist/handlers-tb3xgjnm.js +0 -37
- package/dist/index-nyfcdpky.js +0 -39
- package/dist/{cli-n5mrsg0f.js → cli-60cgh1rv.js} +3 -3
- /package/dist/{cli-j0v75y13.js → cli-y83zk5sb.js} +0 -0
|
@@ -69,28 +69,6 @@ import {
|
|
|
69
69
|
resolveKvView,
|
|
70
70
|
toolErr,
|
|
71
71
|
createToolRegistrar,
|
|
72
|
-
duplicateGuardedQueryKey,
|
|
73
|
-
warnIfCorsAllowsAnyOrigin,
|
|
74
|
-
isOriginAllowedForCredentials,
|
|
75
|
-
allowedCredentialRedirect,
|
|
76
|
-
setCorsHeaders,
|
|
77
|
-
parseQueryParams,
|
|
78
|
-
getPathSegments,
|
|
79
|
-
wireHttpSpanLifecycle,
|
|
80
|
-
safeRequestUrlForLog,
|
|
81
|
-
agentWithCapacity,
|
|
82
|
-
parseBody,
|
|
83
|
-
BODY_TOO_LARGE,
|
|
84
|
-
enforceContentLengthCap,
|
|
85
|
-
json,
|
|
86
|
-
jsonError,
|
|
87
|
-
writeUnhandledError,
|
|
88
|
-
triggerSchemaErrorResponse,
|
|
89
|
-
deriveApiBaseUrl,
|
|
90
|
-
httpServerSemconvAttributes,
|
|
91
|
-
runtimeInstanceHeader,
|
|
92
|
-
describeRequestRoute,
|
|
93
|
-
route,
|
|
94
72
|
handleMcpBridge,
|
|
95
73
|
Redacted,
|
|
96
74
|
SCRIPT_SDK_RESPONSE_LIMIT_BYTES,
|
|
@@ -199,9 +177,6 @@ import {
|
|
|
199
177
|
scheduleIntegrationsReload,
|
|
200
178
|
handleCore,
|
|
201
179
|
userCtx,
|
|
202
|
-
resolveTaskAuditUserId,
|
|
203
|
-
resolveHttpAuditUserId,
|
|
204
|
-
resolveHttpFavoriteOwner,
|
|
205
180
|
handleApps,
|
|
206
181
|
cancelApprovalRequest,
|
|
207
182
|
getUserCommsPrefs,
|
|
@@ -262,6 +237,8 @@ import {
|
|
|
262
237
|
resolveRoomNamespace,
|
|
263
238
|
roomRequestInfo,
|
|
264
239
|
authorizeRoomNamespace,
|
|
240
|
+
sessionAccessTopic,
|
|
241
|
+
sessionPresenceRoot,
|
|
265
242
|
RoomOperationSchema,
|
|
266
243
|
removeAwarenessStates,
|
|
267
244
|
roomTopic,
|
|
@@ -303,7 +280,7 @@ import {
|
|
|
303
280
|
hasCapability,
|
|
304
281
|
getEnabledCapabilities,
|
|
305
282
|
createServer
|
|
306
|
-
} from "./cli-
|
|
283
|
+
} from "./cli-x719j3vs.js";
|
|
307
284
|
import {
|
|
308
285
|
chatThreadOfContextKey,
|
|
309
286
|
agentContextKey,
|
|
@@ -440,6 +417,17 @@ import {
|
|
|
440
417
|
CHAT_SDK_ADAPTER_NAMES,
|
|
441
418
|
isAdapterEntryEnabled,
|
|
442
419
|
init_schema,
|
|
420
|
+
TELEMETRY_RANKING_KEY,
|
|
421
|
+
PUBLIC_RANKING_ENABLED_KEY,
|
|
422
|
+
RANKING_CATEGORIES,
|
|
423
|
+
readTelemetryRanking,
|
|
424
|
+
rankingFormSchema,
|
|
425
|
+
mintRankingClaim,
|
|
426
|
+
buildListing,
|
|
427
|
+
rankingEntryFile,
|
|
428
|
+
rankingPrUrl,
|
|
429
|
+
rankingLeaveUrl,
|
|
430
|
+
init_telemetry_ranking,
|
|
443
431
|
API_DRAINING_HEADER,
|
|
444
432
|
init_api_drain,
|
|
445
433
|
parseTaskToolManifest,
|
|
@@ -724,26 +712,26 @@ import {
|
|
|
724
712
|
countScriptRunJournalSteps2,
|
|
725
713
|
countScriptRunJournalAgentTaskSteps2,
|
|
726
714
|
init_db3
|
|
727
|
-
} from "./cli-
|
|
715
|
+
} from "./cli-rg7ntypm.js";
|
|
728
716
|
import {
|
|
729
717
|
getUserGrant2,
|
|
730
718
|
init_rbac_roles
|
|
731
|
-
} from "./cli-
|
|
732
|
-
import"./cli-
|
|
719
|
+
} from "./cli-5s5hx57y.js";
|
|
720
|
+
import"./cli-kk2r80n5.js";
|
|
733
721
|
import {
|
|
734
722
|
normalizeModelKey
|
|
735
|
-
} from "./cli-
|
|
723
|
+
} from "./cli-tg9ksbn8.js";
|
|
736
724
|
import {
|
|
737
725
|
upsertModelCatalogOverlay,
|
|
738
726
|
deleteModelCatalogOverlay,
|
|
739
727
|
loadModelsCatalog,
|
|
740
728
|
requestModelCatalogRefresh2
|
|
741
|
-
} from "./cli-
|
|
729
|
+
} from "./cli-ttaz6c7m.js";
|
|
742
730
|
import {
|
|
743
731
|
AMP_ESTIMATE_MODELS,
|
|
744
732
|
ampBillsCacheWrites,
|
|
745
733
|
resolveAmpModel
|
|
746
|
-
} from "./cli-
|
|
734
|
+
} from "./cli-2rwet3r7.js";
|
|
747
735
|
import {
|
|
748
736
|
automationIntegrationFixUrl,
|
|
749
737
|
preflightAutomation,
|
|
@@ -755,7 +743,7 @@ import {
|
|
|
755
743
|
cancelWorkflowRun2,
|
|
756
744
|
TriggerSchemaError,
|
|
757
745
|
startWorkflowExecution2
|
|
758
|
-
} from "./cli-
|
|
746
|
+
} from "./cli-nme7wery.js";
|
|
759
747
|
import {
|
|
760
748
|
require_dist2,
|
|
761
749
|
isInvalidClientError,
|
|
@@ -835,14 +823,14 @@ import {
|
|
|
835
823
|
typecheckWithAmbient,
|
|
836
824
|
typecheckScript,
|
|
837
825
|
parseSkillContent
|
|
838
|
-
} from "./cli-
|
|
826
|
+
} from "./cli-nrrg0fvy.js";
|
|
839
827
|
import {
|
|
840
828
|
buildAuthorizationUrl,
|
|
841
829
|
exchangeAuthorizationCode,
|
|
842
830
|
oauthAppRowToProviderConfig,
|
|
843
831
|
forceRefreshAuthorizationOrThrow,
|
|
844
832
|
forceRefreshTokenOrThrow
|
|
845
|
-
} from "./cli-
|
|
833
|
+
} from "./cli-b80a1100.js";
|
|
846
834
|
import {
|
|
847
835
|
signalProcessGroup,
|
|
848
836
|
detachedProcessGroup,
|
|
@@ -870,15 +858,15 @@ import {
|
|
|
870
858
|
getSlackApp2,
|
|
871
859
|
startSlackApp2,
|
|
872
860
|
stopSlackApp2
|
|
873
|
-
} from "./cli-
|
|
874
|
-
import"./cli-
|
|
861
|
+
} from "./cli-4fhyq711.js";
|
|
862
|
+
import"./cli-xfe63zx3.js";
|
|
875
863
|
import {
|
|
876
864
|
createApprovalFollowUpTask,
|
|
877
865
|
generateEdges,
|
|
878
866
|
definitionNodeIds,
|
|
879
867
|
validateDefinition
|
|
880
|
-
} from "./cli-
|
|
881
|
-
import"./cli-
|
|
868
|
+
} from "./cli-tj4j2ts4.js";
|
|
869
|
+
import"./cli-bn26xbcs.js";
|
|
882
870
|
import {
|
|
883
871
|
_fetchHolder,
|
|
884
872
|
CLIENT_ID,
|
|
@@ -894,6 +882,48 @@ import {
|
|
|
894
882
|
workflowEventBus2,
|
|
895
883
|
init_event_bus
|
|
896
884
|
} from "./cli-ptkpaqfy.js";
|
|
885
|
+
import {
|
|
886
|
+
duplicateGuardedQueryKey,
|
|
887
|
+
warnIfCorsAllowsAnyOrigin,
|
|
888
|
+
isOriginAllowedForCredentials,
|
|
889
|
+
allowedCredentialRedirect,
|
|
890
|
+
setCorsHeaders,
|
|
891
|
+
parseQueryParams,
|
|
892
|
+
getPathSegments,
|
|
893
|
+
wireHttpSpanLifecycle,
|
|
894
|
+
safeRequestUrlForLog,
|
|
895
|
+
agentWithCapacity,
|
|
896
|
+
parseBody,
|
|
897
|
+
BODY_TOO_LARGE,
|
|
898
|
+
enforceContentLengthCap,
|
|
899
|
+
json,
|
|
900
|
+
jsonError,
|
|
901
|
+
writeUnhandledError,
|
|
902
|
+
triggerSchemaErrorResponse,
|
|
903
|
+
deriveApiBaseUrl,
|
|
904
|
+
httpServerSemconvAttributes,
|
|
905
|
+
hasSessionAccess,
|
|
906
|
+
getSessionRoot,
|
|
907
|
+
sessionAccessForRoot,
|
|
908
|
+
listActiveSessionShares,
|
|
909
|
+
toSessionSharesState,
|
|
910
|
+
setSessionShares,
|
|
911
|
+
resolveTaskAuditUserId,
|
|
912
|
+
resolveHttpAuditUserId,
|
|
913
|
+
dashboardUserIdHeader,
|
|
914
|
+
resolveHttpFavoriteOwner,
|
|
915
|
+
resolveSessionActor2,
|
|
916
|
+
sessionAccessFor2,
|
|
917
|
+
SESSION_READ_DENIED2,
|
|
918
|
+
canReadSession2,
|
|
919
|
+
readableByFor2,
|
|
920
|
+
SESSION_WRITE_DENIED2,
|
|
921
|
+
runtimeInstanceHeader,
|
|
922
|
+
bodyTask,
|
|
923
|
+
bodyListTask,
|
|
924
|
+
describeRequestRoute,
|
|
925
|
+
route
|
|
926
|
+
} from "./cli-02vhhssk.js";
|
|
897
927
|
import {
|
|
898
928
|
isMultiRuntimeEnabled
|
|
899
929
|
} from "./cli-7a91w22y.js";
|
|
@@ -906,24 +936,6 @@ import {
|
|
|
906
936
|
} from "./cli-qje9k2nh.js";
|
|
907
937
|
import {
|
|
908
938
|
RuntimePoolError2,
|
|
909
|
-
registerSessionTokenConnection,
|
|
910
|
-
init_session_token_connections,
|
|
911
|
-
findUserById,
|
|
912
|
-
getUserIdentities,
|
|
913
|
-
listUserEvents,
|
|
914
|
-
listUserTokens,
|
|
915
|
-
recordIdentityEvent,
|
|
916
|
-
linkIdentity,
|
|
917
|
-
unlinkIdentity,
|
|
918
|
-
mintToken,
|
|
919
|
-
revokeToken,
|
|
920
|
-
resolveUserByToken,
|
|
921
|
-
InvalidRuntimeTokenError,
|
|
922
|
-
mintSessionToken,
|
|
923
|
-
mintRuntimeToken,
|
|
924
|
-
revokeSessionToken,
|
|
925
|
-
fingerprintApiKey,
|
|
926
|
-
init_users,
|
|
927
939
|
mintControllerToken,
|
|
928
940
|
init_tokens,
|
|
929
941
|
listRuntimeControllers2,
|
|
@@ -942,7 +954,7 @@ import {
|
|
|
942
954
|
resolvePoolDelivery2,
|
|
943
955
|
createPoolAgent2,
|
|
944
956
|
init_db
|
|
945
|
-
} from "./cli-
|
|
957
|
+
} from "./cli-6ftrrwm1.js";
|
|
946
958
|
import {
|
|
947
959
|
RATING_MODEL_MAX_LENGTH,
|
|
948
960
|
REFERENCES_SOURCE_MAX_LENGTH,
|
|
@@ -958,8 +970,8 @@ import {
|
|
|
958
970
|
checkHeartbeatChecklist2,
|
|
959
971
|
runHeartbeatSweep2,
|
|
960
972
|
stopHeartbeat2
|
|
961
|
-
} from "./cli-
|
|
962
|
-
import"./cli-
|
|
973
|
+
} from "./cli-bhwa8rzc.js";
|
|
974
|
+
import"./cli-eqgfs202.js";
|
|
963
975
|
import {
|
|
964
976
|
import_websocket,
|
|
965
977
|
import_websocket_server
|
|
@@ -968,7 +980,7 @@ import {
|
|
|
968
980
|
runtimeSupervisorStatus,
|
|
969
981
|
startRuntimeSupervisor,
|
|
970
982
|
stopRuntimeSupervisor
|
|
971
|
-
} from "./cli-
|
|
983
|
+
} from "./cli-rsd7ga7v.js";
|
|
972
984
|
import"./cli-ns59dc6r.js";
|
|
973
985
|
import {
|
|
974
986
|
ACP_TARGET_IDS
|
|
@@ -980,20 +992,22 @@ import {
|
|
|
980
992
|
import {
|
|
981
993
|
MAX_RATE_LIMIT_RESET_MS
|
|
982
994
|
} from "./cli-gx4rm0qx.js";
|
|
983
|
-
import {
|
|
984
|
-
inviteEmailToSharedOrg,
|
|
985
|
-
ensureAgentFsCredentialsForAgent
|
|
986
|
-
} from "./cli-yv3n83x8.js";
|
|
987
|
-
import {
|
|
988
|
-
Anthropic
|
|
989
|
-
} from "./cli-er83cjbn.js";
|
|
990
995
|
import {
|
|
991
996
|
isLeadChannelMonitoringEnabled,
|
|
997
|
+
ORG_IDENTITY_KEYS,
|
|
998
|
+
orgIdentityStatus,
|
|
992
999
|
SIMILARITY_THRESHOLD,
|
|
993
1000
|
memoryRelevance,
|
|
994
1001
|
isUnknownModelError,
|
|
995
1002
|
writeSkillsToFilesystem
|
|
996
|
-
} from "./cli-
|
|
1003
|
+
} from "./cli-wrv09v7q.js";
|
|
1004
|
+
import {
|
|
1005
|
+
inviteEmailToSharedOrg,
|
|
1006
|
+
ensureAgentFsCredentialsForAgent
|
|
1007
|
+
} from "./cli-5ff2sjyt.js";
|
|
1008
|
+
import {
|
|
1009
|
+
Anthropic
|
|
1010
|
+
} from "./cli-er83cjbn.js";
|
|
997
1011
|
import {
|
|
998
1012
|
isCodexOAuthConfigKey
|
|
999
1013
|
} from "./cli-j4bwnpkm.js";
|
|
@@ -1005,7 +1019,27 @@ import"./cli-13p25grh.js";
|
|
|
1005
1019
|
import"./cli-0adyhvq2.js";
|
|
1006
1020
|
import {
|
|
1007
1021
|
require_content_type
|
|
1008
|
-
} from "./cli-
|
|
1022
|
+
} from "./cli-1jx0srjt.js";
|
|
1023
|
+
import {
|
|
1024
|
+
registerSessionTokenConnection,
|
|
1025
|
+
init_session_token_connections,
|
|
1026
|
+
findUserById,
|
|
1027
|
+
getUserIdentities,
|
|
1028
|
+
listUserEvents,
|
|
1029
|
+
listUserTokens,
|
|
1030
|
+
recordIdentityEvent,
|
|
1031
|
+
linkIdentity,
|
|
1032
|
+
unlinkIdentity,
|
|
1033
|
+
mintToken,
|
|
1034
|
+
revokeToken,
|
|
1035
|
+
resolveUserByToken,
|
|
1036
|
+
InvalidRuntimeTokenError,
|
|
1037
|
+
mintSessionToken,
|
|
1038
|
+
mintRuntimeToken,
|
|
1039
|
+
revokeSessionToken,
|
|
1040
|
+
fingerprintApiKey,
|
|
1041
|
+
init_users
|
|
1042
|
+
} from "./cli-8cxkw1f5.js";
|
|
1009
1043
|
import"./cli-v41kn3cd.js";
|
|
1010
1044
|
import"./cli-wgtk7xxr.js";
|
|
1011
1045
|
import {
|
|
@@ -1019,7 +1053,7 @@ import {
|
|
|
1019
1053
|
clearAuditSink,
|
|
1020
1054
|
can,
|
|
1021
1055
|
init_rbac
|
|
1022
|
-
} from "./cli-
|
|
1056
|
+
} from "./cli-1pa3rz69.js";
|
|
1023
1057
|
import {
|
|
1024
1058
|
isSafeBundlePath,
|
|
1025
1059
|
init_bundle_path,
|
|
@@ -1039,6 +1073,10 @@ import {
|
|
|
1039
1073
|
ProviderNameSchema,
|
|
1040
1074
|
ModelProfileNameSchema,
|
|
1041
1075
|
ModelProfileSchema,
|
|
1076
|
+
SessionAccessSchema,
|
|
1077
|
+
SessionOwnerSchema,
|
|
1078
|
+
SessionSharesSchema,
|
|
1079
|
+
SessionSharesUpdateSchema,
|
|
1042
1080
|
SteerModeSchema,
|
|
1043
1081
|
SteeringSourceSchema,
|
|
1044
1082
|
SteeringMessageSchema,
|
|
@@ -1156,12 +1194,12 @@ import {
|
|
|
1156
1194
|
KvKeySchema,
|
|
1157
1195
|
KvEntrySchema,
|
|
1158
1196
|
init_types
|
|
1159
|
-
} from "./cli-
|
|
1197
|
+
} from "./cli-a1esmmee.js";
|
|
1160
1198
|
import {
|
|
1161
1199
|
IDENTITY_FIELD_BUDGETS,
|
|
1162
1200
|
IdentityFieldBudgetError,
|
|
1163
1201
|
init_identity_field_budget
|
|
1164
|
-
} from "./cli-
|
|
1202
|
+
} from "./cli-wyrr38xm.js";
|
|
1165
1203
|
import {
|
|
1166
1204
|
getSlackConfiguration,
|
|
1167
1205
|
init_config
|
|
@@ -1179,7 +1217,7 @@ import {
|
|
|
1179
1217
|
resolveTemplate,
|
|
1180
1218
|
init_resolver,
|
|
1181
1219
|
init_session_templates
|
|
1182
|
-
} from "./cli-
|
|
1220
|
+
} from "./cli-tx00c0h6.js";
|
|
1183
1221
|
import {
|
|
1184
1222
|
MODEL_SCOPED_WINDOWS,
|
|
1185
1223
|
activeModelBlocks,
|
|
@@ -1201,6 +1239,7 @@ import {
|
|
|
1201
1239
|
import {
|
|
1202
1240
|
NEVER,
|
|
1203
1241
|
toJSONSchema,
|
|
1242
|
+
ZodError,
|
|
1204
1243
|
string2,
|
|
1205
1244
|
email,
|
|
1206
1245
|
uuid,
|
|
@@ -1228,7 +1267,7 @@ import {
|
|
|
1228
1267
|
import {
|
|
1229
1268
|
init_package,
|
|
1230
1269
|
package_default
|
|
1231
|
-
} from "./cli-
|
|
1270
|
+
} from "./cli-mz1ezzzh.js";
|
|
1232
1271
|
import {
|
|
1233
1272
|
realtimeBus,
|
|
1234
1273
|
init_bus
|
|
@@ -2367,7 +2406,8 @@ function identityFromHttpAuth(req, auth) {
|
|
|
2367
2406
|
agentId,
|
|
2368
2407
|
sourceTaskId: auth.kind === "agent" ? auth.taskId ?? undefined : header(req, "x-source-task-id"),
|
|
2369
2408
|
userId: auth.kind === "user" ? auth.userId : undefined,
|
|
2370
|
-
isOperator: auth.kind === "operator"
|
|
2409
|
+
isOperator: auth.kind === "operator",
|
|
2410
|
+
dashboardUserId: auth.kind === "operator" ? auth.dashboardUserId : undefined
|
|
2371
2411
|
},
|
|
2372
2412
|
me: {
|
|
2373
2413
|
userId: auth.kind === "user" ? auth.userId : agentId ?? guestId,
|
|
@@ -2560,6 +2600,9 @@ function connect(ws, auth, runtimeId) {
|
|
|
2560
2600
|
if (namespace.startsWith("presence:comb:") && msg.name !== "default") {
|
|
2561
2601
|
throw new Error("Comb presence uses the default room");
|
|
2562
2602
|
}
|
|
2603
|
+
if (namespace.startsWith("presence:session:") && msg.name !== "default") {
|
|
2604
|
+
throw new Error("Session presence uses the default room");
|
|
2605
|
+
}
|
|
2563
2606
|
const denied = await authorizeRoomNamespace(namespace, auth.identity, msg.op, msg.name);
|
|
2564
2607
|
if (denied)
|
|
2565
2608
|
throw new Error(typeof denied === "string" ? denied : "Forbidden");
|
|
@@ -2600,7 +2643,7 @@ function connect(ws, auth, runtimeId) {
|
|
|
2600
2643
|
} catch (error) {
|
|
2601
2644
|
if (!(error instanceof Error) || error.message !== "room does not exist")
|
|
2602
2645
|
throw error;
|
|
2603
|
-
const creationDenied = await authorizeRoomNamespace(namespace, auth.identity, namespace.startsWith("presence:comb:") ? "join" : true);
|
|
2646
|
+
const creationDenied = await authorizeRoomNamespace(namespace, auth.identity, namespace.startsWith("presence:comb:") || namespace.startsWith("presence:session:") ? "join" : true);
|
|
2604
2647
|
if (creationDenied)
|
|
2605
2648
|
throw new Error(creationDenied);
|
|
2606
2649
|
if (closed)
|
|
@@ -2610,6 +2653,8 @@ function connect(ws, auth, runtimeId) {
|
|
|
2610
2653
|
if (closed)
|
|
2611
2654
|
return;
|
|
2612
2655
|
const stopRoom = realtimeBus.subscribe(key, (event) => {
|
|
2656
|
+
if (rooms.get(key)?.suspended)
|
|
2657
|
+
return;
|
|
2613
2658
|
const view = event;
|
|
2614
2659
|
const type = view.type;
|
|
2615
2660
|
if (type === "deleted") {
|
|
@@ -2631,15 +2676,62 @@ function connect(ws, auth, runtimeId) {
|
|
|
2631
2676
|
}).catch(() => ws.close(1011, "Room reset failed"));
|
|
2632
2677
|
}
|
|
2633
2678
|
});
|
|
2634
|
-
const stopPresence = realtimeBus.subscribe(`presence:${key}`, (peers) =>
|
|
2679
|
+
const stopPresence = realtimeBus.subscribe(`presence:${key}`, (peers) => {
|
|
2680
|
+
if (rooms.get(key)?.suspended)
|
|
2681
|
+
return;
|
|
2682
|
+
send({ type: "presence", name: msg.name, namespace, peers });
|
|
2683
|
+
});
|
|
2684
|
+
const sessionRoot = sessionPresenceRoot(namespace);
|
|
2685
|
+
let accessCheck = 0;
|
|
2686
|
+
const stopAccess = sessionRoot ? realtimeBus.subscribe(sessionAccessTopic(sessionRoot), () => {
|
|
2687
|
+
const joined = rooms.get(key);
|
|
2688
|
+
if (!joined)
|
|
2689
|
+
return;
|
|
2690
|
+
joined.suspended = true;
|
|
2691
|
+
const check = ++accessCheck;
|
|
2692
|
+
authorizeRoomNamespace(namespace, auth.identity, "join").catch(() => "Session access check failed").then((denied) => {
|
|
2693
|
+
const current = rooms.get(key);
|
|
2694
|
+
if (closed || !current || check !== accessCheck)
|
|
2695
|
+
return;
|
|
2696
|
+
if (denied) {
|
|
2697
|
+
leave(key);
|
|
2698
|
+
send({ type: "error", name: msg.name, namespace, error: denied });
|
|
2699
|
+
return;
|
|
2700
|
+
}
|
|
2701
|
+
current.suspended = false;
|
|
2702
|
+
send({
|
|
2703
|
+
type: "presence",
|
|
2704
|
+
name: msg.name,
|
|
2705
|
+
namespace,
|
|
2706
|
+
peers: [...current.room.awareness.getStates().values()]
|
|
2707
|
+
});
|
|
2708
|
+
});
|
|
2709
|
+
}) : undefined;
|
|
2635
2710
|
rooms.set(key, {
|
|
2636
2711
|
room,
|
|
2637
2712
|
version: msg.schemaVersion,
|
|
2638
2713
|
stop: () => {
|
|
2639
2714
|
stopRoom();
|
|
2640
2715
|
stopPresence();
|
|
2641
|
-
|
|
2716
|
+
stopAccess?.();
|
|
2717
|
+
},
|
|
2718
|
+
suspended: sessionRoot !== undefined
|
|
2642
2719
|
});
|
|
2720
|
+
if (sessionRoot) {
|
|
2721
|
+
const check = ++accessCheck;
|
|
2722
|
+
const denied = await authorizeRoomNamespace(namespace, auth.identity, "join").catch(() => "Session access check failed");
|
|
2723
|
+
if (closed)
|
|
2724
|
+
return;
|
|
2725
|
+
if (denied) {
|
|
2726
|
+
leave(key);
|
|
2727
|
+
throw new Error(denied);
|
|
2728
|
+
}
|
|
2729
|
+
const current = rooms.get(key);
|
|
2730
|
+
if (!current)
|
|
2731
|
+
throw new Error("You don't have access to this session");
|
|
2732
|
+
if (check === accessCheck)
|
|
2733
|
+
current.suspended = false;
|
|
2734
|
+
}
|
|
2643
2735
|
room.awareness.states.set(clientId, { ...auth.me, data: {} });
|
|
2644
2736
|
room.awareness.meta.set(clientId, { clock: 1, lastUpdated: Date.now() });
|
|
2645
2737
|
publishPresence(room);
|
|
@@ -3863,6 +3955,7 @@ var createActiveSession = route({
|
|
|
3863
3955
|
method: "post",
|
|
3864
3956
|
path: "/api/active-sessions",
|
|
3865
3957
|
pattern: ["api", "active-sessions"],
|
|
3958
|
+
session: bodyTask("taskId"),
|
|
3866
3959
|
summary: "Create a new active session",
|
|
3867
3960
|
tags: ["Active Sessions"],
|
|
3868
3961
|
body: object2({
|
|
@@ -3883,6 +3976,7 @@ var deleteSessionByTask = route({
|
|
|
3883
3976
|
method: "delete",
|
|
3884
3977
|
path: "/api/active-sessions/by-task/{taskId}",
|
|
3885
3978
|
pattern: ["api", "active-sessions", "by-task", null],
|
|
3979
|
+
session: { taskParam: "taskId" },
|
|
3886
3980
|
summary: "Delete active session by task ID",
|
|
3887
3981
|
tags: ["Active Sessions"],
|
|
3888
3982
|
params: object2({ taskId: string2() }),
|
|
@@ -3894,6 +3988,7 @@ var deleteSessionById = route({
|
|
|
3894
3988
|
method: "delete",
|
|
3895
3989
|
path: "/api/active-sessions/{id}",
|
|
3896
3990
|
pattern: ["api", "active-sessions", null],
|
|
3991
|
+
session: { activeSessionParam: "id" },
|
|
3897
3992
|
summary: "Delete active session by ID",
|
|
3898
3993
|
tags: ["Active Sessions"],
|
|
3899
3994
|
params: object2({ id: string2() }),
|
|
@@ -3905,6 +4000,7 @@ var heartbeatSession = route({
|
|
|
3905
4000
|
method: "put",
|
|
3906
4001
|
path: "/api/active-sessions/heartbeat/{taskId}",
|
|
3907
4002
|
pattern: ["api", "active-sessions", "heartbeat", null],
|
|
4003
|
+
session: { taskParam: "taskId" },
|
|
3908
4004
|
summary: "Update heartbeat for an active session",
|
|
3909
4005
|
tags: ["Active Sessions"],
|
|
3910
4006
|
params: object2({ taskId: string2() }),
|
|
@@ -3916,6 +4012,7 @@ var updateProviderSession = route({
|
|
|
3916
4012
|
method: "put",
|
|
3917
4013
|
path: "/api/active-sessions/provider-session/{taskId}",
|
|
3918
4014
|
pattern: ["api", "active-sessions", "provider-session", null],
|
|
4015
|
+
session: { taskParam: "taskId" },
|
|
3919
4016
|
summary: "Update provider session ID on an active session",
|
|
3920
4017
|
tags: ["Active Sessions"],
|
|
3921
4018
|
params: object2({ taskId: string2() }),
|
|
@@ -3928,6 +4025,7 @@ var cleanupSessions = route({
|
|
|
3928
4025
|
method: "post",
|
|
3929
4026
|
path: "/api/active-sessions/cleanup",
|
|
3930
4027
|
pattern: ["api", "active-sessions", "cleanup"],
|
|
4028
|
+
session: { agentWide: "Deletes every session of an agent, or every stale session." },
|
|
3931
4029
|
summary: "Clean up stale sessions",
|
|
3932
4030
|
tags: ["Active Sessions"],
|
|
3933
4031
|
body: object2({
|
|
@@ -3942,6 +4040,7 @@ var recoverOrphanedTasks = route({
|
|
|
3942
4040
|
method: "post",
|
|
3943
4041
|
path: "/api/active-sessions/recover-orphaned-tasks",
|
|
3944
4042
|
pattern: ["api", "active-sessions", "recover-orphaned-tasks"],
|
|
4043
|
+
session: { none: "Its handler admits only the calling agent, never a user." },
|
|
3945
4044
|
summary: "Recover orphaned in-progress tasks for an agent",
|
|
3946
4045
|
tags: ["Active Sessions"],
|
|
3947
4046
|
body: object2({
|
|
@@ -3961,7 +4060,7 @@ async function handleActiveSessions(req, res, pathSegments, queryParams, myAgent
|
|
|
3961
4060
|
const parsed = await listActiveSessions.parse(req, res, pathSegments, queryParams);
|
|
3962
4061
|
if (!parsed)
|
|
3963
4062
|
return true;
|
|
3964
|
-
const sessions = await getActiveSessions2(parsed.query.agentId || undefined);
|
|
4063
|
+
const sessions = await getActiveSessions2(parsed.query.agentId || undefined, readableByFor2(await resolveSessionActor2(req, myAgentId)));
|
|
3965
4064
|
listActiveSessions.respond(res, 200, { sessions });
|
|
3966
4065
|
return true;
|
|
3967
4066
|
}
|
|
@@ -4610,14 +4709,17 @@ async function handleAgentRegister(req, res, pathSegments, myAgentId) {
|
|
|
4610
4709
|
}
|
|
4611
4710
|
return false;
|
|
4612
4711
|
}
|
|
4613
|
-
async function handleAgentsRest(req, res, pathSegments, queryParams,
|
|
4712
|
+
async function handleAgentsRest(req, res, pathSegments, queryParams, myAgentId) {
|
|
4614
4713
|
if (listAgents.match(req.method, pathSegments)) {
|
|
4615
4714
|
const parsed = await listAgents.parse(req, res, pathSegments, queryParams);
|
|
4616
4715
|
if (!parsed)
|
|
4617
4716
|
return true;
|
|
4618
4717
|
const includeTasks = parsed.query.include === "tasks";
|
|
4619
4718
|
const slim = parsed.query.fields !== "full";
|
|
4620
|
-
const agents = includeTasks ? await getAllAgentsWithTasks2({
|
|
4719
|
+
const agents = includeTasks ? await getAllAgentsWithTasks2({
|
|
4720
|
+
slim,
|
|
4721
|
+
readableBy: readableByFor2(await resolveSessionActor2(req, myAgentId))
|
|
4722
|
+
}) : await getAllAgents2({ slim });
|
|
4621
4723
|
const [agentsWithCapacity, transports] = await Promise.all([
|
|
4622
4724
|
Promise.all(agents.map(agentWithCapacity)),
|
|
4623
4725
|
resolveListClaudeTransports(agents)
|
|
@@ -5155,7 +5257,7 @@ async function handleAgentsRest(req, res, pathSegments, queryParams, _myAgentId)
|
|
|
5155
5257
|
if (!parsed)
|
|
5156
5258
|
return true;
|
|
5157
5259
|
const includeTasks = parsed.query.include === "tasks";
|
|
5158
|
-
const agent = includeTasks ? await getAgentWithTasks2(parsed.params.id) : await getAgentById2(parsed.params.id);
|
|
5260
|
+
const agent = includeTasks ? await getAgentWithTasks2(parsed.params.id, readableByFor2(await resolveSessionActor2(req, myAgentId))) : await getAgentById2(parsed.params.id);
|
|
5159
5261
|
if (!agent) {
|
|
5160
5262
|
jsonError(res, "Agent not found", 404);
|
|
5161
5263
|
return true;
|
|
@@ -5234,6 +5336,7 @@ var reportUsage = route({
|
|
|
5234
5336
|
method: "post",
|
|
5235
5337
|
path: "/api/keys/report-usage",
|
|
5236
5338
|
pattern: ["api", "keys", "report-usage"],
|
|
5339
|
+
session: bodyTask("taskId"),
|
|
5237
5340
|
summary: "Record which API key was used for a task",
|
|
5238
5341
|
tags: ["API Keys"],
|
|
5239
5342
|
body: object2({
|
|
@@ -5277,6 +5380,7 @@ var reportAuthFailure = route({
|
|
|
5277
5380
|
method: "post",
|
|
5278
5381
|
path: "/api/keys/report-auth-failure",
|
|
5279
5382
|
pattern: ["api", "keys", "report-auth-failure"],
|
|
5383
|
+
session: bodyTask("taskId"),
|
|
5280
5384
|
summary: "Record an auth failure for a pooled key; bench it after 2 in a row",
|
|
5281
5385
|
tags: ["API Keys"],
|
|
5282
5386
|
body: object2({
|
|
@@ -5974,6 +6078,7 @@ var createRoute = route({
|
|
|
5974
6078
|
method: "post",
|
|
5975
6079
|
path: "/api/approval-requests",
|
|
5976
6080
|
pattern: ["api", "approval-requests"],
|
|
6081
|
+
session: bodyTask("sourceTaskId"),
|
|
5977
6082
|
summary: "Create a new approval request",
|
|
5978
6083
|
tags: ["ApprovalRequests"],
|
|
5979
6084
|
body: object2({
|
|
@@ -7590,6 +7695,396 @@ init_rbac();
|
|
|
7590
7695
|
init_types();
|
|
7591
7696
|
init_request_auth_context();
|
|
7592
7697
|
init_secret_scrubber();
|
|
7698
|
+
|
|
7699
|
+
// src/http/ranking.ts
|
|
7700
|
+
init_zod();
|
|
7701
|
+
init_db3();
|
|
7702
|
+
init_telemetry_ranking();
|
|
7703
|
+
init_telemetry();
|
|
7704
|
+
init_env_flag();
|
|
7705
|
+
|
|
7706
|
+
// src/http/used-by.ts
|
|
7707
|
+
init_zod();
|
|
7708
|
+
init_db3();
|
|
7709
|
+
init_telemetry();
|
|
7710
|
+
init_org_website();
|
|
7711
|
+
var CONSENT_KEY = "SWARM_USED_BY_CONSENT";
|
|
7712
|
+
var CONSENT_AT_KEY = "SWARM_USED_BY_CONSENT_AT";
|
|
7713
|
+
var GRANTED_NAME_KEY = "SWARM_USED_BY_ORG_NAME";
|
|
7714
|
+
var GRANTED_WEBSITE_KEY = "SWARM_USED_BY_ORG_WEBSITE";
|
|
7715
|
+
var TIMEOUT_MS = 1e4;
|
|
7716
|
+
var usedBy = route({
|
|
7717
|
+
method: "post",
|
|
7718
|
+
path: "/api/used-by",
|
|
7719
|
+
pattern: ["api", "used-by"],
|
|
7720
|
+
summary: "Grant or revoke the 'used by' logo consent",
|
|
7721
|
+
description: "Records whether agent-swarm.dev may show this organization's logo as a company that uses Agent Swarm. Sends the organization name and website to the telemetry proxy, where a person approves each logo by hand. An explicit admin action, so it is not gated by the telemetry opt-out.",
|
|
7722
|
+
tags: ["Telemetry"],
|
|
7723
|
+
body: object2({ granted: boolean() }),
|
|
7724
|
+
responses: {
|
|
7725
|
+
200: {
|
|
7726
|
+
description: "Consent recorded",
|
|
7727
|
+
schema: object2({ granted: boolean(), changedAt: string2() })
|
|
7728
|
+
},
|
|
7729
|
+
400: {
|
|
7730
|
+
description: "Organization name or website is not set (a revoke falls back to the identity of the last grant)"
|
|
7731
|
+
},
|
|
7732
|
+
401: { description: "Unauthorized" },
|
|
7733
|
+
403: { description: "Only a config admin can change the consent" },
|
|
7734
|
+
502: { description: "The telemetry proxy did not accept the consent" }
|
|
7735
|
+
},
|
|
7736
|
+
rbac: { permission: "config.write.any" }
|
|
7737
|
+
});
|
|
7738
|
+
async function globalConfig(key) {
|
|
7739
|
+
const stored = (await getSwarmConfigs2({ scope: "global", key }))?.[0]?.value?.trim();
|
|
7740
|
+
return stored || process.env[key]?.trim() || undefined;
|
|
7741
|
+
}
|
|
7742
|
+
async function telemetryProxyEndpoint(path) {
|
|
7743
|
+
const feedback = await globalConfig("feedback_endpoint");
|
|
7744
|
+
if (feedback && /^https?:\/\/[^/]+\/v1\/feedback\/?$/.test(feedback)) {
|
|
7745
|
+
return feedback.replace(/\/v1\/feedback\/?$/, path);
|
|
7746
|
+
}
|
|
7747
|
+
return `${TELEMETRY_PROXY_ORIGIN}${path}`;
|
|
7748
|
+
}
|
|
7749
|
+
function usedByEndpoint() {
|
|
7750
|
+
return telemetryProxyEndpoint("/v1/used-by");
|
|
7751
|
+
}
|
|
7752
|
+
async function handleUsedBy(req, res, pathSegments, queryParams, myAgentId) {
|
|
7753
|
+
if (!usedBy.match(req.method, pathSegments))
|
|
7754
|
+
return false;
|
|
7755
|
+
const parsed = await usedBy.parse(req, res, pathSegments, queryParams);
|
|
7756
|
+
if (!parsed)
|
|
7757
|
+
return true;
|
|
7758
|
+
if (!await ensureConfigAdmin(req, res, "config.write.any"))
|
|
7759
|
+
return true;
|
|
7760
|
+
const { granted } = parsed.body;
|
|
7761
|
+
const current = orgIdentityStatus({
|
|
7762
|
+
SWARM_ORG_NAME: await globalConfig("SWARM_ORG_NAME"),
|
|
7763
|
+
SWARM_ORG_WEBSITE: await globalConfig("SWARM_ORG_WEBSITE")
|
|
7764
|
+
});
|
|
7765
|
+
const currentName = current.name ?? undefined;
|
|
7766
|
+
const currentWebsite = current.website;
|
|
7767
|
+
const grantedName = granted ? undefined : await globalConfig(GRANTED_NAME_KEY);
|
|
7768
|
+
const grantedWebsite = granted ? null : normalizeOrgWebsite(await globalConfig(GRANTED_WEBSITE_KEY));
|
|
7769
|
+
const [orgName, orgWebsite] = grantedName && grantedWebsite ? [grantedName, grantedWebsite] : [currentName, currentWebsite];
|
|
7770
|
+
if (!orgName || !orgWebsite) {
|
|
7771
|
+
jsonError(res, "Set the organization name and website first", 400);
|
|
7772
|
+
return true;
|
|
7773
|
+
}
|
|
7774
|
+
const installId = isTelemetryEnabled() ? await globalConfig("telemetry_installation_id") : undefined;
|
|
7775
|
+
const orgDomain = await globalConfig("telemetry_org_domain");
|
|
7776
|
+
const changedAt = new Date().toISOString();
|
|
7777
|
+
try {
|
|
7778
|
+
const response = await fetch(await usedByEndpoint(), {
|
|
7779
|
+
method: "POST",
|
|
7780
|
+
headers: { "Content-Type": "application/json" },
|
|
7781
|
+
body: JSON.stringify({
|
|
7782
|
+
...installId ? { install_id: installId } : {},
|
|
7783
|
+
org_name: orgName,
|
|
7784
|
+
org_website: orgWebsite,
|
|
7785
|
+
...orgDomain ? { org_domain: orgDomain } : {},
|
|
7786
|
+
granted,
|
|
7787
|
+
changed_at: changedAt
|
|
7788
|
+
}),
|
|
7789
|
+
signal: AbortSignal.timeout(TIMEOUT_MS)
|
|
7790
|
+
});
|
|
7791
|
+
if (!response.ok) {
|
|
7792
|
+
jsonError(res, `The telemetry proxy answered ${response.status}`, 502);
|
|
7793
|
+
return true;
|
|
7794
|
+
}
|
|
7795
|
+
} catch {
|
|
7796
|
+
jsonError(res, "Could not reach the telemetry proxy", 502);
|
|
7797
|
+
return true;
|
|
7798
|
+
}
|
|
7799
|
+
await upsertSwarmConfig2({ scope: "global", key: CONSENT_KEY, value: String(granted) });
|
|
7800
|
+
await upsertSwarmConfig2({ scope: "global", key: CONSENT_AT_KEY, value: changedAt });
|
|
7801
|
+
if (granted) {
|
|
7802
|
+
await upsertSwarmConfig2({ scope: "global", key: GRANTED_NAME_KEY, value: orgName });
|
|
7803
|
+
await upsertSwarmConfig2({ scope: "global", key: GRANTED_WEBSITE_KEY, value: orgWebsite });
|
|
7804
|
+
}
|
|
7805
|
+
scheduleIntegrationsReload();
|
|
7806
|
+
const owner = await resolveHttpFavoriteOwner(req, myAgentId);
|
|
7807
|
+
trackRelayed("used_by.consent_changed", { granted }, { actor: owner?.userId ? { userId: owner.userId } : undefined, emitter: "ui" });
|
|
7808
|
+
usedBy.respond(res, 200, { granted, changedAt });
|
|
7809
|
+
return true;
|
|
7810
|
+
}
|
|
7811
|
+
|
|
7812
|
+
// src/http/ranking.ts
|
|
7813
|
+
var ListingSchema = object2({
|
|
7814
|
+
v: literal2(1),
|
|
7815
|
+
claim: string2(),
|
|
7816
|
+
name: string2(),
|
|
7817
|
+
domain: string2(),
|
|
7818
|
+
category: _enum2(RANKING_CATEGORIES),
|
|
7819
|
+
subcategory: string2().nullable(),
|
|
7820
|
+
description: string2().nullable(),
|
|
7821
|
+
sourceCodeUrl: string2().nullable(),
|
|
7822
|
+
updatedAt: string2()
|
|
7823
|
+
});
|
|
7824
|
+
var RankingStateSchema = object2({
|
|
7825
|
+
eligible: boolean(),
|
|
7826
|
+
missing: array2(_enum2(ORG_IDENTITY_KEYS)),
|
|
7827
|
+
telemetryOn: boolean(),
|
|
7828
|
+
enabled: boolean(),
|
|
7829
|
+
name: string2().nullable(),
|
|
7830
|
+
domain: string2().nullable(),
|
|
7831
|
+
listing: ListingSchema.nullable(),
|
|
7832
|
+
listingMatchesDomain: boolean(),
|
|
7833
|
+
fileJson: string2().nullable(),
|
|
7834
|
+
prUrl: string2().nullable(),
|
|
7835
|
+
verifyUrl: string2().nullable()
|
|
7836
|
+
});
|
|
7837
|
+
var OptInResponseSchema = object2({
|
|
7838
|
+
domain: string2(),
|
|
7839
|
+
claim: string2(),
|
|
7840
|
+
listing: ListingSchema,
|
|
7841
|
+
fileJson: string2(),
|
|
7842
|
+
prUrl: string2(),
|
|
7843
|
+
verifyUrl: string2()
|
|
7844
|
+
});
|
|
7845
|
+
var OptOutResponseSchema = object2({
|
|
7846
|
+
enabled: literal2(false),
|
|
7847
|
+
leaveUrl: string2().nullable()
|
|
7848
|
+
});
|
|
7849
|
+
var getRanking = route({
|
|
7850
|
+
method: "get",
|
|
7851
|
+
path: "/api/ranking",
|
|
7852
|
+
pattern: ["api", "ranking"],
|
|
7853
|
+
summary: "Public ranking state",
|
|
7854
|
+
description: "Whether this install can join the public agent-swarm.dev ranking (telemetry on, organization name and website set), whether it is opted in, and its stored listing. The listing carries the private ranking claim, so only a config admin can read it.",
|
|
7855
|
+
tags: ["Telemetry"],
|
|
7856
|
+
responses: {
|
|
7857
|
+
200: { description: "Ranking state", schema: RankingStateSchema },
|
|
7858
|
+
401: { description: "Unauthorized" },
|
|
7859
|
+
403: { description: "Only a config admin can read the ranking state" }
|
|
7860
|
+
},
|
|
7861
|
+
rbac: { permission: "config.write.any" }
|
|
7862
|
+
});
|
|
7863
|
+
var optIn = route({
|
|
7864
|
+
method: "post",
|
|
7865
|
+
path: "/api/ranking/opt-in",
|
|
7866
|
+
pattern: ["api", "ranking", "opt-in"],
|
|
7867
|
+
summary: "Opt this install into the public ranking",
|
|
7868
|
+
description: "Builds the telemetry_ranking listing from the organization name and website plus the chosen category, stores it, turns PUBLIC_RANKING_ENABLED on and sends ranking.opted_in. The install is ranked only after a ranking PR with the returned file is merged into desplega-ai/agent-swarm.",
|
|
7869
|
+
tags: ["Telemetry"],
|
|
7870
|
+
body: rankingFormSchema,
|
|
7871
|
+
responses: {
|
|
7872
|
+
200: { description: "Opted in", schema: OptInResponseSchema },
|
|
7873
|
+
400: { description: "A listing field is invalid" },
|
|
7874
|
+
401: { description: "Unauthorized" },
|
|
7875
|
+
403: { description: "Only a config admin can opt in" },
|
|
7876
|
+
409: {
|
|
7877
|
+
description: "telemetry_off: telemetry is off or the install has no ID. org_identity_missing: the organization name or website is not set (`missing` lists which)."
|
|
7878
|
+
}
|
|
7879
|
+
},
|
|
7880
|
+
rbac: { permission: "config.write.any" }
|
|
7881
|
+
});
|
|
7882
|
+
var optOut = route({
|
|
7883
|
+
method: "post",
|
|
7884
|
+
path: "/api/ranking/opt-out",
|
|
7885
|
+
pattern: ["api", "ranking", "opt-out"],
|
|
7886
|
+
summary: "Leave the public ranking",
|
|
7887
|
+
description: "Turns PUBLIC_RANKING_ENABLED off and sends ranking.opted_out, so workers stop sending ranking.usage. Returns the GitHub page that deletes the ranking entry.",
|
|
7888
|
+
tags: ["Telemetry"],
|
|
7889
|
+
responses: {
|
|
7890
|
+
200: { description: "Opted out", schema: OptOutResponseSchema },
|
|
7891
|
+
401: { description: "Unauthorized" },
|
|
7892
|
+
403: { description: "Only a config admin can opt out" }
|
|
7893
|
+
},
|
|
7894
|
+
rbac: { permission: "config.write.any" }
|
|
7895
|
+
});
|
|
7896
|
+
var RANKING_CONFIG_KEYS = new Set([...ORG_IDENTITY_KEYS, PUBLIC_RANKING_ENABLED_KEY]);
|
|
7897
|
+
async function currentIdentity(changed) {
|
|
7898
|
+
const read = async (key) => changed?.key === key ? changed.value : await globalConfig(key);
|
|
7899
|
+
return orgIdentityStatus({
|
|
7900
|
+
SWARM_ORG_NAME: await read("SWARM_ORG_NAME"),
|
|
7901
|
+
SWARM_ORG_WEBSITE: await read("SWARM_ORG_WEBSITE")
|
|
7902
|
+
});
|
|
7903
|
+
}
|
|
7904
|
+
async function storedListing() {
|
|
7905
|
+
return readTelemetryRanking(await globalConfig(TELEMETRY_RANKING_KEY));
|
|
7906
|
+
}
|
|
7907
|
+
async function rankingEnabled() {
|
|
7908
|
+
const raw = await globalConfig(PUBLIC_RANKING_ENABLED_KEY);
|
|
7909
|
+
return isEnvFlagEnabled(PUBLIC_RANKING_ENABLED_KEY, false, {
|
|
7910
|
+
[PUBLIC_RANKING_ENABLED_KEY]: raw
|
|
7911
|
+
});
|
|
7912
|
+
}
|
|
7913
|
+
async function telemetryReady() {
|
|
7914
|
+
return isTelemetryEnabled() && Boolean(await globalConfig("telemetry_installation_id"));
|
|
7915
|
+
}
|
|
7916
|
+
async function verifyUrl(listing) {
|
|
7917
|
+
const params = new URLSearchParams({ domain: listing.domain, claim: listing.claim });
|
|
7918
|
+
return `${await telemetryProxyEndpoint("/v1/ranking/verify")}?${params.toString()}`;
|
|
7919
|
+
}
|
|
7920
|
+
async function setEnabled(enabled) {
|
|
7921
|
+
await upsertSwarmConfig2({
|
|
7922
|
+
scope: "global",
|
|
7923
|
+
key: PUBLIC_RANKING_ENABLED_KEY,
|
|
7924
|
+
value: String(enabled)
|
|
7925
|
+
});
|
|
7926
|
+
}
|
|
7927
|
+
function emitOptedIn(listing) {
|
|
7928
|
+
telemetry.ranking("opted_in", { listing: JSON.stringify(listing) }, { orgName: listing.name, orgWebsite: listing.domain });
|
|
7929
|
+
}
|
|
7930
|
+
function emitOptedOut(domain) {
|
|
7931
|
+
telemetry.ranking("opted_out", { domain });
|
|
7932
|
+
}
|
|
7933
|
+
async function buildRankingState() {
|
|
7934
|
+
const [identity, listing, enabled, telemetryOn] = await Promise.all([
|
|
7935
|
+
currentIdentity(),
|
|
7936
|
+
storedListing(),
|
|
7937
|
+
rankingEnabled(),
|
|
7938
|
+
telemetryReady()
|
|
7939
|
+
]);
|
|
7940
|
+
const listingMatchesDomain = Boolean(listing && listing.domain === identity.website);
|
|
7941
|
+
const current = listingMatchesDomain ? listing : null;
|
|
7942
|
+
return {
|
|
7943
|
+
eligible: telemetryOn && identity.ok,
|
|
7944
|
+
missing: identity.missing,
|
|
7945
|
+
telemetryOn,
|
|
7946
|
+
enabled: enabled && listingMatchesDomain,
|
|
7947
|
+
name: identity.name,
|
|
7948
|
+
domain: identity.website,
|
|
7949
|
+
listing,
|
|
7950
|
+
listingMatchesDomain,
|
|
7951
|
+
fileJson: current ? rankingEntryFile(current) : null,
|
|
7952
|
+
prUrl: current ? rankingPrUrl(current) : null,
|
|
7953
|
+
verifyUrl: current ? await verifyUrl(current) : null
|
|
7954
|
+
};
|
|
7955
|
+
}
|
|
7956
|
+
async function syncRankingAfterConfigChange(key, value) {
|
|
7957
|
+
if (!RANKING_CONFIG_KEYS.has(key))
|
|
7958
|
+
return;
|
|
7959
|
+
const listing = await storedListing();
|
|
7960
|
+
if (!listing)
|
|
7961
|
+
return;
|
|
7962
|
+
if (key === PUBLIC_RANKING_ENABLED_KEY) {
|
|
7963
|
+
if (!isEnvFlagEnabled(key, false, { [key]: value ?? undefined })) {
|
|
7964
|
+
emitOptedOut(listing.domain);
|
|
7965
|
+
}
|
|
7966
|
+
return;
|
|
7967
|
+
}
|
|
7968
|
+
if (!await rankingEnabled())
|
|
7969
|
+
return;
|
|
7970
|
+
const identity = await currentIdentity({ key, value });
|
|
7971
|
+
let rebuilt = null;
|
|
7972
|
+
if (identity.ok && identity.website === listing.domain) {
|
|
7973
|
+
if (identity.name === listing.name)
|
|
7974
|
+
return;
|
|
7975
|
+
try {
|
|
7976
|
+
rebuilt = buildListing(identity, listing, listing.claim);
|
|
7977
|
+
} catch {}
|
|
7978
|
+
}
|
|
7979
|
+
if (!rebuilt) {
|
|
7980
|
+
await setEnabled(false);
|
|
7981
|
+
emitOptedOut(listing.domain);
|
|
7982
|
+
return;
|
|
7983
|
+
}
|
|
7984
|
+
await upsertSwarmConfig2({
|
|
7985
|
+
scope: "global",
|
|
7986
|
+
key: TELEMETRY_RANKING_KEY,
|
|
7987
|
+
value: JSON.stringify(rebuilt)
|
|
7988
|
+
});
|
|
7989
|
+
emitOptedIn(rebuilt);
|
|
7990
|
+
}
|
|
7991
|
+
function conflict(res, body) {
|
|
7992
|
+
res.writeHead(409, { "Content-Type": "application/json" });
|
|
7993
|
+
res.end(JSON.stringify(body));
|
|
7994
|
+
}
|
|
7995
|
+
async function handleRanking(req, res, pathSegments, queryParams) {
|
|
7996
|
+
if (getRanking.match(req.method, pathSegments)) {
|
|
7997
|
+
const parsed = await getRanking.parse(req, res, pathSegments, queryParams);
|
|
7998
|
+
if (!parsed)
|
|
7999
|
+
return true;
|
|
8000
|
+
if (!await ensureConfigAdmin(req, res, "config.write.any"))
|
|
8001
|
+
return true;
|
|
8002
|
+
getRanking.respond(res, 200, await buildRankingState());
|
|
8003
|
+
return true;
|
|
8004
|
+
}
|
|
8005
|
+
if (optIn.match(req.method, pathSegments)) {
|
|
8006
|
+
const parsed = await optIn.parse(req, res, pathSegments, queryParams);
|
|
8007
|
+
if (!parsed)
|
|
8008
|
+
return true;
|
|
8009
|
+
if (!await ensureConfigAdmin(req, res, "config.write.any"))
|
|
8010
|
+
return true;
|
|
8011
|
+
if (!await telemetryReady()) {
|
|
8012
|
+
conflict(res, {
|
|
8013
|
+
error: "telemetry_off",
|
|
8014
|
+
message: "Turn telemetry on first: the ranking counts tokens from telemetry."
|
|
8015
|
+
});
|
|
8016
|
+
return true;
|
|
8017
|
+
}
|
|
8018
|
+
const identity = await currentIdentity();
|
|
8019
|
+
if (!identity.ok || !identity.website) {
|
|
8020
|
+
conflict(res, {
|
|
8021
|
+
error: "org_identity_missing",
|
|
8022
|
+
message: "Set the organization name and website first",
|
|
8023
|
+
missing: identity.missing
|
|
8024
|
+
});
|
|
8025
|
+
return true;
|
|
8026
|
+
}
|
|
8027
|
+
const website = identity.website;
|
|
8028
|
+
const db = getDbClient2();
|
|
8029
|
+
const built = await db.transaction(async () => {
|
|
8030
|
+
const stored = await storedListing();
|
|
8031
|
+
const claim = stored?.domain === website ? stored.claim : mintRankingClaim();
|
|
8032
|
+
let listing;
|
|
8033
|
+
try {
|
|
8034
|
+
listing = buildListing(identity, parsed.body, claim);
|
|
8035
|
+
} catch (error) {
|
|
8036
|
+
return { ok: false, error };
|
|
8037
|
+
}
|
|
8038
|
+
await upsertSwarmConfig2({
|
|
8039
|
+
scope: "global",
|
|
8040
|
+
key: TELEMETRY_RANKING_KEY,
|
|
8041
|
+
value: JSON.stringify(listing)
|
|
8042
|
+
});
|
|
8043
|
+
await setEnabled(true);
|
|
8044
|
+
db.afterCommit(() => emitOptedIn(listing));
|
|
8045
|
+
return { ok: true, listing };
|
|
8046
|
+
});
|
|
8047
|
+
if (!built.ok) {
|
|
8048
|
+
const issue = built.error instanceof ZodError ? built.error.issues[0] : undefined;
|
|
8049
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
8050
|
+
res.end(JSON.stringify({
|
|
8051
|
+
error: issue ? `Invalid ${issue.path.join(".") || "listing"}: ${issue.message}` : "Invalid listing"
|
|
8052
|
+
}));
|
|
8053
|
+
return true;
|
|
8054
|
+
}
|
|
8055
|
+
const { listing } = built;
|
|
8056
|
+
scheduleIntegrationsReload();
|
|
8057
|
+
optIn.respond(res, 200, {
|
|
8058
|
+
domain: listing.domain,
|
|
8059
|
+
claim: listing.claim,
|
|
8060
|
+
listing,
|
|
8061
|
+
fileJson: rankingEntryFile(listing),
|
|
8062
|
+
prUrl: rankingPrUrl(listing),
|
|
8063
|
+
verifyUrl: await verifyUrl(listing)
|
|
8064
|
+
});
|
|
8065
|
+
return true;
|
|
8066
|
+
}
|
|
8067
|
+
if (optOut.match(req.method, pathSegments)) {
|
|
8068
|
+
const parsed = await optOut.parse(req, res, pathSegments, queryParams);
|
|
8069
|
+
if (!parsed)
|
|
8070
|
+
return true;
|
|
8071
|
+
if (!await ensureConfigAdmin(req, res, "config.write.any"))
|
|
8072
|
+
return true;
|
|
8073
|
+
const listing = await storedListing();
|
|
8074
|
+
await setEnabled(false);
|
|
8075
|
+
if (listing)
|
|
8076
|
+
emitOptedOut(listing.domain);
|
|
8077
|
+
scheduleIntegrationsReload();
|
|
8078
|
+
optOut.respond(res, 200, {
|
|
8079
|
+
enabled: false,
|
|
8080
|
+
leaveUrl: listing ? rankingLeaveUrl(listing.domain) : null
|
|
8081
|
+
});
|
|
8082
|
+
return true;
|
|
8083
|
+
}
|
|
8084
|
+
return false;
|
|
8085
|
+
}
|
|
8086
|
+
|
|
8087
|
+
// src/http/config.ts
|
|
7593
8088
|
var MAX_ENV_PRESENCE_KEYS = 200;
|
|
7594
8089
|
var SECRETS_FORCE_MASK_NOTE = " (secret values masked: this token cannot read secrets in this scope)";
|
|
7595
8090
|
function stripApiOnlyKeys(configs) {
|
|
@@ -7959,6 +8454,8 @@ async function handleConfig(req, res, pathSegments, queryParams) {
|
|
|
7959
8454
|
if (scope === "global" && key === "SWARM_ORG_WEBSITE") {
|
|
7960
8455
|
await fillOrgLogoFromWebsite(String(value));
|
|
7961
8456
|
}
|
|
8457
|
+
if (scope === "global")
|
|
8458
|
+
await syncRankingAfterConfigChange(key, String(value));
|
|
7962
8459
|
if (scope === "global") {
|
|
7963
8460
|
scheduleIntegrationsReload();
|
|
7964
8461
|
}
|
|
@@ -7994,6 +8491,7 @@ async function handleConfig(req, res, pathSegments, queryParams) {
|
|
|
7994
8491
|
return true;
|
|
7995
8492
|
}
|
|
7996
8493
|
if (existing.scope === "global") {
|
|
8494
|
+
await syncRankingAfterConfigChange(existing.key, null);
|
|
7997
8495
|
scheduleIntegrationsReload();
|
|
7998
8496
|
}
|
|
7999
8497
|
if (existing.scope === "agent" && existing.scopeId && existing.key === AGENT_MAX_TASKS_CONFIG_KEY) {
|
|
@@ -8830,6 +9328,7 @@ var postContext = route({
|
|
|
8830
9328
|
method: "post",
|
|
8831
9329
|
path: "/api/tasks/{id}/context",
|
|
8832
9330
|
pattern: ["api", "tasks", null, "context"],
|
|
9331
|
+
session: { taskParam: "id" },
|
|
8833
9332
|
summary: "Record a context usage snapshot for a task",
|
|
8834
9333
|
tags: ["Tasks"],
|
|
8835
9334
|
params: object2({ id: string2() }),
|
|
@@ -8856,6 +9355,7 @@ var getContext = route({
|
|
|
8856
9355
|
method: "get",
|
|
8857
9356
|
path: "/api/tasks/{id}/context",
|
|
8858
9357
|
pattern: ["api", "tasks", null, "context"],
|
|
9358
|
+
session: { taskParam: "id" },
|
|
8859
9359
|
summary: "Get context usage history for a task",
|
|
8860
9360
|
tags: ["Tasks"],
|
|
8861
9361
|
params: object2({ id: string2() }),
|
|
@@ -8936,6 +9436,7 @@ var createEventRoute = route({
|
|
|
8936
9436
|
method: "post",
|
|
8937
9437
|
path: "/api/events",
|
|
8938
9438
|
pattern: ["api", "events"],
|
|
9439
|
+
session: bodyTask("taskId"),
|
|
8939
9440
|
summary: "Store a single event",
|
|
8940
9441
|
tags: ["Events"],
|
|
8941
9442
|
body: eventBodySchema,
|
|
@@ -8952,6 +9453,7 @@ var createEventsBatchRoute = route({
|
|
|
8952
9453
|
method: "post",
|
|
8953
9454
|
path: "/api/events/batch",
|
|
8954
9455
|
pattern: ["api", "events", "batch"],
|
|
9456
|
+
session: bodyListTask("events", "taskId"),
|
|
8955
9457
|
summary: "Store multiple events in a batch",
|
|
8956
9458
|
tags: ["Events"],
|
|
8957
9459
|
body: object2({
|
|
@@ -9026,7 +9528,7 @@ var getEventCountsRoute = route({
|
|
|
9026
9528
|
auth: { apiKey: true }
|
|
9027
9529
|
});
|
|
9028
9530
|
var MAX_LATEST_PAIRS = 50;
|
|
9029
|
-
async function handleEvents(req, res, pathSegments, queryParams,
|
|
9531
|
+
async function handleEvents(req, res, pathSegments, queryParams, myAgentId) {
|
|
9030
9532
|
if (createEventsBatchRoute.match(req.method, pathSegments)) {
|
|
9031
9533
|
const parsed = await createEventsBatchRoute.parse(req, res, pathSegments, queryParams);
|
|
9032
9534
|
if (!parsed)
|
|
@@ -9100,7 +9602,8 @@ async function handleEvents(req, res, pathSegments, queryParams, _myAgentId) {
|
|
|
9100
9602
|
until: parsed.query.until || undefined,
|
|
9101
9603
|
limit: parsed.query.limit ?? 100,
|
|
9102
9604
|
events: eventFilter,
|
|
9103
|
-
latestPerDataField: latestPerDataField ? { events: latestEvents, dataFields } : undefined
|
|
9605
|
+
latestPerDataField: latestPerDataField ? { events: latestEvents, dataFields } : undefined,
|
|
9606
|
+
readableBy: readableByFor2(await resolveSessionActor2(req, myAgentId))
|
|
9104
9607
|
});
|
|
9105
9608
|
getEventsRoute.respond(res, 200, latestPerDataField ? { events, latestPerDataField: true } : { events });
|
|
9106
9609
|
return true;
|
|
@@ -12524,110 +13027,6 @@ async function getLocalFleetStats(now = new Date) {
|
|
|
12524
13027
|
|
|
12525
13028
|
// src/http/fleet-benchmark.ts
|
|
12526
13029
|
init_telemetry();
|
|
12527
|
-
|
|
12528
|
-
// src/http/used-by.ts
|
|
12529
|
-
init_zod();
|
|
12530
|
-
init_db3();
|
|
12531
|
-
init_telemetry();
|
|
12532
|
-
init_org_website();
|
|
12533
|
-
var CONSENT_KEY = "SWARM_USED_BY_CONSENT";
|
|
12534
|
-
var CONSENT_AT_KEY = "SWARM_USED_BY_CONSENT_AT";
|
|
12535
|
-
var GRANTED_NAME_KEY = "SWARM_USED_BY_ORG_NAME";
|
|
12536
|
-
var GRANTED_WEBSITE_KEY = "SWARM_USED_BY_ORG_WEBSITE";
|
|
12537
|
-
var TIMEOUT_MS = 1e4;
|
|
12538
|
-
var usedBy = route({
|
|
12539
|
-
method: "post",
|
|
12540
|
-
path: "/api/used-by",
|
|
12541
|
-
pattern: ["api", "used-by"],
|
|
12542
|
-
summary: "Grant or revoke the 'used by' logo consent",
|
|
12543
|
-
description: "Records whether agent-swarm.dev may show this organization's logo as a company that uses Agent Swarm. Sends the organization name and website to the telemetry proxy, where a person approves each logo by hand. An explicit admin action, so it is not gated by the telemetry opt-out.",
|
|
12544
|
-
tags: ["Telemetry"],
|
|
12545
|
-
body: object2({ granted: boolean() }),
|
|
12546
|
-
responses: {
|
|
12547
|
-
200: {
|
|
12548
|
-
description: "Consent recorded",
|
|
12549
|
-
schema: object2({ granted: boolean(), changedAt: string2() })
|
|
12550
|
-
},
|
|
12551
|
-
400: {
|
|
12552
|
-
description: "Organization name or website is not set (a revoke falls back to the identity of the last grant)"
|
|
12553
|
-
},
|
|
12554
|
-
401: { description: "Unauthorized" },
|
|
12555
|
-
403: { description: "Only a config admin can change the consent" },
|
|
12556
|
-
502: { description: "The telemetry proxy did not accept the consent" }
|
|
12557
|
-
},
|
|
12558
|
-
rbac: { permission: "config.write.any" }
|
|
12559
|
-
});
|
|
12560
|
-
async function globalConfig(key) {
|
|
12561
|
-
const stored = (await getSwarmConfigs2({ scope: "global", key }))?.[0]?.value?.trim();
|
|
12562
|
-
return stored || process.env[key]?.trim() || undefined;
|
|
12563
|
-
}
|
|
12564
|
-
async function telemetryProxyEndpoint(path) {
|
|
12565
|
-
const feedback = await globalConfig("feedback_endpoint");
|
|
12566
|
-
if (feedback && /^https?:\/\/[^/]+\/v1\/feedback\/?$/.test(feedback)) {
|
|
12567
|
-
return feedback.replace(/\/v1\/feedback\/?$/, path);
|
|
12568
|
-
}
|
|
12569
|
-
return `${TELEMETRY_PROXY_ORIGIN}${path}`;
|
|
12570
|
-
}
|
|
12571
|
-
function usedByEndpoint() {
|
|
12572
|
-
return telemetryProxyEndpoint("/v1/used-by");
|
|
12573
|
-
}
|
|
12574
|
-
async function handleUsedBy(req, res, pathSegments, queryParams, myAgentId) {
|
|
12575
|
-
if (!usedBy.match(req.method, pathSegments))
|
|
12576
|
-
return false;
|
|
12577
|
-
const parsed = await usedBy.parse(req, res, pathSegments, queryParams);
|
|
12578
|
-
if (!parsed)
|
|
12579
|
-
return true;
|
|
12580
|
-
if (!await ensureConfigAdmin(req, res, "config.write.any"))
|
|
12581
|
-
return true;
|
|
12582
|
-
const { granted } = parsed.body;
|
|
12583
|
-
const currentName = await globalConfig("SWARM_ORG_NAME");
|
|
12584
|
-
const currentWebsite = normalizeOrgWebsite(await globalConfig("SWARM_ORG_WEBSITE"));
|
|
12585
|
-
const grantedName = granted ? undefined : await globalConfig(GRANTED_NAME_KEY);
|
|
12586
|
-
const grantedWebsite = granted ? null : normalizeOrgWebsite(await globalConfig(GRANTED_WEBSITE_KEY));
|
|
12587
|
-
const [orgName, orgWebsite] = grantedName && grantedWebsite ? [grantedName, grantedWebsite] : [currentName, currentWebsite];
|
|
12588
|
-
if (!orgName || !orgWebsite) {
|
|
12589
|
-
jsonError(res, "Set the organization name and website first", 400);
|
|
12590
|
-
return true;
|
|
12591
|
-
}
|
|
12592
|
-
const installId = isTelemetryEnabled() ? await globalConfig("telemetry_installation_id") : undefined;
|
|
12593
|
-
const orgDomain = await globalConfig("telemetry_org_domain");
|
|
12594
|
-
const changedAt = new Date().toISOString();
|
|
12595
|
-
try {
|
|
12596
|
-
const response = await fetch(await usedByEndpoint(), {
|
|
12597
|
-
method: "POST",
|
|
12598
|
-
headers: { "Content-Type": "application/json" },
|
|
12599
|
-
body: JSON.stringify({
|
|
12600
|
-
...installId ? { install_id: installId } : {},
|
|
12601
|
-
org_name: orgName,
|
|
12602
|
-
org_website: orgWebsite,
|
|
12603
|
-
...orgDomain ? { org_domain: orgDomain } : {},
|
|
12604
|
-
granted,
|
|
12605
|
-
changed_at: changedAt
|
|
12606
|
-
}),
|
|
12607
|
-
signal: AbortSignal.timeout(TIMEOUT_MS)
|
|
12608
|
-
});
|
|
12609
|
-
if (!response.ok) {
|
|
12610
|
-
jsonError(res, `The telemetry proxy answered ${response.status}`, 502);
|
|
12611
|
-
return true;
|
|
12612
|
-
}
|
|
12613
|
-
} catch {
|
|
12614
|
-
jsonError(res, "Could not reach the telemetry proxy", 502);
|
|
12615
|
-
return true;
|
|
12616
|
-
}
|
|
12617
|
-
await upsertSwarmConfig2({ scope: "global", key: CONSENT_KEY, value: String(granted) });
|
|
12618
|
-
await upsertSwarmConfig2({ scope: "global", key: CONSENT_AT_KEY, value: changedAt });
|
|
12619
|
-
if (granted) {
|
|
12620
|
-
await upsertSwarmConfig2({ scope: "global", key: GRANTED_NAME_KEY, value: orgName });
|
|
12621
|
-
await upsertSwarmConfig2({ scope: "global", key: GRANTED_WEBSITE_KEY, value: orgWebsite });
|
|
12622
|
-
}
|
|
12623
|
-
scheduleIntegrationsReload();
|
|
12624
|
-
const owner = await resolveHttpFavoriteOwner(req, myAgentId);
|
|
12625
|
-
trackRelayed("used_by.consent_changed", { granted }, { actor: owner?.userId ? { userId: owner.userId } : undefined, emitter: "ui" });
|
|
12626
|
-
usedBy.respond(res, 200, { granted, changedAt });
|
|
12627
|
-
return true;
|
|
12628
|
-
}
|
|
12629
|
-
|
|
12630
|
-
// src/http/fleet-benchmark.ts
|
|
12631
13030
|
var FLEET_TTL_MS = 24 * 60 * 60 * 1000;
|
|
12632
13031
|
var FLEET_FAILURE_TTL_MS = 60 * 60 * 1000;
|
|
12633
13032
|
var LOCAL_TTL_MS = 10 * 60 * 1000;
|
|
@@ -12886,6 +13285,7 @@ var listTaskFilesRoute = route({
|
|
|
12886
13285
|
method: "get",
|
|
12887
13286
|
path: "/api/fs/tasks/{taskId}/files",
|
|
12888
13287
|
pattern: ["api", "fs", "tasks", null, "files"],
|
|
13288
|
+
session: { taskParam: "taskId" },
|
|
12889
13289
|
summary: "List task file attachments",
|
|
12890
13290
|
tags: ["FS"],
|
|
12891
13291
|
params: taskParams,
|
|
@@ -12901,6 +13301,7 @@ var uploadTaskFileRoute = route({
|
|
|
12901
13301
|
method: "post",
|
|
12902
13302
|
path: "/api/fs/tasks/{taskId}/files",
|
|
12903
13303
|
pattern: ["api", "fs", "tasks", null, "files"],
|
|
13304
|
+
session: { taskParam: "taskId" },
|
|
12904
13305
|
summary: "Upload a binary task file attachment",
|
|
12905
13306
|
description: "Accepts a raw binary request body. Pass the display/path name as the `name` query parameter.",
|
|
12906
13307
|
tags: ["FS"],
|
|
@@ -12920,6 +13321,7 @@ var getTaskFileRoute = route({
|
|
|
12920
13321
|
method: "get",
|
|
12921
13322
|
path: "/api/fs/tasks/{taskId}/files/{attachmentId}",
|
|
12922
13323
|
pattern: ["api", "fs", "tasks", null, "files", null],
|
|
13324
|
+
session: { taskParam: "taskId" },
|
|
12923
13325
|
summary: "Get task file attachment metadata",
|
|
12924
13326
|
tags: ["FS"],
|
|
12925
13327
|
params: attachmentParams,
|
|
@@ -12932,6 +13334,7 @@ var downloadTaskFileRoute = route({
|
|
|
12932
13334
|
method: "get",
|
|
12933
13335
|
path: "/api/fs/tasks/{taskId}/files/{attachmentId}/raw",
|
|
12934
13336
|
pattern: ["api", "fs", "tasks", null, "files", null, "raw"],
|
|
13337
|
+
session: { taskParam: "taskId" },
|
|
12935
13338
|
summary: "Download raw task file bytes",
|
|
12936
13339
|
description: "Streams raw bytes. File content is not secret-scrubbed.",
|
|
12937
13340
|
tags: ["FS"],
|
|
@@ -12948,6 +13351,7 @@ var signedUrlTaskFileRoute = route({
|
|
|
12948
13351
|
method: "get",
|
|
12949
13352
|
path: "/api/fs/tasks/{taskId}/files/{attachmentId}/signed-url",
|
|
12950
13353
|
pattern: ["api", "fs", "tasks", null, "files", null, "signed-url"],
|
|
13354
|
+
session: { taskParam: "taskId" },
|
|
12951
13355
|
summary: "Create a provider signed GET URL for a task file",
|
|
12952
13356
|
tags: ["FS"],
|
|
12953
13357
|
params: attachmentParams,
|
|
@@ -12962,6 +13366,7 @@ var deleteTaskFileRoute = route({
|
|
|
12962
13366
|
method: "delete",
|
|
12963
13367
|
path: "/api/fs/tasks/{taskId}/files/{attachmentId}",
|
|
12964
13368
|
pattern: ["api", "fs", "tasks", null, "files", null],
|
|
13369
|
+
session: { taskParam: "taskId" },
|
|
12965
13370
|
summary: "Delete a task file attachment",
|
|
12966
13371
|
tags: ["FS"],
|
|
12967
13372
|
params: attachmentParams,
|
|
@@ -13010,7 +13415,7 @@ async function handleFs(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
13010
13415
|
const parsed = await downloadTaskFileRoute.parse(req, res, pathSegments, queryParams);
|
|
13011
13416
|
if (!parsed)
|
|
13012
13417
|
return true;
|
|
13013
|
-
const attachment = await findAttachment(parsed.params.taskId, parsed.params.attachmentId, res);
|
|
13418
|
+
const attachment = await findAttachment(req, myAgentId, parsed.params.taskId, parsed.params.attachmentId, res);
|
|
13014
13419
|
if (!attachment)
|
|
13015
13420
|
return true;
|
|
13016
13421
|
return sendDownload(res, attachment);
|
|
@@ -13019,7 +13424,7 @@ async function handleFs(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
13019
13424
|
const parsed = await signedUrlTaskFileRoute.parse(req, res, pathSegments, queryParams);
|
|
13020
13425
|
if (!parsed)
|
|
13021
13426
|
return true;
|
|
13022
|
-
const attachment = await findAttachment(parsed.params.taskId, parsed.params.attachmentId, res);
|
|
13427
|
+
const attachment = await findAttachment(req, myAgentId, parsed.params.taskId, parsed.params.attachmentId, res);
|
|
13023
13428
|
if (!attachment)
|
|
13024
13429
|
return true;
|
|
13025
13430
|
return sendSignedUrl(res, attachment, parsed.query.expiresIn);
|
|
@@ -13028,7 +13433,7 @@ async function handleFs(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
13028
13433
|
const parsed = await getTaskFileRoute.parse(req, res, pathSegments, queryParams);
|
|
13029
13434
|
if (!parsed)
|
|
13030
13435
|
return true;
|
|
13031
|
-
const attachment = await findAttachment(parsed.params.taskId, parsed.params.attachmentId, res);
|
|
13436
|
+
const attachment = await findAttachment(req, myAgentId, parsed.params.taskId, parsed.params.attachmentId, res);
|
|
13032
13437
|
if (!attachment)
|
|
13033
13438
|
return true;
|
|
13034
13439
|
getTaskFileRoute.respond(res, 200, attachment);
|
|
@@ -13067,6 +13472,10 @@ async function handleFs(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
13067
13472
|
return true;
|
|
13068
13473
|
if (!await getTaskById2(parsed.params.taskId))
|
|
13069
13474
|
return notFound(res, "Task not found");
|
|
13475
|
+
if (!await canReadSession2(req, myAgentId, parsed.params.taskId)) {
|
|
13476
|
+
jsonError(res, SESSION_READ_DENIED2, 403);
|
|
13477
|
+
return true;
|
|
13478
|
+
}
|
|
13070
13479
|
listTaskFilesRoute.respond(res, 200, {
|
|
13071
13480
|
attachments: await getTaskAttachments2(parsed.params.taskId)
|
|
13072
13481
|
});
|
|
@@ -13202,11 +13611,15 @@ function backingProviderId(attachment) {
|
|
|
13202
13611
|
return "local-fs";
|
|
13203
13612
|
return null;
|
|
13204
13613
|
}
|
|
13205
|
-
async function findAttachment(taskId, attachmentId, res) {
|
|
13614
|
+
async function findAttachment(req, myAgentId, taskId, attachmentId, res) {
|
|
13206
13615
|
if (!await getTaskById2(taskId)) {
|
|
13207
13616
|
notFound(res, "Task not found");
|
|
13208
13617
|
return null;
|
|
13209
13618
|
}
|
|
13619
|
+
if (!await canReadSession2(req, myAgentId, taskId)) {
|
|
13620
|
+
jsonError(res, SESSION_READ_DENIED2, 403);
|
|
13621
|
+
return null;
|
|
13622
|
+
}
|
|
13210
13623
|
const attachment = (await getTaskAttachments2(taskId)).find((item) => item.id === attachmentId);
|
|
13211
13624
|
if (!attachment) {
|
|
13212
13625
|
notFound(res, "Attachment not found");
|
|
@@ -17846,6 +18259,7 @@ var indexMemory = route({
|
|
|
17846
18259
|
method: "post",
|
|
17847
18260
|
path: "/api/memory/index",
|
|
17848
18261
|
pattern: ["api", "memory", "index"],
|
|
18262
|
+
session: bodyTask("sourceTaskId"),
|
|
17849
18263
|
summary: "Ingest content into memory system (async embedding)",
|
|
17850
18264
|
tags: ["Memory"],
|
|
17851
18265
|
rbac: { permission: "memory.write.consolidated" },
|
|
@@ -18323,6 +18737,7 @@ var rateMemory = route({
|
|
|
18323
18737
|
method: "post",
|
|
18324
18738
|
path: "/api/memory/rate",
|
|
18325
18739
|
pattern: ["api", "memory", "rate"],
|
|
18740
|
+
session: { none: "worker-only: it needs X-Agent-ID, which a user token cannot send" },
|
|
18326
18741
|
summary: "Submit RatingEvents to update memory usefulness posteriors",
|
|
18327
18742
|
tags: ["Memory"],
|
|
18328
18743
|
auth: { apiKey: true, agentId: true },
|
|
@@ -21770,7 +22185,7 @@ var listTasks = route({
|
|
|
21770
22185
|
path: "/api/tasks",
|
|
21771
22186
|
pattern: ["api", "tasks"],
|
|
21772
22187
|
summary: "List tasks with filters",
|
|
21773
|
-
description: "Returns tasks with the full `task` text replaced by a bounded `taskPreview` and completion/integration blobs dropped by default — list views only need the preview. Pass `fields=full` to restore the full `AgentTask`, or `fields=timeline` for the narrow shape the dashboard timeline draws. Fetch a single task in full via `GET /api/tasks/{id}`. `total` (the filtered row count, ignoring limit/offset) is computed only with `includeTotal=true`.",
|
|
22188
|
+
description: "Returns tasks with the full `task` text replaced by a bounded `taskPreview` and completion/integration blobs dropped by default — list views only need the preview. Pass `fields=full` to restore the full `AgentTask`, or `fields=timeline` for the narrow shape the dashboard timeline draws. Every shape gives a user caller only tasks of sessions they can read. Fetch a single task in full via `GET /api/tasks/{id}`. `total` (the filtered row count, ignoring limit/offset) is computed only with `includeTotal=true`.",
|
|
21774
22189
|
tags: ["Tasks"],
|
|
21775
22190
|
query: object2({
|
|
21776
22191
|
status: string2().optional(),
|
|
@@ -21809,6 +22224,7 @@ var createTask = route({
|
|
|
21809
22224
|
method: "post",
|
|
21810
22225
|
path: "/api/tasks",
|
|
21811
22226
|
pattern: ["api", "tasks"],
|
|
22227
|
+
session: bodyTask("parentTaskId"),
|
|
21812
22228
|
summary: "Create a new task",
|
|
21813
22229
|
tags: ["Tasks"],
|
|
21814
22230
|
body: object2({
|
|
@@ -21864,6 +22280,7 @@ var promoteDraftTaskRoute = route({
|
|
|
21864
22280
|
method: "post",
|
|
21865
22281
|
path: "/api/tasks/{id}/promote-draft",
|
|
21866
22282
|
pattern: ["api", "tasks", null, "promote-draft"],
|
|
22283
|
+
session: { taskParam: "id" },
|
|
21867
22284
|
summary: "Promote a draft task out of the pre-dispatch draft state",
|
|
21868
22285
|
description: "Transitions a `draft` task (#1240 — created with attachments still uploading) to its normal dispatch-eligible status: `offered` if it was offered to an agent, `pending` if it has an owning agent (the common case — UI-composer tasks default to Lead), otherwise `unassigned`. Called by the UI composer once its attachment upload batch settles, whether every file uploaded, some failed, or all failed — a draft must never be stranded by an upload error. Idempotent: calling it on a task that already left `draft` returns the current task unchanged rather than erroring, so a retried request is safe.",
|
|
21869
22286
|
tags: ["Tasks"],
|
|
@@ -21879,6 +22296,7 @@ var updateSession = route({
|
|
|
21879
22296
|
method: "put",
|
|
21880
22297
|
path: "/api/tasks/{id}/session",
|
|
21881
22298
|
pattern: ["api", "tasks", null, "session"],
|
|
22299
|
+
session: { taskParam: "id" },
|
|
21882
22300
|
summary: "Update provider session ID and harness metadata for a task",
|
|
21883
22301
|
tags: ["Tasks"],
|
|
21884
22302
|
params: object2({ id: string2() }),
|
|
@@ -21912,6 +22330,7 @@ var cancelTaskRoute = route({
|
|
|
21912
22330
|
method: "post",
|
|
21913
22331
|
path: "/api/tasks/{id}/cancel",
|
|
21914
22332
|
pattern: ["api", "tasks", null, "cancel"],
|
|
22333
|
+
session: { taskParam: "id" },
|
|
21915
22334
|
summary: "Cancel a pending or in-progress task",
|
|
21916
22335
|
tags: ["Tasks"],
|
|
21917
22336
|
params: object2({ id: string2() }),
|
|
@@ -21926,6 +22345,7 @@ var steerTaskRoute = route({
|
|
|
21926
22345
|
method: "post",
|
|
21927
22346
|
path: "/api/tasks/{id}/steer",
|
|
21928
22347
|
pattern: ["api", "tasks", null, "steer"],
|
|
22348
|
+
session: { taskParam: "id" },
|
|
21929
22349
|
summary: "Deliver a steering message to a running task",
|
|
21930
22350
|
tags: ["Tasks"],
|
|
21931
22351
|
params: object2({ id: string2() }),
|
|
@@ -21954,6 +22374,7 @@ var getTaskSteeringMessagesRoute = route({
|
|
|
21954
22374
|
method: "get",
|
|
21955
22375
|
path: "/api/tasks/{id}/steering-messages",
|
|
21956
22376
|
pattern: ["api", "tasks", null, "steering-messages"],
|
|
22377
|
+
session: { taskParam: "id" },
|
|
21957
22378
|
summary: "List steering messages for a task",
|
|
21958
22379
|
tags: ["Tasks"],
|
|
21959
22380
|
params: object2({ id: string2() }),
|
|
@@ -21980,6 +22401,7 @@ var markSteeringDeliveredRoute = route({
|
|
|
21980
22401
|
method: "post",
|
|
21981
22402
|
path: "/api/steering-messages/{id}/delivered",
|
|
21982
22403
|
pattern: ["api", "steering-messages", null, "delivered"],
|
|
22404
|
+
session: { steeringParam: "id" },
|
|
21983
22405
|
summary: "Mark a steering message delivered",
|
|
21984
22406
|
tags: ["Tasks"],
|
|
21985
22407
|
params: object2({ id: string2() }),
|
|
@@ -22003,6 +22425,7 @@ var markSteeringHandledRoute = route({
|
|
|
22003
22425
|
method: "post",
|
|
22004
22426
|
path: "/api/steering-messages/{id}/handled",
|
|
22005
22427
|
pattern: ["api", "steering-messages", null, "handled"],
|
|
22428
|
+
session: { steeringParam: "id" },
|
|
22006
22429
|
summary: "Mark a steering message handled",
|
|
22007
22430
|
description: "Optionally accepts a JSON body `{ note?: string }` — a short acceptance note describing how the steering was incorporated, persisted as `handledNote`.",
|
|
22008
22431
|
tags: ["Tasks"],
|
|
@@ -22025,6 +22448,7 @@ var markSteeringUndeliverableRoute = route({
|
|
|
22025
22448
|
method: "post",
|
|
22026
22449
|
path: "/api/steering-messages/{id}/undeliverable",
|
|
22027
22450
|
pattern: ["api", "steering-messages", null, "undeliverable"],
|
|
22451
|
+
session: { steeringParam: "id" },
|
|
22028
22452
|
summary: "Promote an undeliverable steering message",
|
|
22029
22453
|
tags: ["Tasks"],
|
|
22030
22454
|
params: object2({ id: string2() }),
|
|
@@ -22048,6 +22472,7 @@ var getTask = route({
|
|
|
22048
22472
|
method: "get",
|
|
22049
22473
|
path: "/api/tasks/{id}",
|
|
22050
22474
|
pattern: ["api", "tasks", null],
|
|
22475
|
+
session: { taskParam: "id" },
|
|
22051
22476
|
summary: "Get task details with logs and attachments",
|
|
22052
22477
|
description: "Returns the full `AgentTask` row decorated with `logs` (capped by `logsLimit`) and `attachments` (pointer-based artifacts stored on the task, ordered by `created_at`).",
|
|
22053
22478
|
tags: ["Tasks"],
|
|
@@ -22057,6 +22482,7 @@ var getTask = route({
|
|
|
22057
22482
|
}),
|
|
22058
22483
|
responses: {
|
|
22059
22484
|
200: { description: "Task with logs and attachments", schema: GetTaskResponseSchema },
|
|
22485
|
+
403: { description: "A user caller cannot read the task's session" },
|
|
22060
22486
|
404: { description: "Task not found" }
|
|
22061
22487
|
}
|
|
22062
22488
|
});
|
|
@@ -22064,6 +22490,7 @@ var updateTaskProgressRoute = route({
|
|
|
22064
22490
|
method: "post",
|
|
22065
22491
|
path: "/api/tasks/{id}/progress",
|
|
22066
22492
|
pattern: ["api", "tasks", null, "progress"],
|
|
22493
|
+
session: { taskParam: "id" },
|
|
22067
22494
|
summary: "Update task progress text",
|
|
22068
22495
|
tags: ["Tasks"],
|
|
22069
22496
|
params: object2({ id: string2() }),
|
|
@@ -22081,6 +22508,7 @@ var finishTask = route({
|
|
|
22081
22508
|
method: "post",
|
|
22082
22509
|
path: "/api/tasks/{id}/finish",
|
|
22083
22510
|
pattern: ["api", "tasks", null, "finish"],
|
|
22511
|
+
session: { taskParam: "id" },
|
|
22084
22512
|
summary: "Mark task as completed or failed (runner endpoint)",
|
|
22085
22513
|
tags: ["Tasks"],
|
|
22086
22514
|
params: object2({ id: string2() }),
|
|
@@ -22126,6 +22554,7 @@ var pauseTaskRoute = route({
|
|
|
22126
22554
|
method: "post",
|
|
22127
22555
|
path: "/api/tasks/{id}/pause",
|
|
22128
22556
|
pattern: ["api", "tasks", null, "pause"],
|
|
22557
|
+
session: { taskParam: "id" },
|
|
22129
22558
|
summary: "Pause an in-progress task",
|
|
22130
22559
|
tags: ["Tasks"],
|
|
22131
22560
|
params: object2({ id: string2() }),
|
|
@@ -22140,6 +22569,7 @@ var resumeTaskRoute = route({
|
|
|
22140
22569
|
method: "post",
|
|
22141
22570
|
path: "/api/tasks/{id}/resume",
|
|
22142
22571
|
pattern: ["api", "tasks", null, "resume"],
|
|
22572
|
+
session: { taskParam: "id" },
|
|
22143
22573
|
summary: "Resume a paused task",
|
|
22144
22574
|
tags: ["Tasks"],
|
|
22145
22575
|
params: object2({ id: string2() }),
|
|
@@ -22154,6 +22584,7 @@ var supersedeTaskRoute = route({
|
|
|
22154
22584
|
method: "post",
|
|
22155
22585
|
path: "/api/tasks/{id}/supersede",
|
|
22156
22586
|
pattern: ["api", "tasks", null, "supersede"],
|
|
22587
|
+
session: { taskParam: "id" },
|
|
22157
22588
|
summary: "Supersede an in-progress task (terminate + spawn resume follow-up)",
|
|
22158
22589
|
description: 'Marks the original task `superseded` (terminal) and creates a fresh `taskType="resume"` follow-up so a worker can pick up the work in a new provider session. Workflow-step tasks (those with `workflowRunStepId`) are carved out: the original is marked `failed` with reason `superseded_workflow_task` and no follow-up is created — the workflow engine\'s retry/failure policy applies.',
|
|
22159
22590
|
tags: ["Tasks"],
|
|
@@ -22174,6 +22605,7 @@ var updateTaskVcsRoute = route({
|
|
|
22174
22605
|
method: "patch",
|
|
22175
22606
|
path: "/api/tasks/{id}/vcs",
|
|
22176
22607
|
pattern: ["api", "tasks", null, "vcs"],
|
|
22608
|
+
session: { taskParam: "id" },
|
|
22177
22609
|
summary: "Update VCS (PR/MR) info for a task",
|
|
22178
22610
|
tags: ["Tasks"],
|
|
22179
22611
|
params: object2({ id: string2() }),
|
|
@@ -22194,6 +22626,7 @@ var updateTaskTitleRoute = route({
|
|
|
22194
22626
|
method: "patch",
|
|
22195
22627
|
path: "/api/tasks/{id}/title",
|
|
22196
22628
|
pattern: ["api", "tasks", null, "title"],
|
|
22629
|
+
session: { taskParam: "id" },
|
|
22197
22630
|
summary: "Set or clear a task's display title (session rename)",
|
|
22198
22631
|
description: "Sets a human-facing display title override on a task. The sessions UI only reads this from root tasks (session list items), but titles on child tasks are harmless. Pass `title: null` (or an empty string) to clear the override and fall back to the task prompt.",
|
|
22199
22632
|
tags: ["Tasks"],
|
|
@@ -22210,17 +22643,21 @@ var updateTaskTitleRoute = route({
|
|
|
22210
22643
|
ungated: "mirrors the pre-RBAC PATCH /api/tasks/{id}/vcs sibling route: bearer auth only"
|
|
22211
22644
|
}
|
|
22212
22645
|
});
|
|
22213
|
-
async function
|
|
22646
|
+
async function hasSessionWrite(req, myAgentId, taskId) {
|
|
22647
|
+
const access = await sessionAccessFor2(await resolveSessionActor2(req, myAgentId), taskId);
|
|
22648
|
+
return hasSessionAccess(access, "write");
|
|
22649
|
+
}
|
|
22650
|
+
async function canSteerTask(req, myAgentId, task, sessionAccess = "none") {
|
|
22651
|
+
const auth = getRequestAuth(req);
|
|
22214
22652
|
const resource = {
|
|
22215
22653
|
kind: "task",
|
|
22216
22654
|
taskId: task.id,
|
|
22217
|
-
requestedByUserId: task.requestedByUserId,
|
|
22655
|
+
requestedByUserId: auth?.kind === "user" && sessionAccess === "write" ? auth.userId : task.requestedByUserId,
|
|
22218
22656
|
creatorAgentId: task.creatorAgentId,
|
|
22219
22657
|
agentId: task.agentId
|
|
22220
22658
|
};
|
|
22221
22659
|
let principal;
|
|
22222
22660
|
let verb;
|
|
22223
|
-
const auth = getRequestAuth(req);
|
|
22224
22661
|
if (auth?.kind === "operator") {
|
|
22225
22662
|
principal = { kind: "operator" };
|
|
22226
22663
|
verb = "task.steer.own";
|
|
@@ -22329,6 +22766,7 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
22329
22766
|
if (validated.length > 0)
|
|
22330
22767
|
source = validated;
|
|
22331
22768
|
}
|
|
22769
|
+
const actor = await resolveSessionActor2(req, myAgentId);
|
|
22332
22770
|
const filters = {
|
|
22333
22771
|
status,
|
|
22334
22772
|
agentId: parsed.query.agentId || undefined,
|
|
@@ -22344,7 +22782,8 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
22344
22782
|
requestedByUserIdIsNull: parsed.query.requestedByUserId === "none" || undefined,
|
|
22345
22783
|
orderBy: parsed.query.orderBy,
|
|
22346
22784
|
limit: parsed.query.limit,
|
|
22347
|
-
offset: parsed.query.offset
|
|
22785
|
+
offset: parsed.query.offset,
|
|
22786
|
+
readableBy: actor.kind === "user" ? { userId: actor.userId } : undefined
|
|
22348
22787
|
};
|
|
22349
22788
|
const tasks = parsed.query.fields === "full" ? await getAllTasks2(filters) : parsed.query.fields === "timeline" ? await getAllTasks2(filters, { fields: "timeline" }) : await getAllTasks2(filters, { slim: true });
|
|
22350
22789
|
if (parsed.query.includeTotal === "true") {
|
|
@@ -22402,6 +22841,10 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
22402
22841
|
jsonError(res, `You don't have context for parent task ${parentTask.id}.`, 403);
|
|
22403
22842
|
return true;
|
|
22404
22843
|
}
|
|
22844
|
+
if (parentTask && !await hasSessionWrite(req, myAgentId, parentTask.id)) {
|
|
22845
|
+
jsonError(res, SESSION_WRITE_DENIED2, 403);
|
|
22846
|
+
return true;
|
|
22847
|
+
}
|
|
22405
22848
|
if (principal.kind === "agent" && parsed.body.contextKey && parsed.body.contextKey !== parentTask?.contextKey && chatThreadOfContextKey(parsed.body.contextKey) && !can({ principal, verb: "integration.chat.post", resource: { kind: "none" }, source: "http" }).allow) {
|
|
22406
22849
|
jsonError(res, "Permission denied: only a lead can bind a task to a chat thread.", 403);
|
|
22407
22850
|
return true;
|
|
@@ -22601,7 +23044,13 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
22601
23044
|
jsonError(res, "Task not found", 404);
|
|
22602
23045
|
return true;
|
|
22603
23046
|
}
|
|
22604
|
-
|
|
23047
|
+
const sessionActor = await resolveSessionActor2(req, myAgentId);
|
|
23048
|
+
const steerAccess = await sessionAccessFor2(sessionActor, task.id);
|
|
23049
|
+
if (!hasSessionAccess(steerAccess, "write")) {
|
|
23050
|
+
jsonError(res, SESSION_WRITE_DENIED2, 403);
|
|
23051
|
+
return true;
|
|
23052
|
+
}
|
|
23053
|
+
if (!await canSteerTask(req, myAgentId, task, steerAccess)) {
|
|
22605
23054
|
jsonError(res, "Forbidden: caller cannot steer this task", 403);
|
|
22606
23055
|
return true;
|
|
22607
23056
|
}
|
|
@@ -22641,6 +23090,10 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
22641
23090
|
jsonError(res, "Task not found", 404);
|
|
22642
23091
|
return true;
|
|
22643
23092
|
}
|
|
23093
|
+
if (!await canReadSession2(req, myAgentId, parsed.params.id)) {
|
|
23094
|
+
jsonError(res, SESSION_READ_DENIED2, 403);
|
|
23095
|
+
return true;
|
|
23096
|
+
}
|
|
22644
23097
|
getTaskSteeringMessagesRoute.respond(res, 200, {
|
|
22645
23098
|
messages: await getSteeringMessagesForTask2(parsed.params.id)
|
|
22646
23099
|
});
|
|
@@ -22659,13 +23112,18 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
22659
23112
|
return true;
|
|
22660
23113
|
}
|
|
22661
23114
|
if (parsed.query.taskId) {
|
|
23115
|
+
if (!await canReadSession2(req, myAgentId, parsed.query.taskId)) {
|
|
23116
|
+
jsonError(res, SESSION_READ_DENIED2, 403);
|
|
23117
|
+
return true;
|
|
23118
|
+
}
|
|
22662
23119
|
const task = await getTaskById2(parsed.query.taskId);
|
|
22663
23120
|
const messages = task?.agentId === myAgentId ? await getPendingSteeringForTask2(parsed.query.taskId) : [];
|
|
22664
23121
|
getPendingSteeringMessagesRoute.respond(res, 200, { messages });
|
|
22665
23122
|
return true;
|
|
22666
23123
|
}
|
|
23124
|
+
const actor = await resolveSessionActor2(req, myAgentId);
|
|
22667
23125
|
getPendingSteeringMessagesRoute.respond(res, 200, {
|
|
22668
|
-
messages: await getPendingSteeringForAgent2(myAgentId)
|
|
23126
|
+
messages: await getPendingSteeringForAgent2(myAgentId, readableByFor2(actor))
|
|
22669
23127
|
});
|
|
22670
23128
|
return true;
|
|
22671
23129
|
}
|
|
@@ -22806,6 +23264,11 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
22806
23264
|
jsonError(res, "Task not found", 404);
|
|
22807
23265
|
return true;
|
|
22808
23266
|
}
|
|
23267
|
+
const readAccess = await sessionAccessFor2(await resolveSessionActor2(req, myAgentId), task.id);
|
|
23268
|
+
if (!hasSessionAccess(readAccess, "read")) {
|
|
23269
|
+
jsonError(res, "You don't have access to this session. Ask the owner to share it.", 403);
|
|
23270
|
+
return true;
|
|
23271
|
+
}
|
|
22809
23272
|
const logs = await getLogsByTaskId2(parsed.params.id, parsed.query.logsLimit ?? 200);
|
|
22810
23273
|
const attachments = await getTaskAttachments2(parsed.params.id);
|
|
22811
23274
|
getTask.respond(res, 200, {
|
|
@@ -22957,7 +23420,7 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
22957
23420
|
jsonError(res, "Missing X-Agent-ID header", 400);
|
|
22958
23421
|
return true;
|
|
22959
23422
|
}
|
|
22960
|
-
const pausedTasks = await getPausedTasksForAgent2(myAgentId);
|
|
23423
|
+
const pausedTasks = await getPausedTasksForAgent2(myAgentId, readableByFor2(await resolveSessionActor2(req, myAgentId)));
|
|
22961
23424
|
const tasks = await Promise.all(pausedTasks.map(async (task) => {
|
|
22962
23425
|
const requestedBy = await buildTaskRequestedBy(task);
|
|
22963
23426
|
return {
|
|
@@ -26820,6 +27283,7 @@ ${templateBody}` : templateBody;
|
|
|
26820
27283
|
|
|
26821
27284
|
// src/http/realtime.ts
|
|
26822
27285
|
init_zod();
|
|
27286
|
+
init_users();
|
|
26823
27287
|
init_rbac();
|
|
26824
27288
|
|
|
26825
27289
|
// src/realtime/browser.generated.txt
|
|
@@ -26833,14 +27297,14 @@ var realtimeTicketRoute = route({
|
|
|
26833
27297
|
pattern: ["api", "realtime", "ticket"],
|
|
26834
27298
|
summary: "Issue a one-shot dashboard realtime ticket",
|
|
26835
27299
|
tags: ["Rooms"],
|
|
26836
|
-
|
|
27300
|
+
description: "The ticket authorizes one dashboard socket for presence rooms: Comb drives (`comb.presence`) and sessions (`session.presence`). An operator-key tab's picked user (`X-Swarm-User-Id`) rides on the ticket so session presence can check that user's access.",
|
|
27301
|
+
rbac: { permission: "session.presence", alsoAdmits: ["comb.presence"] },
|
|
26837
27302
|
responses: {
|
|
26838
27303
|
200: {
|
|
26839
27304
|
description: "One-shot realtime ticket",
|
|
26840
27305
|
schema: object2({ ticket: string2(), expiresAt: number2().int() })
|
|
26841
27306
|
},
|
|
26842
|
-
403: { description: "
|
|
26843
|
-
404: { description: "Comb is not enabled" }
|
|
27307
|
+
403: { description: "Presence is not allowed" }
|
|
26844
27308
|
}
|
|
26845
27309
|
});
|
|
26846
27310
|
route({
|
|
@@ -26857,29 +27321,28 @@ route({
|
|
|
26857
27321
|
async function handleRealtimeTicket(req, res, pathSegments, queryParams) {
|
|
26858
27322
|
if (!realtimeTicketRoute.match(req.method, pathSegments))
|
|
26859
27323
|
return false;
|
|
26860
|
-
if (!getCombConfig().enabled) {
|
|
26861
|
-
jsonError(res, "Comb is not enabled", 404);
|
|
26862
|
-
return true;
|
|
26863
|
-
}
|
|
26864
27324
|
const parsed = await realtimeTicketRoute.parse(req, res, pathSegments, queryParams);
|
|
26865
27325
|
if (!parsed)
|
|
26866
27326
|
return true;
|
|
26867
27327
|
const auth = getRequestAuth(req);
|
|
26868
27328
|
if (!auth || auth.kind === "agent" || auth.kind === "guest" || auth.kind === "controller") {
|
|
26869
|
-
jsonError(res, "
|
|
27329
|
+
jsonError(res, "Presence requires dashboard authentication", 403);
|
|
26870
27330
|
return true;
|
|
26871
27331
|
}
|
|
26872
27332
|
const principal = auth.kind === "operator" ? { kind: "operator" } : { kind: "user", userId: auth.userId };
|
|
26873
|
-
|
|
26874
|
-
|
|
26875
|
-
|
|
26876
|
-
resource: { kind: "none" },
|
|
26877
|
-
source: "http"
|
|
26878
|
-
}).allow) {
|
|
26879
|
-
jsonError(res, "Comb presence requires the comb.presence permission", 403);
|
|
27333
|
+
const allowed = (verb) => can({ principal, verb, resource: { kind: "none" }, source: "http" }).allow;
|
|
27334
|
+
if (!allowed("comb.presence") && !allowed("session.presence")) {
|
|
27335
|
+
jsonError(res, "Presence requires the comb.presence or session.presence permission", 403);
|
|
26880
27336
|
return true;
|
|
26881
27337
|
}
|
|
26882
|
-
|
|
27338
|
+
let dashboardUserId;
|
|
27339
|
+
if (auth.kind === "operator" && !auth.page) {
|
|
27340
|
+
const picked = dashboardUserIdHeader(req);
|
|
27341
|
+
const user = picked ? await findUserById(picked) : null;
|
|
27342
|
+
if (user?.status === "active")
|
|
27343
|
+
dashboardUserId = user.id;
|
|
27344
|
+
}
|
|
27345
|
+
realtimeTicketRoute.respond(res, 200, issueRealtimeTicket(dashboardUserId ? { ...auth, dashboardUserId } : auth));
|
|
26883
27346
|
return true;
|
|
26884
27347
|
}
|
|
26885
27348
|
async function handleRealtimeAsset(req, res) {
|
|
@@ -30768,6 +31231,7 @@ var agentTaskRoute = route({
|
|
|
30768
31231
|
method: "post",
|
|
30769
31232
|
path: "/api/internal/script-runs/{runId}/agent-task",
|
|
30770
31233
|
pattern: ["api", "internal", "script-runs", null, "agent-task"],
|
|
31234
|
+
session: bodyTask("parentTaskId"),
|
|
30771
31235
|
operationId: "script_runs_internal_agent_task",
|
|
30772
31236
|
summary: "Create or wait for a script workflow agent task step",
|
|
30773
31237
|
tags: ["Script Runs"],
|
|
@@ -31247,6 +31711,9 @@ var upsertRoute2 = route({
|
|
|
31247
31711
|
method: "post",
|
|
31248
31712
|
path: "/api/scripts/upsert",
|
|
31249
31713
|
pattern: ["api", "scripts", "upsert"],
|
|
31714
|
+
auth: {
|
|
31715
|
+
userNamesAgent: "dashboard script playground: a user runs or saves a script in a chosen agent's scope"
|
|
31716
|
+
},
|
|
31250
31717
|
operationId: "scripts_upsert",
|
|
31251
31718
|
summary: "Create or update a reusable script",
|
|
31252
31719
|
description: "Explicit script upserts run a TypeScript typecheck before writing.",
|
|
@@ -31271,6 +31738,9 @@ var runRoute = route({
|
|
|
31271
31738
|
method: "post",
|
|
31272
31739
|
path: "/api/scripts/run",
|
|
31273
31740
|
pattern: ["api", "scripts", "run"],
|
|
31741
|
+
auth: {
|
|
31742
|
+
userNamesAgent: "dashboard script playground: a user runs or saves a script in a chosen agent's scope"
|
|
31743
|
+
},
|
|
31274
31744
|
operationId: "scripts_run",
|
|
31275
31745
|
summary: "Run a reusable or inline script",
|
|
31276
31746
|
description: "Inline source skips typecheck and is auto-saved as a scratch script only on success.",
|
|
@@ -32241,6 +32711,7 @@ var createSessionLogsRoute = route({
|
|
|
32241
32711
|
method: "post",
|
|
32242
32712
|
path: "/api/session-logs",
|
|
32243
32713
|
pattern: ["api", "session-logs"],
|
|
32714
|
+
session: bodyTask("taskId"),
|
|
32244
32715
|
summary: "Store session logs",
|
|
32245
32716
|
tags: ["Session Data"],
|
|
32246
32717
|
body: object2({
|
|
@@ -32262,6 +32733,7 @@ var getSessionLogsByTask = route({
|
|
|
32262
32733
|
method: "get",
|
|
32263
32734
|
path: "/api/tasks/{taskId}/session-logs",
|
|
32264
32735
|
pattern: ["api", "tasks", null, "session-logs"],
|
|
32736
|
+
session: { taskParam: "taskId" },
|
|
32265
32737
|
summary: "Get session logs for a task",
|
|
32266
32738
|
tags: ["Session Data"],
|
|
32267
32739
|
params: object2({ taskId: string2() }),
|
|
@@ -32280,6 +32752,7 @@ var createSessionCostRoute = route({
|
|
|
32280
32752
|
method: "post",
|
|
32281
32753
|
path: "/api/session-costs",
|
|
32282
32754
|
pattern: ["api", "session-costs"],
|
|
32755
|
+
session: bodyTask("taskId"),
|
|
32283
32756
|
summary: "Store session cost record",
|
|
32284
32757
|
tags: ["Session Data"],
|
|
32285
32758
|
body: object2({
|
|
@@ -32378,7 +32851,7 @@ var listSessionCosts = route({
|
|
|
32378
32851
|
}
|
|
32379
32852
|
}
|
|
32380
32853
|
});
|
|
32381
|
-
async function handleSessionData(req, res, pathSegments, queryParams,
|
|
32854
|
+
async function handleSessionData(req, res, pathSegments, queryParams, myAgentId) {
|
|
32382
32855
|
if (createSessionLogsRoute.match(req.method, pathSegments)) {
|
|
32383
32856
|
const parsed = await createSessionLogsRoute.parse(req, res, pathSegments, queryParams);
|
|
32384
32857
|
if (!parsed)
|
|
@@ -32417,6 +32890,10 @@ async function handleSessionData(req, res, pathSegments, queryParams, _myAgentId
|
|
|
32417
32890
|
jsonError(res, "Task not found", 404);
|
|
32418
32891
|
return true;
|
|
32419
32892
|
}
|
|
32893
|
+
if (!await canReadSession2(req, myAgentId, task.id)) {
|
|
32894
|
+
jsonError(res, SESSION_READ_DENIED2, 403);
|
|
32895
|
+
return true;
|
|
32896
|
+
}
|
|
32420
32897
|
const logs = await getSessionLogsByTaskId2(parsed.params.taskId, parsed.query?.limit);
|
|
32421
32898
|
getSessionLogsByTask.respond(res, 200, { logs });
|
|
32422
32899
|
return true;
|
|
@@ -32563,6 +33040,8 @@ init_zod();
|
|
|
32563
33040
|
init_db3();
|
|
32564
33041
|
init_steering();
|
|
32565
33042
|
init_users();
|
|
33043
|
+
init_rbac();
|
|
33044
|
+
init_bus();
|
|
32566
33045
|
init_types();
|
|
32567
33046
|
init_request_auth_context();
|
|
32568
33047
|
init_runtime_pools_flag();
|
|
@@ -32611,6 +33090,9 @@ var mintSessionTokenRoute = route({
|
|
|
32611
33090
|
method: "post",
|
|
32612
33091
|
path: "/api/sessions/tokens",
|
|
32613
33092
|
pattern: ["api", "sessions", "tokens"],
|
|
33093
|
+
session: {
|
|
33094
|
+
none: "user tokens cannot mint: the handler admits only the operator key or the task's own runtime"
|
|
33095
|
+
},
|
|
32614
33096
|
summary: "Mint an ephemeral task or runtime token",
|
|
32615
33097
|
description: "Operators can mint task or runtime tokens. Runtime tokens can mint task tokens for their own assigned tasks. Child tokens expire with their parent runtime.",
|
|
32616
33098
|
tags: ["Sessions"],
|
|
@@ -32673,7 +33155,8 @@ var listSessions = route({
|
|
|
32673
33155
|
q: string2().optional(),
|
|
32674
33156
|
requestedByUserId: string2().min(1).optional(),
|
|
32675
33157
|
contextKeyPrefix: string2().min(1).optional(),
|
|
32676
|
-
fields: _enum2(["full", "slim"]).optional()
|
|
33158
|
+
fields: _enum2(["full", "slim"]).optional(),
|
|
33159
|
+
scope: _enum2(["mine", "shared"]).optional()
|
|
32677
33160
|
}),
|
|
32678
33161
|
responses: {
|
|
32679
33162
|
200: {
|
|
@@ -32693,23 +33176,68 @@ var getSession = route({
|
|
|
32693
33176
|
method: "get",
|
|
32694
33177
|
path: "/api/sessions/{rootTaskId}",
|
|
32695
33178
|
pattern: ["api", "sessions", null],
|
|
33179
|
+
session: { taskParam: "rootTaskId" },
|
|
32696
33180
|
summary: "Get a session — root task + the entire descendant chain",
|
|
32697
33181
|
tags: ["Sessions"],
|
|
32698
33182
|
params: object2({ rootTaskId: string2() }),
|
|
32699
33183
|
responses: {
|
|
32700
33184
|
200: {
|
|
32701
|
-
description: "Root task + chain (ordered by createdAt)",
|
|
33185
|
+
description: "Root task + chain (ordered by createdAt), plus the caller's `access` and the session `owner`",
|
|
32702
33186
|
schema: object2({
|
|
32703
33187
|
root: TaskWithSteeringSchema,
|
|
32704
|
-
chain: array2(TaskWithSteeringSchema)
|
|
33188
|
+
chain: array2(TaskWithSteeringSchema),
|
|
33189
|
+
access: SessionAccessSchema,
|
|
33190
|
+
owner: SessionOwnerSchema.nullable()
|
|
32705
33191
|
})
|
|
32706
33192
|
},
|
|
32707
33193
|
401: { description: "Unauthorized" },
|
|
33194
|
+
403: { description: "The caller has no access to this session" },
|
|
32708
33195
|
404: { description: "Root task not found" }
|
|
32709
33196
|
},
|
|
32710
33197
|
auth: { apiKey: true }
|
|
32711
33198
|
});
|
|
32712
|
-
|
|
33199
|
+
var getSessionShares = route({
|
|
33200
|
+
method: "get",
|
|
33201
|
+
path: "/api/sessions/{rootTaskId}/shares",
|
|
33202
|
+
pattern: ["api", "sessions", null, "shares"],
|
|
33203
|
+
session: { taskParam: "rootTaskId" },
|
|
33204
|
+
summary: "List a session's active shares",
|
|
33205
|
+
description: "Active shares only. `everyone` is the access every user has; `users` are per-person shares. A session with no shares is private to its owner.",
|
|
33206
|
+
tags: ["Sessions"],
|
|
33207
|
+
params: object2({ rootTaskId: string2() }),
|
|
33208
|
+
responses: {
|
|
33209
|
+
200: { description: "Active shares", schema: SessionSharesSchema },
|
|
33210
|
+
401: { description: "Unauthorized" },
|
|
33211
|
+
403: { description: "The caller has no access to this session" },
|
|
33212
|
+
404: { description: "Root task not found" }
|
|
33213
|
+
},
|
|
33214
|
+
auth: { apiKey: true }
|
|
33215
|
+
});
|
|
33216
|
+
var putSessionShares = route({
|
|
33217
|
+
method: "put",
|
|
33218
|
+
path: "/api/sessions/{rootTaskId}/shares",
|
|
33219
|
+
pattern: ["api", "sessions", null, "shares"],
|
|
33220
|
+
session: { taskParam: "rootTaskId" },
|
|
33221
|
+
summary: "Set who can view or edit a session",
|
|
33222
|
+
description: "Owner only. The body is the full desired state: users left out lose access. Changed targets have their active share revoked and a new one inserted in one transaction; shares are never deleted.",
|
|
33223
|
+
tags: ["Sessions"],
|
|
33224
|
+
params: object2({ rootTaskId: string2() }),
|
|
33225
|
+
body: SessionSharesUpdateSchema,
|
|
33226
|
+
responses: {
|
|
33227
|
+
200: { description: "Active shares after the change", schema: SessionSharesSchema },
|
|
33228
|
+
400: { description: "Validation error or unknown user" },
|
|
33229
|
+
401: { description: "Unauthorized" },
|
|
33230
|
+
403: { description: "Only the session owner can share it" },
|
|
33231
|
+
404: { description: "Root task not found" },
|
|
33232
|
+
409: { description: "The session has no owner, so it is already open to everyone" }
|
|
33233
|
+
},
|
|
33234
|
+
auth: { apiKey: true },
|
|
33235
|
+
rbac: { permission: "session.share" }
|
|
33236
|
+
});
|
|
33237
|
+
async function accessForRoot(actor, root) {
|
|
33238
|
+
return actor.kind === "bypass" ? "owner" : sessionAccessForRoot(actor.userId, root);
|
|
33239
|
+
}
|
|
33240
|
+
async function handleSessions(req, res, pathSegments, queryParams, myAgentId) {
|
|
32713
33241
|
if (mintSessionTokenRoute.match(req.method, pathSegments)) {
|
|
32714
33242
|
const auth = getRequestAuth(req);
|
|
32715
33243
|
if (auth?.kind !== "operator" && !(auth?.kind === "agent" && auth.runtimeId)) {
|
|
@@ -32786,21 +33314,30 @@ async function handleSessions(req, res, pathSegments, queryParams) {
|
|
|
32786
33314
|
if (!parsed)
|
|
32787
33315
|
return true;
|
|
32788
33316
|
const sources = parsed.query.source ? parsed.query.source.split(",").map((s) => s.trim()).filter(Boolean) : undefined;
|
|
32789
|
-
const
|
|
32790
|
-
|
|
32791
|
-
|
|
33317
|
+
const actor = await resolveSessionActor2(req, myAgentId);
|
|
33318
|
+
if (actor.kind === "bypass" && parsed.query.scope) {
|
|
33319
|
+
listSessions.respond(res, 200, {
|
|
33320
|
+
sessions: [],
|
|
33321
|
+
total: 0,
|
|
33322
|
+
limit: parsed.query.limit ?? 25,
|
|
33323
|
+
offset: parsed.query.offset ?? 0
|
|
33324
|
+
});
|
|
33325
|
+
return true;
|
|
33326
|
+
}
|
|
33327
|
+
const filterOpts = {
|
|
32792
33328
|
source: sources,
|
|
32793
33329
|
q: parsed.query.q,
|
|
32794
33330
|
requestedByUserId: parsed.query.requestedByUserId,
|
|
32795
|
-
contextKeyPrefix: parsed.query.contextKeyPrefix
|
|
33331
|
+
contextKeyPrefix: parsed.query.contextKeyPrefix,
|
|
33332
|
+
...actor.kind === "user" ? { viewer: { userId: actor.userId, scope: parsed.query.scope ?? "all" } } : {}
|
|
33333
|
+
};
|
|
33334
|
+
const baseOpts = {
|
|
33335
|
+
...filterOpts,
|
|
33336
|
+
limit: parsed.query.limit,
|
|
33337
|
+
offset: parsed.query.offset
|
|
32796
33338
|
};
|
|
32797
33339
|
const sessions = parsed.query.fields === "full" ? await listRecentSessions2(baseOpts) : await listRecentSessions2({ ...baseOpts, slim: true });
|
|
32798
|
-
const total = await countSessions2(
|
|
32799
|
-
source: sources,
|
|
32800
|
-
q: parsed.query.q,
|
|
32801
|
-
requestedByUserId: parsed.query.requestedByUserId,
|
|
32802
|
-
contextKeyPrefix: parsed.query.contextKeyPrefix
|
|
32803
|
-
});
|
|
33340
|
+
const total = await countSessions2(filterOpts);
|
|
32804
33341
|
listSessions.respond(res, 200, {
|
|
32805
33342
|
sessions,
|
|
32806
33343
|
total,
|
|
@@ -32818,6 +33355,20 @@ async function handleSessions(req, res, pathSegments, queryParams) {
|
|
|
32818
33355
|
jsonError(res, "Root task not found", 404);
|
|
32819
33356
|
return true;
|
|
32820
33357
|
}
|
|
33358
|
+
const sessionRoot = await getSessionRoot(root.id) ?? {
|
|
33359
|
+
id: root.id,
|
|
33360
|
+
requestedByUserId: root.requestedByUserId ?? null
|
|
33361
|
+
};
|
|
33362
|
+
const access = await accessForRoot(await resolveSessionActor2(req, myAgentId), sessionRoot);
|
|
33363
|
+
if (access === "none") {
|
|
33364
|
+
jsonError(res, "You don't have access to this session. Ask the owner to share it.", 403);
|
|
33365
|
+
return true;
|
|
33366
|
+
}
|
|
33367
|
+
const ownerUser = sessionRoot.requestedByUserId ? await findUserById(sessionRoot.requestedByUserId) : null;
|
|
33368
|
+
const owner = sessionRoot.requestedByUserId ? {
|
|
33369
|
+
id: sessionRoot.requestedByUserId,
|
|
33370
|
+
name: ownerUser?.name ?? sessionRoot.requestedByUserId
|
|
33371
|
+
} : null;
|
|
32821
33372
|
const chain = await getRootTaskChain2(parsed.params.rootTaskId);
|
|
32822
33373
|
const tasks = [root, ...chain];
|
|
32823
33374
|
const [steering, citations] = await Promise.all([
|
|
@@ -32829,7 +33380,69 @@ async function handleSessions(req, res, pathSegments, queryParams) {
|
|
|
32829
33380
|
...steering.get(task.id),
|
|
32830
33381
|
citations: citations.get(task.id)
|
|
32831
33382
|
});
|
|
32832
|
-
getSession.respond(res, 200, {
|
|
33383
|
+
getSession.respond(res, 200, {
|
|
33384
|
+
root: decorate(root),
|
|
33385
|
+
chain: chain.map(decorate),
|
|
33386
|
+
access,
|
|
33387
|
+
owner
|
|
33388
|
+
});
|
|
33389
|
+
return true;
|
|
33390
|
+
}
|
|
33391
|
+
if (getSessionShares.match(req.method, pathSegments)) {
|
|
33392
|
+
const parsed = await getSessionShares.parse(req, res, pathSegments, queryParams);
|
|
33393
|
+
if (!parsed)
|
|
33394
|
+
return true;
|
|
33395
|
+
const root = await getSessionRoot(parsed.params.rootTaskId);
|
|
33396
|
+
if (!root) {
|
|
33397
|
+
jsonError(res, "Root task not found", 404);
|
|
33398
|
+
return true;
|
|
33399
|
+
}
|
|
33400
|
+
const access = await accessForRoot(await resolveSessionActor2(req, myAgentId), root);
|
|
33401
|
+
if (access === "none") {
|
|
33402
|
+
jsonError(res, "You don't have access to this session. Ask the owner to share it.", 403);
|
|
33403
|
+
return true;
|
|
33404
|
+
}
|
|
33405
|
+
getSessionShares.respond(res, 200, toSessionSharesState(await listActiveSessionShares(root.id)));
|
|
33406
|
+
return true;
|
|
33407
|
+
}
|
|
33408
|
+
if (putSessionShares.match(req.method, pathSegments)) {
|
|
33409
|
+
const parsed = await putSessionShares.parse(req, res, pathSegments, queryParams);
|
|
33410
|
+
if (!parsed)
|
|
33411
|
+
return true;
|
|
33412
|
+
const auth = getRequestAuth(req);
|
|
33413
|
+
const actor = await resolveSessionActor2(req, myAgentId);
|
|
33414
|
+
const principal = auth?.kind === "user" ? { kind: "user", userId: auth.userId } : auth?.kind === "operator" && !myAgentId ? { kind: "operator" } : null;
|
|
33415
|
+
if (!principal || !can({ principal, verb: "session.share", resource: { kind: "none" }, source: "http" }).allow) {
|
|
33416
|
+
jsonError(res, "Only the session owner can share it", 403);
|
|
33417
|
+
return true;
|
|
33418
|
+
}
|
|
33419
|
+
const root = await getSessionRoot(parsed.params.rootTaskId);
|
|
33420
|
+
if (!root) {
|
|
33421
|
+
jsonError(res, "Root task not found", 404);
|
|
33422
|
+
return true;
|
|
33423
|
+
}
|
|
33424
|
+
if (!root.requestedByUserId) {
|
|
33425
|
+
jsonError(res, "This session has no owner, so it is already open to everyone", 409);
|
|
33426
|
+
return true;
|
|
33427
|
+
}
|
|
33428
|
+
if (actor.kind === "user" && actor.userId !== root.requestedByUserId) {
|
|
33429
|
+
jsonError(res, "Only the session owner can share it", 403);
|
|
33430
|
+
return true;
|
|
33431
|
+
}
|
|
33432
|
+
const userIds = [...new Set(parsed.body.users.map((user) => user.userId))];
|
|
33433
|
+
if (userIds.length !== parsed.body.users.length) {
|
|
33434
|
+
jsonError(res, "Each user may appear only once", 400);
|
|
33435
|
+
return true;
|
|
33436
|
+
}
|
|
33437
|
+
for (const userId of userIds) {
|
|
33438
|
+
if (!await findUserById(userId)) {
|
|
33439
|
+
jsonError(res, `Unknown user ${userId}`, 400);
|
|
33440
|
+
return true;
|
|
33441
|
+
}
|
|
33442
|
+
}
|
|
33443
|
+
const state = await setSessionShares(root, parsed.body, actor.kind === "user" ? actor.userId : null);
|
|
33444
|
+
realtimeBus.publish(sessionAccessTopic(root.id), null);
|
|
33445
|
+
putSessionShares.respond(res, 200, state);
|
|
32833
33446
|
return true;
|
|
32834
33447
|
}
|
|
32835
33448
|
return false;
|
|
@@ -34231,11 +34844,12 @@ async function handleStats(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
34231
34844
|
return true;
|
|
34232
34845
|
const limit = parsed.query.limit ?? 100;
|
|
34233
34846
|
const agentId = parsed.query.agentId;
|
|
34847
|
+
const readableBy = readableByFor2(await resolveSessionActor2(req, myAgentId));
|
|
34234
34848
|
let logs = [];
|
|
34235
34849
|
if (agentId) {
|
|
34236
|
-
logs = (await getLogsByAgentId2(agentId)).slice(0, limit);
|
|
34850
|
+
logs = (await getLogsByAgentId2(agentId, readableBy)).slice(0, limit);
|
|
34237
34851
|
} else {
|
|
34238
|
-
logs = await getAllLogs2(limit);
|
|
34852
|
+
logs = await getAllLogs2(limit, readableBy);
|
|
34239
34853
|
}
|
|
34240
34854
|
listLogs.respond(res, 200, { logs });
|
|
34241
34855
|
return true;
|
|
@@ -34291,7 +34905,7 @@ async function handleStats(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
34291
34905
|
return true;
|
|
34292
34906
|
}
|
|
34293
34907
|
if (getConcurrentContextRoute.match(req.method, pathSegments)) {
|
|
34294
|
-
const context = await getConcurrentContext2();
|
|
34908
|
+
const context = await getConcurrentContext2(readableByFor2(await resolveSessionActor2(req, myAgentId)));
|
|
34295
34909
|
getConcurrentContextRoute.respond(res, 200, context);
|
|
34296
34910
|
return true;
|
|
34297
34911
|
}
|
|
@@ -38362,10 +38976,11 @@ var httpServer = createHttpServer(async (req, res) => {
|
|
|
38362
38976
|
() => handleExtensions(req, res, pathSegments, queryParams, myAgentId),
|
|
38363
38977
|
() => handleFavorites(req, res, pathSegments, queryParams, myAgentId),
|
|
38364
38978
|
() => handleUsers(req, res, pathSegments, queryParams),
|
|
38365
|
-
() => handleSessions(req, res, pathSegments, queryParams),
|
|
38979
|
+
() => handleSessions(req, res, pathSegments, queryParams, myAgentId),
|
|
38366
38980
|
() => handleInboxState(req, res, pathSegments, queryParams),
|
|
38367
38981
|
() => handleTelemetryUi(req, res, pathSegments, queryParams, myAgentId),
|
|
38368
38982
|
() => handleUsedBy(req, res, pathSegments, queryParams, myAgentId),
|
|
38983
|
+
() => handleRanking(req, res, pathSegments, queryParams),
|
|
38369
38984
|
() => handleFleetBenchmark(req, res, pathSegments, queryParams),
|
|
38370
38985
|
() => handleTaskTemplates(req, res, pathSegments, queryParams),
|
|
38371
38986
|
() => handleMcp(req, res, transports, transportActivity, mcpSessionAgents),
|
|
@@ -38397,7 +39012,7 @@ var httpServer = createHttpServer(async (req, res) => {
|
|
|
38397
39012
|
});
|
|
38398
39013
|
});
|
|
38399
39014
|
var detachRealtime = attachRealtimeTransport(httpServer);
|
|
38400
|
-
var { attachControllerTransport } = await import("./controllers-connect-
|
|
39015
|
+
var { attachControllerTransport } = await import("./controllers-connect-gkxmqw9d.js");
|
|
38401
39016
|
var detachControllers = attachControllerTransport(httpServer);
|
|
38402
39017
|
var stopWorkerNudges = startWorkerNudgeListener();
|
|
38403
39018
|
var stopRoomDeletion = realtimeBus.subscribe("room:namespace-deleted", (namespace) => {
|
|
@@ -38426,7 +39041,7 @@ async function shutdown() {
|
|
|
38426
39041
|
sessionsProcessed: getServerSessionsProcessed()
|
|
38427
39042
|
});
|
|
38428
39043
|
if (hasCapability("scheduling")) {
|
|
38429
|
-
const { stopScheduler } = await import("./index-
|
|
39044
|
+
const { stopScheduler } = await import("./index-8pwc1jc8.js");
|
|
38430
39045
|
stopScheduler();
|
|
38431
39046
|
}
|
|
38432
39047
|
stopHeartbeat2();
|
|
@@ -38438,7 +39053,7 @@ async function shutdown() {
|
|
|
38438
39053
|
await stopSlackApp2();
|
|
38439
39054
|
await stopChatSdk();
|
|
38440
39055
|
if (process.env.OAUTH_KEEPALIVE_DISABLE !== "true") {
|
|
38441
|
-
const { stopOAuthKeepalive } = await import("./keepalive-
|
|
39056
|
+
const { stopOAuthKeepalive } = await import("./keepalive-3nr4st3r.js");
|
|
38442
39057
|
await stopOAuthKeepalive();
|
|
38443
39058
|
}
|
|
38444
39059
|
stopOAuthPendingGc();
|
|
@@ -38518,21 +39133,21 @@ try {
|
|
|
38518
39133
|
console.warn("[startup] CAPABILITIES upgrade seed failed (non-fatal):", err);
|
|
38519
39134
|
}
|
|
38520
39135
|
try {
|
|
38521
|
-
const { ensurePricingSeeded } = await import("./boot-seeds-
|
|
39136
|
+
const { ensurePricingSeeded } = await import("./boot-seeds-xs9a8dx1.js");
|
|
38522
39137
|
ensurePricingSeeded();
|
|
38523
|
-
const { startPricingRefreshLoop } = await import("./pricing-refresh-
|
|
39138
|
+
const { startPricingRefreshLoop } = await import("./pricing-refresh-5nvme3sm.js");
|
|
38524
39139
|
startPricingRefreshLoop();
|
|
38525
39140
|
} catch (err) {
|
|
38526
39141
|
console.error("[startup] Failed to seed pricing rows:", err);
|
|
38527
39142
|
}
|
|
38528
39143
|
try {
|
|
38529
|
-
const { ensureModelProfilesSeeded } = await import("./boot-seeds-
|
|
39144
|
+
const { ensureModelProfilesSeeded } = await import("./boot-seeds-xs9a8dx1.js");
|
|
38530
39145
|
await ensureModelProfilesSeeded();
|
|
38531
39146
|
} catch (err) {
|
|
38532
39147
|
console.error("[startup] Failed to seed model profiles:", err);
|
|
38533
39148
|
}
|
|
38534
39149
|
try {
|
|
38535
|
-
const { ensureRbacSeeded } = await import("./boot-seeds-
|
|
39150
|
+
const { ensureRbacSeeded } = await import("./boot-seeds-xs9a8dx1.js");
|
|
38536
39151
|
ensureRbacSeeded();
|
|
38537
39152
|
} catch (err) {
|
|
38538
39153
|
console.error("[startup] Failed to sync RBAC seed rows:", err);
|
|
@@ -38540,7 +39155,7 @@ try {
|
|
|
38540
39155
|
throw err;
|
|
38541
39156
|
}
|
|
38542
39157
|
try {
|
|
38543
|
-
const { runAllSeeders } = await import("./index-
|
|
39158
|
+
const { runAllSeeders } = await import("./index-s7ckdajq.js");
|
|
38544
39159
|
await runAllSeeders({ scriptEmbeddingMode: "skip" });
|
|
38545
39160
|
} catch (err) {
|
|
38546
39161
|
console.error("[startup] Failed to seed built-in entities:", err);
|
|
@@ -38602,39 +39217,39 @@ httpServer.listen(port, async () => {
|
|
|
38602
39217
|
await initWorkflows2();
|
|
38603
39218
|
await startScriptRunSupervisor(getMcpBaseUrl());
|
|
38604
39219
|
if (hasCapability("scheduling")) {
|
|
38605
|
-
const { startScheduler } = await import("./index-
|
|
38606
|
-
const { getExecutorRegistry } = await import("./index-
|
|
39220
|
+
const { startScheduler } = await import("./index-8pwc1jc8.js");
|
|
39221
|
+
const { getExecutorRegistry } = await import("./index-dg2tmj99.js");
|
|
38607
39222
|
const intervalMs = Number(process.env.SCHEDULER_INTERVAL_MS) || 1e4;
|
|
38608
39223
|
startScheduler(getExecutorRegistry(), intervalMs, {
|
|
38609
39224
|
runId: globalState.__runId
|
|
38610
39225
|
});
|
|
38611
39226
|
}
|
|
38612
39227
|
if (!isEnvFlagEnabled("HEARTBEAT_DISABLE", false)) {
|
|
38613
|
-
const { startHeartbeat } = await import("./index-
|
|
39228
|
+
const { startHeartbeat } = await import("./index-nxa6me0q.js");
|
|
38614
39229
|
const heartbeatMs = Number(process.env.HEARTBEAT_INTERVAL_MS) || 90000;
|
|
38615
39230
|
startHeartbeat(heartbeatMs);
|
|
38616
39231
|
}
|
|
38617
39232
|
startPoolRouting();
|
|
38618
39233
|
startRuntimeSupervisor();
|
|
38619
39234
|
if (process.env.OAUTH_KEEPALIVE_DISABLE !== "true") {
|
|
38620
|
-
const { startOAuthKeepalive } = await import("./keepalive-
|
|
39235
|
+
const { startOAuthKeepalive } = await import("./keepalive-3nr4st3r.js");
|
|
38621
39236
|
startOAuthKeepalive();
|
|
38622
39237
|
}
|
|
38623
39238
|
if (process.env.OAUTH_REFRESH_SWEEP_DISABLE !== "true") {
|
|
38624
|
-
const { startOAuthRefreshSweep } = await import("./oauth-refresh-sweep-
|
|
39239
|
+
const { startOAuthRefreshSweep } = await import("./oauth-refresh-sweep-9q2t0y3q.js");
|
|
38625
39240
|
startOAuthRefreshSweep();
|
|
38626
39241
|
}
|
|
38627
39242
|
startOAuthPendingGc();
|
|
38628
39243
|
await startMemoryGc();
|
|
38629
39244
|
await startDbRetention();
|
|
38630
39245
|
startHumanFreeDrain();
|
|
38631
|
-
import("./boot-reembed-
|
|
39246
|
+
import("./boot-reembed-qr8a894z.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
|
|
38632
39247
|
console.error("[boot-reembed] startup backfill failed (non-fatal):", err);
|
|
38633
39248
|
});
|
|
38634
|
-
import("./boot-reembed-
|
|
39249
|
+
import("./boot-reembed-rj85jjhw.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
|
|
38635
39250
|
console.error("[boot-reembed-scripts] startup backfill failed (non-fatal):", err);
|
|
38636
39251
|
});
|
|
38637
|
-
import("./boot-scrub-sweep-
|
|
39252
|
+
import("./boot-scrub-sweep-eyfvn6v9.js").then(({ runBootScrubSweep }) => runBootScrubSweep()).catch((err) => {
|
|
38638
39253
|
console.error("[boot-scrub-sweep] startup scrub failed (non-fatal):", err);
|
|
38639
39254
|
});
|
|
38640
39255
|
}).on("error", (err) => {
|