@lota-sdk/core 0.4.13 → 0.4.15
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.
- package/package.json +4 -4
- package/src/ai/embedding-cache.ts +17 -11
- package/src/ai-gateway/ai-gateway.ts +164 -94
- package/src/ai-gateway/index.ts +4 -1
- package/src/config/agent-defaults.ts +2 -2
- package/src/config/agent-types.ts +1 -1
- package/src/config/constants.ts +1 -1
- package/src/create-runtime.ts +259 -200
- package/src/db/cursor-pagination.ts +2 -9
- package/src/db/memory-store.ts +194 -175
- package/src/db/memory.ts +125 -71
- package/src/db/schema-fingerprint.ts +5 -4
- package/src/db/service-normalization.ts +4 -3
- package/src/db/service.ts +3 -2
- package/src/db/startup.ts +15 -16
- package/src/effect/errors.ts +161 -21
- package/src/effect/index.ts +0 -1
- package/src/embeddings/provider.ts +15 -7
- package/src/queues/autonomous-job.queue.ts +10 -22
- package/src/queues/delayed-node-promotion.queue.ts +8 -14
- package/src/queues/document-processor.queue.ts +13 -4
- package/src/queues/memory-consolidation.queue.ts +26 -14
- package/src/queues/plan-agent-heartbeat.queue.ts +48 -31
- package/src/queues/plan-scheduler.queue.ts +37 -15
- package/src/queues/queue-factory.ts +59 -35
- package/src/queues/standalone-worker.ts +3 -2
- package/src/redis/connection.ts +10 -3
- package/src/redis/org-memory-lock.ts +1 -1
- package/src/redis/redis-lease-lock.ts +5 -5
- package/src/redis/stream-context.ts +1 -1
- package/src/runtime/chat-message.ts +64 -1
- package/src/runtime/chat-run-orchestration.ts +33 -20
- package/src/runtime/context-compaction/context-compaction-runtime.ts +14 -7
- package/src/runtime/context-compaction/context-compaction.ts +78 -66
- package/src/runtime/domain-layer.ts +19 -13
- package/src/runtime/execution-plan.ts +7 -3
- package/src/runtime/memory/memory-block.ts +3 -9
- package/src/runtime/memory/memory-scope.ts +3 -1
- package/src/runtime/plugin-resolution.ts +2 -1
- package/src/runtime/post-turn-side-effects.ts +6 -5
- package/src/runtime/retrieval-adapters.ts +8 -20
- package/src/runtime/runtime-config.ts +3 -9
- package/src/runtime/runtime-extensions.ts +2 -4
- package/src/runtime/runtime-lifecycle.ts +56 -16
- package/src/runtime/runtime-services.ts +180 -102
- package/src/runtime/runtime-worker-registry.ts +3 -1
- package/src/runtime/social-chat/social-chat-agent-runner.ts +1 -1
- package/src/runtime/social-chat/social-chat-history.ts +21 -18
- package/src/runtime/social-chat/social-chat.ts +356 -223
- package/src/runtime/specialist-runner.ts +3 -1
- package/src/runtime/team-consultation/team-consultation-orchestrator.ts +3 -2
- package/src/runtime/thread-turn-context.ts +142 -102
- package/src/runtime/turn-lifecycle.ts +15 -46
- package/src/services/agent-activity.service.ts +1 -1
- package/src/services/agent-executor.service.ts +107 -77
- package/src/services/autonomous-job.service.ts +354 -293
- package/src/services/background-work.service.ts +3 -3
- package/src/services/context-compaction.service.ts +7 -2
- package/src/services/document-chunk.service.ts +50 -32
- package/src/services/execution-plan/execution-plan-schedule.ts +5 -3
- package/src/services/execution-plan/execution-plan.service.ts +162 -179
- package/src/services/feedback-loop.service.ts +5 -4
- package/src/services/graph-full-routing.ts +37 -36
- package/src/services/institutional-memory.service.ts +28 -30
- package/src/services/learned-skill.service.ts +107 -72
- package/src/services/memory/memory-errors.ts +4 -23
- package/src/services/memory/memory-org-memory.ts +10 -5
- package/src/services/memory/memory-rerank.ts +18 -6
- package/src/services/memory/memory.service.ts +170 -111
- package/src/services/memory/rerank.service.ts +29 -20
- package/src/services/organization-member.service.ts +1 -1
- package/src/services/organization.service.ts +69 -75
- package/src/services/ownership-dispatcher.service.ts +40 -39
- package/src/services/plan/plan-agent-heartbeat.service.ts +22 -24
- package/src/services/plan/plan-agent-query.service.ts +39 -31
- package/src/services/plan/plan-completion-side-effects.ts +13 -17
- package/src/services/plan/plan-coordination.service.ts +2 -1
- package/src/services/plan/plan-cycle.service.ts +6 -5
- package/src/services/plan/plan-deadline.service.ts +57 -54
- package/src/services/plan/plan-event-delivery.service.ts +5 -4
- package/src/services/plan/plan-executor-graph.ts +18 -15
- package/src/services/plan/plan-executor.service.ts +235 -262
- package/src/services/plan/plan-run.service.ts +169 -93
- package/src/services/plan/plan-scheduler.service.ts +192 -202
- package/src/services/plan/plan-template.service.ts +1 -1
- package/src/services/plan/plan-transaction-events.ts +1 -1
- package/src/services/plan/plan-workspace.service.ts +23 -14
- package/src/services/plugin-executor.service.ts +5 -9
- package/src/services/queue-job.service.ts +117 -59
- package/src/services/recent-activity-title.service.ts +13 -12
- package/src/services/recent-activity.service.ts +6 -1
- package/src/services/social-chat-history.service.ts +29 -25
- package/src/services/system-executor.service.ts +5 -9
- package/src/services/thread/thread-active-run.ts +2 -2
- package/src/services/thread/thread-listing.ts +61 -57
- package/src/services/thread/thread-memory-block.ts +73 -48
- package/src/services/thread/thread-message.service.ts +76 -65
- package/src/services/thread/thread-record-store.ts +8 -8
- package/src/services/thread/thread-title.service.ts +10 -4
- package/src/services/thread/thread-turn-execution.ts +43 -45
- package/src/services/thread/thread-turn-preparation.service.ts +257 -135
- package/src/services/thread/thread-turn-streaming.ts +83 -92
- package/src/services/thread/thread-turn.ts +18 -16
- package/src/services/thread/thread.service.ts +135 -100
- package/src/services/user.service.ts +45 -48
- package/src/storage/attachment-parser.ts +6 -2
- package/src/storage/attachment-storage.service.ts +5 -6
- package/src/storage/generated-document-storage.service.ts +1 -1
- package/src/system-agents/context-compaction.agent.ts +10 -9
- package/src/system-agents/delegated-agent-factory.ts +30 -6
- package/src/system-agents/memory-reranker.agent.ts +10 -9
- package/src/system-agents/memory.agent.ts +10 -9
- package/src/system-agents/recent-activity-title-refiner.agent.ts +13 -15
- package/src/system-agents/regular-chat-memory-digest.agent.ts +13 -12
- package/src/system-agents/skill-extractor.agent.ts +13 -12
- package/src/system-agents/skill-manager.agent.ts +13 -12
- package/src/system-agents/thread-router.agent.ts +11 -7
- package/src/system-agents/title-generator.agent.ts +13 -12
- package/src/tools/fetch-webpage.tool.ts +13 -13
- package/src/tools/memory-block.tool.ts +3 -1
- package/src/tools/plan-approval.tool.ts +4 -2
- package/src/tools/read-file-parts.tool.ts +10 -4
- package/src/tools/remember-memory.tool.ts +3 -1
- package/src/tools/research-topic.tool.ts +9 -5
- package/src/tools/search-web.tool.ts +16 -16
- package/src/tools/search.tool.ts +20 -5
- package/src/tools/team-think.tool.ts +61 -38
- package/src/utils/async.ts +5 -5
- package/src/utils/errors.ts +19 -18
- package/src/utils/sse-keepalive.ts +28 -25
- package/src/workers/bootstrap.ts +75 -11
- package/src/workers/memory-consolidation.worker.ts +82 -91
- package/src/workers/organization-learning.worker.ts +14 -4
- package/src/workers/regular-chat-memory-digest.runner.ts +105 -67
- package/src/workers/skill-extraction.runner.ts +97 -61
- package/src/workers/utils/repo-structure-extractor.ts +13 -8
- package/src/workers/utils/thread-message-query.ts +24 -24
- package/src/workers/worker-utils.ts +23 -4
- package/src/effect/helpers.ts +0 -123
|
@@ -5,6 +5,7 @@ import { z } from 'zod'
|
|
|
5
5
|
|
|
6
6
|
import type { ToolDefinition } from '../ai/definitions'
|
|
7
7
|
import { aiLogger } from '../config/logger'
|
|
8
|
+
import { ERROR_TAGS } from '../effect/errors'
|
|
8
9
|
import { formatUtcPromptDate, nowDate } from '../utils/date-time'
|
|
9
10
|
import { getErrorMessage } from '../utils/errors'
|
|
10
11
|
import { isRecord } from '../utils/string'
|
|
@@ -12,6 +13,7 @@ import { assertSubstantiveAgentResult } from './agent-result'
|
|
|
12
13
|
|
|
13
14
|
type AgentProviderOptions = ToolLoopAgentSettings['providerOptions']
|
|
14
15
|
type AgentModel = LanguageModel | (() => LanguageModel)
|
|
16
|
+
type AgentModelWithContext<TContext> = LanguageModel | ((context: TContext) => LanguageModel)
|
|
15
17
|
|
|
16
18
|
interface DelegatedAgentDefinition {
|
|
17
19
|
id: string
|
|
@@ -24,13 +26,26 @@ interface DelegatedAgentDefinition {
|
|
|
24
26
|
maxSteps?: number
|
|
25
27
|
maxOutputTokens?: number
|
|
26
28
|
temperature?: number
|
|
29
|
+
runPromise: <A, E>(effect: Effect.Effect<A, E, never>, options?: { signal?: AbortSignal }) => Promise<A>
|
|
27
30
|
}
|
|
28
31
|
|
|
29
|
-
|
|
32
|
+
type DelegatedAgentRunPromise = <A, E>(
|
|
33
|
+
effect: Effect.Effect<A, E, never>,
|
|
34
|
+
options?: { signal?: AbortSignal },
|
|
35
|
+
) => Promise<A>
|
|
36
|
+
|
|
37
|
+
interface DelegatedAgentDefinitionWithContext<TContext> extends Omit<
|
|
38
|
+
DelegatedAgentDefinition,
|
|
39
|
+
'tools' | 'model' | 'runPromise'
|
|
40
|
+
> {
|
|
41
|
+
model: AgentModelWithContext<TContext>
|
|
30
42
|
createTools: (context: TContext) => ToolSet
|
|
43
|
+
/** Pull runPromise off the caller's context so each tool invocation carries
|
|
44
|
+
* its own runtime binding rather than closing over a boot-time one. */
|
|
45
|
+
getRunPromise: (context: TContext) => DelegatedAgentRunPromise
|
|
31
46
|
}
|
|
32
47
|
|
|
33
|
-
class DelegatedAgentError extends Schema.TaggedErrorClass<DelegatedAgentError>()(
|
|
48
|
+
class DelegatedAgentError extends Schema.TaggedErrorClass<DelegatedAgentError>()(ERROR_TAGS.DelegatedAgentError, {
|
|
34
49
|
stage: Schema.Literals(['generate', 'validate', 'follow-up-generate', 'follow-up-validate']),
|
|
35
50
|
label: Schema.String,
|
|
36
51
|
message: Schema.String,
|
|
@@ -49,6 +64,13 @@ function resolveAgentModel(model: AgentModel): LanguageModel {
|
|
|
49
64
|
return typeof model === 'function' ? model() : model
|
|
50
65
|
}
|
|
51
66
|
|
|
67
|
+
function resolveAgentModelWithContext<TContext>(
|
|
68
|
+
model: AgentModelWithContext<TContext>,
|
|
69
|
+
context: TContext,
|
|
70
|
+
): LanguageModel {
|
|
71
|
+
return typeof model === 'function' ? (model as (ctx: TContext) => LanguageModel)(context) : model
|
|
72
|
+
}
|
|
73
|
+
|
|
52
74
|
function buildCurrentDateContext(now = nowDate()): string {
|
|
53
75
|
return [`Today is ${formatUtcPromptDate(now)}.`, 'Use this exact date for any recency reasoning.'].join(' ')
|
|
54
76
|
}
|
|
@@ -229,7 +251,7 @@ export function createDelegatedAgentTool(definition: DelegatedAgentDefinition):
|
|
|
229
251
|
description: definition.description,
|
|
230
252
|
inputSchema: z.object({ task: z.string().min(1) }),
|
|
231
253
|
execute: ({ task }: { task: string }, { abortSignal }) =>
|
|
232
|
-
|
|
254
|
+
definition.runPromise(
|
|
233
255
|
Effect.gen(function* () {
|
|
234
256
|
const agentTools = definition.tools
|
|
235
257
|
const createAgent = () =>
|
|
@@ -268,6 +290,7 @@ export function createDelegatedAgentTool(definition: DelegatedAgentDefinition):
|
|
|
268
290
|
}),
|
|
269
291
|
}
|
|
270
292
|
}),
|
|
293
|
+
abortSignal ? { signal: abortSignal } : undefined,
|
|
271
294
|
),
|
|
272
295
|
}),
|
|
273
296
|
} as const satisfies ToolDefinition<void>
|
|
@@ -286,13 +309,13 @@ export function createDelegatedAgentToolWithContext<TContext>(
|
|
|
286
309
|
description: definition.description,
|
|
287
310
|
inputSchema: z.object({ task: z.string().min(1) }),
|
|
288
311
|
execute: ({ task }: { task: string }, { abortSignal }) =>
|
|
289
|
-
|
|
312
|
+
definition.getRunPromise(context)(
|
|
290
313
|
Effect.gen(function* () {
|
|
291
314
|
const agentTools = definition.createTools(context)
|
|
292
315
|
const createAgent = () =>
|
|
293
316
|
new ToolLoopAgent({
|
|
294
317
|
id: definition.id,
|
|
295
|
-
model:
|
|
318
|
+
model: resolveAgentModelWithContext(definition.model, context),
|
|
296
319
|
...(definition.providerOptions ? { providerOptions: definition.providerOptions } : {}),
|
|
297
320
|
...(definition.headers ? { headers: definition.headers } : {}),
|
|
298
321
|
instructions: buildDelegatedAgentInstructions(definition.instructions, agentTools),
|
|
@@ -304,7 +327,7 @@ export function createDelegatedAgentToolWithContext<TContext>(
|
|
|
304
327
|
})
|
|
305
328
|
const synthesize = (prompt: string, abortSignal?: AbortSignal) =>
|
|
306
329
|
generateText({
|
|
307
|
-
model:
|
|
330
|
+
model: resolveAgentModelWithContext(definition.model, context),
|
|
308
331
|
...(definition.providerOptions ? { providerOptions: definition.providerOptions } : {}),
|
|
309
332
|
...(definition.headers ? { headers: definition.headers } : {}),
|
|
310
333
|
system: `${definition.instructions.trim()}\n\nReturn a complete final markdown answer using only the provided research data. Do not call tools.`,
|
|
@@ -325,6 +348,7 @@ export function createDelegatedAgentToolWithContext<TContext>(
|
|
|
325
348
|
}),
|
|
326
349
|
}
|
|
327
350
|
}),
|
|
351
|
+
abortSignal ? { signal: abortSignal } : undefined,
|
|
328
352
|
),
|
|
329
353
|
}),
|
|
330
354
|
} as const satisfies ToolDefinition<TContext>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { CreateHelperToolLoopAgentOptions } from '@lota-sdk/shared'
|
|
2
2
|
import { ToolLoopAgent } from 'ai'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import type { AiGatewayModels } from '../ai-gateway/ai-gateway'
|
|
5
5
|
import { buildAiGatewayDirectCacheHeaders } from '../ai-gateway/cache-headers'
|
|
6
6
|
import {
|
|
7
7
|
OPENROUTER_LOW_REASONING_PROVIDER_OPTIONS,
|
|
@@ -29,12 +29,13 @@ Set every item.relevance as a string; use empty string when no reason is needed.
|
|
|
29
29
|
</output>
|
|
30
30
|
</agent-instructions>`
|
|
31
31
|
|
|
32
|
-
export function
|
|
33
|
-
return
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
export function makeMemoryRerankerAgentFactory(models: AiGatewayModels) {
|
|
33
|
+
return (options: CreateHelperToolLoopAgentOptions) =>
|
|
34
|
+
new ToolLoopAgent({
|
|
35
|
+
id: 'memory-reranker',
|
|
36
|
+
model: models.chatModel(OPENROUTER_STRUCTURED_HELPER_MODEL_ID),
|
|
37
|
+
headers: buildAiGatewayDirectCacheHeaders('lota-sdk'),
|
|
38
|
+
providerOptions: OPENROUTER_LOW_REASONING_PROVIDER_OPTIONS,
|
|
39
|
+
...resolveHelperAgentOptions(options),
|
|
40
|
+
})
|
|
40
41
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { CreateHelperToolLoopAgentOptions } from '@lota-sdk/shared'
|
|
2
2
|
import { ToolLoopAgent } from 'ai'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import type { AiGatewayModels } from '../ai-gateway/ai-gateway'
|
|
5
5
|
import { buildAiGatewayDirectCacheHeaders } from '../ai-gateway/cache-headers'
|
|
6
6
|
import {
|
|
7
7
|
OPENROUTER_STRUCTURED_HELPER_MODEL_ID,
|
|
@@ -49,12 +49,13 @@ Return only the schema fields with no extra formatting.
|
|
|
49
49
|
</format>
|
|
50
50
|
</agent-instructions>`
|
|
51
51
|
|
|
52
|
-
export function
|
|
53
|
-
return
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
52
|
+
export function makeOrgMemoryAgentFactory(models: AiGatewayModels) {
|
|
53
|
+
return (options: CreateHelperToolLoopAgentOptions) =>
|
|
54
|
+
new ToolLoopAgent({
|
|
55
|
+
id: 'org-memory',
|
|
56
|
+
model: models.chatModel(OPENROUTER_STRUCTURED_HELPER_MODEL_ID),
|
|
57
|
+
headers: buildAiGatewayDirectCacheHeaders('lota-sdk'),
|
|
58
|
+
providerOptions: OPENROUTER_HIGH_REASONING_PROVIDER_OPTIONS,
|
|
59
|
+
...resolveHelperAgentOptions(options),
|
|
60
|
+
})
|
|
60
61
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { CreateHelperToolLoopAgentOptions } from '@lota-sdk/shared'
|
|
2
2
|
import { ToolLoopAgent } from 'ai'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import type { AiGatewayModels } from '../ai-gateway/ai-gateway'
|
|
5
5
|
import { buildAiGatewayDirectCacheHeaders } from '../ai-gateway/cache-headers'
|
|
6
6
|
import type { ResolvedAgentConfig } from '../config/agent-defaults'
|
|
7
7
|
import {
|
|
@@ -76,18 +76,16 @@ Return only the title text. No quotes, labels, JSON, markdown, or explanation.
|
|
|
76
76
|
</output>
|
|
77
77
|
</agent-instructions>`
|
|
78
78
|
|
|
79
|
-
export function
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}),
|
|
92
|
-
})
|
|
79
|
+
export function makeRecentActivityTitleRefinerAgentFactory(models: AiGatewayModels, agentConfig: ResolvedAgentConfig) {
|
|
80
|
+
return (options: CreateHelperToolLoopAgentOptions) =>
|
|
81
|
+
new ToolLoopAgent({
|
|
82
|
+
id: 'recent-activity-title-refiner',
|
|
83
|
+
model: models.chatModel(OPENROUTER_STRUCTURED_HELPER_MODEL_ID),
|
|
84
|
+
headers: buildAiGatewayDirectCacheHeaders('lota-sdk'),
|
|
85
|
+
providerOptions: OPENROUTER_HIGH_REASONING_PROVIDER_OPTIONS,
|
|
86
|
+
...resolveHelperAgentOptions(options, {
|
|
87
|
+
instructions: buildRecentActivityTitleRefinerPrompt(agentConfig),
|
|
88
|
+
maxOutputTokens: RECENT_ACTIVITY_TITLE_MAX_TOKENS,
|
|
89
|
+
}),
|
|
90
|
+
})
|
|
93
91
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { CreateHelperToolLoopAgentOptions } from '@lota-sdk/shared'
|
|
2
2
|
import { ToolLoopAgent } from 'ai'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import type { AiGatewayModels } from '../ai-gateway/ai-gateway'
|
|
5
5
|
import { buildAiGatewayDirectCacheHeaders } from '../ai-gateway/cache-headers'
|
|
6
6
|
import {
|
|
7
7
|
OPENROUTER_STRUCTURED_HELPER_MODEL_ID,
|
|
@@ -24,15 +24,16 @@ Synthesize an updated workspace profile summary and durable memory facts from co
|
|
|
24
24
|
</rules>
|
|
25
25
|
</agent-instructions>`
|
|
26
26
|
|
|
27
|
-
export function
|
|
28
|
-
return
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
27
|
+
export function makeRegularChatMemoryDigestAgentFactory(models: AiGatewayModels) {
|
|
28
|
+
return (options: CreateHelperToolLoopAgentOptions) =>
|
|
29
|
+
new ToolLoopAgent({
|
|
30
|
+
id: 'regular-chat-memory-digest',
|
|
31
|
+
model: models.chatModel(OPENROUTER_STRUCTURED_HELPER_MODEL_ID),
|
|
32
|
+
headers: buildAiGatewayDirectCacheHeaders('lota-sdk'),
|
|
33
|
+
providerOptions: OPENROUTER_HIGH_REASONING_PROVIDER_OPTIONS,
|
|
34
|
+
...resolveHelperAgentOptions(options, {
|
|
35
|
+
instructions: regularChatMemoryDigestPrompt,
|
|
36
|
+
maxOutputTokens: REGULAR_CHAT_MEMORY_DIGEST_MAX_TOKENS,
|
|
37
|
+
}),
|
|
38
|
+
})
|
|
38
39
|
}
|
|
@@ -2,7 +2,7 @@ import type { CreateHelperToolLoopAgentOptions } from '@lota-sdk/shared'
|
|
|
2
2
|
import { ToolLoopAgent } from 'ai'
|
|
3
3
|
import { z } from 'zod'
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import type { AiGatewayModels } from '../ai-gateway/ai-gateway'
|
|
6
6
|
import { buildAiGatewayDirectCacheHeaders } from '../ai-gateway/cache-headers'
|
|
7
7
|
import {
|
|
8
8
|
OPENROUTER_STRUCTURED_HELPER_MODEL_ID,
|
|
@@ -42,15 +42,16 @@ export const SkillExtractionOutputSchema = z.object({ candidates: z.array(SkillC
|
|
|
42
42
|
|
|
43
43
|
export type SkillCandidate = z.infer<typeof SkillCandidateSchema>
|
|
44
44
|
|
|
45
|
-
export function
|
|
46
|
-
return
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
45
|
+
export function makeSkillExtractorAgentFactory(models: AiGatewayModels) {
|
|
46
|
+
return (options: CreateHelperToolLoopAgentOptions) =>
|
|
47
|
+
new ToolLoopAgent({
|
|
48
|
+
id: 'skill-extractor',
|
|
49
|
+
model: models.chatModel(OPENROUTER_STRUCTURED_HELPER_MODEL_ID),
|
|
50
|
+
headers: buildAiGatewayDirectCacheHeaders('lota-sdk'),
|
|
51
|
+
providerOptions: OPENROUTER_HIGH_REASONING_PROVIDER_OPTIONS,
|
|
52
|
+
...resolveHelperAgentOptions(options, {
|
|
53
|
+
instructions: skillExtractorPrompt,
|
|
54
|
+
maxOutputTokens: SKILL_EXTRACTOR_MAX_TOKENS,
|
|
55
|
+
}),
|
|
56
|
+
})
|
|
56
57
|
}
|
|
@@ -2,7 +2,7 @@ import type { CreateHelperToolLoopAgentOptions } from '@lota-sdk/shared'
|
|
|
2
2
|
import { ToolLoopAgent } from 'ai'
|
|
3
3
|
import { z } from 'zod'
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import type { AiGatewayModels } from '../ai-gateway/ai-gateway'
|
|
6
6
|
import { buildAiGatewayDirectCacheHeaders } from '../ai-gateway/cache-headers'
|
|
7
7
|
import {
|
|
8
8
|
OPENROUTER_STRUCTURED_HELPER_MODEL_ID,
|
|
@@ -66,15 +66,16 @@ export const SkillManagerOutputSchema = z.object({
|
|
|
66
66
|
mergedSkill: MergedSkillSchema.optional(),
|
|
67
67
|
})
|
|
68
68
|
|
|
69
|
-
export function
|
|
70
|
-
return
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
69
|
+
export function makeSkillManagerAgentFactory(models: AiGatewayModels) {
|
|
70
|
+
return (options: CreateHelperToolLoopAgentOptions) =>
|
|
71
|
+
new ToolLoopAgent({
|
|
72
|
+
id: 'skill-manager',
|
|
73
|
+
model: models.chatModel(OPENROUTER_STRUCTURED_HELPER_MODEL_ID),
|
|
74
|
+
headers: buildAiGatewayDirectCacheHeaders('lota-sdk'),
|
|
75
|
+
providerOptions: OPENROUTER_HIGH_REASONING_PROVIDER_OPTIONS,
|
|
76
|
+
...resolveHelperAgentOptions(options, {
|
|
77
|
+
instructions: skillManagerPrompt,
|
|
78
|
+
maxOutputTokens: SKILL_MANAGER_MAX_TOKENS,
|
|
79
|
+
}),
|
|
80
|
+
})
|
|
80
81
|
}
|
|
@@ -2,12 +2,12 @@ import { generateObject } from 'ai'
|
|
|
2
2
|
import { Effect } from 'effect'
|
|
3
3
|
import { z } from 'zod'
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import type { AiGatewayModels } from '../ai-gateway/ai-gateway'
|
|
6
6
|
import { buildAiGatewayDirectCacheHeaders } from '../ai-gateway/cache-headers'
|
|
7
7
|
import type { ResolvedAgentConfig } from '../config/agent-defaults'
|
|
8
8
|
import { chatLogger } from '../config/logger'
|
|
9
9
|
import type { ValidationError } from '../effect/errors'
|
|
10
|
-
import { AiGenerationError } from '../effect/errors'
|
|
10
|
+
import { ERROR_TAGS, AiGenerationError } from '../effect/errors'
|
|
11
11
|
import { zodParse } from '../effect/zod'
|
|
12
12
|
|
|
13
13
|
const TriageResultSchema = z.object({ agentId: z.string(), routingContext: z.string() })
|
|
@@ -170,19 +170,19 @@ function toRouterGenerationError(label: 'triage' | 'check', error: unknown): AiG
|
|
|
170
170
|
|
|
171
171
|
function generateRouterObjectEffect<TSchema extends z.ZodTypeAny>(params: {
|
|
172
172
|
agentConfig: ResolvedAgentConfig
|
|
173
|
+
aiGatewayModels: AiGatewayModels
|
|
173
174
|
schema: TSchema
|
|
174
175
|
system: string
|
|
175
176
|
prompt: string
|
|
176
177
|
label: 'triage' | 'check'
|
|
177
178
|
}): Effect.Effect<z.infer<TSchema> | null, never> {
|
|
178
|
-
const modelId = params.agentConfig.routerModelId ?? '
|
|
179
|
+
const modelId = params.agentConfig.routerModelId ?? 'gpt-5.4-nano'
|
|
179
180
|
|
|
180
181
|
return Effect.tryPromise({
|
|
181
182
|
try: () =>
|
|
182
183
|
generateObject({
|
|
183
|
-
model:
|
|
184
|
+
model: params.aiGatewayModels.chatModel(modelId),
|
|
184
185
|
headers: buildAiGatewayDirectCacheHeaders('lota-sdk'),
|
|
185
|
-
providerOptions: { openai: { reasoningEffort: 'low' } },
|
|
186
186
|
schema: params.schema,
|
|
187
187
|
system: params.system,
|
|
188
188
|
prompt: params.prompt,
|
|
@@ -201,12 +201,12 @@ function generateRouterObjectEffect<TSchema extends z.ZodTypeAny>(params: {
|
|
|
201
201
|
),
|
|
202
202
|
Effect.flatMap(({ object }) => zodParse(params.schema, object)),
|
|
203
203
|
Effect.catchTags({
|
|
204
|
-
AiGenerationError: (error: AiGenerationError) =>
|
|
204
|
+
[ERROR_TAGS.AiGenerationError]: (error: AiGenerationError) =>
|
|
205
205
|
Effect.sync(() => {
|
|
206
206
|
chatLogger.error`[thread-router] ${params.label} failed: ${error.message}`
|
|
207
207
|
return null
|
|
208
208
|
}),
|
|
209
|
-
ValidationError: (error: ValidationError) =>
|
|
209
|
+
[ERROR_TAGS.ValidationError]: (error: ValidationError) =>
|
|
210
210
|
Effect.sync(() => {
|
|
211
211
|
chatLogger.error`[thread-router] ${params.label} failed: ${error.message}`
|
|
212
212
|
return null
|
|
@@ -217,6 +217,7 @@ function generateRouterObjectEffect<TSchema extends z.ZodTypeAny>(params: {
|
|
|
217
217
|
|
|
218
218
|
export function triageThreadMessage(params: {
|
|
219
219
|
agentConfig: ResolvedAgentConfig
|
|
220
|
+
aiGatewayModels: AiGatewayModels
|
|
220
221
|
threadTitle: string
|
|
221
222
|
members: readonly string[]
|
|
222
223
|
messageText: string
|
|
@@ -254,6 +255,7 @@ export function triageThreadMessage(params: {
|
|
|
254
255
|
|
|
255
256
|
const parsed = yield* generateRouterObjectEffect({
|
|
256
257
|
agentConfig: params.agentConfig,
|
|
258
|
+
aiGatewayModels: params.aiGatewayModels,
|
|
257
259
|
schema: TriageResultSchema,
|
|
258
260
|
system: TRIAGE_SYSTEM_PROMPT,
|
|
259
261
|
prompt,
|
|
@@ -280,6 +282,7 @@ export function triageThreadMessage(params: {
|
|
|
280
282
|
|
|
281
283
|
export function checkForNextAgent(params: {
|
|
282
284
|
agentConfig: ResolvedAgentConfig
|
|
285
|
+
aiGatewayModels: AiGatewayModels
|
|
283
286
|
threadTitle: string
|
|
284
287
|
members: readonly string[]
|
|
285
288
|
messageText: string
|
|
@@ -323,6 +326,7 @@ export function checkForNextAgent(params: {
|
|
|
323
326
|
|
|
324
327
|
const parsed = yield* generateRouterObjectEffect({
|
|
325
328
|
agentConfig: params.agentConfig,
|
|
329
|
+
aiGatewayModels: params.aiGatewayModels,
|
|
326
330
|
schema: CheckResultObjectSchema,
|
|
327
331
|
system: CHECK_SYSTEM_PROMPT,
|
|
328
332
|
prompt,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { CreateHelperToolLoopAgentOptions } from '@lota-sdk/shared'
|
|
2
2
|
import { ToolLoopAgent } from 'ai'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import type { AiGatewayModels } from '../ai-gateway/ai-gateway'
|
|
5
5
|
import { buildAiGatewayDirectCacheHeaders } from '../ai-gateway/cache-headers'
|
|
6
6
|
import {
|
|
7
7
|
OPENROUTER_FAST_REASONING_MODEL_ID,
|
|
@@ -30,15 +30,16 @@ Return only the title text. No quotes, no labels, no explanation.
|
|
|
30
30
|
</output-format>
|
|
31
31
|
</agent-instructions>`
|
|
32
32
|
|
|
33
|
-
export function
|
|
34
|
-
return
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
33
|
+
export function makeThreadTitleGeneratorAgentFactory(models: AiGatewayModels) {
|
|
34
|
+
return (options: CreateHelperToolLoopAgentOptions) =>
|
|
35
|
+
new ToolLoopAgent({
|
|
36
|
+
id: 'thread-title-generator',
|
|
37
|
+
model: models.chatModel(OPENROUTER_FAST_REASONING_MODEL_ID),
|
|
38
|
+
headers: buildAiGatewayDirectCacheHeaders('lota-sdk'),
|
|
39
|
+
providerOptions: OPENROUTER_MINIMAL_REASONING_PROVIDER_OPTIONS,
|
|
40
|
+
...resolveHelperAgentOptions(options, {
|
|
41
|
+
instructions: THREAD_TITLE_GENERATOR_PROMPT,
|
|
42
|
+
maxOutputTokens: THREAD_TITLE_MAX_TOKENS,
|
|
43
|
+
}),
|
|
44
|
+
})
|
|
44
45
|
}
|
|
@@ -12,6 +12,7 @@ import { toRecord, WEB_TOOL_TIMEOUT_MS } from './web-tool-shared'
|
|
|
12
12
|
|
|
13
13
|
export interface FetchWebpageToolContext {
|
|
14
14
|
firecrawl: Firecrawl
|
|
15
|
+
runPromise: <A, E>(effect: Effect.Effect<A, E, never>, options?: { signal?: AbortSignal }) => Promise<A>
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
class FetchWebpageToolError extends Schema.TaggedErrorClass<FetchWebpageToolError>()(
|
|
@@ -102,7 +103,7 @@ function buildFetchCitations(url: string, document: unknown): WebCitation[] {
|
|
|
102
103
|
|
|
103
104
|
export const fetchWebpageTool = {
|
|
104
105
|
name: 'fetchWebpage',
|
|
105
|
-
create: ({ firecrawl }: FetchWebpageToolContext) =>
|
|
106
|
+
create: ({ firecrawl, runPromise }: FetchWebpageToolContext) =>
|
|
106
107
|
tool({
|
|
107
108
|
description: 'Retrieve and parse a single webpage.',
|
|
108
109
|
inputSchema: z
|
|
@@ -113,18 +114,16 @@ export const fetchWebpageTool = {
|
|
|
113
114
|
maxAge: z.number().int().min(1).optional(),
|
|
114
115
|
})
|
|
115
116
|
.strict(),
|
|
116
|
-
execute: (
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
url: string
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}) =>
|
|
127
|
-
Effect.runPromise(
|
|
117
|
+
execute: (
|
|
118
|
+
{
|
|
119
|
+
url,
|
|
120
|
+
formats,
|
|
121
|
+
onlyMainContent,
|
|
122
|
+
maxAge,
|
|
123
|
+
}: { url: string; formats?: z.infer<typeof FormatSchema>[]; onlyMainContent?: boolean; maxAge?: number },
|
|
124
|
+
{ abortSignal }: { abortSignal?: AbortSignal } = {},
|
|
125
|
+
) =>
|
|
126
|
+
runPromise(
|
|
128
127
|
Effect.gen(function* () {
|
|
129
128
|
const result = yield* Effect.tryPromise({
|
|
130
129
|
try: () =>
|
|
@@ -141,6 +140,7 @@ export const fetchWebpageTool = {
|
|
|
141
140
|
})
|
|
142
141
|
return { url, document: summarizeDocument(url, result), citations: buildFetchCitations(url, result) }
|
|
143
142
|
}).pipe(Effect.withSpan('tool.fetchWebpage.execute')),
|
|
143
|
+
abortSignal ? { signal: abortSignal } : undefined,
|
|
144
144
|
),
|
|
145
145
|
}),
|
|
146
146
|
} as const satisfies ToolDefinition<FetchWebpageToolContext>
|
|
@@ -18,12 +18,14 @@ export function createMemoryBlockTool({
|
|
|
18
18
|
threadId,
|
|
19
19
|
agentLabel,
|
|
20
20
|
threadService,
|
|
21
|
+
runPromise,
|
|
21
22
|
getCurrentBlock,
|
|
22
23
|
onAppend,
|
|
23
24
|
}: {
|
|
24
25
|
threadId: RecordIdRef
|
|
25
26
|
agentLabel: string
|
|
26
27
|
threadService: MemoryBlockThreadService
|
|
28
|
+
runPromise: <A, E>(effect: Effect.Effect<A, E, never>) => Promise<A>
|
|
27
29
|
getCurrentBlock?: () => string
|
|
28
30
|
onAppend?: (value: string) => void
|
|
29
31
|
}) {
|
|
@@ -48,7 +50,7 @@ export function createMemoryBlockTool({
|
|
|
48
50
|
|
|
49
51
|
void safeEnqueue(
|
|
50
52
|
() =>
|
|
51
|
-
|
|
53
|
+
runPromise(
|
|
52
54
|
Effect.gen(function* () {
|
|
53
55
|
const updated = yield* threadService.appendMemoryBlock(threadId, prepared.formatted)
|
|
54
56
|
onAppend?.(updated)
|
|
@@ -21,14 +21,15 @@ export function createPlanApprovalTool(params: {
|
|
|
21
21
|
threadId: RecordIdRef
|
|
22
22
|
actorId: string
|
|
23
23
|
executionPlanService: PlanApprovalExecutionPlanService
|
|
24
|
+
runPromise: <A, E>(effect: Effect.Effect<A, E, never>, options?: { signal?: AbortSignal }) => Promise<A>
|
|
24
25
|
}) {
|
|
25
26
|
return tool({
|
|
26
27
|
description:
|
|
27
28
|
'Approve, reject, or request changes to a plan that is pending approval. Use approve to start execution, reject to abort it, or modify to request a revised plan.',
|
|
28
29
|
inputSchema: PlanApprovalArgsSchema,
|
|
29
30
|
outputSchema: PlanApprovalToolResultDataSchema,
|
|
30
|
-
execute: (input) =>
|
|
31
|
-
|
|
31
|
+
execute: (input, { abortSignal }: { abortSignal?: AbortSignal } = {}) =>
|
|
32
|
+
params.runPromise(
|
|
32
33
|
Effect.gen(function* () {
|
|
33
34
|
switch (input.action) {
|
|
34
35
|
case 'approve': {
|
|
@@ -71,6 +72,7 @@ export function createPlanApprovalTool(params: {
|
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
74
|
}),
|
|
75
|
+
abortSignal ? { signal: abortSignal } : undefined,
|
|
74
76
|
),
|
|
75
77
|
})
|
|
76
78
|
}
|
|
@@ -3,6 +3,7 @@ import { Schema, Effect } from 'effect'
|
|
|
3
3
|
import { z } from 'zod'
|
|
4
4
|
|
|
5
5
|
import type { ToolDefinition } from '../ai/definitions'
|
|
6
|
+
import { ERROR_TAGS } from '../effect/errors'
|
|
6
7
|
import type { makeAttachmentService } from '../services/attachment.service'
|
|
7
8
|
import type { ReadableUploadMetadata } from '../storage/attachment-types'
|
|
8
9
|
|
|
@@ -15,6 +16,7 @@ export interface ReadFilePartsToolContext {
|
|
|
15
16
|
userId: string
|
|
16
17
|
uploads: ReadableUploadMetadata[]
|
|
17
18
|
attachmentService: ReadFilePartsAttachmentService
|
|
19
|
+
runPromise: <A, E>(effect: Effect.Effect<A, E, never>, options?: { signal?: AbortSignal }) => Promise<A>
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
function toUploadSummary(upload: ReadableUploadMetadata) {
|
|
@@ -26,7 +28,7 @@ function toUploadSummary(upload: ReadableUploadMetadata) {
|
|
|
26
28
|
}
|
|
27
29
|
}
|
|
28
30
|
|
|
29
|
-
class ReadFilePartsError extends Schema.TaggedErrorClass<ReadFilePartsError>()(
|
|
31
|
+
class ReadFilePartsError extends Schema.TaggedErrorClass<ReadFilePartsError>()(ERROR_TAGS.ReadFilePartsError, {
|
|
30
32
|
message: Schema.String,
|
|
31
33
|
}) {}
|
|
32
34
|
|
|
@@ -47,15 +49,18 @@ function resolveUploadTargetEffect(params: {
|
|
|
47
49
|
|
|
48
50
|
export const readFilePartsTool = {
|
|
49
51
|
name: 'readFileParts',
|
|
50
|
-
create: ({ orgId, userId, uploads, attachmentService }: ReadFilePartsToolContext) =>
|
|
52
|
+
create: ({ orgId, userId, uploads, attachmentService, runPromise }: ReadFilePartsToolContext) =>
|
|
51
53
|
tool({
|
|
52
54
|
description:
|
|
53
55
|
'Read uploaded file content by part. Call with no args to list uploads metadata, then call with storageKey and part (25 pages per part).',
|
|
54
56
|
inputSchema: z
|
|
55
57
|
.object({ storageKey: z.string().trim().min(1).optional(), part: z.number().int().positive().default(1) })
|
|
56
58
|
.strict(),
|
|
57
|
-
execute: (
|
|
58
|
-
|
|
59
|
+
execute: (
|
|
60
|
+
{ storageKey, part }: { storageKey?: string; part?: number },
|
|
61
|
+
{ abortSignal }: { abortSignal?: AbortSignal } = {},
|
|
62
|
+
) =>
|
|
63
|
+
runPromise(
|
|
59
64
|
Effect.gen(function* () {
|
|
60
65
|
const availableUploads = uploads.map(toUploadSummary)
|
|
61
66
|
const selected = yield* resolveUploadTargetEffect({ uploads, storageKey })
|
|
@@ -86,6 +91,7 @@ export const readFilePartsTool = {
|
|
|
86
91
|
|
|
87
92
|
return { availableUploads, selectedUpload: toUploadSummary(selected), ...parts }
|
|
88
93
|
}),
|
|
94
|
+
abortSignal ? { signal: abortSignal } : undefined,
|
|
89
95
|
),
|
|
90
96
|
}),
|
|
91
97
|
} as const satisfies ToolDefinition<ReadFilePartsToolContext>
|
|
@@ -24,10 +24,12 @@ export function createRememberMemoryTool({
|
|
|
24
24
|
orgId,
|
|
25
25
|
agentName,
|
|
26
26
|
memoryService,
|
|
27
|
+
runPromise,
|
|
27
28
|
}: {
|
|
28
29
|
orgId: RecordIdRef
|
|
29
30
|
agentName: string
|
|
30
31
|
memoryService: RememberMemoryService
|
|
32
|
+
runPromise: <A, E>(effect: Effect.Effect<A, E, never>) => Promise<A>
|
|
31
33
|
}) {
|
|
32
34
|
return tool({
|
|
33
35
|
description:
|
|
@@ -42,7 +44,7 @@ export function createRememberMemoryTool({
|
|
|
42
44
|
const orgIdString = recordIdToString(orgId, TABLES.ORGANIZATION)
|
|
43
45
|
void safeEnqueue(
|
|
44
46
|
() =>
|
|
45
|
-
|
|
47
|
+
runPromise(
|
|
46
48
|
Effect.gen(function* () {
|
|
47
49
|
const assessment = yield* memoryService.assessMemoryCandidate({ orgId: orgIdString, content: trimmed })
|
|
48
50
|
if (!assessment) {
|