@lota-sdk/core 0.4.9 → 0.4.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 (182) hide show
  1. package/package.json +2 -2
  2. package/src/ai/embedding-cache.ts +3 -1
  3. package/src/ai-gateway/ai-gateway.ts +164 -82
  4. package/src/ai-gateway/index.ts +16 -1
  5. package/src/config/agent-defaults.ts +4 -107
  6. package/src/config/agent-types.ts +1 -1
  7. package/src/config/background-processing.ts +1 -1
  8. package/src/config/index.ts +0 -1
  9. package/src/config/logger.ts +22 -25
  10. package/src/config/thread-defaults.ts +1 -10
  11. package/src/create-runtime.ts +145 -670
  12. package/src/db/base.service.ts +30 -38
  13. package/src/db/memory-query-builder.ts +2 -1
  14. package/src/db/memory-store.ts +29 -20
  15. package/src/db/memory.ts +188 -195
  16. package/src/db/service-normalization.ts +97 -64
  17. package/src/db/service.ts +496 -384
  18. package/src/db/startup.ts +30 -19
  19. package/src/effect/helpers.ts +30 -5
  20. package/src/effect/index.ts +7 -7
  21. package/src/effect/layers.ts +75 -72
  22. package/src/effect/services.ts +15 -11
  23. package/src/embeddings/provider.ts +65 -71
  24. package/src/index.ts +13 -12
  25. package/src/queues/autonomous-job.queue.ts +177 -143
  26. package/src/queues/context-compaction.queue.ts +41 -39
  27. package/src/queues/delayed-node-promotion.queue.ts +61 -42
  28. package/src/queues/document-processor.queue.ts +5 -3
  29. package/src/queues/index.ts +1 -0
  30. package/src/queues/memory-consolidation.queue.ts +79 -53
  31. package/src/queues/organization-learning.queue.ts +70 -33
  32. package/src/queues/plan-agent-heartbeat.queue.ts +111 -83
  33. package/src/queues/plan-scheduler.queue.ts +101 -97
  34. package/src/queues/post-chat-memory.queue.ts +56 -46
  35. package/src/queues/queue-factory.ts +146 -69
  36. package/src/queues/queues.service.ts +61 -0
  37. package/src/queues/title-generation.queue.ts +44 -44
  38. package/src/redis/connection.ts +181 -164
  39. package/src/redis/org-memory-lock.ts +24 -9
  40. package/src/redis/redis-lease-lock.ts +8 -1
  41. package/src/redis/stream-context.ts +17 -9
  42. package/src/runtime/agent-identity-overrides.ts +7 -3
  43. package/src/runtime/agent-runtime-policy.ts +10 -5
  44. package/src/runtime/agent-stream-helpers.ts +24 -15
  45. package/src/runtime/chat-run-orchestration.ts +1 -1
  46. package/src/runtime/context-compaction/context-compaction-runtime.ts +28 -32
  47. package/src/runtime/context-compaction/context-compaction.ts +131 -85
  48. package/src/runtime/domain-layer.ts +203 -0
  49. package/src/runtime/execution-plan-visibility.ts +5 -2
  50. package/src/runtime/graph-designer.ts +0 -14
  51. package/src/runtime/helper-model.ts +8 -4
  52. package/src/runtime/index.ts +1 -1
  53. package/src/runtime/indexed-repositories-policy.ts +2 -6
  54. package/src/runtime/memory/memory-block.ts +19 -9
  55. package/src/runtime/memory/memory-pipeline.ts +53 -66
  56. package/src/runtime/memory/memory-scope.ts +33 -29
  57. package/src/runtime/plugin-resolution.ts +58 -62
  58. package/src/runtime/post-turn-side-effects.ts +139 -161
  59. package/src/runtime/retrieval-adapters.ts +4 -4
  60. package/src/runtime/runtime-config.ts +3 -9
  61. package/src/runtime/runtime-extensions.ts +0 -43
  62. package/src/runtime/runtime-lifecycle.ts +124 -0
  63. package/src/runtime/runtime-services.ts +455 -0
  64. package/src/runtime/runtime-worker-registry.ts +113 -30
  65. package/src/runtime/social-chat/social-chat-agent-runner.ts +13 -8
  66. package/src/runtime/social-chat/social-chat-history.ts +24 -13
  67. package/src/runtime/social-chat/social-chat.ts +420 -369
  68. package/src/runtime/team-consultation/team-consultation-orchestrator.ts +64 -57
  69. package/src/runtime/team-consultation/team-consultation-prompts.ts +11 -6
  70. package/src/runtime/thread-chat-helpers.ts +18 -9
  71. package/src/runtime/thread-turn-context.ts +28 -74
  72. package/src/runtime/turn-lifecycle.ts +6 -14
  73. package/src/services/agent-activity.service.ts +169 -176
  74. package/src/services/agent-executor.service.ts +207 -196
  75. package/src/services/artifact.service.ts +10 -5
  76. package/src/services/attachment.service.ts +16 -48
  77. package/src/services/autonomous-job.service.ts +81 -87
  78. package/src/services/background-work.service.ts +54 -0
  79. package/src/services/chat-run-registry.service.ts +3 -1
  80. package/src/services/context-compaction.service.ts +8 -10
  81. package/src/services/document-chunk.service.ts +8 -17
  82. package/src/services/execution-plan/execution-plan-graph.ts +122 -109
  83. package/src/services/execution-plan/execution-plan-schedule.ts +1 -15
  84. package/src/services/execution-plan/execution-plan.service.ts +68 -51
  85. package/src/services/feedback-loop.service.ts +1 -1
  86. package/src/services/global-orchestrator.service.ts +49 -15
  87. package/src/services/graph-full-routing.ts +49 -37
  88. package/src/services/index.ts +1 -0
  89. package/src/services/institutional-memory.service.ts +8 -17
  90. package/src/services/learned-skill.service.ts +38 -35
  91. package/src/services/memory/memory-conversation.ts +10 -5
  92. package/src/services/memory/memory-errors.ts +27 -0
  93. package/src/services/memory/memory-org-memory.ts +14 -3
  94. package/src/services/memory/memory-preseeded.ts +10 -4
  95. package/src/services/memory/memory-utils.ts +2 -1
  96. package/src/services/memory/memory.service.ts +37 -52
  97. package/src/services/memory/rerank.service.ts +3 -11
  98. package/src/services/monitoring-window.service.ts +1 -1
  99. package/src/services/mutating-approval.service.ts +1 -1
  100. package/src/services/node-workspace.service.ts +2 -2
  101. package/src/services/notification.service.ts +16 -4
  102. package/src/services/organization-member.service.ts +1 -1
  103. package/src/services/organization.service.ts +34 -51
  104. package/src/services/ownership-dispatcher.service.ts +148 -95
  105. package/src/services/plan/plan-agent-heartbeat.service.ts +30 -16
  106. package/src/services/plan/plan-agent-query.service.ts +13 -9
  107. package/src/services/plan/plan-approval.service.ts +52 -48
  108. package/src/services/plan/plan-artifact.service.ts +2 -2
  109. package/src/services/plan/plan-builder.service.ts +2 -2
  110. package/src/services/plan/plan-checkpoint.service.ts +1 -1
  111. package/src/services/plan/plan-compiler.service.ts +1 -1
  112. package/src/services/plan/plan-completion-side-effects.ts +99 -113
  113. package/src/services/plan/plan-coordination.service.ts +1 -1
  114. package/src/services/plan/plan-cycle.service.ts +171 -202
  115. package/src/services/plan/plan-deadline.service.ts +304 -307
  116. package/src/services/plan/plan-event-delivery.service.ts +84 -72
  117. package/src/services/plan/plan-executor-context.ts +2 -0
  118. package/src/services/plan/plan-executor-graph.ts +375 -353
  119. package/src/services/plan/plan-executor-helpers.ts +60 -75
  120. package/src/services/plan/plan-executor.service.ts +494 -489
  121. package/src/services/plan/plan-run.service.ts +12 -19
  122. package/src/services/plan/plan-scheduler.service.ts +89 -82
  123. package/src/services/plan/plan-template.service.ts +1 -1
  124. package/src/services/plan/plan-transaction-events.ts +8 -5
  125. package/src/services/plan/plan-validator.service.ts +1 -1
  126. package/src/services/plan/plan-workspace.service.ts +17 -11
  127. package/src/services/plugin-executor.service.ts +26 -21
  128. package/src/services/quality-metrics.service.ts +1 -1
  129. package/src/services/queue-job.service.ts +8 -17
  130. package/src/services/recent-activity-title.service.ts +22 -10
  131. package/src/services/recent-activity.service.ts +1 -1
  132. package/src/services/skill-resolver.service.ts +1 -1
  133. package/src/services/social-chat-history.service.ts +37 -20
  134. package/src/services/system-executor.service.ts +25 -20
  135. package/src/services/thread/thread-bootstrap.ts +37 -19
  136. package/src/services/thread/thread-listing.ts +2 -1
  137. package/src/services/thread/thread-memory-block.ts +18 -5
  138. package/src/services/thread/thread-message.service.ts +30 -13
  139. package/src/services/thread/thread-title.service.ts +1 -1
  140. package/src/services/thread/thread-turn-execution.ts +87 -83
  141. package/src/services/thread/thread-turn-preparation.service.ts +65 -40
  142. package/src/services/thread/thread-turn-streaming.ts +32 -36
  143. package/src/services/thread/thread-turn.ts +43 -29
  144. package/src/services/thread/thread.service.ts +32 -8
  145. package/src/services/user.service.ts +1 -1
  146. package/src/services/write-intent-validator.service.ts +1 -1
  147. package/src/storage/attachment-storage.service.ts +7 -4
  148. package/src/storage/generated-document-storage.service.ts +1 -1
  149. package/src/system-agents/context-compaction.agent.ts +1 -1
  150. package/src/system-agents/helper-agent-options.ts +1 -1
  151. package/src/system-agents/memory-reranker.agent.ts +1 -1
  152. package/src/system-agents/memory.agent.ts +1 -1
  153. package/src/system-agents/recent-activity-title-refiner.agent.ts +9 -6
  154. package/src/system-agents/regular-chat-memory-digest.agent.ts +1 -1
  155. package/src/system-agents/skill-extractor.agent.ts +1 -1
  156. package/src/system-agents/skill-manager.agent.ts +1 -1
  157. package/src/system-agents/thread-router.agent.ts +23 -20
  158. package/src/system-agents/title-generator.agent.ts +1 -1
  159. package/src/tools/execution-plan.tool.ts +36 -20
  160. package/src/tools/fetch-webpage.tool.ts +30 -22
  161. package/src/tools/firecrawl-client.ts +1 -6
  162. package/src/tools/plan-approval.tool.ts +9 -1
  163. package/src/tools/remember-memory.tool.ts +3 -6
  164. package/src/tools/research-topic.tool.ts +12 -3
  165. package/src/tools/search-web.tool.ts +26 -18
  166. package/src/tools/search.tool.ts +4 -5
  167. package/src/tools/team-think.tool.ts +139 -121
  168. package/src/utils/async.ts +15 -6
  169. package/src/utils/errors.ts +27 -15
  170. package/src/workers/bootstrap.ts +34 -58
  171. package/src/workers/memory-consolidation.worker.ts +4 -1
  172. package/src/workers/organization-learning.worker.ts +16 -3
  173. package/src/workers/regular-chat-memory-digest.helpers.ts +3 -4
  174. package/src/workers/regular-chat-memory-digest.runner.ts +46 -29
  175. package/src/workers/skill-extraction.runner.ts +13 -15
  176. package/src/workers/worker-utils.ts +14 -8
  177. package/src/config/search.ts +0 -3
  178. package/src/effect/awaitable-effect.ts +0 -87
  179. package/src/effect/runtime-ref.ts +0 -25
  180. package/src/effect/runtime.ts +0 -31
  181. package/src/redis/runtime-connection.ts +0 -10
  182. package/src/runtime/agent-types.ts +0 -1
