@lota-sdk/core 0.4.10 → 0.4.12

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 (110) hide show
  1. package/package.json +3 -3
  2. package/src/ai-gateway/ai-gateway.ts +214 -98
  3. package/src/ai-gateway/index.ts +16 -1
  4. package/src/config/agent-defaults.ts +4 -120
  5. package/src/config/logger.ts +18 -34
  6. package/src/config/model-constants.ts +1 -0
  7. package/src/config/thread-defaults.ts +1 -18
  8. package/src/create-runtime.ts +90 -28
  9. package/src/db/base.service.ts +30 -38
  10. package/src/db/service.ts +489 -545
  11. package/src/effect/index.ts +0 -2
  12. package/src/effect/layers.ts +6 -13
  13. package/src/embeddings/provider.ts +2 -7
  14. package/src/index.ts +4 -5
  15. package/src/queues/autonomous-job.queue.ts +159 -113
  16. package/src/queues/context-compaction.queue.ts +39 -25
  17. package/src/queues/delayed-node-promotion.queue.ts +56 -29
  18. package/src/queues/document-processor.queue.ts +5 -3
  19. package/src/queues/index.ts +1 -0
  20. package/src/queues/memory-consolidation.queue.ts +79 -53
  21. package/src/queues/organization-learning.queue.ts +63 -39
  22. package/src/queues/plan-agent-heartbeat.queue.ts +104 -79
  23. package/src/queues/plan-scheduler.queue.ts +100 -84
  24. package/src/queues/post-chat-memory.queue.ts +55 -33
  25. package/src/queues/queue-factory.ts +40 -41
  26. package/src/queues/queues.service.ts +61 -0
  27. package/src/queues/title-generation.queue.ts +42 -31
  28. package/src/redis/org-memory-lock.ts +24 -9
  29. package/src/redis/redis-lease-lock.ts +8 -1
  30. package/src/runtime/agent-identity-overrides.ts +7 -3
  31. package/src/runtime/agent-runtime-policy.ts +9 -4
  32. package/src/runtime/agent-stream-helpers.ts +9 -4
  33. package/src/runtime/context-compaction/context-compaction-runtime.ts +28 -32
  34. package/src/runtime/context-compaction/context-compaction.ts +9 -7
  35. package/src/runtime/domain-layer.ts +15 -4
  36. package/src/runtime/execution-plan-visibility.ts +5 -2
  37. package/src/runtime/graph-designer.ts +0 -22
  38. package/src/runtime/index.ts +2 -0
  39. package/src/runtime/indexed-repositories-policy.ts +2 -6
  40. package/src/runtime/live-turn-trace.ts +344 -0
  41. package/src/runtime/plugin-resolution.ts +29 -12
  42. package/src/runtime/post-turn-side-effects.ts +139 -141
  43. package/src/runtime/runtime-config.ts +0 -6
  44. package/src/runtime/runtime-extensions.ts +0 -54
  45. package/src/runtime/runtime-lifecycle.ts +4 -4
  46. package/src/runtime/runtime-services.ts +125 -53
  47. package/src/runtime/runtime-worker-registry.ts +113 -30
  48. package/src/runtime/social-chat/social-chat-agent-runner.ts +6 -3
  49. package/src/runtime/social-chat/social-chat-history.ts +3 -1
  50. package/src/runtime/social-chat/social-chat.ts +35 -20
  51. package/src/runtime/team-consultation/team-consultation-orchestrator.ts +6 -5
  52. package/src/runtime/team-consultation/team-consultation-prompts.ts +11 -6
  53. package/src/runtime/thread-chat-helpers.ts +18 -9
  54. package/src/runtime/thread-turn-context.ts +7 -47
  55. package/src/runtime/turn-lifecycle.ts +6 -14
  56. package/src/services/agent-activity.service.ts +168 -175
  57. package/src/services/agent-executor.service.ts +35 -16
  58. package/src/services/attachment.service.ts +4 -70
  59. package/src/services/autonomous-job.service.ts +53 -61
  60. package/src/services/context-compaction.service.ts +7 -9
  61. package/src/services/execution-plan/execution-plan-graph.ts +106 -115
  62. package/src/services/execution-plan/execution-plan-schedule.ts +1 -15
  63. package/src/services/execution-plan/execution-plan.service.ts +67 -50
  64. package/src/services/global-orchestrator.service.ts +18 -7
  65. package/src/services/graph-full-routing.ts +7 -6
  66. package/src/services/memory/memory-conversation.ts +10 -5
  67. package/src/services/memory/memory.service.ts +11 -8
  68. package/src/services/ownership-dispatcher.service.ts +16 -5
  69. package/src/services/plan/plan-agent-heartbeat.service.ts +29 -15
  70. package/src/services/plan/plan-agent-query.service.ts +12 -8
  71. package/src/services/plan/plan-completion-side-effects.ts +93 -101
  72. package/src/services/plan/plan-cycle.service.ts +7 -45
  73. package/src/services/plan/plan-deadline.service.ts +28 -17
  74. package/src/services/plan/plan-event-delivery.service.ts +47 -40
  75. package/src/services/plan/plan-executor-context.ts +2 -0
  76. package/src/services/plan/plan-executor-graph.ts +366 -391
  77. package/src/services/plan/plan-executor.service.ts +13 -91
  78. package/src/services/plan/plan-scheduler.service.ts +62 -49
  79. package/src/services/plan/plan-transaction-events.ts +1 -1
  80. package/src/services/recent-activity-title.service.ts +6 -2
  81. package/src/services/thread/thread-bootstrap.ts +11 -9
  82. package/src/services/thread/thread-message.service.ts +6 -5
  83. package/src/services/thread/thread-turn-execution.ts +86 -82
  84. package/src/services/thread/thread-turn-preparation.service.ts +92 -45
  85. package/src/services/thread/thread-turn-streaming.ts +60 -28
  86. package/src/services/thread/thread-turn.ts +212 -46
  87. package/src/services/thread/thread.service.ts +21 -6
  88. package/src/system-agents/recent-activity-title-refiner.agent.ts +8 -5
  89. package/src/system-agents/thread-router.agent.ts +23 -20
  90. package/src/tools/execution-plan.tool.ts +8 -3
  91. package/src/tools/fetch-webpage.tool.ts +10 -9
  92. package/src/tools/firecrawl-client.ts +0 -15
  93. package/src/tools/remember-memory.tool.ts +3 -6
  94. package/src/tools/research-topic.tool.ts +12 -3
  95. package/src/tools/search-web.tool.ts +10 -9
  96. package/src/tools/search.tool.ts +4 -5
  97. package/src/tools/team-think.tool.ts +139 -121
  98. package/src/workers/bootstrap.ts +9 -10
  99. package/src/workers/memory-consolidation.worker.ts +4 -1
  100. package/src/workers/organization-learning.worker.ts +15 -2
  101. package/src/workers/regular-chat-memory-digest.helpers.ts +3 -4
  102. package/src/workers/regular-chat-memory-digest.runner.ts +21 -14
  103. package/src/workers/skill-extraction.runner.ts +13 -15
  104. package/src/workers/worker-utils.ts +6 -18
  105. package/src/effect/awaitable-effect.ts +0 -96
  106. package/src/effect/runtime-ref.ts +0 -25
  107. package/src/effect/runtime.ts +0 -46
  108. package/src/redis/runtime-connection.ts +0 -20
  109. package/src/runtime/runtime-accessors.ts +0 -92
  110. package/src/runtime/runtime-token.ts +0 -47
