@desplega.ai/agent-swarm 1.145.0 → 1.147.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 -1
- package/dist/{acp-adapter-580t41c0.js → acp-adapter-9n319wqc.js} +61 -6
- package/dist/{actions-m662tjng.js → actions-2vxqvpr9.js} +9 -8
- package/dist/{app-zb3rndm8.js → app-w066xfy0.js} +6 -5
- package/dist/assistant-kt31dj2h.js +236 -0
- package/dist/{boot-reembed-072x00vn.js → boot-reembed-az5rassp.js} +7 -6
- package/dist/{boot-reembed-65zz2smt.js → boot-reembed-j3mm3rfz.js} +8 -7
- package/dist/{boot-scrub-logs-yz0ams04.js → boot-scrub-logs-b6h54817.js} +4 -4
- package/dist/{claude-adapter-paj270y2.js → claude-adapter-w1z04ann.js} +8 -6
- package/dist/{claude-managed-setup-w619jncn.js → claude-managed-setup-f5pmsyrp.js} +24 -3
- package/dist/{claude-sdk-session-swt80j9z.js → claude-sdk-session-f0cc1kec.js} +8 -6
- package/dist/{cli-dt553ktb.js → cli-0b6y7kxm.js} +1 -1
- package/dist/{cli-bxdhw615.js → cli-12fz972k.js} +4 -4
- package/dist/{cli-s2f20r5w.js → cli-1th1728g.js} +2 -2
- package/dist/{cli-rs6ec3b9.js → cli-3tgwnf43.js} +3 -3
- package/dist/{cli-gxnzc6wh.js → cli-4nr988h6.js} +1 -1
- package/dist/{cli-axs8e6d4.js → cli-53s590z8.js} +1 -1
- package/dist/{cli-ygbjp3z8.js → cli-54wwve05.js} +5 -4
- package/dist/{cli-v0asr5yv.js → cli-719k9j2c.js} +2 -2
- package/dist/{cli-anktweqr.js → cli-89xfd7f9.js} +21 -47
- package/dist/{cli-q34a0e10.js → cli-8v0g1yc8.js} +1 -1
- package/dist/cli-9d8ntetj.js +42 -0
- package/dist/{cli-z9fprcrf.js → cli-atcve9y8.js} +881 -738
- package/dist/{cli-jmb7g47h.js → cli-b5bq9crk.js} +14 -31
- package/dist/cli-d8brzxjb.js +190 -0
- package/dist/{cli-gzky0gkr.js → cli-de14znh8.js} +2 -2
- package/dist/{cli-xytwff7f.js → cli-dttph1bw.js} +2 -2
- package/dist/cli-ep19k3mb.js +19 -0
- package/dist/{cli-m1xa8be7.js → cli-f146mn5s.js} +7 -50
- package/dist/{cli-1fj0chdk.js → cli-f7dsy61y.js} +5 -3
- package/dist/{cli-f567d5c1.js → cli-ftht3zzj.js} +2782 -2589
- package/dist/{cli-a0g1gbt5.js → cli-hbv0kq6w.js} +2 -2
- package/dist/{cli-fhsz3twr.js → cli-jsp14b6c.js} +171 -1
- package/dist/{cli-7fnkj1hj.js → cli-kpv03zhj.js} +21 -17
- package/dist/{cli-m4j6trn4.js → cli-m8yrsg97.js} +2 -2
- package/dist/cli-m9sxbkhm.js +779 -0
- package/dist/cli-mmemxxdc.js +823 -0
- package/dist/{cli-tqtvj5pt.js → cli-n8508nre.js} +1 -1
- package/dist/{cli-z96t0thj.js → cli-p1d5b073.js} +37 -2
- package/dist/{cli-gh8y8f36.js → cli-rw51bq3j.js} +13 -10
- package/dist/{cli-59ej1c07.js → cli-smby5m17.js} +7 -6
- package/dist/{cli-65vqzz3v.js → cli-tzvk9haz.js} +94 -372
- package/dist/{cli-dc9k2ba9.js → cli-w9kb3bk1.js} +1 -1
- package/dist/{cli-kpev657q.js → cli-y6b6fb76.js} +25 -3
- package/dist/{cli-123q2get.js → cli-yz3djrm0.js} +9 -9
- package/dist/{cli-wvp6bvy4.js → cli-zhjmqxzh.js} +1 -1
- package/dist/cli.js +13 -13
- package/dist/{codex-adapter-k98vaw2r.js → codex-adapter-zw4dwsx7.js} +2 -2
- package/dist/{codex-hook-9pf19cks.js → codex-hook-bw8p5nh4.js} +2 -2
- package/dist/{codex-session-runner-tngtphx7.js → codex-session-runner-k981s65v.js} +2 -2
- package/dist/{commands-y8nbr3fv.js → commands-sykrxx7e.js} +4 -4
- package/dist/{db-30p4h2t1.js → db-sfbsc8wt.js} +6 -4
- package/dist/handlers-0aspcejm.js +603 -0
- package/dist/{hook-dcw4jfbj.js → hook-4nvqj2sb.js} +7 -5
- package/dist/{hook-21jexvfx.js → hook-hxccs7m5.js} +24 -49
- package/dist/{http-r4kq5g8d.js → http-y06z517d.js} +230 -94
- package/dist/{index-q3qja6ta.js → index-hssww7kj.js} +15 -14
- package/dist/{index-gay66b9w.js → index-k8znfx0z.js} +13 -12
- package/dist/{index-53zyht4z.js → index-tce1rss4.js} +371 -110
- package/dist/{index-nqvf26za.js → index-x5j894zf.js} +14 -13
- package/dist/{keepalive-xs8fa55y.js → keepalive-w733ax66.js} +6 -6
- package/dist/{lead-d9m2t4s0.js → lead-75bjqa9d.js} +29 -27
- package/dist/{maintenance-3zh82g6z.js → maintenance-w4f1zjck.js} +8 -7
- package/dist/{oauth-refresh-sweep-03snsye5.js → oauth-refresh-sweep-wdetky26.js} +5 -5
- package/dist/{onboard-0cg1925x.js → onboard-bb5net8s.js} +2 -2
- package/dist/{otel-impl-0ab95z27.js → otel-impl-0w7c14ap.js} +1 -1
- package/dist/{pi-mono-adapter-dtkz4e7j.js → pi-mono-adapter-2has4gnp.js} +12 -2
- package/dist/{pricing-refresh-e5jhzz4j.js → pricing-refresh-9nzsrgcq.js} +6 -6
- package/dist/{rbac-roles-p1mf40z3.js → rbac-roles-r3hqjp09.js} +5 -5
- package/dist/{rbac-roles-2w3cmrkc.js → rbac-roles-z1jrffbt.js} +4 -4
- package/dist/{registry-9kdck5ye.js → registry-v5wytg0s.js} +1 -2
- package/dist/{render-v2-xhawry3k.js → render-v2-vbr89fnb.js} +6 -5
- package/dist/{seed-pricing-t223sw91.js → seed-pricing-g62hy1pk.js} +7 -5
- package/dist/{setup-zcs0rce7.js → setup-gnfqnptp.js} +2 -2
- package/dist/{worker-qnp2ka62.js → worker-kznxp4qm.js} +29 -27
- package/openapi.json +263 -12
- package/package.json +1 -1
- package/plugin/commands/start-worker.md +4 -9
- package/plugin/pi-skills/start-worker/SKILL.md +4 -9
- package/src/be/db/agents.ts +556 -0
- package/src/be/db/context-versions.ts +117 -0
- package/src/be/db/runtime.ts +406 -0
- package/src/be/db/tasks/read.ts +1167 -0
- package/src/be/db/tasks/write.ts +953 -0
- package/src/be/db.ts +584 -3429
- package/src/be/migrations/147_scheduled_tasks_parent_task.sql +7 -0
- package/src/be/migrations/148_pages_svg.sql +123 -0
- package/src/be/migrations/149_session_tokens.sql +24 -0
- package/src/be/scripts/typecheck.ts +1 -0
- package/src/be/seed-pricing.ts +13 -8
- package/src/be/seed-scripts/catalog/ops-catalog-audit.inline.ts +1 -1
- package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +1 -1
- package/src/be/seed-scripts/catalog/star-history-refresh.ts +101 -0
- package/src/be/seed-scripts/catalog/star-history-renderer.ts +119 -0
- package/src/be/seed-scripts/index.ts +17 -0
- package/src/be/seed-skills/index.ts +14 -0
- package/src/be/swarm-config-guard.ts +5 -2
- package/src/be/task-attachment-store.ts +70 -0
- package/src/be/users.ts +77 -0
- package/src/commands/attachments-section.ts +37 -0
- package/src/commands/claude-managed-setup.ts +45 -3
- package/src/commands/claude-md-session.ts +408 -0
- package/src/commands/context-preamble.ts +15 -3
- package/src/commands/profile-sync.ts +205 -5
- package/src/commands/provider-credentials.ts +60 -27
- package/src/commands/runner.ts +63 -58
- package/src/commands/templates.ts +25 -2
- package/src/hooks/hook.ts +26 -67
- package/src/http/agents.ts +40 -1
- package/src/http/auth.ts +13 -1
- package/src/http/fs.ts +21 -51
- package/src/http/index.ts +2 -0
- package/src/http/mcp.ts +32 -0
- package/src/http/pages-public.ts +20 -4
- package/src/http/pages.ts +11 -3
- package/src/http/poll.ts +4 -0
- package/src/http/repos.ts +3 -3
- package/src/http/sessions.ts +82 -0
- package/src/http/tasks.ts +10 -2
- package/src/http/utils.ts +79 -1
- package/src/prompts/session-templates.ts +12 -8
- package/src/providers/acp-adapter.ts +62 -8
- package/src/providers/pi-mono-adapter.ts +23 -6
- package/src/providers/pricing-sources.md +11 -0
- package/src/scheduler/scheduler.test.ts +49 -2
- package/src/scheduler/scheduler.ts +4 -0
- package/src/scripts-runtime/sdk-allowlist.ts +1 -0
- package/src/scripts-runtime/types/stdlib.d.ts +8 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +8 -0
- package/src/server.ts +2 -0
- package/src/slack/assistant.ts +87 -46
- package/src/slack/handlers.test.ts +1 -3
- package/src/slack/handlers.ts +102 -87
- package/src/slack/inbound-files.ts +466 -0
- package/src/slack/templates.ts +14 -0
- package/src/tasks/task-terminal-effects.ts +158 -0
- package/src/tests/acp-adapter.test.ts +369 -117
- package/src/tests/budget-claim-gate.test.ts +1 -0
- package/src/tests/build-pi-skills.test.ts +5 -7
- package/src/tests/claude-managed-setup.test.ts +52 -4
- package/src/tests/claude-md-session.test.ts +603 -0
- package/src/tests/codex-skill-resolver.test.ts +19 -0
- package/src/tests/context-versioning.test.ts +107 -0
- package/src/tests/cors-allowlist.test.ts +309 -0
- package/src/tests/credential-check.test.ts +157 -14
- package/src/tests/db-agents.test.ts +91 -0
- package/src/tests/db-context-versions.test.ts +37 -0
- package/src/tests/db-extraction-contract.test.ts +45 -0
- package/src/tests/db-runtime.test.ts +70 -0
- package/src/tests/db-task-read-contract.test.ts +624 -0
- package/src/tests/db-task-write-contract.test.ts +653 -0
- package/src/tests/db-tasks-read.test.ts +183 -0
- package/src/tests/db-tasks-write.test.ts +230 -0
- package/src/tests/defer-task.test.ts +389 -0
- package/src/tests/docs-index-footprint.test.js +2 -2
- package/src/tests/e2e-visuals-stage.test.ts +151 -0
- package/src/tests/file-lock.test.ts +144 -0
- package/src/tests/fixtures/file-lock-holder.ts +13 -0
- package/src/tests/fixtures/hold-file-lock.ts +25 -0
- package/src/tests/heartbeat-expiry.test.ts +188 -0
- package/src/tests/http-api-integration.test.ts +78 -1
- package/src/tests/pages-public-html.test.ts +43 -0
- package/src/tests/pages-svg-migration.test.ts +42 -0
- package/src/tests/preload.ts +4 -1
- package/src/tests/profile-sync-warning.test.ts +16 -0
- package/src/tests/profile-sync.test.ts +126 -0
- package/src/tests/prompt-template-session.test.ts +20 -4
- package/src/tests/provider-registration.test.ts +93 -0
- package/src/tests/rbac-e2e-helpers.test.ts +53 -0
- package/src/tests/rbac-e2e-helpers.ts +19 -2
- package/src/tests/reload-config.test.ts +26 -0
- package/src/tests/routing-affinity-inventory.test.ts +1 -1
- package/src/tests/runner-attachments-section.test.ts +22 -2
- package/src/tests/runner-context-preamble.test.ts +30 -0
- package/src/tests/runner-deployment-resume.test.ts +107 -0
- package/src/tests/runner-repo-autostash.test.ts +12 -0
- package/src/tests/script-connections.test.ts +4 -0
- package/src/tests/seed-scripts.test.ts +2 -2
- package/src/tests/session-tokens.test.ts +279 -0
- package/src/tests/slack-file-tools-attachments.test.ts +408 -0
- package/src/tests/slack-inbound-files.test.ts +847 -0
- package/src/tests/star-history-refresh.test.ts +102 -0
- package/src/tests/swarm-config-reserved-keys.test.ts +21 -0
- package/src/tests/swarm-repos.test.ts +20 -0
- package/src/tests/tool-annotations.test.ts +4 -3
- package/src/tests/ui-logs-parser.test.ts +176 -0
- package/src/tools/create-page.ts +4 -2
- package/src/tools/defer-task.ts +239 -0
- package/src/tools/repos/update-repo.ts +2 -2
- package/src/tools/schedules/create-schedule.ts +1 -0
- package/src/tools/schedules/list-schedules.ts +1 -0
- package/src/tools/schedules/patch-schedule.ts +1 -0
- package/src/tools/schedules/update-schedule.ts +1 -0
- package/src/tools/slack-download-file.ts +60 -29
- package/src/tools/slack-read.ts +73 -32
- package/src/tools/store-progress.ts +16 -146
- package/src/tools/tool-config.ts +1 -0
- package/src/tools/utils.ts +21 -0
- package/src/types.ts +37 -4
- package/src/utils/acp-session-token.ts +56 -0
- package/src/utils/file-lock.ts +111 -0
- package/src/utils/heartbeat-expiry.ts +78 -0
- package/src/utils/request-auth-context.ts +2 -0
- package/src/utils/task-attachment-links.ts +22 -0
- package/templates/skills/code-quality/content.md +8 -5
- package/templates/skills/download-task-attachment/content.md +2 -1
- package/{plugin/pi-skills → templates/skills}/review-offered-task/SKILL.md +5 -5
- package/templates/skills/review-offered-task/config.json +14 -0
- package/{plugin/commands/review-offered-task.md → templates/skills/review-offered-task/content.md} +3 -8
- package/templates/skills/scheduling/content.md +4 -0
- package/templates/skills/slack-interaction/content.md +2 -2
- package/templates/skills/work-on-task/SKILL.md +16 -0
- package/templates/skills/work-on-task/config.json +14 -0
- package/templates/skills/work-on-task/content.md +11 -0
- package/dist/assistant-0qt42nzg.js +0 -212
- package/dist/cli-fs1kkqgr.js +0 -317
- package/dist/cli-jnf5zghe.js +0 -269
- package/dist/cli-n1q8q14d.js +0 -177
- package/dist/handlers-yfp1qn81.js +0 -592
- package/plugin/commands/work-on-task.md +0 -39
- package/plugin/pi-skills/work-on-task/SKILL.md +0 -39
|
@@ -11,17 +11,17 @@ import {
|
|
|
11
11
|
import {
|
|
12
12
|
calculateNextRun,
|
|
13
13
|
runScheduleNow
|
|
14
|
-
} from "./cli-
|
|
14
|
+
} from "./cli-smby5m17.js";
|
|
15
15
|
import {
|
|
16
16
|
startPricingRefreshLoop
|
|
17
|
-
} from "./cli-
|
|
17
|
+
} from "./cli-m8yrsg97.js";
|
|
18
18
|
import {
|
|
19
19
|
seedPricingFromModelsDev
|
|
20
|
-
} from "./cli-
|
|
20
|
+
} from "./cli-rw51bq3j.js";
|
|
21
21
|
import {
|
|
22
22
|
ensureRbacSeedsSynced,
|
|
23
23
|
getUserGrant
|
|
24
|
-
} from "./cli-
|
|
24
|
+
} from "./cli-8v0g1yc8.js";
|
|
25
25
|
import {
|
|
26
26
|
can,
|
|
27
27
|
decideAdmission,
|
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
runSavedScriptAsAgent,
|
|
49
49
|
updateApp,
|
|
50
50
|
upgradeAppDefinition
|
|
51
|
-
} from "./cli-
|
|
51
|
+
} from "./cli-de14znh8.js";
|
|
52
52
|
import {
|
|
53
53
|
require_dist as require_dist2
|
|
54
54
|
} from "./cli-qgm2pfpq.js";
|
|
@@ -72,7 +72,7 @@ import {
|
|
|
72
72
|
updateTrackerSync,
|
|
73
73
|
updateTrackerSyncSwarmId,
|
|
74
74
|
upsertSwarmConfigWithPolicyMirror
|
|
75
|
-
} from "./cli-
|
|
75
|
+
} from "./cli-f7dsy61y.js";
|
|
76
76
|
import {
|
|
77
77
|
isMultiRuntimeEnabled
|
|
78
78
|
} from "./cli-07jd68a1.js";
|
|
@@ -86,7 +86,7 @@ import {
|
|
|
86
86
|
snapshotWorkflow,
|
|
87
87
|
startWorkflowExecution,
|
|
88
88
|
validateJsonSchema
|
|
89
|
-
} from "./cli-
|
|
89
|
+
} from "./cli-yz3djrm0.js";
|
|
90
90
|
import {
|
|
91
91
|
ConnectionAuthInputSchema,
|
|
92
92
|
SCRIPT_LONG_TIMEOUT_HINT_MS,
|
|
@@ -109,7 +109,7 @@ import {
|
|
|
109
109
|
upsertCredentialBinding,
|
|
110
110
|
upsertScriptConnection,
|
|
111
111
|
validateDefinition
|
|
112
|
-
} from "./cli-
|
|
112
|
+
} from "./cli-3tgwnf43.js";
|
|
113
113
|
import {
|
|
114
114
|
CANDIDATE_SET_MULTIPLIER,
|
|
115
115
|
computeScore,
|
|
@@ -121,7 +121,7 @@ import {
|
|
|
121
121
|
isGraphExpansionEnabled,
|
|
122
122
|
rerank,
|
|
123
123
|
rowToCandidate
|
|
124
|
-
} from "./cli-
|
|
124
|
+
} from "./cli-1th1728g.js";
|
|
125
125
|
import {
|
|
126
126
|
getApiKey
|
|
127
127
|
} from "./cli-f14fvzag.js";
|
|
@@ -139,22 +139,29 @@ import {
|
|
|
139
139
|
listAuthorizationsForApp,
|
|
140
140
|
onAuthorizationRefreshed,
|
|
141
141
|
upsertOAuthApp
|
|
142
|
-
} from "./cli-
|
|
142
|
+
} from "./cli-zhjmqxzh.js";
|
|
143
143
|
import {
|
|
144
144
|
ZodFirstPartyTypeKind,
|
|
145
145
|
objectType
|
|
146
146
|
} from "./cli-fad8m16k.js";
|
|
147
|
-
import {
|
|
148
|
-
AgentFsProvider
|
|
149
|
-
} from "./cli-fhsz3twr.js";
|
|
150
147
|
import {
|
|
151
148
|
require_dist
|
|
152
149
|
} from "./cli-51tf7ac3.js";
|
|
153
150
|
import {
|
|
151
|
+
DEFAULT_DOWNLOAD_DIR,
|
|
152
|
+
MAX_FILE_SIZE,
|
|
153
|
+
attachSlackFilesForAgent,
|
|
154
|
+
attachableTask,
|
|
154
155
|
createAdditiveBuffer,
|
|
156
|
+
downloadFile,
|
|
155
157
|
extractSlackMessageText,
|
|
156
|
-
|
|
157
|
-
|
|
158
|
+
getFileInfo,
|
|
159
|
+
parseSlackTs,
|
|
160
|
+
uploadFile
|
|
161
|
+
} from "./cli-mmemxxdc.js";
|
|
162
|
+
import {
|
|
163
|
+
AgentFsProvider
|
|
164
|
+
} from "./cli-jsp14b6c.js";
|
|
158
165
|
import {
|
|
159
166
|
findOrCreateUserByEmail,
|
|
160
167
|
findUserByExternalId,
|
|
@@ -166,14 +173,15 @@ import {
|
|
|
166
173
|
recordIdentityEvent,
|
|
167
174
|
recordUnmappedIdentity,
|
|
168
175
|
renderIdentity,
|
|
176
|
+
resolveBySessionToken,
|
|
169
177
|
resolveIdentity,
|
|
170
178
|
resolveIdentityByEmail,
|
|
171
179
|
resolveUserByToken,
|
|
172
180
|
unlinkIdentity
|
|
173
|
-
} from "./cli-
|
|
181
|
+
} from "./cli-p1d5b073.js";
|
|
174
182
|
import {
|
|
175
183
|
createTaskWithSiblingAwareness
|
|
176
|
-
} from "./cli-
|
|
184
|
+
} from "./cli-53s590z8.js";
|
|
177
185
|
import {
|
|
178
186
|
ensure,
|
|
179
187
|
getAgentDisplayName,
|
|
@@ -184,7 +192,7 @@ import {
|
|
|
184
192
|
startSlackApp,
|
|
185
193
|
stopSlackApp,
|
|
186
194
|
withSpan
|
|
187
|
-
} from "./cli-
|
|
195
|
+
} from "./cli-b5bq9crk.js";
|
|
188
196
|
import {
|
|
189
197
|
$OpenAPIRegistry,
|
|
190
198
|
$OpenApiGeneratorV31,
|
|
@@ -215,7 +223,7 @@ import {
|
|
|
215
223
|
PromptTemplateStateSchema,
|
|
216
224
|
ProviderNameSchema,
|
|
217
225
|
ReasoningEffortSchema,
|
|
218
|
-
|
|
226
|
+
RepoGuidelinesInputSchema,
|
|
219
227
|
RepoHooksSchema,
|
|
220
228
|
ScheduledTaskTargetTypeSchema,
|
|
221
229
|
ScriptRunStatusSchema,
|
|
@@ -431,13 +439,13 @@ import {
|
|
|
431
439
|
upsertPromptTemplate,
|
|
432
440
|
upsertService,
|
|
433
441
|
validateConfigValue
|
|
434
|
-
} from "./cli-
|
|
442
|
+
} from "./cli-ftht3zzj.js";
|
|
435
443
|
import {
|
|
436
444
|
generateDefaultClaudeMd,
|
|
437
445
|
generateDefaultIdentityMd,
|
|
438
446
|
generateDefaultSoulMd,
|
|
439
447
|
init_defaults
|
|
440
|
-
} from "./cli-
|
|
448
|
+
} from "./cli-y6b6fb76.js";
|
|
441
449
|
import {
|
|
442
450
|
getTemplateDefinition,
|
|
443
451
|
init_registry,
|
|
@@ -446,7 +454,7 @@ import {
|
|
|
446
454
|
interpolate,
|
|
447
455
|
registerTemplate,
|
|
448
456
|
resolveTemplate
|
|
449
|
-
} from "./cli-
|
|
457
|
+
} from "./cli-kpv03zhj.js";
|
|
450
458
|
import {
|
|
451
459
|
MAX_PROFILE_FILE_LENGTH,
|
|
452
460
|
getAppUrl,
|
|
@@ -507,7 +515,7 @@ import {
|
|
|
507
515
|
import {
|
|
508
516
|
init_package,
|
|
509
517
|
package_default
|
|
510
|
-
} from "./cli-
|
|
518
|
+
} from "./cli-w9kb3bk1.js";
|
|
511
519
|
import {
|
|
512
520
|
init_secret_scrubber,
|
|
513
521
|
refreshSecretScrubberCache,
|
|
@@ -22295,7 +22303,7 @@ async function notifySlack(text) {
|
|
|
22295
22303
|
return;
|
|
22296
22304
|
}
|
|
22297
22305
|
try {
|
|
22298
|
-
const { getSlackApp: getSlackApp2 } = await import("./app-
|
|
22306
|
+
const { getSlackApp: getSlackApp2 } = await import("./app-w066xfy0.js");
|
|
22299
22307
|
const app = getSlackApp2();
|
|
22300
22308
|
if (!app) {
|
|
22301
22309
|
console.warn("[Jira webhook keepalive] Slack not available, cannot send notification");
|
|
@@ -22366,7 +22374,7 @@ async function deleteJiraWebhook(webhookId) {
|
|
|
22366
22374
|
console.log(`[Jira webhook keepalive] Deleted webhook id=${webhookId}`);
|
|
22367
22375
|
}
|
|
22368
22376
|
async function overwriteWebhookIds(next) {
|
|
22369
|
-
const { getDbClient: getDbClient2 } = await import("./db-
|
|
22377
|
+
const { getDbClient: getDbClient2 } = await import("./db-sfbsc8wt.js");
|
|
22370
22378
|
await getDbClient2().transaction(async (tx) => {
|
|
22371
22379
|
const row = await tx.get("SELECT metadata FROM oauth_apps WHERE provider = 'jira'");
|
|
22372
22380
|
if (!row) {
|
|
@@ -95048,156 +95056,6 @@ function warnIfMcpBaseUrlLooksLikeAppUrl2() {
|
|
|
95048
95056
|
console.warn(`[Linear] WARNING: MCP_BASE_URL (${mcp}) equals APP_URL — surfaced webhook URL points at the dashboard host, not the API. Configure Linear with this URL only if the dashboard host also serves /api/*.`);
|
|
95049
95057
|
}
|
|
95050
95058
|
}
|
|
95051
|
-
// src/slack/files.ts
|
|
95052
|
-
import { createWriteStream } from "node:fs";
|
|
95053
|
-
import { mkdir } from "node:fs/promises";
|
|
95054
|
-
import { dirname } from "node:path";
|
|
95055
|
-
var MAX_FILE_SIZE = 1073741824;
|
|
95056
|
-
var DEFAULT_DOWNLOAD_DIR = `/workspace/shared/downloads/${process.env.AGENT_ID || "default"}/slack`;
|
|
95057
|
-
async function uploadFile(client, options) {
|
|
95058
|
-
const { file, filename, channelId, threadTs, initialComment, title } = options;
|
|
95059
|
-
try {
|
|
95060
|
-
if (Buffer.isBuffer(file) && file.length > MAX_FILE_SIZE) {
|
|
95061
|
-
return {
|
|
95062
|
-
success: false,
|
|
95063
|
-
error: `File size ${file.length} bytes exceeds maximum of ${MAX_FILE_SIZE} bytes (1 GB)`
|
|
95064
|
-
};
|
|
95065
|
-
}
|
|
95066
|
-
if (typeof file === "string") {
|
|
95067
|
-
const bunFile = Bun.file(file);
|
|
95068
|
-
const size = bunFile.size;
|
|
95069
|
-
if (size > MAX_FILE_SIZE) {
|
|
95070
|
-
return {
|
|
95071
|
-
success: false,
|
|
95072
|
-
error: `File size ${size} bytes exceeds maximum of ${MAX_FILE_SIZE} bytes (1 GB)`
|
|
95073
|
-
};
|
|
95074
|
-
}
|
|
95075
|
-
}
|
|
95076
|
-
const uploadArgs = {
|
|
95077
|
-
file,
|
|
95078
|
-
filename,
|
|
95079
|
-
title: title || filename
|
|
95080
|
-
};
|
|
95081
|
-
if (channelId) {
|
|
95082
|
-
uploadArgs.channel_id = channelId;
|
|
95083
|
-
if (threadTs) {
|
|
95084
|
-
uploadArgs.thread_ts = threadTs;
|
|
95085
|
-
}
|
|
95086
|
-
if (initialComment) {
|
|
95087
|
-
uploadArgs.initial_comment = initialComment;
|
|
95088
|
-
}
|
|
95089
|
-
}
|
|
95090
|
-
const result = await client.filesUploadV2(uploadArgs);
|
|
95091
|
-
const uploadedFile = result.files?.[0];
|
|
95092
|
-
const fileId = uploadedFile?.files?.[0]?.id;
|
|
95093
|
-
if (!fileId) {
|
|
95094
|
-
return {
|
|
95095
|
-
success: false,
|
|
95096
|
-
error: "Upload succeeded but no file ID returned"
|
|
95097
|
-
};
|
|
95098
|
-
}
|
|
95099
|
-
return {
|
|
95100
|
-
success: true,
|
|
95101
|
-
fileId
|
|
95102
|
-
};
|
|
95103
|
-
} catch (error) {
|
|
95104
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
95105
|
-
return {
|
|
95106
|
-
success: false,
|
|
95107
|
-
error: errorMsg
|
|
95108
|
-
};
|
|
95109
|
-
}
|
|
95110
|
-
}
|
|
95111
|
-
async function downloadFile(options) {
|
|
95112
|
-
const { file, savePath, token } = options;
|
|
95113
|
-
try {
|
|
95114
|
-
const downloadUrl = typeof file === "string" ? file : file.url_private_download;
|
|
95115
|
-
if (!downloadUrl) {
|
|
95116
|
-
return {
|
|
95117
|
-
success: false,
|
|
95118
|
-
error: "No download URL available for this file"
|
|
95119
|
-
};
|
|
95120
|
-
}
|
|
95121
|
-
let finalPath = savePath;
|
|
95122
|
-
if (typeof file !== "string" && (savePath.endsWith("/") || !savePath.includes("."))) {
|
|
95123
|
-
finalPath = savePath.endsWith("/") ? `${savePath}${file.name}` : `${savePath}/${file.name}`;
|
|
95124
|
-
}
|
|
95125
|
-
await mkdir(dirname(finalPath), { recursive: true });
|
|
95126
|
-
const response = await fetch(downloadUrl, {
|
|
95127
|
-
headers: {
|
|
95128
|
-
Authorization: `Bearer ${token}`
|
|
95129
|
-
}
|
|
95130
|
-
});
|
|
95131
|
-
if (!response.ok) {
|
|
95132
|
-
return {
|
|
95133
|
-
success: false,
|
|
95134
|
-
error: `HTTP error ${response.status}: ${response.statusText}`
|
|
95135
|
-
};
|
|
95136
|
-
}
|
|
95137
|
-
const body = response.body;
|
|
95138
|
-
if (!body) {
|
|
95139
|
-
return {
|
|
95140
|
-
success: false,
|
|
95141
|
-
error: "No response body"
|
|
95142
|
-
};
|
|
95143
|
-
}
|
|
95144
|
-
const writer = createWriteStream(finalPath);
|
|
95145
|
-
const reader = body.getReader();
|
|
95146
|
-
try {
|
|
95147
|
-
while (true) {
|
|
95148
|
-
const { done, value } = await reader.read();
|
|
95149
|
-
if (done)
|
|
95150
|
-
break;
|
|
95151
|
-
writer.write(value);
|
|
95152
|
-
}
|
|
95153
|
-
writer.end();
|
|
95154
|
-
} finally {
|
|
95155
|
-
reader.releaseLock();
|
|
95156
|
-
}
|
|
95157
|
-
await new Promise((resolve, reject) => {
|
|
95158
|
-
writer.on("finish", resolve);
|
|
95159
|
-
writer.on("error", reject);
|
|
95160
|
-
});
|
|
95161
|
-
return {
|
|
95162
|
-
success: true,
|
|
95163
|
-
savedPath: finalPath
|
|
95164
|
-
};
|
|
95165
|
-
} catch (error) {
|
|
95166
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
95167
|
-
return {
|
|
95168
|
-
success: false,
|
|
95169
|
-
error: errorMsg
|
|
95170
|
-
};
|
|
95171
|
-
}
|
|
95172
|
-
}
|
|
95173
|
-
async function getFileInfo(client, fileId) {
|
|
95174
|
-
try {
|
|
95175
|
-
const result = await client.files.info({ file: fileId });
|
|
95176
|
-
if (!result.file) {
|
|
95177
|
-
return null;
|
|
95178
|
-
}
|
|
95179
|
-
const f = result.file;
|
|
95180
|
-
return {
|
|
95181
|
-
id: f.id,
|
|
95182
|
-
name: f.name,
|
|
95183
|
-
title: f.title,
|
|
95184
|
-
mimetype: f.mimetype,
|
|
95185
|
-
filetype: f.filetype,
|
|
95186
|
-
size: f.size,
|
|
95187
|
-
url_private: f.url_private,
|
|
95188
|
-
url_private_download: f.url_private_download,
|
|
95189
|
-
thumb_64: f.thumb_64,
|
|
95190
|
-
thumb_80: f.thumb_80,
|
|
95191
|
-
thumb_160: f.thumb_160,
|
|
95192
|
-
thumb_360: f.thumb_360,
|
|
95193
|
-
thumb_480: f.thumb_480,
|
|
95194
|
-
user: f.user,
|
|
95195
|
-
created: f.created
|
|
95196
|
-
};
|
|
95197
|
-
} catch {
|
|
95198
|
-
return null;
|
|
95199
|
-
}
|
|
95200
|
-
}
|
|
95201
95059
|
// src/http/core.ts
|
|
95202
95060
|
init_request_auth_context();
|
|
95203
95061
|
init_secret_scrubber();
|
|
@@ -95421,6 +95279,12 @@ async function resolveHttpRequestAuth(req, apiKey) {
|
|
|
95421
95279
|
return { kind: "user", userId: user.id, user };
|
|
95422
95280
|
}
|
|
95423
95281
|
}
|
|
95282
|
+
if (bearer.startsWith("aseph_")) {
|
|
95283
|
+
const principal = await resolveBySessionToken(bearer);
|
|
95284
|
+
if (principal) {
|
|
95285
|
+
return { kind: "agent", agentId: principal.agentId, taskId: principal.taskId };
|
|
95286
|
+
}
|
|
95287
|
+
}
|
|
95424
95288
|
return null;
|
|
95425
95289
|
}
|
|
95426
95290
|
function isActiveUser(user) {
|
|
@@ -95438,14 +95302,68 @@ init_secret_scrubber();
|
|
|
95438
95302
|
|
|
95439
95303
|
// src/http/utils.ts
|
|
95440
95304
|
init_db();
|
|
95305
|
+
init_env_flag();
|
|
95441
95306
|
init_secret_scrubber();
|
|
95307
|
+
var DEFAULT_ALLOWED_ORIGINS = [
|
|
95308
|
+
"https://*.agent-swarm.dev",
|
|
95309
|
+
"https://*.agent-swarm.cloud",
|
|
95310
|
+
"http://localhost:5274",
|
|
95311
|
+
"http://127.0.0.1:5274",
|
|
95312
|
+
"http://[::1]:5274",
|
|
95313
|
+
"https://ui.swarm.localhost:1355"
|
|
95314
|
+
];
|
|
95315
|
+
var warnedAboutAllowAnyOrigin = false;
|
|
95316
|
+
function warnIfCorsAllowsAnyOrigin() {
|
|
95317
|
+
if (isEnvFlagEnabled("CORS_ALLOW_ANY_ORIGIN", false) && !warnedAboutAllowAnyOrigin) {
|
|
95318
|
+
warnedAboutAllowAnyOrigin = true;
|
|
95319
|
+
console.warn("[CORS] CORS_ALLOW_ANY_ORIGIN=true: any request origin can receive non-credentialed responses; cookie-authenticated responses still require CORS_ALLOWED_ORIGINS. Set CORS_ALLOWED_ORIGINS and disable CORS_ALLOW_ANY_ORIGIN to restrict access.");
|
|
95320
|
+
}
|
|
95321
|
+
}
|
|
95322
|
+
function getAllowedOrigins() {
|
|
95323
|
+
const raw = process.env.CORS_ALLOWED_ORIGINS;
|
|
95324
|
+
if (!raw || !raw.trim())
|
|
95325
|
+
return DEFAULT_ALLOWED_ORIGINS;
|
|
95326
|
+
return raw.split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
95327
|
+
}
|
|
95328
|
+
function isOriginAllowedForCredentials(origin) {
|
|
95329
|
+
const allowed = getAllowedOrigins().some((entry) => {
|
|
95330
|
+
if (!entry.includes("*"))
|
|
95331
|
+
return entry === origin;
|
|
95332
|
+
const pattern = /^([a-zA-Z][a-zA-Z0-9+.-]*):\/\/\*\.([a-zA-Z0-9.-]+)(:\d+)?$/.exec(entry);
|
|
95333
|
+
const candidate = /^([a-zA-Z][a-zA-Z0-9+.-]*):\/\/([a-zA-Z0-9.-]+)(:\d+)?$/.exec(origin);
|
|
95334
|
+
if (!pattern || !candidate)
|
|
95335
|
+
return false;
|
|
95336
|
+
if (pattern[1] !== candidate[1] || pattern[3] !== candidate[3])
|
|
95337
|
+
return false;
|
|
95338
|
+
const suffix = pattern[2].toLowerCase();
|
|
95339
|
+
const hostname = candidate[2].toLowerCase();
|
|
95340
|
+
const validLabel = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
95341
|
+
if (![...suffix.split("."), ...hostname.split(".")].every((label) => validLabel.test(label))) {
|
|
95342
|
+
return false;
|
|
95343
|
+
}
|
|
95344
|
+
return hostname.endsWith(`.${suffix}`);
|
|
95345
|
+
});
|
|
95346
|
+
if (!allowed) {
|
|
95347
|
+
console.warn(`[CORS] Denied credentialed origin ${scrubSecrets(JSON.stringify(origin.slice(0, 512)))}; add the trusted SPA origin to CORS_ALLOWED_ORIGINS (custom values replace hosted/dev defaults).`);
|
|
95348
|
+
}
|
|
95349
|
+
return allowed;
|
|
95350
|
+
}
|
|
95442
95351
|
function setCorsHeaders(req, res) {
|
|
95443
95352
|
const rawOrigin = req.headers.origin;
|
|
95444
95353
|
const origin = Array.isArray(rawOrigin) ? rawOrigin[0] : rawOrigin;
|
|
95354
|
+
const allowCredentials = origin ? isOriginAllowedForCredentials(origin) : false;
|
|
95355
|
+
const allowAnyOrigin = isEnvFlagEnabled("CORS_ALLOW_ANY_ORIGIN", false);
|
|
95356
|
+
if (allowAnyOrigin)
|
|
95357
|
+
warnIfCorsAllowsAnyOrigin();
|
|
95358
|
+
if (origin && !allowCredentials && !allowAnyOrigin) {
|
|
95359
|
+
res.setHeader("Vary", "Origin");
|
|
95360
|
+
return;
|
|
95361
|
+
}
|
|
95445
95362
|
if (origin) {
|
|
95446
95363
|
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
95447
95364
|
res.setHeader("Vary", "Origin");
|
|
95448
|
-
|
|
95365
|
+
if (allowCredentials)
|
|
95366
|
+
res.setHeader("Access-Control-Allow-Credentials", "true");
|
|
95449
95367
|
const reqHeaders = req.headers["access-control-request-headers"];
|
|
95450
95368
|
const askedHeaders = Array.isArray(reqHeaders) ? reqHeaders.join(", ") : reqHeaders;
|
|
95451
95369
|
res.setHeader("Access-Control-Allow-Headers", askedHeaders ?? "Authorization, Content-Type, X-Agent-ID, X-Requested-With");
|
|
@@ -95962,7 +95880,7 @@ async function reloadGlobalConfigsAndIntegrations() {
|
|
|
95962
95880
|
}
|
|
95963
95881
|
async function reloadGlobalConfigsAndIntegrationsInner() {
|
|
95964
95882
|
const updated = await loadGlobalConfigsIntoEnv(true);
|
|
95965
|
-
const { resetFileStorageProvider } = await import("./registry-
|
|
95883
|
+
const { resetFileStorageProvider } = await import("./registry-v5wytg0s.js");
|
|
95966
95884
|
resetFileStorageProvider();
|
|
95967
95885
|
const integrations = [];
|
|
95968
95886
|
resetAgentMail();
|
|
@@ -96418,6 +96336,14 @@ var scriptRunNudge = (r) => {
|
|
|
96418
96336
|
const body = r.data?.data;
|
|
96419
96337
|
return !r.ok && body?.error === "timeout" ? SCRIPT_RUN_TIMEOUT_NUDGE : scriptAuthoringNudge(r);
|
|
96420
96338
|
};
|
|
96339
|
+
var SLACK_API_DISK_NUDGE = "That path is on the API server's disk, not in your container — call this from a task you own (or pass its taskId) to get the file as a task attachment with a fetchCommand.";
|
|
96340
|
+
var slackDownloadFileNudge = (r) => r.ok && r.data?.savedPath ? SLACK_API_DISK_NUDGE : undefined;
|
|
96341
|
+
var slackReadNudge = (r) => {
|
|
96342
|
+
if (!r.ok)
|
|
96343
|
+
return;
|
|
96344
|
+
const messages = r.data?.messages;
|
|
96345
|
+
return messages?.some((m) => m.files?.some((f) => Boolean(f.localPath))) ? SLACK_API_DISK_NUDGE : undefined;
|
|
96346
|
+
};
|
|
96421
96347
|
var workflowLongScriptTimeoutNudge = (r) => {
|
|
96422
96348
|
if (!r.ok)
|
|
96423
96349
|
return;
|
|
@@ -96425,6 +96351,7 @@ var workflowLongScriptTimeoutNudge = (r) => {
|
|
|
96425
96351
|
return hint ? WORKFLOW_LONG_SCRIPT_TIMEOUT_NUDGE : undefined;
|
|
96426
96352
|
};
|
|
96427
96353
|
var NUDGES = {
|
|
96354
|
+
"defer-task": (r) => r.ok ? "Stop working on this task now; the wake-up task will carry your note." : undefined,
|
|
96428
96355
|
"script-run": scriptRunNudge,
|
|
96429
96356
|
"script-upsert": scriptAuthoringNudge,
|
|
96430
96357
|
"launch-script-run": scriptAuthoringNudge,
|
|
@@ -96433,6 +96360,8 @@ var NUDGES = {
|
|
|
96433
96360
|
"update-workflow": workflowLongScriptTimeoutNudge,
|
|
96434
96361
|
"patch-workflow": workflowLongScriptTimeoutNudge,
|
|
96435
96362
|
"patch-workflow-node": workflowLongScriptTimeoutNudge,
|
|
96363
|
+
"slack-download-file": slackDownloadFileNudge,
|
|
96364
|
+
"slack-read": slackReadNudge,
|
|
96436
96365
|
"script-search": (r) => {
|
|
96437
96366
|
if (!r.ok)
|
|
96438
96367
|
return;
|
|
@@ -101974,8 +101903,8 @@ var registerCreatePageTool = (server) => {
|
|
|
101974
101903
|
key: AssetKeySchema.optional().describe("Logical namespace. Defaults to a shared/page:<id>/ resource key."),
|
|
101975
101904
|
title: string().min(1).describe("Human-readable title shown in listings."),
|
|
101976
101905
|
slug: string().min(1).optional().describe("URL slug. Defaults to the kebab-cased title. Same slug → updates the existing row."),
|
|
101977
|
-
body: string().min(1).describe("Full page body (HTML document or JSON-render spec, per contentType)."),
|
|
101978
|
-
contentType: PageContentTypeSchema.describe("'text/html'
|
|
101906
|
+
body: string().min(1).describe("Full page body (HTML document, SVG image, or JSON-render spec, per contentType)."),
|
|
101907
|
+
contentType: PageContentTypeSchema.describe("'text/html' and 'image/svg+xml' render directly at /p/:id; 'application/json' is rendered by the SPA."),
|
|
101979
101908
|
authMode: PageAuthModeSchema.default("authed").describe("'authed' — requires page-session cookie (default); 'public' — no gate and must be explicit; 'password' — requires key."),
|
|
101980
101909
|
password: string().min(1).optional().describe("Plaintext password, hashed before storage. Only meaningful for authMode='password'."),
|
|
101981
101910
|
description: string().optional().describe("Optional short description, used in listings + OG-tag unfurl."),
|
|
@@ -102674,6 +102603,688 @@ ${result.total} rows in ${result.elapsed}ms`;
|
|
|
102674
102603
|
});
|
|
102675
102604
|
};
|
|
102676
102605
|
|
|
102606
|
+
// src/tools/defer-task.ts
|
|
102607
|
+
init_zod();
|
|
102608
|
+
init_db();
|
|
102609
|
+
|
|
102610
|
+
// src/tasks/task-terminal-effects.ts
|
|
102611
|
+
init_db();
|
|
102612
|
+
|
|
102613
|
+
// src/be/memory/raters/retrieval.ts
|
|
102614
|
+
init_db();
|
|
102615
|
+
function dedupeMemoryDocumentIds(memories) {
|
|
102616
|
+
const documents = new Map;
|
|
102617
|
+
for (const memory of memories) {
|
|
102618
|
+
const identity = memory.sourcePath ?? memory.key;
|
|
102619
|
+
if (identity == null)
|
|
102620
|
+
continue;
|
|
102621
|
+
const documentKey = JSON.stringify([memory.agentId, memory.scope, identity]);
|
|
102622
|
+
if (!documents.has(documentKey))
|
|
102623
|
+
documents.set(documentKey, memory.id);
|
|
102624
|
+
}
|
|
102625
|
+
return [...documents.values()];
|
|
102626
|
+
}
|
|
102627
|
+
async function recordMemoryAccesses(memoryIds) {
|
|
102628
|
+
const ids = [...new Set(memoryIds)].filter(Boolean);
|
|
102629
|
+
if (ids.length === 0)
|
|
102630
|
+
return;
|
|
102631
|
+
const now = new Date().toISOString();
|
|
102632
|
+
await getDbClient().transaction(async (tx) => {
|
|
102633
|
+
for (const id of ids) {
|
|
102634
|
+
await tx.run("UPDATE agent_memory SET accessedAt = ?, accessCount = accessCount + 1 WHERE id = ?", [now, id]);
|
|
102635
|
+
}
|
|
102636
|
+
});
|
|
102637
|
+
}
|
|
102638
|
+
async function recordRetrievals(taskId, agentId, results, sessionId, extras) {
|
|
102639
|
+
if (!taskId || results.length === 0)
|
|
102640
|
+
return;
|
|
102641
|
+
const insertSql = `INSERT INTO memory_retrieval
|
|
102642
|
+
(id, taskId, agentId, sessionId, memoryId, similarity, retrievedAt, contextKey, intent, eventType, retrievalId, rank, retrievalSource)
|
|
102643
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
|
|
102644
|
+
const now = new Date().toISOString();
|
|
102645
|
+
const retrievalId = crypto.randomUUID();
|
|
102646
|
+
const contextKey = extras?.contextKey ?? null;
|
|
102647
|
+
const intent = extras?.intent ?? null;
|
|
102648
|
+
const eventType = extras?.eventType ?? "search";
|
|
102649
|
+
await getDbClient().transaction(async (tx) => {
|
|
102650
|
+
for (const [rank, r] of results.entries()) {
|
|
102651
|
+
await tx.run(insertSql, [
|
|
102652
|
+
crypto.randomUUID(),
|
|
102653
|
+
taskId,
|
|
102654
|
+
agentId,
|
|
102655
|
+
sessionId ?? null,
|
|
102656
|
+
r.memoryId,
|
|
102657
|
+
r.similarity,
|
|
102658
|
+
now,
|
|
102659
|
+
contextKey,
|
|
102660
|
+
intent,
|
|
102661
|
+
eventType,
|
|
102662
|
+
retrievalId,
|
|
102663
|
+
rank,
|
|
102664
|
+
r.retrievalSource ?? null
|
|
102665
|
+
]);
|
|
102666
|
+
}
|
|
102667
|
+
});
|
|
102668
|
+
ensure({
|
|
102669
|
+
id: "memory_retrieved",
|
|
102670
|
+
flow: "task",
|
|
102671
|
+
runId: taskId,
|
|
102672
|
+
data: {
|
|
102673
|
+
count: results.length,
|
|
102674
|
+
taskId,
|
|
102675
|
+
agentId
|
|
102676
|
+
},
|
|
102677
|
+
validator: (data) => typeof data.count === "number" && data.count > 0 && typeof data.taskId === "string" && data.taskId.length > 0 && typeof data.agentId === "string" && data.agentId.length > 0
|
|
102678
|
+
});
|
|
102679
|
+
}
|
|
102680
|
+
async function getRetrievalsForTask(taskId) {
|
|
102681
|
+
return getDbClient().query("SELECT memoryId, similarity FROM memory_retrieval WHERE taskId = ?", [taskId]);
|
|
102682
|
+
}
|
|
102683
|
+
|
|
102684
|
+
// src/be/memory/raters/explicit-self.ts
|
|
102685
|
+
class ExplicitSelfRatingRater {
|
|
102686
|
+
name = "explicit-self";
|
|
102687
|
+
async rate() {
|
|
102688
|
+
return [];
|
|
102689
|
+
}
|
|
102690
|
+
}
|
|
102691
|
+
|
|
102692
|
+
// src/be/memory/raters/implicit-citation.ts
|
|
102693
|
+
class ImplicitCitationRater {
|
|
102694
|
+
name = "implicit-citation";
|
|
102695
|
+
async rate(ctx) {
|
|
102696
|
+
if (ctx.retrievedMemoryIds.length === 0)
|
|
102697
|
+
return [];
|
|
102698
|
+
const evidence = ctx.evidence ?? "";
|
|
102699
|
+
const events = [];
|
|
102700
|
+
for (const memoryId of ctx.retrievedMemoryIds) {
|
|
102701
|
+
if (evidence.length > 0 && evidence.includes(memoryId)) {
|
|
102702
|
+
events.push({ memoryId, signal: 1, weight: 0.5, source: "" });
|
|
102703
|
+
} else {
|
|
102704
|
+
events.push({ memoryId, signal: -1, weight: 0.25, source: "" });
|
|
102705
|
+
}
|
|
102706
|
+
}
|
|
102707
|
+
return events;
|
|
102708
|
+
}
|
|
102709
|
+
}
|
|
102710
|
+
|
|
102711
|
+
// src/be/memory/raters/noop.ts
|
|
102712
|
+
class NoopRater {
|
|
102713
|
+
name = "noop";
|
|
102714
|
+
async rate() {
|
|
102715
|
+
return [];
|
|
102716
|
+
}
|
|
102717
|
+
}
|
|
102718
|
+
|
|
102719
|
+
// src/be/memory/raters/registry.ts
|
|
102720
|
+
var FACTORIES = {
|
|
102721
|
+
noop: () => new NoopRater,
|
|
102722
|
+
"implicit-citation": () => new ImplicitCitationRater,
|
|
102723
|
+
"explicit-self": () => new ExplicitSelfRatingRater,
|
|
102724
|
+
llm: () => new LlmRater
|
|
102725
|
+
};
|
|
102726
|
+
var SERVER_RATERS = new Set(["implicit-citation"]);
|
|
102727
|
+
function getRegisteredRaters() {
|
|
102728
|
+
const raw = process.env.MEMORY_RATERS;
|
|
102729
|
+
if (!raw || raw.trim() === "") {
|
|
102730
|
+
return [new NoopRater];
|
|
102731
|
+
}
|
|
102732
|
+
const names = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
102733
|
+
const raters = [];
|
|
102734
|
+
for (const name of names) {
|
|
102735
|
+
const factory = FACTORIES[name];
|
|
102736
|
+
if (!factory) {
|
|
102737
|
+
console.warn(`[memory-rater] Unknown rater "${name}" in MEMORY_RATERS — skipping`);
|
|
102738
|
+
continue;
|
|
102739
|
+
}
|
|
102740
|
+
raters.push(factory());
|
|
102741
|
+
}
|
|
102742
|
+
if (raters.length === 0) {
|
|
102743
|
+
return [new NoopRater];
|
|
102744
|
+
}
|
|
102745
|
+
return raters;
|
|
102746
|
+
}
|
|
102747
|
+
function getRaterWeightMultiplier(name) {
|
|
102748
|
+
const raw = process.env.MEMORY_RATER_WEIGHTS;
|
|
102749
|
+
if (!raw || raw.trim() === "")
|
|
102750
|
+
return 1;
|
|
102751
|
+
for (const pair of raw.split(",")) {
|
|
102752
|
+
const trimmed = pair.trim();
|
|
102753
|
+
if (trimmed === "")
|
|
102754
|
+
continue;
|
|
102755
|
+
const [rawName, rawMult] = trimmed.split(":");
|
|
102756
|
+
if (!rawName || !rawMult)
|
|
102757
|
+
continue;
|
|
102758
|
+
if (rawName.trim() !== name)
|
|
102759
|
+
continue;
|
|
102760
|
+
const mult = Number(rawMult);
|
|
102761
|
+
if (Number.isFinite(mult) && mult >= 0)
|
|
102762
|
+
return mult;
|
|
102763
|
+
}
|
|
102764
|
+
return 1;
|
|
102765
|
+
}
|
|
102766
|
+
|
|
102767
|
+
// src/be/memory/raters/store.ts
|
|
102768
|
+
init_db();
|
|
102769
|
+
class ExplicitSelfDuplicateError extends Error {
|
|
102770
|
+
event;
|
|
102771
|
+
constructor(message, event) {
|
|
102772
|
+
super(message);
|
|
102773
|
+
this.event = event;
|
|
102774
|
+
this.name = "ExplicitSelfDuplicateError";
|
|
102775
|
+
}
|
|
102776
|
+
}
|
|
102777
|
+
async function applyRating(events, ctx = {}) {
|
|
102778
|
+
if (events.length === 0) {
|
|
102779
|
+
return { applied: 0, rejected: [] };
|
|
102780
|
+
}
|
|
102781
|
+
const accepted = [];
|
|
102782
|
+
const rejected = [];
|
|
102783
|
+
for (const event of events) {
|
|
102784
|
+
const reason = validate(event);
|
|
102785
|
+
if (reason) {
|
|
102786
|
+
rejected.push({ event, reason });
|
|
102787
|
+
continue;
|
|
102788
|
+
}
|
|
102789
|
+
let sanitizedReferencesSource = null;
|
|
102790
|
+
if (event.referencesSource !== undefined) {
|
|
102791
|
+
if (event.referencesSource.length === 0) {
|
|
102792
|
+
rejected.push({ event, reason: "referencesSource must be non-empty" });
|
|
102793
|
+
continue;
|
|
102794
|
+
}
|
|
102795
|
+
if (event.referencesSource.length > REFERENCES_SOURCE_MAX_LENGTH) {
|
|
102796
|
+
rejected.push({
|
|
102797
|
+
event,
|
|
102798
|
+
reason: `referencesSource exceeds ${REFERENCES_SOURCE_MAX_LENGTH} chars`
|
|
102799
|
+
});
|
|
102800
|
+
continue;
|
|
102801
|
+
}
|
|
102802
|
+
sanitizedReferencesSource = sanitizeReferencesSource(event.referencesSource);
|
|
102803
|
+
if (sanitizedReferencesSource === null) {
|
|
102804
|
+
rejected.push({
|
|
102805
|
+
event,
|
|
102806
|
+
reason: "referencesSource contains a NUL byte or strips to empty"
|
|
102807
|
+
});
|
|
102808
|
+
continue;
|
|
102809
|
+
}
|
|
102810
|
+
}
|
|
102811
|
+
accepted.push({ event, sanitizedReferencesSource });
|
|
102812
|
+
}
|
|
102813
|
+
if (accepted.length === 0) {
|
|
102814
|
+
return { applied: 0, rejected };
|
|
102815
|
+
}
|
|
102816
|
+
const UPDATE_MEMORY_SQL = "UPDATE agent_memory SET alpha = alpha + ?, beta = beta + ? WHERE id = ?";
|
|
102817
|
+
const CHECK_EXISTS_SQL = "SELECT id FROM agent_memory WHERE id = ?";
|
|
102818
|
+
const INSERT_RATING_SQL = `INSERT INTO memory_rating
|
|
102819
|
+
(id, memoryId, taskId, source, signal, weight, reasoning, createdAt, contextKey)
|
|
102820
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`;
|
|
102821
|
+
const UPSERT_EDGE_SQL = `INSERT INTO agent_memory_edge (from_id, to_id, type, alpha, beta, createdAt)
|
|
102822
|
+
VALUES (?, ?, 'references-source', ?, ?, ?)
|
|
102823
|
+
ON CONFLICT(from_id, to_id, type) DO UPDATE SET
|
|
102824
|
+
alpha = alpha + excluded.alpha - 1.0,
|
|
102825
|
+
beta = beta + excluded.beta - 1.0`;
|
|
102826
|
+
const { applied, lateRejects, appliedEvents } = await getDbClient().transaction(async (tx) => {
|
|
102827
|
+
let applied2 = 0;
|
|
102828
|
+
const lateRejects2 = [];
|
|
102829
|
+
const appliedEvents2 = [];
|
|
102830
|
+
for (const { event, sanitizedReferencesSource } of accepted) {
|
|
102831
|
+
const exists = await tx.get(CHECK_EXISTS_SQL, [event.memoryId]);
|
|
102832
|
+
if (!exists) {
|
|
102833
|
+
lateRejects2.push({ event, reason: "memoryId not found in agent_memory" });
|
|
102834
|
+
continue;
|
|
102835
|
+
}
|
|
102836
|
+
const alphaDelta = Math.max(0, event.signal) * event.weight;
|
|
102837
|
+
const betaDelta = Math.max(0, -event.signal) * event.weight;
|
|
102838
|
+
await tx.run(UPDATE_MEMORY_SQL, [alphaDelta, betaDelta, event.memoryId]);
|
|
102839
|
+
try {
|
|
102840
|
+
await tx.run(INSERT_RATING_SQL, [
|
|
102841
|
+
crypto.randomUUID(),
|
|
102842
|
+
event.memoryId,
|
|
102843
|
+
ctx.taskId ?? null,
|
|
102844
|
+
event.source,
|
|
102845
|
+
event.signal,
|
|
102846
|
+
event.weight,
|
|
102847
|
+
event.reasoning ?? null,
|
|
102848
|
+
new Date().toISOString(),
|
|
102849
|
+
ctx.contextKey ?? null
|
|
102850
|
+
]);
|
|
102851
|
+
} catch (err) {
|
|
102852
|
+
if (isUniqueConstraintError(err)) {
|
|
102853
|
+
throw new ExplicitSelfDuplicateError(`duplicate explicit-self rating for memoryId=${event.memoryId} taskId=${ctx.taskId}`, event);
|
|
102854
|
+
}
|
|
102855
|
+
throw err;
|
|
102856
|
+
}
|
|
102857
|
+
if (sanitizedReferencesSource !== null) {
|
|
102858
|
+
await tx.run(UPSERT_EDGE_SQL, [
|
|
102859
|
+
event.memoryId,
|
|
102860
|
+
sanitizedReferencesSource,
|
|
102861
|
+
1 + alphaDelta,
|
|
102862
|
+
1 + betaDelta,
|
|
102863
|
+
new Date().toISOString()
|
|
102864
|
+
]);
|
|
102865
|
+
}
|
|
102866
|
+
appliedEvents2.push({ event, sanitizedReferencesSource });
|
|
102867
|
+
applied2 += 1;
|
|
102868
|
+
}
|
|
102869
|
+
return { applied: applied2, lateRejects: lateRejects2, appliedEvents: appliedEvents2 };
|
|
102870
|
+
});
|
|
102871
|
+
if (ctx.taskId && appliedEvents.length > 0) {
|
|
102872
|
+
for (const { event, sanitizedReferencesSource } of appliedEvents) {
|
|
102873
|
+
ensure({
|
|
102874
|
+
id: "memory_rated",
|
|
102875
|
+
flow: "task",
|
|
102876
|
+
runId: ctx.taskId,
|
|
102877
|
+
data: {
|
|
102878
|
+
memoryId: event.memoryId,
|
|
102879
|
+
source: event.source,
|
|
102880
|
+
signal: event.signal,
|
|
102881
|
+
weight: event.weight,
|
|
102882
|
+
hasReferencesSource: sanitizedReferencesSource !== null
|
|
102883
|
+
},
|
|
102884
|
+
validator: (data) => typeof data.memoryId === "string" && data.memoryId.length > 0 && typeof data.source === "string" && data.source.length > 0 && typeof data.signal === "number" && data.signal >= -1 && data.signal <= 1 && typeof data.weight === "number" && data.weight >= 0 && data.weight <= 1
|
|
102885
|
+
});
|
|
102886
|
+
}
|
|
102887
|
+
}
|
|
102888
|
+
return { applied, rejected: [...rejected, ...lateRejects] };
|
|
102889
|
+
}
|
|
102890
|
+
function validate(event) {
|
|
102891
|
+
if (!event.source || event.source.trim() === "") {
|
|
102892
|
+
return "source is required";
|
|
102893
|
+
}
|
|
102894
|
+
if (!Number.isFinite(event.signal) || event.signal < -1 || event.signal > 1) {
|
|
102895
|
+
return "signal must be in [-1, +1]";
|
|
102896
|
+
}
|
|
102897
|
+
if (!Number.isFinite(event.weight) || event.weight < 0 || event.weight > 1) {
|
|
102898
|
+
return "weight must be in [0, 1]";
|
|
102899
|
+
}
|
|
102900
|
+
if (!event.memoryId) {
|
|
102901
|
+
return "memoryId is required";
|
|
102902
|
+
}
|
|
102903
|
+
return null;
|
|
102904
|
+
}
|
|
102905
|
+
function isUniqueConstraintError(err) {
|
|
102906
|
+
if (!(err instanceof Error))
|
|
102907
|
+
return false;
|
|
102908
|
+
return /UNIQUE constraint failed|SQLITE_CONSTRAINT/i.test(err.message);
|
|
102909
|
+
}
|
|
102910
|
+
|
|
102911
|
+
// src/be/memory/raters/run-server-raters.ts
|
|
102912
|
+
async function runServerRaters(input, deps = {}) {
|
|
102913
|
+
const result = { ratersFired: 0, outcomes: [] };
|
|
102914
|
+
if (input.retrievedMemoryIds.length === 0)
|
|
102915
|
+
return result;
|
|
102916
|
+
const allRaters = deps.raters ?? getRegisteredRaters();
|
|
102917
|
+
const allowed = deps.serverRaterNames ?? SERVER_RATERS;
|
|
102918
|
+
const weightFor = deps.weightMultiplierFor ?? getRaterWeightMultiplier;
|
|
102919
|
+
const applyFn = deps.applyRating ?? applyRating;
|
|
102920
|
+
const serverRaters = allRaters.filter((r) => allowed.has(r.name));
|
|
102921
|
+
for (const rater of serverRaters) {
|
|
102922
|
+
const events = await rater.rate({
|
|
102923
|
+
taskId: input.taskId,
|
|
102924
|
+
agentId: input.agentId,
|
|
102925
|
+
retrievedMemoryIds: input.retrievedMemoryIds,
|
|
102926
|
+
evidence: input.evidence
|
|
102927
|
+
});
|
|
102928
|
+
if (events.length === 0)
|
|
102929
|
+
continue;
|
|
102930
|
+
const multiplier = weightFor(rater.name);
|
|
102931
|
+
const stamped = events.map((e) => ({
|
|
102932
|
+
...e,
|
|
102933
|
+
source: rater.name,
|
|
102934
|
+
weight: Math.max(0, Math.min(1, e.weight * multiplier))
|
|
102935
|
+
}));
|
|
102936
|
+
const applied = await applyFn(stamped, { taskId: input.taskId });
|
|
102937
|
+
result.ratersFired += 1;
|
|
102938
|
+
result.outcomes.push({ rater: rater.name, events: stamped, result: applied });
|
|
102939
|
+
}
|
|
102940
|
+
return result;
|
|
102941
|
+
}
|
|
102942
|
+
|
|
102943
|
+
// src/memory/automatic-task-gate.ts
|
|
102944
|
+
var SCHEDULE_TAG_PREFIX = "schedule:";
|
|
102945
|
+
var AUTOMATIC_TASK_TYPES = new Set([
|
|
102946
|
+
"boot-triage",
|
|
102947
|
+
"heartbeat",
|
|
102948
|
+
"heartbeat-checklist",
|
|
102949
|
+
"health-check",
|
|
102950
|
+
"health-probe",
|
|
102951
|
+
"monitor",
|
|
102952
|
+
"monitoring"
|
|
102953
|
+
]);
|
|
102954
|
+
function isAutomaticOrRecurringTaskCompletion(task) {
|
|
102955
|
+
const tags = task.tags ?? [];
|
|
102956
|
+
const taskType = task.taskType?.toLowerCase();
|
|
102957
|
+
return task.source === "schedule" || task.source === "system" || tags.includes("scheduled") || tags.includes("auto-generated") || tags.some((tag) => tag.startsWith(SCHEDULE_TAG_PREFIX)) || taskType !== undefined && (AUTOMATIC_TASK_TYPES.has(taskType) || taskType.endsWith("-monitor") || taskType.endsWith("-digest"));
|
|
102958
|
+
}
|
|
102959
|
+
function shouldPersistAutomaticTaskMemory(task, persistMemory) {
|
|
102960
|
+
if (persistMemory)
|
|
102961
|
+
return true;
|
|
102962
|
+
return !isAutomaticOrRecurringTaskCompletion(task);
|
|
102963
|
+
}
|
|
102964
|
+
var shouldPersistTaskCompletionMemory = shouldPersistAutomaticTaskMemory;
|
|
102965
|
+
|
|
102966
|
+
// src/tasks/task-terminal-effects.ts
|
|
102967
|
+
init_secret_scrubber();
|
|
102968
|
+
async function runTaskTerminalEffects(args) {
|
|
102969
|
+
const { task, status, output, failureReason, agentId, persistMemory } = args;
|
|
102970
|
+
const taskId = task.id;
|
|
102971
|
+
if (shouldPersistTaskCompletionMemory(task, persistMemory)) {
|
|
102972
|
+
(async () => {
|
|
102973
|
+
try {
|
|
102974
|
+
const taskContent = status === "completed" ? `Task: ${task.task}
|
|
102975
|
+
|
|
102976
|
+
Output:
|
|
102977
|
+
${output || "(no output)"}` : `Task: ${task.task}
|
|
102978
|
+
|
|
102979
|
+
Failure reason:
|
|
102980
|
+
${failureReason || "No reason provided"}
|
|
102981
|
+
|
|
102982
|
+
This task failed. Learn from this to avoid repeating the mistake.`;
|
|
102983
|
+
if (taskContent.length < 30)
|
|
102984
|
+
return;
|
|
102985
|
+
const store = getMemoryStore();
|
|
102986
|
+
const provider = getEmbeddingProvider();
|
|
102987
|
+
const memory = await store.store({
|
|
102988
|
+
agentId: agentId ?? null,
|
|
102989
|
+
content: taskContent,
|
|
102990
|
+
name: `Task: ${task.task.slice(0, 80)}`,
|
|
102991
|
+
scope: "agent",
|
|
102992
|
+
source: "task_completion",
|
|
102993
|
+
sourceTaskId: taskId
|
|
102994
|
+
});
|
|
102995
|
+
const embedding = await provider.embed(taskContent);
|
|
102996
|
+
if (embedding) {
|
|
102997
|
+
await store.updateEmbedding(memory.id, embedding, provider.name);
|
|
102998
|
+
}
|
|
102999
|
+
const shouldShareWithSwarm = status === "completed" && (task.taskType === "research" || task.tags?.includes("knowledge") || task.tags?.includes("shared"));
|
|
103000
|
+
if (shouldShareWithSwarm) {
|
|
103001
|
+
try {
|
|
103002
|
+
const swarmMemory = await store.store({
|
|
103003
|
+
agentId: agentId ?? null,
|
|
103004
|
+
scope: "swarm",
|
|
103005
|
+
name: `Shared: ${task.task.slice(0, 80)}`,
|
|
103006
|
+
content: `Task completed by agent ${agentId}:
|
|
103007
|
+
|
|
103008
|
+
${taskContent}`,
|
|
103009
|
+
source: "task_completion",
|
|
103010
|
+
sourceTaskId: taskId
|
|
103011
|
+
});
|
|
103012
|
+
const swarmEmbedding = await provider.embed(taskContent);
|
|
103013
|
+
if (swarmEmbedding) {
|
|
103014
|
+
await store.updateEmbedding(swarmMemory.id, swarmEmbedding, provider.name);
|
|
103015
|
+
}
|
|
103016
|
+
} catch {}
|
|
103017
|
+
}
|
|
103018
|
+
} catch {}
|
|
103019
|
+
})().catch((err) => console.error("[task-terminal-effects] task completion memory write failed:", scrubSecrets(err instanceof Error ? err.message : String(err))));
|
|
103020
|
+
}
|
|
103021
|
+
(async () => {
|
|
103022
|
+
try {
|
|
103023
|
+
const retrievals = await getRetrievalsForTask(taskId);
|
|
103024
|
+
if (retrievals.length === 0)
|
|
103025
|
+
return;
|
|
103026
|
+
const retrievedMemoryIds = retrievals.map((r) => r.memoryId);
|
|
103027
|
+
const logs = await getSessionLogsByTaskId(taskId);
|
|
103028
|
+
const evidence = logs.map((l) => l.content).join(`
|
|
103029
|
+
`);
|
|
103030
|
+
await runServerRaters({
|
|
103031
|
+
taskId,
|
|
103032
|
+
agentId: agentId ?? "",
|
|
103033
|
+
retrievedMemoryIds,
|
|
103034
|
+
evidence
|
|
103035
|
+
});
|
|
103036
|
+
} catch (err) {
|
|
103037
|
+
console.error("[task-terminal-effects] server-rater fire failed:", err instanceof Error ? err.message : String(err));
|
|
103038
|
+
}
|
|
103039
|
+
})().catch((err) => console.error("[task-terminal-effects] server rater run failed:", scrubSecrets(err instanceof Error ? err.message : String(err))));
|
|
103040
|
+
if (!task.workflowRunId) {
|
|
103041
|
+
try {
|
|
103042
|
+
const followUp = await createWorkerTaskFollowUp({ task, status, output, failureReason });
|
|
103043
|
+
if (followUp) {
|
|
103044
|
+
console.log(`[task-terminal-effects] Created follow-up task ${followUp.id.slice(0, 8)} for ${status} task ${taskId.slice(0, 8)}`);
|
|
103045
|
+
}
|
|
103046
|
+
} catch (err) {
|
|
103047
|
+
console.warn(`[task-terminal-effects] Failed to create follow-up task: ${err}`);
|
|
103048
|
+
}
|
|
103049
|
+
}
|
|
103050
|
+
}
|
|
103051
|
+
|
|
103052
|
+
// src/tasks/terminal-result-guard.ts
|
|
103053
|
+
init_db();
|
|
103054
|
+
init_types();
|
|
103055
|
+
init_secret_scrubber();
|
|
103056
|
+
function getTaskOutputValidationError(outputSchema, output) {
|
|
103057
|
+
if (!outputSchema || typeof outputSchema !== "object")
|
|
103058
|
+
return;
|
|
103059
|
+
const schema = outputSchema;
|
|
103060
|
+
if (!output) {
|
|
103061
|
+
return `Task has an outputSchema but no output was provided. You must call store-progress with a valid JSON output matching this schema:
|
|
103062
|
+
${JSON.stringify(schema, null, 2)}`;
|
|
103063
|
+
}
|
|
103064
|
+
let parsed;
|
|
103065
|
+
try {
|
|
103066
|
+
parsed = JSON.parse(output);
|
|
103067
|
+
} catch {
|
|
103068
|
+
return `Task output must be valid JSON matching the outputSchema. Got invalid JSON. Schema:
|
|
103069
|
+
${JSON.stringify(schema, null, 2)}`;
|
|
103070
|
+
}
|
|
103071
|
+
let validationErrors;
|
|
103072
|
+
try {
|
|
103073
|
+
validationErrors = validateJsonSchema(schema, parsed);
|
|
103074
|
+
} catch (error) {
|
|
103075
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
103076
|
+
return `Task outputSchema is malformed and cannot be validated (${detail}). Ask an operator to correct the task's outputSchema, or force-complete with store-progress force: true.`;
|
|
103077
|
+
}
|
|
103078
|
+
if (validationErrors.length > 0) {
|
|
103079
|
+
return `Task output does not match the outputSchema. Errors:
|
|
103080
|
+
${validationErrors.join(`
|
|
103081
|
+
`)}
|
|
103082
|
+
|
|
103083
|
+
Expected schema:
|
|
103084
|
+
${JSON.stringify(schema, null, 2)}
|
|
103085
|
+
|
|
103086
|
+
Please fix your output and retry.`;
|
|
103087
|
+
}
|
|
103088
|
+
return;
|
|
103089
|
+
}
|
|
103090
|
+
async function guardTerminalTaskResultWrite(task, write) {
|
|
103091
|
+
if (!isTerminalTaskStatus(task.status) || !write.status && !write.force) {
|
|
103092
|
+
return { handled: false };
|
|
103093
|
+
}
|
|
103094
|
+
const scrubbedOutput = write.output !== undefined ? scrubSecrets(write.output) : undefined;
|
|
103095
|
+
const scrubbedFailureReason = write.failureReason !== undefined ? scrubSecrets(write.failureReason) : undefined;
|
|
103096
|
+
const hasDifferingOutput = scrubbedOutput !== undefined && scrubbedOutput !== task.output;
|
|
103097
|
+
const hasDifferingFailureReason = scrubbedFailureReason !== undefined && scrubbedFailureReason !== task.failureReason;
|
|
103098
|
+
const hasDifferingResultText = hasDifferingOutput || hasDifferingFailureReason;
|
|
103099
|
+
if (hasDifferingResultText && write.force) {
|
|
103100
|
+
const outputValidationError = hasDifferingOutput ? getTaskOutputValidationError(task.outputSchema, write.output) : undefined;
|
|
103101
|
+
if (outputValidationError) {
|
|
103102
|
+
return { handled: true, success: false, message: outputValidationError, task };
|
|
103103
|
+
}
|
|
103104
|
+
const overwrittenTask = await overwriteTerminalTaskResultText(task.id, {
|
|
103105
|
+
...write.output !== undefined ? { output: write.output } : {},
|
|
103106
|
+
...write.failureReason !== undefined ? { failureReason: write.failureReason } : {}
|
|
103107
|
+
});
|
|
103108
|
+
if (!overwrittenTask) {
|
|
103109
|
+
return {
|
|
103110
|
+
handled: true,
|
|
103111
|
+
success: false,
|
|
103112
|
+
message: `Task "${task.id}" terminal result text could not be overwritten.`,
|
|
103113
|
+
task
|
|
103114
|
+
};
|
|
103115
|
+
}
|
|
103116
|
+
return {
|
|
103117
|
+
handled: true,
|
|
103118
|
+
success: true,
|
|
103119
|
+
message: `Task "${task.id}" is already ${task.status}; force-overwrote terminal result text ` + "without replaying completion side effects.",
|
|
103120
|
+
task: overwrittenTask,
|
|
103121
|
+
wasForcedOverwrite: true
|
|
103122
|
+
};
|
|
103123
|
+
}
|
|
103124
|
+
if (hasDifferingResultText) {
|
|
103125
|
+
return {
|
|
103126
|
+
handled: true,
|
|
103127
|
+
success: false,
|
|
103128
|
+
message: `Discarded write for already-${task.status} task "${task.id}"; ` + "existing output/failureReason and finishedAt were preserved. Retry with force: true " + "to overwrite terminal result text without replaying completion side effects.",
|
|
103129
|
+
task
|
|
103130
|
+
};
|
|
103131
|
+
}
|
|
103132
|
+
return {
|
|
103133
|
+
handled: true,
|
|
103134
|
+
success: true,
|
|
103135
|
+
message: `Task "${task.id}" is already ${task.status}; treating as no-op. ` + "Existing output preserved (first-call-wins).",
|
|
103136
|
+
task,
|
|
103137
|
+
wasNoOp: true
|
|
103138
|
+
};
|
|
103139
|
+
}
|
|
103140
|
+
|
|
103141
|
+
// src/tools/defer-task.ts
|
|
103142
|
+
init_types();
|
|
103143
|
+
|
|
103144
|
+
class DeferAbortedError extends Error {
|
|
103145
|
+
}
|
|
103146
|
+
function renderChecks(checks2) {
|
|
103147
|
+
if (!checks2 || checks2.length === 0)
|
|
103148
|
+
return "";
|
|
103149
|
+
return `
|
|
103150
|
+
|
|
103151
|
+
Checks:
|
|
103152
|
+
${checks2.map((c) => `- ${c}`).join(`
|
|
103153
|
+
`)}`;
|
|
103154
|
+
}
|
|
103155
|
+
var registerDeferTaskTool = (server) => {
|
|
103156
|
+
createToolRegistrar(server)("defer-task", {
|
|
103157
|
+
title: "Defer Task",
|
|
103158
|
+
annotations: { destructiveHint: false, idempotentHint: false },
|
|
103159
|
+
description: "Completes this task now with status `completed` and books a wake-up for you. Use when the result needs time: a build, a deploy, a reply. The task reaches its final state on this call; the lead sees your summary as its output. A one-off schedule wakes you up later with a child task that carries this task as its parent. Provide delayMs or runAt, a summary of what you did, and a note that says what is pending and what to check.",
|
|
103160
|
+
inputSchema: object({
|
|
103161
|
+
taskId: string().describe("The ID of the task you are working on."),
|
|
103162
|
+
delayMs: number().int().positive().optional().describe("Wake up after this many milliseconds (e.g. 1800000 for 30 min)."),
|
|
103163
|
+
runAt: string().datetime().optional().describe("Wake up at this ISO datetime (e.g. '2026-03-06T15:00:00Z'). Must be future."),
|
|
103164
|
+
summary: string().min(1).max(4000).describe("What you did so far and where things stand. This becomes the task's output; the lead and your wake-up run both read it."),
|
|
103165
|
+
note: string().min(1).max(2000).describe("What is pending, and what to check on wake-up."),
|
|
103166
|
+
checks: array(string().min(1)).max(20).optional().describe("Concrete things to verify on wake-up, one per entry.")
|
|
103167
|
+
}),
|
|
103168
|
+
outputSchema: swarmToolOutputSchema({
|
|
103169
|
+
yourAgentId: string().optional(),
|
|
103170
|
+
taskId: string().optional(),
|
|
103171
|
+
scheduleId: string().optional(),
|
|
103172
|
+
nextRunAt: string().optional()
|
|
103173
|
+
})
|
|
103174
|
+
}, async ({ taskId, delayMs, runAt, summary, note, checks: checks2 }, requestInfo, _meta) => {
|
|
103175
|
+
if (!requestInfo.agentId) {
|
|
103176
|
+
return toolErr('Agent ID not found. Set the "X-Agent-ID" header.');
|
|
103177
|
+
}
|
|
103178
|
+
const agent = await getAgentById(requestInfo.agentId);
|
|
103179
|
+
if (!agent) {
|
|
103180
|
+
return toolErr(`Agent not found: ${requestInfo.agentId}`);
|
|
103181
|
+
}
|
|
103182
|
+
const task = await getTaskById(taskId);
|
|
103183
|
+
if (!task) {
|
|
103184
|
+
return toolErr(`Task with ID "${taskId}" not found.`);
|
|
103185
|
+
}
|
|
103186
|
+
const forbidden = assertOwnsTask(ownerCtx(requestInfo), task);
|
|
103187
|
+
if (forbidden)
|
|
103188
|
+
return forbidden;
|
|
103189
|
+
if (task.agentId !== requestInfo.agentId) {
|
|
103190
|
+
return toolErr(`Task "${taskId}" is not assigned to you.`);
|
|
103191
|
+
}
|
|
103192
|
+
if (isTerminalTaskStatus(task.status)) {
|
|
103193
|
+
return toolErr(`Task ${taskId} is already ${task.status}; nothing to defer.`);
|
|
103194
|
+
}
|
|
103195
|
+
if (task.workflowRunId) {
|
|
103196
|
+
return toolErr(`Task ${taskId} is owned by workflow run ${task.workflowRunId}; workflow-owned tasks cannot be deferred.`);
|
|
103197
|
+
}
|
|
103198
|
+
if (!delayMs && !runAt) {
|
|
103199
|
+
return toolErr("Provide either delayMs or runAt.");
|
|
103200
|
+
}
|
|
103201
|
+
if (delayMs && runAt) {
|
|
103202
|
+
return toolErr("Provide either delayMs or runAt, not both.");
|
|
103203
|
+
}
|
|
103204
|
+
if (runAt && new Date(runAt).getTime() <= Date.now()) {
|
|
103205
|
+
return toolErr("runAt must be in the future.");
|
|
103206
|
+
}
|
|
103207
|
+
const nextRunAt = delayMs ? new Date(Date.now() + delayMs).toISOString() : runAt;
|
|
103208
|
+
const checksBlock = renderChecks(checks2);
|
|
103209
|
+
const taskTemplate = `Resume task ${taskId}: ${note}${checksBlock}`;
|
|
103210
|
+
const createdBy = await resolveTaskAuditUserId(requestInfo.sourceTaskId, requestInfo.agentId) ?? undefined;
|
|
103211
|
+
const previewOutput = `${summary}
|
|
103212
|
+
|
|
103213
|
+
Deferred until ${nextRunAt} (schedule pending). Pending: ${note}${checksBlock}`;
|
|
103214
|
+
const outputValidationError = getTaskOutputValidationError(task.outputSchema, previewOutput);
|
|
103215
|
+
if (outputValidationError) {
|
|
103216
|
+
return toolErr(`Task ${taskId} has an outputSchema; its terminal output must satisfy it, but a deferral note cannot. ${outputValidationError}`);
|
|
103217
|
+
}
|
|
103218
|
+
try {
|
|
103219
|
+
const committed = await getDbClient().transaction(async () => {
|
|
103220
|
+
const schedule = await createScheduledTask({
|
|
103221
|
+
name: `deferred-${taskId.slice(0, 8)}-${Date.now()}-${crypto.randomUUID()}`,
|
|
103222
|
+
description: note,
|
|
103223
|
+
taskTemplate,
|
|
103224
|
+
targetType: "agent-task",
|
|
103225
|
+
scheduleType: "one_time",
|
|
103226
|
+
nextRunAt,
|
|
103227
|
+
targetAgentId: requestInfo.agentId,
|
|
103228
|
+
createdByAgentId: requestInfo.agentId,
|
|
103229
|
+
taskType: "deferred",
|
|
103230
|
+
tags: ["deferred"],
|
|
103231
|
+
priority: task.priority,
|
|
103232
|
+
modelTier: task.modelTier,
|
|
103233
|
+
parentTaskId: taskId,
|
|
103234
|
+
createdBy
|
|
103235
|
+
});
|
|
103236
|
+
const output = `${summary}
|
|
103237
|
+
|
|
103238
|
+
Deferred until ${nextRunAt} (schedule ${schedule.id}). Pending: ${note}${checksBlock}`;
|
|
103239
|
+
const completed = await completeTask(taskId, output);
|
|
103240
|
+
if (!completed) {
|
|
103241
|
+
throw new DeferAbortedError(`Task ${taskId} reached a terminal state before this deferral committed.`);
|
|
103242
|
+
}
|
|
103243
|
+
getDbClient().afterCommit(() => {
|
|
103244
|
+
ensure({
|
|
103245
|
+
id: "completed",
|
|
103246
|
+
flow: "task",
|
|
103247
|
+
runId: taskId,
|
|
103248
|
+
depIds: task.wasPaused ? ["started", "resumed"] : ["started"],
|
|
103249
|
+
data: {
|
|
103250
|
+
taskId,
|
|
103251
|
+
agentId: task.agentId,
|
|
103252
|
+
previousStatus: task.status,
|
|
103253
|
+
hasOutput: true
|
|
103254
|
+
},
|
|
103255
|
+
validator: (data) => data.previousStatus === "in_progress",
|
|
103256
|
+
filter: ({}, ctx) => ctx.deps.length > 0,
|
|
103257
|
+
conditions: [{ timeout_ms: 3600000 }]
|
|
103258
|
+
});
|
|
103259
|
+
});
|
|
103260
|
+
if (task.agentId) {
|
|
103261
|
+
await updateAgentStatusFromCapacity(task.agentId);
|
|
103262
|
+
}
|
|
103263
|
+
return { scheduleId: schedule.id, output, completed };
|
|
103264
|
+
});
|
|
103265
|
+
await runTaskTerminalEffects({
|
|
103266
|
+
task: committed.completed,
|
|
103267
|
+
status: "completed",
|
|
103268
|
+
output: committed.output,
|
|
103269
|
+
agentId: requestInfo.agentId
|
|
103270
|
+
});
|
|
103271
|
+
return toolOk(`Task ${taskId} completed and deferred. Wake-up at ${nextRunAt} (schedule ${committed.scheduleId}). This task is final; the wake-up task continues the work.`, {
|
|
103272
|
+
data: {
|
|
103273
|
+
yourAgentId: requestInfo.agentId,
|
|
103274
|
+
taskId,
|
|
103275
|
+
scheduleId: committed.scheduleId,
|
|
103276
|
+
nextRunAt
|
|
103277
|
+
}
|
|
103278
|
+
});
|
|
103279
|
+
} catch (error) {
|
|
103280
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
103281
|
+
return toolErr(`Failed to defer task: ${message}`, {
|
|
103282
|
+
data: { yourAgentId: requestInfo.agentId, taskId }
|
|
103283
|
+
});
|
|
103284
|
+
}
|
|
103285
|
+
});
|
|
103286
|
+
};
|
|
103287
|
+
|
|
102677
103288
|
// src/tools/delete-channel.ts
|
|
102678
103289
|
init_zod();
|
|
102679
103290
|
init_db();
|
|
@@ -104837,77 +105448,6 @@ async function getLinksForMemory(memoryId, options = {}) {
|
|
|
104837
105448
|
return { links, backlinks };
|
|
104838
105449
|
}
|
|
104839
105450
|
|
|
104840
|
-
// src/be/memory/raters/retrieval.ts
|
|
104841
|
-
init_db();
|
|
104842
|
-
function dedupeMemoryDocumentIds(memories) {
|
|
104843
|
-
const documents = new Map;
|
|
104844
|
-
for (const memory of memories) {
|
|
104845
|
-
const identity = memory.sourcePath ?? memory.key;
|
|
104846
|
-
if (identity == null)
|
|
104847
|
-
continue;
|
|
104848
|
-
const documentKey = JSON.stringify([memory.agentId, memory.scope, identity]);
|
|
104849
|
-
if (!documents.has(documentKey))
|
|
104850
|
-
documents.set(documentKey, memory.id);
|
|
104851
|
-
}
|
|
104852
|
-
return [...documents.values()];
|
|
104853
|
-
}
|
|
104854
|
-
async function recordMemoryAccesses(memoryIds) {
|
|
104855
|
-
const ids = [...new Set(memoryIds)].filter(Boolean);
|
|
104856
|
-
if (ids.length === 0)
|
|
104857
|
-
return;
|
|
104858
|
-
const now = new Date().toISOString();
|
|
104859
|
-
await getDbClient().transaction(async (tx) => {
|
|
104860
|
-
for (const id of ids) {
|
|
104861
|
-
await tx.run("UPDATE agent_memory SET accessedAt = ?, accessCount = accessCount + 1 WHERE id = ?", [now, id]);
|
|
104862
|
-
}
|
|
104863
|
-
});
|
|
104864
|
-
}
|
|
104865
|
-
async function recordRetrievals(taskId, agentId, results, sessionId, extras) {
|
|
104866
|
-
if (!taskId || results.length === 0)
|
|
104867
|
-
return;
|
|
104868
|
-
const insertSql = `INSERT INTO memory_retrieval
|
|
104869
|
-
(id, taskId, agentId, sessionId, memoryId, similarity, retrievedAt, contextKey, intent, eventType, retrievalId, rank, retrievalSource)
|
|
104870
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
|
|
104871
|
-
const now = new Date().toISOString();
|
|
104872
|
-
const retrievalId = crypto.randomUUID();
|
|
104873
|
-
const contextKey = extras?.contextKey ?? null;
|
|
104874
|
-
const intent = extras?.intent ?? null;
|
|
104875
|
-
const eventType = extras?.eventType ?? "search";
|
|
104876
|
-
await getDbClient().transaction(async (tx) => {
|
|
104877
|
-
for (const [rank, r] of results.entries()) {
|
|
104878
|
-
await tx.run(insertSql, [
|
|
104879
|
-
crypto.randomUUID(),
|
|
104880
|
-
taskId,
|
|
104881
|
-
agentId,
|
|
104882
|
-
sessionId ?? null,
|
|
104883
|
-
r.memoryId,
|
|
104884
|
-
r.similarity,
|
|
104885
|
-
now,
|
|
104886
|
-
contextKey,
|
|
104887
|
-
intent,
|
|
104888
|
-
eventType,
|
|
104889
|
-
retrievalId,
|
|
104890
|
-
rank,
|
|
104891
|
-
r.retrievalSource ?? null
|
|
104892
|
-
]);
|
|
104893
|
-
}
|
|
104894
|
-
});
|
|
104895
|
-
ensure({
|
|
104896
|
-
id: "memory_retrieved",
|
|
104897
|
-
flow: "task",
|
|
104898
|
-
runId: taskId,
|
|
104899
|
-
data: {
|
|
104900
|
-
count: results.length,
|
|
104901
|
-
taskId,
|
|
104902
|
-
agentId
|
|
104903
|
-
},
|
|
104904
|
-
validator: (data) => typeof data.count === "number" && data.count > 0 && typeof data.taskId === "string" && data.taskId.length > 0 && typeof data.agentId === "string" && data.agentId.length > 0
|
|
104905
|
-
});
|
|
104906
|
-
}
|
|
104907
|
-
async function getRetrievalsForTask(taskId) {
|
|
104908
|
-
return getDbClient().query("SELECT memoryId, similarity FROM memory_retrieval WHERE taskId = ?", [taskId]);
|
|
104909
|
-
}
|
|
104910
|
-
|
|
104911
105451
|
// src/tools/memory-get.ts
|
|
104912
105452
|
init_types();
|
|
104913
105453
|
var NUDGE_ELIGIBLE_SOURCES = new Set(["manual", "file_index"]);
|
|
@@ -107062,7 +107602,7 @@ var registerUpdateRepoTool = (server) => {
|
|
|
107062
107602
|
defaultBranch: string().optional().describe("New default branch."),
|
|
107063
107603
|
autoClone: boolean().optional().describe("Whether to auto-clone."),
|
|
107064
107604
|
hooks: RepoHooksSchema.nullable().optional().describe("Repository hook install config. Set { enabled: true } to opt into best-effort worker hook installation, or null to disable."),
|
|
107065
|
-
guidelines:
|
|
107605
|
+
guidelines: RepoGuidelinesInputSchema.nullable().optional().describe("Repository guidelines: prChecks (commands before PR), mergeChecks (conditions before merge), allowMerge (default false), review (guidance for reviewers). Pass null to clear.")
|
|
107066
107606
|
}),
|
|
107067
107607
|
outputSchema: swarmToolOutputSchema({
|
|
107068
107608
|
repo: swarmRepoOutputShape2.nullable().optional()
|
|
@@ -113654,6 +114194,7 @@ var scheduleDataShape = {
|
|
|
113654
114194
|
lastRunAt: string().optional(),
|
|
113655
114195
|
nextRunAt: string().optional(),
|
|
113656
114196
|
createdByAgentId: string().optional(),
|
|
114197
|
+
parentTaskId: string().optional(),
|
|
113657
114198
|
timezone: string().optional(),
|
|
113658
114199
|
model: string().optional(),
|
|
113659
114200
|
modelTier: ModelTierSchema.optional(),
|
|
@@ -114066,6 +114607,7 @@ var scheduleRowShape = {
|
|
|
114066
114607
|
lastRunAt: string().optional(),
|
|
114067
114608
|
nextRunAt: string().optional(),
|
|
114068
114609
|
createdByAgentId: string().optional(),
|
|
114610
|
+
parentTaskId: string().optional(),
|
|
114069
114611
|
timezone: string().optional(),
|
|
114070
114612
|
consecutiveErrors: number().optional(),
|
|
114071
114613
|
lastErrorAt: string().optional(),
|
|
@@ -114204,6 +114746,7 @@ var scheduleDataShape2 = {
|
|
|
114204
114746
|
lastRunAt: string().optional(),
|
|
114205
114747
|
nextRunAt: string().optional(),
|
|
114206
114748
|
createdByAgentId: string().optional(),
|
|
114749
|
+
parentTaskId: string().optional(),
|
|
114207
114750
|
timezone: string().optional(),
|
|
114208
114751
|
model: string().optional(),
|
|
114209
114752
|
modelTier: ModelTierSchema.optional(),
|
|
@@ -114490,6 +115033,7 @@ var scheduleDataShape3 = {
|
|
|
114490
115033
|
lastRunAt: string().optional(),
|
|
114491
115034
|
nextRunAt: string().optional(),
|
|
114492
115035
|
createdByAgentId: string().optional(),
|
|
115036
|
+
parentTaskId: string().optional(),
|
|
114493
115037
|
timezone: string().optional(),
|
|
114494
115038
|
model: string().optional(),
|
|
114495
115039
|
modelTier: ModelTierSchema.optional(),
|
|
@@ -117046,19 +117590,26 @@ var registerSlackDeleteTool = (server) => {
|
|
|
117046
117590
|
// src/tools/slack-download-file.ts
|
|
117047
117591
|
init_zod();
|
|
117048
117592
|
init_db();
|
|
117593
|
+
function fileIdFromUrl(url) {
|
|
117594
|
+
return /\/files-pri\/[A-Z0-9]+-([A-Z0-9]+)\//.exec(url)?.[1];
|
|
117595
|
+
}
|
|
117049
117596
|
var registerSlackDownloadFileTool = (server) => {
|
|
117050
117597
|
createToolRegistrar(server)("slack-download-file", {
|
|
117051
117598
|
title: "Download file from Slack",
|
|
117052
|
-
description: "Download a file from Slack by file ID or URL.
|
|
117053
|
-
annotations: { readOnlyHint:
|
|
117599
|
+
description: "Download a file from Slack by file ID or URL. From a task, the file is stored as an attachment of that task and the result carries a ready-to-run `fetchCommand` to get the bytes into your container. Without a task, the file is saved on the API server's disk, which your container usually can't read.",
|
|
117600
|
+
annotations: { readOnlyHint: false, openWorldHint: true },
|
|
117054
117601
|
inputSchema: object({
|
|
117055
117602
|
fileId: string().optional().describe("The Slack file ID to download (e.g., 'F0RDC39U1')."),
|
|
117056
117603
|
url: string().url().optional().describe("Direct URL to download (url_private_download from a file object)."),
|
|
117057
|
-
|
|
117604
|
+
taskId: uuid().optional().describe("Task to attach the file to. Defaults to the task you are working on; must be a task you own or created."),
|
|
117605
|
+
savePath: string().optional().describe("Only without a task: where to save the file on the API server (directory or full path). Defaults to /workspace/shared/downloads/{agentId}/slack/."),
|
|
117058
117606
|
filename: string().optional().describe("Filename to use when saving. Only used if savePath is a directory.")
|
|
117059
117607
|
}),
|
|
117060
117608
|
outputSchema: swarmToolOutputSchema({
|
|
117061
|
-
|
|
117609
|
+
taskId: string().optional(),
|
|
117610
|
+
attachmentId: string().optional(),
|
|
117611
|
+
fetchCommand: string().optional(),
|
|
117612
|
+
savedPath: string().optional().describe("Only without a task: the path on the API server's disk, not in your container."),
|
|
117062
117613
|
fileInfo: looseObject({
|
|
117063
117614
|
id: string().optional(),
|
|
117064
117615
|
name: string().optional(),
|
|
@@ -117066,7 +117617,7 @@ var registerSlackDownloadFileTool = (server) => {
|
|
|
117066
117617
|
size: number().optional()
|
|
117067
117618
|
}).optional()
|
|
117068
117619
|
})
|
|
117069
|
-
}, async ({ fileId, url, savePath, filename }, requestInfo, _meta) => {
|
|
117620
|
+
}, async ({ fileId, url, taskId, savePath, filename }, requestInfo, _meta) => {
|
|
117070
117621
|
if (!requestInfo.agentId) {
|
|
117071
117622
|
return toolErr("Agent ID not found.");
|
|
117072
117623
|
}
|
|
@@ -117085,22 +117636,33 @@ var registerSlackDownloadFileTool = (server) => {
|
|
|
117085
117636
|
if (!token) {
|
|
117086
117637
|
return toolErr("Slack bot token not configured.");
|
|
117087
117638
|
}
|
|
117639
|
+
const task = await attachableTask(agent.id, taskId ?? requestInfo.sourceTaskId);
|
|
117640
|
+
if (taskId && !task) {
|
|
117641
|
+
return toolErr("You don't have context for this task.");
|
|
117642
|
+
}
|
|
117088
117643
|
try {
|
|
117089
|
-
|
|
117090
|
-
|
|
117091
|
-
if (fileId) {
|
|
117092
|
-
|
|
117644
|
+
const id2 = fileId ?? (url ? fileIdFromUrl(url) : undefined);
|
|
117645
|
+
const info = id2 ? await getFileInfo(app.client, id2) : null;
|
|
117646
|
+
if (fileId && !info) {
|
|
117647
|
+
return toolErr(`File not found: ${fileId}`);
|
|
117648
|
+
}
|
|
117649
|
+
const fileInfo = info ? { id: info.id, name: info.name, mimetype: info.mimetype, size: info.size } : undefined;
|
|
117650
|
+
if (task) {
|
|
117093
117651
|
if (!info) {
|
|
117094
|
-
return toolErr(
|
|
117652
|
+
return toolErr("Could not identify the Slack file in that URL; pass fileId instead.");
|
|
117095
117653
|
}
|
|
117096
|
-
|
|
117097
|
-
|
|
117098
|
-
|
|
117099
|
-
|
|
117100
|
-
|
|
117101
|
-
|
|
117102
|
-
|
|
117654
|
+
const outcome = (await attachSlackFilesForAgent(app.client, task, [info], agent.id)).get(info.id);
|
|
117655
|
+
if (!outcome || "reason" in outcome) {
|
|
117656
|
+
return toolErr(`Failed to attach file: ${outcome?.reason ?? "unknown error"}`);
|
|
117657
|
+
}
|
|
117658
|
+
const { attachment, fetchCommand } = outcome;
|
|
117659
|
+
return toolOk(`Attached ${attachment.name} to task ${task.id} (attachment ${attachment.id}).`, {
|
|
117660
|
+
details: `Get it into your container with:
|
|
117661
|
+
${fetchCommand}`,
|
|
117662
|
+
data: { taskId: task.id, attachmentId: attachment.id, fetchCommand, fileInfo }
|
|
117663
|
+
});
|
|
117103
117664
|
}
|
|
117665
|
+
const downloadUrl = info?.url_private_download ?? url;
|
|
117104
117666
|
if (!downloadUrl) {
|
|
117105
117667
|
return toolErr("No download URL available.");
|
|
117106
117668
|
}
|
|
@@ -117117,8 +117679,9 @@ var registerSlackDownloadFileTool = (server) => {
|
|
|
117117
117679
|
if (!result.success) {
|
|
117118
117680
|
return toolErr(`Failed to download file: ${result.error}`);
|
|
117119
117681
|
}
|
|
117120
|
-
|
|
117121
|
-
|
|
117682
|
+
return toolOk(`File saved on the API server at ${result.savedPath}.`, {
|
|
117683
|
+
data: { savedPath: result.savedPath, fileInfo }
|
|
117684
|
+
});
|
|
117122
117685
|
} catch (error) {
|
|
117123
117686
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
117124
117687
|
return toolErr(`Failed to download file: ${errorMsg}`);
|
|
@@ -117389,7 +117952,10 @@ var SlackFileSchema = looseObject({
|
|
|
117389
117952
|
filetype: string().optional(),
|
|
117390
117953
|
size: number().optional(),
|
|
117391
117954
|
url_private_download: string().optional(),
|
|
117392
|
-
|
|
117955
|
+
attachmentId: string().optional(),
|
|
117956
|
+
fetchCommand: string().optional(),
|
|
117957
|
+
notAttached: string().optional(),
|
|
117958
|
+
localPath: string().optional().describe("Only without a task: the path on the API server's disk, not in your container.")
|
|
117393
117959
|
});
|
|
117394
117960
|
var SlackMessageSchema = looseObject({
|
|
117395
117961
|
user: string().optional(),
|
|
@@ -117402,15 +117968,15 @@ var SlackMessageSchema = looseObject({
|
|
|
117402
117968
|
var registerSlackReadTool = (server) => {
|
|
117403
117969
|
createToolRegistrar(server)("slack-read", {
|
|
117404
117970
|
title: "Read Slack thread/channel history",
|
|
117405
|
-
description: "Read messages from a Slack thread or channel. Use inboxMessageId or taskId to read from a thread you have context for, or provide channelId directly for channel history (leads only).",
|
|
117406
|
-
annotations: { readOnlyHint:
|
|
117971
|
+
description: "Read messages from a Slack thread or channel. Use inboxMessageId or taskId to read from a thread you have context for, or provide channelId directly for channel history (leads only). From a task, files in the messages are stored as attachments of that task, each with a ready-to-run `fetchCommand`.",
|
|
117972
|
+
annotations: { readOnlyHint: false, openWorldHint: true },
|
|
117407
117973
|
inputSchema: object({
|
|
117408
117974
|
inboxMessageId: uuid().optional().describe("Read thread history for an inbox message."),
|
|
117409
117975
|
taskId: uuid().optional().describe("Read thread history for a task."),
|
|
117410
117976
|
channelId: string().optional().describe("Slack channel ID to read from (requires lead privileges)."),
|
|
117411
117977
|
threadTs: string().optional().describe("Thread timestamp (required with channelId for thread history)."),
|
|
117412
117978
|
limit: number().int().min(1).max(100).default(20).describe("Maximum number of messages to retrieve (default: 20, max: 100)."),
|
|
117413
|
-
includeFiles: boolean().default(true).describe("Include file attachments in the response (default: true).")
|
|
117979
|
+
includeFiles: boolean().default(true).describe("Include file attachments in the response (default: true). From a task, they are also stored as attachments of that task.")
|
|
117414
117980
|
}),
|
|
117415
117981
|
outputSchema: swarmToolOutputSchema({
|
|
117416
117982
|
channelId: string().optional(),
|
|
@@ -117427,6 +117993,7 @@ var registerSlackReadTool = (server) => {
|
|
|
117427
117993
|
}
|
|
117428
117994
|
let slackChannelId = channelId;
|
|
117429
117995
|
let slackThreadTs = threadTs;
|
|
117996
|
+
let contextTask = null;
|
|
117430
117997
|
if (inboxMessageId) {
|
|
117431
117998
|
const inboxMsg = await getInboxMessageById(inboxMessageId);
|
|
117432
117999
|
if (!inboxMsg) {
|
|
@@ -117447,6 +118014,7 @@ var registerSlackReadTool = (server) => {
|
|
|
117447
118014
|
}
|
|
117448
118015
|
slackChannelId = task.slackChannelId;
|
|
117449
118016
|
slackThreadTs = task.slackThreadTs;
|
|
118017
|
+
contextTask = task;
|
|
117450
118018
|
} else if (channelId) {
|
|
117451
118019
|
const decision = can({
|
|
117452
118020
|
principal: { kind: "agent", agentId: agent.id, isLead: agent.isLead },
|
|
@@ -117500,6 +118068,11 @@ var registerSlackReadTool = (server) => {
|
|
|
117500
118068
|
}
|
|
117501
118069
|
}
|
|
117502
118070
|
const token = process.env.SLACK_BOT_TOKEN;
|
|
118071
|
+
const attachTo = contextTask ?? await attachableTask(agent.id, taskId ?? requestInfo.sourceTaskId);
|
|
118072
|
+
if (taskId && !attachTo) {
|
|
118073
|
+
return toolErr("You don't have context for this task.", { data: { messages: [] } });
|
|
118074
|
+
}
|
|
118075
|
+
const toAttach = [];
|
|
117503
118076
|
const messages = [];
|
|
117504
118077
|
for (const m of rawMessages) {
|
|
117505
118078
|
const extractedText = extractSlackMessageText(m);
|
|
@@ -117524,7 +118097,9 @@ var registerSlackReadTool = (server) => {
|
|
|
117524
118097
|
size: f.size,
|
|
117525
118098
|
url_private_download: f.url_private_download
|
|
117526
118099
|
};
|
|
117527
|
-
if (
|
|
118100
|
+
if (attachTo) {
|
|
118101
|
+
toAttach.push({ raw: f, info: fileInfo });
|
|
118102
|
+
} else if (token && f.url_private_download) {
|
|
117528
118103
|
const savePath = `${AUTO_DOWNLOAD_DIR}/${f.id}_${f.name}`;
|
|
117529
118104
|
try {
|
|
117530
118105
|
const downloadResult = await downloadFile({
|
|
@@ -117549,13 +118124,29 @@ var registerSlackReadTool = (server) => {
|
|
|
117549
118124
|
files
|
|
117550
118125
|
});
|
|
117551
118126
|
}
|
|
118127
|
+
if (attachTo && toAttach.length > 0) {
|
|
118128
|
+
const outcomes = await attachSlackFilesForAgent(client, attachTo, toAttach.map(({ raw }) => raw), agent.id);
|
|
118129
|
+
for (const { info } of toAttach) {
|
|
118130
|
+
const outcome = outcomes.get(info.id);
|
|
118131
|
+
if (outcome && "attachment" in outcome) {
|
|
118132
|
+
info.attachmentId = outcome.attachment.id;
|
|
118133
|
+
info.fetchCommand = outcome.fetchCommand;
|
|
118134
|
+
} else {
|
|
118135
|
+
info.notAttached = outcome?.reason ?? "not downloaded";
|
|
118136
|
+
}
|
|
118137
|
+
}
|
|
118138
|
+
}
|
|
117552
118139
|
const textOutput = messages.map((m) => {
|
|
117553
118140
|
let text = `[${m.username || m.user || "Unknown"}]: ${m.text}`;
|
|
117554
118141
|
if (m.files && m.files.length > 0) {
|
|
117555
118142
|
const fileList = m.files.map((f) => {
|
|
117556
118143
|
let line = ` - ${f.name} (${f.mimetype}, ${Math.round(f.size / 1024)} KB)`;
|
|
117557
|
-
if (f.
|
|
117558
|
-
line += ` [
|
|
118144
|
+
if (f.fetchCommand) {
|
|
118145
|
+
line += ` [Task attachment ${f.attachmentId}: ${f.fetchCommand}]`;
|
|
118146
|
+
} else if (f.notAttached) {
|
|
118147
|
+
line += ` [Not attached: ${f.notAttached}]`;
|
|
118148
|
+
} else if (f.localPath) {
|
|
118149
|
+
line += ` [Downloaded on the API server: ${f.localPath}]`;
|
|
117559
118150
|
}
|
|
117560
118151
|
return line;
|
|
117561
118152
|
}).join(`
|
|
@@ -118168,379 +118759,6 @@ var registerSteerTaskTool = (server) => {
|
|
|
118168
118759
|
// src/tools/store-progress.ts
|
|
118169
118760
|
init_zod();
|
|
118170
118761
|
init_db();
|
|
118171
|
-
|
|
118172
|
-
// src/be/memory/raters/explicit-self.ts
|
|
118173
|
-
class ExplicitSelfRatingRater {
|
|
118174
|
-
name = "explicit-self";
|
|
118175
|
-
async rate() {
|
|
118176
|
-
return [];
|
|
118177
|
-
}
|
|
118178
|
-
}
|
|
118179
|
-
|
|
118180
|
-
// src/be/memory/raters/implicit-citation.ts
|
|
118181
|
-
class ImplicitCitationRater {
|
|
118182
|
-
name = "implicit-citation";
|
|
118183
|
-
async rate(ctx) {
|
|
118184
|
-
if (ctx.retrievedMemoryIds.length === 0)
|
|
118185
|
-
return [];
|
|
118186
|
-
const evidence = ctx.evidence ?? "";
|
|
118187
|
-
const events = [];
|
|
118188
|
-
for (const memoryId of ctx.retrievedMemoryIds) {
|
|
118189
|
-
if (evidence.length > 0 && evidence.includes(memoryId)) {
|
|
118190
|
-
events.push({ memoryId, signal: 1, weight: 0.5, source: "" });
|
|
118191
|
-
} else {
|
|
118192
|
-
events.push({ memoryId, signal: -1, weight: 0.25, source: "" });
|
|
118193
|
-
}
|
|
118194
|
-
}
|
|
118195
|
-
return events;
|
|
118196
|
-
}
|
|
118197
|
-
}
|
|
118198
|
-
|
|
118199
|
-
// src/be/memory/raters/noop.ts
|
|
118200
|
-
class NoopRater {
|
|
118201
|
-
name = "noop";
|
|
118202
|
-
async rate() {
|
|
118203
|
-
return [];
|
|
118204
|
-
}
|
|
118205
|
-
}
|
|
118206
|
-
|
|
118207
|
-
// src/be/memory/raters/registry.ts
|
|
118208
|
-
var FACTORIES = {
|
|
118209
|
-
noop: () => new NoopRater,
|
|
118210
|
-
"implicit-citation": () => new ImplicitCitationRater,
|
|
118211
|
-
"explicit-self": () => new ExplicitSelfRatingRater,
|
|
118212
|
-
llm: () => new LlmRater
|
|
118213
|
-
};
|
|
118214
|
-
var SERVER_RATERS = new Set(["implicit-citation"]);
|
|
118215
|
-
function getRegisteredRaters() {
|
|
118216
|
-
const raw = process.env.MEMORY_RATERS;
|
|
118217
|
-
if (!raw || raw.trim() === "") {
|
|
118218
|
-
return [new NoopRater];
|
|
118219
|
-
}
|
|
118220
|
-
const names = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
118221
|
-
const raters = [];
|
|
118222
|
-
for (const name of names) {
|
|
118223
|
-
const factory = FACTORIES[name];
|
|
118224
|
-
if (!factory) {
|
|
118225
|
-
console.warn(`[memory-rater] Unknown rater "${name}" in MEMORY_RATERS — skipping`);
|
|
118226
|
-
continue;
|
|
118227
|
-
}
|
|
118228
|
-
raters.push(factory());
|
|
118229
|
-
}
|
|
118230
|
-
if (raters.length === 0) {
|
|
118231
|
-
return [new NoopRater];
|
|
118232
|
-
}
|
|
118233
|
-
return raters;
|
|
118234
|
-
}
|
|
118235
|
-
function getRaterWeightMultiplier(name) {
|
|
118236
|
-
const raw = process.env.MEMORY_RATER_WEIGHTS;
|
|
118237
|
-
if (!raw || raw.trim() === "")
|
|
118238
|
-
return 1;
|
|
118239
|
-
for (const pair of raw.split(",")) {
|
|
118240
|
-
const trimmed = pair.trim();
|
|
118241
|
-
if (trimmed === "")
|
|
118242
|
-
continue;
|
|
118243
|
-
const [rawName, rawMult] = trimmed.split(":");
|
|
118244
|
-
if (!rawName || !rawMult)
|
|
118245
|
-
continue;
|
|
118246
|
-
if (rawName.trim() !== name)
|
|
118247
|
-
continue;
|
|
118248
|
-
const mult = Number(rawMult);
|
|
118249
|
-
if (Number.isFinite(mult) && mult >= 0)
|
|
118250
|
-
return mult;
|
|
118251
|
-
}
|
|
118252
|
-
return 1;
|
|
118253
|
-
}
|
|
118254
|
-
|
|
118255
|
-
// src/be/memory/raters/store.ts
|
|
118256
|
-
init_db();
|
|
118257
|
-
class ExplicitSelfDuplicateError extends Error {
|
|
118258
|
-
event;
|
|
118259
|
-
constructor(message, event) {
|
|
118260
|
-
super(message);
|
|
118261
|
-
this.event = event;
|
|
118262
|
-
this.name = "ExplicitSelfDuplicateError";
|
|
118263
|
-
}
|
|
118264
|
-
}
|
|
118265
|
-
async function applyRating(events, ctx = {}) {
|
|
118266
|
-
if (events.length === 0) {
|
|
118267
|
-
return { applied: 0, rejected: [] };
|
|
118268
|
-
}
|
|
118269
|
-
const accepted = [];
|
|
118270
|
-
const rejected = [];
|
|
118271
|
-
for (const event of events) {
|
|
118272
|
-
const reason = validate(event);
|
|
118273
|
-
if (reason) {
|
|
118274
|
-
rejected.push({ event, reason });
|
|
118275
|
-
continue;
|
|
118276
|
-
}
|
|
118277
|
-
let sanitizedReferencesSource = null;
|
|
118278
|
-
if (event.referencesSource !== undefined) {
|
|
118279
|
-
if (event.referencesSource.length === 0) {
|
|
118280
|
-
rejected.push({ event, reason: "referencesSource must be non-empty" });
|
|
118281
|
-
continue;
|
|
118282
|
-
}
|
|
118283
|
-
if (event.referencesSource.length > REFERENCES_SOURCE_MAX_LENGTH) {
|
|
118284
|
-
rejected.push({
|
|
118285
|
-
event,
|
|
118286
|
-
reason: `referencesSource exceeds ${REFERENCES_SOURCE_MAX_LENGTH} chars`
|
|
118287
|
-
});
|
|
118288
|
-
continue;
|
|
118289
|
-
}
|
|
118290
|
-
sanitizedReferencesSource = sanitizeReferencesSource(event.referencesSource);
|
|
118291
|
-
if (sanitizedReferencesSource === null) {
|
|
118292
|
-
rejected.push({
|
|
118293
|
-
event,
|
|
118294
|
-
reason: "referencesSource contains a NUL byte or strips to empty"
|
|
118295
|
-
});
|
|
118296
|
-
continue;
|
|
118297
|
-
}
|
|
118298
|
-
}
|
|
118299
|
-
accepted.push({ event, sanitizedReferencesSource });
|
|
118300
|
-
}
|
|
118301
|
-
if (accepted.length === 0) {
|
|
118302
|
-
return { applied: 0, rejected };
|
|
118303
|
-
}
|
|
118304
|
-
const UPDATE_MEMORY_SQL = "UPDATE agent_memory SET alpha = alpha + ?, beta = beta + ? WHERE id = ?";
|
|
118305
|
-
const CHECK_EXISTS_SQL = "SELECT id FROM agent_memory WHERE id = ?";
|
|
118306
|
-
const INSERT_RATING_SQL = `INSERT INTO memory_rating
|
|
118307
|
-
(id, memoryId, taskId, source, signal, weight, reasoning, createdAt, contextKey)
|
|
118308
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`;
|
|
118309
|
-
const UPSERT_EDGE_SQL = `INSERT INTO agent_memory_edge (from_id, to_id, type, alpha, beta, createdAt)
|
|
118310
|
-
VALUES (?, ?, 'references-source', ?, ?, ?)
|
|
118311
|
-
ON CONFLICT(from_id, to_id, type) DO UPDATE SET
|
|
118312
|
-
alpha = alpha + excluded.alpha - 1.0,
|
|
118313
|
-
beta = beta + excluded.beta - 1.0`;
|
|
118314
|
-
const { applied, lateRejects, appliedEvents } = await getDbClient().transaction(async (tx) => {
|
|
118315
|
-
let applied2 = 0;
|
|
118316
|
-
const lateRejects2 = [];
|
|
118317
|
-
const appliedEvents2 = [];
|
|
118318
|
-
for (const { event, sanitizedReferencesSource } of accepted) {
|
|
118319
|
-
const exists = await tx.get(CHECK_EXISTS_SQL, [event.memoryId]);
|
|
118320
|
-
if (!exists) {
|
|
118321
|
-
lateRejects2.push({ event, reason: "memoryId not found in agent_memory" });
|
|
118322
|
-
continue;
|
|
118323
|
-
}
|
|
118324
|
-
const alphaDelta = Math.max(0, event.signal) * event.weight;
|
|
118325
|
-
const betaDelta = Math.max(0, -event.signal) * event.weight;
|
|
118326
|
-
await tx.run(UPDATE_MEMORY_SQL, [alphaDelta, betaDelta, event.memoryId]);
|
|
118327
|
-
try {
|
|
118328
|
-
await tx.run(INSERT_RATING_SQL, [
|
|
118329
|
-
crypto.randomUUID(),
|
|
118330
|
-
event.memoryId,
|
|
118331
|
-
ctx.taskId ?? null,
|
|
118332
|
-
event.source,
|
|
118333
|
-
event.signal,
|
|
118334
|
-
event.weight,
|
|
118335
|
-
event.reasoning ?? null,
|
|
118336
|
-
new Date().toISOString(),
|
|
118337
|
-
ctx.contextKey ?? null
|
|
118338
|
-
]);
|
|
118339
|
-
} catch (err) {
|
|
118340
|
-
if (isUniqueConstraintError(err)) {
|
|
118341
|
-
throw new ExplicitSelfDuplicateError(`duplicate explicit-self rating for memoryId=${event.memoryId} taskId=${ctx.taskId}`, event);
|
|
118342
|
-
}
|
|
118343
|
-
throw err;
|
|
118344
|
-
}
|
|
118345
|
-
if (sanitizedReferencesSource !== null) {
|
|
118346
|
-
await tx.run(UPSERT_EDGE_SQL, [
|
|
118347
|
-
event.memoryId,
|
|
118348
|
-
sanitizedReferencesSource,
|
|
118349
|
-
1 + alphaDelta,
|
|
118350
|
-
1 + betaDelta,
|
|
118351
|
-
new Date().toISOString()
|
|
118352
|
-
]);
|
|
118353
|
-
}
|
|
118354
|
-
appliedEvents2.push({ event, sanitizedReferencesSource });
|
|
118355
|
-
applied2 += 1;
|
|
118356
|
-
}
|
|
118357
|
-
return { applied: applied2, lateRejects: lateRejects2, appliedEvents: appliedEvents2 };
|
|
118358
|
-
});
|
|
118359
|
-
if (ctx.taskId && appliedEvents.length > 0) {
|
|
118360
|
-
for (const { event, sanitizedReferencesSource } of appliedEvents) {
|
|
118361
|
-
ensure({
|
|
118362
|
-
id: "memory_rated",
|
|
118363
|
-
flow: "task",
|
|
118364
|
-
runId: ctx.taskId,
|
|
118365
|
-
data: {
|
|
118366
|
-
memoryId: event.memoryId,
|
|
118367
|
-
source: event.source,
|
|
118368
|
-
signal: event.signal,
|
|
118369
|
-
weight: event.weight,
|
|
118370
|
-
hasReferencesSource: sanitizedReferencesSource !== null
|
|
118371
|
-
},
|
|
118372
|
-
validator: (data) => typeof data.memoryId === "string" && data.memoryId.length > 0 && typeof data.source === "string" && data.source.length > 0 && typeof data.signal === "number" && data.signal >= -1 && data.signal <= 1 && typeof data.weight === "number" && data.weight >= 0 && data.weight <= 1
|
|
118373
|
-
});
|
|
118374
|
-
}
|
|
118375
|
-
}
|
|
118376
|
-
return { applied, rejected: [...rejected, ...lateRejects] };
|
|
118377
|
-
}
|
|
118378
|
-
function validate(event) {
|
|
118379
|
-
if (!event.source || event.source.trim() === "") {
|
|
118380
|
-
return "source is required";
|
|
118381
|
-
}
|
|
118382
|
-
if (!Number.isFinite(event.signal) || event.signal < -1 || event.signal > 1) {
|
|
118383
|
-
return "signal must be in [-1, +1]";
|
|
118384
|
-
}
|
|
118385
|
-
if (!Number.isFinite(event.weight) || event.weight < 0 || event.weight > 1) {
|
|
118386
|
-
return "weight must be in [0, 1]";
|
|
118387
|
-
}
|
|
118388
|
-
if (!event.memoryId) {
|
|
118389
|
-
return "memoryId is required";
|
|
118390
|
-
}
|
|
118391
|
-
return null;
|
|
118392
|
-
}
|
|
118393
|
-
function isUniqueConstraintError(err) {
|
|
118394
|
-
if (!(err instanceof Error))
|
|
118395
|
-
return false;
|
|
118396
|
-
return /UNIQUE constraint failed|SQLITE_CONSTRAINT/i.test(err.message);
|
|
118397
|
-
}
|
|
118398
|
-
|
|
118399
|
-
// src/be/memory/raters/run-server-raters.ts
|
|
118400
|
-
async function runServerRaters(input, deps = {}) {
|
|
118401
|
-
const result = { ratersFired: 0, outcomes: [] };
|
|
118402
|
-
if (input.retrievedMemoryIds.length === 0)
|
|
118403
|
-
return result;
|
|
118404
|
-
const allRaters = deps.raters ?? getRegisteredRaters();
|
|
118405
|
-
const allowed = deps.serverRaterNames ?? SERVER_RATERS;
|
|
118406
|
-
const weightFor = deps.weightMultiplierFor ?? getRaterWeightMultiplier;
|
|
118407
|
-
const applyFn = deps.applyRating ?? applyRating;
|
|
118408
|
-
const serverRaters = allRaters.filter((r) => allowed.has(r.name));
|
|
118409
|
-
for (const rater of serverRaters) {
|
|
118410
|
-
const events = await rater.rate({
|
|
118411
|
-
taskId: input.taskId,
|
|
118412
|
-
agentId: input.agentId,
|
|
118413
|
-
retrievedMemoryIds: input.retrievedMemoryIds,
|
|
118414
|
-
evidence: input.evidence
|
|
118415
|
-
});
|
|
118416
|
-
if (events.length === 0)
|
|
118417
|
-
continue;
|
|
118418
|
-
const multiplier = weightFor(rater.name);
|
|
118419
|
-
const stamped = events.map((e) => ({
|
|
118420
|
-
...e,
|
|
118421
|
-
source: rater.name,
|
|
118422
|
-
weight: Math.max(0, Math.min(1, e.weight * multiplier))
|
|
118423
|
-
}));
|
|
118424
|
-
const applied = await applyFn(stamped, { taskId: input.taskId });
|
|
118425
|
-
result.ratersFired += 1;
|
|
118426
|
-
result.outcomes.push({ rater: rater.name, events: stamped, result: applied });
|
|
118427
|
-
}
|
|
118428
|
-
return result;
|
|
118429
|
-
}
|
|
118430
|
-
|
|
118431
|
-
// src/memory/automatic-task-gate.ts
|
|
118432
|
-
var SCHEDULE_TAG_PREFIX = "schedule:";
|
|
118433
|
-
var AUTOMATIC_TASK_TYPES = new Set([
|
|
118434
|
-
"boot-triage",
|
|
118435
|
-
"heartbeat",
|
|
118436
|
-
"heartbeat-checklist",
|
|
118437
|
-
"health-check",
|
|
118438
|
-
"health-probe",
|
|
118439
|
-
"monitor",
|
|
118440
|
-
"monitoring"
|
|
118441
|
-
]);
|
|
118442
|
-
function isAutomaticOrRecurringTaskCompletion(task) {
|
|
118443
|
-
const tags = task.tags ?? [];
|
|
118444
|
-
const taskType = task.taskType?.toLowerCase();
|
|
118445
|
-
return task.source === "schedule" || task.source === "system" || tags.includes("scheduled") || tags.includes("auto-generated") || tags.some((tag) => tag.startsWith(SCHEDULE_TAG_PREFIX)) || taskType !== undefined && (AUTOMATIC_TASK_TYPES.has(taskType) || taskType.endsWith("-monitor") || taskType.endsWith("-digest"));
|
|
118446
|
-
}
|
|
118447
|
-
function shouldPersistAutomaticTaskMemory(task, persistMemory) {
|
|
118448
|
-
if (persistMemory)
|
|
118449
|
-
return true;
|
|
118450
|
-
return !isAutomaticOrRecurringTaskCompletion(task);
|
|
118451
|
-
}
|
|
118452
|
-
var shouldPersistTaskCompletionMemory = shouldPersistAutomaticTaskMemory;
|
|
118453
|
-
|
|
118454
|
-
// src/tasks/terminal-result-guard.ts
|
|
118455
|
-
init_db();
|
|
118456
|
-
init_types();
|
|
118457
|
-
init_secret_scrubber();
|
|
118458
|
-
function getTaskOutputValidationError(outputSchema, output) {
|
|
118459
|
-
if (!outputSchema || typeof outputSchema !== "object")
|
|
118460
|
-
return;
|
|
118461
|
-
const schema = outputSchema;
|
|
118462
|
-
if (!output) {
|
|
118463
|
-
return `Task has an outputSchema but no output was provided. You must call store-progress with a valid JSON output matching this schema:
|
|
118464
|
-
${JSON.stringify(schema, null, 2)}`;
|
|
118465
|
-
}
|
|
118466
|
-
let parsed;
|
|
118467
|
-
try {
|
|
118468
|
-
parsed = JSON.parse(output);
|
|
118469
|
-
} catch {
|
|
118470
|
-
return `Task output must be valid JSON matching the outputSchema. Got invalid JSON. Schema:
|
|
118471
|
-
${JSON.stringify(schema, null, 2)}`;
|
|
118472
|
-
}
|
|
118473
|
-
let validationErrors;
|
|
118474
|
-
try {
|
|
118475
|
-
validationErrors = validateJsonSchema(schema, parsed);
|
|
118476
|
-
} catch (error) {
|
|
118477
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
118478
|
-
return `Task outputSchema is malformed and cannot be validated (${detail}). Ask an operator to correct the task's outputSchema, or force-complete with store-progress force: true.`;
|
|
118479
|
-
}
|
|
118480
|
-
if (validationErrors.length > 0) {
|
|
118481
|
-
return `Task output does not match the outputSchema. Errors:
|
|
118482
|
-
${validationErrors.join(`
|
|
118483
|
-
`)}
|
|
118484
|
-
|
|
118485
|
-
Expected schema:
|
|
118486
|
-
${JSON.stringify(schema, null, 2)}
|
|
118487
|
-
|
|
118488
|
-
Please fix your output and retry.`;
|
|
118489
|
-
}
|
|
118490
|
-
return;
|
|
118491
|
-
}
|
|
118492
|
-
async function guardTerminalTaskResultWrite(task, write2) {
|
|
118493
|
-
if (!isTerminalTaskStatus(task.status) || !write2.status && !write2.force) {
|
|
118494
|
-
return { handled: false };
|
|
118495
|
-
}
|
|
118496
|
-
const scrubbedOutput = write2.output !== undefined ? scrubSecrets(write2.output) : undefined;
|
|
118497
|
-
const scrubbedFailureReason = write2.failureReason !== undefined ? scrubSecrets(write2.failureReason) : undefined;
|
|
118498
|
-
const hasDifferingOutput = scrubbedOutput !== undefined && scrubbedOutput !== task.output;
|
|
118499
|
-
const hasDifferingFailureReason = scrubbedFailureReason !== undefined && scrubbedFailureReason !== task.failureReason;
|
|
118500
|
-
const hasDifferingResultText = hasDifferingOutput || hasDifferingFailureReason;
|
|
118501
|
-
if (hasDifferingResultText && write2.force) {
|
|
118502
|
-
const outputValidationError = hasDifferingOutput ? getTaskOutputValidationError(task.outputSchema, write2.output) : undefined;
|
|
118503
|
-
if (outputValidationError) {
|
|
118504
|
-
return { handled: true, success: false, message: outputValidationError, task };
|
|
118505
|
-
}
|
|
118506
|
-
const overwrittenTask = await overwriteTerminalTaskResultText(task.id, {
|
|
118507
|
-
...write2.output !== undefined ? { output: write2.output } : {},
|
|
118508
|
-
...write2.failureReason !== undefined ? { failureReason: write2.failureReason } : {}
|
|
118509
|
-
});
|
|
118510
|
-
if (!overwrittenTask) {
|
|
118511
|
-
return {
|
|
118512
|
-
handled: true,
|
|
118513
|
-
success: false,
|
|
118514
|
-
message: `Task "${task.id}" terminal result text could not be overwritten.`,
|
|
118515
|
-
task
|
|
118516
|
-
};
|
|
118517
|
-
}
|
|
118518
|
-
return {
|
|
118519
|
-
handled: true,
|
|
118520
|
-
success: true,
|
|
118521
|
-
message: `Task "${task.id}" is already ${task.status}; force-overwrote terminal result text ` + "without replaying completion side effects.",
|
|
118522
|
-
task: overwrittenTask,
|
|
118523
|
-
wasForcedOverwrite: true
|
|
118524
|
-
};
|
|
118525
|
-
}
|
|
118526
|
-
if (hasDifferingResultText) {
|
|
118527
|
-
return {
|
|
118528
|
-
handled: true,
|
|
118529
|
-
success: false,
|
|
118530
|
-
message: `Discarded write for already-${task.status} task "${task.id}"; ` + "existing output/failureReason and finishedAt were preserved. Retry with force: true " + "to overwrite terminal result text without replaying completion side effects.",
|
|
118531
|
-
task
|
|
118532
|
-
};
|
|
118533
|
-
}
|
|
118534
|
-
return {
|
|
118535
|
-
handled: true,
|
|
118536
|
-
success: true,
|
|
118537
|
-
message: `Task "${task.id}" is already ${task.status}; treating as no-op. ` + "Existing output preserved (first-call-wins).",
|
|
118538
|
-
task,
|
|
118539
|
-
wasNoOp: true
|
|
118540
|
-
};
|
|
118541
|
-
}
|
|
118542
|
-
|
|
118543
|
-
// src/tools/store-progress.ts
|
|
118544
118762
|
init_types();
|
|
118545
118763
|
init_secret_scrubber();
|
|
118546
118764
|
var storeProgressOutputSchema = swarmToolOutputSchema({
|
|
@@ -118760,91 +118978,15 @@ var registerStoreProgressTool = (server) => {
|
|
|
118760
118978
|
};
|
|
118761
118979
|
});
|
|
118762
118980
|
const shouldRunTerminalSideEffects = (status === "completed" || status === "failed") && result.success && result.task && !(("wasNoOp" in result) && result.wasNoOp) && !(("wasForcedOverwrite" in result) && result.wasForcedOverwrite);
|
|
118763
|
-
if (shouldRunTerminalSideEffects &&
|
|
118764
|
-
|
|
118765
|
-
|
|
118766
|
-
|
|
118767
|
-
|
|
118768
|
-
|
|
118769
|
-
|
|
118770
|
-
|
|
118771
|
-
|
|
118772
|
-
${failureReason || "No reason provided"}
|
|
118773
|
-
|
|
118774
|
-
This task failed. Learn from this to avoid repeating the mistake.`;
|
|
118775
|
-
if (taskContent.length < 30)
|
|
118776
|
-
return;
|
|
118777
|
-
const store = getMemoryStore();
|
|
118778
|
-
const provider = getEmbeddingProvider();
|
|
118779
|
-
const memory = await store.store({
|
|
118780
|
-
agentId: requestInfo.agentId ?? null,
|
|
118781
|
-
content: taskContent,
|
|
118782
|
-
name: `Task: ${result.task.task.slice(0, 80)}`,
|
|
118783
|
-
scope: "agent",
|
|
118784
|
-
source: "task_completion",
|
|
118785
|
-
sourceTaskId: taskId
|
|
118786
|
-
});
|
|
118787
|
-
const embedding = await provider.embed(taskContent);
|
|
118788
|
-
if (embedding) {
|
|
118789
|
-
await store.updateEmbedding(memory.id, embedding, provider.name);
|
|
118790
|
-
}
|
|
118791
|
-
const shouldShareWithSwarm = status === "completed" && (result.task.taskType === "research" || result.task.tags?.includes("knowledge") || result.task.tags?.includes("shared"));
|
|
118792
|
-
if (shouldShareWithSwarm) {
|
|
118793
|
-
try {
|
|
118794
|
-
const swarmMemory = await store.store({
|
|
118795
|
-
agentId: requestInfo.agentId ?? null,
|
|
118796
|
-
scope: "swarm",
|
|
118797
|
-
name: `Shared: ${result.task.task.slice(0, 80)}`,
|
|
118798
|
-
content: `Task completed by agent ${requestInfo.agentId}:
|
|
118799
|
-
|
|
118800
|
-
${taskContent}`,
|
|
118801
|
-
source: "task_completion",
|
|
118802
|
-
sourceTaskId: taskId
|
|
118803
|
-
});
|
|
118804
|
-
const swarmEmbedding = await provider.embed(taskContent);
|
|
118805
|
-
if (swarmEmbedding) {
|
|
118806
|
-
await store.updateEmbedding(swarmMemory.id, swarmEmbedding, provider.name);
|
|
118807
|
-
}
|
|
118808
|
-
} catch {}
|
|
118809
|
-
}
|
|
118810
|
-
} catch {}
|
|
118811
|
-
})().catch((err) => console.error("[store-progress] task completion memory write failed:", scrubSecrets(err instanceof Error ? err.message : String(err))));
|
|
118812
|
-
}
|
|
118813
|
-
if (shouldRunTerminalSideEffects) {
|
|
118814
|
-
(async () => {
|
|
118815
|
-
try {
|
|
118816
|
-
const retrievals = await getRetrievalsForTask(taskId);
|
|
118817
|
-
if (retrievals.length === 0)
|
|
118818
|
-
return;
|
|
118819
|
-
const retrievedMemoryIds = retrievals.map((r) => r.memoryId);
|
|
118820
|
-
const logs = await getSessionLogsByTaskId(taskId);
|
|
118821
|
-
const evidence = logs.map((l) => l.content).join(`
|
|
118822
|
-
`);
|
|
118823
|
-
await runServerRaters({
|
|
118824
|
-
taskId,
|
|
118825
|
-
agentId: requestInfo.agentId ?? "",
|
|
118826
|
-
retrievedMemoryIds,
|
|
118827
|
-
evidence
|
|
118828
|
-
});
|
|
118829
|
-
} catch (err) {
|
|
118830
|
-
console.error("[store-progress] server-rater fire failed:", err instanceof Error ? err.message : String(err));
|
|
118831
|
-
}
|
|
118832
|
-
})().catch((err) => console.error("[store-progress] server rater run failed:", scrubSecrets(err instanceof Error ? err.message : String(err))));
|
|
118833
|
-
}
|
|
118834
|
-
if (status && result.success && result.task && !result.task.workflowRunId && !(("wasNoOp" in result) && result.wasNoOp) && !(("wasForcedOverwrite" in result) && result.wasForcedOverwrite)) {
|
|
118835
|
-
try {
|
|
118836
|
-
const followUp = await createWorkerTaskFollowUp({
|
|
118837
|
-
task: result.task,
|
|
118838
|
-
status,
|
|
118839
|
-
output,
|
|
118840
|
-
failureReason
|
|
118841
|
-
});
|
|
118842
|
-
if (followUp) {
|
|
118843
|
-
console.log(`[store-progress] Created follow-up task ${followUp.id.slice(0, 8)} for ${status} task ${taskId.slice(0, 8)}`);
|
|
118844
|
-
}
|
|
118845
|
-
} catch (err) {
|
|
118846
|
-
console.warn(`[store-progress] Failed to create follow-up task: ${err}`);
|
|
118847
|
-
}
|
|
118981
|
+
if (shouldRunTerminalSideEffects && status) {
|
|
118982
|
+
await runTaskTerminalEffects({
|
|
118983
|
+
task: result.task,
|
|
118984
|
+
status,
|
|
118985
|
+
output,
|
|
118986
|
+
failureReason,
|
|
118987
|
+
agentId: requestInfo.agentId,
|
|
118988
|
+
persistMemory
|
|
118989
|
+
});
|
|
118848
118990
|
}
|
|
118849
118991
|
const { success, message } = result;
|
|
118850
118992
|
const task = result.task ? {
|
|
@@ -121296,6 +121438,7 @@ async function createServer(opts = {}) {
|
|
|
121296
121438
|
if (hasCapability2("scheduling")) {
|
|
121297
121439
|
registerListSchedulesTool(server);
|
|
121298
121440
|
registerCreateScheduleTool(server);
|
|
121441
|
+
registerDeferTaskTool(server);
|
|
121299
121442
|
registerUpdateScheduleTool(server);
|
|
121300
121443
|
registerPatchScheduleTool(server);
|
|
121301
121444
|
registerDeleteScheduleTool(server);
|
|
@@ -121456,7 +121599,7 @@ function isExplicitSelfRaterEnabled() {
|
|
|
121456
121599
|
|
|
121457
121600
|
// src/utils/skill-fs-writer.ts
|
|
121458
121601
|
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readdirSync, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
121459
|
-
import { dirname
|
|
121602
|
+
import { dirname, join as join3 } from "node:path";
|
|
121460
121603
|
var SWARM_MARKER_FILE = ".swarm-managed";
|
|
121461
121604
|
function reconcileManagedSkillFiles(skillDir, currentRelativeFiles) {
|
|
121462
121605
|
if (!existsSync2(join3(skillDir, SWARM_MARKER_FILE)))
|
|
@@ -121560,7 +121703,7 @@ function writeSkillsToFilesystem(entries, harnessType = "all", home) {
|
|
|
121560
121703
|
}
|
|
121561
121704
|
const targetPath = join3(skillDir, file.path);
|
|
121562
121705
|
try {
|
|
121563
|
-
mkdirSync2(
|
|
121706
|
+
mkdirSync2(dirname(targetPath), { recursive: true });
|
|
121564
121707
|
writeFileSync2(targetPath, file.content, "utf-8");
|
|
121565
121708
|
} catch (err) {
|
|
121566
121709
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
@@ -121593,4 +121736,4 @@ function writeSkillsToFilesystem(entries, harnessType = "all", home) {
|
|
|
121593
121736
|
return { synced, removed, errors };
|
|
121594
121737
|
}
|
|
121595
121738
|
|
|
121596
|
-
export { safeParseAsync2 as safeParseAsync, normalizeObjectSchema, getParseErrorMessage, DEFAULT_NEGOTIATED_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, isJSONRPCRequest, isJSONRPCResultResponse, isJSONRPCErrorResponse, JSONRPCMessageSchema, isInitializeRequest, McpServer, isGitHubEnabled, initGitHub, verifyWebhookSignature, isAgentMailEnabled, initAgentMail, verifyAgentMailWebhook, isInboxAllowed, isSenderAllowed, handleMessageReceived, enqueueAuditRow, enqueueAdmissionRow, flushAuditBuffer, startAuditWriter, stopAuditWriter, startAuditGc, stopAuditGc, handlePullRequest, handleIssue, handleComment, handlePullRequestReview, handleCheckRun, handleCheckSuite, handleWorkflowRun, isGitLabEnabled, initGitLab, verifyGitLabWebhook, handleMergeRequest, handleIssue2 as handleIssue1, handleNote, handlePipeline, getJiraMetadata, updateJiraMetadata, clearJiraMetadata, registerJiraWebhook, deleteJiraWebhook, isJiraEnabled, initJira, handleJiraWebhook, handleAgentSessionEvent, handleIssueUpdate, handleIssueDelete, handleAgentSessionPrompted, isLinearEnabled, initLinear, parseCookieHeader, extractAndVerifyCookie, issuePageSessionCookie, resolveHttpRequestAuth, setCorsHeaders, parseQueryParams, getPathSegments, wireHttpSpanLifecycle, safeRequestUrlForLog, agentWithCapacity, parseBody, BODY_TOO_LARGE, enforceContentLengthCap, json, jsonError, triggerSchemaErrorResponse, deriveApiBaseUrl, httpServerSemconvAttributes, runtimeInstanceHeader, describeRequestRoute, route, loadGlobalConfigsIntoEnv, reloadGlobalConfigsAndIntegrations, scheduleIntegrationsReload, handleCore, mcpOverflowAuthError, markScriptSdkRequestOrigin, toolErr, createToolRegistrar, userCtx, resolveTaskAuditUserId, resolveHttpAuditUserId, resolveHttpFavoriteOwner, handleApps, getUserCommsPrefs, getTaskDetailsInputSchema, getTaskDetailsOutputSchema, getTaskDetailsHandler, cancelTaskInputSchema, cancelTaskOutputSchema, cancelTaskHandler, executeReadOnlyQuery, assertSelectOnlyQuery, handleDbQuery, snapshotMetric, AssetKeyAuthorizationError, authorizeAssetKeyWrite, snapshotPage, assertOAuthAppUrlsSafe, assertOAuthEgressUrlSafe, listOAuthPresets, listOAuthPresetIds, getOAuthPreset, hydrateOAuthAppFromPreset, scopedResourceScopeIdSchema, resolveScopedResourceId, getTasksInputSchema, getTasksOutputSchema, getTasksHandler, reservedNamespaceError, reservedRoomKeyError, refreshLinks, canReadMemory, getLinksForMemory,
|
|
121739
|
+
export { safeParseAsync2 as safeParseAsync, normalizeObjectSchema, getParseErrorMessage, DEFAULT_NEGOTIATED_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, isJSONRPCRequest, isJSONRPCResultResponse, isJSONRPCErrorResponse, JSONRPCMessageSchema, isInitializeRequest, McpServer, isGitHubEnabled, initGitHub, verifyWebhookSignature, isAgentMailEnabled, initAgentMail, verifyAgentMailWebhook, isInboxAllowed, isSenderAllowed, handleMessageReceived, enqueueAuditRow, enqueueAdmissionRow, flushAuditBuffer, startAuditWriter, stopAuditWriter, startAuditGc, stopAuditGc, handlePullRequest, handleIssue, handleComment, handlePullRequestReview, handleCheckRun, handleCheckSuite, handleWorkflowRun, isGitLabEnabled, initGitLab, verifyGitLabWebhook, handleMergeRequest, handleIssue2 as handleIssue1, handleNote, handlePipeline, getJiraMetadata, updateJiraMetadata, clearJiraMetadata, registerJiraWebhook, deleteJiraWebhook, isJiraEnabled, initJira, handleJiraWebhook, handleAgentSessionEvent, handleIssueUpdate, handleIssueDelete, handleAgentSessionPrompted, isLinearEnabled, initLinear, parseCookieHeader, extractAndVerifyCookie, issuePageSessionCookie, resolveHttpRequestAuth, warnIfCorsAllowsAnyOrigin, isOriginAllowedForCredentials, setCorsHeaders, parseQueryParams, getPathSegments, wireHttpSpanLifecycle, safeRequestUrlForLog, agentWithCapacity, parseBody, BODY_TOO_LARGE, enforceContentLengthCap, json, jsonError, triggerSchemaErrorResponse, deriveApiBaseUrl, httpServerSemconvAttributes, runtimeInstanceHeader, describeRequestRoute, route, loadGlobalConfigsIntoEnv, reloadGlobalConfigsAndIntegrations, scheduleIntegrationsReload, handleCore, mcpOverflowAuthError, markScriptSdkRequestOrigin, toolErr, createToolRegistrar, userCtx, resolveTaskAuditUserId, resolveHttpAuditUserId, resolveHttpFavoriteOwner, handleApps, getUserCommsPrefs, getTaskDetailsInputSchema, getTaskDetailsOutputSchema, getTaskDetailsHandler, cancelTaskInputSchema, cancelTaskOutputSchema, cancelTaskHandler, executeReadOnlyQuery, assertSelectOnlyQuery, handleDbQuery, snapshotMetric, AssetKeyAuthorizationError, authorizeAssetKeyWrite, snapshotPage, assertOAuthAppUrlsSafe, assertOAuthEgressUrlSafe, listOAuthPresets, listOAuthPresetIds, getOAuthPreset, hydrateOAuthAppFromPreset, scopedResourceScopeIdSchema, resolveScopedResourceId, dedupeMemoryDocumentIds, recordMemoryAccesses, recordRetrievals, ExplicitSelfDuplicateError, applyRating, shouldPersistAutomaticTaskMemory, guardTerminalTaskResultWrite, getTasksInputSchema, getTasksOutputSchema, getTasksHandler, reservedNamespaceError, reservedRoomKeyError, refreshLinks, canReadMemory, getLinksForMemory, expandCandidatesWithGraph, indexMemoryContent, markKapsoMessageRead, sendKapsoReaction, getKapsoConfig, getKapsoNumberMapping, markKapsoMessageSeen, resolveRoomNamespace, roomRequestInfo, authorizeRoomNamespace, RoomOperationSchema, removeAwarenessStates, roomTopic, decodeRoomSnapshot, roomView, getRoom, changeRoom, applyRoomUpdate, resetRoom, sweepRooms, closeRooms, removeNamespaceRooms, createEvent, createEventsBatch, getEventCountsFiltered, getEventsFiltered, mergeScheduleTiming, validateRecurringTiming, checkOutputSchemaShape, sendTaskOutputSchema, sendTaskHandler, parseSkillContent, steerTaskUserInputSchema, steerTaskOutputSchema, steerTaskHandler, canClaim, emitBudgetRefusalSideEffects, taskActionInputSchema, taskActionOutputSchema, taskActionHandler, patchWorkflowDefinition, resolveScriptsOnlyMode, ALL_CAPABILITIES, hasCapability, getEnabledCapabilities, createServer, SIMILARITY_THRESHOLD, renderMemoriesPrompt, writeSkillsToFilesystem };
|