@lota-sdk/core 0.1.8 → 0.1.11

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 (38) hide show
  1. package/infrastructure/schema/00_workstream.surql +2 -1
  2. package/infrastructure/schema/02_execution_plan.surql +202 -52
  3. package/package.json +4 -2
  4. package/src/bifrost/bifrost.ts +94 -25
  5. package/src/config/model-constants.ts +8 -6
  6. package/src/db/memory-store.ts +3 -71
  7. package/src/db/service.ts +42 -2
  8. package/src/db/tables.ts +9 -2
  9. package/src/embeddings/provider.ts +92 -21
  10. package/src/index.ts +6 -0
  11. package/src/redis/stream-context.ts +44 -0
  12. package/src/runtime/approval-continuation.ts +59 -0
  13. package/src/runtime/chat-request-routing.ts +5 -1
  14. package/src/runtime/execution-plan.ts +21 -14
  15. package/src/runtime/turn-lifecycle.ts +14 -6
  16. package/src/runtime/workstream-chat-helpers.ts +5 -5
  17. package/src/services/context-compaction.service.ts +6 -2
  18. package/src/services/document-chunk.service.ts +2 -2
  19. package/src/services/execution-plan.service.ts +579 -786
  20. package/src/services/learned-skill.service.ts +2 -2
  21. package/src/services/plan-approval.service.ts +83 -0
  22. package/src/services/plan-artifact.service.ts +45 -0
  23. package/src/services/plan-builder.service.ts +61 -0
  24. package/src/services/plan-checkpoint.service.ts +53 -0
  25. package/src/services/plan-compiler.service.ts +81 -0
  26. package/src/services/plan-executor.service.ts +1623 -0
  27. package/src/services/plan-run.service.ts +422 -0
  28. package/src/services/plan-validator.service.ts +760 -0
  29. package/src/services/workstream-turn-preparation.ts +70 -196
  30. package/src/services/workstream-turn.ts +12 -0
  31. package/src/services/workstream.service.ts +24 -182
  32. package/src/services/workstream.types.ts +2 -65
  33. package/src/system-agents/title-generator.agent.ts +2 -2
  34. package/src/tools/execution-plan.tool.ts +20 -46
  35. package/src/tools/log-hello-world.tool.ts +17 -0
  36. package/src/workers/skill-extraction.runner.ts +2 -2
  37. package/src/services/workstream-change-tracker.service.ts +0 -313
  38. package/src/system-agents/workstream-tracker.agent.ts +0 -58
@@ -13,7 +13,8 @@ DEFINE FIELD IF NOT EXISTS updatedAt ON TABLE workstream TYPE datetime VALUE tim
13
13
  DEFINE FIELD IF NOT EXISTS memoryBlock ON TABLE workstream TYPE option<string>;
14
14
  DEFINE FIELD IF NOT EXISTS memoryBlockSummary ON TABLE workstream TYPE option<string>;
15
15
  DEFINE FIELD IF NOT EXISTS activeRunId ON TABLE workstream TYPE option<string>;
16
- DEFINE FIELD IF NOT EXISTS chatSummary ON TABLE workstream TYPE option<string>;
16
+ DEFINE FIELD IF NOT EXISTS activeStreamId ON TABLE workstream TYPE option<string>;
17
+ DEFINE FIELD IF NOT EXISTS compactionSummary ON TABLE workstream TYPE option<string>;
17
18
  DEFINE FIELD IF NOT EXISTS lastCompactedMessageId ON TABLE workstream TYPE option<string>;
18
19
  DEFINE FIELD IF NOT EXISTS nameGenerated ON TABLE workstream TYPE bool DEFAULT false;
19
20
  DEFINE FIELD IF NOT EXISTS isCompacting ON TABLE workstream TYPE bool DEFAULT false;