@@ -24,22 +24,33 @@ import { toValidationError } from '../effect/zod'
24
24
  import type { makeExecutionPlanService } from '../services/execution-plan/execution-plan.service'
25
25
  import type { makeThreadService } from '../services/thread/thread.service'
26
26
 
27
- type ExecutionPlanThreadService = Pick<
28
- ReturnType<typeof makeThreadService>,
29
- 'createThread' | 'deleteThread' | 'getThread'
27
+ type NoContextService<TService> = {
28
+ [K in keyof TService]: TService[K] extends (...args: infer TArgs) => Effect.Effect<infer A, infer E, unknown>
29
+ ? (...args: TArgs) => Effect.Effect<A, E, never>
30
+ : TService[K]
31
+ }
32
+
33
+ type ExecutionPlanThreadService = NoContextService<
34
+ Pick<ReturnType<typeof makeThreadService>, 'createThread' | 'deleteThread' | 'getThread'>
30
35
  >
31
36
 
32
- type ExecutionPlanExecutionPlanService = Pick<
33
- ReturnType<typeof makeExecutionPlanService>,
34
- | 'createPlan'
35
- | 'replacePlan'
36
- | 'resumeRun'
37
- | 'submitNodeResult'
38
- | 'listActivePlanSummaries'
39
- | 'getActivePlanToolResult'
40
- | 'getActivePlansForThread'
37
+ type ExecutionPlanExecutionPlanService = NoContextService<
38
+ Pick<
39
+ ReturnType<typeof makeExecutionPlanService>,
40
+ | 'createPlan'
41
+ | 'replacePlan'
42
+ | 'resumeRun'
43
+ | 'submitNodeResult'
44
+ | 'listActivePlanSummaries'
45
+ | 'getActivePlanToolResult'
46
+ | 'getActivePlansForThread'
47
+ >
41
48
  >
