@desplega.ai/agent-swarm 2.4.3 → 2.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{acp-adapter-1885dpr7.js → acp-adapter-2wdkktv6.js} +1 -2
- package/dist/{actions-pn76n32q.js → actions-c40ebcm4.js} +18 -18
- package/dist/{amp-adapter-af84rx1d.js → amp-adapter-wb67m95z.js} +2 -2
- package/dist/{app-6sv8mhzm.js → app-353vre8g.js} +3 -3
- package/dist/{assistant-sc2tf825.js → assistant-sj1njh23.js} +21 -21
- package/dist/{boot-reembed-y3m0ydzj.js → boot-reembed-b9c3az3c.js} +1 -1
- package/dist/{boot-reembed-gvxjs2py.js → boot-reembed-qdkvxeem.js} +1 -1
- package/dist/{boot-scrub-sweep-1j9mk05f.js → boot-scrub-sweep-m3wh8eks.js} +2 -2
- package/dist/{boot-seeds-37sp626b.js → boot-seeds-j2273s54.js} +4 -4
- package/dist/{claude-adapter-rp0jtnwr.js → claude-adapter-m7q0a085.js} +2 -2
- package/dist/{claude-managed-adapter-h2y889ge.js → claude-managed-adapter-5ptb6tzs.js} +2 -2
- package/dist/{claude-managed-setup-rdt248k7.js → claude-managed-setup-smrqk5j5.js} +3 -3
- package/dist/{claude-sdk-session-53rcw5we.js → claude-sdk-session-38xnz21e.js} +8284 -8267
- package/dist/{cli-6eyncg0y.js → cli-018r4jq6.js} +34 -6
- package/dist/{cli-sds5zzs8.js → cli-1f3qzw6y.js} +78 -12
- package/dist/{cli-f0p0f6ja.js → cli-1sp861s4.js} +7 -7
- package/dist/{cli-dm8p2dpf.js → cli-1syn2xy1.js} +10 -10
- package/dist/{cli-tkf4x6ha.js → cli-37j04k05.js} +11 -11
- package/dist/{cli-v87dr6e3.js → cli-3a45zcgm.js} +1 -1
- package/dist/{cli-1n9gdg56.js → cli-43x64hv3.js} +4 -4
- package/dist/{cli-p0qerd2r.js → cli-4zfqgjc5.js} +2 -2
- package/dist/{cli-aa3tb29r.js → cli-7c9qs530.js} +1 -1
- package/dist/{cli-9qtjfd60.js → cli-848hxdwj.js} +1 -1
- package/dist/{cli-1xsraagq.js → cli-94gwyg7m.js} +8 -8
- package/dist/{cli-0dxxwfkt.js → cli-9hstj09h.js} +17 -14
- package/dist/{cli-1012xb7j.js → cli-9yqgm9nd.js} +22 -22
- package/dist/{cli-pygdsgh8.js → cli-a92r1127.js} +1 -1
- package/dist/{cli-8vverzf7.js → cli-ba8ne1es.js} +5 -0
- package/dist/{cli-bxrqvpg5.js → cli-be2161h1.js} +7 -7
- package/dist/{cli-npfe9t1s.js → cli-bnes4z6b.js} +2 -2
- package/dist/{cli-aypbg9r2.js → cli-cxxe61f6.js} +1 -1
- package/dist/{cli-vq9gqarq.js → cli-dk44dxec.js} +1 -1
- package/dist/{cli-836ehxmt.js → cli-eww120g8.js} +3 -2
- package/dist/{cli-a0kcty51.js → cli-f01h25yt.js} +1 -1
- package/dist/{cli-mzkwkbdy.js → cli-f0g3pgvf.js} +1 -1
- package/dist/{cli-1ma335fz.js → cli-ftc1g5tj.js} +2 -2
- package/dist/{cli-4yef8ghv.js → cli-fv5hepyy.js} +3 -3
- package/dist/{cli-58vwn100.js → cli-g35m2xwm.js} +4 -4
- package/dist/{cli-qje9k2nh.js → cli-g9ypd5en.js} +12 -2
- package/dist/{cli-gx0j2khs.js → cli-j99azg3g.js} +3 -3
- package/dist/{cli-er83cjbn.js → cli-k8g16gz3.js} +416 -116
- package/dist/{cli-qp2m4btv.js → cli-kpw04va0.js} +2 -2
- package/dist/{cli-8y99kfey.js → cli-ms85309d.js} +33 -15
- package/dist/{cli-kgnkyabk.js → cli-n72rg53p.js} +1555 -645
- package/dist/{cli-e4d78xsv.js → cli-p14m2cnp.js} +1 -1
- package/dist/{cli-1eszr343.js → cli-qfxc84gh.js} +1 -1
- package/dist/{cli-wk28hzqn.js → cli-qwhy2qma.js} +1 -1
- package/dist/{cli-73ezfhha.js → cli-st8aw1m6.js} +228 -11
- package/dist/{cli-zvbb4n0e.js → cli-tw4p90jb.js} +92 -192
- package/dist/{cli-038fga5k.js → cli-v0yrfmdh.js} +148 -183
- package/dist/{cli-6aen3ezb.js → cli-v8fjakwf.js} +1 -1
- package/dist/{cli-99jez72r.js → cli-w9etnnxk.js} +6 -1
- package/dist/{cli-vcgscaan.js → cli-wt0jf9hm.js} +217 -80
- package/dist/{cli-s9rr4gr2.js → cli-xpa64rek.js} +1065 -305
- package/dist/{cli-h0mgxann.js → cli-z7d29rw9.js} +2 -2
- package/dist/cli.js +45 -20
- package/dist/{codex-adapter-2zrmab9b.js → codex-adapter-tn6k5mkg.js} +1 -1
- package/dist/{codex-session-runner-kbkz62vc.js → codex-session-runner-7vjt7jbw.js} +1 -1
- package/dist/{commands-hd574th6.js → commands-t7rz9146.js} +2 -2
- package/dist/{controller-pz5mcfg4.js → controller-m2jasma5.js} +2 -2
- package/dist/{controllers-connect-5rgq2hfk.js → controllers-connect-9ftpex99.js} +19 -19
- package/dist/{cursor-adapter-mgaprq0j.js → cursor-adapter-mjv79e4z.js} +1 -1
- package/dist/{db-6nf1207q.js → db-6sfrn9g3.js} +1 -1
- package/dist/{db-h06dxp05.js → db-rn673r06.js} +3 -3
- package/dist/{dispatcher-zthpy4m1.js → dispatcher-c155xz0p.js} +17 -17
- package/dist/{dsh-adapter-64dhw0j7.js → dsh-adapter-3mmszc1x.js} +1 -1
- package/dist/{external-channel-x01t7ke6.js → external-channel-35k6tkv8.js} +2 -2
- package/dist/{grok-adapter-h21jv594.js → grok-adapter-tfrq7tg1.js} +2 -3
- package/dist/handlers-7gw64dxw.js +39 -0
- package/dist/{heartbeat-zzfksckz.js → heartbeat-dyg4npkp.js} +20 -20
- package/dist/{hook-z4zhzj1f.js → hook-drspbwpe.js} +1 -1
- package/dist/{hook-3xfqhh2s.js → hook-x26b31bg.js} +1 -1
- package/dist/{http-q813tmya.js → http-pk972xyw.js} +571 -294
- package/dist/{index-va3y63es.js → index-6srwvd5b.js} +1 -2
- package/dist/{index-x8xbyn1t.js → index-arytgj5q.js} +1 -1
- package/dist/{index-wbbs14c5.js → index-bgdyvcnv.js} +17 -17
- package/dist/{index-s98037v0.js → index-cbxkmfc5.js} +1 -2
- package/dist/{index-c4ykd0f1.js → index-dr94zbnh.js} +13348 -11611
- package/dist/{index-m0a4ydqj.js → index-gabbcdn2.js} +17 -17
- package/dist/{index-220tk9bw.js → index-jwxkkex2.js} +139 -76
- package/dist/index-tfb26zhy.js +41 -0
- package/dist/{keepalive-y5t1my7m.js → keepalive-7yrng7px.js} +3 -3
- package/dist/{lead-2xwtq66b.js → lead-7e02z839.js} +29 -30
- package/dist/{maintenance-ybfsaedv.js → maintenance-e6cemdqt.js} +1 -1
- package/dist/{node-3v3f08f7.js → node-de6akczr.js} +10 -9
- package/dist/{oauth-refresh-sweep-909jmn12.js → oauth-refresh-sweep-yw3xdbcj.js} +2 -2
- package/dist/{onboard-xn6fkkys.js → onboard-0a9y5yrc.js} +2 -2
- package/dist/{otel-impl-e6mn0z13.js → otel-impl-trjpkfb7.js} +1 -1
- package/dist/{pricing-refresh-ygd362ep.js → pricing-refresh-d2b5my0y.js} +3 -3
- package/dist/{rbac-roles-mb470p4e.js → rbac-roles-hey3yv9d.js} +2 -2
- package/dist/{rbac-roles-c9axvfnz.js → rbac-roles-nxh5ahwk.js} +2 -2
- package/dist/{registry-rxw10xzg.js → registry-ajhexe44.js} +1 -1
- package/dist/{render-v2-g0306nh1.js → render-v2-rr3p2atg.js} +3 -3
- package/dist/{resume-v315hnq6.js → resume-2efkf1s1.js} +5 -5
- package/dist/{session-access-2zg285a1.js → session-access-s2mttxpw.js} +6 -4
- package/dist/{setup-a4mtf02k.js → setup-vypma5yt.js} +1 -1
- package/dist/{work-objects-9fr0fgtn.js → work-objects-rvhckdkp.js} +20 -20
- package/dist/{worker-qae22jeb.js → worker-5snytpbd.js} +29 -30
- package/dist/worker-token-xf11yyds.js +136 -0
- package/openapi.json +303 -13
- package/package.json +8 -8
- package/src/apps/action-runner.ts +4 -0
- package/src/apps/catalog.generated.json +209 -4
- package/src/apps/page-validator.ts +21 -3
- package/src/be/chunking.ts +42 -9
- package/src/be/db/tasks/draft-text.ts +15 -0
- package/src/be/db/tasks/read.ts +14 -1
- package/src/be/db.ts +5 -1
- package/src/be/memory/index-content.ts +36 -17
- package/src/be/memory/providers/openai-embedding.ts +115 -61
- package/src/be/memory/providers/sqlite-store.ts +69 -23
- package/src/be/memory/reranker.ts +31 -1
- package/src/be/memory/search-candidates.ts +47 -0
- package/src/be/memory/types.ts +14 -0
- package/src/be/migrations/232_agent_session_tokens.sql +41 -0
- package/src/be/scripts/typecheck.ts +2 -0
- package/src/be/seed-scripts/catalog/heartbeat-jev-gate.ts +116 -55
- package/src/be/seed-scripts/index.ts +2 -2
- package/src/be/swarm-config-guard.ts +40 -1
- package/src/be/task-attachment-store.ts +30 -0
- package/src/be/users.ts +169 -12
- package/src/cli.tsx +24 -0
- package/src/commands/worker-token.ts +164 -0
- package/src/extensions/catalog.generated.json +4 -4
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/extensions/contract.ts +7 -0
- package/src/fs/provider.ts +13 -1
- package/src/heartbeat/heartbeat.ts +31 -11
- package/src/http/apps.ts +43 -5
- package/src/http/codex-oauth-keep-warm.ts +27 -9
- package/src/http/config.ts +5 -3
- package/src/http/core.ts +2 -0
- package/src/http/fs.ts +54 -34
- package/src/http/mcp-body.ts +37 -0
- package/src/http/mcp-user.ts +3 -5
- package/src/http/mcp.ts +6 -7
- package/src/http/memory.ts +26 -15
- package/src/http/page-proxy.ts +61 -5
- package/src/http/pages-public.ts +27 -44
- package/src/http/pages.ts +4 -4
- package/src/http/script-runs.ts +2 -0
- package/src/http/session-access.ts +51 -2
- package/src/http/sessions.ts +249 -10
- package/src/http/tasks.ts +4 -32
- package/src/http/users.ts +12 -1
- package/src/integrations/chat-sdk/adapters.ts +7 -3
- package/src/integrations/chat-sdk/attachments.ts +90 -12
- package/src/integrations/chat-sdk/facts.ts +120 -0
- package/src/integrations/chat-sdk/inbound.ts +156 -8
- package/src/integrations/chat-sdk/limits.ts +24 -0
- package/src/integrations/chat-sdk/outbound-files.ts +186 -0
- package/src/integrations/chat-sdk/outbound.ts +234 -4
- package/src/integrations/chat-sdk/relay.ts +4 -1
- package/src/integrations/chat-sdk/router.ts +28 -2
- package/src/integrations/chat-sdk/steering.ts +9 -0
- package/src/integrations/chat-sdk/templates.ts +14 -0
- package/src/integrations/chat-sdk/thread-buffer.ts +4 -0
- package/src/mcp-limits.ts +20 -0
- package/src/pages/browser-sdk.ts +8 -3
- package/src/pages/feedback-overlay.ts +1 -1
- package/src/providers/acp-adapter.ts +33 -13
- package/src/providers/acp-swarm-events.ts +1 -1
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/codex-adapter.ts +106 -119
- package/src/providers/codex-agents-md.ts +35 -229
- package/src/providers/codex-oauth/storage.ts +1 -1
- package/src/providers/cursor-adapter.ts +1 -1
- package/src/rbac/legacy-policy.ts +3 -1
- package/src/rbac/permissions.ts +4 -0
- package/src/realtime/transport.ts +1 -2
- package/src/script-workflows/workflow-ctx.ts +1 -0
- package/src/scripts-runtime/types/stdlib.d.ts +2 -0
- package/src/scripts-runtime/types/swarm-extension.d.ts +8 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +2 -0
- package/src/server-user.ts +2 -0
- package/src/server.ts +2 -0
- package/src/slack/assistant.ts +2 -2
- package/src/slack/files.ts +2 -0
- package/src/slack/handlers.ts +4 -4
- package/src/slack/inbound-files.ts +39 -6
- package/src/slack/thread-buffer.ts +2 -1
- package/src/tasks/task-terminal-effects.ts +21 -17
- package/src/tests/acp-adapter.test.ts +10 -23
- package/src/tests/acp-fake-agent.ts +36 -0
- package/src/tests/acp-swarm-events.test.ts +1 -1
- package/src/tests/agent-session-tokens.test.ts +452 -0
- package/src/tests/apps-action-parent-task.test.ts +295 -0
- package/src/tests/apps-card-grid.test.ts +197 -0
- package/src/tests/apps-catalog-additions.test.ts +120 -0
- package/src/tests/apps-tree.test.ts +129 -0
- package/src/tests/chat-sdk-attachments-reply.test.ts +52 -0
- package/src/tests/chat-sdk-config.test.ts +11 -0
- package/src/tests/chat-sdk-facts.test.ts +23 -0
- package/src/tests/chat-sdk-inbound.test.ts +558 -4
- package/src/tests/chat-sdk-outbound-files.test.ts +652 -0
- package/src/tests/codex-adapter.test.ts +167 -242
- package/src/tests/codex-oauth-keep-warm.test.ts +85 -1
- package/src/tests/config-api-only-keys.test.ts +9 -0
- package/src/tests/config-session-auth.test.ts +14 -0
- package/src/tests/cors-allowlist.test.ts +1 -1
- package/src/tests/docs-index-footprint.test.js +2 -2
- package/src/tests/extensions-example-slack-reply-gate.test.ts +262 -91
- package/src/tests/grok-adapter.test.ts +3 -3
- package/src/tests/heartbeat-checklist.test.ts +33 -0
- package/src/tests/heartbeat-jev-gate-credentials.test.ts +44 -0
- package/src/tests/heartbeat-jev-gate.test.ts +265 -1
- package/src/tests/kv-page-proxy.test.ts +91 -5
- package/src/tests/launch-password-rejection.test.ts +2 -2
- package/src/tests/mcp-input-caps.test.ts +294 -0
- package/src/tests/memory-chunked-search-starvation.test.ts +200 -0
- package/src/tests/memory-embedding-input-cap.test.ts +114 -0
- package/src/tests/memory.test.ts +14 -0
- package/src/tests/migration-232-agent-session-tokens.test.ts +67 -0
- package/src/tests/page-guest-session.test.ts +19 -8
- package/src/tests/page-proxy-authed.test.ts +1 -1
- package/src/tests/page-proxy.test.ts +17 -10
- package/src/tests/page-session.test.ts +102 -1
- package/src/tests/pages-authed-mode.test.ts +82 -12
- package/src/tests/pages-password-mode.test.ts +5 -5
- package/src/tests/rbac-engine.test.ts +1 -0
- package/src/tests/realtime-transport.test.ts +13 -7
- package/src/tests/runtime-child-token-cleanup.test.ts +3 -3
- package/src/tests/script-connections.test.ts +2 -0
- package/src/tests/script-runs-http.test.ts +84 -0
- package/src/tests/scripts-http.test.ts +10 -1
- package/src/tests/session-route-posture.test.ts +2 -0
- package/src/tests/swarm-config-export-to-env.test.ts +22 -3
- package/src/tests/task-audio-transcription.test.ts +299 -0
- package/src/tests/task-completion-memory-chunking.test.ts +434 -0
- package/src/tests/task-terminal-secret-scrub.test.ts +6 -1
- package/src/tests/transcription.test.ts +299 -0
- package/src/tests/worker-token-cli.test.ts +76 -0
- package/src/tests/workflow-executors.test.ts +4 -2
- package/src/tests/workflow-system-one-decision-providers.test.ts +98 -1
- package/src/tests/workflow-system-one-decision.test.ts +2 -1
- package/src/tests/workflow-system-one-extraction.test.ts +805 -0
- package/src/tools/chat-access.ts +10 -0
- package/src/tools/chat-post.ts +31 -11
- package/src/tools/chat-reply.ts +32 -10
- package/src/tools/memory-search.ts +3 -1
- package/src/tools/system-one-decide.ts +17 -4
- package/src/types.ts +8 -1
- package/src/utils/config-env-export.ts +3 -1
- package/src/utils/page-session.ts +133 -20
- package/src/utils/request-auth-context.ts +2 -1
- package/src/utils/transcription.ts +246 -0
- package/src/workflows/definition.ts +7 -1
- package/src/workflows/engine.ts +18 -12
- package/src/workflows/executors/index.ts +1 -0
- package/src/workflows/executors/registry.ts +2 -0
- package/src/workflows/executors/system-one-decision.ts +84 -262
- package/src/workflows/executors/system-one-extract-wire.ts +57 -0
- package/src/workflows/executors/system-one-extraction.ts +830 -0
- package/src/workflows/executors/system-one-providers.ts +316 -114
- package/src/workflows/executors/system-one-transport.ts +264 -0
- package/templates/extensions/slack-reply-gate/README.md +24 -22
- package/templates/extensions/slack-reply-gate/hooks.ts +146 -95
- package/templates/extensions/slack-reply-gate/manifest.json +2 -2
- package/templates/official/lead/HEARTBEAT.md +1 -1
- package/templates/skills/apps/SKILL.md +31 -7
- package/templates/skills/apps/content.md +31 -7
- package/templates/skills/chat-sdk/content.md +6 -2
- package/templates/skills/code-quality/content.md +2 -1
- package/templates/skills/heartbeat-runbook/content.md +8 -8
- package/templates/skills/pages/content.md +6 -4
- package/templates/skills/swarm-scripts/SKILL.md +2 -2
- package/templates/skills/swarm-scripts/content.md +2 -2
- package/dist/cli-v1sjhn52.js +0 -7
- package/dist/handlers-2qjw434w.js +0 -39
- package/dist/index-d0g18bax.js +0 -41
|
@@ -13,11 +13,15 @@ export const argsSchema = z.object({
|
|
|
13
13
|
.min(0)
|
|
14
14
|
.max(1)
|
|
15
15
|
.optional()
|
|
16
|
-
.describe(
|
|
16
|
+
.describe(
|
|
17
|
+
"Quiet when the model's p(needs action) is below this (default: the provider's measured threshold, 0.5 for Jev, 0.2 for Clef)",
|
|
18
|
+
),
|
|
17
19
|
provider: z
|
|
18
|
-
.enum(["auto", "typesafe", "openrouter"])
|
|
20
|
+
.enum(["auto", "typesafe", "openrouter", "cloudflare"])
|
|
19
21
|
.optional()
|
|
20
|
-
.describe(
|
|
22
|
+
.describe(
|
|
23
|
+
"Decision host: typesafe or openrouter (Jev), cloudflare (Clef). auto tries them in that order (default auto)",
|
|
24
|
+
),
|
|
21
25
|
timeZone: z
|
|
22
26
|
.string()
|
|
23
27
|
.optional()
|
|
@@ -28,25 +32,56 @@ export const argsSchema = z.object({
|
|
|
28
32
|
.min(1_000)
|
|
29
33
|
.max(45_000)
|
|
30
34
|
.optional()
|
|
31
|
-
.describe(
|
|
35
|
+
.describe(
|
|
36
|
+
"Abandon the decision call after this many ms (default 25000); the gate deadline is 60 s",
|
|
37
|
+
),
|
|
32
38
|
});
|
|
33
39
|
|
|
34
40
|
const KV_NAMESPACE = "heartbeat-jev-gate";
|
|
35
41
|
const KV_KEY = "setup";
|
|
36
|
-
//
|
|
37
|
-
const
|
|
42
|
+
// Jev's cost, measured per decision in the 2026-10-15 heartbeat replay (229 states).
|
|
43
|
+
const JEV_COST_PER_DECISION = "$0.00004";
|
|
44
|
+
// Clef replayed on the same 229 states and labels (2026-10-20): 0.2 is the highest
|
|
45
|
+
// threshold that misses none of the 9 ticks where the Lead acted (57 quiet ticks;
|
|
46
|
+
// Jev at 0.5 has 100). Above 0.21 Clef starts missing real asks.
|
|
47
|
+
const CLEF_THRESHOLD = 0.2;
|
|
38
48
|
|
|
39
|
-
//
|
|
40
|
-
// key and sends the request, so no key ever enters this script's realm. The
|
|
49
|
+
// The model is called through `ctx.swarm.systemOne_decide`: the API server reads
|
|
50
|
+
// the key and sends the request, so no key ever enters this script's realm. The
|
|
41
51
|
// server also refuses OpenRouter when the effective OPENROUTER_BASE_URL (stored
|
|
42
|
-
// config or deployment env) points at a gateway
|
|
52
|
+
// config or deployment env) points at a gateway; `auto` then tries the next
|
|
53
|
+
// usable provider, since this script cannot read the deployment env.
|
|
54
|
+
//
|
|
55
|
+
// `credentials` lists what must be set: every group needs one of its keys.
|
|
56
|
+
// `threshold` is the default the provider's own replay measured (see `CLEF_THRESHOLD`).
|
|
43
57
|
const PROVIDERS = {
|
|
44
|
-
typesafe: {
|
|
45
|
-
|
|
58
|
+
typesafe: {
|
|
59
|
+
model: "jev-latest",
|
|
60
|
+
family: "jev",
|
|
61
|
+
threshold: 0.5,
|
|
62
|
+
credentials: [["TYPESAFE_API_KEY"]],
|
|
63
|
+
setup: "`TYPESAFE_API_KEY` (Jev on TypeSafe)",
|
|
64
|
+
},
|
|
65
|
+
openrouter: {
|
|
66
|
+
model: "~typesafe/jev-latest",
|
|
67
|
+
family: "jev",
|
|
68
|
+
threshold: 0.5,
|
|
69
|
+
credentials: [["OPENROUTER_API_KEY"]],
|
|
70
|
+
setup: "`OPENROUTER_API_KEY` (Jev on OpenRouter)",
|
|
71
|
+
},
|
|
72
|
+
cloudflare: {
|
|
73
|
+
model: "clef",
|
|
74
|
+
family: "clef",
|
|
75
|
+
threshold: CLEF_THRESHOLD,
|
|
76
|
+
credentials: [["CLOUDFLARE_API_TOKEN", "CLOUDFLARE_API_KEY"], ["CLOUDFLARE_ACCOUNT_ID"]],
|
|
77
|
+
setup:
|
|
78
|
+
"`CLOUDFLARE_API_TOKEN` (or `CLOUDFLARE_API_KEY`) as a secret plus the `CLOUDFLARE_ACCOUNT_ID` config value (Clef on Cloudflare Workers AI)",
|
|
79
|
+
},
|
|
46
80
|
} as const;
|
|
47
81
|
type ProviderId = keyof typeof PROVIDERS;
|
|
82
|
+
const AUTO_ORDER: ProviderId[] = ["typesafe", "openrouter", "cloudflare"];
|
|
48
83
|
|
|
49
|
-
// Worded exactly as in the
|
|
84
|
+
// Worded exactly as in the replays that set the thresholds; changing it voids those results.
|
|
50
85
|
const QUESTIONS = {
|
|
51
86
|
act: {
|
|
52
87
|
type: "noul",
|
|
@@ -189,11 +224,20 @@ async function buildState(ctx: any, leadId: string, nowMs: number, timeZone: str
|
|
|
189
224
|
const mmdd = new Date(nowMs).toISOString().slice(5, 10);
|
|
190
225
|
const mmddLocal = stamp.slice(5, 10);
|
|
191
226
|
const due: string[] = [];
|
|
227
|
+
// An MM-DD counts only as a bare token: "release on 10-20" is due, while a
|
|
228
|
+
// re-verification stamp ("2026-10-20 ~10:45Z", a UUID piece) and a suffixed
|
|
229
|
+
// token ("10-20s") are not.
|
|
230
|
+
const mentionsMmdd = (s: string, tok: string) =>
|
|
231
|
+
new RegExp(`(?<![\\w-])${tok}(?![\\w-])`).test(s);
|
|
192
232
|
for (const line of String(lead[0]?.heartbeatMd ?? "").split("\n")) {
|
|
193
233
|
const l = line.trim();
|
|
194
234
|
if (!l) continue;
|
|
195
235
|
const del = /DELETE <?(\d\d-\d\d)>?/.exec(l);
|
|
196
|
-
if (
|
|
236
|
+
if (
|
|
237
|
+
mentionsMmdd(l, mmdd) ||
|
|
238
|
+
mentionsMmdd(l, mmddLocal) ||
|
|
239
|
+
(del?.[1] && del[1] <= mmddLocal)
|
|
240
|
+
) {
|
|
197
241
|
due.push(oneLine(l).slice(0, 200));
|
|
198
242
|
}
|
|
199
243
|
if (due.length >= 6) break;
|
|
@@ -220,21 +264,25 @@ async function buildState(ctx: any, leadId: string, nowMs: number, timeZone: str
|
|
|
220
264
|
};
|
|
221
265
|
}
|
|
222
266
|
|
|
223
|
-
function setupPrompt(
|
|
267
|
+
function setupPrompt(candidates: ProviderId[]) {
|
|
268
|
+
const options = candidates.map((id) => `- ${PROVIDERS[id].setup}`);
|
|
224
269
|
return {
|
|
225
|
-
title: "Heartbeat
|
|
270
|
+
title: "Heartbeat gate: add a decision model credential or decline",
|
|
226
271
|
detached: true,
|
|
227
272
|
questions: [
|
|
228
273
|
{
|
|
229
274
|
id: "enable",
|
|
230
275
|
type: "approval",
|
|
231
|
-
label: "Enable the
|
|
276
|
+
label: "Enable the heartbeat checklist gate?",
|
|
232
277
|
description: [
|
|
233
|
-
"Before each recurring heartbeat checklist, the `heartbeat-jev-gate` script sends a short summary of swarm state (about 1,500 characters: new failures, due tracked items, task and agent counts) to
|
|
278
|
+
"Before each recurring heartbeat checklist, the `heartbeat-jev-gate` script sends a short summary of swarm state (about 1,500 characters: new failures, due tracked items, task and agent counts) to a small SystemOne decision model (Jev by TypeSafe, or Clef on Cloudflare Workers AI) and asks whether the Lead needs to act. With `HEARTBEAT_CHECKLIST_GATE_MODE=enforce`, quiet ticks skip the Lead's checklist task.",
|
|
234
279
|
"",
|
|
235
|
-
`Cost:
|
|
280
|
+
`Cost: one decision per checklist tick, about ${JEV_COST_PER_DECISION} each with Jev.`,
|
|
236
281
|
"",
|
|
237
|
-
|
|
282
|
+
"No credential for the gate is configured. To enable, approve and add one of these as a global value on the Secrets page (Settings > Secrets):",
|
|
283
|
+
...options,
|
|
284
|
+
"",
|
|
285
|
+
"Do not paste a key here. The next tick picks it up.",
|
|
238
286
|
"",
|
|
239
287
|
"Reject to decline. The gate then stays inactive, with no further prompts, until a key is added.",
|
|
240
288
|
].join("\n"),
|
|
@@ -244,9 +292,10 @@ function setupPrompt(keys: string[]) {
|
|
|
244
292
|
}
|
|
245
293
|
|
|
246
294
|
/**
|
|
247
|
-
* Heartbeat checklist gate backed by
|
|
248
|
-
* tick needs the Lead and returns
|
|
249
|
-
* credential it asks a human once, then
|
|
295
|
+
* Heartbeat checklist gate backed by a SystemOne decision model (Jev or Clef):
|
|
296
|
+
* asks whether a recurring checklist tick needs the Lead and returns
|
|
297
|
+
* { quiet, reason, summary }. With no credential it asks a human once, then
|
|
298
|
+
* stays a no-op until a key is added.
|
|
250
299
|
*/
|
|
251
300
|
export default async function heartbeatJevGate(args: any, ctx: any) {
|
|
252
301
|
const parsed = argsSchema.safeParse(args ?? {});
|
|
@@ -267,25 +316,21 @@ export default async function heartbeatJevGate(args: any, ctx: any) {
|
|
|
267
316
|
};
|
|
268
317
|
|
|
269
318
|
const cfgThreshold = Number.parseFloat(cfg("HEARTBEAT_JEV_GATE_THRESHOLD"));
|
|
270
|
-
const threshold =
|
|
271
|
-
a.threshold ?? (cfgThreshold >= 0 && cfgThreshold <= 1 ? cfgThreshold : 0.5);
|
|
272
319
|
const providerPref = a.provider ?? (cfg("HEARTBEAT_JEV_GATE_PROVIDER").toLowerCase() || "auto");
|
|
273
320
|
const timeZone = a.timeZone ?? (cfg("HEARTBEAT_JEV_GATE_TIMEZONE") || "UTC");
|
|
274
321
|
|
|
275
|
-
const usable:
|
|
276
|
-
|
|
277
|
-
openrouter: cfg(PROVIDERS.openrouter.keyName) !== "",
|
|
278
|
-
};
|
|
322
|
+
const usable = (id: ProviderId) =>
|
|
323
|
+
PROVIDERS[id].credentials.every((group) => group.some((key) => cfg(key) !== ""));
|
|
279
324
|
const candidates: ProviderId[] =
|
|
280
|
-
providerPref
|
|
281
|
-
|
|
282
|
-
: providerPref === "openrouter"
|
|
283
|
-
? ["openrouter"]
|
|
284
|
-
: ["typesafe", "openrouter"];
|
|
285
|
-
const provider = candidates.find((id) => usable[id]);
|
|
325
|
+
Object.hasOwn(PROVIDERS, providerPref) ? [providerPref as ProviderId] : AUTO_ORDER;
|
|
326
|
+
const usableCandidates = candidates.filter(usable);
|
|
286
327
|
|
|
287
|
-
if (
|
|
288
|
-
const keys = candidates.map((id) =>
|
|
328
|
+
if (usableCandidates.length === 0) {
|
|
329
|
+
const keys = candidates.map((id) =>
|
|
330
|
+
PROVIDERS[id].credentials
|
|
331
|
+
.map((group) => (group.length > 1 ? `(${group.join(" or ")})` : group[0]))
|
|
332
|
+
.join(" + "),
|
|
333
|
+
);
|
|
289
334
|
const inactive = (state: string, extra: Record<string, unknown> = {}) => ({
|
|
290
335
|
quiet: false,
|
|
291
336
|
reason: `jev-gate inactive: ${state}`.slice(0, 300),
|
|
@@ -296,7 +341,7 @@ export default async function heartbeatJevGate(args: any, ctx: any) {
|
|
|
296
341
|
let setup: SetupState | null = typeof stored === "string" ? JSON.parse(stored) : (stored ?? null);
|
|
297
342
|
|
|
298
343
|
if (!setup) {
|
|
299
|
-
const prompt = setupPrompt(
|
|
344
|
+
const prompt = setupPrompt(candidates);
|
|
300
345
|
if (dryRun) {
|
|
301
346
|
const state = await buildState(ctx, leadId, Date.now(), timeZone);
|
|
302
347
|
return inactive("no credential, would ask a human", { prompt, state });
|
|
@@ -340,35 +385,51 @@ export default async function heartbeatJevGate(args: any, ctx: any) {
|
|
|
340
385
|
return inactive(why, { setup });
|
|
341
386
|
}
|
|
342
387
|
|
|
343
|
-
const target = PROVIDERS[provider];
|
|
344
388
|
const state = await buildState(ctx, leadId, Date.now(), timeZone);
|
|
345
389
|
|
|
346
|
-
// The server enforces the time budget. No retries, as in the replay.
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
390
|
+
// The server enforces the time budget. No retries, as in the replay. A provider
|
|
391
|
+
// this deployment refuses (OpenRouter behind a gateway) sends nothing, so the
|
|
392
|
+
// next usable one is tried; only an explicit choice or the last one throws.
|
|
393
|
+
let provider = usableCandidates[0] as ProviderId;
|
|
394
|
+
let body: any;
|
|
395
|
+
const skipped: string[] = [];
|
|
396
|
+
for (const [i, id] of usableCandidates.entries()) {
|
|
397
|
+
provider = id;
|
|
398
|
+
const res: any = await ctx.swarm.systemOne_decide({
|
|
399
|
+
provider: id,
|
|
400
|
+
model: PROVIDERS[id].model,
|
|
401
|
+
state,
|
|
402
|
+
questions: QUESTIONS,
|
|
403
|
+
timeoutMs: a.jevTimeoutMs ?? 25_000,
|
|
404
|
+
maxRetries: 0,
|
|
405
|
+
});
|
|
406
|
+
body = res?.data ?? res;
|
|
407
|
+
if (res?.success !== false && body?.success !== false) break;
|
|
408
|
+
const why = String(body?.message ?? body?.error ?? `HTTP ${res?.status}`).slice(0, 250);
|
|
409
|
+
if (body?.providerUnavailable === true && i < usableCandidates.length - 1) {
|
|
410
|
+
skipped.push(`${id}: ${why}`);
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
throw new Error(`${PROVIDERS[id].family} ${id}: ${why}`);
|
|
358
414
|
}
|
|
415
|
+
const target = PROVIDERS[provider];
|
|
416
|
+
// A configured threshold applies to every provider; unset, each uses its measured one.
|
|
417
|
+
const threshold =
|
|
418
|
+
a.threshold ?? (cfgThreshold >= 0 && cfgThreshold <= 1 ? cfgThreshold : target.threshold);
|
|
359
419
|
const p = body?.answers?.act?.noul;
|
|
360
420
|
if (typeof p !== "number" || !Number.isFinite(p)) {
|
|
361
|
-
throw new Error(
|
|
421
|
+
throw new Error(`${target.family} ${provider}: response has no numeric answers.act.noul`);
|
|
362
422
|
}
|
|
363
423
|
|
|
364
424
|
const pText = p.toFixed(3);
|
|
365
425
|
const quiet = p < threshold;
|
|
366
426
|
const verdict: Record<string, unknown> = {
|
|
367
427
|
quiet,
|
|
368
|
-
reason:
|
|
428
|
+
reason: `${target.family} p(needs action)=${pText} ${quiet ? "<" : ">="} ${threshold} via ${provider}`,
|
|
369
429
|
};
|
|
370
430
|
if (!quiet) {
|
|
371
|
-
const
|
|
431
|
+
const model = target.family === "jev" ? "Jev" : "Clef";
|
|
432
|
+
const lines = [`${model} p(needs action) = ${pText} (threshold ${threshold}, ${provider}).`];
|
|
372
433
|
const failures = state.new_failures_since_previous_heartbeat;
|
|
373
434
|
const tracked = state.tracked_items_mentioning_today_or_past_delete_date;
|
|
374
435
|
if (Array.isArray(failures)) {
|
|
@@ -378,9 +439,9 @@ export default async function heartbeatJevGate(args: any, ctx: any) {
|
|
|
378
439
|
lines.push("", "Tracked items due today or past their DELETE date:", ...tracked.map((t) => `- ${t.replace(/^[-*] /, "")}`));
|
|
379
440
|
}
|
|
380
441
|
if (!Array.isArray(failures) && !Array.isArray(tracked)) {
|
|
381
|
-
lines.push("",
|
|
442
|
+
lines.push("", `No new failures or due tracked items; ${model} flagged the overall state.`);
|
|
382
443
|
}
|
|
383
444
|
verdict.summary = lines.join("\n").slice(0, 4000);
|
|
384
445
|
}
|
|
385
|
-
return dryRun ? { ...verdict, dryRun: true, provider, p, threshold, state } : verdict;
|
|
446
|
+
return dryRun ? { ...verdict, dryRun: true, provider, skipped, p, threshold, state } : verdict;
|
|
386
447
|
}
|
|
@@ -116,9 +116,9 @@ export const SEED_SCRIPTS: SeedScript[] = [
|
|
|
116
116
|
{
|
|
117
117
|
name: "heartbeat-jev-gate",
|
|
118
118
|
description:
|
|
119
|
-
"Heartbeat checklist gate backed by Jev
|
|
119
|
+
"Heartbeat checklist gate backed by a SystemOne decision model (Jev on TypeSafe or OpenRouter, Clef on Cloudflare Workers AI): scores a compact swarm state and returns {quiet, reason, summary} for HEARTBEAT_CHECKLIST_GATE_SCRIPT.",
|
|
120
120
|
intent:
|
|
121
|
-
"Skip quiet Lead heartbeat checklist ticks with a cheap Jev decision; with no
|
|
121
|
+
"Skip quiet Lead heartbeat checklist ticks with a cheap Jev or Clef decision; with no credential it asks a human once, then stays a no-op until a key is added.",
|
|
122
122
|
source: asText(heartbeatJevGateSrc),
|
|
123
123
|
},
|
|
124
124
|
{
|
|
@@ -68,7 +68,11 @@ const RESERVED_KEYS = new Set([
|
|
|
68
68
|
// the agent-fs bootstrap admin key would let a compromised worker administer the
|
|
69
69
|
// shared org. The API materializes these into its own process.env at boot via
|
|
70
70
|
// getInjectableGlobalConfigs, so no HTTP consumer legitimately needs them.
|
|
71
|
-
const API_ONLY_CONFIG_KEYS = new Set([
|
|
71
|
+
const API_ONLY_CONFIG_KEYS = new Set([
|
|
72
|
+
"API_AGENT_FS_API_KEY",
|
|
73
|
+
"SLACK_SIGNING_SECRET",
|
|
74
|
+
"TRANSCRIPTION_API_KEY",
|
|
75
|
+
]);
|
|
72
76
|
|
|
73
77
|
export function isApiOnlyConfigKey(key: string): boolean {
|
|
74
78
|
return API_ONLY_CONFIG_KEYS.has(key);
|
|
@@ -149,6 +153,31 @@ export const DB_RETENTION_TUNING_BOUNDS = {
|
|
|
149
153
|
*/
|
|
150
154
|
export const APPS_JSON_COLUMN_MAX_BYTES_BOUNDS = { min: 1_024, max: 16_777_216 } as const;
|
|
151
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Bounds for the Codex OAuth keep-warm age threshold
|
|
158
|
+
* (`CODEX_OAUTH_KEEP_WARM_MAX_AGE_HOURS`).
|
|
159
|
+
*
|
|
160
|
+
* `src/http/codex-oauth-keep-warm.ts` reads the knob against exactly these at
|
|
161
|
+
* call time and falls back to its default outside them. The 216 h (9 day)
|
|
162
|
+
* ceiling stays under the 9.5 day point where task-time near-expiry refresh
|
|
163
|
+
* takes over, so every accepted value still changes when a slot refreshes.
|
|
164
|
+
*/
|
|
165
|
+
export const CODEX_OAUTH_KEEP_WARM_MAX_AGE_HOURS_BOUNDS = { min: 1, max: 216 } as const;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Decision hosts `SYSTEM_ONE_DEFAULT_PROVIDER` may name: `SYSTEM_ONE_PROVIDER_IDS`
|
|
169
|
+
* in `src/workflows/executors/system-one-providers.ts`, listed here because that
|
|
170
|
+
* module's credential readers would pull the LLM stack into every `db.ts` import.
|
|
171
|
+
* A test keeps the two lists equal.
|
|
172
|
+
*/
|
|
173
|
+
export const SYSTEM_ONE_DEFAULT_PROVIDER_OPTIONS = [
|
|
174
|
+
"typesafe",
|
|
175
|
+
"openrouter",
|
|
176
|
+
"laya",
|
|
177
|
+
"openai",
|
|
178
|
+
"cloudflare",
|
|
179
|
+
] as const;
|
|
180
|
+
|
|
152
181
|
/** Build `{ KEY: validator }` entries accepting only boolean literals. */
|
|
153
182
|
function booleanValidators(keys: string[]): Record<string, ConfigValidator> {
|
|
154
183
|
const message = (key: string) =>
|
|
@@ -388,6 +417,7 @@ const VALIDATED_KEYS: Record<string, ConfigValidator> = {
|
|
|
388
417
|
},
|
|
389
418
|
...enumValidator("CLAUDE_TRANSPORT", ["cli", "sdk"]),
|
|
390
419
|
...enumValidator("SCRIPT_EXECUTOR", ["native", "quickjs"]),
|
|
420
|
+
...enumValidator("TRANSCRIPTION_PROVIDER", ["openai", "elevenlabs", "groq"]),
|
|
391
421
|
SCRIPT_QUICKJS_POOL_SIZE: validateQuickJSPoolSize,
|
|
392
422
|
...booleanValidators(["SCRIPT_EGRESS_ALLOW_PRIVATE"]),
|
|
393
423
|
SCRIPT_EGRESS_ALLOWLIST: (value) =>
|
|
@@ -396,6 +426,7 @@ const VALIDATED_KEYS: Record<string, ConfigValidator> = {
|
|
|
396
426
|
// model's weekly window (Fable/Opus/Sonnet). fallback: legacy random pick.
|
|
397
427
|
...enumValidator("MODEL_WINDOW_EXHAUSTED_POLICY", ["fail", "fallback"]),
|
|
398
428
|
...enumValidator("HEARTBEAT_CHECKLIST_GATE_MODE", ["shadow", "enforce"]),
|
|
429
|
+
...enumValidator("SYSTEM_ONE_DEFAULT_PROVIDER", [...SYSTEM_ONE_DEFAULT_PROVIDER_OPTIONS]),
|
|
399
430
|
// Codex credits-exhausted cooldown (ms). Permissive on range here (positive
|
|
400
431
|
// integer) — the worker clamps to [5m, 7d] via resolveCodexCreditsExhaustedCooldownMs.
|
|
401
432
|
CODEX_CREDITS_EXHAUSTED_COOLDOWN_MS: (value) => {
|
|
@@ -542,6 +573,11 @@ const VALIDATED_KEYS: Record<string, ConfigValidator> = {
|
|
|
542
573
|
APPS_JSON_COLUMN_MAX_BYTES_BOUNDS.min,
|
|
543
574
|
APPS_JSON_COLUMN_MAX_BYTES_BOUNDS.max,
|
|
544
575
|
),
|
|
576
|
+
...boundedIntegerValidators(
|
|
577
|
+
["CODEX_OAUTH_KEEP_WARM_MAX_AGE_HOURS"],
|
|
578
|
+
CODEX_OAUTH_KEEP_WARM_MAX_AGE_HOURS_BOUNDS.min,
|
|
579
|
+
CODEX_OAUTH_KEEP_WARM_MAX_AGE_HOURS_BOUNDS.max,
|
|
580
|
+
),
|
|
545
581
|
...boundedIntegerValidators(
|
|
546
582
|
[
|
|
547
583
|
"SESSION_LOG_RETENTION_DAYS",
|
|
@@ -566,6 +602,9 @@ const VALIDATED_KEYS: Record<string, ConfigValidator> = {
|
|
|
566
602
|
// default in thread-buffer.ts; above 10 minutes a
|
|
567
603
|
// reply waits longer than any operator expects.
|
|
568
604
|
...boundedIntegerValidators(["CHAT_SDK_BUFFER_MS"], 1, 600_000),
|
|
605
|
+
// Minutes a Chat SDK thread keeps its owner after the owner's task ends.
|
|
606
|
+
// 0 keeps it only while the task is open; a day is the longest useful window.
|
|
607
|
+
...boundedIntegerValidators(["CHAT_SDK_OWNER_WINDOW_MIN"], 0, 1440),
|
|
569
608
|
// Below ~100 tokens the preamble can't fit a useful summary; above 20000
|
|
570
609
|
// (~80k chars) it risks the SIGTERM-143 context-saturation failure mode
|
|
571
610
|
// the cap exists to prevent (see context-preamble.ts).
|
|
@@ -68,3 +68,33 @@ export async function recordTaskAttachmentUpload(
|
|
|
68
68
|
throw error;
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
|
+
|
|
72
|
+
// Resolve against the row's ACTUAL stored key + its own org/drive, rather than
|
|
73
|
+
// reconstructing `tasks/<taskId>/<name>`. Attachments written to agent-fs via the
|
|
74
|
+
// CLI live at arbitrary paths (`misc/…`, `smoke/…`); reconstruction mis-resolves
|
|
75
|
+
// them, which previously caused downloads to 404 and deletes to orphan the real
|
|
76
|
+
// file. New uploads have no stored key yet at scope-build time and keep the
|
|
77
|
+
// forward-looking layout.
|
|
78
|
+
export function scopeFromAttachment(attachment: TaskAttachment): FileScope {
|
|
79
|
+
const storedKey = attachment.providerKey ?? attachment.path ?? "";
|
|
80
|
+
return {
|
|
81
|
+
taskId: attachment.taskId,
|
|
82
|
+
name: attachment.name,
|
|
83
|
+
key: storedKey.trim() ? storedKey : undefined,
|
|
84
|
+
orgId: attachment.orgId,
|
|
85
|
+
driveId: attachment.driveId,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Which file-storage provider (if any) actually holds this attachment's bytes.
|
|
90
|
+
// Only agent-fs objects and local-fs uploads are provider-backed; `shared-fs`
|
|
91
|
+
// worker-volume pointers, `url`, and `page` attachments have no provider object,
|
|
92
|
+
// so they must never be fetched or deleted through a provider (doing so would
|
|
93
|
+
// mis-resolve and, on delete, orphan the real target). Note local-fs uploads are
|
|
94
|
+
// recorded with kind "shared-fs" but an explicit local-fs providerId, so key off
|
|
95
|
+
// both signals rather than kind alone.
|
|
96
|
+
export function backingProviderId(attachment: TaskAttachment): string | null {
|
|
97
|
+
if (attachment.kind === "agent-fs") return attachment.providerId ?? "agent-fs";
|
|
98
|
+
if (attachment.providerId === "local-fs") return "local-fs";
|
|
99
|
+
return null;
|
|
100
|
+
}
|