@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
@@ -20,23 +20,12 @@ import {
20
20
  parseMemoryBlock,
21
21
  serializeMemoryBlock,
22
22
  } from '../runtime/memory-block'
23
- import { toOptionalTrimmedString } from '../runtime/workstream-chat-helpers'
24
- import { WorkstreamStateSchema } from '../runtime/workstream-state'
25
- import type { WorkstreamState } from '../runtime/workstream-state'
26
23
  import { toIsoDateTimeString } from '../utils/date-time'
27
24
  import { chatRunRegistry } from './chat-run-registry.service'
28
25
  import { contextCompactionService } from './context-compaction.service'
29
26
  import { workstreamMessageService } from './workstream-message.service'
30
27
  import { WorkstreamSchema, WorkstreamStatusSchema } from './workstream.types'
31
- import type {
32
- NormalizedWorkstream,
33
- PublicWorkstreamApprovalState,
34
- PublicWorkstreamDetail,
35
- PublicWorkstreamStateFocus,
36
- PublicWorkstreamStatePayload,
37
- PublicWorkstreamStateProgress,
38
- WorkstreamRecord,
39
- } from './workstream.types'
28
+ import type { NormalizedWorkstream, WorkstreamRecord } from './workstream.types'
40
29
 
41
30
  // Uses SurrealQL directly to keep pagination/order logic close to queries.
42
31
 
