@lota-sdk/core 0.4.8 → 0.4.10
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 +96 -22
- package/src/ai-gateway/ai-gateway.ts +766 -223
- package/src/config/agent-defaults.ts +189 -75
- package/src/config/agent-types.ts +54 -4
- package/src/config/background-processing.ts +1 -1
- package/src/config/constants.ts +8 -2
- package/src/config/index.ts +0 -1
- package/src/config/logger.ts +299 -19
- package/src/config/thread-defaults.ts +40 -20
- package/src/create-runtime.ts +200 -449
- package/src/db/base.service.ts +52 -28
- package/src/db/cursor-pagination.ts +71 -30
- package/src/db/memory-query-builder.ts +2 -1
- package/src/db/memory-store.helpers.ts +4 -7
- package/src/db/memory-store.ts +868 -601
- package/src/db/memory.ts +396 -280
- package/src/db/record-id.ts +32 -10
- package/src/db/schema-fingerprint.ts +30 -12
- package/src/db/service-normalization.ts +288 -0
- package/src/db/service.ts +912 -779
- package/src/db/startup.ts +153 -68
- package/src/db/transaction-conflict.ts +15 -0
- package/src/effect/awaitable-effect.ts +96 -0
- package/src/effect/errors.ts +121 -0
- package/src/effect/helpers.ts +123 -0
- package/src/effect/index.ts +24 -0
- package/src/effect/layers.ts +238 -0
- package/src/effect/runtime-ref.ts +25 -0
- package/src/effect/runtime.ts +46 -0
- package/src/effect/services.ts +61 -0
- package/src/effect/zod.ts +43 -0
- package/src/embeddings/provider.ts +128 -83
- package/src/index.ts +48 -1
- package/src/openrouter/direct-provider.ts +11 -35
- package/src/queues/autonomous-job.queue.ts +117 -73
- package/src/queues/context-compaction.queue.ts +50 -17
- package/src/queues/delayed-node-promotion.queue.ts +46 -17
- 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 +26 -4
- package/src/queues/plan-agent-heartbeat.queue.ts +71 -24
- package/src/queues/plan-scheduler.queue.ts +97 -33
- package/src/queues/post-chat-memory.queue.ts +56 -26
- package/src/queues/queue-factory.ts +227 -59
- package/src/queues/standalone-worker.ts +39 -0
- package/src/queues/title-generation.queue.ts +45 -11
- package/src/redis/connection.ts +182 -113
- 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 +20 -0
- package/src/redis/stream-context.ts +92 -46
- package/src/runtime/agent-identity-overrides.ts +2 -2
- package/src/runtime/agent-runtime-policy.ts +5 -2
- package/src/runtime/agent-stream-helpers.ts +24 -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} +161 -94
- package/src/runtime/domain-layer.ts +192 -0
- package/src/runtime/execution-plan-visibility.ts +2 -2
- package/src/runtime/execution-plan.ts +42 -15
- package/src/runtime/graph-designer.ts +16 -4
- package/src/runtime/helper-model.ts +139 -48
- package/src/runtime/index.ts +7 -8
- package/src/runtime/indexed-repositories-policy.ts +3 -3
- package/src/runtime/{memory-block.ts → memory/memory-block.ts} +50 -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} +54 -67
- package/src/runtime/{memory-prompts-fact.ts → memory/memory-prompts-fact.ts} +2 -2
- package/src/runtime/memory/memory-scope.ts +53 -0
- package/src/runtime/plugin-resolution.ts +124 -25
- package/src/runtime/plugin-types.ts +9 -1
- package/src/runtime/post-turn-side-effects.ts +177 -130
- package/src/runtime/retrieval-adapters.ts +40 -6
- package/src/runtime/runtime-accessors.ts +92 -0
- package/src/runtime/runtime-config.ts +150 -61
- package/src/runtime/runtime-extensions.ts +23 -25
- package/src/runtime/runtime-lifecycle.ts +124 -0
- package/src/runtime/runtime-services.ts +386 -0
- package/src/runtime/runtime-token.ts +47 -0
- package/src/runtime/social-chat/social-chat-agent-runner.ts +159 -0
- package/src/runtime/{social-chat-history.ts → social-chat/social-chat-history.ts} +51 -20
- package/src/runtime/social-chat/social-chat.ts +630 -0
- package/src/runtime/specialist-runner.ts +36 -10
- package/src/runtime/team-consultation/team-consultation-orchestrator.ts +433 -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 +183 -111
- package/src/runtime/turn-lifecycle.ts +93 -27
- package/src/services/agent-activity.service.ts +287 -203
- package/src/services/agent-executor.service.ts +253 -149
- package/src/services/artifact.service.ts +231 -149
- package/src/services/attachment.service.ts +171 -115
- package/src/services/autonomous-job.service.ts +890 -491
- package/src/services/background-work.service.ts +54 -0
- package/src/services/chat-run-registry.service.ts +13 -1
- package/src/services/context-compaction.service.ts +136 -86
- package/src/services/document-chunk.service.ts +151 -88
- 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 +278 -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 +101 -168
- package/src/services/graph-full-routing.ts +193 -0
- package/src/services/index.ts +19 -21
- package/src/services/institutional-memory.service.ts +213 -125
- package/src/services/learned-skill.service.ts +368 -260
- package/src/services/memory/memory-conversation.ts +95 -0
- package/src/services/memory/memory-errors.ts +27 -0
- package/src/services/memory/memory-org-memory.ts +50 -0
- package/src/services/memory/memory-preseeded.ts +86 -0
- package/src/services/memory/memory-rerank.ts +297 -0
- package/src/services/{memory-utils.ts → memory/memory-utils.ts} +6 -5
- package/src/services/memory/memory.service.ts +674 -0
- package/src/services/memory/rerank.service.ts +201 -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 +29 -16
- package/src/services/organization-member.service.ts +120 -66
- package/src/services/organization.service.ts +153 -77
- package/src/services/ownership-dispatcher.service.ts +456 -263
- 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-approval.service.ts → plan/plan-approval.service.ts} +45 -22
- 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 +169 -0
- package/src/services/plan/plan-coordination.service.ts +181 -0
- package/src/services/plan/plan-cycle.service.ts +405 -0
- package/src/services/plan/plan-deadline.service.ts +533 -0
- package/src/services/plan/plan-event-delivery.service.ts +266 -0
- package/src/services/plan/plan-executor-context.ts +35 -0
- package/src/services/plan/plan-executor-graph.ts +522 -0
- package/src/services/plan/plan-executor-helpers.ts +307 -0
- package/src/services/plan/plan-executor-persistence.ts +209 -0
- package/src/services/plan/plan-executor.service.ts +1737 -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 +637 -0
- package/src/services/plan/plan-scheduler.service.ts +379 -0
- package/src/services/plan/plan-template.service.ts +224 -0
- package/src/services/plan/plan-transaction-events.ts +36 -0
- package/src/services/plan/plan-validator.service.ts +907 -0
- package/src/services/plan/plan-workspace.service.ts +131 -0
- package/src/services/plugin-executor.service.ts +102 -68
- package/src/services/quality-metrics.service.ts +112 -94
- package/src/services/queue-job.service.ts +288 -231
- package/src/services/recent-activity-title.service.ts +73 -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 +190 -122
- package/src/services/system-executor.service.ts +96 -61
- package/src/services/thread/thread-active-run.ts +203 -0
- package/src/services/thread/thread-bootstrap.ts +385 -0
- package/src/services/thread/thread-listing.ts +199 -0
- package/src/services/thread/thread-memory-block.ts +130 -0
- package/src/services/thread/thread-message.service.ts +379 -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 +1148 -0
- package/src/services/thread/thread-turn-streaming.ts +403 -0
- package/src/services/thread/thread-turn-tracing.ts +35 -0
- package/src/services/thread/thread-turn.ts +376 -0
- package/src/services/thread/thread.service.ts +344 -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 +334 -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 +3 -3
- package/src/system-agents/delegated-agent-factory.ts +159 -90
- package/src/system-agents/helper-agent-options.ts +1 -1
- package/src/system-agents/memory-reranker.agent.ts +3 -3
- package/src/system-agents/memory.agent.ts +3 -3
- package/src/system-agents/recent-activity-title-refiner.agent.ts +3 -3
- package/src/system-agents/regular-chat-memory-digest.agent.ts +3 -3
- package/src/system-agents/skill-extractor.agent.ts +3 -3
- package/src/system-agents/skill-manager.agent.ts +3 -3
- package/src/system-agents/thread-router.agent.ts +157 -113
- package/src/system-agents/title-generator.agent.ts +3 -3
- package/src/tools/execution-plan.tool.ts +241 -171
- package/src/tools/fetch-webpage.tool.ts +29 -18
- package/src/tools/firecrawl-client.ts +26 -6
- package/src/tools/index.ts +1 -0
- package/src/tools/memory-block.tool.ts +14 -6
- package/src/tools/plan-approval.tool.ts +57 -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 +33 -22
- package/src/tools/search.tool.ts +41 -29
- package/src/tools/team-think.tool.ts +125 -84
- package/src/tools/user-questions.tool.ts +4 -3
- package/src/tools/web-tool-shared.ts +6 -0
- package/src/utils/async.ts +25 -22
- package/src/utils/crypto.ts +21 -0
- package/src/utils/date-time.ts +40 -1
- package/src/utils/errors.ts +111 -20
- 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 +164 -52
- 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 +185 -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 +74 -31
- package/src/config/debug-logger.ts +0 -47
- package/src/config/search.ts +0 -3
- package/src/redis/connection-accessor.ts +0 -26
- package/src/runtime/agent-types.ts +0 -1
- package/src/runtime/context-compaction-runtime.ts +0 -87
- package/src/runtime/memory-scope.ts +0 -43
- 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 -914
- package/src/services/plan-agent-heartbeat.service.ts +0 -136
- package/src/services/plan-agent-query.service.ts +0 -267
- 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/rerank.service.ts +0 -156
- 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
package/src/db/memory.ts
CHANGED
|
@@ -1,23 +1,27 @@
|
|
|
1
|
+
import type { Context } from 'effect'
|
|
2
|
+
import { Effect } from 'effect'
|
|
1
3
|
import type { z } from 'zod'
|
|
2
4
|
|
|
3
5
|
import { aiLogger } from '../config/logger'
|
|
4
|
-
import type { CreateHelperAgentFn } from '../runtime/helper-model'
|
|
5
|
-
import {
|
|
6
|
-
import { formatResults } from '../runtime/memory-format'
|
|
6
|
+
import type { CreateHelperAgentFn, HelperModelRuntime } from '../runtime/helper-model'
|
|
7
|
+
import { formatResults } from '../runtime/memory/memory-format'
|
|
7
8
|
import {
|
|
8
9
|
buildMemoryFactMaps,
|
|
9
10
|
compileMemoryUpdatesFromDelta,
|
|
10
11
|
createMemoryActionPlan,
|
|
11
12
|
postProcessMemoryFacts,
|
|
12
13
|
projectMemoryDeltaToScope,
|
|
13
|
-
} from '../runtime/memory-pipeline'
|
|
14
|
-
import { getFactRetrievalMessages } from '../runtime/memory-prompts-fact'
|
|
15
|
-
import { parseMessages } from '../runtime/memory-prompts-parse'
|
|
16
|
-
import { getClassifyMemoryDeltaPrompt } from '../runtime/memory-prompts-update'
|
|
17
|
-
import {
|
|
14
|
+
} from '../runtime/memory/memory-pipeline'
|
|
15
|
+
import { getFactRetrievalMessages } from '../runtime/memory/memory-prompts-fact'
|
|
16
|
+
import { parseMessages } from '../runtime/memory/memory-prompts-parse'
|
|
17
|
+
import { getClassifyMemoryDeltaPrompt } from '../runtime/memory/memory-prompts-update'
|
|
18
|
+
import type { ResolvedLotaRuntimeConfig } from '../runtime/runtime-config'
|
|
19
|
+
import type { BackgroundWorkService } from '../services/background-work.service'
|
|
20
|
+
import { MemoryServiceError, tryMemoryPromise } from '../services/memory/memory-errors'
|
|
21
|
+
import { sha256Hex } from '../utils/crypto'
|
|
18
22
|
import { compactWhitespace, truncateText } from '../utils/string'
|
|
19
23
|
import type { SurrealMemoryStore } from './memory-store'
|
|
20
|
-
import {
|
|
24
|
+
import { createMemoryStore } from './memory-store'
|
|
21
25
|
import { hashContent, isUniqueIndexConflict } from './memory-store.helpers'
|
|
22
26
|
import { FactRetrievalSchema, MemoryDeltaSchema, MemoryUpdateSchema } from './memory-types'
|
|
23
27
|
import type {
|
|
@@ -35,6 +39,7 @@ import type {
|
|
|
35
39
|
SearchOptions,
|
|
36
40
|
WeightedSearchOptions,
|
|
37
41
|
} from './memory-types'
|
|
42
|
+
import type { SurrealDBService } from './service'
|
|
38
43
|
|
|
39
44
|
const MEMORY_WORKER_MODEL_TIMEOUT_MS = 10 * 60 * 1000
|
|
40
45
|
const MEMORY_FACT_EXTRACTION_TIMEOUT_MS = MEMORY_WORKER_MODEL_TIMEOUT_MS
|
|
@@ -44,7 +49,6 @@ const MEMORY_DELTA_MAX_CANDIDATES_PER_FACT = 10
|
|
|
44
49
|
const MEMORY_DELTA_MIN_BASELINE_CANDIDATES = 12
|
|
45
50
|
const MEMORY_DELTA_MEMORY_TEXT_MAX_CHARS = 400
|
|
46
51
|
const CANDIDATE_FANOUT_MULTIPLIER = 4
|
|
47
|
-
const helperModelRuntime = createHelperModelRuntime()
|
|
48
52
|
|
|
49
53
|
interface PreparedScopeUpdate {
|
|
50
54
|
options: AddOptions
|
|
@@ -53,20 +57,34 @@ interface PreparedScopeUpdate {
|
|
|
53
57
|
existingMemories: Array<{ id: string; text: string }>
|
|
54
58
|
}
|
|
55
59
|
|
|
56
|
-
interface ScopedExistingMemories {
|
|
57
|
-
options: AddOptions
|
|
58
|
-
existingMemories: Array<{ id: string; text: string }>
|
|
59
|
-
scopeMemoryIdsByUnionId: Record<string, string[]>
|
|
60
|
-
}
|
|
61
|
-
|
|
62
60
|
export class Memory {
|
|
63
61
|
private store: SurrealMemoryStore
|
|
64
62
|
private createAgent: CreateHelperAgentFn
|
|
65
63
|
private maxOutputTokens?: number
|
|
66
64
|
private config: MemoryConfig
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
private runtimeConfig: ResolvedLotaRuntimeConfig
|
|
66
|
+
private helperModelRuntime: HelperModelRuntime
|
|
67
|
+
|
|
68
|
+
constructor(
|
|
69
|
+
deps: {
|
|
70
|
+
db: SurrealDBService
|
|
71
|
+
runtimeConfig: ResolvedLotaRuntimeConfig
|
|
72
|
+
helperModelRuntime: HelperModelRuntime
|
|
73
|
+
background: Context.Service.Shape<typeof BackgroundWorkService>
|
|
74
|
+
},
|
|
75
|
+
agent: { createAgent: CreateHelperAgentFn; maxOutputTokens?: number },
|
|
76
|
+
config: MemoryConfig = {},
|
|
77
|
+
) {
|
|
78
|
+
this.store = createMemoryStore(
|
|
79
|
+
deps.db,
|
|
80
|
+
{
|
|
81
|
+
embeddingModel: deps.runtimeConfig.aiGateway.embeddingModel,
|
|
82
|
+
openRouterApiKey: deps.runtimeConfig.aiGateway.openRouterApiKey,
|
|
83
|
+
},
|
|
84
|
+
deps.background,
|
|
85
|
+
)
|
|
86
|
+
this.runtimeConfig = deps.runtimeConfig
|
|
87
|
+
this.helperModelRuntime = deps.helperModelRuntime
|
|
70
88
|
this.createAgent = agent.createAgent
|
|
71
89
|
this.maxOutputTokens = agent.maxOutputTokens
|
|
72
90
|
|
|
@@ -84,10 +102,10 @@ export class Memory {
|
|
|
84
102
|
private buildMemoryUnionId(text: string): string | null {
|
|
85
103
|
const normalized = this.normalizeMemoryDeltaText(text, MEMORY_DELTA_MEMORY_TEXT_MAX_CHARS)
|
|
86
104
|
if (!normalized) return null
|
|
87
|
-
return `union_${
|
|
105
|
+
return `union_${sha256Hex(normalized)}`
|
|
88
106
|
}
|
|
89
107
|
|
|
90
|
-
|
|
108
|
+
insert(
|
|
91
109
|
content: string,
|
|
92
110
|
options: {
|
|
93
111
|
scopeId: string
|
|
@@ -96,242 +114,320 @@ export class Memory {
|
|
|
96
114
|
metadata?: Record<string, unknown>
|
|
97
115
|
durability?: Durability
|
|
98
116
|
},
|
|
99
|
-
):
|
|
100
|
-
return
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
117
|
+
): Effect.Effect<string, MemoryServiceError, never> {
|
|
118
|
+
return tryMemoryPromise('Failed to insert memory.', () =>
|
|
119
|
+
this.store.insert(
|
|
120
|
+
content,
|
|
121
|
+
options.scopeId,
|
|
122
|
+
options.memoryType,
|
|
123
|
+
options.metadata ?? {},
|
|
124
|
+
options.importance ?? 1,
|
|
125
|
+
options.durability ?? 'standard',
|
|
126
|
+
),
|
|
107
127
|
)
|
|
108
128
|
}
|
|
109
129
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
130
|
+
search(query: string, options: SearchOptions): Effect.Effect<string, MemoryServiceError, never> {
|
|
131
|
+
return Effect.gen(
|
|
132
|
+
function* (this: Memory) {
|
|
133
|
+
const limit = options.limit ?? this.runtimeConfig.memory.searchK
|
|
134
|
+
const results = yield* tryMemoryPromise('Failed to search memory.', () =>
|
|
135
|
+
this.store.search(query, options.scopeId, limit, options.memoryType),
|
|
136
|
+
)
|
|
137
|
+
return formatResults(results)
|
|
138
|
+
}.bind(this),
|
|
139
|
+
)
|
|
115
140
|
}
|
|
116
141
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
142
|
+
hybridSearch(query: string, options: SearchOptions): Effect.Effect<string, MemoryServiceError, never> {
|
|
143
|
+
return Effect.gen(
|
|
144
|
+
function* (this: Memory) {
|
|
145
|
+
const limit = options.limit ?? this.runtimeConfig.memory.searchK
|
|
146
|
+
const results = yield* tryMemoryPromise('Failed to perform hybrid search.', () =>
|
|
147
|
+
this.store.hybridSearch(query, options.scopeId, limit, options.memoryType),
|
|
148
|
+
)
|
|
149
|
+
return formatResults(results)
|
|
150
|
+
}.bind(this),
|
|
151
|
+
)
|
|
122
152
|
}
|
|
123
153
|
|
|
124
|
-
|
|
154
|
+
hybridSearchWeighted(
|
|
125
155
|
query: string,
|
|
126
156
|
options: SearchOptions & { weights?: [number, number]; normalization?: 'minmax' | 'zscore' },
|
|
127
|
-
):
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
157
|
+
): Effect.Effect<string, MemoryServiceError, never> {
|
|
158
|
+
return Effect.gen(
|
|
159
|
+
function* (this: Memory) {
|
|
160
|
+
const limit = options.limit ?? this.runtimeConfig.memory.searchK
|
|
161
|
+
const results = yield* tryMemoryPromise('Failed to perform weighted hybrid search.', () =>
|
|
162
|
+
this.store.hybridSearchWeighted(query, {
|
|
163
|
+
scopeId: options.scopeId,
|
|
164
|
+
limit,
|
|
165
|
+
memoryType: options.memoryType,
|
|
166
|
+
weights: options.weights,
|
|
167
|
+
normalization: options.normalization,
|
|
168
|
+
}),
|
|
169
|
+
)
|
|
170
|
+
return formatResults(results)
|
|
171
|
+
}.bind(this),
|
|
172
|
+
)
|
|
138
173
|
}
|
|
139
174
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
175
|
+
searchCandidates(
|
|
176
|
+
query: string,
|
|
177
|
+
options: WeightedSearchOptions,
|
|
178
|
+
): Effect.Effect<MemorySearchResult[], MemoryServiceError, never> {
|
|
179
|
+
return Effect.gen(
|
|
180
|
+
function* (this: Memory) {
|
|
181
|
+
const limit = options.limit ?? this.runtimeConfig.memory.searchK
|
|
182
|
+
const results = yield* tryMemoryPromise('Failed to search memory candidates.', () =>
|
|
183
|
+
this.store.hybridSearchWeighted(query, {
|
|
184
|
+
scopeId: options.scopeId,
|
|
185
|
+
limit,
|
|
186
|
+
memoryType: options.memoryType,
|
|
187
|
+
weights: options.weights,
|
|
188
|
+
normalization: options.normalization,
|
|
189
|
+
fastMode: options.fastMode,
|
|
190
|
+
}),
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
if (options.fastMode || options.includeNeighborContext === false) {
|
|
194
|
+
return results
|
|
195
|
+
}
|
|
154
196
|
|
|
155
|
-
|
|
197
|
+
return yield* tryMemoryPromise('Failed to enrich memory candidates.', () =>
|
|
198
|
+
this.store.enrichWithNeighbors(results),
|
|
199
|
+
)
|
|
200
|
+
}.bind(this),
|
|
201
|
+
)
|
|
156
202
|
}
|
|
157
203
|
|
|
158
|
-
|
|
204
|
+
listTopMemories(options: {
|
|
159
205
|
scopeId: string
|
|
160
206
|
limit: number
|
|
161
207
|
memoryType?: MemoryType
|
|
162
208
|
durability?: Durability
|
|
163
209
|
minImportance?: number
|
|
164
|
-
}):
|
|
165
|
-
return this.store.listTopMemories(options)
|
|
210
|
+
}): Effect.Effect<MemoryRecord[], MemoryServiceError, never> {
|
|
211
|
+
return tryMemoryPromise('Failed to list top memories.', () => this.store.listTopMemories(options))
|
|
166
212
|
}
|
|
167
213
|
|
|
168
|
-
|
|
169
|
-
return this.store.list(options)
|
|
214
|
+
list(options: MemoryListOptions): Effect.Effect<MemoryRecord[], MemoryServiceError, never> {
|
|
215
|
+
return tryMemoryPromise('Failed to list memories.', () => this.store.list(options))
|
|
170
216
|
}
|
|
171
217
|
|
|
172
|
-
|
|
173
|
-
|
|
218
|
+
updateMemory(id: string, newContent: string): Effect.Effect<void, MemoryServiceError, never> {
|
|
219
|
+
return tryMemoryPromise(`Failed to update memory ${id}.`, () => this.store.update(id, newContent))
|
|
174
220
|
}
|
|
175
221
|
|
|
176
|
-
|
|
177
|
-
|
|
222
|
+
addRelation(
|
|
223
|
+
fromId: string,
|
|
224
|
+
toId: string,
|
|
225
|
+
relationType: RelationType,
|
|
226
|
+
confidence = 1,
|
|
227
|
+
): Effect.Effect<void, MemoryServiceError, never> {
|
|
228
|
+
return tryMemoryPromise(`Failed to add ${relationType} relation.`, () =>
|
|
229
|
+
this.store.addRelation(fromId, toId, relationType, confidence),
|
|
230
|
+
)
|
|
178
231
|
}
|
|
179
232
|
|
|
180
|
-
|
|
181
|
-
return this.store.getStaleMemories(scopeId, limit)
|
|
233
|
+
getStaleMemories(scopeId: string, limit?: number): Effect.Effect<MemorySearchResult[], MemoryServiceError, never> {
|
|
234
|
+
return tryMemoryPromise('Failed to load stale memories.', () => this.store.getStaleMemories(scopeId, limit))
|
|
182
235
|
}
|
|
183
236
|
|
|
184
|
-
|
|
237
|
+
extractFactsFromMessages(
|
|
185
238
|
messages: Message[],
|
|
186
239
|
extractionOptions?: { customPrompt?: string; maxFacts?: number },
|
|
187
|
-
):
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
240
|
+
): Effect.Effect<ExtractedFact[], MemoryServiceError, never> {
|
|
241
|
+
return Effect.gen(
|
|
242
|
+
function* (this: Memory) {
|
|
243
|
+
if (messages.length === 0) return []
|
|
244
|
+
|
|
245
|
+
const parsedMessages = parseMessages(messages)
|
|
246
|
+
const facts = yield* this.extractFactsEffect(parsedMessages, extractionOptions)
|
|
247
|
+
if (facts.length === 0) {
|
|
248
|
+
aiLogger.debug`No facts extracted from conversation`
|
|
249
|
+
return []
|
|
250
|
+
}
|
|
197
251
|
|
|
198
|
-
|
|
252
|
+
return facts
|
|
253
|
+
}.bind(this),
|
|
254
|
+
)
|
|
199
255
|
}
|
|
200
256
|
|
|
201
|
-
|
|
202
|
-
|
|
257
|
+
applyFactsToScopes(facts: ExtractedFact[], scopes: AddOptions[]): Effect.Effect<void, MemoryServiceError, never> {
|
|
258
|
+
return Effect.gen(
|
|
259
|
+
function* (this: Memory) {
|
|
260
|
+
if (facts.length === 0 || scopes.length === 0) return
|
|
261
|
+
const prepared = yield* this.prepareFactsToScopesEffect(facts, scopes)
|
|
262
|
+
yield* this.applyPreparedScopeUpdates(prepared)
|
|
263
|
+
}.bind(this),
|
|
264
|
+
)
|
|
265
|
+
}
|
|
203
266
|
|
|
204
|
-
|
|
205
|
-
|
|
267
|
+
prepareFactsToScopes(
|
|
268
|
+
facts: ExtractedFact[],
|
|
269
|
+
scopes: AddOptions[],
|
|
270
|
+
): Effect.Effect<PreparedScopeUpdate[], MemoryServiceError, never> {
|
|
271
|
+
return this.prepareFactsToScopesEffect(facts, scopes)
|
|
206
272
|
}
|
|
207
273
|
|
|
208
|
-
|
|
209
|
-
if (
|
|
274
|
+
applyPreparedScopeUpdates(prepared: PreparedScopeUpdate[]): Effect.Effect<void, MemoryServiceError, never> {
|
|
275
|
+
if (prepared.length === 0) return Effect.void
|
|
210
276
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
})
|
|
219
|
-
const normalizedMemories = existingMemories.map((memory) => ({ id: memory.id, text: memory.content }))
|
|
220
|
-
const scopeMemoryIdsByUnionId: Record<string, string[]> = {}
|
|
221
|
-
for (const memory of normalizedMemories) {
|
|
222
|
-
const unionId = this.buildMemoryUnionId(memory.text)
|
|
223
|
-
if (!unionId) continue
|
|
224
|
-
;(scopeMemoryIdsByUnionId[unionId] ??= []).push(memory.id)
|
|
225
|
-
}
|
|
226
|
-
return { options: scopeOptions, existingMemories: normalizedMemories, scopeMemoryIdsByUnionId }
|
|
227
|
-
}),
|
|
277
|
+
return Effect.forEach(
|
|
278
|
+
prepared,
|
|
279
|
+
(item) =>
|
|
280
|
+
tryMemoryPromise('Failed to apply memory updates', () =>
|
|
281
|
+
this.applyUpdates(item.updates, item.options, item.factMaps, item.existingMemories),
|
|
282
|
+
),
|
|
283
|
+
{ concurrency: 2, discard: true },
|
|
228
284
|
)
|
|
229
|
-
const unionMemories = new Map<string, { id: string; text: string }>()
|
|
230
|
-
for (const scopePayload of scopePayloads) {
|
|
231
|
-
for (const memory of scopePayload.existingMemories) {
|
|
232
|
-
const unionId = this.buildMemoryUnionId(memory.text)
|
|
233
|
-
if (!unionId || unionMemories.has(unionId)) continue
|
|
234
|
-
const normalizedText = this.normalizeMemoryDeltaText(memory.text, MEMORY_DELTA_MEMORY_TEXT_MAX_CHARS)
|
|
235
|
-
if (!normalizedText) continue
|
|
236
|
-
unionMemories.set(unionId, { id: unionId, text: normalizedText })
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
const delta = await this.determineDelta([...unionMemories.values()], factContents)
|
|
241
|
-
return scopePayloads.map(({ options, existingMemories, scopeMemoryIdsByUnionId }) => ({
|
|
242
|
-
options,
|
|
243
|
-
updates: MemoryUpdateSchema.parse(
|
|
244
|
-
compileMemoryUpdatesFromDelta({
|
|
245
|
-
existingMemories,
|
|
246
|
-
newFacts: factContents,
|
|
247
|
-
delta: projectMemoryDeltaToScope({
|
|
248
|
-
delta,
|
|
249
|
-
scopeMemoryIds: existingMemories.map((memory) => memory.id),
|
|
250
|
-
scopeMemoryIdsByUnionId,
|
|
251
|
-
}),
|
|
252
|
-
}),
|
|
253
|
-
),
|
|
254
|
-
factMaps,
|
|
255
|
-
existingMemories,
|
|
256
|
-
}))
|
|
257
285
|
}
|
|
258
286
|
|
|
259
|
-
|
|
260
|
-
|
|
287
|
+
private prepareFactsToScopesEffect(
|
|
288
|
+
facts: ExtractedFact[],
|
|
289
|
+
scopes: AddOptions[],
|
|
290
|
+
): Effect.Effect<PreparedScopeUpdate[], MemoryServiceError, never> {
|
|
291
|
+
return Effect.gen(
|
|
292
|
+
function* (this: Memory) {
|
|
293
|
+
if (facts.length === 0 || scopes.length === 0) return []
|
|
294
|
+
|
|
295
|
+
const factMaps = buildMemoryFactMaps(facts)
|
|
296
|
+
const factContents = facts.map((fact) => fact.content)
|
|
297
|
+
const scopePayloads = yield* Effect.all(
|
|
298
|
+
scopes.map((scopeOptions) =>
|
|
299
|
+
tryMemoryPromise(`Failed to list memories for scope ${scopeOptions.scopeId}.`, () =>
|
|
300
|
+
this.store.list({ scopeId: scopeOptions.scopeId, memoryType: scopeOptions.memoryType }),
|
|
301
|
+
).pipe(
|
|
302
|
+
Effect.map((existingMemories) => {
|
|
303
|
+
const normalizedMemories = existingMemories.map((memory) => ({ id: memory.id, text: memory.content }))
|
|
304
|
+
const scopeMemoryIdsByUnionId: Record<string, string[]> = {}
|
|
305
|
+
for (const memory of normalizedMemories) {
|
|
306
|
+
const unionId = this.buildMemoryUnionId(memory.text)
|
|
307
|
+
if (!unionId) continue
|
|
308
|
+
;(scopeMemoryIdsByUnionId[unionId] ??= []).push(memory.id)
|
|
309
|
+
}
|
|
310
|
+
return { options: scopeOptions, existingMemories: normalizedMemories, scopeMemoryIdsByUnionId }
|
|
311
|
+
}),
|
|
312
|
+
),
|
|
313
|
+
),
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
const unionMemories = new Map<string, { id: string; text: string }>()
|
|
317
|
+
for (const scopePayload of scopePayloads) {
|
|
318
|
+
for (const memory of scopePayload.existingMemories) {
|
|
319
|
+
const unionId = this.buildMemoryUnionId(memory.text)
|
|
320
|
+
if (!unionId || unionMemories.has(unionId)) continue
|
|
321
|
+
const normalizedText = this.normalizeMemoryDeltaText(memory.text, MEMORY_DELTA_MEMORY_TEXT_MAX_CHARS)
|
|
322
|
+
if (!normalizedText) continue
|
|
323
|
+
unionMemories.set(unionId, { id: unionId, text: normalizedText })
|
|
324
|
+
}
|
|
325
|
+
}
|
|
261
326
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
327
|
+
const delta = yield* this.determineDeltaEffect([...unionMemories.values()], factContents)
|
|
328
|
+
return scopePayloads.map(({ options, existingMemories, scopeMemoryIdsByUnionId }) => ({
|
|
329
|
+
options,
|
|
330
|
+
updates: MemoryUpdateSchema.parse(
|
|
331
|
+
compileMemoryUpdatesFromDelta({
|
|
332
|
+
existingMemories,
|
|
333
|
+
newFacts: factContents,
|
|
334
|
+
delta: projectMemoryDeltaToScope({
|
|
335
|
+
delta,
|
|
336
|
+
scopeMemoryIds: existingMemories.map((memory) => memory.id),
|
|
337
|
+
scopeMemoryIdsByUnionId,
|
|
338
|
+
}),
|
|
339
|
+
}),
|
|
340
|
+
),
|
|
341
|
+
factMaps,
|
|
342
|
+
existingMemories,
|
|
343
|
+
}))
|
|
344
|
+
}.bind(this),
|
|
345
|
+
)
|
|
265
346
|
}
|
|
266
347
|
|
|
267
|
-
private
|
|
348
|
+
private extractFactsEffect(
|
|
268
349
|
parsedMessages: string,
|
|
269
350
|
extractionOptions?: { customPrompt?: string; maxFacts?: number },
|
|
270
|
-
):
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
351
|
+
): Effect.Effect<ExtractedFact[], MemoryServiceError, never> {
|
|
352
|
+
return Effect.gen(
|
|
353
|
+
function* (this: Memory) {
|
|
354
|
+
const [systemPrompt, userPrompt] = getFactRetrievalMessages(
|
|
355
|
+
parsedMessages,
|
|
356
|
+
this.buildFactExtractionPrompt(extractionOptions?.customPrompt),
|
|
357
|
+
extractionOptions?.maxFacts,
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
const result = yield* Effect.tryPromise({
|
|
361
|
+
try: () =>
|
|
362
|
+
this.helperModelRuntime.generateHelperStructured({
|
|
363
|
+
tag: 'memory-extract-facts',
|
|
364
|
+
createAgent: this.createAgent,
|
|
365
|
+
defaultSystemPrompt: this.config.customPrompt,
|
|
366
|
+
systemPrompt,
|
|
367
|
+
maxOutputTokens: this.maxOutputTokens,
|
|
368
|
+
timeoutMs: MEMORY_FACT_EXTRACTION_TIMEOUT_MS,
|
|
369
|
+
messages: [{ role: 'user', content: userPrompt }],
|
|
370
|
+
schema: FactRetrievalSchema,
|
|
371
|
+
}),
|
|
372
|
+
catch: (cause) => new MemoryServiceError({ message: 'Failed to extract facts.', cause }),
|
|
373
|
+
})
|
|
288
374
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
375
|
+
return postProcessMemoryFacts(
|
|
376
|
+
result.facts,
|
|
377
|
+
typeof extractionOptions?.maxFacts === 'number' ? { maxFacts: extractionOptions.maxFacts } : {},
|
|
378
|
+
)
|
|
379
|
+
}.bind(this),
|
|
380
|
+
).pipe(
|
|
381
|
+
Effect.catchTag('MemoryServiceError', (error) =>
|
|
382
|
+
Effect.sync(() => {
|
|
383
|
+
aiLogger.warn`Failed to extract facts: ${error.message}`
|
|
384
|
+
return []
|
|
385
|
+
}),
|
|
386
|
+
),
|
|
387
|
+
)
|
|
297
388
|
}
|
|
298
389
|
|
|
299
|
-
private
|
|
390
|
+
private determineDeltaEffect(
|
|
300
391
|
existingMemories: { id: string; text: string }[],
|
|
301
392
|
newFacts: string[],
|
|
302
|
-
):
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
393
|
+
): Effect.Effect<{ deltas: Array<z.infer<typeof MemoryDeltaSchema>['deltas'][number]> }, MemoryServiceError, never> {
|
|
394
|
+
return Effect.gen(
|
|
395
|
+
function* (this: Memory) {
|
|
396
|
+
if (existingMemories.length === 0) {
|
|
397
|
+
return {
|
|
398
|
+
deltas: newFacts.map((fact) => ({
|
|
399
|
+
fact,
|
|
400
|
+
classification: 'new' as const,
|
|
401
|
+
targetMemoryIds: [],
|
|
402
|
+
invalidateTargetIds: [],
|
|
403
|
+
relations: [],
|
|
404
|
+
rationale: 'No existing memories in scope.',
|
|
405
|
+
})),
|
|
406
|
+
}
|
|
407
|
+
}
|
|
315
408
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
409
|
+
const candidateMemories = this.selectDeltaCandidateMemories(existingMemories, newFacts)
|
|
410
|
+
const { systemPrompt, userPrompt } = getClassifyMemoryDeltaPrompt({
|
|
411
|
+
existingMemories: candidateMemories,
|
|
412
|
+
newFacts,
|
|
413
|
+
})
|
|
414
|
+
aiLogger.debug`Memory delta candidate selection (existing=${existingMemories.length}, selected=${candidateMemories.length}, facts=${newFacts.length})`
|
|
415
|
+
|
|
416
|
+
return yield* Effect.tryPromise({
|
|
417
|
+
try: () =>
|
|
418
|
+
this.helperModelRuntime.generateHelperStructured({
|
|
419
|
+
tag: 'memory-classify-delta',
|
|
420
|
+
createAgent: this.createAgent,
|
|
421
|
+
systemPrompt,
|
|
422
|
+
maxOutputTokens: this.maxOutputTokens,
|
|
423
|
+
timeoutMs: MEMORY_DELTA_CLASSIFICATION_TIMEOUT_MS,
|
|
424
|
+
messages: [{ role: 'user', content: userPrompt }],
|
|
425
|
+
schema: MemoryDeltaSchema,
|
|
426
|
+
}),
|
|
427
|
+
catch: (cause) => new MemoryServiceError({ message: 'Failed to determine memory updates.', cause }),
|
|
428
|
+
})
|
|
429
|
+
}.bind(this),
|
|
430
|
+
)
|
|
335
431
|
}
|
|
336
432
|
|
|
337
433
|
private normalizeMemoryDeltaText(value: string, maxChars?: number): string {
|
|
@@ -441,92 +537,112 @@ export class Memory {
|
|
|
441
537
|
return selected.map((memory) => ({ id: memory.id, text: memory.text }))
|
|
442
538
|
}
|
|
443
539
|
|
|
444
|
-
private
|
|
540
|
+
private applyUpdates(
|
|
445
541
|
updates: MemoryUpdateOutput,
|
|
446
542
|
options: AddOptions,
|
|
447
543
|
factMaps: ReturnType<typeof buildMemoryFactMaps>,
|
|
448
544
|
existingMemories: Array<{ id: string; text: string }>,
|
|
449
|
-
):
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
545
|
+
): Effect.Effect<void, MemoryServiceError, never> {
|
|
546
|
+
return Effect.gen(
|
|
547
|
+
function* (this: Memory) {
|
|
548
|
+
const plan = createMemoryActionPlan({
|
|
549
|
+
updates,
|
|
550
|
+
memoryType: options.memoryType,
|
|
551
|
+
explicitImportance: options.importance,
|
|
552
|
+
extractedImportanceByKey: factMaps.extractedImportanceByKey,
|
|
553
|
+
confidenceByKey: factMaps.confidenceByKey,
|
|
554
|
+
durabilityByKey: factMaps.durabilityByKey,
|
|
555
|
+
categoryByKey: factMaps.categoryByKey,
|
|
556
|
+
existingMemories,
|
|
557
|
+
})
|
|
558
|
+
|
|
559
|
+
const idMap = new Map<string, string>()
|
|
560
|
+
for (const action of plan.actions) {
|
|
561
|
+
switch (action.type) {
|
|
562
|
+
case 'add': {
|
|
563
|
+
const truncatedContent = truncateText(action.text, 50)
|
|
564
|
+
const metadata = { ...options.metadata, memoryCategory: action.category }
|
|
565
|
+
const hash = hashContent(action.text, options.scopeId, options.memoryType)
|
|
566
|
+
|
|
567
|
+
const newId = yield* tryMemoryPromise(`Failed to insert memory for scope ${options.scopeId}.`, () =>
|
|
568
|
+
this.store.insert(
|
|
569
|
+
action.text,
|
|
570
|
+
options.scopeId,
|
|
571
|
+
options.memoryType,
|
|
572
|
+
metadata,
|
|
573
|
+
action.importance,
|
|
574
|
+
action.durability as Durability,
|
|
575
|
+
),
|
|
576
|
+
).pipe(
|
|
577
|
+
Effect.catchTag('MemoryServiceError', (error) => {
|
|
578
|
+
if (!isUniqueIndexConflict(error.cause, 'memoryHashIdx')) {
|
|
579
|
+
return Effect.fail(error)
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
return tryMemoryPromise(`Failed to look up memory hash ${hash}.`, () =>
|
|
583
|
+
this.store.getByHash(hash),
|
|
584
|
+
).pipe(
|
|
585
|
+
Effect.flatMap((existing) => {
|
|
586
|
+
if (!existing) {
|
|
587
|
+
return Effect.fail(error)
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
return Effect.sync(() => {
|
|
591
|
+
aiLogger.debug`Skipped duplicate memory insert due to hash conflict: ${existing.id}`
|
|
592
|
+
return existing.id
|
|
593
|
+
})
|
|
594
|
+
}),
|
|
595
|
+
)
|
|
596
|
+
}),
|
|
597
|
+
)
|
|
598
|
+
|
|
599
|
+
idMap.set(action.refId, newId)
|
|
600
|
+
aiLogger.debug`Added new memory (memoryType: ${options.memoryType}, category: ${action.category}, durability: ${action.durability}, importance: ${action.importance.toFixed(2)}, content: ${truncatedContent})`
|
|
601
|
+
break
|
|
483
602
|
}
|
|
484
603
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
604
|
+
case 'update': {
|
|
605
|
+
const metadata = { ...options.metadata, ...(action.category ? { memoryCategory: action.category } : {}) }
|
|
606
|
+
yield* tryMemoryPromise(`Failed to update memory ${action.refId}.`, () =>
|
|
607
|
+
this.store.update(action.refId, action.text, {
|
|
608
|
+
importance: action.importance,
|
|
609
|
+
durability: action.durability as Durability | undefined,
|
|
610
|
+
metadata: Object.keys(metadata).length > 0 ? metadata : undefined,
|
|
611
|
+
}),
|
|
612
|
+
)
|
|
613
|
+
idMap.set(action.refId, action.refId)
|
|
614
|
+
aiLogger.debug`Updated memory ${action.refId}: ${truncateText(action.text, 50)}`
|
|
615
|
+
break
|
|
488
616
|
}
|
|
489
617
|
|
|
490
|
-
|
|
491
|
-
|
|
618
|
+
case 'delete':
|
|
619
|
+
yield* tryMemoryPromise(`Failed to delete memory ${action.refId}.`, () => this.store.delete(action.refId))
|
|
620
|
+
aiLogger.debug`Deleted memory ${action.refId}`
|
|
621
|
+
break
|
|
492
622
|
}
|
|
493
|
-
|
|
494
|
-
idMap.set(action.refId, newId)
|
|
495
|
-
aiLogger.debug`Added new memory (memoryType: ${options.memoryType}, category: ${action.category}, durability: ${action.durability}, importance: ${action.importance.toFixed(2)}, content: ${truncatedContent})`
|
|
496
|
-
break
|
|
497
623
|
}
|
|
498
624
|
|
|
499
|
-
|
|
500
|
-
const
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
625
|
+
for (const relation of plan.relations) {
|
|
626
|
+
const fromId = idMap.get(relation.fromRefId)
|
|
627
|
+
if (!fromId) continue
|
|
628
|
+
|
|
629
|
+
const toId = idMap.get(relation.toRefId) ?? relation.toRefId
|
|
630
|
+
yield* tryMemoryPromise(`Failed to create memory relation ${relation.relation}.`, () =>
|
|
631
|
+
this.store.addRelation(fromId, toId, relation.relation),
|
|
632
|
+
).pipe(
|
|
633
|
+
Effect.tap(() =>
|
|
634
|
+
Effect.sync(() => {
|
|
635
|
+
aiLogger.debug`Created ${relation.relation} relation: ${fromId} -> ${toId}`
|
|
636
|
+
}),
|
|
637
|
+
),
|
|
638
|
+
Effect.catchTag('MemoryServiceError', (error) =>
|
|
639
|
+
Effect.sync(() => {
|
|
640
|
+
aiLogger.warn`Failed to create memory relation (non-fatal, graph may be incomplete): ${error.message}`
|
|
641
|
+
}),
|
|
642
|
+
),
|
|
643
|
+
)
|
|
509
644
|
}
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
await this.store.delete(action.refId)
|
|
513
|
-
aiLogger.debug`Deleted memory ${action.refId}`
|
|
514
|
-
break
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
for (const relation of plan.relations) {
|
|
519
|
-
const fromId = idMap.get(relation.fromRefId)
|
|
520
|
-
if (!fromId) continue
|
|
521
|
-
|
|
522
|
-
const toId = idMap.get(relation.toRefId) ?? relation.toRefId
|
|
523
|
-
|
|
524
|
-
try {
|
|
525
|
-
await this.store.addRelation(fromId, toId, relation.relation)
|
|
526
|
-
aiLogger.debug`Created ${relation.relation} relation: ${fromId} -> ${toId}`
|
|
527
|
-
} catch (error) {
|
|
528
|
-
aiLogger.warn`Failed to create memory relation (non-fatal, graph may be incomplete): ${error}`
|
|
529
|
-
}
|
|
530
|
-
}
|
|
645
|
+
}.bind(this),
|
|
646
|
+
)
|
|
531
647
|
}
|
|
532
648
|
}
|