@lota-sdk/core 0.4.7 → 0.4.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +11 -12
- package/src/ai/embedding-cache.ts +94 -22
- package/src/ai-gateway/ai-gateway.ts +738 -223
- package/src/config/agent-defaults.ts +176 -75
- package/src/config/agent-types.ts +54 -4
- package/src/config/constants.ts +8 -2
- package/src/config/logger.ts +286 -19
- package/src/config/model-constants.ts +1 -0
- package/src/config/thread-defaults.ts +33 -21
- package/src/create-runtime.ts +725 -383
- package/src/db/base.service.ts +52 -28
- package/src/db/cursor-pagination.ts +71 -30
- package/src/db/memory-store.helpers.ts +4 -7
- package/src/db/memory-store.ts +856 -598
- package/src/db/memory.ts +398 -275
- package/src/db/record-id.ts +32 -10
- package/src/db/schema-fingerprint.ts +30 -12
- package/src/db/service-normalization.ts +255 -0
- package/src/db/service.ts +726 -761
- package/src/db/startup.ts +140 -66
- package/src/db/transaction-conflict.ts +15 -0
- package/src/effect/awaitable-effect.ts +87 -0
- package/src/effect/errors.ts +121 -0
- package/src/effect/helpers.ts +98 -0
- package/src/effect/index.ts +22 -0
- package/src/effect/layers.ts +228 -0
- package/src/effect/runtime-ref.ts +25 -0
- package/src/effect/runtime.ts +31 -0
- package/src/effect/services.ts +57 -0
- package/src/effect/zod.ts +43 -0
- package/src/embeddings/provider.ts +122 -71
- package/src/index.ts +46 -1
- package/src/openrouter/direct-provider.ts +29 -0
- package/src/queues/autonomous-job.queue.ts +130 -74
- package/src/queues/context-compaction.queue.ts +60 -15
- package/src/queues/delayed-node-promotion.queue.ts +52 -15
- package/src/queues/document-processor.queue.ts +52 -77
- package/src/queues/memory-consolidation.queue.ts +47 -32
- package/src/queues/organization-learning.queue.ts +13 -4
- package/src/queues/plan-agent-heartbeat.queue.ts +65 -21
- package/src/queues/plan-scheduler.queue.ts +107 -31
- package/src/queues/post-chat-memory.queue.ts +66 -24
- package/src/queues/queue-factory.ts +142 -52
- package/src/queues/standalone-worker.ts +39 -0
- package/src/queues/title-generation.queue.ts +54 -9
- package/src/redis/connection.ts +84 -32
- package/src/redis/index.ts +6 -8
- package/src/redis/org-memory-lock.ts +60 -27
- package/src/redis/redis-lease-lock.ts +200 -121
- package/src/redis/runtime-connection.ts +10 -0
- package/src/redis/stream-context.ts +84 -46
- package/src/runtime/agent-identity-overrides.ts +2 -2
- package/src/runtime/agent-runtime-policy.ts +4 -1
- package/src/runtime/agent-stream-helpers.ts +20 -9
- package/src/runtime/chat-run-orchestration.ts +102 -19
- package/src/runtime/chat-run-registry.ts +36 -2
- package/src/runtime/context-compaction/context-compaction-runtime.ts +107 -0
- package/src/runtime/{context-compaction.ts → context-compaction/context-compaction.ts} +114 -91
- package/src/runtime/execution-plan-visibility.ts +2 -2
- package/src/runtime/execution-plan.ts +42 -15
- package/src/runtime/graph-designer.ts +11 -7
- package/src/runtime/helper-model.ts +135 -48
- package/src/runtime/index.ts +7 -7
- package/src/runtime/indexed-repositories-policy.ts +3 -3
- package/src/runtime/{memory-block.ts → memory/memory-block.ts} +40 -36
- package/src/runtime/{memory-digest-policy.ts → memory/memory-digest-policy.ts} +1 -1
- package/src/runtime/{memory-pipeline.ts → memory/memory-pipeline.ts} +1 -1
- package/src/runtime/{memory-prompts-fact.ts → memory/memory-prompts-fact.ts} +2 -2
- package/src/runtime/{memory-scope.ts → memory/memory-scope.ts} +12 -6
- package/src/runtime/plugin-resolution.ts +144 -24
- package/src/runtime/plugin-types.ts +9 -1
- package/src/runtime/post-turn-side-effects.ts +197 -130
- package/src/runtime/retrieval-adapters.ts +38 -4
- package/src/runtime/runtime-config.ts +165 -61
- package/src/runtime/runtime-extensions.ts +21 -34
- package/src/runtime/social-chat/social-chat-agent-runner.ts +157 -0
- package/src/runtime/{social-chat-history.ts → social-chat/social-chat-history.ts} +42 -20
- package/src/runtime/social-chat/social-chat.ts +594 -0
- package/src/runtime/specialist-runner.ts +36 -10
- package/src/runtime/team-consultation/team-consultation-orchestrator.ts +427 -0
- package/src/runtime/{team-consultation-prompts.ts → team-consultation/team-consultation-prompts.ts} +6 -2
- package/src/runtime/thread-chat-helpers.ts +2 -2
- package/src/runtime/thread-plan-turn.ts +2 -1
- package/src/runtime/thread-turn-context.ts +172 -94
- package/src/runtime/turn-lifecycle.ts +93 -27
- package/src/services/agent-activity.service.ts +287 -203
- package/src/services/agent-executor.service.ts +329 -217
- package/src/services/artifact.service.ts +225 -148
- package/src/services/attachment.service.ts +137 -115
- package/src/services/autonomous-job.service.ts +888 -491
- package/src/services/chat-run-registry.service.ts +11 -1
- package/src/services/context-compaction.service.ts +136 -86
- package/src/services/document-chunk.service.ts +162 -90
- package/src/services/execution-plan/execution-plan-approval.ts +26 -0
- package/src/services/execution-plan/execution-plan-context.ts +29 -0
- package/src/services/execution-plan/execution-plan-graph.ts +256 -0
- package/src/services/execution-plan/execution-plan-schedule.ts +84 -0
- package/src/services/execution-plan/execution-plan-spec.ts +75 -0
- package/src/services/execution-plan/execution-plan.service.ts +1041 -0
- package/src/services/feedback-loop.service.ts +132 -76
- package/src/services/global-orchestrator.service.ts +80 -170
- package/src/services/graph-full-routing.ts +182 -0
- package/src/services/index.ts +18 -20
- package/src/services/institutional-memory.service.ts +220 -123
- package/src/services/learned-skill.service.ts +364 -259
- package/src/services/memory/memory-conversation.ts +95 -0
- package/src/services/memory/memory-org-memory.ts +39 -0
- package/src/services/memory/memory-preseeded.ts +80 -0
- package/src/services/memory/memory-rerank.ts +297 -0
- package/src/services/{memory-utils.ts → memory/memory-utils.ts} +5 -5
- package/src/services/memory/memory.service.ts +692 -0
- package/src/services/memory/rerank.service.ts +209 -0
- package/src/services/monitoring-window.service.ts +92 -70
- package/src/services/mutating-approval.service.ts +62 -53
- package/src/services/node-workspace.service.ts +141 -98
- package/src/services/notification.service.ts +17 -16
- package/src/services/organization-member.service.ts +120 -66
- package/src/services/organization.service.ts +144 -51
- package/src/services/ownership-dispatcher.service.ts +415 -264
- package/src/services/plan/plan-agent-heartbeat.service.ts +234 -0
- package/src/services/plan/plan-agent-query.service.ts +322 -0
- package/src/services/plan/plan-approval.service.ts +102 -0
- package/src/services/plan/plan-artifact.service.ts +60 -0
- package/src/services/plan/plan-builder.service.ts +76 -0
- package/src/services/plan/plan-checkpoint.service.ts +103 -0
- package/src/services/{plan-compiler.service.ts → plan/plan-compiler.service.ts} +26 -9
- package/src/services/plan/plan-completion-side-effects.ts +175 -0
- package/src/services/plan/plan-coordination.service.ts +181 -0
- package/src/services/plan/plan-cycle.service.ts +398 -0
- package/src/services/plan/plan-deadline.service.ts +547 -0
- package/src/services/plan/plan-event-delivery.service.ts +261 -0
- package/src/services/plan/plan-executor-context.ts +35 -0
- package/src/services/plan/plan-executor-graph.ts +475 -0
- package/src/services/plan/plan-executor-helpers.ts +322 -0
- package/src/services/plan/plan-executor-persistence.ts +209 -0
- package/src/services/plan/plan-executor.service.ts +1654 -0
- package/src/services/{plan-helpers.ts → plan/plan-helpers.ts} +1 -1
- package/src/services/{plan-run-data.ts → plan/plan-run-data.ts} +4 -4
- package/src/services/plan/plan-run-serialization.ts +15 -0
- package/src/services/plan/plan-run.service.ts +644 -0
- package/src/services/plan/plan-scheduler.service.ts +385 -0
- package/src/services/plan/plan-template.service.ts +224 -0
- package/src/services/plan/plan-transaction-events.ts +33 -0
- package/src/services/plan/plan-validator.service.ts +907 -0
- package/src/services/plan/plan-workspace.service.ts +125 -0
- package/src/services/plugin-executor.service.ts +97 -68
- package/src/services/quality-metrics.service.ts +112 -94
- package/src/services/queue-job.service.ts +296 -230
- package/src/services/recent-activity-title.service.ts +65 -36
- package/src/services/recent-activity.service.ts +274 -259
- package/src/services/skill-resolver.service.ts +38 -12
- package/src/services/social-chat-history.service.ts +176 -125
- package/src/services/system-executor.service.ts +91 -61
- package/src/services/thread/thread-active-run.ts +203 -0
- package/src/services/thread/thread-bootstrap.ts +369 -0
- package/src/services/thread/thread-listing.ts +198 -0
- package/src/services/thread/thread-memory-block.ts +117 -0
- package/src/services/thread/thread-message.service.ts +363 -0
- package/src/services/thread/thread-record-store.ts +155 -0
- package/src/services/thread/thread-title.service.ts +74 -0
- package/src/services/thread/thread-turn-execution.ts +280 -0
- package/src/services/thread/thread-turn-message-context.ts +73 -0
- package/src/services/thread/thread-turn-preparation.service.ts +1146 -0
- package/src/services/thread/thread-turn-streaming.ts +402 -0
- package/src/services/thread/thread-turn-tracing.ts +35 -0
- package/src/services/thread/thread-turn.ts +343 -0
- package/src/services/thread/thread.service.ts +335 -0
- package/src/services/user.service.ts +82 -32
- package/src/services/write-intent-validator.service.ts +63 -51
- package/src/storage/attachment-parser.ts +69 -27
- package/src/storage/attachment-storage.service.ts +331 -275
- package/src/storage/generated-document-storage.service.ts +66 -34
- package/src/system-agents/agent-result.ts +3 -1
- package/src/system-agents/context-compaction.agent.ts +2 -2
- package/src/system-agents/delegated-agent-factory.ts +159 -90
- package/src/system-agents/memory-reranker.agent.ts +2 -2
- package/src/system-agents/memory.agent.ts +2 -2
- package/src/system-agents/recent-activity-title-refiner.agent.ts +2 -2
- package/src/system-agents/regular-chat-memory-digest.agent.ts +2 -2
- package/src/system-agents/skill-extractor.agent.ts +2 -2
- package/src/system-agents/skill-manager.agent.ts +2 -2
- package/src/system-agents/thread-router.agent.ts +157 -113
- package/src/system-agents/title-generator.agent.ts +2 -2
- package/src/tools/execution-plan.tool.ts +220 -161
- package/src/tools/fetch-webpage.tool.ts +21 -17
- package/src/tools/firecrawl-client.ts +16 -6
- package/src/tools/index.ts +1 -0
- package/src/tools/memory-block.tool.ts +14 -6
- package/src/tools/plan-approval.tool.ts +49 -47
- package/src/tools/read-file-parts.tool.ts +44 -33
- package/src/tools/remember-memory.tool.ts +65 -45
- package/src/tools/search-web.tool.ts +26 -22
- package/src/tools/search.tool.ts +41 -29
- package/src/tools/team-think.tool.ts +124 -83
- package/src/tools/user-questions.tool.ts +4 -3
- package/src/tools/web-tool-shared.ts +6 -0
- package/src/utils/async.ts +17 -23
- package/src/utils/crypto.ts +21 -0
- package/src/utils/date-time.ts +40 -1
- package/src/utils/errors.ts +95 -16
- package/src/utils/hono-error-handler.ts +24 -39
- package/src/utils/index.ts +2 -1
- package/src/utils/null-proto-record.ts +41 -0
- package/src/utils/sse-keepalive.ts +124 -21
- package/src/workers/bootstrap.ts +186 -51
- package/src/workers/memory-consolidation.worker.ts +325 -237
- package/src/workers/organization-learning.worker.ts +50 -16
- package/src/workers/regular-chat-memory-digest.helpers.ts +28 -27
- package/src/workers/regular-chat-memory-digest.runner.ts +175 -114
- package/src/workers/skill-extraction.runner.ts +176 -93
- package/src/workers/utils/file-section-chunker.ts +8 -10
- package/src/workers/utils/repo-structure-extractor.ts +349 -260
- package/src/workers/utils/repomix-file-sections.ts +2 -2
- package/src/workers/utils/thread-message-query.ts +97 -38
- package/src/workers/worker-utils.ts +56 -31
- package/src/config/debug-logger.ts +0 -47
- package/src/redis/connection-accessor.ts +0 -26
- package/src/runtime/context-compaction-runtime.ts +0 -87
- package/src/runtime/social-chat-agent-runner.ts +0 -118
- package/src/runtime/social-chat.ts +0 -516
- package/src/runtime/team-consultation-orchestrator.ts +0 -272
- package/src/services/adaptive-playbook.service.ts +0 -152
- package/src/services/artifact-provenance.service.ts +0 -172
- package/src/services/chat-attachments.service.ts +0 -17
- package/src/services/context-compaction-runtime.singleton.ts +0 -13
- package/src/services/execution-plan.service.ts +0 -1118
- package/src/services/memory.service.ts +0 -844
- package/src/services/plan-agent-heartbeat.service.ts +0 -136
- package/src/services/plan-agent-query.service.ts +0 -267
- package/src/services/plan-approval.service.ts +0 -83
- package/src/services/plan-artifact.service.ts +0 -50
- package/src/services/plan-builder.service.ts +0 -67
- package/src/services/plan-checkpoint.service.ts +0 -81
- package/src/services/plan-completion-side-effects.ts +0 -80
- package/src/services/plan-coordination.service.ts +0 -157
- package/src/services/plan-cycle.service.ts +0 -284
- package/src/services/plan-deadline.service.ts +0 -430
- package/src/services/plan-event-delivery.service.ts +0 -166
- package/src/services/plan-executor.service.ts +0 -1950
- package/src/services/plan-run.service.ts +0 -515
- package/src/services/plan-scheduler.service.ts +0 -240
- package/src/services/plan-template.service.ts +0 -177
- package/src/services/plan-validator.service.ts +0 -818
- package/src/services/plan-workspace.service.ts +0 -83
- package/src/services/thread-message.service.ts +0 -275
- package/src/services/thread-plan-registry.service.ts +0 -22
- package/src/services/thread-title.service.ts +0 -39
- package/src/services/thread-turn-preparation.service.ts +0 -1147
- package/src/services/thread-turn.ts +0 -172
- package/src/services/thread.service.ts +0 -869
- package/src/utils/env.ts +0 -8
- /package/src/runtime/{context-compaction-constants.ts → context-compaction/context-compaction-constants.ts} +0 -0
- /package/src/runtime/{memory-format.ts → memory/memory-format.ts} +0 -0
- /package/src/runtime/{memory-prompts-parse.ts → memory/memory-prompts-parse.ts} +0 -0
- /package/src/runtime/{memory-prompts-update.ts → memory/memory-prompts-update.ts} +0 -0
- /package/src/runtime/{social-chat-prompts.ts → social-chat/social-chat-prompts.ts} +0 -0
- /package/src/services/{plan-node-spec.ts → plan/plan-node-spec.ts} +0 -0
- /package/src/services/{thread-constants.ts → thread/thread-constants.ts} +0 -0
- /package/src/services/{thread.types.ts → thread/thread.types.ts} +0 -0
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod'
|
|
2
|
-
|
|
3
|
-
import { getRedisConnection } from '../redis'
|
|
4
|
-
|
|
5
|
-
const PlanWorkspaceEntrySchema = z.object({
|
|
6
|
-
value: z.unknown(),
|
|
7
|
-
version: z.number(),
|
|
8
|
-
writeSequence: z.number(),
|
|
9
|
-
nodeId: z.string(),
|
|
10
|
-
timestamp: z.number(),
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
export type PlanWorkspaceEntry = z.infer<typeof PlanWorkspaceEntrySchema>
|
|
14
|
-
|
|
15
|
-
class PlanWorkspaceService {
|
|
16
|
-
private keyPrefix = 'plan-workspace:'
|
|
17
|
-
|
|
18
|
-
async write(params: {
|
|
19
|
-
runId: string
|
|
20
|
-
nodeId: string
|
|
21
|
-
key: string
|
|
22
|
-
value: unknown
|
|
23
|
-
version: number
|
|
24
|
-
checkpointSequence: number
|
|
25
|
-
}): Promise<void> {
|
|
26
|
-
const redis = getRedisConnection()
|
|
27
|
-
const hashKey = `${this.keyPrefix}${params.runId}`
|
|
28
|
-
const fieldKey = `${params.nodeId}:${params.key}`
|
|
29
|
-
const entry: PlanWorkspaceEntry = {
|
|
30
|
-
value: params.value,
|
|
31
|
-
version: params.version,
|
|
32
|
-
writeSequence: params.checkpointSequence,
|
|
33
|
-
nodeId: params.nodeId,
|
|
34
|
-
timestamp: Date.now(),
|
|
35
|
-
}
|
|
36
|
-
await redis.hset(hashKey, fieldKey, JSON.stringify(entry))
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async snapshotRead(params: {
|
|
40
|
-
runId: string
|
|
41
|
-
readerNodeId: string
|
|
42
|
-
snapshotSequence?: number
|
|
43
|
-
}): Promise<Record<string, PlanWorkspaceEntry>> {
|
|
44
|
-
const redis = getRedisConnection()
|
|
45
|
-
const hashKey = `${this.keyPrefix}${params.runId}`
|
|
46
|
-
const nodePrefix = `${params.readerNodeId}:`
|
|
47
|
-
const all = await redis.hgetall(hashKey)
|
|
48
|
-
const result: Record<string, PlanWorkspaceEntry> = {}
|
|
49
|
-
for (const [fieldKey, raw] of Object.entries(all)) {
|
|
50
|
-
if (!fieldKey.startsWith(nodePrefix)) continue
|
|
51
|
-
const entry = PlanWorkspaceEntrySchema.parse(JSON.parse(raw))
|
|
52
|
-
if (params.snapshotSequence !== undefined && entry.writeSequence > params.snapshotSequence) {
|
|
53
|
-
continue
|
|
54
|
-
}
|
|
55
|
-
result[fieldKey] = entry
|
|
56
|
-
}
|
|
57
|
-
return result
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
async currentRead(params: { runId: string; key?: string }): Promise<Record<string, PlanWorkspaceEntry>> {
|
|
61
|
-
const redis = getRedisConnection()
|
|
62
|
-
const hashKey = `${this.keyPrefix}${params.runId}`
|
|
63
|
-
if (params.key) {
|
|
64
|
-
// Support both raw field keys (e.g. 'nodeId:key') and plain keys
|
|
65
|
-
const raw = await redis.hget(hashKey, params.key)
|
|
66
|
-
if (!raw) return {}
|
|
67
|
-
return { [params.key]: PlanWorkspaceEntrySchema.parse(JSON.parse(raw)) }
|
|
68
|
-
}
|
|
69
|
-
const all = await redis.hgetall(hashKey)
|
|
70
|
-
const result: Record<string, PlanWorkspaceEntry> = {}
|
|
71
|
-
for (const [k, v] of Object.entries(all)) {
|
|
72
|
-
result[k] = PlanWorkspaceEntrySchema.parse(JSON.parse(v))
|
|
73
|
-
}
|
|
74
|
-
return result
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
async cleanup(runId: string): Promise<void> {
|
|
78
|
-
const redis = getRedisConnection()
|
|
79
|
-
await redis.del(`${this.keyPrefix}${runId}`)
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export const planWorkspaceService = new PlanWorkspaceService()
|
|
@@ -1,275 +0,0 @@
|
|
|
1
|
-
import { parseRowMetadata, recordIdSchema, requireTimestamp, withCreatedAtMetadata } from '@lota-sdk/shared'
|
|
2
|
-
import type { ChatMessage } from '@lota-sdk/shared'
|
|
3
|
-
import { RecordId, surql } from 'surrealdb'
|
|
4
|
-
import { z } from 'zod'
|
|
5
|
-
|
|
6
|
-
import { agentDisplayNames } from '../config/agent-defaults'
|
|
7
|
-
import { CursorRowSchema, listMessageHistoryPage } from '../db/cursor-pagination'
|
|
8
|
-
import type { CursorPaginationConfig, MessageHistoryPage } from '../db/cursor-pagination'
|
|
9
|
-
import { ensureRecordId, recordIdToString } from '../db/record-id'
|
|
10
|
-
import type { RecordIdRef } from '../db/record-id'
|
|
11
|
-
import { databaseService } from '../db/service'
|
|
12
|
-
import { TABLES } from '../db/tables'
|
|
13
|
-
import { ThreadMessageRowSchema } from '../db/thread-message-row'
|
|
14
|
-
import type { ThreadMessageRow } from '../db/thread-message-row'
|
|
15
|
-
|
|
16
|
-
const ThreadMessageExistingRowSchema = z.object({ id: recordIdSchema, createdAt: z.coerce.date() })
|
|
17
|
-
|
|
18
|
-
function toMessageId(value: string | RecordIdRef): string {
|
|
19
|
-
return recordIdToString(value, TABLES.THREAD_MESSAGE)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Builds a collision-free row id by hashing the thread + message id pair.
|
|
24
|
-
* Previous implementation replaced non-alphanumeric chars with '_', which was
|
|
25
|
-
* lossy (e.g. "msg:foo" and "msg_foo" mapped to the same row id).
|
|
26
|
-
* Now uses a 32-char SHA-256 hex prefix -- short enough for ergonomic ids,
|
|
27
|
-
* long enough (128 bits) to make collisions negligible.
|
|
28
|
-
*/
|
|
29
|
-
function toThreadMessageRowId(threadId: RecordIdRef, messageId: string): RecordId {
|
|
30
|
-
const threadStr = recordIdToString(threadId, TABLES.THREAD)
|
|
31
|
-
const digest = new Bun.CryptoHasher('sha256').update(`${threadStr}\0${messageId}`).digest('hex').slice(0, 32)
|
|
32
|
-
return new RecordId(TABLES.THREAD_MESSAGE, digest)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function toThreadRef(threadId: RecordIdRef): RecordId {
|
|
36
|
-
return ensureRecordId(threadId, TABLES.THREAD)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function toChatMessage(row: ThreadMessageRow): ChatMessage {
|
|
40
|
-
const rowCreatedAt = requireTimestamp(row.createdAt)
|
|
41
|
-
const metadata = withCreatedAtMetadata(parseRowMetadata(row.metadata), rowCreatedAt)
|
|
42
|
-
|
|
43
|
-
return { id: row.messageId, role: row.role, parts: row.parts as ChatMessage['parts'], metadata }
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const threadPaginationConfig: CursorPaginationConfig = {
|
|
47
|
-
table: TABLES.THREAD_MESSAGE,
|
|
48
|
-
parentFilterField: 'threadId',
|
|
49
|
-
toRowId: toThreadMessageRowId,
|
|
50
|
-
parseRow: (row: unknown) => ThreadMessageRowSchema.parse(row),
|
|
51
|
-
toMessage: (row: unknown) => toChatMessage(ThreadMessageRowSchema.parse(row)),
|
|
52
|
-
queryLatest: (parentId, limit) => surql`
|
|
53
|
-
SELECT * FROM threadMessage
|
|
54
|
-
WHERE threadId = ${parentId}
|
|
55
|
-
ORDER BY createdAt DESC, id DESC
|
|
56
|
-
LIMIT ${limit}
|
|
57
|
-
`,
|
|
58
|
-
queryBefore: (parentId, cursorCreatedAt, cursorId, limit) => surql`
|
|
59
|
-
SELECT * FROM threadMessage
|
|
60
|
-
WHERE threadId = ${parentId}
|
|
61
|
-
AND (
|
|
62
|
-
createdAt < ${cursorCreatedAt}
|
|
63
|
-
OR (createdAt = ${cursorCreatedAt} AND id < ${cursorId})
|
|
64
|
-
)
|
|
65
|
-
ORDER BY createdAt DESC, id DESC
|
|
66
|
-
LIMIT ${limit}
|
|
67
|
-
`,
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
class ThreadMessageService {
|
|
71
|
-
async upsertMessages(params: { threadId: RecordIdRef; messages: ChatMessage[] }): Promise<void> {
|
|
72
|
-
const threadId = toThreadRef(params.threadId)
|
|
73
|
-
|
|
74
|
-
const upsertPromises = params.messages.map(async (message) => {
|
|
75
|
-
const messageId = message.id.trim()
|
|
76
|
-
if (!messageId) return
|
|
77
|
-
|
|
78
|
-
const role = message.role
|
|
79
|
-
const parts = Array.isArray(message.parts)
|
|
80
|
-
? message.parts.map((part) => structuredClone(part) as Record<string, unknown>)
|
|
81
|
-
: []
|
|
82
|
-
if (parts.length === 0) {
|
|
83
|
-
if (role === 'assistant') return
|
|
84
|
-
throw new Error(`Refusing to persist thread message "${messageId}" with empty parts`)
|
|
85
|
-
}
|
|
86
|
-
const rowId = toThreadMessageRowId(threadId, messageId)
|
|
87
|
-
const existingRow = await databaseService.findOne(
|
|
88
|
-
TABLES.THREAD_MESSAGE,
|
|
89
|
-
{ threadId, messageId },
|
|
90
|
-
ThreadMessageExistingRowSchema,
|
|
91
|
-
)
|
|
92
|
-
const persistedCreatedAt =
|
|
93
|
-
existingRow === null ? requireTimestamp(message.metadata?.createdAt) : requireTimestamp(existingRow.createdAt)
|
|
94
|
-
const metadata = withCreatedAtMetadata({ ...message.metadata, createdAt: persistedCreatedAt })
|
|
95
|
-
|
|
96
|
-
await databaseService.upsert(
|
|
97
|
-
TABLES.THREAD_MESSAGE,
|
|
98
|
-
rowId,
|
|
99
|
-
{
|
|
100
|
-
threadId,
|
|
101
|
-
messageId,
|
|
102
|
-
role,
|
|
103
|
-
parts,
|
|
104
|
-
metadata,
|
|
105
|
-
createdAt: existingRow ? existingRow.createdAt : new Date(persistedCreatedAt),
|
|
106
|
-
},
|
|
107
|
-
ThreadMessageRowSchema,
|
|
108
|
-
{ mutation: 'content' },
|
|
109
|
-
)
|
|
110
|
-
})
|
|
111
|
-
await Promise.all(upsertPromises)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
async listMessages(threadId: RecordIdRef): Promise<ChatMessage[]> {
|
|
115
|
-
const threadRef = toThreadRef(threadId)
|
|
116
|
-
const rows = await databaseService.query<unknown>(surql`
|
|
117
|
-
SELECT * FROM threadMessage
|
|
118
|
-
WHERE threadId = ${threadRef}
|
|
119
|
-
ORDER BY createdAt ASC, id ASC
|
|
120
|
-
`)
|
|
121
|
-
|
|
122
|
-
return rows.map((row) => ThreadMessageRowSchema.parse(row)).map((row) => toChatMessage(row))
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
async listMessageHistoryPage(params: {
|
|
126
|
-
threadId: RecordIdRef
|
|
127
|
-
take: number
|
|
128
|
-
beforeMessageId?: string
|
|
129
|
-
}): Promise<MessageHistoryPage> {
|
|
130
|
-
const threadRef = toThreadRef(params.threadId)
|
|
131
|
-
return listMessageHistoryPage(threadPaginationConfig, {
|
|
132
|
-
parentId: threadRef,
|
|
133
|
-
take: params.take,
|
|
134
|
-
beforeMessageId: params.beforeMessageId,
|
|
135
|
-
})
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
async listMessagesAfterCursor(threadId: RecordIdRef, afterMessageId?: string): Promise<ChatMessage[]> {
|
|
139
|
-
const threadRef = toThreadRef(threadId)
|
|
140
|
-
const cursorMessageId = afterMessageId?.trim()
|
|
141
|
-
if (!cursorMessageId) {
|
|
142
|
-
return this.listMessages(threadRef)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const cursorRow = await databaseService.findOne(
|
|
146
|
-
TABLES.THREAD_MESSAGE,
|
|
147
|
-
{ threadId: threadRef, messageId: cursorMessageId },
|
|
148
|
-
CursorRowSchema,
|
|
149
|
-
)
|
|
150
|
-
|
|
151
|
-
if (!cursorRow) {
|
|
152
|
-
throw new Error(`Thread cursor message not found: ${cursorMessageId}`)
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const cursorCreatedAt = cursorRow.createdAt
|
|
156
|
-
const cursorId = toThreadMessageRowId(threadRef, cursorMessageId)
|
|
157
|
-
const rows = await databaseService.query<unknown>(surql`
|
|
158
|
-
SELECT * FROM threadMessage
|
|
159
|
-
WHERE threadId = ${threadRef}
|
|
160
|
-
AND (
|
|
161
|
-
createdAt > ${cursorCreatedAt}
|
|
162
|
-
OR (createdAt = ${cursorCreatedAt} AND id > ${cursorId})
|
|
163
|
-
)
|
|
164
|
-
ORDER BY createdAt ASC, id ASC
|
|
165
|
-
`)
|
|
166
|
-
|
|
167
|
-
return rows.map((row) => ThreadMessageRowSchema.parse(row)).map((row) => toChatMessage(row))
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
async listRecentMessages(threadId: RecordIdRef, limit: number): Promise<ChatMessage[]> {
|
|
171
|
-
const threadRef = toThreadRef(threadId)
|
|
172
|
-
const rows = await databaseService.query<unknown>(surql`
|
|
173
|
-
SELECT * FROM threadMessage
|
|
174
|
-
WHERE threadId = ${threadRef}
|
|
175
|
-
ORDER BY createdAt DESC, id DESC
|
|
176
|
-
LIMIT ${Math.max(1, limit)}
|
|
177
|
-
`)
|
|
178
|
-
|
|
179
|
-
return rows
|
|
180
|
-
.map((row) => ThreadMessageRowSchema.parse(row))
|
|
181
|
-
.reverse()
|
|
182
|
-
.map((row) => toChatMessage(row))
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
async searchMessages(params: {
|
|
186
|
-
threadId: RecordIdRef
|
|
187
|
-
role: 'user' | 'assistant'
|
|
188
|
-
query: string
|
|
189
|
-
limit: number
|
|
190
|
-
}): Promise<Array<{ id: string; role: 'user' | 'assistant'; createdAt: string; content: string }>> {
|
|
191
|
-
const normalizedQuery = params.query.trim().toLowerCase()
|
|
192
|
-
if (!normalizedQuery) return []
|
|
193
|
-
|
|
194
|
-
const messages = await this.listMessages(toThreadRef(params.threadId))
|
|
195
|
-
return messages
|
|
196
|
-
.filter((message) => message.role === params.role)
|
|
197
|
-
.map((message) => ({
|
|
198
|
-
id: message.id,
|
|
199
|
-
role: message.role as 'user' | 'assistant',
|
|
200
|
-
createdAt: new Date(requireTimestamp(message.metadata?.createdAt)).toISOString(),
|
|
201
|
-
content: message.parts
|
|
202
|
-
.flatMap((part) => (part.type === 'text' && typeof part.text === 'string' ? [part.text] : []))
|
|
203
|
-
.join('\n')
|
|
204
|
-
.trim(),
|
|
205
|
-
}))
|
|
206
|
-
.filter((item) => item.content.length > 0 && item.content.toLowerCase().includes(normalizedQuery))
|
|
207
|
-
.slice(-Math.max(1, params.limit))
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
async addUserMessage(params: {
|
|
211
|
-
messageId: RecordIdRef
|
|
212
|
-
threadId: RecordIdRef
|
|
213
|
-
content: string
|
|
214
|
-
}): Promise<ChatMessage> {
|
|
215
|
-
const threadRef = toThreadRef(params.threadId)
|
|
216
|
-
const message: ChatMessage = {
|
|
217
|
-
id: toMessageId(params.messageId),
|
|
218
|
-
role: 'user',
|
|
219
|
-
parts: [{ type: 'text', text: params.content }],
|
|
220
|
-
metadata: { createdAt: Date.now() },
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
await this.upsertMessages({ threadId: threadRef, messages: [message] })
|
|
224
|
-
return message
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
async addAgentMessage(params: {
|
|
228
|
-
messageId: RecordIdRef
|
|
229
|
-
threadId: RecordIdRef
|
|
230
|
-
parts: ChatMessage['parts']
|
|
231
|
-
metadata?: ChatMessage['metadata']
|
|
232
|
-
}): Promise<ChatMessage> {
|
|
233
|
-
const threadRef = toThreadRef(params.threadId)
|
|
234
|
-
const message: ChatMessage = {
|
|
235
|
-
id: toMessageId(params.messageId),
|
|
236
|
-
role: 'assistant',
|
|
237
|
-
parts: params.parts,
|
|
238
|
-
metadata: withCreatedAtMetadata(params.metadata, Date.now()),
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
await this.upsertMessages({ threadId: threadRef, messages: [message] })
|
|
242
|
-
return message
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
async ensureBootstrapWelcomeMessage(params: { threadId: RecordIdRef; agentId: string; text: string }): Promise<void> {
|
|
246
|
-
const threadRef = toThreadRef(params.threadId)
|
|
247
|
-
const existingRow = await databaseService.findOne(
|
|
248
|
-
TABLES.THREAD_MESSAGE,
|
|
249
|
-
{ threadId: threadRef },
|
|
250
|
-
ThreadMessageExistingRowSchema,
|
|
251
|
-
)
|
|
252
|
-
if (existingRow) return
|
|
253
|
-
|
|
254
|
-
const messageText = params.text.trim()
|
|
255
|
-
if (!messageText) return
|
|
256
|
-
|
|
257
|
-
await this.upsertMessages({
|
|
258
|
-
threadId: threadRef,
|
|
259
|
-
messages: [
|
|
260
|
-
{
|
|
261
|
-
id: Bun.randomUUIDv7(),
|
|
262
|
-
role: 'assistant',
|
|
263
|
-
parts: [{ type: 'text', text: messageText }],
|
|
264
|
-
metadata: {
|
|
265
|
-
agentId: params.agentId,
|
|
266
|
-
agentName: agentDisplayNames[params.agentId] ?? params.agentId,
|
|
267
|
-
createdAt: Date.now(),
|
|
268
|
-
},
|
|
269
|
-
},
|
|
270
|
-
],
|
|
271
|
-
})
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
export const threadMessageService = new ThreadMessageService()
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { PlanRunRecord, SerializableExecutionPlan } from '@lota-sdk/shared'
|
|
2
|
-
|
|
3
|
-
import type { RecordIdInput } from '../db/record-id'
|
|
4
|
-
import { planRunService } from './plan-run.service'
|
|
5
|
-
|
|
6
|
-
class ThreadPlanRegistryService {
|
|
7
|
-
async listActiveRuns(threadId: RecordIdInput): Promise<PlanRunRecord[]> {
|
|
8
|
-
return planRunService.getActiveRunRecords(threadId)
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
async countActiveRuns(threadId: RecordIdInput): Promise<number> {
|
|
12
|
-
const runs = await this.listActiveRuns(threadId)
|
|
13
|
-
return runs.length
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
async listActivePlans(threadId: RecordIdInput): Promise<SerializableExecutionPlan[]> {
|
|
17
|
-
const runs = await this.listActiveRuns(threadId)
|
|
18
|
-
return Promise.all(runs.map((run) => planRunService.toSerializablePlan(run)))
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export const threadPlanRegistryService = new ThreadPlanRegistryService()
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { THREAD } from '@lota-sdk/shared'
|
|
2
|
-
|
|
3
|
-
import { chatLogger } from '../config/logger'
|
|
4
|
-
import type { RecordIdRef } from '../db/record-id'
|
|
5
|
-
import { createHelperModelRuntime } from '../runtime/helper-model'
|
|
6
|
-
import { deriveTitle, limitTitleWords, normalizeTitle } from '../runtime/title-helpers'
|
|
7
|
-
import { createThreadTitleGeneratorAgent, THREAD_TITLE_GENERATOR_PROMPT } from '../system-agents/title-generator.agent'
|
|
8
|
-
import { threadService } from './thread.service'
|
|
9
|
-
|
|
10
|
-
const THREAD_TITLE_TIMEOUT_MS = 30_000
|
|
11
|
-
|
|
12
|
-
class ThreadTitleService {
|
|
13
|
-
helperRuntime = createHelperModelRuntime()
|
|
14
|
-
|
|
15
|
-
async generateAndPersistTitle(threadId: RecordIdRef, sourceText: string): Promise<void> {
|
|
16
|
-
let title = ''
|
|
17
|
-
try {
|
|
18
|
-
title = normalizeTitle(
|
|
19
|
-
await this.helperRuntime.generateHelperText({
|
|
20
|
-
tag: 'thread-title',
|
|
21
|
-
createAgent: createThreadTitleGeneratorAgent,
|
|
22
|
-
defaultSystemPrompt: THREAD_TITLE_GENERATOR_PROMPT,
|
|
23
|
-
timeoutMs: THREAD_TITLE_TIMEOUT_MS,
|
|
24
|
-
messages: [{ role: 'user', content: sourceText }],
|
|
25
|
-
}),
|
|
26
|
-
)
|
|
27
|
-
} catch (error) {
|
|
28
|
-
chatLogger.warn`Failed to generate thread title via LLM (non-fatal): ${error}`
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (!title) {
|
|
32
|
-
title = limitTitleWords(deriveTitle(sourceText || THREAD.DEFAULT_TITLE))
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
await threadService.update(threadId, { title, nameGenerated: true })
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export const threadTitleService = new ThreadTitleService()
|