@jungjaehoon/mama-core 1.5.0 → 1.7.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.
Files changed (103) hide show
  1. package/README.md +48 -10
  2. package/db/migrations/032-add-memory-provenance-columns.sql +21 -0
  3. package/db/migrations/033-create-model-runs-and-tool-traces.sql +53 -0
  4. package/db/migrations/034-add-connector-event-scope-columns.sql +14 -0
  5. package/db/migrations/035-create-twin-edges.sql +63 -0
  6. package/db/migrations/036-create-agent-situation-packets.sql +61 -0
  7. package/db/migrations/037-create-context-packets.sql +32 -0
  8. package/dist/agent-graph/alias-write.d.ts +3 -0
  9. package/dist/agent-graph/alias-write.js +231 -0
  10. package/dist/agent-graph/entity-resolve.d.ts +3 -0
  11. package/dist/agent-graph/entity-resolve.js +275 -0
  12. package/dist/agent-graph/errors.d.ts +4 -0
  13. package/dist/agent-graph/errors.js +11 -0
  14. package/dist/agent-graph/graph-query.d.ts +5 -0
  15. package/dist/agent-graph/graph-query.js +359 -0
  16. package/dist/agent-graph/index.d.ts +6 -0
  17. package/dist/agent-graph/index.js +22 -0
  18. package/dist/agent-graph/types.d.ts +162 -0
  19. package/dist/agent-graph/types.js +3 -0
  20. package/dist/agent-situation/builder.d.ts +8 -0
  21. package/dist/agent-situation/builder.js +239 -0
  22. package/dist/agent-situation/cache-key.d.ts +4 -0
  23. package/dist/agent-situation/cache-key.js +64 -0
  24. package/dist/agent-situation/index.d.ts +7 -0
  25. package/dist/agent-situation/index.js +28 -0
  26. package/dist/agent-situation/packet-store.d.ts +27 -0
  27. package/dist/agent-situation/packet-store.js +228 -0
  28. package/dist/agent-situation/ranking-policy.d.ts +18 -0
  29. package/dist/agent-situation/ranking-policy.js +75 -0
  30. package/dist/agent-situation/source-readers.d.ts +52 -0
  31. package/dist/agent-situation/source-readers.js +300 -0
  32. package/dist/agent-situation/types.d.ts +195 -0
  33. package/dist/agent-situation/types.js +3 -0
  34. package/dist/cases/search-rollup.d.ts +4 -0
  35. package/dist/cases/search-rollup.js +84 -0
  36. package/dist/cases/wiki-page-index.js +6 -2
  37. package/dist/connectors/event-index.d.ts +1 -0
  38. package/dist/connectors/event-index.js +19 -4
  39. package/dist/connectors/raw-query.d.ts +18 -0
  40. package/dist/connectors/raw-query.js +305 -0
  41. package/dist/connectors/types.d.ts +40 -0
  42. package/dist/context-compile/boundary-defaults.d.ts +12 -0
  43. package/dist/context-compile/boundary-defaults.js +105 -0
  44. package/dist/context-compile/compiler-policy.d.ts +39 -0
  45. package/dist/context-compile/compiler-policy.js +147 -0
  46. package/dist/context-compile/compiler.d.ts +18 -0
  47. package/dist/context-compile/compiler.js +401 -0
  48. package/dist/context-compile/index.d.ts +9 -0
  49. package/dist/context-compile/index.js +25 -0
  50. package/dist/context-compile/packet-store.d.ts +9 -0
  51. package/dist/context-compile/packet-store.js +255 -0
  52. package/dist/context-compile/ref.d.ts +7 -0
  53. package/dist/context-compile/ref.js +102 -0
  54. package/dist/context-compile/source-readers.d.ts +69 -0
  55. package/dist/context-compile/source-readers.js +707 -0
  56. package/dist/context-compile/types.d.ts +138 -0
  57. package/dist/context-compile/types.js +11 -0
  58. package/dist/context-compile/visibility.d.ts +21 -0
  59. package/dist/context-compile/visibility.js +200 -0
  60. package/dist/db-adapter/node-sqlite-adapter.d.ts +9 -0
  61. package/dist/db-adapter/node-sqlite-adapter.js +207 -0
  62. package/dist/db-manager.d.ts +8 -1
  63. package/dist/db-manager.js +53 -5
  64. package/dist/edges/ref-validation.d.ts +8 -0
  65. package/dist/edges/ref-validation.js +301 -0
  66. package/dist/edges/store.d.ts +10 -0
  67. package/dist/edges/store.js +343 -0
  68. package/dist/edges/types.d.ts +88 -0
  69. package/dist/edges/types.js +18 -0
  70. package/dist/embeddings.d.ts +3 -0
  71. package/dist/embeddings.js +49 -9
  72. package/dist/entities/store.d.ts +4 -1
  73. package/dist/entities/store.js +206 -78
  74. package/dist/entities/types.d.ts +5 -1
  75. package/dist/entities/types.js +1 -1
  76. package/dist/index.d.ts +18 -3
  77. package/dist/index.js +54 -4
  78. package/dist/mama-api.d.ts +32 -35
  79. package/dist/mama-api.js +173 -22
  80. package/dist/memory/api.d.ts +17 -56
  81. package/dist/memory/api.js +494 -52
  82. package/dist/memory/event-store.d.ts +3 -0
  83. package/dist/memory/event-store.js +21 -2
  84. package/dist/memory/provenance-audit.d.ts +22 -0
  85. package/dist/memory/provenance-audit.js +112 -0
  86. package/dist/memory/provenance-query.d.ts +11 -0
  87. package/dist/memory/provenance-query.js +193 -0
  88. package/dist/memory/provenance.d.ts +29 -0
  89. package/dist/memory/provenance.js +137 -0
  90. package/dist/memory/scope-backfill.d.ts +17 -0
  91. package/dist/memory/scope-backfill.js +77 -0
  92. package/dist/memory/types.d.ts +87 -14
  93. package/dist/model-runs/store.d.ts +13 -0
  94. package/dist/model-runs/store.js +457 -0
  95. package/dist/model-runs/tool-trace-store.d.ts +4 -0
  96. package/dist/model-runs/tool-trace-store.js +114 -0
  97. package/dist/model-runs/types.d.ts +69 -0
  98. package/dist/model-runs/types.js +5 -0
  99. package/dist/runtime/trusted-provenance.d.ts +3 -0
  100. package/dist/runtime/trusted-provenance.js +6 -0
  101. package/dist/search/search-quality.d.ts +36 -0
  102. package/dist/search/search-quality.js +29 -0
  103. package/package.json +11 -3
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @jungjaehoon/mama-core
2
2
 