@@ -1,53 +1,204 @@
1
- # Execution plan runtime.
2
- DEFINE TABLE IF NOT EXISTS plan SCHEMAFULL;
3
- DEFINE FIELD IF NOT EXISTS organizationId ON TABLE plan TYPE record<organization>;
4
- DEFINE FIELD IF NOT EXISTS workstreamId ON TABLE plan TYPE record<workstream> REFERENCE ON DELETE CASCADE;
5
- DEFINE FIELD IF NOT EXISTS title ON TABLE plan TYPE string;
6
- DEFINE FIELD IF NOT EXISTS objective ON TABLE plan TYPE string;
7
- DEFINE FIELD IF NOT EXISTS status ON TABLE plan TYPE string;
8
- DEFINE FIELD IF NOT EXISTS leadAgentId ON TABLE plan TYPE string;
9
- DEFINE FIELD IF NOT EXISTS currentTaskId ON TABLE plan TYPE option<record<planTask>>;
10
- DEFINE FIELD IF NOT EXISTS restartFromTaskId ON TABLE plan TYPE option<record<planTask>>;
11
- DEFINE FIELD IF NOT EXISTS replacedPlanId ON TABLE plan TYPE option<record<plan>>;
12
- DEFINE FIELD IF NOT EXISTS failureCount ON TABLE plan TYPE int DEFAULT 0;
13
- DEFINE FIELD IF NOT EXISTS createdAt ON TABLE plan TYPE datetime DEFAULT time::now() READONLY;
14
- DEFINE FIELD IF NOT EXISTS updatedAt ON TABLE plan TYPE datetime VALUE time::now();
15
- DEFINE FIELD IF NOT EXISTS startedAt ON TABLE plan TYPE option<datetime>;
16
- DEFINE FIELD IF NOT EXISTS completedAt ON TABLE plan TYPE option<datetime>;
17
-
18
- DEFINE INDEX IF NOT EXISTS planWorkstreamIdx ON TABLE plan COLUMNS workstreamId;
19
- DEFINE INDEX IF NOT EXISTS planWorkstreamStatusIdx ON TABLE plan COLUMNS workstreamId, status;
20
-
21
- DEFINE TABLE IF NOT EXISTS planTask SCHEMAFULL;
22
- DEFINE FIELD IF NOT EXISTS planId ON TABLE planTask TYPE record<plan> REFERENCE ON DELETE CASCADE;
23
- DEFINE FIELD IF NOT EXISTS organizationId ON TABLE planTask TYPE record<organization>;
24
- DEFINE FIELD IF NOT EXISTS workstreamId ON TABLE planTask TYPE record<workstream>;
25
- DEFINE FIELD IF NOT EXISTS position ON TABLE planTask TYPE int;
26
- DEFINE FIELD IF NOT EXISTS title ON TABLE planTask TYPE string;
27
- DEFINE FIELD IF NOT EXISTS rationale ON TABLE planTask TYPE string;
28
- DEFINE FIELD IF NOT EXISTS kind ON TABLE planTask TYPE string;
29
- DEFINE FIELD IF NOT EXISTS ownerType ON TABLE planTask TYPE string;
30
- DEFINE FIELD IF NOT EXISTS ownerRef ON TABLE planTask TYPE string;
31
- DEFINE FIELD IF NOT EXISTS status ON TABLE planTask TYPE string;
32
- DEFINE FIELD IF NOT EXISTS resultStatus ON TABLE planTask TYPE string DEFAULT 'not-started';
33
- DEFINE FIELD IF NOT EXISTS input ON TABLE planTask TYPE option<object | string> FLEXIBLE;
34
- DEFINE FIELD IF NOT EXISTS outputSummary ON TABLE planTask TYPE option<string>;
35
- DEFINE FIELD IF NOT EXISTS blockedReason ON TABLE planTask TYPE option<string>;
36
- DEFINE FIELD IF NOT EXISTS externalRef ON TABLE planTask TYPE option<string>;
37
- DEFINE FIELD IF NOT EXISTS retryCount ON TABLE planTask TYPE int DEFAULT 0;
38
- DEFINE FIELD IF NOT EXISTS idempotencyKey ON TABLE planTask TYPE string;
39
- DEFINE FIELD IF NOT EXISTS createdAt ON TABLE planTask TYPE datetime DEFAULT time::now() READONLY;
40
- DEFINE FIELD IF NOT EXISTS updatedAt ON TABLE planTask TYPE datetime VALUE time::now();
41
- DEFINE FIELD IF NOT EXISTS startedAt ON TABLE planTask TYPE option<datetime>;
42
- DEFINE FIELD IF NOT EXISTS completedAt ON TABLE planTask TYPE option<datetime>;
43
-
44
- DEFINE INDEX IF NOT EXISTS planTaskPlanPositionIdx ON TABLE planTask COLUMNS planId, position;
45
- DEFINE INDEX IF NOT EXISTS planTaskPlanStatusIdx ON TABLE planTask COLUMNS planId, status;
46
- DEFINE INDEX IF NOT EXISTS planTaskIdempotencyIdx ON TABLE planTask COLUMNS idempotencyKey UNIQUE;
1
+ # Execution plan runtime v2.
2
+
3
+ DEFINE TABLE IF NOT EXISTS planSpec SCHEMAFULL;
4
+ DEFINE FIELD IF NOT EXISTS organizationId ON TABLE planSpec TYPE record<organization>;
5
+ DEFINE FIELD IF NOT EXISTS workstreamId ON TABLE planSpec TYPE record<workstream> REFERENCE ON DELETE CASCADE;
6
+ DEFINE FIELD IF NOT EXISTS title ON TABLE planSpec TYPE string;
7
+ DEFINE FIELD IF NOT EXISTS objective ON TABLE planSpec TYPE string;
8
+ DEFINE FIELD IF NOT EXISTS version ON TABLE planSpec TYPE int;
9
+ DEFINE FIELD IF NOT EXISTS status ON TABLE planSpec TYPE string;
10
+ DEFINE FIELD IF NOT EXISTS leadAgentId ON TABLE planSpec TYPE string;
11
+ DEFINE FIELD IF NOT EXISTS schemaRegistry ON TABLE planSpec TYPE object FLEXIBLE;
12
+ DEFINE FIELD IF NOT EXISTS edges ON TABLE planSpec TYPE array<object> FLEXIBLE DEFAULT [];
13
+ DEFINE FIELD IF NOT EXISTS edges.* ON TABLE planSpec TYPE object FLEXIBLE;
14
+ DEFINE FIELD IF NOT EXISTS edges.*.id ON TABLE planSpec TYPE string;
15
+ DEFINE FIELD IF NOT EXISTS edges.*.source ON TABLE planSpec TYPE string;
16
+ DEFINE FIELD IF NOT EXISTS edges.*.target ON TABLE planSpec TYPE string;
17
+ DEFINE FIELD IF NOT EXISTS edges.*.when ON TABLE planSpec TYPE option<string>;
18
+ DEFINE FIELD IF NOT EXISTS edges.*.map ON TABLE planSpec TYPE object FLEXIBLE DEFAULT {};
19
+ DEFINE FIELD IF NOT EXISTS entryNodeIds ON TABLE planSpec TYPE array<string>;
20
+ DEFINE FIELD IF NOT EXISTS replacedSpecId ON TABLE planSpec TYPE option<record<planSpec>>;
21
+ DEFINE FIELD IF NOT EXISTS createdAt ON TABLE planSpec TYPE datetime DEFAULT time::now() READONLY;
22
+ DEFINE FIELD IF NOT EXISTS updatedAt ON TABLE planSpec TYPE datetime VALUE time::now();
23
+ DEFINE FIELD IF NOT EXISTS compiledAt ON TABLE planSpec TYPE option<datetime>;
24
+
25
+ DEFINE INDEX IF NOT EXISTS planSpecWorkstreamIdx ON TABLE planSpec COLUMNS workstreamId;
26
+ DEFINE INDEX IF NOT EXISTS planSpecWorkstreamStatusIdx ON TABLE planSpec COLUMNS workstreamId, status;
27
+
28
+ DEFINE TABLE IF NOT EXISTS planNodeSpec SCHEMAFULL;
29
+ DEFINE FIELD IF NOT EXISTS planSpecId ON TABLE planNodeSpec TYPE record<planSpec> REFERENCE ON DELETE CASCADE;
30
+ DEFINE FIELD IF NOT EXISTS nodeId ON TABLE planNodeSpec TYPE string;
31
+ DEFINE FIELD IF NOT EXISTS position ON TABLE planNodeSpec TYPE int;
32
+ DEFINE FIELD IF NOT EXISTS type ON TABLE planNodeSpec TYPE string;
33
+ DEFINE FIELD IF NOT EXISTS label ON TABLE planNodeSpec TYPE string;
34
+ DEFINE FIELD IF NOT EXISTS owner ON TABLE planNodeSpec TYPE object FLEXIBLE;
35
+ DEFINE FIELD IF NOT EXISTS objective ON TABLE planNodeSpec TYPE string;
36
+ DEFINE FIELD IF NOT EXISTS instructions ON TABLE planNodeSpec TYPE string;
37
+ DEFINE FIELD IF NOT EXISTS inputSchemaRef ON TABLE planNodeSpec TYPE option<string>;
38
+ DEFINE FIELD IF NOT EXISTS outputSchemaRef ON TABLE planNodeSpec TYPE option<string>;
39
+ DEFINE FIELD IF NOT EXISTS deliverables ON TABLE planNodeSpec TYPE array<object> FLEXIBLE DEFAULT [];
40
+ DEFINE FIELD IF NOT EXISTS deliverables.* ON TABLE planNodeSpec TYPE object FLEXIBLE;
41
+ DEFINE FIELD IF NOT EXISTS deliverables.*.name ON TABLE planNodeSpec TYPE string;
42
+ DEFINE FIELD IF NOT EXISTS deliverables.*.kind ON TABLE planNodeSpec TYPE string;
43
+ DEFINE FIELD IF NOT EXISTS deliverables.*.required ON TABLE planNodeSpec TYPE bool DEFAULT true;
44
+ DEFINE FIELD IF NOT EXISTS deliverables.*.schemaRef ON TABLE planNodeSpec TYPE option<string>;
45
+ DEFINE FIELD IF NOT EXISTS deliverables.*.description ON TABLE planNodeSpec TYPE string;
46
+ DEFINE FIELD IF NOT EXISTS successCriteria ON TABLE planNodeSpec TYPE array<string> DEFAULT [];
47
+ DEFINE FIELD IF NOT EXISTS completionChecks ON TABLE planNodeSpec TYPE array<object> FLEXIBLE DEFAULT [];
48
+ DEFINE FIELD IF NOT EXISTS completionChecks.* ON TABLE planNodeSpec TYPE object FLEXIBLE;
49
+ DEFINE FIELD IF NOT EXISTS completionChecks.*.type ON TABLE planNodeSpec TYPE string;
50
+ DEFINE FIELD IF NOT EXISTS completionChecks.*.config ON TABLE planNodeSpec TYPE object FLEXIBLE;
51
+ DEFINE FIELD IF NOT EXISTS completionChecks.*.blocking ON TABLE planNodeSpec TYPE bool DEFAULT true;
52
+ DEFINE FIELD IF NOT EXISTS completionChecks.*.description ON TABLE planNodeSpec TYPE string;
53
+ DEFINE FIELD IF NOT EXISTS retryPolicy ON TABLE planNodeSpec TYPE object FLEXIBLE;
54
+ DEFINE FIELD IF NOT EXISTS failurePolicy ON TABLE planNodeSpec TYPE array<object> FLEXIBLE DEFAULT [];
55
+ DEFINE FIELD IF NOT EXISTS failurePolicy.* ON TABLE planNodeSpec TYPE object FLEXIBLE;
56
+ DEFINE FIELD IF NOT EXISTS failurePolicy.*.on ON TABLE planNodeSpec TYPE string;
57
+ DEFINE FIELD IF NOT EXISTS failurePolicy.*.action ON TABLE planNodeSpec TYPE string;
58
+ DEFINE FIELD IF NOT EXISTS failurePolicy.*.note ON TABLE planNodeSpec TYPE string;
59
+ DEFINE FIELD IF NOT EXISTS timeoutMs ON TABLE planNodeSpec TYPE option<int>;
60
+ DEFINE FIELD IF NOT EXISTS toolPolicy ON TABLE planNodeSpec TYPE object FLEXIBLE;
61
+ DEFINE FIELD IF NOT EXISTS contextPolicy ON TABLE planNodeSpec TYPE object FLEXIBLE;
62
+ DEFINE FIELD IF NOT EXISTS upstreamNodeIds ON TABLE planNodeSpec TYPE array<string> DEFAULT [];
63
+ DEFINE FIELD IF NOT EXISTS downstreamNodeIds ON TABLE planNodeSpec TYPE array<string> DEFAULT [];
64
+ DEFINE FIELD IF NOT EXISTS createdAt ON TABLE planNodeSpec TYPE datetime DEFAULT time::now() READONLY;
65
+ DEFINE FIELD IF NOT EXISTS updatedAt ON TABLE planNodeSpec TYPE datetime VALUE time::now();
66
+
67
+ DEFINE INDEX IF NOT EXISTS planNodeSpecPlanIdx ON TABLE planNodeSpec COLUMNS planSpecId;
68
+ DEFINE INDEX IF NOT EXISTS planNodeSpecPlanNodeIdx ON TABLE planNodeSpec COLUMNS planSpecId, nodeId UNIQUE;
69
+ DEFINE INDEX IF NOT EXISTS planNodeSpecPlanPositionIdx ON TABLE planNodeSpec COLUMNS planSpecId, position;
70
+
71
+ DEFINE TABLE IF NOT EXISTS planRun SCHEMAFULL;
72
+ DEFINE FIELD IF NOT EXISTS planSpecId ON TABLE planRun TYPE record<planSpec> REFERENCE ON DELETE CASCADE;
73
+ DEFINE FIELD IF NOT EXISTS organizationId ON TABLE planRun TYPE record<organization>;
74
+ DEFINE FIELD IF NOT EXISTS workstreamId ON TABLE planRun TYPE record<workstream> REFERENCE ON DELETE CASCADE;
75
+ DEFINE FIELD IF NOT EXISTS leadAgentId ON TABLE planRun TYPE string;
76
+ DEFINE FIELD IF NOT EXISTS status ON TABLE planRun TYPE string;
77
+ DEFINE FIELD IF NOT EXISTS currentNodeId ON TABLE planRun TYPE option<string>;
78
+ DEFINE FIELD IF NOT EXISTS waitingNodeId ON TABLE planRun TYPE option<string>;
79
+ DEFINE FIELD IF NOT EXISTS readyNodeIds ON TABLE planRun TYPE array<string> DEFAULT [];
80
+ DEFINE FIELD IF NOT EXISTS failureCount ON TABLE planRun TYPE int DEFAULT 0;
81
+ DEFINE FIELD IF NOT EXISTS replacedRunId ON TABLE planRun TYPE option<record<planRun>>;
82
+ DEFINE FIELD IF NOT EXISTS lastCheckpointId ON TABLE planRun TYPE option<record<planCheckpoint>>;
83
+ DEFINE FIELD IF NOT EXISTS createdAt ON TABLE planRun TYPE datetime DEFAULT time::now() READONLY;
84
+ DEFINE FIELD IF NOT EXISTS updatedAt ON TABLE planRun TYPE datetime VALUE time::now();
85
+ DEFINE FIELD IF NOT EXISTS startedAt ON TABLE planRun TYPE option<datetime>;
86
+ DEFINE FIELD IF NOT EXISTS completedAt ON TABLE planRun TYPE option<datetime>;
87
+
88
+ DEFINE INDEX IF NOT EXISTS planRunWorkstreamIdx ON TABLE planRun COLUMNS workstreamId;
89
+ DEFINE INDEX IF NOT EXISTS planRunWorkstreamStatusIdx ON TABLE planRun COLUMNS workstreamId, status;
90
+ DEFINE INDEX IF NOT EXISTS planRunSpecIdx ON TABLE planRun COLUMNS planSpecId;
91
+
92
+ DEFINE TABLE IF NOT EXISTS planNodeRun SCHEMAFULL;
93
+ DEFINE FIELD IF NOT EXISTS runId ON TABLE planNodeRun TYPE record<planRun> REFERENCE ON DELETE CASCADE;
94
+ DEFINE FIELD IF NOT EXISTS planSpecId ON TABLE planNodeRun TYPE record<planSpec> REFERENCE ON DELETE CASCADE;
95
+ DEFINE FIELD IF NOT EXISTS nodeId ON TABLE planNodeRun TYPE string;
96
+ DEFINE FIELD IF NOT EXISTS status ON TABLE planNodeRun TYPE string;
97
+ DEFINE FIELD IF NOT EXISTS attemptCount ON TABLE planNodeRun TYPE int DEFAULT 0;
98
+ DEFINE FIELD IF NOT EXISTS retryCount ON TABLE planNodeRun TYPE int DEFAULT 0;
99
+ DEFINE FIELD IF NOT EXISTS resolvedInput ON TABLE planNodeRun TYPE option<object> FLEXIBLE;
100
+ DEFINE FIELD IF NOT EXISTS latestStructuredOutput ON TABLE planNodeRun TYPE option<object> FLEXIBLE;
101
+ DEFINE FIELD IF NOT EXISTS latestNotes ON TABLE planNodeRun TYPE option<string>;
102
+ DEFINE FIELD IF NOT EXISTS latestAttemptId ON TABLE planNodeRun TYPE option<record<planNodeAttempt>>;
103
+ DEFINE FIELD IF NOT EXISTS blockedReason ON TABLE planNodeRun TYPE option<string>;
104
+ DEFINE FIELD IF NOT EXISTS failureClass ON TABLE planNodeRun TYPE option<string>;
105
+ DEFINE FIELD IF NOT EXISTS readyAt ON TABLE planNodeRun TYPE option<datetime>;
106
+ DEFINE FIELD IF NOT EXISTS startedAt ON TABLE planNodeRun TYPE option<datetime>;
107
+ DEFINE FIELD IF NOT EXISTS completedAt ON TABLE planNodeRun TYPE option<datetime>;
108
+ DEFINE FIELD IF NOT EXISTS createdAt ON TABLE planNodeRun TYPE datetime DEFAULT time::now() READONLY;
109
+ DEFINE FIELD IF NOT EXISTS updatedAt ON TABLE planNodeRun TYPE datetime VALUE time::now();
110
+
111
+ DEFINE INDEX IF NOT EXISTS planNodeRunRunIdx ON TABLE planNodeRun COLUMNS runId;
112
+ DEFINE INDEX IF NOT EXISTS planNodeRunRunNodeIdx ON TABLE planNodeRun COLUMNS runId, nodeId UNIQUE;
113
+ DEFINE INDEX IF NOT EXISTS planNodeRunRunStatusIdx ON TABLE planNodeRun COLUMNS runId, status;
114
+
115
+ DEFINE TABLE IF NOT EXISTS planNodeAttempt SCHEMAFULL;
116
+ DEFINE FIELD IF NOT EXISTS runId ON TABLE planNodeAttempt TYPE record<planRun> REFERENCE ON DELETE CASCADE;
117
+ DEFINE FIELD IF NOT EXISTS nodeRunId ON TABLE planNodeAttempt TYPE record<planNodeRun> REFERENCE ON DELETE CASCADE;
118
+ DEFINE FIELD IF NOT EXISTS nodeId ON TABLE planNodeAttempt TYPE string;
119
+ DEFINE FIELD IF NOT EXISTS emittedBy ON TABLE planNodeAttempt TYPE string;
120
+ DEFINE FIELD IF NOT EXISTS status ON TABLE planNodeAttempt TYPE string;
121
+ DEFINE FIELD IF NOT EXISTS structuredOutput ON TABLE planNodeAttempt TYPE option<object> FLEXIBLE;
122
+ DEFINE FIELD IF NOT EXISTS notes ON TABLE planNodeAttempt TYPE option<string>;
123
+ DEFINE FIELD IF NOT EXISTS validationIssueIds ON TABLE planNodeAttempt TYPE array<record<planValidationIssue>> DEFAULT [];
124
+ DEFINE FIELD IF NOT EXISTS failureClass ON TABLE planNodeAttempt TYPE option<string>;
125
+ DEFINE FIELD IF NOT EXISTS createdAt ON TABLE planNodeAttempt TYPE datetime DEFAULT time::now() READONLY;
126
+
127
+ DEFINE INDEX IF NOT EXISTS planNodeAttemptRunIdx ON TABLE planNodeAttempt COLUMNS runId;
128
+ DEFINE INDEX IF NOT EXISTS planNodeAttemptNodeRunIdx ON TABLE planNodeAttempt COLUMNS nodeRunId;
129
+ DEFINE INDEX IF NOT EXISTS planNodeAttemptRunNodeIdx ON TABLE planNodeAttempt COLUMNS runId, nodeId;
130
+
131
+ DEFINE TABLE IF NOT EXISTS planArtifact SCHEMAFULL;
132
+ DEFINE FIELD IF NOT EXISTS runId ON TABLE planArtifact TYPE record<planRun> REFERENCE ON DELETE CASCADE;
133
+ DEFINE FIELD IF NOT EXISTS nodeId ON TABLE planArtifact TYPE string;
134
+ DEFINE FIELD IF NOT EXISTS attemptId ON TABLE planArtifact TYPE record<planNodeAttempt> REFERENCE ON DELETE CASCADE;
135
+ DEFINE FIELD IF NOT EXISTS name ON TABLE planArtifact TYPE string;
136
+ DEFINE FIELD IF NOT EXISTS kind ON TABLE planArtifact TYPE string;
137
+ DEFINE FIELD IF NOT EXISTS pointer ON TABLE planArtifact TYPE string;
138
+ DEFINE FIELD IF NOT EXISTS schemaRef ON TABLE planArtifact TYPE option<string>;
139
+ DEFINE FIELD IF NOT EXISTS description ON TABLE planArtifact TYPE option<string>;
140
+ DEFINE FIELD IF NOT EXISTS payload ON TABLE planArtifact TYPE option<object | array> FLEXIBLE;
141
+ DEFINE FIELD IF NOT EXISTS createdAt ON TABLE planArtifact TYPE datetime DEFAULT time::now() READONLY;
142
+
143
+ DEFINE INDEX IF NOT EXISTS planArtifactRunIdx ON TABLE planArtifact COLUMNS runId;
144
+ DEFINE INDEX IF NOT EXISTS planArtifactAttemptIdx ON TABLE planArtifact COLUMNS attemptId;
145
+ DEFINE INDEX IF NOT EXISTS planArtifactRunNodeNameIdx ON TABLE planArtifact COLUMNS runId, nodeId, name;
146
+
147
+ DEFINE TABLE IF NOT EXISTS planValidationIssue SCHEMAFULL;
148
+ DEFINE FIELD IF NOT EXISTS planSpecId ON TABLE planValidationIssue TYPE option<record<planSpec>>;
149
+ DEFINE FIELD IF NOT EXISTS runId ON TABLE planValidationIssue TYPE option<record<planRun>>;
150
+ DEFINE FIELD IF NOT EXISTS nodeId ON TABLE planValidationIssue TYPE option<string>;
151
+ DEFINE FIELD IF NOT EXISTS attemptId ON TABLE planValidationIssue TYPE option<record<planNodeAttempt>>;
152
+ DEFINE FIELD IF NOT EXISTS severity ON TABLE planValidationIssue TYPE string;
153
+ DEFINE FIELD IF NOT EXISTS code ON TABLE planValidationIssue TYPE string;
154
+ DEFINE FIELD IF NOT EXISTS message ON TABLE planValidationIssue TYPE string;
155
+ DEFINE FIELD IF NOT EXISTS detail ON TABLE planValidationIssue TYPE option<object> FLEXIBLE;
156
+ DEFINE FIELD IF NOT EXISTS createdAt ON TABLE planValidationIssue TYPE datetime DEFAULT time::now() READONLY;
157
+
158
+ DEFINE INDEX IF NOT EXISTS planValidationIssueSpecIdx ON TABLE planValidationIssue COLUMNS planSpecId;
159
+ DEFINE INDEX IF NOT EXISTS planValidationIssueRunIdx ON TABLE planValidationIssue COLUMNS runId;
160
+ DEFINE INDEX IF NOT EXISTS planValidationIssueAttemptIdx ON TABLE planValidationIssue COLUMNS attemptId;
161
+
162
+ DEFINE TABLE IF NOT EXISTS planCheckpoint SCHEMAFULL;
163
+ DEFINE FIELD IF NOT EXISTS runId ON TABLE planCheckpoint TYPE record<planRun> REFERENCE ON DELETE CASCADE;
164
+ DEFINE FIELD IF NOT EXISTS sequence ON TABLE planCheckpoint TYPE int;
165
+ DEFINE FIELD IF NOT EXISTS runStatus ON TABLE planCheckpoint TYPE string;
166
+ DEFINE FIELD IF NOT EXISTS readyNodeIds ON TABLE planCheckpoint TYPE array<string> DEFAULT [];
167
+ DEFINE FIELD IF NOT EXISTS activeNodeIds ON TABLE planCheckpoint TYPE array<string> DEFAULT [];
168
+ DEFINE FIELD IF NOT EXISTS artifactIds ON TABLE planCheckpoint TYPE array<record<planArtifact>> DEFAULT [];
169
+ DEFINE FIELD IF NOT EXISTS lastCompletedNodeIds ON TABLE planCheckpoint TYPE array<string> DEFAULT [];
170
+ DEFINE FIELD IF NOT EXISTS snapshot ON TABLE planCheckpoint TYPE object FLEXIBLE;
171
+ DEFINE FIELD IF NOT EXISTS createdAt ON TABLE planCheckpoint TYPE datetime DEFAULT time::now() READONLY;
172
+
173
+ DEFINE INDEX IF NOT EXISTS planCheckpointRunIdx ON TABLE planCheckpoint COLUMNS runId;
174
+ DEFINE INDEX IF NOT EXISTS planCheckpointRunSequenceIdx ON TABLE planCheckpoint COLUMNS runId, sequence UNIQUE;
175
+
176
+ DEFINE TABLE IF NOT EXISTS planApproval SCHEMAFULL;
177
+ DEFINE FIELD IF NOT EXISTS runId ON TABLE planApproval TYPE record<planRun> REFERENCE ON DELETE CASCADE;
178
+ DEFINE FIELD IF NOT EXISTS nodeId ON TABLE planApproval TYPE string;
179
+ DEFINE FIELD IF NOT EXISTS nodeRunId ON TABLE planApproval TYPE record<planNodeRun> REFERENCE ON DELETE CASCADE;
180
+ DEFINE FIELD IF NOT EXISTS status ON TABLE planApproval TYPE string;
181
+ DEFINE FIELD IF NOT EXISTS presented ON TABLE planApproval TYPE option<object> FLEXIBLE;
182
+ DEFINE FIELD IF NOT EXISTS response ON TABLE planApproval TYPE option<object> FLEXIBLE;
183
+ DEFINE FIELD IF NOT EXISTS requestedBy ON TABLE planApproval TYPE string;
184
+ DEFINE FIELD IF NOT EXISTS respondedBy ON TABLE planApproval TYPE option<string>;
185
+ DEFINE FIELD IF NOT EXISTS approvalMessageId ON TABLE planApproval TYPE option<string>;
186
+ DEFINE FIELD IF NOT EXISTS comments ON TABLE planApproval TYPE option<string>;
187
+ DEFINE FIELD IF NOT EXISTS requiredEdits ON TABLE planApproval TYPE array<string> DEFAULT [];
188
+ DEFINE FIELD IF NOT EXISTS createdAt ON TABLE planApproval TYPE datetime DEFAULT time::now() READONLY;
189
+ DEFINE FIELD IF NOT EXISTS updatedAt ON TABLE planApproval TYPE datetime VALUE time::now();
190
+ DEFINE FIELD IF NOT EXISTS respondedAt ON TABLE planApproval TYPE option<datetime>;
191
+
192
+ DEFINE INDEX IF NOT EXISTS planApprovalRunIdx ON TABLE planApproval COLUMNS runId;
193
+ DEFINE INDEX IF NOT EXISTS planApprovalNodeRunIdx ON TABLE planApproval COLUMNS nodeRunId;
194
+ DEFINE INDEX IF NOT EXISTS planApprovalRunStatusIdx ON TABLE planApproval COLUMNS runId, status;
47
195
 
