@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
|
@@ -4,18 +4,18 @@ import { convertToModelMessages, stepCountIs } from 'ai'
|
|
|
4
4
|
import type { PrepareStepFunction, StopCondition, ToolSet, UIMessageStreamWriter } from 'ai'
|
|
5
5
|
import { Effect, Ref, Schema, Stream } from 'effect'
|
|
6
6
|
|
|
7
|
-
import { getAgentRuntimeConfig, getResolvedAgentFactoryConfig } from '../../config/agent-defaults'
|
|
8
7
|
import { aiLogger } from '../../config/logger'
|
|
9
8
|
import type { RecordIdRef } from '../../db/record-id'
|
|
10
9
|
import { effectTryMaybeAsync, makeEffectTryPromiseWithMessage } from '../../effect/helpers'
|
|
11
|
-
import {
|
|
10
|
+
import { AgentConfigServiceTag, AgentFactoryServiceTag } from '../../effect/services'
|
|
12
11
|
import {
|
|
13
12
|
readRuntimeAgentIdentityOverrides,
|
|
14
13
|
resolveRuntimeAgentDisplayName,
|
|
15
14
|
} from '../../runtime/agent-identity-overrides'
|
|
16
15
|
import { createAgentMessageMetadata } from '../../runtime/agent-stream-helpers'
|
|
17
16
|
import { mergeInstructionSections } from '../../runtime/instruction-sections'
|
|
18
|
-
import
|
|
17
|
+
import { createLiveTurnTraceStreamObserver } from '../../runtime/live-turn-trace'
|
|
18
|
+
import type { LotaRuntimeTurnHooks } from '../../runtime/runtime-extensions'
|
|
19
19
|
import {
|
|
20
20
|
asRecord,
|
|
21
21
|
collectToolOutputErrors,
|
|
@@ -122,7 +122,7 @@ function buildFallbackResponseMessage(
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
export interface StreamAgentResponseContext {
|
|
125
|
-
turnHooks:
|
|
125
|
+
turnHooks: LotaRuntimeTurnHooks
|
|
126
126
|
thread: NormalizedThread
|
|
127
127
|
threadRef: RecordIdRef
|
|
128
128
|
orgRef: RecordIdRef
|
|
@@ -226,8 +226,9 @@ const streamAgentResponseEffect = Effect.fn('ThreadTurnStreaming.streamAgentResp
|
|
|
226
226
|
(streamParams.skills ?? []).some((skill) => skill.startsWith('cpo-') || skill.startsWith('mentor-')) ||
|
|
227
227
|
resolvedAgentId === 'cpo' ||
|
|
228
228
|
resolvedAgentId === 'mentor'
|
|
229
|
-
const agentFactoryConfig =
|
|
230
|
-
const
|
|
229
|
+
const agentFactoryConfig = yield* AgentFactoryServiceTag
|
|
230
|
+
const agentConfig = yield* AgentConfigServiceTag
|
|
231
|
+
const config = agentFactoryConfig.getAgentRuntimeConfig({
|
|
231
232
|
agentId: resolvedAgentId,
|
|
232
233
|
threadType: ctx.thread.type,
|
|
233
234
|
mode: streamParams.mode,
|
|
@@ -277,6 +278,7 @@ const streamAgentResponseEffect = Effect.fn('ThreadTurnStreaming.streamAgentResp
|
|
|
277
278
|
prepareStep: (agentResolution?.prepareStep as PrepareStepFunction<ToolSet> | undefined) ?? streamParams.prepareStep,
|
|
278
279
|
})
|
|
279
280
|
const agentAbortSignal = streamParams.abortSignal ?? ctx.runAbortSignal
|
|
281
|
+
const resolvedAgentName = resolveRuntimeAgentDisplayName(agentConfig, agentIdentityOverrides, resolvedAgentId)
|
|
280
282
|
|
|
281
283
|
const generateFallback = (cause: ThreadTurnStreamingError) =>
|
|
282
284
|
effectTryPromise(
|
|
@@ -291,6 +293,34 @@ const streamAgentResponseEffect = Effect.fn('ThreadTurnStreaming.streamAgentResp
|
|
|
291
293
|
Effect.flatMap((result) => buildFallbackResponseMessage(result as ToolLoopGenerateResult)),
|
|
292
294
|
)
|
|
293
295
|
|
|
296
|
+
const generateWithoutUiStream = effectTryPromise(
|
|
297
|
+
() => streamParams.observer.run(() => agent.generate({ messages: modelMessages, abortSignal: agentAbortSignal })),
|
|
298
|
+
`Agent generate failed for ${resolvedAgentId}.`,
|
|
299
|
+
).pipe(
|
|
300
|
+
Effect.tapError((error) =>
|
|
301
|
+
Effect.sync(() => {
|
|
302
|
+
if (agentAbortSignal.aborted) {
|
|
303
|
+
streamParams.observer.recordAbort(error)
|
|
304
|
+
return
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
streamParams.observer.recordError(error)
|
|
308
|
+
}),
|
|
309
|
+
),
|
|
310
|
+
Effect.withSpan('ThreadTurnStreaming.startAgentGenerate'),
|
|
311
|
+
Effect.flatMap((result) => buildFallbackResponseMessage(result as ToolLoopGenerateResult)),
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
if (!streamParams.writer) {
|
|
315
|
+
const generatedResponse = yield* generateWithoutUiStream
|
|
316
|
+
|
|
317
|
+
for (const toolError of collectToolOutputErrors({ responseMessage: generatedResponse })) {
|
|
318
|
+
aiLogger.error`Tool execution failed (agent=${resolvedAgentId}, tool=${toolError.toolName}, toolCallId=${toolError.toolCallId}): ${toolError.errorText}`
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return generatedResponse
|
|
322
|
+
}
|
|
323
|
+
|
|
294
324
|
const result = yield* effectTryPromise(
|
|
295
325
|
() => streamParams.observer.run(() => agent.stream({ messages: modelMessages, abortSignal: agentAbortSignal })),
|
|
296
326
|
`Agent stream failed for ${resolvedAgentId}.`,
|
|
@@ -320,14 +350,19 @@ const streamAgentResponseEffect = Effect.fn('ThreadTurnStreaming.streamAgentResp
|
|
|
320
350
|
originalMessages: streamParams.messages,
|
|
321
351
|
sendReasoning: true,
|
|
322
352
|
sendSources: true,
|
|
323
|
-
messageMetadata: createAgentMessageMetadata({
|
|
324
|
-
agentId: resolvedAgentId,
|
|
325
|
-
agentName: resolveRuntimeAgentDisplayName(agentIdentityOverrides, resolvedAgentId),
|
|
326
|
-
}),
|
|
353
|
+
messageMetadata: createAgentMessageMetadata({ agentId: resolvedAgentId, agentName: resolvedAgentName }),
|
|
327
354
|
onFinish: ({ responseMessage: finishedResponseMessage }: { responseMessage: ChatMessage }) => {
|
|
328
355
|
resolveFinishedStream(withMessageCreatedAt(finishedResponseMessage, nowEpochMillis()))
|
|
329
356
|
},
|
|
330
357
|
}) as ReadableStream<ChatStreamChunk>
|
|
358
|
+
const liveTurnTrace = streamParams.writer
|
|
359
|
+
? createLiveTurnTraceStreamObserver({
|
|
360
|
+
traceId: `trace:${Bun.randomUUIDv7()}`,
|
|
361
|
+
writer: streamParams.writer,
|
|
362
|
+
agentId: resolvedAgentId,
|
|
363
|
+
agentName: resolvedAgentName,
|
|
364
|
+
})
|
|
365
|
+
: null
|
|
331
366
|
const streamStartedAt = performance.now()
|
|
332
367
|
const firstVisibleOutputRecorded = yield* Ref.make(false)
|
|
333
368
|
const firstTextTokenRecorded = yield* Ref.make(false)
|
|
@@ -361,6 +396,7 @@ const streamAgentResponseEffect = Effect.fn('ThreadTurnStreaming.streamAgentResp
|
|
|
361
396
|
if (streamParams.writer) {
|
|
362
397
|
yield* Effect.sync(() => {
|
|
363
398
|
streamParams.writer?.write(value)
|
|
399
|
+
liveTurnTrace?.observeChunk(value)
|
|
364
400
|
})
|
|
365
401
|
}
|
|
366
402
|
}),
|
|
@@ -371,6 +407,7 @@ const streamAgentResponseEffect = Effect.fn('ThreadTurnStreaming.streamAgentResp
|
|
|
371
407
|
),
|
|
372
408
|
Effect.catchTag('ThreadTurnStreamingError', generateFallback),
|
|
373
409
|
)
|
|
410
|
+
liveTurnTrace?.finish()
|
|
374
411
|
|
|
375
412
|
for (const toolError of collectToolOutputErrors({ responseMessage: streamedResponse })) {
|
|
376
413
|
aiLogger.error`Tool execution failed (agent=${resolvedAgentId}, tool=${toolError.toolName}, toolCallId=${toolError.toolCallId}): ${toolError.errorText}`
|
|
@@ -379,25 +416,20 @@ const streamAgentResponseEffect = Effect.fn('ThreadTurnStreaming.streamAgentResp
|
|
|
379
416
|
return streamedResponse
|
|
380
417
|
})
|
|
381
418
|
|
|
382
|
-
export function streamAgentResponse(
|
|
383
|
-
ctx
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
userRef: ctx.userRef,
|
|
394
|
-
agentId: streamParams.agentId,
|
|
395
|
-
threadType: ctx.thread.type,
|
|
396
|
-
mode: streamParams.mode,
|
|
397
|
-
}),
|
|
398
|
-
includeExecutionPlanTools: streamParams.includeExecutionPlanTools ?? true,
|
|
419
|
+
export function streamAgentResponse(ctx: StreamAgentResponseContext, streamParams: StreamAgentResponseParams) {
|
|
420
|
+
return streamAgentResponseEffect(ctx, streamParams).pipe(
|
|
421
|
+
Effect.annotateSpans(
|
|
422
|
+
compactSpanAttributes({
|
|
423
|
+
...buildThreadTurnSpanAttributes({
|
|
424
|
+
threadRef: ctx.threadRef,
|
|
425
|
+
orgRef: ctx.orgRef,
|
|
426
|
+
userRef: ctx.userRef,
|
|
427
|
+
agentId: streamParams.agentId,
|
|
428
|
+
threadType: ctx.thread.type,
|
|
429
|
+
mode: streamParams.mode,
|
|
399
430
|
}),
|
|
400
|
-
|
|
431
|
+
includeExecutionPlanTools: streamParams.includeExecutionPlanTools ?? true,
|
|
432
|
+
}),
|
|
401
433
|
),
|
|
402
434
|
)
|
|
403
435
|
}
|
|
@@ -2,45 +2,84 @@ import type { ChatMessage } from '@lota-sdk/shared'
|
|
|
2
2
|
import { createUIMessageStream } from 'ai'
|
|
3
3
|
import { Context, Schema, Effect, Layer } from 'effect'
|
|
4
4
|
|
|
5
|
+
import type { ResolvedAgentConfig } from '../../config/agent-defaults'
|
|
5
6
|
import { ensureRecordId, recordIdToString } from '../../db/record-id'
|
|
6
7
|
import { TABLES } from '../../db/tables'
|
|
7
|
-
import { BadRequestError } from '../../effect/errors'
|
|
8
|
-
import {
|
|
8
|
+
import { BadRequestError, ForbiddenError } from '../../effect/errors'
|
|
9
|
+
import { AgentConfigServiceTag } from '../../effect/services'
|
|
9
10
|
import { hasApprovalRespondedParts, isApprovalContinuationRequest } from '../../runtime/approval-continuation'
|
|
10
11
|
import { shouldPlanNodeUseVisibleTurn } from '../../runtime/execution-plan-visibility'
|
|
11
12
|
import { wrapResponseWithKeepalive } from '../../utils/sse-keepalive'
|
|
13
|
+
import { BackgroundWorkService } from '../background-work.service'
|
|
12
14
|
import type { makePlanExecutorService } from '../plan/plan-executor.service'
|
|
13
15
|
import { PlanExecutorServiceTag } from '../plan/plan-executor.service'
|
|
14
16
|
import type { makePlanRunService } from '../plan/plan-run.service'
|
|
15
17
|
import { PlanRunServiceTag } from '../plan/plan-run.service'
|
|
16
18
|
import type { makeUserService } from '../user.service'
|
|
17
19
|
import { UserServiceTag } from '../user.service'
|
|
20
|
+
import type { makeThreadMessageService } from './thread-message.service'
|
|
21
|
+
import { ThreadMessageServiceTag } from './thread-message.service'
|
|
18
22
|
import type {
|
|
19
23
|
PreparedThreadTurnResult,
|
|
20
24
|
ThreadApprovalContinuationParams,
|
|
21
|
-
ThreadPlanTurnParams,
|
|
22
25
|
ThreadTurnParams,
|
|
26
|
+
ThreadPlanTurnParams,
|
|
23
27
|
makeThreadTurnPreparationService,
|
|
24
28
|
} from './thread-turn-preparation.service'
|
|
25
29
|
import { ThreadTurnPreparationServiceTag } from './thread-turn-preparation.service'
|
|
26
30
|
import { buildThreadTurnSpanAttributes, compactSpanAttributes } from './thread-turn-tracing'
|
|
27
31
|
import type { makeThreadService } from './thread.service'
|
|
28
32
|
import { ThreadServiceTag } from './thread.service'
|
|
33
|
+
import type { NormalizedThread } from './thread.types'
|
|
29
34
|
|
|
30
35
|
export { hasApprovalRespondedParts, isApprovalContinuationRequest }
|
|
31
36
|
export { wrapResponseWithKeepalive }
|
|
32
37
|
export type { PreparedThreadTurnResult }
|
|
33
38
|
export type { ThreadPlanTurnParams }
|
|
34
39
|
|
|
40
|
+
export interface BackgroundThreadLaunchMessage {
|
|
41
|
+
parts: ChatMessage['parts']
|
|
42
|
+
metadata?: ChatMessage['metadata']
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface LaunchBackgroundThreadWorkParams {
|
|
46
|
+
sourceThreadId: Parameters<typeof ensureRecordId>[0]
|
|
47
|
+
orgRef: Parameters<typeof ensureRecordId>[0]
|
|
48
|
+
userRef: Parameters<typeof ensureRecordId>[0]
|
|
49
|
+
userName?: string | null
|
|
50
|
+
targetThreadId?: Parameters<typeof ensureRecordId>[0]
|
|
51
|
+
projectTitle?: string
|
|
52
|
+
targetAgentId?: string
|
|
53
|
+
handoff: BackgroundThreadLaunchMessage
|
|
54
|
+
input: BackgroundThreadLaunchMessage
|
|
55
|
+
abortSignal?: AbortSignal
|
|
56
|
+
streamId?: string
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface LaunchBackgroundThreadWorkResult {
|
|
60
|
+
launched: boolean
|
|
61
|
+
threadId: string
|
|
62
|
+
threadTitle: string
|
|
63
|
+
sourceThreadId: string
|
|
64
|
+
targetAgentId?: string
|
|
65
|
+
handoffMessageId: string
|
|
66
|
+
createdThread: boolean
|
|
67
|
+
message: string
|
|
68
|
+
}
|
|
69
|
+
|
|
35
70
|
class ThreadTurnServiceError extends Schema.TaggedErrorClass<ThreadTurnServiceError>()('ThreadTurnServiceError', {
|
|
36
71
|
message: Schema.String,
|
|
37
72
|
cause: Schema.optional(Schema.Defect),
|
|
38
73
|
}) {}
|
|
39
74
|
|
|
40
75
|
interface ThreadTurnDeps {
|
|
76
|
+
agentConfig: ResolvedAgentConfig
|
|
77
|
+
background: Context.Service.Shape<typeof BackgroundWorkService>
|
|
41
78
|
planExecutor: ReturnType<typeof makePlanExecutorService>
|
|
42
79
|
planRun: ReturnType<typeof makePlanRunService>
|
|
80
|
+
provideCurrentContext: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, never>
|
|
43
81
|
thread: ReturnType<typeof makeThreadService>
|
|
82
|
+
threadMessage: ReturnType<typeof makeThreadMessageService>
|
|
44
83
|
threadTurnPreparation: ReturnType<typeof makeThreadTurnPreparationService>
|
|
45
84
|
user: ReturnType<typeof makeUserService>
|
|
46
85
|
}
|
|
@@ -170,6 +209,129 @@ function runThreadTurnInBackgroundWith(deps: ThreadTurnDeps, params: ThreadTurnP
|
|
|
170
209
|
)
|
|
171
210
|
}
|
|
172
211
|
|
|
212
|
+
function buildBackgroundLaunchMessage(params: { createdThread: boolean; threadTitle: string }) {
|
|
213
|
+
return params.createdThread
|
|
214
|
+
? `Background work launched in "${params.threadTitle}".`
|
|
215
|
+
: `Background work launched in existing thread "${params.threadTitle}".`
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const launchBackgroundThreadWorkEffect = Effect.fn('ThreadTurn.launchBackgroundThreadWork')(function* (
|
|
219
|
+
deps: ThreadTurnDeps,
|
|
220
|
+
params: LaunchBackgroundThreadWorkParams,
|
|
221
|
+
) {
|
|
222
|
+
const orgIdString = recordIdToString(params.orgRef, TABLES.ORGANIZATION)
|
|
223
|
+
const userIdString = recordIdToString(params.userRef, TABLES.USER)
|
|
224
|
+
const sourceThreadId = recordIdToString(params.sourceThreadId, TABLES.THREAD)
|
|
225
|
+
|
|
226
|
+
const resolveTargetThread = (): Effect.Effect<
|
|
227
|
+
{ thread: NormalizedThread; createdThread: boolean },
|
|
228
|
+
BadRequestError | ForbiddenError | ThreadTurnServiceError
|
|
229
|
+
> =>
|
|
230
|
+
Effect.gen(function* () {
|
|
231
|
+
if (params.targetThreadId) {
|
|
232
|
+
const existingThread = yield* deps.thread
|
|
233
|
+
.getThread(params.targetThreadId)
|
|
234
|
+
.pipe(
|
|
235
|
+
Effect.mapError((cause) => new ThreadTurnServiceError({ message: 'Failed to load target thread.', cause })),
|
|
236
|
+
)
|
|
237
|
+
if (existingThread.organizationId !== orgIdString) {
|
|
238
|
+
return yield* new ForbiddenError({ message: 'Target thread belongs to a different organization.' })
|
|
239
|
+
}
|
|
240
|
+
if (existingThread.userId !== userIdString) {
|
|
241
|
+
return yield* new ForbiddenError({ message: 'Target thread belongs to a different user.' })
|
|
242
|
+
}
|
|
243
|
+
if (existingThread.status !== 'active') {
|
|
244
|
+
return yield* new BadRequestError({ message: 'Target thread must be active.' })
|
|
245
|
+
}
|
|
246
|
+
return { thread: existingThread, createdThread: false }
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const projectTitle = params.projectTitle?.trim()
|
|
250
|
+
if (!projectTitle) {
|
|
251
|
+
return yield* new BadRequestError({
|
|
252
|
+
message: 'projectTitle is required when launching background work without targetThreadId.',
|
|
253
|
+
})
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const createdThread = yield* deps.thread
|
|
257
|
+
.createThread({ userId: params.userRef, organizationId: params.orgRef, title: projectTitle, type: 'group' })
|
|
258
|
+
.pipe(
|
|
259
|
+
Effect.mapError((cause) => new ThreadTurnServiceError({ message: 'Failed to create target thread.', cause })),
|
|
260
|
+
)
|
|
261
|
+
return { thread: createdThread, createdThread: true }
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
let createdThreadId: string | null = null
|
|
265
|
+
const cleanupCreatedThread = () =>
|
|
266
|
+
createdThreadId ? deps.thread.deleteThread(createdThreadId).pipe(Effect.catch(() => Effect.void)) : Effect.void
|
|
267
|
+
|
|
268
|
+
return yield* Effect.gen(function* () {
|
|
269
|
+
const { thread: targetThread, createdThread } = yield* resolveTargetThread()
|
|
270
|
+
if (createdThread) {
|
|
271
|
+
createdThreadId = targetThread.id
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const handoffMessage = yield* deps.threadMessage.addAgentMessage({
|
|
275
|
+
messageId: { tb: TABLES.THREAD_MESSAGE, id: Bun.randomUUIDv7() },
|
|
276
|
+
threadId: ensureRecordId(targetThread.id, TABLES.THREAD),
|
|
277
|
+
parts: params.handoff.parts,
|
|
278
|
+
metadata: params.handoff.metadata,
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
yield* deps.background.run(
|
|
282
|
+
deps.provideCurrentContext(
|
|
283
|
+
runThreadTurnInBackgroundWith(deps, {
|
|
284
|
+
thread: targetThread,
|
|
285
|
+
threadRef: ensureRecordId(targetThread.id, TABLES.THREAD),
|
|
286
|
+
orgRef: params.orgRef,
|
|
287
|
+
userRef: params.userRef,
|
|
288
|
+
userName: params.userName,
|
|
289
|
+
agentIdOverride: params.targetAgentId,
|
|
290
|
+
inputMessage: {
|
|
291
|
+
id: Bun.randomUUIDv7(),
|
|
292
|
+
role: 'user',
|
|
293
|
+
parts: params.input.parts,
|
|
294
|
+
metadata: params.input.metadata,
|
|
295
|
+
},
|
|
296
|
+
skipInputMessagePersistence: true,
|
|
297
|
+
abortSignal: params.abortSignal,
|
|
298
|
+
streamId: params.streamId,
|
|
299
|
+
}),
|
|
300
|
+
),
|
|
301
|
+
'thread.launchBackgroundThreadWork',
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
return {
|
|
305
|
+
launched: true,
|
|
306
|
+
threadId: targetThread.id,
|
|
307
|
+
threadTitle: targetThread.title,
|
|
308
|
+
sourceThreadId,
|
|
309
|
+
...(params.targetAgentId ? { targetAgentId: params.targetAgentId } : {}),
|
|
310
|
+
handoffMessageId: handoffMessage.id,
|
|
311
|
+
createdThread,
|
|
312
|
+
message: buildBackgroundLaunchMessage({ createdThread, threadTitle: targetThread.title }),
|
|
313
|
+
} satisfies LaunchBackgroundThreadWorkResult
|
|
314
|
+
}).pipe(Effect.catch((error) => cleanupCreatedThread().pipe(Effect.andThen(Effect.fail(error)))))
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
function launchBackgroundThreadWorkWith(deps: ThreadTurnDeps, params: LaunchBackgroundThreadWorkParams) {
|
|
318
|
+
return launchBackgroundThreadWorkEffect(deps, params).pipe(
|
|
319
|
+
Effect.annotateSpans(
|
|
320
|
+
compactSpanAttributes({
|
|
321
|
+
...buildThreadTurnSpanAttributes({
|
|
322
|
+
threadRef: params.sourceThreadId,
|
|
323
|
+
orgRef: params.orgRef,
|
|
324
|
+
userRef: params.userRef,
|
|
325
|
+
kind: 'background-launch',
|
|
326
|
+
streamId: params.streamId,
|
|
327
|
+
agentId: params.targetAgentId,
|
|
328
|
+
}),
|
|
329
|
+
targetThreadId: params.targetThreadId ? recordIdToString(params.targetThreadId, TABLES.THREAD) : undefined,
|
|
330
|
+
}),
|
|
331
|
+
),
|
|
332
|
+
)
|
|
333
|
+
}
|
|
334
|
+
|
|
173
335
|
const triggerPlanNodeTurnEffect = Effect.fn('ThreadTurn.triggerPlanNodeTurn')(function* (
|
|
174
336
|
deps: ThreadTurnDeps,
|
|
175
337
|
params: { runId: string; nodeId: string; abortSignal?: AbortSignal; streamId?: string },
|
|
@@ -178,7 +340,7 @@ const triggerPlanNodeTurnEffect = Effect.fn('ThreadTurn.triggerPlanNodeTurn')(fu
|
|
|
178
340
|
const spec = yield* deps.planRun.getPlanSpecById(run.planSpecId)
|
|
179
341
|
const nodeSpec = yield* deps.planRun.getNodeSpecByNodeId(spec.id, params.nodeId)
|
|
180
342
|
|
|
181
|
-
if (!shouldPlanNodeUseVisibleTurn(spec, nodeSpec) || nodeSpec.owner.executorType !== 'agent') {
|
|
343
|
+
if (!shouldPlanNodeUseVisibleTurn(deps.agentConfig, spec, nodeSpec) || nodeSpec.owner.executorType !== 'agent') {
|
|
182
344
|
return yield* new BadRequestError({
|
|
183
345
|
message: `Plan node "${params.nodeId}" is not eligible for a visible plan turn.`,
|
|
184
346
|
})
|
|
@@ -187,10 +349,13 @@ const triggerPlanNodeTurnEffect = Effect.fn('ThreadTurn.triggerPlanNodeTurn')(fu
|
|
|
187
349
|
let activeRun = run
|
|
188
350
|
let nodeRun = yield* deps.planRun.getNodeRunByNodeId(run.id, params.nodeId)
|
|
189
351
|
if (nodeRun.status === 'ready') {
|
|
190
|
-
yield*
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
352
|
+
yield* deps.planExecutor
|
|
353
|
+
.transitionNodeToRunning({ runId: params.runId, nodeId: params.nodeId })
|
|
354
|
+
.pipe(
|
|
355
|
+
Effect.mapError(
|
|
356
|
+
(cause) => new ThreadTurnServiceError({ message: 'Failed to transition plan node to running.', cause }),
|
|
357
|
+
),
|
|
358
|
+
)
|
|
194
359
|
activeRun = yield* deps.planRun.getRunById(params.runId)
|
|
195
360
|
nodeRun = yield* deps.planRun.getNodeRunByNodeId(run.id, params.nodeId)
|
|
196
361
|
}
|
|
@@ -286,6 +451,9 @@ export function makeThreadTurnService(deps: ThreadTurnDeps) {
|
|
|
286
451
|
createThreadTurnStream(params: ThreadTurnParams) {
|
|
287
452
|
return createThreadTurnStreamWith(deps, params)
|
|
288
453
|
},
|
|
454
|
+
launchBackgroundThreadWork(params: LaunchBackgroundThreadWorkParams) {
|
|
455
|
+
return launchBackgroundThreadWorkWith(deps, params)
|
|
456
|
+
},
|
|
289
457
|
runThreadTurnInBackground(params: ThreadTurnParams) {
|
|
290
458
|
return runThreadTurnInBackgroundWith(deps, params)
|
|
291
459
|
},
|
|
@@ -303,44 +471,67 @@ export class ThreadTurnServiceTag extends Context.Service<
|
|
|
303
471
|
export const ThreadTurnServiceLive = Layer.effect(
|
|
304
472
|
ThreadTurnServiceTag,
|
|
305
473
|
Effect.gen(function* () {
|
|
474
|
+
const currentContext = yield* Effect.context()
|
|
475
|
+
const provideCurrentContext = <A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, never> =>
|
|
476
|
+
effect.pipe(Effect.provide(currentContext)) as Effect.Effect<A, E, never>
|
|
477
|
+
const agentConfig = yield* AgentConfigServiceTag
|
|
478
|
+
const background = yield* BackgroundWorkService
|
|
306
479
|
const planExecutor = yield* PlanExecutorServiceTag
|
|
307
480
|
const planRun = yield* PlanRunServiceTag
|
|
308
481
|
const thread = yield* ThreadServiceTag
|
|
482
|
+
const threadMessage = yield* ThreadMessageServiceTag
|
|
309
483
|
const threadTurnPreparation = yield* ThreadTurnPreparationServiceTag
|
|
310
484
|
const user = yield* UserServiceTag
|
|
311
|
-
return makeThreadTurnService({
|
|
485
|
+
return makeThreadTurnService({
|
|
486
|
+
agentConfig,
|
|
487
|
+
background,
|
|
488
|
+
planExecutor,
|
|
489
|
+
planRun,
|
|
490
|
+
provideCurrentContext,
|
|
491
|
+
thread,
|
|
492
|
+
threadMessage,
|
|
493
|
+
threadTurnPreparation,
|
|
494
|
+
user,
|
|
495
|
+
})
|
|
312
496
|
}),
|
|
313
497
|
)
|
|
314
498
|
|
|
315
|
-
const
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
499
|
+
export const createThreadApprovalContinuationStream = Effect.fn('ThreadTurn.createApprovalContinuationStream')(
|
|
500
|
+
function* (params: ThreadApprovalContinuationParams) {
|
|
501
|
+
const threadTurnService = yield* ThreadTurnServiceTag
|
|
502
|
+
return yield* threadTurnService.createThreadApprovalContinuationStream(params)
|
|
503
|
+
},
|
|
504
|
+
)
|
|
321
505
|
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
)
|
|
506
|
+
export const createThreadNativeToolApprovalStream = Effect.fn('ThreadTurn.createNativeToolApprovalStream')(function* (
|
|
507
|
+
params: ThreadApprovalContinuationParams,
|
|
508
|
+
) {
|
|
325
509
|
const threadTurnService = yield* ThreadTurnServiceTag
|
|
326
510
|
return yield* threadTurnService.createThreadNativeToolApprovalStream(params)
|
|
327
511
|
})
|
|
328
512
|
|
|
329
|
-
const
|
|
513
|
+
export const createThreadTurnStream = Effect.fn('ThreadTurn.createThreadTurnStream')(function* (
|
|
330
514
|
params: ThreadTurnParams,
|
|
331
515
|
) {
|
|
332
516
|
const threadTurnService = yield* ThreadTurnServiceTag
|
|
333
517
|
return yield* threadTurnService.createThreadTurnStream(params)
|
|
334
518
|
})
|
|
335
519
|
|
|
336
|
-
const
|
|
520
|
+
export const launchBackgroundThreadWork = Effect.fn('ThreadTurn.launchBackgroundThreadWork')(function* (
|
|
521
|
+
params: LaunchBackgroundThreadWorkParams,
|
|
522
|
+
) {
|
|
523
|
+
const threadTurnService = yield* ThreadTurnServiceTag
|
|
524
|
+
return yield* threadTurnService.launchBackgroundThreadWork(params)
|
|
525
|
+
})
|
|
526
|
+
|
|
527
|
+
export const runThreadTurnInBackground = Effect.fn('ThreadTurn.runThreadTurnInBackground')(function* (
|
|
337
528
|
params: ThreadTurnParams,
|
|
338
529
|
) {
|
|
339
530
|
const threadTurnService = yield* ThreadTurnServiceTag
|
|
340
531
|
return yield* threadTurnService.runThreadTurnInBackground(params)
|
|
341
532
|
})
|
|
342
533
|
|
|
343
|
-
const
|
|
534
|
+
export const triggerPlanNodeTurn = Effect.fn('ThreadTurn.triggerPlanNodeTurn')(function* (params: {
|
|
344
535
|
runId: string
|
|
345
536
|
nodeId: string
|
|
346
537
|
abortSignal?: AbortSignal
|
|
@@ -349,28 +540,3 @@ const triggerPlanNodeTurnWithRuntime = Effect.fn('ThreadTurn.triggerPlanNodeTurn
|
|
|
349
540
|
const threadTurnService = yield* ThreadTurnServiceTag
|
|
350
541
|
return yield* threadTurnService.triggerPlanNodeTurn(params)
|
|
351
542
|
})
|
|
352
|
-
|
|
353
|
-
export function createThreadApprovalContinuationStream(params: ThreadApprovalContinuationParams) {
|
|
354
|
-
return runPromise(createThreadApprovalContinuationStreamWithRuntime(params))
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
export function createThreadNativeToolApprovalStream(params: ThreadApprovalContinuationParams) {
|
|
358
|
-
return runPromise(createThreadNativeToolApprovalStreamWithRuntime(params))
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
export function createThreadTurnStream(params: ThreadTurnParams) {
|
|
362
|
-
return runPromise(createThreadTurnStreamWithRuntime(params))
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
export function runThreadTurnInBackground(params: ThreadTurnParams): Promise<PreparedThreadTurnResult> {
|
|
366
|
-
return runPromise(runThreadTurnInBackgroundWithRuntime(params))
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
export function triggerPlanNodeTurn(params: {
|
|
370
|
-
runId: string
|
|
371
|
-
nodeId: string
|
|
372
|
-
abortSignal?: AbortSignal
|
|
373
|
-
streamId?: string
|
|
374
|
-
}): Promise<PreparedThreadTurnResult> {
|
|
375
|
-
return runPromise(triggerPlanNodeTurnWithRuntime(params))
|
|
376
|
-
}
|
|
@@ -2,14 +2,21 @@ import { THREAD, sdkThreadStatusSchema } from '@lota-sdk/shared'
|
|
|
2
2
|
import { Context, Effect, Layer } from 'effect'
|
|
3
3
|
import { surql } from 'surrealdb'
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import type { ResolvedAgentConfig } from '../../config/agent-defaults'
|
|
6
|
+
import { isAgentName } from '../../config/agent-defaults'
|
|
7
|
+
import type { ResolvedThreadBootstrapConfig } from '../../config/thread-defaults'
|
|
6
8
|
import { ensureRecordId, isRecordIdInput, recordIdToString } from '../../db/record-id'
|
|
7
9
|
import type { RecordIdRef } from '../../db/record-id'
|
|
8
10
|
import type { SurrealDBService } from '../../db/service'
|
|
9
11
|
import { TABLES } from '../../db/tables'
|
|
10
12
|
import { BadRequestError, ServiceError } from '../../effect/errors'
|
|
11
13
|
import { makeEffectTryPromiseWithMessage } from '../../effect/helpers'
|
|
12
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
AgentConfigServiceTag,
|
|
16
|
+
DatabaseServiceTag,
|
|
17
|
+
RedisServiceTag,
|
|
18
|
+
ThreadConfigServiceTag,
|
|
19
|
+
} from '../../effect/services'
|
|
13
20
|
import type { RedisConnectionManager } from '../../redis/connection'
|
|
14
21
|
import { CompactionCoordinationTag } from '../../runtime/chat-run-orchestration'
|
|
15
22
|
import { toIsoDateTimeString } from '../../utils/date-time'
|
|
@@ -35,9 +42,9 @@ function assertMutableThreadEffect(thread: ThreadRecord): Effect.Effect<void, Ba
|
|
|
35
42
|
: Effect.void
|
|
36
43
|
}
|
|
37
44
|
|
|
38
|
-
function getDefaultTitle(thread: Pick<ThreadRecord, 'type' | 'threadType'>): string {
|
|
45
|
+
function getDefaultTitle(agentConfig: ResolvedAgentConfig, thread: Pick<ThreadRecord, 'type' | 'threadType'>): string {
|
|
39
46
|
if (thread.type === 'thread' && typeof thread.threadType === 'string') {
|
|
40
|
-
return getCoreThreadProfile(thread.threadType).config.title
|
|
47
|
+
return agentConfig.getCoreThreadProfile(thread.threadType).config.title
|
|
41
48
|
}
|
|
42
49
|
|
|
43
50
|
return THREAD.DEFAULT_TITLE
|
|
@@ -63,6 +70,8 @@ type ChatRunRegistry = Context.Service.Shape<typeof ChatRunRegistryTag>
|
|
|
63
70
|
type CompactionCoordination = Context.Service.Shape<typeof CompactionCoordinationTag>
|
|
64
71
|
|
|
65
72
|
interface ThreadServiceDeps {
|
|
73
|
+
agentConfig: ResolvedAgentConfig
|
|
74
|
+
threadBootstrapConfig: ResolvedThreadBootstrapConfig
|
|
66
75
|
db: SurrealDBService
|
|
67
76
|
redis: RedisConnectionManager
|
|
68
77
|
chatRunRegistry: ChatRunRegistry
|
|
@@ -126,8 +135,8 @@ export function makeThreadService(deps: ThreadServiceDeps) {
|
|
|
126
135
|
nameGenerated: thread.nameGenerated,
|
|
127
136
|
isRunning,
|
|
128
137
|
isCompacting: thread.isCompacting === true,
|
|
129
|
-
...(isAgentName(thread.agentId) ? { agentId: thread.agentId } : {}),
|
|
130
|
-
title: thread.title ?? getDefaultTitle(thread),
|
|
138
|
+
...(isAgentName(deps.agentConfig, thread.agentId) ? { agentId: thread.agentId } : {}),
|
|
139
|
+
title: thread.title ?? getDefaultTitle(deps.agentConfig, thread),
|
|
131
140
|
status: thread.status,
|
|
132
141
|
memoryBlock: formatMemoryBlockForPrompt(thread),
|
|
133
142
|
members: thread.members,
|
|
@@ -149,6 +158,8 @@ export function makeThreadService(deps: ThreadServiceDeps) {
|
|
|
149
158
|
}
|
|
150
159
|
|
|
151
160
|
const bootstrap = createThreadBootstrapHelpers({
|
|
161
|
+
agentConfig: deps.agentConfig,
|
|
162
|
+
threadBootstrapConfig: deps.threadBootstrapConfig,
|
|
152
163
|
threadStore,
|
|
153
164
|
threadMessageService: deps.threadMessageService,
|
|
154
165
|
redis: deps.redis,
|
|
@@ -324,6 +335,8 @@ export class ThreadServiceTag extends Context.Service<ThreadServiceTag, ReturnTy
|
|
|
324
335
|
export const ThreadServiceLive = Layer.effect(
|
|
325
336
|
ThreadServiceTag,
|
|
326
337
|
Effect.gen(function* () {
|
|
338
|
+
const agentConfig = yield* AgentConfigServiceTag
|
|
339
|
+
const threadBootstrapConfig = yield* ThreadConfigServiceTag
|
|
327
340
|
const db = yield* DatabaseServiceTag
|
|
328
341
|
const redis = yield* RedisServiceTag
|
|
329
342
|
const chatRunRegistry = yield* ChatRunRegistryTag
|
|
@@ -332,6 +345,8 @@ export const ThreadServiceLive = Layer.effect(
|
|
|
332
345
|
const compactionCoordination = yield* CompactionCoordinationTag
|
|
333
346
|
const background = yield* BackgroundWorkService
|
|
334
347
|
return makeThreadService({
|
|
348
|
+
agentConfig,
|
|
349
|
+
threadBootstrapConfig,
|
|
335
350
|
db,
|
|
336
351
|
redis,
|
|
337
352
|
chatRunRegistry,
|
|
@@ -3,7 +3,7 @@ import { ToolLoopAgent } from 'ai'
|
|
|
3
3
|
|
|
4
4
|
import { aiGatewayChatModel } from '../ai-gateway/ai-gateway'
|
|
5
5
|
import { buildAiGatewayDirectCacheHeaders } from '../ai-gateway/cache-headers'
|
|
6
|
-
import {
|
|
6
|
+
import type { ResolvedAgentConfig } from '../config/agent-defaults'
|
|
7
7
|
import {
|
|
8
8
|
OPENROUTER_STRUCTURED_HELPER_MODEL_ID,
|
|
9
9
|
OPENROUTER_HIGH_REASONING_PROVIDER_OPTIONS,
|
|
@@ -12,8 +12,8 @@ import { resolveHelperAgentOptions } from './helper-agent-options'
|
|
|
12
12
|
|
|
13
13
|
const RECENT_ACTIVITY_TITLE_MAX_TOKENS = 256
|
|
14
14
|
|
|
15
|
-
export function buildRecentActivityTitleRefinerPrompt(): string {
|
|
16
|
-
const leadAgentDisplayName =
|
|
15
|
+
export function buildRecentActivityTitleRefinerPrompt(agentConfig: ResolvedAgentConfig): string {
|
|
16
|
+
const leadAgentDisplayName = agentConfig.displayNames[agentConfig.leadAgentId] || 'the lead agent'
|
|
17
17
|
|
|
18
18
|
return `<agent-instructions>
|
|
19
19
|
You are ${leadAgentDisplayName} writing the visible title for a recent activity item.
|
|
@@ -76,14 +76,17 @@ Return only the title text. No quotes, labels, JSON, markdown, or explanation.
|
|
|
76
76
|
</output>
|
|
77
77
|
</agent-instructions>`
|
|
78
78
|
|
|
79
|
-
export function createRecentActivityTitleRefinerAgent(
|
|
79
|
+
export function createRecentActivityTitleRefinerAgent(
|
|
80
|
+
agentConfig: ResolvedAgentConfig,
|
|
81
|
+
options: CreateHelperToolLoopAgentOptions,
|
|
82
|
+
) {
|
|
80
83
|
return new ToolLoopAgent({
|
|
81
84
|
id: 'recent-activity-title-refiner',
|
|
82
85
|
model: aiGatewayChatModel(OPENROUTER_STRUCTURED_HELPER_MODEL_ID),
|
|
83
86
|
headers: buildAiGatewayDirectCacheHeaders('lota-sdk'),
|
|
84
87
|
providerOptions: OPENROUTER_HIGH_REASONING_PROVIDER_OPTIONS,
|
|
85
88
|
...resolveHelperAgentOptions(options, {
|
|
86
|
-
instructions: buildRecentActivityTitleRefinerPrompt(),
|
|
89
|
+
instructions: buildRecentActivityTitleRefinerPrompt(agentConfig),
|
|
87
90
|
maxOutputTokens: RECENT_ACTIVITY_TITLE_MAX_TOKENS,
|
|
88
91
|
}),
|
|
89
92
|
})
|