@askdkc/kiokuko 0.1.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 +21 -0
- package/README.ja.md +112 -0
- package/README.ko.md +112 -0
- package/README.md +147 -0
- package/README.zh-CN.md +112 -0
- package/dist/agent-file/atomic-write.d.ts +6 -0
- package/dist/agent-file/atomic-write.d.ts.map +1 -0
- package/dist/agent-file/atomic-write.js +36 -0
- package/dist/agent-file/atomic-write.js.map +1 -0
- package/dist/agent-file/managed-block.d.ts +12 -0
- package/dist/agent-file/managed-block.d.ts.map +1 -0
- package/dist/agent-file/managed-block.js +56 -0
- package/dist/agent-file/managed-block.js.map +1 -0
- package/dist/agent-file/render.d.ts +14 -0
- package/dist/agent-file/render.d.ts.map +1 -0
- package/dist/agent-file/render.js +41 -0
- package/dist/agent-file/render.js.map +1 -0
- package/dist/akinator/domain.d.ts +25 -0
- package/dist/akinator/domain.d.ts.map +1 -0
- package/dist/akinator/domain.js +255 -0
- package/dist/akinator/domain.js.map +1 -0
- package/dist/akinator/orchestrator.d.ts +8 -0
- package/dist/akinator/orchestrator.d.ts.map +1 -0
- package/dist/akinator/orchestrator.js +11 -0
- package/dist/akinator/orchestrator.js.map +1 -0
- package/dist/akinator/service.d.ts +35 -0
- package/dist/akinator/service.d.ts.map +1 -0
- package/dist/akinator/service.js +296 -0
- package/dist/akinator/service.js.map +1 -0
- package/dist/akinator/store.d.ts +96 -0
- package/dist/akinator/store.d.ts.map +1 -0
- package/dist/akinator/store.js +583 -0
- package/dist/akinator/store.js.map +1 -0
- package/dist/akinator/types.d.ts +49 -0
- package/dist/akinator/types.d.ts.map +1 -0
- package/dist/akinator/types.js +2 -0
- package/dist/akinator/types.js.map +1 -0
- package/dist/bin/kiokuko.d.ts +3 -0
- package/dist/bin/kiokuko.d.ts.map +1 -0
- package/dist/bin/kiokuko.js +6 -0
- package/dist/bin/kiokuko.js.map +1 -0
- package/dist/cli.d.ts +10 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +362 -0
- package/dist/cli.js.map +1 -0
- package/dist/client/runtime-discovery.d.ts +15 -0
- package/dist/client/runtime-discovery.d.ts.map +1 -0
- package/dist/client/runtime-discovery.js +45 -0
- package/dist/client/runtime-discovery.js.map +1 -0
- package/dist/client/server-client.d.ts +20 -0
- package/dist/client/server-client.d.ts.map +1 -0
- package/dist/client/server-client.js +424 -0
- package/dist/client/server-client.js.map +1 -0
- package/dist/commands/agent.d.ts +10 -0
- package/dist/commands/agent.d.ts.map +1 -0
- package/dist/commands/agent.js +283 -0
- package/dist/commands/agent.js.map +1 -0
- package/dist/commands/backup.d.ts +5 -0
- package/dist/commands/backup.d.ts.map +1 -0
- package/dist/commands/backup.js +14 -0
- package/dist/commands/backup.js.map +1 -0
- package/dist/commands/call.d.ts +7 -0
- package/dist/commands/call.d.ts.map +1 -0
- package/dist/commands/call.js +10 -0
- package/dist/commands/call.js.map +1 -0
- package/dist/commands/doctor.d.ts +31 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +142 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/export.d.ts +21 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +68 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/import.d.ts +15 -0
- package/dist/commands/import.d.ts.map +1 -0
- package/dist/commands/import.js +265 -0
- package/dist/commands/import.js.map +1 -0
- package/dist/commands/init.d.ts +14 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +26 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/ledger.d.ts +7 -0
- package/dist/commands/ledger.d.ts.map +1 -0
- package/dist/commands/ledger.js +66 -0
- package/dist/commands/ledger.js.map +1 -0
- package/dist/commands/link.d.ts +6 -0
- package/dist/commands/link.d.ts.map +1 -0
- package/dist/commands/link.js +6 -0
- package/dist/commands/link.js.map +1 -0
- package/dist/commands/promote.d.ts +6 -0
- package/dist/commands/promote.d.ts.map +1 -0
- package/dist/commands/promote.js +6 -0
- package/dist/commands/promote.js.map +1 -0
- package/dist/commands/purge.d.ts +10 -0
- package/dist/commands/purge.d.ts.map +1 -0
- package/dist/commands/purge.js +26 -0
- package/dist/commands/purge.js.map +1 -0
- package/dist/commands/read.d.ts +6 -0
- package/dist/commands/read.d.ts.map +1 -0
- package/dist/commands/read.js +4 -0
- package/dist/commands/read.js.map +1 -0
- package/dist/commands/recall.d.ts +6 -0
- package/dist/commands/recall.d.ts.map +1 -0
- package/dist/commands/recall.js +4 -0
- package/dist/commands/recall.js.map +1 -0
- package/dist/commands/record.d.ts +6 -0
- package/dist/commands/record.d.ts.map +1 -0
- package/dist/commands/record.js +4 -0
- package/dist/commands/record.js.map +1 -0
- package/dist/commands/search.d.ts +6 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +4 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/serve.d.ts +34 -0
- package/dist/commands/serve.d.ts.map +1 -0
- package/dist/commands/serve.js +120 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/commands/server-status.d.ts +20 -0
- package/dist/commands/server-status.d.ts.map +1 -0
- package/dist/commands/server-status.js +21 -0
- package/dist/commands/server-status.js.map +1 -0
- package/dist/commands/server.d.ts +13 -0
- package/dist/commands/server.d.ts.map +1 -0
- package/dist/commands/server.js +89 -0
- package/dist/commands/server.js.map +1 -0
- package/dist/commands/setup.d.ts +32 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +121 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/supersede.d.ts +6 -0
- package/dist/commands/supersede.d.ts.map +1 -0
- package/dist/commands/supersede.js +6 -0
- package/dist/commands/supersede.js.map +1 -0
- package/dist/commands/use.d.ts +28 -0
- package/dist/commands/use.d.ts.map +1 -0
- package/dist/commands/use.js +176 -0
- package/dist/commands/use.js.map +1 -0
- package/dist/config/paths.d.ts +18 -0
- package/dist/config/paths.d.ts.map +1 -0
- package/dist/config/paths.js +104 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/config/project-config.d.ts +10 -0
- package/dist/config/project-config.d.ts.map +1 -0
- package/dist/config/project-config.js +59 -0
- package/dist/config/project-config.js.map +1 -0
- package/dist/context/broker.d.ts +80 -0
- package/dist/context/broker.d.ts.map +1 -0
- package/dist/context/broker.js +437 -0
- package/dist/context/broker.js.map +1 -0
- package/dist/context/delivery.d.ts +66 -0
- package/dist/context/delivery.d.ts.map +1 -0
- package/dist/context/delivery.js +758 -0
- package/dist/context/delivery.js.map +1 -0
- package/dist/context/feedback.d.ts +75 -0
- package/dist/context/feedback.d.ts.map +1 -0
- package/dist/context/feedback.js +997 -0
- package/dist/context/feedback.js.map +1 -0
- package/dist/context/ranking.d.ts +98 -0
- package/dist/context/ranking.d.ts.map +1 -0
- package/dist/context/ranking.js +513 -0
- package/dist/context/ranking.js.map +1 -0
- package/dist/context/recommendations.d.ts +85 -0
- package/dist/context/recommendations.d.ts.map +1 -0
- package/dist/context/recommendations.js +342 -0
- package/dist/context/recommendations.js.map +1 -0
- package/dist/db/adapter.d.ts +25 -0
- package/dist/db/adapter.d.ts.map +1 -0
- package/dist/db/adapter.js +37 -0
- package/dist/db/adapter.js.map +1 -0
- package/dist/db/capabilities.d.ts +13 -0
- package/dist/db/capabilities.d.ts.map +1 -0
- package/dist/db/capabilities.js +25 -0
- package/dist/db/capabilities.js.map +1 -0
- package/dist/db/connection.d.ts +6 -0
- package/dist/db/connection.d.ts.map +1 -0
- package/dist/db/connection.js +42 -0
- package/dist/db/connection.js.map +1 -0
- package/dist/db/migrate.d.ts +9 -0
- package/dist/db/migrate.d.ts.map +1 -0
- package/dist/db/migrate.js +102 -0
- package/dist/db/migrate.js.map +1 -0
- package/dist/db/transaction.d.ts +4 -0
- package/dist/db/transaction.d.ts.map +1 -0
- package/dist/db/transaction.js +39 -0
- package/dist/db/transaction.js.map +1 -0
- package/dist/errors.d.ts +9 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +32 -0
- package/dist/errors.js.map +1 -0
- package/dist/gateway/agent-service.d.ts +69 -0
- package/dist/gateway/agent-service.d.ts.map +1 -0
- package/dist/gateway/agent-service.js +581 -0
- package/dist/gateway/agent-service.js.map +1 -0
- package/dist/gateway/checkpoint-service.d.ts +42 -0
- package/dist/gateway/checkpoint-service.d.ts.map +1 -0
- package/dist/gateway/checkpoint-service.js +295 -0
- package/dist/gateway/checkpoint-service.js.map +1 -0
- package/dist/knowledge/sources.d.ts +72 -0
- package/dist/knowledge/sources.d.ts.map +1 -0
- package/dist/knowledge/sources.js +406 -0
- package/dist/knowledge/sources.js.map +1 -0
- package/dist/ledger/archive.d.ts +50 -0
- package/dist/ledger/archive.d.ts.map +1 -0
- package/dist/ledger/archive.js +1072 -0
- package/dist/ledger/archive.js.map +1 -0
- package/dist/ledger/hash.d.ts +22 -0
- package/dist/ledger/hash.d.ts.map +1 -0
- package/dist/ledger/hash.js +25 -0
- package/dist/ledger/hash.js.map +1 -0
- package/dist/ledger/maintenance.d.ts +78 -0
- package/dist/ledger/maintenance.d.ts.map +1 -0
- package/dist/ledger/maintenance.js +683 -0
- package/dist/ledger/maintenance.js.map +1 -0
- package/dist/ledger/projection.d.ts +37 -0
- package/dist/ledger/projection.d.ts.map +1 -0
- package/dist/ledger/projection.js +307 -0
- package/dist/ledger/projection.js.map +1 -0
- package/dist/ledger/promotion.d.ts +28 -0
- package/dist/ledger/promotion.d.ts.map +1 -0
- package/dist/ledger/promotion.js +308 -0
- package/dist/ledger/promotion.js.map +1 -0
- package/dist/ledger/query.d.ts +55 -0
- package/dist/ledger/query.d.ts.map +1 -0
- package/dist/ledger/query.js +321 -0
- package/dist/ledger/query.js.map +1 -0
- package/dist/ledger/redaction.d.ts +8 -0
- package/dist/ledger/redaction.d.ts.map +1 -0
- package/dist/ledger/redaction.js +40 -0
- package/dist/ledger/redaction.js.map +1 -0
- package/dist/ledger/store.d.ts +46 -0
- package/dist/ledger/store.d.ts.map +1 -0
- package/dist/ledger/store.js +324 -0
- package/dist/ledger/store.js.map +1 -0
- package/dist/ledger/types.d.ts +119 -0
- package/dist/ledger/types.d.ts.map +1 -0
- package/dist/ledger/types.js +22 -0
- package/dist/ledger/types.js.map +1 -0
- package/dist/ledger/validate.d.ts +10 -0
- package/dist/ledger/validate.d.ts.map +1 -0
- package/dist/ledger/validate.js +183 -0
- package/dist/ledger/validate.js.map +1 -0
- package/dist/mcp/server.d.ts +9 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +86 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/memory/audit.d.ts +14 -0
- package/dist/memory/audit.d.ts.map +1 -0
- package/dist/memory/audit.js +16 -0
- package/dist/memory/audit.js.map +1 -0
- package/dist/memory/entries.d.ts +65 -0
- package/dist/memory/entries.d.ts.map +1 -0
- package/dist/memory/entries.js +200 -0
- package/dist/memory/entries.js.map +1 -0
- package/dist/memory/lifecycle.d.ts +29 -0
- package/dist/memory/lifecycle.d.ts.map +1 -0
- package/dist/memory/lifecycle.js +61 -0
- package/dist/memory/lifecycle.js.map +1 -0
- package/dist/memory/retrieval.d.ts +44 -0
- package/dist/memory/retrieval.d.ts.map +1 -0
- package/dist/memory/retrieval.js +174 -0
- package/dist/memory/retrieval.js.map +1 -0
- package/dist/memory/scoped-memory.d.ts +41 -0
- package/dist/memory/scoped-memory.d.ts.map +1 -0
- package/dist/memory/scoped-memory.js +65 -0
- package/dist/memory/scoped-memory.js.map +1 -0
- package/dist/memory/secrets.d.ts +6 -0
- package/dist/memory/secrets.d.ts.map +1 -0
- package/dist/memory/secrets.js +17 -0
- package/dist/memory/secrets.js.map +1 -0
- package/dist/memory/workspaces.d.ts +17 -0
- package/dist/memory/workspaces.d.ts.map +1 -0
- package/dist/memory/workspaces.js +92 -0
- package/dist/memory/workspaces.js.map +1 -0
- package/dist/repository/binding.d.ts +19 -0
- package/dist/repository/binding.d.ts.map +1 -0
- package/dist/repository/binding.js +78 -0
- package/dist/repository/binding.js.map +1 -0
- package/dist/repository/detect-root.d.ts +12 -0
- package/dist/repository/detect-root.d.ts.map +1 -0
- package/dist/repository/detect-root.js +57 -0
- package/dist/repository/detect-root.js.map +1 -0
- package/dist/repository/git-origin.d.ts +2 -0
- package/dist/repository/git-origin.d.ts.map +1 -0
- package/dist/repository/git-origin.js +15 -0
- package/dist/repository/git-origin.js.map +1 -0
- package/dist/repository/identity.d.ts +19 -0
- package/dist/repository/identity.d.ts.map +1 -0
- package/dist/repository/identity.js +23 -0
- package/dist/repository/identity.js.map +1 -0
- package/dist/repository/remote-url.d.ts +4 -0
- package/dist/repository/remote-url.d.ts.map +1 -0
- package/dist/repository/remote-url.js +36 -0
- package/dist/repository/remote-url.js.map +1 -0
- package/dist/security/sanitize.d.ts +4 -0
- package/dist/security/sanitize.d.ts.map +1 -0
- package/dist/security/sanitize.js +174 -0
- package/dist/security/sanitize.js.map +1 -0
- package/dist/serialization/envelope.d.ts +20 -0
- package/dist/serialization/envelope.d.ts.map +1 -0
- package/dist/serialization/envelope.js +11 -0
- package/dist/serialization/envelope.js.map +1 -0
- package/dist/serialization/validate.d.ts +31 -0
- package/dist/serialization/validate.d.ts.map +1 -0
- package/dist/serialization/validate.js +168 -0
- package/dist/serialization/validate.js.map +1 -0
- package/dist/server/agent-application.d.ts +6 -0
- package/dist/server/agent-application.d.ts.map +1 -0
- package/dist/server/agent-application.js +60 -0
- package/dist/server/agent-application.js.map +1 -0
- package/dist/server/app.d.ts +5 -0
- package/dist/server/app.d.ts.map +1 -0
- package/dist/server/app.js +87 -0
- package/dist/server/app.js.map +1 -0
- package/dist/server/auth.d.ts +2 -0
- package/dist/server/auth.d.ts.map +1 -0
- package/dist/server/auth.js +22 -0
- package/dist/server/auth.js.map +1 -0
- package/dist/server/http.d.ts +69 -0
- package/dist/server/http.d.ts.map +1 -0
- package/dist/server/http.js +349 -0
- package/dist/server/http.js.map +1 -0
- package/dist/server/idempotency.d.ts +12 -0
- package/dist/server/idempotency.d.ts.map +1 -0
- package/dist/server/idempotency.js +210 -0
- package/dist/server/idempotency.js.map +1 -0
- package/dist/server/instance-lock.d.ts +17 -0
- package/dist/server/instance-lock.d.ts.map +1 -0
- package/dist/server/instance-lock.js +118 -0
- package/dist/server/instance-lock.js.map +1 -0
- package/dist/server/router.d.ts +29 -0
- package/dist/server/router.d.ts.map +1 -0
- package/dist/server/router.js +112 -0
- package/dist/server/router.js.map +1 -0
- package/dist/server/routes/agent-events.d.ts +5 -0
- package/dist/server/routes/agent-events.d.ts.map +1 -0
- package/dist/server/routes/agent-events.js +46 -0
- package/dist/server/routes/agent-events.js.map +1 -0
- package/dist/server/routes/agent-intake.d.ts +5 -0
- package/dist/server/routes/agent-intake.d.ts.map +1 -0
- package/dist/server/routes/agent-intake.js +42 -0
- package/dist/server/routes/agent-intake.js.map +1 -0
- package/dist/server/routes/agent-promotions.d.ts +5 -0
- package/dist/server/routes/agent-promotions.d.ts.map +1 -0
- package/dist/server/routes/agent-promotions.js +52 -0
- package/dist/server/routes/agent-promotions.js.map +1 -0
- package/dist/server/routes/agent-runs.d.ts +25 -0
- package/dist/server/routes/agent-runs.d.ts.map +1 -0
- package/dist/server/routes/agent-runs.js +151 -0
- package/dist/server/routes/agent-runs.js.map +1 -0
- package/dist/server/routes/task5-support.d.ts +11 -0
- package/dist/server/routes/task5-support.d.ts.map +1 -0
- package/dist/server/routes/task5-support.js +22 -0
- package/dist/server/routes/task5-support.js.map +1 -0
- package/dist/server/routes/task5.d.ts +5 -0
- package/dist/server/routes/task5.d.ts.map +1 -0
- package/dist/server/routes/task5.js +72 -0
- package/dist/server/routes/task5.js.map +1 -0
- package/dist/server/runtime-descriptor.d.ts +24 -0
- package/dist/server/runtime-descriptor.d.ts.map +1 -0
- package/dist/server/runtime-descriptor.js +156 -0
- package/dist/server/runtime-descriptor.js.map +1 -0
- package/dist/server/write-queue.d.ts +20 -0
- package/dist/server/write-queue.d.ts.map +1 -0
- package/dist/server/write-queue.js +83 -0
- package/dist/server/write-queue.js.map +1 -0
- package/dist/setup/managed-text.d.ts +6 -0
- package/dist/setup/managed-text.d.ts.map +1 -0
- package/dist/setup/managed-text.js +42 -0
- package/dist/setup/managed-text.js.map +1 -0
- package/dist/setup/opencode-config.d.ts +3 -0
- package/dist/setup/opencode-config.d.ts.map +1 -0
- package/dist/setup/opencode-config.js +26 -0
- package/dist/setup/opencode-config.js.map +1 -0
- package/dist/setup/render.d.ts +8 -0
- package/dist/setup/render.d.ts.map +1 -0
- package/dist/setup/render.js +45 -0
- package/dist/setup/render.js.map +1 -0
- package/dist/web/server.d.ts +16 -0
- package/dist/web/server.d.ts.map +1 -0
- package/dist/web/server.js +424 -0
- package/dist/web/server.js.map +1 -0
- package/dist/web/ui.d.ts +2 -0
- package/dist/web/ui.d.ts.map +1 -0
- package/dist/web/ui.js +271 -0
- package/dist/web/ui.js.map +1 -0
- package/migrations/001_initial.sql +89 -0
- package/migrations/002_fts.sql +66 -0
- package/migrations/003_akinator.sql +30 -0
- package/migrations/004_agent_gateway.sql +259 -0
- package/package.json +45 -0
- package/templates/AGENTS.md +29 -0
|
@@ -0,0 +1,758 @@
|
|
|
1
|
+
import { withImmediateTransaction } from '../db/transaction.js';
|
|
2
|
+
import { KiokukoError } from '../errors.js';
|
|
3
|
+
import { CONTEXT_RANKING_COMPONENTS, CONTEXT_SELECTION_REASON_ORDER } from './ranking.js';
|
|
4
|
+
import { sanitizeJson } from '../security/sanitize.js';
|
|
5
|
+
import { canonicalJson } from '../serialization/validate.js';
|
|
6
|
+
const MAX_IDENTIFIER_BYTES = 256;
|
|
7
|
+
const MAX_ITEMS = 100;
|
|
8
|
+
const MAX_SCORE_COMPONENT = 1_000_000;
|
|
9
|
+
const MAX_CHAR_BUDGET = 100_000;
|
|
10
|
+
const MAX_EXTERNAL_SUMMARY_BYTES = 16 * 1024;
|
|
11
|
+
const MAX_EXTERNAL_ERROR_BYTES = 1024;
|
|
12
|
+
const MAX_SOURCES = 16;
|
|
13
|
+
const MAX_LIMIT = 100;
|
|
14
|
+
const DEFAULT_LIMIT = 100;
|
|
15
|
+
const DELIVERY_CURSOR_VERSION = 1;
|
|
16
|
+
const VALIDATION_MESSAGE = 'Context delivery input is invalid';
|
|
17
|
+
const NOT_FOUND_MESSAGE = 'Context delivery target was not found';
|
|
18
|
+
const CONFLICT_MESSAGE = 'Context delivery conflicts with existing record';
|
|
19
|
+
const DATABASE_MESSAGE = 'Context delivery database operation failed';
|
|
20
|
+
const INTEGRITY_MESSAGE = 'Stored context delivery is invalid';
|
|
21
|
+
function fail(code, message) {
|
|
22
|
+
throw new KiokukoError(code, message);
|
|
23
|
+
}
|
|
24
|
+
function validation() {
|
|
25
|
+
return fail('VALIDATION_ERROR', VALIDATION_MESSAGE);
|
|
26
|
+
}
|
|
27
|
+
function notFound() {
|
|
28
|
+
return fail('NOT_FOUND', NOT_FOUND_MESSAGE);
|
|
29
|
+
}
|
|
30
|
+
function conflict() {
|
|
31
|
+
return fail('CONFLICT', CONFLICT_MESSAGE);
|
|
32
|
+
}
|
|
33
|
+
function databaseFailure() {
|
|
34
|
+
return fail('DATABASE_ERROR', DATABASE_MESSAGE);
|
|
35
|
+
}
|
|
36
|
+
function integrity() {
|
|
37
|
+
return fail('INTEGRITY_ERROR', INTEGRITY_MESSAGE);
|
|
38
|
+
}
|
|
39
|
+
function isKiokukoError(error) {
|
|
40
|
+
return error instanceof KiokukoError;
|
|
41
|
+
}
|
|
42
|
+
function normalizeDatabaseError(error) {
|
|
43
|
+
if (isKiokukoError(error))
|
|
44
|
+
throw error;
|
|
45
|
+
if (error instanceof Error && /unique|constraint/i.test(error.message))
|
|
46
|
+
conflict();
|
|
47
|
+
databaseFailure();
|
|
48
|
+
}
|
|
49
|
+
function isPlainObject(value) {
|
|
50
|
+
try {
|
|
51
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
52
|
+
return false;
|
|
53
|
+
const prototype = Object.getPrototypeOf(value);
|
|
54
|
+
return prototype === Object.prototype || prototype === null;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function isCanonicalArrayIndex(value) {
|
|
61
|
+
if (value === '0')
|
|
62
|
+
return true;
|
|
63
|
+
if (!/^[1-9]\d*$/u.test(value))
|
|
64
|
+
return false;
|
|
65
|
+
const index = Number(value);
|
|
66
|
+
return Number.isSafeInteger(index) && index < 4_294_967_295 && String(index) === value;
|
|
67
|
+
}
|
|
68
|
+
function ownKeys(value) {
|
|
69
|
+
let keys;
|
|
70
|
+
try {
|
|
71
|
+
keys = Reflect.ownKeys(value);
|
|
72
|
+
if (keys.some((key) => typeof key === 'symbol'))
|
|
73
|
+
validation();
|
|
74
|
+
for (const key of keys) {
|
|
75
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
76
|
+
if (descriptor === undefined || !('value' in descriptor))
|
|
77
|
+
validation();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
if (isKiokukoError(error))
|
|
82
|
+
throw error;
|
|
83
|
+
validation();
|
|
84
|
+
}
|
|
85
|
+
return keys;
|
|
86
|
+
}
|
|
87
|
+
function assertCloneableInput(value) {
|
|
88
|
+
try {
|
|
89
|
+
structuredClone(value);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
validation();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function objectInput(value, fields, requireAll) {
|
|
96
|
+
if (!isPlainObject(value))
|
|
97
|
+
validation();
|
|
98
|
+
const keys = ownKeys(value);
|
|
99
|
+
assertCloneableInput(value);
|
|
100
|
+
const allowed = new Set(fields);
|
|
101
|
+
if (keys.some((key) => !allowed.has(key)))
|
|
102
|
+
validation();
|
|
103
|
+
if (requireAll && fields.some((field) => !keys.includes(field)))
|
|
104
|
+
validation();
|
|
105
|
+
return value;
|
|
106
|
+
}
|
|
107
|
+
function arrayInput(value) {
|
|
108
|
+
if (!Array.isArray(value))
|
|
109
|
+
validation();
|
|
110
|
+
try {
|
|
111
|
+
if (Object.getPrototypeOf(value) !== Array.prototype)
|
|
112
|
+
validation();
|
|
113
|
+
const keys = ownKeys(value);
|
|
114
|
+
assertCloneableInput(value);
|
|
115
|
+
if (!keys.includes('length') || keys.some((key) => key !== 'length' && (!isCanonicalArrayIndex(key) || Number(key) >= value.length)))
|
|
116
|
+
validation();
|
|
117
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
118
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
|
119
|
+
if (descriptor === undefined || !('value' in descriptor))
|
|
120
|
+
validation();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
if (isKiokukoError(error))
|
|
125
|
+
throw error;
|
|
126
|
+
validation();
|
|
127
|
+
}
|
|
128
|
+
return value;
|
|
129
|
+
}
|
|
130
|
+
function hasOwn(value, field) {
|
|
131
|
+
return Object.prototype.hasOwnProperty.call(value, field);
|
|
132
|
+
}
|
|
133
|
+
function readField(value, field) {
|
|
134
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, field);
|
|
135
|
+
if (descriptor === undefined || !('value' in descriptor))
|
|
136
|
+
validation();
|
|
137
|
+
return descriptor.value;
|
|
138
|
+
}
|
|
139
|
+
function boundedIdentifier(value) {
|
|
140
|
+
if (typeof value !== 'string' || value.trim().length === 0 || /[\p{C}]/u.test(value) || Buffer.byteLength(value, 'utf8') > MAX_IDENTIFIER_BYTES)
|
|
141
|
+
validation();
|
|
142
|
+
return value;
|
|
143
|
+
}
|
|
144
|
+
function boundedStoredIdentifier(value) {
|
|
145
|
+
if (typeof value !== 'string' || value.trim().length === 0 || /[\p{C}]/u.test(value) || Buffer.byteLength(value, 'utf8') > MAX_IDENTIFIER_BYTES)
|
|
146
|
+
integrity();
|
|
147
|
+
return value;
|
|
148
|
+
}
|
|
149
|
+
function nonNegativeSafeInteger(value) {
|
|
150
|
+
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0)
|
|
151
|
+
validation();
|
|
152
|
+
return value;
|
|
153
|
+
}
|
|
154
|
+
function positiveSafeInteger(value) {
|
|
155
|
+
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 1)
|
|
156
|
+
validation();
|
|
157
|
+
return value;
|
|
158
|
+
}
|
|
159
|
+
function storedNonNegativeSafeInteger(value) {
|
|
160
|
+
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0)
|
|
161
|
+
integrity();
|
|
162
|
+
return value;
|
|
163
|
+
}
|
|
164
|
+
function storedPositiveSafeInteger(value) {
|
|
165
|
+
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 1)
|
|
166
|
+
integrity();
|
|
167
|
+
return value;
|
|
168
|
+
}
|
|
169
|
+
function hash(value) {
|
|
170
|
+
if (typeof value !== 'string' || !/^[0-9a-f]{64}$/u.test(value))
|
|
171
|
+
validation();
|
|
172
|
+
return value;
|
|
173
|
+
}
|
|
174
|
+
function storedHash(value) {
|
|
175
|
+
if (typeof value !== 'string' || !/^[0-9a-f]{64}$/u.test(value))
|
|
176
|
+
integrity();
|
|
177
|
+
return value;
|
|
178
|
+
}
|
|
179
|
+
function timestamp(value) {
|
|
180
|
+
if (typeof value !== 'string' || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/u.test(value))
|
|
181
|
+
validation();
|
|
182
|
+
const parsed = Date.parse(value);
|
|
183
|
+
if (!Number.isFinite(parsed) || new Date(parsed).toISOString() !== value)
|
|
184
|
+
validation();
|
|
185
|
+
return value;
|
|
186
|
+
}
|
|
187
|
+
function storedTimestamp(value) {
|
|
188
|
+
if (typeof value !== 'string' || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/u.test(value))
|
|
189
|
+
integrity();
|
|
190
|
+
const parsed = Date.parse(value);
|
|
191
|
+
if (!Number.isFinite(parsed) || new Date(parsed).toISOString() !== value)
|
|
192
|
+
integrity();
|
|
193
|
+
return value;
|
|
194
|
+
}
|
|
195
|
+
function booleanValue(value) {
|
|
196
|
+
if (typeof value !== 'boolean')
|
|
197
|
+
validation();
|
|
198
|
+
return value;
|
|
199
|
+
}
|
|
200
|
+
function storedBoolean(value) {
|
|
201
|
+
if (value !== 0 && value !== 1)
|
|
202
|
+
integrity();
|
|
203
|
+
return value === 1;
|
|
204
|
+
}
|
|
205
|
+
function scoreComponents(value) {
|
|
206
|
+
const object = objectInput(value, CONTEXT_RANKING_COMPONENTS, true);
|
|
207
|
+
const keys = ownKeys(object);
|
|
208
|
+
if (keys.length !== CONTEXT_RANKING_COMPONENTS.length || CONTEXT_RANKING_COMPONENTS.some((component) => !keys.includes(component)))
|
|
209
|
+
validation();
|
|
210
|
+
const result = {};
|
|
211
|
+
for (const component of CONTEXT_RANKING_COMPONENTS) {
|
|
212
|
+
const score = readField(object, component);
|
|
213
|
+
if (typeof score !== 'number' || !Number.isSafeInteger(score) || !Number.isFinite(score) || score < -MAX_SCORE_COMPONENT || score > MAX_SCORE_COMPONENT)
|
|
214
|
+
validation();
|
|
215
|
+
result[component] = score;
|
|
216
|
+
}
|
|
217
|
+
return result;
|
|
218
|
+
}
|
|
219
|
+
function storedScoreComponents(value) {
|
|
220
|
+
try {
|
|
221
|
+
return scoreComponents(value);
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
integrity();
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function selectionReasons(value) {
|
|
228
|
+
const array = arrayInput(value);
|
|
229
|
+
if (array.length === 0)
|
|
230
|
+
validation();
|
|
231
|
+
const result = [];
|
|
232
|
+
let previousIndex = -1;
|
|
233
|
+
for (const item of array) {
|
|
234
|
+
if (typeof item !== 'string')
|
|
235
|
+
validation();
|
|
236
|
+
const reasonIndex = CONTEXT_SELECTION_REASON_ORDER.indexOf(item);
|
|
237
|
+
if (reasonIndex < 0 || reasonIndex <= previousIndex)
|
|
238
|
+
validation();
|
|
239
|
+
previousIndex = reasonIndex;
|
|
240
|
+
result.push(item);
|
|
241
|
+
}
|
|
242
|
+
return result;
|
|
243
|
+
}
|
|
244
|
+
function storedSelectionReasons(value) {
|
|
245
|
+
try {
|
|
246
|
+
return selectionReasons(value);
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
integrity();
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
function validateDeliveryItems(value) {
|
|
253
|
+
const array = arrayInput(value);
|
|
254
|
+
if (array.length > MAX_ITEMS)
|
|
255
|
+
validation();
|
|
256
|
+
const entries = new Set();
|
|
257
|
+
return array.map((item, index) => {
|
|
258
|
+
const object = objectInput(item, ['entryId', 'entryRevision', 'rank', 'scoreComponents', 'selectionReasons'], true);
|
|
259
|
+
const entryId = boundedIdentifier(readField(object, 'entryId'));
|
|
260
|
+
if (entries.has(entryId))
|
|
261
|
+
validation();
|
|
262
|
+
entries.add(entryId);
|
|
263
|
+
const entryRevision = positiveSafeInteger(readField(object, 'entryRevision'));
|
|
264
|
+
const rank = positiveSafeInteger(readField(object, 'rank'));
|
|
265
|
+
if (rank !== index + 1)
|
|
266
|
+
validation();
|
|
267
|
+
return {
|
|
268
|
+
entryId,
|
|
269
|
+
entryRevision,
|
|
270
|
+
rank,
|
|
271
|
+
scoreComponents: scoreComponents(readField(object, 'scoreComponents')),
|
|
272
|
+
selectionReasons: selectionReasons(readField(object, 'selectionReasons')),
|
|
273
|
+
};
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
function sanitizeExternalError(value, workspace) {
|
|
277
|
+
if (typeof value !== 'string' || value.length === 0)
|
|
278
|
+
validation();
|
|
279
|
+
let sanitized;
|
|
280
|
+
try {
|
|
281
|
+
sanitized = sanitizeJson({ error: value }, { workspace }).value;
|
|
282
|
+
}
|
|
283
|
+
catch {
|
|
284
|
+
validation();
|
|
285
|
+
}
|
|
286
|
+
if (!isPlainObject(sanitized))
|
|
287
|
+
validation();
|
|
288
|
+
const error = readField(sanitized, 'error');
|
|
289
|
+
if (typeof error !== 'string' || error.length === 0 || Buffer.byteLength(error, 'utf8') > MAX_EXTERNAL_ERROR_BYTES)
|
|
290
|
+
validation();
|
|
291
|
+
return error;
|
|
292
|
+
}
|
|
293
|
+
function validateExternalSummary(value, workspace) {
|
|
294
|
+
const object = objectInput(value, ['attempted', 'imported', 'sources'], true);
|
|
295
|
+
const attempted = booleanValue(readField(object, 'attempted'));
|
|
296
|
+
const imported = nonNegativeSafeInteger(readField(object, 'imported'));
|
|
297
|
+
const sourceArray = arrayInput(readField(object, 'sources'));
|
|
298
|
+
if (sourceArray.length > MAX_SOURCES)
|
|
299
|
+
validation();
|
|
300
|
+
const sourceIds = new Set();
|
|
301
|
+
const sources = sourceArray.map((source) => {
|
|
302
|
+
const sourceObject = objectInput(source, ['sourceId', 'commit', 'documents', 'imported', 'error'], false);
|
|
303
|
+
for (const field of ['sourceId', 'commit', 'documents', 'imported']) {
|
|
304
|
+
if (!hasOwn(sourceObject, field))
|
|
305
|
+
validation();
|
|
306
|
+
}
|
|
307
|
+
const sourceId = boundedIdentifier(readField(sourceObject, 'sourceId'));
|
|
308
|
+
if (sourceIds.has(sourceId))
|
|
309
|
+
validation();
|
|
310
|
+
sourceIds.add(sourceId);
|
|
311
|
+
const rawCommit = readField(sourceObject, 'commit');
|
|
312
|
+
const commit = rawCommit === null
|
|
313
|
+
? null
|
|
314
|
+
: typeof rawCommit === 'string' && rawCommit.length > 0 && /^[0-9a-f]+$/u.test(rawCommit) && Buffer.byteLength(rawCommit, 'utf8') <= MAX_IDENTIFIER_BYTES
|
|
315
|
+
? rawCommit
|
|
316
|
+
: validation();
|
|
317
|
+
const documents = nonNegativeSafeInteger(readField(sourceObject, 'documents'));
|
|
318
|
+
const sourceImported = nonNegativeSafeInteger(readField(sourceObject, 'imported'));
|
|
319
|
+
if (sourceImported > documents)
|
|
320
|
+
validation();
|
|
321
|
+
const result = { sourceId, commit, documents, imported: sourceImported };
|
|
322
|
+
if (hasOwn(sourceObject, 'error'))
|
|
323
|
+
result.error = sanitizeExternalError(readField(sourceObject, 'error'), workspace);
|
|
324
|
+
return result;
|
|
325
|
+
});
|
|
326
|
+
if (!attempted && (imported !== 0 || sources.length !== 0))
|
|
327
|
+
validation();
|
|
328
|
+
const sourceTotal = sources.reduce((total, source) => total + source.imported, 0);
|
|
329
|
+
if (imported !== sourceTotal)
|
|
330
|
+
validation();
|
|
331
|
+
const summary = { attempted, imported, sources };
|
|
332
|
+
if (Buffer.byteLength(canonicalJson(summary), 'utf8') > MAX_EXTERNAL_SUMMARY_BYTES)
|
|
333
|
+
validation();
|
|
334
|
+
return summary;
|
|
335
|
+
}
|
|
336
|
+
function validateContextDeliveryInput(value) {
|
|
337
|
+
try {
|
|
338
|
+
const object = objectInput(value, [
|
|
339
|
+
'workspace', 'deliveryId', 'runId', 'throughSequence', 'intakeSessionId', 'taskProfileHash',
|
|
340
|
+
'queryHash', 'policyVersion', 'externalSyncSummary', 'charBudget', 'charCount', 'truncated',
|
|
341
|
+
'createdAt', 'items',
|
|
342
|
+
], true);
|
|
343
|
+
const workspace = boundedIdentifier(readField(object, 'workspace'));
|
|
344
|
+
const deliveryId = boundedIdentifier(readField(object, 'deliveryId'));
|
|
345
|
+
const runId = boundedIdentifier(readField(object, 'runId'));
|
|
346
|
+
const throughSequence = nonNegativeSafeInteger(readField(object, 'throughSequence'));
|
|
347
|
+
const rawIntakeSessionId = readField(object, 'intakeSessionId');
|
|
348
|
+
const intakeSessionId = rawIntakeSessionId === null ? null : boundedIdentifier(rawIntakeSessionId);
|
|
349
|
+
const taskProfileHash = hash(readField(object, 'taskProfileHash'));
|
|
350
|
+
const queryHash = hash(readField(object, 'queryHash'));
|
|
351
|
+
const policyVersion = boundedIdentifier(readField(object, 'policyVersion'));
|
|
352
|
+
const externalSyncSummary = validateExternalSummary(readField(object, 'externalSyncSummary'), workspace);
|
|
353
|
+
const charBudget = readField(object, 'charBudget');
|
|
354
|
+
if (typeof charBudget !== 'number' || !Number.isSafeInteger(charBudget) || charBudget < 1 || charBudget > MAX_CHAR_BUDGET)
|
|
355
|
+
validation();
|
|
356
|
+
const charCount = readField(object, 'charCount');
|
|
357
|
+
if (typeof charCount !== 'number' || !Number.isSafeInteger(charCount) || charCount < 0 || charCount > charBudget)
|
|
358
|
+
validation();
|
|
359
|
+
const truncated = booleanValue(readField(object, 'truncated'));
|
|
360
|
+
const createdAt = timestamp(readField(object, 'createdAt'));
|
|
361
|
+
const items = validateDeliveryItems(readField(object, 'items'));
|
|
362
|
+
return {
|
|
363
|
+
workspace,
|
|
364
|
+
deliveryId,
|
|
365
|
+
runId,
|
|
366
|
+
throughSequence,
|
|
367
|
+
intakeSessionId,
|
|
368
|
+
taskProfileHash,
|
|
369
|
+
queryHash,
|
|
370
|
+
policyVersion,
|
|
371
|
+
externalSyncSummary,
|
|
372
|
+
charBudget,
|
|
373
|
+
charCount,
|
|
374
|
+
truncated,
|
|
375
|
+
createdAt,
|
|
376
|
+
items,
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
catch {
|
|
380
|
+
validation();
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
function validateReadInput(value) {
|
|
384
|
+
try {
|
|
385
|
+
const object = objectInput(value, ['workspace', 'deliveryId'], true);
|
|
386
|
+
return {
|
|
387
|
+
workspace: boundedIdentifier(readField(object, 'workspace')),
|
|
388
|
+
deliveryId: boundedIdentifier(readField(object, 'deliveryId')),
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
catch {
|
|
392
|
+
validation();
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
function encodeCursor(cursor) {
|
|
396
|
+
return Buffer.from(JSON.stringify(cursor), 'utf8').toString('base64url');
|
|
397
|
+
}
|
|
398
|
+
function parseCursor(value) {
|
|
399
|
+
if (value === undefined)
|
|
400
|
+
return undefined;
|
|
401
|
+
try {
|
|
402
|
+
if (typeof value !== 'string' || !/^[A-Za-z0-9_-]+$/u.test(value))
|
|
403
|
+
validation();
|
|
404
|
+
const decoded = Buffer.from(value, 'base64url');
|
|
405
|
+
if (decoded.toString('base64url') !== value)
|
|
406
|
+
validation();
|
|
407
|
+
const parsed = JSON.parse(decoded.toString('utf8'));
|
|
408
|
+
if (!isPlainObject(parsed))
|
|
409
|
+
validation();
|
|
410
|
+
const keys = ownKeys(parsed);
|
|
411
|
+
if (keys.length !== 3 || keys[0] !== 'version' || keys[1] !== 'createdAt' || keys[2] !== 'deliveryId')
|
|
412
|
+
validation();
|
|
413
|
+
if (readField(parsed, 'version') !== DELIVERY_CURSOR_VERSION)
|
|
414
|
+
validation();
|
|
415
|
+
const createdAt = timestamp(readField(parsed, 'createdAt'));
|
|
416
|
+
const deliveryId = boundedIdentifier(readField(parsed, 'deliveryId'));
|
|
417
|
+
const cursor = { version: DELIVERY_CURSOR_VERSION, createdAt, deliveryId };
|
|
418
|
+
if (encodeCursor(cursor) !== value)
|
|
419
|
+
validation();
|
|
420
|
+
return cursor;
|
|
421
|
+
}
|
|
422
|
+
catch {
|
|
423
|
+
validation();
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
function validateListInput(value) {
|
|
427
|
+
try {
|
|
428
|
+
const object = objectInput(value, ['workspace', 'runId', 'cursor', 'limit'], false);
|
|
429
|
+
if (!hasOwn(object, 'workspace') || !hasOwn(object, 'runId'))
|
|
430
|
+
validation();
|
|
431
|
+
const workspace = boundedIdentifier(readField(object, 'workspace'));
|
|
432
|
+
const runId = boundedIdentifier(readField(object, 'runId'));
|
|
433
|
+
const rawLimit = hasOwn(object, 'limit') ? readField(object, 'limit') : undefined;
|
|
434
|
+
const limit = rawLimit === undefined ? DEFAULT_LIMIT : rawLimit;
|
|
435
|
+
if (typeof limit !== 'number' || !Number.isSafeInteger(limit) || limit < 1 || limit > MAX_LIMIT)
|
|
436
|
+
validation();
|
|
437
|
+
const cursor = parseCursor(hasOwn(object, 'cursor') ? readField(object, 'cursor') : undefined);
|
|
438
|
+
return { workspace, runId, limit, ...(cursor === undefined ? {} : { cursor }) };
|
|
439
|
+
}
|
|
440
|
+
catch {
|
|
441
|
+
validation();
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
function canonicalDeliveryBody(input) {
|
|
445
|
+
return canonicalJson({
|
|
446
|
+
workspace: input.workspace,
|
|
447
|
+
deliveryId: input.deliveryId,
|
|
448
|
+
runId: input.runId,
|
|
449
|
+
throughSequence: input.throughSequence,
|
|
450
|
+
intakeSessionId: input.intakeSessionId,
|
|
451
|
+
taskProfileHash: input.taskProfileHash,
|
|
452
|
+
queryHash: input.queryHash,
|
|
453
|
+
policyVersion: input.policyVersion,
|
|
454
|
+
externalSyncSummary: input.externalSyncSummary,
|
|
455
|
+
charBudget: input.charBudget,
|
|
456
|
+
charCount: input.charCount,
|
|
457
|
+
truncated: input.truncated,
|
|
458
|
+
createdAt: input.createdAt,
|
|
459
|
+
items: input.items.map((item) => ({
|
|
460
|
+
entryId: item.entryId,
|
|
461
|
+
entryRevision: item.entryRevision,
|
|
462
|
+
rank: item.rank,
|
|
463
|
+
scoreComponents: item.scoreComponents,
|
|
464
|
+
selectionReasons: item.selectionReasons,
|
|
465
|
+
})),
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
function selectHeaderByDeliveryId(database, deliveryId) {
|
|
469
|
+
return database.prepare(`
|
|
470
|
+
SELECT cd.delivery_id, cd.run_id, cd.through_sequence, cd.intake_session_id,
|
|
471
|
+
cd.task_profile_hash, cd.query_hash, cd.policy_version,
|
|
472
|
+
cd.external_sync_summary_json, cd.char_budget, cd.char_count,
|
|
473
|
+
cd.truncated, cd.created_at,
|
|
474
|
+
lr.workspace AS run_workspace, lr.last_sequence AS run_last_sequence
|
|
475
|
+
FROM context_deliveries AS cd
|
|
476
|
+
LEFT JOIN ledger_runs AS lr ON lr.run_id = cd.run_id
|
|
477
|
+
WHERE cd.delivery_id = ?
|
|
478
|
+
`).get(deliveryId);
|
|
479
|
+
}
|
|
480
|
+
function assertRunForWrite(database, input) {
|
|
481
|
+
const run = database.prepare('SELECT run_id, last_sequence FROM ledger_runs WHERE run_id = ? AND workspace = ?').get(input.runId, input.workspace);
|
|
482
|
+
if (!run)
|
|
483
|
+
notFound();
|
|
484
|
+
if (typeof run.run_id !== 'string')
|
|
485
|
+
integrity();
|
|
486
|
+
const lastSequence = storedNonNegativeSafeInteger(run.last_sequence);
|
|
487
|
+
if (input.throughSequence > lastSequence)
|
|
488
|
+
conflict();
|
|
489
|
+
if (input.intakeSessionId !== null) {
|
|
490
|
+
const intake = database.prepare(`
|
|
491
|
+
SELECT ri.session_id, s.id AS session_id_join, s.workspace AS session_workspace
|
|
492
|
+
FROM run_intakes AS ri
|
|
493
|
+
LEFT JOIN akinator_sessions AS s ON s.id = ri.session_id
|
|
494
|
+
WHERE ri.run_id = ?
|
|
495
|
+
`).get(input.runId);
|
|
496
|
+
if (!intake || intake.session_id !== input.intakeSessionId || intake.session_id_join !== input.intakeSessionId || intake.session_workspace !== input.workspace)
|
|
497
|
+
notFound();
|
|
498
|
+
}
|
|
499
|
+
for (const item of input.items) {
|
|
500
|
+
const entry = database.prepare('SELECT id, workspace, revision FROM entries WHERE id = ?').get(item.entryId);
|
|
501
|
+
if (!entry || entry.workspace !== input.workspace || entry.id !== item.entryId)
|
|
502
|
+
notFound();
|
|
503
|
+
const revision = storedPositiveSafeInteger(entry.revision);
|
|
504
|
+
if (item.entryRevision > revision)
|
|
505
|
+
conflict();
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
function validateStoredJson(value) {
|
|
509
|
+
if (typeof value !== 'string')
|
|
510
|
+
integrity();
|
|
511
|
+
let parsed;
|
|
512
|
+
try {
|
|
513
|
+
parsed = JSON.parse(value);
|
|
514
|
+
}
|
|
515
|
+
catch {
|
|
516
|
+
integrity();
|
|
517
|
+
}
|
|
518
|
+
try {
|
|
519
|
+
if (canonicalJson(parsed) !== value)
|
|
520
|
+
integrity();
|
|
521
|
+
}
|
|
522
|
+
catch {
|
|
523
|
+
integrity();
|
|
524
|
+
}
|
|
525
|
+
return parsed;
|
|
526
|
+
}
|
|
527
|
+
function validateStoredExternalSummary(value, workspace) {
|
|
528
|
+
try {
|
|
529
|
+
const parsed = validateStoredJson(value);
|
|
530
|
+
const normalized = validateExternalSummary(parsed, workspace);
|
|
531
|
+
if (canonicalJson(normalized) !== value)
|
|
532
|
+
integrity();
|
|
533
|
+
return normalized;
|
|
534
|
+
}
|
|
535
|
+
catch (error) {
|
|
536
|
+
if (isKiokukoError(error) && error.code === 'INTEGRITY_ERROR')
|
|
537
|
+
throw error;
|
|
538
|
+
integrity();
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
function validateStoredHeader(row, workspace) {
|
|
542
|
+
const deliveryId = boundedStoredIdentifier(row.delivery_id);
|
|
543
|
+
const runId = boundedStoredIdentifier(row.run_id);
|
|
544
|
+
const runWorkspace = boundedStoredIdentifier(row.run_workspace);
|
|
545
|
+
if (runWorkspace !== workspace)
|
|
546
|
+
notFound();
|
|
547
|
+
const lastSequence = storedNonNegativeSafeInteger(row.run_last_sequence);
|
|
548
|
+
const throughSequence = storedNonNegativeSafeInteger(row.through_sequence);
|
|
549
|
+
if (throughSequence > lastSequence)
|
|
550
|
+
integrity();
|
|
551
|
+
const rawIntakeSessionId = row.intake_session_id;
|
|
552
|
+
const intakeSessionId = rawIntakeSessionId === null ? null : boundedStoredIdentifier(rawIntakeSessionId);
|
|
553
|
+
const taskProfileHash = storedHash(row.task_profile_hash);
|
|
554
|
+
const queryHash = storedHash(row.query_hash);
|
|
555
|
+
const policyVersion = boundedStoredIdentifier(row.policy_version);
|
|
556
|
+
const externalSyncSummary = validateStoredExternalSummary(row.external_sync_summary_json, workspace);
|
|
557
|
+
const charBudget = storedPositiveSafeInteger(row.char_budget);
|
|
558
|
+
if (charBudget > MAX_CHAR_BUDGET)
|
|
559
|
+
integrity();
|
|
560
|
+
const charCount = storedNonNegativeSafeInteger(row.char_count);
|
|
561
|
+
if (charCount > charBudget)
|
|
562
|
+
integrity();
|
|
563
|
+
const truncated = storedBoolean(row.truncated);
|
|
564
|
+
const createdAt = storedTimestamp(row.created_at);
|
|
565
|
+
return {
|
|
566
|
+
workspace,
|
|
567
|
+
deliveryId,
|
|
568
|
+
runId,
|
|
569
|
+
throughSequence,
|
|
570
|
+
intakeSessionId,
|
|
571
|
+
taskProfileHash,
|
|
572
|
+
queryHash,
|
|
573
|
+
policyVersion,
|
|
574
|
+
externalSyncSummary,
|
|
575
|
+
charBudget,
|
|
576
|
+
charCount,
|
|
577
|
+
truncated,
|
|
578
|
+
createdAt,
|
|
579
|
+
items: [],
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
function selectDeliveryEntries(database, deliveryId) {
|
|
583
|
+
return database.prepare(`
|
|
584
|
+
SELECT cde.delivery_id, cde.entry_id, cde.entry_revision, cde.rank,
|
|
585
|
+
cde.score_components_json, cde.selection_reason_json,
|
|
586
|
+
e.workspace AS entry_workspace, e.revision AS current_revision
|
|
587
|
+
FROM context_delivery_entries AS cde
|
|
588
|
+
LEFT JOIN entries AS e ON e.id = cde.entry_id
|
|
589
|
+
WHERE cde.delivery_id = ?
|
|
590
|
+
ORDER BY cde.rank ASC, cde.entry_id ASC
|
|
591
|
+
`).all(deliveryId);
|
|
592
|
+
}
|
|
593
|
+
function validateStoredEntries(database, header) {
|
|
594
|
+
const rows = selectDeliveryEntries(database, header.deliveryId);
|
|
595
|
+
if (rows.length > MAX_ITEMS)
|
|
596
|
+
integrity();
|
|
597
|
+
const entryIds = new Set();
|
|
598
|
+
let expectedRank = 1;
|
|
599
|
+
return rows.map((row) => {
|
|
600
|
+
const deliveryId = boundedStoredIdentifier(row.delivery_id);
|
|
601
|
+
const entryId = boundedStoredIdentifier(row.entry_id);
|
|
602
|
+
if (deliveryId !== header.deliveryId || entryIds.has(entryId))
|
|
603
|
+
integrity();
|
|
604
|
+
entryIds.add(entryId);
|
|
605
|
+
const entryWorkspace = boundedStoredIdentifier(row.entry_workspace);
|
|
606
|
+
if (entryWorkspace !== header.workspace)
|
|
607
|
+
integrity();
|
|
608
|
+
const currentRevision = storedPositiveSafeInteger(row.current_revision);
|
|
609
|
+
const entryRevision = storedPositiveSafeInteger(row.entry_revision);
|
|
610
|
+
if (entryRevision > currentRevision)
|
|
611
|
+
integrity();
|
|
612
|
+
const rank = storedPositiveSafeInteger(row.rank);
|
|
613
|
+
if (rank !== expectedRank)
|
|
614
|
+
integrity();
|
|
615
|
+
expectedRank += 1;
|
|
616
|
+
const scoreValue = validateStoredJson(row.score_components_json);
|
|
617
|
+
const reasonValue = validateStoredJson(row.selection_reason_json);
|
|
618
|
+
const score = storedScoreComponents(scoreValue);
|
|
619
|
+
const reasons = storedSelectionReasons(reasonValue);
|
|
620
|
+
if (canonicalJson(score) !== row.score_components_json || canonicalJson(reasons) !== row.selection_reason_json)
|
|
621
|
+
integrity();
|
|
622
|
+
return { entryId, entryRevision, rank, scoreComponents: score, selectionReasons: reasons };
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
function assertStoredIntakeLink(database, header) {
|
|
626
|
+
if (header.intakeSessionId === null)
|
|
627
|
+
return;
|
|
628
|
+
const intake = database.prepare(`
|
|
629
|
+
SELECT ri.run_id, ri.session_id, s.id AS session_id_join, s.workspace AS session_workspace
|
|
630
|
+
FROM run_intakes AS ri
|
|
631
|
+
LEFT JOIN akinator_sessions AS s ON s.id = ri.session_id
|
|
632
|
+
WHERE ri.run_id = ?
|
|
633
|
+
`).get(header.runId);
|
|
634
|
+
if (!intake || intake.run_id !== header.runId || intake.session_id !== header.intakeSessionId || intake.session_id_join !== header.intakeSessionId || intake.session_workspace !== header.workspace)
|
|
635
|
+
integrity();
|
|
636
|
+
}
|
|
637
|
+
function readStoredDelivery(database, workspace, deliveryId) {
|
|
638
|
+
const row = selectHeaderByDeliveryId(database, deliveryId);
|
|
639
|
+
if (!row)
|
|
640
|
+
notFound();
|
|
641
|
+
if (row.run_workspace === null || row.run_workspace === undefined)
|
|
642
|
+
integrity();
|
|
643
|
+
if (row.run_workspace !== workspace)
|
|
644
|
+
notFound();
|
|
645
|
+
const header = validateStoredHeader(row, workspace);
|
|
646
|
+
assertStoredIntakeLink(database, header);
|
|
647
|
+
const items = validateStoredEntries(database, header);
|
|
648
|
+
const view = {
|
|
649
|
+
...header,
|
|
650
|
+
items: items.map((item) => ({ ...item, scoreComponents: { ...item.scoreComponents }, selectionReasons: [...item.selectionReasons], untrusted: true })),
|
|
651
|
+
untrusted: true,
|
|
652
|
+
};
|
|
653
|
+
return view;
|
|
654
|
+
}
|
|
655
|
+
function writeContextDelivery(database, input) {
|
|
656
|
+
const existing = selectHeaderByDeliveryId(database, input.deliveryId);
|
|
657
|
+
if (existing) {
|
|
658
|
+
if (existing.run_workspace !== input.workspace)
|
|
659
|
+
conflict();
|
|
660
|
+
const stored = readStoredDelivery(database, input.workspace, input.deliveryId);
|
|
661
|
+
if (canonicalDeliveryBody(stored) === canonicalDeliveryBody(input))
|
|
662
|
+
return stored;
|
|
663
|
+
conflict();
|
|
664
|
+
}
|
|
665
|
+
assertRunForWrite(database, input);
|
|
666
|
+
const summaryJson = canonicalJson(input.externalSyncSummary);
|
|
667
|
+
database.prepare(`
|
|
668
|
+
INSERT INTO context_deliveries (
|
|
669
|
+
delivery_id, run_id, through_sequence, intake_session_id, task_profile_hash, query_hash,
|
|
670
|
+
policy_version, external_sync_summary_json, char_budget, char_count, truncated, created_at
|
|
671
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
672
|
+
`).run(input.deliveryId, input.runId, input.throughSequence, input.intakeSessionId, input.taskProfileHash, input.queryHash, input.policyVersion, summaryJson, input.charBudget, input.charCount, input.truncated ? 1 : 0, input.createdAt);
|
|
673
|
+
for (const item of input.items) {
|
|
674
|
+
database.prepare(`
|
|
675
|
+
INSERT INTO context_delivery_entries (
|
|
676
|
+
delivery_id, entry_id, entry_revision, rank, score_components_json, selection_reason_json
|
|
677
|
+
) VALUES (?, ?, ?, ?, ?, ?)
|
|
678
|
+
`).run(input.deliveryId, item.entryId, item.entryRevision, item.rank, canonicalJson(item.scoreComponents), canonicalJson(item.selectionReasons));
|
|
679
|
+
}
|
|
680
|
+
return readStoredDelivery(database, input.workspace, input.deliveryId);
|
|
681
|
+
}
|
|
682
|
+
export function recordContextDeliveryInTransaction(database, input) {
|
|
683
|
+
const validated = validateContextDeliveryInput(input);
|
|
684
|
+
try {
|
|
685
|
+
return writeContextDelivery(database, validated);
|
|
686
|
+
}
|
|
687
|
+
catch (error) {
|
|
688
|
+
normalizeDatabaseError(error);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
export function recordContextDelivery(database, input) {
|
|
692
|
+
const validated = validateContextDeliveryInput(input);
|
|
693
|
+
try {
|
|
694
|
+
return withImmediateTransaction(database, () => writeContextDelivery(database, validated));
|
|
695
|
+
}
|
|
696
|
+
catch (error) {
|
|
697
|
+
normalizeDatabaseError(error);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
export function readContextDelivery(database, input) {
|
|
701
|
+
const validated = validateReadInput(input);
|
|
702
|
+
try {
|
|
703
|
+
return readStoredDelivery(database, validated.workspace, validated.deliveryId);
|
|
704
|
+
}
|
|
705
|
+
catch (error) {
|
|
706
|
+
normalizeDatabaseError(error);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
export function listContextDeliveries(database, input) {
|
|
710
|
+
const validated = validateListInput(input);
|
|
711
|
+
try {
|
|
712
|
+
const run = database.prepare('SELECT run_id, workspace, last_sequence FROM ledger_runs WHERE run_id = ? AND workspace = ?').get(validated.runId, validated.workspace);
|
|
713
|
+
if (!run)
|
|
714
|
+
notFound();
|
|
715
|
+
if (run.run_id !== validated.runId || run.workspace !== validated.workspace)
|
|
716
|
+
integrity();
|
|
717
|
+
storedNonNegativeSafeInteger(run.last_sequence);
|
|
718
|
+
const parameters = [validated.runId, validated.workspace];
|
|
719
|
+
let cursorClause = '';
|
|
720
|
+
if (validated.cursor !== undefined) {
|
|
721
|
+
cursorClause = ' AND (cd.created_at < ? OR (cd.created_at = ? AND cd.delivery_id > ?))';
|
|
722
|
+
parameters.push(validated.cursor.createdAt, validated.cursor.createdAt, validated.cursor.deliveryId);
|
|
723
|
+
}
|
|
724
|
+
parameters.push(validated.limit + 1);
|
|
725
|
+
const rows = database.prepare(`
|
|
726
|
+
SELECT cd.delivery_id, cd.run_id, cd.through_sequence, cd.intake_session_id,
|
|
727
|
+
cd.task_profile_hash, cd.query_hash, cd.policy_version,
|
|
728
|
+
cd.external_sync_summary_json, cd.char_budget, cd.char_count,
|
|
729
|
+
cd.truncated, cd.created_at,
|
|
730
|
+
lr.workspace AS run_workspace, lr.last_sequence AS run_last_sequence
|
|
731
|
+
FROM context_deliveries AS cd
|
|
732
|
+
LEFT JOIN ledger_runs AS lr ON lr.run_id = cd.run_id
|
|
733
|
+
WHERE cd.run_id = ? AND lr.workspace = ?${cursorClause}
|
|
734
|
+
ORDER BY cd.created_at DESC, cd.delivery_id ASC
|
|
735
|
+
LIMIT ?
|
|
736
|
+
`).all(...parameters);
|
|
737
|
+
const pageRows = rows.slice(0, validated.limit);
|
|
738
|
+
const items = pageRows.map((row) => {
|
|
739
|
+
const header = validateStoredHeader(row, validated.workspace);
|
|
740
|
+
assertStoredIntakeLink(database, header);
|
|
741
|
+
const storedItems = validateStoredEntries(database, header);
|
|
742
|
+
return {
|
|
743
|
+
...header,
|
|
744
|
+
items: storedItems.map((item) => ({ ...item, scoreComponents: { ...item.scoreComponents }, selectionReasons: [...item.selectionReasons], untrusted: true })),
|
|
745
|
+
untrusted: true,
|
|
746
|
+
};
|
|
747
|
+
});
|
|
748
|
+
const last = pageRows.at(-1);
|
|
749
|
+
const nextCursor = rows.length > validated.limit && last !== undefined
|
|
750
|
+
? encodeCursor({ version: DELIVERY_CURSOR_VERSION, createdAt: storedTimestamp(last.created_at), deliveryId: boundedStoredIdentifier(last.delivery_id) })
|
|
751
|
+
: null;
|
|
752
|
+
return { items, nextCursor };
|
|
753
|
+
}
|
|
754
|
+
catch (error) {
|
|
755
|
+
normalizeDatabaseError(error);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
//# sourceMappingURL=delivery.js.map
|