nodal-agents 0.7.9 → 0.7.95
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 +6 -5
- package/cli.js +38 -2
- package/migrations/0066_schedule_notify_channel.sql +19 -0
- package/migrations/0067_webhook_notify_channel.sql +12 -0
- package/migrations/meta/_journal.json +14 -0
- package/package.json +1 -1
- package/runner.js +277 -154
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/app-path-routes-manifest.json +11 -11
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/required-server-files.json +1 -0
- package/web/.next/server/app/(dashboard)/agents/[id]/channels/page.js +2 -2
- package/web/.next/server/app/(dashboard)/agents/[id]/channels/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/agents/[id]/channels/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/agents/[id]/edit/page.js +5 -5
- package/web/.next/server/app/(dashboard)/agents/[id]/edit/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/agents/[id]/edit/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/agents/[id]/telegram/page.js +1 -1
- package/web/.next/server/app/(dashboard)/agents/[id]/telegram/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/agents/[id]/telegram/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/agents/page.js +2 -2
- package/web/.next/server/app/(dashboard)/agents/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/agents/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/approvals/page.js +2 -2
- package/web/.next/server/app/(dashboard)/approvals/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/approvals/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/automations/page.js +2 -2
- package/web/.next/server/app/(dashboard)/automations/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/automations/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/chat/page.js +2 -2
- package/web/.next/server/app/(dashboard)/chat/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/chat/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/connectors/page.js +2 -2
- package/web/.next/server/app/(dashboard)/connectors/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/connectors/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/credentials/page.js +2 -2
- package/web/.next/server/app/(dashboard)/credentials/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/credentials/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/jobs/[id]/page.js +2 -2
- package/web/.next/server/app/(dashboard)/jobs/[id]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/jobs/[id]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/jobs/page.js +2 -2
- package/web/.next/server/app/(dashboard)/jobs/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/jobs/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/learned-skills/page.js +2 -2
- package/web/.next/server/app/(dashboard)/learned-skills/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/learned-skills/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/llm-providers/page.js +2 -2
- package/web/.next/server/app/(dashboard)/llm-providers/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/llm-providers/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/logs/page.js +2 -2
- package/web/.next/server/app/(dashboard)/logs/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/logs/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/mcp/page.js +2 -2
- package/web/.next/server/app/(dashboard)/mcp/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/mcp/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/memories/page.js +2 -2
- package/web/.next/server/app/(dashboard)/memories/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/memories/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/page.js +4 -4
- package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/settings/page.js +2 -2
- package/web/.next/server/app/(dashboard)/settings/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/settings/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/settings/root-context/page.js +1 -1
- package/web/.next/server/app/(dashboard)/settings/root-context/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/settings/root-context/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/skills/[id]/edit/page.js +2 -2
- package/web/.next/server/app/(dashboard)/skills/[id]/edit/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/skills/[id]/edit/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/skills/new/page.js +1 -1
- package/web/.next/server/app/(dashboard)/skills/new/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/skills/new/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/skills/page.js +2 -2
- package/web/.next/server/app/(dashboard)/skills/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/_global-error/page.js +2 -2
- package/web/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/_global-error.html +1 -1
- package/web/.next/server/app/_global-error.rsc +3 -3
- package/web/.next/server/app/_global-error.segments/_full.segment.rsc +3 -3
- package/web/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
- package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/_not-found/page.js +1 -1
- package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/_not-found.html +1 -1
- package/web/.next/server/app/_not-found.rsc +4 -4
- package/web/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
- package/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
- package/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/web/.next/server/app/login/page.js +2 -2
- package/web/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/onboarding/page.js +165 -165
- package/web/.next/server/app/onboarding/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app-paths-manifest.json +11 -11
- package/web/.next/server/chunks/1466.js +1 -0
- package/web/.next/server/chunks/1767.js +1 -0
- package/web/.next/server/chunks/3308.js +1 -0
- package/web/.next/server/chunks/4574.js +1 -1
- package/web/.next/server/chunks/5300.js +1 -0
- package/web/.next/server/chunks/6184.js +1 -0
- package/web/.next/server/chunks/6539.js +1 -0
- package/web/.next/server/chunks/7124.js +20 -20
- package/web/.next/server/chunks/8380.js +1 -0
- package/web/.next/server/chunks/9137.js +1 -0
- package/web/.next/server/chunks/{3847.js → 9507.js} +7 -7
- package/web/.next/server/chunks/9982.js +1 -0
- package/web/.next/server/middleware-build-manifest.js +1 -1
- package/web/.next/server/pages/404.html +1 -1
- package/web/.next/server/pages/500.html +1 -1
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +1 -1
- package/web/.next/static/chunks/{7357-df6d26fbdbae296b.js → 1498-d0d434749bb18cd2.js} +1 -1
- package/web/.next/static/chunks/{7536-169aab9ed2feeab6.js → 2491-b14243a2db419dd9.js} +1 -1
- package/web/.next/static/chunks/4095-f76de40c53ae3d47.js +1 -0
- package/web/.next/static/chunks/4766-d80c537321cca448.js +1 -0
- package/web/.next/static/chunks/5876-4423499f49214575.js +1 -0
- package/web/.next/static/chunks/5953-54a29fc1e2d84c0c.js +1 -0
- package/web/.next/static/chunks/7829-78f753c50b408cde.js +1 -0
- package/web/.next/static/chunks/8542-ba178b7c68e14cf3.js +1 -0
- package/web/.next/static/chunks/9387-f5283e69fe4d4e83.js +1 -0
- package/web/.next/static/chunks/9567-db1512a42580d07c.js +1 -0
- package/web/.next/static/chunks/{8097-bad68cd78aa59a10.js → 9583-f93faba69d4c1f57.js} +1 -1
- package/web/.next/static/chunks/app/(dashboard)/agents/[id]/channels/page-d40d5db150472c4f.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/agents/[id]/edit/page-74934ff99c3b1261.js +6 -0
- package/web/.next/static/chunks/app/(dashboard)/agents/[id]/telegram/page-d40d5db150472c4f.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/agents/page-8ec50d6f48425813.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/approvals/page-d907a7c12917ab8a.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/automations/page-dd20cb7f04d22cca.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/chat/page-e9ffd3d09a46ad38.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/connectors/page-52828e317e7a63e6.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/credentials/page-f84a3f991cf69228.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/jobs/[id]/page-a0866da7952de417.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/jobs/page-aade90b389efb824.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/layout-10486dd8640fb6a0.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/learned-skills/page-e22d1e586ac8579c.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/llm-providers/page-46858f7d737ee49b.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/logs/page-17dd2080f6196b01.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/mcp/page-81e83a08c7b65719.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/memories/page-0336ba541b5ab006.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/page-3bf3a72ec95863d8.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/settings/page-0ee25e256bc3097f.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/settings/root-context/page-76653439bca06d8c.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/skills/[id]/edit/page-de1bf934a2c5e8b2.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/skills/new/page-a9640274b845190a.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/skills/page-928b6f005ba4dafb.js +1 -0
- package/web/.next/static/chunks/app/_global-error/page-d40d5db150472c4f.js +1 -0
- package/web/.next/static/chunks/app/_not-found/page-d40d5db150472c4f.js +1 -0
- package/web/.next/static/chunks/app/api/auth/[...all]/route-d40d5db150472c4f.js +1 -0
- package/web/.next/static/chunks/app/api/health/route-d40d5db150472c4f.js +1 -0
- package/web/.next/static/chunks/app/api/oauth/[provider]/callback/route-d40d5db150472c4f.js +1 -0
- package/web/.next/static/chunks/app/api/oauth/[provider]/start/route-d40d5db150472c4f.js +1 -0
- package/web/.next/static/chunks/app/auth/callback/route-d40d5db150472c4f.js +1 -0
- package/web/.next/static/chunks/app/error-ec052ef28a67f9b0.js +1 -0
- package/web/.next/static/chunks/app/login/{page-1063bbdf158045cf.js → page-97a658fa01e36c3f.js} +1 -1
- package/web/.next/static/chunks/app/onboarding/page-d7c5a220f9244b45.js +26 -0
- package/web/.next/static/chunks/next/dist/client/components/builtin/app-error-d40d5db150472c4f.js +1 -0
- package/web/.next/static/chunks/next/dist/client/components/builtin/forbidden-d40d5db150472c4f.js +1 -0
- package/web/.next/static/chunks/next/dist/client/components/builtin/unauthorized-d40d5db150472c4f.js +1 -0
- package/web/.next/static/css/0f40c037c3aa9ff2.css +3 -0
- package/web/server.js +1 -1
- package/web/.next/server/chunks/1957.js +0 -1
- package/web/.next/server/chunks/2313.js +0 -1
- package/web/.next/server/chunks/2314.js +0 -1
- package/web/.next/server/chunks/2747.js +0 -1
- package/web/.next/server/chunks/3422.js +0 -1
- package/web/.next/server/chunks/4761.js +0 -1
- package/web/.next/server/chunks/5128.js +0 -1
- package/web/.next/server/chunks/6128.js +0 -1
- package/web/.next/server/chunks/9857.js +0 -1
- package/web/.next/static/chunks/2281-928529ce483ceb72.js +0 -1
- package/web/.next/static/chunks/3114-d846062bc8434b58.js +0 -1
- package/web/.next/static/chunks/3763-2fa54c0e83122050.js +0 -1
- package/web/.next/static/chunks/4766-0433c4d93110e059.js +0 -1
- package/web/.next/static/chunks/7831-b5f0e41f306942cc.js +0 -1
- package/web/.next/static/chunks/8447-ec639f4e1d42d912.js +0 -1
- package/web/.next/static/chunks/8943-8619f44ee3282119.js +0 -1
- package/web/.next/static/chunks/8992-1b711ff6a77d023a.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/agents/[id]/channels/page-5c6067025edafbc0.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/agents/[id]/edit/page-fc4002bde145810b.js +0 -6
- package/web/.next/static/chunks/app/(dashboard)/agents/[id]/telegram/page-9397b9b7fccbb444.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/agents/page-be616beb457238ca.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/approvals/page-ca87808aaa42a079.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/automations/page-88c5b2061235936a.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/chat/page-197ee8afc4ef48b2.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/connectors/page-7bee350e3c9d4682.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/credentials/page-567d0e2e3c255976.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/jobs/[id]/page-2a5d3e0fd5248864.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/jobs/page-0d50850f43cb7ccb.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/layout-7f9bdb14405ef107.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/learned-skills/page-17878b5d662400b2.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/llm-providers/page-e38d2642e44278b1.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/logs/page-7ac6dbdcd9cf7042.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/mcp/page-a5b036571bb575b8.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/memories/page-1d7007962535c0db.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/page-55efec02eb59c413.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/settings/page-db76b2ad9934ead0.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/settings/root-context/page-5ffdba723e59a369.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/skills/[id]/edit/page-eaa016de6c6d8b02.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/skills/new/page-07669c2c3c9e3b0e.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/skills/page-393ec6f04d00e50f.js +0 -1
- package/web/.next/static/chunks/app/_global-error/page-9397b9b7fccbb444.js +0 -1
- package/web/.next/static/chunks/app/_not-found/page-9397b9b7fccbb444.js +0 -1
- package/web/.next/static/chunks/app/api/auth/[...all]/route-9397b9b7fccbb444.js +0 -1
- package/web/.next/static/chunks/app/api/health/route-9397b9b7fccbb444.js +0 -1
- package/web/.next/static/chunks/app/api/oauth/[provider]/callback/route-9397b9b7fccbb444.js +0 -1
- package/web/.next/static/chunks/app/api/oauth/[provider]/start/route-9397b9b7fccbb444.js +0 -1
- package/web/.next/static/chunks/app/auth/callback/route-9397b9b7fccbb444.js +0 -1
- package/web/.next/static/chunks/app/error-5e6b38c936ae1a78.js +0 -1
- package/web/.next/static/chunks/app/onboarding/page-799f8658aea94b41.js +0 -26
- package/web/.next/static/chunks/next/dist/client/components/builtin/app-error-9397b9b7fccbb444.js +0 -1
- package/web/.next/static/chunks/next/dist/client/components/builtin/forbidden-9397b9b7fccbb444.js +0 -1
- package/web/.next/static/chunks/next/dist/client/components/builtin/unauthorized-9397b9b7fccbb444.js +0 -1
- package/web/.next/static/css/110d6e5ec0dc635f.css +0 -3
- /package/web/.next/static/{xZ_yeD2bqK-_EOEqMMFYk → TWzSfBwiIIU81SgNxXcIw}/_buildManifest.js +0 -0
- /package/web/.next/static/{xZ_yeD2bqK-_EOEqMMFYk → TWzSfBwiIIU81SgNxXcIw}/_ssgManifest.js +0 -0
package/runner.js
CHANGED
|
@@ -2372,6 +2372,17 @@ var init_schedules = __esm({
|
|
|
2372
2372
|
// forces the agent to send the user a success confirmation before finishing.
|
|
2373
2373
|
// Default false → the cron runs silently (the user must opt in per schedule).
|
|
2374
2374
|
notifyOnSuccess: boolean5("notify_on_success").notNull().default(false),
|
|
2375
|
+
// Explicit notify channel choice (B1, notify-channel-choice plan). One of
|
|
2376
|
+
// 'telegram'|'discord'|'slack'|'whatsapp', or NULL = auto (the historical
|
|
2377
|
+
// behavior: first active channel by CHANNEL_PRIORITY — see run-schedules.ts).
|
|
2378
|
+
// Choosing a channel here LINKS chatId resolution to it: the owner
|
|
2379
|
+
// conversation resolved at fire time is the owner's conversation ON THIS
|
|
2380
|
+
// CHANNEL, not whichever channel happened to win priority. 'whatsapp' is
|
|
2381
|
+
// accepted at the DB layer for forward-compat but the UI does not offer it
|
|
2382
|
+
// yet — no outbound send tool exists for whatsapp (TOOL_ONLY_DELIVERY_CHANNELS,
|
|
2383
|
+
// execute.ts), so a whatsapp notify would only ever reach the user through
|
|
2384
|
+
// deliver-results.ts's adapter-direct path, never a mid-run agent send.
|
|
2385
|
+
notifyChannel: text5("notify_channel"),
|
|
2375
2386
|
// Per-schedule daily cost ceiling in USD (Event Triggers, Brique 3). Rolled
|
|
2376
2387
|
// up against agent_jobs.total_cost_usd for this schedule since the start
|
|
2377
2388
|
// of its local day — see runScheduleTick (apps/runner/src/cron/run-schedules.ts).
|
|
@@ -2387,7 +2398,11 @@ var init_schedules = __esm({
|
|
|
2387
2398
|
check3("agent_schedules_type_check", sql3`${table.type} IN ('cron','heartbeat')`),
|
|
2388
2399
|
check3(
|
|
2389
2400
|
"agent_schedules_last_status_check",
|
|
2390
|
-
sql3`${table.lastStatus} IN ('success','failed','no_action','budget_exhausted') OR ${table.lastStatus} IS NULL`
|
|
2401
|
+
sql3`${table.lastStatus} IN ('success','failed','no_action','budget_exhausted','notify_unreachable') OR ${table.lastStatus} IS NULL`
|
|
2402
|
+
),
|
|
2403
|
+
check3(
|
|
2404
|
+
"agent_schedules_notify_channel_check",
|
|
2405
|
+
sql3`${table.notifyChannel} IN ('telegram','discord','slack','whatsapp') OR ${table.notifyChannel} IS NULL`
|
|
2391
2406
|
)
|
|
2392
2407
|
]
|
|
2393
2408
|
);
|
|
@@ -2918,7 +2933,17 @@ var init_memory2 = __esm({
|
|
|
2918
2933
|
});
|
|
2919
2934
|
|
|
2920
2935
|
// ../../packages/db/src/schema/webhooks.ts
|
|
2921
|
-
import {
|
|
2936
|
+
import {
|
|
2937
|
+
pgTable as pgTable13,
|
|
2938
|
+
text as text13,
|
|
2939
|
+
uuid as uuid13,
|
|
2940
|
+
boolean as boolean8,
|
|
2941
|
+
integer as integer7,
|
|
2942
|
+
timestamp as timestamp13,
|
|
2943
|
+
index as index12,
|
|
2944
|
+
check as check10
|
|
2945
|
+
} from "drizzle-orm/pg-core";
|
|
2946
|
+
import { sql as sql11 } from "drizzle-orm";
|
|
2922
2947
|
var webhookTriggers;
|
|
2923
2948
|
var init_webhooks = __esm({
|
|
2924
2949
|
"../../packages/db/src/schema/webhooks.ts"() {
|
|
@@ -2939,10 +2964,30 @@ var init_webhooks = __esm({
|
|
|
2939
2964
|
secret: text13("secret"),
|
|
2940
2965
|
lastTriggeredAt: timestamp13("last_triggered_at", { withTimezone: true }),
|
|
2941
2966
|
triggerCount: integer7("trigger_count").default(0),
|
|
2967
|
+
// B2 (notify-channel-choice plan): same pair of columns as
|
|
2968
|
+
// agent_schedules (see schedules.ts), same mechanic — the schedules
|
|
2969
|
+
// brique (B1) established the pattern, this just closes the gap the plan
|
|
2970
|
+
// identified: webhooks had no notify at all, not by design, just because
|
|
2971
|
+
// the original webhooks brique scoped delivery to the HTTP caller (202 +
|
|
2972
|
+
// jobId) and never to the owner. Default false → firing stays silent
|
|
2973
|
+
// unless opted in per trigger.
|
|
2974
|
+
notifyOnSuccess: boolean8("notify_on_success").notNull().default(false),
|
|
2975
|
+
// Explicit notify channel choice, NULL = auto (first active channel by
|
|
2976
|
+
// CHANNEL_PRIORITY — see routes/webhook.ts). Unlike agent_schedules,
|
|
2977
|
+
// there is no legacy webhook-notify behavior to preserve, so "auto" here
|
|
2978
|
+
// is a plain first-active-channel resolution from the start (no
|
|
2979
|
+
// telegram-only wrapper).
|
|
2980
|
+
notifyChannel: text13("notify_channel"),
|
|
2942
2981
|
createdAt: timestamp13("created_at", { withTimezone: true }).defaultNow(),
|
|
2943
2982
|
updatedAt: timestamp13("updated_at", { withTimezone: true }).defaultNow()
|
|
2944
2983
|
},
|
|
2945
|
-
(table) => [
|
|
2984
|
+
(table) => [
|
|
2985
|
+
index12("idx_webhook_triggers_entity_id").on(table.entityId),
|
|
2986
|
+
check10(
|
|
2987
|
+
"webhook_triggers_notify_channel_check",
|
|
2988
|
+
sql11`${table.notifyChannel} IN ('telegram','discord','slack','whatsapp') OR ${table.notifyChannel} IS NULL`
|
|
2989
|
+
)
|
|
2990
|
+
]
|
|
2946
2991
|
);
|
|
2947
2992
|
}
|
|
2948
2993
|
});
|
|
@@ -2959,7 +3004,7 @@ import {
|
|
|
2959
3004
|
index as index13,
|
|
2960
3005
|
unique as unique3
|
|
2961
3006
|
} from "drizzle-orm/pg-core";
|
|
2962
|
-
import { sql as
|
|
3007
|
+
import { sql as sql12 } from "drizzle-orm";
|
|
2963
3008
|
var agentSkills, skillVersions, skillConnectors, agentSkillAssignments;
|
|
2964
3009
|
var init_skills = __esm({
|
|
2965
3010
|
"../../packages/db/src/schema/skills.ts"() {
|
|
@@ -2979,9 +3024,9 @@ var init_skills = __esm({
|
|
|
2979
3024
|
description: text14("description"),
|
|
2980
3025
|
defaultContent: text14("default_content"),
|
|
2981
3026
|
contentOverridden: boolean9("content_overridden").default(false),
|
|
2982
|
-
requiredConfig: jsonb7("required_config").default(
|
|
2983
|
-
operations: jsonb7("operations").default(
|
|
2984
|
-
requiredBuiltins: text14("required_builtins").array().notNull().default(
|
|
3027
|
+
requiredConfig: jsonb7("required_config").default(sql12`'[]'::jsonb`),
|
|
3028
|
+
operations: jsonb7("operations").default(sql12`'[]'::jsonb`),
|
|
3029
|
+
requiredBuiltins: text14("required_builtins").array().notNull().default(sql12`'{}'::text[]`),
|
|
2985
3030
|
// ─── Community-installed skills (open Agent Skills / SKILL.md format) ───
|
|
2986
3031
|
// is_community = true for skills installed at runtime from an external
|
|
2987
3032
|
// source (vs system catalog or user-authored custom skills). source is the
|
|
@@ -3042,7 +3087,7 @@ var init_skills = __esm({
|
|
|
3042
3087
|
},
|
|
3043
3088
|
(table) => [
|
|
3044
3089
|
index13("idx_skill_versions_entity_id").on(table.entityId),
|
|
3045
|
-
index13("idx_skill_versions_skill_id").on(table.skillId,
|
|
3090
|
+
index13("idx_skill_versions_skill_id").on(table.skillId, sql12`${table.version} DESC`)
|
|
3046
3091
|
]
|
|
3047
3092
|
);
|
|
3048
3093
|
skillConnectors = pgTable14(
|
|
@@ -3064,7 +3109,7 @@ var init_skills = __esm({
|
|
|
3064
3109
|
entityId: uuid14("entity_id").notNull().references(() => entities.id, { onDelete: "cascade" }),
|
|
3065
3110
|
agentId: uuid14("agent_id").notNull().references(() => agents.id, { onDelete: "cascade" }),
|
|
3066
3111
|
skillId: uuid14("skill_id").notNull().references(() => agentSkills.id, { onDelete: "cascade" }),
|
|
3067
|
-
approvalOverrides: jsonb7("approval_overrides").default(
|
|
3112
|
+
approvalOverrides: jsonb7("approval_overrides").default(sql12`'{}'::jsonb`),
|
|
3068
3113
|
useCustomInstructions: boolean9("use_custom_instructions").notNull().default(false),
|
|
3069
3114
|
enabledOperations: text14("enabled_operations").array(),
|
|
3070
3115
|
// Per-skill × per-agent authorization to EXECUTE the skill's bundled scripts
|
|
@@ -3105,9 +3150,9 @@ import {
|
|
|
3105
3150
|
timestamp as timestamp15,
|
|
3106
3151
|
index as index14,
|
|
3107
3152
|
uniqueIndex as uniqueIndex2,
|
|
3108
|
-
check as
|
|
3153
|
+
check as check11
|
|
3109
3154
|
} from "drizzle-orm/pg-core";
|
|
3110
|
-
import { sql as
|
|
3155
|
+
import { sql as sql13 } from "drizzle-orm";
|
|
3111
3156
|
var mcpServers, agentMcpServers, mcpConnections;
|
|
3112
3157
|
var init_mcp = __esm({
|
|
3113
3158
|
"../../packages/db/src/schema/mcp.ts"() {
|
|
@@ -3124,8 +3169,8 @@ var init_mcp = __esm({
|
|
|
3124
3169
|
transport: text15("transport").notNull(),
|
|
3125
3170
|
url: text15("url"),
|
|
3126
3171
|
command: text15("command"),
|
|
3127
|
-
args: text15("args").array().default(
|
|
3128
|
-
envVars: jsonb8("env_vars").default(
|
|
3172
|
+
args: text15("args").array().default(sql13`'{}'::text[]`),
|
|
3173
|
+
envVars: jsonb8("env_vars").default(sql13`'{}'::jsonb`),
|
|
3129
3174
|
// Encrypted (enc:v1: blob) credential for HTTP MCP servers — same pattern
|
|
3130
3175
|
// as connectors.api_key. NULL for servers that need no auth.
|
|
3131
3176
|
apiKey: text15("api_key"),
|
|
@@ -3143,10 +3188,10 @@ var init_mcp = __esm({
|
|
|
3143
3188
|
updatedAt: timestamp15("updated_at", { withTimezone: true }).defaultNow()
|
|
3144
3189
|
},
|
|
3145
3190
|
(table) => [
|
|
3146
|
-
|
|
3147
|
-
|
|
3191
|
+
check11("mcp_servers_transport_check", sql13`${table.transport} IN ('http','stdio')`),
|
|
3192
|
+
check11(
|
|
3148
3193
|
"mcp_servers_auth_scheme_check",
|
|
3149
|
-
|
|
3194
|
+
sql13`${table.authScheme} IN ('header','query','bearer') OR ${table.authScheme} IS NULL`
|
|
3150
3195
|
)
|
|
3151
3196
|
// Multi-instance brique (migration 0017): the (entity_id, slug) UNIQUE
|
|
3152
3197
|
// index was dropped to allow multiple instances of the same MCP server
|
|
@@ -3179,7 +3224,7 @@ var init_mcp = __esm({
|
|
|
3179
3224
|
entityId: uuid15("entity_id").notNull().references(() => entities.id, { onDelete: "cascade" }),
|
|
3180
3225
|
slug: text15("slug").notNull(),
|
|
3181
3226
|
active: boolean10("active").notNull().default(true),
|
|
3182
|
-
toolConfig: jsonb8("tool_config").notNull().default(
|
|
3227
|
+
toolConfig: jsonb8("tool_config").notNull().default(sql13`'{}'::jsonb`),
|
|
3183
3228
|
createdAt: timestamp15("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
3184
3229
|
updatedAt: timestamp15("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
3185
3230
|
},
|
|
@@ -3205,10 +3250,10 @@ import {
|
|
|
3205
3250
|
jsonb as jsonb9,
|
|
3206
3251
|
timestamp as timestamp16,
|
|
3207
3252
|
index as index15,
|
|
3208
|
-
check as
|
|
3253
|
+
check as check12,
|
|
3209
3254
|
unique as unique4
|
|
3210
3255
|
} from "drizzle-orm/pg-core";
|
|
3211
|
-
import { sql as
|
|
3256
|
+
import { sql as sql14 } from "drizzle-orm";
|
|
3212
3257
|
var configuratorSessions, agentPlugins, rateLimits;
|
|
3213
3258
|
var init_misc = __esm({
|
|
3214
3259
|
"../../packages/db/src/schema/misc.ts"() {
|
|
@@ -3221,7 +3266,7 @@ var init_misc = __esm({
|
|
|
3221
3266
|
id: uuid16("id").primaryKey().defaultRandom(),
|
|
3222
3267
|
entityId: uuid16("entity_id").notNull().references(() => entities.id, { onDelete: "cascade" }),
|
|
3223
3268
|
agentId: uuid16("agent_id").references(() => agents.id, { onDelete: "cascade" }),
|
|
3224
|
-
messages: jsonb9("messages").notNull().default(
|
|
3269
|
+
messages: jsonb9("messages").notNull().default(sql14`'[]'::jsonb`),
|
|
3225
3270
|
status: text16("status").notNull().default("active"),
|
|
3226
3271
|
turnCount: integer9("turn_count").notNull().default(0),
|
|
3227
3272
|
createdAt: timestamp16("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
@@ -3241,7 +3286,7 @@ var init_misc = __esm({
|
|
|
3241
3286
|
slug: text16("slug").notNull(),
|
|
3242
3287
|
description: text16("description"),
|
|
3243
3288
|
pluginType: text16("plugin_type").notNull(),
|
|
3244
|
-
config: jsonb9("config").default(
|
|
3289
|
+
config: jsonb9("config").default(sql14`'{}'::jsonb`),
|
|
3245
3290
|
active: boolean11("active").default(true),
|
|
3246
3291
|
hook: text16("hook").notNull(),
|
|
3247
3292
|
webhookUrl: text16("webhook_url"),
|
|
@@ -3249,13 +3294,13 @@ var init_misc = __esm({
|
|
|
3249
3294
|
updatedAt: timestamp16("updated_at", { withTimezone: true }).defaultNow()
|
|
3250
3295
|
},
|
|
3251
3296
|
(table) => [
|
|
3252
|
-
|
|
3297
|
+
check12(
|
|
3253
3298
|
"agent_plugins_plugin_type_check",
|
|
3254
|
-
|
|
3299
|
+
sql14`${table.pluginType} IN ('webhook','transform','schedule')`
|
|
3255
3300
|
),
|
|
3256
|
-
|
|
3301
|
+
check12(
|
|
3257
3302
|
"agent_plugins_hook_check",
|
|
3258
|
-
|
|
3303
|
+
sql14`${table.hook} IN ('pre_task','post_task','pre_tool','post_tool','on_memory_save')`
|
|
3259
3304
|
),
|
|
3260
3305
|
// R5 (audit #2 follow-up): the pglite test DDL (packages/db/src/tests/
|
|
3261
3306
|
// helpers.ts) already assumed a per-entity unique slug here — same class
|
|
@@ -3385,8 +3430,8 @@ var init_agent_workspaces = __esm({
|
|
|
3385
3430
|
});
|
|
3386
3431
|
|
|
3387
3432
|
// ../../packages/db/src/schema/chat-messages.ts
|
|
3388
|
-
import { pgTable as pgTable20, text as text20, uuid as uuid20, timestamp as timestamp20, index as index18, check as
|
|
3389
|
-
import { sql as
|
|
3433
|
+
import { pgTable as pgTable20, text as text20, uuid as uuid20, timestamp as timestamp20, index as index18, check as check13 } from "drizzle-orm/pg-core";
|
|
3434
|
+
import { sql as sql15 } from "drizzle-orm";
|
|
3390
3435
|
var conversations, chatMessages;
|
|
3391
3436
|
var init_chat_messages = __esm({
|
|
3392
3437
|
"../../packages/db/src/schema/chat-messages.ts"() {
|
|
@@ -3412,7 +3457,7 @@ var init_chat_messages = __esm({
|
|
|
3412
3457
|
},
|
|
3413
3458
|
(table) => [
|
|
3414
3459
|
index18("idx_conversations_entity_agent").on(table.entityId, table.agentId, table.updatedAt),
|
|
3415
|
-
|
|
3460
|
+
check13("conversations_origin_check", sql15`${table.origin} IN ('user','onboarding')`)
|
|
3416
3461
|
]
|
|
3417
3462
|
);
|
|
3418
3463
|
chatMessages = pgTable20(
|
|
@@ -3433,7 +3478,7 @@ var init_chat_messages = __esm({
|
|
|
3433
3478
|
},
|
|
3434
3479
|
(table) => [
|
|
3435
3480
|
index18("idx_chat_messages_conversation").on(table.conversationId, table.createdAt),
|
|
3436
|
-
|
|
3481
|
+
check13("chat_messages_role_check", sql15`${table.role} IN ('user','assistant')`)
|
|
3437
3482
|
]
|
|
3438
3483
|
);
|
|
3439
3484
|
}
|
|
@@ -3471,11 +3516,11 @@ import {
|
|
|
3471
3516
|
uuid as uuid22,
|
|
3472
3517
|
timestamp as timestamp22,
|
|
3473
3518
|
index as index19,
|
|
3474
|
-
check as
|
|
3519
|
+
check as check14,
|
|
3475
3520
|
unique as unique6,
|
|
3476
3521
|
uniqueIndex as uniqueIndex4
|
|
3477
3522
|
} from "drizzle-orm/pg-core";
|
|
3478
|
-
import { sql as
|
|
3523
|
+
import { sql as sql16 } from "drizzle-orm";
|
|
3479
3524
|
var telegramAllowedChats;
|
|
3480
3525
|
var init_telegram_allowed_chats = __esm({
|
|
3481
3526
|
"../../packages/db/src/schema/telegram-allowed-chats.ts"() {
|
|
@@ -3504,8 +3549,8 @@ var init_telegram_allowed_chats = __esm({
|
|
|
3504
3549
|
unique6("telegram_allowed_chats_agent_chat_unique").on(table.agentId, table.chatId),
|
|
3505
3550
|
index19("idx_telegram_allowed_chats_agent").on(table.agentId),
|
|
3506
3551
|
index19("idx_telegram_allowed_chats_entity").on(table.entityId),
|
|
3507
|
-
|
|
3508
|
-
|
|
3552
|
+
check14("telegram_allowed_chats_role_check", sql16`${table.role} IN ('owner','member')`),
|
|
3553
|
+
check14("telegram_allowed_chats_status_check", sql16`${table.status} IN ('active','pending')`),
|
|
3509
3554
|
// F1 (audit #2 remediation follow-up, migration 0060): concurrent
|
|
3510
3555
|
// first-contact claims could each pass the "no owner yet" check before
|
|
3511
3556
|
// either row committed, creating two role='owner' rows for one agent —
|
|
@@ -3513,7 +3558,7 @@ var init_telegram_allowed_chats = __esm({
|
|
|
3513
3558
|
// resolveApprovalDeliveryTarget) does LIMIT 1 assuming uniqueness. A
|
|
3514
3559
|
// partial unique index (owner rows only; 'member' rows are unrestricted)
|
|
3515
3560
|
// closes the race at the DB level.
|
|
3516
|
-
uniqueIndex4("telegram_allowed_chats_single_owner").on(table.agentId).where(
|
|
3561
|
+
uniqueIndex4("telegram_allowed_chats_single_owner").on(table.agentId).where(sql16`${table.role} = 'owner'`)
|
|
3517
3562
|
]
|
|
3518
3563
|
);
|
|
3519
3564
|
}
|
|
@@ -3528,10 +3573,10 @@ import {
|
|
|
3528
3573
|
jsonb as jsonb10,
|
|
3529
3574
|
timestamp as timestamp23,
|
|
3530
3575
|
index as index20,
|
|
3531
|
-
check as
|
|
3576
|
+
check as check15,
|
|
3532
3577
|
unique as unique7
|
|
3533
3578
|
} from "drizzle-orm/pg-core";
|
|
3534
|
-
import { sql as
|
|
3579
|
+
import { sql as sql17 } from "drizzle-orm";
|
|
3535
3580
|
var channelBindings;
|
|
3536
3581
|
var init_channel_bindings = __esm({
|
|
3537
3582
|
"../../packages/db/src/schema/channel-bindings.ts"() {
|
|
@@ -3560,9 +3605,9 @@ var init_channel_bindings = __esm({
|
|
|
3560
3605
|
unique7("channel_bindings_agent_channel_unique").on(table.agentId, table.channel),
|
|
3561
3606
|
index20("idx_channel_bindings_agent").on(table.agentId),
|
|
3562
3607
|
index20("idx_channel_bindings_entity").on(table.entityId),
|
|
3563
|
-
|
|
3608
|
+
check15(
|
|
3564
3609
|
"channel_bindings_channel_check",
|
|
3565
|
-
|
|
3610
|
+
sql17`${table.channel} IN ('telegram','discord','slack','whatsapp')`
|
|
3566
3611
|
)
|
|
3567
3612
|
]
|
|
3568
3613
|
);
|
|
@@ -3576,11 +3621,11 @@ import {
|
|
|
3576
3621
|
uuid as uuid24,
|
|
3577
3622
|
timestamp as timestamp24,
|
|
3578
3623
|
index as index21,
|
|
3579
|
-
check as
|
|
3624
|
+
check as check16,
|
|
3580
3625
|
unique as unique8,
|
|
3581
3626
|
uniqueIndex as uniqueIndex5
|
|
3582
3627
|
} from "drizzle-orm/pg-core";
|
|
3583
|
-
import { sql as
|
|
3628
|
+
import { sql as sql18 } from "drizzle-orm";
|
|
3584
3629
|
var channelAllowedConversations;
|
|
3585
3630
|
var init_channel_allowed_conversations = __esm({
|
|
3586
3631
|
"../../packages/db/src/schema/channel-allowed-conversations.ts"() {
|
|
@@ -3616,24 +3661,24 @@ var init_channel_allowed_conversations = __esm({
|
|
|
3616
3661
|
),
|
|
3617
3662
|
index21("idx_channel_allowed_conversations_agent").on(table.agentId),
|
|
3618
3663
|
index21("idx_channel_allowed_conversations_entity").on(table.entityId),
|
|
3619
|
-
|
|
3664
|
+
check16(
|
|
3620
3665
|
"channel_allowed_conversations_channel_check",
|
|
3621
|
-
|
|
3666
|
+
sql18`${table.channel} IN ('telegram','discord','slack','whatsapp')`
|
|
3622
3667
|
),
|
|
3623
|
-
|
|
3668
|
+
check16(
|
|
3624
3669
|
"channel_allowed_conversations_kind_check",
|
|
3625
|
-
|
|
3670
|
+
sql18`${table.kind} IN ('private','group','channel','thread')`
|
|
3626
3671
|
),
|
|
3627
|
-
|
|
3628
|
-
|
|
3672
|
+
check16("channel_allowed_conversations_role_check", sql18`${table.role} IN ('owner','member')`),
|
|
3673
|
+
check16(
|
|
3629
3674
|
"channel_allowed_conversations_status_check",
|
|
3630
|
-
|
|
3675
|
+
sql18`${table.status} IN ('active','pending')`
|
|
3631
3676
|
),
|
|
3632
3677
|
// Mirrors telegram_allowed_chats_single_owner (migration 0060): at most one
|
|
3633
3678
|
// active-owner-authority row per (agent, channel) — same race this closes
|
|
3634
3679
|
// (concurrent first-contact claims), scoped so each channel gets its OWN
|
|
3635
3680
|
// owner rather than sharing one across an agent's whole multichannel surface.
|
|
3636
|
-
uniqueIndex5("channel_allowed_conversations_single_owner").on(table.agentId, table.channel).where(
|
|
3681
|
+
uniqueIndex5("channel_allowed_conversations_single_owner").on(table.agentId, table.channel).where(sql18`${table.role} = 'owner'`)
|
|
3637
3682
|
]
|
|
3638
3683
|
);
|
|
3639
3684
|
}
|
|
@@ -19084,12 +19129,12 @@ var require_formdata_parser = __commonJS({
|
|
|
19084
19129
|
return "failure";
|
|
19085
19130
|
}
|
|
19086
19131
|
if (bufferStartsWith(input, filenameBuffer, position)) {
|
|
19087
|
-
let
|
|
19088
|
-
if (input[
|
|
19132
|
+
let check17 = position.position + filenameBuffer.length;
|
|
19133
|
+
if (input[check17] === 42) {
|
|
19089
19134
|
position.position += 1;
|
|
19090
|
-
|
|
19135
|
+
check17 += 1;
|
|
19091
19136
|
}
|
|
19092
|
-
if (input[
|
|
19137
|
+
if (input[check17] !== 61 || input[check17 + 1] !== 34) {
|
|
19093
19138
|
return "failure";
|
|
19094
19139
|
}
|
|
19095
19140
|
position.position += 12;
|
|
@@ -46574,7 +46619,7 @@ var require_Util = __commonJS({
|
|
|
46574
46619
|
await client.rest.patch(route, { body: updatedItems, reason });
|
|
46575
46620
|
return updatedItems;
|
|
46576
46621
|
}
|
|
46577
|
-
function
|
|
46622
|
+
function basename5(path2, ext) {
|
|
46578
46623
|
const res = parse2(path2);
|
|
46579
46624
|
return ext && res.ext.startsWith(ext) ? res.name : res.base.split("?")[0];
|
|
46580
46625
|
}
|
|
@@ -46697,7 +46742,7 @@ var require_Util = __commonJS({
|
|
|
46697
46742
|
resolveColor,
|
|
46698
46743
|
discordSort,
|
|
46699
46744
|
setPosition,
|
|
46700
|
-
basename:
|
|
46745
|
+
basename: basename5,
|
|
46701
46746
|
cleanContent,
|
|
46702
46747
|
cleanCodeBlockContent,
|
|
46703
46748
|
parseWebhookURL,
|
|
@@ -65389,7 +65434,7 @@ var require_MessagePayload = __commonJS({
|
|
|
65389
65434
|
var { DiscordjsError: DiscordjsError2, DiscordjsRangeError: DiscordjsRangeError2, ErrorCodes: ErrorCodes2 } = require_errors2();
|
|
65390
65435
|
var { resolveFile } = require_DataResolver();
|
|
65391
65436
|
var MessageFlagsBitField = require_MessageFlagsBitField();
|
|
65392
|
-
var { basename:
|
|
65437
|
+
var { basename: basename5, verifyString, resolvePartialEmoji } = require_Util();
|
|
65393
65438
|
var getBaseInteraction = lazy(() => require_BaseInteraction());
|
|
65394
65439
|
var MessagePayload = class {
|
|
65395
65440
|
/**
|
|
@@ -65608,10 +65653,10 @@ var require_MessagePayload = __commonJS({
|
|
|
65608
65653
|
let name;
|
|
65609
65654
|
const findName = (thing) => {
|
|
65610
65655
|
if (typeof thing === "string") {
|
|
65611
|
-
return
|
|
65656
|
+
return basename5(thing);
|
|
65612
65657
|
}
|
|
65613
65658
|
if (thing.path) {
|
|
65614
|
-
return
|
|
65659
|
+
return basename5(thing.path);
|
|
65615
65660
|
}
|
|
65616
65661
|
return "file.jpg";
|
|
65617
65662
|
};
|
|
@@ -88063,7 +88108,7 @@ var require_EmbedBuilder = __commonJS({
|
|
|
88063
88108
|
var require_AttachmentBuilder = __commonJS({
|
|
88064
88109
|
"../../node_modules/.pnpm/discord.js@14.26.5/node_modules/discord.js/src/structures/AttachmentBuilder.js"(exports2, module2) {
|
|
88065
88110
|
"use strict";
|
|
88066
|
-
var { basename:
|
|
88111
|
+
var { basename: basename5, flatten } = require_Util();
|
|
88067
88112
|
var AttachmentBuilder = class _AttachmentBuilder {
|
|
88068
88113
|
/**
|
|
88069
88114
|
* @param {BufferResolvable|Stream} attachment The file
|
|
@@ -88123,7 +88168,7 @@ var require_AttachmentBuilder = __commonJS({
|
|
|
88123
88168
|
* @readonly
|
|
88124
88169
|
*/
|
|
88125
88170
|
get spoiler() {
|
|
88126
|
-
return
|
|
88171
|
+
return basename5(this.name).startsWith("SPOILER_");
|
|
88127
88172
|
}
|
|
88128
88173
|
toJSON() {
|
|
88129
88174
|
return flatten(this);
|
|
@@ -156730,7 +156775,7 @@ var require_wait2 = __commonJS({
|
|
|
156730
156775
|
return;
|
|
156731
156776
|
}
|
|
156732
156777
|
let prior = current;
|
|
156733
|
-
const
|
|
156778
|
+
const check17 = (backoff) => {
|
|
156734
156779
|
if (Date.now() > max2) {
|
|
156735
156780
|
done(null, "timed-out");
|
|
156736
156781
|
} else {
|
|
@@ -156738,7 +156783,7 @@ var require_wait2 = __commonJS({
|
|
|
156738
156783
|
prior = current;
|
|
156739
156784
|
current = Atomics.load(state, index22);
|
|
156740
156785
|
if (current === prior) {
|
|
156741
|
-
|
|
156786
|
+
check17(backoff >= MAX_TIMEOUT ? MAX_TIMEOUT : backoff * 2);
|
|
156742
156787
|
} else {
|
|
156743
156788
|
if (current === expected) done(null, "ok");
|
|
156744
156789
|
else done(null, "not-equal");
|
|
@@ -156746,7 +156791,7 @@ var require_wait2 = __commonJS({
|
|
|
156746
156791
|
}, backoff);
|
|
156747
156792
|
}
|
|
156748
156793
|
};
|
|
156749
|
-
|
|
156794
|
+
check17(1);
|
|
156750
156795
|
}
|
|
156751
156796
|
function waitDiff(state, index22, expected, timeout, done) {
|
|
156752
156797
|
const max2 = Date.now() + timeout;
|
|
@@ -156755,7 +156800,7 @@ var require_wait2 = __commonJS({
|
|
|
156755
156800
|
done(null, "ok");
|
|
156756
156801
|
return;
|
|
156757
156802
|
}
|
|
156758
|
-
const
|
|
156803
|
+
const check17 = (backoff) => {
|
|
156759
156804
|
if (Date.now() > max2) {
|
|
156760
156805
|
done(null, "timed-out");
|
|
156761
156806
|
} else {
|
|
@@ -156764,12 +156809,12 @@ var require_wait2 = __commonJS({
|
|
|
156764
156809
|
if (current !== expected) {
|
|
156765
156810
|
done(null, "ok");
|
|
156766
156811
|
} else {
|
|
156767
|
-
|
|
156812
|
+
check17(backoff >= MAX_TIMEOUT ? MAX_TIMEOUT : backoff * 2);
|
|
156768
156813
|
}
|
|
156769
156814
|
}, backoff);
|
|
156770
156815
|
}
|
|
156771
156816
|
};
|
|
156772
|
-
|
|
156817
|
+
check17(1);
|
|
156773
156818
|
}
|
|
156774
156819
|
module2.exports = { wait, waitDiff };
|
|
156775
156820
|
}
|
|
@@ -199127,7 +199172,7 @@ var require_view2 = __commonJS({
|
|
|
199127
199172
|
var path2 = __require("node:path");
|
|
199128
199173
|
var fs4 = __require("node:fs");
|
|
199129
199174
|
var dirname8 = path2.dirname;
|
|
199130
|
-
var
|
|
199175
|
+
var basename5 = path2.basename;
|
|
199131
199176
|
var extname2 = path2.extname;
|
|
199132
199177
|
var join16 = path2.join;
|
|
199133
199178
|
var resolve3 = path2.resolve;
|
|
@@ -199166,7 +199211,7 @@ var require_view2 = __commonJS({
|
|
|
199166
199211
|
var root = roots[i];
|
|
199167
199212
|
var loc = resolve3(root, name);
|
|
199168
199213
|
var dir = dirname8(loc);
|
|
199169
|
-
var file =
|
|
199214
|
+
var file = basename5(loc);
|
|
199170
199215
|
path3 = this.resolve(dir, file);
|
|
199171
199216
|
}
|
|
199172
199217
|
return path3;
|
|
@@ -199196,7 +199241,7 @@ var require_view2 = __commonJS({
|
|
|
199196
199241
|
if (stat11 && stat11.isFile()) {
|
|
199197
199242
|
return path3;
|
|
199198
199243
|
}
|
|
199199
|
-
path3 = join16(dir,
|
|
199244
|
+
path3 = join16(dir, basename5(file, ext), "index" + ext);
|
|
199200
199245
|
stat11 = tryStat(path3);
|
|
199201
199246
|
if (stat11 && stat11.isFile()) {
|
|
199202
199247
|
return path3;
|
|
@@ -202158,9 +202203,9 @@ var require_content_disposition = __commonJS({
|
|
|
202158
202203
|
if (typeof fallback === "string" && NON_LATIN1_REGEXP.test(fallback)) {
|
|
202159
202204
|
throw new TypeError("fallback must be ISO-8859-1 string");
|
|
202160
202205
|
}
|
|
202161
|
-
var name =
|
|
202206
|
+
var name = basename5(filename);
|
|
202162
202207
|
var isQuotedString = TEXT_REGEXP.test(name);
|
|
202163
|
-
var fallbackName = typeof fallback !== "string" ? fallback && getlatin1(name) :
|
|
202208
|
+
var fallbackName = typeof fallback !== "string" ? fallback && getlatin1(name) : basename5(fallback);
|
|
202164
202209
|
var hasFallback = typeof fallbackName === "string" && fallbackName !== name;
|
|
202165
202210
|
if (hasFallback || !isQuotedString || hasHexEscape(name)) {
|
|
202166
202211
|
params["filename*"] = name;
|
|
@@ -202280,7 +202325,7 @@ var require_content_disposition = __commonJS({
|
|
|
202280
202325
|
this.type = type;
|
|
202281
202326
|
this.parameters = parameters;
|
|
202282
202327
|
}
|
|
202283
|
-
function
|
|
202328
|
+
function basename5(path2) {
|
|
202284
202329
|
const normalized = path2.replaceAll("\\", "/");
|
|
202285
202330
|
let end = normalized.length;
|
|
202286
202331
|
while (end > 0 && normalized[end - 1] === "/") {
|
|
@@ -204687,8 +204732,6 @@ var envSchema = z.object({
|
|
|
204687
204732
|
EMBEDDING_PROVIDER: z.enum(["ollama", "openai", "keyword"]).default("keyword"),
|
|
204688
204733
|
EMBEDDING_MODEL: z.string().optional(),
|
|
204689
204734
|
EMBEDDING_BASE_URL: z.string().optional(),
|
|
204690
|
-
// Delivery
|
|
204691
|
-
TELEGRAM_BOT_TOKEN: z.string().optional(),
|
|
204692
204735
|
// Auth
|
|
204693
204736
|
AUTH_MODE: z.enum(["local-trust", "local-auth", "bearer-token"]).default("local-trust"),
|
|
204694
204737
|
WORKER_SECRET: z.string().default(""),
|
|
@@ -204715,8 +204758,6 @@ var envSchema = z.object({
|
|
|
204715
204758
|
// Enable reflection per entity via the dashboard toggle — NOT via this env var.
|
|
204716
204759
|
// The other knobs gate WHICH jobs qualify and bound the pass.
|
|
204717
204760
|
REFLECTION_ENABLED: z.string().default(""),
|
|
204718
|
-
// Minimum job turns before a completed job is "substantial" enough to reflect on.
|
|
204719
|
-
REFLECTION_MIN_TURNS: z.coerce.number().default(3),
|
|
204720
204761
|
// Per-entity rolling-hour cap on reflection passes (rate limit / cost guard).
|
|
204721
204762
|
REFLECTION_MAX_PER_HOUR: z.coerce.number().default(6),
|
|
204722
204763
|
// Max LLM turns inside a single reflection pass (the reflection loop itself).
|
|
@@ -204859,7 +204900,7 @@ init_schema();
|
|
|
204859
204900
|
|
|
204860
204901
|
// ../../packages/db/src/queries/credentials.ts
|
|
204861
204902
|
init_credentials();
|
|
204862
|
-
import { eq, sql as
|
|
204903
|
+
import { eq, sql as sql19 } from "drizzle-orm";
|
|
204863
204904
|
|
|
204864
204905
|
// ../../packages/secrets/src/index.ts
|
|
204865
204906
|
import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
|
|
@@ -205051,7 +205092,7 @@ async function getDecryptedCredentialById(db, credentialId) {
|
|
|
205051
205092
|
if (provider?.supportsRefresh && payload.refreshToken) {
|
|
205052
205093
|
try {
|
|
205053
205094
|
payload = await db.transaction(async (tx) => {
|
|
205054
|
-
await tx.execute(
|
|
205095
|
+
await tx.execute(sql19`SELECT pg_advisory_xact_lock(hashtext(${credentialId}))`);
|
|
205055
205096
|
const [freshRow] = await tx.select().from(credentials).where(eq(credentials.id, credentialId));
|
|
205056
205097
|
if (!freshRow) return payload;
|
|
205057
205098
|
const freshPayload = decryptPayload(freshRow.payload);
|
|
@@ -205319,7 +205360,7 @@ async function attachAgentToOrchestrator(db, entityId, orchestratorId, agentSlug
|
|
|
205319
205360
|
// ../../packages/db/src/repos/skills.ts
|
|
205320
205361
|
init_agents();
|
|
205321
205362
|
init_skills();
|
|
205322
|
-
import { eq as eq4, and as and3, or as or3, inArray as inArray2, sql as
|
|
205363
|
+
import { eq as eq4, and as and3, or as or3, inArray as inArray2, sql as sql20 } from "drizzle-orm";
|
|
205323
205364
|
async function createSkillRepo(db, entityId, input, reservedSlugs = []) {
|
|
205324
205365
|
if (reservedSlugs.includes(input.slug)) {
|
|
205325
205366
|
return { error: "slug_reserved" };
|
|
@@ -205362,7 +205403,7 @@ async function updateSkillRepo(db, entityId, skillId, patch) {
|
|
|
205362
205403
|
}
|
|
205363
205404
|
if (patch.createdBy === "agent") {
|
|
205364
205405
|
set.createdBy = "agent";
|
|
205365
|
-
set.patchCount =
|
|
205406
|
+
set.patchCount = sql20`${agentSkills.patchCount} + 1`;
|
|
205366
205407
|
}
|
|
205367
205408
|
await db.update(agentSkills).set(set).where(eq4(agentSkills.id, skillId));
|
|
205368
205409
|
return { ok: true };
|
|
@@ -205398,7 +205439,7 @@ async function assignSkillRepo(db, entityId, input, systemSkillSlugs2) {
|
|
|
205398
205439
|
}
|
|
205399
205440
|
async function touchSkillsLastUsed(db, skillIds) {
|
|
205400
205441
|
if (skillIds.length === 0) return;
|
|
205401
|
-
await db.update(agentSkills).set({ lastUsedAt:
|
|
205442
|
+
await db.update(agentSkills).set({ lastUsedAt: sql20`now()` }).where(inArray2(agentSkills.id, skillIds));
|
|
205402
205443
|
}
|
|
205403
205444
|
async function transitionSkillLifecycle(db, thresholds) {
|
|
205404
205445
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -205412,21 +205453,21 @@ async function transitionSkillLifecycle(db, thresholds) {
|
|
|
205412
205453
|
and3(
|
|
205413
205454
|
eq4(agentSkills.createdBy, "agent"),
|
|
205414
205455
|
eq4(agentSkills.state, "active"),
|
|
205415
|
-
|
|
205456
|
+
sql20`coalesce(${agentSkills.lastUsedAt}, ${agentSkills.createdAt}) < ${staleAt}`
|
|
205416
205457
|
)
|
|
205417
205458
|
).returning({ id: agentSkills.id });
|
|
205418
205459
|
const archivedRows = await db.update(agentSkills).set({ state: "archived", archivedAt: now, updatedAt: now }).where(
|
|
205419
205460
|
and3(
|
|
205420
205461
|
eq4(agentSkills.createdBy, "agent"),
|
|
205421
205462
|
eq4(agentSkills.state, "stale"),
|
|
205422
|
-
|
|
205463
|
+
sql20`coalesce(${agentSkills.lastUsedAt}, ${agentSkills.createdAt}) < ${archiveAt}`
|
|
205423
205464
|
)
|
|
205424
205465
|
).returning({ id: agentSkills.id });
|
|
205425
205466
|
const reactivatedRows = await db.update(agentSkills).set({ state: "active", updatedAt: now }).where(
|
|
205426
205467
|
and3(
|
|
205427
205468
|
eq4(agentSkills.createdBy, "agent"),
|
|
205428
205469
|
eq4(agentSkills.state, "stale"),
|
|
205429
|
-
|
|
205470
|
+
sql20`${agentSkills.lastUsedAt} >= ${staleAt}`
|
|
205430
205471
|
)
|
|
205431
205472
|
).returning({ id: agentSkills.id });
|
|
205432
205473
|
return {
|
|
@@ -205445,25 +205486,25 @@ async function archiveAgentSkill(db, entityId, skillId) {
|
|
|
205445
205486
|
|
|
205446
205487
|
// ../../packages/db/src/repos/retention.ts
|
|
205447
205488
|
init_schema();
|
|
205448
|
-
import { sql as
|
|
205489
|
+
import { sql as sql21, inArray as inArray3 } from "drizzle-orm";
|
|
205449
205490
|
async function pruneOldJobs(db, retentionDays, batchSize = 1e3) {
|
|
205450
205491
|
if (retentionDays <= 0) {
|
|
205451
205492
|
return { jobsDeleted: 0, toolCallsDeleted: 0 };
|
|
205452
205493
|
}
|
|
205453
|
-
const cutoffExpr =
|
|
205494
|
+
const cutoffExpr = sql21`now() - make_interval(days => ${retentionDays})`;
|
|
205454
205495
|
let jobsDeleted = 0;
|
|
205455
205496
|
let toolCallsDeleted = 0;
|
|
205456
205497
|
for (; ; ) {
|
|
205457
205498
|
const batch = await db.transaction(async (tx) => {
|
|
205458
205499
|
const prunableRows = await tx.select({ id: agentJobs.id }).from(agentJobs).where(
|
|
205459
|
-
|
|
205500
|
+
sql21`${agentJobs.status} IN ('completed','failed','cancelled')
|
|
205460
205501
|
AND ${agentJobs.completedAt} < ${cutoffExpr}`
|
|
205461
205502
|
).limit(batchSize);
|
|
205462
205503
|
if (prunableRows.length === 0) {
|
|
205463
205504
|
return null;
|
|
205464
205505
|
}
|
|
205465
205506
|
const jobIds = prunableRows.map((r) => r.id);
|
|
205466
|
-
const [tcCountRow] = await tx.select({ n:
|
|
205507
|
+
const [tcCountRow] = await tx.select({ n: sql21`count(*)::int` }).from(toolCalls).where(inArray3(toolCalls.jobId, jobIds));
|
|
205467
205508
|
const batchToolCallsDeleted = tcCountRow?.n ?? 0;
|
|
205468
205509
|
await tx.delete(agentJobs).where(inArray3(agentJobs.id, jobIds));
|
|
205469
205510
|
return { jobsDeleted: jobIds.length, toolCallsDeleted: batchToolCallsDeleted };
|
|
@@ -205478,7 +205519,7 @@ async function pruneOldJobs(db, retentionDays, batchSize = 1e3) {
|
|
|
205478
205519
|
|
|
205479
205520
|
// ../../packages/db/src/repos/app-settings.ts
|
|
205480
205521
|
init_schema();
|
|
205481
|
-
import { and as and4, eq as eq5, sql as
|
|
205522
|
+
import { and as and4, eq as eq5, sql as sql22 } from "drizzle-orm";
|
|
205482
205523
|
var INSTALL_NOTES_KEY = "install_notes";
|
|
205483
205524
|
async function getEntitySetting(db, entityId, key) {
|
|
205484
205525
|
const [row] = await db.select({ value: entitySettings.value }).from(entitySettings).where(and4(eq5(entitySettings.entityId, entityId), eq5(entitySettings.key, key))).limit(1);
|
|
@@ -205493,7 +205534,7 @@ import {
|
|
|
205493
205534
|
eq as eq6,
|
|
205494
205535
|
and as and5,
|
|
205495
205536
|
or as or4,
|
|
205496
|
-
sql as
|
|
205537
|
+
sql as sql23,
|
|
205497
205538
|
desc,
|
|
205498
205539
|
asc,
|
|
205499
205540
|
not,
|
|
@@ -207610,8 +207651,8 @@ function rowToMemory(row) {
|
|
|
207610
207651
|
// ../../packages/memory/src/access-tracking.ts
|
|
207611
207652
|
async function touchMemory(db, id, entityId) {
|
|
207612
207653
|
await db.update(agentMemory).set({
|
|
207613
|
-
lastAccessedAt:
|
|
207614
|
-
accessCount:
|
|
207654
|
+
lastAccessedAt: sql23`now()`,
|
|
207655
|
+
accessCount: sql23`${agentMemory.accessCount} + 1`
|
|
207615
207656
|
}).where(and5(eq6(agentMemory.id, id), eq6(agentMemory.entityId, entityId)));
|
|
207616
207657
|
}
|
|
207617
207658
|
async function touchMemories(db, ids, entityId) {
|
|
@@ -207629,9 +207670,9 @@ async function keywordSearch(db, query, filters, sort = "importance") {
|
|
|
207629
207670
|
const conditions = buildWhereConditions({ entityId, agentId, skillTags, category });
|
|
207630
207671
|
const orderBy = keywordOrderBy(sort);
|
|
207631
207672
|
if (orTerms.length > 0) {
|
|
207632
|
-
const tsv =
|
|
207633
|
-
const tsq =
|
|
207634
|
-
const rows2 = await db.select().from(agentMemory).where(and5(...conditions,
|
|
207673
|
+
const tsv = sql23`"agent_memory"."search_tsv"`;
|
|
207674
|
+
const tsq = sql23`to_tsquery('english', ${orTerms.join(" | ")})`;
|
|
207675
|
+
const rows2 = await db.select().from(agentMemory).where(and5(...conditions, sql23`${tsv} @@ ${tsq}`)).orderBy(sql23`ts_rank(${tsv}, ${tsq}) DESC`, ...orderBy).limit(limit);
|
|
207635
207676
|
return rows2;
|
|
207636
207677
|
}
|
|
207637
207678
|
const rows = await db.select().from(agentMemory).where(and5(...conditions)).orderBy(...orderBy).limit(limit);
|
|
@@ -207676,10 +207717,10 @@ function buildWhereConditions(filters) {
|
|
|
207676
207717
|
if (skillTags && skillTags.length > 0) {
|
|
207677
207718
|
const tagLiteral = pgTextArray(skillTags);
|
|
207678
207719
|
conditions.push(
|
|
207679
|
-
|
|
207720
|
+
sql23`(
|
|
207680
207721
|
${agentMemory.skillTags} = '{}'::text[]
|
|
207681
207722
|
OR ${agentMemory.skillTags} IS NULL
|
|
207682
|
-
OR ${agentMemory.skillTags} && ${
|
|
207723
|
+
OR ${agentMemory.skillTags} && ${sql23.raw(tagLiteral)}::text[]
|
|
207683
207724
|
)`
|
|
207684
207725
|
);
|
|
207685
207726
|
}
|
|
@@ -207720,10 +207761,10 @@ async function transitionMemoryLifecycle(db, opts) {
|
|
|
207720
207761
|
const rows = await db.update(agentMemory).set({ archived: true, updatedAt: /* @__PURE__ */ new Date() }).where(
|
|
207721
207762
|
and5(
|
|
207722
207763
|
eq6(agentMemory.archived, false),
|
|
207723
|
-
|
|
207724
|
-
|
|
207725
|
-
|
|
207726
|
-
|
|
207764
|
+
sql23`${agentMemory.source} IN ('agent','reflection')`,
|
|
207765
|
+
sql23`${agentMemory.importance} <= ${opts.importanceMax}`,
|
|
207766
|
+
sql23`coalesce(${agentMemory.accessCount}, 0) = 0`,
|
|
207767
|
+
sql23`coalesce(${agentMemory.importanceLocked}, false) = false`,
|
|
207727
207768
|
lt(agentMemory.createdAt, cutoff)
|
|
207728
207769
|
)
|
|
207729
207770
|
).returning({ id: agentMemory.id });
|
|
@@ -207928,16 +207969,16 @@ async function selectMemoriesForInjection(db, opts) {
|
|
|
207928
207969
|
const baseConditions = and5(
|
|
207929
207970
|
eq6(agentMemory.entityId, opts.entityId),
|
|
207930
207971
|
eq6(agentMemory.archived, false),
|
|
207931
|
-
|
|
207972
|
+
sql23`(${agentMemory.validTo} IS NULL OR ${agentMemory.validTo} > now())`
|
|
207932
207973
|
);
|
|
207933
207974
|
const rawQuery = opts.query ?? "";
|
|
207934
207975
|
const tokens = tokenizeQuery(rawQuery);
|
|
207935
207976
|
let packed;
|
|
207936
207977
|
if (tokens.length > 0) {
|
|
207937
|
-
const tsv =
|
|
207938
|
-
const tsq =
|
|
207978
|
+
const tsv = sql23`"agent_memory"."search_tsv"`;
|
|
207979
|
+
const tsq = sql23`to_tsquery('english', ${tokens.join(" | ")})`;
|
|
207939
207980
|
const candidates = await db.select().from(agentMemory).where(baseConditions).orderBy(
|
|
207940
|
-
|
|
207981
|
+
sql23`ts_rank(${tsv}, ${tsq}) DESC`,
|
|
207941
207982
|
desc(agentMemory.importance),
|
|
207942
207983
|
desc(agentMemory.lastAccessedAt)
|
|
207943
207984
|
).limit(MAX_CANDIDATES);
|
|
@@ -207968,7 +208009,7 @@ async function findMemoriesByFactSubstring(db, entityId, substring, limit = 5) {
|
|
|
207968
208009
|
and5(
|
|
207969
208010
|
eq6(agentMemory.entityId, entityId),
|
|
207970
208011
|
eq6(agentMemory.archived, false),
|
|
207971
|
-
|
|
208012
|
+
sql23`(${agentMemory.validTo} IS NULL OR ${agentMemory.validTo} > now())`,
|
|
207972
208013
|
ilike2(agentMemory.fact, `%${substring}%`)
|
|
207973
208014
|
)
|
|
207974
208015
|
).limit(limit);
|
|
@@ -208095,16 +208136,16 @@ var searchHistoryTool = {
|
|
|
208095
208136
|
riskLevel: "read",
|
|
208096
208137
|
execute: async (input, ctx) => {
|
|
208097
208138
|
const limit = input.limit ?? 6;
|
|
208098
|
-
const tsq =
|
|
208099
|
-
const tsv =
|
|
208139
|
+
const tsq = sql23`plainto_tsquery('simple', ${input.query})`;
|
|
208140
|
+
const tsv = sql23`"agent_jobs"."search_tsv"`;
|
|
208100
208141
|
const rows = await ctx.db.select({
|
|
208101
208142
|
job_id: agentJobs.id,
|
|
208102
208143
|
agent: agents.slug,
|
|
208103
208144
|
channel: agentJobs.channel,
|
|
208104
208145
|
when: agentJobs.createdAt,
|
|
208105
208146
|
task: agentJobs.task,
|
|
208106
|
-
snippet:
|
|
208107
|
-
}).from(agentJobs).leftJoin(agents, eq6(agents.id, agentJobs.agentId)).where(and5(eq6(agentJobs.entityId, ctx.entityId),
|
|
208147
|
+
snippet: sql23`ts_headline('simple', coalesce(${agentJobs.searchText}, ${agentJobs.task}, ''), ${tsq}, 'StartSel=«, StopSel=», MaxFragments=2, MinWords=4, MaxWords=18, FragmentDelimiter= … ')`
|
|
208148
|
+
}).from(agentJobs).leftJoin(agents, eq6(agents.id, agentJobs.agentId)).where(and5(eq6(agentJobs.entityId, ctx.entityId), sql23`${tsv} @@ ${tsq}`)).orderBy(sql23`ts_rank(${tsv}, ${tsq}) DESC`, desc(agentJobs.createdAt)).limit(limit);
|
|
208108
208149
|
return rows.map((r) => ({
|
|
208109
208150
|
job_id: r.job_id,
|
|
208110
208151
|
agent: r.agent ?? null,
|
|
@@ -208321,7 +208362,7 @@ import { z as z29 } from "zod";
|
|
|
208321
208362
|
|
|
208322
208363
|
// ../../packages/tools/src/builtin/file-ops/workspace.ts
|
|
208323
208364
|
import { realpath, stat } from "node:fs/promises";
|
|
208324
|
-
import { resolve as resolvePath, sep, isAbsolute
|
|
208365
|
+
import { resolve as resolvePath, sep, isAbsolute } from "node:path";
|
|
208325
208366
|
var SHARED_WORKSPACE_LABEL = "shared";
|
|
208326
208367
|
var MAX_READ_BYTES = 1024 * 1024;
|
|
208327
208368
|
var MAX_READ_FILE_BYTES = 50 * 1024 * 1024;
|
|
@@ -208633,7 +208674,7 @@ var fileReadTool = {
|
|
|
208633
208674
|
|
|
208634
208675
|
// ../../packages/tools/src/builtin/file-ops/file-write.ts
|
|
208635
208676
|
import { writeFile, rename, mkdir, unlink } from "node:fs/promises";
|
|
208636
|
-
import { dirname as dirname2, basename
|
|
208677
|
+
import { dirname as dirname2, basename } from "node:path";
|
|
208637
208678
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
208638
208679
|
import { z as z30 } from "zod";
|
|
208639
208680
|
var FileWriteInputSchema = z30.object({
|
|
@@ -208667,7 +208708,7 @@ var fileWriteTool = {
|
|
|
208667
208708
|
if (input.create_dirs) {
|
|
208668
208709
|
await mkdir(dir, { recursive: true });
|
|
208669
208710
|
}
|
|
208670
|
-
const tmp = `${dir}/.${
|
|
208711
|
+
const tmp = `${dir}/.${basename(path2)}.${randomBytes2(6).toString("hex")}.tmp`;
|
|
208671
208712
|
try {
|
|
208672
208713
|
await writeFile(tmp, input.content, "utf8");
|
|
208673
208714
|
await rename(tmp, path2);
|
|
@@ -208692,7 +208733,7 @@ var fileWriteTool = {
|
|
|
208692
208733
|
|
|
208693
208734
|
// ../../packages/tools/src/builtin/file-ops/file-edit.ts
|
|
208694
208735
|
import { readFile as readFile2, writeFile as writeFile2, rename as rename2, unlink as unlink2 } from "node:fs/promises";
|
|
208695
|
-
import { dirname as dirname3, basename as
|
|
208736
|
+
import { dirname as dirname3, basename as basename2 } from "node:path";
|
|
208696
208737
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
208697
208738
|
import { z as z31 } from "zod";
|
|
208698
208739
|
var FileEditInputSchema = z31.object({
|
|
@@ -208750,7 +208791,7 @@ var fileEditTool = {
|
|
|
208750
208791
|
};
|
|
208751
208792
|
}
|
|
208752
208793
|
const dir = dirname3(path2);
|
|
208753
|
-
const tmp = `${dir}/.${
|
|
208794
|
+
const tmp = `${dir}/.${basename2(path2)}.${randomBytes3(6).toString("hex")}.tmp`;
|
|
208754
208795
|
try {
|
|
208755
208796
|
await writeFile2(tmp, updated, "utf8");
|
|
208756
208797
|
await rename2(tmp, path2);
|
|
@@ -208991,7 +209032,7 @@ import { z as z34 } from "zod";
|
|
|
208991
209032
|
// ../../packages/tools/src/builtin/office-ops/office-helpers.ts
|
|
208992
209033
|
var import_jszip = __toESM(require_lib3(), 1);
|
|
208993
209034
|
import { readFile as readFile4, writeFile as writeFile3, rename as rename3, unlink as unlink3, stat as stat5 } from "node:fs/promises";
|
|
208994
|
-
import { dirname as dirname4, basename as
|
|
209035
|
+
import { dirname as dirname4, basename as basename3 } from "node:path";
|
|
208995
209036
|
import { randomBytes as randomBytes4 } from "node:crypto";
|
|
208996
209037
|
var MAX_OFFICE_BYTES = 25 * 1024 * 1024;
|
|
208997
209038
|
var MAX_OFFICE_INFLATED_BYTES = 1024 * 1024 * 1024;
|
|
@@ -209105,7 +209146,7 @@ async function writeWorkspaceBinary(ctx, path2, buffer2, { overwrite = false } =
|
|
|
209105
209146
|
};
|
|
209106
209147
|
}
|
|
209107
209148
|
const dir = dirname4(resolvedPath);
|
|
209108
|
-
const tmp = `${dir}/.${
|
|
209149
|
+
const tmp = `${dir}/.${basename3(resolvedPath)}.${randomBytes4(6).toString("hex")}.tmp`;
|
|
209109
209150
|
try {
|
|
209110
209151
|
await writeFile3(tmp, buffer2);
|
|
209111
209152
|
await rename3(tmp, resolvedPath);
|
|
@@ -211739,8 +211780,8 @@ var createAgentTool = {
|
|
|
211739
211780
|
const { dbRole, orchestratorMode } = mapRole(input.role);
|
|
211740
211781
|
const resolved = await resolveAgentProvider(ctx.db, ctx.entityId, null);
|
|
211741
211782
|
if (resolved) {
|
|
211742
|
-
const
|
|
211743
|
-
if (!
|
|
211783
|
+
const check17 = validateModelForProvider(resolved.provider, input.model);
|
|
211784
|
+
if (!check17.ok) return check17;
|
|
211744
211785
|
}
|
|
211745
211786
|
let result;
|
|
211746
211787
|
try {
|
|
@@ -211812,8 +211853,8 @@ var updateAgentTool = {
|
|
|
211812
211853
|
if (input.model) {
|
|
211813
211854
|
const resolved = await resolveAgentProvider(ctx.db, ctx.entityId, agent.llmKeyId);
|
|
211814
211855
|
if (resolved) {
|
|
211815
|
-
const
|
|
211816
|
-
if (!
|
|
211856
|
+
const check17 = validateModelForProvider(resolved.provider, input.model);
|
|
211857
|
+
if (!check17.ok) return check17;
|
|
211817
211858
|
}
|
|
211818
211859
|
}
|
|
211819
211860
|
const patch = { updatedAt: /* @__PURE__ */ new Date() };
|
|
@@ -212556,13 +212597,15 @@ var runScheduleTool = {
|
|
|
212556
212597
|
task: agentSchedules.task,
|
|
212557
212598
|
chatId: agentSchedules.chatId,
|
|
212558
212599
|
notifyOnSuccess: agentSchedules.notifyOnSuccess,
|
|
212600
|
+
// B1 (notify-channel-choice): the schedule's explicit channel choice, if any.
|
|
212601
|
+
notifyChannel: agentSchedules.notifyChannel,
|
|
212559
212602
|
// Manual "run now": prevRunAt is still "when did this schedule last
|
|
212560
212603
|
// actually run" — this fire doesn't change that semantic.
|
|
212561
212604
|
lastRun: agentSchedules.lastRun
|
|
212562
212605
|
}).from(agentSchedules).where(and5(eq6(agentSchedules.entityId, ctx.entityId), eq6(agentSchedules.name, input.name))).limit(1);
|
|
212563
212606
|
if (!sched) return { ok: false, error: `No schedule named "${input.name}" in this workspace.` };
|
|
212564
212607
|
if (!sched.task) return { ok: false, error: `Schedule "${input.name}" has no task to run.` };
|
|
212565
|
-
const resolvedChatId = sched.notifyOnSuccess ? sched.chatId ?? await resolveOwnerChatId(ctx.db, sched.agentId) ?? null : null;
|
|
212608
|
+
const resolvedChatId = sched.notifyOnSuccess ? sched.notifyChannel ? sched.chatId ?? await resolveOwnerConversation(ctx.db, sched.agentId, sched.notifyChannel) : sched.chatId ?? await resolveOwnerChatId(ctx.db, sched.agentId) ?? null : null;
|
|
212566
212609
|
const [job] = await ctx.db.insert(agentJobs).values({
|
|
212567
212610
|
entityId: ctx.entityId,
|
|
212568
212611
|
agentId: sched.agentId,
|
|
@@ -212575,7 +212618,8 @@ var runScheduleTool = {
|
|
|
212575
212618
|
triggerContext: {
|
|
212576
212619
|
type: "cron",
|
|
212577
212620
|
scheduleName: input.name,
|
|
212578
|
-
prevRunAt: sched.lastRun ? sched.lastRun.toISOString() : null
|
|
212621
|
+
prevRunAt: sched.lastRun ? sched.lastRun.toISOString() : null,
|
|
212622
|
+
notifyChannel: sched.notifyChannel ?? null
|
|
212579
212623
|
}
|
|
212580
212624
|
}).returning({ id: agentJobs.id });
|
|
212581
212625
|
if (!job) return { ok: false, error: "Failed to queue the schedule run." };
|
|
@@ -321049,7 +321093,7 @@ var generateMessageIDV2 = (userId) => {
|
|
|
321049
321093
|
};
|
|
321050
321094
|
var generateMessageID = () => "3EB0" + randomBytes5(18).toString("hex").toUpperCase();
|
|
321051
321095
|
function bindWaitForEvent(ev, event) {
|
|
321052
|
-
return async (
|
|
321096
|
+
return async (check17, timeoutMs) => {
|
|
321053
321097
|
let listener;
|
|
321054
321098
|
let closeListener;
|
|
321055
321099
|
await promiseTimeout(timeoutMs, (resolve3, reject) => {
|
|
@@ -321060,7 +321104,7 @@ function bindWaitForEvent(ev, event) {
|
|
|
321060
321104
|
};
|
|
321061
321105
|
ev.on("connection.update", closeListener);
|
|
321062
321106
|
listener = async (update) => {
|
|
321063
|
-
if (await
|
|
321107
|
+
if (await check17(update)) {
|
|
321064
321108
|
resolve3();
|
|
321065
321109
|
}
|
|
321066
321110
|
};
|
|
@@ -335338,16 +335382,28 @@ function getAdapter3(channel2) {
|
|
|
335338
335382
|
}
|
|
335339
335383
|
|
|
335340
335384
|
// ../../packages/delivery/src/transport-channel.ts
|
|
335341
|
-
var
|
|
335342
|
-
|
|
335343
|
-
|
|
335344
|
-
"slack",
|
|
335345
|
-
"whatsapp"
|
|
335346
|
-
]);
|
|
335347
|
-
function resolveTransportChannel(channel2) {
|
|
335385
|
+
var CHANNEL_PRIORITY = ["telegram", "discord", "slack", "whatsapp"];
|
|
335386
|
+
var TRANSPORT_CHANNELS = new Set(CHANNEL_PRIORITY);
|
|
335387
|
+
function resolveTransportChannel(channel2, activeChannels) {
|
|
335348
335388
|
if (channel2 && TRANSPORT_CHANNELS.has(channel2)) return channel2;
|
|
335389
|
+
if (activeChannels && activeChannels.length > 0) {
|
|
335390
|
+
const active = new Set(activeChannels);
|
|
335391
|
+
const preferred = CHANNEL_PRIORITY.find((c) => active.has(c));
|
|
335392
|
+
if (preferred) return preferred;
|
|
335393
|
+
}
|
|
335349
335394
|
return "telegram";
|
|
335350
335395
|
}
|
|
335396
|
+
async function listActiveChannelsForAgent(db, agentId) {
|
|
335397
|
+
const [agentRow] = await db.select({ telegramBotToken: agents.telegramBotToken }).from(agents).where(eq6(agents.id, agentId)).limit(1);
|
|
335398
|
+
const bindings = await listChannelBindings(db, agentId);
|
|
335399
|
+
const enabled = new Set(bindings.filter((b) => b.enabled).map((b) => b.channel));
|
|
335400
|
+
const active = [];
|
|
335401
|
+
if (agentRow?.telegramBotToken) active.push("telegram");
|
|
335402
|
+
for (const channel2 of CHANNEL_PRIORITY) {
|
|
335403
|
+
if (channel2 !== "telegram" && enabled.has(channel2)) active.push(channel2);
|
|
335404
|
+
}
|
|
335405
|
+
return active;
|
|
335406
|
+
}
|
|
335351
335407
|
|
|
335352
335408
|
// ../../packages/tools/src/builtin/list-conversations.ts
|
|
335353
335409
|
var MAX_ROWS = 150;
|
|
@@ -335508,8 +335564,11 @@ import { z as z60 } from "zod";
|
|
|
335508
335564
|
import { realpath as realpath3 } from "node:fs/promises";
|
|
335509
335565
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
335510
335566
|
import path from "node:path";
|
|
335567
|
+
function defaultChannelForJob(ctx) {
|
|
335568
|
+
return ctx.notifyChannelOverride ?? resolveTransportChannel(ctx.jobChannel, ctx.activeChannels);
|
|
335569
|
+
}
|
|
335511
335570
|
async function resolveChannelForJob(ctx, explicitChannel) {
|
|
335512
|
-
const jobChannel =
|
|
335571
|
+
const jobChannel = defaultChannelForJob(ctx);
|
|
335513
335572
|
if (explicitChannel === void 0 || explicitChannel === jobChannel) {
|
|
335514
335573
|
return jobChannel;
|
|
335515
335574
|
}
|
|
@@ -335555,7 +335614,7 @@ async function resolveRecipientChatId(explicitChatId, ctx, noRecipientErrorName,
|
|
|
335555
335614
|
throw err;
|
|
335556
335615
|
}
|
|
335557
335616
|
const channel2 = await resolveChannelForJob(ctx, explicitChannel);
|
|
335558
|
-
const crossChannel = explicitChannel !== void 0 && explicitChannel !==
|
|
335617
|
+
const crossChannel = explicitChannel !== void 0 && explicitChannel !== defaultChannelForJob(ctx);
|
|
335559
335618
|
let chatId = explicitChatId ?? (crossChannel ? null : ctx.jobChatId);
|
|
335560
335619
|
if (explicitChatId === void 0 && chatId === null) {
|
|
335561
335620
|
chatId = await resolveOwnerConversation(ctx.db, ctx.agentId, channel2);
|
|
@@ -336302,7 +336361,7 @@ async function healthRoute(c, deps) {
|
|
|
336302
336361
|
// LLM is not pinged on every health check (expensive)
|
|
336303
336362
|
};
|
|
336304
336363
|
try {
|
|
336305
|
-
await deps.db.execute(
|
|
336364
|
+
await deps.db.execute(sql23`SELECT 1`);
|
|
336306
336365
|
result.db = "ok";
|
|
336307
336366
|
} catch (err) {
|
|
336308
336367
|
console.error("[health] DB ping failed:", err instanceof Error ? err.message : err);
|
|
@@ -351699,7 +351758,9 @@ async function walkJobChainToRoot(db, jobId) {
|
|
|
351699
351758
|
async function resolveChannelApprovalDeliveryTarget(db, jobId) {
|
|
351700
351759
|
const chain = await walkJobChainToRoot(db, jobId);
|
|
351701
351760
|
if (!chain) return null;
|
|
351702
|
-
const
|
|
351761
|
+
const rootHop = chain[chain.length - 1];
|
|
351762
|
+
const activeChannels = await listActiveChannelsForAgent(db, rootHop.agentId);
|
|
351763
|
+
const rootChannel = resolveTransportChannel(rootHop.channel, activeChannels);
|
|
351703
351764
|
if (rootChannel === "telegram") {
|
|
351704
351765
|
const target = await resolveApprovalDeliveryTarget(db, jobId);
|
|
351705
351766
|
if (!target) return null;
|
|
@@ -351788,7 +351849,7 @@ import { join as join12 } from "node:path";
|
|
|
351788
351849
|
|
|
351789
351850
|
// src/skills/install.ts
|
|
351790
351851
|
import { cp, rm as rm2, mkdir as mkdir5, readFile as readFile11 } from "node:fs/promises";
|
|
351791
|
-
import { dirname as dirname7, join as join11, basename as
|
|
351852
|
+
import { dirname as dirname7, join as join11, basename as basename4, sep as sep5, resolve as resolve2 } from "node:path";
|
|
351792
351853
|
|
|
351793
351854
|
// src/skills/source.ts
|
|
351794
351855
|
var SkillSourceError = class extends Error {
|
|
@@ -352568,7 +352629,7 @@ async function pickManifest(extractRoot, subdir, skillName) {
|
|
|
352568
352629
|
}
|
|
352569
352630
|
}
|
|
352570
352631
|
if (byFrontmatter.length > 0) return byFrontmatter[0];
|
|
352571
|
-
const byFolder = manifests.filter((rel) =>
|
|
352632
|
+
const byFolder = manifests.filter((rel) => basename4(dirname7(rel)) === skillName);
|
|
352572
352633
|
if (byFolder.length > 0) return byFolder[0];
|
|
352573
352634
|
throw new SkillInstallError(
|
|
352574
352635
|
`Repository has multiple skills but none named "${skillName}". Found: ${manifests.map((m) => dirname7(m)).join(", ")}.`
|
|
@@ -353471,13 +353532,15 @@ async function runJob(jobId, deps, runnerEnv, opts) {
|
|
|
353471
353532
|
const canSeeImages = llmClient.capabilities.vision === true || modelCanSeeImages(llmClient.config.model);
|
|
353472
353533
|
const imageCache = /* @__PURE__ */ new Map();
|
|
353473
353534
|
const isOrchestrator = agent.role === "orchestrator";
|
|
353474
|
-
const
|
|
353535
|
+
const triggerWantsConfirmation = (job.channel === "cron" || job.channel === "webhook") && job.chatId != null;
|
|
353536
|
+
const jobTriggerContext = job.triggerContext;
|
|
353537
|
+
const notifyChannelOverride = jobTriggerContext?.type === "cron" || jobTriggerContext?.type === "webhook" ? jobTriggerContext.notifyChannel ?? void 0 : void 0;
|
|
353475
353538
|
const deployment = await getDeploymentContext(db, job.entityId ?? void 0);
|
|
353476
353539
|
const jobContext = {
|
|
353477
353540
|
origin: job.channel ?? "unknown",
|
|
353478
353541
|
...job.task ? { task: job.task } : {},
|
|
353479
353542
|
...job.chatId ? { telegramChatId: job.chatId } : {},
|
|
353480
|
-
...
|
|
353543
|
+
...triggerWantsConfirmation ? { notifyOnSuccess: true } : {},
|
|
353481
353544
|
...job.parentJobId ? { isDelegated: true } : {},
|
|
353482
353545
|
...job.triggerContext ? { triggerContext: job.triggerContext } : {},
|
|
353483
353546
|
deployment
|
|
@@ -353513,6 +353576,11 @@ async function runJob(jobId, deps, runnerEnv, opts) {
|
|
|
353513
353576
|
capabilityTools.push(createSendVoiceTool());
|
|
353514
353577
|
capabilityTools.push(createListConversationsTool());
|
|
353515
353578
|
}
|
|
353579
|
+
const activeChannels = [
|
|
353580
|
+
...deliveryBotToken ? ["telegram"] : [],
|
|
353581
|
+
...hasDiscordBinding ? ["discord"] : [],
|
|
353582
|
+
...hasSlackBinding ? ["slack"] : []
|
|
353583
|
+
];
|
|
353516
353584
|
const mcpClosers = [];
|
|
353517
353585
|
try {
|
|
353518
353586
|
const [rootEntityRow] = await db.select({
|
|
@@ -353602,7 +353670,10 @@ async function runJob(jobId, deps, runnerEnv, opts) {
|
|
|
353602
353670
|
decryptedEnv = Object.fromEntries(
|
|
353603
353671
|
Object.entries(rawEnv).map(([k, v]) => [k, decrypt(v)])
|
|
353604
353672
|
);
|
|
353605
|
-
} catch {
|
|
353673
|
+
} catch (err) {
|
|
353674
|
+
console.error(
|
|
353675
|
+
`[execute] MCP server '${ms.slug}' env vars failed to decrypt (tampered, or wrong/rotated master key): ${err instanceof Error ? err.message : String(err)}`
|
|
353676
|
+
);
|
|
353606
353677
|
continue;
|
|
353607
353678
|
}
|
|
353608
353679
|
const connectOpts = {
|
|
@@ -353716,8 +353787,8 @@ async function runJob(jobId, deps, runnerEnv, opts) {
|
|
|
353716
353787
|
return { status: "failed", error: errorCode };
|
|
353717
353788
|
}
|
|
353718
353789
|
const ruleRows = await db.select().from(approvalRules).where(eq6(approvalRules.entityId, job.entityId ?? "")).orderBy(
|
|
353719
|
-
|
|
353720
|
-
|
|
353790
|
+
sql23`${approvalRules.agentId} IS NULL`,
|
|
353791
|
+
sql23`${approvalRules.toolName} = '*'`,
|
|
353721
353792
|
approvalRules.id
|
|
353722
353793
|
);
|
|
353723
353794
|
let approvalRuleList = ruleRows.map((r) => ({
|
|
@@ -353836,6 +353907,8 @@ async function runJob(jobId, deps, runnerEnv, opts) {
|
|
|
353836
353907
|
db,
|
|
353837
353908
|
jobChatId: job.chatId ?? null,
|
|
353838
353909
|
jobChannel: job.channel,
|
|
353910
|
+
activeChannels,
|
|
353911
|
+
notifyChannelOverride,
|
|
353839
353912
|
resolvedTelegramBotToken: inheritedRootBotToken ?? void 0,
|
|
353840
353913
|
embeddingClient: deps.embeddingClient,
|
|
353841
353914
|
workspaces: agentWorkspacesList,
|
|
@@ -353937,7 +354010,7 @@ async function runJob(jobId, deps, runnerEnv, opts) {
|
|
|
353937
354010
|
const MAX_EMPTY_TURN_RETRIES = 2;
|
|
353938
354011
|
let emptyTurnRetries = 0;
|
|
353939
354012
|
let consecutiveDeliveryOnlyTurns = 0;
|
|
353940
|
-
const requiresToolDelivery = TOOL_ONLY_DELIVERY_CHANNELS.has(job.channel ?? "") ||
|
|
354013
|
+
const requiresToolDelivery = TOOL_ONLY_DELIVERY_CHANNELS.has(job.channel ?? "") || triggerWantsConfirmation;
|
|
353941
354014
|
const CHANNEL_DISPLAY_NAMES = {
|
|
353942
354015
|
telegram: "Telegram",
|
|
353943
354016
|
discord: "Discord",
|
|
@@ -354388,6 +354461,8 @@ ${notice}` : notice;
|
|
|
354388
354461
|
db,
|
|
354389
354462
|
jobChatId: job.chatId ?? null,
|
|
354390
354463
|
jobChannel: job.channel,
|
|
354464
|
+
activeChannels,
|
|
354465
|
+
notifyChannelOverride,
|
|
354391
354466
|
resolvedTelegramBotToken: inheritedRootBotToken ?? void 0,
|
|
354392
354467
|
embeddingClient: deps.embeddingClient,
|
|
354393
354468
|
workspaces: agentWorkspacesList,
|
|
@@ -354576,6 +354651,8 @@ ${notice}` : notice;
|
|
|
354576
354651
|
db,
|
|
354577
354652
|
jobChatId: job.chatId ?? null,
|
|
354578
354653
|
jobChannel: job.channel,
|
|
354654
|
+
activeChannels,
|
|
354655
|
+
notifyChannelOverride,
|
|
354579
354656
|
resolvedTelegramBotToken: inheritedRootBotToken ?? void 0,
|
|
354580
354657
|
embeddingClient: deps.embeddingClient,
|
|
354581
354658
|
workspaces: agentWorkspacesList,
|
|
@@ -355732,7 +355809,8 @@ async function notifyBudgetExhausted(db, agentId, scheduleName, dailyBudgetUsd)
|
|
|
355732
355809
|
try {
|
|
355733
355810
|
const ownerChatId = await resolveOwnerChatId(db, agentId);
|
|
355734
355811
|
if (!ownerChatId) return;
|
|
355735
|
-
const
|
|
355812
|
+
const activeChannels = await listActiveChannelsForAgent(db, agentId);
|
|
355813
|
+
const channel2 = resolveTransportChannel("cron", activeChannels);
|
|
355736
355814
|
const creds = await getBindingCredentials(db, agentId, channel2);
|
|
355737
355815
|
if (!creds) return;
|
|
355738
355816
|
const adapter2 = getAdapter3(channel2);
|
|
@@ -355766,6 +355844,9 @@ async function runScheduleTick(db, deps, max2 = 5) {
|
|
|
355766
355844
|
notifyOnSuccess: agentSchedules.notifyOnSuccess,
|
|
355767
355845
|
// Explicit delivery target (e.g. "post to #team"), null for the common case.
|
|
355768
355846
|
chatId: agentSchedules.chatId,
|
|
355847
|
+
// Explicit notify channel choice (B1), null = auto (first active channel
|
|
355848
|
+
// by priority, the historical behavior — see the chatId resolution below).
|
|
355849
|
+
notifyChannel: agentSchedules.notifyChannel,
|
|
355769
355850
|
// Read BEFORE this tick's writes — "was it already budget_exhausted" is
|
|
355770
355851
|
// the transition check the notify-once-per-day dedup relies on below.
|
|
355771
355852
|
lastStatus: agentSchedules.lastStatus,
|
|
@@ -355778,6 +355859,7 @@ async function runScheduleTick(db, deps, max2 = 5) {
|
|
|
355778
355859
|
).limit(max2 * 2);
|
|
355779
355860
|
if (candidates.length === 0) return 0;
|
|
355780
355861
|
const fires = [];
|
|
355862
|
+
const notifyUnreachableScheduleIds = /* @__PURE__ */ new Set();
|
|
355781
355863
|
for (const sched of candidates.slice(0, max2)) {
|
|
355782
355864
|
if (!sched.task || !sched.entityId) continue;
|
|
355783
355865
|
const [liveJob] = await db.select({ id: agentJobs.id, createdAt: agentJobs.createdAt }).from(agentJobs).where(and5(eq6(agentJobs.scheduleId, sched.id), inArray4(agentJobs.status, LIVE_JOB_STATUSES))).orderBy(desc(agentJobs.createdAt)).limit(1);
|
|
@@ -355795,8 +355877,8 @@ async function runScheduleTick(db, deps, max2 = 5) {
|
|
|
355795
355877
|
continue;
|
|
355796
355878
|
}
|
|
355797
355879
|
const tz = resolveTimezone(sched.timezone);
|
|
355798
|
-
const [spentRow] = await db.select({ spent:
|
|
355799
|
-
|
|
355880
|
+
const [spentRow] = await db.select({ spent: sql23`COALESCE(SUM(${agentJobs.totalCostUsd}), 0)` }).from(agentJobs).where(
|
|
355881
|
+
sql23`${agentJobs.scheduleId} = ${sched.id} AND ${agentJobs.createdAt} >= (date_trunc('day', now() AT TIME ZONE ${tz}) AT TIME ZONE ${tz})`
|
|
355800
355882
|
);
|
|
355801
355883
|
const spentToday = Number(spentRow?.spent ?? 0);
|
|
355802
355884
|
if (spentToday >= sched.dailyBudgetUsd) {
|
|
@@ -355837,7 +355919,21 @@ async function runScheduleTick(db, deps, max2 = 5) {
|
|
|
355837
355919
|
)
|
|
355838
355920
|
).returning({ id: agentSchedules.id });
|
|
355839
355921
|
if (claimed.length === 0) continue;
|
|
355840
|
-
|
|
355922
|
+
let notifyChatId = null;
|
|
355923
|
+
if (sched.notifyOnSuccess) {
|
|
355924
|
+
if (sched.notifyChannel) {
|
|
355925
|
+
const channel2 = sched.notifyChannel;
|
|
355926
|
+
notifyChatId = sched.chatId ?? await resolveOwnerConversation(db, sched.agentId, channel2);
|
|
355927
|
+
if (!notifyChatId) {
|
|
355928
|
+
notifyUnreachableScheduleIds.add(sched.id);
|
|
355929
|
+
console.error(
|
|
355930
|
+
`[runScheduleTick] schedule "${sched.name}" (${sched.id}) chose notify channel '${channel2}' but has no owner conversation there yet (never DMed on that channel). Firing WITHOUT a delivery target \u2014 not falling back to another channel. lastStatus will read 'notify_unreachable'.`
|
|
355931
|
+
);
|
|
355932
|
+
}
|
|
355933
|
+
} else {
|
|
355934
|
+
notifyChatId = sched.chatId ?? await resolveOwnerChatId(db, sched.agentId) ?? null;
|
|
355935
|
+
}
|
|
355936
|
+
}
|
|
355841
355937
|
const [job] = await db.insert(agentJobs).values({
|
|
355842
355938
|
entityId: sched.entityId,
|
|
355843
355939
|
agentId: sched.agentId,
|
|
@@ -355850,7 +355946,8 @@ async function runScheduleTick(db, deps, max2 = 5) {
|
|
|
355850
355946
|
triggerContext: {
|
|
355851
355947
|
type: "cron",
|
|
355852
355948
|
scheduleName: sched.name,
|
|
355853
|
-
prevRunAt: sched.lastRun ? sched.lastRun.toISOString() : null
|
|
355949
|
+
prevRunAt: sched.lastRun ? sched.lastRun.toISOString() : null,
|
|
355950
|
+
notifyChannel: sched.notifyChannel ?? null
|
|
355854
355951
|
}
|
|
355855
355952
|
}).returning({ id: agentJobs.id });
|
|
355856
355953
|
if (!job) {
|
|
@@ -355879,7 +355976,9 @@ async function runScheduleTick(db, deps, max2 = 5) {
|
|
|
355879
355976
|
if (settled.status === "rejected") continue;
|
|
355880
355977
|
const { fire, result } = settled.value;
|
|
355881
355978
|
let lastStatus;
|
|
355882
|
-
if (
|
|
355979
|
+
if (notifyUnreachableScheduleIds.has(fire.scheduleId)) {
|
|
355980
|
+
lastStatus = "notify_unreachable";
|
|
355981
|
+
} else if (result.status === "completed") lastStatus = "success";
|
|
355883
355982
|
else if (result.status === "failed") lastStatus = "failed";
|
|
355884
355983
|
else if (result.status === "cancelled") lastStatus = "failed";
|
|
355885
355984
|
else lastStatus = "no_action";
|
|
@@ -355913,7 +356012,8 @@ async function deliverCompletedRoots(db) {
|
|
|
355913
356012
|
chatId: agentJobs.chatId,
|
|
355914
356013
|
agentId: agentJobs.agentId,
|
|
355915
356014
|
entityId: agentJobs.entityId,
|
|
355916
|
-
task: agentJobs.task
|
|
356015
|
+
task: agentJobs.task,
|
|
356016
|
+
triggerContext: agentJobs.triggerContext
|
|
355917
356017
|
}).from(agentJobs).where(eq6(agentJobs.id, rootJobId)).limit(1);
|
|
355918
356018
|
const rootJob = rootJobRows[0];
|
|
355919
356019
|
if (!rootJob) continue;
|
|
@@ -355958,7 +356058,10 @@ async function deliverCompletedRoots(db) {
|
|
|
355958
356058
|
}
|
|
355959
356059
|
if (rootJob.chatId && rootJob.agentId && compiledResult.trim()) {
|
|
355960
356060
|
try {
|
|
355961
|
-
const
|
|
356061
|
+
const activeChannels = await listActiveChannelsForAgent(db, rootJob.agentId);
|
|
356062
|
+
const triggerContext = rootJob.triggerContext;
|
|
356063
|
+
const notifyChannelOverride = triggerContext?.type === "cron" || triggerContext?.type === "webhook" ? triggerContext.notifyChannel ?? void 0 : void 0;
|
|
356064
|
+
const channel2 = notifyChannelOverride ?? resolveTransportChannel(rootJob.channel, activeChannels);
|
|
355962
356065
|
const allowed = rootJob.entityId !== null && await isConversationAllowed(db, {
|
|
355963
356066
|
entityId: rootJob.entityId,
|
|
355964
356067
|
agentId: rootJob.agentId,
|
|
@@ -356471,12 +356574,12 @@ async function runCuratorTick(db, _deps, runnerEnv) {
|
|
|
356471
356574
|
eq6(agentSkills.state, "active"),
|
|
356472
356575
|
eq6(entities.reflectionEnabled, true)
|
|
356473
356576
|
)
|
|
356474
|
-
).groupBy(agentSkills.entityId).having(
|
|
356577
|
+
).groupBy(agentSkills.entityId).having(sql23`count(${agentSkills.id}) >= ${e2.CURATOR_MIN_SKILLS}`);
|
|
356475
356578
|
for (const c of skillCandidates) if (c.entityId) skillSet.add(c.entityId);
|
|
356476
356579
|
}
|
|
356477
356580
|
const memorySet = /* @__PURE__ */ new Set();
|
|
356478
356581
|
if (e2.MEMORY_CURATION_ENABLED !== "false") {
|
|
356479
|
-
const memoryCandidates = await db.select({ entityId: agentMemory.entityId }).from(agentMemory).innerJoin(entities, eq6(entities.id, agentMemory.entityId)).where(and5(eq6(agentMemory.archived, false), eq6(entities.memoryCurationEnabled, true))).groupBy(agentMemory.entityId).having(
|
|
356582
|
+
const memoryCandidates = await db.select({ entityId: agentMemory.entityId }).from(agentMemory).innerJoin(entities, eq6(entities.id, agentMemory.entityId)).where(and5(eq6(agentMemory.archived, false), eq6(entities.memoryCurationEnabled, true))).groupBy(agentMemory.entityId).having(sql23`count(${agentMemory.id}) >= ${e2.CURATOR_MEMORY_MIN}`);
|
|
356480
356583
|
for (const c of memoryCandidates) if (c.entityId) memorySet.add(c.entityId);
|
|
356481
356584
|
}
|
|
356482
356585
|
if (skillSet.size === 0 && memorySet.size === 0) {
|
|
@@ -357119,18 +357222,38 @@ async function webhookRoute(c, deps, runnerEnv) {
|
|
|
357119
357222
|
const triggeredAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
357120
357223
|
const interpolated = interpolateTemplate(trigger.taskTemplate, bodyResult.value);
|
|
357121
357224
|
const task = buildWebhookEnvelope(trigger.name, triggeredAt, interpolated);
|
|
357225
|
+
let notifyChatId = null;
|
|
357226
|
+
let notifyChannel = null;
|
|
357227
|
+
if (trigger.notifyOnSuccess) {
|
|
357228
|
+
if (trigger.notifyChannel) {
|
|
357229
|
+
notifyChannel = trigger.notifyChannel;
|
|
357230
|
+
} else {
|
|
357231
|
+
const activeChannels = (await listActiveChannelsForAgent(deps.db, agentId)).filter(
|
|
357232
|
+
(c2) => c2 !== "whatsapp"
|
|
357233
|
+
);
|
|
357234
|
+
notifyChannel = resolveTransportChannel("webhook", activeChannels);
|
|
357235
|
+
}
|
|
357236
|
+
notifyChatId = await resolveOwnerConversation(deps.db, agentId, notifyChannel);
|
|
357237
|
+
if (!notifyChatId) {
|
|
357238
|
+
console.error(
|
|
357239
|
+
`[webhook] trigger "${trigger.name}" (${trigger.slug}) chose notify channel '${notifyChannel}' but has no owner conversation there yet (never DMed on that channel). Firing WITHOUT a delivery target \u2014 not falling back to another channel.`
|
|
357240
|
+
);
|
|
357241
|
+
}
|
|
357242
|
+
}
|
|
357122
357243
|
const [job] = await deps.db.insert(agentJobs).values({
|
|
357123
357244
|
entityId: trigger.entityId ?? void 0,
|
|
357124
357245
|
agentId,
|
|
357125
357246
|
channel: "webhook",
|
|
357126
357247
|
task,
|
|
357127
357248
|
status: "pending",
|
|
357249
|
+
chatId: notifyChatId,
|
|
357128
357250
|
messages: [{ role: "user", content: task }],
|
|
357129
357251
|
triggerContext: {
|
|
357130
357252
|
type: "webhook",
|
|
357131
357253
|
webhookName: trigger.name,
|
|
357132
357254
|
slug: trigger.slug,
|
|
357133
|
-
triggeredAt
|
|
357255
|
+
triggeredAt,
|
|
357256
|
+
notifyChannel
|
|
357134
357257
|
}
|
|
357135
357258
|
}).returning({ id: agentJobs.id });
|
|
357136
357259
|
if (!job) {
|