@capybara-hq/kernel 0.0.0-stage → 0.1.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +2 -0
- package/README.md +20 -2
- package/bootstrap.json +22 -0
- package/dist/admin/admin.controller.d.ts +139 -0
- package/dist/admin/admin.controller.js +238 -0
- package/dist/admin/extensions.controller.d.ts +100 -0
- package/dist/admin/extensions.controller.js +226 -0
- package/dist/admin/setup.controller.d.ts +36 -0
- package/dist/admin/setup.controller.js +106 -0
- package/dist/admin/setup.service.d.ts +47 -0
- package/dist/admin/setup.service.js +90 -0
- package/dist/agents/agents.controller.d.ts +205 -0
- package/dist/agents/agents.controller.js +144 -0
- package/dist/agents/agents.service.d.ts +177 -0
- package/dist/agents/agents.service.js +677 -0
- package/dist/agents/definition.d.ts +198 -0
- package/dist/agents/definition.js +152 -0
- package/dist/agents/models.controller.d.ts +13 -0
- package/dist/agents/models.controller.js +31 -0
- package/dist/agents/templates.controller.d.ts +15 -0
- package/dist/agents/templates.controller.js +37 -0
- package/dist/agents/templates.d.ts +83 -0
- package/dist/agents/templates.js +173 -0
- package/dist/catalog/admin-catalog.controller.d.ts +143 -0
- package/dist/catalog/admin-catalog.controller.js +245 -0
- package/dist/catalog/catalog.service.d.ts +430 -0
- package/dist/catalog/catalog.service.js +882 -0
- package/dist/catalog/claude/agents.d.ts +27 -0
- package/dist/catalog/claude/agents.js +270 -0
- package/dist/catalog/claude/commands.d.ts +50 -0
- package/dist/catalog/claude/commands.js +179 -0
- package/dist/catalog/claude/manifest.d.ts +69 -0
- package/dist/catalog/claude/manifest.js +134 -0
- package/dist/catalog/claude/marketplace.d.ts +35 -0
- package/dist/catalog/claude/marketplace.js +194 -0
- package/dist/catalog/claude/mcp.d.ts +33 -0
- package/dist/catalog/claude/mcp.js +226 -0
- package/dist/catalog/claude/report.d.ts +86 -0
- package/dist/catalog/claude/report.js +121 -0
- package/dist/catalog/claude/translate.d.ts +56 -0
- package/dist/catalog/claude/translate.js +857 -0
- package/dist/catalog/cli.d.ts +46 -0
- package/dist/catalog/cli.js +211 -0
- package/dist/catalog/git-source.d.ts +127 -0
- package/dist/catalog/git-source.js +520 -0
- package/dist/catalog/marketplace-fetch.d.ts +99 -0
- package/dist/catalog/marketplace-fetch.js +203 -0
- package/dist/catalog/marketplaces.controller.d.ts +97 -0
- package/dist/catalog/marketplaces.controller.js +197 -0
- package/dist/catalog/marketplaces.service.d.ts +340 -0
- package/dist/catalog/marketplaces.service.js +1217 -0
- package/dist/catalog/org-catalog.controller.d.ts +128 -0
- package/dist/catalog/org-catalog.controller.js +277 -0
- package/dist/catalog/org-catalog.service.d.ts +246 -0
- package/dist/catalog/org-catalog.service.js +625 -0
- package/dist/catalog/plugin-import.d.ts +436 -0
- package/dist/catalog/plugin-import.js +1069 -0
- package/dist/catalog/plugin-install.d.ts +447 -0
- package/dist/catalog/plugin-install.js +1333 -0
- package/dist/catalog/plugin-package.d.ts +143 -0
- package/dist/catalog/plugin-package.js +382 -0
- package/dist/catalog/plugin-upgrade.d.ts +222 -0
- package/dist/catalog/plugin-upgrade.js +1219 -0
- package/dist/catalog/requests.service.d.ts +162 -0
- package/dist/catalog/requests.service.js +504 -0
- package/dist/catalog/schema-path.d.ts +7 -0
- package/dist/catalog/schema-path.js +63 -0
- package/dist/catalog/upgrade-targets.d.ts +59 -0
- package/dist/catalog/upgrade-targets.js +90 -0
- package/dist/catalog/versions.d.ts +31 -0
- package/dist/catalog/versions.js +44 -0
- package/dist/channels/actions.d.ts +37 -0
- package/dist/channels/actions.js +121 -0
- package/dist/channels/cards.d.ts +44 -0
- package/dist/channels/cards.js +156 -0
- package/dist/channels/connections.controller.d.ts +59 -0
- package/dist/channels/connections.controller.js +115 -0
- package/dist/channels/connections.service.d.ts +187 -0
- package/dist/channels/connections.service.js +534 -0
- package/dist/channels/features.d.ts +12 -0
- package/dist/channels/features.js +22 -0
- package/dist/channels/inbound.d.ts +120 -0
- package/dist/channels/inbound.js +332 -0
- package/dist/channels/outbound.d.ts +140 -0
- package/dist/channels/outbound.js +1125 -0
- package/dist/channels/phrases.d.ts +100 -0
- package/dist/channels/phrases.js +81 -0
- package/dist/channels/supervisor.d.ts +182 -0
- package/dist/channels/supervisor.js +625 -0
- package/dist/channels/threads.d.ts +29 -0
- package/dist/channels/threads.js +104 -0
- package/dist/channels/webhook-url.d.ts +16 -0
- package/dist/channels/webhook-url.js +34 -0
- package/dist/channels/webhook.controller.d.ts +19 -0
- package/dist/channels/webhook.controller.js +72 -0
- package/dist/channels/webhook.d.ts +73 -0
- package/dist/channels/webhook.js +274 -0
- package/dist/config/docs.d.ts +9 -0
- package/dist/config/docs.js +85 -0
- package/dist/config/env.d.ts +6 -0
- package/dist/config/env.js +73 -0
- package/dist/config/fields.d.ts +42 -0
- package/dist/config/fields.js +214 -0
- package/dist/config/file-source.d.ts +3 -0
- package/dist/config/file-source.js +31 -0
- package/dist/config/load.d.ts +20 -0
- package/dist/config/load.js +98 -0
- package/dist/config/nacos-source.d.ts +31 -0
- package/dist/config/nacos-source.js +229 -0
- package/dist/config/schema.d.ts +223 -0
- package/dist/config/schema.js +1151 -0
- package/dist/config/sources.d.ts +18 -0
- package/dist/config/sources.js +59 -0
- package/dist/config/types.d.ts +9 -0
- package/dist/config/types.js +7 -0
- package/dist/conversations/artifacts.d.ts +52 -0
- package/dist/conversations/artifacts.js +137 -0
- package/dist/conversations/attachments.controller.d.ts +28 -0
- package/dist/conversations/attachments.controller.js +96 -0
- package/dist/conversations/attachments.service.d.ts +180 -0
- package/dist/conversations/attachments.service.js +578 -0
- package/dist/conversations/conversations.controller.d.ts +288 -0
- package/dist/conversations/conversations.controller.js +607 -0
- package/dist/conversations/conversations.service.d.ts +321 -0
- package/dist/conversations/conversations.service.js +754 -0
- package/dist/conversations/event-log.d.ts +122 -0
- package/dist/conversations/event-log.js +259 -0
- package/dist/conversations/events.d.ts +856 -0
- package/dist/conversations/events.js +639 -0
- package/dist/conversations/files.d.ts +92 -0
- package/dist/conversations/files.js +213 -0
- package/dist/conversations/outputs-read.d.ts +34 -0
- package/dist/conversations/outputs-read.js +37 -0
- package/dist/conversations/queue.d.ts +169 -0
- package/dist/conversations/queue.js +527 -0
- package/dist/conversations/sandbox-status.d.ts +21 -0
- package/dist/conversations/sandbox-status.js +24 -0
- package/dist/conversations/selection.d.ts +46 -0
- package/dist/conversations/selection.js +75 -0
- package/dist/conversations/titles.d.ts +93 -0
- package/dist/conversations/titles.js +422 -0
- package/dist/ctx/bus.d.ts +16 -0
- package/dist/ctx/bus.js +101 -0
- package/dist/ctx/create-ctx.d.ts +109 -0
- package/dist/ctx/create-ctx.js +592 -0
- package/dist/ctx/kv.d.ts +4 -0
- package/dist/ctx/kv.js +31 -0
- package/dist/ctx/lock.d.ts +4 -0
- package/dist/ctx/lock.js +39 -0
- package/dist/ctx/namespace.d.ts +6 -0
- package/dist/ctx/namespace.js +12 -0
- package/dist/ctx/queue.d.ts +25 -0
- package/dist/ctx/queue.js +150 -0
- package/dist/ctx/secrets.d.ts +45 -0
- package/dist/ctx/secrets.js +175 -0
- package/dist/db/kernel-schema.d.ts +1122 -0
- package/dist/db/kernel-schema.js +5 -0
- package/dist/db/migrator.d.ts +28 -0
- package/dist/db/migrator.js +140 -0
- package/dist/db/pool.d.ts +21 -0
- package/dist/db/pool.js +28 -0
- package/dist/db/sql-statements.d.ts +34 -0
- package/dist/db/sql-statements.js +168 -0
- package/dist/errors.d.ts +210 -0
- package/dist/errors.js +212 -0
- package/dist/evals/budget.d.ts +61 -0
- package/dist/evals/budget.js +181 -0
- package/dist/evals/diff.d.ts +55 -0
- package/dist/evals/diff.js +133 -0
- package/dist/evals/judge.d.ts +53 -0
- package/dist/evals/judge.js +149 -0
- package/dist/evals/plan.d.ts +47 -0
- package/dist/evals/plan.js +77 -0
- package/dist/evals/reconstruct.d.ts +137 -0
- package/dist/evals/reconstruct.js +322 -0
- package/dist/evals/recorded-tools.d.ts +54 -0
- package/dist/evals/recorded-tools.js +167 -0
- package/dist/evals/run-replay.d.ts +86 -0
- package/dist/evals/run-replay.js +502 -0
- package/dist/evals/runs.controller.d.ts +100 -0
- package/dist/evals/runs.controller.js +199 -0
- package/dist/evals/runs.service.d.ts +275 -0
- package/dist/evals/runs.service.js +836 -0
- package/dist/evals/sets.controller.d.ts +61 -0
- package/dist/evals/sets.controller.js +183 -0
- package/dist/evals/sets.service.d.ts +128 -0
- package/dist/evals/sets.service.js +558 -0
- package/dist/evals/snapshot.d.ts +76 -0
- package/dist/evals/snapshot.js +207 -0
- package/dist/evals/step-replay.d.ts +113 -0
- package/dist/evals/step-replay.js +181 -0
- package/dist/evals/trajectory.controller.d.ts +41 -0
- package/dist/evals/trajectory.controller.js +88 -0
- package/dist/evals/trajectory.d.ts +144 -0
- package/dist/evals/trajectory.js +338 -0
- package/dist/evals/trajectory.service.d.ts +108 -0
- package/dist/evals/trajectory.service.js +323 -0
- package/dist/evals/worker.d.ts +101 -0
- package/dist/evals/worker.js +789 -0
- package/dist/extensions/admin-ops.d.ts +105 -0
- package/dist/extensions/admin-ops.js +353 -0
- package/dist/extensions/admin-view.d.ts +79 -0
- package/dist/extensions/admin-view.js +327 -0
- package/dist/extensions/approvals.d.ts +119 -0
- package/dist/extensions/approvals.js +205 -0
- package/dist/extensions/blobs.d.ts +45 -0
- package/dist/extensions/blobs.js +160 -0
- package/dist/extensions/bootstrap.d.ts +149 -0
- package/dist/extensions/bootstrap.js +441 -0
- package/dist/extensions/cli.d.ts +61 -0
- package/dist/extensions/cli.js +165 -0
- package/dist/extensions/config-json-schema.d.ts +9 -0
- package/dist/extensions/config-json-schema.js +73 -0
- package/dist/extensions/deployment-config.d.ts +138 -0
- package/dist/extensions/deployment-config.js +394 -0
- package/dist/extensions/enabled.d.ts +31 -0
- package/dist/extensions/enabled.js +55 -0
- package/dist/extensions/hooks.d.ts +161 -0
- package/dist/extensions/hooks.js +425 -0
- package/dist/extensions/host.d.ts +577 -0
- package/dist/extensions/host.js +2071 -0
- package/dist/extensions/inflight.d.ts +69 -0
- package/dist/extensions/inflight.js +277 -0
- package/dist/extensions/installs.d.ts +166 -0
- package/dist/extensions/installs.js +253 -0
- package/dist/extensions/instance.d.ts +167 -0
- package/dist/extensions/instance.js +329 -0
- package/dist/extensions/ledger.d.ts +30 -0
- package/dist/extensions/ledger.js +50 -0
- package/dist/extensions/lifecycle.d.ts +80 -0
- package/dist/extensions/lifecycle.js +152 -0
- package/dist/extensions/migrate-lock.d.ts +51 -0
- package/dist/extensions/migrate-lock.js +100 -0
- package/dist/extensions/org-config.controller.d.ts +24 -0
- package/dist/extensions/org-config.controller.js +59 -0
- package/dist/extensions/org-config.d.ts +169 -0
- package/dist/extensions/org-config.js +520 -0
- package/dist/extensions/package.d.ts +115 -0
- package/dist/extensions/package.js +246 -0
- package/dist/extensions/permission-set.d.ts +117 -0
- package/dist/extensions/permission-set.js +184 -0
- package/dist/extensions/permission-view.d.ts +194 -0
- package/dist/extensions/permission-view.js +284 -0
- package/dist/extensions/registry.d.ts +24 -0
- package/dist/extensions/registry.js +56 -0
- package/dist/extensions/resolve.d.ts +12 -0
- package/dist/extensions/resolve.js +71 -0
- package/dist/extensions/sources.d.ts +69 -0
- package/dist/extensions/sources.js +120 -0
- package/dist/extensions/sync.d.ts +40 -0
- package/dist/extensions/sync.js +242 -0
- package/dist/files/previewers.controller.d.ts +46 -0
- package/dist/files/previewers.controller.js +105 -0
- package/dist/files/previewers.d.ts +100 -0
- package/dist/files/previewers.js +250 -0
- package/dist/http/api.module.d.ts +114 -0
- package/dist/http/api.module.js +448 -0
- package/dist/http/app.d.ts +77 -0
- package/dist/http/app.js +170 -0
- package/dist/http/error.filter.d.ts +21 -0
- package/dist/http/error.filter.js +85 -0
- package/dist/http/gateway.module.d.ts +15 -0
- package/dist/http/gateway.module.js +13 -0
- package/dist/http/health.controller.d.ts +26 -0
- package/dist/http/health.controller.js +79 -0
- package/dist/http/nest-logger.d.ts +20 -0
- package/dist/http/nest-logger.js +28 -0
- package/dist/http/plugin-dispatch.d.ts +68 -0
- package/dist/http/plugin-dispatch.js +200 -0
- package/dist/http/tokens.d.ts +131 -0
- package/dist/http/tokens.js +131 -0
- package/dist/http/zod.pipe.d.ts +8 -0
- package/dist/http/zod.pipe.js +14 -0
- package/dist/identity/accounts.d.ts +93 -0
- package/dist/identity/accounts.js +367 -0
- package/dist/identity/api-tokens.d.ts +73 -0
- package/dist/identity/api-tokens.js +197 -0
- package/dist/identity/audit.d.ts +23 -0
- package/dist/identity/audit.js +41 -0
- package/dist/identity/auth.controller.d.ts +40 -0
- package/dist/identity/auth.controller.js +130 -0
- package/dist/identity/auth.guard.d.ts +41 -0
- package/dist/identity/auth.guard.js +162 -0
- package/dist/identity/binding.d.ts +47 -0
- package/dist/identity/binding.js +84 -0
- package/dist/identity/cookies.d.ts +16 -0
- package/dist/identity/cookies.js +32 -0
- package/dist/identity/credential-check.d.ts +17 -0
- package/dist/identity/credential-check.js +24 -0
- package/dist/identity/enterprise-admin.d.ts +14 -0
- package/dist/identity/enterprise-admin.js +27 -0
- package/dist/identity/external.d.ts +106 -0
- package/dist/identity/external.js +337 -0
- package/dist/identity/hash.d.ts +2 -0
- package/dist/identity/hash.js +3 -0
- package/dist/identity/login.d.ts +6 -0
- package/dist/identity/login.js +20 -0
- package/dist/identity/me.controller.d.ts +61 -0
- package/dist/identity/me.controller.js +159 -0
- package/dist/identity/passwords.d.ts +6 -0
- package/dist/identity/passwords.js +37 -0
- package/dist/identity/principal.d.ts +56 -0
- package/dist/identity/principal.js +38 -0
- package/dist/identity/rate-limit.d.ts +55 -0
- package/dist/identity/rate-limit.js +121 -0
- package/dist/identity/sessions.d.ts +84 -0
- package/dist/identity/sessions.js +306 -0
- package/dist/identity/settings.d.ts +121 -0
- package/dist/identity/settings.js +248 -0
- package/dist/identity/sso.controller.d.ts +59 -0
- package/dist/identity/sso.controller.js +192 -0
- package/dist/identity/sso.d.ts +83 -0
- package/dist/identity/sso.js +202 -0
- package/dist/inbox/inbox.service.d.ts +43 -0
- package/dist/inbox/inbox.service.js +57 -0
- package/dist/index.d.ts +67 -0
- package/dist/index.js +65 -0
- package/dist/kernel.d.ts +256 -0
- package/dist/kernel.js +1326 -0
- package/dist/log.d.ts +48 -0
- package/dist/log.js +229 -0
- package/dist/models/prices.d.ts +53 -0
- package/dist/models/prices.js +121 -0
- package/dist/models/purposes.controller.d.ts +19 -0
- package/dist/models/purposes.controller.js +56 -0
- package/dist/models/purposes.d.ts +140 -0
- package/dist/models/purposes.js +267 -0
- package/dist/net/proxy.d.ts +44 -0
- package/dist/net/proxy.js +162 -0
- package/dist/net/public-address.d.ts +60 -0
- package/dist/net/public-address.js +271 -0
- package/dist/net/safe-fetch.d.ts +38 -0
- package/dist/net/safe-fetch.js +140 -0
- package/dist/orgs/directory-sync.controller.d.ts +14 -0
- package/dist/orgs/directory-sync.controller.js +40 -0
- package/dist/orgs/directory-sync.d.ts +166 -0
- package/dist/orgs/directory-sync.js +558 -0
- package/dist/orgs/invitations.controller.d.ts +58 -0
- package/dist/orgs/invitations.controller.js +137 -0
- package/dist/orgs/invitations.service.d.ts +80 -0
- package/dist/orgs/invitations.service.js +217 -0
- package/dist/orgs/members.service.d.ts +63 -0
- package/dist/orgs/members.service.js +234 -0
- package/dist/orgs/offboarding.d.ts +141 -0
- package/dist/orgs/offboarding.js +398 -0
- package/dist/orgs/org-lock.d.ts +32 -0
- package/dist/orgs/org-lock.js +46 -0
- package/dist/orgs/org.guard.d.ts +35 -0
- package/dist/orgs/org.guard.js +95 -0
- package/dist/orgs/orgs.controller.d.ts +78 -0
- package/dist/orgs/orgs.controller.js +192 -0
- package/dist/orgs/orgs.service.d.ts +61 -0
- package/dist/orgs/orgs.service.js +209 -0
- package/dist/orgs/roles.d.ts +13 -0
- package/dist/orgs/roles.js +58 -0
- package/dist/orgs/settings.controller.d.ts +20 -0
- package/dist/orgs/settings.controller.js +53 -0
- package/dist/orgs/settings.service.d.ts +120 -0
- package/dist/orgs/settings.service.js +178 -0
- package/dist/packages/npm.d.ts +50 -0
- package/dist/packages/npm.js +218 -0
- package/dist/packages/provenance.d.ts +47 -0
- package/dist/packages/provenance.js +147 -0
- package/dist/packages/tgz.d.ts +76 -0
- package/dist/packages/tgz.js +225 -0
- package/dist/runtime/abort.d.ts +32 -0
- package/dist/runtime/abort.js +71 -0
- package/dist/runtime/checkpointer.d.ts +32 -0
- package/dist/runtime/checkpointer.js +243 -0
- package/dist/runtime/context/build.d.ts +254 -0
- package/dist/runtime/context/build.js +693 -0
- package/dist/runtime/context/claude-tools.d.ts +11 -0
- package/dist/runtime/context/claude-tools.js +24 -0
- package/dist/runtime/context/compaction.d.ts +26 -0
- package/dist/runtime/context/compaction.js +195 -0
- package/dist/runtime/context/pairing.d.ts +11 -0
- package/dist/runtime/context/pairing.js +82 -0
- package/dist/runtime/context/reminders.d.ts +5 -0
- package/dist/runtime/context/reminders.js +11 -0
- package/dist/runtime/context/skills.d.ts +105 -0
- package/dist/runtime/context/skills.js +283 -0
- package/dist/runtime/context/tokens.d.ts +19 -0
- package/dist/runtime/context/tokens.js +104 -0
- package/dist/runtime/conversation-lock.d.ts +40 -0
- package/dist/runtime/conversation-lock.js +97 -0
- package/dist/runtime/hook-calls.d.ts +84 -0
- package/dist/runtime/hook-calls.js +136 -0
- package/dist/runtime/langgraph-loop.d.ts +52 -0
- package/dist/runtime/langgraph-loop.js +247 -0
- package/dist/runtime/loop.d.ts +93 -0
- package/dist/runtime/loop.js +7 -0
- package/dist/runtime/maintenance.d.ts +80 -0
- package/dist/runtime/maintenance.js +147 -0
- package/dist/runtime/media-cache.d.ts +21 -0
- package/dist/runtime/media-cache.js +51 -0
- package/dist/runtime/model-call.d.ts +176 -0
- package/dist/runtime/model-call.js +1049 -0
- package/dist/runtime/providers.d.ts +86 -0
- package/dist/runtime/providers.js +224 -0
- package/dist/runtime/quota.d.ts +29 -0
- package/dist/runtime/quota.js +70 -0
- package/dist/runtime/run-finish.d.ts +45 -0
- package/dist/runtime/run-finish.js +69 -0
- package/dist/runtime/run-queue.d.ts +121 -0
- package/dist/runtime/run-queue.js +493 -0
- package/dist/runtime/run-worker.d.ts +138 -0
- package/dist/runtime/run-worker.js +805 -0
- package/dist/runtime/stream.controller.d.ts +34 -0
- package/dist/runtime/stream.controller.js +122 -0
- package/dist/runtime/stream.d.ts +63 -0
- package/dist/runtime/stream.js +262 -0
- package/dist/runtime/subagents/child.d.ts +80 -0
- package/dist/runtime/subagents/child.js +225 -0
- package/dist/runtime/subagents/definition.d.ts +103 -0
- package/dist/runtime/subagents/definition.js +392 -0
- package/dist/runtime/subagents/dispatch.d.ts +69 -0
- package/dist/runtime/subagents/dispatch.js +502 -0
- package/dist/runtime/subagents/limits.d.ts +23 -0
- package/dist/runtime/subagents/limits.js +34 -0
- package/dist/runtime/subagents/org-agents.d.ts +50 -0
- package/dist/runtime/subagents/org-agents.js +70 -0
- package/dist/runtime/subagents/preamble.d.ts +7 -0
- package/dist/runtime/subagents/preamble.js +11 -0
- package/dist/runtime/subagents/progress.d.ts +26 -0
- package/dist/runtime/subagents/progress.js +36 -0
- package/dist/runtime/subagents/roster.d.ts +55 -0
- package/dist/runtime/subagents/roster.js +111 -0
- package/dist/runtime/subagents/skill-fork.d.ts +123 -0
- package/dist/runtime/subagents/skill-fork.js +259 -0
- package/dist/runtime/usage-report.d.ts +163 -0
- package/dist/runtime/usage-report.js +550 -0
- package/dist/runtime/waits.d.ts +233 -0
- package/dist/runtime/waits.js +883 -0
- package/dist/sandbox/leases.d.ts +169 -0
- package/dist/sandbox/leases.js +515 -0
- package/dist/sandbox/lifecycle.d.ts +21 -0
- package/dist/sandbox/lifecycle.js +68 -0
- package/dist/sandbox/sandbox.service.d.ts +249 -0
- package/dist/sandbox/sandbox.service.js +908 -0
- package/dist/skills/catalog.d.ts +149 -0
- package/dist/skills/catalog.js +405 -0
- package/dist/skills/changes.controller.d.ts +56 -0
- package/dist/skills/changes.controller.js +136 -0
- package/dist/skills/changes.service.d.ts +175 -0
- package/dist/skills/changes.service.js +805 -0
- package/dist/skills/invocable.controller.d.ts +23 -0
- package/dist/skills/invocable.controller.js +50 -0
- package/dist/skills/invocation-keys.d.ts +23 -0
- package/dist/skills/invocation-keys.js +44 -0
- package/dist/skills/invoke.d.ts +135 -0
- package/dist/skills/invoke.js +286 -0
- package/dist/skills/package.d.ts +87 -0
- package/dist/skills/package.js +227 -0
- package/dist/skills/skills.controller.d.ts +40 -0
- package/dist/skills/skills.controller.js +110 -0
- package/dist/skills/skills.service.d.ts +192 -0
- package/dist/skills/skills.service.js +567 -0
- package/dist/storage/prefix.d.ts +36 -0
- package/dist/storage/prefix.js +104 -0
- package/dist/storage/purge.d.ts +27 -0
- package/dist/storage/purge.js +75 -0
- package/dist/storage/storage.service.d.ts +44 -0
- package/dist/storage/storage.service.js +145 -0
- package/dist/text.d.ts +13 -0
- package/dist/text.js +13 -0
- package/dist/tools/approvals.controller.d.ts +53 -0
- package/dist/tools/approvals.controller.js +128 -0
- package/dist/tools/approvals.service.d.ts +172 -0
- package/dist/tools/approvals.service.js +568 -0
- package/dist/tools/breaker.d.ts +28 -0
- package/dist/tools/breaker.js +72 -0
- package/dist/tools/builtins/agent.d.ts +81 -0
- package/dist/tools/builtins/agent.js +223 -0
- package/dist/tools/builtins/ask-user.d.ts +28 -0
- package/dist/tools/builtins/ask-user.js +139 -0
- package/dist/tools/builtins/read-tool-output.d.ts +18 -0
- package/dist/tools/builtins/read-tool-output.js +108 -0
- package/dist/tools/builtins/sandbox/bash.d.ts +16 -0
- package/dist/tools/builtins/sandbox/bash.js +137 -0
- package/dist/tools/builtins/sandbox/common.d.ts +114 -0
- package/dist/tools/builtins/sandbox/common.js +304 -0
- package/dist/tools/builtins/sandbox/deliver.d.ts +5 -0
- package/dist/tools/builtins/sandbox/deliver.js +180 -0
- package/dist/tools/builtins/sandbox/edit.d.ts +4 -0
- package/dist/tools/builtins/sandbox/edit.js +98 -0
- package/dist/tools/builtins/sandbox/glob-match.d.ts +25 -0
- package/dist/tools/builtins/sandbox/glob-match.js +240 -0
- package/dist/tools/builtins/sandbox/glob.d.ts +4 -0
- package/dist/tools/builtins/sandbox/glob.js +104 -0
- package/dist/tools/builtins/sandbox/grep.d.ts +9 -0
- package/dist/tools/builtins/sandbox/grep.js +133 -0
- package/dist/tools/builtins/sandbox/index.d.ts +12 -0
- package/dist/tools/builtins/sandbox/index.js +27 -0
- package/dist/tools/builtins/sandbox/names.d.ts +7 -0
- package/dist/tools/builtins/sandbox/names.js +20 -0
- package/dist/tools/builtins/sandbox/read.d.ts +8 -0
- package/dist/tools/builtins/sandbox/read.js +121 -0
- package/dist/tools/builtins/sandbox/write.d.ts +4 -0
- package/dist/tools/builtins/sandbox/write.js +88 -0
- package/dist/tools/builtins/skill-load.d.ts +53 -0
- package/dist/tools/builtins/skill-load.js +446 -0
- package/dist/tools/builtins/skill-write.d.ts +59 -0
- package/dist/tools/builtins/skill-write.js +244 -0
- package/dist/tools/builtins/tool-search.d.ts +31 -0
- package/dist/tools/builtins/tool-search.js +171 -0
- package/dist/tools/connector-content.controller.d.ts +34 -0
- package/dist/tools/connector-content.controller.js +78 -0
- package/dist/tools/connector-content.d.ts +104 -0
- package/dist/tools/connector-content.js +267 -0
- package/dist/tools/connectors.controller.d.ts +210 -0
- package/dist/tools/connectors.controller.js +234 -0
- package/dist/tools/connectors.service.d.ts +303 -0
- package/dist/tools/connectors.service.js +1102 -0
- package/dist/tools/credentials.d.ts +139 -0
- package/dist/tools/credentials.js +351 -0
- package/dist/tools/drift.d.ts +141 -0
- package/dist/tools/drift.js +539 -0
- package/dist/tools/elicitation.d.ts +81 -0
- package/dist/tools/elicitation.js +266 -0
- package/dist/tools/endpoint.d.ts +18 -0
- package/dist/tools/endpoint.js +115 -0
- package/dist/tools/info.d.ts +67 -0
- package/dist/tools/info.js +113 -0
- package/dist/tools/naming.d.ts +27 -0
- package/dist/tools/naming.js +47 -0
- package/dist/tools/oauth/discovery.d.ts +65 -0
- package/dist/tools/oauth/discovery.js +307 -0
- package/dist/tools/oauth/flow.d.ts +63 -0
- package/dist/tools/oauth/flow.js +237 -0
- package/dist/tools/oauth/oauth.controller.d.ts +31 -0
- package/dist/tools/oauth/oauth.controller.js +95 -0
- package/dist/tools/oauth/tokens.d.ts +111 -0
- package/dist/tools/oauth/tokens.js +258 -0
- package/dist/tools/outputs.d.ts +61 -0
- package/dist/tools/outputs.js +156 -0
- package/dist/tools/pipeline.d.ts +322 -0
- package/dist/tools/pipeline.js +1236 -0
- package/dist/tools/policy.d.ts +60 -0
- package/dist/tools/policy.js +236 -0
- package/dist/tools/questions.controller.d.ts +24 -0
- package/dist/tools/questions.controller.js +58 -0
- package/dist/tools/questions.service.d.ts +103 -0
- package/dist/tools/questions.service.js +295 -0
- package/dist/tools/redact.d.ts +20 -0
- package/dist/tools/redact.js +60 -0
- package/dist/tools/registry.d.ts +246 -0
- package/dist/tools/registry.js +481 -0
- package/dist/tools/resources.d.ts +16 -0
- package/dist/tools/resources.js +76 -0
- package/dist/tools/specs.d.ts +14 -0
- package/dist/tools/specs.js +31 -0
- package/dist/tools/validate.d.ts +20 -0
- package/dist/tools/validate.js +183 -0
- package/dist/tools/view.d.ts +43 -0
- package/dist/tools/view.js +225 -0
- package/dist/ui/embed-token.d.ts +31 -0
- package/dist/ui/embed-token.js +132 -0
- package/dist/ui/registry.d.ts +58 -0
- package/dist/ui/registry.js +90 -0
- package/dist/ui/ui-stream.d.ts +37 -0
- package/dist/ui/ui-stream.js +162 -0
- package/dist/ui/views.controller.d.ts +81 -0
- package/dist/ui/views.controller.js +261 -0
- package/dist/ui/views.d.ts +155 -0
- package/dist/ui/views.js +306 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.js +6 -0
- package/package.json +67 -3
- package/src/migrations/0001_init.sql +8 -0
- package/src/migrations/0002_secrets.sql +8 -0
- package/src/migrations/0003_identity.sql +117 -0
- package/src/migrations/0004_plugin_org_config_nullable.sql +3 -0
- package/src/migrations/0005_agents.sql +27 -0
- package/src/migrations/0006_conversations.sql +37 -0
- package/src/migrations/0007_checkpoints.sql +26 -0
- package/src/migrations/0008_runs_trigger_seq.sql +3 -0
- package/src/migrations/0009_runs_active_unique.sql +4 -0
- package/src/migrations/0010_tools.sql +125 -0
- package/src/migrations/0011_approvals_spec.sql +10 -0
- package/src/migrations/0012_run_waits.sql +24 -0
- package/src/migrations/0013_app_tools_source.sql +4 -0
- package/src/migrations/0014_tool_specs.sql +8 -0
- package/src/migrations/0015_tool_drift.sql +20 -0
- package/src/migrations/0016_plugin_permissions.sql +11 -0
- package/src/migrations/0017_identity_sources.sql +6 -0
- package/src/migrations/0018_channels.sql +74 -0
- package/src/migrations/0019_identity_trust.sql +17 -0
- package/src/migrations/0020_channel_card_lookup.sql +10 -0
- package/src/migrations/0021_org_storage_purge.sql +9 -0
- package/src/migrations/0022_attachments.sql +29 -0
- package/src/migrations/0023_sandboxes.sql +37 -0
- package/src/migrations/0024_skills.sql +46 -0
- package/src/migrations/0025_skills_catalog_idx.sql +6 -0
- package/src/migrations/0026_skill_changes.sql +34 -0
- package/src/migrations/0027_model_prices.sql +18 -0
- package/src/migrations/0028_evals.sql +105 -0
- package/src/migrations/0029_model_purposes.sql +18 -0
- package/src/migrations/0030_plugin_installs.sql +73 -0
- package/src/migrations/0031_plugin_snapshot_source.sql +6 -0
- package/src/migrations/0032_plugin_deployment_configs.sql +10 -0
- package/src/migrations/0033_rename_apps_to_connectors.sql +25 -0
- package/src/migrations/0034_directory.sql +49 -0
- package/src/migrations/0035_catalogs.sql +40 -0
- package/src/migrations/0036_app_import_staging.sql +17 -0
- package/src/migrations/0037_directory_installs.sql +92 -0
- package/src/migrations/0038_channel_inbound_mode.sql +6 -0
- package/src/migrations/0039_channel_card_pending.sql +8 -0
- package/src/migrations/0040_usage_report_sweep.sql +10 -0
- package/src/migrations/0041_rename_plugins_to_extensions.sql +38 -0
- package/src/migrations/0042_rename_directory_to_catalog.sql +80 -0
- package/src/migrations/0043_rename_app_installs_to_plugin_installs.sql +20 -0
- package/src/migrations/0044_catalog_one_kind.sql +90 -0
- package/src/migrations/0045_plugin_dependencies.sql +9 -0
- package/src/migrations/0046_git_sources.sql +25 -0
- package/src/migrations/0047_marketplace_entry_heads.sql +7 -0
- package/src/migrations/0048_marketplace_entry_trees.sql +8 -0
- package/src/migrations/0049_plugin_upgrades.sql +37 -0
- package/src/migrations/0050_bootstrap.sql +53 -0
- package/src/migrations/0051_claude_compat.sql +26 -0
- package/src/migrations/0052_conversations_account_agent_idx.sql +5 -0
- package/src/migrations/0053_subagents.sql +73 -0
- package/src/migrations/0054_subagent_wait_expiry.sql +7 -0
- package/src/migrations/0055_subagent_parent_indexes.sql +10 -0
- package/src/migrations/0056_approval_reason.sql +3 -0
- package/src/migrations/0057_conversation_titles.sql +11 -0
- package/src/migrations/0058_conversation_selection.sql +4 -0
- package/src/migrations/0059_conversation_queue.sql +22 -0
- package/src/migrations/0060_file_previewers.sql +10 -0
- package/src/migrations/0061_queue_selection.sql +5 -0
- package/src/migrations/0062_queued_skill.sql +8 -0
|
@@ -0,0 +1,550 @@
|
|
|
1
|
+
import { DelayedError, Job, Queue, UnrecoverableError, Worker } from "bullmq";
|
|
2
|
+
import { sql } from "kysely";
|
|
3
|
+
import { enabledExtensionsQuery } from "../extensions/enabled.js";
|
|
4
|
+
import { deepFreeze, errMsg } from "../extensions/hooks.js";
|
|
5
|
+
import { bullConnection } from "./run-queue.js";
|
|
6
|
+
/** Queue of `usage.report` deliveries (no `:` in the name). */
|
|
7
|
+
export const USAGE_REPORT_QUEUE = "cap-kernel-usage-report";
|
|
8
|
+
/** One job per `usage` event (no `:`: conversation ids are UUIDs, seq is a number). */
|
|
9
|
+
export const usageReportJobId = (conversationId, seq) => `usage-${conversationId}-${seq}`;
|
|
10
|
+
/** First attempt plus 5 retries (F11). */
|
|
11
|
+
export const USAGE_REPORT_ATTEMPTS = 6;
|
|
12
|
+
/** Retry backoff: 2 s, doubling (2, 4, 8, 16, 32 s). */
|
|
13
|
+
export const USAGE_REPORT_BACKOFF_MS = 2000;
|
|
14
|
+
/** Failed jobs (given up) are kept for inspection, at most {@link KEEP_FAILED_MAX} of them. */
|
|
15
|
+
const KEEP_FAILED_S = 7 * 86_400;
|
|
16
|
+
/** Upper bound on kept failed jobs (I-2): a long outage of a billing endpoint cannot grow Redis. */
|
|
17
|
+
const KEEP_FAILED_MAX = 100_000;
|
|
18
|
+
/** Warnings about a plugin that cannot take deliveries are logged at most once per this window. */
|
|
19
|
+
const WARN_WINDOW_MS = 60_000;
|
|
20
|
+
/**
|
|
21
|
+
* Upper bound on kept finished jobs (Redis memory). At the default retention it only bites above
|
|
22
|
+
* ~1.1 usage events per second sustained for a day; dedupe needs the jobs only for the sweeper overlap.
|
|
23
|
+
*/
|
|
24
|
+
const KEEP_COMPLETED_MAX = 100_000;
|
|
25
|
+
/** Maintenance job of the sweeper (no `:`), its scheduler id and period. */
|
|
26
|
+
export const USAGE_SWEEP_JOB = "usage-report-sweep";
|
|
27
|
+
export const USAGE_SWEEP_SCHEDULER_ID = "usage-report-sweep-every";
|
|
28
|
+
export const USAGE_SWEEP_EVERY_MS = 60_000;
|
|
29
|
+
/** The sweep leaves the newest events to the fast path (and to transactions still committing). */
|
|
30
|
+
export const USAGE_SWEEP_LAG_MS = 30_000;
|
|
31
|
+
/**
|
|
32
|
+
* Each sweep re-scans this far behind the watermark: events whose transaction committed after a
|
|
33
|
+
* previous sweep passed their `created_at` are still found. Far inside the dedupe window
|
|
34
|
+
* (`hooks.usageReportKeepHours` ≥ 1 h), so re-enqueued events dedupe on the kept job.
|
|
35
|
+
*/
|
|
36
|
+
export const USAGE_SWEEP_OVERLAP_MS = 10 * 60_000;
|
|
37
|
+
const SWEEP_PAGE = 500;
|
|
38
|
+
const JOB = "usage-report";
|
|
39
|
+
/**
|
|
40
|
+
* Plugins that subscribe to `usage.report` according to deployment state: an approved permission
|
|
41
|
+
* snapshot that declares the `usage.report` hook, for a plugin the deployment still knows: an enabled
|
|
42
|
+
* install, or a config-declared plugin with a replica status row that is not `unloaded`. With `orgId`, only plugins
|
|
43
|
+
* the organization enabled (org config rows and required bootstrap plugins).
|
|
44
|
+
*/
|
|
45
|
+
export async function queryUsageSubscribers(db, orgId) {
|
|
46
|
+
let q = db
|
|
47
|
+
.selectFrom("extension_permission_snapshots as s")
|
|
48
|
+
.select("s.plugin")
|
|
49
|
+
.where(sql `s.permissions -> 'permissions' -> 'hooks' ? 'usage.report'`)
|
|
50
|
+
.where((eb) => eb.or([
|
|
51
|
+
eb.exists(eb
|
|
52
|
+
.selectFrom("extension_installs as i")
|
|
53
|
+
.select(sql `1`.as("one"))
|
|
54
|
+
.whereRef("i.name", "=", "s.plugin")
|
|
55
|
+
.where("i.desired_state", "=", "enabled")),
|
|
56
|
+
// config-declared plugins still declared (and not unloaded) on some replica; installs are
|
|
57
|
+
// covered by desired_state above (their replica rows linger as `unloaded` when disabled)
|
|
58
|
+
eb.exists(eb
|
|
59
|
+
.selectFrom("extension_replica_status as r")
|
|
60
|
+
.select(sql `1`.as("one"))
|
|
61
|
+
.whereRef("r.plugin", "=", "s.plugin")
|
|
62
|
+
.where("r.source", "=", "config")
|
|
63
|
+
.where("r.state", "<>", "unloaded")),
|
|
64
|
+
]));
|
|
65
|
+
if (orgId !== undefined) {
|
|
66
|
+
q = q.where("s.plugin", "in", enabledExtensionsQuery(db, orgId));
|
|
67
|
+
}
|
|
68
|
+
return new Set((await q.execute()).map((r) => r.plugin));
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Of `plugins`, those that are **definitely** unservable right now (I-2, N-3): live replicas report
|
|
72
|
+
* them (a `extension_replica_status` row with a heartbeat newer than `staleSeconds`), no live row is
|
|
73
|
+
* `loaded` or still serves an older version (`serving_version`, e.g. an upgrade pending approval), and
|
|
74
|
+
* the rows are not all `unloaded` (that is the state right after a re-enable, before the replicas
|
|
75
|
+
* reconcile). A plugin with no live row at all is unknown too (slow to load, or a host without a
|
|
76
|
+
* status store). Unknown plugins are never listed.
|
|
77
|
+
*/
|
|
78
|
+
export async function queryUnservable(db, plugins, staleSeconds) {
|
|
79
|
+
if (plugins.length === 0)
|
|
80
|
+
return new Set();
|
|
81
|
+
const rows = await db
|
|
82
|
+
.selectFrom("extension_replica_status")
|
|
83
|
+
.select("plugin")
|
|
84
|
+
.where("plugin", "in", [...plugins])
|
|
85
|
+
.where("heartbeat_at", ">", sql `now() - make_interval(secs => ${staleSeconds})`)
|
|
86
|
+
.groupBy("plugin")
|
|
87
|
+
.having(sql `bool_or(state = 'loaded' OR serving_version IS NOT NULL)`, "=", false)
|
|
88
|
+
.having(sql `bool_and(state = 'unloaded')`, "=", false)
|
|
89
|
+
.execute();
|
|
90
|
+
return new Set(rows.map((r) => r.plugin));
|
|
91
|
+
}
|
|
92
|
+
/** `" dropped: x (why), y (why)"`, or empty. */
|
|
93
|
+
const droppedNote = (dropped) => dropped.size === 0
|
|
94
|
+
? ""
|
|
95
|
+
: ` dropped: ${[...dropped].map(([p, why]) => `${p} (${why})`).join(", ")}`;
|
|
96
|
+
/** A target this replica cannot deliver to: not loaded here, or loaded without a handler. */
|
|
97
|
+
class Undeliverable extends Error {
|
|
98
|
+
plugin;
|
|
99
|
+
why;
|
|
100
|
+
constructor(plugin, why) {
|
|
101
|
+
super(why === "no_handler"
|
|
102
|
+
? `plugin ${plugin} is loaded on this replica but registered no usage.report handler`
|
|
103
|
+
: `plugin ${plugin} has no usage.report handler on this replica`);
|
|
104
|
+
this.plugin = plugin;
|
|
105
|
+
this.why = why;
|
|
106
|
+
this.name = "Undeliverable";
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* The next `pending` set (m-2 fence): plugins that failed now, narrowed to what the stored job data
|
|
111
|
+
* still lists. A plugin another (stalled-over) execution already delivered never comes back.
|
|
112
|
+
*/
|
|
113
|
+
export function narrowPending(stored, failed) {
|
|
114
|
+
return stored === undefined ? [...failed] : failed.filter((p) => stored.includes(p));
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Reliable `usage.report` delivery (F11, P-17, R13). Every `usage` event written to the event log (chat
|
|
118
|
+
* runs and full-run eval replays) is delivered at least once to every subscribing plugin.
|
|
119
|
+
* - **Fast path:** `model-call` enqueues job `usage-<conversationId>-<seq>` right after writing the event
|
|
120
|
+
* (never awaited; an enqueue failure only logs). Skipped without I/O when this replica has no
|
|
121
|
+
* `usage.report` handler (M-2); the sweeper then offers the event.
|
|
122
|
+
* - **Sweeper (R13):** a maintenance job (once across replicas, every minute) re-enqueues the `usage`
|
|
123
|
+
* events in `[watermark - 10 min, now - 30 s]` with the same job ids, so a lost fast-path enqueue is
|
|
124
|
+
* caught up and duplicates dedupe on the kept job (`hooks.usageReportKeepHours`).
|
|
125
|
+
* - **Worker** (worker role, `hooks.usageReportConcurrency` per replica): reads the payload from the log
|
|
126
|
+
* at execution time (the `usage` event, the conversation with `kind`, the run). On the first attempt
|
|
127
|
+
* the targets are the deployment's subscribers the organization enabled (I-2: not this replica's
|
|
128
|
+
* handlers), written into `pending`; plugins run concurrently (`allSettled`); failed ones stay in
|
|
129
|
+
* `pending` and are retried (5 retries, 2 s doubling). A plugin not loaded on this replica (or
|
|
130
|
+
* between generations) is a failure, so another replica or a later attempt delivers it. On the
|
|
131
|
+
* last attempt it is dropped only when it is definitely unservable ({@link queryUnservable});
|
|
132
|
+
* otherwise the job fails as usual. A plugin loaded here that registered no handler is dropped at
|
|
133
|
+
* once (I-2). A drop (N-3) is never silent: after delivering to the other targets the job ends
|
|
134
|
+
* failed with an `UnrecoverableError` whose failedReason names the dropped plugins, plus a
|
|
135
|
+
* throttled warning. Plugins the organization disabled by delivery time are dropped silently (not
|
|
136
|
+
* targets any more). The final failure logs an error (no audit); failed jobs are kept 7 days, at
|
|
137
|
+
* most 100 000. Each call runs through the instance's `inflight.run`, limited by `hooks.timeoutMs`;
|
|
138
|
+
* when this replica stops, in-flight calls are aborted and the job goes back to the queue without
|
|
139
|
+
* using up an attempt.
|
|
140
|
+
* Handlers must be idempotent by `eventId` (`<conversationId>/<seq>`). Nothing is written to the event
|
|
141
|
+
* log (never model-visible). Compaction calls log usage too (`purpose: "compaction"`) and are reported,
|
|
142
|
+
* as are conversation title calls (`purpose: "title"`, no run: `runId` is "").
|
|
143
|
+
* Single-step eval replays and judge requests log no usage: not reported (M7).
|
|
144
|
+
*/
|
|
145
|
+
export class UsageReporter {
|
|
146
|
+
d;
|
|
147
|
+
queue;
|
|
148
|
+
queueConn;
|
|
149
|
+
worker;
|
|
150
|
+
workerConn;
|
|
151
|
+
closed = false;
|
|
152
|
+
stopping = new AbortController();
|
|
153
|
+
constructor(d) {
|
|
154
|
+
this.d = d;
|
|
155
|
+
}
|
|
156
|
+
jobOpts(conversationId, seq) {
|
|
157
|
+
return {
|
|
158
|
+
jobId: usageReportJobId(conversationId, seq),
|
|
159
|
+
attempts: this.d.retry?.attempts ?? USAGE_REPORT_ATTEMPTS,
|
|
160
|
+
backoff: { type: "exponential", delay: this.d.retry?.backoffMs ?? USAGE_REPORT_BACKOFF_MS },
|
|
161
|
+
removeOnComplete: {
|
|
162
|
+
age: this.d.config().hooks.usageReportKeepHours * 3600,
|
|
163
|
+
count: KEEP_COMPLETED_MAX,
|
|
164
|
+
},
|
|
165
|
+
removeOnFail: { age: KEEP_FAILED_S, count: KEEP_FAILED_MAX },
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Enqueues the delivery of one `usage` event. Returns without a job when no plugin subscribes.
|
|
170
|
+
* Never throws: an enqueue failure (e.g. a Redis hiccup) only logs a warning; the sweeper catches up.
|
|
171
|
+
*/
|
|
172
|
+
async enqueue(conversationId, seq) {
|
|
173
|
+
if (this.closed)
|
|
174
|
+
return;
|
|
175
|
+
// M-2: no usage.report handler on this replica → no I/O at all. A plugin loaded only on other
|
|
176
|
+
// replicas still gets the event: the sweeper re-offers it within about a minute and a half.
|
|
177
|
+
if (!this.d.hooks.has("usage.report"))
|
|
178
|
+
return;
|
|
179
|
+
try {
|
|
180
|
+
if ((await this.d.subscribers()).size === 0)
|
|
181
|
+
return;
|
|
182
|
+
await this.getQueue().add(JOB, { conversationId, seq }, this.jobOpts(conversationId, seq));
|
|
183
|
+
}
|
|
184
|
+
catch (err) {
|
|
185
|
+
this.d.log.warn("cannot enqueue usage report", { conversationId, seq, err });
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* One sweep (R13): re-enqueues the `usage` events created in `[watermark - overlap, now - lag]` in
|
|
190
|
+
* pages, then advances the watermark to `now - lag`. With no subscriber it only advances. The first
|
|
191
|
+
* sweep starts at `now - lag - overlap`. Returns the number of events offered to the queue.
|
|
192
|
+
*/
|
|
193
|
+
async sweep(opts = {}) {
|
|
194
|
+
// bounds and keyset as full-precision timestamp text (microseconds), computed with the DB clock
|
|
195
|
+
// unless a test fixes "now" (m-a, m-c)
|
|
196
|
+
const to = opts.now !== undefined
|
|
197
|
+
? new Date(opts.now - USAGE_SWEEP_LAG_MS).toISOString()
|
|
198
|
+
: (await sql `SELECT (now() - make_interval(secs => ${USAGE_SWEEP_LAG_MS / 1000}))::text AS to`.execute(this.d.db)).rows[0]?.to;
|
|
199
|
+
if (to === undefined)
|
|
200
|
+
return 0;
|
|
201
|
+
const row = await this.d.db
|
|
202
|
+
.selectFrom("usage_report_sweep")
|
|
203
|
+
.select(sql `watermark::text`.as("watermark"))
|
|
204
|
+
.where("id", "=", 1)
|
|
205
|
+
.executeTakeFirst();
|
|
206
|
+
const watermark = row?.watermark ?? to;
|
|
207
|
+
let offered = 0;
|
|
208
|
+
if ((await this.d.subscribers()).size > 0) {
|
|
209
|
+
let after;
|
|
210
|
+
for (;;) {
|
|
211
|
+
let q = this.d.db
|
|
212
|
+
.selectFrom("conversation_events")
|
|
213
|
+
.select(["conversation_id", "seq", sql `created_at::text`.as("at")])
|
|
214
|
+
.where("type", "=", "usage")
|
|
215
|
+
.where(sql `created_at >= ${watermark}::timestamptz - make_interval(secs => ${USAGE_SWEEP_OVERLAP_MS / 1000})`)
|
|
216
|
+
.where(sql `created_at <= ${to}::timestamptz`);
|
|
217
|
+
if (after) {
|
|
218
|
+
q = q.where(sql `(created_at, conversation_id, seq) > (${after.at}::timestamptz, ${after.conv}, ${after.seq}::bigint)`);
|
|
219
|
+
}
|
|
220
|
+
const page = await q
|
|
221
|
+
.orderBy("created_at")
|
|
222
|
+
.orderBy("conversation_id")
|
|
223
|
+
.orderBy("seq")
|
|
224
|
+
.limit(SWEEP_PAGE)
|
|
225
|
+
.execute();
|
|
226
|
+
if (page.length > 0) {
|
|
227
|
+
await this.getQueue().addBulk(page.map((r) => ({
|
|
228
|
+
name: JOB,
|
|
229
|
+
data: { conversationId: r.conversation_id, seq: Number(r.seq) },
|
|
230
|
+
opts: this.jobOpts(r.conversation_id, Number(r.seq)),
|
|
231
|
+
})));
|
|
232
|
+
offered += page.length;
|
|
233
|
+
}
|
|
234
|
+
const last = page.at(-1);
|
|
235
|
+
if (!last || page.length < SWEEP_PAGE)
|
|
236
|
+
break;
|
|
237
|
+
after = { at: last.at, conv: last.conversation_id, seq: String(last.seq) };
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
await this.d.db
|
|
241
|
+
.insertInto("usage_report_sweep")
|
|
242
|
+
.values({ id: 1, watermark: sql `${to}::timestamptz` })
|
|
243
|
+
.onConflict((oc) => oc.column("id").doUpdateSet({
|
|
244
|
+
watermark: sql `GREATEST(usage_report_sweep.watermark, excluded.watermark)`,
|
|
245
|
+
updated_at: sql `now()`,
|
|
246
|
+
}))
|
|
247
|
+
.execute();
|
|
248
|
+
return offered;
|
|
249
|
+
}
|
|
250
|
+
/** Starts the worker (worker role only). Job lock and stalled detection follow the run queue. */
|
|
251
|
+
startWorker() {
|
|
252
|
+
if (this.worker || this.closed)
|
|
253
|
+
return;
|
|
254
|
+
const { jobLockMs, stalledIntervalMs } = this.d.config().runtime;
|
|
255
|
+
// the queue exists before any job runs: in-flight jobs fence and requeue through it, even on a
|
|
256
|
+
// replica that never enqueued (m-b)
|
|
257
|
+
this.getQueue();
|
|
258
|
+
this.workerConn = bullConnection(this.d.redisUrl, this.d.log);
|
|
259
|
+
this.worker = new Worker(USAGE_REPORT_QUEUE, (j, t) => this.process(j, t), {
|
|
260
|
+
connection: this.workerConn,
|
|
261
|
+
concurrency: this.d.config().hooks.usageReportConcurrency,
|
|
262
|
+
lockDuration: jobLockMs,
|
|
263
|
+
stalledInterval: stalledIntervalMs,
|
|
264
|
+
maxStalledCount: 3,
|
|
265
|
+
});
|
|
266
|
+
this.worker.on("error", (err) => this.d.log.error("usage report worker error", { err }));
|
|
267
|
+
this.worker.on("failed", (j, err) => {
|
|
268
|
+
if (!j || err instanceof DelayedError || err.name === "DelayedError")
|
|
269
|
+
return;
|
|
270
|
+
// a definite drop (N-3) was already warned about (throttled); the failed job is the trace
|
|
271
|
+
if (err instanceof UnrecoverableError || err.name === "UnrecoverableError")
|
|
272
|
+
return;
|
|
273
|
+
const final = j.attemptsMade >= (j.opts.attempts ?? 1);
|
|
274
|
+
const fields = {
|
|
275
|
+
jobId: j.id,
|
|
276
|
+
conversationId: j.data.conversationId,
|
|
277
|
+
seq: j.data.seq,
|
|
278
|
+
pending: j.data.pending,
|
|
279
|
+
attempt: j.attemptsMade,
|
|
280
|
+
error: err.message,
|
|
281
|
+
};
|
|
282
|
+
if (final)
|
|
283
|
+
this.d.log.error("usage report given up after retries", fields);
|
|
284
|
+
else
|
|
285
|
+
this.d.log.warn("usage report attempt failed; retrying", fields);
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
/** Stops the worker (in-flight calls are aborted, their jobs requeued) and the queue. */
|
|
289
|
+
async stop() {
|
|
290
|
+
this.closed = true;
|
|
291
|
+
this.stopping.abort();
|
|
292
|
+
const w = this.worker;
|
|
293
|
+
this.worker = undefined;
|
|
294
|
+
// the worker first: its in-flight jobs still use the queue to fence and requeue
|
|
295
|
+
await w?.close().catch(() => { });
|
|
296
|
+
const q = this.queue;
|
|
297
|
+
this.queue = undefined;
|
|
298
|
+
await q?.close().catch(() => { });
|
|
299
|
+
for (const c of [this.workerConn, this.queueConn]) {
|
|
300
|
+
if (c)
|
|
301
|
+
await c.quit().catch(() => c.disconnect());
|
|
302
|
+
}
|
|
303
|
+
this.workerConn = undefined;
|
|
304
|
+
this.queueConn = undefined;
|
|
305
|
+
}
|
|
306
|
+
getQueue() {
|
|
307
|
+
if (!this.queue) {
|
|
308
|
+
if (this.closed)
|
|
309
|
+
throw new Error("usage report queue is closed");
|
|
310
|
+
this.queueConn = bullConnection(this.d.redisUrl, this.d.log);
|
|
311
|
+
this.queue = new Queue(USAGE_REPORT_QUEUE, { connection: this.queueConn });
|
|
312
|
+
this.queue.on("error", (err) => this.d.log.error("usage report queue error", { err }));
|
|
313
|
+
}
|
|
314
|
+
return this.queue;
|
|
315
|
+
}
|
|
316
|
+
/** The payload of one usage event, read from the log; null when the event no longer exists. */
|
|
317
|
+
async payloadOf(conversationId, seq) {
|
|
318
|
+
const row = await this.d.db
|
|
319
|
+
.selectFrom("conversation_events as e")
|
|
320
|
+
.innerJoin("conversations as c", "c.id", "e.conversation_id")
|
|
321
|
+
.leftJoin("runs as r", "r.id", "e.run_id")
|
|
322
|
+
// a sub-agent's run: its dispatch says where it was dispatched from (spec §11)
|
|
323
|
+
.leftJoin("subagent_dispatches as sd", "sd.child_run_id", "e.run_id")
|
|
324
|
+
.select([
|
|
325
|
+
"e.payload",
|
|
326
|
+
"e.run_id",
|
|
327
|
+
"e.created_at",
|
|
328
|
+
"e.type",
|
|
329
|
+
"c.org_id",
|
|
330
|
+
"c.agent_id",
|
|
331
|
+
"c.account_id",
|
|
332
|
+
"c.kind",
|
|
333
|
+
"r.trigger_account_id",
|
|
334
|
+
"sd.parent_conversation_id",
|
|
335
|
+
"sd.parent_run_id",
|
|
336
|
+
"sd.parent_call_id",
|
|
337
|
+
])
|
|
338
|
+
.where("e.conversation_id", "=", conversationId)
|
|
339
|
+
.where("e.seq", "=", String(seq))
|
|
340
|
+
.executeTakeFirst();
|
|
341
|
+
if (row?.type !== "usage")
|
|
342
|
+
return null;
|
|
343
|
+
const p = row.payload;
|
|
344
|
+
return {
|
|
345
|
+
eventId: `${conversationId}/${seq}`,
|
|
346
|
+
purpose: p.purpose ?? "step",
|
|
347
|
+
orgId: row.org_id,
|
|
348
|
+
accountId: row.trigger_account_id ?? row.account_id,
|
|
349
|
+
agentId: row.agent_id,
|
|
350
|
+
conversationId,
|
|
351
|
+
// a sub-agent's calls report "chat" (spec §11: the SDK union is not widened)
|
|
352
|
+
conversationKind: row.kind === "eval" ? "eval" : "chat",
|
|
353
|
+
runId: row.run_id ?? "",
|
|
354
|
+
...(row.parent_conversation_id !== null &&
|
|
355
|
+
row.parent_run_id !== null &&
|
|
356
|
+
row.parent_call_id !== null && {
|
|
357
|
+
parent: {
|
|
358
|
+
conversationId: row.parent_conversation_id,
|
|
359
|
+
runId: row.parent_run_id,
|
|
360
|
+
callId: row.parent_call_id,
|
|
361
|
+
},
|
|
362
|
+
}),
|
|
363
|
+
provider: p.provider,
|
|
364
|
+
model: p.model,
|
|
365
|
+
usage: {
|
|
366
|
+
inputTokens: p.inputTokens,
|
|
367
|
+
outputTokens: p.outputTokens,
|
|
368
|
+
cacheReadTokens: p.cacheReadTokens,
|
|
369
|
+
cacheWriteTokens: p.cacheWriteTokens,
|
|
370
|
+
},
|
|
371
|
+
occurredAt: new Date(row.created_at).toISOString(),
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Writes the next `pending` set and the accumulated drops, fenced against a concurrent
|
|
376
|
+
* (stalled-over) execution (m-2 fence): only plugins the stored data still lists as pending or
|
|
377
|
+
* dropped can stay, so a plugin another execution delivered never comes back.
|
|
378
|
+
*/
|
|
379
|
+
async writePending(j, next, dropped) {
|
|
380
|
+
const fresh = j.id === undefined ? undefined : await Job.fromId(this.getQueue(), j.id);
|
|
381
|
+
const data = fresh?.data;
|
|
382
|
+
const stored = data?.pending ?? j.data.pending;
|
|
383
|
+
const storedDropped = data?.dropped ?? j.data.dropped ?? {};
|
|
384
|
+
const allowed = stored === undefined ? undefined : [...stored, ...Object.keys(storedDropped)];
|
|
385
|
+
const keep = [...dropped].filter(([p]) => allowed === undefined || allowed.includes(p));
|
|
386
|
+
const out = {
|
|
387
|
+
conversationId: j.data.conversationId,
|
|
388
|
+
seq: j.data.seq,
|
|
389
|
+
pending: narrowPending(allowed, next),
|
|
390
|
+
...(keep.length > 0 && { dropped: Object.fromEntries(keep) }),
|
|
391
|
+
};
|
|
392
|
+
await j.updateData(out);
|
|
393
|
+
j.data = out;
|
|
394
|
+
}
|
|
395
|
+
async process(j, token) {
|
|
396
|
+
const { conversationId, seq } = j.data;
|
|
397
|
+
const payload = await this.payloadOf(conversationId, seq);
|
|
398
|
+
if (payload === null)
|
|
399
|
+
return; // conversation deleted meanwhile: nothing to report
|
|
400
|
+
const subscribers = await this.d.subscribers(payload.orgId);
|
|
401
|
+
if (j.data.pending === undefined) {
|
|
402
|
+
// first attempt: the targets come from deployment state, recorded so later attempts (on any
|
|
403
|
+
// replica) deliver exactly the plugins that have not succeeded yet
|
|
404
|
+
const targets = [...subscribers];
|
|
405
|
+
await j.updateData({ conversationId, seq, pending: targets });
|
|
406
|
+
j.data.pending = targets;
|
|
407
|
+
}
|
|
408
|
+
// plugins the organization disabled meanwhile are dropped (not a failure)
|
|
409
|
+
const targets = (j.data.pending ?? []).filter((p) => subscribers.has(p));
|
|
410
|
+
if (targets.length === 0)
|
|
411
|
+
return;
|
|
412
|
+
const byPlugin = new Map();
|
|
413
|
+
for (const h of this.d.hooks.handlers("usage.report")) {
|
|
414
|
+
byPlugin.set(h.plugin, [...(byPlugin.get(h.plugin) ?? []), h.handler]);
|
|
415
|
+
}
|
|
416
|
+
const frozen = deepFreeze(structuredClone(payload));
|
|
417
|
+
const timeoutMs = this.d.config().hooks.timeoutMs;
|
|
418
|
+
const results = await Promise.allSettled(targets.map(async (plugin) => {
|
|
419
|
+
const handlers = byPlugin.get(plugin);
|
|
420
|
+
if (!handlers || handlers.length === 0) {
|
|
421
|
+
throw new Undeliverable(plugin, this.d.isActive?.(plugin) ? "no_handler" : "not_loaded");
|
|
422
|
+
}
|
|
423
|
+
for (const h of handlers)
|
|
424
|
+
await this.call(h, frozen, timeoutMs);
|
|
425
|
+
}));
|
|
426
|
+
const failed = [];
|
|
427
|
+
const notHere = [];
|
|
428
|
+
/** Definite drops (N-3): plugin → why; they end the job as failed, with no further retries. */
|
|
429
|
+
const dropped = new Map();
|
|
430
|
+
results.forEach((r, i) => {
|
|
431
|
+
if (r.status === "fulfilled")
|
|
432
|
+
return;
|
|
433
|
+
const plugin = targets[i];
|
|
434
|
+
if (r.reason instanceof Undeliverable) {
|
|
435
|
+
// I-2: loaded here without a handler: not a subscriber (declared but never registered, or
|
|
436
|
+
// a downgrade); dropped, not retried
|
|
437
|
+
if (r.reason.why === "no_handler")
|
|
438
|
+
dropped.set(plugin, "registered no usage.report handler");
|
|
439
|
+
else
|
|
440
|
+
notHere.push(plugin);
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
failed.push(plugin);
|
|
444
|
+
if (!this.stopping.signal.aborted) {
|
|
445
|
+
this.d.log.warn("usage.report delivery to a plugin failed", {
|
|
446
|
+
plugin,
|
|
447
|
+
eventId: payload.eventId,
|
|
448
|
+
error: errMsg(r.reason),
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
// not loaded here: another replica or a later attempt may serve it (retry). On the last attempt a
|
|
453
|
+
// target is dropped only when it is definitely unservable; unknown ones fail the job as before.
|
|
454
|
+
const final = j.attemptsMade + 1 >= (j.opts.attempts ?? 1);
|
|
455
|
+
const gone = final && notHere.length > 0 && !this.stopping.signal.aborted
|
|
456
|
+
? await this.unservable(notHere)
|
|
457
|
+
: new Set();
|
|
458
|
+
for (const plugin of notHere) {
|
|
459
|
+
if (gone.has(plugin))
|
|
460
|
+
dropped.set(plugin, "no replica has it loaded");
|
|
461
|
+
else
|
|
462
|
+
failed.push(plugin);
|
|
463
|
+
}
|
|
464
|
+
// m-2: drops accumulate across attempts (minus plugins delivered now), so a drop on an attempt
|
|
465
|
+
// that also had a transient failure still fails the job once the rest succeeds
|
|
466
|
+
const delivered = new Set(targets.filter((_, i) => results[i]?.status === "fulfilled"));
|
|
467
|
+
const allDropped = new Map(
|
|
468
|
+
// (a plugin the organization disabled meanwhile is no target any more: not traced)
|
|
469
|
+
Object.entries(j.data.dropped ?? {}).filter(([p]) => !delivered.has(p) && subscribers.has(p)));
|
|
470
|
+
for (const [p, why] of dropped)
|
|
471
|
+
allDropped.set(p, why);
|
|
472
|
+
if (failed.length > 0) {
|
|
473
|
+
await this.writePending(j, failed, allDropped);
|
|
474
|
+
if (this.stopping.signal.aborted) {
|
|
475
|
+
// shutdown is not the plugin's fault: back to the queue without using up an attempt (m-3)
|
|
476
|
+
await j.moveToDelayed(Date.now(), token);
|
|
477
|
+
throw new DelayedError();
|
|
478
|
+
}
|
|
479
|
+
throw new Error(`usage.report failed for: ${failed.join(", ")}${droppedNote(dropped)}`);
|
|
480
|
+
}
|
|
481
|
+
// m-1: pending = the dropped plugins only, so a manual retry reaches them and never the
|
|
482
|
+
// plugins already served
|
|
483
|
+
await this.writePending(j, [...allDropped.keys()], allDropped);
|
|
484
|
+
const traced = new Map([...allDropped].filter(([p]) => j.data.dropped?.[p] !== undefined));
|
|
485
|
+
if (traced.size === 0)
|
|
486
|
+
return;
|
|
487
|
+
// N-3: a definite drop leaves a durable trace: the job ends failed (kept under the failed-job
|
|
488
|
+
// cap, visible in queue tooling) with the dropped plugins in failedReason; no more retries
|
|
489
|
+
for (const [plugin, reason] of dropped) {
|
|
490
|
+
void this.warnOnce(plugin, "dropped", "usage.report target dropped", {
|
|
491
|
+
plugin,
|
|
492
|
+
eventId: payload.eventId,
|
|
493
|
+
reason,
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
throw new UnrecoverableError(`usage.report delivered to the rest;${droppedNote(traced)}`);
|
|
497
|
+
}
|
|
498
|
+
/** {@link UsageReporterDeps.unservable}; a lookup failure counts as "unknown" (keep retrying). */
|
|
499
|
+
async unservable(plugins) {
|
|
500
|
+
if (!this.d.unservable)
|
|
501
|
+
return new Set();
|
|
502
|
+
try {
|
|
503
|
+
return await this.d.unservable(plugins);
|
|
504
|
+
}
|
|
505
|
+
catch (err) {
|
|
506
|
+
this.d.log.warn("cannot read plugin replica status for usage.report", { err });
|
|
507
|
+
return new Set();
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
/** Logs a warning at most once per plugin and kind per minute (Redis key with a TTL). */
|
|
511
|
+
async warnOnce(plugin, kind, msg, fields) {
|
|
512
|
+
let first = true;
|
|
513
|
+
try {
|
|
514
|
+
this.getQueue();
|
|
515
|
+
const key = `capk:usage-warn:${plugin}:${kind}`;
|
|
516
|
+
first = (await this.queueConn?.set(key, "1", "PX", WARN_WINDOW_MS, "NX")) !== null;
|
|
517
|
+
}
|
|
518
|
+
catch {
|
|
519
|
+
// Redis unavailable: log anyway rather than hiding it
|
|
520
|
+
}
|
|
521
|
+
if (first)
|
|
522
|
+
this.d.log.warn(msg, fields);
|
|
523
|
+
}
|
|
524
|
+
/** One handler call with its own signal (timeout or replica stop aborts it); rejects on either. */
|
|
525
|
+
async call(h, payload, timeoutMs) {
|
|
526
|
+
const ac = new AbortController();
|
|
527
|
+
const onStop = () => ac.abort(new Error("replica stopping"));
|
|
528
|
+
if (this.stopping.signal.aborted)
|
|
529
|
+
onStop();
|
|
530
|
+
else
|
|
531
|
+
this.stopping.signal.addEventListener("abort", onStop, { once: true });
|
|
532
|
+
let timer;
|
|
533
|
+
try {
|
|
534
|
+
await Promise.race([
|
|
535
|
+
Promise.resolve().then(() => h(payload, ac.signal)),
|
|
536
|
+
new Promise((_, reject) => {
|
|
537
|
+
timer = setTimeout(() => {
|
|
538
|
+
ac.abort(new Error(`timed out after ${timeoutMs} ms`));
|
|
539
|
+
reject(new Error(`timed out after ${timeoutMs} ms`));
|
|
540
|
+
}, timeoutMs);
|
|
541
|
+
ac.signal.addEventListener("abort", () => reject(ac.signal.reason), { once: true });
|
|
542
|
+
}),
|
|
543
|
+
]);
|
|
544
|
+
}
|
|
545
|
+
finally {
|
|
546
|
+
clearTimeout(timer);
|
|
547
|
+
this.stopping.signal.removeEventListener("abort", onStop);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}
|