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