@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.
- package/package.json +2 -2
- package/src/ai/embedding-cache.ts +3 -1
- package/src/ai-gateway/ai-gateway.ts +164 -82
- package/src/ai-gateway/index.ts +16 -1
- package/src/config/agent-defaults.ts +4 -107
- package/src/config/agent-types.ts +1 -1
- package/src/config/background-processing.ts +1 -1
- package/src/config/index.ts +0 -1
- package/src/config/logger.ts +22 -25
- package/src/config/thread-defaults.ts +1 -10
- package/src/create-runtime.ts +145 -670
- package/src/db/base.service.ts +30 -38
- package/src/db/memory-query-builder.ts +2 -1
- package/src/db/memory-store.ts +29 -20
- package/src/db/memory.ts +188 -195
- package/src/db/service-normalization.ts +97 -64
- package/src/db/service.ts +496 -384
- package/src/db/startup.ts +30 -19
- package/src/effect/helpers.ts +30 -5
- package/src/effect/index.ts +7 -7
- package/src/effect/layers.ts +75 -72
- package/src/effect/services.ts +15 -11
- package/src/embeddings/provider.ts +65 -71
- package/src/index.ts +13 -12
- package/src/queues/autonomous-job.queue.ts +177 -143
- package/src/queues/context-compaction.queue.ts +41 -39
- package/src/queues/delayed-node-promotion.queue.ts +61 -42
- package/src/queues/document-processor.queue.ts +5 -3
- package/src/queues/index.ts +1 -0
- package/src/queues/memory-consolidation.queue.ts +79 -53
- package/src/queues/organization-learning.queue.ts +70 -33
- package/src/queues/plan-agent-heartbeat.queue.ts +111 -83
- package/src/queues/plan-scheduler.queue.ts +101 -97
- package/src/queues/post-chat-memory.queue.ts +56 -46
- package/src/queues/queue-factory.ts +146 -69
- package/src/queues/queues.service.ts +61 -0
- package/src/queues/title-generation.queue.ts +44 -44
- package/src/redis/connection.ts +181 -164
- package/src/redis/org-memory-lock.ts +24 -9
- package/src/redis/redis-lease-lock.ts +8 -1
- package/src/redis/stream-context.ts +17 -9
- package/src/runtime/agent-identity-overrides.ts +7 -3
- package/src/runtime/agent-runtime-policy.ts +10 -5
- package/src/runtime/agent-stream-helpers.ts +24 -15
- package/src/runtime/chat-run-orchestration.ts +1 -1
- package/src/runtime/context-compaction/context-compaction-runtime.ts +28 -32
- package/src/runtime/context-compaction/context-compaction.ts +131 -85
- package/src/runtime/domain-layer.ts +203 -0
- package/src/runtime/execution-plan-visibility.ts +5 -2
- package/src/runtime/graph-designer.ts +0 -14
- package/src/runtime/helper-model.ts +8 -4
- package/src/runtime/index.ts +1 -1
- package/src/runtime/indexed-repositories-policy.ts +2 -6
- package/src/runtime/memory/memory-block.ts +19 -9
- package/src/runtime/memory/memory-pipeline.ts +53 -66
- package/src/runtime/memory/memory-scope.ts +33 -29
- package/src/runtime/plugin-resolution.ts +58 -62
- package/src/runtime/post-turn-side-effects.ts +139 -161
- package/src/runtime/retrieval-adapters.ts +4 -4
- package/src/runtime/runtime-config.ts +3 -9
- package/src/runtime/runtime-extensions.ts +0 -43
- package/src/runtime/runtime-lifecycle.ts +124 -0
- package/src/runtime/runtime-services.ts +455 -0
- package/src/runtime/runtime-worker-registry.ts +113 -30
- package/src/runtime/social-chat/social-chat-agent-runner.ts +13 -8
- package/src/runtime/social-chat/social-chat-history.ts +24 -13
- package/src/runtime/social-chat/social-chat.ts +420 -369
- package/src/runtime/team-consultation/team-consultation-orchestrator.ts +64 -57
- package/src/runtime/team-consultation/team-consultation-prompts.ts +11 -6
- package/src/runtime/thread-chat-helpers.ts +18 -9
- package/src/runtime/thread-turn-context.ts +28 -74
- package/src/runtime/turn-lifecycle.ts +6 -14
- package/src/services/agent-activity.service.ts +169 -176
- package/src/services/agent-executor.service.ts +207 -196
- package/src/services/artifact.service.ts +10 -5
- package/src/services/attachment.service.ts +16 -48
- package/src/services/autonomous-job.service.ts +81 -87
- package/src/services/background-work.service.ts +54 -0
- package/src/services/chat-run-registry.service.ts +3 -1
- package/src/services/context-compaction.service.ts +8 -10
- package/src/services/document-chunk.service.ts +8 -17
- package/src/services/execution-plan/execution-plan-graph.ts +122 -109
- package/src/services/execution-plan/execution-plan-schedule.ts +1 -15
- package/src/services/execution-plan/execution-plan.service.ts +68 -51
- package/src/services/feedback-loop.service.ts +1 -1
- package/src/services/global-orchestrator.service.ts +49 -15
- package/src/services/graph-full-routing.ts +49 -37
- package/src/services/index.ts +1 -0
- package/src/services/institutional-memory.service.ts +8 -17
- package/src/services/learned-skill.service.ts +38 -35
- package/src/services/memory/memory-conversation.ts +10 -5
- package/src/services/memory/memory-errors.ts +27 -0
- package/src/services/memory/memory-org-memory.ts +14 -3
- package/src/services/memory/memory-preseeded.ts +10 -4
- package/src/services/memory/memory-utils.ts +2 -1
- package/src/services/memory/memory.service.ts +37 -52
- package/src/services/memory/rerank.service.ts +3 -11
- package/src/services/monitoring-window.service.ts +1 -1
- package/src/services/mutating-approval.service.ts +1 -1
- package/src/services/node-workspace.service.ts +2 -2
- package/src/services/notification.service.ts +16 -4
- package/src/services/organization-member.service.ts +1 -1
- package/src/services/organization.service.ts +34 -51
- package/src/services/ownership-dispatcher.service.ts +148 -95
- package/src/services/plan/plan-agent-heartbeat.service.ts +30 -16
- package/src/services/plan/plan-agent-query.service.ts +13 -9
- package/src/services/plan/plan-approval.service.ts +52 -48
- package/src/services/plan/plan-artifact.service.ts +2 -2
- package/src/services/plan/plan-builder.service.ts +2 -2
- package/src/services/plan/plan-checkpoint.service.ts +1 -1
- package/src/services/plan/plan-compiler.service.ts +1 -1
- package/src/services/plan/plan-completion-side-effects.ts +99 -113
- package/src/services/plan/plan-coordination.service.ts +1 -1
- package/src/services/plan/plan-cycle.service.ts +171 -202
- package/src/services/plan/plan-deadline.service.ts +304 -307
- package/src/services/plan/plan-event-delivery.service.ts +84 -72
- package/src/services/plan/plan-executor-context.ts +2 -0
- package/src/services/plan/plan-executor-graph.ts +375 -353
- package/src/services/plan/plan-executor-helpers.ts +60 -75
- package/src/services/plan/plan-executor.service.ts +494 -489
- package/src/services/plan/plan-run.service.ts +12 -19
- package/src/services/plan/plan-scheduler.service.ts +89 -82
- package/src/services/plan/plan-template.service.ts +1 -1
- package/src/services/plan/plan-transaction-events.ts +8 -5
- package/src/services/plan/plan-validator.service.ts +1 -1
- package/src/services/plan/plan-workspace.service.ts +17 -11
- package/src/services/plugin-executor.service.ts +26 -21
- package/src/services/quality-metrics.service.ts +1 -1
- package/src/services/queue-job.service.ts +8 -17
- package/src/services/recent-activity-title.service.ts +22 -10
- package/src/services/recent-activity.service.ts +1 -1
- package/src/services/skill-resolver.service.ts +1 -1
- package/src/services/social-chat-history.service.ts +37 -20
- package/src/services/system-executor.service.ts +25 -20
- package/src/services/thread/thread-bootstrap.ts +37 -19
- package/src/services/thread/thread-listing.ts +2 -1
- package/src/services/thread/thread-memory-block.ts +18 -5
- package/src/services/thread/thread-message.service.ts +30 -13
- package/src/services/thread/thread-title.service.ts +1 -1
- package/src/services/thread/thread-turn-execution.ts +87 -83
- package/src/services/thread/thread-turn-preparation.service.ts +65 -40
- package/src/services/thread/thread-turn-streaming.ts +32 -36
- package/src/services/thread/thread-turn.ts +43 -29
- package/src/services/thread/thread.service.ts +32 -8
- package/src/services/user.service.ts +1 -1
- package/src/services/write-intent-validator.service.ts +1 -1
- package/src/storage/attachment-storage.service.ts +7 -4
- package/src/storage/generated-document-storage.service.ts +1 -1
- package/src/system-agents/context-compaction.agent.ts +1 -1
- package/src/system-agents/helper-agent-options.ts +1 -1
- package/src/system-agents/memory-reranker.agent.ts +1 -1
- package/src/system-agents/memory.agent.ts +1 -1
- package/src/system-agents/recent-activity-title-refiner.agent.ts +9 -6
- package/src/system-agents/regular-chat-memory-digest.agent.ts +1 -1
- package/src/system-agents/skill-extractor.agent.ts +1 -1
- package/src/system-agents/skill-manager.agent.ts +1 -1
- package/src/system-agents/thread-router.agent.ts +23 -20
- package/src/system-agents/title-generator.agent.ts +1 -1
- package/src/tools/execution-plan.tool.ts +36 -20
- package/src/tools/fetch-webpage.tool.ts +30 -22
- package/src/tools/firecrawl-client.ts +1 -6
- package/src/tools/plan-approval.tool.ts +9 -1
- package/src/tools/remember-memory.tool.ts +3 -6
- package/src/tools/research-topic.tool.ts +12 -3
- package/src/tools/search-web.tool.ts +26 -18
- package/src/tools/search.tool.ts +4 -5
- package/src/tools/team-think.tool.ts +139 -121
- package/src/utils/async.ts +15 -6
- package/src/utils/errors.ts +27 -15
- package/src/workers/bootstrap.ts +34 -58
- package/src/workers/memory-consolidation.worker.ts +4 -1
- package/src/workers/organization-learning.worker.ts +16 -3
- package/src/workers/regular-chat-memory-digest.helpers.ts +3 -4
- package/src/workers/regular-chat-memory-digest.runner.ts +46 -29
- package/src/workers/skill-extraction.runner.ts +13 -15
- package/src/workers/worker-utils.ts +14 -8
- package/src/config/search.ts +0 -3
- package/src/effect/awaitable-effect.ts +0 -87
- package/src/effect/runtime-ref.ts +0 -25
- package/src/effect/runtime.ts +0 -31
- package/src/redis/runtime-connection.ts +0 -10
- package/src/runtime/agent-types.ts +0 -1
|
@@ -3,16 +3,20 @@ import { stepCountIs } from 'ai'
|
|
|
3
3
|
import type { ToolSet } from 'ai'
|
|
4
4
|
import { Schema, Effect } from 'effect'
|
|
5
5
|
|
|
6
|
-
import { getAgentRuntimeConfig, getResolvedAgentFactoryConfig } from '../config/agent-defaults'
|
|
7
6
|
import { aiLogger } from '../config/logger'
|
|
8
7
|
import type { RecordIdRef } from '../db/record-id'
|
|
9
8
|
import { recordIdToString } from '../db/record-id'
|
|
10
9
|
import { TABLES } from '../db/tables'
|
|
11
10
|
import { effectTryMaybeAsync as effectTryMaybeAsyncShared } from '../effect/helpers'
|
|
11
|
+
import {
|
|
12
|
+
AgentConfigServiceTag,
|
|
13
|
+
AgentFactoryServiceTag,
|
|
14
|
+
RuntimeAdaptersServiceTag,
|
|
15
|
+
TurnHooksServiceTag,
|
|
16
|
+
} from '../effect/services'
|
|
12
17
|
import { readRuntimeAgentIdentityOverrides } from '../runtime/agent-identity-overrides'
|
|
13
18
|
import { mergeInstructionSections } from '../runtime/instruction-sections'
|
|
14
|
-
import {
|
|
15
|
-
import type { LotaRuntimeTeamThinkToolsParams } from '../runtime/runtime-extensions'
|
|
19
|
+
import type { LotaRuntimeAdapters, LotaRuntimeTeamThinkToolsParams } from '../runtime/runtime-extensions'
|
|
16
20
|
import { createConsultTeamTool as createConsultTeamToolSdk } from '../runtime/team-consultation/team-consultation-orchestrator'
|
|
17
21
|
import type {
|
|
18
22
|
DefaultRepoSections,
|
|
@@ -24,8 +28,9 @@ import type { ReadableUploadMetadata } from '../services/attachment.service'
|
|
|
24
28
|
|
|
25
29
|
function buildTeamThinkAgentToolsEffect(
|
|
26
30
|
params: LotaRuntimeTeamThinkToolsParams,
|
|
31
|
+
runtimeAdapters: LotaRuntimeAdapters,
|
|
27
32
|
): Effect.Effect<{ tools: ToolSet }, TeamThinkRuntimeError> {
|
|
28
|
-
const builder =
|
|
33
|
+
const builder = runtimeAdapters.buildTeamThinkAgentTools
|
|
29
34
|
if (!builder) {
|
|
30
35
|
return Effect.succeed({ tools: {} })
|
|
31
36
|
}
|
|
@@ -72,124 +77,137 @@ export function createTeamThinkTool(params: {
|
|
|
72
77
|
toolProviders?: ToolSet
|
|
73
78
|
abortSignal: AbortSignal
|
|
74
79
|
}) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
yield* effectTryMaybeAsync(
|
|
90
|
-
() =>
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
systemWorkspaceDetails: runParams.systemWorkspaceDetails,
|
|
118
|
-
preSeededMemoriesSection: runParams.preSeededMemoriesSection,
|
|
119
|
-
retrievedKnowledgeSection: runParams.retrievedKnowledgeSection,
|
|
120
|
-
additionalInstructionSections: mergeInstructionSections(
|
|
121
|
-
dynamicInstructionSections,
|
|
122
|
-
params.additionalInstructionSections,
|
|
123
|
-
readInstructionSections(agentResolution?.additionalInstructionSections),
|
|
124
|
-
),
|
|
125
|
-
responseGuardSection: buildTeamConsultationResponseGuard({
|
|
80
|
+
return Effect.gen(function* () {
|
|
81
|
+
const turnHooks = yield* TurnHooksServiceTag
|
|
82
|
+
const runtimeAdapters = yield* RuntimeAdaptersServiceTag
|
|
83
|
+
const agentConfig = yield* AgentConfigServiceTag
|
|
84
|
+
const agentFactoryConfig = yield* AgentFactoryServiceTag
|
|
85
|
+
const agentIdentityOverrides = readRuntimeAgentIdentityOverrides(
|
|
86
|
+
(params.context as Record<string, unknown> | null | undefined) ?? null,
|
|
87
|
+
)
|
|
88
|
+
const participantRunner: TeamConsultationParticipantRunner = {
|
|
89
|
+
buildParticipantAgent(agentId, runParams) {
|
|
90
|
+
return Effect.runPromise(
|
|
91
|
+
Effect.gen(function* () {
|
|
92
|
+
const currentContext = yield* Effect.context()
|
|
93
|
+
const runPromiseWithCurrentContext = Effect.runPromiseWith(currentContext)
|
|
94
|
+
const dynamicInstructionSections = yield* effectTryMaybeAsync(
|
|
95
|
+
() => params.getAdditionalInstructionSections?.(),
|
|
96
|
+
'Failed to load dynamic team-think instruction sections.',
|
|
97
|
+
)
|
|
98
|
+
const agentResolution = asRecord(
|
|
99
|
+
yield* effectTryMaybeAsync(
|
|
100
|
+
() =>
|
|
101
|
+
turnHooks.resolveAgent?.({
|
|
102
|
+
agentId,
|
|
103
|
+
mode: 'fixedThreadMode',
|
|
104
|
+
thread: null,
|
|
105
|
+
threadRef: params.threadId,
|
|
106
|
+
orgRef: params.orgId,
|
|
107
|
+
userRef: params.userId,
|
|
108
|
+
onboardingActive: false,
|
|
109
|
+
linearInstalled: false,
|
|
110
|
+
githubInstalled: params.githubInstalled,
|
|
111
|
+
additionalInstructionSections: mergeInstructionSections(
|
|
112
|
+
dynamicInstructionSections,
|
|
113
|
+
params.additionalInstructionSections,
|
|
114
|
+
),
|
|
115
|
+
context: (params.context as Record<string, unknown> | null | undefined) ?? null,
|
|
116
|
+
}),
|
|
117
|
+
'Failed to resolve team-think participant agent.',
|
|
118
|
+
),
|
|
119
|
+
)
|
|
120
|
+
const resolvedAgentId = readOptionalString(agentResolution?.agentId) ?? agentId
|
|
121
|
+
const config = agentFactoryConfig.getAgentRuntimeConfig({
|
|
126
122
|
agentId: resolvedAgentId,
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
123
|
+
threadType: 'group' as const,
|
|
124
|
+
mode: 'fixedThreadMode',
|
|
125
|
+
onboardingActive: false,
|
|
126
|
+
linearInstalled: false,
|
|
127
|
+
systemWorkspaceDetails: runParams.systemWorkspaceDetails,
|
|
128
|
+
preSeededMemoriesSection: runParams.preSeededMemoriesSection,
|
|
129
|
+
retrievedKnowledgeSection: runParams.retrievedKnowledgeSection,
|
|
130
|
+
additionalInstructionSections: mergeInstructionSections(
|
|
131
|
+
dynamicInstructionSections,
|
|
132
|
+
params.additionalInstructionSections,
|
|
133
|
+
readInstructionSections(agentResolution?.additionalInstructionSections),
|
|
134
|
+
),
|
|
135
|
+
responseGuardSection: buildTeamConsultationResponseGuard({
|
|
136
|
+
agentConfig,
|
|
137
|
+
agentId: resolvedAgentId,
|
|
138
|
+
task: runParams.task,
|
|
139
|
+
}),
|
|
140
|
+
})
|
|
141
|
+
const { tools } = yield* buildTeamThinkAgentToolsEffect(
|
|
142
|
+
{
|
|
143
|
+
agentId: resolvedAgentId,
|
|
144
|
+
workspaceId: params.orgId,
|
|
145
|
+
userId: params.userId,
|
|
146
|
+
workspaceIdString: recordIdToString(params.orgId, TABLES.ORGANIZATION),
|
|
147
|
+
threadId: params.threadId,
|
|
148
|
+
githubInstalled: params.githubInstalled,
|
|
149
|
+
provideRepoTool: resolvedAgentId !== 'mentor' && params.provideRepoTool,
|
|
150
|
+
availableUploads: params.availableUploads,
|
|
151
|
+
defaultRepoSections: params.defaultRepoSectionsByAgent[resolvedAgentId],
|
|
152
|
+
context: params.context,
|
|
153
|
+
toolProviders: params.toolProviders,
|
|
154
|
+
},
|
|
155
|
+
runtimeAdapters,
|
|
156
|
+
)
|
|
157
|
+
const agentId_ = config.id || resolvedAgentId
|
|
158
|
+
const configuredMaxSteps = config.maxSteps
|
|
159
|
+
const maxSteps = Math.min(configuredMaxSteps, TEAM_THINK_AGENT_MAX_STEPS)
|
|
160
|
+
const agentFactory = agentFactoryConfig.createAgent[agentId_]
|
|
161
|
+
if (!agentFactory) {
|
|
162
|
+
return yield* new TeamThinkAgentFactoryNotConfiguredError({ agentId: agentId_ })
|
|
163
|
+
}
|
|
164
|
+
const agent = agentFactory({
|
|
165
|
+
mode: 'fixedThreadMode',
|
|
166
|
+
tools,
|
|
167
|
+
extraInstructions: config.extraInstructions,
|
|
168
|
+
maxRetries: TEAM_THINK_AGENT_MAX_RETRIES,
|
|
169
|
+
stopWhen: [stepCountIs(maxSteps)],
|
|
170
|
+
})
|
|
171
|
+
const observer = {
|
|
172
|
+
run: <T>(fn: () => T | Promise<T>): Promise<T> =>
|
|
173
|
+
runPromiseWithCurrentContext(
|
|
174
|
+
effectTryMaybeAsync(fn, `Team-think participant run failed (${agentId}).`),
|
|
175
|
+
),
|
|
176
|
+
recordError: (error: unknown) => {
|
|
177
|
+
aiLogger.error`Team-think participant failed (${agentId}): ${error}`
|
|
178
|
+
},
|
|
179
|
+
recordAbort: (error: unknown) => {
|
|
180
|
+
aiLogger.debug`Team-think participant aborted (${agentId}): ${
|
|
181
|
+
error instanceof Error ? error.message : String(error)
|
|
182
|
+
}`
|
|
183
|
+
},
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
agent: agent as Awaited<ReturnType<TeamConsultationParticipantRunner['buildParticipantAgent']>>['agent'],
|
|
187
|
+
observer,
|
|
188
|
+
}
|
|
189
|
+
}).pipe(Effect.withSpan('tool.teamThink.buildParticipantAgent')),
|
|
190
|
+
)
|
|
191
|
+
},
|
|
192
|
+
}
|
|
177
193
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
+
return createConsultTeamToolSdk({
|
|
195
|
+
agentConfig,
|
|
196
|
+
historyMessages: params.historyMessages,
|
|
197
|
+
latestUserMessageId: params.latestUserMessageId,
|
|
198
|
+
availableUploads: params.availableUploads,
|
|
199
|
+
defaultRepoSectionsByAgent: params.defaultRepoSectionsByAgent,
|
|
200
|
+
systemWorkspaceDetails: params.systemWorkspaceDetails,
|
|
201
|
+
getPreSeededMemoriesSection: params.getPreSeededMemoriesSection,
|
|
202
|
+
retrievedKnowledgeSection: params.retrievedKnowledgeSection,
|
|
203
|
+
displayNamesById: agentIdentityOverrides.displayNamesById,
|
|
204
|
+
abortSignal: params.abortSignal,
|
|
205
|
+
participantRunner,
|
|
206
|
+
onReadError: (agentId, error) => {
|
|
207
|
+
if (!(error instanceof Error && error.name === 'AbortError')) {
|
|
208
|
+
aiLogger.error`UI message read failed for team-think participant ${agentId}: ${error}`
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
})
|
|
194
212
|
})
|
|
195
213
|
}
|
package/src/utils/async.ts
CHANGED
|
@@ -1,24 +1,33 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Cause, Duration, Effect, Exit, Schema } from 'effect'
|
|
2
2
|
|
|
3
3
|
import { serverLogger } from '../config/logger'
|
|
4
4
|
import { TimeoutError } from '../effect/errors'
|
|
5
|
-
import { getErrorMessage } from './errors'
|
|
5
|
+
import { getErrorMessage, toError } from './errors'
|
|
6
6
|
|
|
7
7
|
class TimedOperationError extends Schema.TaggedErrorClass<TimedOperationError>()('TimedOperationError', {
|
|
8
8
|
operation: Schema.String,
|
|
9
9
|
cause: Schema.Defect,
|
|
10
10
|
}) {}
|
|
11
11
|
|
|
12
|
+
function isTimedOperationError(error: unknown): error is TimedOperationError {
|
|
13
|
+
return typeof error === 'object' && error !== null && '_tag' in error && error._tag === 'TimedOperationError'
|
|
14
|
+
}
|
|
15
|
+
|
|
12
16
|
export function withTimeout<T>(promise: Promise<T>, ms: number, operation: string): Promise<T> {
|
|
13
17
|
return Effect.runPromise(
|
|
14
18
|
Effect.tryPromise({ try: () => promise, catch: (cause) => new TimedOperationError({ operation, cause }) }).pipe(
|
|
15
19
|
Effect.timeout(Duration.millis(ms)),
|
|
16
20
|
Effect.catchTag('TimeoutError', () => Effect.fail(new TimeoutError({ operation, ms }))),
|
|
17
|
-
Effect.
|
|
18
|
-
Effect.fail(error.cause instanceof Error ? error.cause : new Error(String(error.cause))),
|
|
19
|
-
),
|
|
21
|
+
Effect.exit,
|
|
20
22
|
),
|
|
21
|
-
)
|
|
23
|
+
).then((exit) => {
|
|
24
|
+
if (Exit.isSuccess(exit)) {
|
|
25
|
+
return exit.value
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const error = Cause.squash(exit.cause)
|
|
29
|
+
throw isTimedOperationError(error) ? toError(error.cause) : error
|
|
30
|
+
})
|
|
22
31
|
}
|
|
23
32
|
|
|
24
33
|
export function createSafeEnqueue(logger: { warn: (message: string) => void }) {
|
package/src/utils/errors.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { getErrorMessage } from '@lota-sdk/shared'
|
|
2
|
-
import { Match } from 'effect'
|
|
2
|
+
import { Data, Match } from 'effect'
|
|
3
3
|
|
|
4
4
|
import type { EffectError, ValidationIssue } from '../effect/errors'
|
|
5
5
|
import { BaseServicePersistenceError, isEffectError } from '../effect/errors'
|
|
@@ -19,18 +19,16 @@ export interface AppErrorResponse {
|
|
|
19
19
|
body: { error: { code: string; message: string } }
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
export type AppErrorLike = Error & { code: string; statusCode: number; toResponse?: () =>
|
|
22
|
+
export type AppErrorLike = Error & { code: string; statusCode: number; toResponse?: () => unknown }
|
|
23
23
|
|
|
24
|
-
export class AppError extends Error
|
|
24
|
+
export class AppError extends Data.Error<{
|
|
25
|
+
readonly message: string
|
|
25
26
|
readonly code: string
|
|
26
27
|
readonly statusCode: number
|
|
27
|
-
|
|
28
|
+
}> {
|
|
28
29
|
constructor(message: string, code: string, statusCode: number) {
|
|
29
|
-
super(message)
|
|
30
|
+
super({ message, code, statusCode })
|
|
30
31
|
this.name = new.target.name
|
|
31
|
-
this.code = code
|
|
32
|
-
this.statusCode = statusCode
|
|
33
|
-
Object.setPrototypeOf(this, new.target.prototype)
|
|
34
32
|
}
|
|
35
33
|
|
|
36
34
|
toResponse(): AppErrorResponse {
|
|
@@ -99,16 +97,30 @@ export function isAppErrorLike(error: unknown): error is AppErrorLike {
|
|
|
99
97
|
return typeof candidate.code === 'string' && typeof candidate.statusCode === 'number'
|
|
100
98
|
}
|
|
101
99
|
|
|
100
|
+
function isAppErrorResponse(value: unknown): value is AppErrorResponse {
|
|
101
|
+
if (typeof value !== 'object' || value === null) {
|
|
102
|
+
return false
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const candidate = value as {
|
|
106
|
+
status?: unknown
|
|
107
|
+
body?: { error?: { code?: unknown; message?: unknown } | null } | null
|
|
108
|
+
}
|
|
109
|
+
return (
|
|
110
|
+
typeof candidate.status === 'number' &&
|
|
111
|
+
typeof candidate.body === 'object' &&
|
|
112
|
+
candidate.body !== null &&
|
|
113
|
+
typeof candidate.body.error === 'object' &&
|
|
114
|
+
candidate.body.error !== null &&
|
|
115
|
+
typeof candidate.body.error.code === 'string' &&
|
|
116
|
+
typeof candidate.body.error.message === 'string'
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
|
|
102
120
|
export function toAppErrorResponse(error: AppErrorLike): AppErrorResponse {
|
|
103
121
|
if (typeof error.toResponse === 'function') {
|
|
104
122
|
const response = error.toResponse()
|
|
105
|
-
if (
|
|
106
|
-
response &&
|
|
107
|
-
typeof response === 'object' &&
|
|
108
|
-
typeof response.status === 'number' &&
|
|
109
|
-
response.body &&
|
|
110
|
-
typeof response.body === 'object'
|
|
111
|
-
) {
|
|
123
|
+
if (isAppErrorResponse(response)) {
|
|
112
124
|
return response
|
|
113
125
|
}
|
|
114
126
|
}
|
package/src/workers/bootstrap.ts
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ConfigProvider, Option, Schema, Effect, Layer, ManagedRuntime, Redacted } from 'effect'
|
|
2
2
|
|
|
3
3
|
import { AiGatewayLive } from '../ai-gateway/ai-gateway'
|
|
4
4
|
import { EmbeddingCacheLive } from '../ai/embedding-cache'
|
|
5
|
-
import {
|
|
6
|
-
import { configureLotaLogger, resolveLotaLogLevel, serverLogger } from '../config/logger'
|
|
5
|
+
import { serverLogger } from '../config/logger'
|
|
7
6
|
import { connectWithStartupRetry, waitForDatabaseBootstrap } from '../db/startup'
|
|
8
|
-
import { buildWorkerInfrastructureLayer
|
|
9
|
-
import { DatabaseServiceTag } from '../effect/services'
|
|
10
|
-
import { parseLotaRuntimeConfig, parseWorkerBootstrapEnv } from '../runtime/runtime-config'
|
|
11
|
-
import { getConfiguredPluginDatabaseConnector } from '../runtime/runtime-extensions'
|
|
7
|
+
import { buildWorkerInfrastructureLayer } from '../effect'
|
|
8
|
+
import { DatabaseServiceTag, RuntimeAdaptersServiceTag } from '../effect/services'
|
|
9
|
+
import { lotaRuntimeEnvConfig, parseLotaRuntimeConfig, parseWorkerBootstrapEnv } from '../runtime/runtime-config'
|
|
12
10
|
import { FirecrawlLive } from '../tools/firecrawl-client'
|
|
13
11
|
import { getErrorMessage } from '../utils/errors'
|
|
14
12
|
|
|
@@ -28,27 +26,8 @@ function toSandboxedWorkerBootstrapError(
|
|
|
28
26
|
return new SandboxedWorkerBootstrapError({ stage, message: getErrorMessage(cause), cause })
|
|
29
27
|
}
|
|
30
28
|
|
|
31
|
-
const workerConfig = Config.all({
|
|
32
|
-
surrealdbUrl: Config.string('SURREALDB_URL'),
|
|
33
|
-
surrealdbNamespace: Config.string('SURREALDB_NAMESPACE'),
|
|
34
|
-
surrealdbUser: Config.string('SURREALDB_USER'),
|
|
35
|
-
surrealdbPassword: Config.redacted('SURREALDB_PASSWORD'),
|
|
36
|
-
redisUrl: Config.string('REDIS_URL'),
|
|
37
|
-
aiGatewayUrl: Config.string('AI_GATEWAY_URL').pipe(Config.withDefault(DEFAULT_AI_GATEWAY_URL)),
|
|
38
|
-
aiGatewayKey: Config.redacted('AI_GATEWAY_KEY'),
|
|
39
|
-
openRouterApiKey: Config.redacted('OPENROUTER_API_KEY'),
|
|
40
|
-
s3Endpoint: Config.string('S3_ENDPOINT'),
|
|
41
|
-
s3Bucket: Config.string('S3_BUCKET'),
|
|
42
|
-
s3Region: Config.string('S3_REGION').pipe(Config.withDefault('garage')),
|
|
43
|
-
s3AccessKeyId: Config.redacted('S3_ACCESS_KEY_ID'),
|
|
44
|
-
s3SecretAccessKey: Config.redacted('S3_SECRET_ACCESS_KEY'),
|
|
45
|
-
attachmentUrlExpiresIn: Config.string('ATTACHMENT_URL_EXPIRES_IN').pipe(Config.withDefault('1800')),
|
|
46
|
-
firecrawlApiKey: Config.redacted('FIRECRAWL_API_KEY'),
|
|
47
|
-
firecrawlApiBaseUrl: Config.string('FIRECRAWL_API_BASE_URL').pipe(Config.option),
|
|
48
|
-
})
|
|
49
|
-
|
|
50
29
|
function buildSandboxedWorkerRuntimeConfigEffect() {
|
|
51
|
-
return
|
|
30
|
+
return lotaRuntimeEnvConfig
|
|
52
31
|
.parse(ConfigProvider.fromEnv())
|
|
53
32
|
.pipe(
|
|
54
33
|
Effect.map((env) =>
|
|
@@ -63,7 +42,9 @@ function buildSandboxedWorkerRuntimeConfigEffect() {
|
|
|
63
42
|
aiGateway: {
|
|
64
43
|
url: env.aiGatewayUrl,
|
|
65
44
|
key: Redacted.value(env.aiGatewayKey),
|
|
66
|
-
|
|
45
|
+
...(Option.isSome(env.openRouterApiKey)
|
|
46
|
+
? { openRouterApiKey: Redacted.value(env.openRouterApiKey.value) }
|
|
47
|
+
: {}),
|
|
67
48
|
},
|
|
68
49
|
s3: {
|
|
69
50
|
endpoint: env.s3Endpoint,
|
|
@@ -75,7 +56,7 @@ function buildSandboxedWorkerRuntimeConfigEffect() {
|
|
|
75
56
|
},
|
|
76
57
|
firecrawl: {
|
|
77
58
|
apiKey: Redacted.value(env.firecrawlApiKey),
|
|
78
|
-
...(env.firecrawlApiBaseUrl
|
|
59
|
+
...(Option.isSome(env.firecrawlApiBaseUrl) ? { apiBaseUrl: env.firecrawlApiBaseUrl.value } : {}),
|
|
79
60
|
},
|
|
80
61
|
agents: {
|
|
81
62
|
roster: ['worker'],
|
|
@@ -91,23 +72,18 @@ function buildSandboxedWorkerRuntimeConfigEffect() {
|
|
|
91
72
|
// eslint-disable-next-line typescript-eslint/no-explicit-any -- wildcard for host-provided ManagedRuntime
|
|
92
73
|
type WorkerManagedRuntime = ManagedRuntime.ManagedRuntime<any, any>
|
|
93
74
|
|
|
94
|
-
let
|
|
95
|
-
let
|
|
96
|
-
let sandboxedWorkerRuntimeSetupPromise: Promise<WorkerManagedRuntime> | null = null
|
|
75
|
+
let sandboxedWorkerSetupPromise: Promise<WorkerManagedRuntime> | null = null
|
|
76
|
+
let sandboxedWorkerInitPromise: Promise<WorkerManagedRuntime> | null = null
|
|
97
77
|
|
|
98
78
|
function ensureSandboxedWorkerRuntimeConfigured(): Promise<WorkerManagedRuntime> {
|
|
99
|
-
if (
|
|
100
|
-
return
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (sandboxedWorkerRuntimeSetupPromise) {
|
|
104
|
-
return sandboxedWorkerRuntimeSetupPromise
|
|
79
|
+
if (sandboxedWorkerSetupPromise) {
|
|
80
|
+
return sandboxedWorkerSetupPromise
|
|
105
81
|
}
|
|
106
82
|
|
|
107
|
-
|
|
83
|
+
// Assign before the async kicks off so concurrent callers observe the in-flight promise.
|
|
84
|
+
sandboxedWorkerSetupPromise = Effect.runPromise(
|
|
108
85
|
Effect.gen(function* () {
|
|
109
86
|
const runtimeConfig = yield* buildSandboxedWorkerRuntimeConfigEffect()
|
|
110
|
-
yield* Effect.sync(() => configureLotaLogger(resolveLotaLogLevel(Bun.env.LOG_LEVEL) ?? 'info'))
|
|
111
87
|
|
|
112
88
|
const infrastructureLayer = buildWorkerInfrastructureLayer(runtimeConfig)
|
|
113
89
|
|
|
@@ -117,27 +93,23 @@ function ensureSandboxedWorkerRuntimeConfigured(): Promise<WorkerManagedRuntime>
|
|
|
117
93
|
|
|
118
94
|
const managedRuntime = ManagedRuntime.make(fullLayer)
|
|
119
95
|
|
|
120
|
-
yield* Effect.sync(() => {
|
|
121
|
-
setLotaSdkRuntime(managedRuntime)
|
|
122
|
-
sandboxedWorkerRuntime = managedRuntime
|
|
123
|
-
})
|
|
124
|
-
|
|
125
96
|
return managedRuntime
|
|
126
97
|
}),
|
|
127
|
-
).
|
|
128
|
-
|
|
98
|
+
).catch((error) => {
|
|
99
|
+
sandboxedWorkerSetupPromise = null
|
|
100
|
+
throw error
|
|
129
101
|
})
|
|
130
102
|
|
|
131
|
-
|
|
132
|
-
return setupPromise
|
|
103
|
+
return sandboxedWorkerSetupPromise
|
|
133
104
|
}
|
|
134
105
|
|
|
135
106
|
export function initializeSandboxedWorkerRuntime(): Promise<WorkerManagedRuntime> {
|
|
136
|
-
if (
|
|
137
|
-
return
|
|
107
|
+
if (sandboxedWorkerInitPromise) {
|
|
108
|
+
return sandboxedWorkerInitPromise
|
|
138
109
|
}
|
|
139
110
|
|
|
140
|
-
|
|
111
|
+
// Assign before the async kicks off so concurrent callers observe the in-flight promise.
|
|
112
|
+
sandboxedWorkerInitPromise = Effect.runPromise(
|
|
141
113
|
Effect.gen(function* () {
|
|
142
114
|
const env = parseWorkerBootstrapEnv(Bun.env)
|
|
143
115
|
const runtime = yield* Effect.tryPromise({
|
|
@@ -159,11 +131,16 @@ export function initializeSandboxedWorkerRuntime(): Promise<WorkerManagedRuntime
|
|
|
159
131
|
catch: (error) => toSandboxedWorkerBootstrapError('connect-db', error),
|
|
160
132
|
})
|
|
161
133
|
|
|
134
|
+
const runtimeAdapters = yield* Effect.tryPromise({
|
|
135
|
+
try: () => runtime.runPromise(Effect.service(RuntimeAdaptersServiceTag)),
|
|
136
|
+
catch: (error) => toSandboxedWorkerBootstrapError('initialize', error),
|
|
137
|
+
})
|
|
138
|
+
|
|
162
139
|
yield* Effect.tryPromise({
|
|
163
140
|
try: () =>
|
|
164
141
|
connectWithStartupRetry({
|
|
165
142
|
connect: () => {
|
|
166
|
-
const connectPluginRuntimeDatabases =
|
|
143
|
+
const connectPluginRuntimeDatabases = runtimeAdapters.connectPluginDatabases
|
|
167
144
|
return connectPluginRuntimeDatabases ? connectPluginRuntimeDatabases() : Promise.resolve()
|
|
168
145
|
},
|
|
169
146
|
label: 'sandboxed worker plugin database runtime',
|
|
@@ -186,11 +163,10 @@ export function initializeSandboxedWorkerRuntime(): Promise<WorkerManagedRuntime
|
|
|
186
163
|
|
|
187
164
|
return runtime
|
|
188
165
|
}),
|
|
189
|
-
)
|
|
190
|
-
|
|
191
|
-
sandboxedWorkerRuntimePromise = initPromise
|
|
192
|
-
return initPromise.catch((error) => {
|
|
193
|
-
sandboxedWorkerRuntimePromise = null
|
|
166
|
+
).catch((error) => {
|
|
167
|
+
sandboxedWorkerInitPromise = null
|
|
194
168
|
throw error
|
|
195
169
|
})
|
|
170
|
+
|
|
171
|
+
return sandboxedWorkerInitPromise
|
|
196
172
|
}
|
|
@@ -11,6 +11,7 @@ import { TABLES } from '../db/tables'
|
|
|
11
11
|
import { effectTryPromise } from '../effect/helpers'
|
|
12
12
|
import { DatabaseServiceTag } from '../effect/services'
|
|
13
13
|
import type { MemoryConsolidationJob } from '../queues/memory-consolidation.queue'
|
|
14
|
+
import { QueueJobServiceTag } from '../services/queue-job.service'
|
|
14
15
|
import { nowDate, unsafeDateFrom } from '../utils/date-time'
|
|
15
16
|
import { getErrorMessage } from '../utils/errors'
|
|
16
17
|
import { initializeSandboxedWorkerRuntime } from './bootstrap'
|
|
@@ -59,6 +60,8 @@ const memoryConsolidationDatabaseService: SurrealDBService = await runtime.runPr
|
|
|
59
60
|
Effect.service(DatabaseServiceTag),
|
|
60
61
|
)
|
|
61
62
|
|
|
63
|
+
const memoryConsolidationQueueJobService = await runtime.runPromise(Effect.service(QueueJobServiceTag))
|
|
64
|
+
|
|
62
65
|
function db(): SurrealDBService {
|
|
63
66
|
return memoryConsolidationDatabaseService
|
|
64
67
|
}
|
|
@@ -395,4 +398,4 @@ const handler = (job: SandboxedJob<MemoryConsolidationJob>) =>
|
|
|
395
398
|
),
|
|
396
399
|
)
|
|
397
400
|
|
|
398
|
-
export default createTracedWorkerProcessor('memory-consolidation', handler)
|
|
401
|
+
export default createTracedWorkerProcessor('memory-consolidation', handler, memoryConsolidationQueueJobService)
|
|
@@ -4,10 +4,17 @@ import type { Context } from 'effect'
|
|
|
4
4
|
|
|
5
5
|
import { serverLogger } from '../config/logger'
|
|
6
6
|
import { effectTryPromise } from '../effect/helpers'
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
AgentConfigServiceTag,
|
|
9
|
+
DatabaseServiceTag,
|
|
10
|
+
RuntimeAdaptersServiceTag,
|
|
11
|
+
RuntimeConfigServiceTag,
|
|
12
|
+
} from '../effect/services'
|
|
8
13
|
import type { OrganizationLearningJob } from '../queues/organization-learning.queue'
|
|
14
|
+
import { LotaQueuesServiceTag } from '../queues/queues.service'
|
|
9
15
|
import { LearnedSkillServiceTag } from '../services/learned-skill.service'
|
|
10
16
|
import { MemoryServiceTag } from '../services/memory/memory.service'
|
|
17
|
+
import { QueueJobServiceTag } from '../services/queue-job.service'
|
|
11
18
|
import { SocialChatHistoryServiceTag } from '../services/social-chat-history.service'
|
|
12
19
|
import { initializeSandboxedWorkerRuntime } from './bootstrap'
|
|
13
20
|
import { runRegularChatMemoryDigest } from './regular-chat-memory-digest.runner'
|
|
@@ -18,15 +25,20 @@ import { toSandboxedWorkerError } from './utils/sandbox-error'
|
|
|
18
25
|
import { createTracedWorkerProcessor } from './worker-utils'
|
|
19
26
|
|
|
20
27
|
const runtime = await initializeSandboxedWorkerRuntime()
|
|
21
|
-
const resolve =
|
|
28
|
+
const resolve = <I, T>(tag: Context.Key<I, T>): Promise<T> => runtime.runPromise(Effect.service(tag))
|
|
29
|
+
const agentConfig = await resolve(AgentConfigServiceTag)
|
|
30
|
+
const queues = await resolve(LotaQueuesServiceTag)
|
|
22
31
|
const regularChatDigestServices: RegularChatDigestServices = {
|
|
32
|
+
agentConfig,
|
|
23
33
|
databaseService: await resolve(DatabaseServiceTag),
|
|
24
34
|
memoryService: await resolve(MemoryServiceTag),
|
|
25
35
|
socialChatHistoryService: await resolve(SocialChatHistoryServiceTag),
|
|
26
36
|
runtimeAdapters: await resolve(RuntimeAdaptersServiceTag),
|
|
37
|
+
organizationLearningQueue: queues.organizationLearning,
|
|
27
38
|
}
|
|
28
39
|
const workerRuntimeConfig = await resolve(RuntimeConfigServiceTag)
|
|
29
40
|
const skillExtractionServices: SkillExtractionServices = {
|
|
41
|
+
agentConfig,
|
|
30
42
|
databaseService: await resolve(DatabaseServiceTag),
|
|
31
43
|
learnedSkillService: await resolve(LearnedSkillServiceTag),
|
|
32
44
|
socialChatHistoryService: await resolve(SocialChatHistoryServiceTag),
|
|
@@ -34,6 +46,7 @@ const skillExtractionServices: SkillExtractionServices = {
|
|
|
34
46
|
embeddingModel: workerRuntimeConfig.aiGateway.embeddingModel,
|
|
35
47
|
openRouterApiKey: workerRuntimeConfig.aiGateway.openRouterApiKey,
|
|
36
48
|
}
|
|
49
|
+
const organizationLearningQueueJobService = await resolve(QueueJobServiceTag)
|
|
37
50
|
|
|
38
51
|
// One sandboxed worker handles both organization-learning branches so the
|
|
39
52
|
// queue can dispatch digest and skill jobs without separate worker images.
|
|
@@ -62,4 +75,4 @@ const handler = (job: SandboxedJob<OrganizationLearningJob>) =>
|
|
|
62
75
|
),
|
|
63
76
|
)
|
|
64
77
|
|
|
65
|
-
export default createTracedWorkerProcessor('organization-learning', handler)
|
|
78
|
+
export default createTracedWorkerProcessor('organization-learning', handler, organizationLearningQueueJobService)
|