@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
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto'
|
|
2
|
+
|
|
1
3
|
import { parseRowMetadata, toTimestamp, withCreatedAtMetadata } from '@lota-sdk/shared'
|
|
2
4
|
import type { ChatMessage } from '@lota-sdk/shared'
|
|
3
5
|
import { RecordId, surql } from 'surrealdb'
|
|
@@ -33,14 +35,21 @@ function toMessageId(value: string | RecordIdRef): string {
|
|
|
33
35
|
return recordIdToString(value, TABLES.WORKSTREAM_MESSAGE)
|
|
34
36
|
}
|
|
35
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Builds a collision-free row id by hashing the workstream + message id pair.
|
|
40
|
+
* Previous implementation replaced non-alphanumeric chars with '_', which was
|
|
41
|
+
* lossy (e.g. "msg:foo" and "msg_foo" mapped to the same row id).
|
|
42
|
+
* Now uses a 32-char SHA-256 hex prefix -- short enough for ergonomic ids,
|
|
43
|
+
* long enough (128 bits) to make collisions negligible.
|
|
44
|
+
*/
|
|
36
45
|
function toWorkstreamMessageRowId(workstreamId: RecordIdRef, messageId: string): RecordId {
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
return new RecordId(TABLES.WORKSTREAM_MESSAGE,
|
|
46
|
+
const workstreamStr = recordIdToString(workstreamId, TABLES.WORKSTREAM)
|
|
47
|
+
const digest = createHash('sha256').update(`${workstreamStr}\0${messageId}`).digest('hex').slice(0, 32)
|
|
48
|
+
return new RecordId(TABLES.WORKSTREAM_MESSAGE, digest)
|
|
40
49
|
}
|
|
41
50
|
|
|
42
51
|
function toChatMessage(row: WorkstreamMessageRow): ChatMessage {
|
|
43
|
-
const rowCreatedAt = toTimestamp(row.createdAt)
|
|
52
|
+
const rowCreatedAt = toTimestamp(row.createdAt) ?? Date.now()
|
|
44
53
|
const metadata = withCreatedAtMetadata(parseRowMetadata(row.metadata), rowCreatedAt)
|
|
45
54
|
|
|
46
55
|
return { id: row.messageId, role: row.role, parts: (row.parts ?? []) as ChatMessage['parts'], metadata }
|
|
@@ -74,16 +83,16 @@ class WorkstreamMessageService {
|
|
|
74
83
|
async upsertMessages(params: { workstreamId: RecordIdRef; messages: ChatMessage[] }): Promise<void> {
|
|
75
84
|
const workstreamId = params.workstreamId
|
|
76
85
|
|
|
77
|
-
|
|
86
|
+
const upsertPromises = params.messages.map(async (message) => {
|
|
78
87
|
const messageId = message.id.trim()
|
|
79
|
-
if (!messageId)
|
|
88
|
+
if (!messageId) return
|
|
80
89
|
|
|
81
90
|
const role = message.role
|
|
82
91
|
const parts = Array.isArray(message.parts)
|
|
83
92
|
? message.parts.map((part) => structuredClone(part) as Record<string, unknown>)
|
|
84
93
|
: []
|
|
85
94
|
if (parts.length === 0) {
|
|
86
|
-
if (role === 'assistant')
|
|
95
|
+
if (role === 'assistant') return
|
|
87
96
|
throw new Error(`Refusing to persist workstream message "${messageId}" with empty parts`)
|
|
88
97
|
}
|
|
89
98
|
const rowId = toWorkstreamMessageRowId(workstreamId, messageId)
|
|
@@ -93,7 +102,9 @@ class WorkstreamMessageService {
|
|
|
93
102
|
WorkstreamMessageExistingRowSchema,
|
|
94
103
|
)
|
|
95
104
|
const persistedCreatedAt =
|
|
96
|
-
existingRow === null
|
|
105
|
+
existingRow === null
|
|
106
|
+
? (toTimestamp(message.metadata?.createdAt) ?? Date.now())
|
|
107
|
+
: (toTimestamp(existingRow.createdAt) ?? Date.now())
|
|
97
108
|
const metadata = withCreatedAtMetadata({ ...message.metadata, createdAt: persistedCreatedAt })
|
|
98
109
|
|
|
99
110
|
await databaseService.upsert(
|
|
@@ -105,12 +116,15 @@ class WorkstreamMessageService {
|
|
|
105
116
|
role,
|
|
106
117
|
parts,
|
|
107
118
|
metadata,
|
|
108
|
-
createdAt: existingRow
|
|
119
|
+
createdAt: existingRow
|
|
120
|
+
? new Date(toTimestamp(existingRow.createdAt) ?? Date.now())
|
|
121
|
+
: new Date(persistedCreatedAt),
|
|
109
122
|
},
|
|
110
123
|
WorkstreamMessageRowSchema,
|
|
111
124
|
{ mutation: 'content' },
|
|
112
125
|
)
|
|
113
|
-
}
|
|
126
|
+
})
|
|
127
|
+
await Promise.all(upsertPromises)
|
|
114
128
|
}
|
|
115
129
|
|
|
116
130
|
async listMessages(workstreamId: RecordIdRef): Promise<ChatMessage[]> {
|
|
@@ -151,7 +165,7 @@ class WorkstreamMessageService {
|
|
|
151
165
|
throw new Error(`Workstream cursor message not found: ${cursorMessageId}`)
|
|
152
166
|
}
|
|
153
167
|
|
|
154
|
-
const cursorCreatedAt = new Date(toTimestamp(cursorRow.createdAt))
|
|
168
|
+
const cursorCreatedAt = new Date(toTimestamp(cursorRow.createdAt) ?? Date.now())
|
|
155
169
|
const cursorId = toWorkstreamMessageRowId(workstreamId, cursorMessageId)
|
|
156
170
|
const rows = await databaseService.query<unknown>(surql`
|
|
157
171
|
SELECT * FROM workstreamMessage
|
|
@@ -195,7 +209,7 @@ class WorkstreamMessageService {
|
|
|
195
209
|
.map((message) => ({
|
|
196
210
|
id: message.id,
|
|
197
211
|
role: message.role as 'user' | 'assistant',
|
|
198
|
-
createdAt: new Date(toTimestamp(message.metadata?.createdAt)).toISOString(),
|
|
212
|
+
createdAt: new Date(toTimestamp(message.metadata?.createdAt) ?? Date.now()).toISOString(),
|
|
199
213
|
content: message.parts
|
|
200
214
|
.flatMap((part) => (part.type === 'text' && typeof part.text === 'string' ? [part.text] : []))
|
|
201
215
|
.join('\n')
|
|
@@ -273,10 +287,6 @@ class WorkstreamMessageService {
|
|
|
273
287
|
async listAllMessages(workstreamId: RecordIdRef): Promise<ChatMessage[]> {
|
|
274
288
|
return await this.listMessages(workstreamId)
|
|
275
289
|
}
|
|
276
|
-
|
|
277
|
-
async addAttachments(): Promise<void> {
|
|
278
|
-
// Attachments are no longer persisted via workstreamMessage service in AI SDK mode.
|
|
279
|
-
}
|
|
280
290
|
}
|
|
281
291
|
|
|
282
292
|
export const workstreamMessageService = new WorkstreamMessageService()
|
|
@@ -3,21 +3,13 @@ import { WORKSTREAM } from '@lota-sdk/shared'
|
|
|
3
3
|
import { chatLogger } from '../config/logger'
|
|
4
4
|
import type { RecordIdRef } from '../db/record-id'
|
|
5
5
|
import { createHelperModelRuntime } from '../runtime/helper-model'
|
|
6
|
-
import { deriveTitle, limitTitleWords } from '../runtime/title-helpers'
|
|
6
|
+
import { deriveTitle, limitTitleWords, normalizeTitle } from '../runtime/title-helpers'
|
|
7
7
|
import {
|
|
8
8
|
createWorkstreamTitleGeneratorAgent,
|
|
9
9
|
WORKSTREAM_TITLE_GENERATOR_PROMPT,
|
|
10
10
|
} from '../system-agents/title-generator.agent'
|
|
11
|
-
import { compactWhitespace } from '../utils/string'
|
|
12
11
|
import { workstreamService } from './workstream.service'
|
|
13
12
|
|
|
14
|
-
function normalizeTitle(value: string): string {
|
|
15
|
-
const normalized = compactWhitespace(value)
|
|
16
|
-
.replace(/^["'`]+|["'`]+$/g, '')
|
|
17
|
-
.replace(/[.!?,;:]+$/g, '')
|
|
18
|
-
return normalized.length <= 80 ? normalized : normalized.slice(0, 80).trim()
|
|
19
|
-
}
|
|
20
|
-
|
|
21
13
|
class WorkstreamTitleService {
|
|
22
14
|
helperRuntime = createHelperModelRuntime()
|
|
23
15
|
|