@lota-sdk/core 0.1.13 → 0.1.15
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 +5 -5
- package/src/ai/embedding-cache.ts +7 -6
- package/src/ai/index.ts +1 -0
- package/src/bifrost/bifrost.ts +12 -7
- package/src/config/agent-defaults.ts +1 -1
- package/src/config/logger.ts +7 -9
- package/src/{runtime.ts → create-runtime.ts} +6 -6
- package/src/db/cursor-pagination.ts +1 -1
- package/src/db/memory-store.ts +10 -6
- package/src/db/memory.ts +6 -4
- package/src/db/schema-fingerprint.ts +1 -0
- package/src/db/service.ts +45 -51
- package/src/db/startup.ts +3 -3
- package/src/index.ts +1 -1
- package/src/queues/context-compaction.queue.ts +4 -8
- package/src/queues/document-processor.queue.ts +7 -7
- package/src/queues/memory-consolidation.queue.ts +7 -8
- package/src/queues/post-chat-memory.queue.ts +2 -6
- package/src/queues/recent-activity-title-refinement.queue.ts +2 -6
- package/src/queues/regular-chat-memory-digest.queue.ts +4 -7
- package/src/queues/skill-extraction.queue.ts +4 -7
- package/src/queues/workstream-title-generation.queue.ts +2 -6
- package/src/redis/connection.ts +6 -3
- package/src/redis/index.ts +1 -0
- package/src/redis/org-memory-lock.ts +1 -1
- package/src/redis/redis-lease-lock.ts +41 -8
- package/src/runtime/agent-stream-helpers.ts +2 -1
- package/src/runtime/context-compaction-constants.ts +1 -1
- package/src/runtime/context-compaction-runtime.ts +6 -4
- package/src/runtime/context-compaction.ts +19 -38
- package/src/runtime/execution-plan.ts +2 -2
- package/src/runtime/helper-model.ts +3 -1
- package/src/runtime/index.ts +12 -1
- package/src/runtime/memory-block.ts +3 -2
- package/src/runtime/memory-pipeline.ts +24 -5
- package/src/runtime/plugin-types.ts +1 -1
- package/src/runtime/runtime-extensions.ts +89 -13
- package/src/runtime/title-helpers.ts +11 -2
- package/src/runtime/workstream-chat-helpers.ts +5 -6
- package/src/runtime/workstream-routing-policy.ts +0 -30
- package/src/runtime/workstream-state.ts +17 -7
- package/src/services/attachment.service.ts +1 -1
- package/src/services/context-compaction.service.ts +3 -3
- package/src/services/document-chunk.service.ts +37 -32
- package/src/services/execution-plan.service.ts +2 -0
- package/src/services/learned-skill.service.ts +6 -10
- package/src/services/{memory.utils.ts → memory-utils.ts} +4 -8
- package/src/services/memory.service.ts +21 -18
- package/src/services/organization-member.service.ts +1 -1
- package/src/services/plan-artifact.service.ts +1 -0
- package/src/services/plan-executor.service.ts +2 -18
- package/src/services/plan-helpers.ts +15 -0
- package/src/services/plan-validator.service.ts +3 -18
- package/src/services/recent-activity-title.service.ts +3 -10
- package/src/services/recent-activity.service.ts +6 -12
- package/src/services/workstream-message.service.ts +26 -16
- package/src/services/workstream-title.service.ts +1 -9
- package/src/services/{workstream-turn-preparation.ts → workstream-turn-preparation.service.ts} +401 -314
- package/src/services/workstream-turn.ts +2 -2
- package/src/services/workstream.service.ts +22 -10
- package/src/services/workstream.types.ts +7 -16
- package/src/storage/attachment-storage.service.ts +4 -4
- package/src/storage/{attachments.utils.ts → attachment-utils.ts} +1 -4
- package/src/storage/index.ts +2 -2
- package/src/system-agents/{context-compacter.agent.ts → context-compaction.agent.ts} +4 -4
- package/src/system-agents/delegated-agent-factory.ts +3 -2
- package/src/system-agents/index.ts +8 -0
- package/src/system-agents/memory-reranker.agent.ts +1 -1
- package/src/system-agents/memory.agent.ts +1 -1
- package/src/system-agents/recent-activity-title-refiner.agent.ts +1 -1
- package/src/tools/execution-plan.tool.ts +6 -2
- package/src/tools/fetch-webpage.tool.ts +20 -18
- package/src/tools/index.ts +2 -2
- package/src/tools/read-file-parts.tool.ts +1 -1
- package/src/tools/search-web.tool.ts +18 -15
- package/src/tools/{search-tools.ts → search.tool.ts} +1 -1
- package/src/tools/team-think.tool.ts +9 -5
- package/src/tools/{tool-contract.ts → tool-contracts.ts} +9 -2
- package/src/utils/async.ts +1 -1
- package/src/utils/errors.ts +15 -0
- package/src/utils/hono-error-handler.ts +1 -2
- package/src/utils/index.ts +10 -2
- package/src/utils/string.ts +14 -0
- package/src/workers/bootstrap.ts +2 -2
- package/src/workers/memory-consolidation.worker.ts +12 -12
- package/src/workers/regular-chat-memory-digest.helpers.ts +2 -7
- package/src/workers/regular-chat-memory-digest.runner.ts +9 -103
- package/src/workers/skill-extraction.runner.ts +7 -101
- package/src/workers/utils/file-section-chunker.ts +5 -3
- package/src/workers/utils/workstream-message-query.ts +106 -0
- package/src/workers/worker-utils.ts +4 -0
- package/src/runtime/retrieval-pipeline.ts +0 -3
- package/src/utils/error.ts +0 -10
- /package/src/services/{context-compaction-runtime.ts → context-compaction-runtime.singleton.ts} +0 -0
- /package/src/storage/{attachments.types.ts → attachment-types.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lota-sdk/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -28,19 +28,19 @@
|
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@ai-sdk/devtools": "^0.0.15",
|
|
31
|
-
"@ai-sdk/openai": "^3.0.
|
|
31
|
+
"@ai-sdk/openai": "^3.0.47",
|
|
32
32
|
"@logtape/logtape": "^2.0.4",
|
|
33
|
-
"@lota-sdk/shared": "0.1.
|
|
33
|
+
"@lota-sdk/shared": "0.1.15",
|
|
34
34
|
"@mendable/firecrawl-js": "^4.16.0",
|
|
35
35
|
"@surrealdb/node": "^3.0.3",
|
|
36
|
-
"ai": "^6.0.
|
|
36
|
+
"ai": "^6.0.134",
|
|
37
37
|
"bullmq": "^5.71.0",
|
|
38
38
|
"hono": "^4.12.8",
|
|
39
39
|
"ioredis": "5.9.3",
|
|
40
40
|
"mammoth": "^1.12.0",
|
|
41
41
|
"pdf-parse": "^2.4.5",
|
|
42
42
|
"resumable-stream": "^2.2.12",
|
|
43
|
-
"surrealdb": "^2.0.
|
|
43
|
+
"surrealdb": "^2.0.3",
|
|
44
44
|
"zod": "^4.3.6"
|
|
45
45
|
}
|
|
46
46
|
}
|
|
@@ -4,17 +4,18 @@ import type IORedis from 'ioredis'
|
|
|
4
4
|
|
|
5
5
|
import { aiLogger } from '../config/logger'
|
|
6
6
|
|
|
7
|
-
const
|
|
7
|
+
export const DEFAULT_EMBEDDING_CACHE_TTL_SECONDS = 3600
|
|
8
|
+
const EMBEDDING_CACHE_KEY_PREFIX = 'emb'
|
|
8
9
|
|
|
9
10
|
export class EmbeddingCache {
|
|
10
11
|
constructor(
|
|
11
12
|
private redis: IORedis,
|
|
12
|
-
private ttlSeconds: number =
|
|
13
|
+
private ttlSeconds: number = DEFAULT_EMBEDDING_CACHE_TTL_SECONDS,
|
|
13
14
|
) {}
|
|
14
15
|
|
|
15
16
|
private buildKey(model: string, text: string): string {
|
|
16
17
|
const hash = createHash('sha256').update(text).digest('hex')
|
|
17
|
-
return
|
|
18
|
+
return `${EMBEDDING_CACHE_KEY_PREFIX}:${model}:${hash}`
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
async get(model: string, text: string): Promise<number[] | null> {
|
|
@@ -23,7 +24,7 @@ export class EmbeddingCache {
|
|
|
23
24
|
if (!cached) return null
|
|
24
25
|
return JSON.parse(cached.toString()) as number[]
|
|
25
26
|
} catch (error) {
|
|
26
|
-
aiLogger.
|
|
27
|
+
aiLogger.warn`Embedding cache get failed: ${error}`
|
|
27
28
|
return null
|
|
28
29
|
}
|
|
29
30
|
}
|
|
@@ -32,7 +33,7 @@ export class EmbeddingCache {
|
|
|
32
33
|
try {
|
|
33
34
|
await this.redis.set(this.buildKey(model, text), JSON.stringify(embedding), 'EX', this.ttlSeconds)
|
|
34
35
|
} catch (error) {
|
|
35
|
-
aiLogger.
|
|
36
|
+
aiLogger.warn`Embedding cache set failed: ${error}`
|
|
36
37
|
}
|
|
37
38
|
}
|
|
38
39
|
}
|
|
@@ -40,7 +41,7 @@ export class EmbeddingCache {
|
|
|
40
41
|
let embeddingCacheInstance: EmbeddingCache | null = null
|
|
41
42
|
|
|
42
43
|
export function configureEmbeddingCache(redis: IORedis, ttlSeconds?: number): void {
|
|
43
|
-
embeddingCacheInstance = new EmbeddingCache(redis, ttlSeconds ??
|
|
44
|
+
embeddingCacheInstance = new EmbeddingCache(redis, ttlSeconds ?? DEFAULT_EMBEDDING_CACHE_TTL_SECONDS)
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
export function getEmbeddingCache(): EmbeddingCache | null {
|
package/src/ai/index.ts
CHANGED
package/src/bifrost/bifrost.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type { LanguageModelMiddleware } from 'ai'
|
|
|
5
5
|
|
|
6
6
|
import { isRecord, readString } from '../utils/string'
|
|
7
7
|
|
|
8
|
+
type BifrostLanguageModel = Parameters<typeof wrapLanguageModel>[0]['model']
|
|
8
9
|
type BifrostExtraParams = Record<string, unknown>
|
|
9
10
|
type BifrostChatResponse = { body?: unknown }
|
|
10
11
|
type BifrostTransformParamsOptions = Parameters<NonNullable<LanguageModelMiddleware['transformParams']>>[0]
|
|
@@ -131,7 +132,7 @@ export function injectBifrostChatReasoningStream(
|
|
|
131
132
|
const closeReasoning = () => {
|
|
132
133
|
if (!reasoningOpen || reasoningClosed) return
|
|
133
134
|
|
|
134
|
-
controller.enqueue({ type: 'reasoning-end', id: reasoningId }
|
|
135
|
+
controller.enqueue({ type: 'reasoning-end', id: reasoningId } satisfies BifrostStreamPart)
|
|
135
136
|
reasoningClosed = true
|
|
136
137
|
}
|
|
137
138
|
|
|
@@ -141,11 +142,15 @@ export function injectBifrostChatReasoningStream(
|
|
|
141
142
|
|
|
142
143
|
if (reasoningDelta) {
|
|
143
144
|
if (!reasoningOpen) {
|
|
144
|
-
controller.enqueue({ type: 'reasoning-start', id: reasoningId }
|
|
145
|
+
controller.enqueue({ type: 'reasoning-start', id: reasoningId } satisfies BifrostStreamPart)
|
|
145
146
|
reasoningOpen = true
|
|
146
147
|
}
|
|
147
148
|
|
|
148
|
-
controller.enqueue({
|
|
149
|
+
controller.enqueue({
|
|
150
|
+
type: 'reasoning-delta',
|
|
151
|
+
id: reasoningId,
|
|
152
|
+
delta: reasoningDelta,
|
|
153
|
+
} satisfies BifrostStreamPart)
|
|
149
154
|
}
|
|
150
155
|
return
|
|
151
156
|
}
|
|
@@ -158,7 +163,7 @@ export function injectBifrostChatReasoningStream(
|
|
|
158
163
|
},
|
|
159
164
|
flush(controller) {
|
|
160
165
|
if (!reasoningOpen || reasoningClosed) return
|
|
161
|
-
controller.enqueue({ type: 'reasoning-end', id: reasoningId }
|
|
166
|
+
controller.enqueue({ type: 'reasoning-end', id: reasoningId } satisfies BifrostStreamPart)
|
|
162
167
|
},
|
|
163
168
|
}),
|
|
164
169
|
)
|
|
@@ -182,7 +187,7 @@ export function injectBifrostResponsesReasoningStream(
|
|
|
182
187
|
id: reasoningDelta.id,
|
|
183
188
|
delta: reasoningDelta.delta,
|
|
184
189
|
providerMetadata: { openai: { itemId: reasoningDelta.itemId } },
|
|
185
|
-
}
|
|
190
|
+
} satisfies BifrostStreamPart)
|
|
186
191
|
},
|
|
187
192
|
}),
|
|
188
193
|
)
|
|
@@ -242,12 +247,12 @@ function createBifrostProvider(extraParams?: BifrostExtraParams) {
|
|
|
242
247
|
})
|
|
243
248
|
}
|
|
244
249
|
|
|
245
|
-
function withBifrostDevTools<TModel>(model: TModel): TModel {
|
|
250
|
+
function withBifrostDevTools<TModel extends BifrostLanguageModel>(model: TModel): TModel {
|
|
246
251
|
if (process.env.NODE_ENV === 'production') {
|
|
247
252
|
return model
|
|
248
253
|
}
|
|
249
254
|
|
|
250
|
-
return wrapLanguageModel({ model
|
|
255
|
+
return wrapLanguageModel({ model, middleware: devToolsMiddleware() }) as TModel
|
|
251
256
|
}
|
|
252
257
|
|
|
253
258
|
let provider: ReturnType<typeof createOpenAI> | null = null
|
package/src/config/logger.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { LogLevel } from '@logtape/logtape'
|
|
2
2
|
import { configure, getAnsiColorFormatter, getConsoleSink, getLogger as getLogTapeLogger } from '@logtape/logtape'
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
const LOG_CATEGORY = 'lota-sdk'
|
|
5
|
+
|
|
6
|
+
export async function configureLotaLogger(logLevel: LogLevel = 'info'): Promise<void> {
|
|
5
7
|
const formatter = getAnsiColorFormatter({ level: 'FULL' })
|
|
6
8
|
|
|
7
9
|
await configure({
|
|
@@ -10,7 +12,7 @@ export async function configureLotaLogger(logLevel: LogLevel): Promise<void> {
|
|
|
10
12
|
loggers: [
|
|
11
13
|
{ category: ['logtape', 'meta'], lowestLevel: 'warning', sinks: ['console'] },
|
|
12
14
|
{ category: ['server'], lowestLevel: logLevel, sinks: ['console'] },
|
|
13
|
-
{ category: [
|
|
15
|
+
{ category: [LOG_CATEGORY], lowestLevel: logLevel, sinks: ['console'] },
|
|
14
16
|
{ category: ['hono'], lowestLevel: logLevel, sinks: ['console'] },
|
|
15
17
|
],
|
|
16
18
|
})
|
|
@@ -20,10 +22,6 @@ export function getLogger(category: readonly string[]) {
|
|
|
20
22
|
return getLogTapeLogger([...category])
|
|
21
23
|
}
|
|
22
24
|
|
|
23
|
-
export
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
export const serverLogger = getLogger(['lota-sdk'])
|
|
28
|
-
export const chatLogger = getLogger(['lota-sdk', 'chat'])
|
|
29
|
-
export const aiLogger = getLogger(['lota-sdk', 'ai'])
|
|
25
|
+
export const serverLogger = getLogger([LOG_CATEGORY])
|
|
26
|
+
export const chatLogger = getLogger([LOG_CATEGORY, 'chat'])
|
|
27
|
+
export const aiLogger = getLogger([LOG_CATEGORY, 'ai'])
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import type { ChatMessage } from '@lota-sdk/shared'
|
|
2
|
+
|
|
1
3
|
import { configureEmbeddingCache } from './ai/embedding-cache'
|
|
2
4
|
import { configureAgentFactory, configureAgents } from './config/agent-defaults'
|
|
3
5
|
import { configureBackgroundProcessing } from './config/background-processing'
|
|
4
|
-
import {
|
|
6
|
+
import { configureLotaLogger } from './config/logger'
|
|
5
7
|
import { configureWorkstreams } from './config/workstream-defaults'
|
|
6
8
|
import { ensureRecordId } from './db/record-id'
|
|
7
9
|
import { computeSchemaFingerprint } from './db/schema-fingerprint'
|
|
@@ -76,7 +78,6 @@ type UnarchiveSdkWorkstream = (
|
|
|
76
78
|
export interface LotaRuntime {
|
|
77
79
|
services: {
|
|
78
80
|
database: SurrealDBService
|
|
79
|
-
databaseService: SurrealDBService
|
|
80
81
|
redis: RedisConnectionManager
|
|
81
82
|
closeRedisConnection: () => Promise<void>
|
|
82
83
|
attachmentService: typeof attachmentService
|
|
@@ -132,7 +133,7 @@ export interface LotaRuntime {
|
|
|
132
133
|
delete: typeof workstreamServiceSingleton.deleteWorkstream
|
|
133
134
|
stop: typeof workstreamServiceSingleton.stopActiveRun
|
|
134
135
|
listMessages: typeof workstreamMessageServiceSingleton.listMessageHistoryPage
|
|
135
|
-
getMessage: (params: { workstreamId: string; messageId: string }) => Promise<
|
|
136
|
+
getMessage: (params: { workstreamId: string; messageId: string }) => Promise<ChatMessage>
|
|
136
137
|
sendMessage: (params: {
|
|
137
138
|
workstreamId: string
|
|
138
139
|
organizationId: string
|
|
@@ -170,7 +171,7 @@ export async function createLotaRuntime(config: LotaRuntimeConfig): Promise<Lota
|
|
|
170
171
|
const resolvedConfig = parseLotaRuntimeConfig(config)
|
|
171
172
|
configureRuntimeConfig(resolvedConfig)
|
|
172
173
|
|
|
173
|
-
await
|
|
174
|
+
await configureLotaLogger(resolvedConfig.logging.level)
|
|
174
175
|
|
|
175
176
|
const db = new SurrealDBServiceClass({
|
|
176
177
|
url: resolvedConfig.database.url,
|
|
@@ -306,7 +307,6 @@ export async function createLotaRuntime(config: LotaRuntimeConfig): Promise<Lota
|
|
|
306
307
|
return {
|
|
307
308
|
services: {
|
|
308
309
|
database: db,
|
|
309
|
-
databaseService: db,
|
|
310
310
|
redis: redisManager,
|
|
311
311
|
closeRedisConnection: async () => await redisManager.closeConnection(),
|
|
312
312
|
attachmentService: attachmentServiceSingleton,
|
|
@@ -375,7 +375,7 @@ function getBuiltInSchemaFiles(): URL[] {
|
|
|
375
375
|
function createPluginDatabaseConnector(pluginRuntime: Record<string, LotaPlugin>): () => Promise<void> {
|
|
376
376
|
return async () => {
|
|
377
377
|
for (const plugin of Object.values(pluginRuntime)) {
|
|
378
|
-
const services = plugin.services
|
|
378
|
+
const services = plugin.services
|
|
379
379
|
const connectDatabase = services.connectDatabase
|
|
380
380
|
if (typeof connectDatabase !== 'function') {
|
|
381
381
|
continue
|
|
@@ -64,7 +64,7 @@ async function listRowsBefore(
|
|
|
64
64
|
throw new Error(`Cursor message not found in ${config.table}: ${params.beforeMessageId}`)
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
const cursorCreatedAt = new Date(toTimestamp(cursorRow.createdAt))
|
|
67
|
+
const cursorCreatedAt = new Date(toTimestamp(cursorRow.createdAt) ?? Date.now())
|
|
68
68
|
const cursorId = config.toRowId(params.parentId, params.beforeMessageId)
|
|
69
69
|
|
|
70
70
|
return await databaseService.query<unknown>(
|
package/src/db/memory-store.ts
CHANGED
|
@@ -24,6 +24,10 @@ const MEMORY_TABLE = TABLES.MEMORY
|
|
|
24
24
|
const MEMORY_HISTORY_TABLE = TABLES.MEMORY_HISTORY
|
|
25
25
|
const MEMORY_RELATION_TABLE = TABLES.MEMORY_RELATION
|
|
26
26
|
const MIN_RELEVANCE_SCORE = 0.25
|
|
27
|
+
const STRONG_GRAPH_BOOSTS = { support: 0.1, contradict: 0.2 } as const
|
|
28
|
+
const WEAK_GRAPH_BOOSTS = { support: 0.05, contradict: 0.1 } as const
|
|
29
|
+
const CANDIDATE_FANOUT_MULTIPLIER = 4
|
|
30
|
+
const CANDIDATE_SLICE_FLOOR = 50
|
|
27
31
|
const TOUCH_MEMORIES_MAX_ATTEMPTS = 4
|
|
28
32
|
const TOUCH_MEMORIES_RETRY_BASE_DELAY_MS = 25
|
|
29
33
|
const TOUCH_MEMORIES_RETRY_JITTER_MS = 20
|
|
@@ -153,7 +157,7 @@ export class SurrealMemoryStore {
|
|
|
153
157
|
relationCounts,
|
|
154
158
|
options.limit,
|
|
155
159
|
(row) => 1 / (1 + row.distance),
|
|
156
|
-
|
|
160
|
+
STRONG_GRAPH_BOOSTS,
|
|
157
161
|
MIN_RELEVANCE_SCORE,
|
|
158
162
|
)
|
|
159
163
|
|
|
@@ -317,7 +321,7 @@ export class SurrealMemoryStore {
|
|
|
317
321
|
if (b.textScore !== a.textScore) return b.textScore - a.textScore
|
|
318
322
|
return a.index - b.index
|
|
319
323
|
})
|
|
320
|
-
.slice(0, Math.max(options.limit *
|
|
324
|
+
.slice(0, Math.max(options.limit * CANDIDATE_FANOUT_MULTIPLIER, CANDIDATE_SLICE_FLOOR))
|
|
321
325
|
|
|
322
326
|
if (options.fastMode) {
|
|
323
327
|
return this.mapFastRows(scoredRows, options.limit, (row) => row.textScore)
|
|
@@ -330,7 +334,7 @@ export class SurrealMemoryStore {
|
|
|
330
334
|
recentRelationCounts,
|
|
331
335
|
options.limit,
|
|
332
336
|
(row) => row.textScore,
|
|
333
|
-
|
|
337
|
+
WEAK_GRAPH_BOOSTS,
|
|
334
338
|
MIN_RELEVANCE_SCORE,
|
|
335
339
|
)
|
|
336
340
|
|
|
@@ -483,7 +487,7 @@ export class SurrealMemoryStore {
|
|
|
483
487
|
relationCounts,
|
|
484
488
|
limit,
|
|
485
489
|
(row) => 1 / (1 + row.distance),
|
|
486
|
-
|
|
490
|
+
STRONG_GRAPH_BOOSTS,
|
|
487
491
|
MIN_RELEVANCE_SCORE,
|
|
488
492
|
)
|
|
489
493
|
|
|
@@ -520,7 +524,7 @@ export class SurrealMemoryStore {
|
|
|
520
524
|
relationCounts,
|
|
521
525
|
limit,
|
|
522
526
|
(row) => row.rrfScore,
|
|
523
|
-
|
|
527
|
+
WEAK_GRAPH_BOOSTS,
|
|
524
528
|
MIN_RELEVANCE_SCORE,
|
|
525
529
|
)
|
|
526
530
|
|
|
@@ -619,7 +623,7 @@ export class SurrealMemoryStore {
|
|
|
619
623
|
relationCounts,
|
|
620
624
|
options.limit,
|
|
621
625
|
(row) => row.linearScore,
|
|
622
|
-
|
|
626
|
+
WEAK_GRAPH_BOOSTS,
|
|
623
627
|
MIN_RELEVANCE_SCORE,
|
|
624
628
|
)
|
|
625
629
|
|
package/src/db/memory.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { getFactRetrievalMessages } from '../runtime/memory-prompts-fact'
|
|
|
12
12
|
import { parseMessages } from '../runtime/memory-prompts-parse'
|
|
13
13
|
import { getClassifyMemoryDeltaPrompt } from '../runtime/memory-prompts-update'
|
|
14
14
|
import { getRuntimeConfig } from '../runtime/runtime-config'
|
|
15
|
+
import { compactWhitespace } from '../utils/string'
|
|
15
16
|
import type { SurrealMemoryStore } from './memory-store'
|
|
16
17
|
import { getDefaultMemoryStore } from './memory-store'
|
|
17
18
|
import { hashContent, isUniqueIndexConflict } from './memory-store.helpers'
|
|
@@ -39,6 +40,7 @@ const MEMORY_DELTA_MAX_CANDIDATE_MEMORIES = 80
|
|
|
39
40
|
const MEMORY_DELTA_MAX_CANDIDATES_PER_FACT = 10
|
|
40
41
|
const MEMORY_DELTA_MIN_BASELINE_CANDIDATES = 12
|
|
41
42
|
const MEMORY_DELTA_MEMORY_TEXT_MAX_CHARS = 400
|
|
43
|
+
const CANDIDATE_FANOUT_MULTIPLIER = 4
|
|
42
44
|
const helperModelRuntime = createHelperModelRuntime()
|
|
43
45
|
|
|
44
46
|
interface PreparedScopeUpdate {
|
|
@@ -277,7 +279,7 @@ export class Memory {
|
|
|
277
279
|
typeof extractionOptions?.maxFacts === 'number' ? { maxFacts: extractionOptions.maxFacts } : {},
|
|
278
280
|
)
|
|
279
281
|
} catch (error) {
|
|
280
|
-
aiLogger.
|
|
282
|
+
aiLogger.warn`Failed to extract facts: ${error}`
|
|
281
283
|
return []
|
|
282
284
|
}
|
|
283
285
|
}
|
|
@@ -313,7 +315,7 @@ export class Memory {
|
|
|
313
315
|
}
|
|
314
316
|
|
|
315
317
|
private normalizeMemoryDeltaText(value: string, maxChars?: number): string {
|
|
316
|
-
const normalized = value
|
|
318
|
+
const normalized = compactWhitespace(value)
|
|
317
319
|
if (!normalized) return ''
|
|
318
320
|
if (typeof maxChars !== 'number' || normalized.length <= maxChars) return normalized
|
|
319
321
|
return `${normalized.slice(0, maxChars - 3)}...`
|
|
@@ -384,7 +386,7 @@ export class Memory {
|
|
|
384
386
|
const targetCandidateCount = Math.min(MEMORY_DELTA_MAX_CANDIDATE_MEMORIES, normalizedExisting.length)
|
|
385
387
|
const baselineCount = Math.min(
|
|
386
388
|
targetCandidateCount,
|
|
387
|
-
Math.max(MEMORY_DELTA_MIN_BASELINE_CANDIDATES, newFacts.length *
|
|
389
|
+
Math.max(MEMORY_DELTA_MIN_BASELINE_CANDIDATES, newFacts.length * CANDIDATE_FANOUT_MULTIPLIER),
|
|
388
390
|
)
|
|
389
391
|
|
|
390
392
|
const selectedIds = new Set<string>(
|
|
@@ -502,7 +504,7 @@ export class Memory {
|
|
|
502
504
|
await this.store.addRelation(fromId, toId, relation.relation)
|
|
503
505
|
aiLogger.debug`Created ${relation.relation} relation: ${fromId} -> ${toId}`
|
|
504
506
|
} catch (error) {
|
|
505
|
-
aiLogger.warn`Failed to create relation: ${error}`
|
|
507
|
+
aiLogger.warn`Failed to create memory relation (non-fatal, graph may be incomplete): ${error}`
|
|
506
508
|
}
|
|
507
509
|
}
|
|
508
510
|
}
|
|
@@ -7,6 +7,7 @@ function toSchemaFilePath(value: string | URL): string {
|
|
|
7
7
|
export async function computeSchemaFingerprint(schemaFiles: readonly (string | URL)[]): Promise<string> {
|
|
8
8
|
const hash = createHash('sha256')
|
|
9
9
|
|
|
10
|
+
// Sequential reads required: hash must be computed in deterministic file order
|
|
10
11
|
for (const schemaFile of schemaFiles) {
|
|
11
12
|
const sortKey = toSchemaFilePath(schemaFile)
|
|
12
13
|
const file = schemaFile instanceof URL ? Bun.file(schemaFile.pathname) : Bun.file(schemaFile)
|