@lota-sdk/core 0.4.10 → 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-gateway/ai-gateway.ts +149 -95
- package/src/ai-gateway/index.ts +16 -1
- package/src/config/agent-defaults.ts +4 -120
- package/src/config/logger.ts +18 -34
- package/src/config/thread-defaults.ts +1 -18
- package/src/create-runtime.ts +90 -28
- package/src/db/base.service.ts +30 -38
- package/src/db/service.ts +489 -545
- package/src/effect/index.ts +0 -2
- package/src/effect/layers.ts +6 -13
- package/src/embeddings/provider.ts +2 -7
- package/src/index.ts +4 -5
- package/src/queues/autonomous-job.queue.ts +159 -113
- package/src/queues/context-compaction.queue.ts +39 -25
- package/src/queues/delayed-node-promotion.queue.ts +56 -29
- 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 +63 -39
- package/src/queues/plan-agent-heartbeat.queue.ts +104 -79
- package/src/queues/plan-scheduler.queue.ts +100 -84
- package/src/queues/post-chat-memory.queue.ts +55 -33
- package/src/queues/queue-factory.ts +40 -41
- package/src/queues/queues.service.ts +61 -0
- package/src/queues/title-generation.queue.ts +42 -31
- package/src/redis/org-memory-lock.ts +24 -9
- package/src/redis/redis-lease-lock.ts +8 -1
- package/src/runtime/agent-identity-overrides.ts +7 -3
- package/src/runtime/agent-runtime-policy.ts +9 -4
- package/src/runtime/agent-stream-helpers.ts +9 -4
- package/src/runtime/context-compaction/context-compaction-runtime.ts +28 -32
- package/src/runtime/context-compaction/context-compaction.ts +9 -7
- package/src/runtime/domain-layer.ts +15 -4
- package/src/runtime/execution-plan-visibility.ts +5 -2
- package/src/runtime/graph-designer.ts +0 -22
- package/src/runtime/index.ts +1 -0
- package/src/runtime/indexed-repositories-policy.ts +2 -6
- package/src/runtime/plugin-resolution.ts +29 -12
- package/src/runtime/post-turn-side-effects.ts +139 -141
- package/src/runtime/runtime-config.ts +0 -6
- package/src/runtime/runtime-extensions.ts +0 -54
- package/src/runtime/runtime-lifecycle.ts +4 -4
- package/src/runtime/runtime-services.ts +122 -53
- package/src/runtime/runtime-worker-registry.ts +113 -30
- package/src/runtime/social-chat/social-chat-agent-runner.ts +6 -3
- package/src/runtime/social-chat/social-chat-history.ts +3 -1
- package/src/runtime/social-chat/social-chat.ts +35 -20
- package/src/runtime/team-consultation/team-consultation-orchestrator.ts +6 -5
- 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 +7 -47
- package/src/runtime/turn-lifecycle.ts +6 -14
- package/src/services/agent-activity.service.ts +168 -175
- package/src/services/agent-executor.service.ts +35 -16
- package/src/services/attachment.service.ts +4 -70
- package/src/services/autonomous-job.service.ts +53 -61
- package/src/services/context-compaction.service.ts +7 -9
- package/src/services/execution-plan/execution-plan-graph.ts +106 -115
- package/src/services/execution-plan/execution-plan-schedule.ts +1 -15
- package/src/services/execution-plan/execution-plan.service.ts +67 -50
- package/src/services/global-orchestrator.service.ts +18 -7
- package/src/services/graph-full-routing.ts +7 -6
- package/src/services/memory/memory-conversation.ts +10 -5
- package/src/services/memory/memory.service.ts +11 -8
- package/src/services/ownership-dispatcher.service.ts +16 -5
- package/src/services/plan/plan-agent-heartbeat.service.ts +29 -15
- package/src/services/plan/plan-agent-query.service.ts +12 -8
- package/src/services/plan/plan-completion-side-effects.ts +93 -101
- package/src/services/plan/plan-cycle.service.ts +7 -45
- package/src/services/plan/plan-deadline.service.ts +28 -17
- package/src/services/plan/plan-event-delivery.service.ts +47 -40
- package/src/services/plan/plan-executor-context.ts +2 -0
- package/src/services/plan/plan-executor-graph.ts +366 -391
- package/src/services/plan/plan-executor.service.ts +13 -91
- package/src/services/plan/plan-scheduler.service.ts +62 -49
- package/src/services/plan/plan-transaction-events.ts +1 -1
- package/src/services/recent-activity-title.service.ts +6 -2
- package/src/services/thread/thread-bootstrap.ts +11 -9
- package/src/services/thread/thread-message.service.ts +6 -5
- package/src/services/thread/thread-turn-execution.ts +86 -82
- package/src/services/thread/thread-turn-preparation.service.ts +47 -24
- package/src/services/thread/thread-turn-streaming.ts +20 -25
- package/src/services/thread/thread-turn.ts +25 -44
- package/src/services/thread/thread.service.ts +21 -6
- package/src/system-agents/recent-activity-title-refiner.agent.ts +8 -5
- package/src/system-agents/thread-router.agent.ts +23 -20
- package/src/tools/execution-plan.tool.ts +8 -3
- package/src/tools/fetch-webpage.tool.ts +10 -9
- package/src/tools/firecrawl-client.ts +0 -15
- 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 +10 -9
- package/src/tools/search.tool.ts +4 -5
- package/src/tools/team-think.tool.ts +139 -121
- package/src/workers/bootstrap.ts +9 -10
- package/src/workers/memory-consolidation.worker.ts +4 -1
- package/src/workers/organization-learning.worker.ts +15 -2
- package/src/workers/regular-chat-memory-digest.helpers.ts +3 -4
- package/src/workers/regular-chat-memory-digest.runner.ts +21 -14
- package/src/workers/skill-extraction.runner.ts +13 -15
- package/src/workers/worker-utils.ts +6 -18
- package/src/effect/awaitable-effect.ts +0 -96
- package/src/effect/runtime-ref.ts +0 -25
- package/src/effect/runtime.ts +0 -46
- package/src/redis/runtime-connection.ts +0 -20
- package/src/runtime/runtime-accessors.ts +0 -92
- package/src/runtime/runtime-token.ts +0 -47
|
@@ -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/workers/bootstrap.ts
CHANGED
|
@@ -2,12 +2,11 @@ import { ConfigProvider, Option, Schema, Effect, Layer, ManagedRuntime, Redacted
|
|
|
2
2
|
|
|
3
3
|
import { AiGatewayLive } from '../ai-gateway/ai-gateway'
|
|
4
4
|
import { EmbeddingCacheLive } from '../ai/embedding-cache'
|
|
5
|
-
import {
|
|
5
|
+
import { serverLogger } from '../config/logger'
|
|
6
6
|
import { connectWithStartupRetry, waitForDatabaseBootstrap } from '../db/startup'
|
|
7
|
-
import { buildWorkerInfrastructureLayer
|
|
8
|
-
import { DatabaseServiceTag } from '../effect/services'
|
|
7
|
+
import { buildWorkerInfrastructureLayer } from '../effect'
|
|
8
|
+
import { DatabaseServiceTag, RuntimeAdaptersServiceTag } from '../effect/services'
|
|
9
9
|
import { lotaRuntimeEnvConfig, parseLotaRuntimeConfig, parseWorkerBootstrapEnv } from '../runtime/runtime-config'
|
|
10
|
-
import { getConfiguredPluginDatabaseConnector } from '../runtime/runtime-extensions'
|
|
11
10
|
import { FirecrawlLive } from '../tools/firecrawl-client'
|
|
12
11
|
import { getErrorMessage } from '../utils/errors'
|
|
13
12
|
|
|
@@ -85,7 +84,6 @@ function ensureSandboxedWorkerRuntimeConfigured(): Promise<WorkerManagedRuntime>
|
|
|
85
84
|
sandboxedWorkerSetupPromise = Effect.runPromise(
|
|
86
85
|
Effect.gen(function* () {
|
|
87
86
|
const runtimeConfig = yield* buildSandboxedWorkerRuntimeConfigEffect()
|
|
88
|
-
yield* Effect.sync(() => configureLotaLogger(resolveLotaLogLevel(Bun.env.LOG_LEVEL) ?? 'info'))
|
|
89
87
|
|
|
90
88
|
const infrastructureLayer = buildWorkerInfrastructureLayer(runtimeConfig)
|
|
91
89
|
|
|
@@ -95,10 +93,6 @@ function ensureSandboxedWorkerRuntimeConfigured(): Promise<WorkerManagedRuntime>
|
|
|
95
93
|
|
|
96
94
|
const managedRuntime = ManagedRuntime.make(fullLayer)
|
|
97
95
|
|
|
98
|
-
yield* Effect.sync(() => {
|
|
99
|
-
setLotaSdkRuntime(managedRuntime)
|
|
100
|
-
})
|
|
101
|
-
|
|
102
96
|
return managedRuntime
|
|
103
97
|
}),
|
|
104
98
|
).catch((error) => {
|
|
@@ -137,11 +131,16 @@ export function initializeSandboxedWorkerRuntime(): Promise<WorkerManagedRuntime
|
|
|
137
131
|
catch: (error) => toSandboxedWorkerBootstrapError('connect-db', error),
|
|
138
132
|
})
|
|
139
133
|
|
|
134
|
+
const runtimeAdapters = yield* Effect.tryPromise({
|
|
135
|
+
try: () => runtime.runPromise(Effect.service(RuntimeAdaptersServiceTag)),
|
|
136
|
+
catch: (error) => toSandboxedWorkerBootstrapError('initialize', error),
|
|
137
|
+
})
|
|
138
|
+
|
|
140
139
|
yield* Effect.tryPromise({
|
|
141
140
|
try: () =>
|
|
142
141
|
connectWithStartupRetry({
|
|
143
142
|
connect: () => {
|
|
144
|
-
const connectPluginRuntimeDatabases =
|
|
143
|
+
const connectPluginRuntimeDatabases = runtimeAdapters.connectPluginDatabases
|
|
145
144
|
return connectPluginRuntimeDatabases ? connectPluginRuntimeDatabases() : Promise.resolve()
|
|
146
145
|
},
|
|
147
146
|
label: 'sandboxed worker plugin database runtime',
|
|
@@ -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'
|
|
@@ -19,14 +26,19 @@ import { createTracedWorkerProcessor } from './worker-utils'
|
|
|
19
26
|
|
|
20
27
|
const runtime = await initializeSandboxedWorkerRuntime()
|
|
21
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)
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { isAgentName } from '../config/agent-defaults'
|
|
2
1
|
import { compactWhitespace, readRecord, readString } from '../utils/string'
|
|
3
2
|
import type { DigestMessage } from './utils/thread-message-query'
|
|
4
3
|
|
|
@@ -26,7 +25,7 @@ function normalizeFilePartMetadata(part: DigestMessagePart): string | null {
|
|
|
26
25
|
|
|
27
26
|
function extractAssistantLabel(
|
|
28
27
|
message: DigestMessageForTranscript,
|
|
29
|
-
isKnownAgentName: (value: string) => boolean
|
|
28
|
+
isKnownAgentName: (value: string) => boolean,
|
|
30
29
|
): string {
|
|
31
30
|
const metadataAgentId =
|
|
32
31
|
typeof message.metadata?.agentId === 'string' ? message.metadata.agentId.trim().toLowerCase() : ''
|
|
@@ -44,11 +43,11 @@ function extractAssistantLabel(
|
|
|
44
43
|
|
|
45
44
|
export function buildDigestTranscript(params: {
|
|
46
45
|
messages: DigestMessageForTranscript[]
|
|
47
|
-
isKnownAgentName
|
|
46
|
+
isKnownAgentName: (value: string) => boolean
|
|
48
47
|
}): { transcript: string; involvedAgentNames: string[] } {
|
|
49
48
|
const lines: string[] = []
|
|
50
49
|
const involvedAgentNames = new Set<string>()
|
|
51
|
-
const isKnownAgentName = params
|
|
50
|
+
const { isKnownAgentName } = params
|
|
52
51
|
|
|
53
52
|
for (const message of params.messages) {
|
|
54
53
|
if (message.role !== 'user' && message.role !== 'assistant') continue
|
|
@@ -3,17 +3,18 @@ import type { Context } from 'effect'
|
|
|
3
3
|
import { BoundQuery } from 'surrealdb'
|
|
4
4
|
import { z } from 'zod'
|
|
5
5
|
|
|
6
|
+
import type { ResolvedAgentConfig } from '../config/agent-defaults'
|
|
7
|
+
import { isAgentName } from '../config/agent-defaults'
|
|
6
8
|
import { serverLogger } from '../config/logger'
|
|
7
9
|
import { ensureRecordId, recordIdToString } from '../db/record-id'
|
|
8
10
|
import type { RecordIdRef } from '../db/record-id'
|
|
9
11
|
import type { SurrealDBService } from '../db/service'
|
|
10
12
|
import { TABLES } from '../db/tables'
|
|
11
13
|
import { effectTryPromise } from '../effect/helpers'
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
import type {
|
|
15
|
+
OrganizationLearningQueueRuntime,
|
|
16
|
+
RegularChatMemoryDigestJob,
|
|
15
17
|
} from '../queues/organization-learning.queue'
|
|
16
|
-
import type { RegularChatMemoryDigestJob } from '../queues/organization-learning.queue'
|
|
17
18
|
import { createHelperModelRuntime } from '../runtime/helper-model'
|
|
18
19
|
import type { LotaRuntimeAdapters, LotaRuntimeBackgroundCursor } from '../runtime/runtime-extensions'
|
|
19
20
|
import type { MemoryServiceTag } from '../services/memory/memory.service'
|
|
@@ -43,10 +44,12 @@ class MemoryDigestError extends Schema.TaggedErrorClass<MemoryDigestError>()('Me
|
|
|
43
44
|
const REGULAR_CHAT_MEMORY_DIGEST_TIMEOUT_MS = 10 * 60 * 1000
|
|
44
45
|
const WorkspaceMemoryRowSchema = z.object({ content: z.string() })
|
|
45
46
|
export interface RegularChatDigestServices {
|
|
47
|
+
agentConfig: ResolvedAgentConfig
|
|
46
48
|
databaseService: SurrealDBService
|
|
47
49
|
memoryService: Context.Service.Shape<typeof MemoryServiceTag>
|
|
48
50
|
socialChatHistoryService: Context.Service.Shape<typeof SocialChatHistoryServiceTag>
|
|
49
51
|
runtimeAdapters: LotaRuntimeAdapters
|
|
52
|
+
organizationLearningQueue: OrganizationLearningQueueRuntime
|
|
50
53
|
}
|
|
51
54
|
|
|
52
55
|
const ExtractedFactSchema = z.object({
|
|
@@ -240,7 +243,10 @@ function runRegularChatMemoryDigestEffect(
|
|
|
240
243
|
}
|
|
241
244
|
|
|
242
245
|
const combinedMessages = [...threadMessages, ...socialMessages].sort(compareDigestMessageOrder)
|
|
243
|
-
const { transcript, involvedAgentNames } = buildDigestTranscript({
|
|
246
|
+
const { transcript, involvedAgentNames } = buildDigestTranscript({
|
|
247
|
+
messages: combinedMessages,
|
|
248
|
+
isKnownAgentName: (value: string) => isAgentName(services.agentConfig, value),
|
|
249
|
+
})
|
|
244
250
|
const existingMemories = yield* effectTryPromise(() =>
|
|
245
251
|
loadExistingOrganizationMemories(services.databaseService, orgId),
|
|
246
252
|
)
|
|
@@ -331,8 +337,10 @@ function runRegularChatMemoryDigestEffect(
|
|
|
331
337
|
|
|
332
338
|
const followUpScheduled = hasMoreThreadMessages || hasMoreSocialMessages
|
|
333
339
|
if (followUpScheduled) {
|
|
334
|
-
yield* effectTryPromise(() =>
|
|
335
|
-
|
|
340
|
+
yield* effectTryPromise(() =>
|
|
341
|
+
services.organizationLearningQueue.clearRegularChatMemoryDigestDeduplicationKey(orgId),
|
|
342
|
+
)
|
|
343
|
+
yield* effectTryPromise(() => services.organizationLearningQueue.enqueueRegularChatMemoryDigest({ orgId }))
|
|
336
344
|
}
|
|
337
345
|
|
|
338
346
|
serverLogger.info`Regular chat memory digest completed for ${orgId}: threadMessages=${threadMessages.length}, socialMessages=${socialMessages.length}, facts=${synthesis.facts.length}, followUpScheduled=${followUpScheduled}`
|
|
@@ -350,7 +358,7 @@ export function runRegularChatMemoryDigest(
|
|
|
350
358
|
data: RegularChatMemoryDigestJob,
|
|
351
359
|
services: RegularChatDigestServices,
|
|
352
360
|
): Promise<RegularChatDigestRunResult> {
|
|
353
|
-
const {
|
|
361
|
+
const { runtimeAdapters } = services
|
|
354
362
|
const orgRef = ensureRecordId(data.orgId, TABLES.ORGANIZATION)
|
|
355
363
|
const orgId = recordIdToString(orgRef, TABLES.ORGANIZATION)
|
|
356
364
|
const workspaceProvider = runtimeAdapters.workspaceProvider
|
|
@@ -367,12 +375,11 @@ export function runRegularChatMemoryDigest(
|
|
|
367
375
|
const withMemoryLock = runtimeAdapters.withWorkspaceMemoryLock
|
|
368
376
|
const runDigest = () =>
|
|
369
377
|
Effect.runPromise(
|
|
370
|
-
runRegularChatMemoryDigestEffect(
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
),
|
|
378
|
+
runRegularChatMemoryDigestEffect(services, orgRef, orgId, workspaceProvider) as Effect.Effect<
|
|
379
|
+
RegularChatDigestRunResult,
|
|
380
|
+
never,
|
|
381
|
+
never
|
|
382
|
+
>,
|
|
376
383
|
)
|
|
377
384
|
|
|
378
385
|
return withMemoryLock ? withMemoryLock(orgId, runDigest) : runDigest()
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Context, Cause } from 'effect'
|
|
2
2
|
import { Effect } from 'effect'
|
|
3
3
|
|
|
4
|
+
import type { ResolvedAgentConfig } from '../config/agent-defaults'
|
|
5
|
+
import { isAgentName } from '../config/agent-defaults'
|
|
4
6
|
import { serverLogger } from '../config/logger'
|
|
5
7
|
import { ensureRecordId, recordIdToString } from '../db/record-id'
|
|
6
8
|
import type { RecordIdRef } from '../db/record-id'
|
|
@@ -27,6 +29,7 @@ const SKILL_EXTRACTION_TIMEOUT_MS = 10 * 60 * 1000
|
|
|
27
29
|
const MIN_MESSAGE_THRESHOLD = 10
|
|
28
30
|
|
|
29
31
|
export interface SkillExtractionServices {
|
|
32
|
+
agentConfig: ResolvedAgentConfig
|
|
30
33
|
databaseService: SurrealDBService
|
|
31
34
|
learnedSkillService: Context.Service.Shape<typeof LearnedSkillServiceTag>
|
|
32
35
|
socialChatHistoryService: Context.Service.Shape<typeof SocialChatHistoryServiceTag>
|
|
@@ -149,7 +152,10 @@ function runSkillExtractionEffect(
|
|
|
149
152
|
}
|
|
150
153
|
|
|
151
154
|
const sortedMessages = [...messages].sort(compareDigestMessageOrder)
|
|
152
|
-
const { transcript } = buildDigestTranscript({
|
|
155
|
+
const { transcript } = buildDigestTranscript({
|
|
156
|
+
messages: sortedMessages,
|
|
157
|
+
isKnownAgentName: (value: string) => isAgentName(services.agentConfig, value),
|
|
158
|
+
})
|
|
153
159
|
|
|
154
160
|
const existingSkills = yield* services.learnedSkillService.listForOrg(orgId)
|
|
155
161
|
const existingSkillsSummary =
|
|
@@ -301,7 +307,7 @@ export function runSkillExtraction(
|
|
|
301
307
|
data: SkillExtractionJob,
|
|
302
308
|
services: SkillExtractionServices,
|
|
303
309
|
): Promise<SkillExtractionRunResult> {
|
|
304
|
-
const {
|
|
310
|
+
const { runtimeAdapters } = services
|
|
305
311
|
const orgRef = ensureRecordId(data.orgId, TABLES.ORGANIZATION)
|
|
306
312
|
const orgId = recordIdToString(orgRef, TABLES.ORGANIZATION)
|
|
307
313
|
const workspaceProvider = runtimeAdapters.workspaceProvider
|
|
@@ -317,19 +323,11 @@ export function runSkillExtraction(
|
|
|
317
323
|
const withMemoryLock = runtimeAdapters.withWorkspaceMemoryLock
|
|
318
324
|
const runExtraction = () =>
|
|
319
325
|
Effect.runPromise(
|
|
320
|
-
runSkillExtractionEffect(
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
runtimeAdapters,
|
|
326
|
-
embeddingModel: services.embeddingModel,
|
|
327
|
-
},
|
|
328
|
-
orgRef,
|
|
329
|
-
orgId,
|
|
330
|
-
workspaceProvider,
|
|
331
|
-
embeddings,
|
|
332
|
-
),
|
|
326
|
+
runSkillExtractionEffect(services, orgRef, orgId, workspaceProvider, embeddings) as Effect.Effect<
|
|
327
|
+
SkillExtractionRunResult,
|
|
328
|
+
never,
|
|
329
|
+
never
|
|
330
|
+
>,
|
|
333
331
|
)
|
|
334
332
|
|
|
335
333
|
return withMemoryLock ? withMemoryLock(orgId, runExtraction) : runExtraction()
|