@jungjaehoon/mama-core 1.4.2 → 1.6.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 (181) hide show
  1. package/README.md +48 -10
  2. package/db/migrations/026-create-canonical-entity-tables.sql +99 -0
  3. package/db/migrations/027-create-entity-review-support.sql +44 -0
  4. package/db/migrations/028-create-entity-audit-tables.sql +45 -0
  5. package/db/migrations/029-extend-entity-observations-observation-type.sql +60 -0
  6. package/db/migrations/030-case-first-memory-substrate.sql +901 -0
  7. package/db/migrations/031-wiki-page-index-provenance-columns.sql +2 -0
  8. package/db/migrations/032-add-memory-provenance-columns.sql +21 -0
  9. package/db/migrations/033-create-model-runs-and-tool-traces.sql +53 -0
  10. package/db/migrations/034-add-connector-event-scope-columns.sql +14 -0
  11. package/db/migrations/035-create-twin-edges.sql +63 -0
  12. package/db/migrations/036-create-agent-situation-packets.sql +61 -0
  13. package/dist/agent-graph/alias-write.d.ts +3 -0
  14. package/dist/agent-graph/alias-write.js +231 -0
  15. package/dist/agent-graph/entity-resolve.d.ts +3 -0
  16. package/dist/agent-graph/entity-resolve.js +275 -0
  17. package/dist/agent-graph/errors.d.ts +4 -0
  18. package/dist/agent-graph/errors.js +11 -0
  19. package/dist/agent-graph/graph-query.d.ts +5 -0
  20. package/dist/agent-graph/graph-query.js +359 -0
  21. package/dist/agent-graph/index.d.ts +6 -0
  22. package/dist/agent-graph/index.js +22 -0
  23. package/dist/agent-graph/types.d.ts +162 -0
  24. package/dist/agent-graph/types.js +3 -0
  25. package/dist/agent-situation/builder.d.ts +8 -0
  26. package/dist/agent-situation/builder.js +239 -0
  27. package/dist/agent-situation/cache-key.d.ts +4 -0
  28. package/dist/agent-situation/cache-key.js +64 -0
  29. package/dist/agent-situation/index.d.ts +7 -0
  30. package/dist/agent-situation/index.js +28 -0
  31. package/dist/agent-situation/packet-store.d.ts +27 -0
  32. package/dist/agent-situation/packet-store.js +228 -0
  33. package/dist/agent-situation/ranking-policy.d.ts +18 -0
  34. package/dist/agent-situation/ranking-policy.js +75 -0
  35. package/dist/agent-situation/source-readers.d.ts +52 -0
  36. package/dist/agent-situation/source-readers.js +300 -0
  37. package/dist/agent-situation/types.d.ts +195 -0
  38. package/dist/agent-situation/types.js +3 -0
  39. package/dist/canonicalize.d.ts +38 -0
  40. package/dist/canonicalize.js +106 -0
  41. package/dist/cases/case-links.d.ts +116 -0
  42. package/dist/cases/case-links.js +794 -0
  43. package/dist/cases/composition-overrides.d.ts +90 -0
  44. package/dist/cases/composition-overrides.js +724 -0
  45. package/dist/cases/corrections.d.ts +156 -0
  46. package/dist/cases/corrections.js +1045 -0
  47. package/dist/cases/freshness.d.ts +57 -0
  48. package/dist/cases/freshness.js +283 -0
  49. package/dist/cases/live-state.d.ts +48 -0
  50. package/dist/cases/live-state.js +256 -0
  51. package/dist/cases/membership-explain.d.ts +56 -0
  52. package/dist/cases/membership-explain.js +140 -0
  53. package/dist/cases/membership-matcher.d.ts +23 -0
  54. package/dist/cases/membership-matcher.js +193 -0
  55. package/dist/cases/merge-split.d.ts +61 -0
  56. package/dist/cases/merge-split.js +368 -0
  57. package/dist/cases/role-inference.d.ts +10 -0
  58. package/dist/cases/role-inference.js +85 -0
  59. package/dist/cases/search-rollup.d.ts +27 -0
  60. package/dist/cases/search-rollup.js +309 -0
  61. package/dist/cases/sqlite-transaction.d.ts +10 -0
  62. package/dist/cases/sqlite-transaction.js +62 -0
  63. package/dist/cases/store.d.ts +74 -0
  64. package/dist/cases/store.js +816 -0
  65. package/dist/cases/target-ref.d.ts +25 -0
  66. package/dist/cases/target-ref.js +22 -0
  67. package/dist/cases/timeline-range.d.ts +6 -0
  68. package/dist/cases/timeline-range.js +322 -0
  69. package/dist/cases/tombstone-sweeper.d.ts +13 -0
  70. package/dist/cases/tombstone-sweeper.js +128 -0
  71. package/dist/cases/types.d.ts +244 -0
  72. package/dist/cases/types.js +47 -0
  73. package/dist/cases/wiki-page-index.d.ts +50 -0
  74. package/dist/cases/wiki-page-index.js +350 -0
  75. package/dist/connectors/event-index.d.ts +45 -0
  76. package/dist/connectors/event-index.js +381 -0
  77. package/dist/connectors/raw-query.d.ts +18 -0
  78. package/dist/connectors/raw-query.js +305 -0
  79. package/dist/connectors/types.d.ts +109 -0
  80. package/dist/connectors/types.js +3 -0
  81. package/dist/db-adapter/node-sqlite-adapter.d.ts +6 -0
  82. package/dist/db-adapter/node-sqlite-adapter.js +131 -0
  83. package/dist/db-manager.d.ts +12 -1
  84. package/dist/db-manager.js +60 -5
  85. package/dist/decision-formatter.d.ts +2 -0
  86. package/dist/decision-formatter.js +11 -8
  87. package/dist/edges/ref-validation.d.ts +8 -0
  88. package/dist/edges/ref-validation.js +262 -0
  89. package/dist/edges/store.d.ts +10 -0
  90. package/dist/edges/store.js +343 -0
  91. package/dist/edges/types.d.ts +86 -0
  92. package/dist/edges/types.js +18 -0
  93. package/dist/embedding-server/mobile/daemon.d.ts +1 -0
  94. package/dist/embedding-server/mobile/daemon.js +11 -1
  95. package/dist/embeddings.js +13 -0
  96. package/dist/entities/audit-metrics.d.ts +73 -0
  97. package/dist/entities/audit-metrics.js +128 -0
  98. package/dist/entities/candidate-generator.d.ts +9 -0
  99. package/dist/entities/candidate-generator.js +436 -0
  100. package/dist/entities/entity-impact.d.ts +41 -0
  101. package/dist/entities/entity-impact.js +140 -0
  102. package/dist/entities/entity-linked-decision-counts.d.ts +2 -0
  103. package/dist/entities/entity-linked-decision-counts.js +29 -0
  104. package/dist/entities/entity-list.d.ts +23 -0
  105. package/dist/entities/entity-list.js +99 -0
  106. package/dist/entities/entity-orphan-list.d.ts +26 -0
  107. package/dist/entities/entity-orphan-list.js +91 -0
  108. package/dist/entities/entity-search.d.ts +21 -0
  109. package/dist/entities/entity-search.js +150 -0
  110. package/dist/entities/errors.d.ts +65 -0
  111. package/dist/entities/errors.js +124 -0
  112. package/dist/entities/exact-merge-backfill.d.ts +11 -0
  113. package/dist/entities/exact-merge-backfill.js +161 -0
  114. package/dist/entities/lineage-backfill.d.ts +12 -0
  115. package/dist/entities/lineage-backfill.js +101 -0
  116. package/dist/entities/lineage-store.d.ts +51 -0
  117. package/dist/entities/lineage-store.js +308 -0
  118. package/dist/entities/normalization.d.ts +14 -0
  119. package/dist/entities/normalization.js +63 -0
  120. package/dist/entities/policy-store.d.ts +17 -0
  121. package/dist/entities/policy-store.js +263 -0
  122. package/dist/entities/policy-types.d.ts +72 -0
  123. package/dist/entities/policy-types.js +59 -0
  124. package/dist/entities/projection.d.ts +8 -0
  125. package/dist/entities/projection.js +82 -0
  126. package/dist/entities/provenance-query.d.ts +33 -0
  127. package/dist/entities/provenance-query.js +167 -0
  128. package/dist/entities/read-identity.d.ts +31 -0
  129. package/dist/entities/read-identity.js +264 -0
  130. package/dist/entities/recall-bridge.d.ts +5 -0
  131. package/dist/entities/recall-bridge.js +171 -0
  132. package/dist/entities/resolution-engine.d.ts +15 -0
  133. package/dist/entities/resolution-engine.js +69 -0
  134. package/dist/entities/rollback-preview.d.ts +39 -0
  135. package/dist/entities/rollback-preview.js +235 -0
  136. package/dist/entities/source-locator.d.ts +3 -0
  137. package/dist/entities/source-locator.js +32 -0
  138. package/dist/entities/store.d.ts +75 -0
  139. package/dist/entities/store.js +465 -0
  140. package/dist/entities/types.d.ts +162 -0
  141. package/dist/entities/types.js +30 -0
  142. package/dist/index.d.ts +62 -3
  143. package/dist/index.js +116 -26
  144. package/dist/mama-api.d.ts +53 -35
  145. package/dist/mama-api.js +437 -78
  146. package/dist/memory/api.d.ts +26 -38
  147. package/dist/memory/api.js +772 -68
  148. package/dist/memory/event-store.d.ts +3 -0
  149. package/dist/memory/event-store.js +21 -2
  150. package/dist/memory/provenance-audit.d.ts +22 -0
  151. package/dist/memory/provenance-audit.js +112 -0
  152. package/dist/memory/provenance-query.d.ts +11 -0
  153. package/dist/memory/provenance-query.js +193 -0
  154. package/dist/memory/provenance.d.ts +29 -0
  155. package/dist/memory/provenance.js +136 -0
  156. package/dist/memory/scope-backfill.d.ts +17 -0
  157. package/dist/memory/scope-backfill.js +77 -0
  158. package/dist/memory/types.d.ts +97 -16
  159. package/dist/model-runs/store.d.ts +13 -0
  160. package/dist/model-runs/store.js +457 -0
  161. package/dist/model-runs/tool-trace-store.d.ts +4 -0
  162. package/dist/model-runs/tool-trace-store.js +114 -0
  163. package/dist/model-runs/types.d.ts +69 -0
  164. package/dist/model-runs/types.js +5 -0
  165. package/dist/runtime/trusted-provenance.d.ts +3 -0
  166. package/dist/runtime/trusted-provenance.js +6 -0
  167. package/dist/search/feedback-store.d.ts +59 -0
  168. package/dist/search/feedback-store.js +211 -0
  169. package/dist/search/question-type.d.ts +5 -0
  170. package/dist/search/question-type.js +41 -0
  171. package/dist/search/ranker-features.d.ts +23 -0
  172. package/dist/search/ranker-features.js +104 -0
  173. package/dist/search/ranker-rescore.d.ts +31 -0
  174. package/dist/search/ranker-rescore.js +226 -0
  175. package/dist/search/ranker-trainer.d.ts +94 -0
  176. package/dist/search/ranker-trainer.js +860 -0
  177. package/dist/search/search-quality.d.ts +36 -0
  178. package/dist/search/search-quality.js +29 -0
  179. package/dist/test-utils.d.ts +14 -0
  180. package/dist/test-utils.js +52 -0
  181. package/package.json +28 -3