@@ -146,155 +135,6 @@ function buildCoreWorkstreamId({
146
135
  return new RecordId(TABLES.WORKSTREAM, `core_${typeValue}_user_${userValue}_organization_${orgValue}`)
147
136
  }
148
137
 
149
- function toOptionalIsoDateTimeString(value: number | null | undefined): string | null {
150
- if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0) return null
151
- return toIsoDateTimeString(new Date(value))
152
- }
153
-
154
- function getCompactedSummaryFocus(chatSummary: string | null): string | null {
155
- if (!chatSummary) return null
156
-
157
- const lines = chatSummary
158
- .split('\n')
159
- .map((line) => line.trim())
160
- .filter(Boolean)
161
-
162
- for (const line of lines) {
163
- if (line.endsWith(':')) continue
164
- if (line.startsWith('- ')) {
165
- return toOptionalTrimmedString(line.slice(2))
166
- }
167
- return toOptionalTrimmedString(line)
168
- }
169
-
170
- return null
171
- }
172
-
173
- function parsePersistedWorkstreamState(value: unknown): WorkstreamState | null {
174
- const parsed = WorkstreamStateSchema.safeParse(value)
175
- return parsed.success ? parsed.data : null
176
- }
177
-
178
- function buildEmptyWorkstreamStateProgress(): PublicWorkstreamStateProgress {
179
- return {
180
- hasState: false,
181
- lastUpdated: null,
182
- completionRatio: null,
183
- tasks: { total: 0, open: 0, inProgress: 0, done: 0, blocked: 0 },
184
- constraints: { total: 0, approved: 0, candidate: 0 },
185
- keyDecisions: 0,
186
- openQuestions: 0,
187
- risks: 0,
188
- artifacts: 0,
189
- agentContributions: 0,
190
- }
191
- }
192
-
193
- function buildWorkstreamStateProgress(state: WorkstreamState | null): PublicWorkstreamStateProgress {
194
- if (!state) {
195
- return buildEmptyWorkstreamStateProgress()
196
- }
197
-
198
- const tasks = {
199
- total: state.tasks.length,
200
- open: state.tasks.filter((task) => task.status === 'open').length,
201
- inProgress: state.tasks.filter((task) => task.status === 'in-progress').length,
202
- done: state.tasks.filter((task) => task.status === 'done').length,
203
- blocked: state.tasks.filter((task) => task.status === 'blocked').length,
204
- }
205
- const constraintsApproved = state.activeConstraints.filter((constraint) => constraint.approved).length
206
-
207
- return {
208
- hasState:
209
- state.currentPlan !== null ||
210
- state.activeConstraints.length > 0 ||
211
- state.keyDecisions.length > 0 ||
212
- state.tasks.length > 0 ||
213
- state.openQuestions.length > 0 ||
214
- state.risks.length > 0 ||
215
- state.artifacts.length > 0 ||
216
- state.agentContributions.length > 0 ||
217
- toOptionalTrimmedString(state.approvedBy) !== null ||
218
- typeof state.approvedAt === 'number' ||
219
- toOptionalTrimmedString(state.approvalMessageId) !== null ||
220
- toOptionalTrimmedString(state.approvalNote) !== null,
221
- lastUpdated: toOptionalIsoDateTimeString(state.lastUpdated),
222
- completionRatio: tasks.total > 0 ? Number((tasks.done / tasks.total).toFixed(4)) : null,
223
- tasks,
224
- constraints: {
225
- total: state.activeConstraints.length,
226
- approved: constraintsApproved,
227
- candidate: state.activeConstraints.length - constraintsApproved,
228
- },
229
- keyDecisions: state.keyDecisions.length,
230
- openQuestions: state.openQuestions.length,
231
- risks: state.risks.length,
232
- artifacts: state.artifacts.length,
233
- agentContributions: state.agentContributions.length,
234
- }
235
- }
236
-
237
- function buildWorkstreamApprovalState(state: WorkstreamState | null): PublicWorkstreamApprovalState | null {
238
- if (!state) return null
239
-
240
- const approvedBy = toOptionalTrimmedString(state.approvedBy)
241
- const approvedAt = toOptionalIsoDateTimeString(state.approvedAt)
242
- const approvalMessageId = toOptionalTrimmedString(state.approvalMessageId)
243
- const approvalNote = toOptionalTrimmedString(state.approvalNote)
244
-
245
- if (!approvedBy && !approvedAt && !approvalMessageId && !approvalNote) {
246
- return null
247
- }
248
-
249
- return { approvedBy, approvedAt, approvalMessageId, approvalNote }
250
- }
251
-
252
- function buildWorkstreamStateFocus(
253
- state: WorkstreamState | null,
254
- chatSummary: string | null,
255
- ): PublicWorkstreamStateFocus | null {
256
- if (!state) {
257
- const compactedSummaryFocus = getCompactedSummaryFocus(chatSummary)
258
- return compactedSummaryFocus ? { kind: 'chat-summary', text: compactedSummaryFocus } : null
259
- }
260
-
261
- const currentPlan = toOptionalTrimmedString(state.currentPlan?.text)
262
- if (currentPlan) {
263
- return { kind: 'plan', text: currentPlan }
264
- }
265
-
266
- const latestTask =
267
- [...state.tasks].reverse().find((task) => task.status === 'blocked') ??
268
- [...state.tasks].reverse().find((task) => task.status === 'in-progress') ??
269
- [...state.tasks].reverse().find((task) => task.status === 'open')
270
- const taskTitle = toOptionalTrimmedString(latestTask?.title)
271
- if (taskTitle) {
272
- return { kind: 'task', text: taskTitle }
273
- }
274
-
275
- const latestQuestion = toOptionalTrimmedString(state.openQuestions.at(-1)?.text)
276
- if (latestQuestion) {
277
- return { kind: 'question', text: latestQuestion }
278
- }
279
-
280
- const latestDecision = toOptionalTrimmedString(state.keyDecisions.at(-1)?.decision)
281
- if (latestDecision) {
282
- return { kind: 'decision', text: latestDecision }
283
- }
284
-
285
- const latestAgentNote = toOptionalTrimmedString(state.agentContributions.at(-1)?.summary)
286
- if (latestAgentNote) {
287
- return { kind: 'agent-note', text: latestAgentNote }
288
- }
289
-
290
- const compactedSummaryFocus = getCompactedSummaryFocus(chatSummary)
291
- if (compactedSummaryFocus) {
292
- return { kind: 'chat-summary', text: compactedSummaryFocus }
293
- }
294
-
295
- return null
296
- }
297
-
298
138
  class WorkstreamService extends BaseService<typeof WorkstreamSchema> {
299
139
  constructor() {
300
140
  super(TABLES.WORKSTREAM, WorkstreamSchema)
@@ -664,12 +504,30 @@ class WorkstreamService extends BaseService<typeof WorkstreamSchema> {
664
504
  await this.setActiveRunId(workstreamId, null)
665
505
  }
666
506
 
667
- async persistChangeTracker(
668
- workstreamId: RecordIdRef,
669
- payload: { chatSummary: string; state: WorkstreamState },
670
- ): Promise<void> {
507
+ async setActiveStreamId(workstreamId: RecordIdRef, streamId: string): Promise<void> {
508
+ const workstreamRef = ensureRecordId(workstreamId, TABLES.WORKSTREAM)
509
+ await databaseService.query<unknown>(surql`
510
+ UPDATE ONLY ${workstreamRef}
511
+ SET activeStreamId = ${streamId}
512
+ `)
513
+ }
514
+
515
+ async getActiveStreamId(workstreamId: RecordIdRef): Promise<string | null> {
516
+ const workstream = await this.getById(workstreamId)
517
+ const activeStreamId = workstream.activeStreamId
518
+ if (typeof activeStreamId !== 'string') return null
519
+ const normalized = activeStreamId.trim()
520
+ return normalized.length > 0 ? normalized : null
521
+ }
522
+
523
+ async clearActiveStreamIdIfMatches(workstreamId: RecordIdRef, streamId: string): Promise<void> {
524
+ const activeStreamId = await this.getActiveStreamId(workstreamId)
525
+ if (activeStreamId !== streamId) return
671
526
  const workstreamRef = ensureRecordId(workstreamId, TABLES.WORKSTREAM)
672
- await this.update(workstreamRef, { chatSummary: payload.chatSummary, state: payload.state })
527
+ await databaseService.query<unknown>(surql`
528
+ UPDATE ONLY ${workstreamRef}
529
+ SET activeStreamId = NONE
530
+ `)
673
531
  }
674
532
 
675
533
  async stopActiveRun(workstreamId: RecordIdRef): Promise<boolean> {
@@ -868,22 +726,6 @@ class WorkstreamService extends BaseService<typeof WorkstreamSchema> {
868
726
  }
869
727
  }
870
728
 
871
- toPublicWorkstreamDetail(workstream: WorkstreamRecord): PublicWorkstreamDetail {
872
- const publicWorkstream = this.toPublicWorkstream(workstream)
873
- const snapshot = parsePersistedWorkstreamState(workstream.state)
874
- const chatSummary = toOptionalTrimmedString(workstream.chatSummary)
875
- const progress = buildWorkstreamStateProgress(snapshot)
876
- const workstreamState: PublicWorkstreamStatePayload = {
877
- focus: buildWorkstreamStateFocus(snapshot, chatSummary),
878
- chatSummary,
879
- approval: buildWorkstreamApprovalState(snapshot),
880
- progress,
881
- snapshot,
882
- }
883
-
884
- return { ...publicWorkstream, workstreamState }
885
- }
886
-
887
729
  async incrementTurnCount(workstreamId: RecordIdRef): Promise<number> {
888
730
  const workstreamRef = ensureRecordId(workstreamId, TABLES.WORKSTREAM)
889
731
  const result = await databaseService.query<{ turnCount: number }>(surql`
@@ -1,7 +1,5 @@
1
1
  import { z } from 'zod'
2
2
 
3
- import type { WorkstreamState } from '../runtime/workstream-state'
4
-
5
3
  export interface Citation {
6
4
  title?: string
7
5
  url?: string
@@ -33,68 +31,6 @@ export interface NormalizedWorkstream {
33
31
  organizationId: string
34
32
  }
35
33
 
36
- export interface PublicWorkstreamStateFocus {
37
- kind: 'plan' | 'task' | 'question' | 'decision' | 'agent-note' | 'chat-summary'
38
- text: string
39
- }
40
-
41
- export interface PublicWorkstreamTaskProgress {
42
- total: number
43
- open: number
44
- inProgress: number
45
- done: number
46
- blocked: number
47
- }
48
-
49
- export interface PublicWorkstreamConstraintProgress {
50
- total: number
51
- approved: number
52
- candidate: number
53
- }
54
-
55
- export interface PublicWorkstreamStateProgress {
56
- hasState: boolean
57
- lastUpdated: string | null
58
- completionRatio: number | null
59
- tasks: PublicWorkstreamTaskProgress
60
- constraints: PublicWorkstreamConstraintProgress
61
- keyDecisions: number
62
- openQuestions: number
63
- risks: number
64
- artifacts: number
65
- agentContributions: number
66
- }
67
-
68
- export interface PublicWorkstreamApprovalState {
69
- approvedBy: string | null
70
- approvedAt: string | null
71
- approvalMessageId: string | null
72
- approvalNote: string | null
73
- }
74
-
75
- export interface PublicWorkstreamStatePayload {
76
- focus: PublicWorkstreamStateFocus | null
77
- chatSummary: string | null
78
- approval: PublicWorkstreamApprovalState | null
79
- progress: PublicWorkstreamStateProgress
80
- snapshot: WorkstreamState | null
81
- }
82
-
83
- export interface PublicWorkstreamDetail {
84
- id: string
85
- title: string
86
- status: 'regular' | 'archived'
87
- mode: 'direct' | 'group'
88
- core: boolean
89
- coreType?: string
90
- isRunning: boolean
91
- isCompacting: boolean
92
- agentId?: string | null
93
- createdAt: string
94
- updatedAt: string
95
- workstreamState: PublicWorkstreamStatePayload
96
- }
97
-
98
34
  export const WorkstreamSchema = z.object({
99
35
  id: z.any(), // RecordId
100
36
  mode: WorkstreamModeSchema.optional().default('group'),
@@ -106,7 +42,8 @@ export const WorkstreamSchema = z.object({
106
42
  memoryBlock: z.string().nullish(),
107
43
  memoryBlockSummary: z.string().nullish(),
108
44
  activeRunId: z.string().nullish(),
109
- chatSummary: z.string().nullish(),
45
+ activeStreamId: z.string().nullish(),
46
+ compactionSummary: z.string().nullish(),
110
47
  lastCompactedMessageId: z.string().nullish(),
111
48
  nameGenerated: z.boolean().optional().default(false),
112
49
  isCompacting: z.boolean().optional(),
@@ -8,7 +8,7 @@ import {
8
8
  import type { CreateHelperToolLoopAgentOptions } from '../runtime/agent-types'
9
9
  import { resolveHelperAgentOptions } from './helper-agent-options'
10
10
 
11
- const WORKSTREAM_TITLE_MAX_TOKENS = 64
11
+ const WORKSTREAM_TITLE_MAX_TOKENS = 512
12
12
 
13
13
  export const WORKSTREAM_TITLE_GENERATOR_PROMPT = `<agent-instructions>
14
14
  You are a **Title Generator** that creates concise chat titles.
@@ -18,7 +18,7 @@ Generate a chat title based only on the user's message.
18
18
  </task>
19
19
 
20
20
  <constraints>
21
- - Maximum 4-5 words
21
+ - Maximum 3-4 words
22
22
  - Capture the core workstream or intent
23
23
  - Use natural, readable language
24
24
  - No punctuation at the end
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  CreateExecutionPlanArgsSchema,
3
3
  GetActiveExecutionPlanArgsSchema,
4
- RestartExecutionTaskArgsSchema,
4
+ ResumeExecutionPlanRunArgsSchema,
5
5
  ReplaceExecutionPlanArgsSchema,
6
- SetExecutionTaskStatusArgsSchema,
6
+ SubmitExecutionNodeResultArgsSchema,
7
7
  } from '@lota-sdk/shared/schemas/tools'
8
8
  import type { ExecutionPlanToolResultData } from '@lota-sdk/shared/schemas/tools'
9
9
  import { tool } from 'ai'
@@ -34,7 +34,7 @@ export function createCreateExecutionPlanTool(params: {
34
34
  }) {
35
35
  return tool({
36
36
  description:
37
- 'Create a structured execution plan for multi-step work in this workstream. Use this before starting multi-step execution.',
37
+ 'Create a contract-driven execution plan for this workstream. Nodes must define deliverables, success criteria, completion checks, and executor policy.',
38
38
  inputSchema: CreateExecutionPlanArgsSchema,
39
39
  execute: async (input) => {
40
40
  const result = await executionPlanService.createPlan({
@@ -56,7 +56,8 @@ export function createReplaceExecutionPlanTool(params: {
56
56
  onPlanChanged?: () => void
57
57
  }) {
58
58
  return tool({
59
- description: 'Replace the active execution plan when the ordered steps or approach have materially changed.',
59
+ description:
60
+ 'Replace the active execution run with a new contract-driven plan when the graph, contracts, or approach materially change.',
60
61
  inputSchema: ReplaceExecutionPlanArgsSchema,
61
62
  execute: async (input) => {
62
63
  const result = await executionPlanService.replacePlan({
@@ -71,48 +72,17 @@ export function createReplaceExecutionPlanTool(params: {
71
72
  })
72
73
  }
73
74
 
74
- export function createSetExecutionTaskStatusTool(params: {
75
+ export function createSubmitExecutionNodeResultTool(params: {
75
76
  workstreamId: RecordIdRef
76
77
  agentId: string
77
78
  onPlanChanged?: () => void
78
79
  }) {
79
80
  return tool({
80
81
  description:
81
- 'Update the active execution-plan task state, including in-progress, completed, blocked, failed, or skipped outcomes.',
82
- inputSchema: SetExecutionTaskStatusArgsSchema,
83
- execute: async function* (input) {
84
- const activePlan = await executionPlanService.getActivePlanToolResult({
85
- workstreamId: params.workstreamId,
86
- includeEvents: true,
87
- })
88
-
89
- if (activePlan.plan && activePlan.plan.planId === input.planId) {
90
- const optimisticPlan = structuredClone(activePlan.plan)
91
- const targetTask = optimisticPlan.tasks.find((task) => task.id === input.taskId)
92
-
93
- if (targetTask) {
94
- targetTask.status = input.status
95
- if (input.resultStatus !== undefined) targetTask.resultStatus = input.resultStatus
96
- if (input.outputSummary !== undefined) targetTask.outputSummary = input.outputSummary || undefined
97
- if (input.blockedReason !== undefined) targetTask.blockedReason = input.blockedReason || undefined
98
- if (input.externalRef !== undefined) targetTask.externalRef = input.externalRef || undefined
99
- if (input.status === 'in-progress') {
100
- optimisticPlan.status = 'executing'
101
- optimisticPlan.currentTaskId = targetTask.id
102
- }
103
-
104
- yield {
105
- action: 'task-status-updated',
106
- message: `Updating task "${targetTask.title}".`,
107
- changedTaskId: targetTask.id,
108
- plan: optimisticPlan,
109
- hasPlan: true,
110
- status: optimisticPlan.status,
111
- } satisfies ExecutionPlanToolResultData
112
- }
113
- }
114
-
115
- const result = await executionPlanService.setTaskStatus({
82
+ 'Submit the result for the currently running execution node. The executor validates outputs, artifacts, and completion checks before advancing the run.',
83
+ inputSchema: SubmitExecutionNodeResultArgsSchema,
84
+ execute: async (input) => {
85
+ const result = await executionPlanService.submitNodeResult({
116
86
  workstreamId: params.workstreamId,
117
87
  emittedBy: params.agentId,
118
88
  input,
@@ -123,7 +93,7 @@ export function createSetExecutionTaskStatusTool(params: {
123
93
  toModelOutput: ({ output }) => {
124
94
  const result = getLatestExecutionPlanToolResult(output)
125
95
  const summary = result?.message?.trim()
126
- return { type: 'text', value: summary && summary.length > 0 ? summary : 'Execution task status updated.' }
96
+ return { type: 'text', value: summary && summary.length > 0 ? summary : 'Execution node result submitted.' }
127
97
  },
128
98
  })
129
99
  }
@@ -131,27 +101,31 @@ export function createSetExecutionTaskStatusTool(params: {
131
101
  export function createGetActiveExecutionPlanTool(params: { workstreamId: RecordIdRef }) {
132
102
  return tool({
133
103
  description:
134
- 'Load the active execution plan for this workstream, including task state and recent events when needed.',
104
+ 'Load the active execution run for this workstream, including graph state, node contracts, recent events, approvals, artifacts, and checkpoints when requested.',
135
105
  inputSchema: GetActiveExecutionPlanArgsSchema,
136
106
  execute: async (input) =>
137
107
  await executionPlanService.getActivePlanToolResult({
138
108
  workstreamId: params.workstreamId,
139
109
  includeEvents: input.includeEvents,
110
+ includeArtifacts: input.includeArtifacts,
111
+ includeApprovals: input.includeApprovals,
112
+ includeCheckpoints: input.includeCheckpoints,
113
+ includeValidationIssues: input.includeValidationIssues,
140
114
  }),
141
115
  })
142
116
  }
143
117
 
144
- export function createRestartExecutionTaskTool(params: {
118
+ export function createResumeExecutionPlanRunTool(params: {
145
119
  workstreamId: RecordIdRef
146
120
  agentId: string
147
121
  onPlanChanged?: () => void
148
122
  }) {
149
123
  return tool({
150
124
  description:
151
- 'Restart a failed or blocked execution-plan task and optionally reset downstream tasks back to pending.',
152
- inputSchema: RestartExecutionTaskArgsSchema,
125
+ 'Resume the active execution run from its latest checkpoint after interruption. The executor reconciles state before re-activating nodes.',
126
+ inputSchema: ResumeExecutionPlanRunArgsSchema,
153
127
  execute: async (input) => {
154
- const result = await executionPlanService.restartTask({
128
+ const result = await executionPlanService.resumeRun({
155
129
  workstreamId: params.workstreamId,
156
130
  emittedBy: params.agentId,
157
131
  input,
@@ -0,0 +1,17 @@
1
+ import { tool } from 'ai'
2
+ import { z } from 'zod'
3
+
4
+ export function createLogHelloWorldTool() {
5
+ return tool({
6
+ description: 'Logs "Hello World" to the server console. Requires user approval before running.',
7
+ inputSchema: z.object({
8
+ message: z.string().optional().describe('Optional custom message to log alongside Hello World'),
9
+ }),
10
+ needsApproval: true,
11
+ execute: async ({ message }: { message?: string }) => {
12
+ const output = message ? `Hello World: ${message}` : 'Hello World'
13
+ console.log('[logHelloWorld]', output)
14
+ return { logged: output, timestamp: new Date().toISOString() }
15
+ },
16
+ })
17
+ }
@@ -7,7 +7,7 @@ import { ensureRecordId, recordIdToString } from '../db/record-id'
7
7
  import type { RecordIdRef } from '../db/record-id'
8
8
  import { databaseService } from '../db/service'
9
9
  import { TABLES } from '../db/tables'
10
- import { createDefaultEmbeddings } from '../embeddings/provider'
10
+ import { getDefaultEmbeddings } from '../embeddings/provider'
11
11
  import type { SkillExtractionJob } from '../queues/skill-extraction.queue'
12
12
  import { createHelperModelRuntime } from '../runtime/helper-model'
13
13
  import { getRuntimeAdapters, withConfiguredWorkspaceMemoryLock } from '../runtime/runtime-extensions'
@@ -54,7 +54,7 @@ interface SkillExtractionRunResult {
54
54
  extractedSkills: number
55
55
  }
56
56
 
57
- const embeddings = createDefaultEmbeddings()
57
+ const embeddings = getDefaultEmbeddings()
58
58
 
59
59
  const helperModelRuntime = createHelperModelRuntime()
60
60