42
49
 
50
+ type ExecutionPlanToolValidationError = ReturnType<typeof toValidationError>
51
+
52
+ export type ExecutionPlanToolRunPromise = <A, E>(effect: Effect.Effect<A, E, never>) => Promise<A>
53
+
43
54
  export function createExecutionPlanTool(params: {
44
55
  orgId: RecordIdRef
45
56
  userId: RecordIdRef
@@ -47,6 +58,7 @@ export function createExecutionPlanTool(params: {
47
58
  agentId: string
48
59
  executionPlanService: ExecutionPlanExecutionPlanService
49
60
  threadService: ExecutionPlanThreadService
61
+ runPromise: ExecutionPlanToolRunPromise
50
62
  onPlanChanged?: () => void
51
63
  validateInlinePlan?: (draft: ReturnType<typeof expandAgentPlanDraft>) => void
52
64
  }) {
@@ -55,7 +67,7 @@ export function createExecutionPlanTool(params: {
55
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).',
56
68
  inputSchema: ExecutionPlanArgsSchema,
57
69
  execute: (input) =>
58
- Effect.runPromise(
70
+ params.runPromise(
59
71
  Effect.gen(function* () {
60
72
  const parsed = yield* parseExecutionPlanArgsEffect(input)
61
73
 
@@ -198,12 +210,14 @@ export function createExecutionPlanTool(params: {
198
210
  return result
199
211
  }
200
212
  }
201
- }),
213
+ }).pipe(Effect.withSpan('tool.executionPlan.execute')),
202
214
  ),
203
215
  })
204
216
  }
