@lota-sdk/core 0.1.9 → 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 (34) hide show
  1. package/infrastructure/schema/00_workstream.surql +1 -0
  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 +12 -4
  16. package/src/services/document-chunk.service.ts +2 -2
  17. package/src/services/execution-plan.service.ts +579 -786
  18. package/src/services/learned-skill.service.ts +2 -2
  19. package/src/services/plan-approval.service.ts +83 -0
  20. package/src/services/plan-artifact.service.ts +45 -0
  21. package/src/services/plan-builder.service.ts +61 -0
  22. package/src/services/plan-checkpoint.service.ts +53 -0
  23. package/src/services/plan-compiler.service.ts +81 -0
  24. package/src/services/plan-executor.service.ts +1623 -0
  25. package/src/services/plan-run.service.ts +422 -0
  26. package/src/services/plan-validator.service.ts +760 -0
  27. package/src/services/workstream-turn-preparation.ts +57 -15
  28. package/src/services/workstream-turn.ts +12 -0
  29. package/src/services/workstream.service.ts +26 -0
  30. package/src/services/workstream.types.ts +1 -0
  31. package/src/system-agents/title-generator.agent.ts +2 -2
  32. package/src/tools/execution-plan.tool.ts +20 -46
  33. package/src/tools/log-hello-world.tool.ts +17 -0
  34. package/src/workers/skill-extraction.runner.ts +2 -2
@@ -140,6 +140,15 @@ export function parsePersistedWorkstreamState(value: unknown): WorkstreamState |
140
140
  return parseWorkstreamState(value)
141
141
  }
142
142
 
