@desplega.ai/agent-swarm 2.5.4 → 2.6.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 +2 -2
- package/dist/{acp-adapter-ek38cwsv.js → acp-adapter-dgfakfpw.js} +9 -9
- package/dist/{actions-92mepq03.js → actions-fbqma8aa.js} +21 -21
- package/dist/{amp-adapter-9gaxg015.js → amp-adapter-en0jy6hs.js} +4 -4
- package/dist/{app-ctn8gsgx.js → app-k8a5cgpp.js} +3 -3
- package/dist/{assistant-zyr5kz47.js → assistant-a16433gr.js} +29 -25
- package/dist/{boot-reembed-dwzfttdr.js → boot-reembed-6c1sjfnr.js} +1 -1
- package/dist/{boot-reembed-w75maga2.js → boot-reembed-f4nn561n.js} +1 -1
- package/dist/{boot-scrub-sweep-e9kq43kf.js → boot-scrub-sweep-d4w9gajf.js} +4 -4
- package/dist/{boot-seeds-x28v3fhb.js → boot-seeds-9bmkspyw.js} +4 -4
- package/dist/{claude-adapter-f0afqnne.js → claude-adapter-nys1kjxa.js} +9 -9
- package/dist/{claude-managed-adapter-x81a7r65.js → claude-managed-adapter-55207973.js} +2 -2
- package/dist/{claude-managed-setup-bqzwjd9x.js → claude-managed-setup-3cm35gey.js} +10 -3
- package/dist/{claude-sdk-session-7b7whkaq.js → claude-sdk-session-nw5yd8cp.js} +11 -11
- package/dist/{cli-c61mbdds.js → cli-03gg9pd1.js} +4 -4
- package/dist/{cli-kxpfx2xr.js → cli-0z1xjzwa.js} +2 -2
- package/dist/cli-1tem6ns9.js +894 -0
- package/dist/{cli-jbnn4vxb.js → cli-24j1jeeb.js} +3 -3
- package/dist/{cli-pzatvw94.js → cli-2sjhpsns.js} +2 -2
- package/dist/{cli-dew6x255.js → cli-39aet655.js} +2 -2
- package/dist/{cli-g1cw7xtt.js → cli-39rrw8yp.js} +1 -1
- package/dist/{cli-x0f2v69c.js → cli-3aqd4jaa.js} +12 -7
- package/dist/{cli-gbfxp48k.js → cli-3fwqy71j.js} +15 -15
- package/dist/{cli-7p4jxgtt.js → cli-3gfvmzht.js} +6 -6
- package/dist/{cli-03vpq45j.js → cli-3ndmpxxv.js} +2 -2
- package/dist/{cli-asq5ydm4.js → cli-4hxrf0p4.js} +131 -50
- package/dist/{cli-mz9afxxf.js → cli-4rf0f5vg.js} +15 -3
- package/dist/{cli-k4tjsdx9.js → cli-5rj83bam.js} +272 -195
- package/dist/{cli-sbwsxvtd.js → cli-5sckpqcx.js} +2 -2
- package/dist/{cli-cz5nmdxt.js → cli-683y0b3a.js} +2 -2
- package/dist/{cli-ethgy7ha.js → cli-6y51ryva.js} +2 -2
- package/dist/{cli-n4c8e3s5.js → cli-708wdy32.js} +1 -1
- package/dist/{cli-pasyvjmm.js → cli-737pyqxr.js} +1 -1
- package/dist/{cli-gx4rm0qx.js → cli-7enjwya9.js} +1 -1
- package/dist/{cli-6x9ma5w5.js → cli-803188pb.js} +1 -1
- package/dist/{cli-hh5we352.js → cli-9abdgn5t.js} +7 -7
- package/dist/{cli-ff1tm9n9.js → cli-a2rr0fmg.js} +1 -1
- package/dist/{cli-c952c7ac.js → cli-a34pr3w1.js} +2 -2
- package/dist/{cli-s682zgqz.js → cli-abkm71vr.js} +1 -1
- package/dist/{cli-mmhj8vd7.js → cli-ag2yrnt5.js} +11 -2
- package/dist/{cli-bvpgr9ny.js → cli-aj8djyqt.js} +5 -5
- package/dist/{cli-gwhjmh8g.js → cli-art7c1zh.js} +5 -5
- package/dist/{cli-5bnsc0e1.js → cli-az25fn5f.js} +4 -4
- package/dist/{cli-9s05422w.js → cli-bqztfyve.js} +1 -1
- package/dist/{cli-bn0rewsy.js → cli-c081bj3b.js} +2 -2
- package/dist/{cli-1r5ad7j5.js → cli-c2habvsf.js} +12 -12
- package/dist/{cli-64mh9mf3.js → cli-ca6banwz.js} +69 -17
- package/dist/{cli-25n3mv5d.js → cli-cz37jqss.js} +5 -5
- package/dist/{cli-6n8axjv1.js → cli-d2dpf95n.js} +2 -2
- package/dist/{cli-gn5af0x5.js → cli-emhjcj2y.js} +11 -11
- package/dist/{cli-6a1xg1p7.js → cli-esakngh8.js} +2 -2
- package/dist/{cli-ha9rmwgq.js → cli-fb8m699c.js} +2 -2
- package/dist/{cli-4b2z6n0m.js → cli-ffvsj2qw.js} +17 -8
- package/dist/{cli-abs8ndtr.js → cli-g20jjwt4.js} +26 -26
- package/dist/{cli-jb30dzvk.js → cli-g8ka5j4j.js} +446 -164
- package/dist/{cli-19202kew.js → cli-gf95q3bm.js} +5 -5
- package/dist/{cli-eftzyh9y.js → cli-gnsb1zxa.js} +2 -2
- package/dist/{cli-nwyw3zhg.js → cli-gxee0bqa.js} +1 -1
- package/dist/{cli-e42vss7b.js → cli-hfeb68z4.js} +5 -5
- package/dist/{cli-g9vd9ece.js → cli-k21gx5ht.js} +14 -16
- package/dist/{cli-tsma7p8v.js → cli-kf4jree9.js} +2 -2
- package/dist/{cli-dabehxhp.js → cli-kt907da6.js} +1 -1
- package/dist/{cli-wx2nj19m.js → cli-m5a9m0ak.js} +6 -6
- package/dist/{cli-621ce7kw.js → cli-m70bajzr.js} +3 -3
- package/dist/{cli-9j129brq.js → cli-mtnj4fwa.js} +6 -6
- package/dist/{cli-xzfq4at3.js → cli-mvjz5an3.js} +15 -11
- package/dist/{cli-277c31dw.js → cli-n7asmce6.js} +225 -3
- package/dist/{cli-xtrz6bzs.js → cli-nn6vx2mq.js} +1 -1
- package/dist/{cli-2655k16q.js → cli-nq677csy.js} +1 -1
- package/dist/{cli-0shx9j93.js → cli-pfk92eqz.js} +2 -2
- package/dist/{cli-wghjkr0e.js → cli-sqma6vw1.js} +10 -7
- package/dist/{cli-nzfnt2gs.js → cli-tf1n0r0b.js} +1 -1
- package/dist/{cli-qqzmjxkf.js → cli-v49fkghp.js} +11 -6
- package/dist/{cli-x77gen2p.js → cli-w2656ka1.js} +7 -7
- package/dist/{cli-5kqnemen.js → cli-yvy48785.js} +1 -1
- package/dist/{cli-m4ecdxvz.js → cli-zqne1qcj.js} +7 -7
- package/dist/cli.js +17 -17
- package/dist/{codex-adapter-wch12q99.js → codex-adapter-d95q4qsn.js} +7 -7
- package/dist/{codex-login-rn7c5gxt.js → codex-login-8cg0vhf2.js} +1 -1
- package/dist/{codex-session-runner-41pfcr95.js → codex-session-runner-gdwd8h0c.js} +8 -8
- package/dist/{commands-9849dkj6.js → commands-jqmgk54b.js} +2 -2
- package/dist/{controller-ja0sd95p.js → controller-z3jq589f.js} +4 -4
- package/dist/{controllers-connect-xp05dj6x.js → controllers-connect-r2za39ef.js} +23 -23
- package/dist/{cursor-adapter-623qxqew.js → cursor-adapter-4mr4jgkw.js} +2 -2
- package/dist/{db-47vj40dy.js → db-ppv2tze7.js} +3 -3
- package/dist/{db-w759qmx0.js → db-w36wwb5g.js} +4 -2
- package/dist/{devin-adapter-4ycy4vrf.js → devin-adapter-byen2cxt.js} +1 -1
- package/dist/{dispatcher-7b8e4z2j.js → dispatcher-pv5h77vf.js} +20 -20
- package/dist/{docker-s84hjs91.js → docker-fdzyewpz.js} +2 -2
- package/dist/{dsh-adapter-2ezw3xea.js → dsh-adapter-d4pdpb3r.js} +2 -2
- package/dist/{e2b-9gkdhm3c.js → e2b-222hsajc.js} +2 -2
- package/dist/{e2b-cjtf8k1z.js → e2b-fn3zacvt.js} +2 -2
- package/dist/{easter-egg-3d-e4qv8dxj.js → easter-egg-3d-4sp4dvmc.js} +1 -1
- package/dist/{event-bus-3z78ep5n.js → event-bus-pghg8hqy.js} +1 -1
- package/dist/{execute-0xpz8950.js → execute-jev839y1.js} +1 -1
- package/dist/{external-channel-e2s028da.js → external-channel-y6nkzhnn.js} +2 -2
- package/dist/{grok-adapter-ys7gaqee.js → grok-adapter-t08b9ntm.js} +10 -10
- package/dist/handlers-eqsnmv95.js +41 -0
- package/dist/{heartbeat-w3mntghj.js → heartbeat-vn31xwdk.js} +23 -23
- package/dist/{hook-g7kvv6x9.js → hook-6d0zbvvt.js} +6 -6
- package/dist/{hook-3jjywnpb.js → hook-cpjs8q51.js} +8 -8
- package/dist/{http-tkp7d4kb.js → http-9c6medda.js} +856 -99
- package/dist/{index-xdaahthb.js → index-38t35h0n.js} +20 -20
- package/dist/{index-3n8m9ea2.js → index-g6k9tctj.js} +1 -1
- package/dist/{index-1ef1myq2.js → index-k0yt1tvq.js} +20 -20
- package/dist/{index-31ceyf42.js → index-pkma1yf8.js} +1 -1
- package/dist/{index-q7m26kvs.js → index-qhjf2htm.js} +13 -10
- package/dist/index-yqgbfgaj.js +43 -0
- package/dist/{keepalive-v4ta8wgg.js → keepalive-em0117bp.js} +4 -4
- package/dist/lead-23e7z59t.js +79 -0
- package/dist/{maintenance-84n1ex21.js → maintenance-kbme3qy9.js} +1 -1
- package/dist/{oauth-refresh-sweep-vjnnandw.js → oauth-refresh-sweep-xysj4yse.js} +3 -3
- package/dist/{onboard-sfmpe4np.js → onboard-p6q0vz97.js} +3 -3
- package/dist/{opencode-adapter-jmpst4q4.js → opencode-adapter-esv3k9yn.js} +7 -7
- package/dist/{otel-impl-v6cc0zve.js → otel-impl-54qhqh1z.js} +2 -2
- package/dist/{pi-mono-adapter-fk8fkcf6.js → pi-mono-adapter-mymbwhj0.js} +10 -10
- package/dist/{pricing-refresh-fsk1e1zc.js → pricing-refresh-yb75wv33.js} +3 -3
- package/dist/{rbac-roles-prmkdnkw.js → rbac-roles-1vp2mw4p.js} +2 -2
- package/dist/{rbac-roles-zxmxqa39.js → rbac-roles-dexhc9x8.js} +1 -1
- package/dist/render-v2-tjay5hhf.js +16 -0
- package/dist/{resume-frdtgfa0.js → resume-8ayf37g5.js} +9 -9
- package/dist/{runtime-bt5pkpm1.js → runtime-hqe5cqcd.js} +1 -1
- package/dist/{session-access-fpez4y5q.js → session-access-fdhp987s.js} +4 -4
- package/dist/session-source-backfill-qgtc86z1.js +110 -0
- package/dist/{setup-mq6m3m8q.js → setup-4rrmqcq3.js} +1 -1
- package/dist/{virtual-modules-mnfbh5mr.js → virtual-modules-52km00d6.js} +2 -2
- package/dist/{work-objects-kfahhjsq.js → work-objects-p28fgd70.js} +23 -23
- package/dist/worker-e3w7vye1.js +79 -0
- package/dist/{x-pbpezr0s.js → x-wxrzvzx8.js} +2 -2
- package/openapi.json +1274 -32
- package/package.json +1 -1
- package/src/assets/source-key.ts +95 -0
- package/src/be/db/api-keys.ts +80 -0
- package/src/be/db/session-labels.ts +28 -0
- package/src/be/db/session-moves.ts +5 -6
- package/src/be/db/session-tree.ts +153 -14
- package/src/be/db/tasks/read.ts +11 -0
- package/src/be/db/tasks/write.ts +6 -1
- package/src/be/db/workflow-runs.ts +183 -1
- package/src/be/db-retention.ts +61 -6
- package/src/be/db.ts +59 -114
- package/src/be/memory/providers/openai-embedding.ts +5 -1
- package/src/be/migrations/244_api_key_validation.sql +4 -0
- package/src/be/onboarding.ts +4 -0
- package/src/be/scripts/typecheck.ts +1 -1
- package/src/be/session-source-backfill.ts +163 -0
- package/src/be/swarm-config-guard.ts +1 -0
- package/src/comb/review-batch.ts +28 -1
- package/src/comb/templates.ts +7 -2
- package/src/commands/claude-managed-setup.ts +7 -1
- package/src/commands/credential-refresh.ts +76 -1
- package/src/commands/credential-wait.ts +2 -2
- package/src/commands/provider-credentials.ts +210 -170
- package/src/commands/runner.ts +25 -4
- package/src/extensions/apply-task-create.ts +8 -1
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/extensions/contract.ts +5 -0
- package/src/http/all-routes.ts +2 -0
- package/src/http/api-keys.ts +53 -0
- package/src/http/assets.ts +15 -0
- package/src/http/codex-oauth-accounts.ts +191 -0
- package/src/http/comb.ts +15 -2
- package/src/http/config.ts +1 -1
- package/src/http/core.ts +6 -0
- package/src/http/fleet-benchmark.ts +5 -2
- package/src/http/index.ts +11 -0
- package/src/http/integrations.ts +5 -1
- package/src/http/kv.ts +8 -3
- package/src/http/onboarding.ts +6 -1
- package/src/http/pool-keys.ts +354 -0
- package/src/http/sessions.ts +37 -12
- package/src/http/stats.ts +1 -0
- package/src/http/status.ts +26 -12
- package/src/http/tasks.ts +3 -0
- package/src/http/used-by.ts +7 -2
- package/src/http/workflows.ts +78 -9
- package/src/integrations/chat-sdk/inbound.ts +27 -0
- package/src/kv-reserved-namespaces.ts +19 -0
- package/src/providers/acp-targets.ts +1 -1
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/claude-adapter.ts +5 -1
- package/src/providers/claude-managed-adapter.ts +16 -9
- package/src/providers/codex-adapter.ts +71 -11
- package/src/scheduler/scheduler.ts +3 -2
- package/src/scripts-runtime/swarm-sdk.ts +7 -1
- package/src/scripts-runtime/types/stdlib.d.ts +1 -1
- package/src/scripts-runtime/types/swarm-extension.d.ts +17 -8
- package/src/scripts-runtime/types/swarm-sdk.d.ts +1 -1
- package/src/slack/assistant.ts +7 -0
- package/src/slack/channel-labels.ts +74 -0
- package/src/slack/handlers.ts +8 -0
- package/src/slack/inbound-files.ts +5 -2
- package/src/slack/thread-buffer.ts +4 -0
- package/src/tasks/sibling-awareness.ts +12 -3
- package/src/telemetry-context.ts +5 -6
- package/src/telemetry-identity.ts +3 -3
- package/src/tests/api-keys-validation.test.ts +170 -0
- package/src/tests/claude-managed-adapter.test.ts +46 -0
- package/src/tests/claude-routes-e2e.test.ts +7 -2
- package/src/tests/codex-credential-pools.test.ts +120 -0
- package/src/tests/codex-gateway-route.test.ts +165 -0
- package/src/tests/codex-oauth-accounts.test.ts +357 -0
- package/src/tests/comb-review-batch.test.ts +63 -2
- package/src/tests/config-pool-keys.test.ts +533 -0
- package/src/tests/credential-check.test.ts +290 -2
- package/src/tests/credential-refresh.test.ts +172 -1
- package/src/tests/db-retention.test.ts +9 -3
- package/src/tests/db-task-read-contract.test.ts +1 -0
- package/src/tests/db-task-write-contract.test.ts +1 -3
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/extensions-pre-task.test.ts +53 -1
- package/src/tests/fixtures/extensions/record-task-create/hooks.ts +9 -0
- package/src/tests/fixtures/extensions/record-task-create/manifest.json +7 -0
- package/src/tests/fleet-benchmark.test.ts +8 -0
- package/src/tests/get-workflow-run-tool.test.ts +98 -0
- package/src/tests/integrations-http.test.ts +32 -2
- package/src/tests/internal-ai/complete-structured.test.ts +37 -1
- package/src/tests/internal-ai/credentials.test.ts +23 -0
- package/src/tests/kv-http.test.ts +32 -0
- package/src/tests/kv-tool.test.ts +25 -0
- package/src/tests/multi-runtime-registration.test.ts +12 -12
- package/src/tests/onboarding.test.ts +108 -1
- package/src/tests/openai-embedding-credentials.test.ts +35 -0
- package/src/tests/openrouter-attribution-call-sites.test.ts +2 -2
- package/src/tests/org-website.test.ts +36 -0
- package/src/tests/provider-key-probes.test.ts +181 -0
- package/src/tests/rbac-e2e-helpers.test.ts +88 -1
- package/src/tests/rbac-e2e-helpers.ts +36 -11
- package/src/tests/script-connections.test.ts +2 -0
- package/src/tests/script-runs-retention.test.ts +212 -0
- package/src/tests/sdk-allowlist.test.ts +39 -0
- package/src/tests/session-source-backfill.test.ts +429 -0
- package/src/tests/session-source-keys.test.ts +236 -0
- package/src/tests/session-source-labels.test.ts +419 -0
- package/src/tests/sessions-detail-batch.test.ts +2 -0
- package/src/tests/sessions-move.test.ts +131 -0
- package/src/tests/sessions-tree.test.ts +299 -2
- package/src/tests/slack-inbound-files.test.ts +103 -23
- package/src/tests/status.test.ts +101 -18
- package/src/tests/tasks-workflow-run-filter.test.ts +146 -0
- package/src/tests/test-net.ts +31 -0
- package/src/tests/transcription.test.ts +8 -0
- package/src/tests/used-by-route.test.ts +11 -0
- package/src/tests/workflow-cascade-cancel.test.ts +172 -0
- package/src/tests/workflow-http-v2.test.ts +131 -0
- package/src/tests/workflow-step-order.test.ts +92 -0
- package/src/tests/workflow-sub-workflow.test.ts +30 -0
- package/src/tools/get-tasks.ts +8 -0
- package/src/tools/kv/kv-read-auth.ts +4 -2
- package/src/tools/task-action.ts +1 -1
- package/src/tools/workflows/get-workflow-run.ts +14 -4
- package/src/types.ts +24 -0
- package/src/utils/company-profile.ts +51 -1
- package/src/utils/credentials.ts +5 -2
- package/src/utils/internal-ai/complete-structured.ts +5 -0
- package/src/utils/internal-ai/credentials.ts +4 -3
- package/src/utils/provider-key-probes.ts +328 -0
- package/src/utils/transcription.ts +4 -1
- package/src/workflows/executors/sub-workflow.ts +8 -1
- package/templates/ai-toolbox.manifest.json +2 -2
- package/templates/skills/researching/content.md +2 -0
- package/templates/skills/swarm-scripts/SKILL.md +1 -0
- package/templates/skills/swarm-scripts/content.md +1 -0
- package/dist/cli-7421jzsw.js +0 -84
- package/dist/cli-e45e4m6b.js +0 -413
- package/dist/cli-zw88zjba.js +0 -307
- package/dist/handlers-wy1dr6ja.js +0 -41
- package/dist/index-nmm79qgr.js +0 -43
- package/dist/lead-sawnyqxk.js +0 -79
- package/dist/render-v2-pjwxvnkw.js +0 -12
- package/dist/worker-v5e5rxj3.js +0 -79
package/src/http/tasks.ts
CHANGED
|
@@ -227,6 +227,8 @@ const listTasks = route({
|
|
|
227
227
|
status: z.string().optional(),
|
|
228
228
|
agentId: z.string().optional(),
|
|
229
229
|
scheduleId: z.string().optional(),
|
|
230
|
+
/** Only tasks of this workflow run (indexed; independent of fleet size). */
|
|
231
|
+
workflowRunId: z.string().uuid().optional(),
|
|
230
232
|
key: AssetKeySchema.optional(),
|
|
231
233
|
keyPrefix: AssetKeySchema.optional(),
|
|
232
234
|
search: z.string().optional(),
|
|
@@ -976,6 +978,7 @@ export async function handleTasks(
|
|
|
976
978
|
status,
|
|
977
979
|
agentId: parsed.query.agentId || undefined,
|
|
978
980
|
scheduleId: parsed.query.scheduleId || undefined,
|
|
981
|
+
workflowRunId: parsed.query.workflowRunId,
|
|
979
982
|
key: parsed.query.key,
|
|
980
983
|
keyPrefix: parsed.query.keyPrefix,
|
|
981
984
|
search: parsed.query.search || undefined,
|
package/src/http/used-by.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { IncomingMessage, ServerResponse } from "node:http";
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { getDbClient, upsertSwarmConfig } from "../be/db";
|
|
4
4
|
import { isTelemetryEnabled, trackRelayed } from "../telemetry";
|
|
5
|
-
import { USER_FUNCTIONS } from "../utils/company-profile";
|
|
5
|
+
import { reportedUserFunction, USER_FUNCTIONS } from "../utils/company-profile";
|
|
6
6
|
import { orgIdentityStatus } from "../utils/org-identity";
|
|
7
7
|
import { normalizeOrgWebsite, TELEMETRY_PROXY_ORIGIN } from "../utils/org-website";
|
|
8
8
|
import { ensureConfigAdmin } from "./config";
|
|
@@ -129,7 +129,12 @@ export async function handleUsedBy(
|
|
|
129
129
|
...(orgDomain ? { org_domain: orgDomain } : {}),
|
|
130
130
|
granted,
|
|
131
131
|
...(granted
|
|
132
|
-
? {
|
|
132
|
+
? {
|
|
133
|
+
contact_email: contactEmail,
|
|
134
|
+
// The proxy rejects a job function its catalog does not list yet.
|
|
135
|
+
contact_function: reportedUserFunction(contactFunction),
|
|
136
|
+
quote,
|
|
137
|
+
}
|
|
133
138
|
: {}),
|
|
134
139
|
changed_at: changedAt,
|
|
135
140
|
}),
|
package/src/http/workflows.ts
CHANGED
|
@@ -23,7 +23,14 @@ import {
|
|
|
23
23
|
type WorkflowIdempotencyClaim,
|
|
24
24
|
workflowRequestFingerprint,
|
|
25
25
|
} from "../be/db/workflow-idempotency";
|
|
26
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
getWorkflowRunParent,
|
|
28
|
+
getWorkflowRunStepsSlimByRunId,
|
|
29
|
+
getWorkflowRunSummary,
|
|
30
|
+
getWorkflowRunTree,
|
|
31
|
+
WORKFLOW_RUN_TREE_MAX_DEPTH,
|
|
32
|
+
WorkflowRunTreeError,
|
|
33
|
+
} from "../be/db/workflow-runs";
|
|
27
34
|
import {
|
|
28
35
|
AssetKeySchema,
|
|
29
36
|
AutomationIntegrationIdSchema,
|
|
@@ -39,6 +46,7 @@ import {
|
|
|
39
46
|
WorkflowRunSchema,
|
|
40
47
|
WorkflowRunStatusSchema,
|
|
41
48
|
WorkflowRunStepSchema,
|
|
49
|
+
WorkflowRunStepSlimSchema,
|
|
42
50
|
WorkflowRunSummarySchema,
|
|
43
51
|
WorkflowSchema,
|
|
44
52
|
WorkflowVersionSchema,
|
|
@@ -109,6 +117,13 @@ const WorkflowRunPageSchema = z.object({
|
|
|
109
117
|
}),
|
|
110
118
|
});
|
|
111
119
|
|
|
120
|
+
/** Mirrors `WorkflowRunTree` in src/be/db/workflow-runs.ts. */
|
|
121
|
+
const WorkflowRunTreeSchema = z.object({
|
|
122
|
+
rootRunId: z.string(),
|
|
123
|
+
runs: z.array(WorkflowRunSummarySchema),
|
|
124
|
+
hasOpenWork: z.boolean(),
|
|
125
|
+
});
|
|
126
|
+
|
|
112
127
|
const SuccessResponseSchema = z.object({ success: z.literal(true) });
|
|
113
128
|
|
|
114
129
|
/** Adds `warnings` to a just-saved workflow when a node in it cannot run yet. */
|
|
@@ -349,22 +364,50 @@ const getWorkflowRunRoute = route({
|
|
|
349
364
|
path: "/api/workflow-runs/{id}",
|
|
350
365
|
pattern: ["api", "workflow-runs", null],
|
|
351
366
|
summary: "Get a workflow run with steps (includes retry columns)",
|
|
367
|
+
description:
|
|
368
|
+
"Returns the run with its `context` and every step with its `input` by default. A step's `input` is a snapshot of the context when the step started, so in runs with loops (polling, `wait`, iterations) the response grows with steps × context size. Pass `fields=slim` to drop `run.context` and `steps[].input`; outputs, errors, diagnostics, retry fields and `parent` stay.",
|
|
352
369
|
tags: ["Workflows"],
|
|
353
370
|
params: z.object({ id: z.string() }),
|
|
371
|
+
query: z.object({
|
|
372
|
+
/** `slim` omits `run.context` and `steps[].input`; default is full. */
|
|
373
|
+
fields: z.enum(["full", "slim"]).optional(),
|
|
374
|
+
}),
|
|
354
375
|
responses: {
|
|
355
376
|
200: {
|
|
356
377
|
description: "Workflow run details with steps including retry info",
|
|
357
|
-
schema: z.
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
378
|
+
schema: z.union([
|
|
379
|
+
z.object({
|
|
380
|
+
run: WorkflowRunSchema,
|
|
381
|
+
steps: z.array(WorkflowRunStepSchema),
|
|
382
|
+
/** Set on a child run: the run and `sub-workflow` step that started it. */
|
|
383
|
+
parent: WorkflowRunParentSchema.optional(),
|
|
384
|
+
}),
|
|
385
|
+
z.object({
|
|
386
|
+
run: WorkflowRunSummarySchema,
|
|
387
|
+
steps: z.array(WorkflowRunStepSlimSchema),
|
|
388
|
+
parent: WorkflowRunParentSchema.optional(),
|
|
389
|
+
}),
|
|
390
|
+
]),
|
|
363
391
|
},
|
|
364
392
|
404: { description: "Run not found" },
|
|
365
393
|
},
|
|
366
394
|
});
|
|
367
395
|
|
|
396
|
+
const getWorkflowRunTreeRoute = route({
|
|
397
|
+
method: "get",
|
|
398
|
+
path: "/api/workflow-runs/{id}/tree",
|
|
399
|
+
pattern: ["api", "workflow-runs", null, "tree"],
|
|
400
|
+
summary: "Get a workflow run and every sub-workflow run below it",
|
|
401
|
+
description: `Follows stored parent links (\`parentStepId\` → step → run) through every attempt of every step, terminal runs included. \`runs\` holds list rows without \`context\`, root first. \`hasOpenWork\` is true while any run in the tree is live, has a pending, running or waiting step, a queued retry, an open task or a pending approval; after a cancel it turns false once the tree has settled. Both come from one read snapshot. The tree is not paginated. Links that form a cycle or nest deeper than ${WORKFLOW_RUN_TREE_MAX_DEPTH} levels return 409.`,
|
|
402
|
+
tags: ["Workflows"],
|
|
403
|
+
params: z.object({ id: z.string() }),
|
|
404
|
+
responses: {
|
|
405
|
+
200: { description: "The run tree", schema: WorkflowRunTreeSchema },
|
|
406
|
+
404: { description: "Run not found" },
|
|
407
|
+
409: { description: "Stored parent links form a cycle or nest past the depth bound" },
|
|
408
|
+
},
|
|
409
|
+
});
|
|
410
|
+
|
|
368
411
|
const retryWorkflowRunRoute = route({
|
|
369
412
|
method: "post",
|
|
370
413
|
path: "/api/workflow-runs/{id}/retry",
|
|
@@ -1014,18 +1057,44 @@ export async function handleWorkflows(
|
|
|
1014
1057
|
const parsed = await getWorkflowRunRoute.parse(req, res, pathSegments, queryParams);
|
|
1015
1058
|
if (!parsed) return true;
|
|
1016
1059
|
// Display view: the scrubbed context and step outputs, never replay state.
|
|
1017
|
-
|
|
1060
|
+
// `fields=slim` skips the context and step-input columns in SQL too.
|
|
1061
|
+
const slim = parsed.query.fields === "slim";
|
|
1062
|
+
const run = slim
|
|
1063
|
+
? await getWorkflowRunSummary(parsed.params.id)
|
|
1064
|
+
: await getWorkflowRun(parsed.params.id, "display");
|
|
1018
1065
|
if (!run) {
|
|
1019
1066
|
res.writeHead(404);
|
|
1020
1067
|
res.end();
|
|
1021
1068
|
return true;
|
|
1022
1069
|
}
|
|
1023
|
-
const steps =
|
|
1070
|
+
const steps = slim
|
|
1071
|
+
? await getWorkflowRunStepsSlimByRunId(parsed.params.id)
|
|
1072
|
+
: await getWorkflowRunStepsByRunId(parsed.params.id, "display");
|
|
1024
1073
|
const parent = run.parentStepId ? await getWorkflowRunParent(run.parentStepId) : null;
|
|
1025
1074
|
getWorkflowRunRoute.respond(res, 200, { run, steps, ...(parent ? { parent } : {}) });
|
|
1026
1075
|
return true;
|
|
1027
1076
|
}
|
|
1028
1077
|
|
|
1078
|
+
if (getWorkflowRunTreeRoute.match(req.method, pathSegments)) {
|
|
1079
|
+
const parsed = await getWorkflowRunTreeRoute.parse(req, res, pathSegments, queryParams);
|
|
1080
|
+
if (!parsed) return true;
|
|
1081
|
+
let tree: Awaited<ReturnType<typeof getWorkflowRunTree>>;
|
|
1082
|
+
try {
|
|
1083
|
+
tree = await getWorkflowRunTree(parsed.params.id);
|
|
1084
|
+
} catch (err) {
|
|
1085
|
+
if (!(err instanceof WorkflowRunTreeError)) throw err;
|
|
1086
|
+
jsonError(res, err.message, 409);
|
|
1087
|
+
return true;
|
|
1088
|
+
}
|
|
1089
|
+
if (!tree) {
|
|
1090
|
+
res.writeHead(404);
|
|
1091
|
+
res.end();
|
|
1092
|
+
return true;
|
|
1093
|
+
}
|
|
1094
|
+
getWorkflowRunTreeRoute.respond(res, 200, tree);
|
|
1095
|
+
return true;
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1029
1098
|
if (retryWorkflowRunRoute.match(req.method, pathSegments)) {
|
|
1030
1099
|
const parsed = await retryWorkflowRunRoute.parse(req, res, pathSegments, queryParams);
|
|
1031
1100
|
if (!parsed) return true;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Adapter, Message, Thread } from "chat";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
import { sessionGroupKey } from "@/assets/key";
|
|
4
|
+
import { sessionSourceKey } from "@/assets/source-key";
|
|
3
5
|
import {
|
|
4
6
|
getAgentById,
|
|
5
7
|
getAgentWorkingOnContextKey,
|
|
@@ -9,6 +11,7 @@ import {
|
|
|
9
11
|
getLeadAgent,
|
|
10
12
|
isExtensionAgent,
|
|
11
13
|
} from "@/be/db";
|
|
14
|
+
import { rememberSessionLabel } from "@/be/db/session-labels";
|
|
12
15
|
import { resolveIdentity } from "@/be/identity";
|
|
13
16
|
import { recordUnmappedIdentity } from "@/be/unmapped-identities";
|
|
14
17
|
import { dispatchPre } from "@/extensions/dispatcher";
|
|
@@ -373,6 +376,20 @@ async function targetFromExtension(
|
|
|
373
376
|
* Runs outside any transaction, so `pre.chat.route` is dispatched here, after
|
|
374
377
|
* the flush and before any task exists.
|
|
375
378
|
*/
|
|
379
|
+
/**
|
|
380
|
+
* The source group label a Telegram or Discord message gives: the DM sender,
|
|
381
|
+
* or a Telegram group title. Slack labels come from the Slack lookup instead.
|
|
382
|
+
*/
|
|
383
|
+
function chatSourceLabel(adapter: string, item: ChatBufferedMessage): string | undefined {
|
|
384
|
+
if (adapter !== "telegram" && adapter !== "discord") return undefined;
|
|
385
|
+
const { facts } = item;
|
|
386
|
+
if (facts.chatType === "dm" || item.isDirectMessage)
|
|
387
|
+
return facts.from ? `DM · ${facts.from}` : undefined;
|
|
388
|
+
if (adapter === "telegram" && (facts.chatType === "group" || facts.chatType === "supergroup"))
|
|
389
|
+
return facts.title || undefined;
|
|
390
|
+
return undefined;
|
|
391
|
+
}
|
|
392
|
+
|
|
376
393
|
export async function flushChatThread(
|
|
377
394
|
threadId: string,
|
|
378
395
|
items: ChatBufferedMessage[],
|
|
@@ -538,6 +555,7 @@ export async function flushChatThread(
|
|
|
538
555
|
const latestActive = await getLatestActiveTaskByContextKey(contextKey, "chat");
|
|
539
556
|
const dependsOn = !immediate && latestActive ? [latestActive.id] : undefined;
|
|
540
557
|
let created = 0;
|
|
558
|
+
let sourceKey: string | null = null;
|
|
541
559
|
for (const match of target.matches) {
|
|
542
560
|
const options: CreateTaskOptions = {
|
|
543
561
|
agentId: match.agent?.id ?? null,
|
|
@@ -564,6 +582,7 @@ export async function flushChatThread(
|
|
|
564
582
|
};
|
|
565
583
|
try {
|
|
566
584
|
const { task, unattached } = await createChatTaskWithFiles(description, options, inbound);
|
|
585
|
+
sourceKey ??= sessionSourceKey(task);
|
|
567
586
|
created++;
|
|
568
587
|
console.log(
|
|
569
588
|
`[chat-sdk] ${threadId}: task ${task.id} for ${match.agent ? `agent ${match.agent.id}` : "no agent (queued)"} (${match.matchedText}, dependsOn: ${dependsOn?.join(", ") ?? "none"}${unattached.length ? `, ${unattached.length} file(s) not attached` : ""})`,
|
|
@@ -578,6 +597,14 @@ export async function flushChatThread(
|
|
|
578
597
|
}
|
|
579
598
|
}
|
|
580
599
|
}
|
|
600
|
+
const label = chatSourceLabel(adapter, requester);
|
|
601
|
+
if (sourceKey && label) {
|
|
602
|
+
// Every message refreshes the label, so a renamed group shows its new title.
|
|
603
|
+
// The error may echo the label, which can hold a person's name: do not log it.
|
|
604
|
+
await rememberSessionLabel(sessionGroupKey(sourceKey), label).catch(() => {
|
|
605
|
+
console.warn("[chat-sdk] Could not save a session source label");
|
|
606
|
+
});
|
|
607
|
+
}
|
|
581
608
|
if (created > 0) {
|
|
582
609
|
await rememberChatThreadRequester(threadId, requester.userId);
|
|
583
610
|
await subscribe(thread);
|
|
@@ -12,8 +12,20 @@ const RESERVED_FAMILIES = new Map([
|
|
|
12
12
|
["worker", "namespace is reserved for worker nudges"],
|
|
13
13
|
// Durable dedupe for SLACK_BLOCK_EXTERNAL_CHANNELS alerts (src/slack/external-channel.ts).
|
|
14
14
|
["slack-external-alert", "namespace is reserved for Slack external channel alerts"],
|
|
15
|
+
// Source group labels (src/be/db/session-labels.ts). Private, see PRIVATE_FAMILIES.
|
|
16
|
+
[
|
|
17
|
+
"session-labels",
|
|
18
|
+
"namespace is reserved for session source labels; GET /api/session-tree returns them",
|
|
19
|
+
],
|
|
15
20
|
]);
|
|
16
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Reserved families that generic KV callers may not read either. Their rows
|
|
24
|
+
* hold data that another route returns only to callers with access (a
|
|
25
|
+
* source label names a private channel or a DM partner).
|
|
26
|
+
*/
|
|
27
|
+
const PRIVATE_FAMILIES = new Set(["session-labels"]);
|
|
28
|
+
|
|
17
29
|
export function isReservedNamespace(namespace: string): boolean {
|
|
18
30
|
return reservedNamespaceError(namespace) !== null;
|
|
19
31
|
}
|
|
@@ -22,6 +34,13 @@ export function reservedNamespaceError(namespace: string): string | null {
|
|
|
22
34
|
return RESERVED_FAMILIES.get(namespace.split(":", 1)[0] ?? "") ?? null;
|
|
23
35
|
}
|
|
24
36
|
|
|
37
|
+
/** The error a generic KV read of a private family gets, or null. */
|
|
38
|
+
export function privateNamespaceError(namespace: string): string | null {
|
|
39
|
+
return PRIVATE_FAMILIES.has(namespace.split(":", 1)[0] ?? "")
|
|
40
|
+
? reservedNamespaceError(namespace)
|
|
41
|
+
: null;
|
|
42
|
+
}
|
|
43
|
+
|
|
25
44
|
export function reservedRoomKeyError(key: string): string | null {
|
|
26
45
|
return key.startsWith("_room/")
|
|
27
46
|
? "room snapshot keys are reserved; use the room endpoints"
|
|
@@ -359,7 +359,7 @@ const copilotTargetProfile: AcpTargetProfile = {
|
|
|
359
359
|
},
|
|
360
360
|
};
|
|
361
361
|
|
|
362
|
-
/** Qwen Code's `--auth-type` choices (0.26.
|
|
362
|
+
/** Qwen Code's `--auth-type` choices (0.26.1). `qwen-oauth` needs a browser, so it is left out. */
|
|
363
363
|
const QWEN_AUTH_TYPES = ["openai", "openai-responses", "anthropic", "gemini", "vertex-ai"] as const;
|
|
364
364
|
|
|
365
365
|
// Qwen Code is a Gemini CLI fork: QWEN_SYSTEM_MD replaces its built-in prompt
|
|
@@ -45,7 +45,7 @@ import type {
|
|
|
45
45
|
* default; the image installs exactly this version and the per-task settings
|
|
46
46
|
* set `amp.updates.mode: "disabled"`. Bump it deliberately, with a live run.
|
|
47
47
|
*/
|
|
48
|
-
export const AMP_PACKAGE = "@ampcode/cli@0.0.
|
|
48
|
+
export const AMP_PACKAGE = "@ampcode/cli@0.0.1792929650-g000512";
|
|
49
49
|
|
|
50
50
|
/** MCP server name. Amp exposes its tools as `agent_swarm` / `store_progress` (dashes become underscores). */
|
|
51
51
|
const AMP_MCP_SERVER_NAME = "agent-swarm";
|
|
@@ -1445,7 +1445,11 @@ export class ClaudeAdapter implements ProviderAdapter {
|
|
|
1445
1445
|
// (headless) or block on the trust dialog (tmux), so seed trust for every session.
|
|
1446
1446
|
if (isEnvFlagEnabled("CLAUDE_TRUST_PRESEED", true, sourceEnv)) {
|
|
1447
1447
|
try {
|
|
1448
|
-
|
|
1448
|
+
// Seed the ~/.claude.json the CLI reads: its HOME comes from the session env.
|
|
1449
|
+
await preseedClaudeTrustDialog(
|
|
1450
|
+
await resolveClaudeTrustDirs(config.cwd),
|
|
1451
|
+
sourceEnv.HOME || undefined,
|
|
1452
|
+
);
|
|
1449
1453
|
} catch (err) {
|
|
1450
1454
|
console.warn(
|
|
1451
1455
|
`\x1b[33m[claude]\x1b[0m ${scrubSecrets(`Failed to pre-seed trust for ${config.cwd}: ${err}`)}`,
|
|
@@ -64,6 +64,7 @@ import {
|
|
|
64
64
|
computeContextUsedUnified,
|
|
65
65
|
getContextWindowSize,
|
|
66
66
|
} from "../utils/context-window";
|
|
67
|
+
import { selectCredential } from "../utils/credentials";
|
|
67
68
|
import { scrubSecrets } from "../utils/secret-scrubber";
|
|
68
69
|
import { computeClaudeManagedCostUsd } from "./claude-managed-models";
|
|
69
70
|
import { getRuntimeFeePerHour } from "./claude-managed-pricing";
|
|
@@ -862,7 +863,11 @@ export class ClaudeManagedAdapter implements ProviderAdapter {
|
|
|
862
863
|
);
|
|
863
864
|
}
|
|
864
865
|
|
|
865
|
-
this.apiKey =
|
|
866
|
+
this.apiKey = selectCredential(
|
|
867
|
+
process.env.ANTHROPIC_API_KEY as string,
|
|
868
|
+
undefined,
|
|
869
|
+
"ANTHROPIC_API_KEY",
|
|
870
|
+
).selected;
|
|
866
871
|
this.agentId = process.env.MANAGED_AGENT_ID as string;
|
|
867
872
|
this.environmentId = process.env.MANAGED_ENVIRONMENT_ID as string;
|
|
868
873
|
|
|
@@ -879,6 +884,14 @@ export class ClaudeManagedAdapter implements ProviderAdapter {
|
|
|
879
884
|
}
|
|
880
885
|
|
|
881
886
|
async createSession(config: ProviderSessionConfig): Promise<ProviderSession> {
|
|
887
|
+
// Keep the runner's task selection instead of the container's pool.
|
|
888
|
+
const taskKey = config.env?.ANTHROPIC_API_KEY;
|
|
889
|
+
const client =
|
|
890
|
+
taskKey && this.client instanceof Anthropic
|
|
891
|
+
? this.client.withOptions({
|
|
892
|
+
apiKey: selectCredential(taskKey, undefined, "ANTHROPIC_API_KEY").selected,
|
|
893
|
+
})
|
|
894
|
+
: this.client;
|
|
882
895
|
// Native resume is deprecated. Follow-up continuity is delivered via the
|
|
883
896
|
// context preamble (see src/commands/context-preamble.ts). Any stray
|
|
884
897
|
// resumeSessionId is logged and ignored — we always create a fresh session.
|
|
@@ -942,16 +955,10 @@ export class ClaudeManagedAdapter implements ProviderAdapter {
|
|
|
942
955
|
if (vaultIds.length > 0) {
|
|
943
956
|
createParams.vault_ids = Array.from(new Set(vaultIds));
|
|
944
957
|
}
|
|
945
|
-
const created = await Promise.resolve(
|
|
958
|
+
const created = await Promise.resolve(client.beta.sessions.create(createParams));
|
|
946
959
|
const sessionId = created.id;
|
|
947
960
|
|
|
948
|
-
return new ClaudeManagedSession(
|
|
949
|
-
this.client,
|
|
950
|
-
sessionId,
|
|
951
|
-
config,
|
|
952
|
-
userMessageContent,
|
|
953
|
-
seenEventIds,
|
|
954
|
-
);
|
|
961
|
+
return new ClaudeManagedSession(client, sessionId, config, userMessageContent, seenEventIds);
|
|
955
962
|
}
|
|
956
963
|
|
|
957
964
|
/**
|
|
@@ -30,6 +30,13 @@
|
|
|
30
30
|
|
|
31
31
|
import { existsSync as nodeExistsSync } from "node:fs";
|
|
32
32
|
import { join } from "node:path";
|
|
33
|
+
import {
|
|
34
|
+
CODEX_GATEWAY_API_KEY,
|
|
35
|
+
deriveDefaultRoute,
|
|
36
|
+
type ModelRoute,
|
|
37
|
+
routeCredentialStatus,
|
|
38
|
+
routeUnsetEnv,
|
|
39
|
+
} from "@desplega/model-routing";
|
|
33
40
|
import { buildRatingsFromLlm, fetchRetrievalsForTask, postRatings } from "../be/memory/raters/llm";
|
|
34
41
|
import { contextBoundNoteThreshold, createContextBoundNote } from "../hooks/context-bound-note";
|
|
35
42
|
import { getApiKey } from "../utils/api-key";
|
|
@@ -38,6 +45,7 @@ import {
|
|
|
38
45
|
clampContextPercent,
|
|
39
46
|
computeContextUsedUnified,
|
|
40
47
|
} from "../utils/context-window";
|
|
48
|
+
import { selectCredential } from "../utils/credentials";
|
|
41
49
|
import { isEnvFlagEnabled, isSessionSummarySkipped } from "../utils/env-flag";
|
|
42
50
|
import { SessionErrorTracker } from "../utils/error-tracker";
|
|
43
51
|
import { summarizeSession as runSummarize } from "../utils/internal-ai";
|
|
@@ -82,6 +90,32 @@ import type {
|
|
|
82
90
|
|
|
83
91
|
type CodexConfig = Record<string, CodexConfigValue | undefined>;
|
|
84
92
|
|
|
93
|
+
/** `model_provider` id of the generated gateway block. */
|
|
94
|
+
const CODEX_GATEWAY_PROVIDER_ID = "swarm-gateway";
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Config overrides that send Codex through the gateway route. Codex 0.164
|
|
98
|
+
* ignores `OPENAI_BASE_URL` and env keys for its built-in `openai` provider, so
|
|
99
|
+
* the gateway needs its own provider block. Verified on 0.164 against a local
|
|
100
|
+
* gateway: Codex sends `Authorization: Bearer $CODEX_GATEWAY_API_KEY` to
|
|
101
|
+
* `<base_url>/responses` and never the auth.json OAuth token. `wire_api`
|
|
102
|
+
* defaults to `responses` (`chat` is rejected); it is set to state intent.
|
|
103
|
+
*/
|
|
104
|
+
export function codexGatewayConfig(route: ModelRoute): CodexConfig {
|
|
105
|
+
return {
|
|
106
|
+
model_provider: CODEX_GATEWAY_PROVIDER_ID,
|
|
107
|
+
model_providers: {
|
|
108
|
+
[CODEX_GATEWAY_PROVIDER_ID]: {
|
|
109
|
+
name: "Swarm gateway",
|
|
110
|
+
base_url: route.baseUrl,
|
|
111
|
+
env_key: CODEX_GATEWAY_API_KEY,
|
|
112
|
+
wire_api: "responses",
|
|
113
|
+
requires_openai_auth: false,
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
85
119
|
/** Plugin id the worker image installs (`codex plugin add context-mode@context-mode`). */
|
|
86
120
|
const CONTEXT_MODE_CODEX_PLUGIN = "context-mode@context-mode";
|
|
87
121
|
|
|
@@ -187,7 +221,10 @@ export type CodexThreadFactory = (options: {
|
|
|
187
221
|
}) => Promise<CodexThread> | CodexThread;
|
|
188
222
|
|
|
189
223
|
/**
|
|
190
|
-
*
|
|
224
|
+
* A gateway route (`CODEX_GATEWAY_BASE_URL` + `CODEX_GATEWAY_API_KEY`) wins
|
|
225
|
+
* and alone decides readiness: a gateway URL without its key is not ready,
|
|
226
|
+
* whatever OAuth or auth.json is present. Otherwise Codex satisfies its
|
|
227
|
+
* credential requirement by ANY of:
|
|
191
228
|
* 1. `~/.codex/auth.json` already exists on disk (the canonical state once
|
|
192
229
|
* `codex login` has run).
|
|
193
230
|
* 2. `OPENAI_API_KEY` is set — the entrypoint will run
|
|
@@ -204,6 +241,13 @@ export function checkCodexCredentials(
|
|
|
204
241
|
env: Record<string, string | undefined>,
|
|
205
242
|
opts: CredCheckOptions = {},
|
|
206
243
|
): CredStatus {
|
|
244
|
+
const gateway = deriveDefaultRoute("codex", env);
|
|
245
|
+
if (gateway) {
|
|
246
|
+
const status = routeCredentialStatus(gateway, env);
|
|
247
|
+
return status.ready
|
|
248
|
+
? { ready: true, missing: [], satisfiedBy: "env", hint: status.hint }
|
|
249
|
+
: { ready: false, missing: status.missing, hint: status.hint };
|
|
250
|
+
}
|
|
207
251
|
const homeDir = opts.homeDir ?? env.HOME ?? "/root";
|
|
208
252
|
const existsSync = opts.fs?.existsSync ?? nodeExistsSync;
|
|
209
253
|
const authFile = `${homeDir}/.codex/auth.json`;
|
|
@@ -1965,14 +2009,21 @@ export async function createInProcessCodexSession(
|
|
|
1965
2009
|
preSessionEvents.push(event);
|
|
1966
2010
|
};
|
|
1967
2011
|
|
|
1968
|
-
const
|
|
2012
|
+
const routeEnv = config.env ?? process.env;
|
|
2013
|
+
const gateway = deriveDefaultRoute("codex", routeEnv);
|
|
2014
|
+
const mergedConfig = {
|
|
2015
|
+
...(await buildCodexConfig(config, resolvedModel, bufferedEmit)),
|
|
2016
|
+
...(gateway ? codexGatewayConfig(gateway) : {}),
|
|
2017
|
+
};
|
|
1969
2018
|
|
|
1970
2019
|
// Auth resolution. `codex_oauth` (in the swarm config store) wins over
|
|
1971
2020
|
// `OPENAI_API_KEY` so users can keep an OpenAI key set for embeddings
|
|
1972
2021
|
// without it shadowing their ChatGPT login. The entrypoint already runs
|
|
1973
2022
|
// this same precedence at boot — this block handles local dev (where
|
|
1974
2023
|
// the entrypoint didn't run) and any case where auth.json is stale.
|
|
1975
|
-
|
|
2024
|
+
// A gateway route skips it: no OAuth is restored for a session whose traffic
|
|
2025
|
+
// goes to the gateway.
|
|
2026
|
+
const authMode = gateway ? null : await resolveCodexAuthMode(config, bufferedEmit);
|
|
1976
2027
|
|
|
1977
2028
|
// The app-server receives an explicit environment. Construct a
|
|
1978
2029
|
// minimal env explicitly so the spawned Codex CLI can find its binary
|
|
@@ -1999,7 +2050,14 @@ export async function createInProcessCodexSession(
|
|
|
1999
2050
|
...buildOtelTraceparentEnv(config.env ?? process.env),
|
|
2000
2051
|
SWARM_CODEX_APP_SERVER: "1",
|
|
2001
2052
|
};
|
|
2002
|
-
if (
|
|
2053
|
+
if (gateway) {
|
|
2054
|
+
for (const key of routeUnsetEnv("codex", gateway)) delete env[key];
|
|
2055
|
+
const gatewayKey = routeEnv[CODEX_GATEWAY_API_KEY];
|
|
2056
|
+
if (gatewayKey) env[CODEX_GATEWAY_API_KEY] = gatewayKey;
|
|
2057
|
+
} else if (authMode === "chatgpt") delete env.OPENAI_API_KEY;
|
|
2058
|
+
else if (env.OPENAI_API_KEY) {
|
|
2059
|
+
env.OPENAI_API_KEY = selectCredential(env.OPENAI_API_KEY, undefined, "OPENAI_API_KEY").selected;
|
|
2060
|
+
}
|
|
2003
2061
|
|
|
2004
2062
|
const codexPathOverride = process.env.CODEX_PATH_OVERRIDE;
|
|
2005
2063
|
|
|
@@ -2151,6 +2209,11 @@ class CodexSubprocessSession implements ProviderSession {
|
|
|
2151
2209
|
};
|
|
2152
2210
|
|
|
2153
2211
|
const apiKey = getApiKey();
|
|
2212
|
+
const providerKeys: Record<string, string> = {};
|
|
2213
|
+
for (const keyVar of ["OPENAI_API_KEY", "OPENROUTER_API_KEY", "ANTHROPIC_API_KEY"]) {
|
|
2214
|
+
const value = config.env?.[keyVar] ?? process.env[keyVar];
|
|
2215
|
+
if (value) providerKeys[keyVar] = selectCredential(value, undefined, keyVar).selected;
|
|
2216
|
+
}
|
|
2154
2217
|
|
|
2155
2218
|
this.proc = registerProcessGroup(
|
|
2156
2219
|
Bun.spawn(argv, {
|
|
@@ -2168,13 +2231,7 @@ class CodexSubprocessSession implements ProviderSession {
|
|
|
2168
2231
|
...(process.env.MCP_BASE_URL ? { MCP_BASE_URL: process.env.MCP_BASE_URL } : {}),
|
|
2169
2232
|
...(apiKey ? { AGENT_SWARM_API_KEY: apiKey, API_KEY: apiKey } : {}),
|
|
2170
2233
|
// Embedding / summarization paths read these:
|
|
2171
|
-
...
|
|
2172
|
-
...(process.env.OPENROUTER_API_KEY
|
|
2173
|
-
? { OPENROUTER_API_KEY: process.env.OPENROUTER_API_KEY }
|
|
2174
|
-
: {}),
|
|
2175
|
-
...(process.env.ANTHROPIC_API_KEY
|
|
2176
|
-
? { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY }
|
|
2177
|
-
: {}),
|
|
2234
|
+
...providerKeys,
|
|
2178
2235
|
...(process.env.CODEX_PATH_OVERRIDE
|
|
2179
2236
|
? { CODEX_PATH_OVERRIDE: process.env.CODEX_PATH_OVERRIDE }
|
|
2180
2237
|
: {}),
|
|
@@ -2475,6 +2532,9 @@ export class CodexAdapter implements ProviderAdapter {
|
|
|
2475
2532
|
}
|
|
2476
2533
|
|
|
2477
2534
|
async createSession(config: ProviderSessionConfig): Promise<ProviderSession> {
|
|
2535
|
+
if (deriveDefaultRoute("codex", config.env ?? process.env)) {
|
|
2536
|
+
console.log("\x1b[2m[codex]\x1b[0m Using credential: gateway");
|
|
2537
|
+
}
|
|
2478
2538
|
if (this.bypassSubprocess) {
|
|
2479
2539
|
return createInProcessCodexSession(config, {
|
|
2480
2540
|
skillsDir: this.skillsDir,
|
|
@@ -91,8 +91,9 @@ async function executeScheduleScript(schedule: ScheduledTask): Promise<void> {
|
|
|
91
91
|
agentId,
|
|
92
92
|
scriptName: schedule.scriptName,
|
|
93
93
|
// A pointer, not a copy: script schedules fire as often as every minute and
|
|
94
|
-
// script_runs
|
|
95
|
-
// would grow the table by tens of MB a
|
|
94
|
+
// script_runs retention (SCRIPT_RUNS_RETENTION_DAYS) is off by default, so
|
|
95
|
+
// copying the source on every fire would grow the table by tens of MB a
|
|
96
|
+
// day. script_versions keeps the text.
|
|
96
97
|
source: `// Scheduled run of '${script.name}' v${script.version} (global, contentHash ${script.contentHash}) by schedule '${schedule.name}'.\n// Full source: script_versions row for this version.\n`,
|
|
97
98
|
args,
|
|
98
99
|
startedAt: new Date().toISOString(),
|
|
@@ -319,7 +319,13 @@ function bridgeRequestFor(name: string, args: unknown): BridgeRequest | null {
|
|
|
319
319
|
case "workflow_getRun": {
|
|
320
320
|
const id = typeof body.id === "string" ? body.id : undefined;
|
|
321
321
|
if (!id) throw new Error("workflow_getRun requires string `id`");
|
|
322
|
-
|
|
322
|
+
if (body.fields !== undefined && body.fields !== "full" && body.fields !== "slim") {
|
|
323
|
+
throw new Error('workflow_getRun `fields` must be "full" or "slim"');
|
|
324
|
+
}
|
|
325
|
+
return {
|
|
326
|
+
method: "GET",
|
|
327
|
+
path: appendQuery(`/api/workflow-runs/${encodeURIComponent(id)}`, { fields: body.fields }),
|
|
328
|
+
};
|
|
323
329
|
}
|
|
324
330
|
case "workflow_delete": {
|
|
325
331
|
const id = typeof body.id === "string" ? body.id : undefined;
|
|
@@ -378,7 +378,7 @@ declare module "swarm-sdk" {
|
|
|
378
378
|
limit?: number;
|
|
379
379
|
offset?: number;
|
|
380
380
|
}): Promise<unknown>;
|
|
381
|
-
workflow_getRun(args: { id: string }): Promise<unknown>;
|
|
381
|
+
workflow_getRun(args: { id: string; fields?: "full" | "slim" }): Promise<unknown>;
|
|
382
382
|
// --- prompt templates ---
|
|
383
383
|
prompt_list(args?: {
|
|
384
384
|
eventType?: string;
|
|
@@ -9,16 +9,16 @@ declare module "swarm-extension" {
|
|
|
9
9
|
| "schedule"
|
|
10
10
|
| "slack"
|
|
11
11
|
| "agentmail"
|
|
12
|
-
| "mcp"
|
|
13
|
-
| "api"
|
|
14
|
-
| "ui"
|
|
15
12
|
| "github"
|
|
16
13
|
| "gitlab"
|
|
17
14
|
| "azure-devops"
|
|
18
15
|
| "bitbucket"
|
|
19
|
-
| "system"
|
|
20
16
|
| "linear"
|
|
21
17
|
| "jira"
|
|
18
|
+
| "mcp"
|
|
19
|
+
| "api"
|
|
20
|
+
| "ui"
|
|
21
|
+
| "system"
|
|
22
22
|
| "comb"
|
|
23
23
|
| "chat"
|
|
24
24
|
| undefined;
|
|
@@ -127,16 +127,16 @@ declare module "swarm-extension" {
|
|
|
127
127
|
| "schedule"
|
|
128
128
|
| "slack"
|
|
129
129
|
| "agentmail"
|
|
130
|
-
| "mcp"
|
|
131
|
-
| "api"
|
|
132
|
-
| "ui"
|
|
133
130
|
| "github"
|
|
134
131
|
| "gitlab"
|
|
135
132
|
| "azure-devops"
|
|
136
133
|
| "bitbucket"
|
|
137
|
-
| "system"
|
|
138
134
|
| "linear"
|
|
139
135
|
| "jira"
|
|
136
|
+
| "mcp"
|
|
137
|
+
| "api"
|
|
138
|
+
| "ui"
|
|
139
|
+
| "system"
|
|
140
140
|
| "comb"
|
|
141
141
|
| "chat";
|
|
142
142
|
tags: string[];
|
|
@@ -401,6 +401,15 @@ declare module "swarm-extension" {
|
|
|
401
401
|
description: string;
|
|
402
402
|
origin: TaskCreateOrigin;
|
|
403
403
|
requestInfo?: RequestInfo;
|
|
404
|
+
/** Slack ingress metadata; not persisted or writable through modify. */
|
|
405
|
+
slack?: {
|
|
406
|
+
trigger: "mention" | "thread-buffer";
|
|
407
|
+
messages: {
|
|
408
|
+
ts: string;
|
|
409
|
+
userId: string;
|
|
410
|
+
text: string;
|
|
411
|
+
}[];
|
|
412
|
+
};
|
|
404
413
|
}
|
|
405
414
|
/** A pre.task.create hook blocked a task before it was created. */
|
|
406
415
|
export interface TaskBlockedEvent {
|
|
@@ -360,7 +360,7 @@ declare module "swarm-sdk" {
|
|
|
360
360
|
limit?: number;
|
|
361
361
|
offset?: number;
|
|
362
362
|
}): Promise<unknown>;
|
|
363
|
-
workflow_getRun(args: { id: string }): Promise<unknown>;
|
|
363
|
+
workflow_getRun(args: { id: string; fields?: "full" | "slim" }): Promise<unknown>;
|
|
364
364
|
// --- prompt templates ---
|
|
365
365
|
prompt_list(args?: {
|
|
366
366
|
eventType?: string;
|