3
- Shared core modules for MAMA (Memory-Augmented MCP Assistant).
3
+ Shared memory, provenance, graph, and context substrate for MAMA.
4
4
 
5
5
  ## What is MAMA Core?
6
6
 
@@ -10,7 +10,9 @@ MAMA Core is a shared package containing the fundamental modules used by all MAM
10
10
  - **claude-code-plugin**: Claude Code plugin
11
11
  - **standalone**: Standalone HTTP server
12
12
 
13
- This package provides embedding generation, database management, decision tracking, and other core functionality without the transport layer (MCP/HTTP).
13
+ This package provides embedding generation, database management, scoped memory, provenance, raw
14
+ evidence refs, graph/entity helpers, and worker context primitives without the transport layer
15
+ (MCP/HTTP).
14
16
 
15
17
  ## Installation
16
18
 
@@ -78,7 +80,7 @@ const mamaApi = require('@jungjaehoon/mama-core/mama-api');
78
80
 
79
81
  - **memory/api** - Scoped memory operations
80
82
  - `saveMemory(input)` - Save typed memory with scopes and optional event_date (preference, fact, decision, lesson, constraint)
81
- - `recallMemory(query, options)` - Truth-aware recall with scope filtering
83
+ - `recallMemory(query, options)` - Truth-aware recall with scope filtering, strictness modes, and retrieval diagnostics
82
84
  - `buildProfile(scopes)` - Build memory profile (static/dynamic/evidence)
83
85
  - `ingestMemory(input)` - Ingest raw content as memory
84
86
  - `ingestConversation(input)` - Decompose conversations into typed memory units via optional LLM extraction
@@ -102,14 +104,39 @@ const mamaApi = require('@jungjaehoon/mama-core/mama-api');
102
104
  - **memory/channel-summary-state-store** - Channel state management
103
105
  - `recordChannelAudit(input)` - Accumulate audit outcomes into channel state
104
106
 
107
+ - **memory/provenance** - Trusted memory provenance
108
+ - Preserves compact runtime origin metadata in `provenance_json`
109
+ - Keeps underlying raw/memory/case/entity refs in `source_refs_json`
110
+ - Ignores caller-supplied untrusted provenance on public paths
111
+
112
+ - **model-runs** - Agent execution lineage
113
+ - `model-runs/store` records model run lifecycle and replay metadata
114
+ - `model-runs/tool-trace-store` records tool calls for later audit and reconstruction
115
+
116
+ - **connectors/raw-query** - Unified raw evidence reads
117
+ - Query raw connector rows through scope-aware filters
118
+ - Preserve raw source ids for downstream provenance
119
+
120
+ - **agent-situation** - Worker situation packets
121
+ - Build, rank, cache, insert, and read append-only situation packets for worker context
122
+
123
+ - **agent-graph** - Worker graph/entity helpers
124
+ - Query graph neighborhoods, resolve entities, and write aliases with visibility checks
125
+
105
126
  ### Core API (Legacy)
106
127
 
107
128
  - **mama-api** - High-level API interface (wraps memory API)
108
129
  - `save(decision)` - Save decision
109
130
  - `recall(topic)` - Retrieve decision history
110
- - `suggest(query)` - Semantic search with hybrid FTS5 + vector + recency
131
+ - `suggest(query, options)` - Semantic search with hybrid FTS5 + vector + recency, strictness controls, and diagnostics
111
132
  - `updateOutcome(id, outcome)` - Update decision outcome
112
133
 
134
+ - **search/search-quality** - Search option normalization
135
+ - `normalizeSearchQualityOptions(options)` - Normalize recall/balanced/strict thresholds and confirmation requirements
136
+
137
+ - **edges** - Twin edge ledger
138
+ - Validate refs and store durable edges between memory, raw, entity, case, and packet refs
139
+
113
140
  - **decision-tracker** - Decision graph management