@@ -1,3 +1,6 @@
1
+ import type { ConnectorEventSearchHit } from '../connectors/types.js';
2
+ import type { ReadIdentity } from '../entities/read-identity.js';
3
+ import type { SearchHitDiagnostics, SearchQualityOptions, SearchStrictness } from '../search/search-quality.js';
1
4
  export declare const MEMORY_SCOPE_KINDS: readonly ["global", "user", "channel", "project"];
2
5
  export type MemoryScopeKind = (typeof MEMORY_SCOPE_KINDS)[number];
3
6
  export declare const MEMORY_KINDS: readonly ["decision", "preference", "constraint", "lesson", "fact", "task", "schedule", "compiled"];
@@ -18,6 +21,13 @@ export interface MemoryScopeRef {
18
21
  kind: MemoryScopeKind;
19
22
  id: string;
20
23
  }
24
+ export interface MemorySourceRef {
25
+ package: 'mama-core' | 'mcp-server' | 'standalone' | 'claude-code-plugin';
26
+ source_type: string;
27
+ user_id?: string;
28
+ channel_id?: string;
29
+ project_id?: string;
30
+ }
21
31
  export interface MemoryRecord {
22
32
  id: string;
23
33
  topic: string;
@@ -27,17 +37,34 @@ export interface MemoryRecord {
27
37
  confidence: number;
28
38
  status: MemoryStatus;
29
39
  scopes: MemoryScopeRef[];
30
- source: {
31
- package: 'mama-core' | 'mcp-server' | 'standalone' | 'claude-code-plugin';
32
- source_type: string;
33
- user_id?: string;
34
- channel_id?: string;
35
- project_id?: string;
36
- };
40
+ source: MemorySourceRef;
37
41
  created_at: number | string;
38
42
  updated_at: number | string;
39
43
  /** ISO 8601 date when the event actually occurred (e.g. "2023-01-15"). Null if not set. */
40
44
  event_date?: string | null;
45
+ /** Source event timestamp in milliseconds when known. Null if not set. */
46
+ event_datetime?: number | null;
47
+ read_identity?: ReadIdentity;
48
+ retrieval_diagnostics?: SearchHitDiagnostics;
49
+ }
50
+ export type RecallMemoryOptions = SearchQualityOptions & {
51
+ scopes?: MemoryScopeRef[];
52
+ includeProfile?: boolean;
53
+ includeHistory?: boolean;
54
+ skipGraphExpansion?: boolean;
55
+ limit?: number;
56
+ };
57
+ export interface RecallSearchDiagnostics {
58
+ candidate_counts: {
59
+ vector: number;
60
+ lexical: number;
61
+ entity: number;
62
+ graph_expanded: number;
63
+ vector_only: number;
64
+ rejected_by_strictness: number;
65
+ };
66
+ threshold: number;
67
+ strictness: SearchStrictness;
41
68
  }
42
69
  export interface MemoryEdge {
43
70
  from_id: string;
@@ -57,6 +84,8 @@ export interface ProfileSnapshot {
57
84
  export interface RecallBundle {
58
85
  profile: ProfileSnapshot;
59
86
  memories: MemoryRecord[];
87
+ /** Phase 3: cross-connector event hits, populated when searchWithConnectorEvents=true */
88
+ connector_event_hits?: ConnectorEventSearchHit[];
60
89
  graph_context: {
61
90
  primary: MemoryRecord[];
62
91
  expanded: MemoryRecord[];
@@ -66,12 +95,15 @@ export interface RecallBundle {
66
95
  query: string;
67
96
  scope_order: MemoryScopeKind[];
68
97
  retrieval_sources: string[];
98
+ diagnostics?: RecallSearchDiagnostics;
69
99
  };
70
100
  }
101
+ /** Phase 3: unified search result type — memory-authored or connector-enriched. */
102
+ export type MemorySearchResultHit = MemoryRecord | ConnectorEventSearchHit;
71
103
  export interface MemoryEventRecord {
72
104
  event_id: string;
73
- event_type: 'observed_conversation' | 'save' | 'supersede' | 'contradict' | 'mark_stale' | 'quarantine' | 'no_op' | 'audit_failed' | 'notice_sent';
74
- actor: 'memory_agent' | 'main_agent' | 'user' | 'system';
105
+ event_type: 'observed_conversation' | 'save' | 'supersede' | 'contradict' | 'mark_stale' | 'quarantine' | 'no_op' | 'audit_failed' | 'notice_sent' | 'provenance.empty_batch' | 'provenance.link_write_failed' | 'connector_event_index.retention_swept' | 'case.link_created' | 'case.link_revoked' | 'case.membership_pinned' | 'case.membership_unpinned' | 'case.source_promoted' | 'case.freshness_drifted' | 'automation.job.started' | 'automation.job.succeeded' | 'automation.job.failed' | 'automation.job.skipped_concurrent' | 'review.bulk.approved' | 'review.bulk.rejected' | 'review.bulk.deferred' | 'canary.drift.false_merge_rate' | 'canary.drift.projection_fragmentation_rate' | 'canary.drift.replay_stale' | 'auth.role_denied' | 'ontology.proposal' | 'ontology.approval' | 'repair.approval' | 'case.fast_write_applied' | 'case.fast_write_lock_skipped' | 'case.correction_applied' | 'case.correction_reverted' | 'case.correction_superseded' | 'case.membership_tombstoned' | 'case.merged' | 'case.split' | 'case.membership_matched' | 'case.membership_candidate';
106
+ actor: 'memory_agent' | 'main_agent' | 'user' | 'system' | `user:${string}` | `user_uuid:${string}` | `local:${string}` | `actor:${string}` | 'token:bearer';
75
107
  source_turn_id?: string;
76
108
  memory_id?: string;
77
109
  topic?: string;
@@ -80,6 +112,61 @@ export interface MemoryEventRecord {
80
112
  reason?: string;
81
113
  created_at: number;
82
114
  }
115
+ export interface MemoryWriteProvenance {
116
+ actor?: MemoryEventRecord['actor'];
117
+ agent_id?: string;
118
+ model_run_id?: string;
119
+ envelope_hash?: string;
120
+ tool_name?: string;
121
+ gateway_call_id?: string;
122
+ source_turn_id?: string;
123
+ source_message_ref?: string;
124
+ source_refs?: string[];
125
+ }
126
+ export interface MemoryProvenanceRecord {
127
+ memory_id: string;
128
+ agent_id: string | null;
129
+ model_run_id: string | null;
130
+ envelope_hash: string | null;
131
+ gateway_call_id: string | null;
132
+ source_refs: string[];
133
+ provenance: Record<string, unknown>;
134
+ latest_event?: MemoryEventRecord;
135
+ }
136
+ export interface PublicSaveMemoryInput {
137
+ topic: string;
138
+ kind: MemoryKind;
139
+ summary: string;
140
+ details: string;
141
+ confidence?: number;
142
+ status?: MemoryStatus;
143
+ scopes: MemoryScopeRef[];
144
+ source: MemorySourceRef;
145
+ excludeIds?: string[];
146
+ eventDate?: string;
147
+ eventDateTime?: number;
148
+ entityObservationIds?: string[];
149
+ timelineEvent?: {
150
+ id?: string;
151
+ entity_id?: string;
152
+ event_type: string;
153
+ role?: string | null;
154
+ valid_from?: number | null;
155
+ valid_to?: number | null;
156
+ observed_at?: number | null;
157
+ source_ref?: string | null;
158
+ summary: string;
159
+ details?: string | null;
160
+ };
161
+ }
162
+ export interface PublicIngestMemoryInput {
163
+ content: string;
164
+ scopes?: MemoryScopeRef[];
165
+ source: MemorySourceRef;
166
+ eventDate?: string;
167
+ eventDateTime?: number;
168
+ }
169
+ export type PublicIngestConversationInput = IngestConversationInput;
83
170
  export interface AuditFindingRecord {
84
171
  finding_id: string;
85
172
  kind: 'wrong_direction' | 'memory_conflict' | 'stale_memory' | 'unsupported_claim';
@@ -227,13 +314,7 @@ export interface ConversationMessage {
227
314
  export interface IngestConversationInput {
228
315
  messages: ConversationMessage[];
229
316
  scopes: MemoryScopeRef[];
230
- source: {
231
- package: 'mama-core' | 'mcp-server' | 'standalone' | 'claude-code-plugin';
232
- source_type: string;
233
- user_id?: string;
234
- channel_id?: string;
235
- project_id?: string;
236
- };
317
+ source: MemorySourceRef;
237
318
  extract?: {
238
319
  enabled: boolean;
239
320
  model?: string;
@@ -0,0 +1,13 @@
1
+ import type { DatabaseAdapter } from '../db-manager.js';
2
+ import type { BeginModelRunInput, ModelRunRecord } from './types.js';
3
+ type ModelRunAdapter = Pick<DatabaseAdapter, 'prepare'>;
4
+ export declare function beginModelRunInAdapter(adapter: ModelRunAdapter, input: BeginModelRunInput): ModelRunRecord;
5
+ export declare function commitModelRunInAdapter(adapter: ModelRunAdapter, modelRunId: string, summary?: string): ModelRunRecord;
6
+ export declare function failModelRunInAdapter(adapter: ModelRunAdapter, modelRunId: string, errorSummary: string): ModelRunRecord;
7
+ export declare function getModelRunInAdapter(adapter: ModelRunAdapter, modelRunId: string): ModelRunRecord | null;
8
+ export declare function beginModelRun(input: BeginModelRunInput): Promise<ModelRunRecord>;
9
+ export declare function commitModelRun(modelRunId: string, summary?: string): Promise<ModelRunRecord>;
10
+ export declare function failModelRun(modelRunId: string, errorSummary: string): Promise<ModelRunRecord>;
11
+ export declare function getModelRun(modelRunId: string): Promise<ModelRunRecord | null>;
12
+ export {};
13
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1,457 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.beginModelRunInAdapter = beginModelRunInAdapter;
7
+ exports.commitModelRunInAdapter = commitModelRunInAdapter;
8
+ exports.failModelRunInAdapter = failModelRunInAdapter;
9
+ exports.getModelRunInAdapter = getModelRunInAdapter;
10
+ exports.beginModelRun = beginModelRun;
11
+ exports.commitModelRun = commitModelRun;
12
+ exports.failModelRun = failModelRun;
13
+ exports.getModelRun = getModelRun;
14
+ const node_crypto_1 = __importDefault(require("node:crypto"));
15
+ const db_manager_js_1 = require("../db-manager.js");
16
+ const types_js_1 = require("./types.js");
17
+ const BEGIN_REPLAY_FIELDS = [
18
+ 'model_id',
19
+ 'model_provider',
20
+ 'prompt_version',
21
+ 'tool_manifest_version',
22
+ 'output_schema_version',
23
+ 'agent_id',
24
+ 'instance_id',
25
+ 'envelope_hash',
26
+ 'parent_model_run_id',
27
+ 'input_snapshot_ref',
28
+ 'input_refs_json',
29
+ 'token_count',
30
+ 'cost_estimate',
31
+ ];
32
+ const STABLE_INPUT_REF_KEYS = new Set([
33
+ 'request_idempotency_key',
34
+ 'gateway_call_id',
35
+ 'source_turn_id',
36
+ 'turn_id',
37
+ 'message_id',
38
+ 'event_id',
39
+ 'raw_event_id',
40
+ 'trace_id',
41
+ 'cache_key',
42
+ ]);
43
+ function modelRunId() {
44
+ return `mr_${node_crypto_1.default.randomUUID().replace(/-/g, '')}`;
45
+ }
46
+ function nullableString(value) {
47
+ return typeof value === 'string' && value.length > 0 ? value : null;
48
+ }
49
+ function formatInvalidValue(value) {
50
+ return typeof value === 'string' ? JSON.stringify(value) : String(value);
51
+ }
52
+ function requireString(value, field) {
53
+ if (typeof value !== 'string' || value.length === 0) {
54
+ throw new Error(`model_runs.${field} must be a non-empty string: ${formatInvalidValue(value)}`);
55
+ }
56
+ return value;
57
+ }
58
+ function normalizeTimestamp(value) {
59
+ if (value === undefined) {
60
+ return Date.now();
61
+ }
62
+ if (typeof value === 'number' && Number.isFinite(value)) {
63
+ return Math.floor(value);
64
+ }
65
+ throw new Error(`model_runs.created_at must be a finite number: ${formatInvalidValue(value)}`);
66
+ }
67
+ function requireTimestamp(value, field, modelRunId) {
68
+ if (typeof value !== 'number' || !Number.isFinite(value)) {
69
+ throw new Error(`Invalid model_runs.${field} for ${modelRunId}: ${formatInvalidValue(value)}`);
70
+ }
71
+ return Math.floor(value);
72
+ }
73
+ function normalizeNumber(value, fallback) {
74
+ return typeof value === 'number' && Number.isFinite(value) ? Math.floor(value) : fallback;
75
+ }
76
+ function normalizeCost(value) {
77
+ return typeof value === 'number' && Number.isFinite(value) ? value : null;
78
+ }
79
+ function requireInputRefsObject(value, field) {
80
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
81
+ return value;
82
+ }
83
+ throw new Error(`model_runs.${field} must be a JSON object`);
84
+ }
85
+ function normalizeInputRefsJson(input) {
86
+ if (typeof input.input_refs_json === 'string') {
87
+ try {
88
+ requireInputRefsObject(JSON.parse(input.input_refs_json), 'input_refs_json');
89
+ }
90
+ catch (error) {
91
+ const message = error instanceof Error ? error.message : String(error);
92
+ throw new Error(`Invalid model_runs.input_refs_json: ${message}`);
93
+ }
94
+ return input.input_refs_json;
95
+ }
96
+ if (input.input_refs === null || input.input_refs === undefined) {
97
+ return null;
98
+ }
99
+ const inputRefs = requireInputRefsObject(input.input_refs, 'input_refs');
100
+ try {
101
+ return JSON.stringify(inputRefs);
102
+ }
103
+ catch (error) {
104
+ const message = error instanceof Error ? error.message : String(error);
105
+ throw new Error(`Invalid model_runs.input_refs: ${message}`);
106
+ }
107
+ }
108
+ function parseInputRefs(row) {
109
+ const inputRefsJson = nullableString(row.input_refs_json);
110
+ if (!inputRefsJson) {
111
+ return { input_refs_json: null, input_refs: null };
112
+ }
113
+ try {
114
+ const parsed = JSON.parse(inputRefsJson);
115
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
116
+ return {
117
+ input_refs_json: inputRefsJson,
118
+ input_refs: parsed,
119
+ };
120
+ }
121
+ }
122
+ catch (error) {
123
+ const message = error instanceof Error ? error.message : String(error);
124
+ throw new Error(`Invalid model_runs.input_refs_json for ${row.model_run_id}: ${message}`);
125
+ }
126
+ throw new Error(`Invalid model_runs.input_refs_json for ${row.model_run_id}: expected object`);
127
+ }
128
+ const MODEL_RUN_STATUS_SET = new Set(types_js_1.MODEL_RUN_STATUSES);
129
+ function requireModelRunStatus(value, modelRunId) {
130
+ if (typeof value === 'string' && MODEL_RUN_STATUS_SET.has(value)) {
131
+ return value;
132
+ }
133
+ throw new Error(`Invalid model_runs.status for ${modelRunId}: ${formatInvalidValue(value)}`);
134
+ }
135
+ function normalizeBeginStatus(value, modelRunId) {
136
+ const status = requireModelRunStatus(value ?? 'running', modelRunId);
137
+ if (status !== 'running') {
138
+ throw new Error(`model_runs.status must begin in running status for ${modelRunId}: ${status}`);
139
+ }
140
+ return status;
141
+ }
142
+ function mapModelRunRow(row) {
143
+ const model_run_id = requireString(row.model_run_id, 'model_run_id');
144
+ const inputRefs = parseInputRefs({ model_run_id, input_refs_json: row.input_refs_json });
145
+ return {
146
+ model_run_id,
147
+ model_id: nullableString(row.model_id),
148
+ model_provider: nullableString(row.model_provider),
149
+ prompt_version: nullableString(row.prompt_version),
150
+ tool_manifest_version: nullableString(row.tool_manifest_version),
151
+ output_schema_version: nullableString(row.output_schema_version),
152
+ agent_id: nullableString(row.agent_id),
153
+ instance_id: nullableString(row.instance_id),
154
+ envelope_hash: nullableString(row.envelope_hash),
155
+ parent_model_run_id: nullableString(row.parent_model_run_id),
156
+ input_snapshot_ref: nullableString(row.input_snapshot_ref),
157
+ input_refs_json: inputRefs.input_refs_json,
158
+ input_refs: inputRefs.input_refs,
159
+ completion_summary: nullableString(row.completion_summary),
160
+ status: requireModelRunStatus(row.status, model_run_id),
161
+ error_summary: nullableString(row.error_summary),
162
+ token_count: normalizeNumber(row.token_count, 0),
163
+ cost_estimate: normalizeCost(row.cost_estimate),
164
+ created_at: requireTimestamp(row.created_at, 'created_at', model_run_id),
165
+ completed_at: typeof row.completed_at === 'number' && Number.isFinite(row.completed_at)
166
+ ? Math.floor(row.completed_at)
167
+ : null,
168
+ };
169
+ }
170
+ async function initializedAdapter() {
171
+ await (0, db_manager_js_1.initDB)();
172
+ return (0, db_manager_js_1.getAdapter)();
173
+ }
174
+ function selectModelRun(adapter, id) {
175
+ const row = adapter
176
+ .prepare(`
177
+ SELECT
178
+ model_run_id, model_id, model_provider, prompt_version, tool_manifest_version,
179
+ output_schema_version, agent_id, instance_id, envelope_hash, parent_model_run_id,
180
+ input_snapshot_ref, input_refs_json, completion_summary, status, error_summary,
181
+ token_count, cost_estimate, created_at, completed_at
182
+ FROM model_runs
183
+ WHERE model_run_id = ?
184
+ `)
185
+ .get(id);
186
+ return row ? mapModelRunRow(row) : null;
187
+ }
188
+ function requireModelRun(adapter, id) {
189
+ const run = selectModelRun(adapter, id);
190
+ if (!run) {
191
+ throw new Error(`Model run not found: ${id}`);
192
+ }
193
+ return run;
194
+ }
195
+ function normalizeBeginModelRunInput(id, input, createdAt, status, inputRefsJson) {
196
+ return {
197
+ model_run_id: id,
198
+ model_id: nullableString(input.model_id),
199
+ model_provider: nullableString(input.model_provider),
200
+ prompt_version: nullableString(input.prompt_version),
201
+ tool_manifest_version: nullableString(input.tool_manifest_version),
202
+ output_schema_version: nullableString(input.output_schema_version),
203
+ agent_id: nullableString(input.agent_id),
204
+ instance_id: nullableString(input.instance_id),
205
+ envelope_hash: nullableString(input.envelope_hash),
206
+ parent_model_run_id: nullableString(input.parent_model_run_id),
207
+ input_snapshot_ref: nullableString(input.input_snapshot_ref),
208
+ input_refs_json: inputRefsJson,
209
+ status,
210
+ error_summary: nullableString(input.error_summary),
211
+ token_count: normalizeNumber(input.token_count, 0),
212
+ cost_estimate: normalizeCost(input.cost_estimate),
213
+ created_at: createdAt,
214
+ };
215
+ }
216
+ function assertReplayHasIdempotencyDiscriminator(expected) {
217
+ if (expected.envelope_hash || hasStableInputRefs(expected.input_refs_json)) {
218
+ return;
219
+ }
220
+ throw new Error(`Model run already exists and replay is missing an idempotency discriminator: ${expected.model_run_id}`);
221
+ }
222
+ function hasStableInputRefs(inputRefsJson) {
223
+ if (!inputRefsJson) {
224
+ return false;
225
+ }
226
+ const inputRefs = JSON.parse(inputRefsJson);
227
+ return hasStableInputRef(inputRefs);
228
+ }
229
+ function hasStableInputRef(value) {
230
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
231
+ return false;
232
+ }
233
+ for (const [key, item] of Object.entries(value)) {
234
+ if (STABLE_INPUT_REF_KEYS.has(key) && isNonEmptyStableInputRefValue(item)) {
235
+ return true;
236
+ }
237
+ if (hasStableInputRef(item)) {
238
+ return true;
239
+ }
240
+ }
241
+ return false;
242
+ }
243
+ function isNonEmptyStableInputRefValue(value) {
244
+ if (typeof value === 'string') {
245
+ return value.trim().length > 0;
246
+ }
247
+ return typeof value === 'number' && Number.isFinite(value);
248
+ }
249
+ function pushReplayField(fields, field) {
250
+ if (!fields.includes(field)) {
251
+ fields.push(field);
252
+ }
253
+ }
254
+ function replayFieldsForInput(input) {
255
+ const fields = [];
256
+ for (const field of BEGIN_REPLAY_FIELDS) {
257
+ if (field === 'input_refs_json') {
258
+ if (input.input_refs !== undefined || input.input_refs_json !== undefined) {
259
+ pushReplayField(fields, field);
260
+ }
261
+ }
262
+ else if (input[field] !== undefined) {
263
+ pushReplayField(fields, field);
264
+ }
265
+ }
266
+ if (input.created_at !== undefined) {
267
+ pushReplayField(fields, 'created_at');
268
+ }
269
+ if (input.status !== undefined && input.status !== 'running') {
270
+ pushReplayField(fields, 'status');
271
+ }
272
+ if (input.error_summary !== undefined) {
273
+ pushReplayField(fields, 'error_summary');
274
+ }
275
+ return fields;
276
+ }
277
+ function canonicalJson(value) {
278
+ if (Array.isArray(value)) {
279
+ return value.map((item) => canonicalJson(item));
280
+ }
281
+ if (value && typeof value === 'object') {
282
+ const object = value;
283
+ const sorted = Object.create(null);
284
+ for (const key of Object.keys(object).sort()) {
285
+ Object.defineProperty(sorted, key, {
286
+ value: canonicalJson(object[key]),
287
+ enumerable: true,
288
+ configurable: true,
289
+ writable: true,
290
+ });
291
+ }
292
+ return sorted;
293
+ }
294
+ return value;
295
+ }
296
+ function canonicalJsonString(value) {
297
+ return JSON.stringify(canonicalJson(JSON.parse(value)));
298
+ }
299
+ function replayFieldMatches(existing, expected, field) {
300
+ if (field === 'input_refs_json') {
301
+ if (existing.input_refs_json === expected.input_refs_json) {
302
+ return true;
303
+ }
304
+ if (!existing.input_refs_json || !expected.input_refs_json) {
305
+ return existing.input_refs_json === expected.input_refs_json;
306
+ }
307
+ return (canonicalJsonString(existing.input_refs_json) ===
308
+ canonicalJsonString(expected.input_refs_json));
309
+ }
310
+ return existing[field] === expected[field];
311
+ }
312
+ function assertExistingModelRunMatchesInput(existing, expected, replayFields) {
313
+ assertReplayHasIdempotencyDiscriminator(expected);
314
+ for (const field of replayFields) {
315
+ if (!replayFieldMatches(existing, expected, field)) {
316
+ throw new Error(`Model run already exists with different ${field}: ${existing.model_run_id}`);
317
+ }
318
+ }
319
+ }
320
+ function isDuplicateModelRunError(error) {
321
+ if (error && typeof error === 'object' && 'code' in error) {
322
+ const code = error.code;
323
+ if (code === 'SQLITE_CONSTRAINT' ||
324
+ code === 'SQLITE_CONSTRAINT_PRIMARYKEY' ||
325
+ code === 'SQLITE_CONSTRAINT_UNIQUE') {
326
+ return true;
327
+ }
328
+ }
329
+ const message = error instanceof Error ? error.message : String(error);
330
+ return /UNIQUE constraint failed: model_runs\.model_run_id|PRIMARY KEY constraint failed/i.test(message);
331
+ }
332
+ function resolveExistingCommittedRun(existing, summary) {
333
+ if (existing.status === 'committed') {
334
+ if (existing.completion_summary === summary) {
335
+ return existing;
336
+ }
337
+ throw new Error(`Model run already committed with different completion_summary: ${existing.model_run_id}`);
338
+ }
339
+ if (existing.status === 'failed') {
340
+ throw new Error(`Model run already failed: ${existing.model_run_id}`);
341
+ }
342
+ throw new Error(`Cannot commit model run in ${existing.status} status: ${existing.model_run_id}`);
343
+ }
344
+ function resolveExistingFailedRun(existing, errorSummary) {
345
+ if (existing.status === 'failed') {
346
+ if (existing.error_summary === errorSummary) {
347
+ return existing;
348
+ }
349
+ throw new Error(`Model run already failed with different error_summary: ${existing.model_run_id}`);
350
+ }
351
+ if (existing.status === 'committed') {
352
+ throw new Error(`Model run already committed: ${existing.model_run_id}`);
353
+ }
354
+ throw new Error(`Cannot fail model run in ${existing.status} status: ${existing.model_run_id}`);
355
+ }
356
+ function beginModelRunInAdapter(adapter, input) {
357
+ const id = nullableString(input.model_run_id) ?? modelRunId();
358
+ const createdAt = normalizeTimestamp(input.created_at);
359
+ const status = normalizeBeginStatus(input.status, id);
360
+ const inputRefsJson = normalizeInputRefsJson(input);
361
+ const expected = normalizeBeginModelRunInput(id, input, createdAt, status, inputRefsJson);
362
+ const replayFields = replayFieldsForInput(input);
363
+ const existing = selectModelRun(adapter, id);
364
+ if (existing) {
365
+ assertExistingModelRunMatchesInput(existing, expected, replayFields);
366
+ return existing;
367
+ }
368
+ try {
369
+ adapter
370
+ .prepare(`
371
+ INSERT INTO model_runs (
372
+ model_run_id, model_id, model_provider, prompt_version, tool_manifest_version,
373
+ output_schema_version, agent_id, instance_id, envelope_hash, parent_model_run_id,
374
+ input_snapshot_ref, input_refs_json, completion_summary, status, error_summary,
375
+ token_count, cost_estimate, created_at, completed_at
376
+ )
377
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
378
+ `)
379
+ .run(id, nullableString(input.model_id), nullableString(input.model_provider), nullableString(input.prompt_version), nullableString(input.tool_manifest_version), nullableString(input.output_schema_version), nullableString(input.agent_id), nullableString(input.instance_id), nullableString(input.envelope_hash), nullableString(input.parent_model_run_id), nullableString(input.input_snapshot_ref), inputRefsJson, null, status, nullableString(input.error_summary), normalizeNumber(input.token_count, 0), normalizeCost(input.cost_estimate), createdAt, null);
380
+ }
381
+ catch (error) {
382
+ if (!isDuplicateModelRunError(error)) {
383
+ throw error;
384
+ }
385
+ const duplicate = selectModelRun(adapter, id);
386
+ if (duplicate) {
387
+ assertExistingModelRunMatchesInput(duplicate, expected, replayFields);
388
+ return duplicate;
389
+ }
390
+ throw error;
391
+ }
392
+ return requireModelRun(adapter, id);
393
+ }
394
+ function commitModelRunInAdapter(adapter, modelRunId, summary) {
395
+ const summaryValue = nullableString(summary);
396
+ const existing = requireModelRun(adapter, modelRunId);
397
+ if (existing.status !== 'running') {
398
+ return resolveExistingCommittedRun(existing, summaryValue);
399
+ }
400
+ const completedAt = Date.now();
401
+ const result = adapter
402
+ .prepare(`
403
+ UPDATE model_runs
404
+ SET status = 'committed',
405
+ completion_summary = ?,
406
+ error_summary = NULL,
407
+ completed_at = ?
408
+ WHERE model_run_id = ? AND status = 'running'
409
+ `)
410
+ .run(summaryValue, completedAt, modelRunId);
411
+ if (result.changes === 0) {
412
+ return resolveExistingCommittedRun(requireModelRun(adapter, modelRunId), summaryValue);
413
+ }
414
+ return requireModelRun(adapter, modelRunId);
415
+ }
416
+ function failModelRunInAdapter(adapter, modelRunId, errorSummary) {
417
+ const errorSummaryValue = nullableString(errorSummary);
418
+ const existing = requireModelRun(adapter, modelRunId);
419
+ if (existing.status !== 'running') {
420
+ return resolveExistingFailedRun(existing, errorSummaryValue);
421
+ }
422
+ const completedAt = Date.now();
423
+ const result = adapter
424
+ .prepare(`
425
+ UPDATE model_runs
426
+ SET status = 'failed',
427
+ completion_summary = NULL,
428
+ error_summary = ?,
429
+ completed_at = ?
430
+ WHERE model_run_id = ? AND status = 'running'
431
+ `)
432
+ .run(errorSummaryValue, completedAt, modelRunId);
433
+ if (result.changes === 0) {
434
+ return resolveExistingFailedRun(requireModelRun(adapter, modelRunId), errorSummaryValue);
435
+ }
436
+ return requireModelRun(adapter, modelRunId);
437
+ }
438
+ function getModelRunInAdapter(adapter, modelRunId) {
439
+ return selectModelRun(adapter, modelRunId);
440
+ }
441
+ async function beginModelRun(input) {
442
+ const adapter = await initializedAdapter();
443
+ return beginModelRunInAdapter(adapter, input);
444
+ }
445
+ async function commitModelRun(modelRunId, summary) {
446
+ const adapter = await initializedAdapter();
447
+ return commitModelRunInAdapter(adapter, modelRunId, summary);
448
+ }
449
+ async function failModelRun(modelRunId, errorSummary) {
450
+ const adapter = await initializedAdapter();
451
+ return failModelRunInAdapter(adapter, modelRunId, errorSummary);
452
+ }
453
+ async function getModelRun(modelRunId) {
454
+ const adapter = await initializedAdapter();
455
+ return getModelRunInAdapter(adapter, modelRunId);
456
+ }
457
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1,4 @@
1
+ import type { AppendToolTraceInput, ToolTraceRecord } from './types.js';
2
+ export declare function appendToolTrace(input: AppendToolTraceInput): Promise<ToolTraceRecord>;
3
+ export declare function listToolTracesForRun(modelRunId: string): Promise<ToolTraceRecord[]>;
4
+ //# sourceMappingURL=tool-trace-store.d.ts.map