48
196
  DEFINE TABLE IF NOT EXISTS planEvent SCHEMAFULL;
49
- DEFINE FIELD IF NOT EXISTS planId ON TABLE planEvent TYPE record<plan> REFERENCE ON DELETE CASCADE;
50
- DEFINE FIELD IF NOT EXISTS taskId ON TABLE planEvent TYPE option<record<planTask>>;
197
+ DEFINE FIELD IF NOT EXISTS planSpecId ON TABLE planEvent TYPE record<planSpec> REFERENCE ON DELETE CASCADE;
198
+ DEFINE FIELD IF NOT EXISTS runId ON TABLE planEvent TYPE record<planRun> REFERENCE ON DELETE CASCADE;
199
+ DEFINE FIELD IF NOT EXISTS nodeId ON TABLE planEvent TYPE option<string>;
200
+ DEFINE FIELD IF NOT EXISTS attemptId ON TABLE planEvent TYPE option<record<planNodeAttempt>>;
201
+ DEFINE FIELD IF NOT EXISTS approvalId ON TABLE planEvent TYPE option<record<planApproval>>;
51
202
  DEFINE FIELD IF NOT EXISTS eventType ON TABLE planEvent TYPE string;
52
203
  DEFINE FIELD IF NOT EXISTS fromStatus ON TABLE planEvent TYPE option<string>;
