@lota-sdk/core 0.4.9 → 0.4.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/ai/embedding-cache.ts +3 -1
- package/src/ai-gateway/ai-gateway.ts +164 -82
- package/src/ai-gateway/index.ts +16 -1
- package/src/config/agent-defaults.ts +4 -107
- package/src/config/agent-types.ts +1 -1
- package/src/config/background-processing.ts +1 -1
- package/src/config/index.ts +0 -1
- package/src/config/logger.ts +22 -25
- package/src/config/thread-defaults.ts +1 -10
- package/src/create-runtime.ts +145 -670
- package/src/db/base.service.ts +30 -38
- package/src/db/memory-query-builder.ts +2 -1
- package/src/db/memory-store.ts +29 -20
- package/src/db/memory.ts +188 -195
- package/src/db/service-normalization.ts +97 -64
- package/src/db/service.ts +496 -384
- package/src/db/startup.ts +30 -19
- package/src/effect/helpers.ts +30 -5
- package/src/effect/index.ts +7 -7
- package/src/effect/layers.ts +75 -72
- package/src/effect/services.ts +15 -11
- package/src/embeddings/provider.ts +65 -71
- package/src/index.ts +13 -12
- package/src/queues/autonomous-job.queue.ts +177 -143
- package/src/queues/context-compaction.queue.ts +41 -39
- package/src/queues/delayed-node-promotion.queue.ts +61 -42
- package/src/queues/document-processor.queue.ts +5 -3
- package/src/queues/index.ts +1 -0
- package/src/queues/memory-consolidation.queue.ts +79 -53
- package/src/queues/organization-learning.queue.ts +70 -33
- package/src/queues/plan-agent-heartbeat.queue.ts +111 -83
- package/src/queues/plan-scheduler.queue.ts +101 -97
- package/src/queues/post-chat-memory.queue.ts +56 -46
- package/src/queues/queue-factory.ts +146 -69
- package/src/queues/queues.service.ts +61 -0
- package/src/queues/title-generation.queue.ts +44 -44
- package/src/redis/connection.ts +181 -164
- package/src/redis/org-memory-lock.ts +24 -9
- package/src/redis/redis-lease-lock.ts +8 -1
- package/src/redis/stream-context.ts +17 -9
- package/src/runtime/agent-identity-overrides.ts +7 -3
- package/src/runtime/agent-runtime-policy.ts +10 -5
- package/src/runtime/agent-stream-helpers.ts +24 -15
- package/src/runtime/chat-run-orchestration.ts +1 -1
- package/src/runtime/context-compaction/context-compaction-runtime.ts +28 -32
- package/src/runtime/context-compaction/context-compaction.ts +131 -85
- package/src/runtime/domain-layer.ts +203 -0
- package/src/runtime/execution-plan-visibility.ts +5 -2
- package/src/runtime/graph-designer.ts +0 -14
- package/src/runtime/helper-model.ts +8 -4
- package/src/runtime/index.ts +1 -1
- package/src/runtime/indexed-repositories-policy.ts +2 -6
- package/src/runtime/memory/memory-block.ts +19 -9
- package/src/runtime/memory/memory-pipeline.ts +53 -66
- package/src/runtime/memory/memory-scope.ts +33 -29
- package/src/runtime/plugin-resolution.ts +58 -62
- package/src/runtime/post-turn-side-effects.ts +139 -161
- package/src/runtime/retrieval-adapters.ts +4 -4
- package/src/runtime/runtime-config.ts +3 -9
- package/src/runtime/runtime-extensions.ts +0 -43
- package/src/runtime/runtime-lifecycle.ts +124 -0
- package/src/runtime/runtime-services.ts +455 -0
- package/src/runtime/runtime-worker-registry.ts +113 -30
- package/src/runtime/social-chat/social-chat-agent-runner.ts +13 -8
- package/src/runtime/social-chat/social-chat-history.ts +24 -13
- package/src/runtime/social-chat/social-chat.ts +420 -369
- package/src/runtime/team-consultation/team-consultation-orchestrator.ts +64 -57
- package/src/runtime/team-consultation/team-consultation-prompts.ts +11 -6
- package/src/runtime/thread-chat-helpers.ts +18 -9
- package/src/runtime/thread-turn-context.ts +28 -74
- package/src/runtime/turn-lifecycle.ts +6 -14
- package/src/services/agent-activity.service.ts +169 -176
- package/src/services/agent-executor.service.ts +207 -196
- package/src/services/artifact.service.ts +10 -5
- package/src/services/attachment.service.ts +16 -48
- package/src/services/autonomous-job.service.ts +81 -87
- package/src/services/background-work.service.ts +54 -0
- package/src/services/chat-run-registry.service.ts +3 -1
- package/src/services/context-compaction.service.ts +8 -10
- package/src/services/document-chunk.service.ts +8 -17
- package/src/services/execution-plan/execution-plan-graph.ts +122 -109
- package/src/services/execution-plan/execution-plan-schedule.ts +1 -15
- package/src/services/execution-plan/execution-plan.service.ts +68 -51
- package/src/services/feedback-loop.service.ts +1 -1
- package/src/services/global-orchestrator.service.ts +49 -15
- package/src/services/graph-full-routing.ts +49 -37
- package/src/services/index.ts +1 -0
- package/src/services/institutional-memory.service.ts +8 -17
- package/src/services/learned-skill.service.ts +38 -35
- package/src/services/memory/memory-conversation.ts +10 -5
- package/src/services/memory/memory-errors.ts +27 -0
- package/src/services/memory/memory-org-memory.ts +14 -3
- package/src/services/memory/memory-preseeded.ts +10 -4
- package/src/services/memory/memory-utils.ts +2 -1
- package/src/services/memory/memory.service.ts +37 -52
- package/src/services/memory/rerank.service.ts +3 -11
- package/src/services/monitoring-window.service.ts +1 -1
- package/src/services/mutating-approval.service.ts +1 -1
- package/src/services/node-workspace.service.ts +2 -2
- package/src/services/notification.service.ts +16 -4
- package/src/services/organization-member.service.ts +1 -1
- package/src/services/organization.service.ts +34 -51
- package/src/services/ownership-dispatcher.service.ts +148 -95
- package/src/services/plan/plan-agent-heartbeat.service.ts +30 -16
- package/src/services/plan/plan-agent-query.service.ts +13 -9
- package/src/services/plan/plan-approval.service.ts +52 -48
- package/src/services/plan/plan-artifact.service.ts +2 -2
- package/src/services/plan/plan-builder.service.ts +2 -2
- package/src/services/plan/plan-checkpoint.service.ts +1 -1
- package/src/services/plan/plan-compiler.service.ts +1 -1
- package/src/services/plan/plan-completion-side-effects.ts +99 -113
- package/src/services/plan/plan-coordination.service.ts +1 -1
- package/src/services/plan/plan-cycle.service.ts +171 -202
- package/src/services/plan/plan-deadline.service.ts +304 -307
- package/src/services/plan/plan-event-delivery.service.ts +84 -72
- package/src/services/plan/plan-executor-context.ts +2 -0
- package/src/services/plan/plan-executor-graph.ts +375 -353
- package/src/services/plan/plan-executor-helpers.ts +60 -75
- package/src/services/plan/plan-executor.service.ts +494 -489
- package/src/services/plan/plan-run.service.ts +12 -19
- package/src/services/plan/plan-scheduler.service.ts +89 -82
- package/src/services/plan/plan-template.service.ts +1 -1
- package/src/services/plan/plan-transaction-events.ts +8 -5
- package/src/services/plan/plan-validator.service.ts +1 -1
- package/src/services/plan/plan-workspace.service.ts +17 -11
- package/src/services/plugin-executor.service.ts +26 -21
- package/src/services/quality-metrics.service.ts +1 -1
- package/src/services/queue-job.service.ts +8 -17
- package/src/services/recent-activity-title.service.ts +22 -10
- package/src/services/recent-activity.service.ts +1 -1
- package/src/services/skill-resolver.service.ts +1 -1
- package/src/services/social-chat-history.service.ts +37 -20
- package/src/services/system-executor.service.ts +25 -20
- package/src/services/thread/thread-bootstrap.ts +37 -19
- package/src/services/thread/thread-listing.ts +2 -1
- package/src/services/thread/thread-memory-block.ts +18 -5
- package/src/services/thread/thread-message.service.ts +30 -13
- package/src/services/thread/thread-title.service.ts +1 -1
- package/src/services/thread/thread-turn-execution.ts +87 -83
- package/src/services/thread/thread-turn-preparation.service.ts +65 -40
- package/src/services/thread/thread-turn-streaming.ts +32 -36
- package/src/services/thread/thread-turn.ts +43 -29
- package/src/services/thread/thread.service.ts +32 -8
- package/src/services/user.service.ts +1 -1
- package/src/services/write-intent-validator.service.ts +1 -1
- package/src/storage/attachment-storage.service.ts +7 -4
- package/src/storage/generated-document-storage.service.ts +1 -1
- package/src/system-agents/context-compaction.agent.ts +1 -1
- package/src/system-agents/helper-agent-options.ts +1 -1
- package/src/system-agents/memory-reranker.agent.ts +1 -1
- package/src/system-agents/memory.agent.ts +1 -1
- package/src/system-agents/recent-activity-title-refiner.agent.ts +9 -6
- package/src/system-agents/regular-chat-memory-digest.agent.ts +1 -1
- package/src/system-agents/skill-extractor.agent.ts +1 -1
- package/src/system-agents/skill-manager.agent.ts +1 -1
- package/src/system-agents/thread-router.agent.ts +23 -20
- package/src/system-agents/title-generator.agent.ts +1 -1
- package/src/tools/execution-plan.tool.ts +36 -20
- package/src/tools/fetch-webpage.tool.ts +30 -22
- package/src/tools/firecrawl-client.ts +1 -6
- package/src/tools/plan-approval.tool.ts +9 -1
- package/src/tools/remember-memory.tool.ts +3 -6
- package/src/tools/research-topic.tool.ts +12 -3
- package/src/tools/search-web.tool.ts +26 -18
- package/src/tools/search.tool.ts +4 -5
- package/src/tools/team-think.tool.ts +139 -121
- package/src/utils/async.ts +15 -6
- package/src/utils/errors.ts +27 -15
- package/src/workers/bootstrap.ts +34 -58
- package/src/workers/memory-consolidation.worker.ts +4 -1
- package/src/workers/organization-learning.worker.ts +16 -3
- package/src/workers/regular-chat-memory-digest.helpers.ts +3 -4
- package/src/workers/regular-chat-memory-digest.runner.ts +46 -29
- package/src/workers/skill-extraction.runner.ts +13 -15
- package/src/workers/worker-utils.ts +14 -8
- package/src/config/search.ts +0 -3
- package/src/effect/awaitable-effect.ts +0 -87
- package/src/effect/runtime-ref.ts +0 -25
- package/src/effect/runtime.ts +0 -31
- package/src/redis/runtime-connection.ts +0 -10
- package/src/runtime/agent-types.ts +0 -1
|
@@ -10,20 +10,19 @@ import type { ChatMessage, ConsultSpecialistArgs } from '@lota-sdk/shared'
|
|
|
10
10
|
import { tool as createTool } from 'ai'
|
|
11
11
|
import { Chat, ConsoleLogger } from 'chat'
|
|
12
12
|
import type { Message, Thread, WebhookOptions } from 'chat'
|
|
13
|
-
import type { Context } from 'effect'
|
|
14
|
-
import {
|
|
13
|
+
import type { Context, Cause } from 'effect'
|
|
14
|
+
import { Clock, Effect, Schema } from 'effect'
|
|
15
15
|
|
|
16
|
-
import {
|
|
16
|
+
import type { ResolvedAgentConfig, ResolvedAgentFactoryConfig } from '../../config/agent-defaults'
|
|
17
17
|
import { aiLogger } from '../../config/logger'
|
|
18
18
|
import { recordIdToString } from '../../db/record-id'
|
|
19
19
|
import { TABLES } from '../../db/tables'
|
|
20
20
|
import { ForbiddenError } from '../../effect/errors'
|
|
21
21
|
import { effectTryMaybeAsync, effectTryPromise } from '../../effect/helpers'
|
|
22
|
-
import {
|
|
23
|
-
import { enqueuePostChatMemory } from '../../queues/post-chat-memory.queue'
|
|
22
|
+
import type { LotaQueuesRuntime } from '../../queues/queues.service'
|
|
24
23
|
import type { LearnedSkillServiceTag } from '../../services/learned-skill.service'
|
|
25
24
|
import type { MemoryServiceTag } from '../../services/memory/memory.service'
|
|
26
|
-
import type { makeSocialChatHistoryService } from '../../services/social-chat-history.service'
|
|
25
|
+
import type { SocialChatHistoryError, makeSocialChatHistoryService } from '../../services/social-chat-history.service'
|
|
27
26
|
import { safeEnqueue } from '../../utils/async'
|
|
28
27
|
import { buildAgentPromptContext } from '../agent-prompt-context'
|
|
29
28
|
import { createServerRunAbortController } from '../agent-stream-helpers'
|
|
@@ -32,7 +31,7 @@ import type {
|
|
|
32
31
|
LotaRuntimeSocialChatConfig,
|
|
33
32
|
LotaSocialChatResolvedContext,
|
|
34
33
|
} from '../runtime-config'
|
|
35
|
-
import {
|
|
34
|
+
import type { LotaRuntimeAdapters } from '../runtime-extensions'
|
|
36
35
|
import { runSpecialistSession } from '../specialist-runner'
|
|
37
36
|
import {
|
|
38
37
|
buildAgentHistoryMessages,
|
|
@@ -58,8 +57,15 @@ export interface SocialChatRuntimeServices {
|
|
|
58
57
|
learnedSkillService: Context.Service.Shape<typeof LearnedSkillServiceTag>
|
|
59
58
|
memoryService: Context.Service.Shape<typeof MemoryServiceTag>
|
|
60
59
|
socialChatHistoryService: ReturnType<typeof makeSocialChatHistoryService>
|
|
60
|
+
runtimeAdapters: LotaRuntimeAdapters
|
|
61
|
+
queues: LotaQueuesRuntime
|
|
61
62
|
}
|
|
62
63
|
|
|
64
|
+
class SocialChatServiceError extends Schema.TaggedErrorClass<SocialChatServiceError>()('SocialChatServiceError', {
|
|
65
|
+
message: Schema.String,
|
|
66
|
+
cause: Schema.optional(Schema.Defect),
|
|
67
|
+
}) {}
|
|
68
|
+
|
|
63
69
|
const DEFAULT_SOCIAL_CHAT_AGENT_ID = 'socialChat'
|
|
64
70
|
const DEFAULT_SOCIAL_CHAT_AGENT_DISPLAY_NAME = 'Lota'
|
|
65
71
|
const DEFAULT_SOCIAL_CHAT_STATE_PREFIX = 'lota:social:chat-sdk'
|
|
@@ -107,8 +113,8 @@ function createAssistantMessage(params: {
|
|
|
107
113
|
}
|
|
108
114
|
}
|
|
109
115
|
|
|
110
|
-
function getAgentDisplayName(agentId: string): string {
|
|
111
|
-
return
|
|
116
|
+
function getAgentDisplayName(agentConfig: ResolvedAgentConfig, agentId: string): string {
|
|
117
|
+
return agentConfig.displayNames[agentId] ?? agentId
|
|
112
118
|
}
|
|
113
119
|
|
|
114
120
|
function toSafeJobIdSegment(value: string): string {
|
|
@@ -152,6 +158,8 @@ function buildBuildToolsParams(params: {
|
|
|
152
158
|
}
|
|
153
159
|
|
|
154
160
|
export function createSocialChatRuntime(params: {
|
|
161
|
+
agentConfig: ResolvedAgentConfig
|
|
162
|
+
agentFactoryConfig: ResolvedAgentFactoryConfig
|
|
155
163
|
redisClient: SocialChatStateRedisClient
|
|
156
164
|
socialChat?: LotaRuntimeSocialChatConfig
|
|
157
165
|
services: SocialChatRuntimeServices
|
|
@@ -192,384 +200,427 @@ export function createSocialChatRuntime(params: {
|
|
|
192
200
|
const handleMessage = (
|
|
193
201
|
thread: Thread,
|
|
194
202
|
incomingMessage: Message,
|
|
195
|
-
): Effect.Effect<
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
)
|
|
223
|
-
const workspaceIdString = recordIdToString(resolvedContext.workspaceId, TABLES.ORGANIZATION)
|
|
224
|
-
const userIdString = recordIdToString(resolvedContext.userId, TABLES.USER)
|
|
225
|
-
aiLogger.info`Slack social-chat context resolved: workspaceId=${workspaceIdString}, userId=${userIdString}`
|
|
226
|
-
|
|
227
|
-
const threadMessages = yield* effectTryPromise(() => collectThreadMessages(thread, incomingMessage))
|
|
228
|
-
const normalizedMessages = threadMessages
|
|
229
|
-
.map((message) =>
|
|
230
|
-
normalizeSocialHistoryMessage({
|
|
231
|
-
workspaceId: workspaceIdString,
|
|
203
|
+
): Effect.Effect<
|
|
204
|
+
void,
|
|
205
|
+
Cause.UnknownError | ForbiddenError | SocialChatHistoryError | SocialChatServiceError,
|
|
206
|
+
never
|
|
207
|
+
> =>
|
|
208
|
+
Effect.scoped(
|
|
209
|
+
Effect.gen(function* () {
|
|
210
|
+
const { memoryService, learnedSkillService, socialChatHistoryService } = params.services
|
|
211
|
+
const agentConfig = params.agentConfig
|
|
212
|
+
const agentFactoryConfig = params.agentFactoryConfig
|
|
213
|
+
const currentContext = yield* Effect.context()
|
|
214
|
+
const runPromiseWithCurrentContext = Effect.runPromiseWith(currentContext)
|
|
215
|
+
const rawSlackMessage = incomingMessage.raw as { channel?: unknown } | undefined
|
|
216
|
+
const channelId = toOptionalTrimmedString(rawSlackMessage?.channel) ?? thread.channelId
|
|
217
|
+
const messageContext: SlackSocialMessageContext = {
|
|
218
|
+
channelId,
|
|
219
|
+
threadId: thread.id,
|
|
220
|
+
messageId: incomingMessage.id,
|
|
221
|
+
text: incomingMessage.text.trim(),
|
|
222
|
+
authorId: toOptionalTrimmedString(incomingMessage.author.userId) ?? undefined,
|
|
223
|
+
authorName: readSlackAuthorName(incomingMessage),
|
|
224
|
+
}
|
|
225
|
+
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
|
+
|
|
227
|
+
const resolvedContext = yield* effectTryMaybeAsync(() =>
|
|
228
|
+
socialChatConfig.resolveContext({
|
|
229
|
+
platform: 'slack',
|
|
232
230
|
channelId: messageContext.channelId,
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
231
|
+
threadId: messageContext.threadId,
|
|
232
|
+
messageId: messageContext.messageId,
|
|
233
|
+
text: messageContext.text,
|
|
234
|
+
authorId: messageContext.authorId,
|
|
235
|
+
authorName: messageContext.authorName,
|
|
236
236
|
}),
|
|
237
237
|
)
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
const getWorkspace = workspaceProvider?.getWorkspace
|
|
253
|
-
? workspaceProvider.getWorkspace.bind(workspaceProvider)
|
|
254
|
-
: undefined
|
|
255
|
-
const getLifecycleState = workspaceProvider?.getLifecycleState
|
|
256
|
-
? workspaceProvider.getLifecycleState.bind(workspaceProvider)
|
|
257
|
-
: undefined
|
|
258
|
-
const readProfileProjectionState = workspaceProvider?.readProfileProjectionState
|
|
259
|
-
? workspaceProvider.readProfileProjectionState.bind(workspaceProvider)
|
|
260
|
-
: undefined
|
|
261
|
-
const listRecentDomainEvents = workspaceProvider?.listRecentDomainEvents
|
|
262
|
-
? workspaceProvider.listRecentDomainEvents.bind(workspaceProvider)
|
|
263
|
-
: undefined
|
|
264
|
-
const buildPromptSummary = workspaceProvider?.buildPromptSummary
|
|
265
|
-
? workspaceProvider.buildPromptSummary.bind(workspaceProvider)
|
|
266
|
-
: undefined
|
|
267
|
-
const buildRetrievedKnowledgeSection = workspaceProvider?.buildRetrievedKnowledgeSection
|
|
268
|
-
? workspaceProvider.buildRetrievedKnowledgeSection.bind(workspaceProvider)
|
|
269
|
-
: undefined
|
|
270
|
-
const getConsultParticipants = socialChatConfig.getConsultParticipants
|
|
271
|
-
|
|
272
|
-
const workspace = getWorkspace ? yield* effectTryMaybeAsync(() => getWorkspace(resolvedContext.workspaceId)) : {}
|
|
273
|
-
const lifecycleState = getLifecycleState
|
|
274
|
-
? yield* effectTryMaybeAsync(() => getLifecycleState(workspace))
|
|
275
|
-
: undefined
|
|
276
|
-
const workspaceProfileState = readProfileProjectionState
|
|
277
|
-
? yield* effectTryMaybeAsync(() => readProfileProjectionState(workspace))
|
|
278
|
-
: undefined
|
|
279
|
-
const recentDomainEvents = listRecentDomainEvents
|
|
280
|
-
? yield* effectTryMaybeAsync(() => listRecentDomainEvents(resolvedContext.workspaceId, 5))
|
|
281
|
-
: ([] as Array<Record<string, unknown>>)
|
|
282
|
-
const promptSummary = buildPromptSummary
|
|
283
|
-
? yield* effectTryMaybeAsync(() => buildPromptSummary(resolvedContext.workspaceId)).pipe(
|
|
284
|
-
Effect.orElseSucceed(() => undefined),
|
|
238
|
+
const workspaceIdString = recordIdToString(resolvedContext.workspaceId, TABLES.ORGANIZATION)
|
|
239
|
+
const userIdString = recordIdToString(resolvedContext.userId, TABLES.USER)
|
|
240
|
+
aiLogger.debug`Slack social-chat context resolved: workspaceId=${workspaceIdString}, userId=${userIdString}`
|
|
241
|
+
|
|
242
|
+
const threadMessages = yield* effectTryPromise(() => collectThreadMessages(thread, incomingMessage))
|
|
243
|
+
const normalizedMessages = threadMessages
|
|
244
|
+
.map((message) =>
|
|
245
|
+
normalizeSocialHistoryMessage({
|
|
246
|
+
workspaceId: workspaceIdString,
|
|
247
|
+
channelId: messageContext.channelId,
|
|
248
|
+
agentId: socialAgentId,
|
|
249
|
+
agentDisplayName: socialAgentDisplayName,
|
|
250
|
+
message,
|
|
251
|
+
}),
|
|
285
252
|
)
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
253
|
+
.filter((message): message is NonNullable<typeof message> => message !== null)
|
|
254
|
+
yield* socialChatHistoryService.upsertMessages(normalizedMessages)
|
|
255
|
+
|
|
256
|
+
const historyBeforeReply = yield* socialChatHistoryService.listThreadMessages({
|
|
257
|
+
workspaceId: workspaceIdString,
|
|
258
|
+
threadId: messageContext.threadId,
|
|
259
|
+
})
|
|
260
|
+
const currentUserMessage =
|
|
261
|
+
historyBeforeReply.find((message) => message.messageId === incomingMessage.id) ?? historyBeforeReply.at(-1)
|
|
262
|
+
const priorHistory = currentUserMessage
|
|
263
|
+
? historyBeforeReply.filter((message) => message.cursor.id !== currentUserMessage.cursor.id)
|
|
264
|
+
: historyBeforeReply
|
|
265
|
+
|
|
266
|
+
const workspaceProvider = params.services.runtimeAdapters.workspaceProvider
|
|
267
|
+
const getWorkspace = workspaceProvider?.getWorkspace
|
|
268
|
+
? workspaceProvider.getWorkspace.bind(workspaceProvider)
|
|
269
|
+
: undefined
|
|
270
|
+
const getLifecycleState = workspaceProvider?.getLifecycleState
|
|
271
|
+
? workspaceProvider.getLifecycleState.bind(workspaceProvider)
|
|
272
|
+
: undefined
|
|
273
|
+
const readProfileProjectionState = workspaceProvider?.readProfileProjectionState
|
|
274
|
+
? workspaceProvider.readProfileProjectionState.bind(workspaceProvider)
|
|
275
|
+
: undefined
|
|
276
|
+
const listRecentDomainEvents = workspaceProvider?.listRecentDomainEvents
|
|
277
|
+
? workspaceProvider.listRecentDomainEvents.bind(workspaceProvider)
|
|
278
|
+
: undefined
|
|
279
|
+
const buildPromptSummary = workspaceProvider?.buildPromptSummary
|
|
280
|
+
? workspaceProvider.buildPromptSummary.bind(workspaceProvider)
|
|
281
|
+
: undefined
|
|
282
|
+
const buildRetrievedKnowledgeSection = workspaceProvider?.buildRetrievedKnowledgeSection
|
|
283
|
+
? workspaceProvider.buildRetrievedKnowledgeSection.bind(workspaceProvider)
|
|
284
|
+
: undefined
|
|
285
|
+
const getConsultParticipants = socialChatConfig.getConsultParticipants
|
|
286
|
+
|
|
287
|
+
const workspace = getWorkspace
|
|
288
|
+
? yield* effectTryMaybeAsync(() => getWorkspace(resolvedContext.workspaceId))
|
|
289
|
+
: {}
|
|
290
|
+
const lifecycleState = getLifecycleState
|
|
291
|
+
? yield* effectTryMaybeAsync(() => getLifecycleState(workspace))
|
|
292
|
+
: undefined
|
|
293
|
+
const workspaceProfileState = readProfileProjectionState
|
|
294
|
+
? yield* effectTryMaybeAsync(() => readProfileProjectionState(workspace))
|
|
295
|
+
: undefined
|
|
296
|
+
const recentDomainEvents = listRecentDomainEvents
|
|
297
|
+
? yield* effectTryMaybeAsync(() => listRecentDomainEvents(resolvedContext.workspaceId, 5))
|
|
298
|
+
: ([] as Array<Record<string, unknown>>)
|
|
299
|
+
const promptSummary = buildPromptSummary
|
|
300
|
+
? yield* effectTryMaybeAsync(() => buildPromptSummary(resolvedContext.workspaceId)).pipe(
|
|
301
|
+
Effect.orElseSucceed(() => undefined),
|
|
302
|
+
)
|
|
303
|
+
: undefined
|
|
304
|
+
|
|
305
|
+
const promptContext = buildAgentPromptContext({
|
|
306
|
+
workspaceName:
|
|
307
|
+
workspaceProfileState?.workspaceName ??
|
|
308
|
+
toOptionalTrimmedString((workspace as { name?: unknown }).name) ??
|
|
309
|
+
undefined,
|
|
310
|
+
summaryBlock: workspaceProfileState?.summaryBlock,
|
|
311
|
+
promptSummary,
|
|
312
|
+
userName: messageContext.authorName,
|
|
313
|
+
recentDomainEvents,
|
|
314
|
+
})
|
|
315
|
+
const retrievedKnowledgeSection =
|
|
316
|
+
lifecycleState?.bootstrapActive || messageContext.text.length === 0
|
|
317
|
+
? undefined
|
|
318
|
+
: buildRetrievedKnowledgeSection
|
|
319
|
+
? yield* effectTryMaybeAsync(() =>
|
|
320
|
+
buildRetrievedKnowledgeSection({
|
|
321
|
+
workspaceId: workspaceIdString,
|
|
322
|
+
userId: userIdString,
|
|
323
|
+
query: messageContext.text,
|
|
324
|
+
}),
|
|
325
|
+
)
|
|
326
|
+
: undefined
|
|
327
|
+
|
|
328
|
+
const preSeededMemoriesSection = yield* memoryService
|
|
329
|
+
.getTopMemories({ orgId: workspaceIdString, agentName: socialAgentId, limit: PRESEEDED_MEMORY_LOOKUP_LIMIT })
|
|
330
|
+
.pipe(
|
|
331
|
+
Effect.mapError(
|
|
332
|
+
(cause) =>
|
|
333
|
+
new SocialChatServiceError({
|
|
334
|
+
message: `Failed to load pre-seeded memories for ${socialAgentId}.`,
|
|
335
|
+
cause,
|
|
307
336
|
}),
|
|
308
|
-
|
|
309
|
-
: undefined
|
|
310
|
-
|
|
311
|
-
const preSeededMemoriesSection = yield* memoryService
|
|
312
|
-
.getTopMemories({ orgId: workspaceIdString, agentName: socialAgentId, limit: PRESEEDED_MEMORY_LOOKUP_LIMIT })
|
|
313
|
-
.pipe(Effect.mapError((cause) => new Cause.UnknownError(cause)))
|
|
314
|
-
const learnedSkillsSection = lifecycleState?.bootstrapActive
|
|
315
|
-
? undefined
|
|
316
|
-
: yield* learnedSkillService
|
|
317
|
-
.retrieveForTurn({
|
|
318
|
-
orgId: workspaceIdString,
|
|
319
|
-
agentId: socialAgentId,
|
|
320
|
-
query: messageContext.text,
|
|
321
|
-
limit: 3,
|
|
322
|
-
minConfidence: 0.6,
|
|
323
|
-
})
|
|
324
|
-
.pipe(Effect.orElseSucceed(() => undefined))
|
|
325
|
-
|
|
326
|
-
let memoryBlock = ''
|
|
327
|
-
const consultedAgents = getConsultParticipants
|
|
328
|
-
? yield* effectTryMaybeAsync(() =>
|
|
329
|
-
getConsultParticipants({ workspaceId: resolvedContext.workspaceId, workspaceIdString, platform: 'slack' }),
|
|
337
|
+
),
|
|
330
338
|
)
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
339
|
+
const learnedSkillsSection = lifecycleState?.bootstrapActive
|
|
340
|
+
? undefined
|
|
341
|
+
: yield* learnedSkillService
|
|
342
|
+
.retrieveForTurn({
|
|
343
|
+
orgId: workspaceIdString,
|
|
344
|
+
agentId: socialAgentId,
|
|
345
|
+
query: messageContext.text,
|
|
346
|
+
limit: 3,
|
|
347
|
+
minConfidence: 0.6,
|
|
348
|
+
})
|
|
349
|
+
.pipe(Effect.orElseSucceed(() => undefined))
|
|
350
|
+
|
|
351
|
+
let memoryBlock = ''
|
|
352
|
+
const consultedAgents = getConsultParticipants
|
|
353
|
+
? yield* effectTryMaybeAsync(() =>
|
|
354
|
+
getConsultParticipants({
|
|
355
|
+
workspaceId: resolvedContext.workspaceId,
|
|
356
|
+
workspaceIdString,
|
|
357
|
+
platform: 'slack',
|
|
358
|
+
}),
|
|
359
|
+
)
|
|
360
|
+
: [...agentConfig.teamConsultParticipants]
|
|
361
|
+
const consultParticipants = [...new Set(consultedAgents)].filter((agentId) => agentId !== socialAgentId)
|
|
362
|
+
const executedToolNames: string[] = []
|
|
363
|
+
|
|
364
|
+
const baseTools = withLoggedSocialToolSet(
|
|
365
|
+
yield* effectTryMaybeAsync(() =>
|
|
366
|
+
socialChatConfig.buildAgentTools(
|
|
367
|
+
buildBuildToolsParams({
|
|
368
|
+
agentId: socialAgentId,
|
|
369
|
+
context: resolvedContext,
|
|
370
|
+
workspaceIdString,
|
|
371
|
+
userIdString,
|
|
372
|
+
messageContext,
|
|
373
|
+
memoryBlock,
|
|
374
|
+
onAppendMemoryBlock: (value: string) => {
|
|
375
|
+
memoryBlock = value
|
|
376
|
+
},
|
|
377
|
+
}),
|
|
378
|
+
),
|
|
349
379
|
),
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
workspaceIdString,
|
|
386
|
-
userIdString,
|
|
387
|
-
messageContext,
|
|
388
|
-
memoryBlock: currentMemoryBlock,
|
|
389
|
-
onAppendMemoryBlock,
|
|
390
|
-
}),
|
|
391
|
-
),
|
|
392
|
-
)
|
|
393
|
-
|
|
394
|
-
return withLoggedSocialToolSet(tools, {
|
|
395
|
-
agentId,
|
|
396
|
-
channelId: messageContext.channelId,
|
|
397
|
-
threadId: messageContext.threadId,
|
|
398
|
-
executedToolNames,
|
|
399
|
-
})
|
|
400
|
-
}),
|
|
401
|
-
),
|
|
402
|
-
run: ({ tools }) =>
|
|
403
|
-
runPromiseWithCurrentContext(
|
|
404
|
-
Effect.gen(function* () {
|
|
405
|
-
const specialistPreSeededMemories = yield* memoryService
|
|
406
|
-
.getTopMemories({
|
|
407
|
-
orgId: workspaceIdString,
|
|
408
|
-
agentName: agentId,
|
|
409
|
-
limit: PRESEEDED_MEMORY_LOOKUP_LIMIT,
|
|
410
|
-
})
|
|
411
|
-
.pipe(Effect.mapError((cause) => new Cause.UnknownError(cause)))
|
|
412
|
-
const specialistLearnedSkills = lifecycleState?.bootstrapActive
|
|
413
|
-
? undefined
|
|
414
|
-
: yield* learnedSkillService
|
|
415
|
-
.retrieveForTurn({
|
|
416
|
-
orgId: workspaceIdString,
|
|
380
|
+
{
|
|
381
|
+
agentId: socialAgentId,
|
|
382
|
+
channelId: messageContext.channelId,
|
|
383
|
+
threadId: messageContext.threadId,
|
|
384
|
+
executedToolNames,
|
|
385
|
+
},
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
const transcript = buildSocialChatThreadTranscript(agentConfig, historyBeforeReply)
|
|
389
|
+
const runAbort = yield* Effect.acquireRelease(
|
|
390
|
+
Effect.sync(() => createServerRunAbortController()),
|
|
391
|
+
(controller) => Effect.sync(() => controller.dispose()),
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
const consultSpecialistTool = createTool({
|
|
395
|
+
description: 'Consult one specialist teammate for targeted guidance before replying to the user.',
|
|
396
|
+
inputSchema: ConsultSpecialistArgsSchema,
|
|
397
|
+
execute: ({ agentId, task }: ConsultSpecialistArgs) =>
|
|
398
|
+
runPromiseWithCurrentContext(
|
|
399
|
+
Effect.gen(function* () {
|
|
400
|
+
if (!consultParticipants.includes(agentId)) {
|
|
401
|
+
return yield* new ForbiddenError({
|
|
402
|
+
message: `Agent "${agentId}" is not an allowed social-chat specialist.`,
|
|
403
|
+
})
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const { result: specialistRun } = yield* effectTryMaybeAsync(() =>
|
|
407
|
+
runSpecialistSession({
|
|
408
|
+
initialMemoryBlock: '',
|
|
409
|
+
buildTools: ({ memoryBlock: currentMemoryBlock, onAppendMemoryBlock }) =>
|
|
410
|
+
runPromiseWithCurrentContext(
|
|
411
|
+
Effect.gen(function* () {
|
|
412
|
+
const tools = yield* effectTryMaybeAsync(() =>
|
|
413
|
+
socialChatConfig.buildAgentTools(
|
|
414
|
+
buildBuildToolsParams({
|
|
417
415
|
agentId,
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
416
|
+
context: resolvedContext,
|
|
417
|
+
workspaceIdString,
|
|
418
|
+
userIdString,
|
|
419
|
+
messageContext,
|
|
420
|
+
memoryBlock: currentMemoryBlock,
|
|
421
|
+
onAppendMemoryBlock,
|
|
422
|
+
}),
|
|
423
|
+
),
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
return withLoggedSocialToolSet(tools, {
|
|
426
427
|
agentId,
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
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,
|
|
449
|
+
}),
|
|
450
|
+
),
|
|
451
|
+
)
|
|
452
|
+
const specialistLearnedSkills = lifecycleState?.bootstrapActive
|
|
453
|
+
? undefined
|
|
454
|
+
: yield* learnedSkillService
|
|
455
|
+
.retrieveForTurn({
|
|
456
|
+
orgId: workspaceIdString,
|
|
457
|
+
agentId,
|
|
458
|
+
query: task,
|
|
459
|
+
limit: 3,
|
|
460
|
+
minConfidence: 0.6,
|
|
461
|
+
})
|
|
462
|
+
.pipe(Effect.orElseSucceed(() => undefined))
|
|
463
|
+
|
|
464
|
+
return yield* effectTryPromise(() =>
|
|
465
|
+
runSocialAgentTurn({
|
|
466
|
+
agentFactoryConfig,
|
|
467
|
+
agentId,
|
|
468
|
+
mode: 'fixedThreadMode',
|
|
469
|
+
threadType: 'group',
|
|
470
|
+
onboardingActive: lifecycleState?.bootstrapActive ?? false,
|
|
471
|
+
linearInstalled: false,
|
|
472
|
+
systemWorkspaceDetails: promptContext.systemWorkspaceDetails,
|
|
473
|
+
preSeededMemoriesSection: specialistPreSeededMemories,
|
|
474
|
+
retrievedKnowledgeSection,
|
|
475
|
+
learnedSkillsSection: specialistLearnedSkills,
|
|
476
|
+
userMessageText: task,
|
|
477
|
+
additionalInstructionSections: [
|
|
478
|
+
`You are supporting ${socialAgentDisplayName} in a Slack social-chat thread. Stay within your role.`,
|
|
479
|
+
],
|
|
480
|
+
tools,
|
|
481
|
+
prompt: buildSpecialistSocialChatPrompt({
|
|
482
|
+
requesterName: socialAgentDisplayName,
|
|
483
|
+
agentName: getAgentDisplayName(agentConfig, agentId),
|
|
484
|
+
task,
|
|
485
|
+
transcript,
|
|
486
|
+
}),
|
|
487
|
+
abortSignal: runAbort.signal,
|
|
445
488
|
}),
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
489
|
+
)
|
|
490
|
+
}),
|
|
491
|
+
),
|
|
492
|
+
}),
|
|
493
|
+
)
|
|
494
|
+
const text = specialistRun.text
|
|
495
|
+
const createdAt = yield* Clock.currentTimeMillis
|
|
496
|
+
|
|
497
|
+
return createAssistantMessage({
|
|
498
|
+
agentId,
|
|
499
|
+
agentName: getAgentDisplayName(agentConfig, agentId),
|
|
500
|
+
text,
|
|
501
|
+
createdAt,
|
|
502
|
+
})
|
|
503
|
+
}),
|
|
504
|
+
),
|
|
505
|
+
toModelOutput: ({ output }) => {
|
|
506
|
+
const message = output
|
|
507
|
+
const agentName =
|
|
508
|
+
typeof message.metadata?.agentName === 'string' && message.metadata.agentName.trim().length > 0
|
|
509
|
+
? message.metadata.agentName.trim()
|
|
510
|
+
: 'Specialist'
|
|
511
|
+
const summary = extractMessageText(message).trim()
|
|
512
|
+
return {
|
|
513
|
+
type: 'text',
|
|
514
|
+
value: summary ? `${agentName}: ${summary}` : `${agentName} completed the requested task.`,
|
|
515
|
+
}
|
|
516
|
+
},
|
|
517
|
+
})
|
|
518
|
+
|
|
519
|
+
yield* effectTryPromise(() => thread.startTyping('Thinking...')).pipe(Effect.orElseSucceed(() => undefined))
|
|
520
|
+
aiLogger.debug`Slack social-chat generating reply: channelId=${messageContext.channelId}, threadId=${messageContext.threadId}`
|
|
521
|
+
const leadRun = yield* effectTryPromise(() =>
|
|
522
|
+
runSocialAgentTurn({
|
|
523
|
+
agentFactoryConfig,
|
|
524
|
+
agentId: socialAgentId,
|
|
525
|
+
mode: 'threadMode',
|
|
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,
|
|
457
543
|
}),
|
|
458
|
-
|
|
459
|
-
toModelOutput: ({ output }) => {
|
|
460
|
-
const message = output
|
|
461
|
-
const agentName =
|
|
462
|
-
typeof message.metadata?.agentName === 'string' && message.metadata.agentName.trim().length > 0
|
|
463
|
-
? message.metadata.agentName.trim()
|
|
464
|
-
: 'Specialist'
|
|
465
|
-
const summary = extractMessageText(message).trim()
|
|
466
|
-
return {
|
|
467
|
-
type: 'text',
|
|
468
|
-
value: summary ? `${agentName}: ${summary}` : `${agentName} completed the requested task.`,
|
|
469
|
-
}
|
|
470
|
-
},
|
|
471
|
-
})
|
|
472
|
-
|
|
473
|
-
yield* effectTryPromise(() => thread.startTyping('Thinking...')).pipe(Effect.orElseSucceed(() => undefined))
|
|
474
|
-
aiLogger.info`Slack social-chat generating reply: channelId=${messageContext.channelId}, threadId=${messageContext.threadId}`
|
|
475
|
-
const leadRun = yield* effectTryPromise(() =>
|
|
476
|
-
runSocialAgentTurn({
|
|
477
|
-
agentId: socialAgentId,
|
|
478
|
-
mode: 'threadMode',
|
|
479
|
-
threadType: 'group',
|
|
480
|
-
onboardingActive: lifecycleState?.bootstrapActive ?? false,
|
|
481
|
-
linearInstalled: false,
|
|
482
|
-
systemWorkspaceDetails: promptContext.systemWorkspaceDetails,
|
|
483
|
-
preSeededMemoriesSection,
|
|
484
|
-
retrievedKnowledgeSection,
|
|
485
|
-
learnedSkillsSection,
|
|
486
|
-
userMessageText: messageContext.text,
|
|
487
|
-
additionalInstructionSections: [buildSocialChatIdentitySection(socialAgentDisplayName)],
|
|
488
|
-
tools: { ...baseTools, [CONSULT_SPECIALIST_TOOL_NAME]: consultSpecialistTool },
|
|
489
|
-
prompt: buildLeadSocialChatPrompt({
|
|
490
|
-
agentDisplayName: socialAgentDisplayName,
|
|
491
|
-
channelId: messageContext.channelId,
|
|
492
|
-
threadId: messageContext.threadId,
|
|
493
|
-
transcript,
|
|
494
|
-
latestUserMessage: messageContext.text,
|
|
495
|
-
latestAuthorName: messageContext.authorName,
|
|
544
|
+
abortSignal: runAbort.signal,
|
|
496
545
|
}),
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
546
|
+
)
|
|
547
|
+
const responseText = leadRun.text
|
|
548
|
+
|
|
549
|
+
const replyMarkdown = buildSlackSocialReplyMarkdown({ replyMarkdown: responseText, executedToolNames })
|
|
550
|
+
const sentMessage = yield* effectTryPromise(() => thread.post({ markdown: replyMarkdown }))
|
|
551
|
+
aiLogger.debug`Slack social-chat reply posted: channelId=${messageContext.channelId}, threadId=${messageContext.threadId}, replyMessageId=${sentMessage.id}`
|
|
552
|
+
const normalizedResponse = normalizeSocialHistoryMessage({
|
|
553
|
+
workspaceId: workspaceIdString,
|
|
554
|
+
channelId: messageContext.channelId,
|
|
555
|
+
agentId: socialAgentId,
|
|
556
|
+
agentDisplayName: socialAgentDisplayName,
|
|
557
|
+
message: sentMessage,
|
|
558
|
+
textOverride: responseText,
|
|
559
|
+
})
|
|
560
|
+
if (normalizedResponse) {
|
|
561
|
+
yield* socialChatHistoryService.upsertMessages([normalizedResponse])
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
const priorHistoryMessages = toHistoryMessages(agentConfig, priorHistory)
|
|
565
|
+
const agentMessages = normalizedResponse ? buildAgentHistoryMessages(agentConfig, [normalizedResponse]) : []
|
|
566
|
+
if (messageContext.text && agentMessages.length > 0) {
|
|
567
|
+
yield* effectTryPromise(() =>
|
|
568
|
+
safeEnqueue(
|
|
569
|
+
() =>
|
|
570
|
+
params.services.queues.postChatMemory.enqueuePostChatMemory(
|
|
571
|
+
{
|
|
572
|
+
orgId: workspaceIdString,
|
|
573
|
+
threadId: `social:slack:${messageContext.threadId}`,
|
|
574
|
+
sourceId: createSocialChatCursorId({
|
|
575
|
+
workspaceId: workspaceIdString,
|
|
576
|
+
threadId: messageContext.threadId,
|
|
577
|
+
messageId: messageContext.messageId,
|
|
578
|
+
}),
|
|
579
|
+
userMessage: messageContext.text,
|
|
580
|
+
historyMessages: priorHistoryMessages,
|
|
581
|
+
agentMessages,
|
|
582
|
+
memoryBlock: memoryBlock.trim() ? memoryBlock : undefined,
|
|
583
|
+
source: 'social_chat',
|
|
584
|
+
sourceMetadata: {
|
|
585
|
+
platform: 'slack',
|
|
586
|
+
channelId: messageContext.channelId,
|
|
587
|
+
threadId: messageContext.threadId,
|
|
588
|
+
messageId: messageContext.messageId,
|
|
589
|
+
authorId: messageContext.authorId,
|
|
590
|
+
authorName: messageContext.authorName,
|
|
591
|
+
},
|
|
592
|
+
},
|
|
593
|
+
{
|
|
594
|
+
dedupeKey: createSocialMemoryDedupeKey({
|
|
595
|
+
workspaceId: workspaceIdString,
|
|
596
|
+
threadId: messageContext.threadId,
|
|
597
|
+
messageId: messageContext.messageId,
|
|
598
|
+
}),
|
|
599
|
+
},
|
|
600
|
+
),
|
|
601
|
+
{ operationName: 'social post-chat memory extraction enqueue' },
|
|
602
|
+
),
|
|
603
|
+
)
|
|
604
|
+
}
|
|
605
|
+
|
|
520
606
|
yield* effectTryPromise(() =>
|
|
521
607
|
safeEnqueue(
|
|
522
608
|
() =>
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
}),
|
|
532
|
-
userMessage: messageContext.text,
|
|
533
|
-
historyMessages: priorHistoryMessages,
|
|
534
|
-
agentMessages,
|
|
535
|
-
memoryBlock: memoryBlock.trim() ? memoryBlock : undefined,
|
|
536
|
-
source: 'social_chat',
|
|
537
|
-
sourceMetadata: {
|
|
538
|
-
platform: 'slack',
|
|
539
|
-
channelId: messageContext.channelId,
|
|
540
|
-
threadId: messageContext.threadId,
|
|
541
|
-
messageId: messageContext.messageId,
|
|
542
|
-
authorId: messageContext.authorId,
|
|
543
|
-
authorName: messageContext.authorName,
|
|
544
|
-
},
|
|
545
|
-
},
|
|
546
|
-
{
|
|
547
|
-
dedupeKey: createSocialMemoryDedupeKey({
|
|
548
|
-
workspaceId: workspaceIdString,
|
|
549
|
-
threadId: messageContext.threadId,
|
|
550
|
-
messageId: messageContext.messageId,
|
|
551
|
-
}),
|
|
552
|
-
},
|
|
553
|
-
),
|
|
554
|
-
{ operationName: 'social post-chat memory extraction enqueue' },
|
|
609
|
+
params.services.queues.organizationLearning.enqueueRegularChatMemoryDigest({ orgId: workspaceIdString }),
|
|
610
|
+
{ operationName: 'social regular chat memory digest enqueue' },
|
|
611
|
+
),
|
|
612
|
+
)
|
|
613
|
+
yield* effectTryPromise(() =>
|
|
614
|
+
safeEnqueue(
|
|
615
|
+
() => params.services.queues.organizationLearning.enqueueSkillExtraction({ orgId: workspaceIdString }),
|
|
616
|
+
{ operationName: 'social skill extraction enqueue' },
|
|
555
617
|
),
|
|
556
618
|
)
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
yield* effectTryPromise(() =>
|
|
560
|
-
safeEnqueue(() => enqueueRegularChatMemoryDigest({ orgId: workspaceIdString }), {
|
|
561
|
-
operationName: 'social regular chat memory digest enqueue',
|
|
562
|
-
}),
|
|
563
|
-
)
|
|
564
|
-
yield* effectTryPromise(() =>
|
|
565
|
-
safeEnqueue(() => enqueueSkillExtraction({ orgId: workspaceIdString }), {
|
|
566
|
-
operationName: 'social skill extraction enqueue',
|
|
567
|
-
}),
|
|
568
|
-
)
|
|
569
|
-
})
|
|
619
|
+
}),
|
|
620
|
+
)
|
|
570
621
|
|
|
571
622
|
chat.onNewMention((thread, message) => {
|
|
572
|
-
aiLogger.
|
|
623
|
+
aiLogger.debug`Slack social-chat new mention received: threadId=${thread.id}, messageId=${message.id}`
|
|
573
624
|
return Effect.runPromise(
|
|
574
625
|
Effect.gen(function* () {
|
|
575
626
|
yield* effectTryPromise(() => thread.subscribe())
|
|
@@ -578,7 +629,7 @@ export function createSocialChatRuntime(params: {
|
|
|
578
629
|
)
|
|
579
630
|
})
|
|
580
631
|
chat.onSubscribedMessage((thread, message) => {
|
|
581
|
-
aiLogger.
|
|
632
|
+
aiLogger.debug`Slack social-chat subscribed thread message received: threadId=${thread.id}, messageId=${message.id}`
|
|
582
633
|
return Effect.runPromise(handleMessage(thread, message))
|
|
583
634
|
})
|
|
584
635
|
|