@jungjaehoon/mama-core 2.4.1 → 4.0.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/README.md +76 -239
- package/db/migrations/030-case-first-memory-substrate.sql +13 -98
- package/db/migrations/034-add-connector-event-scope-columns.sql +9 -13
- package/db/migrations/039-add-connector-event-operator-ingest-seq.sql +9 -95
- package/db/migrations/062-refresh-connector-event-sequences.sql +9 -113
- package/db/migrations/063-refresh-legacy-connector-event-updates.sql +9 -32
- package/db/migrations/067-add-connector-event-source-entity-id.sql +9 -13
- package/db/migrations/069-create-registry-nodes.sql +52 -0
- package/db/migrations/070-record-identity.sql +35 -0
- package/db/migrations/071-service-operation-origins.sql +187 -0
- package/db/migrations/072-observation-versions.sql +29 -0
- package/db/migrations/073-registry-corrections.sql +45 -0
- package/db/migrations/074-work-graph-ref-kinds.sql +39 -0
- package/db/migrations/075-agent-judgments.sql +58 -0
- package/db/migrations/076-scoped-checkpoint-bindings.sql +15 -0
- package/db/migrations/077-legacy-record-kind.sql +6 -0
- package/db/migrations/078-source-ingest-commands.sql +18 -0
- package/db/migrations/079-twin-edge-relations.sql +43 -0
- package/db/migrations/080-restore-duration-days.sql +7 -0
- package/db/migrations/081-mailbox.sql +61 -0
- package/db/migrations/082-commitments-row-id.sql +12 -0
- package/db/migrations/083-observation-is-the-evidence.sql +49 -0
- package/db/migrations/084-scope-kind-is-not-the-cores-to-list.sql +34 -0
- package/db/migrations/085-a-migration-has-a-source.sql +37 -0
- package/db/migrations/086-the-mailbox-is-generic.sql +110 -0
- package/db/migrations/087-mailbox-payload.sql +5 -0
- package/db/migrations/088-native-input-journal.sql +14 -0
- package/db/migrations/089-native-turn-receipt-lookup.sql +3 -0
- package/db/migrations/090-model-run-native-inputs.sql +29 -0
- package/db/migrations/091-native-turn-results.sql +11 -0
- package/db/migrations/092-restore-decision-fts.sql +34 -0
- package/db/migrations/093-native-turn-primary-kind.sql +14 -0
- package/db/migrations/094-commitment-run-provenance.sql +9 -0
- package/db/migrations/095-model-run-native-input-identity.sql +39 -0
- package/db/migrations/096-drop-connector-event-index-fts.sql +9 -0
- package/db/migrations/097-native-input-json-validity.sql +37 -0
- package/db/migrations/098-workflow-memory-kind.sql +105 -0
- package/dist/action-contracts.d.ts +212 -0
- package/dist/action-contracts.js +10 -0
- package/dist/api/catalog.d.ts +118 -0
- package/dist/api/catalog.js +1756 -0
- package/dist/api/dispatch.d.ts +76 -0
- package/dist/api/dispatch.js +372 -0
- package/dist/canonicalize.d.ts +2 -2
- package/dist/canonicalize.js +3 -3
- package/dist/client/client.d.ts +33 -0
- package/dist/client/client.js +123 -0
- package/dist/client/ipc.d.ts +81 -0
- package/dist/client/ipc.js +314 -0
- package/dist/db-adapter/base-adapter.d.ts +6 -66
- package/dist/db-adapter/base-adapter.js +6 -6
- package/dist/db-adapter/index.d.ts +5 -5
- package/dist/db-adapter/index.js +2 -5
- package/dist/db-adapter/node-sqlite-adapter.d.ts +85 -15
- package/dist/db-adapter/node-sqlite-adapter.js +1968 -570
- package/dist/db-manager.d.ts +53 -97
- package/dist/db-manager.js +121 -603
- package/dist/embedding/embedder.d.ts +132 -0
- package/dist/embedding/embedder.js +299 -0
- package/dist/identity/principal-repository.d.ts +2 -2
- package/dist/index.d.ts +43 -58
- package/dist/index.js +97 -145
- package/dist/{context-compile/channel-grant.d.ts → knowledge/access.d.ts} +12 -17
- package/dist/knowledge/access.js +663 -0
- package/dist/knowledge/case-errors.d.ts +31 -0
- package/dist/knowledge/case-errors.js +40 -0
- package/dist/{cases/search-rollup.d.ts → knowledge/case-search-rollup.d.ts} +5 -4
- package/dist/{cases/search-rollup.js → knowledge/case-search-rollup.js} +6 -8
- package/dist/{cases/store.d.ts → knowledge/case-store.d.ts} +3 -6
- package/dist/{cases/store.js → knowledge/case-store.js} +7 -42
- package/dist/{cases/timeline-range.d.ts → knowledge/case-timeline-range.d.ts} +3 -3
- package/dist/{cases/timeline-range.js → knowledge/case-timeline-range.js} +47 -25
- package/dist/{cases/types.d.ts → knowledge/case-types.d.ts} +8 -2
- package/dist/{cases/types.js → knowledge/case-types.js} +1 -1
- package/dist/knowledge/commitments.d.ts +188 -0
- package/dist/knowledge/commitments.js +370 -0
- package/dist/knowledge/decision-edges.d.ts +70 -0
- package/dist/knowledge/decision-edges.js +123 -0
- package/dist/{agent-graph/types.d.ts → knowledge/graph-query.d.ts} +80 -70
- package/dist/knowledge/graph-query.js +1585 -0
- package/dist/knowledge/identity.d.ts +16 -0
- package/dist/knowledge/identity.js +22 -0
- package/dist/knowledge/index.d.ts +47 -0
- package/dist/knowledge/index.js +90 -0
- package/dist/knowledge/judgments.d.ts +118 -0
- package/dist/knowledge/judgments.js +808 -0
- package/dist/knowledge/observations.d.ts +160 -0
- package/dist/knowledge/observations.js +449 -0
- package/dist/knowledge/question-type.d.ts +34 -0
- package/dist/knowledge/question-type.js +70 -0
- package/dist/{search → knowledge}/ranker-features.js +1 -1
- package/dist/{search → knowledge}/search-quality.d.ts +0 -1
- package/dist/knowledge/search.d.ts +38 -0
- package/dist/knowledge/search.js +91 -0
- package/dist/knowledge/source-ingest.d.ts +65 -0
- package/dist/knowledge/source-ingest.js +174 -0
- package/dist/{edges/types.d.ts → knowledge/twin-edge-types.d.ts} +31 -4
- package/dist/{edges/types.js → knowledge/twin-edge-types.js} +13 -2
- package/dist/knowledge/work-dates.d.ts +49 -0
- package/dist/knowledge/work-dates.js +120 -0
- package/dist/mama-api.d.ts +114 -778
- package/dist/mama-api.js +313 -2461
- package/dist/memory/api.d.ts +264 -24
- package/dist/memory/api.js +1633 -843
- package/dist/memory/bootstrap-builder.d.ts +2 -1
- package/dist/memory/bootstrap-builder.js +5 -5
- package/dist/memory/channel-summary-state-store.d.ts +3 -2
- package/dist/memory/channel-summary-state-store.js +53 -51
- package/dist/memory/channel-summary-store.d.ts +5 -3
- package/dist/memory/channel-summary-store.js +3 -8
- package/dist/memory/dashboard-read.d.ts +46 -0
- package/dist/memory/dashboard-read.js +94 -0
- package/dist/memory/event-store.d.ts +3 -3
- package/dist/memory/event-store.js +3 -10
- package/dist/memory/finding-store.d.ts +3 -2
- package/dist/memory/finding-store.js +2 -7
- package/dist/memory/graph-read.d.ts +52 -0
- package/dist/memory/graph-read.js +130 -0
- package/dist/memory/judgment-types.d.ts +394 -0
- package/dist/memory/judgment-types.js +16 -0
- package/dist/memory/provenance-audit.d.ts +5 -2
- package/dist/memory/provenance-audit.js +8 -14
- package/dist/memory/provenance-live.d.ts +141 -0
- package/dist/memory/provenance-live.js +409 -0
- package/dist/memory/provenance-query.d.ts +5 -4
- package/dist/memory/provenance-query.js +21 -29
- package/dist/memory/provenance-resolver.d.ts +191 -0
- package/dist/memory/provenance-resolver.js +155 -0
- package/dist/memory/provenance.d.ts +1 -11
- package/dist/memory/provenance.js +2 -33
- package/dist/memory/recall-sanitize.d.ts +55 -0
- package/dist/memory/recall-sanitize.js +144 -0
- package/dist/memory/secret-filter.d.ts +32 -0
- package/dist/memory/secret-filter.js +126 -0
- package/dist/memory/truth-store.d.ts +2 -1
- package/dist/memory/truth-store.js +1 -4
- package/dist/memory/types.d.ts +74 -24
- package/dist/memory/types.js +75 -5
- package/dist/memory/write-adapters.d.ts +98 -0
- package/dist/memory/write-adapters.js +242 -0
- package/dist/operations/owner-action-effects.d.ts +53 -0
- package/dist/operations/owner-action-effects.js +96 -0
- package/dist/provenance/source-ref.d.ts +1 -1
- package/dist/provenance/source-ref.js +0 -2
- package/dist/registry/corrections.d.ts +31 -0
- package/dist/registry/corrections.js +332 -0
- package/dist/registry/record-identity.d.ts +49 -0
- package/dist/registry/record-identity.js +133 -0
- package/dist/registry/store.d.ts +101 -0
- package/dist/registry/store.js +395 -0
- package/dist/registry/types.d.ts +28 -0
- package/dist/registry/types.js +5 -0
- package/dist/relevance-scorer.js +2 -2
- package/dist/runtime/agent-event-bus.d.ts +50 -0
- package/dist/runtime/agent-event-bus.js +101 -0
- package/dist/runtime/drivers/claude-cli-wrapper.d.ts +155 -0
- package/dist/runtime/drivers/claude-cli-wrapper.js +392 -0
- package/dist/runtime/drivers/cli-arg-redaction.d.ts +2 -0
- package/dist/runtime/drivers/cli-arg-redaction.js +18 -0
- package/dist/runtime/drivers/cli-secret-redaction.d.ts +17 -0
- package/dist/runtime/drivers/cli-secret-redaction.js +126 -0
- package/dist/runtime/drivers/codex-app-server-process.d.ts +277 -0
- package/dist/runtime/drivers/codex-app-server-process.js +2342 -0
- package/dist/runtime/drivers/codex-auxiliary-tools.d.ts +17 -0
- package/dist/runtime/drivers/codex-auxiliary-tools.js +267 -0
- package/dist/runtime/drivers/codex-home.d.ts +20 -0
- package/dist/runtime/drivers/codex-home.js +674 -0
- package/dist/runtime/drivers/codex-thread-registry.d.ts +63 -0
- package/dist/runtime/drivers/codex-thread-registry.js +433 -0
- package/dist/runtime/drivers/persistent-cli-adapter.d.ts +160 -0
- package/dist/runtime/drivers/persistent-cli-adapter.js +396 -0
- package/dist/runtime/drivers/persistent-cli-process.d.ts +424 -0
- package/dist/runtime/drivers/persistent-cli-process.js +1543 -0
- package/dist/runtime/drivers/types.d.ts +456 -0
- package/dist/runtime/drivers/types.js +110 -0
- package/dist/runtime/mailbox.d.ts +223 -0
- package/dist/runtime/mailbox.js +582 -0
- package/dist/runtime/model-run-store.d.ts +28 -0
- package/dist/{model-runs/store.js → runtime/model-run-store.js} +81 -41
- package/dist/{model-runs/types.d.ts → runtime/model-run-types.d.ts} +33 -4
- package/dist/{model-runs/types.js → runtime/model-run-types.js} +1 -1
- package/dist/runtime/native-effect-observer.d.ts +22 -0
- package/dist/runtime/native-effect-observer.js +103 -0
- package/dist/runtime/native-input-journal.d.ts +46 -0
- package/dist/runtime/native-input-journal.js +308 -0
- package/dist/runtime/native-prompt.d.ts +118 -0
- package/dist/runtime/native-prompt.js +496 -0
- package/dist/runtime/native-session.d.ts +10 -0
- package/dist/{agent-graph/index.js → runtime/native-session.js} +9 -6
- package/dist/runtime/native-tool-trace-observer.d.ts +5 -0
- package/dist/runtime/native-tool-trace-observer.js +65 -0
- package/dist/runtime/native-turn.d.ts +272 -0
- package/dist/runtime/native-turn.js +1041 -0
- package/dist/runtime/operations.d.ts +236 -0
- package/dist/runtime/operations.js +565 -0
- package/dist/runtime/post-tool-handler.d.ts +74 -0
- package/dist/runtime/post-tool-handler.js +137 -0
- package/dist/runtime/prompt-layers.d.ts +126 -0
- package/dist/runtime/prompt-layers.js +239 -0
- package/dist/runtime/runtime-process.d.ts +102 -0
- package/dist/runtime/runtime-process.js +206 -0
- package/dist/runtime/runtime.d.ts +278 -0
- package/dist/runtime/runtime.js +563 -0
- package/dist/runtime/session-pool.d.ts +176 -0
- package/dist/runtime/session-pool.js +369 -0
- package/dist/runtime/stimulus-payload.d.ts +5 -0
- package/dist/runtime/stimulus-payload.js +50 -0
- package/dist/runtime/subagent-bridge.d.ts +24 -0
- package/dist/{agent-graph/types.js → runtime/subagent-bridge.js} +1 -1
- package/dist/runtime/text-completion.d.ts +22 -0
- package/dist/{agent-situation/types.js → runtime/text-completion.js} +1 -1
- package/dist/runtime/token-estimator.d.ts +25 -0
- package/dist/runtime/token-estimator.js +75 -0
- package/dist/runtime/tool-trace-store.d.ts +22 -0
- package/dist/{model-runs → runtime}/tool-trace-store.js +46 -27
- package/dist/runtime/trace-summary.d.ts +5 -0
- package/dist/runtime/trace-summary.js +74 -0
- package/dist/runtime/turn-text.d.ts +23 -0
- package/dist/runtime/turn-text.js +41 -0
- package/dist/storage/database.d.ts +67 -0
- package/dist/storage/database.js +158 -0
- package/package.json +20 -34
- package/dist/agent-graph/alias-write.d.ts +0 -3
- package/dist/agent-graph/alias-write.js +0 -234
- package/dist/agent-graph/entity-resolve.d.ts +0 -3
- package/dist/agent-graph/entity-resolve.js +0 -271
- package/dist/agent-graph/errors.d.ts +0 -4
- package/dist/agent-graph/errors.js +0 -11
- package/dist/agent-graph/graph-query.d.ts +0 -5
- package/dist/agent-graph/graph-query.js +0 -360
- package/dist/agent-graph/index.d.ts +0 -6
- package/dist/agent-situation/builder.d.ts +0 -8
- package/dist/agent-situation/builder.js +0 -239
- package/dist/agent-situation/cache-key.d.ts +0 -4
- package/dist/agent-situation/cache-key.js +0 -64
- package/dist/agent-situation/index.d.ts +0 -7
- package/dist/agent-situation/index.js +0 -28
- package/dist/agent-situation/packet-store.d.ts +0 -27
- package/dist/agent-situation/packet-store.js +0 -228
- package/dist/agent-situation/ranking-policy.d.ts +0 -18
- package/dist/agent-situation/ranking-policy.js +0 -75
- package/dist/agent-situation/source-readers.d.ts +0 -52
- package/dist/agent-situation/source-readers.js +0 -300
- package/dist/agent-situation/types.d.ts +0 -195
- package/dist/cases/wiki-page-index.d.ts +0 -37
- package/dist/cases/wiki-page-index.js +0 -201
- package/dist/config-loader.d.ts +0 -68
- package/dist/config-loader.js +0 -239
- package/dist/connectors/event-index.d.ts +0 -24
- package/dist/connectors/event-index.js +0 -245
- package/dist/connectors/raw-query.d.ts +0 -40
- package/dist/connectors/raw-query.js +0 -412
- package/dist/connectors/types.d.ts +0 -117
- package/dist/connectors/types.js +0 -3
- package/dist/context-compile/boundary-defaults.d.ts +0 -12
- package/dist/context-compile/boundary-defaults.js +0 -105
- package/dist/context-compile/channel-grant.js +0 -66
- package/dist/context-compile/compiler-policy.d.ts +0 -39
- package/dist/context-compile/compiler-policy.js +0 -147
- package/dist/context-compile/compiler.d.ts +0 -18
- package/dist/context-compile/compiler.js +0 -404
- package/dist/context-compile/index.d.ts +0 -10
- package/dist/context-compile/index.js +0 -26
- package/dist/context-compile/packet-store.d.ts +0 -8
- package/dist/context-compile/packet-store.js +0 -239
- package/dist/context-compile/ref.d.ts +0 -7
- package/dist/context-compile/ref.js +0 -102
- package/dist/context-compile/source-readers.d.ts +0 -70
- package/dist/context-compile/source-readers.js +0 -840
- package/dist/context-compile/types.d.ts +0 -155
- package/dist/context-compile/types.js +0 -11
- package/dist/context-compile/visibility.d.ts +0 -21
- package/dist/context-compile/visibility.js +0 -224
- package/dist/decision-tracker.d.ts +0 -206
- package/dist/decision-tracker.js +0 -481
- package/dist/edges/ref-validation.d.ts +0 -7
- package/dist/edges/ref-validation.js +0 -321
- package/dist/edges/store.d.ts +0 -8
- package/dist/edges/store.js +0 -129
- package/dist/embedding-client.d.ts +0 -28
- package/dist/embedding-client.js +0 -53
- package/dist/embedding-server/index.d.ts +0 -67
- package/dist/embedding-server/index.js +0 -405
- package/dist/embedding-server/mobile/auth.d.ts +0 -44
- package/dist/embedding-server/mobile/auth.js +0 -150
- package/dist/embedding-server/mobile/daemon.d.ts +0 -129
- package/dist/embedding-server/mobile/daemon.js +0 -313
- package/dist/embedding-server/mobile/output-parser.d.ts +0 -115
- package/dist/embedding-server/mobile/output-parser.js +0 -241
- package/dist/embedding-server/mobile/session-api.d.ts +0 -57
- package/dist/embedding-server/mobile/session-api.js +0 -261
- package/dist/embedding-server/mobile/session-manager.d.ts +0 -138
- package/dist/embedding-server/mobile/session-manager.js +0 -378
- package/dist/embedding-server/mobile/websocket-handler.d.ts +0 -137
- package/dist/embedding-server/mobile/websocket-handler.js +0 -486
- package/dist/embeddings.d.ts +0 -68
- package/dist/embeddings.js +0 -244
- package/dist/entities/audit-metrics.d.ts +0 -68
- package/dist/entities/audit-metrics.js +0 -124
- package/dist/entities/candidate-generator.d.ts +0 -8
- package/dist/entities/candidate-generator.js +0 -24
- package/dist/entities/entity-linked-decision-counts.d.ts +0 -2
- package/dist/entities/entity-linked-decision-counts.js +0 -29
- package/dist/entities/entity-list.d.ts +0 -22
- package/dist/entities/entity-list.js +0 -3
- package/dist/entities/entity-orphan-list.d.ts +0 -17
- package/dist/entities/entity-orphan-list.js +0 -3
- package/dist/entities/entity-search.d.ts +0 -20
- package/dist/entities/entity-search.js +0 -3
- package/dist/entities/errors.d.ts +0 -55
- package/dist/entities/errors.js +0 -100
- package/dist/entities/lineage-store.d.ts +0 -28
- package/dist/entities/lineage-store.js +0 -204
- package/dist/entities/normalization.d.ts +0 -14
- package/dist/entities/normalization.js +0 -63
- package/dist/entities/policy-store.d.ts +0 -8
- package/dist/entities/policy-store.js +0 -75
- package/dist/entities/policy-types.d.ts +0 -72
- package/dist/entities/policy-types.js +0 -59
- package/dist/entities/projection.d.ts +0 -8
- package/dist/entities/projection.js +0 -82
- package/dist/entities/provenance-query.d.ts +0 -32
- package/dist/entities/provenance-query.js +0 -3
- package/dist/entities/read-identity.d.ts +0 -31
- package/dist/entities/read-identity.js +0 -264
- package/dist/entities/recall-bridge.d.ts +0 -5
- package/dist/entities/recall-bridge.js +0 -171
- package/dist/entities/resolution-engine.d.ts +0 -8
- package/dist/entities/resolution-engine.js +0 -3
- package/dist/entities/rollback-preview.d.ts +0 -35
- package/dist/entities/rollback-preview.js +0 -3
- package/dist/entities/source-locator.d.ts +0 -3
- package/dist/entities/source-locator.js +0 -32
- package/dist/entities/store.d.ts +0 -69
- package/dist/entities/store.js +0 -544
- package/dist/entities/types.d.ts +0 -166
- package/dist/entities/types.js +0 -30
- package/dist/memory/extraction-prompt.d.ts +0 -4
- package/dist/memory/extraction-prompt.js +0 -89
- package/dist/memory/scope-backfill.d.ts +0 -14
- package/dist/memory/scope-backfill.js +0 -3
- package/dist/memory/scope-store.d.ts +0 -4
- package/dist/memory/scope-store.js +0 -9
- package/dist/memory-store.d.ts +0 -87
- package/dist/memory-store.js +0 -78
- package/dist/model-runs/store.d.ts +0 -13
- package/dist/model-runs/tool-trace-store.d.ts +0 -8
- package/dist/notification-manager.d.ts +0 -7
- package/dist/notification-manager.js +0 -12
- package/dist/outcome-tracker.d.ts +0 -151
- package/dist/outcome-tracker.js +0 -271
- package/dist/query-intent.d.ts +0 -23
- package/dist/query-intent.js +0 -114
- package/dist/runtime/trusted-provenance.d.ts +0 -3
- package/dist/runtime/trusted-provenance.js +0 -6
- package/dist/search/question-type.d.ts +0 -5
- package/dist/search/question-type.js +0 -41
- package/dist/test-utils.d.ts +0 -80
- package/dist/test-utils.js +0 -218
- package/dist/tier-validator.d.ts +0 -43
- package/dist/tier-validator.js +0 -159
- package/dist/time-formatter.d.ts +0 -25
- package/dist/time-formatter.js +0 -93
- /package/dist/{search → knowledge}/feedback-store.d.ts +0 -0
- /package/dist/{search → knowledge}/feedback-store.js +0 -0
- /package/dist/{search → knowledge}/ranker-features.d.ts +0 -0
- /package/dist/{search → knowledge}/ranker-rescore.d.ts +0 -0
- /package/dist/{search → knowledge}/ranker-rescore.js +0 -0
- /package/dist/{search → knowledge}/ranker-trainer.d.ts +0 -0
- /package/dist/{search → knowledge}/ranker-trainer.js +0 -0
- /package/dist/{search → knowledge}/search-quality.js +0 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Knowledge observations: immutable observation versions and the visibility
|
|
3
|
+
* rule that decides which of them a caller may read. A cited observation must
|
|
4
|
+
* satisfy the same rule as a row the reader would have returned.
|
|
5
|
+
*
|
|
6
|
+
* @module knowledge/observations
|
|
7
|
+
*/
|
|
8
|
+
import type { DatabaseAdapter } from '../db-manager.js';
|
|
9
|
+
import type { MemoryScopeRef } from '../memory/types.js';
|
|
10
|
+
type ObservationAdapter = Pick<DatabaseAdapter, 'prepare'>;
|
|
11
|
+
type ObservationVisibilityAdapter = Pick<DatabaseAdapter, 'prepare'>;
|
|
12
|
+
export interface ObservationBodyLocation {
|
|
13
|
+
kind: 'raw';
|
|
14
|
+
connectorName: string;
|
|
15
|
+
revisionSourceId: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ObservationVersionInput {
|
|
18
|
+
/**
|
|
19
|
+
* Where this came from -- a namespace, paired with `sourceId` inside it. It was
|
|
20
|
+
* `sourceConnector`; a deployment with no connectors still observes things.
|
|
21
|
+
*/
|
|
22
|
+
source: string;
|
|
23
|
+
sourceId: string;
|
|
24
|
+
producerVersionId?: string | null;
|
|
25
|
+
body?: string;
|
|
26
|
+
bodyLocation?: ObservationBodyLocation;
|
|
27
|
+
author?: string | null;
|
|
28
|
+
sourceAt?: number | null;
|
|
29
|
+
observedAt: number;
|
|
30
|
+
contentHash: string;
|
|
31
|
+
metadata?: Record<string, unknown> | null;
|
|
32
|
+
/**
|
|
33
|
+
* What was observed, beyond its body. These lived only on the connector index,
|
|
34
|
+
* which is why a core read had to go there to answer what a memory rests on.
|
|
35
|
+
*/
|
|
36
|
+
sourceType?: string | null;
|
|
37
|
+
sourceLocator?: string | null;
|
|
38
|
+
title?: string | null;
|
|
39
|
+
artifactLocator?: string | null;
|
|
40
|
+
artifactTitle?: string | null;
|
|
41
|
+
eventDate?: string | null;
|
|
42
|
+
sourceEntityId?: string | null;
|
|
43
|
+
/**
|
|
44
|
+
* Who may see it. Columns rather than a JSON blob because raw visibility is a
|
|
45
|
+
* WHERE clause as well as a predicate, and the two are pinned against each other.
|
|
46
|
+
*/
|
|
47
|
+
channel?: string | null;
|
|
48
|
+
projectId?: string | null;
|
|
49
|
+
tenantId?: string | null;
|
|
50
|
+
memoryScopeKind?: string | null;
|
|
51
|
+
memoryScopeId?: string | null;
|
|
52
|
+
scope?: Record<string, unknown> | null;
|
|
53
|
+
}
|
|
54
|
+
export interface ObservationVersionRecord {
|
|
55
|
+
observationId: string;
|
|
56
|
+
source: string;
|
|
57
|
+
sourceId: string;
|
|
58
|
+
producerVersionId: string | null;
|
|
59
|
+
body: string | null;
|
|
60
|
+
bodyLocation: ObservationBodyLocation | null;
|
|
61
|
+
author: string | null;
|
|
62
|
+
sourceAt: number | null;
|
|
63
|
+
observedAt: number;
|
|
64
|
+
contentHash: string;
|
|
65
|
+
metadata: Record<string, unknown>;
|
|
66
|
+
sourceType: string | null;
|
|
67
|
+
sourceLocator: string | null;
|
|
68
|
+
title: string | null;
|
|
69
|
+
artifactLocator: string | null;
|
|
70
|
+
artifactTitle: string | null;
|
|
71
|
+
eventDate: string | null;
|
|
72
|
+
sourceEntityId: string | null;
|
|
73
|
+
channel: string | null;
|
|
74
|
+
projectId: string | null;
|
|
75
|
+
tenantId: string | null;
|
|
76
|
+
memoryScopeKind: string | null;
|
|
77
|
+
memoryScopeId: string | null;
|
|
78
|
+
scope: Record<string, unknown>;
|
|
79
|
+
}
|
|
80
|
+
export interface OwnerObservationSearchItem {
|
|
81
|
+
observationRef: string;
|
|
82
|
+
source: string;
|
|
83
|
+
sourceId: string;
|
|
84
|
+
author: string | null;
|
|
85
|
+
sourceAt: number | null;
|
|
86
|
+
observedAt: number;
|
|
87
|
+
contentPreview: string;
|
|
88
|
+
metadataPreview: string;
|
|
89
|
+
}
|
|
90
|
+
export interface ObservationBodyReader {
|
|
91
|
+
readVersion(input: ObservationBodyLocation & {
|
|
92
|
+
expectedContentHash: string;
|
|
93
|
+
}): {
|
|
94
|
+
status: 'available';
|
|
95
|
+
body: string;
|
|
96
|
+
contentHash: string;
|
|
97
|
+
} | {
|
|
98
|
+
status: 'version_unavailable';
|
|
99
|
+
reason: 'VERSION_NOT_FOUND' | 'HASH_MISMATCH';
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
export type ObservationReadResult = {
|
|
103
|
+
status: 'available';
|
|
104
|
+
observation: ObservationVersionRecord;
|
|
105
|
+
body: string;
|
|
106
|
+
} | {
|
|
107
|
+
status: 'version_unavailable';
|
|
108
|
+
observation: ObservationVersionRecord;
|
|
109
|
+
reason: 'BODY_READER_UNAVAILABLE' | 'VERSION_NOT_FOUND' | 'HASH_MISMATCH';
|
|
110
|
+
} | {
|
|
111
|
+
status: 'not_found';
|
|
112
|
+
};
|
|
113
|
+
export declare function observationVersionId(input: ObservationVersionInput): string;
|
|
114
|
+
export declare function appendObservationVersion(adapter: ObservationAdapter, input: ObservationVersionInput): ObservationVersionRecord;
|
|
115
|
+
/**
|
|
116
|
+
* The observation's source, without reading the rest of it.
|
|
117
|
+
*
|
|
118
|
+
* A caller deciding whether a row is an owner observation needs one column. It
|
|
119
|
+
* asks for one: mapping the whole record would parse a body and a metadata
|
|
120
|
+
* blob it does not use, and a row whose metadata is malformed would then fail
|
|
121
|
+
* loudly where the answer is simply "not yours" — the disclosure the visibility
|
|
122
|
+
* check exists to avoid.
|
|
123
|
+
*/
|
|
124
|
+
export declare function getObservationVersionSource(adapter: ObservationAdapter, observationId: string): string | null;
|
|
125
|
+
export declare function getObservationVersion(adapter: ObservationAdapter, observationId: string): ObservationVersionRecord | null;
|
|
126
|
+
export declare function searchOwnerObservationVersions(adapter: ObservationAdapter, input: {
|
|
127
|
+
query: string;
|
|
128
|
+
principalId: string;
|
|
129
|
+
agentId: string;
|
|
130
|
+
connectors?: string[];
|
|
131
|
+
connectorChannels?: Readonly<Record<string, readonly string[]>>;
|
|
132
|
+
fromMs?: number;
|
|
133
|
+
toMs?: number;
|
|
134
|
+
cursor?: string;
|
|
135
|
+
limit?: number;
|
|
136
|
+
}): {
|
|
137
|
+
items: OwnerObservationSearchItem[];
|
|
138
|
+
nextCursor: string | null;
|
|
139
|
+
};
|
|
140
|
+
export declare function readObservationVersion(adapter: ObservationAdapter, observationId: string, reader?: ObservationBodyReader, options?: {
|
|
141
|
+
maxSourceMs?: number | null;
|
|
142
|
+
}): ObservationReadResult;
|
|
143
|
+
export interface ObservationVisibilityAuthority {
|
|
144
|
+
principalId?: string;
|
|
145
|
+
agentId?: string;
|
|
146
|
+
scopes?: readonly MemoryScopeRef[];
|
|
147
|
+
connectors?: readonly string[];
|
|
148
|
+
connectorWideRead?: readonly string[];
|
|
149
|
+
channels?: Readonly<Record<string, readonly string[]>>;
|
|
150
|
+
maxSourceMs?: number | null;
|
|
151
|
+
}
|
|
152
|
+
export interface ObservationVisibilityRow {
|
|
153
|
+
source: unknown;
|
|
154
|
+
scope_json: unknown;
|
|
155
|
+
source_at?: unknown;
|
|
156
|
+
}
|
|
157
|
+
export declare function isObservationVersionVisible(adapter: ObservationVisibilityAdapter, observationId: string, authority: ObservationVisibilityAuthority): boolean;
|
|
158
|
+
export declare function isObservationVisibilityRowVisible(row: ObservationVisibilityRow, authority: ObservationVisibilityAuthority): boolean;
|
|
159
|
+
export {};
|
|
160
|
+
//# sourceMappingURL=observations.d.ts.map
|
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Knowledge observations: immutable observation versions and the visibility
|
|
4
|
+
* rule that decides which of them a caller may read. A cited observation must
|
|
5
|
+
* satisfy the same rule as a row the reader would have returned.
|
|
6
|
+
*
|
|
7
|
+
* @module knowledge/observations
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.observationVersionId = observationVersionId;
|
|
11
|
+
exports.appendObservationVersion = appendObservationVersion;
|
|
12
|
+
exports.getObservationVersionSource = getObservationVersionSource;
|
|
13
|
+
exports.getObservationVersion = getObservationVersion;
|
|
14
|
+
exports.searchOwnerObservationVersions = searchOwnerObservationVersions;
|
|
15
|
+
exports.readObservationVersion = readObservationVersion;
|
|
16
|
+
exports.isObservationVersionVisible = isObservationVersionVisible;
|
|
17
|
+
exports.isObservationVisibilityRowVisible = isObservationVisibilityRowVisible;
|
|
18
|
+
const node_crypto_1 = require("node:crypto");
|
|
19
|
+
const canonicalize_js_1 = require("../canonicalize.js");
|
|
20
|
+
function parseObject(value, field) {
|
|
21
|
+
if (typeof value !== 'string') {
|
|
22
|
+
throw new Error(`observation_versions.${field} must be JSON text`);
|
|
23
|
+
}
|
|
24
|
+
let parsed;
|
|
25
|
+
try {
|
|
26
|
+
parsed = JSON.parse(value);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
30
|
+
throw new Error(`observation_versions.${field} is malformed JSON: ${message}`);
|
|
31
|
+
}
|
|
32
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
33
|
+
throw new Error(`observation_versions.${field} must contain a JSON object`);
|
|
34
|
+
}
|
|
35
|
+
return parsed;
|
|
36
|
+
}
|
|
37
|
+
function nullableString(value, field) {
|
|
38
|
+
if (value === null) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
if (typeof value !== 'string') {
|
|
42
|
+
throw new Error(`observation_versions.${field} must be text or null`);
|
|
43
|
+
}
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
function finiteNumber(value, field, nullable = false) {
|
|
47
|
+
if (nullable && value === null) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
51
|
+
throw new Error(`observation_versions.${field} must be a finite number${nullable ? ' or null' : ''}`);
|
|
52
|
+
}
|
|
53
|
+
return value;
|
|
54
|
+
}
|
|
55
|
+
function mapRow(row) {
|
|
56
|
+
if (typeof row.observation_id !== 'string' || row.observation_id.trim() === '') {
|
|
57
|
+
throw new Error('observation_versions.observation_id must be nonblank text');
|
|
58
|
+
}
|
|
59
|
+
if (typeof row.source !== 'string' || row.source.trim() === '') {
|
|
60
|
+
throw new Error('observation_versions.source must be nonblank text');
|
|
61
|
+
}
|
|
62
|
+
if (typeof row.source_id !== 'string' || row.source_id.trim() === '') {
|
|
63
|
+
throw new Error('observation_versions.source_id must be nonblank text');
|
|
64
|
+
}
|
|
65
|
+
if (typeof row.content_hash !== 'string' || row.content_hash.trim() === '') {
|
|
66
|
+
throw new Error('observation_versions.content_hash must be nonblank text');
|
|
67
|
+
}
|
|
68
|
+
const body = nullableString(row.body, 'body');
|
|
69
|
+
const bodyLocationJson = nullableString(row.body_location_json, 'body_location_json');
|
|
70
|
+
if ((body === null) === (bodyLocationJson === null)) {
|
|
71
|
+
throw new Error('observation_versions row requires exactly one body source');
|
|
72
|
+
}
|
|
73
|
+
const bodyLocation = bodyLocationJson
|
|
74
|
+
? parseObject(bodyLocationJson, 'body_location_json')
|
|
75
|
+
: null;
|
|
76
|
+
if (bodyLocation &&
|
|
77
|
+
(bodyLocation.kind !== 'raw' ||
|
|
78
|
+
typeof bodyLocation.connectorName !== 'string' ||
|
|
79
|
+
typeof bodyLocation.revisionSourceId !== 'string' ||
|
|
80
|
+
bodyLocation.connectorName.trim() === '' ||
|
|
81
|
+
bodyLocation.revisionSourceId.trim() === '')) {
|
|
82
|
+
throw new Error('observation_versions.body_location_json has an invalid raw locator');
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
observationId: row.observation_id,
|
|
86
|
+
source: row.source,
|
|
87
|
+
sourceId: row.source_id,
|
|
88
|
+
producerVersionId: nullableString(row.producer_version_id, 'producer_version_id'),
|
|
89
|
+
body,
|
|
90
|
+
bodyLocation: bodyLocation,
|
|
91
|
+
author: nullableString(row.author, 'author'),
|
|
92
|
+
sourceAt: finiteNumber(row.source_at, 'source_at', true),
|
|
93
|
+
observedAt: finiteNumber(row.observed_at, 'observed_at'),
|
|
94
|
+
contentHash: row.content_hash,
|
|
95
|
+
metadata: parseObject(row.metadata_json, 'metadata_json'),
|
|
96
|
+
sourceType: nullableString(row.source_type, 'source_type'),
|
|
97
|
+
sourceLocator: nullableString(row.source_locator, 'source_locator'),
|
|
98
|
+
title: nullableString(row.title, 'title'),
|
|
99
|
+
artifactLocator: nullableString(row.artifact_locator, 'artifact_locator'),
|
|
100
|
+
artifactTitle: nullableString(row.artifact_title, 'artifact_title'),
|
|
101
|
+
eventDate: nullableString(row.event_date, 'event_date'),
|
|
102
|
+
sourceEntityId: nullableString(row.source_entity_id, 'source_entity_id'),
|
|
103
|
+
channel: nullableString(row.channel, 'channel'),
|
|
104
|
+
projectId: nullableString(row.project_id, 'project_id'),
|
|
105
|
+
tenantId: nullableString(row.tenant_id, 'tenant_id'),
|
|
106
|
+
memoryScopeKind: nullableString(row.memory_scope_kind, 'memory_scope_kind'),
|
|
107
|
+
memoryScopeId: nullableString(row.memory_scope_id, 'memory_scope_id'),
|
|
108
|
+
scope: parseObject(row.scope_json, 'scope_json'),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function sameObservation(actual, input, scope) {
|
|
112
|
+
return (actual.source === input.source &&
|
|
113
|
+
actual.sourceId === input.sourceId &&
|
|
114
|
+
actual.producerVersionId === (input.producerVersionId ?? null) &&
|
|
115
|
+
actual.body === (input.body ?? null) &&
|
|
116
|
+
(0, canonicalize_js_1.canonicalizeJSON)(actual.bodyLocation) === (0, canonicalize_js_1.canonicalizeJSON)(input.bodyLocation ?? null) &&
|
|
117
|
+
actual.author === (input.author ?? null) &&
|
|
118
|
+
actual.sourceAt === (input.sourceAt ?? null) &&
|
|
119
|
+
actual.observedAt === Math.floor(input.observedAt) &&
|
|
120
|
+
actual.contentHash === input.contentHash &&
|
|
121
|
+
(0, canonicalize_js_1.canonicalizeJSON)(actual.metadata) === (0, canonicalize_js_1.canonicalizeJSON)(input.metadata ?? {}) &&
|
|
122
|
+
(0, canonicalize_js_1.canonicalizeJSON)(actual.scope) === (0, canonicalize_js_1.canonicalizeJSON)(scope));
|
|
123
|
+
}
|
|
124
|
+
function observationVersionId(input) {
|
|
125
|
+
const identity = (0, canonicalize_js_1.canonicalizeJSON)({
|
|
126
|
+
source: input.source,
|
|
127
|
+
sourceId: input.sourceId,
|
|
128
|
+
producerVersionId: input.producerVersionId ?? null,
|
|
129
|
+
...(input.producerVersionId === null || input.producerVersionId === undefined
|
|
130
|
+
? { contentHash: input.contentHash }
|
|
131
|
+
: {}),
|
|
132
|
+
});
|
|
133
|
+
return `obs_${(0, node_crypto_1.createHash)('sha256').update(identity).digest('hex').slice(0, 24)}`;
|
|
134
|
+
}
|
|
135
|
+
function appendObservationVersion(adapter, input) {
|
|
136
|
+
if ((input.body === undefined) === (input.bodyLocation === undefined)) {
|
|
137
|
+
throw new Error('Observation requires exactly one of body or bodyLocation.');
|
|
138
|
+
}
|
|
139
|
+
if (!Number.isFinite(input.observedAt)) {
|
|
140
|
+
throw new Error('Observation observedAt must be finite.');
|
|
141
|
+
}
|
|
142
|
+
for (const [field, value] of [
|
|
143
|
+
['source', input.source],
|
|
144
|
+
['sourceId', input.sourceId],
|
|
145
|
+
['contentHash', input.contentHash],
|
|
146
|
+
]) {
|
|
147
|
+
if (!value.trim()) {
|
|
148
|
+
throw new Error(`Observation ${field} must be nonblank.`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// The scope bag and the scope columns are one fact in two shapes: the bag is what
|
|
152
|
+
// was stated, the columns are what a WHERE clause can reach. Deriving the columns
|
|
153
|
+
// here, once, is what keeps them from disagreeing -- a caller that fills only one
|
|
154
|
+
// of the two is how they drift apart.
|
|
155
|
+
const scope = input.scope ?? {};
|
|
156
|
+
const fromScope = (key, explicit) => {
|
|
157
|
+
if (explicit !== undefined) {
|
|
158
|
+
return explicit;
|
|
159
|
+
}
|
|
160
|
+
const value = scope[key];
|
|
161
|
+
return typeof value === 'string' && value !== '' ? value : null;
|
|
162
|
+
};
|
|
163
|
+
const channel = fromScope('channel', input.channel);
|
|
164
|
+
const projectId = fromScope('projectId', input.projectId);
|
|
165
|
+
const tenantId = fromScope('tenantId', input.tenantId);
|
|
166
|
+
const memoryScopeKind = fromScope('memoryScopeKind', input.memoryScopeKind);
|
|
167
|
+
const memoryScopeId = fromScope('memoryScopeId', input.memoryScopeId);
|
|
168
|
+
// And the other direction. A caller that named the scope as columns has said the
|
|
169
|
+
// same thing as one that named it in the bag, and the two readers -- a WHERE
|
|
170
|
+
// clause over the columns, a predicate over the bag -- must not disagree about it.
|
|
171
|
+
const scopeBag = { ...scope };
|
|
172
|
+
for (const [key, value] of [
|
|
173
|
+
['channel', channel],
|
|
174
|
+
['projectId', projectId],
|
|
175
|
+
['tenantId', tenantId],
|
|
176
|
+
['memoryScopeKind', memoryScopeKind],
|
|
177
|
+
['memoryScopeId', memoryScopeId],
|
|
178
|
+
]) {
|
|
179
|
+
if (value !== null && scopeBag[key] === undefined) {
|
|
180
|
+
scopeBag[key] = value;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
const id = observationVersionId(input);
|
|
184
|
+
adapter
|
|
185
|
+
.prepare(`INSERT OR IGNORE INTO observation_versions (
|
|
186
|
+
observation_id, source, source_id, producer_version_id, body,
|
|
187
|
+
body_location_json, author, source_at, observed_at, content_hash, metadata_json, scope_json,
|
|
188
|
+
source_type, source_locator, title, artifact_locator, artifact_title, event_date,
|
|
189
|
+
source_entity_id, channel, project_id, tenant_id, memory_scope_kind, memory_scope_id
|
|
190
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
191
|
+
.run(id, input.source, input.sourceId, input.producerVersionId ?? null, input.body ?? null, input.bodyLocation ? (0, canonicalize_js_1.canonicalizeJSON)(input.bodyLocation) : null, input.author ?? null, input.sourceAt ?? null, Math.floor(input.observedAt), input.contentHash, (0, canonicalize_js_1.canonicalizeJSON)(input.metadata ?? {}), (0, canonicalize_js_1.canonicalizeJSON)(scopeBag), input.sourceType ?? null, input.sourceLocator ?? null, input.title ?? null, input.artifactLocator ?? null, input.artifactTitle ?? null, input.eventDate ?? null, input.sourceEntityId ?? null, channel, projectId, tenantId, memoryScopeKind, memoryScopeId);
|
|
192
|
+
const record = getObservationVersion(adapter, id);
|
|
193
|
+
if (!record) {
|
|
194
|
+
throw new Error(`Failed to persist observation ${id}`);
|
|
195
|
+
}
|
|
196
|
+
if (!sameObservation(record, input, scopeBag)) {
|
|
197
|
+
throw new Error(`Observation replay conflict for ${id}`);
|
|
198
|
+
}
|
|
199
|
+
return record;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* The observation's source, without reading the rest of it.
|
|
203
|
+
*
|
|
204
|
+
* A caller deciding whether a row is an owner observation needs one column. It
|
|
205
|
+
* asks for one: mapping the whole record would parse a body and a metadata
|
|
206
|
+
* blob it does not use, and a row whose metadata is malformed would then fail
|
|
207
|
+
* loudly where the answer is simply "not yours" — the disclosure the visibility
|
|
208
|
+
* check exists to avoid.
|
|
209
|
+
*/
|
|
210
|
+
function getObservationVersionSource(adapter, observationId) {
|
|
211
|
+
const row = adapter
|
|
212
|
+
.prepare('SELECT source FROM observation_versions WHERE observation_id = ? LIMIT 1')
|
|
213
|
+
.get(observationId);
|
|
214
|
+
if (!row) {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
if (typeof row.source !== 'string' || row.source.trim() === '') {
|
|
218
|
+
throw new Error('observation_versions.source must be nonblank text');
|
|
219
|
+
}
|
|
220
|
+
return row.source;
|
|
221
|
+
}
|
|
222
|
+
function getObservationVersion(adapter, observationId) {
|
|
223
|
+
const row = adapter
|
|
224
|
+
.prepare('SELECT * FROM observation_versions WHERE observation_id = ? LIMIT 1')
|
|
225
|
+
.get(observationId);
|
|
226
|
+
return row ? mapRow(row) : null;
|
|
227
|
+
}
|
|
228
|
+
function searchOwnerObservationVersions(adapter, input) {
|
|
229
|
+
const query = input.query.trim();
|
|
230
|
+
const limit = Math.min(100, Math.max(1, Math.floor(input.limit ?? 25)));
|
|
231
|
+
const clauses = [
|
|
232
|
+
"(source LIKE 'owner-message:%' OR source LIKE 'owner-result:%')",
|
|
233
|
+
"json_extract(scope_json, '$.visibility') = 'owner'",
|
|
234
|
+
"json_extract(scope_json, '$.principalId') = ?",
|
|
235
|
+
"json_extract(scope_json, '$.agentId') = ?",
|
|
236
|
+
];
|
|
237
|
+
const params = [input.principalId, input.agentId];
|
|
238
|
+
const connectors = [...new Set((input.connectors ?? []).map((value) => value.trim()))].filter(Boolean);
|
|
239
|
+
if (input.connectors !== undefined && connectors.length === 0) {
|
|
240
|
+
return { items: [], nextCursor: null };
|
|
241
|
+
}
|
|
242
|
+
if (connectors.length > 0) {
|
|
243
|
+
clauses.push(`source IN (${connectors.map(() => '?').join(', ')})`);
|
|
244
|
+
params.push(...connectors);
|
|
245
|
+
}
|
|
246
|
+
if (input.connectorChannels !== undefined) {
|
|
247
|
+
const pairs = Object.entries(input.connectorChannels)
|
|
248
|
+
.map(([connector, values]) => [
|
|
249
|
+
connector.trim(),
|
|
250
|
+
[...new Set(values.map((value) => value.trim()).filter(Boolean))],
|
|
251
|
+
])
|
|
252
|
+
.filter(([connector, values]) => connector.length > 0 && values.length > 0);
|
|
253
|
+
if (pairs.length === 0) {
|
|
254
|
+
return { items: [], nextCursor: null };
|
|
255
|
+
}
|
|
256
|
+
clauses.push(`(${pairs
|
|
257
|
+
.map(([, values]) => `(source IN (?, ?) AND channel IN (${values.map(() => '?').join(', ')}))`)
|
|
258
|
+
.join(' OR ')})`);
|
|
259
|
+
for (const [connector, values] of pairs) {
|
|
260
|
+
params.push(`owner-message:${connector}`, `owner-result:${connector}`, ...values);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (input.fromMs !== undefined) {
|
|
264
|
+
clauses.push('observed_at >= ?');
|
|
265
|
+
params.push(input.fromMs);
|
|
266
|
+
}
|
|
267
|
+
if (input.toMs !== undefined) {
|
|
268
|
+
clauses.push('observed_at <= ?');
|
|
269
|
+
params.push(input.toMs);
|
|
270
|
+
}
|
|
271
|
+
if (query) {
|
|
272
|
+
clauses.push('(instr(body, ?) > 0 OR instr(metadata_json, ?) > 0)');
|
|
273
|
+
params.push(query, query);
|
|
274
|
+
}
|
|
275
|
+
if (input.cursor) {
|
|
276
|
+
let cursor;
|
|
277
|
+
try {
|
|
278
|
+
cursor = JSON.parse(Buffer.from(input.cursor, 'base64url').toString('utf8'));
|
|
279
|
+
}
|
|
280
|
+
catch {
|
|
281
|
+
throw new Error('Invalid owner observation cursor.');
|
|
282
|
+
}
|
|
283
|
+
if (!cursor ||
|
|
284
|
+
typeof cursor !== 'object' ||
|
|
285
|
+
Array.isArray(cursor) ||
|
|
286
|
+
!Number.isFinite(cursor.observedAt) ||
|
|
287
|
+
typeof cursor.observationId !== 'string' ||
|
|
288
|
+
!cursor.observationId) {
|
|
289
|
+
throw new Error('Invalid owner observation cursor.');
|
|
290
|
+
}
|
|
291
|
+
clauses.push('(observed_at < ? OR (observed_at = ? AND observation_id > ?))');
|
|
292
|
+
params.push(cursor.observedAt, cursor.observedAt, cursor.observationId);
|
|
293
|
+
}
|
|
294
|
+
const rows = adapter
|
|
295
|
+
.prepare(`SELECT * FROM observation_versions
|
|
296
|
+
WHERE ${clauses.join(' AND ')}
|
|
297
|
+
ORDER BY observed_at DESC, observation_id ASC
|
|
298
|
+
LIMIT ?`)
|
|
299
|
+
.all(...params, limit + 1);
|
|
300
|
+
const pageRows = rows.slice(0, limit);
|
|
301
|
+
const last = rows.length > limit ? pageRows[pageRows.length - 1] : undefined;
|
|
302
|
+
return {
|
|
303
|
+
items: pageRows.map((row) => {
|
|
304
|
+
const record = mapRow(row);
|
|
305
|
+
const compact = (record.body ?? '').replace(/\s+/g, ' ').trim();
|
|
306
|
+
return {
|
|
307
|
+
observationRef: record.observationId,
|
|
308
|
+
source: record.source,
|
|
309
|
+
sourceId: record.sourceId,
|
|
310
|
+
author: record.author,
|
|
311
|
+
sourceAt: record.sourceAt,
|
|
312
|
+
observedAt: record.observedAt,
|
|
313
|
+
contentPreview: compact.length > 500 ? `${compact.slice(0, 497)}...` : compact,
|
|
314
|
+
metadataPreview: (0, canonicalize_js_1.canonicalizeJSON)(record.metadata).slice(0, 500),
|
|
315
|
+
};
|
|
316
|
+
}),
|
|
317
|
+
nextCursor: last
|
|
318
|
+
? Buffer.from(JSON.stringify({
|
|
319
|
+
observedAt: Number(last.observed_at),
|
|
320
|
+
observationId: String(last.observation_id),
|
|
321
|
+
})).toString('base64url')
|
|
322
|
+
: null,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
function readObservationVersion(adapter, observationId, reader, options) {
|
|
326
|
+
const observation = getObservationVersion(adapter, observationId);
|
|
327
|
+
if (!observation) {
|
|
328
|
+
return { status: 'not_found' };
|
|
329
|
+
}
|
|
330
|
+
const maxSourceMs = options?.maxSourceMs ?? null;
|
|
331
|
+
if (maxSourceMs !== null) {
|
|
332
|
+
if (!Number.isSafeInteger(maxSourceMs) || maxSourceMs < 0) {
|
|
333
|
+
throw new Error('Observation source ceiling must be a nonnegative epoch millisecond integer');
|
|
334
|
+
}
|
|
335
|
+
if (observation.sourceAt === null || observation.sourceAt > maxSourceMs) {
|
|
336
|
+
return { status: 'not_found' };
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
if (observation.body !== null) {
|
|
340
|
+
return { status: 'available', observation, body: observation.body };
|
|
341
|
+
}
|
|
342
|
+
if (!reader || !observation.bodyLocation) {
|
|
343
|
+
return { status: 'version_unavailable', observation, reason: 'BODY_READER_UNAVAILABLE' };
|
|
344
|
+
}
|
|
345
|
+
const result = reader.readVersion({
|
|
346
|
+
...observation.bodyLocation,
|
|
347
|
+
expectedContentHash: observation.contentHash,
|
|
348
|
+
});
|
|
349
|
+
if (result.status === 'available') {
|
|
350
|
+
return result.contentHash === observation.contentHash
|
|
351
|
+
? { status: 'available', observation, body: result.body }
|
|
352
|
+
: { status: 'version_unavailable', observation, reason: 'HASH_MISMATCH' };
|
|
353
|
+
}
|
|
354
|
+
return { status: 'version_unavailable', observation, reason: result.reason };
|
|
355
|
+
}
|
|
356
|
+
function parseScopeJson(value) {
|
|
357
|
+
if (typeof value !== 'string') {
|
|
358
|
+
throw new Error('observation_versions.scope_json must be JSON text');
|
|
359
|
+
}
|
|
360
|
+
let parsed;
|
|
361
|
+
try {
|
|
362
|
+
parsed = JSON.parse(value);
|
|
363
|
+
}
|
|
364
|
+
catch (error) {
|
|
365
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
366
|
+
throw new Error(`observation_versions.scope_json is malformed JSON: ${message}`);
|
|
367
|
+
}
|
|
368
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
369
|
+
throw new Error('observation_versions.scope_json must contain a JSON object');
|
|
370
|
+
}
|
|
371
|
+
return parsed;
|
|
372
|
+
}
|
|
373
|
+
function matchesScope(scope, visible) {
|
|
374
|
+
if (visible.kind === 'project') {
|
|
375
|
+
return (scope.projectId === visible.id ||
|
|
376
|
+
(scope.memoryScopeKind === 'project' && scope.memoryScopeId === visible.id));
|
|
377
|
+
}
|
|
378
|
+
if (visible.kind === 'channel') {
|
|
379
|
+
return (scope.channel === visible.id ||
|
|
380
|
+
(scope.memoryScopeKind === 'channel' && scope.memoryScopeId === visible.id));
|
|
381
|
+
}
|
|
382
|
+
return scope.memoryScopeKind === visible.kind && scope.memoryScopeId === visible.id;
|
|
383
|
+
}
|
|
384
|
+
function isObservationVersionVisible(adapter, observationId, authority) {
|
|
385
|
+
const row = adapter
|
|
386
|
+
.prepare(`SELECT scope_json, source, source_at
|
|
387
|
+
FROM observation_versions WHERE observation_id = ?`)
|
|
388
|
+
.get(observationId);
|
|
389
|
+
if (!row) {
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
return isObservationVisibilityRowVisible(row, authority);
|
|
393
|
+
}
|
|
394
|
+
function isObservationVisibilityRowVisible(row, authority) {
|
|
395
|
+
const principalId = authority.principalId?.trim();
|
|
396
|
+
const agentId = authority.agentId?.trim();
|
|
397
|
+
if (!principalId || !agentId) {
|
|
398
|
+
return false;
|
|
399
|
+
}
|
|
400
|
+
const maxSourceMs = authority.maxSourceMs ?? null;
|
|
401
|
+
if (maxSourceMs !== null) {
|
|
402
|
+
if (!Number.isSafeInteger(maxSourceMs) || maxSourceMs < 0) {
|
|
403
|
+
throw new Error('Observation source ceiling must be a nonnegative epoch millisecond integer');
|
|
404
|
+
}
|
|
405
|
+
const sourceAt = typeof row.source_at === 'number' ? row.source_at : null;
|
|
406
|
+
if (sourceAt === null || sourceAt > maxSourceMs)
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
409
|
+
if (typeof row.source !== 'string' || !row.source.trim()) {
|
|
410
|
+
throw new Error('observation_versions.source must be nonblank text');
|
|
411
|
+
}
|
|
412
|
+
const ownerConnector = /^owner-(?:message|result):(.+)$/.exec(row.source)?.[1];
|
|
413
|
+
const connector = ownerConnector ?? row.source;
|
|
414
|
+
if (!authority.connectors?.includes(connector)) {
|
|
415
|
+
return false;
|
|
416
|
+
}
|
|
417
|
+
const scope = parseScopeJson(row.scope_json);
|
|
418
|
+
const connectorWideRead = authority.connectorWideRead?.includes(connector) === true;
|
|
419
|
+
if (authority.channels && !connectorWideRead) {
|
|
420
|
+
const visibleChannels = authority.channels[connector];
|
|
421
|
+
const channel = typeof scope.channel === 'string' ? scope.channel : null;
|
|
422
|
+
const normalizedChannel = channel?.startsWith(`${connector}:`)
|
|
423
|
+
? channel.slice(connector.length + 1)
|
|
424
|
+
: channel;
|
|
425
|
+
if (!visibleChannels ||
|
|
426
|
+
channel === null ||
|
|
427
|
+
(!visibleChannels.includes(channel) &&
|
|
428
|
+
(normalizedChannel === null || !visibleChannels.includes(normalizedChannel)))) {
|
|
429
|
+
return false;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
if (ownerConnector !== undefined || scope.visibility === 'owner') {
|
|
433
|
+
if (ownerConnector === undefined || scope.visibility !== 'owner') {
|
|
434
|
+
throw new Error('owner observation connector and scope visibility are inconsistent');
|
|
435
|
+
}
|
|
436
|
+
return scope.principalId === principalId && scope.agentId === agentId;
|
|
437
|
+
}
|
|
438
|
+
// A current connector/channel grant is the same read authority source.read
|
|
439
|
+
// applies. Imported originals can have no project or memory-scope tag; that
|
|
440
|
+
// absence does not revoke an explicitly granted source read in the graph.
|
|
441
|
+
if (connectorWideRead || authority.channels) {
|
|
442
|
+
return true;
|
|
443
|
+
}
|
|
444
|
+
if (!authority.scopes || authority.scopes.length === 0) {
|
|
445
|
+
return false;
|
|
446
|
+
}
|
|
447
|
+
return authority.scopes.some((visible) => matchesScope(scope, visible));
|
|
448
|
+
}
|
|
449
|
+
//# sourceMappingURL=observations.js.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a search query is asking for.
|
|
3
|
+
*
|
|
4
|
+
* The classifier is a mechanism: an ordered list of patterns, first match wins. The
|
|
5
|
+
* WORDS are not. Two of them named connectors that one deployment happens to run,
|
|
6
|
+
* which told every other product installing this core that asking about that
|
|
7
|
+
* connector is asking about an artifact, whether or not it has one.
|
|
8
|
+
*
|
|
9
|
+
* So the words are injectable. The default below carries only words that name no
|
|
10
|
+
* product: what a file is, what a date is, what asking "why" looks like. A caller
|
|
11
|
+
* with its own domain adds to it.
|
|
12
|
+
*/
|
|
13
|
+
export type QuestionType = 'correction' | 'artifact' | 'timeline' | 'status' | 'decision_reason' | 'how_to' | 'unknown';
|
|
14
|
+
export declare const QUESTION_TYPES: readonly QuestionType[];
|
|
15
|
+
/** One question type and the pattern that names it. Order is the precedence. */
|
|
16
|
+
export interface QuestionPattern {
|
|
17
|
+
readonly type: Exclude<QuestionType, 'unknown'>;
|
|
18
|
+
readonly pattern: RegExp;
|
|
19
|
+
}
|
|
20
|
+
export type QuestionVocabulary = readonly QuestionPattern[];
|
|
21
|
+
export declare const DEFAULT_QUESTION_VOCABULARY: QuestionVocabulary;
|
|
22
|
+
/**
|
|
23
|
+
* Declare the words this deployment asks questions with. Call once, at boot.
|
|
24
|
+
*
|
|
25
|
+
* Replaces the default outright rather than merging: a caller that wants the general
|
|
26
|
+
* words plus its own spreads DEFAULT_QUESTION_VOCABULARY itself, and can see in one
|
|
27
|
+
* place what its classifier actually knows.
|
|
28
|
+
*/
|
|
29
|
+
export declare function declareQuestionVocabulary(next: QuestionVocabulary): void;
|
|
30
|
+
/** Restore the default. For tests that declared their own. */
|
|
31
|
+
export declare function resetQuestionVocabulary(): void;
|
|
32
|
+
export declare function classifyQuestionType(query: string): QuestionType;
|
|
33
|
+
export declare function isQuestionType(value: string): value is QuestionType;
|
|
34
|
+
//# sourceMappingURL=question-type.d.ts.map
|