53
204
  DEFINE FIELD IF NOT EXISTS toStatus ON TABLE planEvent TYPE option<string>;
@@ -56,7 +207,6 @@ DEFINE FIELD IF NOT EXISTS detail ON TABLE planEvent TYPE option<object> FLEXIBL
56
207
  DEFINE FIELD IF NOT EXISTS emittedBy ON TABLE planEvent TYPE string;
57
208
  DEFINE FIELD IF NOT EXISTS createdAt ON TABLE planEvent TYPE datetime DEFAULT time::now() READONLY;
58
209
 
59
- DEFINE INDEX IF NOT EXISTS planEventPlanIdx ON TABLE planEvent COLUMNS planId;
60
- DEFINE INDEX IF NOT EXISTS planEventTaskIdx ON TABLE planEvent COLUMNS taskId;
61
- DEFINE INDEX IF NOT EXISTS planEventTypeIdx ON TABLE planEvent COLUMNS planId, eventType;
62
- DEFINE INDEX IF NOT EXISTS planEventTimeIdx ON TABLE planEvent COLUMNS planId, createdAt;
210
+ DEFINE INDEX IF NOT EXISTS planEventRunIdx ON TABLE planEvent COLUMNS runId;
211
+ DEFINE INDEX IF NOT EXISTS planEventRunNodeIdx ON TABLE planEvent COLUMNS runId, nodeId;
212
+ DEFINE INDEX IF NOT EXISTS planEventRunTimeIdx ON TABLE planEvent COLUMNS runId, createdAt;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lota-sdk/core",
3
- "version": "0.1.8",
3
+ "version": "0.1.11",
4
4
  "type": "module",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -112,9 +112,10 @@
