@raybase/core 0.0.1 → 0.3.3
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/LICENSE +21 -0
- package/dist/.admin-build/AdminApp.css +2 -0
- package/dist/.admin-build/AdminApp.js +77 -0
- package/dist/.admin-docs-build/AdminDocsApp.css +2 -0
- package/dist/.admin-docs-build/AdminDocsApp.js +45 -0
- package/dist/actions.d.ts +347 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +661 -0
- package/dist/actions.js.map +1 -0
- package/dist/admin-assets/admin.7738f50720a8ed7b.css +2 -0
- package/dist/admin-assets/admin.8678cb61db34dc81.js +77 -0
- package/dist/admin-boot.d.ts +94 -0
- package/dist/admin-boot.d.ts.map +1 -0
- package/dist/admin-boot.js +139 -0
- package/dist/admin-boot.js.map +1 -0
- package/dist/admin-docs-content.d.ts +95 -0
- package/dist/admin-docs-content.d.ts.map +1 -0
- package/dist/admin-docs-content.js +463 -0
- package/dist/admin-docs-content.js.map +1 -0
- package/dist/admin-docs-ui.d.ts +11 -0
- package/dist/admin-docs-ui.d.ts.map +1 -0
- package/dist/admin-docs-ui.js +23 -0
- package/dist/admin-docs-ui.js.map +1 -0
- package/dist/admin-kit.d.ts +29 -0
- package/dist/admin-kit.js +1557 -0
- package/dist/admin-role.d.ts +8 -0
- package/dist/admin-role.d.ts.map +1 -0
- package/dist/admin-role.js +22 -0
- package/dist/admin-role.js.map +1 -0
- package/dist/admin-ui.d.ts +3 -0
- package/dist/admin-ui.d.ts.map +1 -0
- package/dist/admin-ui.js +16 -0
- package/dist/admin-ui.js.map +1 -0
- package/dist/agent-ai-chat.d.ts +127 -0
- package/dist/agent-ai-chat.d.ts.map +1 -0
- package/dist/agent-ai-chat.js +5975 -0
- package/dist/agent-ai-chat.js.map +1 -0
- package/dist/agent-chapter-archive.d.ts +214 -0
- package/dist/agent-chapter-archive.d.ts.map +1 -0
- package/dist/agent-chapter-archive.js +696 -0
- package/dist/agent-chapter-archive.js.map +1 -0
- package/dist/agent-chapter-search.d.ts +116 -0
- package/dist/agent-chapter-search.d.ts.map +1 -0
- package/dist/agent-chapter-search.js +605 -0
- package/dist/agent-chapter-search.js.map +1 -0
- package/dist/agent-chapter-tools.d.ts +45 -0
- package/dist/agent-chapter-tools.d.ts.map +1 -0
- package/dist/agent-chapter-tools.js +344 -0
- package/dist/agent-chapter-tools.js.map +1 -0
- package/dist/agent-chapters.d.ts +228 -0
- package/dist/agent-chapters.d.ts.map +1 -0
- package/dist/agent-chapters.js +737 -0
- package/dist/agent-chapters.js.map +1 -0
- package/dist/agent-data-parts.d.ts +167 -0
- package/dist/agent-data-parts.d.ts.map +1 -0
- package/dist/agent-data-parts.js +68 -0
- package/dist/agent-data-parts.js.map +1 -0
- package/dist/agent-errors.d.ts +41 -0
- package/dist/agent-errors.d.ts.map +1 -0
- package/dist/agent-errors.js +191 -0
- package/dist/agent-errors.js.map +1 -0
- package/dist/agent-follow-up-store.d.ts +273 -0
- package/dist/agent-follow-up-store.d.ts.map +1 -0
- package/dist/agent-follow-up-store.js +703 -0
- package/dist/agent-follow-up-store.js.map +1 -0
- package/dist/agent-follow-ups.d.ts +314 -0
- package/dist/agent-follow-ups.d.ts.map +1 -0
- package/dist/agent-follow-ups.js +840 -0
- package/dist/agent-follow-ups.js.map +1 -0
- package/dist/agent-memory.d.ts +323 -0
- package/dist/agent-memory.d.ts.map +1 -0
- package/dist/agent-memory.js +1270 -0
- package/dist/agent-memory.js.map +1 -0
- package/dist/agent-message-parts.d.ts +58 -0
- package/dist/agent-message-parts.d.ts.map +1 -0
- package/dist/agent-message-parts.js +163 -0
- package/dist/agent-message-parts.js.map +1 -0
- package/dist/agent-remote-mcp-credentials.d.ts +154 -0
- package/dist/agent-remote-mcp-credentials.d.ts.map +1 -0
- package/dist/agent-remote-mcp-credentials.js +287 -0
- package/dist/agent-remote-mcp-credentials.js.map +1 -0
- package/dist/agent-remote-mcp-crypto.d.ts +32 -0
- package/dist/agent-remote-mcp-crypto.d.ts.map +1 -0
- package/dist/agent-remote-mcp-crypto.js +101 -0
- package/dist/agent-remote-mcp-crypto.js.map +1 -0
- package/dist/agent-remote-mcp-install.d.ts +299 -0
- package/dist/agent-remote-mcp-install.d.ts.map +1 -0
- package/dist/agent-remote-mcp-install.js +785 -0
- package/dist/agent-remote-mcp-install.js.map +1 -0
- package/dist/agent-remote-mcp-oauth.d.ts +73 -0
- package/dist/agent-remote-mcp-oauth.d.ts.map +1 -0
- package/dist/agent-remote-mcp-oauth.js +344 -0
- package/dist/agent-remote-mcp-oauth.js.map +1 -0
- package/dist/agent-remote-mcp-transport.d.ts +46 -0
- package/dist/agent-remote-mcp-transport.d.ts.map +1 -0
- package/dist/agent-remote-mcp-transport.js +225 -0
- package/dist/agent-remote-mcp-transport.js.map +1 -0
- package/dist/agent-remote-mcp.d.ts +147 -0
- package/dist/agent-remote-mcp.d.ts.map +1 -0
- package/dist/agent-remote-mcp.js +681 -0
- package/dist/agent-remote-mcp.js.map +1 -0
- package/dist/agent-room-redaction.d.ts +66 -0
- package/dist/agent-room-redaction.d.ts.map +1 -0
- package/dist/agent-room-redaction.js +264 -0
- package/dist/agent-room-redaction.js.map +1 -0
- package/dist/agent-rooms.d.ts +209 -0
- package/dist/agent-rooms.d.ts.map +1 -0
- package/dist/agent-rooms.js +244 -0
- package/dist/agent-rooms.js.map +1 -0
- package/dist/agent-runtime.d.ts +541 -0
- package/dist/agent-runtime.d.ts.map +1 -0
- package/dist/agent-runtime.js +4260 -0
- package/dist/agent-runtime.js.map +1 -0
- package/dist/agent-skill-archive.d.ts +20 -0
- package/dist/agent-skill-archive.d.ts.map +1 -0
- package/dist/agent-skill-archive.js +316 -0
- package/dist/agent-skill-archive.js.map +1 -0
- package/dist/agent-skill-discovery.d.ts +96 -0
- package/dist/agent-skill-discovery.d.ts.map +1 -0
- package/dist/agent-skill-discovery.js +464 -0
- package/dist/agent-skill-discovery.js.map +1 -0
- package/dist/agent-skill-format.d.ts +57 -0
- package/dist/agent-skill-format.d.ts.map +1 -0
- package/dist/agent-skill-format.js +238 -0
- package/dist/agent-skill-format.js.map +1 -0
- package/dist/agent-skill-import.d.ts +64 -0
- package/dist/agent-skill-import.d.ts.map +1 -0
- package/dist/agent-skill-import.js +295 -0
- package/dist/agent-skill-import.js.map +1 -0
- package/dist/agent-skill-publish.d.ts +51 -0
- package/dist/agent-skill-publish.d.ts.map +1 -0
- package/dist/agent-skill-publish.js +136 -0
- package/dist/agent-skill-publish.js.map +1 -0
- package/dist/agent-skill-store.d.ts +252 -0
- package/dist/agent-skill-store.d.ts.map +1 -0
- package/dist/agent-skill-store.js +514 -0
- package/dist/agent-skill-store.js.map +1 -0
- package/dist/agent-skills.d.ts +85 -0
- package/dist/agent-skills.d.ts.map +1 -0
- package/dist/agent-skills.js +291 -0
- package/dist/agent-skills.js.map +1 -0
- package/dist/agent-transcript-pager.d.ts +77 -0
- package/dist/agent-transcript-pager.d.ts.map +1 -0
- package/dist/agent-transcript-pager.js +210 -0
- package/dist/agent-transcript-pager.js.map +1 -0
- package/dist/agent-user-data-parts.d.ts +20 -0
- package/dist/agent-user-data-parts.d.ts.map +1 -0
- package/dist/agent-user-data-parts.js +161 -0
- package/dist/agent-user-data-parts.js.map +1 -0
- package/dist/agent-user-transcript.d.ts +46 -0
- package/dist/agent-user-transcript.d.ts.map +1 -0
- package/dist/agent-user-transcript.js +106 -0
- package/dist/agent-user-transcript.js.map +1 -0
- package/dist/agent-voice-notes.d.ts +15 -0
- package/dist/agent-voice-notes.d.ts.map +1 -0
- package/dist/agent-voice-notes.js +17 -0
- package/dist/agent-voice-notes.js.map +1 -0
- package/dist/agent-wakes.d.ts +213 -0
- package/dist/agent-wakes.d.ts.map +1 -0
- package/dist/agent-wakes.js +534 -0
- package/dist/agent-wakes.js.map +1 -0
- package/dist/agent.d.ts +1780 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +3123 -0
- package/dist/agent.js.map +1 -0
- package/dist/ai.d.ts +583 -0
- package/dist/ai.d.ts.map +1 -0
- package/dist/ai.js +1858 -0
- package/dist/ai.js.map +1 -0
- package/dist/app-manifest.d.ts +255 -0
- package/dist/app-manifest.d.ts.map +1 -0
- package/dist/app-manifest.js +372 -0
- package/dist/app-manifest.js.map +1 -0
- package/dist/app-users.d.ts +30 -0
- package/dist/app-users.d.ts.map +1 -0
- package/dist/app-users.js +91 -0
- package/dist/app-users.js.map +1 -0
- package/dist/audit-archive.d.ts +85 -0
- package/dist/audit-archive.d.ts.map +1 -0
- package/dist/audit-archive.js +178 -0
- package/dist/audit-archive.js.map +1 -0
- package/dist/audit.d.ts +54 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +95 -0
- package/dist/audit.js.map +1 -0
- package/dist/auth-logger.d.ts +28 -0
- package/dist/auth-logger.d.ts.map +1 -0
- package/dist/auth-logger.js +53 -0
- package/dist/auth-logger.js.map +1 -0
- package/dist/auth-password-secret.d.ts +59 -0
- package/dist/auth-password-secret.d.ts.map +1 -0
- package/dist/auth-password-secret.js +409 -0
- package/dist/auth-password-secret.js.map +1 -0
- package/dist/auth-schema.d.ts +120 -0
- package/dist/auth-schema.d.ts.map +1 -0
- package/dist/auth-schema.js +285 -0
- package/dist/auth-schema.js.map +1 -0
- package/dist/auth.d.ts +321 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +1562 -0
- package/dist/auth.js.map +1 -0
- package/dist/backup-archive.d.ts +257 -0
- package/dist/backup-archive.d.ts.map +1 -0
- package/dist/backup-archive.js +2068 -0
- package/dist/backup-archive.js.map +1 -0
- package/dist/backup-crypto.d.ts +313 -0
- package/dist/backup-crypto.d.ts.map +1 -0
- package/dist/backup-crypto.js +693 -0
- package/dist/backup-crypto.js.map +1 -0
- package/dist/backup-format.d.ts +200 -0
- package/dist/backup-format.d.ts.map +1 -0
- package/dist/backup-format.js +1247 -0
- package/dist/backup-format.js.map +1 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +15 -0
- package/dist/cli.js.map +1 -0
- package/dist/clock.d.ts +35 -0
- package/dist/clock.d.ts.map +1 -0
- package/dist/clock.js +83 -0
- package/dist/clock.js.map +1 -0
- package/dist/data-client.d.ts +187 -0
- package/dist/data-client.d.ts.map +1 -0
- package/dist/data-client.js +590 -0
- package/dist/data-client.js.map +1 -0
- package/dist/data-secrets.d.ts +164 -0
- package/dist/data-secrets.d.ts.map +1 -0
- package/dist/data-secrets.js +383 -0
- package/dist/data-secrets.js.map +1 -0
- package/dist/db.d.ts +453 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +324 -0
- package/dist/db.js.map +1 -0
- package/dist/dev-activity.d.ts +48 -0
- package/dist/dev-activity.d.ts.map +1 -0
- package/dist/dev-activity.js +50 -0
- package/dist/dev-activity.js.map +1 -0
- package/dist/do.d.ts +429 -0
- package/dist/do.d.ts.map +1 -0
- package/dist/do.js +4526 -0
- package/dist/do.js.map +1 -0
- package/dist/email.d.ts +137 -0
- package/dist/email.d.ts.map +1 -0
- package/dist/email.js +527 -0
- package/dist/email.js.map +1 -0
- package/dist/generated/admin-assets.d.ts +16 -0
- package/dist/generated/admin-assets.d.ts.map +1 -0
- package/dist/generated/admin-assets.js +16 -0
- package/dist/generated/admin-assets.js.map +1 -0
- package/dist/generated/admin-docs-assets.d.ts +3 -0
- package/dist/generated/admin-docs-assets.d.ts.map +1 -0
- package/dist/generated/admin-docs-assets.js +3 -0
- package/dist/generated/admin-docs-assets.js.map +1 -0
- package/dist/handoff-consumer.d.ts +79 -0
- package/dist/handoff-consumer.d.ts.map +1 -0
- package/dist/handoff-consumer.js +300 -0
- package/dist/handoff-consumer.js.map +1 -0
- package/dist/handoff.d.ts +70 -0
- package/dist/handoff.d.ts.map +1 -0
- package/dist/handoff.js +228 -0
- package/dist/handoff.js.map +1 -0
- package/dist/host-auth.d.ts +47 -0
- package/dist/host-auth.d.ts.map +1 -0
- package/dist/host-auth.js +59 -0
- package/dist/host-auth.js.map +1 -0
- package/dist/host-user.d.ts +15 -0
- package/dist/host-user.d.ts.map +1 -0
- package/dist/host-user.js +23 -0
- package/dist/host-user.js.map +1 -0
- package/dist/html.d.ts +35 -0
- package/dist/html.d.ts.map +1 -0
- package/dist/html.js +634 -0
- package/dist/html.js.map +1 -0
- package/dist/http-error.d.ts +13 -0
- package/dist/http-error.d.ts.map +1 -0
- package/dist/http-error.js +15 -0
- package/dist/http-error.js.map +1 -0
- package/dist/imports.d.ts +219 -0
- package/dist/imports.d.ts.map +1 -0
- package/dist/imports.js +571 -0
- package/dist/imports.js.map +1 -0
- package/dist/index.d.ts +78 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +76 -0
- package/dist/index.js.map +1 -0
- package/dist/inference-tape.d.ts +64 -0
- package/dist/inference-tape.d.ts.map +1 -0
- package/dist/inference-tape.js +278 -0
- package/dist/inference-tape.js.map +1 -0
- package/dist/internal.d.ts +15 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +48 -0
- package/dist/internal.js.map +1 -0
- package/dist/jobs.d.ts +796 -0
- package/dist/jobs.d.ts.map +1 -0
- package/dist/jobs.js +538 -0
- package/dist/jobs.js.map +1 -0
- package/dist/json-schema.d.ts +91 -0
- package/dist/json-schema.d.ts.map +1 -0
- package/dist/json-schema.js +884 -0
- package/dist/json-schema.js.map +1 -0
- package/dist/knowledge.d.ts +33 -0
- package/dist/knowledge.d.ts.map +1 -0
- package/dist/knowledge.js +348 -0
- package/dist/knowledge.js.map +1 -0
- package/dist/local-dev-chrome.d.ts +29 -0
- package/dist/local-dev-chrome.d.ts.map +1 -0
- package/dist/local-dev-chrome.js +514 -0
- package/dist/local-dev-chrome.js.map +1 -0
- package/dist/local-dev-personas.d.ts +15 -0
- package/dist/local-dev-personas.d.ts.map +1 -0
- package/dist/local-dev-personas.js +46 -0
- package/dist/local-dev-personas.js.map +1 -0
- package/dist/mcp.d.ts +567 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +2480 -0
- package/dist/mcp.js.map +1 -0
- package/dist/modules.d.ts +145 -0
- package/dist/modules.d.ts.map +1 -0
- package/dist/modules.js +164 -0
- package/dist/modules.js.map +1 -0
- package/dist/notification-client.d.ts +94 -0
- package/dist/notification-client.d.ts.map +1 -0
- package/dist/notification-client.js +127 -0
- package/dist/notification-client.js.map +1 -0
- package/dist/notifications.d.ts +447 -0
- package/dist/notifications.d.ts.map +1 -0
- package/dist/notifications.js +1625 -0
- package/dist/notifications.js.map +1 -0
- package/dist/operator-data-query.d.ts +117 -0
- package/dist/operator-data-query.d.ts.map +1 -0
- package/dist/operator-data-query.js +431 -0
- package/dist/operator-data-query.js.map +1 -0
- package/dist/operator-mcp.d.ts +63 -0
- package/dist/operator-mcp.d.ts.map +1 -0
- package/dist/operator-mcp.js +2828 -0
- package/dist/operator-mcp.js.map +1 -0
- package/dist/outbound-https.d.ts +24 -0
- package/dist/outbound-https.d.ts.map +1 -0
- package/dist/outbound-https.js +172 -0
- package/dist/outbound-https.js.map +1 -0
- package/dist/pitr.d.ts +60 -0
- package/dist/pitr.d.ts.map +1 -0
- package/dist/pitr.js +94 -0
- package/dist/pitr.js.map +1 -0
- package/dist/platform.d.ts +199 -0
- package/dist/platform.d.ts.map +1 -0
- package/dist/platform.js +196 -0
- package/dist/platform.js.map +1 -0
- package/dist/policies.d.ts +115 -0
- package/dist/policies.d.ts.map +1 -0
- package/dist/policies.js +158 -0
- package/dist/policies.js.map +1 -0
- package/dist/principal.d.ts +143 -0
- package/dist/principal.d.ts.map +1 -0
- package/dist/principal.js +174 -0
- package/dist/principal.js.map +1 -0
- package/dist/realtime.d.ts +280 -0
- package/dist/realtime.d.ts.map +1 -0
- package/dist/realtime.js +578 -0
- package/dist/realtime.js.map +1 -0
- package/dist/retrieval.d.ts +263 -0
- package/dist/retrieval.d.ts.map +1 -0
- package/dist/retrieval.js +602 -0
- package/dist/retrieval.js.map +1 -0
- package/dist/runtime-error-client.d.ts +10 -0
- package/dist/runtime-error-client.d.ts.map +1 -0
- package/dist/runtime-error-client.js +70 -0
- package/dist/runtime-error-client.js.map +1 -0
- package/dist/runtime-errors.d.ts +180 -0
- package/dist/runtime-errors.d.ts.map +1 -0
- package/dist/runtime-errors.js +572 -0
- package/dist/runtime-errors.js.map +1 -0
- package/dist/schema.d.ts +434 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +232 -0
- package/dist/schema.js.map +1 -0
- package/dist/search.d.ts +216 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +785 -0
- package/dist/search.js.map +1 -0
- package/dist/settings.d.ts +191 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +478 -0
- package/dist/settings.js.map +1 -0
- package/dist/sql.d.ts +7 -0
- package/dist/sql.d.ts.map +1 -0
- package/dist/sql.js +30 -0
- package/dist/sql.js.map +1 -0
- package/dist/storage-client.d.ts +69 -0
- package/dist/storage-client.d.ts.map +1 -0
- package/dist/storage-client.js +469 -0
- package/dist/storage-client.js.map +1 -0
- package/dist/storage.d.ts +21 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +82 -0
- package/dist/storage.js.map +1 -0
- package/dist/subject-domains.d.ts +15 -0
- package/dist/subject-domains.d.ts.map +1 -0
- package/dist/subject-domains.js +38 -0
- package/dist/subject-domains.js.map +1 -0
- package/dist/support.d.ts +132 -0
- package/dist/support.d.ts.map +1 -0
- package/dist/support.js +483 -0
- package/dist/support.js.map +1 -0
- package/dist/system-tables.d.ts +12 -0
- package/dist/system-tables.d.ts.map +1 -0
- package/dist/system-tables.js +225 -0
- package/dist/system-tables.js.map +1 -0
- package/dist/test.d.ts +57 -0
- package/dist/test.d.ts.map +1 -0
- package/dist/test.js +454 -0
- package/dist/test.js.map +1 -0
- package/dist/vite.d.ts +82 -0
- package/dist/vite.d.ts.map +1 -0
- package/dist/vite.js +82 -0
- package/dist/vite.js.map +1 -0
- package/dist/webpush-crypto.d.ts +39 -0
- package/dist/webpush-crypto.d.ts.map +1 -0
- package/dist/webpush-crypto.js +213 -0
- package/dist/webpush-crypto.js.map +1 -0
- package/dist/webpush-private.d.ts +11 -0
- package/dist/webpush-private.d.ts.map +1 -0
- package/dist/webpush-private.js +11 -0
- package/dist/webpush-private.js.map +1 -0
- package/dist/webpush.d.ts +86 -0
- package/dist/webpush.d.ts.map +1 -0
- package/dist/webpush.js +375 -0
- package/dist/webpush.js.map +1 -0
- package/dist/worker.d.ts +185 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +13021 -0
- package/dist/worker.js.map +1 -0
- package/package.json +161 -8
- package/README.md +0 -3
|
@@ -0,0 +1,703 @@
|
|
|
1
|
+
import { stableJson } from "./internal.js";
|
|
2
|
+
import { id, integer, longText, raybaseSystemTable, text } from "./schema.js";
|
|
3
|
+
import { nowIso, q, randomId } from "./sql.js";
|
|
4
|
+
export const followUpStaleRunningMs = 10 * 60_000;
|
|
5
|
+
export const followUpMaxDispatchAttempts = 5;
|
|
6
|
+
export const followUpDispatchRecencyMs = 24 * 60 * 60_000;
|
|
7
|
+
export const followUpDispatchClaimLeaseMs = 60_000;
|
|
8
|
+
export const raybaseAgentFollowUpSystemTables = [
|
|
9
|
+
raybaseSystemTable("_agent_follow_ups", {
|
|
10
|
+
id: id(),
|
|
11
|
+
agentName: text({ required: true }),
|
|
12
|
+
key: text({ required: true }),
|
|
13
|
+
ownerKey: text(),
|
|
14
|
+
body: longText({ required: true }),
|
|
15
|
+
contextJson: longText(),
|
|
16
|
+
conversationJson: longText(),
|
|
17
|
+
dueAt: text({ required: true }),
|
|
18
|
+
idleAfterMs: integer(),
|
|
19
|
+
notLaterThan: text(),
|
|
20
|
+
wakeOnEvent: text(),
|
|
21
|
+
wakeOnMatchJson: longText(),
|
|
22
|
+
wokeBy: text(),
|
|
23
|
+
wokeEvent: text(),
|
|
24
|
+
wokeEventId: text(),
|
|
25
|
+
wokePayloadJson: longText(),
|
|
26
|
+
wokeAt: text(),
|
|
27
|
+
onDue: text({ required: true }),
|
|
28
|
+
fallbackEveryMs: integer(),
|
|
29
|
+
maxRuns: integer(),
|
|
30
|
+
status: text({ required: true }),
|
|
31
|
+
reason: longText(),
|
|
32
|
+
dispatchGeneration: integer({ required: true }),
|
|
33
|
+
dispatchAttempts: integer({ required: true }),
|
|
34
|
+
dispatchStartedAt: text(),
|
|
35
|
+
dispatchClaimToken: text(),
|
|
36
|
+
claimAcquiredAt: text(),
|
|
37
|
+
lastRunGeneration: integer(),
|
|
38
|
+
continuedGeneration: integer(),
|
|
39
|
+
runCount: integer({ required: true }),
|
|
40
|
+
lastRunAt: text(),
|
|
41
|
+
continuedAt: text(),
|
|
42
|
+
driftCount: integer({ required: true }),
|
|
43
|
+
lastDriftAt: text(),
|
|
44
|
+
settledAt: text(),
|
|
45
|
+
lapseHandledAt: text(),
|
|
46
|
+
lapseAttempts: integer({ required: true }),
|
|
47
|
+
createdBy: text({ required: true }),
|
|
48
|
+
requestedByConversationId: text(),
|
|
49
|
+
requestedByRunId: text(),
|
|
50
|
+
triggerEventId: text(),
|
|
51
|
+
createdAt: text({ required: true }),
|
|
52
|
+
updatedAt: text({ required: true })
|
|
53
|
+
}, {
|
|
54
|
+
label: "Agent follow-ups",
|
|
55
|
+
indexes: [
|
|
56
|
+
{ columns: ["agentName", "key"], unique: true, where: "\"status\" = 'pending'" },
|
|
57
|
+
["status", "dueAt"],
|
|
58
|
+
["agentName", "status", "dueAt"],
|
|
59
|
+
["agentName", "ownerKey"],
|
|
60
|
+
["agentName", "createdAt"],
|
|
61
|
+
["agentName", "status", "wakeOnEvent"]
|
|
62
|
+
]
|
|
63
|
+
})
|
|
64
|
+
];
|
|
65
|
+
/** Reads one of this table's JSON columns without letting bad JSON break a dispatch. */
|
|
66
|
+
export function parsedFollowUpJson(value) {
|
|
67
|
+
if (!value)
|
|
68
|
+
return null;
|
|
69
|
+
try {
|
|
70
|
+
return JSON.parse(value);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export async function getAgentFollowUp(control, id) {
|
|
77
|
+
return (await control.first(`SELECT * FROM ${q("_agent_follow_ups")} WHERE "id" = ? LIMIT 1`, [id])) ?? null;
|
|
78
|
+
}
|
|
79
|
+
export async function listDueAgentFollowUps(control, input = {}) {
|
|
80
|
+
return control.all(`SELECT * FROM ${q("_agent_follow_ups")} WHERE "status" = 'pending' AND "dueAt" <= ? ORDER BY "dueAt" ASC LIMIT ?`, [input.now ?? nowIso(), Math.max(1, Math.min(500, input.limit ?? 100))]);
|
|
81
|
+
}
|
|
82
|
+
export async function listUnhandledLapsedAgentFollowUps(control, input = {}) {
|
|
83
|
+
return control.all(`SELECT * FROM ${q("_agent_follow_ups")}
|
|
84
|
+
WHERE "status" = 'lapsed' AND "lapseHandledAt" IS NULL AND "lapseAttempts" < 10
|
|
85
|
+
ORDER BY "updatedAt" ASC LIMIT ?`, [Math.max(1, Math.min(500, input.limit ?? 100))]);
|
|
86
|
+
}
|
|
87
|
+
export async function agentFollowUpAlarmWork(control) {
|
|
88
|
+
const pending = await control.first(`SELECT MIN("dueAt") AS "nextDueAt" FROM ${q("_agent_follow_ups")} WHERE "status" = 'pending'`);
|
|
89
|
+
const lapsed = await control.first(`SELECT 1 AS "present" FROM ${q("_agent_follow_ups")}
|
|
90
|
+
WHERE "status" = 'lapsed' AND "lapseHandledAt" IS NULL AND "lapseAttempts" < 10
|
|
91
|
+
LIMIT 1`);
|
|
92
|
+
const outstanding = await control.first(`SELECT 1 AS "present"
|
|
93
|
+
FROM ${q("_agent_follow_ups")} f
|
|
94
|
+
JOIN ${q("_agent_trigger_events")} e ON e."id" = f."triggerEventId"
|
|
95
|
+
WHERE e."triggerType" = 'follow-up'
|
|
96
|
+
AND e."status" IN ('queued','failed','running')
|
|
97
|
+
AND f."status" IN ('pending','fired')
|
|
98
|
+
LIMIT 1`);
|
|
99
|
+
return {
|
|
100
|
+
nextDueAt: pending?.nextDueAt ?? null,
|
|
101
|
+
hasUnhandledLapse: Boolean(lapsed?.present),
|
|
102
|
+
hasOutstandingDispatch: Boolean(outstanding?.present)
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
export async function settleDueLapse(control, input) {
|
|
106
|
+
const now = input.now ?? nowIso();
|
|
107
|
+
const wallNow = input.wallNow ?? now;
|
|
108
|
+
const claimToken = randomId("follow_up_lapse");
|
|
109
|
+
await control.run(`UPDATE ${q("_agent_follow_ups")}
|
|
110
|
+
SET "status" = 'lapsed', "settledAt" = ?, "dispatchClaimToken" = ?, "claimAcquiredAt" = ?, "updatedAt" = ?
|
|
111
|
+
WHERE "id" = ? AND "status" = 'pending' AND "dueAt" <= ?`, [now, claimToken, wallNow, now, input.id, now]);
|
|
112
|
+
const row = await getAgentFollowUp(control, input.id);
|
|
113
|
+
return row?.status === "lapsed" && row.dispatchClaimToken === claimToken ? row : null;
|
|
114
|
+
}
|
|
115
|
+
export async function claimRunOnceAgentFollowUp(control, input) {
|
|
116
|
+
const now = input.now ?? nowIso();
|
|
117
|
+
const wallNow = input.wallNow ?? now;
|
|
118
|
+
const claimToken = randomId("follow_up_generation");
|
|
119
|
+
await control.run(`UPDATE ${q("_agent_follow_ups")}
|
|
120
|
+
SET "status" = 'fired', "settledAt" = ?, "dispatchGeneration" = 1,
|
|
121
|
+
"dispatchAttempts" = 0, "dispatchStartedAt" = ?, "dispatchClaimToken" = ?, "claimAcquiredAt" = ?,
|
|
122
|
+
"triggerEventId" = ?, "updatedAt" = ?
|
|
123
|
+
WHERE "id" = ? AND "status" = 'pending' AND "onDue" = 'run' AND "fallbackEveryMs" IS NULL AND "dueAt" <= ?`, [now, wallNow, claimToken, wallNow, input.eventId, now, input.id, now]);
|
|
124
|
+
const row = await getAgentFollowUp(control, input.id);
|
|
125
|
+
return row?.status === "fired"
|
|
126
|
+
&& row.triggerEventId === input.eventId
|
|
127
|
+
&& row.dispatchClaimToken === claimToken
|
|
128
|
+
? row
|
|
129
|
+
: null;
|
|
130
|
+
}
|
|
131
|
+
export async function claimContinuingAgentFollowUp(control, input) {
|
|
132
|
+
const now = input.now ?? nowIso();
|
|
133
|
+
const wallNow = input.wallNow ?? now;
|
|
134
|
+
const claimToken = randomId("follow_up_generation");
|
|
135
|
+
await control.run(
|
|
136
|
+
// A continuing chain starts a fresh wait with each generation, so the
|
|
137
|
+
// wake marks of the generation being dispatched are cleared here — the
|
|
138
|
+
// trigger envelope was already built from the row that carried them.
|
|
139
|
+
`UPDATE ${q("_agent_follow_ups")}
|
|
140
|
+
SET "dispatchGeneration" = ?, "dispatchAttempts" = 0, "dispatchStartedAt" = ?,
|
|
141
|
+
"dispatchClaimToken" = ?, "claimAcquiredAt" = ?, "triggerEventId" = ?, "dueAt" = ?, "updatedAt" = ?,
|
|
142
|
+
"wokeBy" = NULL, "wokeEvent" = NULL, "wokeEventId" = NULL, "wokePayloadJson" = NULL, "wokeAt" = NULL
|
|
143
|
+
WHERE "id" = ? AND "status" = 'pending' AND "fallbackEveryMs" IS NOT NULL
|
|
144
|
+
AND "dispatchGeneration" = ? AND "dueAt" <= ?`, [input.generation, wallNow, claimToken, wallNow, input.eventId, input.dueAt, now, input.id, input.expectedGeneration, now]);
|
|
145
|
+
const row = await getAgentFollowUp(control, input.id);
|
|
146
|
+
return row?.status === "pending"
|
|
147
|
+
&& row.dispatchGeneration === input.generation
|
|
148
|
+
&& row.triggerEventId === input.eventId
|
|
149
|
+
&& row.dispatchClaimToken === claimToken
|
|
150
|
+
? row
|
|
151
|
+
: null;
|
|
152
|
+
}
|
|
153
|
+
export async function claimAgentFollowUpDispatchAttempt(control, input) {
|
|
154
|
+
const now = input.now ?? nowIso();
|
|
155
|
+
const wallNow = input.wallNow ?? now;
|
|
156
|
+
const maxAttempts = Math.max(1, input.maxAttempts ?? followUpMaxDispatchAttempts);
|
|
157
|
+
const notBefore = new Date(Date.parse(wallNow) - (input.recencyMs ?? followUpDispatchRecencyMs)).toISOString();
|
|
158
|
+
const before = await getAgentFollowUp(control, input.id);
|
|
159
|
+
if (!before || before.triggerEventId !== input.eventId)
|
|
160
|
+
return null;
|
|
161
|
+
if (before.dispatchClaimToken?.startsWith("follow_up_dispatch_")
|
|
162
|
+
&& Date.parse(before.claimAcquiredAt ?? "") > Date.parse(wallNow) - followUpDispatchClaimLeaseMs) {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
const claimToken = randomId("follow_up_dispatch");
|
|
166
|
+
await control.run(`UPDATE ${q("_agent_follow_ups")}
|
|
167
|
+
SET "dispatchAttempts" = "dispatchAttempts" + 1, "dispatchClaimToken" = ?, "claimAcquiredAt" = ?, "updatedAt" = ?
|
|
168
|
+
WHERE "id" = ? AND "triggerEventId" = ? AND "status" IN ('pending','fired')
|
|
169
|
+
AND "dispatchAttempts" = ? AND "updatedAt" = ?
|
|
170
|
+
AND (("dispatchClaimToken" IS NULL AND ? IS NULL) OR "dispatchClaimToken" = ?)
|
|
171
|
+
AND "dispatchAttempts" < ? AND "dispatchStartedAt" >= ?`, [
|
|
172
|
+
claimToken,
|
|
173
|
+
wallNow,
|
|
174
|
+
now,
|
|
175
|
+
input.id,
|
|
176
|
+
input.eventId,
|
|
177
|
+
before.dispatchAttempts,
|
|
178
|
+
before.updatedAt,
|
|
179
|
+
before.dispatchClaimToken,
|
|
180
|
+
before.dispatchClaimToken,
|
|
181
|
+
maxAttempts,
|
|
182
|
+
notBefore
|
|
183
|
+
]);
|
|
184
|
+
const row = await getAgentFollowUp(control, input.id);
|
|
185
|
+
return row?.triggerEventId === input.eventId && row.dispatchClaimToken === claimToken ? row : null;
|
|
186
|
+
}
|
|
187
|
+
export async function abandonAgentFollowUpDispatch(control, input) {
|
|
188
|
+
const now = input.now ?? nowIso();
|
|
189
|
+
const wallNow = input.wallNow ?? now;
|
|
190
|
+
const reason = input.reason ?? "dispatch-attempts-exhausted";
|
|
191
|
+
const claimToken = randomId("follow_up_abandon");
|
|
192
|
+
await control.run(`UPDATE ${q("_agent_follow_ups")}
|
|
193
|
+
SET "status" = 'closed', "reason" = ?, "settledAt" = ?, "dispatchClaimToken" = ?, "claimAcquiredAt" = ?, "updatedAt" = ?
|
|
194
|
+
WHERE "id" = ? AND "triggerEventId" = ? AND "status" IN ('pending','fired')`, [reason, now, claimToken, wallNow, now, input.id, input.eventId]);
|
|
195
|
+
const row = await getAgentFollowUp(control, input.id);
|
|
196
|
+
return row?.status === "closed"
|
|
197
|
+
&& row.triggerEventId === input.eventId
|
|
198
|
+
&& row.dispatchClaimToken === claimToken
|
|
199
|
+
? row
|
|
200
|
+
: null;
|
|
201
|
+
}
|
|
202
|
+
export async function parkContinuingAgentFollowUp(control, input) {
|
|
203
|
+
const now = input.now ?? nowIso();
|
|
204
|
+
await control.run(`UPDATE ${q("_agent_follow_ups")} SET "dueAt" = ?, "updatedAt" = ?
|
|
205
|
+
WHERE "id" = ? AND "status" = 'pending' AND "dispatchGeneration" = ?`, [input.dueAt, now, input.id, input.generation]);
|
|
206
|
+
const row = await getAgentFollowUp(control, input.id);
|
|
207
|
+
return row?.status === "pending" && row.dispatchGeneration === input.generation && row.dueAt === input.dueAt;
|
|
208
|
+
}
|
|
209
|
+
export async function getAgentFollowUpTriggerEvent(control, eventId) {
|
|
210
|
+
return control.first(`SELECT * FROM ${q("_agent_trigger_events")} WHERE "id" = ? AND "triggerType" = 'follow-up' LIMIT 1`, [eventId]);
|
|
211
|
+
}
|
|
212
|
+
export async function findAgentFollowUpTriggerEvent(control, idempotencyKey) {
|
|
213
|
+
return control.first(`SELECT * FROM ${q("_agent_trigger_events")}
|
|
214
|
+
WHERE "idempotencyKey" = ? AND "triggerType" = 'follow-up' LIMIT 1`, [idempotencyKey]);
|
|
215
|
+
}
|
|
216
|
+
async function findOrCreateAgentFollowUpTriggerEvent(control, input) {
|
|
217
|
+
const idempotencyKey = `follow_up:${input.row.id}:${input.generation}`;
|
|
218
|
+
const existing = await findAgentFollowUpTriggerEvent(control, idempotencyKey);
|
|
219
|
+
if (existing)
|
|
220
|
+
return existing;
|
|
221
|
+
const event = {
|
|
222
|
+
id: randomId("agent_evt"),
|
|
223
|
+
agentName: input.row.agentName,
|
|
224
|
+
triggerType: "follow-up",
|
|
225
|
+
triggerKey: `follow-up:${input.row.agentName}:${input.row.key}`,
|
|
226
|
+
sourceTable: null,
|
|
227
|
+
sourceOp: null,
|
|
228
|
+
rowId: null,
|
|
229
|
+
inputJson: stableJson({
|
|
230
|
+
trigger: {
|
|
231
|
+
type: "follow-up",
|
|
232
|
+
key: input.row.key,
|
|
233
|
+
ownerKey: input.row.ownerKey,
|
|
234
|
+
body: input.row.body,
|
|
235
|
+
context: input.row.contextJson ? JSON.parse(input.row.contextJson) : null,
|
|
236
|
+
conversation: input.row.conversationJson ? JSON.parse(input.row.conversationJson) : { mode: "new" },
|
|
237
|
+
mode: input.row.fallbackEveryMs === null ? "once" : "continuing",
|
|
238
|
+
runCount: input.row.runCount,
|
|
239
|
+
generation: input.generation,
|
|
240
|
+
maxRuns: input.row.maxRuns,
|
|
241
|
+
fallbackEveryMs: input.row.fallbackEveryMs,
|
|
242
|
+
createdBy: input.row.createdBy,
|
|
243
|
+
createdAt: input.row.createdAt,
|
|
244
|
+
drifted: input.row.driftCount > 0,
|
|
245
|
+
wakeOn: input.row.wakeOnEvent
|
|
246
|
+
? { event: input.row.wakeOnEvent, match: parsedFollowUpJson(input.row.wakeOnMatchJson) }
|
|
247
|
+
: null,
|
|
248
|
+
wokeBy: input.row.wokeBy === "event" ? "event" : "deadline",
|
|
249
|
+
wokeEvent: input.row.wokeEvent,
|
|
250
|
+
wokeEventId: input.row.wokeEventId,
|
|
251
|
+
wokePayload: parsedFollowUpJson(input.row.wokePayloadJson),
|
|
252
|
+
wokeAt: input.row.wokeAt
|
|
253
|
+
},
|
|
254
|
+
followUpId: input.row.id,
|
|
255
|
+
scheduledAt: input.now
|
|
256
|
+
}),
|
|
257
|
+
idempotencyKey,
|
|
258
|
+
status: "queued",
|
|
259
|
+
runId: null,
|
|
260
|
+
error: null,
|
|
261
|
+
createdAt: input.wallNow,
|
|
262
|
+
updatedAt: input.wallNow
|
|
263
|
+
};
|
|
264
|
+
await control.run(`INSERT OR IGNORE INTO ${q("_agent_trigger_events")}
|
|
265
|
+
("id", "agentName", "triggerType", "triggerKey", "sourceTable", "sourceOp", "rowId", "inputJson",
|
|
266
|
+
"idempotencyKey", "status", "runId", "error", "createdAt", "updatedAt")
|
|
267
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
268
|
+
event.id,
|
|
269
|
+
event.agentName,
|
|
270
|
+
event.triggerType,
|
|
271
|
+
event.triggerKey,
|
|
272
|
+
event.sourceTable,
|
|
273
|
+
event.sourceOp,
|
|
274
|
+
event.rowId,
|
|
275
|
+
event.inputJson,
|
|
276
|
+
event.idempotencyKey,
|
|
277
|
+
event.status,
|
|
278
|
+
event.runId,
|
|
279
|
+
event.error,
|
|
280
|
+
event.createdAt,
|
|
281
|
+
event.updatedAt
|
|
282
|
+
]);
|
|
283
|
+
const stored = await findAgentFollowUpTriggerEvent(control, idempotencyKey);
|
|
284
|
+
if (!stored)
|
|
285
|
+
throw new Error(`Failed to create Agent follow-up trigger event ${idempotencyKey}`);
|
|
286
|
+
return stored;
|
|
287
|
+
}
|
|
288
|
+
async function markAgentFollowUpTriggerEvent(control, eventId, input) {
|
|
289
|
+
await control.run(`UPDATE ${q("_agent_trigger_events")}
|
|
290
|
+
SET "status" = ?, "error" = ?, "updatedAt" = ?
|
|
291
|
+
WHERE "id" = ? AND "triggerType" = 'follow-up'`, [input.status, input.error ?? null, input.wallNow, eventId]);
|
|
292
|
+
return getAgentFollowUpTriggerEvent(control, eventId);
|
|
293
|
+
}
|
|
294
|
+
export async function releaseAgentFollowUpClaim(control, rowId, claimToken) {
|
|
295
|
+
await control.run(`UPDATE ${q("_agent_follow_ups")} SET "dispatchClaimToken" = NULL, "claimAcquiredAt" = NULL
|
|
296
|
+
WHERE "id" = ? AND "dispatchClaimToken" = ?`, [rowId, claimToken]);
|
|
297
|
+
}
|
|
298
|
+
export async function claimDueAgentFollowUps(control, input = {}) {
|
|
299
|
+
const now = input.now ?? nowIso();
|
|
300
|
+
const wallNow = input.wallNow ?? now;
|
|
301
|
+
const outcomes = [];
|
|
302
|
+
for (const candidate of await listDueAgentFollowUps(control, { now, limit: input.limit })) {
|
|
303
|
+
if (candidate.onDue === "lapse") {
|
|
304
|
+
const row = await settleDueLapse(control, { id: candidate.id, now, wallNow });
|
|
305
|
+
if (row)
|
|
306
|
+
outcomes.push({ type: "lapsed", row });
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
if (candidate.fallbackEveryMs !== null && candidate.triggerEventId) {
|
|
310
|
+
const currentEvent = await getAgentFollowUpTriggerEvent(control, candidate.triggerEventId);
|
|
311
|
+
if (currentEvent && currentEvent.status !== "completed" && currentEvent.status !== "skipped") {
|
|
312
|
+
const runningFresh = currentEvent.status === "running"
|
|
313
|
+
&& Date.parse(currentEvent.updatedAt) > Date.parse(wallNow) - followUpStaleRunningMs;
|
|
314
|
+
const attemptedRecently = Date.parse(currentEvent.updatedAt) > Date.parse(wallNow) - followUpDispatchClaimLeaseMs;
|
|
315
|
+
if (!runningFresh
|
|
316
|
+
&& !attemptedRecently
|
|
317
|
+
&& candidate.dispatchClaimToken?.startsWith("follow_up_dispatch_")) {
|
|
318
|
+
await releaseAgentFollowUpClaim(control, candidate.id, candidate.dispatchClaimToken);
|
|
319
|
+
}
|
|
320
|
+
const dueAt = new Date(Date.parse(now) + candidate.fallbackEveryMs).toISOString();
|
|
321
|
+
const parked = await parkContinuingAgentFollowUp(control, {
|
|
322
|
+
id: candidate.id,
|
|
323
|
+
generation: candidate.dispatchGeneration,
|
|
324
|
+
dueAt,
|
|
325
|
+
now
|
|
326
|
+
});
|
|
327
|
+
if (!parked)
|
|
328
|
+
continue;
|
|
329
|
+
if (!runningFresh && !attemptedRecently) {
|
|
330
|
+
const row = await getAgentFollowUp(control, candidate.id);
|
|
331
|
+
if (row) {
|
|
332
|
+
outcomes.push({
|
|
333
|
+
type: "dispatch",
|
|
334
|
+
source: "outstanding",
|
|
335
|
+
row,
|
|
336
|
+
event: currentEvent,
|
|
337
|
+
generation: candidate.dispatchGeneration
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
if (candidate.fallbackEveryMs !== null && candidate.maxRuns !== null && candidate.runCount >= candidate.maxRuns) {
|
|
345
|
+
const row = await closeAgentFollowUpForMaxRuns(control, { id: candidate.id, now, wallNow });
|
|
346
|
+
if (row)
|
|
347
|
+
outcomes.push({ type: "closed", reason: "max-runs", row, event: null });
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
const generation = candidate.fallbackEveryMs === null ? 1 : candidate.dispatchGeneration + 1;
|
|
351
|
+
const event = await findOrCreateAgentFollowUpTriggerEvent(control, { row: candidate, generation, now, wallNow });
|
|
352
|
+
const row = candidate.fallbackEveryMs === null
|
|
353
|
+
? await claimRunOnceAgentFollowUp(control, { id: candidate.id, eventId: event.id, now, wallNow })
|
|
354
|
+
: await claimContinuingAgentFollowUp(control, {
|
|
355
|
+
id: candidate.id,
|
|
356
|
+
expectedGeneration: candidate.dispatchGeneration,
|
|
357
|
+
generation,
|
|
358
|
+
eventId: event.id,
|
|
359
|
+
dueAt: new Date(Date.parse(now) + candidate.fallbackEveryMs).toISOString(),
|
|
360
|
+
now,
|
|
361
|
+
wallNow
|
|
362
|
+
});
|
|
363
|
+
if (row)
|
|
364
|
+
outcomes.push({ type: "dispatch", source: "new", row, event, generation });
|
|
365
|
+
}
|
|
366
|
+
return outcomes;
|
|
367
|
+
}
|
|
368
|
+
export async function listOutstandingAgentFollowUpDispatches(control, input) {
|
|
369
|
+
const rows = await control.all(`SELECT f.*,
|
|
370
|
+
e."id" AS "eventId", e."agentName" AS "eventAgentName", e."triggerKey" AS "eventTriggerKey",
|
|
371
|
+
e."inputJson" AS "eventInputJson", e."idempotencyKey" AS "eventIdempotencyKey",
|
|
372
|
+
e."status" AS "eventStatus", e."runId" AS "eventRunId", e."error" AS "eventError",
|
|
373
|
+
e."createdAt" AS "eventCreatedAt", e."updatedAt" AS "eventUpdatedAt"
|
|
374
|
+
FROM ${q("_agent_follow_ups")} f
|
|
375
|
+
JOIN ${q("_agent_trigger_events")} e ON e."id" = f."triggerEventId"
|
|
376
|
+
WHERE e."triggerType" = 'follow-up'
|
|
377
|
+
AND e."idempotencyKey" LIKE 'follow_up:%'
|
|
378
|
+
AND e."status" IN ('queued','failed','running')
|
|
379
|
+
AND f."status" IN ('pending','fired')
|
|
380
|
+
ORDER BY e."updatedAt" ASC
|
|
381
|
+
LIMIT ?`, [Math.max(1, Math.min(500, input.limit ?? 100))]);
|
|
382
|
+
return rows.map((joined) => {
|
|
383
|
+
const { eventId, eventAgentName, eventTriggerKey, eventInputJson, eventIdempotencyKey, eventStatus, eventRunId, eventError, eventCreatedAt, eventUpdatedAt, ...row } = joined;
|
|
384
|
+
return {
|
|
385
|
+
row,
|
|
386
|
+
event: {
|
|
387
|
+
id: eventId,
|
|
388
|
+
agentName: eventAgentName,
|
|
389
|
+
triggerType: "follow-up",
|
|
390
|
+
triggerKey: eventTriggerKey,
|
|
391
|
+
sourceTable: null,
|
|
392
|
+
sourceOp: null,
|
|
393
|
+
rowId: null,
|
|
394
|
+
inputJson: eventInputJson,
|
|
395
|
+
idempotencyKey: eventIdempotencyKey,
|
|
396
|
+
status: eventStatus,
|
|
397
|
+
runId: eventRunId,
|
|
398
|
+
error: eventError,
|
|
399
|
+
createdAt: eventCreatedAt,
|
|
400
|
+
updatedAt: eventUpdatedAt
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
function agentFollowUpDispatchOrigin(event) {
|
|
406
|
+
if (!event.inputJson)
|
|
407
|
+
return null;
|
|
408
|
+
try {
|
|
409
|
+
const envelope = JSON.parse(event.inputJson);
|
|
410
|
+
if (!envelope || typeof envelope !== "object" || Array.isArray(envelope))
|
|
411
|
+
return null;
|
|
412
|
+
const origin = envelope.dispatchOrigin;
|
|
413
|
+
if (!origin || typeof origin !== "object" || Array.isArray(origin))
|
|
414
|
+
return null;
|
|
415
|
+
const claimedBy = origin.claimedBy;
|
|
416
|
+
const claimedAt = origin.claimedAt;
|
|
417
|
+
if ((claimedBy !== "sweep" && claimedBy !== "alarm") || typeof claimedAt !== "string")
|
|
418
|
+
return null;
|
|
419
|
+
return { claimedBy, claimedAt };
|
|
420
|
+
}
|
|
421
|
+
catch {
|
|
422
|
+
return null;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
async function preserveAgentFollowUpDispatchOrigin(control, event, claimedBy) {
|
|
426
|
+
const existing = agentFollowUpDispatchOrigin(event);
|
|
427
|
+
if (existing || !claimedBy || !event.inputJson)
|
|
428
|
+
return { event, origin: existing };
|
|
429
|
+
let envelope;
|
|
430
|
+
try {
|
|
431
|
+
const parsed = JSON.parse(event.inputJson);
|
|
432
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
433
|
+
return { event, origin: null };
|
|
434
|
+
envelope = parsed;
|
|
435
|
+
}
|
|
436
|
+
catch {
|
|
437
|
+
return { event, origin: null };
|
|
438
|
+
}
|
|
439
|
+
const claimedAt = event.createdAt;
|
|
440
|
+
const inputJson = stableJson({
|
|
441
|
+
...envelope,
|
|
442
|
+
dispatchOrigin: { claimedBy, claimedAt }
|
|
443
|
+
});
|
|
444
|
+
await control.run(`UPDATE ${q("_agent_trigger_events")}
|
|
445
|
+
SET "inputJson" = ?
|
|
446
|
+
WHERE "id" = ? AND "triggerType" = 'follow-up' AND "inputJson" = ?`, [inputJson, event.id, event.inputJson]);
|
|
447
|
+
const stored = (await getAgentFollowUpTriggerEvent(control, event.id)) ?? event;
|
|
448
|
+
return {
|
|
449
|
+
event: stored,
|
|
450
|
+
origin: agentFollowUpDispatchOrigin(stored)
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
async function dispatchAgentFollowUpRun(input) {
|
|
454
|
+
const claimed = await claimAgentFollowUpDispatchAttempt(input.control, {
|
|
455
|
+
id: input.claim.row.id,
|
|
456
|
+
eventId: input.claim.event.id,
|
|
457
|
+
now: input.now,
|
|
458
|
+
wallNow: input.wallNow
|
|
459
|
+
});
|
|
460
|
+
if (!claimed) {
|
|
461
|
+
const current = await getAgentFollowUp(input.control, input.claim.row.id);
|
|
462
|
+
const dispatchExpired = current
|
|
463
|
+
&& current.triggerEventId === input.claim.event.id
|
|
464
|
+
&& (current.dispatchAttempts >= followUpMaxDispatchAttempts
|
|
465
|
+
|| Date.parse(current.dispatchStartedAt ?? "") < Date.parse(input.wallNow) - followUpDispatchRecencyMs);
|
|
466
|
+
if (!dispatchExpired)
|
|
467
|
+
return null;
|
|
468
|
+
const row = await abandonAgentFollowUpDispatch(input.control, {
|
|
469
|
+
id: input.claim.row.id,
|
|
470
|
+
eventId: input.claim.event.id,
|
|
471
|
+
now: input.now,
|
|
472
|
+
wallNow: input.wallNow
|
|
473
|
+
});
|
|
474
|
+
if (!row)
|
|
475
|
+
return null;
|
|
476
|
+
const event = await markAgentFollowUpTriggerEvent(input.control, input.claim.event.id, {
|
|
477
|
+
status: "skipped",
|
|
478
|
+
error: "Follow-up dispatch retry budget or recency window was exhausted",
|
|
479
|
+
wallNow: input.wallNow
|
|
480
|
+
});
|
|
481
|
+
return {
|
|
482
|
+
type: "closed",
|
|
483
|
+
reason: "dispatch-attempts-exhausted",
|
|
484
|
+
row,
|
|
485
|
+
event
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
const claimToken = claimed.dispatchClaimToken;
|
|
489
|
+
let persisted;
|
|
490
|
+
try {
|
|
491
|
+
persisted = await preserveAgentFollowUpDispatchOrigin(input.control, input.claim.event, input.claimedBy);
|
|
492
|
+
}
|
|
493
|
+
catch (error) {
|
|
494
|
+
await releaseAgentFollowUpClaim(input.control, claimed.id, claimToken);
|
|
495
|
+
throw error;
|
|
496
|
+
}
|
|
497
|
+
const dispatchOrigin = persisted.origin;
|
|
498
|
+
let delivery;
|
|
499
|
+
let event;
|
|
500
|
+
let retainSuccessfulClaim = false;
|
|
501
|
+
try {
|
|
502
|
+
await input.send({
|
|
503
|
+
kind: "raybase.agent.run",
|
|
504
|
+
version: 1,
|
|
505
|
+
eventId: persisted.event.id,
|
|
506
|
+
agentName: claimed.agentName,
|
|
507
|
+
triggerType: "follow-up",
|
|
508
|
+
...(input.organizationId ? { organizationId: input.organizationId } : {}),
|
|
509
|
+
...(dispatchOrigin ? {
|
|
510
|
+
claimedBy: dispatchOrigin.claimedBy,
|
|
511
|
+
claimedAt: dispatchOrigin.claimedAt
|
|
512
|
+
} : {})
|
|
513
|
+
});
|
|
514
|
+
event = await markAgentFollowUpTriggerEvent(input.control, persisted.event.id, {
|
|
515
|
+
status: "queued",
|
|
516
|
+
wallNow: input.wallNow
|
|
517
|
+
});
|
|
518
|
+
retainSuccessfulClaim = true;
|
|
519
|
+
delivery = { ok: true };
|
|
520
|
+
}
|
|
521
|
+
catch (error) {
|
|
522
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
523
|
+
event = await markAgentFollowUpTriggerEvent(input.control, persisted.event.id, {
|
|
524
|
+
status: "failed",
|
|
525
|
+
error: message,
|
|
526
|
+
wallNow: input.wallNow
|
|
527
|
+
});
|
|
528
|
+
delivery = { ok: false, error: message };
|
|
529
|
+
}
|
|
530
|
+
finally {
|
|
531
|
+
if (!retainSuccessfulClaim) {
|
|
532
|
+
await releaseAgentFollowUpClaim(input.control, claimed.id, claimToken);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
return {
|
|
536
|
+
type: "dispatched",
|
|
537
|
+
source: input.claim.source,
|
|
538
|
+
row: (await getAgentFollowUp(input.control, claimed.id)) ?? claimed,
|
|
539
|
+
event: event ?? persisted.event,
|
|
540
|
+
generation: input.claim.generation,
|
|
541
|
+
delivery
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
export async function dispatchDueAgentFollowUps(input) {
|
|
545
|
+
const now = input.now ?? nowIso();
|
|
546
|
+
const wallNow = input.wallNow ?? now;
|
|
547
|
+
const limit = Math.max(1, Math.min(500, input.limit ?? 100));
|
|
548
|
+
const outcomes = [];
|
|
549
|
+
const attemptedEventIds = new Set();
|
|
550
|
+
const claims = await claimDueAgentFollowUps(input.control, { now, wallNow, limit });
|
|
551
|
+
for (const claim of claims) {
|
|
552
|
+
if (claim.type === "closed") {
|
|
553
|
+
outcomes.push(claim);
|
|
554
|
+
continue;
|
|
555
|
+
}
|
|
556
|
+
if (claim.type === "lapsed") {
|
|
557
|
+
try {
|
|
558
|
+
await input.send({
|
|
559
|
+
kind: "raybase.agent.follow_up.lapse",
|
|
560
|
+
version: 1,
|
|
561
|
+
followUpId: claim.row.id,
|
|
562
|
+
agentName: claim.row.agentName,
|
|
563
|
+
...(input.organizationId ? { organizationId: input.organizationId } : {}),
|
|
564
|
+
...(input.claimedBy ? { claimedBy: input.claimedBy, lapsedAt: claim.row.settledAt ?? claim.row.updatedAt } : {})
|
|
565
|
+
});
|
|
566
|
+
outcomes.push({ ...claim, delivery: { ok: true } });
|
|
567
|
+
}
|
|
568
|
+
catch (error) {
|
|
569
|
+
outcomes.push({
|
|
570
|
+
...claim,
|
|
571
|
+
delivery: { ok: false, error: error instanceof Error ? error.message : String(error) }
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
continue;
|
|
575
|
+
}
|
|
576
|
+
attemptedEventIds.add(claim.event.id);
|
|
577
|
+
const outcome = await dispatchAgentFollowUpRun({
|
|
578
|
+
organizationId: input.organizationId,
|
|
579
|
+
control: input.control,
|
|
580
|
+
send: input.send,
|
|
581
|
+
now,
|
|
582
|
+
wallNow,
|
|
583
|
+
claimedBy: input.claimedBy,
|
|
584
|
+
claim
|
|
585
|
+
});
|
|
586
|
+
if (outcome)
|
|
587
|
+
outcomes.push(outcome);
|
|
588
|
+
}
|
|
589
|
+
for (const outstanding of await listOutstandingAgentFollowUpDispatches(input.control, { now, limit })) {
|
|
590
|
+
if (attemptedEventIds.has(outstanding.event.id))
|
|
591
|
+
continue;
|
|
592
|
+
const runningFresh = outstanding.event.status === "running"
|
|
593
|
+
&& Date.parse(outstanding.event.updatedAt) > Date.parse(wallNow) - followUpStaleRunningMs;
|
|
594
|
+
const attemptedRecently = Date.parse(outstanding.event.updatedAt) > Date.parse(wallNow) - followUpDispatchClaimLeaseMs;
|
|
595
|
+
if (runningFresh || attemptedRecently)
|
|
596
|
+
continue;
|
|
597
|
+
if (outstanding.row.dispatchClaimToken?.startsWith("follow_up_dispatch_")) {
|
|
598
|
+
await releaseAgentFollowUpClaim(input.control, outstanding.row.id, outstanding.row.dispatchClaimToken);
|
|
599
|
+
}
|
|
600
|
+
const outcome = await dispatchAgentFollowUpRun({
|
|
601
|
+
organizationId: input.organizationId,
|
|
602
|
+
control: input.control,
|
|
603
|
+
send: input.send,
|
|
604
|
+
now,
|
|
605
|
+
wallNow,
|
|
606
|
+
claimedBy: input.claimedBy,
|
|
607
|
+
claim: {
|
|
608
|
+
type: "dispatch",
|
|
609
|
+
source: "outstanding",
|
|
610
|
+
row: outstanding.row,
|
|
611
|
+
event: outstanding.event,
|
|
612
|
+
generation: outstanding.row.dispatchGeneration
|
|
613
|
+
}
|
|
614
|
+
});
|
|
615
|
+
if (outcome)
|
|
616
|
+
outcomes.push(outcome);
|
|
617
|
+
}
|
|
618
|
+
return outcomes;
|
|
619
|
+
}
|
|
620
|
+
export async function beginAgentFollowUpRun(control, input) {
|
|
621
|
+
const now = input.now ?? nowIso();
|
|
622
|
+
const wallNow = input.wallNow ?? now;
|
|
623
|
+
const claimToken = randomId("follow_up_run");
|
|
624
|
+
await control.run(`UPDATE ${q("_agent_follow_ups")}
|
|
625
|
+
SET "lastRunGeneration" = ?, "runCount" = "runCount" + 1, "lastRunAt" = ?,
|
|
626
|
+
"dispatchClaimToken" = ?, "claimAcquiredAt" = ?, "updatedAt" = ?
|
|
627
|
+
WHERE "id" = ? AND ("lastRunGeneration" IS NULL OR "lastRunGeneration" < ?)`, [input.generation, now, claimToken, wallNow, now, input.id, input.generation]);
|
|
628
|
+
let row = await getAgentFollowUp(control, input.id);
|
|
629
|
+
const began = row?.lastRunGeneration === input.generation && row.dispatchClaimToken === claimToken;
|
|
630
|
+
if (began) {
|
|
631
|
+
await releaseAgentFollowUpClaim(control, input.id, claimToken);
|
|
632
|
+
row = await getAgentFollowUp(control, input.id);
|
|
633
|
+
}
|
|
634
|
+
return { began, row };
|
|
635
|
+
}
|
|
636
|
+
export async function continueAgentFollowUpStore(control, input) {
|
|
637
|
+
const now = input.now ?? nowIso();
|
|
638
|
+
await control.run(`UPDATE ${q("_agent_follow_ups")}
|
|
639
|
+
SET "dueAt" = ?, "contextJson" = COALESCE(?, "contextJson"), "body" = COALESCE(?, "body"),
|
|
640
|
+
"continuedGeneration" = ?, "continuedAt" = ?, "updatedAt" = ?
|
|
641
|
+
WHERE "id" = ? AND "status" = 'pending' AND "dispatchGeneration" = ?`, [input.dueAt, input.contextJson ?? null, input.body ?? null, input.generation, now, now, input.id, input.generation]);
|
|
642
|
+
const row = await getAgentFollowUp(control, input.id);
|
|
643
|
+
return row?.continuedGeneration === input.generation && row.continuedAt === now ? row : null;
|
|
644
|
+
}
|
|
645
|
+
export async function markAgentFollowUpDrifted(control, input) {
|
|
646
|
+
const now = input.now ?? nowIso();
|
|
647
|
+
await control.run(`UPDATE ${q("_agent_follow_ups")}
|
|
648
|
+
SET "driftCount" = "driftCount" + 1, "lastDriftAt" = ?, "dueAt" = ?, "updatedAt" = ?
|
|
649
|
+
WHERE "id" = ? AND "status" = 'pending' AND "dispatchGeneration" = ?`, [now, input.dueAt, now, input.id, input.generation]);
|
|
650
|
+
const row = await getAgentFollowUp(control, input.id);
|
|
651
|
+
return row?.lastDriftAt === now && row.dispatchGeneration === input.generation ? row : null;
|
|
652
|
+
}
|
|
653
|
+
export async function closeAgentFollowUpForMaxRuns(control, input) {
|
|
654
|
+
const now = input.now ?? nowIso();
|
|
655
|
+
const wallNow = input.wallNow ?? now;
|
|
656
|
+
const claimToken = randomId("follow_up_max_runs");
|
|
657
|
+
await control.run(`UPDATE ${q("_agent_follow_ups")}
|
|
658
|
+
SET "status" = 'closed', "reason" = 'max-runs', "settledAt" = ?,
|
|
659
|
+
"dispatchClaimToken" = ?, "claimAcquiredAt" = ?, "updatedAt" = ?
|
|
660
|
+
WHERE "id" = ? AND "status" = 'pending'`, [now, claimToken, wallNow, now, input.id]);
|
|
661
|
+
const row = await getAgentFollowUp(control, input.id);
|
|
662
|
+
return row?.status === "closed"
|
|
663
|
+
&& row.reason === "max-runs"
|
|
664
|
+
&& row.dispatchClaimToken === claimToken
|
|
665
|
+
? row
|
|
666
|
+
: null;
|
|
667
|
+
}
|
|
668
|
+
export async function claimAgentFollowUpLapseAttempt(control, input) {
|
|
669
|
+
const now = input.now ?? nowIso();
|
|
670
|
+
const wallNow = input.wallNow ?? now;
|
|
671
|
+
const before = await getAgentFollowUp(control, input.id);
|
|
672
|
+
if (!before || before.status !== "lapsed" || before.lapseHandledAt || before.lapseAttempts >= 10)
|
|
673
|
+
return null;
|
|
674
|
+
if (before.dispatchClaimToken?.startsWith("follow_up_lapse_attempt_")
|
|
675
|
+
&& Date.parse(before.claimAcquiredAt ?? "") > Date.parse(wallNow) - followUpDispatchClaimLeaseMs) {
|
|
676
|
+
return null;
|
|
677
|
+
}
|
|
678
|
+
const claimToken = randomId("follow_up_lapse_attempt");
|
|
679
|
+
await control.run(`UPDATE ${q("_agent_follow_ups")}
|
|
680
|
+
SET "lapseAttempts" = "lapseAttempts" + 1, "dispatchClaimToken" = ?, "claimAcquiredAt" = ?, "updatedAt" = ?
|
|
681
|
+
WHERE "id" = ? AND "status" = 'lapsed' AND "lapseHandledAt" IS NULL
|
|
682
|
+
AND "lapseAttempts" = ? AND "updatedAt" = ?
|
|
683
|
+
AND (("dispatchClaimToken" IS NULL AND ? IS NULL) OR "dispatchClaimToken" = ?)
|
|
684
|
+
AND "lapseAttempts" < 10`, [
|
|
685
|
+
claimToken,
|
|
686
|
+
wallNow,
|
|
687
|
+
now,
|
|
688
|
+
input.id,
|
|
689
|
+
before.lapseAttempts,
|
|
690
|
+
before.updatedAt,
|
|
691
|
+
before.dispatchClaimToken,
|
|
692
|
+
before.dispatchClaimToken
|
|
693
|
+
]);
|
|
694
|
+
const row = await getAgentFollowUp(control, input.id);
|
|
695
|
+
return row?.dispatchClaimToken === claimToken ? row : null;
|
|
696
|
+
}
|
|
697
|
+
export async function finishAgentFollowUpLapse(control, input) {
|
|
698
|
+
const now = input.now ?? nowIso();
|
|
699
|
+
await control.run(`UPDATE ${q("_agent_follow_ups")} SET "lapseHandledAt" = ?, "updatedAt" = ?
|
|
700
|
+
WHERE "id" = ? AND "status" = 'lapsed' AND "lapseHandledAt" IS NULL`, [now, now, input.id]);
|
|
701
|
+
return (await getAgentFollowUp(control, input.id))?.lapseHandledAt === now;
|
|
702
|
+
}
|
|
703
|
+
//# sourceMappingURL=agent-follow-up-store.js.map
|