114
141
  - `learnDecision(decision)` - Learn from decision
115
142
  - `createEdgesFromReasoning(reasoning)` - Parse decision links
@@ -135,7 +162,7 @@ const mamaApi = require('@jungjaehoon/mama-core/mama-api');
135
162
  ## Dependencies
136
163
 
137
164
  - **@huggingface/transformers** - Local embedding generation
138
- - **node:sqlite** - Built-in SQLite runtime (Node.js 22+)
165
+ - **better-sqlite3** - SQLite runtime with FTS5 support
139
166
  - **Pure-TS cosine similarity** - Vector search (no native extensions)
140
167
 
141
168
  ## Development
@@ -153,7 +180,7 @@ pnpm test:watch
153
180
 
154
181
  ## Test Coverage
155
182
 
156
- - 72 unit tests across 17 test files
183
+ - 120+ unit/integration test files in `packages/mama-core/tests`
157
184
  - 100% passing
158
185
  - Tests cover:
159
186
  - Config loader, database initialization, module exports
@@ -161,6 +188,9 @@ pnpm test:watch
161
188
  - Truth store, evolution engine, scope schema
162
189
  - Channel summary, channel summary state
163
190
  - Event store, finding store, bootstrap builder
191
+ - Memory provenance, model runs, tool traces
192
+ - Twin edges, raw query, agent situation, agent graph
193
+ - Strict search diagnostics and rollup provenance
164
194
  - Legacy shim compatibility
165
195
 
166
196
  ## Architecture
@@ -175,7 +205,7 @@ packages/mama-core/
175
205
  │ ├── db-manager.ts # Database management
176
206
  │ ├── mama-api.ts # High-level API (wraps memory API)
177
207
  │ ├── db-adapter/ # Database adapter (SQLite)
178
- │ └── memory/ # Memory infrastructure
208
+ │ ├── memory/ # Memory infrastructure
179
209
  │ ├── types.ts # MemoryRecord, MemoryScopeRef, RecallBundle, etc.
180
210
  │ ├── api.ts # saveMemory, recallMemory, buildProfile, etc.
181
211
  │ ├── truth-store.ts # Truth projection layer
@@ -188,13 +218,19 @@ packages/mama-core/
188
218
  │ ├── channel-summary-state-store.ts # Channel state reducer
189
219
  │ ├── bootstrap-builder.ts # Memory agent bootstrap
190
220
  │ └── profile-builder.ts # Profile classification
