@capybara-hq/kernel 0.0.0-stage → 0.1.0-rc.1
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 +26 -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 +1126 -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 +237 -0
- package/dist/config/schema.js +1192 -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 +423 -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 +151 -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 +211 -0
- package/dist/errors.js +213 -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 +790 -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 +176 -0
- package/dist/extensions/bootstrap.js +535 -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 +220 -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 +69 -0
- package/dist/index.js +67 -0
- package/dist/kernel.d.ts +259 -0
- package/dist/kernel.js +1326 -0
- package/dist/log-config.d.ts +9 -0
- package/dist/log-config.js +27 -0
- package/dist/log-context.d.ts +32 -0
- package/dist/log-context.js +40 -0
- package/dist/log-loki.d.ts +34 -0
- package/dist/log-loki.js +145 -0
- package/dist/log.d.ts +79 -0
- package/dist/log.js +303 -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 +272 -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 +148 -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 +806 -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 +551 -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 +116 -0
- package/dist/tools/builtins/sandbox/common.js +306 -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 +69 -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,836 @@
|
|
|
1
|
+
import { Queue } from "bullmq";
|
|
2
|
+
import { sql } from "kysely";
|
|
3
|
+
import { paramIssues } from "../agents/agents.service.js";
|
|
4
|
+
import { normalizeStoredDefinition, } from "../agents/definition.js";
|
|
5
|
+
import { effectiveDefinition, NO_SELECTION, selectionAt, } from "../conversations/selection.js";
|
|
6
|
+
import { ApiError } from "../errors.js";
|
|
7
|
+
import { audit } from "../identity/audit.js";
|
|
8
|
+
import { costOf, priceKey } from "../models/prices.js";
|
|
9
|
+
import { lockOrgAndAuthorize } from "../orgs/org-lock.js";
|
|
10
|
+
import { ProviderListError } from "../runtime/providers.js";
|
|
11
|
+
import { bullConnection } from "../runtime/run-queue.js";
|
|
12
|
+
import { ACTIVE_EVAL_STATUSES, recountCases, skipPendingJudges, usageTokens } from "./budget.js";
|
|
13
|
+
import { judgeOverheadTokens } from "./judge.js";
|
|
14
|
+
import { candidateModel } from "./step-replay.js";
|
|
15
|
+
/** 评测队列的 BullMQ 队列名(不含 `:`,C7)。 */
|
|
16
|
+
export const EVAL_QUEUE_NAME = "cap-kernel-evals";
|
|
17
|
+
/** 每个用例一个任务(C7;不含 `:`)。 */
|
|
18
|
+
export const evalJobId = (runId, caseId) => `eval-${runId}-${caseId}`;
|
|
19
|
+
/** 评测队列(生产方):懒建连接;`close()` 关闭。 */
|
|
20
|
+
export class EvalQueue {
|
|
21
|
+
redisUrl;
|
|
22
|
+
log;
|
|
23
|
+
queue;
|
|
24
|
+
conn;
|
|
25
|
+
closed = false;
|
|
26
|
+
constructor(redisUrl, log) {
|
|
27
|
+
this.redisUrl = redisUrl;
|
|
28
|
+
this.log = log;
|
|
29
|
+
}
|
|
30
|
+
get() {
|
|
31
|
+
if (this.closed)
|
|
32
|
+
throw new Error("eval queue is closed");
|
|
33
|
+
if (!this.queue) {
|
|
34
|
+
this.conn = bullConnection(this.redisUrl, this.log);
|
|
35
|
+
this.queue = new Queue(EVAL_QUEUE_NAME, { connection: this.conn });
|
|
36
|
+
this.queue.on("error", (err) => this.log.error("eval queue error", { err }));
|
|
37
|
+
}
|
|
38
|
+
return this.queue;
|
|
39
|
+
}
|
|
40
|
+
async enqueue(jobs) {
|
|
41
|
+
await this.get().addBulk(jobs.map((data) => ({
|
|
42
|
+
name: "case",
|
|
43
|
+
data,
|
|
44
|
+
opts: {
|
|
45
|
+
jobId: evalJobId(data.runId, data.caseId),
|
|
46
|
+
// 处理函数外的暂时故障(PG / Redis):指数退避重试,不让整个用例一次失败。
|
|
47
|
+
// 结果按认领号写入,重做不会重复写结果
|
|
48
|
+
attempts: 3,
|
|
49
|
+
backoff: { type: "exponential", delay: 1000 },
|
|
50
|
+
removeOnComplete: true,
|
|
51
|
+
removeOnFail: 1000,
|
|
52
|
+
},
|
|
53
|
+
})));
|
|
54
|
+
}
|
|
55
|
+
async close() {
|
|
56
|
+
this.closed = true;
|
|
57
|
+
await this.queue?.close().catch(() => { });
|
|
58
|
+
this.conn?.disconnect();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
62
|
+
const setNotFound = () => new ApiError("eval.set_not_found", "Eval set not found");
|
|
63
|
+
const runNotFound = () => new ApiError("eval.run_not_found", "Eval run not found");
|
|
64
|
+
const candidateInvalid = (message, details) => new ApiError("eval.candidate_invalid", message, details);
|
|
65
|
+
/** 预建结果时每条 INSERT 的行数。 */
|
|
66
|
+
const INSERT_CHUNK = 500;
|
|
67
|
+
/**
|
|
68
|
+
* 用例的原版本与定义:快照里的;快照缺(较早的快照)时查 `agent_versions`。The definition is the
|
|
69
|
+
* one the run used: with the person's model / effort switch in effect at its `run_started`
|
|
70
|
+
* applied (UI refresh B, `selectionAt`), which is also returned as `selection`.
|
|
71
|
+
*/
|
|
72
|
+
export async function caseBase(db, s) {
|
|
73
|
+
// a sub-agent's case runs its logged effective definition (model included), never the agent
|
|
74
|
+
// version's (spec §15.3); a child conversation has no model switch (selection does not apply)
|
|
75
|
+
if (s.subagent !== undefined) {
|
|
76
|
+
return {
|
|
77
|
+
definition: normalizeStoredDefinition(s.subagent.definition),
|
|
78
|
+
agentVersion: s.agentVersion,
|
|
79
|
+
selection: NO_SELECTION,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const started = s.events.find((e) => e.type === "run_started" && e.runId === s.runId);
|
|
83
|
+
const selection = started ? selectionAt(s.events, started.seq) : NO_SELECTION;
|
|
84
|
+
const of = (d) => ({
|
|
85
|
+
definition: effectiveDefinition(normalizeStoredDefinition(d), selection),
|
|
86
|
+
agentVersion: s.agentVersion,
|
|
87
|
+
selection,
|
|
88
|
+
});
|
|
89
|
+
const fromSnap = s.definitions[String(s.agentVersion)];
|
|
90
|
+
// 调用方一般已经过 readSnapshot;这里再规范化一次(幂等),不依赖调用方
|
|
91
|
+
if (fromSnap)
|
|
92
|
+
return of(fromSnap);
|
|
93
|
+
const row = await db
|
|
94
|
+
.selectFrom("agent_versions")
|
|
95
|
+
.select("definition")
|
|
96
|
+
.where("agent_id", "=", s.agentId)
|
|
97
|
+
.where("version", "=", s.agentVersion)
|
|
98
|
+
.executeTakeFirst();
|
|
99
|
+
return row ? of(row.definition) : null;
|
|
100
|
+
}
|
|
101
|
+
/** 候选 agent 版本的定义(没给版本 → undefined)。 */
|
|
102
|
+
export async function versionDefinition(db, agentId, version) {
|
|
103
|
+
if (version === undefined)
|
|
104
|
+
return undefined;
|
|
105
|
+
const row = await db
|
|
106
|
+
.selectFrom("agent_versions")
|
|
107
|
+
.select("definition")
|
|
108
|
+
.where("agent_id", "=", agentId)
|
|
109
|
+
.where("version", "=", version)
|
|
110
|
+
.executeTakeFirst();
|
|
111
|
+
return row ? normalizeStoredDefinition(row.definition) : undefined;
|
|
112
|
+
}
|
|
113
|
+
const RUN_COLUMNS = [
|
|
114
|
+
"id",
|
|
115
|
+
"set_id",
|
|
116
|
+
"mode",
|
|
117
|
+
"candidate",
|
|
118
|
+
"judge",
|
|
119
|
+
"status",
|
|
120
|
+
"token_cap",
|
|
121
|
+
"tokens_used",
|
|
122
|
+
"cases_total",
|
|
123
|
+
"cases_done",
|
|
124
|
+
"estimate",
|
|
125
|
+
"error",
|
|
126
|
+
"created_at",
|
|
127
|
+
"finished_at",
|
|
128
|
+
];
|
|
129
|
+
const iso = (d) => (d === null ? null : new Date(d).toISOString());
|
|
130
|
+
/** 聚合出的比率(PG numeric / float 读出为字符串);没有数据为 null。 */
|
|
131
|
+
const rate = (v) => v === null || v === undefined ? null : Number(v);
|
|
132
|
+
/** 一行 `eval_results` 的视图。 */
|
|
133
|
+
function resultView(r) {
|
|
134
|
+
return {
|
|
135
|
+
id: r.id,
|
|
136
|
+
caseId: r.case_id,
|
|
137
|
+
step: r.step,
|
|
138
|
+
modelCallSeq: r.model_call_seq === null ? null : Number(r.model_call_seq),
|
|
139
|
+
status: r.status,
|
|
140
|
+
baseline: r.baseline,
|
|
141
|
+
candidate: r.candidate,
|
|
142
|
+
diff: r.diff,
|
|
143
|
+
judge: r.judge,
|
|
144
|
+
judgeStatus: r.judge_status,
|
|
145
|
+
drift: r.drift,
|
|
146
|
+
error: r.error,
|
|
147
|
+
evalConversationId: r.eval_conversation_id,
|
|
148
|
+
label: r.label,
|
|
149
|
+
labelNote: r.label_note,
|
|
150
|
+
labeledBy: r.labeled_by,
|
|
151
|
+
labeledAt: iso(r.labeled_at),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
const resultNotFound = () => new ApiError("eval.result_not_found", "Eval result not found");
|
|
155
|
+
/** 轻量视图的列(JSON 里只取标量,不读内容块)。 */
|
|
156
|
+
const LIGHT_COLUMNS = [
|
|
157
|
+
"id",
|
|
158
|
+
"case_id",
|
|
159
|
+
"step",
|
|
160
|
+
"model_call_seq",
|
|
161
|
+
"status",
|
|
162
|
+
"judge_status",
|
|
163
|
+
"label",
|
|
164
|
+
"updated_at",
|
|
165
|
+
sql `judge->>'verdict'`.as("verdict"),
|
|
166
|
+
sql `cardinality(drift)`.as("drift_count"),
|
|
167
|
+
sql `error->>'code'`.as("error_code"),
|
|
168
|
+
sql `(diff->>'toolCallsMatch')::boolean`.as("tool_calls_match"),
|
|
169
|
+
sql `(diff->>'textSimilarity')::float8`.as("text_similarity"),
|
|
170
|
+
];
|
|
171
|
+
/**
|
|
172
|
+
* 轻量列表的 `asOf`:本次读取时数据库的当前时间往前留的余量(毫秒)。下一次轮询以它为 `updatedSince`:
|
|
173
|
+
* 写结果的事务在读取之前开始、之后才提交时,`updated_at` 早于读取时间,留出余量才不会漏掉;重复的行由调用方按 id 合并。
|
|
174
|
+
*/
|
|
175
|
+
export const RESULTS_ASOF_OVERLAP_MS = 15_000;
|
|
176
|
+
/** 查看结果的审计去重:每位查看者每次运行每小时一条(Redis 键带 TTL,多副本共享)。 */
|
|
177
|
+
const RESULTS_VIEWED_TTL_SECONDS = 3600;
|
|
178
|
+
const resultsViewedKey = (runId, accountId) => `capk:eval-results-viewed:${runId}:${accountId}`;
|
|
179
|
+
/**
|
|
180
|
+
* 评测运行(D5、C7):估算、启动(校验候选、预建结果、每个用例入队一个任务)、查看、结果分页、取消。
|
|
181
|
+
* 执行在 `evals/worker.ts`。写操作在事务里锁组织行并复核角色(`evals.manage`)。
|
|
182
|
+
*/
|
|
183
|
+
export class EvalRunsService {
|
|
184
|
+
d;
|
|
185
|
+
constructor(d) {
|
|
186
|
+
this.d = d;
|
|
187
|
+
}
|
|
188
|
+
async liveSet(orgId, setId) {
|
|
189
|
+
if (!UUID.test(setId))
|
|
190
|
+
throw setNotFound();
|
|
191
|
+
const set = await this.d.db
|
|
192
|
+
.selectFrom("eval_sets")
|
|
193
|
+
.select(["agent_id", "rubric"])
|
|
194
|
+
.where("id", "=", setId)
|
|
195
|
+
.where("org_id", "=", orgId)
|
|
196
|
+
.where("deleted_at", "is", null)
|
|
197
|
+
.executeTakeFirst();
|
|
198
|
+
if (!set)
|
|
199
|
+
throw setNotFound();
|
|
200
|
+
return set;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* 解析模型;不存在 / 不可用 → `eval.candidate_invalid`(供应商列表暂时失败照常抛出)。
|
|
204
|
+
* 按部署范围解析,与运行时一致;组织级模型准入若在第二段落地,须同样覆盖评测候选。
|
|
205
|
+
*/
|
|
206
|
+
async resolveModel(ref) {
|
|
207
|
+
try {
|
|
208
|
+
return await this.d.registry.resolve(ref);
|
|
209
|
+
}
|
|
210
|
+
catch (e) {
|
|
211
|
+
if (e instanceof ProviderListError)
|
|
212
|
+
throw e;
|
|
213
|
+
if (e instanceof ApiError && e.code === "agent.model_unavailable") {
|
|
214
|
+
throw candidateInvalid(`Model ${ref.provider}/${ref.model} is not available`, [
|
|
215
|
+
{ path: "candidate.model", message: "model is not available" },
|
|
216
|
+
]);
|
|
217
|
+
}
|
|
218
|
+
throw e;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* 校验候选:版本存在(该集合的 agent)、模型可解析、参数按所用模型的声明严格通过(`paramIssues`)。
|
|
223
|
+
* 所用模型 = 候选模型,否则候选版本的模型,否则 agent 当前版本的模型。返回候选版本的定义。
|
|
224
|
+
*/
|
|
225
|
+
async checkCandidate(agentId, c) {
|
|
226
|
+
const versionDef = await versionDefinition(this.d.db, agentId, c.agentVersion);
|
|
227
|
+
if (c.agentVersion !== undefined && versionDef === undefined) {
|
|
228
|
+
throw candidateInvalid(`Agent version ${c.agentVersion} does not exist`, [
|
|
229
|
+
{ path: "candidate.agentVersion", message: "version does not exist" },
|
|
230
|
+
]);
|
|
231
|
+
}
|
|
232
|
+
let model = c.model ?? versionDef?.model;
|
|
233
|
+
if (model === undefined && c.modelParams !== undefined) {
|
|
234
|
+
const current = await this.d.db
|
|
235
|
+
.selectFrom("agents as a")
|
|
236
|
+
.innerJoin("agent_versions as v", (j) => j.onRef("v.agent_id", "=", "a.id").onRef("v.version", "=", "a.current_version"))
|
|
237
|
+
.select("v.definition")
|
|
238
|
+
.where("a.id", "=", agentId)
|
|
239
|
+
.executeTakeFirst();
|
|
240
|
+
model = current?.definition?.model;
|
|
241
|
+
}
|
|
242
|
+
if (model === undefined)
|
|
243
|
+
return versionDef;
|
|
244
|
+
const { info } = await this.resolveModel(model);
|
|
245
|
+
if (c.modelParams !== undefined) {
|
|
246
|
+
const issues = paramIssues("candidate.modelParams", info.parameters, c.modelParams);
|
|
247
|
+
if (issues.length > 0)
|
|
248
|
+
throw candidateInvalid("Invalid candidate model parameters", issues);
|
|
249
|
+
}
|
|
250
|
+
return versionDef;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* 各用例的回放计划与成本:只读写入时存好的列(`plan_step` / `plan_run`、`base_model`),不读快照。
|
|
254
|
+
* 给了候选参数时按每个用例实际所用的模型严格校验(同一模型在一次调用里只解析一次)。
|
|
255
|
+
*/
|
|
256
|
+
async plan(setId, mode, c, versionDef) {
|
|
257
|
+
const table = await this.d.prices.table();
|
|
258
|
+
const versionOnly = c.agentVersion !== undefined && c.model === undefined;
|
|
259
|
+
const rows = await this.d.db
|
|
260
|
+
.selectFrom("eval_cases")
|
|
261
|
+
.select([
|
|
262
|
+
"id",
|
|
263
|
+
"base_model",
|
|
264
|
+
sql `${sql.ref(mode === "step" ? "plan_step" : "plan_run")}`.as("plan"),
|
|
265
|
+
// a child case keeps its own model under a version candidate (unless an org agent's):
|
|
266
|
+
// its sub-agent source is read from the snapshot only when that matters
|
|
267
|
+
(versionOnly
|
|
268
|
+
? sql `jsonb_path_query_first(snapshot, '$.events[*] ? (@.type == "subagent_started").payload.template.source') #>> '{}'`
|
|
269
|
+
: sql `null`).as("subagent_source"),
|
|
270
|
+
])
|
|
271
|
+
.where("set_id", "=", setId)
|
|
272
|
+
.orderBy("created_at")
|
|
273
|
+
.orderBy("id")
|
|
274
|
+
.execute();
|
|
275
|
+
const out = [];
|
|
276
|
+
const infos = new Map();
|
|
277
|
+
for (const row of rows) {
|
|
278
|
+
const p = row.plan;
|
|
279
|
+
if (p.results.length === 0)
|
|
280
|
+
continue;
|
|
281
|
+
const baseModel = row.base_model;
|
|
282
|
+
// 没有原版本定义(base_model 为 null)时 worker 会把结果记 eval.definition_missing,不发请求
|
|
283
|
+
const source = (row.subagent_source ?? undefined);
|
|
284
|
+
const model = baseModel
|
|
285
|
+
? candidateModel(baseModel, c, versionDef, p.switchedModel, source)
|
|
286
|
+
: (c.model ?? null);
|
|
287
|
+
const price = model ? table.get(priceKey(model.provider, model.model)) : undefined;
|
|
288
|
+
// 候选参数按每个用例实际所用的模型严格校验(没给候选模型 / 版本时,所用模型是该用例自己的)
|
|
289
|
+
let problem = null;
|
|
290
|
+
if (c.modelParams !== undefined && model) {
|
|
291
|
+
const key = priceKey(model.provider, model.model);
|
|
292
|
+
if (!infos.has(key)) {
|
|
293
|
+
try {
|
|
294
|
+
infos.set(key, (await this.d.registry.resolve(model)).info);
|
|
295
|
+
}
|
|
296
|
+
catch (e) {
|
|
297
|
+
if (e instanceof ProviderListError)
|
|
298
|
+
throw e;
|
|
299
|
+
if (!(e instanceof ApiError && e.code === "agent.model_unavailable"))
|
|
300
|
+
throw e;
|
|
301
|
+
infos.set(key, null);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
const info = infos.get(key);
|
|
305
|
+
if (!info) {
|
|
306
|
+
problem = {
|
|
307
|
+
code: "run.model_unavailable",
|
|
308
|
+
message: `Model ${model.provider}/${model.model} is not available`,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
const issues = paramIssues("candidate.modelParams", info.parameters, c.modelParams);
|
|
313
|
+
if (issues.length > 0) {
|
|
314
|
+
problem = {
|
|
315
|
+
code: "eval.candidate_invalid",
|
|
316
|
+
message: `Invalid candidate model parameters for ${model.provider}/${model.model}`,
|
|
317
|
+
details: issues,
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
out.push({ ...p, caseId: row.id, cost: problem ? 0 : costOf(p.usage, price), problem });
|
|
323
|
+
}
|
|
324
|
+
return out;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* 评委份额的估算设置(不开评委 → null):输出上限 `min(评委模型上限, evals.judgeMaxOutputTokens)`、评委模型的价格。
|
|
328
|
+
* `eval` 用途没有映射时照常估算 token(按配置的上限),成本未知。
|
|
329
|
+
*/
|
|
330
|
+
async judgePricing(orgId, rubric, judge) {
|
|
331
|
+
if (!judge)
|
|
332
|
+
return null;
|
|
333
|
+
const configured = this.d.config().evals.judgeMaxOutputTokens;
|
|
334
|
+
let target;
|
|
335
|
+
try {
|
|
336
|
+
target = await this.d.purposes.resolve(orgId, "eval");
|
|
337
|
+
}
|
|
338
|
+
catch (e) {
|
|
339
|
+
if (e instanceof ApiError && e.code === "model.unconfigured") {
|
|
340
|
+
return { rubric, maxOutputTokens: configured, price: undefined, mapped: false };
|
|
341
|
+
}
|
|
342
|
+
throw e;
|
|
343
|
+
}
|
|
344
|
+
let maxOutputTokens = configured;
|
|
345
|
+
try {
|
|
346
|
+
const { info } = await this.d.registry.resolve(target.model);
|
|
347
|
+
maxOutputTokens = Math.min(configured, info.maxOutputTokens);
|
|
348
|
+
}
|
|
349
|
+
catch (e) {
|
|
350
|
+
if (e instanceof ProviderListError)
|
|
351
|
+
throw e;
|
|
352
|
+
if (!(e instanceof ApiError && e.code === "agent.model_unavailable"))
|
|
353
|
+
throw e;
|
|
354
|
+
}
|
|
355
|
+
const table = await this.d.prices.table();
|
|
356
|
+
return {
|
|
357
|
+
rubric,
|
|
358
|
+
maxOutputTokens,
|
|
359
|
+
price: table.get(priceKey(target.model.provider, target.model.model)),
|
|
360
|
+
mapped: true,
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
/** 估算只算会发请求的用例(候选不合法的用例不发请求);开评委时评委份额单列,也计入总数。 */
|
|
364
|
+
async summarize(all, judge) {
|
|
365
|
+
const plans = all.filter((p) => p.problem === null);
|
|
366
|
+
const { priceCurrency } = await this.d.settings.get();
|
|
367
|
+
let cost = 0;
|
|
368
|
+
for (const p of plans)
|
|
369
|
+
cost = cost === null || p.cost === null ? null : cost + p.cost;
|
|
370
|
+
const judgeRequests = judge ? plans.reduce((n, p) => n + p.results.length, 0) : 0;
|
|
371
|
+
let judgeTokens = 0;
|
|
372
|
+
let judgeCost = 0;
|
|
373
|
+
if (judge && judgeRequests > 0) {
|
|
374
|
+
const input = judgeRequests * judgeOverheadTokens(judge.rubric) +
|
|
375
|
+
plans.reduce((n, p) => n + (p.judgeContextTokens ?? 0), 0);
|
|
376
|
+
const output = judgeRequests * judge.maxOutputTokens;
|
|
377
|
+
judgeTokens = input + output;
|
|
378
|
+
judgeCost = judge.mapped
|
|
379
|
+
? costOf({ inputTokens: input, outputTokens: output, cacheReadTokens: 0, cacheWriteTokens: 0 }, judge.price)
|
|
380
|
+
: null;
|
|
381
|
+
}
|
|
382
|
+
return {
|
|
383
|
+
cases: plans.length,
|
|
384
|
+
modelRequests: plans.reduce((n, p) => n + p.modelRequests, 0),
|
|
385
|
+
judgeRequests,
|
|
386
|
+
estimatedTokens: plans.reduce((n, p) => n + usageTokens(p.usage), 0) + judgeTokens,
|
|
387
|
+
estimatedCost: plans.length === 0 ? 0 : cost === null || judgeCost === null ? null : cost + judgeCost,
|
|
388
|
+
judgeTokens,
|
|
389
|
+
judgeCost,
|
|
390
|
+
currency: priceCurrency,
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* 集合的 agent 已删除 → `agent.not_found`(删除 agent 会取消它的运行;之后再估算 / 启动只会建出全部跳过的运行)。
|
|
395
|
+
* 在事务里调用时 FOR SHARE,与删除 agent 互斥。
|
|
396
|
+
*/
|
|
397
|
+
async assertAgentLive(db, agentId) {
|
|
398
|
+
let q = db
|
|
399
|
+
.selectFrom("agents")
|
|
400
|
+
.select("id")
|
|
401
|
+
.where("id", "=", agentId)
|
|
402
|
+
.where("deleted_at", "is", null);
|
|
403
|
+
if (db !== this.d.db)
|
|
404
|
+
q = q.forShare();
|
|
405
|
+
if (!(await q.executeTakeFirst())) {
|
|
406
|
+
throw new ApiError("agent.not_found", "The agent of this eval set was deleted");
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
async estimate(orgId, setId, input) {
|
|
410
|
+
const set = await this.liveSet(orgId, setId);
|
|
411
|
+
await this.assertAgentLive(this.d.db, set.agent_id);
|
|
412
|
+
const caps = this.tokenCaps(input.tokenCap);
|
|
413
|
+
const versionDef = await this.checkCandidate(set.agent_id, input.candidate);
|
|
414
|
+
const plans = await this.plan(setId, input.mode, input.candidate, versionDef);
|
|
415
|
+
const judge = await this.judgePricing(orgId, set.rubric, input.judge);
|
|
416
|
+
return { estimate: await this.summarize(plans, judge), ...caps };
|
|
417
|
+
}
|
|
418
|
+
/** token 上限:给了就校验 [1, `evals.maxTokenCap`],缺省 `evals.defaultTokenCap`(D5)。 */
|
|
419
|
+
tokenCaps(tokenCap) {
|
|
420
|
+
const { defaultTokenCap, maxTokenCap } = this.d.config().evals;
|
|
421
|
+
const effectiveTokenCap = tokenCap ?? defaultTokenCap;
|
|
422
|
+
if (!Number.isInteger(effectiveTokenCap) ||
|
|
423
|
+
effectiveTokenCap < 1 ||
|
|
424
|
+
effectiveTokenCap > maxTokenCap) {
|
|
425
|
+
throw new ApiError("eval.token_cap_invalid", `tokenCap must be between 1 and ${maxTokenCap}`);
|
|
426
|
+
}
|
|
427
|
+
return { defaultTokenCap, maxTokenCap, effectiveTokenCap };
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* 启动:校验 token 上限([1, `evals.maxTokenCap`],缺省 `evals.defaultTokenCap`)、候选、评委用途;
|
|
431
|
+
* 没有可回放的 → `eval.nothing_to_replay`。事务内建运行行、预建 pending 结果,提交后每个用例入队一个任务;
|
|
432
|
+
* 入队失败 → 运行标 failed、结果 skipped,错误照常抛出。
|
|
433
|
+
*/
|
|
434
|
+
async start(orgId, actor, setId, input, actorTokenId) {
|
|
435
|
+
const set = await this.liveSet(orgId, setId);
|
|
436
|
+
await this.assertAgentLive(this.d.db, set.agent_id);
|
|
437
|
+
const tokenCap = this.tokenCaps(input.tokenCap).effectiveTokenCap;
|
|
438
|
+
const versionDef = await this.checkCandidate(set.agent_id, input.candidate);
|
|
439
|
+
if (input.judge)
|
|
440
|
+
await this.d.purposes.resolve(orgId, "eval");
|
|
441
|
+
const judge = await this.judgePricing(orgId, set.rubric, input.judge);
|
|
442
|
+
const planned = await this.plan(setId, input.mode, input.candidate, versionDef);
|
|
443
|
+
if (planned.length === 0) {
|
|
444
|
+
throw new ApiError("eval.nothing_to_replay", "The eval set has nothing to replay");
|
|
445
|
+
}
|
|
446
|
+
// 候选对每个用例都不合法:不建运行,直接报第一个问题
|
|
447
|
+
const firstProblem = planned.every((p) => p.problem !== null) ? planned[0]?.problem : null;
|
|
448
|
+
if (firstProblem) {
|
|
449
|
+
throw candidateInvalid(firstProblem.message, firstProblem.details ?? []);
|
|
450
|
+
}
|
|
451
|
+
const { runId, plans } = await this.d.db.transaction().execute(async (trx) => {
|
|
452
|
+
await lockOrgAndAuthorize(trx, orgId, actor, "evals.manage");
|
|
453
|
+
// 与删除用例(锁集合行 FOR UPDATE)互斥:之后读到的用例在提交前不会被删
|
|
454
|
+
const locked = await trx
|
|
455
|
+
.selectFrom("eval_sets")
|
|
456
|
+
.select("id")
|
|
457
|
+
.where("id", "=", setId)
|
|
458
|
+
.where("org_id", "=", orgId)
|
|
459
|
+
.where("deleted_at", "is", null)
|
|
460
|
+
.forShare()
|
|
461
|
+
.executeTakeFirst();
|
|
462
|
+
if (!locked)
|
|
463
|
+
throw setNotFound();
|
|
464
|
+
await this.assertAgentLive(trx, set.agent_id);
|
|
465
|
+
const alive = new Set((await trx
|
|
466
|
+
.selectFrom("eval_cases")
|
|
467
|
+
.select("id")
|
|
468
|
+
.where("set_id", "=", setId)
|
|
469
|
+
.where("id", "in", planned.map((p) => p.caseId))
|
|
470
|
+
.execute()).map((r) => r.id));
|
|
471
|
+
const plans = planned.filter((p) => alive.has(p.caseId));
|
|
472
|
+
if (plans.length === 0) {
|
|
473
|
+
throw new ApiError("eval.nothing_to_replay", "The eval set has nothing to replay");
|
|
474
|
+
}
|
|
475
|
+
const estimate = await this.summarize(plans, judge);
|
|
476
|
+
const run = await trx
|
|
477
|
+
.insertInto("eval_runs")
|
|
478
|
+
.values({
|
|
479
|
+
org_id: orgId,
|
|
480
|
+
set_id: setId,
|
|
481
|
+
mode: input.mode,
|
|
482
|
+
candidate: JSON.stringify(input.candidate),
|
|
483
|
+
judge: input.judge,
|
|
484
|
+
token_cap: String(tokenCap),
|
|
485
|
+
cases_total: plans.length,
|
|
486
|
+
estimate: JSON.stringify(estimate),
|
|
487
|
+
created_by: actor,
|
|
488
|
+
})
|
|
489
|
+
.returning("id")
|
|
490
|
+
.executeTakeFirstOrThrow();
|
|
491
|
+
// 候选不合法的用例:结果直接记错误(计入进度,不入队)
|
|
492
|
+
const rows = plans.flatMap((p) => p.results.map((r) => ({
|
|
493
|
+
run_id: run.id,
|
|
494
|
+
case_id: p.caseId,
|
|
495
|
+
org_id: orgId,
|
|
496
|
+
step: r.step,
|
|
497
|
+
model_call_seq: r.modelCallSeq,
|
|
498
|
+
...(p.problem !== null && {
|
|
499
|
+
status: "error",
|
|
500
|
+
error: JSON.stringify(p.problem),
|
|
501
|
+
}),
|
|
502
|
+
})));
|
|
503
|
+
for (let i = 0; i < rows.length; i += INSERT_CHUNK) {
|
|
504
|
+
await trx
|
|
505
|
+
.insertInto("eval_results")
|
|
506
|
+
.values(rows.slice(i, i + INSERT_CHUNK))
|
|
507
|
+
.execute();
|
|
508
|
+
}
|
|
509
|
+
await audit(trx, {
|
|
510
|
+
actorAccountId: actor,
|
|
511
|
+
...(actorTokenId !== undefined && { actorTokenId }),
|
|
512
|
+
orgId,
|
|
513
|
+
action: "eval.run_started",
|
|
514
|
+
target: run.id,
|
|
515
|
+
detail: { setId, mode: input.mode, judge: input.judge, tokenCap, cases: plans.length },
|
|
516
|
+
});
|
|
517
|
+
await recountCases(trx, run.id);
|
|
518
|
+
return { runId: run.id, plans: plans.filter((p) => p.problem === null) };
|
|
519
|
+
});
|
|
520
|
+
try {
|
|
521
|
+
await this.d.queue.enqueue(plans.map((p) => ({ runId, caseId: p.caseId, orgId })));
|
|
522
|
+
}
|
|
523
|
+
catch (e) {
|
|
524
|
+
await this.d.db.transaction().execute(async (trx) => {
|
|
525
|
+
await trx
|
|
526
|
+
.updateTable("eval_runs")
|
|
527
|
+
.set({ status: "failed", finished_at: sql `now()` })
|
|
528
|
+
.where("id", "=", runId)
|
|
529
|
+
.execute();
|
|
530
|
+
await trx
|
|
531
|
+
.updateTable("eval_results")
|
|
532
|
+
.set({ status: "skipped", updated_at: sql `now()` })
|
|
533
|
+
.where("run_id", "=", runId)
|
|
534
|
+
.where("status", "=", "pending")
|
|
535
|
+
.execute();
|
|
536
|
+
await recountCases(trx, runId);
|
|
537
|
+
});
|
|
538
|
+
throw e;
|
|
539
|
+
}
|
|
540
|
+
return this.get(orgId, runId);
|
|
541
|
+
}
|
|
542
|
+
/** 各运行的汇总(只算已结束的)。 */
|
|
543
|
+
async summaries(rows) {
|
|
544
|
+
const finished = rows
|
|
545
|
+
.filter((r) => !ACTIVE_EVAL_STATUSES.includes(r.status))
|
|
546
|
+
.map((r) => r.id);
|
|
547
|
+
const out = new Map();
|
|
548
|
+
if (finished.length === 0)
|
|
549
|
+
return out;
|
|
550
|
+
const agg = await this.d.db
|
|
551
|
+
.selectFrom("eval_results")
|
|
552
|
+
.select([
|
|
553
|
+
"run_id",
|
|
554
|
+
sql `count(*) FILTER (WHERE status = 'done')`.as("done"),
|
|
555
|
+
sql `count(*) FILTER (WHERE status = 'error')`.as("errors"),
|
|
556
|
+
sql `count(*) FILTER (WHERE status = 'skipped')`.as("skipped"),
|
|
557
|
+
sql `count(*) FILTER (WHERE label IS NOT NULL)`.as("labeled"),
|
|
558
|
+
sql `count(*) FILTER (WHERE judge_status = 'error')`.as("judge_errors"),
|
|
559
|
+
sql `count(*) FILTER (WHERE cardinality(drift) > 0)`.as("drifted"),
|
|
560
|
+
// 结构差异只在 done 的结果上有;评委比率只算给出了结论的(解析失败 / 请求失败不计)
|
|
561
|
+
sql `avg(CASE WHEN (diff->>'toolCallsMatch')::boolean THEN 1.0 ELSE 0.0 END)
|
|
562
|
+
FILTER (WHERE status = 'done' AND diff IS NOT NULL)`.as("tool_rate"),
|
|
563
|
+
sql `avg((diff->>'textSimilarity')::float8)
|
|
564
|
+
FILTER (WHERE status = 'done' AND diff IS NOT NULL)`.as("text_sim"),
|
|
565
|
+
sql `avg(CASE WHEN judge->>'verdict' = 'pass' THEN 1.0 ELSE 0.0 END)
|
|
566
|
+
FILTER (WHERE judge->>'verdict' IS NOT NULL)`.as("judge_rate"),
|
|
567
|
+
sql `avg(CASE WHEN label = 'pass' THEN 1.0 ELSE 0.0 END)
|
|
568
|
+
FILTER (WHERE label IS NOT NULL)`.as("human_rate"),
|
|
569
|
+
])
|
|
570
|
+
.where("run_id", "in", finished)
|
|
571
|
+
.groupBy("run_id")
|
|
572
|
+
.execute();
|
|
573
|
+
for (const id of finished) {
|
|
574
|
+
const a = agg.find((x) => x.run_id === id);
|
|
575
|
+
out.set(id, {
|
|
576
|
+
done: Number(a?.done ?? 0),
|
|
577
|
+
errors: Number(a?.errors ?? 0),
|
|
578
|
+
skipped: Number(a?.skipped ?? 0),
|
|
579
|
+
toolCallsMatchRate: rate(a?.tool_rate),
|
|
580
|
+
meanTextSimilarity: rate(a?.text_sim),
|
|
581
|
+
judgePassRate: rate(a?.judge_rate),
|
|
582
|
+
judgeErrors: Number(a?.judge_errors ?? 0),
|
|
583
|
+
humanPassRate: rate(a?.human_rate),
|
|
584
|
+
labeled: Number(a?.labeled ?? 0),
|
|
585
|
+
drifted: Number(a?.drifted ?? 0),
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
return out;
|
|
589
|
+
}
|
|
590
|
+
static toView(r, summary) {
|
|
591
|
+
return {
|
|
592
|
+
id: r.id,
|
|
593
|
+
setId: r.set_id,
|
|
594
|
+
mode: r.mode,
|
|
595
|
+
candidate: r.candidate,
|
|
596
|
+
judge: r.judge,
|
|
597
|
+
status: r.status,
|
|
598
|
+
tokenCap: Number(r.token_cap),
|
|
599
|
+
tokensUsed: Number(r.tokens_used),
|
|
600
|
+
casesTotal: r.cases_total,
|
|
601
|
+
casesDone: r.cases_done,
|
|
602
|
+
estimate: r.estimate,
|
|
603
|
+
summary,
|
|
604
|
+
error: (r.error ?? null),
|
|
605
|
+
createdAt: new Date(r.created_at).toISOString(),
|
|
606
|
+
finishedAt: iso(r.finished_at),
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
async get(orgId, runId) {
|
|
610
|
+
if (!UUID.test(runId))
|
|
611
|
+
throw runNotFound();
|
|
612
|
+
const r = await this.d.db
|
|
613
|
+
.selectFrom("eval_runs as r")
|
|
614
|
+
.innerJoin("eval_sets as s", "s.id", "r.set_id")
|
|
615
|
+
.select(RUN_COLUMNS.map((c) => `r.${c}`))
|
|
616
|
+
.where("r.id", "=", runId)
|
|
617
|
+
.where("r.org_id", "=", orgId)
|
|
618
|
+
.where("s.deleted_at", "is", null)
|
|
619
|
+
.executeTakeFirst();
|
|
620
|
+
if (!r)
|
|
621
|
+
throw runNotFound();
|
|
622
|
+
const sums = await this.summaries([r]);
|
|
623
|
+
return EvalRunsService.toView(r, sums.get(r.id) ?? null);
|
|
624
|
+
}
|
|
625
|
+
async listForSet(orgId, setId) {
|
|
626
|
+
await this.liveSet(orgId, setId);
|
|
627
|
+
const rows = await this.d.db
|
|
628
|
+
.selectFrom("eval_runs")
|
|
629
|
+
.select(RUN_COLUMNS)
|
|
630
|
+
.where("set_id", "=", setId)
|
|
631
|
+
.where("org_id", "=", orgId)
|
|
632
|
+
.orderBy("created_at", "desc")
|
|
633
|
+
.orderBy("id", "desc")
|
|
634
|
+
.execute();
|
|
635
|
+
const sums = await this.summaries(rows);
|
|
636
|
+
return rows.map((r) => EvalRunsService.toView(r, sums.get(r.id) ?? null));
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* 查看结果的审计 `eval.results_viewed`(结果里有回放出来的对话内容):每位查看者每次运行每小时一条——Redis
|
|
640
|
+
* `SET NX EX` 去重(多副本共享),轻量轮询因此不会刷审计。Redis 不可用时照写(宁多不漏)。
|
|
641
|
+
*/
|
|
642
|
+
async viewed(orgId, runId, actor, actorTokenId) {
|
|
643
|
+
if (this.d.redis) {
|
|
644
|
+
let first = true;
|
|
645
|
+
try {
|
|
646
|
+
const r = await this.d.redis.set(resultsViewedKey(runId, actor), "1", "EX", RESULTS_VIEWED_TTL_SECONDS, "NX");
|
|
647
|
+
first = r === "OK";
|
|
648
|
+
}
|
|
649
|
+
catch {
|
|
650
|
+
first = true;
|
|
651
|
+
}
|
|
652
|
+
if (!first)
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
await audit(this.d.db, {
|
|
656
|
+
actorAccountId: actor,
|
|
657
|
+
...(actorTokenId !== undefined && { actorTokenId }),
|
|
658
|
+
orgId,
|
|
659
|
+
action: "eval.results_viewed",
|
|
660
|
+
target: runId,
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
/** 结果分页的公共部分:按 id 升序,`after` 为上一页最后一条的 id;`updatedSince` 只取之后有变化的。 */
|
|
664
|
+
resultsQuery(orgId, runId, q) {
|
|
665
|
+
let query = this.d.db
|
|
666
|
+
.selectFrom("eval_results")
|
|
667
|
+
.where("run_id", "=", runId)
|
|
668
|
+
.where("org_id", "=", orgId)
|
|
669
|
+
.orderBy("id")
|
|
670
|
+
.limit(q.limit + 1);
|
|
671
|
+
if (q.after !== undefined) {
|
|
672
|
+
if (!UUID.test(q.after))
|
|
673
|
+
throw new ApiError("validation_failed", "Invalid cursor");
|
|
674
|
+
query = query.where("id", ">", q.after);
|
|
675
|
+
}
|
|
676
|
+
if (q.updatedSince !== undefined) {
|
|
677
|
+
const since = new Date(q.updatedSince);
|
|
678
|
+
if (Number.isNaN(since.getTime())) {
|
|
679
|
+
throw new ApiError("validation_failed", "Invalid updatedSince");
|
|
680
|
+
}
|
|
681
|
+
query = query.where("updated_at", ">=", since);
|
|
682
|
+
}
|
|
683
|
+
return query;
|
|
684
|
+
}
|
|
685
|
+
/** 结果分页(完整行):按 id 升序,`after` 为上一页最后一条的 id。写查看审计(去重见 {@link viewed})。 */
|
|
686
|
+
async results(orgId, actor, runId, q, actorTokenId) {
|
|
687
|
+
await this.get(orgId, runId);
|
|
688
|
+
const rows = await this.resultsQuery(orgId, runId, q).selectAll().execute();
|
|
689
|
+
const page = rows.slice(0, q.limit);
|
|
690
|
+
await this.viewed(orgId, runId, actor, actorTokenId);
|
|
691
|
+
return {
|
|
692
|
+
results: page.map(resultView),
|
|
693
|
+
next: rows.length > q.limit ? (page.at(-1)?.id ?? null) : null,
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
/**
|
|
697
|
+
* 结果分页(轻量,结果表与轮询用):不含内容块。`asOf` 作为下一次轮询的 `updatedSince`(已留余量,
|
|
698
|
+
* 见 {@link RESULTS_ASOF_OVERLAP_MS};重复的行由调用方按 id 合并)。
|
|
699
|
+
*/
|
|
700
|
+
async resultsLight(orgId, actor, runId, q, actorTokenId) {
|
|
701
|
+
await this.get(orgId, runId);
|
|
702
|
+
const now = await sql `SELECT now() AS now`.execute(this.d.db);
|
|
703
|
+
const asOf = new Date(new Date(now.rows[0]?.now ?? Date.now()).getTime() - RESULTS_ASOF_OVERLAP_MS);
|
|
704
|
+
const rows = await this.resultsQuery(orgId, runId, q).select(LIGHT_COLUMNS).execute();
|
|
705
|
+
const page = rows.slice(0, q.limit);
|
|
706
|
+
await this.viewed(orgId, runId, actor, actorTokenId);
|
|
707
|
+
return {
|
|
708
|
+
results: page.map((r) => ({
|
|
709
|
+
id: r.id,
|
|
710
|
+
caseId: r.case_id,
|
|
711
|
+
step: r.step,
|
|
712
|
+
modelCallSeq: r.model_call_seq === null ? null : Number(r.model_call_seq),
|
|
713
|
+
status: r.status,
|
|
714
|
+
judgeStatus: r.judge_status,
|
|
715
|
+
verdict: r.verdict === "pass" || r.verdict === "fail" ? r.verdict : null,
|
|
716
|
+
label: r.label,
|
|
717
|
+
driftCount: Number(r.drift_count),
|
|
718
|
+
errorCode: r.error_code,
|
|
719
|
+
toolCallsMatch: r.tool_calls_match,
|
|
720
|
+
textSimilarity: r.text_similarity === null ? null : Number(r.text_similarity),
|
|
721
|
+
updatedAt: new Date(r.updated_at).toISOString(),
|
|
722
|
+
})),
|
|
723
|
+
next: rows.length > q.limit ? (page.at(-1)?.id ?? null) : null,
|
|
724
|
+
asOf: asOf.toISOString(),
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
/** 一条结果的完整行(查看器按需读取);不在该运行 / 本组织 → `eval.result_not_found`。写查看审计(去重)。 */
|
|
728
|
+
async result(orgId, actor, runId, resultId, actorTokenId) {
|
|
729
|
+
await this.get(orgId, runId);
|
|
730
|
+
if (!UUID.test(resultId))
|
|
731
|
+
throw resultNotFound();
|
|
732
|
+
const row = await this.d.db
|
|
733
|
+
.selectFrom("eval_results")
|
|
734
|
+
.selectAll()
|
|
735
|
+
.where("id", "=", resultId)
|
|
736
|
+
.where("run_id", "=", runId)
|
|
737
|
+
.where("org_id", "=", orgId)
|
|
738
|
+
.executeTakeFirst();
|
|
739
|
+
if (!row)
|
|
740
|
+
throw resultNotFound();
|
|
741
|
+
await this.viewed(orgId, runId, actor, actorTokenId);
|
|
742
|
+
return resultView(row);
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* 取消:queued / running → cancelled,尚未开始的结果立即 skipped;在途请求做完照常写入(C7 在途可超出),
|
|
746
|
+
* 之后的请求不再发。已结束 → `eval.run_finished`。
|
|
747
|
+
*/
|
|
748
|
+
async cancel(orgId, actor, runId, actorTokenId) {
|
|
749
|
+
if (!UUID.test(runId))
|
|
750
|
+
throw runNotFound();
|
|
751
|
+
await this.get(orgId, runId);
|
|
752
|
+
await this.d.db.transaction().execute(async (trx) => {
|
|
753
|
+
await lockOrgAndAuthorize(trx, orgId, actor, "evals.manage");
|
|
754
|
+
const r = await trx
|
|
755
|
+
.updateTable("eval_runs")
|
|
756
|
+
.set({ status: "cancelled", finished_at: sql `now()` })
|
|
757
|
+
.where("id", "=", runId)
|
|
758
|
+
.where("org_id", "=", orgId)
|
|
759
|
+
.where("status", "in", [...ACTIVE_EVAL_STATUSES])
|
|
760
|
+
.executeTakeFirst();
|
|
761
|
+
if (Number(r.numUpdatedRows) === 0) {
|
|
762
|
+
throw new ApiError("eval.run_finished", "The eval run has already finished");
|
|
763
|
+
}
|
|
764
|
+
await trx
|
|
765
|
+
.updateTable("eval_results")
|
|
766
|
+
.set({ status: "skipped", updated_at: sql `now()` })
|
|
767
|
+
.where("run_id", "=", runId)
|
|
768
|
+
.where("status", "=", "pending")
|
|
769
|
+
.execute();
|
|
770
|
+
await skipPendingJudges(trx, runId);
|
|
771
|
+
// 尚未开始的用例此刻已全部结束:进度立即反映(在途的用例做完后由 worker 再重算)
|
|
772
|
+
await recountCases(trx, runId);
|
|
773
|
+
await audit(trx, {
|
|
774
|
+
actorAccountId: actor,
|
|
775
|
+
...(actorTokenId !== undefined && { actorTokenId }),
|
|
776
|
+
orgId,
|
|
777
|
+
action: "eval.run_cancelled",
|
|
778
|
+
target: runId,
|
|
779
|
+
});
|
|
780
|
+
});
|
|
781
|
+
return this.get(orgId, runId);
|
|
782
|
+
}
|
|
783
|
+
/**
|
|
784
|
+
* 人工标注(D3):标通过 / 不通过(附可选备注),`label: null` 清除标注与备注。评测集已删除、结果不属于本组织 →
|
|
785
|
+
* `eval.result_not_found`。事务内锁组织并复核 `evals.manage`,写审计 `eval.result_labeled`(不含备注全文)。
|
|
786
|
+
*/
|
|
787
|
+
async label(orgId, actor, resultId, input, actorTokenId) {
|
|
788
|
+
if (!UUID.test(resultId))
|
|
789
|
+
throw resultNotFound();
|
|
790
|
+
const row = await this.d.db.transaction().execute(async (trx) => {
|
|
791
|
+
await lockOrgAndAuthorize(trx, orgId, actor, "evals.manage");
|
|
792
|
+
// 先锁住这条结果、读出原标注(写进审计)
|
|
793
|
+
const before = await trx
|
|
794
|
+
.selectFrom("eval_results")
|
|
795
|
+
.select("label")
|
|
796
|
+
.where("id", "=", resultId)
|
|
797
|
+
.where("org_id", "=", orgId)
|
|
798
|
+
.forUpdate()
|
|
799
|
+
.executeTakeFirst();
|
|
800
|
+
if (!before)
|
|
801
|
+
throw resultNotFound();
|
|
802
|
+
const cleared = input.label === null;
|
|
803
|
+
const r = await trx
|
|
804
|
+
.updateTable("eval_results")
|
|
805
|
+
.set({
|
|
806
|
+
label: input.label,
|
|
807
|
+
label_note: cleared ? null : (input.note ?? null),
|
|
808
|
+
labeled_by: cleared ? null : actor,
|
|
809
|
+
labeled_at: cleared ? null : sql `now()`,
|
|
810
|
+
updated_at: sql `now()`,
|
|
811
|
+
})
|
|
812
|
+
.where("id", "=", resultId)
|
|
813
|
+
.where("org_id", "=", orgId)
|
|
814
|
+
.where((eb) => eb.exists(eb
|
|
815
|
+
.selectFrom("eval_runs as er")
|
|
816
|
+
.innerJoin("eval_sets as es", "es.id", "er.set_id")
|
|
817
|
+
.select("er.id")
|
|
818
|
+
.whereRef("er.id", "=", "eval_results.run_id")
|
|
819
|
+
.where("es.deleted_at", "is", null)))
|
|
820
|
+
.returningAll()
|
|
821
|
+
.executeTakeFirst();
|
|
822
|
+
if (!r)
|
|
823
|
+
throw resultNotFound();
|
|
824
|
+
await audit(trx, {
|
|
825
|
+
actorAccountId: actor,
|
|
826
|
+
...(actorTokenId !== undefined && { actorTokenId }),
|
|
827
|
+
orgId,
|
|
828
|
+
action: "eval.result_labeled",
|
|
829
|
+
target: resultId,
|
|
830
|
+
detail: { runId: r.run_id, label: input.label, previousLabel: before.label },
|
|
831
|
+
});
|
|
832
|
+
return r;
|
|
833
|
+
});
|
|
834
|
+
return resultView(row);
|
|
835
|
+
}
|
|
836
|
+
}
|