205
217
 
206
- function parseExecutionPlanArgsEffect(input: unknown) {
218
+ function parseExecutionPlanArgsEffect(
219
+ input: unknown,
220
+ ): Effect.Effect<ExecutionPlanArgs, ExecutionPlanToolValidationError> {
207
221
  return Effect.gen(function* () {
208
222
  const parsedArgs = ExecutionPlanArgsSchema.safeParse(input)
209
223
  if (!parsedArgs.success) {
@@ -233,7 +247,7 @@ function parseExecutionPlanArgsEffect(input: unknown) {
233
247
 
234
248
  function extractAgentPlanDraftEffect(
235
249
  input: Extract<ExecutionPlanArgs, { action: 'create' | 'create-project' | 'replace' }>,
236
- ) {
250
+ ): Effect.Effect<ReturnType<typeof expandAgentPlanDraft>, ExecutionPlanToolValidationError> {
237
251
  return Effect.gen(function* () {
238
252
  const parsedDraft = AgentPlanDraftSchema.safeParse({
239
253
  title: input.title,
@@ -251,13 +265,14 @@ function extractAgentPlanDraftEffect(
251
265
  export function createExecutionPlanQueryTool(params: {
252
266
  threadId: RecordIdRef
253
267
  executionPlanService: Pick<ExecutionPlanExecutionPlanService, 'listActivePlanSummaries' | 'getActivePlanToolResult'>
268
+ runPromise: ExecutionPlanToolRunPromise
254
269
  }) {
255
270
  return tool({
256
271
  description:
257
272
  'Query execution plans. Omit runId to list all active plans. Provide runId to load a specific plan run.',
258
273
  inputSchema: ExecutionPlanQueryArgsSchema,
259
274
  execute: (input) =>
260
- Effect.runPromise(
275
+ params.runPromise(
261
276
  Effect.gen(function* () {
262
277
  if (!input.runId) {
263
278
  return yield* params.executionPlanService.listActivePlanSummaries(params.threadId)
@@ -271,7 +286,7 @@ export function createExecutionPlanQueryTool(params: {
271
286
  includeCheckpoints: input.includeCheckpoints,
272
287
  includeValidationIssues: input.includeValidationIssues,
273
288
  })
274
- }),
289
+ }).pipe(Effect.withSpan('tool.executionPlanQuery.execute')),
275
290
  ),
276
291
  })
277
292
  }
@@ -280,6 +295,7 @@ export function createSubmitExecutionNodeResultTool(params: {
280
295
  threadId: RecordIdRef
281
296
  agentId: string
282
297
  executionPlanService: Pick<ExecutionPlanExecutionPlanService, 'submitNodeResult'>
298
+ runPromise: ExecutionPlanToolRunPromise
283
299
  onPlanChanged?: () => void
284
300
  }) {
285
301
  return tool({
@@ -287,7 +303,7 @@ export function createSubmitExecutionNodeResultTool(params: {
287
303
  'Submit the result for the currently running execution node. The executor validates outputs, artifacts, and completion checks before advancing the run.',
288
304
  inputSchema: SubmitExecutionNodeResultArgsSchema,
289
305
  execute: (input) =>
290
- Effect.runPromise(
306
+ params.runPromise(
291
307
  Effect.gen(function* () {
292
308
  const result = yield* params.executionPlanService.submitNodeResult({
293
309
  threadId: params.threadId,
@@ -296,7 +312,7 @@ export function createSubmitExecutionNodeResultTool(params: {
296
312
  })
297
313
  params.onPlanChanged?.()
298
314
  return result
299
- }),
315
+ }).pipe(Effect.withSpan('tool.submitExecutionNodeResult.execute')),
300
316
  ),
301
317
  toModelOutput: ({ output }) => {
302
318
  const result = getLatestExecutionPlanResult(output)
@@ -1,15 +1,24 @@
1
+ import type Firecrawl from '@mendable/firecrawl-js'
1
2
  import { tool } from 'ai'
2
- import { Effect } from 'effect'
3
+ import { Effect, Schema } from 'effect'
3
4
  import { z } from 'zod'
4
5
 
5
6
  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
+
17
+ class FetchWebpageToolError extends Schema.TaggedErrorClass<FetchWebpageToolError>()(
18
+ '@lota-sdk/core/FetchWebpageToolError',
19
+ { message: Schema.String, cause: Schema.optional(Schema.Defect) },
20
+ ) {}
21
+
13
22
  const FormatSchema = z.enum(['markdown', 'html', 'rawHtml', 'links', 'images', 'screenshot', 'summary'])
14
23
  const MAX_MARKDOWN_CHARS = 6_000
15
24
  const MAX_SUMMARY_CHARS = 1_200
@@ -93,7 +102,7 @@ function buildFetchCitations(url: string, document: unknown): WebCitation[] {
93
102
 
94
103
  export const fetchWebpageTool = {
95
104
  name: 'fetchWebpage',
96
- create: () =>
105
+ create: ({ firecrawl }: FetchWebpageToolContext) =>
97
106
  tool({
98
107
  description: 'Retrieve and parse a single webpage.',
99
108
  inputSchema: z
@@ -114,25 +123,24 @@ export const fetchWebpageTool = {
114
123
  formats?: z.infer<typeof FormatSchema>[]
115
124
  onlyMainContent?: boolean
116
125
  maxAge?: number
117
- }) => {
118
- const firecrawl = getFirecrawlClient()
119
-
120
- return Effect.runPromise(
126
+ }) =>
127
+ Effect.runPromise(
121
128
  Effect.gen(function* () {
122
- const result = yield* Effect.tryPromise(() =>
123
- withTimeout(
124
- firecrawl.scrape(url, {
125
- formats: formats?.length ? formats : ['markdown'],
126
- onlyMainContent: onlyMainContent ?? true,
127
- maxAge,
128
- }),
129
- WEB_TOOL_TIMEOUT_MS,
130
- 'Webpage fetch',
131
- ),
132
- )
129
+ const result = yield* Effect.tryPromise({
130
+ try: () =>
131
+ withTimeout(
132
+ firecrawl.scrape(url, {
133
+ formats: formats?.length ? formats : ['markdown'],
134
+ onlyMainContent: onlyMainContent ?? true,
135
+ maxAge,
136
+ }),
137
+ WEB_TOOL_TIMEOUT_MS,
138
+ 'Webpage fetch',
139
+ ),
140
+ catch: (cause) => new FetchWebpageToolError({ message: `Webpage fetch failed for ${url}.`, cause }),
141
+ })
133
142
  return { url, document: summarizeDocument(url, result), citations: buildFetchCitations(url, result) }
134
- }),
135
- )
136
- },
143
+ }).pipe(Effect.withSpan('tool.fetchWebpage.execute')),
144
+ ),
137
145
  }),
138
- } as const satisfies ToolDefinition<void>
146
+ } as const satisfies ToolDefinition<FetchWebpageToolContext>
@@ -1,10 +1,9 @@
1
1
  import Firecrawl from '@mendable/firecrawl-js'
2
2
  import { Context, Effect, Layer } from 'effect'
3
3
 
4
- import { getCurrentRuntime } from '../effect/runtime-ref'
5
4
  import { RuntimeConfigServiceTag } from '../effect/services'
6
5
 
7
- export class FirecrawlTag extends Context.Service<FirecrawlTag, Firecrawl>()('Firecrawl') {}
6
+ export class FirecrawlTag extends Context.Service<FirecrawlTag, Firecrawl>()('@lota-sdk/core/Firecrawl') {}
8
7
 
9
8
  export const FirecrawlLive = Layer.effect(
10
9
  FirecrawlTag,
@@ -16,7 +15,3 @@ export const FirecrawlLive = Layer.effect(
16
15
  })
17
16
  }),
18
17
  )
19
-
20
- export function getFirecrawlClient(): Firecrawl {
21
- return getCurrentRuntime().runSync(Effect.service(FirecrawlTag))
22
- }
@@ -6,7 +6,15 @@ import type { RecordIdRef } from '../db/record-id'
6
6
  import type { makeExecutionPlanService } from '../services/execution-plan/execution-plan.service'
7
7
  import { toToolPlanSummary } from '../services/plan/plan-run-data'
8
8
 
9
- type PlanApprovalExecutionPlanService = Pick<ReturnType<typeof makeExecutionPlanService>, 'approvePlan' | 'rejectPlan'>
9
+ type NoContextService<TService> = {
10
+ [K in keyof TService]: TService[K] extends (...args: infer TArgs) => Effect.Effect<infer A, infer E, unknown>
11
+ ? (...args: TArgs) => Effect.Effect<A, E, never>
12
+ : TService[K]
13
+ }
14
+
15
+ type PlanApprovalExecutionPlanService = NoContextService<
16
+ Pick<ReturnType<typeof makeExecutionPlanService>, 'approvePlan' | 'rejectPlan'>
17
+ >
10
18
 
11
19
  export function createPlanApprovalTool(params: {
12
20
  orgId: RecordIdRef
@@ -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,15 +1,24 @@
1
+ import type Firecrawl from '@mendable/firecrawl-js'
1
2
  import { tool } from 'ai'
2
- import { Effect } from 'effect'
3
+ import { Effect, Schema } from 'effect'
3
4
  import { z } from 'zod'
4
5
 
5
6
  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
+
17
+ class SearchWebToolError extends Schema.TaggedErrorClass<SearchWebToolError>()('@lota-sdk/core/SearchWebToolError', {
18
+ message: Schema.String,
19
+ cause: Schema.optional(Schema.Defect),
20
+ }) {}
21
+
13
22
  const SourceSchema = z.enum(['web', 'news', 'images'])
14
23
  const MAX_RESULTS_PER_SOURCE = 4
15
24
  const MAX_SNIPPET_CHARS = 320
@@ -130,7 +139,7 @@ function buildWebCitations(results: { web?: unknown[]; news?: unknown[]; images?
130
139
 
131
140
  export const searchWebTool = {
132
141
  name: 'searchWeb',
133
- create: () =>
142
+ create: ({ firecrawl }: SearchWebToolContext) =>
134
143
  tool({
135
144
  description: 'Search the web for real-time information.',
136
145
  inputSchema: z
@@ -154,18 +163,18 @@ export const searchWebTool = {
154
163
  sources?: ('web' | 'news' | 'images')[]
155
164
  location?: string
156
165
  tbs?: string
157
- }) => {
158
- const firecrawl = getFirecrawlClient()
159
-
160
- return Effect.runPromise(
166
+ }) =>
167
+ Effect.runPromise(
161
168
  Effect.gen(function* () {
162
- const results = yield* Effect.tryPromise(() =>
163
- withTimeout(
164
- firecrawl.search(query, { limit, sources, location, tbs }),
165
- WEB_TOOL_TIMEOUT_MS,
166
- 'Web search',
167
- ),
168
- )
169
+ const results = yield* Effect.tryPromise({
170
+ try: () =>
171
+ withTimeout(
172
+ firecrawl.search(query, { limit, sources, location, tbs }),
173
+ WEB_TOOL_TIMEOUT_MS,
174
+ 'Web search',
175
+ ),
176
+ catch: (cause) => new SearchWebToolError({ message: 'Web search request failed.', cause }),
177
+ })
169
178
  return {
170
179
  query,
171
180
  results: {
@@ -175,8 +184,7 @@ export const searchWebTool = {
175
184
  },
176
185
  citations: buildWebCitations(results),
177
186
  }
178
- }),
179
- )
180
- },
187
+ }).pipe(Effect.withSpan('tool.searchWeb.execute')),
188
+ ),
181
189
  }),
182
- } 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'