112
112
  "registry": "https://registry.npmjs.org/"
113
113
  },
114
114
  "dependencies": {
115
+ "@ai-sdk/devtools": "^0.0.15",
115
116
  "@ai-sdk/openai": "^3.0.41",
116
117
  "@logtape/logtape": "^2.0.4",
117
- "@lota-sdk/shared": "0.1.7",
118
+ "@lota-sdk/shared": "0.1.9",
118
119
  "@mendable/firecrawl-js": "^4.16.0",
119
120
  "@surrealdb/node": "^3.0.3",
120
121
  "ai": "^6.0.116",
@@ -123,6 +124,7 @@
123
124
  "ioredis": "5.9.3",
124
125
  "mammoth": "^1.12.0",
125
126
  "pdf-parse": "^2.4.5",
127
+ "resumable-stream": "^2.2.12",
126
128
  "surrealdb": "^2.0.2",
127
129
  "zod": "^4.3.6"
128
130
  }
@@ -1,3 +1,4 @@
1
+ import { devToolsMiddleware } from '@ai-sdk/devtools'
1
2
  import { createOpenAI } from '@ai-sdk/openai'
2
3
  import { wrapLanguageModel } from 'ai'
3
4
  import type { LanguageModelMiddleware } from 'ai'
@@ -36,6 +37,10 @@ function readReasoningDetailsText(value: unknown): string | null {
36
37
  return textParts.join('\n\n')
37
38
  }