@@ -4,12 +4,7 @@ import { z } from 'zod'
4
4
 
5
5
  import { aiGatewayChatModel } from '../ai-gateway/ai-gateway'
6
6
  import { buildAiGatewayDirectCacheHeaders } from '../ai-gateway/cache-headers'
7
- import {
8
- getAgentDescriptions,
9
- getAgentDisplayNames,
10
- getAgentShortDisplayNames,
11
- getRouterModelId,
12
- } from '../config/agent-defaults'
7
+ import type { ResolvedAgentConfig } from '../config/agent-defaults'
13
8
  import { chatLogger } from '../config/logger'
14
9
  import type { ValidationError } from '../effect/errors'
15
10
  import { AiGenerationError } from '../effect/errors'
@@ -28,6 +23,7 @@ export type RouterTriageResult = z.infer<typeof TriageResultSchema>
28
23
  export type RouterCheckResult = { done: true } | RouterCheckContinueResult
29
24
 
30
25
  interface RouterDisplayOptions {
26
+ agentConfig: ResolvedAgentConfig
31
27
  displayNamesById?: Partial<Record<string, string>>
32
28
  shortDisplayNamesById?: Partial<Record<string, string>>
33
29
  routingAliasesByAgentId?: Partial<Record<string, string[]>>
@@ -44,26 +40,26 @@ function readStringArrayOverride(
44
40
  return record && Object.hasOwn(record, key) ? record[key] : undefined
45
41
  }
46
42
 
47
- function readDisplayName(agentId: string, options?: RouterDisplayOptions): string {
48
- const override = readStringOverride(options?.displayNamesById, agentId)
43
+ function readDisplayName(agentId: string, options: RouterDisplayOptions): string {
44
+ const override = readStringOverride(options.displayNamesById, agentId)
49
45
  if (override !== undefined) {
50
46
  return override
51
47
  }
52
48
 
53
- return getAgentDisplayNames()[agentId] ?? agentId
49
+ return options.agentConfig.displayNames[agentId] ?? agentId
54
50
  }
55
51
 
56
- function readShortDisplayName(agentId: string, options?: RouterDisplayOptions): string {
57
- const override = readStringOverride(options?.shortDisplayNamesById, agentId)
52
+ function readShortDisplayName(agentId: string, options: RouterDisplayOptions): string {
53
+ const override = readStringOverride(options.shortDisplayNamesById, agentId)
58
54
  if (override !== undefined) {
59
55
  return override
60
56
  }
61
57
 
62
- return getAgentShortDisplayNames()[agentId] ?? readDisplayName(agentId, options)
58
+ return options.agentConfig.shortDisplayNames[agentId] ?? readDisplayName(agentId, options)
63
59
  }
64
60
 
65
- function buildMembersDescription(members: readonly string[], options?: RouterDisplayOptions): string {
66
- const agentDescriptions = getAgentDescriptions()
61
+ function buildMembersDescription(members: readonly string[], options: RouterDisplayOptions): string {
62
+ const agentDescriptions = options.agentConfig.descriptions
67
63
  return members
68
64
  .map((id) => {
69
65
  const display = readDisplayName(id, options)
@@ -77,7 +73,7 @@ function escapeRegex(value: string): string {
77
73
  return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
78
74
  }
79
75
 
80
- function buildExplicitAgentRoutingContext(agentId: string, options?: RouterDisplayOptions): string {
76
+ function buildExplicitAgentRoutingContext(agentId: string, options: RouterDisplayOptions): string {
81
77
  const displayName = readDisplayName(agentId, options)
82
78
  return `Respond directly to the part of the user's request explicitly addressed to ${displayName}.`
83
79
  }
@@ -85,16 +81,16 @@ function buildExplicitAgentRoutingContext(agentId: string, options?: RouterDispl
85
81
  function extractExplicitAgentTargets(
86
82
  messageText: string,
87
83
  members: readonly string[],
88
- options?: RouterDisplayOptions,
84
+ options: RouterDisplayOptions,
89
85
  ): string[] {
90
86
  const normalizedMessage = messageText.trim()
91
87
  if (!normalizedMessage) return []
92
88
 
93
89
  const memberSet = new Set(members)
94
90
  const aliases = new Map<string, string>()
95
- const defaultDisplayNames = options?.displayNamesById === undefined ? getAgentDisplayNames() : undefined
91
+ const defaultDisplayNames = options.displayNamesById === undefined ? options.agentConfig.displayNames : undefined
96
92
  const defaultShortDisplayNames =
97
- options?.shortDisplayNamesById === undefined ? getAgentShortDisplayNames() : undefined
93
+ options.shortDisplayNamesById === undefined ? options.agentConfig.shortDisplayNames : undefined
98
94
 
99
95
  for (const member of members) {
100
96
  for (const rawAlias of [
@@ -103,7 +99,7 @@ function extractExplicitAgentTargets(
103
99
  defaultShortDisplayNames?.[member],
104
100
  readDisplayName(member, options),
105
101
  readShortDisplayName(member, options),
106
- ...(readStringArrayOverride(options?.routingAliasesByAgentId, member) ?? []),
102
+ ...(readStringArrayOverride(options.routingAliasesByAgentId, member) ?? []),
107
103
  ]) {
108
104
  if (typeof rawAlias !== 'string') continue
109
105
  const alias = rawAlias.trim().toLowerCase()
@@ -173,12 +169,13 @@ function toRouterGenerationError(label: 'triage' | 'check', error: unknown): AiG
173
169
  }
174
170
 
175
171
  function generateRouterObjectEffect<TSchema extends z.ZodTypeAny>(params: {
172
+ agentConfig: ResolvedAgentConfig
176
173
  schema: TSchema
177
174
  system: string
178
175
  prompt: string
179
176
  label: 'triage' | 'check'
180
177
  }): Effect.Effect<z.infer<TSchema> | null, never> {
181
- const modelId = getRouterModelId() ?? 'openrouter/openai/gpt-5.4-nano'
178
+ const modelId = params.agentConfig.routerModelId ?? 'openrouter/openai/gpt-5.4-nano'
182
179
 
183
180
  return Effect.tryPromise({
184
181
  try: () =>
@@ -219,6 +216,7 @@ function generateRouterObjectEffect<TSchema extends z.ZodTypeAny>(params: {
219
216
  }
220
217
 
221
218
  export function triageThreadMessage(params: {
219
+ agentConfig: ResolvedAgentConfig
222
220
  threadTitle: string
223
221
  members: readonly string[]
224
222
  messageText: string
@@ -230,6 +228,7 @@ export function triageThreadMessage(params: {
230
228
  return Effect.runPromise(
231
229
  Effect.gen(function* () {
232
230
  const displayOptions: RouterDisplayOptions = {
231
+ agentConfig: params.agentConfig,
233
232
  displayNamesById: params.displayNamesById,
234
233
  shortDisplayNamesById: params.shortDisplayNamesById,
235
234
  routingAliasesByAgentId: params.routingAliasesByAgentId,
@@ -254,6 +253,7 @@ export function triageThreadMessage(params: {
254
253
  .join('\n\n')
255
254
 
256
255
  const parsed = yield* generateRouterObjectEffect({
256
+ agentConfig: params.agentConfig,
257
257
  schema: TriageResultSchema,
258
258
  system: TRIAGE_SYSTEM_PROMPT,
259
259
  prompt,
@@ -279,6 +279,7 @@ export function triageThreadMessage(params: {
279
279
  }
280
280
 
281
281
  export function checkForNextAgent(params: {
282
+ agentConfig: ResolvedAgentConfig
282
283
  threadTitle: string
283
284
  members: readonly string[]
284
285
  messageText: string
@@ -291,6 +292,7 @@ export function checkForNextAgent(params: {
291
292
  return Effect.runPromise(
292
293
  Effect.gen(function* () {
293
294
  const displayOptions: RouterDisplayOptions = {
295
+ agentConfig: params.agentConfig,
294
296
  displayNamesById: params.displayNamesById,
295
297
  shortDisplayNamesById: params.shortDisplayNamesById,
296
298
  routingAliasesByAgentId: params.routingAliasesByAgentId,
@@ -320,6 +322,7 @@ export function checkForNextAgent(params: {
320
322
  ].join('\n\n')
321
323
 
322
324
  const parsed = yield* generateRouterObjectEffect({
325
+ agentConfig: params.agentConfig,
323
326
  schema: CheckResultObjectSchema,
324
327
  system: CHECK_SYSTEM_PROMPT,
325
328
  prompt,
@@ -49,6 +49,8 @@ type ExecutionPlanExecutionPlanService = NoContextService<
49
49
 
50
50
  type ExecutionPlanToolValidationError = ReturnType<typeof toValidationError>
51
51
 
52
+ export type ExecutionPlanToolRunPromise = <A, E>(effect: Effect.Effect<A, E, never>) => Promise<A>
53
+
52
54
  export function createExecutionPlanTool(params: {
53
55
  orgId: RecordIdRef
54
56
  userId: RecordIdRef
@@ -56,6 +58,7 @@ export function createExecutionPlanTool(params: {
56
58
  agentId: string
57
59
  executionPlanService: ExecutionPlanExecutionPlanService
58
60
  threadService: ExecutionPlanThreadService
61
+ runPromise: ExecutionPlanToolRunPromise
59
62
  onPlanChanged?: () => void
60
63
  validateInlinePlan?: (draft: ReturnType<typeof expandAgentPlanDraft>) => void
61
64
  }) {
@@ -64,7 +67,7 @@ export function createExecutionPlanTool(params: {
64
67
  'Manage execution plans. Actions: create (inline, 1-2 nodes), create-project (dedicated project thread, 3+ nodes), replace (swap active plan), resume (resume interrupted plan), update-node (submit result for a specific node).',
65
68
  inputSchema: ExecutionPlanArgsSchema,
66
69
  execute: (input) =>
67
- Effect.runPromise(
70
+ params.runPromise(
68
71
  Effect.gen(function* () {
69
72
  const parsed = yield* parseExecutionPlanArgsEffect(input)
70
73
 
@@ -262,13 +265,14 @@ function extractAgentPlanDraftEffect(
262
265
  export function createExecutionPlanQueryTool(params: {
263
266
  threadId: RecordIdRef
264
267
  executionPlanService: Pick<ExecutionPlanExecutionPlanService, 'listActivePlanSummaries' | 'getActivePlanToolResult'>
268
+ runPromise: ExecutionPlanToolRunPromise
265
269
  }) {
266
270
  return tool({
267
271
  description:
268
272
  'Query execution plans. Omit runId to list all active plans. Provide runId to load a specific plan run.',
269
273
  inputSchema: ExecutionPlanQueryArgsSchema,
270
274
  execute: (input) =>
271
- Effect.runPromise(
275
+ params.runPromise(
272
276
  Effect.gen(function* () {
273
277
  if (!input.runId) {
274
278
  return yield* params.executionPlanService.listActivePlanSummaries(params.threadId)
@@ -291,6 +295,7 @@ export function createSubmitExecutionNodeResultTool(params: {
291
295
  threadId: RecordIdRef
292
296
  agentId: string
293
297
  executionPlanService: Pick<ExecutionPlanExecutionPlanService, 'submitNodeResult'>
298
+ runPromise: ExecutionPlanToolRunPromise
294
299
  onPlanChanged?: () => void
295
300
  }) {
296
301
  return tool({
@@ -298,7 +303,7 @@ export function createSubmitExecutionNodeResultTool(params: {
298
303
  'Submit the result for the currently running execution node. The executor validates outputs, artifacts, and completion checks before advancing the run.',
299
304
  inputSchema: SubmitExecutionNodeResultArgsSchema,
300
305
  execute: (input) =>
301
- Effect.runPromise(
306
+ params.runPromise(
302
307
  Effect.gen(function* () {
303
308
  const result = yield* params.executionPlanService.submitNodeResult({
304
309
  threadId: params.threadId,
@@ -1,3 +1,4 @@
1
+ import type Firecrawl from '@mendable/firecrawl-js'
1
2
  import { tool } from 'ai'
2
3
  import { Effect, Schema } from 'effect'
3
4
  import { z } from 'zod'
@@ -6,10 +7,13 @@ import type { ToolDefinition } from '../ai/definitions'
6
7
  import { withTimeout } from '../utils/async'
7
8
  import { nowIsoDateTimeString } from '../utils/date-time'
8
9
  import { readStringField, truncateOptionalText } from '../utils/string'
9
- import { getFirecrawlClient } from './firecrawl-client'
10
10
  import type { WebCitation } from './tool-contracts'
11
11
  import { toRecord, WEB_TOOL_TIMEOUT_MS } from './web-tool-shared'
12
12
 
13
+ export interface FetchWebpageToolContext {
14
+ firecrawl: Firecrawl
15
+ }
16
+
13
17
  class FetchWebpageToolError extends Schema.TaggedErrorClass<FetchWebpageToolError>()(
14
18
  '@lota-sdk/core/FetchWebpageToolError',
15
19
  { message: Schema.String, cause: Schema.optional(Schema.Defect) },
@@ -98,7 +102,7 @@ function buildFetchCitations(url: string, document: unknown): WebCitation[] {
98
102
 
99
103
  export const fetchWebpageTool = {
100
104
  name: 'fetchWebpage',
101
- create: () =>
105
+ create: ({ firecrawl }: FetchWebpageToolContext) =>
102
106
  tool({
103
107
  description: 'Retrieve and parse a single webpage.',
104
108
  inputSchema: z
@@ -119,10 +123,8 @@ export const fetchWebpageTool = {
119
123
  formats?: z.infer<typeof FormatSchema>[]
120
124
  onlyMainContent?: boolean
121
125
  maxAge?: number
122
- }) => {
123
- const firecrawl = getFirecrawlClient()
124
-
125
- return Effect.runPromise(
126
+ }) =>
127
+ Effect.runPromise(
126
128
  Effect.gen(function* () {
127
129
  const result = yield* Effect.tryPromise({
128
130
  try: () =>
@@ -139,7 +141,6 @@ export const fetchWebpageTool = {
139
141
  })
140
142
  return { url, document: summarizeDocument(url, result), citations: buildFetchCitations(url, result) }
141
143
  }).pipe(Effect.withSpan('tool.fetchWebpage.execute')),
142
- )
143
- },
144
+ ),
144
145
  }),
145
- } as const satisfies ToolDefinition<void>
146
+ } as const satisfies ToolDefinition<FetchWebpageToolContext>
@@ -1,7 +1,6 @@
1
1
  import Firecrawl from '@mendable/firecrawl-js'
2
2
  import { Context, Effect, Layer } from 'effect'
3
3
 
4
- import { resolveLotaService } from '../effect/runtime'
5
4
  import { RuntimeConfigServiceTag } from '../effect/services'
6
5
 
7
6
  export class FirecrawlTag extends Context.Service<FirecrawlTag, Firecrawl>()('@lota-sdk/core/Firecrawl') {}
@@ -16,17 +15,3 @@ export const FirecrawlLive = Layer.effect(
16
15
  })
17
16
  }),
18
17
  )
19
-
20
- let currentFirecrawlClient: Firecrawl | null = null
21
-
22
- export function configureFirecrawlClient(client: Firecrawl): void {
23
- currentFirecrawlClient = client
24
- }
25
-
26
- export function clearFirecrawlClient(): void {
27
- currentFirecrawlClient = null
28
- }
29
-
30
- export function getFirecrawlClient(): Firecrawl {
31
- return currentFirecrawlClient ?? resolveLotaService(FirecrawlTag)
32
- }
@@ -5,7 +5,6 @@ import { z } from 'zod'
5
5
  import type { RecordIdRef } from '../db/record-id'
6
6
  import { recordIdToString } from '../db/record-id'
7
7
  import { TABLES } from '../db/tables'
8
- import type { MaybeAwaitableService } from '../effect/awaitable-effect'
9
8
  import type { createMemoryService } from '../services/memory/memory.service'
10
9
  import { safeEnqueue } from '../utils/async'
11
10
 
@@ -16,11 +15,9 @@ const RememberMemoryInputSchema = z
16
15
  })
17
16
  .strict()
18
17
 
19
- type RememberMemoryService = MaybeAwaitableService<
20
- Pick<
21
- ReturnType<typeof createMemoryService>,
22
- 'assessMemoryCandidate' | 'createOrganizationMemory' | 'createAgentMemory'
23
- >
18
+ type RememberMemoryService = Pick<
19
+ ReturnType<typeof createMemoryService>,
20
+ 'assessMemoryCandidate' | 'createOrganizationMemory' | 'createAgentMemory'
24
21
  >
25
22
 
26
23
  export function createRememberMemoryTool({
@@ -1,15 +1,21 @@
1
+ import type Firecrawl from '@mendable/firecrawl-js'
2
+
1
3
  import { aiGatewayChatModel } from '../ai-gateway/ai-gateway'
2
4
  import { buildAiGatewayStrictSemanticCacheHeaders } from '../ai-gateway/cache-headers'
3
5
  import {
4
6
  OPENROUTER_FAST_REASONING_MODEL_ID,
5
7
  OPENROUTER_LOW_REASONING_PROVIDER_OPTIONS,
6
8
  } from '../config/model-constants'
7
- import { createDelegatedAgentTool } from '../system-agents/delegated-agent-factory'
9
+ import { createDelegatedAgentToolWithContext } from '../system-agents/delegated-agent-factory'
8
10
  import { RESEARCHER_PROMPT } from '../system-agents/researcher.agent'
9
11
  import { fetchWebpageTool } from './fetch-webpage.tool'
10
12
  import { searchWebTool } from './search-web.tool'
11
13
 
12
- export const researchTopicTool = createDelegatedAgentTool({
14
+ export interface ResearchTopicToolContext {
15
+ firecrawl: Firecrawl
16
+ }
17
+
18
+ export const researchTopicTool = createDelegatedAgentToolWithContext<ResearchTopicToolContext>({
13
19
  id: 'researchTopic',
14
20
  description:
15
21
  'Delegate a research task to a dedicated research agent that searches the web, fetches pages, and returns a synthesized markdown report.',
@@ -17,6 +23,9 @@ export const researchTopicTool = createDelegatedAgentTool({
17
23
  providerOptions: OPENROUTER_LOW_REASONING_PROVIDER_OPTIONS,
18
24
  headers: buildAiGatewayStrictSemanticCacheHeaders('researchTopic'),
19
25
  instructions: RESEARCHER_PROMPT,
20
- tools: { searchWeb: searchWebTool.create(), fetchWebpage: fetchWebpageTool.create() },
26
+ createTools: ({ firecrawl }) => ({
27
+ searchWeb: searchWebTool.create({ firecrawl }),
28
+ fetchWebpage: fetchWebpageTool.create({ firecrawl }),
29
+ }),
21
30
  maxSteps: 6,
22
31
  })
@@ -1,3 +1,4 @@
1
+ import type Firecrawl from '@mendable/firecrawl-js'
1
2
  import { tool } from 'ai'
2
3
  import { Effect, Schema } from 'effect'
3
4
  import { z } from 'zod'
@@ -6,10 +7,13 @@ import type { ToolDefinition } from '../ai/definitions'
6
7
  import { withTimeout } from '../utils/async'
7
8
  import { nowIsoDateTimeString } from '../utils/date-time'
8
9
  import { readStringField, truncateOptionalText } from '../utils/string'
9
- import { getFirecrawlClient } from './firecrawl-client'
10
10
  import type { WebCitation } from './tool-contracts'
11
11
  import { toRecord, WEB_TOOL_TIMEOUT_MS } from './web-tool-shared'
12
12
 
13
+ export interface SearchWebToolContext {
14
+ firecrawl: Firecrawl
15
+ }
16
+
13
17
  class SearchWebToolError extends Schema.TaggedErrorClass<SearchWebToolError>()('@lota-sdk/core/SearchWebToolError', {
14
18
  message: Schema.String,
15
19
  cause: Schema.optional(Schema.Defect),
@@ -135,7 +139,7 @@ function buildWebCitations(results: { web?: unknown[]; news?: unknown[]; images?
135
139
 
136
140
  export const searchWebTool = {
137
141
  name: 'searchWeb',
138
- create: () =>
142
+ create: ({ firecrawl }: SearchWebToolContext) =>
139
143
  tool({
140
144
  description: 'Search the web for real-time information.',
141
145
  inputSchema: z
@@ -159,10 +163,8 @@ export const searchWebTool = {
159
163
  sources?: ('web' | 'news' | 'images')[]
160
164
  location?: string
161
165
  tbs?: string
162
- }) => {
163
- const firecrawl = getFirecrawlClient()
164
-
165
- return Effect.runPromise(
166
+ }) =>
167
+ Effect.runPromise(
166
168
  Effect.gen(function* () {
167
169
  const results = yield* Effect.tryPromise({
168
170
  try: () =>
@@ -183,7 +185,6 @@ export const searchWebTool = {
183
185
  citations: buildWebCitations(results),
184
186
  }
185
187
  }).pipe(Effect.withSpan('tool.searchWeb.execute')),
186
- )
187
- },
188
+ ),
188
189
  }),
189
- } as const satisfies ToolDefinition<void>
190
+ } as const satisfies ToolDefinition<SearchWebToolContext>
@@ -2,9 +2,9 @@ import { tool } from 'ai'
2
2
  import { Effect } from 'effect'
3
3
  import { z } from 'zod'
4
4
 
5
+ import type { ResolvedAgentConfig } from '../config/agent-defaults'
5
6
  import { isAgentName } from '../config/agent-defaults'
6
7
  import type { RecordIdRef } from '../db/record-id'
7
- import type { MaybeAwaitableService } from '../effect/awaitable-effect'
8
8
  import type { createMemoryService } from '../services/memory/memory.service'
9
9
  import type { makeThreadMessageService } from '../services/thread/thread-message.service'
10
10
 
@@ -12,12 +12,11 @@ const CONVERSATION_SEARCH_RESULT_LIMIT = 20
12
12
  const MemorySearchInputSchema = z.object({ query: z.string().min(1) }).strict()
13
13
  const ConversationSearchInputSchema = z.object({ query: z.string().min(1), type: z.enum(['user', 'agent']) }).strict()
14
14
 
15
- type MemorySearchService = MaybeAwaitableService<
16
- Pick<ReturnType<typeof createMemoryService>, 'searchAllMemoriesBatched'>
17
- >
15
+ type MemorySearchService = Pick<ReturnType<typeof createMemoryService>, 'searchAllMemoriesBatched'>
18
16
  type ConversationSearchService = Pick<ReturnType<typeof makeThreadMessageService>, 'searchMessagesEffect'>
19
17
 
20
18
  export function createMemorySearchTool(
19
+ agentConfig: ResolvedAgentConfig,
21
20
  orgIdString: string,
22
21
  memoryService: MemorySearchService,
23
22
  agentName?: string,
@@ -32,7 +31,7 @@ export function createMemorySearchTool(
32
31
  const normalizedQuery = query.trim()
33
32
  const retrieval = yield* memoryService.searchAllMemoriesBatched({
34
33
  orgId: orgIdString,
35
- agentName: isAgentName(agentName) ? agentName : undefined,
34
+ agentName: isAgentName(agentConfig, agentName) ? agentName : undefined,
36
35
  query: normalizedQuery,
37
36
  ...(typeof options?.fastMode === 'boolean' ? { fastMode: options.fastMode } : {}),
38
37
  ...(typeof options?.allowMultiScopeRerank === 'boolean'