@lota-sdk/core 0.4.12 → 0.4.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -4
- package/src/ai/embedding-cache.ts +17 -11
- package/src/ai-gateway/ai-gateway.ts +164 -94
- package/src/ai-gateway/index.ts +4 -1
- package/src/config/agent-defaults.ts +2 -2
- package/src/config/agent-types.ts +1 -1
- package/src/create-runtime.ts +259 -200
- package/src/db/cursor-pagination.ts +2 -9
- package/src/db/memory-store.ts +194 -175
- package/src/db/memory.ts +125 -71
- package/src/db/schema-fingerprint.ts +5 -4
- package/src/db/service-normalization.ts +4 -3
- package/src/db/service.ts +3 -2
- package/src/db/startup.ts +15 -16
- package/src/effect/errors.ts +161 -21
- package/src/effect/index.ts +0 -1
- package/src/embeddings/provider.ts +15 -7
- package/src/queues/autonomous-job.queue.ts +10 -22
- package/src/queues/delayed-node-promotion.queue.ts +8 -14
- package/src/queues/document-processor.queue.ts +13 -4
- package/src/queues/memory-consolidation.queue.ts +26 -14
- package/src/queues/plan-agent-heartbeat.queue.ts +10 -9
- package/src/queues/plan-scheduler.queue.ts +37 -15
- package/src/queues/queue-factory.ts +59 -35
- package/src/queues/standalone-worker.ts +3 -2
- package/src/redis/connection.ts +10 -3
- package/src/redis/org-memory-lock.ts +1 -1
- package/src/redis/redis-lease-lock.ts +5 -5
- package/src/redis/stream-context.ts +1 -1
- package/src/runtime/chat-message.ts +64 -1
- package/src/runtime/chat-run-orchestration.ts +33 -20
- package/src/runtime/context-compaction/context-compaction-runtime.ts +14 -7
- package/src/runtime/context-compaction/context-compaction.ts +78 -66
- package/src/runtime/domain-layer.ts +13 -7
- package/src/runtime/execution-plan.ts +7 -3
- package/src/runtime/live-turn-trace.ts +6 -49
- package/src/runtime/memory/memory-block.ts +3 -9
- package/src/runtime/memory/memory-scope.ts +3 -1
- package/src/runtime/plugin-resolution.ts +2 -1
- package/src/runtime/post-turn-side-effects.ts +6 -5
- package/src/runtime/retrieval-adapters.ts +8 -20
- package/src/runtime/runtime-config.ts +3 -9
- package/src/runtime/runtime-extensions.ts +2 -4
- package/src/runtime/runtime-lifecycle.ts +56 -16
- package/src/runtime/runtime-services.ts +180 -102
- package/src/runtime/runtime-worker-registry.ts +3 -1
- package/src/runtime/social-chat/social-chat-agent-runner.ts +1 -1
- package/src/runtime/social-chat/social-chat-history.ts +21 -18
- package/src/runtime/social-chat/social-chat.ts +356 -223
- package/src/runtime/specialist-runner.ts +3 -1
- package/src/runtime/team-consultation/team-consultation-orchestrator.ts +3 -2
- package/src/runtime/thread-turn-context.ts +142 -102
- package/src/runtime/turn-lifecycle.ts +15 -46
- package/src/services/agent-activity.service.ts +1 -1
- package/src/services/agent-executor.service.ts +107 -77
- package/src/services/autonomous-job.service.ts +354 -293
- package/src/services/background-work.service.ts +3 -3
- package/src/services/context-compaction.service.ts +7 -2
- package/src/services/document-chunk.service.ts +50 -32
- package/src/services/execution-plan/execution-plan-schedule.ts +5 -3
- package/src/services/execution-plan/execution-plan.service.ts +162 -179
- package/src/services/feedback-loop.service.ts +5 -4
- package/src/services/graph-full-routing.ts +37 -36
- package/src/services/institutional-memory.service.ts +28 -30
- package/src/services/learned-skill.service.ts +107 -72
- package/src/services/memory/memory-errors.ts +4 -23
- package/src/services/memory/memory-org-memory.ts +10 -5
- package/src/services/memory/memory-rerank.ts +18 -6
- package/src/services/memory/memory.service.ts +170 -111
- package/src/services/memory/rerank.service.ts +29 -20
- package/src/services/organization-member.service.ts +1 -1
- package/src/services/organization.service.ts +69 -75
- package/src/services/ownership-dispatcher.service.ts +40 -39
- package/src/services/plan/plan-agent-heartbeat.service.ts +26 -23
- package/src/services/plan/plan-agent-query.service.ts +39 -31
- package/src/services/plan/plan-completion-side-effects.ts +13 -17
- package/src/services/plan/plan-coordination.service.ts +2 -1
- package/src/services/plan/plan-cycle.service.ts +6 -5
- package/src/services/plan/plan-deadline.service.ts +57 -54
- package/src/services/plan/plan-event-delivery.service.ts +5 -4
- package/src/services/plan/plan-executor-graph.ts +18 -15
- package/src/services/plan/plan-executor.service.ts +235 -262
- package/src/services/plan/plan-run.service.ts +169 -93
- package/src/services/plan/plan-scheduler.service.ts +192 -202
- package/src/services/plan/plan-template.service.ts +1 -1
- package/src/services/plan/plan-transaction-events.ts +1 -1
- package/src/services/plan/plan-workspace.service.ts +23 -14
- package/src/services/plugin-executor.service.ts +5 -9
- package/src/services/queue-job.service.ts +117 -59
- package/src/services/recent-activity-title.service.ts +13 -12
- package/src/services/recent-activity.service.ts +6 -1
- package/src/services/social-chat-history.service.ts +29 -25
- package/src/services/system-executor.service.ts +5 -9
- package/src/services/thread/thread-active-run.ts +2 -2
- package/src/services/thread/thread-listing.ts +61 -57
- package/src/services/thread/thread-memory-block.ts +73 -48
- package/src/services/thread/thread-message.service.ts +76 -65
- package/src/services/thread/thread-record-store.ts +8 -8
- package/src/services/thread/thread-title.service.ts +10 -4
- package/src/services/thread/thread-turn-execution.ts +43 -45
- package/src/services/thread/thread-turn-preparation.service.ts +257 -135
- package/src/services/thread/thread-turn-streaming.ts +82 -85
- package/src/services/thread/thread-turn.ts +8 -8
- package/src/services/thread/thread.service.ts +135 -100
- package/src/services/user.service.ts +45 -48
- package/src/storage/attachment-parser.ts +6 -2
- package/src/storage/attachment-storage.service.ts +5 -6
- package/src/storage/generated-document-storage.service.ts +1 -1
- package/src/system-agents/context-compaction.agent.ts +10 -9
- package/src/system-agents/delegated-agent-factory.ts +30 -6
- package/src/system-agents/memory-reranker.agent.ts +10 -9
- package/src/system-agents/memory.agent.ts +10 -9
- package/src/system-agents/recent-activity-title-refiner.agent.ts +13 -15
- package/src/system-agents/regular-chat-memory-digest.agent.ts +13 -12
- package/src/system-agents/skill-extractor.agent.ts +13 -12
- package/src/system-agents/skill-manager.agent.ts +13 -12
- package/src/system-agents/thread-router.agent.ts +10 -5
- package/src/system-agents/title-generator.agent.ts +13 -12
- package/src/tools/fetch-webpage.tool.ts +13 -13
- package/src/tools/memory-block.tool.ts +3 -1
- package/src/tools/plan-approval.tool.ts +4 -2
- package/src/tools/read-file-parts.tool.ts +10 -4
- package/src/tools/remember-memory.tool.ts +3 -1
- package/src/tools/research-topic.tool.ts +9 -5
- package/src/tools/search-web.tool.ts +16 -16
- package/src/tools/search.tool.ts +20 -5
- package/src/tools/team-think.tool.ts +61 -38
- package/src/utils/async.ts +5 -5
- package/src/utils/errors.ts +19 -18
- package/src/utils/sse-keepalive.ts +28 -25
- package/src/workers/bootstrap.ts +75 -11
- package/src/workers/memory-consolidation.worker.ts +82 -91
- package/src/workers/organization-learning.worker.ts +14 -4
- package/src/workers/regular-chat-memory-digest.runner.ts +105 -67
- package/src/workers/skill-extraction.runner.ts +97 -61
- package/src/workers/utils/repo-structure-extractor.ts +13 -8
- package/src/workers/utils/thread-message-query.ts +24 -24
- package/src/workers/worker-utils.ts +23 -4
- package/src/effect/helpers.ts +0 -123
|
@@ -17,13 +17,13 @@ import type { ResolvedAgentConfig, ResolvedAgentFactoryConfig } from '../../conf
|
|
|
17
17
|
import { aiLogger } from '../../config/logger'
|
|
18
18
|
import { recordIdToString } from '../../db/record-id'
|
|
19
19
|
import { TABLES } from '../../db/tables'
|
|
20
|
-
import { ForbiddenError } from '../../effect/errors'
|
|
21
|
-
import { effectTryMaybeAsync, effectTryPromise } from '../../effect/helpers'
|
|
20
|
+
import { ERROR_TAGS, ForbiddenError } from '../../effect/errors'
|
|
22
21
|
import type { LotaQueuesRuntime } from '../../queues/queues.service'
|
|
23
22
|
import type { LearnedSkillServiceTag } from '../../services/learned-skill.service'
|
|
24
23
|
import type { MemoryServiceTag } from '../../services/memory/memory.service'
|
|
25
24
|
import type { SocialChatHistoryError, makeSocialChatHistoryService } from '../../services/social-chat-history.service'
|
|
26
25
|
import { safeEnqueue } from '../../utils/async'
|
|
26
|
+
import { getErrorMessage } from '../../utils/errors'
|
|
27
27
|
import { buildAgentPromptContext } from '../agent-prompt-context'
|
|
28
28
|
import { createServerRunAbortController } from '../agent-stream-helpers'
|
|
29
29
|
import type {
|
|
@@ -61,10 +61,31 @@ export interface SocialChatRuntimeServices {
|
|
|
61
61
|
queues: LotaQueuesRuntime
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
class SocialChatServiceError extends Schema.TaggedErrorClass<SocialChatServiceError>()(
|
|
65
|
-
|
|
66
|
-
cause: Schema.optional(Schema.Defect),
|
|
67
|
-
|
|
64
|
+
class SocialChatServiceError extends Schema.TaggedErrorClass<SocialChatServiceError>()(
|
|
65
|
+
ERROR_TAGS.SocialChatServiceError,
|
|
66
|
+
{ message: Schema.String, cause: Schema.optional(Schema.Defect) },
|
|
67
|
+
) {}
|
|
68
|
+
|
|
69
|
+
function toSocialChatServiceError(message: string, cause: unknown): SocialChatServiceError {
|
|
70
|
+
return new SocialChatServiceError({ message, cause })
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function runSlackMessageHandler(params: {
|
|
74
|
+
kind: 'mention' | 'subscribed-message'
|
|
75
|
+
thread: Thread
|
|
76
|
+
message: Message
|
|
77
|
+
effect: Effect.Effect<
|
|
78
|
+
void,
|
|
79
|
+
Cause.UnknownError | ForbiddenError | SocialChatHistoryError | SocialChatServiceError,
|
|
80
|
+
never
|
|
81
|
+
>
|
|
82
|
+
}): Promise<void> {
|
|
83
|
+
return Effect.runPromise(params.effect).catch((cause) => {
|
|
84
|
+
const error = toSocialChatServiceError(`Failed to handle Slack social-chat ${params.kind}.`, cause)
|
|
85
|
+
aiLogger.error`Slack social-chat ${params.kind} failed: threadId=${params.thread.id}, messageId=${params.message.id}, error=${getErrorMessage(error)}`
|
|
86
|
+
throw error
|
|
87
|
+
})
|
|
88
|
+
}
|
|
68
89
|
|
|
69
90
|
const DEFAULT_SOCIAL_CHAT_AGENT_ID = 'socialChat'
|
|
70
91
|
const DEFAULT_SOCIAL_CHAT_AGENT_DISPLAY_NAME = 'Lota'
|
|
@@ -194,8 +215,20 @@ export function createSocialChatRuntime(params: {
|
|
|
194
215
|
dedupeTtlMs: slackConfig?.dedupeTtlMs ?? DEFAULT_SOCIAL_CHAT_DEDUPE_TTL_MS,
|
|
195
216
|
})
|
|
196
217
|
|
|
197
|
-
const initialize = () =>
|
|
198
|
-
|
|
218
|
+
const initialize = () =>
|
|
219
|
+
Effect.runPromise(
|
|
220
|
+
Effect.tryPromise({
|
|
221
|
+
try: () => chat.initialize(),
|
|
222
|
+
catch: (cause) => toSocialChatServiceError('Failed to initialize social chat.', cause),
|
|
223
|
+
}),
|
|
224
|
+
)
|
|
225
|
+
const shutdown = () =>
|
|
226
|
+
Effect.runPromise(
|
|
227
|
+
Effect.tryPromise({
|
|
228
|
+
try: () => chat.shutdown(),
|
|
229
|
+
catch: (cause) => toSocialChatServiceError('Failed to shut down social chat.', cause),
|
|
230
|
+
}),
|
|
231
|
+
)
|
|
199
232
|
|
|
200
233
|
const handleMessage = (
|
|
201
234
|
thread: Thread,
|
|
@@ -224,22 +257,27 @@ export function createSocialChatRuntime(params: {
|
|
|
224
257
|
}
|
|
225
258
|
aiLogger.debug`Slack social-chat message received: channelId=${messageContext.channelId}, threadId=${messageContext.threadId}, messageId=${messageContext.messageId}, author=${messageContext.authorName ?? 'unknown'}, textLength=${messageContext.text.length}`
|
|
226
259
|
|
|
227
|
-
const resolvedContext = yield*
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
260
|
+
const resolvedContext = yield* Effect.tryPromise({
|
|
261
|
+
try: () =>
|
|
262
|
+
socialChatConfig.resolveContext({
|
|
263
|
+
platform: 'slack',
|
|
264
|
+
channelId: messageContext.channelId,
|
|
265
|
+
threadId: messageContext.threadId,
|
|
266
|
+
messageId: messageContext.messageId,
|
|
267
|
+
text: messageContext.text,
|
|
268
|
+
authorId: messageContext.authorId,
|
|
269
|
+
authorName: messageContext.authorName,
|
|
270
|
+
}),
|
|
271
|
+
catch: (cause) => toSocialChatServiceError('Failed to resolve social chat context.', cause),
|
|
272
|
+
})
|
|
238
273
|
const workspaceIdString = recordIdToString(resolvedContext.workspaceId, TABLES.ORGANIZATION)
|
|
239
274
|
const userIdString = recordIdToString(resolvedContext.userId, TABLES.USER)
|
|
240
275
|
aiLogger.debug`Slack social-chat context resolved: workspaceId=${workspaceIdString}, userId=${userIdString}`
|
|
241
276
|
|
|
242
|
-
const threadMessages = yield*
|
|
277
|
+
const threadMessages = yield* Effect.tryPromise({
|
|
278
|
+
try: () => collectThreadMessages(thread, incomingMessage),
|
|
279
|
+
catch: (cause) => toSocialChatServiceError('Failed to collect thread messages.', cause),
|
|
280
|
+
})
|
|
243
281
|
const normalizedMessages = threadMessages
|
|
244
282
|
.map((message) =>
|
|
245
283
|
normalizeSocialHistoryMessage({
|
|
@@ -285,19 +323,39 @@ export function createSocialChatRuntime(params: {
|
|
|
285
323
|
const getConsultParticipants = socialChatConfig.getConsultParticipants
|
|
286
324
|
|
|
287
325
|
const workspace = getWorkspace
|
|
288
|
-
? yield*
|
|
326
|
+
? yield* Effect.tryPromise({
|
|
327
|
+
try: () => getWorkspace(resolvedContext.workspaceId),
|
|
328
|
+
catch: (cause) => toSocialChatServiceError('Failed to load social chat workspace.', cause),
|
|
329
|
+
})
|
|
289
330
|
: {}
|
|
290
331
|
const lifecycleState = getLifecycleState
|
|
291
|
-
? yield*
|
|
332
|
+
? yield* Effect.tryPromise({
|
|
333
|
+
try: () => getLifecycleState(workspace),
|
|
334
|
+
catch: (cause) => toSocialChatServiceError('Failed to load workspace lifecycle state.', cause),
|
|
335
|
+
})
|
|
292
336
|
: undefined
|
|
293
337
|
const workspaceProfileState = readProfileProjectionState
|
|
294
|
-
? yield*
|
|
338
|
+
? yield* Effect.tryPromise({
|
|
339
|
+
try: () => readProfileProjectionState(workspace),
|
|
340
|
+
catch: (cause) => toSocialChatServiceError('Failed to read workspace profile projection state.', cause),
|
|
341
|
+
})
|
|
295
342
|
: undefined
|
|
296
343
|
const recentDomainEvents = listRecentDomainEvents
|
|
297
|
-
? yield*
|
|
344
|
+
? yield* Effect.tryPromise({
|
|
345
|
+
try: () => listRecentDomainEvents(resolvedContext.workspaceId, 5),
|
|
346
|
+
catch: (cause) => toSocialChatServiceError('Failed to load recent workspace domain events.', cause),
|
|
347
|
+
})
|
|
298
348
|
: ([] as Array<Record<string, unknown>>)
|
|
299
349
|
const promptSummary = buildPromptSummary
|
|
300
|
-
? yield*
|
|
350
|
+
? yield* Effect.tryPromise({
|
|
351
|
+
try: () => buildPromptSummary(resolvedContext.workspaceId),
|
|
352
|
+
catch: (cause) => toSocialChatServiceError('Failed to build workspace prompt summary.', cause),
|
|
353
|
+
}).pipe(
|
|
354
|
+
Effect.tapError((error) =>
|
|
355
|
+
Effect.sync(() => {
|
|
356
|
+
aiLogger.warn`Slack social-chat buildPromptSummary failed: ${error}`
|
|
357
|
+
}),
|
|
358
|
+
),
|
|
301
359
|
Effect.orElseSucceed(() => undefined),
|
|
302
360
|
)
|
|
303
361
|
: undefined
|
|
@@ -316,13 +374,15 @@ export function createSocialChatRuntime(params: {
|
|
|
316
374
|
lifecycleState?.bootstrapActive || messageContext.text.length === 0
|
|
317
375
|
? undefined
|
|
318
376
|
: buildRetrievedKnowledgeSection
|
|
319
|
-
? yield*
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
377
|
+
? yield* Effect.tryPromise({
|
|
378
|
+
try: () =>
|
|
379
|
+
buildRetrievedKnowledgeSection({
|
|
380
|
+
workspaceId: workspaceIdString,
|
|
381
|
+
userId: userIdString,
|
|
382
|
+
query: messageContext.text,
|
|
383
|
+
}),
|
|
384
|
+
catch: (cause) => toSocialChatServiceError('Failed to build retrieved knowledge section.', cause),
|
|
385
|
+
})
|
|
326
386
|
: undefined
|
|
327
387
|
|
|
328
388
|
const preSeededMemoriesSection = yield* memoryService
|
|
@@ -346,37 +406,49 @@ export function createSocialChatRuntime(params: {
|
|
|
346
406
|
limit: 3,
|
|
347
407
|
minConfidence: 0.6,
|
|
348
408
|
})
|
|
349
|
-
.pipe(
|
|
409
|
+
.pipe(
|
|
410
|
+
Effect.tapError((error) =>
|
|
411
|
+
Effect.sync(() => {
|
|
412
|
+
aiLogger.warn`Slack social-chat memory retrieval failed: ${error}`
|
|
413
|
+
}),
|
|
414
|
+
),
|
|
415
|
+
Effect.orElseSucceed(() => undefined),
|
|
416
|
+
)
|
|
350
417
|
|
|
351
418
|
let memoryBlock = ''
|
|
352
419
|
const consultedAgents = getConsultParticipants
|
|
353
|
-
? yield*
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
420
|
+
? yield* Effect.tryPromise({
|
|
421
|
+
try: () =>
|
|
422
|
+
getConsultParticipants({
|
|
423
|
+
workspaceId: resolvedContext.workspaceId,
|
|
424
|
+
workspaceIdString,
|
|
425
|
+
platform: 'slack',
|
|
426
|
+
}),
|
|
427
|
+
catch: (cause) => toSocialChatServiceError('Failed to resolve social chat consult participants.', cause),
|
|
428
|
+
})
|
|
360
429
|
: [...agentConfig.teamConsultParticipants]
|
|
361
430
|
const consultParticipants = [...new Set(consultedAgents)].filter((agentId) => agentId !== socialAgentId)
|
|
362
431
|
const executedToolNames: string[] = []
|
|
363
432
|
|
|
364
433
|
const baseTools = withLoggedSocialToolSet(
|
|
365
|
-
yield*
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
434
|
+
yield* Effect.tryPromise({
|
|
435
|
+
try: () =>
|
|
436
|
+
socialChatConfig.buildAgentTools(
|
|
437
|
+
buildBuildToolsParams({
|
|
438
|
+
agentId: socialAgentId,
|
|
439
|
+
context: resolvedContext,
|
|
440
|
+
workspaceIdString,
|
|
441
|
+
userIdString,
|
|
442
|
+
messageContext,
|
|
443
|
+
memoryBlock,
|
|
444
|
+
onAppendMemoryBlock: (value: string) => {
|
|
445
|
+
memoryBlock = value
|
|
446
|
+
},
|
|
447
|
+
}),
|
|
448
|
+
),
|
|
449
|
+
catch: (cause) =>
|
|
450
|
+
toSocialChatServiceError(`Failed to build social chat tools for ${socialAgentId}.`, cause),
|
|
451
|
+
}),
|
|
380
452
|
{
|
|
381
453
|
agentId: socialAgentId,
|
|
382
454
|
channelId: messageContext.channelId,
|
|
@@ -403,94 +475,116 @@ export function createSocialChatRuntime(params: {
|
|
|
403
475
|
})
|
|
404
476
|
}
|
|
405
477
|
|
|
406
|
-
const { result: specialistRun } = yield*
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
)
|
|
425
|
-
|
|
426
|
-
return withLoggedSocialToolSet(tools, {
|
|
427
|
-
agentId,
|
|
428
|
-
channelId: messageContext.channelId,
|
|
429
|
-
threadId: messageContext.threadId,
|
|
430
|
-
executedToolNames,
|
|
431
|
-
})
|
|
432
|
-
}),
|
|
433
|
-
),
|
|
434
|
-
run: ({ tools }) =>
|
|
435
|
-
runPromiseWithCurrentContext(
|
|
436
|
-
Effect.gen(function* () {
|
|
437
|
-
const specialistPreSeededMemories = yield* memoryService
|
|
438
|
-
.getTopMemories({
|
|
439
|
-
orgId: workspaceIdString,
|
|
440
|
-
agentName: agentId,
|
|
441
|
-
limit: PRESEEDED_MEMORY_LOOKUP_LIMIT,
|
|
442
|
-
})
|
|
443
|
-
.pipe(
|
|
444
|
-
Effect.mapError(
|
|
445
|
-
(cause) =>
|
|
446
|
-
new SocialChatServiceError({
|
|
447
|
-
message: `Failed to load pre-seeded memories for specialist ${agentId}.`,
|
|
448
|
-
cause,
|
|
478
|
+
const { result: specialistRun } = yield* Effect.tryPromise({
|
|
479
|
+
try: () =>
|
|
480
|
+
runSpecialistSession({
|
|
481
|
+
initialMemoryBlock: '',
|
|
482
|
+
buildTools: ({ memoryBlock: currentMemoryBlock, onAppendMemoryBlock }) =>
|
|
483
|
+
runPromiseWithCurrentContext(
|
|
484
|
+
Effect.gen(function* () {
|
|
485
|
+
const tools = yield* Effect.tryPromise({
|
|
486
|
+
try: () =>
|
|
487
|
+
socialChatConfig.buildAgentTools(
|
|
488
|
+
buildBuildToolsParams({
|
|
489
|
+
agentId,
|
|
490
|
+
context: resolvedContext,
|
|
491
|
+
workspaceIdString,
|
|
492
|
+
userIdString,
|
|
493
|
+
messageContext,
|
|
494
|
+
memoryBlock: currentMemoryBlock,
|
|
495
|
+
onAppendMemoryBlock,
|
|
449
496
|
}),
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
limit: 3,
|
|
460
|
-
minConfidence: 0.6,
|
|
461
|
-
})
|
|
462
|
-
.pipe(Effect.orElseSucceed(() => undefined))
|
|
463
|
-
|
|
464
|
-
return yield* effectTryPromise(() =>
|
|
465
|
-
runSocialAgentTurn({
|
|
466
|
-
agentFactoryConfig,
|
|
497
|
+
),
|
|
498
|
+
catch: (cause) =>
|
|
499
|
+
toSocialChatServiceError(
|
|
500
|
+
`Failed to build social chat tools for specialist ${agentId}.`,
|
|
501
|
+
cause,
|
|
502
|
+
),
|
|
503
|
+
})
|
|
504
|
+
|
|
505
|
+
return withLoggedSocialToolSet(tools, {
|
|
467
506
|
agentId,
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
507
|
+
channelId: messageContext.channelId,
|
|
508
|
+
threadId: messageContext.threadId,
|
|
509
|
+
executedToolNames,
|
|
510
|
+
})
|
|
511
|
+
}),
|
|
512
|
+
),
|
|
513
|
+
run: ({ tools }) =>
|
|
514
|
+
runPromiseWithCurrentContext(
|
|
515
|
+
Effect.gen(function* () {
|
|
516
|
+
const specialistPreSeededMemories = yield* memoryService
|
|
517
|
+
.getTopMemories({
|
|
518
|
+
orgId: workspaceIdString,
|
|
519
|
+
agentName: agentId,
|
|
520
|
+
limit: PRESEEDED_MEMORY_LOOKUP_LIMIT,
|
|
521
|
+
})
|
|
522
|
+
.pipe(
|
|
523
|
+
Effect.mapError(
|
|
524
|
+
(cause) =>
|
|
525
|
+
new SocialChatServiceError({
|
|
526
|
+
message: `Failed to load pre-seeded memories for specialist ${agentId}.`,
|
|
527
|
+
cause,
|
|
528
|
+
}),
|
|
529
|
+
),
|
|
530
|
+
)
|
|
531
|
+
const specialistLearnedSkills = lifecycleState?.bootstrapActive
|
|
532
|
+
? undefined
|
|
533
|
+
: yield* learnedSkillService
|
|
534
|
+
.retrieveForTurn({
|
|
535
|
+
orgId: workspaceIdString,
|
|
536
|
+
agentId,
|
|
537
|
+
query: task,
|
|
538
|
+
limit: 3,
|
|
539
|
+
minConfidence: 0.6,
|
|
540
|
+
})
|
|
541
|
+
.pipe(
|
|
542
|
+
Effect.tapError((error) =>
|
|
543
|
+
Effect.sync(() => {
|
|
544
|
+
aiLogger.warn`Slack social-chat participant memory retrieval failed: ${error}`
|
|
545
|
+
}),
|
|
546
|
+
),
|
|
547
|
+
Effect.orElseSucceed(() => undefined),
|
|
548
|
+
)
|
|
549
|
+
|
|
550
|
+
return yield* Effect.tryPromise({
|
|
551
|
+
try: () =>
|
|
552
|
+
runSocialAgentTurn({
|
|
553
|
+
agentFactoryConfig,
|
|
554
|
+
agentId,
|
|
555
|
+
mode: 'fixedThreadMode',
|
|
556
|
+
threadType: 'group',
|
|
557
|
+
onboardingActive: lifecycleState?.bootstrapActive ?? false,
|
|
558
|
+
linearInstalled: false,
|
|
559
|
+
systemWorkspaceDetails: promptContext.systemWorkspaceDetails,
|
|
560
|
+
preSeededMemoriesSection: specialistPreSeededMemories,
|
|
561
|
+
retrievedKnowledgeSection,
|
|
562
|
+
learnedSkillsSection: specialistLearnedSkills,
|
|
563
|
+
userMessageText: task,
|
|
564
|
+
additionalInstructionSections: [
|
|
565
|
+
`You are supporting ${socialAgentDisplayName} in a Slack social-chat thread. Stay within your role.`,
|
|
566
|
+
],
|
|
567
|
+
tools,
|
|
568
|
+
prompt: buildSpecialistSocialChatPrompt({
|
|
569
|
+
requesterName: socialAgentDisplayName,
|
|
570
|
+
agentName: getAgentDisplayName(agentConfig, agentId),
|
|
571
|
+
task,
|
|
572
|
+
transcript,
|
|
573
|
+
}),
|
|
574
|
+
abortSignal: runAbort.signal,
|
|
575
|
+
}),
|
|
576
|
+
catch: (cause) =>
|
|
577
|
+
toSocialChatServiceError(
|
|
578
|
+
`Failed to run specialist social agent turn for ${agentId}.`,
|
|
579
|
+
cause,
|
|
580
|
+
),
|
|
581
|
+
})
|
|
582
|
+
}),
|
|
583
|
+
),
|
|
584
|
+
}),
|
|
585
|
+
catch: (cause) =>
|
|
586
|
+
toSocialChatServiceError(`Failed to run social specialist session for ${agentId}.`, cause),
|
|
587
|
+
})
|
|
494
588
|
const text = specialistRun.text
|
|
495
589
|
const createdAt = yield* Clock.currentTimeMillis
|
|
496
590
|
|
|
@@ -516,38 +610,53 @@ export function createSocialChatRuntime(params: {
|
|
|
516
610
|
},
|
|
517
611
|
})
|
|
518
612
|
|
|
519
|
-
yield*
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
threadType: 'group',
|
|
527
|
-
onboardingActive: lifecycleState?.bootstrapActive ?? false,
|
|
528
|
-
linearInstalled: false,
|
|
529
|
-
systemWorkspaceDetails: promptContext.systemWorkspaceDetails,
|
|
530
|
-
preSeededMemoriesSection,
|
|
531
|
-
retrievedKnowledgeSection,
|
|
532
|
-
learnedSkillsSection,
|
|
533
|
-
userMessageText: messageContext.text,
|
|
534
|
-
additionalInstructionSections: [buildSocialChatIdentitySection(socialAgentDisplayName)],
|
|
535
|
-
tools: { ...baseTools, [CONSULT_SPECIALIST_TOOL_NAME]: consultSpecialistTool },
|
|
536
|
-
prompt: buildLeadSocialChatPrompt({
|
|
537
|
-
agentDisplayName: socialAgentDisplayName,
|
|
538
|
-
channelId: messageContext.channelId,
|
|
539
|
-
threadId: messageContext.threadId,
|
|
540
|
-
transcript,
|
|
541
|
-
latestUserMessage: messageContext.text,
|
|
542
|
-
latestAuthorName: messageContext.authorName,
|
|
613
|
+
yield* Effect.tryPromise({
|
|
614
|
+
try: () => thread.startTyping('Thinking...'),
|
|
615
|
+
catch: (cause) => toSocialChatServiceError('Failed to start Slack typing indicator.', cause),
|
|
616
|
+
}).pipe(
|
|
617
|
+
Effect.tapError((error) =>
|
|
618
|
+
Effect.sync(() => {
|
|
619
|
+
aiLogger.warn`Slack social-chat startTyping failed: ${error}`
|
|
543
620
|
}),
|
|
544
|
-
|
|
545
|
-
|
|
621
|
+
),
|
|
622
|
+
Effect.orElseSucceed(() => undefined),
|
|
546
623
|
)
|
|
624
|
+
aiLogger.debug`Slack social-chat generating reply: channelId=${messageContext.channelId}, threadId=${messageContext.threadId}`
|
|
625
|
+
const leadRun = yield* Effect.tryPromise({
|
|
626
|
+
try: () =>
|
|
627
|
+
runSocialAgentTurn({
|
|
628
|
+
agentFactoryConfig,
|
|
629
|
+
agentId: socialAgentId,
|
|
630
|
+
mode: 'threadMode',
|
|
631
|
+
threadType: 'group',
|
|
632
|
+
onboardingActive: lifecycleState?.bootstrapActive ?? false,
|
|
633
|
+
linearInstalled: false,
|
|
634
|
+
systemWorkspaceDetails: promptContext.systemWorkspaceDetails,
|
|
635
|
+
preSeededMemoriesSection,
|
|
636
|
+
retrievedKnowledgeSection,
|
|
637
|
+
learnedSkillsSection,
|
|
638
|
+
userMessageText: messageContext.text,
|
|
639
|
+
additionalInstructionSections: [buildSocialChatIdentitySection(socialAgentDisplayName)],
|
|
640
|
+
tools: { ...baseTools, [CONSULT_SPECIALIST_TOOL_NAME]: consultSpecialistTool },
|
|
641
|
+
prompt: buildLeadSocialChatPrompt({
|
|
642
|
+
agentDisplayName: socialAgentDisplayName,
|
|
643
|
+
channelId: messageContext.channelId,
|
|
644
|
+
threadId: messageContext.threadId,
|
|
645
|
+
transcript,
|
|
646
|
+
latestUserMessage: messageContext.text,
|
|
647
|
+
latestAuthorName: messageContext.authorName,
|
|
648
|
+
}),
|
|
649
|
+
abortSignal: runAbort.signal,
|
|
650
|
+
}),
|
|
651
|
+
catch: (cause) => toSocialChatServiceError(`Failed to run social agent turn for ${socialAgentId}.`, cause),
|
|
652
|
+
})
|
|
547
653
|
const responseText = leadRun.text
|
|
548
654
|
|
|
549
655
|
const replyMarkdown = buildSlackSocialReplyMarkdown({ replyMarkdown: responseText, executedToolNames })
|
|
550
|
-
const sentMessage = yield*
|
|
656
|
+
const sentMessage = yield* Effect.tryPromise({
|
|
657
|
+
try: () => thread.post({ markdown: replyMarkdown }),
|
|
658
|
+
catch: (cause) => toSocialChatServiceError('Failed to post Slack social chat reply.', cause),
|
|
659
|
+
})
|
|
551
660
|
aiLogger.debug`Slack social-chat reply posted: channelId=${messageContext.channelId}, threadId=${messageContext.threadId}, replyMessageId=${sentMessage.id}`
|
|
552
661
|
const normalizedResponse = normalizeSocialHistoryMessage({
|
|
553
662
|
workspaceId: workspaceIdString,
|
|
@@ -564,73 +673,92 @@ export function createSocialChatRuntime(params: {
|
|
|
564
673
|
const priorHistoryMessages = toHistoryMessages(agentConfig, priorHistory)
|
|
565
674
|
const agentMessages = normalizedResponse ? buildAgentHistoryMessages(agentConfig, [normalizedResponse]) : []
|
|
566
675
|
if (messageContext.text && agentMessages.length > 0) {
|
|
567
|
-
yield*
|
|
568
|
-
|
|
569
|
-
(
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
676
|
+
yield* Effect.tryPromise({
|
|
677
|
+
try: () =>
|
|
678
|
+
safeEnqueue(
|
|
679
|
+
() =>
|
|
680
|
+
params.services.queues.postChatMemory.enqueuePostChatMemory(
|
|
681
|
+
{
|
|
682
|
+
orgId: workspaceIdString,
|
|
683
|
+
threadId: `social:slack:${messageContext.threadId}`,
|
|
684
|
+
sourceId: createSocialChatCursorId({
|
|
685
|
+
workspaceId: workspaceIdString,
|
|
686
|
+
threadId: messageContext.threadId,
|
|
687
|
+
messageId: messageContext.messageId,
|
|
688
|
+
}),
|
|
689
|
+
userMessage: messageContext.text,
|
|
690
|
+
historyMessages: priorHistoryMessages,
|
|
691
|
+
agentMessages,
|
|
692
|
+
memoryBlock: memoryBlock.trim() ? memoryBlock : undefined,
|
|
693
|
+
source: 'social_chat',
|
|
694
|
+
sourceMetadata: {
|
|
695
|
+
platform: 'slack',
|
|
696
|
+
channelId: messageContext.channelId,
|
|
697
|
+
threadId: messageContext.threadId,
|
|
698
|
+
messageId: messageContext.messageId,
|
|
699
|
+
authorId: messageContext.authorId,
|
|
700
|
+
authorName: messageContext.authorName,
|
|
701
|
+
},
|
|
591
702
|
},
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
),
|
|
603
|
-
)
|
|
703
|
+
{
|
|
704
|
+
dedupeKey: createSocialMemoryDedupeKey({
|
|
705
|
+
workspaceId: workspaceIdString,
|
|
706
|
+
threadId: messageContext.threadId,
|
|
707
|
+
messageId: messageContext.messageId,
|
|
708
|
+
}),
|
|
709
|
+
},
|
|
710
|
+
),
|
|
711
|
+
{ operationName: 'social post-chat memory extraction enqueue' },
|
|
712
|
+
),
|
|
713
|
+
catch: (cause) => toSocialChatServiceError('Failed to enqueue social post-chat memory extraction.', cause),
|
|
714
|
+
})
|
|
604
715
|
}
|
|
605
716
|
|
|
606
|
-
yield*
|
|
607
|
-
|
|
608
|
-
(
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
717
|
+
yield* Effect.tryPromise({
|
|
718
|
+
try: () =>
|
|
719
|
+
safeEnqueue(
|
|
720
|
+
() =>
|
|
721
|
+
params.services.queues.organizationLearning.enqueueRegularChatMemoryDigest({
|
|
722
|
+
orgId: workspaceIdString,
|
|
723
|
+
}),
|
|
724
|
+
{ operationName: 'social regular chat memory digest enqueue' },
|
|
725
|
+
),
|
|
726
|
+
catch: (cause) => toSocialChatServiceError('Failed to enqueue social regular chat memory digest.', cause),
|
|
727
|
+
})
|
|
728
|
+
yield* Effect.tryPromise({
|
|
729
|
+
try: () =>
|
|
730
|
+
safeEnqueue(
|
|
731
|
+
() => params.services.queues.organizationLearning.enqueueSkillExtraction({ orgId: workspaceIdString }),
|
|
732
|
+
{ operationName: 'social skill extraction enqueue' },
|
|
733
|
+
),
|
|
734
|
+
catch: (cause) => toSocialChatServiceError('Failed to enqueue social skill extraction.', cause),
|
|
735
|
+
})
|
|
619
736
|
}),
|
|
620
737
|
)
|
|
621
738
|
|
|
622
739
|
chat.onNewMention((thread, message) => {
|
|
623
740
|
aiLogger.debug`Slack social-chat new mention received: threadId=${thread.id}, messageId=${message.id}`
|
|
624
|
-
return
|
|
625
|
-
|
|
626
|
-
|
|
741
|
+
return runSlackMessageHandler({
|
|
742
|
+
kind: 'mention',
|
|
743
|
+
thread,
|
|
744
|
+
message,
|
|
745
|
+
effect: Effect.gen(function* () {
|
|
746
|
+
yield* Effect.tryPromise({
|
|
747
|
+
try: () => thread.subscribe(),
|
|
748
|
+
catch: (cause) => toSocialChatServiceError('Failed to subscribe to Slack thread.', cause),
|
|
749
|
+
})
|
|
627
750
|
return yield* handleMessage(thread, message)
|
|
628
751
|
}),
|
|
629
|
-
)
|
|
752
|
+
})
|
|
630
753
|
})
|
|
631
754
|
chat.onSubscribedMessage((thread, message) => {
|
|
632
755
|
aiLogger.debug`Slack social-chat subscribed thread message received: threadId=${thread.id}, messageId=${message.id}`
|
|
633
|
-
return
|
|
756
|
+
return runSlackMessageHandler({
|
|
757
|
+
kind: 'subscribed-message',
|
|
758
|
+
thread,
|
|
759
|
+
message,
|
|
760
|
+
effect: handleMessage(thread, message),
|
|
761
|
+
})
|
|
634
762
|
})
|
|
635
763
|
|
|
636
764
|
return {
|
|
@@ -639,7 +767,12 @@ export function createSocialChatRuntime(params: {
|
|
|
639
767
|
shutdown,
|
|
640
768
|
webhooks: {
|
|
641
769
|
slack: (request: Request, options?: WebhookOptions) =>
|
|
642
|
-
Effect.runPromise(
|
|
770
|
+
Effect.runPromise(
|
|
771
|
+
Effect.tryPromise({
|
|
772
|
+
try: () => chat.webhooks.slack(request, options),
|
|
773
|
+
catch: (cause) => toSocialChatServiceError('Failed to handle Slack social chat webhook.', cause),
|
|
774
|
+
}),
|
|
775
|
+
),
|
|
643
776
|
},
|
|
644
777
|
}
|
|
645
778
|
}
|