143
+ export function stripExecutionPlanFieldsFromWorkstreamState(
144
+ state: WorkstreamState | null | undefined,
145
+ hasExecutionPlan: boolean,
146
+ ): WorkstreamState | null | undefined {
147
+ if (!state || !hasExecutionPlan) return state
148
+
149
+ return { ...state, currentPlan: null, tasks: [], artifacts: [] }
150
+ }
151
+
143
152
  export async function waitForWorkstreamCompactionIfNeeded(workstreamId: RecordIdRef): Promise<WorkstreamRecord> {
144
153
  return await waitForCompactionIfNeeded({
145
154
  entityId: recordIdToString(workstreamId, TABLES.WORKSTREAM),
@@ -220,6 +229,7 @@ export interface WorkstreamTurnParams {
220
229
  inputMessage: ChatMessage
221
230
  persistInputMessage?: boolean
222
231
  abortSignal?: AbortSignal
232
+ streamId?: string
223
233
  }
224
234
 
225
235
  export interface WorkstreamApprovalContinuationParams {
@@ -230,6 +240,7 @@ export interface WorkstreamApprovalContinuationParams {
230
240
  userName?: string | null
231
241
  approvalMessages: ChatMessage[]
232
242
  abortSignal?: AbortSignal
243
+ streamId?: string
233
244
  }
234
245
 
235
246
  export type WorkstreamRunCoreParams = {
@@ -239,9 +250,11 @@ export type WorkstreamRunCoreParams = {
239
250
  userRef: RecordIdRef
240
251
  userName?: string | null
241
252
  abortSignal?: AbortSignal
253
+ streamId?: string
242
254
  } & (
243
255
  | { kind: 'userTurn'; inputMessage: ChatMessage; persistInputMessage?: boolean }
244
256
  | { kind: 'approvalContinuation'; approvalMessages: ChatMessage[] }
257
+ | { kind: 'nativeToolApprovalTurn'; approvalMessages: ChatMessage[] }
245
258
  )
246
259
 
247
260
  export interface PreparedWorkstreamTurn {
@@ -307,7 +320,8 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
307
320
 
308
321
  let inputMessage: ChatMessage | undefined
309
322
  const shouldPersistInputMessage = params.kind === 'userTurn' ? params.persistInputMessage !== false : false
310
- const shouldProcessPostRunSideEffects = params.kind === 'approvalContinuation' || shouldPersistInputMessage
323
+ const shouldProcessPostRunSideEffects =
324
+ params.kind === 'approvalContinuation' || params.kind === 'nativeToolApprovalTurn' || shouldPersistInputMessage
311
325
  if (params.kind === 'userTurn') {
312
326
  inputMessage = hydrateMessageFileUrls(withMessageCreatedAt(params.inputMessage))
313
327
  if (inputMessage.role !== 'user') {
@@ -326,7 +340,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
326
340
  throw new WorkstreamTurnError('A chat run is already active.', 409)
327
341
  }
328
342
 
329
- if (params.kind === 'approvalContinuation') {
343
+ if (params.kind === 'approvalContinuation' || params.kind === 'nativeToolApprovalTurn') {
330
344
  const approvedAssistantMessage = [...params.approvalMessages]
331
345
  .reverse()
332
346
  .find((m) => m.role === 'assistant' && hasApprovalRespondedParts(m))
@@ -539,11 +553,38 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
539
553
  disabled: onboardingActive,
540
554
  loadPlan: async () => await executionPlanService.getActivePlanForWorkstream(workstreamRef),
541
555
  })
556
+ const getExecutionPlan = async () => await executionPlanInstructionSectionCache.getPlan()
542
557
  const getExecutionPlanInstructionSections = async (): Promise<string[] | undefined> =>
543
558
  await executionPlanInstructionSectionCache.getSections()
544
559
  const invalidateExecutionPlanInstructionSections = () => {
545
560
  executionPlanInstructionSectionCache.invalidate()
546
561
  }
562
+ const getWorkstreamStateSection = async (): Promise<string | undefined> => {
563
+ const executionPlan = await getExecutionPlan()
564
+ return contextCompactionRuntime.formatWorkstreamStateForPrompt(
565
+ stripExecutionPlanFieldsFromWorkstreamState(workstreamState, Boolean(executionPlan)),
566
+ )
567
+ }
568
+ const respondedBy = recordIdToString(userRef, TABLES.USER)
569
+ if (params.kind === 'approvalContinuation') {
570
+ const appliedApproval = await executionPlanService.applyApprovalResponseFromMessages({
571
+ workstreamId: workstreamRef,
572
+ approvalMessages: params.approvalMessages,
573
+ respondedBy,
574
+ })
575
+ if (appliedApproval) {
576
+ invalidateExecutionPlanInstructionSections()
577
+ }
578
+ } else if (userMessage) {
579
+ const appliedHumanInput = await executionPlanService.applyHumanInputFromUserMessage({
580
+ workstreamId: workstreamRef,
581
+ message: userMessage,
582
+ respondedBy,
583
+ })
584
+ if (appliedHumanInput) {
585
+ invalidateExecutionPlanInstructionSections()
586
+ }
587
+ }
547
588
  const preSeededMemoriesByAgent = new Map<string, string | undefined>()
548
589
  const getPreSeededMemoriesSection = async (agentId: string): Promise<string | undefined> => {
549
590
  if (preSeededMemoriesByAgent.has(agentId)) {
@@ -601,6 +642,9 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
601
642
  const serverRunId = Bun.randomUUIDv7()
602
643
  const runAbort = createServerRunAbortController(params.abortSignal)
603
644
  await workstreamService.setActiveRunId(workstreamRef, serverRunId)
645
+ if (params.streamId) {
646
+ await workstreamService.setActiveStreamId(workstreamRef, params.streamId)
647
+ }
604
648
  chatRunRegistry.register(serverRunId, runAbort.controller)
605
649
 
606
650
  try {
@@ -692,7 +736,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
692
736
  preSeededMemoriesSection: await getPreSeededMemoriesSection(resolvedAgentId),
693
737
  retrievedKnowledgeSection,
694
738
  workstreamMemoryBlock: memoryBlock,
695
- workstreamStateSection: contextCompactionRuntime.formatWorkstreamStateForPrompt(workstreamState),
739
+ workstreamStateSection: await getWorkstreamStateSection(),
696
740
  learnedSkillsSection: await getLearnedSkillsSection(resolvedAgentId),
697
741
  additionalInstructionSections: mergeInstructionSections(
698
742
  executionPlanInstructionSections,
@@ -839,6 +883,12 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
839
883
  )
840
884
  }
841
885
 
886
+ // Execution-plan approval continuations mutate plan state and persist the approval message,
887
+ // but they do not begin a new visible agent turn.
888
+ if (params.kind === 'approvalContinuation') {
889
+ return
890
+ }
891
+
842
892
  const consultSpecialistTool = createTool({
843
893
  description: 'Consult one specialist teammate for domain-specific guidance before replying to the user.',
844
894
  inputSchema: ConsultSpecialistArgsSchema,
@@ -883,7 +933,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
883
933
  preSeededMemoriesSection: await getPreSeededMemoriesSection(agentId),
884
934
  retrievedKnowledgeSection,
885
935
  workstreamMemoryBlock: specialistMemoryBlock,
886
- workstreamStateSection: contextCompactionRuntime.formatWorkstreamStateForPrompt(workstreamState),
936
+ workstreamStateSection: await getWorkstreamStateSection(),
887
937
  learnedSkillsSection: await getLearnedSkillsSection(agentId),
888
938
  additionalInstructionSections: mergeInstructionSections(
889
939
  specialistExecutionPlanInstructionSections,
@@ -995,17 +1045,6 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
995
1045
  throw new WorkstreamTurnError('Direct workstreams require an assigned agent.', 400)
996
1046
  }
997
1047
  await runVisibleAgent({ agentId: workstream.agentId, mode: 'direct' })
998
- } else if (params.kind === 'userTurn') {
999
- await runVisibleAgent({
1000
- agentId: visibleWorkstreamAgentId ?? 'chief',
1001
- mode: 'workstreamMode',
1002
- skills: coreWorkstreamProfile?.skills ? [...coreWorkstreamProfile.skills] : undefined,
1003
- additionalInstructionSections: mergeInstructionSections(coreInstructionSections, hookInstructionSections),
1004
- extraTools: {
1005
- [CONSULT_SPECIALIST_TOOL_NAME]: consultSpecialistTool,
1006
- ...(teamThinkTool ? { [CONSULT_TEAM_TOOL_NAME]: teamThinkTool } : {}),
1007
- },
1008
- })
1009
1048
  } else {
1010
1049
  await runVisibleAgent({
1011
1050
  agentId: visibleWorkstreamAgentId ?? 'chief',
@@ -1043,6 +1082,9 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
1043
1082
  unregisterRun: (runId) => chatRunRegistry.unregister(runId),
1044
1083
  clearActiveRunId: (runId) => workstreamService.clearActiveRunIdIfMatches(workstreamRef, runId),
1045
1084
  disposeAbort: () => runAbort.dispose(),
1085
+ activeStreamId: params.streamId,
1086
+ clearActiveStreamId: (streamId) =>
1087
+ workstreamService.clearActiveStreamIdIfMatches(workstreamRef, streamId),
1046
1088
  })
1047
1089
 
1048
1090
  if (allAssistantMessages.length > 0 && shouldProcessPostRunSideEffects) {
@@ -21,6 +21,18 @@ export async function createWorkstreamApprovalContinuationStream(params: Workstr
21
21
  })
22
22
  }
23
23
 
24
+ export async function createWorkstreamNativeToolApprovalStream(params: WorkstreamApprovalContinuationParams) {
25
+ const prepared = await prepareWorkstreamRunCore({ ...params, kind: 'nativeToolApprovalTurn' })
26
+
27
+ return createUIMessageStream<ChatMessage>({
28
+ originalMessages: prepared.originalMessages,
29
+ onError: (error) => (error instanceof Error ? error.message : 'Native tool approval stream failed.'),
30
+ execute: async ({ writer }) => {
31
+ await prepared.run(writer)
32
+ },
33
+ })
34
+ }
35
+
24
36
  export async function createWorkstreamTurnStream(params: WorkstreamTurnParams) {
25
37
  const prepared = await prepareWorkstreamRunCore({ ...params, kind: 'userTurn' })
26
38
 
@@ -504,6 +504,32 @@ class WorkstreamService extends BaseService<typeof WorkstreamSchema> {
504
504
  await this.setActiveRunId(workstreamId, null)
505
505
  }
506
506
 
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
526
+ const workstreamRef = ensureRecordId(workstreamId, TABLES.WORKSTREAM)
527
+ await databaseService.query<unknown>(surql`
528
+ UPDATE ONLY ${workstreamRef}
529
+ SET activeStreamId = NONE
530
+ `)
531
+ }
532
+
507
533
  async stopActiveRun(workstreamId: RecordIdRef): Promise<boolean> {
508
534
  const activeRunId = await this.getActiveRunId(workstreamId)
509
535
  if (!activeRunId) return false
@@ -42,6 +42,7 @@ export const WorkstreamSchema = z.object({
42
42
  memoryBlock: z.string().nullish(),
43
43
  memoryBlockSummary: z.string().nullish(),
44
44
  activeRunId: z.string().nullish(),
45
+ activeStreamId: z.string().nullish(),
45
46
  compactionSummary: z.string().nullish(),
46
47
  lastCompactedMessageId: z.string().nullish(),
47
48
  nameGenerated: z.boolean().optional().default(false),
@@ -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