38
39
 
40
+ function readReasoningDeltaText(value: unknown): string | null {
41
+ return typeof value === 'string' && value.length > 0 ? value : null
42
+ }
43
+
39
44
  function readBifrostChatReasoningText(message: Record<string, unknown>): string | null {
40
45
  return (
41
46
  readString(message.reasoning) ??
@@ -63,13 +68,29 @@ export function extractBifrostChatReasoningDeltaText(rawChunk: unknown): string
63
68
  for (const choice of rawChunk.choices) {
64
69
  if (!isRecord(choice) || !isRecord(choice.delta)) continue
65
70
 
66
- const reasoningText = readBifrostChatReasoningText(choice.delta)
71
+ const reasoningText =
72
+ readReasoningDeltaText(choice.delta.reasoning) ??
73
+ readReasoningDeltaText(choice.delta.reasoning_content) ??
74
+ readReasoningDetailsText(choice.delta.reasoning_details)
67
75
  if (reasoningText) return reasoningText
68
76
  }
69
77
 
70
78
  return null
71
79
  }
72
80
 
81
+ type BifrostResponsesReasoningDelta = { id: string; delta: string; itemId: string }
82
+
83
+ export function extractBifrostResponsesReasoningDelta(rawChunk: unknown): BifrostResponsesReasoningDelta | null {
84
+ if (!isRecord(rawChunk) || rawChunk.type !== 'response.reasoning_summary_text.delta') return null
85
+ if ('summary_index' in rawChunk) return null
86
+
87
+ const itemId = readString(rawChunk.item_id)
88
+ const delta = readReasoningDeltaText(rawChunk.delta)
89
+ if (!itemId || !delta) return null
90
+
91
+ return { id: `${itemId}:0`, delta, itemId }
92
+ }
93
+
73
94
  export function injectBifrostChatReasoningContent(
74
95
  content: readonly BifrostGeneratedContent[],
75
96
  response?: BifrostChatResponse,
@@ -143,6 +164,30 @@ export function injectBifrostChatReasoningStream(
143
164
  )
144
165
  }
145
166
 
167
+ export function injectBifrostResponsesReasoningStream(
168
+ stream: ReadableStream<BifrostStreamPart>,
169
+ ): ReadableStream<BifrostStreamPart> {
170
+ return stream.pipeThrough(
171
+ new TransformStream<BifrostStreamPart, BifrostStreamPart>({
172
+ transform(chunk, controller) {
173
+ controller.enqueue(chunk)
174
+
175
+ if (chunk.type !== 'raw') return
176
+
177
+ const reasoningDelta = extractBifrostResponsesReasoningDelta(chunk.rawValue)
178
+ if (!reasoningDelta) return
179
+
180
+ controller.enqueue({
181
+ type: 'reasoning-delta',
182
+ id: reasoningDelta.id,
183
+ delta: reasoningDelta.delta,
184
+ providerMetadata: { openai: { itemId: reasoningDelta.itemId } },
185
+ } as BifrostStreamPart)
186
+ },
187
+ }),
188
+ )
189
+ }
190
+
146
191
  function addBifrostReasoningRawChunks(
147
192
  params: BifrostCallOptions,
148
193
  type: BifrostTransformParamsOptions['type'],
@@ -197,6 +242,14 @@ function createBifrostProvider(extraParams?: BifrostExtraParams) {
197
242
  })
198
243
  }
