@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,696 @@
|
|
|
1
|
+
import { sha256Hex } from "./internal.js";
|
|
2
|
+
import { assertRaybaseObjectKey, raybaseObjectKey, raybaseRuntimeScope, raybaseVectorizeNamespace } from "./platform.js";
|
|
3
|
+
import { nowIso, q } from "./sql.js";
|
|
4
|
+
import { id, integer, longText, raybaseSystemTable, text } from "./schema.js";
|
|
5
|
+
export const raybaseAgentChapterArchiveSystemTables = [
|
|
6
|
+
raybaseSystemTable("_agent_chapter_purges", {
|
|
7
|
+
id: id(),
|
|
8
|
+
scopeKind: text({ required: true }),
|
|
9
|
+
scopeId: text({ required: true }),
|
|
10
|
+
agentName: text(),
|
|
11
|
+
conversationId: text(),
|
|
12
|
+
objectKey: text(),
|
|
13
|
+
vectorIdsJson: longText(),
|
|
14
|
+
actionKind: text(),
|
|
15
|
+
payloadJson: longText(),
|
|
16
|
+
attempts: integer({ required: true }),
|
|
17
|
+
lastError: longText(),
|
|
18
|
+
nextAttemptAt: text(),
|
|
19
|
+
requestedAt: text({ required: true })
|
|
20
|
+
}, { indexes: [["scopeKind", "scopeId"], ["attempts", "nextAttemptAt"], ["conversationId"]] })
|
|
21
|
+
];
|
|
22
|
+
export const agentChapterPurgeMaxAttempts = 8;
|
|
23
|
+
export const agentChapterPurgeBaseBackoffMs = 60_000;
|
|
24
|
+
export const agentChapterPurgeMaxBackoffMs = 6 * 60 * 60_000;
|
|
25
|
+
/**
|
|
26
|
+
* Version stamped on every archive NDJSON line (`raybaseArchiveV`) and on the
|
|
27
|
+
* R2 object (`customMetadata.raybaseArchiveV`). Lines written before the
|
|
28
|
+
* stamp existed carry no field and are read as version 1.
|
|
29
|
+
*/
|
|
30
|
+
export const agentChapterArchiveVersion = 1;
|
|
31
|
+
export function agentChapterArchiveObjectKey(chapter, env) {
|
|
32
|
+
const fallback = () => [
|
|
33
|
+
"thread-archive",
|
|
34
|
+
archiveKeySegment(chapter.agentName),
|
|
35
|
+
archiveKeySegment(chapter.conversationId),
|
|
36
|
+
`${chapter.ordinal}-${archiveKeySegment(chapter.id)}.ndjson`
|
|
37
|
+
].join("/");
|
|
38
|
+
if (!env)
|
|
39
|
+
return fallback();
|
|
40
|
+
return raybaseObjectKey(env, "agent-transcript", [chapter.agentName, chapter.conversationId, `${chapter.ordinal}-${chapter.id}.ndjson`], raybaseRuntimeScope(env), fallback);
|
|
41
|
+
}
|
|
42
|
+
export function agentChapterArchivePrefix(agentName, conversationId, env) {
|
|
43
|
+
const fallback = () => `thread-archive/${archiveKeySegment(agentName)}/${archiveKeySegment(conversationId)}/`;
|
|
44
|
+
if (!env)
|
|
45
|
+
return fallback();
|
|
46
|
+
return `${raybaseObjectKey(env, "agent-transcript", [agentName, conversationId], raybaseRuntimeScope(env), () => fallback().slice(0, -1))}/`;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Reconnects prompt-assembly groups to their unresolved stored UI messages.
|
|
50
|
+
* Model-only image data must never become the verbatim archive source.
|
|
51
|
+
*/
|
|
52
|
+
export function agentChapterArchiveGroupsFromStoredMessages(groups, storedMessages) {
|
|
53
|
+
const storedById = new Map();
|
|
54
|
+
for (const message of storedMessages) {
|
|
55
|
+
const record = archiveRecord(message);
|
|
56
|
+
if (typeof record.id === "string")
|
|
57
|
+
storedById.set(record.id, message);
|
|
58
|
+
}
|
|
59
|
+
return groups.map((group) => {
|
|
60
|
+
const raw = archiveRecord(group.raw);
|
|
61
|
+
const id = typeof raw.id === "string" ? raw.id : group.id;
|
|
62
|
+
return {
|
|
63
|
+
...group,
|
|
64
|
+
raw: sanitizeAgentChapterArchiveRaw(id ? storedById.get(id) ?? group.raw : group.raw)
|
|
65
|
+
};
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
export async function prepareAgentChapterArchive(chapter, groups, env) {
|
|
69
|
+
const lines = groups.map((group) => {
|
|
70
|
+
const safeRaw = sanitizeAgentChapterArchiveRaw(group.raw);
|
|
71
|
+
const message = safeRaw && typeof safeRaw === "object" && !Array.isArray(safeRaw)
|
|
72
|
+
? {
|
|
73
|
+
...safeRaw,
|
|
74
|
+
createdAt: safeRaw.createdAt ?? group.createdAt ?? null
|
|
75
|
+
}
|
|
76
|
+
: {
|
|
77
|
+
id: group.id,
|
|
78
|
+
createdAt: group.createdAt ?? null,
|
|
79
|
+
messages: group.messages
|
|
80
|
+
};
|
|
81
|
+
// Member surfaces read this format back for years; a line without the
|
|
82
|
+
// version field is also version 1 (the field arrived 2026-08, objects
|
|
83
|
+
// are integrity-locked and never rewritten). Readers dispatch on the
|
|
84
|
+
// field, never on shape sniffing.
|
|
85
|
+
return JSON.stringify({ ...message, raybaseArchiveV: agentChapterArchiveVersion });
|
|
86
|
+
});
|
|
87
|
+
const ndjson = lines.length ? `${lines.join("\n")}\n` : "";
|
|
88
|
+
return {
|
|
89
|
+
chapterId: chapter.id,
|
|
90
|
+
objectKey: agentChapterArchiveObjectKey(chapter, env),
|
|
91
|
+
ndjson,
|
|
92
|
+
sha256: await sha256Hex(ndjson),
|
|
93
|
+
bytes: new TextEncoder().encode(ndjson).byteLength
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function sanitizeAgentChapterArchiveRaw(value) {
|
|
97
|
+
const record = archiveRecord(value);
|
|
98
|
+
if (!Object.keys(record).length || !Array.isArray(record.parts))
|
|
99
|
+
return value;
|
|
100
|
+
return {
|
|
101
|
+
...record,
|
|
102
|
+
parts: record.parts.filter((part) => {
|
|
103
|
+
const candidate = archiveRecord(part);
|
|
104
|
+
return !(candidate.type === "file" && typeof candidate.url === "string" && candidate.url.startsWith("data:"));
|
|
105
|
+
})
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function archiveRecord(value) {
|
|
109
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
110
|
+
}
|
|
111
|
+
export async function archivePreparedAgentChapter(input) {
|
|
112
|
+
const current = await input.control.first(`SELECT * FROM ${q("_agent_chapters")} WHERE "id" = ? LIMIT 1`, [input.prepared.chapterId]);
|
|
113
|
+
if (!current)
|
|
114
|
+
throw new Error(`Agent chapter ${input.prepared.chapterId} no longer exists`);
|
|
115
|
+
if (current.archiveObjectKey === input.prepared.objectKey
|
|
116
|
+
&& current.archiveSha256 === input.prepared.sha256
|
|
117
|
+
&& current.archiveBytes === input.prepared.bytes
|
|
118
|
+
&& current.archivedAt) {
|
|
119
|
+
return current;
|
|
120
|
+
}
|
|
121
|
+
const obligationAt = input.now ?? nowIso();
|
|
122
|
+
await input.control.run(`UPDATE ${q("_agent_chapters")}
|
|
123
|
+
SET "archiveObligationAt" = COALESCE("archiveObligationAt", ?), "updatedAt" = ?
|
|
124
|
+
WHERE "id" = ?`, [obligationAt, obligationAt, input.prepared.chapterId]);
|
|
125
|
+
if (!input.bucket)
|
|
126
|
+
throw new Error("RAYBASE_THREAD_ARCHIVE R2 binding is missing");
|
|
127
|
+
await input.bucket.put(input.prepared.objectKey, input.prepared.ndjson, {
|
|
128
|
+
httpMetadata: { contentType: "application/x-ndjson" },
|
|
129
|
+
customMetadata: {
|
|
130
|
+
raybaseSha256: input.prepared.sha256,
|
|
131
|
+
raybaseChapterId: input.prepared.chapterId,
|
|
132
|
+
raybaseArchiveV: String(agentChapterArchiveVersion)
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
const head = await input.bucket.head(input.prepared.objectKey);
|
|
136
|
+
verifyAgentChapterArchiveHead(head, input.prepared);
|
|
137
|
+
const archivedAt = input.now ?? nowIso();
|
|
138
|
+
await input.control.run(`UPDATE ${q("_agent_chapters")}
|
|
139
|
+
SET "archiveObligationAt" = NULL, "archiveObjectKey" = ?, "archiveSha256" = ?, "archiveBytes" = ?,
|
|
140
|
+
"archivedAt" = ?, "updatedAt" = ?
|
|
141
|
+
WHERE "id" = ?`, [
|
|
142
|
+
input.prepared.objectKey,
|
|
143
|
+
input.prepared.sha256,
|
|
144
|
+
input.prepared.bytes,
|
|
145
|
+
archivedAt,
|
|
146
|
+
archivedAt,
|
|
147
|
+
input.prepared.chapterId
|
|
148
|
+
]);
|
|
149
|
+
const confirmed = await input.control.first(`SELECT * FROM ${q("_agent_chapters")} WHERE "id" = ? LIMIT 1`, [input.prepared.chapterId]);
|
|
150
|
+
if (!confirmed
|
|
151
|
+
|| confirmed.archiveObjectKey !== input.prepared.objectKey
|
|
152
|
+
|| confirmed.archiveSha256 !== input.prepared.sha256) {
|
|
153
|
+
throw new Error(`Agent chapter ${input.prepared.chapterId} archive confirmation failed`);
|
|
154
|
+
}
|
|
155
|
+
return confirmed;
|
|
156
|
+
}
|
|
157
|
+
export async function readAgentChapterArchive(bucket, chapter) {
|
|
158
|
+
if (!chapter.archiveObjectKey)
|
|
159
|
+
return null;
|
|
160
|
+
if (!bucket)
|
|
161
|
+
throw new Error("RAYBASE_THREAD_ARCHIVE R2 binding is missing");
|
|
162
|
+
const object = await bucket.get(chapter.archiveObjectKey);
|
|
163
|
+
if (!object)
|
|
164
|
+
throw new Error(`Archived transcript for chapter ${chapter.id} is missing`);
|
|
165
|
+
const text = await object.text();
|
|
166
|
+
const bytes = new TextEncoder().encode(text).byteLength;
|
|
167
|
+
const sha256 = await sha256Hex(text);
|
|
168
|
+
if (chapter.archiveBytes !== null && bytes !== chapter.archiveBytes) {
|
|
169
|
+
throw new Error(`Archived transcript for chapter ${chapter.id} has an unexpected byte length`);
|
|
170
|
+
}
|
|
171
|
+
if (chapter.archiveSha256 && sha256 !== chapter.archiveSha256) {
|
|
172
|
+
throw new Error(`Archived transcript for chapter ${chapter.id} failed sha256 verification`);
|
|
173
|
+
}
|
|
174
|
+
return text;
|
|
175
|
+
}
|
|
176
|
+
export function ensureAgentChapterArchiveSpool(spool) {
|
|
177
|
+
spool.sql `CREATE TABLE IF NOT EXISTS "_agent_chapter_pending_archive" (
|
|
178
|
+
"chapterId" TEXT PRIMARY KEY NOT NULL,
|
|
179
|
+
"ndjson" TEXT NOT NULL,
|
|
180
|
+
"sha256" TEXT NOT NULL,
|
|
181
|
+
"attempts" INTEGER NOT NULL DEFAULT 0,
|
|
182
|
+
"lastError" TEXT,
|
|
183
|
+
"createdAt" TEXT NOT NULL
|
|
184
|
+
)`;
|
|
185
|
+
}
|
|
186
|
+
export function spoolPendingAgentChapterArchive(spool, prepared, error) {
|
|
187
|
+
ensureAgentChapterArchiveSpool(spool);
|
|
188
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
189
|
+
spool.sql `INSERT INTO "_agent_chapter_pending_archive"
|
|
190
|
+
("chapterId", "ndjson", "sha256", "attempts", "lastError", "createdAt")
|
|
191
|
+
VALUES (${prepared.chapterId}, ${prepared.ndjson}, ${prepared.sha256}, ${1}, ${message.slice(0, 2_000)}, ${nowIso()})
|
|
192
|
+
ON CONFLICT("chapterId") DO UPDATE SET
|
|
193
|
+
"ndjson" = excluded."ndjson",
|
|
194
|
+
"sha256" = excluded."sha256",
|
|
195
|
+
"attempts" = "_agent_chapter_pending_archive"."attempts" + 1,
|
|
196
|
+
"lastError" = excluded."lastError"`;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Stage the only verbatim copy before the first external archive mutation.
|
|
200
|
+
* This remains synchronous so isolate death cannot land between the R2 put
|
|
201
|
+
* and a recoverable local copy.
|
|
202
|
+
*/
|
|
203
|
+
export function stagePendingAgentChapterArchive(spool, prepared) {
|
|
204
|
+
ensureAgentChapterArchiveSpool(spool);
|
|
205
|
+
spool.sql `INSERT INTO "_agent_chapter_pending_archive"
|
|
206
|
+
("chapterId", "ndjson", "sha256", "attempts", "lastError", "createdAt")
|
|
207
|
+
VALUES (${prepared.chapterId}, ${prepared.ndjson}, ${prepared.sha256}, ${0}, ${null}, ${nowIso()})
|
|
208
|
+
ON CONFLICT("chapterId") DO UPDATE SET
|
|
209
|
+
"ndjson" = excluded."ndjson",
|
|
210
|
+
"sha256" = excluded."sha256"`;
|
|
211
|
+
}
|
|
212
|
+
export async function archivePreparedAgentChapterWithSpool(input) {
|
|
213
|
+
stagePendingAgentChapterArchive(input.spool, input.prepared);
|
|
214
|
+
try {
|
|
215
|
+
const confirmed = await archivePreparedAgentChapter(input);
|
|
216
|
+
prunePendingAgentChapterArchive(input.spool, input.prepared.chapterId);
|
|
217
|
+
return confirmed;
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
spoolPendingAgentChapterArchive(input.spool, input.prepared, error);
|
|
221
|
+
throw error;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Runs chapter-close side effects behind a durable archive handoff. In
|
|
226
|
+
* archive mode the exact NDJSON is staged synchronously before `afterStage`
|
|
227
|
+
* may await FTS or embedding work. A retry that has neither a confirmed
|
|
228
|
+
* object nor staged bytes is unsafe and must leave hot storage intact.
|
|
229
|
+
*/
|
|
230
|
+
export async function finalizeAgentChapterArchiveFirst(input) {
|
|
231
|
+
if (input.groups.length === 0) {
|
|
232
|
+
if (!input.archiveRequired || (input.chapter.archiveObjectKey && input.chapter.archivedAt))
|
|
233
|
+
return;
|
|
234
|
+
// A chapter closed while transcripts were intentionally discarded never
|
|
235
|
+
// acquired an archive obligation. A later policy change must not make that
|
|
236
|
+
// already-closed span retroactively owed or wedge expiry forever.
|
|
237
|
+
if (!input.chapter.archiveObligationAt)
|
|
238
|
+
return;
|
|
239
|
+
const staged = listPendingAgentChapterArchives(input.spool)
|
|
240
|
+
.some((pending) => pending.chapterId === input.chapter.id);
|
|
241
|
+
if (!staged) {
|
|
242
|
+
throw new Error(`Agent chapter ${input.chapter.id} has no confirmed or staged transcript archive; refusing hot-storage cleanup`);
|
|
243
|
+
}
|
|
244
|
+
const drained = await drainPendingAgentChapterArchives({
|
|
245
|
+
control: input.control,
|
|
246
|
+
bucket: input.bucket,
|
|
247
|
+
spool: input.spool,
|
|
248
|
+
env: input.env
|
|
249
|
+
});
|
|
250
|
+
if (drained.pending > 0) {
|
|
251
|
+
throw new Error(`${drained.pending} pending agent chapter archive spool entr${drained.pending === 1 ? "y" : "ies"} remains`);
|
|
252
|
+
}
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
const prepared = input.archiveRequired
|
|
256
|
+
? await prepareAgentChapterArchive(input.chapter, input.groups, input.env)
|
|
257
|
+
: null;
|
|
258
|
+
if (prepared)
|
|
259
|
+
stagePendingAgentChapterArchive(input.spool, prepared);
|
|
260
|
+
await input.afterStage();
|
|
261
|
+
if (!prepared)
|
|
262
|
+
return;
|
|
263
|
+
try {
|
|
264
|
+
await archivePreparedAgentChapterWithSpool({
|
|
265
|
+
control: input.control,
|
|
266
|
+
bucket: input.bucket,
|
|
267
|
+
spool: input.spool,
|
|
268
|
+
prepared
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
catch (error) {
|
|
272
|
+
if (input.failOnArchiveError)
|
|
273
|
+
throw error;
|
|
274
|
+
console.warn(`Agent chapter ${input.chapter.id} archive deferred to spool`, error);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
export async function assertAgentChapterArchivesConfirmed(input) {
|
|
278
|
+
const unsafe = await input.control.first(`SELECT COUNT(*) AS "count" FROM ${q("_agent_chapters")}
|
|
279
|
+
WHERE "agentName" = ? AND "conversationId" = ?
|
|
280
|
+
AND (
|
|
281
|
+
"archiveObligationAt" IS NOT NULL
|
|
282
|
+
OR (
|
|
283
|
+
"archiveObjectKey" IS NOT NULL
|
|
284
|
+
AND (
|
|
285
|
+
"archiveSha256" IS NULL
|
|
286
|
+
OR "archiveBytes" IS NULL
|
|
287
|
+
OR "archivedAt" IS NULL
|
|
288
|
+
)
|
|
289
|
+
)
|
|
290
|
+
)`, [input.agentName, input.conversationId]);
|
|
291
|
+
const count = Number(unsafe?.count ?? 0);
|
|
292
|
+
if (count > 0) {
|
|
293
|
+
throw new Error(`${count} agent chapter${count === 1 ? "" : "s"} lack a confirmed transcript archive; refusing hot-storage cleanup`);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
export function listPendingAgentChapterArchives(spool) {
|
|
297
|
+
ensureAgentChapterArchiveSpool(spool);
|
|
298
|
+
return spool.sql `SELECT * FROM "_agent_chapter_pending_archive" ORDER BY "createdAt" ASC`;
|
|
299
|
+
}
|
|
300
|
+
export function prunePendingAgentChapterArchive(spool, chapterId) {
|
|
301
|
+
ensureAgentChapterArchiveSpool(spool);
|
|
302
|
+
spool.sql `DELETE FROM "_agent_chapter_pending_archive" WHERE "chapterId" = ${chapterId}`;
|
|
303
|
+
}
|
|
304
|
+
export async function drainPendingAgentChapterArchives(input) {
|
|
305
|
+
const pending = listPendingAgentChapterArchives(input.spool);
|
|
306
|
+
let drained = 0;
|
|
307
|
+
for (const item of pending) {
|
|
308
|
+
const chapter = await input.control.first(`SELECT * FROM ${q("_agent_chapters")} WHERE "id" = ? LIMIT 1`, [item.chapterId]);
|
|
309
|
+
if (!chapter) {
|
|
310
|
+
prunePendingAgentChapterArchive(input.spool, item.chapterId);
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
const prepared = {
|
|
314
|
+
chapterId: chapter.id,
|
|
315
|
+
objectKey: agentChapterArchiveObjectKey(chapter, input.env),
|
|
316
|
+
ndjson: item.ndjson,
|
|
317
|
+
sha256: item.sha256,
|
|
318
|
+
bytes: new TextEncoder().encode(item.ndjson).byteLength
|
|
319
|
+
};
|
|
320
|
+
try {
|
|
321
|
+
await archivePreparedAgentChapter({ control: input.control, bucket: input.bucket, prepared });
|
|
322
|
+
prunePendingAgentChapterArchive(input.spool, item.chapterId);
|
|
323
|
+
drained += 1;
|
|
324
|
+
}
|
|
325
|
+
catch (error) {
|
|
326
|
+
spoolPendingAgentChapterArchive(input.spool, prepared, error);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return {
|
|
330
|
+
drained,
|
|
331
|
+
pending: listPendingAgentChapterArchives(input.spool).length
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
export async function deleteVerifiedAgentChapterArchive(bucket, objectKey, env) {
|
|
335
|
+
if (!bucket)
|
|
336
|
+
throw new Error("RAYBASE_THREAD_ARCHIVE R2 binding is missing");
|
|
337
|
+
if (env) {
|
|
338
|
+
assertRaybaseObjectKey(env, "agent-transcript", objectKey, raybaseRuntimeScope(env));
|
|
339
|
+
}
|
|
340
|
+
await bucket.delete(objectKey);
|
|
341
|
+
if (await bucket.head(objectKey)) {
|
|
342
|
+
throw new Error(`Thread archive object still exists after delete: ${objectKey}`);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
export async function purgeAgentChapterArtifactsForConversation(input) {
|
|
346
|
+
const catalogConversation = input.conversationKind
|
|
347
|
+
? null
|
|
348
|
+
: await input.control.first(`SELECT "kind" FROM ${q("_agent_instances")}
|
|
349
|
+
WHERE "agentName" = ? AND "conversationId" = ? LIMIT 1`, [input.agentName, input.conversationId]);
|
|
350
|
+
const conversationKind = input.conversationKind
|
|
351
|
+
?? (catalogConversation?.kind === "room" ? "room" : "direct");
|
|
352
|
+
if (conversationKind === "room" && input.roomDeletion !== true) {
|
|
353
|
+
throw new Error("Shared Agent room artifacts require an explicit whole-room deletion");
|
|
354
|
+
}
|
|
355
|
+
const scopeKind = input.scopeKind ?? "conversation";
|
|
356
|
+
const scopeId = input.scopeId ?? input.conversationId;
|
|
357
|
+
if (scopeKind === "user") {
|
|
358
|
+
// Adopt any retry work created by an earlier conversation-scoped purge
|
|
359
|
+
// before deleting the chapter rows that associate this conversation with
|
|
360
|
+
// the user. This also covers direct chat-DO erasure calls.
|
|
361
|
+
await input.control.run(`UPDATE ${q("_agent_chapter_purges")}
|
|
362
|
+
SET "scopeKind" = 'user', "scopeId" = ?
|
|
363
|
+
WHERE "conversationId" = ?
|
|
364
|
+
AND NOT ("scopeKind" = 'user' AND "scopeId" = ?)`, [scopeId, input.conversationId, scopeId]);
|
|
365
|
+
}
|
|
366
|
+
const chapters = await input.control.all(`SELECT * FROM ${q("_agent_chapters")} WHERE "agentName" = ? AND "conversationId" = ?`, [input.agentName, input.conversationId]);
|
|
367
|
+
const objectKeys = new Set(chapters.flatMap((chapter) => chapter.archiveObjectKey ? [chapter.archiveObjectKey] : []));
|
|
368
|
+
const hasArchiveObligation = chapters.some((chapter) => Boolean(chapter.archiveObligationAt));
|
|
369
|
+
if (input.spool) {
|
|
370
|
+
for (const pending of listPendingAgentChapterArchives(input.spool)) {
|
|
371
|
+
const chapter = chapters.find((candidate) => candidate.id === pending.chapterId);
|
|
372
|
+
if (chapter)
|
|
373
|
+
objectKeys.add(agentChapterArchiveObjectKey(chapter, input.env));
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
const ledger = await input.control.all(`SELECT e."vectorId", e."backend" FROM ${q("_ai_embedding_chunks")} e
|
|
377
|
+
JOIN ${q("_agent_chapters")} c ON c."id" = e."sourceId"
|
|
378
|
+
WHERE e."sourceType" = 'agent-chapter' AND c."agentName" = ? AND c."conversationId" = ?`, [input.agentName, input.conversationId]).catch(() => []);
|
|
379
|
+
const vectorIds = [...new Set(ledger
|
|
380
|
+
.filter((row) => row.backend === "vectorize")
|
|
381
|
+
.map((row) => row.vectorId)
|
|
382
|
+
.filter(Boolean))];
|
|
383
|
+
const failures = [];
|
|
384
|
+
let deletedObjects = 0;
|
|
385
|
+
for (const objectKey of objectKeys) {
|
|
386
|
+
try {
|
|
387
|
+
await deleteVerifiedAgentChapterArchive(input.env.RAYBASE_THREAD_ARCHIVE, objectKey, input.env);
|
|
388
|
+
deletedObjects += 1;
|
|
389
|
+
}
|
|
390
|
+
catch (error) {
|
|
391
|
+
failures.push({ objectKey, error: errorMessage(error) });
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
if (input.env.RAYBASE_THREAD_ARCHIVE) {
|
|
395
|
+
try {
|
|
396
|
+
deletedObjects += await deleteAgentChapterArchivePrefix(input.env.RAYBASE_THREAD_ARCHIVE, input.agentName, input.conversationId, input.env);
|
|
397
|
+
}
|
|
398
|
+
catch (error) {
|
|
399
|
+
failures.push({ error: errorMessage(error) });
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
else if (hasArchiveObligation && objectKeys.size === 0) {
|
|
403
|
+
failures.push({
|
|
404
|
+
error: "RAYBASE_THREAD_ARCHIVE R2 binding is missing for a durable archive prefix obligation"
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
if (vectorIds.length) {
|
|
408
|
+
try {
|
|
409
|
+
if (!input.env.RAYBASE_VECTORIZE)
|
|
410
|
+
throw new Error("RAYBASE_VECTORIZE binding is missing");
|
|
411
|
+
await input.env.RAYBASE_VECTORIZE.deleteByIds(vectorIds, {
|
|
412
|
+
namespace: await raybaseVectorizeNamespace(input.env, "agent-history", raybaseRuntimeScope(input.env), "default")
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
catch (error) {
|
|
416
|
+
failures.push({ vectorIds, error: errorMessage(error) });
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
for (const failure of failures) {
|
|
420
|
+
await enqueueAgentChapterPurge(input.control, {
|
|
421
|
+
scopeKind,
|
|
422
|
+
scopeId,
|
|
423
|
+
agentName: input.agentName,
|
|
424
|
+
conversationId: input.conversationId,
|
|
425
|
+
objectKey: failure.objectKey ?? null,
|
|
426
|
+
vectorIds: failure.vectorIds ?? [],
|
|
427
|
+
error: failure.error
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
const chapterFts = await input.control.first(`SELECT "name" FROM sqlite_master WHERE "name" = ? LIMIT 1`, ["_agent_chapter_fts"]);
|
|
431
|
+
if (chapterFts) {
|
|
432
|
+
await input.control.run(`DELETE FROM ${q("_agent_chapter_fts")} WHERE "chapterId" IN (
|
|
433
|
+
SELECT "id" FROM ${q("_agent_chapters")} WHERE "agentName" = ? AND "conversationId" = ?
|
|
434
|
+
)`, [input.agentName, input.conversationId]);
|
|
435
|
+
}
|
|
436
|
+
await input.control.run(`DELETE FROM ${q("_ai_embedding_chunks")} WHERE "sourceType" = 'agent-chapter' AND "sourceId" IN (
|
|
437
|
+
SELECT "id" FROM ${q("_agent_chapters")} WHERE "agentName" = ? AND "conversationId" = ?
|
|
438
|
+
)`, [input.agentName, input.conversationId]).catch(() => { });
|
|
439
|
+
await input.control.run(`DELETE FROM ${q("_agent_chapters")} WHERE "agentName" = ? AND "conversationId" = ?`, [input.agentName, input.conversationId]);
|
|
440
|
+
if (input.spool) {
|
|
441
|
+
for (const pending of listPendingAgentChapterArchives(input.spool)) {
|
|
442
|
+
prunePendingAgentChapterArchive(input.spool, pending.chapterId);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
return {
|
|
446
|
+
pending: await countAgentChapterPurges(input.control, scopeKind, scopeId),
|
|
447
|
+
deletedObjects,
|
|
448
|
+
deletedVectors: vectorIds.length && failures.every((failure) => !failure.vectorIds) ? vectorIds.length : 0
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
export async function purgeAgentChapterArtifactsForUser(input) {
|
|
452
|
+
const conversations = await input.control.all(`SELECT DISTINCT "agentName", "conversationId" FROM ${q("_agent_chapters")} WHERE "userId" = ?`, [input.userId]);
|
|
453
|
+
let deletedObjects = 0;
|
|
454
|
+
let deletedVectors = 0;
|
|
455
|
+
for (const conversation of conversations) {
|
|
456
|
+
const result = await purgeAgentChapterArtifactsForConversation({
|
|
457
|
+
...input,
|
|
458
|
+
agentName: conversation.agentName,
|
|
459
|
+
conversationId: conversation.conversationId,
|
|
460
|
+
scopeKind: "user",
|
|
461
|
+
scopeId: input.userId,
|
|
462
|
+
conversationKind: "direct"
|
|
463
|
+
});
|
|
464
|
+
deletedObjects += result.deletedObjects;
|
|
465
|
+
deletedVectors += result.deletedVectors;
|
|
466
|
+
}
|
|
467
|
+
return {
|
|
468
|
+
pending: await countAgentChapterPurges(input.control, "user", input.userId),
|
|
469
|
+
deletedObjects,
|
|
470
|
+
deletedVectors
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
export async function retryAgentChapterPurges(input) {
|
|
474
|
+
const now = input.now ?? nowIso();
|
|
475
|
+
const filters = [
|
|
476
|
+
`"attempts" < ?`,
|
|
477
|
+
`("nextAttemptAt" IS NULL OR "nextAttemptAt" <= ?)`
|
|
478
|
+
];
|
|
479
|
+
const params = [agentChapterPurgeMaxAttempts, now];
|
|
480
|
+
if (input.scopeKind) {
|
|
481
|
+
filters.push(`"scopeKind" = ?`);
|
|
482
|
+
params.push(input.scopeKind);
|
|
483
|
+
}
|
|
484
|
+
if (input.scopeId) {
|
|
485
|
+
filters.push(`"scopeId" = ?`);
|
|
486
|
+
params.push(input.scopeId);
|
|
487
|
+
}
|
|
488
|
+
const rows = await input.control.all(`SELECT * FROM ${q("_agent_chapter_purges")}
|
|
489
|
+
WHERE ${filters.join(" AND ")}
|
|
490
|
+
ORDER BY CASE WHEN "nextAttemptAt" IS NULL THEN 0 ELSE 1 END ASC,
|
|
491
|
+
COALESCE("nextAttemptAt", "requestedAt") ASC,
|
|
492
|
+
"requestedAt" ASC
|
|
493
|
+
LIMIT ?`, [
|
|
494
|
+
...params,
|
|
495
|
+
Math.max(1, Math.min(100, input.limit ?? 25))
|
|
496
|
+
]);
|
|
497
|
+
for (const row of rows) {
|
|
498
|
+
let drainedScope;
|
|
499
|
+
try {
|
|
500
|
+
if (row.scopeKind === "room-member") {
|
|
501
|
+
if (!input.onRoomMemberAction)
|
|
502
|
+
throw new Error("Agent room-member purge action handler is unavailable");
|
|
503
|
+
await input.onRoomMemberAction(row);
|
|
504
|
+
}
|
|
505
|
+
else {
|
|
506
|
+
if (row.objectKey) {
|
|
507
|
+
await deleteVerifiedAgentChapterArchive(input.env.RAYBASE_THREAD_ARCHIVE, row.objectKey, input.env);
|
|
508
|
+
}
|
|
509
|
+
const vectorIds = parseStringArray(row.vectorIdsJson);
|
|
510
|
+
if (vectorIds.length) {
|
|
511
|
+
if (!input.env.RAYBASE_VECTORIZE)
|
|
512
|
+
throw new Error("RAYBASE_VECTORIZE binding is missing");
|
|
513
|
+
await input.env.RAYBASE_VECTORIZE.deleteByIds(vectorIds, {
|
|
514
|
+
namespace: await raybaseVectorizeNamespace(input.env, "agent-history", raybaseRuntimeScope(input.env), "default")
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
if (row.agentName && row.conversationId) {
|
|
518
|
+
if (input.env.RAYBASE_THREAD_ARCHIVE) {
|
|
519
|
+
await deleteAgentChapterArchivePrefix(input.env.RAYBASE_THREAD_ARCHIVE, row.agentName, row.conversationId, input.env);
|
|
520
|
+
}
|
|
521
|
+
else if (!row.objectKey && vectorIds.length === 0) {
|
|
522
|
+
throw new Error("RAYBASE_THREAD_ARCHIVE R2 binding is missing");
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
const otherRows = await input.control.first(`SELECT COUNT(*) AS "count" FROM ${q("_agent_chapter_purges")}
|
|
527
|
+
WHERE "scopeKind" = ? AND "scopeId" = ? AND "id" <> ?`, [row.scopeKind, row.scopeId, row.id]);
|
|
528
|
+
await input.control.run(`DELETE FROM ${q("_agent_chapter_purges")} WHERE "id" = ?`, [row.id]);
|
|
529
|
+
if (Number(otherRows?.count ?? 0) === 0) {
|
|
530
|
+
drainedScope = {
|
|
531
|
+
scopeKind: row.scopeKind,
|
|
532
|
+
scopeId: row.scopeId,
|
|
533
|
+
requestedAt: row.requestedAt,
|
|
534
|
+
attempts: row.attempts
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
catch (error) {
|
|
539
|
+
const attempts = row.attempts + 1;
|
|
540
|
+
await input.control.run(`UPDATE ${q("_agent_chapter_purges")}
|
|
541
|
+
SET "attempts" = ?, "lastError" = ?, "nextAttemptAt" = ?
|
|
542
|
+
WHERE "id" = ?`, [
|
|
543
|
+
attempts,
|
|
544
|
+
errorMessage(error).slice(0, 2_000),
|
|
545
|
+
nextAgentChapterPurgeAttemptAt(attempts, now),
|
|
546
|
+
row.id
|
|
547
|
+
]);
|
|
548
|
+
}
|
|
549
|
+
if (drainedScope)
|
|
550
|
+
await input.onScopeDrained?.(drainedScope);
|
|
551
|
+
}
|
|
552
|
+
const backlog = await agentChapterPurgeBacklog(input.control, { limit: 0, now });
|
|
553
|
+
return {
|
|
554
|
+
attempted: rows.length,
|
|
555
|
+
remaining: backlog.total,
|
|
556
|
+
capped: backlog.capped,
|
|
557
|
+
deferred: backlog.deferred
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
export async function agentChapterPurgeBacklog(control, options = {}) {
|
|
561
|
+
const now = options.now ?? nowIso();
|
|
562
|
+
const summary = await control.first(`SELECT
|
|
563
|
+
COUNT(*) AS "total",
|
|
564
|
+
COALESCE(SUM(CASE WHEN "attempts" < ? AND ("nextAttemptAt" IS NULL OR "nextAttemptAt" <= ?) THEN 1 ELSE 0 END), 0) AS "ready",
|
|
565
|
+
COALESCE(SUM(CASE WHEN "attempts" >= ? THEN 1 ELSE 0 END), 0) AS "capped",
|
|
566
|
+
MIN("requestedAt") AS "oldestRequestedAt",
|
|
567
|
+
MIN(CASE WHEN "attempts" < ? AND "nextAttemptAt" > ? THEN "nextAttemptAt" ELSE NULL END) AS "nextAttemptAt"
|
|
568
|
+
FROM ${q("_agent_chapter_purges")}`, [
|
|
569
|
+
agentChapterPurgeMaxAttempts,
|
|
570
|
+
now,
|
|
571
|
+
agentChapterPurgeMaxAttempts,
|
|
572
|
+
agentChapterPurgeMaxAttempts,
|
|
573
|
+
now
|
|
574
|
+
]);
|
|
575
|
+
const total = Number(summary?.total ?? 0);
|
|
576
|
+
const ready = Number(summary?.ready ?? 0);
|
|
577
|
+
const capped = Number(summary?.capped ?? 0);
|
|
578
|
+
const limit = Math.max(0, Math.min(100, Math.floor(options.limit ?? 50)));
|
|
579
|
+
const rows = limit === 0
|
|
580
|
+
? []
|
|
581
|
+
: await control.all(`SELECT "id", "scopeKind", "scopeId", "agentName", "conversationId", "attempts",
|
|
582
|
+
"lastError", "nextAttemptAt", "requestedAt"
|
|
583
|
+
FROM ${q("_agent_chapter_purges")}
|
|
584
|
+
ORDER BY CASE WHEN "attempts" >= ? THEN 0 ELSE 1 END ASC, "requestedAt" ASC
|
|
585
|
+
LIMIT ?`, [agentChapterPurgeMaxAttempts, limit]);
|
|
586
|
+
return {
|
|
587
|
+
total,
|
|
588
|
+
ready,
|
|
589
|
+
deferred: Math.max(0, total - ready - capped),
|
|
590
|
+
capped,
|
|
591
|
+
oldestRequestedAt: summary?.oldestRequestedAt ?? null,
|
|
592
|
+
nextAttemptAt: summary?.nextAttemptAt ?? null,
|
|
593
|
+
entries: rows.map((row) => ({
|
|
594
|
+
...row,
|
|
595
|
+
attempts: Number(row.attempts),
|
|
596
|
+
capped: Number(row.attempts) >= agentChapterPurgeMaxAttempts
|
|
597
|
+
}))
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
export function nextAgentChapterPurgeAttemptAt(attempts, from) {
|
|
601
|
+
const exponent = Math.max(0, Math.min(16, Math.floor(attempts) - 1));
|
|
602
|
+
const delay = Math.min(agentChapterPurgeMaxBackoffMs, agentChapterPurgeBaseBackoffMs * (2 ** exponent));
|
|
603
|
+
return new Date(new Date(from).getTime() + delay).toISOString();
|
|
604
|
+
}
|
|
605
|
+
export async function countAgentChapterPurges(control, scopeKind, scopeId) {
|
|
606
|
+
const row = await control.first(`SELECT COUNT(*) AS "count" FROM ${q("_agent_chapter_purges")} WHERE "scopeKind" = ? AND "scopeId" = ?`, [scopeKind, scopeId]);
|
|
607
|
+
return Number(row?.count ?? 0);
|
|
608
|
+
}
|
|
609
|
+
export async function enqueueAgentChapterPurgeAction(input) {
|
|
610
|
+
const payloadJson = JSON.stringify(input.payload);
|
|
611
|
+
const existing = await input.control.first(`SELECT "id" FROM ${q("_agent_chapter_purges")}
|
|
612
|
+
WHERE "scopeKind" = ? AND "scopeId" = ? AND "actionKind" = ?
|
|
613
|
+
AND json_extract("payloadJson", '$.chapterId') = json_extract(?, '$.chapterId')
|
|
614
|
+
LIMIT 1`, [input.scopeKind, input.scopeId, input.actionKind, payloadJson]);
|
|
615
|
+
if (existing)
|
|
616
|
+
return existing.id;
|
|
617
|
+
const id = crypto.randomUUID();
|
|
618
|
+
const requestedAt = input.now ?? nowIso();
|
|
619
|
+
await input.control.run(`INSERT INTO ${q("_agent_chapter_purges")}
|
|
620
|
+
("id", "scopeKind", "scopeId", "agentName", "conversationId", "objectKey", "vectorIdsJson",
|
|
621
|
+
"actionKind", "payloadJson", "attempts", "lastError", "nextAttemptAt", "requestedAt")
|
|
622
|
+
VALUES (?, ?, ?, ?, ?, NULL, NULL, ?, ?, 0, NULL, NULL, ?)`, [
|
|
623
|
+
id,
|
|
624
|
+
input.scopeKind,
|
|
625
|
+
input.scopeId,
|
|
626
|
+
input.agentName,
|
|
627
|
+
input.conversationId,
|
|
628
|
+
input.actionKind,
|
|
629
|
+
payloadJson,
|
|
630
|
+
requestedAt
|
|
631
|
+
]);
|
|
632
|
+
return id;
|
|
633
|
+
}
|
|
634
|
+
async function deleteAgentChapterArchivePrefix(bucket, agentName, conversationId, env) {
|
|
635
|
+
let cursor;
|
|
636
|
+
let deleted = 0;
|
|
637
|
+
do {
|
|
638
|
+
const listed = await bucket.list({
|
|
639
|
+
prefix: agentChapterArchivePrefix(agentName, conversationId, env),
|
|
640
|
+
cursor
|
|
641
|
+
});
|
|
642
|
+
for (const object of listed.objects) {
|
|
643
|
+
await deleteVerifiedAgentChapterArchive(bucket, object.key, env);
|
|
644
|
+
deleted += 1;
|
|
645
|
+
}
|
|
646
|
+
cursor = listed.truncated ? listed.cursor : undefined;
|
|
647
|
+
} while (cursor);
|
|
648
|
+
return deleted;
|
|
649
|
+
}
|
|
650
|
+
async function enqueueAgentChapterPurge(control, input) {
|
|
651
|
+
const requestedAt = nowIso();
|
|
652
|
+
await control.run(`INSERT INTO ${q("_agent_chapter_purges")}
|
|
653
|
+
("id", "scopeKind", "scopeId", "agentName", "conversationId", "objectKey", "vectorIdsJson",
|
|
654
|
+
"attempts", "lastError", "nextAttemptAt", "requestedAt")
|
|
655
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?)`, [
|
|
656
|
+
crypto.randomUUID(),
|
|
657
|
+
input.scopeKind,
|
|
658
|
+
input.scopeId,
|
|
659
|
+
input.agentName,
|
|
660
|
+
input.conversationId,
|
|
661
|
+
input.objectKey,
|
|
662
|
+
input.vectorIds.length ? JSON.stringify(input.vectorIds) : null,
|
|
663
|
+
input.error.slice(0, 2_000),
|
|
664
|
+
nextAgentChapterPurgeAttemptAt(1, requestedAt),
|
|
665
|
+
requestedAt
|
|
666
|
+
]);
|
|
667
|
+
}
|
|
668
|
+
function parseStringArray(value) {
|
|
669
|
+
try {
|
|
670
|
+
const parsed = value ? JSON.parse(value) : [];
|
|
671
|
+
return Array.isArray(parsed) ? parsed.filter((item) => typeof item === "string") : [];
|
|
672
|
+
}
|
|
673
|
+
catch {
|
|
674
|
+
return [];
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
function errorMessage(error) {
|
|
678
|
+
return error instanceof Error ? error.message : String(error);
|
|
679
|
+
}
|
|
680
|
+
function verifyAgentChapterArchiveHead(head, prepared) {
|
|
681
|
+
if (!head)
|
|
682
|
+
throw new Error(`Thread archive object was not visible after put: ${prepared.objectKey}`);
|
|
683
|
+
if (head.size !== prepared.bytes) {
|
|
684
|
+
throw new Error(`Thread archive object size mismatch for ${prepared.objectKey}`);
|
|
685
|
+
}
|
|
686
|
+
if (head.customMetadata?.raybaseSha256 !== prepared.sha256) {
|
|
687
|
+
throw new Error(`Thread archive object sha256 metadata mismatch for ${prepared.objectKey}`);
|
|
688
|
+
}
|
|
689
|
+
if (head.customMetadata?.raybaseChapterId !== prepared.chapterId) {
|
|
690
|
+
throw new Error(`Thread archive object chapter metadata mismatch for ${prepared.objectKey}`);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
function archiveKeySegment(value) {
|
|
694
|
+
return encodeURIComponent(value).replace(/%2F/gi, "%252F");
|
|
695
|
+
}
|
|
696
|
+
//# sourceMappingURL=agent-chapter-archive.js.map
|