@lota-sdk/core 0.4.7 → 0.4.9
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 +11 -12
- package/src/ai/embedding-cache.ts +94 -22
- package/src/ai-gateway/ai-gateway.ts +738 -223
- package/src/config/agent-defaults.ts +176 -75
- package/src/config/agent-types.ts +54 -4
- package/src/config/constants.ts +8 -2
- package/src/config/logger.ts +286 -19
- package/src/config/model-constants.ts +1 -0
- package/src/config/thread-defaults.ts +33 -21
- package/src/create-runtime.ts +725 -383
- package/src/db/base.service.ts +52 -28
- package/src/db/cursor-pagination.ts +71 -30
- package/src/db/memory-store.helpers.ts +4 -7
- package/src/db/memory-store.ts +856 -598
- package/src/db/memory.ts +398 -275
- package/src/db/record-id.ts +32 -10
- package/src/db/schema-fingerprint.ts +30 -12
- package/src/db/service-normalization.ts +255 -0
- package/src/db/service.ts +726 -761
- package/src/db/startup.ts +140 -66
- package/src/db/transaction-conflict.ts +15 -0
- package/src/effect/awaitable-effect.ts +87 -0
- package/src/effect/errors.ts +121 -0
- package/src/effect/helpers.ts +98 -0
- package/src/effect/index.ts +22 -0
- package/src/effect/layers.ts +228 -0
- package/src/effect/runtime-ref.ts +25 -0
- package/src/effect/runtime.ts +31 -0
- package/src/effect/services.ts +57 -0
- package/src/effect/zod.ts +43 -0
- package/src/embeddings/provider.ts +122 -71
- package/src/index.ts +46 -1
- package/src/openrouter/direct-provider.ts +29 -0
- package/src/queues/autonomous-job.queue.ts +130 -74
- package/src/queues/context-compaction.queue.ts +60 -15
- package/src/queues/delayed-node-promotion.queue.ts +52 -15
- package/src/queues/document-processor.queue.ts +52 -77
- package/src/queues/memory-consolidation.queue.ts +47 -32
- package/src/queues/organization-learning.queue.ts +13 -4
- package/src/queues/plan-agent-heartbeat.queue.ts +65 -21
- package/src/queues/plan-scheduler.queue.ts +107 -31
- package/src/queues/post-chat-memory.queue.ts +66 -24
- package/src/queues/queue-factory.ts +142 -52
- package/src/queues/standalone-worker.ts +39 -0
- package/src/queues/title-generation.queue.ts +54 -9
- package/src/redis/connection.ts +84 -32
- package/src/redis/index.ts +6 -8
- package/src/redis/org-memory-lock.ts +60 -27
- package/src/redis/redis-lease-lock.ts +200 -121
- package/src/redis/runtime-connection.ts +10 -0
- package/src/redis/stream-context.ts +84 -46
- package/src/runtime/agent-identity-overrides.ts +2 -2
- package/src/runtime/agent-runtime-policy.ts +4 -1
- package/src/runtime/agent-stream-helpers.ts +20 -9
- package/src/runtime/chat-run-orchestration.ts +102 -19
- package/src/runtime/chat-run-registry.ts +36 -2
- package/src/runtime/context-compaction/context-compaction-runtime.ts +107 -0
- package/src/runtime/{context-compaction.ts → context-compaction/context-compaction.ts} +114 -91
- package/src/runtime/execution-plan-visibility.ts +2 -2
- package/src/runtime/execution-plan.ts +42 -15
- package/src/runtime/graph-designer.ts +11 -7
- package/src/runtime/helper-model.ts +135 -48
- package/src/runtime/index.ts +7 -7
- package/src/runtime/indexed-repositories-policy.ts +3 -3
- package/src/runtime/{memory-block.ts → memory/memory-block.ts} +40 -36
- package/src/runtime/{memory-digest-policy.ts → memory/memory-digest-policy.ts} +1 -1
- package/src/runtime/{memory-pipeline.ts → memory/memory-pipeline.ts} +1 -1
- package/src/runtime/{memory-prompts-fact.ts → memory/memory-prompts-fact.ts} +2 -2
- package/src/runtime/{memory-scope.ts → memory/memory-scope.ts} +12 -6
- package/src/runtime/plugin-resolution.ts +144 -24
- package/src/runtime/plugin-types.ts +9 -1
- package/src/runtime/post-turn-side-effects.ts +197 -130
- package/src/runtime/retrieval-adapters.ts +38 -4
- package/src/runtime/runtime-config.ts +165 -61
- package/src/runtime/runtime-extensions.ts +21 -34
- package/src/runtime/social-chat/social-chat-agent-runner.ts +157 -0
- package/src/runtime/{social-chat-history.ts → social-chat/social-chat-history.ts} +42 -20
- package/src/runtime/social-chat/social-chat.ts +594 -0
- package/src/runtime/specialist-runner.ts +36 -10
- package/src/runtime/team-consultation/team-consultation-orchestrator.ts +427 -0
- package/src/runtime/{team-consultation-prompts.ts → team-consultation/team-consultation-prompts.ts} +6 -2
- package/src/runtime/thread-chat-helpers.ts +2 -2
- package/src/runtime/thread-plan-turn.ts +2 -1
- package/src/runtime/thread-turn-context.ts +172 -94
- package/src/runtime/turn-lifecycle.ts +93 -27
- package/src/services/agent-activity.service.ts +287 -203
- package/src/services/agent-executor.service.ts +329 -217
- package/src/services/artifact.service.ts +225 -148
- package/src/services/attachment.service.ts +137 -115
- package/src/services/autonomous-job.service.ts +888 -491
- package/src/services/chat-run-registry.service.ts +11 -1
- package/src/services/context-compaction.service.ts +136 -86
- package/src/services/document-chunk.service.ts +162 -90
- package/src/services/execution-plan/execution-plan-approval.ts +26 -0
- package/src/services/execution-plan/execution-plan-context.ts +29 -0
- package/src/services/execution-plan/execution-plan-graph.ts +256 -0
- package/src/services/execution-plan/execution-plan-schedule.ts +84 -0
- package/src/services/execution-plan/execution-plan-spec.ts +75 -0
- package/src/services/execution-plan/execution-plan.service.ts +1041 -0
- package/src/services/feedback-loop.service.ts +132 -76
- package/src/services/global-orchestrator.service.ts +80 -170
- package/src/services/graph-full-routing.ts +182 -0
- package/src/services/index.ts +18 -20
- package/src/services/institutional-memory.service.ts +220 -123
- package/src/services/learned-skill.service.ts +364 -259
- package/src/services/memory/memory-conversation.ts +95 -0
- package/src/services/memory/memory-org-memory.ts +39 -0
- package/src/services/memory/memory-preseeded.ts +80 -0
- package/src/services/memory/memory-rerank.ts +297 -0
- package/src/services/{memory-utils.ts → memory/memory-utils.ts} +5 -5
- package/src/services/memory/memory.service.ts +692 -0
- package/src/services/memory/rerank.service.ts +209 -0
- package/src/services/monitoring-window.service.ts +92 -70
- package/src/services/mutating-approval.service.ts +62 -53
- package/src/services/node-workspace.service.ts +141 -98
- package/src/services/notification.service.ts +17 -16
- package/src/services/organization-member.service.ts +120 -66
- package/src/services/organization.service.ts +144 -51
- package/src/services/ownership-dispatcher.service.ts +415 -264
- package/src/services/plan/plan-agent-heartbeat.service.ts +234 -0
- package/src/services/plan/plan-agent-query.service.ts +322 -0
- package/src/services/plan/plan-approval.service.ts +102 -0
- package/src/services/plan/plan-artifact.service.ts +60 -0
- package/src/services/plan/plan-builder.service.ts +76 -0
- package/src/services/plan/plan-checkpoint.service.ts +103 -0
- package/src/services/{plan-compiler.service.ts → plan/plan-compiler.service.ts} +26 -9
- package/src/services/plan/plan-completion-side-effects.ts +175 -0
- package/src/services/plan/plan-coordination.service.ts +181 -0
- package/src/services/plan/plan-cycle.service.ts +398 -0
- package/src/services/plan/plan-deadline.service.ts +547 -0
- package/src/services/plan/plan-event-delivery.service.ts +261 -0
- package/src/services/plan/plan-executor-context.ts +35 -0
- package/src/services/plan/plan-executor-graph.ts +475 -0
- package/src/services/plan/plan-executor-helpers.ts +322 -0
- package/src/services/plan/plan-executor-persistence.ts +209 -0
- package/src/services/plan/plan-executor.service.ts +1654 -0
- package/src/services/{plan-helpers.ts → plan/plan-helpers.ts} +1 -1
- package/src/services/{plan-run-data.ts → plan/plan-run-data.ts} +4 -4
- package/src/services/plan/plan-run-serialization.ts +15 -0
- package/src/services/plan/plan-run.service.ts +644 -0
- package/src/services/plan/plan-scheduler.service.ts +385 -0
- package/src/services/plan/plan-template.service.ts +224 -0
- package/src/services/plan/plan-transaction-events.ts +33 -0
- package/src/services/plan/plan-validator.service.ts +907 -0
- package/src/services/plan/plan-workspace.service.ts +125 -0
- package/src/services/plugin-executor.service.ts +97 -68
- package/src/services/quality-metrics.service.ts +112 -94
- package/src/services/queue-job.service.ts +296 -230
- package/src/services/recent-activity-title.service.ts +65 -36
- package/src/services/recent-activity.service.ts +274 -259
- package/src/services/skill-resolver.service.ts +38 -12
- package/src/services/social-chat-history.service.ts +176 -125
- package/src/services/system-executor.service.ts +91 -61
- package/src/services/thread/thread-active-run.ts +203 -0
- package/src/services/thread/thread-bootstrap.ts +369 -0
- package/src/services/thread/thread-listing.ts +198 -0
- package/src/services/thread/thread-memory-block.ts +117 -0
- package/src/services/thread/thread-message.service.ts +363 -0
- package/src/services/thread/thread-record-store.ts +155 -0
- package/src/services/thread/thread-title.service.ts +74 -0
- package/src/services/thread/thread-turn-execution.ts +280 -0
- package/src/services/thread/thread-turn-message-context.ts +73 -0
- package/src/services/thread/thread-turn-preparation.service.ts +1146 -0
- package/src/services/thread/thread-turn-streaming.ts +402 -0
- package/src/services/thread/thread-turn-tracing.ts +35 -0
- package/src/services/thread/thread-turn.ts +343 -0
- package/src/services/thread/thread.service.ts +335 -0
- package/src/services/user.service.ts +82 -32
- package/src/services/write-intent-validator.service.ts +63 -51
- package/src/storage/attachment-parser.ts +69 -27
- package/src/storage/attachment-storage.service.ts +331 -275
- package/src/storage/generated-document-storage.service.ts +66 -34
- package/src/system-agents/agent-result.ts +3 -1
- package/src/system-agents/context-compaction.agent.ts +2 -2
- package/src/system-agents/delegated-agent-factory.ts +159 -90
- package/src/system-agents/memory-reranker.agent.ts +2 -2
- package/src/system-agents/memory.agent.ts +2 -2
- package/src/system-agents/recent-activity-title-refiner.agent.ts +2 -2
- package/src/system-agents/regular-chat-memory-digest.agent.ts +2 -2
- package/src/system-agents/skill-extractor.agent.ts +2 -2
- package/src/system-agents/skill-manager.agent.ts +2 -2
- package/src/system-agents/thread-router.agent.ts +157 -113
- package/src/system-agents/title-generator.agent.ts +2 -2
- package/src/tools/execution-plan.tool.ts +220 -161
- package/src/tools/fetch-webpage.tool.ts +21 -17
- package/src/tools/firecrawl-client.ts +16 -6
- package/src/tools/index.ts +1 -0
- package/src/tools/memory-block.tool.ts +14 -6
- package/src/tools/plan-approval.tool.ts +49 -47
- package/src/tools/read-file-parts.tool.ts +44 -33
- package/src/tools/remember-memory.tool.ts +65 -45
- package/src/tools/search-web.tool.ts +26 -22
- package/src/tools/search.tool.ts +41 -29
- package/src/tools/team-think.tool.ts +124 -83
- package/src/tools/user-questions.tool.ts +4 -3
- package/src/tools/web-tool-shared.ts +6 -0
- package/src/utils/async.ts +17 -23
- package/src/utils/crypto.ts +21 -0
- package/src/utils/date-time.ts +40 -1
- package/src/utils/errors.ts +95 -16
- package/src/utils/hono-error-handler.ts +24 -39
- package/src/utils/index.ts +2 -1
- package/src/utils/null-proto-record.ts +41 -0
- package/src/utils/sse-keepalive.ts +124 -21
- package/src/workers/bootstrap.ts +186 -51
- package/src/workers/memory-consolidation.worker.ts +325 -237
- package/src/workers/organization-learning.worker.ts +50 -16
- package/src/workers/regular-chat-memory-digest.helpers.ts +28 -27
- package/src/workers/regular-chat-memory-digest.runner.ts +175 -114
- package/src/workers/skill-extraction.runner.ts +176 -93
- package/src/workers/utils/file-section-chunker.ts +8 -10
- package/src/workers/utils/repo-structure-extractor.ts +349 -260
- package/src/workers/utils/repomix-file-sections.ts +2 -2
- package/src/workers/utils/thread-message-query.ts +97 -38
- package/src/workers/worker-utils.ts +56 -31
- package/src/config/debug-logger.ts +0 -47
- package/src/redis/connection-accessor.ts +0 -26
- package/src/runtime/context-compaction-runtime.ts +0 -87
- package/src/runtime/social-chat-agent-runner.ts +0 -118
- package/src/runtime/social-chat.ts +0 -516
- package/src/runtime/team-consultation-orchestrator.ts +0 -272
- package/src/services/adaptive-playbook.service.ts +0 -152
- package/src/services/artifact-provenance.service.ts +0 -172
- package/src/services/chat-attachments.service.ts +0 -17
- package/src/services/context-compaction-runtime.singleton.ts +0 -13
- package/src/services/execution-plan.service.ts +0 -1118
- package/src/services/memory.service.ts +0 -844
- package/src/services/plan-agent-heartbeat.service.ts +0 -136
- package/src/services/plan-agent-query.service.ts +0 -267
- package/src/services/plan-approval.service.ts +0 -83
- package/src/services/plan-artifact.service.ts +0 -50
- package/src/services/plan-builder.service.ts +0 -67
- package/src/services/plan-checkpoint.service.ts +0 -81
- package/src/services/plan-completion-side-effects.ts +0 -80
- package/src/services/plan-coordination.service.ts +0 -157
- package/src/services/plan-cycle.service.ts +0 -284
- package/src/services/plan-deadline.service.ts +0 -430
- package/src/services/plan-event-delivery.service.ts +0 -166
- package/src/services/plan-executor.service.ts +0 -1950
- package/src/services/plan-run.service.ts +0 -515
- package/src/services/plan-scheduler.service.ts +0 -240
- package/src/services/plan-template.service.ts +0 -177
- package/src/services/plan-validator.service.ts +0 -818
- package/src/services/plan-workspace.service.ts +0 -83
- package/src/services/thread-message.service.ts +0 -275
- package/src/services/thread-plan-registry.service.ts +0 -22
- package/src/services/thread-title.service.ts +0 -39
- package/src/services/thread-turn-preparation.service.ts +0 -1147
- package/src/services/thread-turn.ts +0 -172
- package/src/services/thread.service.ts +0 -869
- package/src/utils/env.ts +0 -8
- /package/src/runtime/{context-compaction-constants.ts → context-compaction/context-compaction-constants.ts} +0 -0
- /package/src/runtime/{memory-format.ts → memory/memory-format.ts} +0 -0
- /package/src/runtime/{memory-prompts-parse.ts → memory/memory-prompts-parse.ts} +0 -0
- /package/src/runtime/{memory-prompts-update.ts → memory/memory-prompts-update.ts} +0 -0
- /package/src/runtime/{social-chat-prompts.ts → social-chat/social-chat-prompts.ts} +0 -0
- /package/src/services/{plan-node-spec.ts → plan/plan-node-spec.ts} +0 -0
- /package/src/services/{thread-constants.ts → thread/thread-constants.ts} +0 -0
- /package/src/services/{thread.types.ts → thread/thread.types.ts} +0 -0
|
@@ -1,31 +1,65 @@
|
|
|
1
1
|
import type { SandboxedJob } from 'bullmq'
|
|
2
|
+
import { Effect } from 'effect'
|
|
3
|
+
import type { Context } from 'effect'
|
|
2
4
|
|
|
3
5
|
import { serverLogger } from '../config/logger'
|
|
6
|
+
import { effectTryPromise } from '../effect/helpers'
|
|
7
|
+
import { DatabaseServiceTag, RuntimeAdaptersServiceTag, RuntimeConfigServiceTag } from '../effect/services'
|
|
4
8
|
import type { OrganizationLearningJob } from '../queues/organization-learning.queue'
|
|
9
|
+
import { LearnedSkillServiceTag } from '../services/learned-skill.service'
|
|
10
|
+
import { MemoryServiceTag } from '../services/memory/memory.service'
|
|
11
|
+
import { SocialChatHistoryServiceTag } from '../services/social-chat-history.service'
|
|
5
12
|
import { initializeSandboxedWorkerRuntime } from './bootstrap'
|
|
6
13
|
import { runRegularChatMemoryDigest } from './regular-chat-memory-digest.runner'
|
|
14
|
+
import type { RegularChatDigestServices } from './regular-chat-memory-digest.runner'
|
|
7
15
|
import { runSkillExtraction } from './skill-extraction.runner'
|
|
16
|
+
import type { SkillExtractionServices } from './skill-extraction.runner'
|
|
8
17
|
import { toSandboxedWorkerError } from './utils/sandbox-error'
|
|
9
18
|
import { createTracedWorkerProcessor } from './worker-utils'
|
|
10
19
|
|
|
11
|
-
await initializeSandboxedWorkerRuntime()
|
|
20
|
+
const runtime = await initializeSandboxedWorkerRuntime()
|
|
21
|
+
const resolve = async <I, T>(tag: Context.Key<I, T>): Promise<T> => await runtime.runPromise(Effect.service(tag))
|
|
22
|
+
const regularChatDigestServices: RegularChatDigestServices = {
|
|
23
|
+
databaseService: await resolve(DatabaseServiceTag),
|
|
24
|
+
memoryService: await resolve(MemoryServiceTag),
|
|
25
|
+
socialChatHistoryService: await resolve(SocialChatHistoryServiceTag),
|
|
26
|
+
runtimeAdapters: await resolve(RuntimeAdaptersServiceTag),
|
|
27
|
+
}
|
|
28
|
+
const workerRuntimeConfig = await resolve(RuntimeConfigServiceTag)
|
|
29
|
+
const skillExtractionServices: SkillExtractionServices = {
|
|
30
|
+
databaseService: await resolve(DatabaseServiceTag),
|
|
31
|
+
learnedSkillService: await resolve(LearnedSkillServiceTag),
|
|
32
|
+
socialChatHistoryService: await resolve(SocialChatHistoryServiceTag),
|
|
33
|
+
runtimeAdapters: await resolve(RuntimeAdaptersServiceTag),
|
|
34
|
+
embeddingModel: workerRuntimeConfig.aiGateway.embeddingModel,
|
|
35
|
+
openRouterApiKey: workerRuntimeConfig.aiGateway.openRouterApiKey,
|
|
36
|
+
}
|
|
12
37
|
|
|
13
38
|
// One sandboxed worker handles both organization-learning branches so the
|
|
14
39
|
// queue can dispatch digest and skill jobs without separate worker images.
|
|
15
|
-
const handler =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
40
|
+
const handler = (job: SandboxedJob<OrganizationLearningJob>) =>
|
|
41
|
+
Effect.runPromise(
|
|
42
|
+
Effect.gen(function* () {
|
|
43
|
+
if (job.data.kind === 'regular-chat-memory-digest') {
|
|
44
|
+
const digestJob = job.data
|
|
45
|
+
return yield* effectTryPromise(() => runRegularChatMemoryDigest(digestJob, regularChatDigestServices))
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const skillJob = job.data
|
|
49
|
+
return yield* effectTryPromise(() => runSkillExtraction(skillJob, skillExtractionServices))
|
|
50
|
+
}).pipe(
|
|
51
|
+
Effect.catch((error) =>
|
|
52
|
+
Effect.gen(function* () {
|
|
53
|
+
const message =
|
|
54
|
+
job.data.kind === 'regular-chat-memory-digest'
|
|
55
|
+
? 'Regular chat memory digest failed'
|
|
56
|
+
: 'Skill extraction failed'
|
|
57
|
+
const serialized = toSandboxedWorkerError(error, message)
|
|
58
|
+
serverLogger.error`${serialized.message}`
|
|
59
|
+
return yield* Effect.fail(serialized)
|
|
60
|
+
}),
|
|
61
|
+
),
|
|
62
|
+
),
|
|
63
|
+
)
|
|
30
64
|
|
|
31
65
|
export default createTracedWorkerProcessor('organization-learning', handler)
|
|
@@ -1,40 +1,40 @@
|
|
|
1
1
|
import { isAgentName } from '../config/agent-defaults'
|
|
2
|
-
import { compactWhitespace } from '../utils/string'
|
|
2
|
+
import { compactWhitespace, readRecord, readString } from '../utils/string'
|
|
3
|
+
import type { DigestMessage } from './utils/thread-message-query'
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
sourceId: string
|
|
7
|
-
role: 'system' | 'user' | 'assistant'
|
|
8
|
-
parts: Array<Record<string, unknown>>
|
|
9
|
-
metadata?: Record<string, unknown>
|
|
10
|
-
}
|
|
5
|
+
type DigestMessageForTranscript = Pick<DigestMessage, 'source' | 'sourceId' | 'role' | 'parts' | 'metadata'>
|
|
6
|
+
type DigestMessagePart = DigestMessageForTranscript['parts'][number]
|
|
11
7
|
|
|
12
|
-
function normalizeFilePartMetadata(part:
|
|
8
|
+
function normalizeFilePartMetadata(part: DigestMessagePart): string | null {
|
|
13
9
|
if (part.type !== 'file') return null
|
|
10
|
+
const partRecord = readRecord(part)
|
|
11
|
+
if (!partRecord) return null
|
|
14
12
|
|
|
15
|
-
const filename =
|
|
16
|
-
const mediaType =
|
|
17
|
-
const
|
|
13
|
+
const filename = readString(partRecord.filename) ?? 'attachment'
|
|
14
|
+
const mediaType = readString(partRecord.mediaType) ?? 'unknown'
|
|
15
|
+
const providerMetadata = readRecord(partRecord.providerMetadata)
|
|
16
|
+
const lotaMetadata = readRecord(providerMetadata?.lota)
|
|
17
|
+
const storageKey = readString(partRecord.storageKey) ?? readString(lotaMetadata?.attachmentStorageKey) ?? 'unknown'
|
|
18
18
|
const sizeBytes =
|
|
19
|
-
typeof
|
|
20
|
-
? Math.trunc(
|
|
19
|
+
typeof partRecord.sizeBytes === 'number' && Number.isFinite(partRecord.sizeBytes) && partRecord.sizeBytes >= 0
|
|
20
|
+
? Math.trunc(partRecord.sizeBytes)
|
|
21
21
|
: null
|
|
22
22
|
|
|
23
23
|
const sizeSegment = sizeBytes === null ? '' : `, sizeBytes=${sizeBytes}`
|
|
24
24
|
return `${filename} (${mediaType}${sizeSegment}, storageKey=${storageKey})`
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
function extractAssistantLabel(
|
|
27
|
+
function extractAssistantLabel(
|
|
28
|
+
message: DigestMessageForTranscript,
|
|
29
|
+
isKnownAgentName: (value: string) => boolean = isAgentName,
|
|
30
|
+
): string {
|
|
28
31
|
const metadataAgentId =
|
|
29
|
-
message.metadata
|
|
30
|
-
|
|
31
|
-
: ''
|
|
32
|
-
if (metadataAgentId && isAgentName(metadataAgentId)) {
|
|
32
|
+
typeof message.metadata?.agentId === 'string' ? message.metadata.agentId.trim().toLowerCase() : ''
|
|
33
|
+
if (metadataAgentId && isKnownAgentName(metadataAgentId)) {
|
|
33
34
|
return metadataAgentId
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
const metadataAgentName =
|
|
37
|
-
message.metadata && typeof message.metadata.agentName === 'string' ? message.metadata.agentName.trim() : ''
|
|
37
|
+
const metadataAgentName = typeof message.metadata?.agentName === 'string' ? message.metadata.agentName.trim() : ''
|
|
38
38
|
if (metadataAgentName) {
|
|
39
39
|
return metadataAgentName
|
|
40
40
|
}
|
|
@@ -42,12 +42,13 @@ function extractAssistantLabel(message: DigestMessageForTranscript): string {
|
|
|
42
42
|
return 'assistant'
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
export function buildDigestTranscript(params: {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
} {
|
|
45
|
+
export function buildDigestTranscript(params: {
|
|
46
|
+
messages: DigestMessageForTranscript[]
|
|
47
|
+
isKnownAgentName?: (value: string) => boolean
|
|
48
|
+
}): { transcript: string; involvedAgentNames: string[] } {
|
|
49
49
|
const lines: string[] = []
|
|
50
50
|
const involvedAgentNames = new Set<string>()
|
|
51
|
+
const isKnownAgentName = params.isKnownAgentName ?? isAgentName
|
|
51
52
|
|
|
52
53
|
for (const message of params.messages) {
|
|
53
54
|
if (message.role !== 'user' && message.role !== 'assistant') continue
|
|
@@ -70,8 +71,8 @@ export function buildDigestTranscript(params: { messages: DigestMessageForTransc
|
|
|
70
71
|
continue
|
|
71
72
|
}
|
|
72
73
|
|
|
73
|
-
const assistantLabel = extractAssistantLabel(message)
|
|
74
|
-
if (
|
|
74
|
+
const assistantLabel = extractAssistantLabel(message, isKnownAgentName)
|
|
75
|
+
if (isKnownAgentName(assistantLabel)) {
|
|
75
76
|
involvedAgentNames.add(assistantLabel)
|
|
76
77
|
}
|
|
77
78
|
|
|
@@ -1,21 +1,25 @@
|
|
|
1
|
+
import { Cause, Effect } from 'effect'
|
|
2
|
+
import type { Context } from 'effect'
|
|
1
3
|
import { BoundQuery } from 'surrealdb'
|
|
2
4
|
import { z } from 'zod'
|
|
3
5
|
|
|
4
6
|
import { serverLogger } from '../config/logger'
|
|
5
7
|
import { ensureRecordId, recordIdToString } from '../db/record-id'
|
|
6
8
|
import type { RecordIdRef } from '../db/record-id'
|
|
7
|
-
import {
|
|
9
|
+
import type { SurrealDBService } from '../db/service'
|
|
8
10
|
import { TABLES } from '../db/tables'
|
|
11
|
+
import { effectTryPromise } from '../effect/helpers'
|
|
9
12
|
import {
|
|
10
13
|
clearRegularChatMemoryDigestDeduplicationKey,
|
|
11
14
|
enqueueRegularChatMemoryDigest,
|
|
12
15
|
} from '../queues/organization-learning.queue'
|
|
13
16
|
import type { RegularChatMemoryDigestJob } from '../queues/organization-learning.queue'
|
|
14
17
|
import { createHelperModelRuntime } from '../runtime/helper-model'
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
+
import type { LotaRuntimeAdapters, LotaRuntimeBackgroundCursor } from '../runtime/runtime-extensions'
|
|
19
|
+
import type { MemoryServiceTag } from '../services/memory/memory.service'
|
|
20
|
+
import type { SocialChatHistoryServiceTag } from '../services/social-chat-history.service'
|
|
18
21
|
import { createRegularChatMemoryDigestAgent } from '../system-agents/regular-chat-memory-digest.agent'
|
|
22
|
+
import { nowIsoDateTimeString } from '../utils/date-time'
|
|
19
23
|
import { compactWhitespace } from '../utils/string'
|
|
20
24
|
import { buildDigestTranscript, resolveWorkspaceBootstrapCutoff } from './regular-chat-memory-digest.helpers'
|
|
21
25
|
import {
|
|
@@ -24,7 +28,7 @@ import {
|
|
|
24
28
|
listThreadIdsForOrg,
|
|
25
29
|
normalizeBlock,
|
|
26
30
|
} from './utils/thread-message-query'
|
|
27
|
-
import type {
|
|
31
|
+
import type { DigestMessage } from './utils/thread-message-query'
|
|
28
32
|
|
|
29
33
|
// Onboarding extracts memory immediately inside the turn flow. This delayed
|
|
30
34
|
// runner handles the regular-chat path after onboarding so longer transcripts
|
|
@@ -33,6 +37,12 @@ const StructuredProfilePatchSchema = z.record(z.string(), z.unknown()).default({
|
|
|
33
37
|
|
|
34
38
|
const REGULAR_CHAT_MEMORY_DIGEST_TIMEOUT_MS = 10 * 60 * 1000
|
|
35
39
|
const WorkspaceMemoryRowSchema = z.object({ content: z.string() })
|
|
40
|
+
export interface RegularChatDigestServices {
|
|
41
|
+
databaseService: SurrealDBService
|
|
42
|
+
memoryService: Context.Service.Shape<typeof MemoryServiceTag>
|
|
43
|
+
socialChatHistoryService: Context.Service.Shape<typeof SocialChatHistoryServiceTag>
|
|
44
|
+
runtimeAdapters: LotaRuntimeAdapters
|
|
45
|
+
}
|
|
36
46
|
|
|
37
47
|
const ExtractedFactSchema = z.object({
|
|
38
48
|
content: z.string().trim().min(1),
|
|
@@ -96,109 +106,122 @@ function buildPrompt(params: {
|
|
|
96
106
|
].join('\n')
|
|
97
107
|
}
|
|
98
108
|
|
|
99
|
-
function getLastCursor(messages: DigestMessage[]):
|
|
109
|
+
function getLastCursor(messages: DigestMessage[]): LotaRuntimeBackgroundCursor | null {
|
|
100
110
|
return messages.length > 0 ? messages[messages.length - 1].cursor : null
|
|
101
111
|
}
|
|
102
112
|
|
|
103
|
-
|
|
113
|
+
function hasNewEligibleThreadMessages(params: {
|
|
114
|
+
db: SurrealDBService
|
|
104
115
|
threadIds: RecordIdRef[]
|
|
105
|
-
cursor:
|
|
116
|
+
cursor: LotaRuntimeBackgroundCursor | null
|
|
106
117
|
onboardingCutoff: Date | null
|
|
107
118
|
}): Promise<boolean> {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
119
|
+
return Effect.runPromise(
|
|
120
|
+
Effect.gen(function* () {
|
|
121
|
+
if (params.threadIds.length === 0) return false
|
|
122
|
+
|
|
123
|
+
let query: BoundQuery | null = null
|
|
124
|
+
if (params.cursor) {
|
|
125
|
+
const cursorRowId = ensureRecordId(params.cursor.id, TABLES.THREAD_MESSAGE)
|
|
126
|
+
query = new BoundQuery(
|
|
127
|
+
`SELECT id, createdAt FROM ${TABLES.THREAD_MESSAGE}
|
|
128
|
+
WHERE threadId IN $threadIds
|
|
129
|
+
AND (
|
|
130
|
+
createdAt > $cursorCreatedAt
|
|
131
|
+
OR (createdAt = $cursorCreatedAt AND id > $cursorRowId)
|
|
132
|
+
)
|
|
133
|
+
ORDER BY createdAt ASC, id ASC
|
|
134
|
+
LIMIT 1`,
|
|
135
|
+
{ threadIds: params.threadIds, cursorCreatedAt: params.cursor.createdAt, cursorRowId },
|
|
136
|
+
)
|
|
137
|
+
} else if (params.onboardingCutoff) {
|
|
138
|
+
query = new BoundQuery(
|
|
139
|
+
`SELECT id, createdAt FROM ${TABLES.THREAD_MESSAGE}
|
|
140
|
+
WHERE threadId IN $threadIds
|
|
141
|
+
AND createdAt > $onboardingCutoff
|
|
142
|
+
ORDER BY createdAt ASC, id ASC
|
|
143
|
+
LIMIT 1`,
|
|
144
|
+
{ threadIds: params.threadIds, onboardingCutoff: params.onboardingCutoff },
|
|
145
|
+
)
|
|
146
|
+
}
|
|
134
147
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
148
|
+
if (!query) return false
|
|
149
|
+
const rows = yield* effectTryPromise(() => params.db.query<unknown>(query))
|
|
150
|
+
return rows.length > 0
|
|
151
|
+
}),
|
|
152
|
+
)
|
|
138
153
|
}
|
|
139
154
|
|
|
140
|
-
|
|
141
|
-
return
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
155
|
+
function loadExistingOrganizationMemories(db: SurrealDBService, orgId: string): Promise<Array<{ content: string }>> {
|
|
156
|
+
return Effect.runPromise(
|
|
157
|
+
effectTryPromise(() =>
|
|
158
|
+
db.queryMany(
|
|
159
|
+
new BoundQuery(
|
|
160
|
+
`SELECT content, createdAt, id FROM ${TABLES.MEMORY}
|
|
161
|
+
WHERE metadata.orgId = $orgId
|
|
162
|
+
AND archivedAt IS NONE
|
|
163
|
+
AND (validUntil IS NONE OR validUntil > time::now())
|
|
164
|
+
ORDER BY createdAt DESC, id DESC
|
|
165
|
+
LIMIT 250`,
|
|
166
|
+
{ orgId },
|
|
167
|
+
),
|
|
168
|
+
WorkspaceMemoryRowSchema,
|
|
169
|
+
),
|
|
150
170
|
),
|
|
151
|
-
WorkspaceMemoryRowSchema,
|
|
152
171
|
)
|
|
153
172
|
}
|
|
154
173
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
return withConfiguredWorkspaceMemoryLock(orgId, async () => {
|
|
167
|
-
if (
|
|
168
|
-
!workspaceProvider.getBackgroundCursor ||
|
|
169
|
-
!workspaceProvider.setBackgroundCursor ||
|
|
170
|
-
!workspaceProvider.applyProfileProjection
|
|
171
|
-
) {
|
|
174
|
+
function runRegularChatMemoryDigestEffect(
|
|
175
|
+
services: RegularChatDigestServices,
|
|
176
|
+
orgRef: RecordIdRef,
|
|
177
|
+
orgId: string,
|
|
178
|
+
workspaceProvider: NonNullable<LotaRuntimeAdapters['workspaceProvider']>,
|
|
179
|
+
) {
|
|
180
|
+
return Effect.gen(function* () {
|
|
181
|
+
const getBackgroundCursor = workspaceProvider.getBackgroundCursor?.bind(workspaceProvider)
|
|
182
|
+
const setBackgroundCursor = workspaceProvider.setBackgroundCursor?.bind(workspaceProvider)
|
|
183
|
+
const applyProfileProjection = workspaceProvider.applyProfileProjection?.bind(workspaceProvider)
|
|
184
|
+
if (!getBackgroundCursor || !setBackgroundCursor || !applyProfileProjection) {
|
|
172
185
|
serverLogger.info`Skipping regular chat memory digest for ${orgId}: workspaceProvider background/profile methods are incomplete`
|
|
173
186
|
return { skipped: true, processedThreadMessages: 0, processedSocialMessages: 0, followUpScheduled: false }
|
|
174
187
|
}
|
|
175
188
|
|
|
176
|
-
const workspace =
|
|
177
|
-
const lifecycleState =
|
|
189
|
+
const workspace = yield* effectTryPromise(() => workspaceProvider.getWorkspace(orgRef))
|
|
190
|
+
const lifecycleState = workspaceProvider.getLifecycleState
|
|
191
|
+
? yield* effectTryPromise(() => Promise.resolve(workspaceProvider.getLifecycleState?.(workspace)))
|
|
192
|
+
: undefined
|
|
178
193
|
if (lifecycleState?.bootstrapActive ?? false) {
|
|
179
194
|
serverLogger.info`Skipping regular chat memory digest for ${orgId}: onboarding is not completed`
|
|
180
195
|
return { skipped: true, processedThreadMessages: 0, processedSocialMessages: 0, followUpScheduled: false }
|
|
181
196
|
}
|
|
182
|
-
const projectionState =
|
|
197
|
+
const projectionState = workspaceProvider.readProfileProjectionState
|
|
198
|
+
? yield* effectTryPromise(() => Promise.resolve(workspaceProvider.readProfileProjectionState?.(workspace)))
|
|
199
|
+
: undefined
|
|
183
200
|
|
|
184
|
-
const existingThreadCursor =
|
|
201
|
+
const existingThreadCursor = yield* effectTryPromise(() => getBackgroundCursor('regular-chat-digest', orgRef))
|
|
185
202
|
const threadOnboardingCutoff = resolveWorkspaceBootstrapCutoff({
|
|
186
203
|
hasExistingCursor: existingThreadCursor !== null,
|
|
187
204
|
bootstrapCompletedAt: lifecycleState?.bootstrapCompletedAt,
|
|
188
205
|
})
|
|
189
206
|
|
|
190
|
-
const threadIds =
|
|
191
|
-
const threadMessages =
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
207
|
+
const threadIds = yield* effectTryPromise(() => listThreadIdsForOrg(services.databaseService, orgRef))
|
|
208
|
+
const threadMessages = yield* effectTryPromise(() =>
|
|
209
|
+
listEligibleThreadMessages({
|
|
210
|
+
db: services.databaseService,
|
|
211
|
+
threadIds,
|
|
212
|
+
cursor: existingThreadCursor,
|
|
213
|
+
onboardingCutoff: threadOnboardingCutoff,
|
|
214
|
+
}),
|
|
215
|
+
)
|
|
216
|
+
const existingSocialCursor = yield* services.socialChatHistoryService.getBackgroundCursor(
|
|
217
|
+
'regular-chat-digest',
|
|
218
|
+
orgId,
|
|
219
|
+
)
|
|
197
220
|
const socialOnboardingCutoff = resolveWorkspaceBootstrapCutoff({
|
|
198
221
|
hasExistingCursor: existingSocialCursor !== null,
|
|
199
222
|
bootstrapCompletedAt: lifecycleState?.bootstrapCompletedAt,
|
|
200
223
|
})
|
|
201
|
-
const socialMessages =
|
|
224
|
+
const socialMessages = yield* services.socialChatHistoryService.listWorkspaceMessages({
|
|
202
225
|
workspaceId: orgId,
|
|
203
226
|
cursor: existingSocialCursor,
|
|
204
227
|
onboardingCutoff: socialOnboardingCutoff,
|
|
@@ -211,38 +234,42 @@ export async function runRegularChatMemoryDigest(
|
|
|
211
234
|
|
|
212
235
|
const combinedMessages = [...threadMessages, ...socialMessages].sort(compareDigestMessageOrder)
|
|
213
236
|
const { transcript, involvedAgentNames } = buildDigestTranscript({ messages: combinedMessages })
|
|
214
|
-
const existingMemories =
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
237
|
+
const existingMemories = yield* effectTryPromise(() =>
|
|
238
|
+
loadExistingOrganizationMemories(services.databaseService, orgId),
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
const synthesis = yield* effectTryPromise(() =>
|
|
242
|
+
helperModelRuntime.generateHelperStructured({
|
|
243
|
+
tag: 'regular-chat-memory-digest',
|
|
244
|
+
createAgent: createRegularChatMemoryDigestAgent,
|
|
245
|
+
timeoutMs: REGULAR_CHAT_MEMORY_DIGEST_TIMEOUT_MS,
|
|
246
|
+
messages: [
|
|
247
|
+
{
|
|
248
|
+
role: 'user',
|
|
249
|
+
content: buildPrompt({
|
|
250
|
+
workspaceName: projectionState?.workspaceName || 'Workspace',
|
|
251
|
+
currentSummaryBlock: projectionState?.summaryBlock ?? '',
|
|
252
|
+
currentStructuredProfile: JSON.stringify(projectionState?.structuredProfile ?? {}, null, 2),
|
|
253
|
+
existingMemories: buildMemoryContext(existingMemories),
|
|
254
|
+
transcript,
|
|
255
|
+
}),
|
|
256
|
+
},
|
|
257
|
+
],
|
|
258
|
+
schema: RegularChatMemoryDigestOutputSchema,
|
|
259
|
+
}),
|
|
260
|
+
)
|
|
234
261
|
|
|
235
262
|
const summaryBlock = normalizeBlock(synthesis.summaryBlock)
|
|
236
263
|
if (!summaryBlock) {
|
|
237
|
-
|
|
264
|
+
return yield* new Cause.UnknownError(new Error('Regular chat memory digest returned an empty summaryBlock'))
|
|
238
265
|
}
|
|
239
266
|
|
|
240
267
|
const processedThreadCursor = getLastCursor(threadMessages)
|
|
241
268
|
const processedSocialCursor = getLastCursor(socialMessages)
|
|
242
|
-
const digestRunAt =
|
|
269
|
+
const digestRunAt = nowIsoDateTimeString()
|
|
243
270
|
|
|
244
271
|
if (synthesis.facts.length > 0) {
|
|
245
|
-
|
|
272
|
+
yield* services.memoryService.addExtractedFactsToScopes({
|
|
246
273
|
orgId,
|
|
247
274
|
facts: synthesis.facts,
|
|
248
275
|
source: 'regular_chat_digest',
|
|
@@ -266,25 +293,27 @@ export async function runRegularChatMemoryDigest(
|
|
|
266
293
|
})
|
|
267
294
|
}
|
|
268
295
|
|
|
269
|
-
|
|
270
|
-
summaryBlock,
|
|
271
|
-
|
|
272
|
-
})
|
|
296
|
+
yield* effectTryPromise(() =>
|
|
297
|
+
applyProfileProjection(orgRef, { summaryBlock, structuredPatch: synthesis.structuredProfilePatch }),
|
|
298
|
+
)
|
|
273
299
|
if (processedThreadCursor) {
|
|
274
|
-
|
|
300
|
+
yield* effectTryPromise(() => setBackgroundCursor('regular-chat-digest', orgRef, processedThreadCursor))
|
|
275
301
|
}
|
|
276
302
|
if (processedSocialCursor) {
|
|
277
|
-
|
|
303
|
+
yield* services.socialChatHistoryService.setBackgroundCursor('regular-chat-digest', orgId, processedSocialCursor)
|
|
278
304
|
}
|
|
279
305
|
|
|
280
306
|
const threadBoundaryCursor = processedThreadCursor ?? existingThreadCursor
|
|
281
|
-
const hasMoreThreadMessages =
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
307
|
+
const hasMoreThreadMessages = yield* effectTryPromise(() =>
|
|
308
|
+
hasNewEligibleThreadMessages({
|
|
309
|
+
db: services.databaseService,
|
|
310
|
+
threadIds,
|
|
311
|
+
cursor: threadBoundaryCursor,
|
|
312
|
+
onboardingCutoff: threadBoundaryCursor ? null : threadOnboardingCutoff,
|
|
313
|
+
}),
|
|
314
|
+
)
|
|
286
315
|
const socialBoundaryCursor = processedSocialCursor ?? existingSocialCursor
|
|
287
|
-
const hasMoreSocialMessages =
|
|
316
|
+
const hasMoreSocialMessages = yield* services.socialChatHistoryService.hasWorkspaceMessages({
|
|
288
317
|
workspaceId: orgId,
|
|
289
318
|
cursor: socialBoundaryCursor,
|
|
290
319
|
onboardingCutoff: socialBoundaryCursor ? null : socialOnboardingCutoff,
|
|
@@ -292,8 +321,8 @@ export async function runRegularChatMemoryDigest(
|
|
|
292
321
|
|
|
293
322
|
const followUpScheduled = hasMoreThreadMessages || hasMoreSocialMessages
|
|
294
323
|
if (followUpScheduled) {
|
|
295
|
-
|
|
296
|
-
|
|
324
|
+
yield* effectTryPromise(() => clearRegularChatMemoryDigestDeduplicationKey(orgId))
|
|
325
|
+
yield* effectTryPromise(() => enqueueRegularChatMemoryDigest({ orgId }))
|
|
297
326
|
}
|
|
298
327
|
|
|
299
328
|
serverLogger.info`Regular chat memory digest completed for ${orgId}: threadMessages=${threadMessages.length}, socialMessages=${socialMessages.length}, facts=${synthesis.facts.length}, followUpScheduled=${followUpScheduled}`
|
|
@@ -306,3 +335,35 @@ export async function runRegularChatMemoryDigest(
|
|
|
306
335
|
}
|
|
307
336
|
})
|
|
308
337
|
}
|
|
338
|
+
|
|
339
|
+
export function runRegularChatMemoryDigest(
|
|
340
|
+
data: RegularChatMemoryDigestJob,
|
|
341
|
+
services: RegularChatDigestServices,
|
|
342
|
+
): Promise<RegularChatDigestRunResult> {
|
|
343
|
+
const { databaseService, memoryService, socialChatHistoryService, runtimeAdapters } = services
|
|
344
|
+
const orgRef = ensureRecordId(data.orgId, TABLES.ORGANIZATION)
|
|
345
|
+
const orgId = recordIdToString(orgRef, TABLES.ORGANIZATION)
|
|
346
|
+
const workspaceProvider = runtimeAdapters.workspaceProvider
|
|
347
|
+
if (!workspaceProvider) {
|
|
348
|
+
serverLogger.info`Skipping regular chat memory digest for ${orgId}: workspaceProvider is not configured`
|
|
349
|
+
return Promise.resolve({
|
|
350
|
+
skipped: true,
|
|
351
|
+
processedThreadMessages: 0,
|
|
352
|
+
processedSocialMessages: 0,
|
|
353
|
+
followUpScheduled: false,
|
|
354
|
+
})
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
const withMemoryLock = runtimeAdapters.withWorkspaceMemoryLock
|
|
358
|
+
const runDigest = () =>
|
|
359
|
+
Effect.runPromise(
|
|
360
|
+
runRegularChatMemoryDigestEffect(
|
|
361
|
+
{ databaseService, memoryService, socialChatHistoryService, runtimeAdapters },
|
|
362
|
+
orgRef,
|
|
363
|
+
orgId,
|
|
364
|
+
workspaceProvider,
|
|
365
|
+
),
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
return withMemoryLock ? withMemoryLock(orgId, runDigest) : runDigest()
|
|
369
|
+
}
|