199
244
 
245
+ function withBifrostDevTools<TModel>(model: TModel): TModel {
246
+ if (process.env.NODE_ENV === 'production') {
247
+ return model
248
+ }
249
+
250
+ return wrapLanguageModel({ model: model as never, middleware: devToolsMiddleware() }) as unknown as TModel
251
+ }
252
+
200
253
  let provider: ReturnType<typeof createOpenAI> | null = null
201
254
  let openRouterResponseHealingProvider: ReturnType<typeof createOpenAI> | null = null
202
255
 
@@ -217,38 +270,54 @@ export function getBifrostOpenRouterResponseHealingProvider() {
217
270
  }
218
271
 
219
272
  export function bifrostModel(modelId: string) {
220
- return getBifrostProvider()(modelId)
273
+ return withBifrostDevTools(
274
+ wrapLanguageModel({
275
+ model: getBifrostProvider()(modelId),
276
+ middleware: {
277
+ specificationVersion: 'v3',
278
+ transformParams: async ({ params, type }) => addBifrostReasoningRawChunks(params, type),
279
+ wrapStream: async ({ doStream, params }) => {
280
+ const result = await doStream()
281
+ if (!isReasoningEnabled(params)) return result
282
+
283
+ return { ...result, stream: injectBifrostResponsesReasoningStream(result.stream) }
284
+ },
285
+ },
286
+ }),
287
+ )
221
288
  }
222
289
 
223
290
  export function bifrostOpenRouterResponseHealingModel(modelId: string) {
224
- return getBifrostOpenRouterResponseHealingProvider()(modelId)
291
+ return withBifrostDevTools(getBifrostOpenRouterResponseHealingProvider()(modelId))
225
292
  }
226
293
 