191
- ├── db/migrations/ # SQLite migrations (001-023)
192
- └── tests/ # 16 test files, 59 tests
221
+ │ ├── model-runs/ # Model run + tool trace lineage
222
+ │ ├── connectors/ # Raw connector query/index helpers
223
+ │ ├── edges/ # Twin edge ledger
224
+ │ ├── agent-situation/ # Worker situation packets
225
+ │ ├── agent-graph/ # Worker graph/entity helpers
226
+ │ └── search/ # Search quality option normalization
227
+ ├── db/migrations/ # SQLite migrations (001-036)
228
+ └── tests/ # Unit and integration tests
193
229
  ```
194
230
 
195
231
  ## Migration Files
196
232
 
197
- Database migrations are included in `db/migrations/` (001-023):
233
+ Database migrations are included in `db/migrations/` (001-036):
198
234
 
199
235
  - 001-013: Core schema (decisions, embeddings, graph edges)
200
236
  - 014: Add is_static column
@@ -204,6 +240,8 @@ Database migrations are included in `db/migrations/` (001-023):
204
240
  - 019-020: Memory events and audit findings
205
241
  - 021: Memory truth projection
206
242
  - 022-023: Channel summaries and state
243
+ - 024-036: event dates, connector memory kinds, canonical entities, case-first memory, wiki/index
244
+ provenance, model/tool traces, twin edges, and agent situation packets
207
245
 
208
246
  ## License
209
247
 
@@ -0,0 +1,21 @@
1
+ ALTER TABLE decisions ADD COLUMN agent_id TEXT;
2
+ ALTER TABLE decisions ADD COLUMN model_run_id TEXT;
3
+ ALTER TABLE decisions ADD COLUMN envelope_hash TEXT;
4
+ ALTER TABLE decisions ADD COLUMN gateway_call_id TEXT;
5
+ ALTER TABLE decisions ADD COLUMN source_refs_json TEXT;
6
+ ALTER TABLE decisions ADD COLUMN provenance_json TEXT;
7
+
8
+ CREATE INDEX IF NOT EXISTS idx_decisions_envelope_hash
9
+ ON decisions(envelope_hash);
10
+
11
+ CREATE INDEX IF NOT EXISTS idx_decisions_model_run_id
12
+ ON decisions(model_run_id);
13
+
14
+ CREATE INDEX IF NOT EXISTS idx_decisions_gateway_call_id
15
+ ON decisions(gateway_call_id);
16
+
17
+ CREATE INDEX IF NOT EXISTS idx_memory_events_memory_created
18
+ ON memory_events(memory_id, created_at DESC);
19
+
20
+ INSERT OR IGNORE INTO schema_version (version, description)
21
+ VALUES (32, 'Add nullable memory provenance columns');
@@ -0,0 +1,53 @@
1
+ CREATE TABLE IF NOT EXISTS model_runs (
2
+ model_run_id TEXT PRIMARY KEY,
3
+ model_id TEXT,
4
+ model_provider TEXT,
5
+ prompt_version TEXT,
6
+ tool_manifest_version TEXT,
7
+ output_schema_version TEXT,
8
+ agent_id TEXT,
9
+ instance_id TEXT,
10
+ envelope_hash TEXT,
11
+ parent_model_run_id TEXT,
12
+ input_snapshot_ref TEXT,
13
+ input_refs_json TEXT,
14
+ completion_summary TEXT,
15
+ status TEXT NOT NULL CHECK (status IN ('running', 'committed', 'failed', 'legacy')),
16
+ error_summary TEXT,
17
+ token_count INTEGER DEFAULT 0,
18
+ cost_estimate REAL,
19
+ created_at INTEGER NOT NULL,
20
+ completed_at INTEGER
21
+ );
22
+
23
+ CREATE INDEX IF NOT EXISTS idx_model_runs_envelope_hash
24
+ ON model_runs(envelope_hash);
25
+
26
+ CREATE INDEX IF NOT EXISTS idx_model_runs_status_created
27
+ ON model_runs(status, created_at DESC);
28
+
29
+ CREATE INDEX IF NOT EXISTS idx_model_runs_agent_created
30
+ ON model_runs(agent_id, created_at DESC);
31
+
32
+ CREATE TABLE IF NOT EXISTS tool_traces (
33
+ trace_id TEXT PRIMARY KEY,
34
+ model_run_id TEXT NOT NULL,
35
+ gateway_call_id TEXT,
36
+ tool_name TEXT NOT NULL,
37
+ input_summary TEXT,
38
+ output_summary TEXT,
39
+ execution_status TEXT,
40
+ duration_ms INTEGER DEFAULT 0,
41
+ envelope_hash TEXT,
42
+ created_at INTEGER NOT NULL,
43
+ FOREIGN KEY (model_run_id) REFERENCES model_runs(model_run_id)
44
+ );
45
+
46
+ CREATE INDEX IF NOT EXISTS idx_tool_traces_model_run_id
47
+ ON tool_traces(model_run_id, created_at DESC);
48
+
49
+ CREATE INDEX IF NOT EXISTS idx_tool_traces_gateway_call_id
50
+ ON tool_traces(gateway_call_id);
51
+
52
+ INSERT OR IGNORE INTO schema_version (version, description)
53
+ VALUES (33, 'Create model runs and tool traces');
@@ -0,0 +1,14 @@
1
+ ALTER TABLE connector_event_index ADD COLUMN source_cursor TEXT;
2
+ ALTER TABLE connector_event_index ADD COLUMN tenant_id TEXT;
3
+ ALTER TABLE connector_event_index ADD COLUMN project_id TEXT;
4
+ ALTER TABLE connector_event_index ADD COLUMN memory_scope_kind TEXT;
5
+ ALTER TABLE connector_event_index ADD COLUMN memory_scope_id TEXT;
6
+
7
+ CREATE INDEX IF NOT EXISTS idx_connector_event_scope
8
+ ON connector_event_index(tenant_id, project_id, memory_scope_kind, memory_scope_id);
9
+
10
+ CREATE INDEX IF NOT EXISTS idx_connector_event_source_cursor
11
+ ON connector_event_index(source_connector, source_cursor);
12
+
13
+ INSERT OR IGNORE INTO schema_version (version, description)
14
+ VALUES (34, 'Add connector event scope columns');
@@ -0,0 +1,63 @@
1
+ CREATE TABLE IF NOT EXISTS twin_edges (
2
+ edge_id TEXT PRIMARY KEY,
3
+ edge_type TEXT NOT NULL CHECK (
4
+ edge_type IN (
5
+ 'supersedes',
6
+ 'builds_on',
7
+ 'debates',
8
+ 'synthesizes',
9
+ 'mentions',
10
+ 'derived_from',
11
+ 'case_member',
12
+ 'alias_of',
13
+ 'next_action_for',
14
+ 'blocks'
15
+ )
16
+ ),
17
+ subject_kind TEXT NOT NULL CHECK (
18
+ subject_kind IN ('memory', 'case', 'entity', 'report', 'edge')
19
+ ),
20
+ subject_id TEXT NOT NULL,
21
+ object_kind TEXT NOT NULL CHECK (
22
+ object_kind IN ('memory', 'case', 'entity', 'report', 'edge', 'raw')
23
+ ),
24
+ object_id TEXT NOT NULL,
25
+ relation_attrs_json TEXT,
26
+ confidence REAL NOT NULL DEFAULT 1.0 CHECK (confidence >= 0.0 AND confidence <= 1.0),
27
+ source TEXT NOT NULL CHECK (source IN ('agent', 'human', 'code')),
28
+ agent_id TEXT,
29
+ model_run_id TEXT,
30
+ envelope_hash TEXT,
31
+ human_actor_id TEXT,
32
+ human_actor_role TEXT,
33
+ authority_scope_json TEXT,
34
+ reason_classification TEXT,
35
+ reason_text TEXT,
36
+ evidence_refs_json TEXT,
37
+ request_idempotency_key TEXT,
38
+ edge_idempotency_key TEXT,
39
+ content_hash BLOB NOT NULL CHECK(length(content_hash)=32),
40
+ created_at INTEGER NOT NULL
41
+ );
42
+
43
+ CREATE INDEX IF NOT EXISTS idx_twin_edges_subject
44
+ ON twin_edges(subject_kind, subject_id, created_at DESC);
45
+
46
+ CREATE INDEX IF NOT EXISTS idx_twin_edges_object
47
+ ON twin_edges(object_kind, object_id, created_at DESC);
48
+
49
+ CREATE INDEX IF NOT EXISTS idx_twin_edges_model_run_id
50
+ ON twin_edges(model_run_id, created_at DESC);
51
+
52
+ CREATE INDEX IF NOT EXISTS idx_twin_edges_request_idempotency
53
+ ON twin_edges(model_run_id, request_idempotency_key, created_at DESC)
54
+ WHERE model_run_id IS NOT NULL
55
+ AND request_idempotency_key IS NOT NULL;
56
+
57
+ CREATE UNIQUE INDEX IF NOT EXISTS ux_twin_edges_model_run_edge_idempotency
58
+ ON twin_edges(model_run_id, edge_idempotency_key)
59
+ WHERE model_run_id IS NOT NULL
60
+ AND edge_idempotency_key IS NOT NULL;
61
+
62
+ INSERT OR IGNORE INTO schema_version (version, description)
63
+ VALUES (35, 'Create first-class twin edge ledger');
@@ -0,0 +1,61 @@
1
+ CREATE TABLE IF NOT EXISTS agent_situation_packets (
2
+ packet_id TEXT PRIMARY KEY,
3
+ cache_key TEXT NOT NULL,
4
+ scope_json TEXT NOT NULL,
5
+ scope_hash TEXT NOT NULL,
6
+ range_start_ms INTEGER NOT NULL CHECK (range_start_ms >= 0),
7
+ range_end_ms INTEGER NOT NULL CHECK (range_end_ms >= range_start_ms),
8
+ focus_json TEXT NOT NULL,
9
+ envelope_hash TEXT NOT NULL,
10
+ envelope_effective_filters_json TEXT NOT NULL,
11
+ envelope_effective_filters_hash TEXT NOT NULL,
12
+ ranking_policy_version TEXT NOT NULL,
13
+ generated_at INTEGER NOT NULL CHECK (generated_at >= 0),
14
+ expires_at INTEGER NOT NULL CHECK (expires_at >= generated_at),
15
+ ttl_seconds INTEGER NOT NULL CHECK (ttl_seconds > 0),
16
+ freshness_json TEXT NOT NULL,
17
+ source_coverage_json TEXT NOT NULL,
18
+ briefing_json TEXT NOT NULL,
19
+ ranked_items_json TEXT NOT NULL,
20
+ top_memory_refs_json TEXT NOT NULL,
21
+ pending_human_questions_json TEXT NOT NULL,
22
+ entity_clusters_json TEXT NOT NULL,
23
+ recommended_next_tools_json TEXT NOT NULL,
24
+ generated_from_slice_ids_json TEXT NOT NULL DEFAULT '[]',
25
+ caveats_json TEXT NOT NULL,
26
+ agent_id TEXT NOT NULL,
27
+ model_run_id TEXT NOT NULL,
28
+ input_snapshot_ref TEXT NOT NULL,
29
+ source_refs_json TEXT NOT NULL DEFAULT '[]',
30
+ tenant_id TEXT NOT NULL DEFAULT 'default',
31
+ project_id TEXT NOT NULL,
32
+ memory_scope_kind TEXT NOT NULL,
33
+ memory_scope_id TEXT NOT NULL,
34
+ created_at INTEGER NOT NULL
35
+ );
36
+
37
+ CREATE INDEX IF NOT EXISTS idx_agent_situation_cache_fresh
38
+ ON agent_situation_packets(cache_key, ranking_policy_version, expires_at DESC);
39
+
40
+ CREATE INDEX IF NOT EXISTS idx_agent_situation_envelope
41
+ ON agent_situation_packets(envelope_hash, generated_at DESC);
42
+
43
+ CREATE INDEX IF NOT EXISTS idx_agent_situation_model_run
44
+ ON agent_situation_packets(model_run_id, generated_at DESC);
45
+
46
+ CREATE INDEX IF NOT EXISTS idx_agent_situation_scope
47
+ ON agent_situation_packets(tenant_id, project_id, memory_scope_kind, memory_scope_id, generated_at DESC);
48
+
49
+ CREATE TABLE IF NOT EXISTS agent_situation_refresh_leases (
50
+ cache_key TEXT PRIMARY KEY,
51
+ ranking_policy_version TEXT NOT NULL,
52
+ lease_owner TEXT NOT NULL,
53
+ lease_expires_at INTEGER NOT NULL,
54
+ created_at INTEGER NOT NULL
55
+ );
56
+
57
+ CREATE INDEX IF NOT EXISTS idx_agent_situation_leases_expiry
58
+ ON agent_situation_refresh_leases(lease_expires_at);
59
+
60
+ INSERT OR IGNORE INTO schema_version (version, description)
61
+ VALUES (36, 'Create agent situation packet cache');
@@ -0,0 +1,32 @@
1
+ CREATE TABLE IF NOT EXISTS context_packets (
2
+ packet_id TEXT PRIMARY KEY,
3
+ task TEXT NOT NULL,
4
+ packet_json TEXT NOT NULL,
5
+ scope_json TEXT NOT NULL,
6
+ scope_hash TEXT NOT NULL,
7
+ envelope_hash TEXT NOT NULL,
8
+ model_run_id TEXT NOT NULL,
9
+ agent_id TEXT NOT NULL,
10
+ input_snapshot_ref TEXT NOT NULL,
11
+ source_refs_json TEXT NOT NULL DEFAULT '[]',
12
+ tenant_id TEXT NOT NULL DEFAULT 'default',
13
+ project_id TEXT NOT NULL,
14
+ memory_scope_kind TEXT NOT NULL CHECK (memory_scope_kind IN ('global', 'user', 'channel', 'project')),
15
+ memory_scope_id TEXT NOT NULL,
16
+ created_at INTEGER NOT NULL CHECK (created_at >= 0)
17
+ );
18
+
19
+ CREATE INDEX IF NOT EXISTS idx_context_packets_model_run
20
+ ON context_packets(model_run_id, created_at DESC);
21
+
22
+ CREATE INDEX IF NOT EXISTS idx_context_packets_envelope
23
+ ON context_packets(envelope_hash, created_at DESC);
24
+
25
+ CREATE INDEX IF NOT EXISTS idx_context_packets_scope
26
+ ON context_packets(tenant_id, project_id, memory_scope_kind, memory_scope_id, created_at DESC);
27
+
28
+ CREATE INDEX IF NOT EXISTS idx_context_packets_scope_hash
29
+ ON context_packets(scope_hash, created_at DESC);
30
+
31
+ INSERT OR IGNORE INTO schema_version (version, description)
32
+ VALUES (37, 'Create context packet append-only store');
@@ -0,0 +1,3 @@
1
+ import type { AgentGraphAdapter, AttachEntityAliasWithEdgeInput, AttachEntityAliasWithEdgeResult } from './types.js';
2
+ export declare function attachEntityAliasWithEdge(adapter: AgentGraphAdapter, input: AttachEntityAliasWithEdgeInput): AttachEntityAliasWithEdgeResult;
3
+ //# sourceMappingURL=alias-write.d.ts.map
@@ -0,0 +1,231 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.attachEntityAliasWithEdge = attachEntityAliasWithEdge;
4
+ const node_crypto_1 = require("node:crypto");
5
+ const canonicalize_js_1 = require("../canonicalize.js");
6
+ const ref_validation_js_1 = require("../edges/ref-validation.js");
7
+ const store_js_1 = require("../edges/store.js");
8
+ const types_js_1 = require("../edges/types.js");
9
+ const normalization_js_1 = require("../entities/normalization.js");
10
+ const store_js_2 = require("../entities/store.js");
11
+ const errors_js_1 = require("./errors.js");
12
+ const TWIN_REF_KIND_SET = new Set(types_js_1.TWIN_REF_KINDS);
13
+ function stableAliasId(input, normalizedLabel) {
14
+ const replayKey = replayIdempotencyKey(input);
15
+ if (replayKey) {
16
+ const hash = (0, node_crypto_1.createHash)('sha256')
17
+ .update(`${input.entity_id}\0${normalizedLabel}\0${replayKey}`, 'utf8')
18
+ .digest('hex')
19
+ .slice(0, 32);
20
+ return `alias_${hash}`;
21
+ }
22
+ return `alias_${(0, node_crypto_1.randomUUID)().replace(/-/g, '')}`;
23
+ }
24
+ function replayIdempotencyKey(input) {
25
+ return input.edge_idempotency_key ?? input.request_idempotency_key;
26
+ }
27
+ function loadAlias(adapter, aliasId) {
28
+ const row = adapter.prepare('SELECT * FROM entity_aliases WHERE id = ?').get(aliasId);
29
+ if (!row) {
30
+ throw new Error(`Entity alias was not written: ${aliasId}`);
31
+ }
32
+ return {
33
+ id: String(row.id),
34
+ entity_id: String(row.entity_id),
35
+ label: String(row.label),
36
+ normalized_label: String(row.normalized_label),
37
+ lang: typeof row.lang === 'string' ? row.lang : null,
38
+ script: typeof row.script === 'string' ? row.script : null,
39
+ label_type: row.label_type,
40
+ source_type: String(row.source_type),
41
+ source_ref: typeof row.source_ref === 'string' ? row.source_ref : null,
42
+ confidence: typeof row.confidence === 'number' ? row.confidence : null,
43
+ status: row.status,
44
+ created_at: Number(row.created_at),
45
+ };
46
+ }
47
+ function normalizeConfidence(value) {
48
+ if (value === undefined || value === null) {
49
+ return 1;
50
+ }
51
+ if (typeof value === 'number' && Number.isFinite(value) && value >= 0 && value <= 1) {
52
+ return value;
53
+ }
54
+ throw new errors_js_1.AgentGraphValidationError(`confidence must be between 0 and 1: ${String(value)}`);
55
+ }
56
+ function selectExistingAliasEdge(adapter, modelRunId, edgeIdempotencyKey) {
57
+ if (!edgeIdempotencyKey) {
58
+ return null;
59
+ }
60
+ const row = adapter
61
+ .prepare(`
62
+ SELECT *
63
+ FROM twin_edges
64
+ WHERE model_run_id = ?
65
+ AND edge_idempotency_key = ?
66
+ LIMIT 1
67
+ `)
68
+ .get(modelRunId, edgeIdempotencyKey);
69
+ return row ? (0, store_js_1.mapTwinEdgeRow)(row) : null;
70
+ }
71
+ function normalizeSourceRefs(sourceRefs) {
72
+ if (!sourceRefs || sourceRefs.length === 0) {
73
+ return [];
74
+ }
75
+ const refs = [];
76
+ const seen = new Set();
77
+ for (const ref of sourceRefs) {
78
+ if (!ref ||
79
+ typeof ref !== 'object' ||
80
+ typeof ref.kind !== 'string' ||
81
+ typeof ref.id !== 'string' ||
82
+ ref.id.trim().length === 0 ||
83
+ !TWIN_REF_KIND_SET.has(ref.kind)) {
84
+ throw new errors_js_1.AgentGraphValidationError('source_refs must be TwinRef objects with kind and id.');
85
+ }
86
+ const normalized = { kind: ref.kind, id: ref.id.trim() };
87
+ const key = `${normalized.kind}:${normalized.id}`;
88
+ if (!seen.has(key)) {
89
+ seen.add(key);
90
+ refs.push(normalized);
91
+ }
92
+ }
93
+ return refs.sort((left, right) => `${left.kind}:${left.id}`.localeCompare(`${right.kind}:${right.id}`));
94
+ }
95
+ function expectedRelationAttrs(alias, sourceRefs) {
96
+ const attrs = {
97
+ alias_id: alias.id,
98
+ label: alias.label,
99
+ normalized_label: alias.normalized_label,
100
+ lang: alias.lang,
101
+ script: alias.script,
102
+ label_type: alias.label_type,
103
+ };
104
+ if (sourceRefs.length > 0) {
105
+ attrs.source_refs = sourceRefs.map((ref) => ({ kind: ref.kind, id: ref.id }));
106
+ }
107
+ return attrs;
108
+ }
109
+ function assertAliasReplayMatches(alias, input, normalized, confidence) {
110
+ const expectedScript = input.script ?? normalized.script;
111
+ const expectedLabelType = input.label_type ?? 'alt';
112
+ const expectedSourceRef = input.source_ref ?? null;
113
+ const matches = alias.entity_id === input.entity_id &&
114
+ alias.label === input.label &&
115
+ alias.normalized_label === normalized.normalized &&
116
+ alias.lang === (input.lang ?? null) &&
117
+ alias.script === expectedScript &&
118
+ alias.label_type === expectedLabelType &&
119
+ alias.source_type === input.source_type &&
120
+ alias.source_ref === expectedSourceRef &&
121
+ alias.confidence === confidence &&
122
+ alias.status === 'active';
123
+ if (!matches) {
124
+ throw new errors_js_1.AgentGraphValidationError(`Conflicting entity alias replay for request idempotency key: ${replayIdempotencyKey(input)}`);
125
+ }
126
+ }
127
+ function assertAliasEdgeReplayMatches(edge, input, alias, confidence, edgeIdempotencyKey, sourceRefs) {
128
+ const matches = edge.edge_type === 'alias_of' &&
129
+ edge.subject_ref.kind === 'entity' &&
130
+ edge.subject_ref.id === input.entity_id &&
131
+ edge.object_ref.kind === 'entity' &&
132
+ edge.object_ref.id === input.entity_id &&
133
+ edge.relation_attrs_json === (0, canonicalize_js_1.canonicalizeJSON)(expectedRelationAttrs(alias, sourceRefs)) &&
134
+ edge.confidence === confidence &&
135
+ edge.source === 'agent' &&
136
+ edge.agent_id === input.agent_id &&
137
+ edge.model_run_id === input.model_run_id &&
138
+ edge.envelope_hash === input.envelope_hash &&
139
+ edge.request_idempotency_key === (input.request_idempotency_key ?? null) &&
140
+ edge.edge_idempotency_key === (edgeIdempotencyKey ?? null);
141
+ if (!matches) {
142
+ throw new errors_js_1.AgentGraphValidationError(`Conflicting alias edge replay for request idempotency key: ${replayIdempotencyKey(input)}`);
143
+ }
144
+ }
145
+ function insertAliasEdge(adapter, input, alias, confidence, sourceRefs) {
146
+ const edgeIdempotencyKey = replayIdempotencyKey(input);
147
+ const existing = selectExistingAliasEdge(adapter, input.model_run_id, edgeIdempotencyKey);
148
+ const edgeId = `edge_${(0, node_crypto_1.randomUUID)().replace(/-/g, '')}`;
149
+ const relationAttrs = expectedRelationAttrs(alias, sourceRefs);
150
+ const relationAttrsJson = (0, canonicalize_js_1.canonicalizeJSON)(relationAttrs);
151
+ if (existing) {
152
+ assertAliasEdgeReplayMatches(existing, input, alias, confidence, edgeIdempotencyKey, sourceRefs);
153
+ return existing;
154
+ }
155
+ const contentHash = (0, node_crypto_1.createHash)('sha256')
156
+ .update((0, canonicalize_js_1.canonicalizeJSON)({
157
+ edge_type: 'alias_of',
158
+ subject_ref: { kind: 'entity', id: input.entity_id },
159
+ object_ref: { kind: 'entity', id: input.entity_id },
160
+ relation_attrs_json: relationAttrsJson,
161
+ confidence,
162
+ source: 'agent',
163
+ agent_id: input.agent_id,
164
+ model_run_id: input.model_run_id,
165
+ envelope_hash: input.envelope_hash,
166
+ }), 'utf8')
167
+ .digest();
168
+ adapter
169
+ .prepare(`
170
+ INSERT INTO twin_edges (
171
+ edge_id, edge_type, subject_kind, subject_id, object_kind, object_id,
172
+ relation_attrs_json, confidence, source, agent_id, model_run_id, envelope_hash,
173
+ request_idempotency_key, edge_idempotency_key, content_hash, created_at
174
+ )
175
+ VALUES (?, 'alias_of', 'entity', ?, 'entity', ?, ?, ?, 'agent', ?, ?, ?, ?, ?, ?, ?)
176
+ `)
177
+ .run(edgeId, input.entity_id, input.entity_id, relationAttrsJson, confidence, input.agent_id, input.model_run_id, input.envelope_hash, input.request_idempotency_key ?? null, edgeIdempotencyKey ?? null, contentHash, Date.now());
178
+ const row = adapter.prepare('SELECT * FROM twin_edges WHERE edge_id = ?').get(edgeId);
179
+ if (!row) {
180
+ throw new Error(`Entity alias edge was not written: ${edgeId}`);
181
+ }
182
+ return (0, store_js_1.mapTwinEdgeRow)(row);
183
+ }
184
+ function attachEntityAliasWithEdge(adapter, input) {
185
+ const entity = (0, store_js_2.getEntityNode)(input.entity_id, adapter);
186
+ if (!entity || entity.status !== 'active') {
187
+ throw new errors_js_1.AgentGraphValidationError(`Active entity not found: ${input.entity_id}`);
188
+ }
189
+ const visibility = {
190
+ scopes: input.scopes,
191
+ connectors: input.connectors,
192
+ projectRefs: input.project_refs,
193
+ tenantId: input.tenant_id,
194
+ };
195
+ const sourceRefs = normalizeSourceRefs(input.source_refs);
196
+ if (sourceRefs.length === 0) {
197
+ throw new errors_js_1.AgentGraphValidationError('source_refs must include at least one visible source.');
198
+ }
199
+ try {
200
+ (0, ref_validation_js_1.assertTwinRefsVisible)(adapter, [{ kind: 'entity', id: input.entity_id }, ...sourceRefs], visibility);
201
+ }
202
+ catch (error) {
203
+ throw new errors_js_1.AgentGraphValidationError(error instanceof Error ? error.message : String(error));
204
+ }
205
+ let normalized;
206
+ try {
207
+ normalized = (0, normalization_js_1.normalizeEntityLabel)(input.label);
208
+ }
209
+ catch (error) {
210
+ throw new errors_js_1.AgentGraphValidationError(error instanceof Error ? error.message : String(error));
211
+ }
212
+ const confidence = normalizeConfidence(input.confidence);
213
+ const aliasId = stableAliasId(input, normalized.normalized);
214
+ const createdAt = Date.now();
215
+ return adapter.transaction(() => {
216
+ adapter
217
+ .prepare(`
218
+ INSERT OR IGNORE INTO entity_aliases (
219
+ id, entity_id, label, normalized_label, lang, script, label_type,
220
+ source_type, source_ref, confidence, status, created_at
221
+ )
222
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'active', ?)
223
+ `)
224
+ .run(aliasId, input.entity_id, input.label, normalized.normalized, input.lang ?? null, input.script ?? normalized.script, input.label_type ?? 'alt', input.source_type, input.source_ref ?? null, confidence, createdAt);
225
+ const alias = loadAlias(adapter, aliasId);
226
+ assertAliasReplayMatches(alias, input, normalized, confidence);
227
+ const edge = insertAliasEdge(adapter, input, alias, confidence, sourceRefs);
228
+ return { alias, edge };
229
+ });
230
+ }
231
+ //# sourceMappingURL=alias-write.js.map
@@ -0,0 +1,3 @@
1
+ import type { AgentGraphAdapter, ResolveEntityInput, ResolveEntityResult } from './types.js';
2
+ export declare function resolveEntity(adapter: AgentGraphAdapter, input: ResolveEntityInput): ResolveEntityResult;
3
+ //# sourceMappingURL=entity-resolve.d.ts.map