@lota-sdk/core 0.4.10 → 0.4.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/src/ai-gateway/ai-gateway.ts +214 -98
- 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/model-constants.ts +1 -0
- 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 +2 -0
- package/src/runtime/indexed-repositories-policy.ts +2 -6
- package/src/runtime/live-turn-trace.ts +344 -0
- 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 +125 -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 +92 -45
- package/src/services/thread/thread-turn-streaming.ts +60 -28
- package/src/services/thread/thread-turn.ts +212 -46
- 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,10 +3,10 @@ import { SUBMIT_PLAN_TURN_RESULT_TOOL_NAME, toTimestamp, withMessageCreatedAt }
|
|
|
3
3
|
import type { ToolSet, UIMessageStreamWriter } from 'ai'
|
|
4
4
|
import { Schema, Effect } from 'effect'
|
|
5
5
|
|
|
6
|
+
import type { ResolvedAgentConfig } from '../../config/agent-defaults'
|
|
6
7
|
import { aiLogger } from '../../config/logger'
|
|
7
8
|
import type { RecordIdRef } from '../../db/record-id'
|
|
8
9
|
import { effectTryMaybeAsync, effectTryPromise as effectTryPromiseShared } from '../../effect/helpers'
|
|
9
|
-
import { runPromise } from '../../effect/runtime'
|
|
10
10
|
import type { readRuntimeAgentIdentityOverrides } from '../../runtime/agent-identity-overrides'
|
|
11
11
|
import { resolveRuntimeAgentDisplayName } from '../../runtime/agent-identity-overrides'
|
|
12
12
|
import { OWNERSHIP_DISPATCH_BLOCKED_TOOL_NAMES } from '../../runtime/agent-runtime-policy'
|
|
@@ -67,6 +67,7 @@ interface VisibleAgentRunParams {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
interface VisibleAgentRunnerDeps<TBuildTurnToolParams> {
|
|
70
|
+
agentConfig: ResolvedAgentConfig
|
|
70
71
|
agentFactoryConfig: { buildAgentTools: (params: TBuildTurnToolParams) => Promise<ToolSet> | ToolSet }
|
|
71
72
|
buildTurnToolParams: (params: {
|
|
72
73
|
agentId: string
|
|
@@ -100,10 +101,10 @@ export function createThreadTurnVisibleAgentRunner<TBuildTurnToolParams>(
|
|
|
100
101
|
{ message: Schema.String, cause: Schema.optional(Schema.Defect) },
|
|
101
102
|
) {}
|
|
102
103
|
|
|
103
|
-
const effectTryPromise = <A>(
|
|
104
|
-
evaluate: () => PromiseLike<A> | Effect.Effect<A, unknown>,
|
|
104
|
+
const effectTryPromise = <A, R = never>(
|
|
105
|
+
evaluate: () => PromiseLike<A> | Effect.Effect<A, unknown, R>,
|
|
105
106
|
message: string,
|
|
106
|
-
): Effect.Effect<A, ThreadTurnExecutionError> =>
|
|
107
|
+
): Effect.Effect<A, ThreadTurnExecutionError, R> =>
|
|
107
108
|
effectTryPromiseShared(evaluate, (error) => new ThreadTurnExecutionError({ message, cause: error }))
|
|
108
109
|
|
|
109
110
|
function effectFromMaybePromise<A>(
|
|
@@ -130,14 +131,13 @@ export function createThreadTurnVisibleAgentRunner<TBuildTurnToolParams>(
|
|
|
130
131
|
)
|
|
131
132
|
|
|
132
133
|
const createObserver = (agentId: string) => ({
|
|
133
|
-
run: <T>(fn: () => T | Promise<T>) =>
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
),
|
|
134
|
+
run: async <T>(fn: () => T | Promise<T>): Promise<T> => {
|
|
135
|
+
try {
|
|
136
|
+
return await fn()
|
|
137
|
+
} catch (error) {
|
|
138
|
+
throw new ThreadTurnExecutionError({ message: `Agent observer run failed (agent=${agentId}).`, cause: error })
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
141
|
recordError: (error: unknown) => {
|
|
142
142
|
aiLogger.error`Agent run failed (agent=${agentId}): ${error}`
|
|
143
143
|
},
|
|
@@ -151,54 +151,53 @@ export function createThreadTurnVisibleAgentRunner<TBuildTurnToolParams>(
|
|
|
151
151
|
agentId: string,
|
|
152
152
|
agentName: string,
|
|
153
153
|
metadataPatch?: NonNullable<MessageMetadata>,
|
|
154
|
-
)
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
},
|
|
173
|
-
},
|
|
174
|
-
toTimestamp(message.metadata?.createdAt) ?? nowEpochMillis(),
|
|
175
|
-
)
|
|
176
|
-
|
|
177
|
-
const committedConsultMessages = collectCompletedConsultTeamMessages({ responseMessage: response }).flatMap(
|
|
178
|
-
(consultMessage) => {
|
|
179
|
-
const consultAgentId = readOptionalString(consultMessage.metadata?.agentId)
|
|
180
|
-
const consultAgentName = readOptionalString(consultMessage.metadata?.agentName)
|
|
181
|
-
if (!consultAgentId || !consultAgentName) {
|
|
182
|
-
return []
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
return [toCommittedAssistantMessage(consultMessage, consultAgentId, consultAgentName)]
|
|
154
|
+
) =>
|
|
155
|
+
Effect.gen(function* () {
|
|
156
|
+
// Persist the response even if the run is being interrupted (e.g., lease
|
|
157
|
+
// refresh was rejected between the final stream chunk and this commit).
|
|
158
|
+
// The LLM tokens have already been consumed; the message must reach the
|
|
159
|
+
// thread history so callers and post-turn side effects observe the
|
|
160
|
+
// completed turn. `Effect.uninterruptible` shields the persist from the
|
|
161
|
+
// surrounding interrupt without blocking later steps from handling it.
|
|
162
|
+
const toCommittedAssistantMessage = (
|
|
163
|
+
message: ChatMessage,
|
|
164
|
+
resolvedAgentId: string,
|
|
165
|
+
resolvedAgentName: string,
|
|
166
|
+
patch?: NonNullable<MessageMetadata>,
|
|
167
|
+
) =>
|
|
168
|
+
withMessageCreatedAt(
|
|
169
|
+
{
|
|
170
|
+
...message,
|
|
171
|
+
metadata: { ...message.metadata, ...buildAgentMetadataPatch(resolvedAgentId, resolvedAgentName), ...patch },
|
|
186
172
|
},
|
|
173
|
+
toTimestamp(message.metadata?.createdAt) ?? nowEpochMillis(),
|
|
187
174
|
)
|
|
188
175
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
176
|
+
const committedConsultMessages = collectCompletedConsultTeamMessages({ responseMessage: response }).flatMap(
|
|
177
|
+
(consultMessage) => {
|
|
178
|
+
const consultAgentId = readOptionalString(consultMessage.metadata?.agentId)
|
|
179
|
+
const consultAgentName = readOptionalString(consultMessage.metadata?.agentName)
|
|
180
|
+
if (!consultAgentId || !consultAgentName) {
|
|
181
|
+
return []
|
|
182
|
+
}
|
|
192
183
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
}
|
|
197
|
-
yield* failIfRunAborted()
|
|
184
|
+
return [toCommittedAssistantMessage(consultMessage, consultAgentId, consultAgentName)]
|
|
185
|
+
},
|
|
186
|
+
)
|
|
198
187
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
188
|
+
const committed = toCommittedAssistantMessage(response, agentId, agentName, metadataPatch)
|
|
189
|
+
const messagesToPersist = [...committedConsultMessages, committed]
|
|
190
|
+
yield* Effect.uninterruptible(
|
|
191
|
+
deps.threadMessageService.upsertMessagesEffect({ threadId: deps.threadRef, messages: messagesToPersist }),
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
for (const persistedMessage of messagesToPersist) {
|
|
195
|
+
deps.threadTurnMessageContext.appendMessages([persistedMessage])
|
|
196
|
+
deps.onPersistedMessage(persistedMessage)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return committed
|
|
200
|
+
})
|
|
202
201
|
|
|
203
202
|
const runVisibleAgentEffect = Effect.fn('ThreadTurnExecution.runVisibleAgent')(function* (
|
|
204
203
|
runParams: VisibleAgentRunParams,
|
|
@@ -243,36 +242,41 @@ export function createThreadTurnVisibleAgentRunner<TBuildTurnToolParams>(
|
|
|
243
242
|
).pipe(Effect.withSpan('ThreadTurnExecution.streamVisibleAgent'))
|
|
244
243
|
deps.setMemoryBlock(runMemoryBlock)
|
|
245
244
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
)
|
|
254
|
-
|
|
255
|
-
|
|
245
|
+
// Commit the response under `uninterruptible` so a late lease-lost or
|
|
246
|
+
// stop signal arriving after the stream completed still writes the
|
|
247
|
+
// already-generated assistant message into the thread history. Without
|
|
248
|
+
// this, a race between stream completion and lease refresh rejection
|
|
249
|
+
// swallows the response without any error trace.
|
|
250
|
+
return yield* Effect.uninterruptible(
|
|
251
|
+
effectTryPromise(
|
|
252
|
+
() =>
|
|
253
|
+
commitAssistantResponse(
|
|
254
|
+
responseMessage,
|
|
255
|
+
runParams.agentId,
|
|
256
|
+
resolveRuntimeAgentDisplayName(deps.agentConfig, deps.agentIdentityOverrides, runParams.agentId),
|
|
257
|
+
runParams.metadataPatch,
|
|
258
|
+
),
|
|
259
|
+
`Failed to commit assistant response for ${runParams.agentId}.`,
|
|
260
|
+
).pipe(Effect.withSpan('ThreadTurnExecution.commitAssistantResponse')),
|
|
261
|
+
)
|
|
256
262
|
})
|
|
257
263
|
|
|
258
|
-
const runVisibleAgent = (runParams: VisibleAgentRunParams)
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
mode: runParams.mode,
|
|
270
|
-
}),
|
|
271
|
-
includeExecutionPlanTools: runParams.includeExecutionPlanTools ?? runParams.mode !== 'fixedThreadMode',
|
|
272
|
-
extraMessageCount: runParams.extraMessages?.length ?? 0,
|
|
273
|
-
extraToolCount: runParams.extraTools ? Object.keys(runParams.extraTools).length : 0,
|
|
264
|
+
const runVisibleAgent = (runParams: VisibleAgentRunParams) =>
|
|
265
|
+
runVisibleAgentEffect(runParams).pipe(
|
|
266
|
+
Effect.annotateSpans(
|
|
267
|
+
compactSpanAttributes({
|
|
268
|
+
...buildThreadTurnSpanAttributes({
|
|
269
|
+
threadRef: deps.threadRef,
|
|
270
|
+
orgRef: deps.streamCtx.orgRef,
|
|
271
|
+
userRef: deps.streamCtx.userRef,
|
|
272
|
+
agentId: runParams.agentId,
|
|
273
|
+
threadType: deps.streamCtx.thread.type,
|
|
274
|
+
mode: runParams.mode,
|
|
274
275
|
}),
|
|
275
|
-
|
|
276
|
+
includeExecutionPlanTools: runParams.includeExecutionPlanTools ?? runParams.mode !== 'fixedThreadMode',
|
|
277
|
+
extraMessageCount: runParams.extraMessages?.length ?? 0,
|
|
278
|
+
extraToolCount: runParams.extraTools ? Object.keys(runParams.extraTools).length : 0,
|
|
279
|
+
}),
|
|
276
280
|
),
|
|
277
281
|
)
|
|
278
282
|
|
|
@@ -13,12 +13,6 @@ import type { UIMessageStreamWriter } from 'ai'
|
|
|
13
13
|
import { Clock, Context, Schema, Effect, Layer } from 'effect'
|
|
14
14
|
|
|
15
15
|
import type { CoreThreadProfile } from '../../config/agent-defaults'
|
|
16
|
-
import {
|
|
17
|
-
getAgentRoster,
|
|
18
|
-
getLeadAgentId,
|
|
19
|
-
getCoreThreadProfile,
|
|
20
|
-
getResolvedAgentFactoryConfig,
|
|
21
|
-
} from '../../config/agent-defaults'
|
|
22
16
|
import { aiLogger } from '../../config/logger'
|
|
23
17
|
import type { RecordIdRef } from '../../db/record-id'
|
|
24
18
|
import { recordIdToString } from '../../db/record-id'
|
|
@@ -26,8 +20,15 @@ import { TABLES } from '../../db/tables'
|
|
|
26
20
|
import type { DatabaseError, ServiceError } from '../../effect/errors'
|
|
27
21
|
import { ThreadTurnError } from '../../effect/errors'
|
|
28
22
|
import { makeEffectTryPromiseWithMessage } from '../../effect/helpers'
|
|
29
|
-
import {
|
|
30
|
-
|
|
23
|
+
import {
|
|
24
|
+
AgentConfigServiceTag,
|
|
25
|
+
AgentFactoryServiceTag,
|
|
26
|
+
RuntimeAdaptersServiceTag,
|
|
27
|
+
TurnHooksServiceTag,
|
|
28
|
+
} from '../../effect/services'
|
|
29
|
+
import type { ContextCompactionQueueRuntime } from '../../queues/context-compaction.queue'
|
|
30
|
+
import { LotaQueuesServiceTag } from '../../queues/queues.service'
|
|
31
|
+
import type { TitleGenerationQueueRuntime } from '../../queues/title-generation.queue'
|
|
31
32
|
import {
|
|
32
33
|
readRuntimeAgentIdentityOverrides,
|
|
33
34
|
resolveRuntimeAgentDisplayName,
|
|
@@ -42,7 +43,6 @@ import { createExecutionPlanInstructionSectionCache, toExecutionPlanCacheError }
|
|
|
42
43
|
import type { HelperModelRuntime } from '../../runtime/helper-model'
|
|
43
44
|
import { HelperModelTag } from '../../runtime/helper-model'
|
|
44
45
|
import { runPostTurnSideEffects } from '../../runtime/post-turn-side-effects'
|
|
45
|
-
import { getRuntimeAdapters, getTurnHooks } from '../../runtime/runtime-extensions'
|
|
46
46
|
import { extractMessageText, toOptionalTrimmedString } from '../../runtime/thread-chat-helpers'
|
|
47
47
|
import {
|
|
48
48
|
buildPlanTurnInstructionSections,
|
|
@@ -93,6 +93,8 @@ interface ThreadTurnPreparationServiceContext {
|
|
|
93
93
|
threadMessageService: ReturnType<typeof makeThreadMessageService>
|
|
94
94
|
threadService: ReturnType<typeof makeThreadService>
|
|
95
95
|
contextCompactionRuntime: ReturnType<typeof createWiredContextCompactionRuntime>
|
|
96
|
+
contextCompactionQueue: ContextCompactionQueueRuntime
|
|
97
|
+
titleGenerationQueue: TitleGenerationQueueRuntime
|
|
96
98
|
}
|
|
97
99
|
|
|
98
100
|
type ThreadTurnPreparationRuntimeDeps = ThreadTurnPreparationServiceContext
|
|
@@ -365,8 +367,10 @@ const prepareThreadRunCoreEffect = Effect.fn('ThreadTurnPreparation.prepareThrea
|
|
|
365
367
|
deps: ThreadTurnPreparationRuntimeDeps,
|
|
366
368
|
params: ThreadRunCoreParams,
|
|
367
369
|
) {
|
|
368
|
-
const runtimeAdapters =
|
|
369
|
-
const turnHooks =
|
|
370
|
+
const runtimeAdapters = yield* RuntimeAdaptersServiceTag
|
|
371
|
+
const turnHooks = yield* TurnHooksServiceTag
|
|
372
|
+
const agentConfig = yield* AgentConfigServiceTag
|
|
373
|
+
const agentFactoryConfig = yield* AgentFactoryServiceTag
|
|
370
374
|
const workspaceProvider = runtimeAdapters.workspaceProvider
|
|
371
375
|
const workspacePromise =
|
|
372
376
|
params.kind !== 'approvalContinuation' && workspaceProvider
|
|
@@ -488,17 +492,19 @@ const prepareThreadRunCoreEffect = Effect.fn('ThreadTurnPreparation.prepareThrea
|
|
|
488
492
|
threadRecord.title === THREAD.DEFAULT_TITLE &&
|
|
489
493
|
messageText.length > 0
|
|
490
494
|
) {
|
|
491
|
-
void safeEnqueue(
|
|
492
|
-
|
|
493
|
-
|
|
495
|
+
void safeEnqueue(
|
|
496
|
+
() =>
|
|
497
|
+
deps.titleGenerationQueue.enqueueThreadTitleGeneration({ threadId: threadIdString, sourceText: messageText }),
|
|
498
|
+
{ operationName: 'thread-title-generation' },
|
|
499
|
+
)
|
|
494
500
|
}
|
|
495
501
|
|
|
496
502
|
if (thread.type === 'thread' && !thread.threadType) {
|
|
497
503
|
return yield* new ThreadTurnError({ message: 'Core threads require a thread type.', reason: 'bad-request' })
|
|
498
504
|
}
|
|
499
505
|
const coreThreadProfile: CoreThreadProfile | null =
|
|
500
|
-
thread.type === 'thread' && thread.threadType ? getCoreThreadProfile(thread.threadType) : null
|
|
501
|
-
const defaultLeadAgentId =
|
|
506
|
+
thread.type === 'thread' && thread.threadType ? agentConfig.getCoreThreadProfile(thread.threadType) : null
|
|
507
|
+
const defaultLeadAgentId = agentConfig.leadAgentId
|
|
502
508
|
const visibleThreadAgentId =
|
|
503
509
|
params.agentIdOverride ??
|
|
504
510
|
(thread.type === 'default' ? thread.agentId : (coreThreadProfile?.config.agentId ?? defaultLeadAgentId))
|
|
@@ -517,6 +523,8 @@ const prepareThreadRunCoreEffect = Effect.fn('ThreadTurnPreparation.prepareThrea
|
|
|
517
523
|
workspacePromise,
|
|
518
524
|
workspaceProvider,
|
|
519
525
|
turnHooks,
|
|
526
|
+
runtimeAdapters,
|
|
527
|
+
pluginRuntime: agentFactoryConfig.pluginRuntime,
|
|
520
528
|
}),
|
|
521
529
|
'Failed to assemble thread turn context.',
|
|
522
530
|
).pipe(Effect.withSpan('ThreadTurnPreparation.assembleThreadTurnContext'))
|
|
@@ -674,7 +682,11 @@ const prepareThreadRunCoreEffect = Effect.fn('ThreadTurnPreparation.prepareThrea
|
|
|
674
682
|
serverRunId: string
|
|
675
683
|
runAbort: ReturnType<typeof createServerRunAbortController>
|
|
676
684
|
writer?: UIMessageStreamWriter<ChatMessage>
|
|
677
|
-
}): Effect.Effect<
|
|
685
|
+
}): Effect.Effect<
|
|
686
|
+
PreparedThreadTurnResult | void,
|
|
687
|
+
DatabaseError | ThreadTurnError | ThreadTurnPreparationError,
|
|
688
|
+
unknown
|
|
689
|
+
> =>
|
|
678
690
|
Effect.ensuring(
|
|
679
691
|
Effect.gen(function* () {
|
|
680
692
|
const currentRunAbort = runParams.runAbort
|
|
@@ -693,8 +705,6 @@ const prepareThreadRunCoreEffect = Effect.fn('ThreadTurnPreparation.prepareThrea
|
|
|
693
705
|
.pipe(Effect.withSpan('ThreadTurnPreparation.setActiveTurn'))
|
|
694
706
|
}
|
|
695
707
|
|
|
696
|
-
const agentFactoryConfig = getResolvedAgentFactoryConfig()
|
|
697
|
-
|
|
698
708
|
const streamCtx: StreamAgentResponseContext = {
|
|
699
709
|
turnHooks,
|
|
700
710
|
thread,
|
|
@@ -717,6 +727,7 @@ const prepareThreadRunCoreEffect = Effect.fn('ThreadTurnPreparation.prepareThrea
|
|
|
717
727
|
}
|
|
718
728
|
|
|
719
729
|
const { runVisibleAgent } = createThreadTurnVisibleAgentRunner({
|
|
730
|
+
agentConfig,
|
|
720
731
|
agentFactoryConfig: { buildAgentTools: agentFactoryConfig.buildAgentTools },
|
|
721
732
|
buildTurnToolParams,
|
|
722
733
|
threadTurnMessageContext,
|
|
@@ -778,7 +789,7 @@ const prepareThreadRunCoreEffect = Effect.fn('ThreadTurnPreparation.prepareThrea
|
|
|
778
789
|
).pipe(Effect.withSpan('ThreadTurnPreparation.executeDirectThread'))
|
|
779
790
|
} else {
|
|
780
791
|
const wsMembers = (thread as { members?: string[] }).members ?? []
|
|
781
|
-
const members = wsMembers.length > 0 ? wsMembers : [...
|
|
792
|
+
const members = wsMembers.length > 0 ? wsMembers : [...agentConfig.roster]
|
|
782
793
|
const fallbackAgentId = coreThreadProfile?.config.agentId ?? defaultLeadAgentId
|
|
783
794
|
yield* failIfRunAborted()
|
|
784
795
|
writeMultiAgentEvent(runParams.writer, { phase: 'routing', note: 'Routing this turn to the right agent.' })
|
|
@@ -791,6 +802,7 @@ const prepareThreadRunCoreEffect = Effect.fn('ThreadTurnPreparation.prepareThrea
|
|
|
791
802
|
const triageResult = yield* effectTryPromise(
|
|
792
803
|
() =>
|
|
793
804
|
triageThreadMessage({
|
|
805
|
+
agentConfig,
|
|
794
806
|
threadTitle: thread.title,
|
|
795
807
|
members,
|
|
796
808
|
messageText,
|
|
@@ -841,6 +853,7 @@ const prepareThreadRunCoreEffect = Effect.fn('ThreadTurnPreparation.prepareThrea
|
|
|
841
853
|
const checkResult = yield* effectTryPromise(
|
|
842
854
|
() =>
|
|
843
855
|
checkForNextAgent({
|
|
856
|
+
agentConfig,
|
|
844
857
|
threadTitle: thread.title,
|
|
845
858
|
members,
|
|
846
859
|
messageText,
|
|
@@ -859,7 +872,7 @@ const prepareThreadRunCoreEffect = Effect.fn('ThreadTurnPreparation.prepareThrea
|
|
|
859
872
|
writeMultiAgentEvent(runParams.writer, {
|
|
860
873
|
phase: 'waiting-for-agent',
|
|
861
874
|
agentId: checkResult.agentId,
|
|
862
|
-
agentName: resolveRuntimeAgentDisplayName(agentIdentityOverrides, checkResult.agentId),
|
|
875
|
+
agentName: resolveRuntimeAgentDisplayName(agentConfig, agentIdentityOverrides, checkResult.agentId),
|
|
863
876
|
note: checkResult.routingContext ?? undefined,
|
|
864
877
|
})
|
|
865
878
|
|
|
@@ -890,7 +903,7 @@ const prepareThreadRunCoreEffect = Effect.fn('ThreadTurnPreparation.prepareThrea
|
|
|
890
903
|
writeMultiAgentEvent(runParams.writer, {
|
|
891
904
|
phase: 'agent-message-persisted',
|
|
892
905
|
agentId: checkResult.agentId,
|
|
893
|
-
agentName: resolveRuntimeAgentDisplayName(agentIdentityOverrides, checkResult.agentId),
|
|
906
|
+
agentName: resolveRuntimeAgentDisplayName(agentConfig, agentIdentityOverrides, checkResult.agentId),
|
|
894
907
|
messageId: lastResponse.id,
|
|
895
908
|
})
|
|
896
909
|
}
|
|
@@ -919,7 +932,7 @@ const prepareThreadRunCoreEffect = Effect.fn('ThreadTurnPreparation.prepareThrea
|
|
|
919
932
|
contextSize: CONTEXT_WINDOW_TOKENS,
|
|
920
933
|
}),
|
|
921
934
|
enqueueCompaction: () =>
|
|
922
|
-
enqueueContextCompaction({
|
|
935
|
+
deps.contextCompactionQueue.enqueueContextCompaction({
|
|
923
936
|
domain: 'thread',
|
|
924
937
|
entityId: threadIdString,
|
|
925
938
|
contextSize: CONTEXT_WINDOW_TOKENS,
|
|
@@ -980,27 +993,9 @@ const prepareThreadRunCoreEffect = Effect.fn('ThreadTurnPreparation.prepareThrea
|
|
|
980
993
|
).pipe(Effect.withSpan('ThreadTurnPreparation.runPostTurnSideEffects'))
|
|
981
994
|
}
|
|
982
995
|
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
yield* effectTryPromise(
|
|
987
|
-
() =>
|
|
988
|
-
afterTurn({
|
|
989
|
-
thread,
|
|
990
|
-
threadRef,
|
|
991
|
-
orgRef,
|
|
992
|
-
userRef,
|
|
993
|
-
userName,
|
|
994
|
-
onboardingActive,
|
|
995
|
-
referenceUserMessage,
|
|
996
|
-
assistantMessages: allAssistantMessages,
|
|
997
|
-
latestThreadRecord,
|
|
998
|
-
context: buildContextResult,
|
|
999
|
-
}),
|
|
1000
|
-
'Failed to run afterTurn hook.',
|
|
1001
|
-
).pipe(Effect.withSpan('ThreadTurnPreparation.afterTurnHook'))
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
996
|
+
yield* Effect.sync(() => {
|
|
997
|
+
launchAfterTurnHook(latestThreadRecord)
|
|
998
|
+
})
|
|
1004
999
|
}).pipe(
|
|
1005
1000
|
Effect.catch((postRunError) =>
|
|
1006
1001
|
Effect.sync(() => {
|
|
@@ -1021,6 +1016,48 @@ const prepareThreadRunCoreEffect = Effect.fn('ThreadTurnPreparation.prepareThrea
|
|
|
1021
1016
|
assistantMessages: [...allAssistantMessages],
|
|
1022
1017
|
})
|
|
1023
1018
|
|
|
1019
|
+
const launchAfterTurnHook = (latestThreadRecord: typeof threadRecord) => {
|
|
1020
|
+
if (allAssistantMessages.length === 0 || params.kind === 'planTurn') {
|
|
1021
|
+
return
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
const afterTurn = turnHooks.afterTurn
|
|
1025
|
+
if (!afterTurn) {
|
|
1026
|
+
return
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
// `afterTurn` is host-owned follow-up work. Launch it detached so the
|
|
1030
|
+
// streamed turn closes after persistence/finalization instead of waiting on
|
|
1031
|
+
// onboarding/map side effects in the request path.
|
|
1032
|
+
void runPromiseWithCurrentContext(
|
|
1033
|
+
effectTryPromise(
|
|
1034
|
+
() =>
|
|
1035
|
+
afterTurn({
|
|
1036
|
+
thread,
|
|
1037
|
+
threadRef,
|
|
1038
|
+
orgRef,
|
|
1039
|
+
userRef,
|
|
1040
|
+
userName,
|
|
1041
|
+
onboardingActive,
|
|
1042
|
+
referenceUserMessage,
|
|
1043
|
+
assistantMessages: allAssistantMessages,
|
|
1044
|
+
latestThreadRecord,
|
|
1045
|
+
context: buildContextResult,
|
|
1046
|
+
}),
|
|
1047
|
+
'Failed to run afterTurn hook.',
|
|
1048
|
+
).pipe(
|
|
1049
|
+
Effect.withSpan('ThreadTurnPreparation.afterTurnHook'),
|
|
1050
|
+
Effect.catch((error) =>
|
|
1051
|
+
Effect.sync(() => {
|
|
1052
|
+
aiLogger.error`Thread afterTurn hook failed: ${error}`
|
|
1053
|
+
}),
|
|
1054
|
+
),
|
|
1055
|
+
),
|
|
1056
|
+
).catch((error) => {
|
|
1057
|
+
aiLogger.error`Thread afterTurn hook scheduling failed: ${error}`
|
|
1058
|
+
})
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1024
1061
|
const run = (writer?: UIMessageStreamWriter<ChatMessage>) => {
|
|
1025
1062
|
const serverRunId = Bun.randomUUIDv7()
|
|
1026
1063
|
|
|
@@ -1049,7 +1086,10 @@ const prepareThreadRunCoreEffect = Effect.fn('ThreadTurnPreparation.prepareThrea
|
|
|
1049
1086
|
}),
|
|
1050
1087
|
)
|
|
1051
1088
|
|
|
1052
|
-
return runEffect.pipe(
|
|
1089
|
+
return runEffect.pipe(
|
|
1090
|
+
Effect.withSpan('ThreadTurnPreparation.executeRun'),
|
|
1091
|
+
Effect.provide(currentContext),
|
|
1092
|
+
) as Effect.Effect<PreparedThreadTurnResult, DatabaseError | ThreadTurnError | ThreadTurnPreparationError, never>
|
|
1053
1093
|
}
|
|
1054
1094
|
|
|
1055
1095
|
return { originalMessages, run }
|
|
@@ -1066,6 +1106,8 @@ interface ThreadTurnPreparationDeps {
|
|
|
1066
1106
|
threadMessage: ReturnType<typeof makeThreadMessageService>
|
|
1067
1107
|
thread: ReturnType<typeof makeThreadService>
|
|
1068
1108
|
helperModelRuntime: HelperModelRuntime
|
|
1109
|
+
contextCompactionQueue: ContextCompactionQueueRuntime
|
|
1110
|
+
titleGenerationQueue: TitleGenerationQueueRuntime
|
|
1069
1111
|
}
|
|
1070
1112
|
|
|
1071
1113
|
export function makeThreadTurnPreparationService(deps: ThreadTurnPreparationDeps) {
|
|
@@ -1084,6 +1126,8 @@ export function makeThreadTurnPreparationService(deps: ThreadTurnPreparationDeps
|
|
|
1084
1126
|
now: nowEpochMillis,
|
|
1085
1127
|
randomId: () => Bun.randomUUIDv7(),
|
|
1086
1128
|
}),
|
|
1129
|
+
contextCompactionQueue: deps.contextCompactionQueue,
|
|
1130
|
+
titleGenerationQueue: deps.titleGenerationQueue,
|
|
1087
1131
|
}
|
|
1088
1132
|
const annotateTurnSpans = <A, E, R>(params: ThreadRunCoreParams, effect: Effect.Effect<A, E, R>) =>
|
|
1089
1133
|
effect.pipe(
|
|
@@ -1132,6 +1176,7 @@ export const ThreadTurnPreparationServiceLive = Layer.effect(
|
|
|
1132
1176
|
const planRun = yield* PlanRunServiceTag
|
|
1133
1177
|
const threadMessage = yield* ThreadMessageServiceTag
|
|
1134
1178
|
const thread = yield* ThreadServiceTag
|
|
1179
|
+
const queues = yield* LotaQueuesServiceTag
|
|
1135
1180
|
return makeThreadTurnPreparationService({
|
|
1136
1181
|
attachment,
|
|
1137
1182
|
chatRunRegistry,
|
|
@@ -1143,6 +1188,8 @@ export const ThreadTurnPreparationServiceLive = Layer.effect(
|
|
|
1143
1188
|
threadMessage,
|
|
1144
1189
|
thread,
|
|
1145
1190
|
helperModelRuntime: yield* HelperModelTag,
|
|
1191
|
+
contextCompactionQueue: queues.contextCompaction,
|
|
1192
|
+
titleGenerationQueue: queues.titleGeneration,
|
|
1146
1193
|
})
|
|
1147
1194
|
}),
|
|
1148
1195
|
)
|