227
294
  export function bifrostChatModel(modelId: string) {
228
- return wrapLanguageModel({
229
- model: getBifrostProvider().chat(modelId),
230
- middleware: {
231
- specificationVersion: 'v3',
232
- transformParams: async ({ params, type }) => addBifrostReasoningRawChunks(params, type),
233
- wrapGenerate: async ({ doGenerate }) => {
234
- const result = await doGenerate()
235
-
236
- return {
237
- ...result,
238
- content: injectBifrostChatReasoningContent(
239
- result.content,
240
- result.response as BifrostChatResponse | undefined,
241
- ),
242
- }
243
- },
244
- wrapStream: async ({ doStream, params }) => {
245
- const result = await doStream()
246
- if (!isReasoningEnabled(params)) return result
295
+ return withBifrostDevTools(
296
+ wrapLanguageModel({
297
+ model: getBifrostProvider().chat(modelId),
298
+ middleware: {
299
+ specificationVersion: 'v3',
300
+ transformParams: async ({ params, type }) => addBifrostReasoningRawChunks(params, type),
301
+ wrapGenerate: async ({ doGenerate }) => {
302
+ const result = await doGenerate()
303
+
304
+ return {
305
+ ...result,
306
+ content: injectBifrostChatReasoningContent(
307
+ result.content,
308
+ result.response as BifrostChatResponse | undefined,
309
+ ),
310
+ }
311
+ },
312
+ wrapStream: async ({ doStream, params }) => {
313
+ const result = await doStream()
314
+ if (!isReasoningEnabled(params)) return result
247
315
 
248
- return { ...result, stream: injectBifrostChatReasoningStream(result.stream) }
316
+ return { ...result, stream: injectBifrostChatReasoningStream(result.stream) }
317
+ },
249
318
  },
250
- },
251
- })
319
+ }),
320
+ )
252
321
  }
253
322
 
254
323
  export function bifrostEmbeddingModel(modelId: string) {
@@ -10,26 +10,28 @@ export const OPENROUTER_CODE_ANALYSIS_MODEL_ID = 'openrouter/xiaomi/mimo-v2-flas
10
10
  export const OPENROUTER_FAST_REASONING_MODEL_ID = 'openrouter/openai/gpt-oss-120b:nitro' as const
11
11
  export const OPENROUTER_STRUCTURED_REASONING_MODEL_ID = 'openrouter/openai/gpt-oss-120b:exacto' as const
12
12
 
13
+ export const BIFROST_REASONING_SUMMARY_LEVEL = 'detailed' as const
14
+
13
15
  export const OPENAI_HIGH_REASONING_PROVIDER_OPTIONS = {
14
- openai: { forceReasoning: true, reasoningEffort: 'high', reasoningSummary: 'auto' },
16
+ openai: { forceReasoning: true, reasoningEffort: 'high', reasoningSummary: BIFROST_REASONING_SUMMARY_LEVEL },
15
17
  } as const
16
18
 
17
19
  export const OPENROUTER_HIGH_REASONING_PROVIDER_OPTIONS = {
18
- openai: { forceReasoning: true, reasoningEffort: 'high', reasoningSummary: 'auto' },
20
+ openai: { forceReasoning: true, reasoningEffort: 'high', reasoningSummary: BIFROST_REASONING_SUMMARY_LEVEL },
19
21
  } as const
20
22
 
21
23
  export const OPENROUTER_XHIGH_REASONING_PROVIDER_OPTIONS = {
22
- openai: { forceReasoning: true, reasoningEffort: 'xhigh', reasoningSummary: 'auto' },
24
+ openai: { forceReasoning: true, reasoningEffort: 'xhigh', reasoningSummary: BIFROST_REASONING_SUMMARY_LEVEL },
23
25
  } as const
24
26
 
25
27
  export const OPENROUTER_MEDIUM_REASONING_PROVIDER_OPTIONS = {
26
- openai: { forceReasoning: true, reasoningEffort: 'medium', reasoningSummary: 'auto' },
28
+ openai: { forceReasoning: true, reasoningEffort: 'medium', reasoningSummary: BIFROST_REASONING_SUMMARY_LEVEL },
27
29
  } as const
28
30
 
29
31
  export const OPENROUTER_LOW_REASONING_PROVIDER_OPTIONS = {
30
- openai: { forceReasoning: true, reasoningEffort: 'low', reasoningSummary: 'auto' },
32
+ openai: { forceReasoning: true, reasoningEffort: 'low', reasoningSummary: BIFROST_REASONING_SUMMARY_LEVEL },
31
33
  } as const
32
34
 
33
35
  export const OPENROUTER_MINIMAL_REASONING_PROVIDER_OPTIONS = {
34
- openai: { forceReasoning: true, reasoningEffort: 'minimal', reasoningSummary: 'auto' },
36
+ openai: { forceReasoning: true, reasoningEffort: 'minimal', reasoningSummary: BIFROST_REASONING_SUMMARY_LEVEL },
35
37
  } as const
@@ -1,10 +1,8 @@
1
1
  import { BoundQuery, eq, inside } from 'surrealdb'
2
2
 
3
- import { getEmbeddingCache } from '../ai/embedding-cache'
4
- import { env } from '../config/env-shapes'
5
3
  import { aiLogger } from '../config/logger'
6
4
  import { DEFAULT_MEMORY_SEARCH_LIMIT } from '../config/search'
7
- import { createDefaultEmbeddings } from '../embeddings/provider'
5
+ import { getDefaultEmbeddings } from '../embeddings/provider'
8
6
  import { memoryQueryBuilder } from './memory-query-builder'
9
7
  import type { RelationCounts } from './memory-store.helpers'
10
8
  import { hashContent, mapRowToMemoryRecord, processGraphAwareRows } from './memory-store.helpers'
@@ -25,8 +23,6 @@ import { TABLES } from './tables'
25
23
  const MEMORY_TABLE = TABLES.MEMORY
26
24
  const MEMORY_HISTORY_TABLE = TABLES.MEMORY_HISTORY
27
25
  const MEMORY_RELATION_TABLE = TABLES.MEMORY_RELATION
28
- const EMBEDDING_CACHE_TTL_MS = 5 * 60 * 1000
29
- const EMBEDDING_CACHE_MAX_ENTRIES = 64
30
26
  const MIN_RELEVANCE_SCORE = 0.25
31
27
  const TOUCH_MEMORIES_MAX_ATTEMPTS = 4
32
28
  const TOUCH_MEMORIES_RETRY_BASE_DELAY_MS = 25
@@ -37,9 +33,6 @@ interface EmbeddingClient {
37
33
  }
38
34
 
39
35
  export class SurrealMemoryStore {
40
- private embeddingCache = new Map<string, { embedding: number[]; ts: number }>()
41
- private embeddingInFlight = new Map<string, Promise<number[]>>()
42
-
43
36
  constructor(private embeddings: EmbeddingClient) {}
44
37
 
45
38
  private toMetadataFieldPath(key: string): string {
@@ -183,72 +176,11 @@ export class SurrealMemoryStore {
183
176
  }))
184
177
  }
185
178
 
186
- private getEmbeddingCacheKey(content: string): string {
187
- return content.trim().toLowerCase()
188
- }
189
-
190
- private pruneEmbeddingCache(now: number): void {
191
- for (const [cacheKey, entry] of this.embeddingCache.entries()) {
192
- if (now - entry.ts > EMBEDDING_CACHE_TTL_MS) {
193
- this.embeddingCache.delete(cacheKey)
194
- }
195
- }
196
-
197
- while (this.embeddingCache.size > EMBEDDING_CACHE_MAX_ENTRIES) {
198
- const oldest = this.embeddingCache.keys().next().value
199
- if (!oldest) break
200
- this.embeddingCache.delete(oldest)
201
- }
202
- }
203
-
204
179
  private async generateEmbedding(content: string): Promise<number[]> {
205
180
  const normalized = content.trim()
206
181
  if (!normalized) return []
207
182
 
208
- const cacheKey = this.getEmbeddingCacheKey(normalized)
209
- const now = Date.now()
210
- this.pruneEmbeddingCache(now)
211
-
212
- // L1: in-memory cache
213
- const cached = this.embeddingCache.get(cacheKey)
214
- if (cached && now - cached.ts <= EMBEDDING_CACHE_TTL_MS) {
215
- return cached.embedding
216
- }
217
-
218
- const inFlight = this.embeddingInFlight.get(cacheKey)
219
- if (inFlight) {
220
- return await inFlight
221
- }
222
-
223
- const request = (async () => {
224
- // L2: Redis cache
225
- const redisCache = getEmbeddingCache()
226
- if (redisCache) {
227
- const model = env.AI_EMBEDDING_MODEL
228
- const redisCached = await redisCache.get(model, normalized)
229
- if (redisCached) {
230
- this.embeddingCache.set(cacheKey, { embedding: redisCached, ts: Date.now() })
231
- return redisCached
232
- }
233
- }
234
-
235
- // L3: API call
236
- const embedding = await this.embeddings.embedQuery(normalized)
237
- this.embeddingCache.set(cacheKey, { embedding, ts: Date.now() })
238
- this.pruneEmbeddingCache(Date.now())
239
-
240
- // Backfill Redis
241
- if (redisCache) {
242
- void redisCache.set(env.AI_EMBEDDING_MODEL, normalized, embedding)
243
- }
244
-
245
- return embedding
246
- })().finally(() => {
247
- this.embeddingInFlight.delete(cacheKey)
248
- })
249
-
250
- this.embeddingInFlight.set(cacheKey, request)
251
- return await request
183
+ return await this.embeddings.embedQuery(normalized)
252
184
  }
253
185
 
254
186
  async warmEmbedding(content: string): Promise<void> {
@@ -1059,7 +991,7 @@ let defaultMemoryStore: SurrealMemoryStore | null = null
1059
991
 
1060
992
  export function getDefaultMemoryStore(): SurrealMemoryStore {
1061
993
  if (!defaultMemoryStore) {
1062
- defaultMemoryStore = new SurrealMemoryStore(createDefaultEmbeddings())
994
+ defaultMemoryStore = new SurrealMemoryStore(getDefaultEmbeddings())
1063
995
  }
1064
996
  return defaultMemoryStore
1065
997
  }