@lota-sdk/core 0.4.8 → 0.4.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +11 -12
- package/src/ai/embedding-cache.ts +96 -22
- package/src/ai-gateway/ai-gateway.ts +766 -223
- package/src/config/agent-defaults.ts +189 -75
- package/src/config/agent-types.ts +54 -4
- package/src/config/background-processing.ts +1 -1
- package/src/config/constants.ts +8 -2
- package/src/config/index.ts +0 -1
- package/src/config/logger.ts +299 -19
- package/src/config/thread-defaults.ts +40 -20
- package/src/create-runtime.ts +200 -449
- package/src/db/base.service.ts +52 -28
- package/src/db/cursor-pagination.ts +71 -30
- package/src/db/memory-query-builder.ts +2 -1
- package/src/db/memory-store.helpers.ts +4 -7
- package/src/db/memory-store.ts +868 -601
- package/src/db/memory.ts +396 -280
- package/src/db/record-id.ts +32 -10
- package/src/db/schema-fingerprint.ts +30 -12
- package/src/db/service-normalization.ts +288 -0
- package/src/db/service.ts +912 -779
- package/src/db/startup.ts +153 -68
- package/src/db/transaction-conflict.ts +15 -0
- package/src/effect/awaitable-effect.ts +96 -0
- package/src/effect/errors.ts +121 -0
- package/src/effect/helpers.ts +123 -0
- package/src/effect/index.ts +24 -0
- package/src/effect/layers.ts +238 -0
- package/src/effect/runtime-ref.ts +25 -0
- package/src/effect/runtime.ts +46 -0
- package/src/effect/services.ts +61 -0
- package/src/effect/zod.ts +43 -0
- package/src/embeddings/provider.ts +128 -83
- package/src/index.ts +48 -1
- package/src/openrouter/direct-provider.ts +11 -35
- package/src/queues/autonomous-job.queue.ts +117 -73
- package/src/queues/context-compaction.queue.ts +50 -17
- package/src/queues/delayed-node-promotion.queue.ts +46 -17
- package/src/queues/document-processor.queue.ts +52 -77
- package/src/queues/memory-consolidation.queue.ts +47 -32
- package/src/queues/organization-learning.queue.ts +26 -4
- package/src/queues/plan-agent-heartbeat.queue.ts +71 -24
- package/src/queues/plan-scheduler.queue.ts +97 -33
- package/src/queues/post-chat-memory.queue.ts +56 -26
- package/src/queues/queue-factory.ts +227 -59
- package/src/queues/standalone-worker.ts +39 -0
- package/src/queues/title-generation.queue.ts +45 -11
- package/src/redis/connection.ts +182 -113
- package/src/redis/index.ts +6 -8
- package/src/redis/org-memory-lock.ts +60 -27
- package/src/redis/redis-lease-lock.ts +200 -121
- package/src/redis/runtime-connection.ts +20 -0
- package/src/redis/stream-context.ts +92 -46
- package/src/runtime/agent-identity-overrides.ts +2 -2
- package/src/runtime/agent-runtime-policy.ts +5 -2
- package/src/runtime/agent-stream-helpers.ts +24 -9
- package/src/runtime/chat-run-orchestration.ts +102 -19
- package/src/runtime/chat-run-registry.ts +36 -2
- package/src/runtime/context-compaction/context-compaction-runtime.ts +107 -0
- package/src/runtime/{context-compaction.ts → context-compaction/context-compaction.ts} +161 -94
- package/src/runtime/domain-layer.ts +192 -0
- package/src/runtime/execution-plan-visibility.ts +2 -2
- package/src/runtime/execution-plan.ts +42 -15
- package/src/runtime/graph-designer.ts +16 -4
- package/src/runtime/helper-model.ts +139 -48
- package/src/runtime/index.ts +7 -8
- package/src/runtime/indexed-repositories-policy.ts +3 -3
- package/src/runtime/{memory-block.ts → memory/memory-block.ts} +50 -36
- package/src/runtime/{memory-digest-policy.ts → memory/memory-digest-policy.ts} +1 -1
- package/src/runtime/{memory-pipeline.ts → memory/memory-pipeline.ts} +54 -67
- package/src/runtime/{memory-prompts-fact.ts → memory/memory-prompts-fact.ts} +2 -2
- package/src/runtime/memory/memory-scope.ts +53 -0
- package/src/runtime/plugin-resolution.ts +124 -25
- package/src/runtime/plugin-types.ts +9 -1
- package/src/runtime/post-turn-side-effects.ts +177 -130
- package/src/runtime/retrieval-adapters.ts +40 -6
- package/src/runtime/runtime-accessors.ts +92 -0
- package/src/runtime/runtime-config.ts +150 -61
- package/src/runtime/runtime-extensions.ts +23 -25
- package/src/runtime/runtime-lifecycle.ts +124 -0
- package/src/runtime/runtime-services.ts +386 -0
- package/src/runtime/runtime-token.ts +47 -0
- package/src/runtime/social-chat/social-chat-agent-runner.ts +159 -0
- package/src/runtime/{social-chat-history.ts → social-chat/social-chat-history.ts} +51 -20
- package/src/runtime/social-chat/social-chat.ts +630 -0
- package/src/runtime/specialist-runner.ts +36 -10
- package/src/runtime/team-consultation/team-consultation-orchestrator.ts +433 -0
- package/src/runtime/{team-consultation-prompts.ts → team-consultation/team-consultation-prompts.ts} +6 -2
- package/src/runtime/thread-chat-helpers.ts +2 -2
- package/src/runtime/thread-plan-turn.ts +2 -1
- package/src/runtime/thread-turn-context.ts +183 -111
- package/src/runtime/turn-lifecycle.ts +93 -27
- package/src/services/agent-activity.service.ts +287 -203
- package/src/services/agent-executor.service.ts +253 -149
- package/src/services/artifact.service.ts +231 -149
- package/src/services/attachment.service.ts +171 -115
- package/src/services/autonomous-job.service.ts +890 -491
- package/src/services/background-work.service.ts +54 -0
- package/src/services/chat-run-registry.service.ts +13 -1
- package/src/services/context-compaction.service.ts +136 -86
- package/src/services/document-chunk.service.ts +151 -88
- package/src/services/execution-plan/execution-plan-approval.ts +26 -0
- package/src/services/execution-plan/execution-plan-context.ts +29 -0
- package/src/services/execution-plan/execution-plan-graph.ts +278 -0
- package/src/services/execution-plan/execution-plan-schedule.ts +84 -0
- package/src/services/execution-plan/execution-plan-spec.ts +75 -0
- package/src/services/execution-plan/execution-plan.service.ts +1041 -0
- package/src/services/feedback-loop.service.ts +132 -76
- package/src/services/global-orchestrator.service.ts +101 -168
- package/src/services/graph-full-routing.ts +193 -0
- package/src/services/index.ts +19 -21
- package/src/services/institutional-memory.service.ts +213 -125
- package/src/services/learned-skill.service.ts +368 -260
- package/src/services/memory/memory-conversation.ts +95 -0
- package/src/services/memory/memory-errors.ts +27 -0
- package/src/services/memory/memory-org-memory.ts +50 -0
- package/src/services/memory/memory-preseeded.ts +86 -0
- package/src/services/memory/memory-rerank.ts +297 -0
- package/src/services/{memory-utils.ts → memory/memory-utils.ts} +6 -5
- package/src/services/memory/memory.service.ts +674 -0
- package/src/services/memory/rerank.service.ts +201 -0
- package/src/services/monitoring-window.service.ts +92 -70
- package/src/services/mutating-approval.service.ts +62 -53
- package/src/services/node-workspace.service.ts +141 -98
- package/src/services/notification.service.ts +29 -16
- package/src/services/organization-member.service.ts +120 -66
- package/src/services/organization.service.ts +153 -77
- package/src/services/ownership-dispatcher.service.ts +456 -263
- package/src/services/plan/plan-agent-heartbeat.service.ts +234 -0
- package/src/services/plan/plan-agent-query.service.ts +322 -0
- package/src/services/{plan-approval.service.ts → plan/plan-approval.service.ts} +45 -22
- package/src/services/plan/plan-artifact.service.ts +60 -0
- package/src/services/plan/plan-builder.service.ts +76 -0
- package/src/services/plan/plan-checkpoint.service.ts +103 -0
- package/src/services/{plan-compiler.service.ts → plan/plan-compiler.service.ts} +26 -9
- package/src/services/plan/plan-completion-side-effects.ts +169 -0
- package/src/services/plan/plan-coordination.service.ts +181 -0
- package/src/services/plan/plan-cycle.service.ts +405 -0
- package/src/services/plan/plan-deadline.service.ts +533 -0
- package/src/services/plan/plan-event-delivery.service.ts +266 -0
- package/src/services/plan/plan-executor-context.ts +35 -0
- package/src/services/plan/plan-executor-graph.ts +522 -0
- package/src/services/plan/plan-executor-helpers.ts +307 -0
- package/src/services/plan/plan-executor-persistence.ts +209 -0
- package/src/services/plan/plan-executor.service.ts +1737 -0
- package/src/services/{plan-helpers.ts → plan/plan-helpers.ts} +1 -1
- package/src/services/{plan-run-data.ts → plan/plan-run-data.ts} +4 -4
- package/src/services/plan/plan-run-serialization.ts +15 -0
- package/src/services/plan/plan-run.service.ts +637 -0
- package/src/services/plan/plan-scheduler.service.ts +379 -0
- package/src/services/plan/plan-template.service.ts +224 -0
- package/src/services/plan/plan-transaction-events.ts +36 -0
- package/src/services/plan/plan-validator.service.ts +907 -0
- package/src/services/plan/plan-workspace.service.ts +131 -0
- package/src/services/plugin-executor.service.ts +102 -68
- package/src/services/quality-metrics.service.ts +112 -94
- package/src/services/queue-job.service.ts +288 -231
- package/src/services/recent-activity-title.service.ts +73 -36
- package/src/services/recent-activity.service.ts +274 -259
- package/src/services/skill-resolver.service.ts +38 -12
- package/src/services/social-chat-history.service.ts +190 -122
- package/src/services/system-executor.service.ts +96 -61
- package/src/services/thread/thread-active-run.ts +203 -0
- package/src/services/thread/thread-bootstrap.ts +385 -0
- package/src/services/thread/thread-listing.ts +199 -0
- package/src/services/thread/thread-memory-block.ts +130 -0
- package/src/services/thread/thread-message.service.ts +379 -0
- package/src/services/thread/thread-record-store.ts +155 -0
- package/src/services/thread/thread-title.service.ts +74 -0
- package/src/services/thread/thread-turn-execution.ts +280 -0
- package/src/services/thread/thread-turn-message-context.ts +73 -0
- package/src/services/thread/thread-turn-preparation.service.ts +1148 -0
- package/src/services/thread/thread-turn-streaming.ts +403 -0
- package/src/services/thread/thread-turn-tracing.ts +35 -0
- package/src/services/thread/thread-turn.ts +376 -0
- package/src/services/thread/thread.service.ts +344 -0
- package/src/services/user.service.ts +82 -32
- package/src/services/write-intent-validator.service.ts +63 -51
- package/src/storage/attachment-parser.ts +69 -27
- package/src/storage/attachment-storage.service.ts +334 -275
- package/src/storage/generated-document-storage.service.ts +66 -34
- package/src/system-agents/agent-result.ts +3 -1
- package/src/system-agents/context-compaction.agent.ts +3 -3
- package/src/system-agents/delegated-agent-factory.ts +159 -90
- package/src/system-agents/helper-agent-options.ts +1 -1
- package/src/system-agents/memory-reranker.agent.ts +3 -3
- package/src/system-agents/memory.agent.ts +3 -3
- package/src/system-agents/recent-activity-title-refiner.agent.ts +3 -3
- package/src/system-agents/regular-chat-memory-digest.agent.ts +3 -3
- package/src/system-agents/skill-extractor.agent.ts +3 -3
- package/src/system-agents/skill-manager.agent.ts +3 -3
- package/src/system-agents/thread-router.agent.ts +157 -113
- package/src/system-agents/title-generator.agent.ts +3 -3
- package/src/tools/execution-plan.tool.ts +241 -171
- package/src/tools/fetch-webpage.tool.ts +29 -18
- package/src/tools/firecrawl-client.ts +26 -6
- package/src/tools/index.ts +1 -0
- package/src/tools/memory-block.tool.ts +14 -6
- package/src/tools/plan-approval.tool.ts +57 -47
- package/src/tools/read-file-parts.tool.ts +44 -33
- package/src/tools/remember-memory.tool.ts +65 -45
- package/src/tools/search-web.tool.ts +33 -22
- package/src/tools/search.tool.ts +41 -29
- package/src/tools/team-think.tool.ts +125 -84
- package/src/tools/user-questions.tool.ts +4 -3
- package/src/tools/web-tool-shared.ts +6 -0
- package/src/utils/async.ts +25 -22
- package/src/utils/crypto.ts +21 -0
- package/src/utils/date-time.ts +40 -1
- package/src/utils/errors.ts +111 -20
- package/src/utils/hono-error-handler.ts +24 -39
- package/src/utils/index.ts +2 -1
- package/src/utils/null-proto-record.ts +41 -0
- package/src/utils/sse-keepalive.ts +124 -21
- package/src/workers/bootstrap.ts +164 -52
- package/src/workers/memory-consolidation.worker.ts +325 -237
- package/src/workers/organization-learning.worker.ts +50 -16
- package/src/workers/regular-chat-memory-digest.helpers.ts +28 -27
- package/src/workers/regular-chat-memory-digest.runner.ts +185 -114
- package/src/workers/skill-extraction.runner.ts +176 -93
- package/src/workers/utils/file-section-chunker.ts +8 -10
- package/src/workers/utils/repo-structure-extractor.ts +349 -260
- package/src/workers/utils/repomix-file-sections.ts +2 -2
- package/src/workers/utils/thread-message-query.ts +97 -38
- package/src/workers/worker-utils.ts +74 -31
- package/src/config/debug-logger.ts +0 -47
- package/src/config/search.ts +0 -3
- package/src/redis/connection-accessor.ts +0 -26
- package/src/runtime/agent-types.ts +0 -1
- package/src/runtime/context-compaction-runtime.ts +0 -87
- package/src/runtime/memory-scope.ts +0 -43
- package/src/runtime/social-chat-agent-runner.ts +0 -118
- package/src/runtime/social-chat.ts +0 -516
- package/src/runtime/team-consultation-orchestrator.ts +0 -272
- package/src/services/adaptive-playbook.service.ts +0 -152
- package/src/services/artifact-provenance.service.ts +0 -172
- package/src/services/chat-attachments.service.ts +0 -17
- package/src/services/context-compaction-runtime.singleton.ts +0 -13
- package/src/services/execution-plan.service.ts +0 -1118
- package/src/services/memory.service.ts +0 -914
- package/src/services/plan-agent-heartbeat.service.ts +0 -136
- package/src/services/plan-agent-query.service.ts +0 -267
- package/src/services/plan-artifact.service.ts +0 -50
- package/src/services/plan-builder.service.ts +0 -67
- package/src/services/plan-checkpoint.service.ts +0 -81
- package/src/services/plan-completion-side-effects.ts +0 -80
- package/src/services/plan-coordination.service.ts +0 -157
- package/src/services/plan-cycle.service.ts +0 -284
- package/src/services/plan-deadline.service.ts +0 -430
- package/src/services/plan-event-delivery.service.ts +0 -166
- package/src/services/plan-executor.service.ts +0 -1950
- package/src/services/plan-run.service.ts +0 -515
- package/src/services/plan-scheduler.service.ts +0 -240
- package/src/services/plan-template.service.ts +0 -177
- package/src/services/plan-validator.service.ts +0 -818
- package/src/services/plan-workspace.service.ts +0 -83
- package/src/services/rerank.service.ts +0 -156
- package/src/services/thread-message.service.ts +0 -275
- package/src/services/thread-plan-registry.service.ts +0 -22
- package/src/services/thread-title.service.ts +0 -39
- package/src/services/thread-turn-preparation.service.ts +0 -1147
- package/src/services/thread-turn.ts +0 -172
- package/src/services/thread.service.ts +0 -869
- package/src/utils/env.ts +0 -8
- /package/src/runtime/{context-compaction-constants.ts → context-compaction/context-compaction-constants.ts} +0 -0
- /package/src/runtime/{memory-format.ts → memory/memory-format.ts} +0 -0
- /package/src/runtime/{memory-prompts-parse.ts → memory/memory-prompts-parse.ts} +0 -0
- /package/src/runtime/{memory-prompts-update.ts → memory/memory-prompts-update.ts} +0 -0
- /package/src/runtime/{social-chat-prompts.ts → social-chat/social-chat-prompts.ts} +0 -0
- /package/src/services/{plan-node-spec.ts → plan/plan-node-spec.ts} +0 -0
- /package/src/services/{thread-constants.ts → thread/thread-constants.ts} +0 -0
- /package/src/services/{thread.types.ts → thread/thread.types.ts} +0 -0
|
@@ -34,9 +34,9 @@ export function parseRepomixFileSections(repomixOutput: string): FileSection[] {
|
|
|
34
34
|
return sections
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
export
|
|
37
|
+
export function chunkRepomixFileSections(
|
|
38
38
|
repomixOutput: string,
|
|
39
39
|
options: FileSectionChunkOptions = {},
|
|
40
|
-
):
|
|
40
|
+
): FileSectionChunk[] {
|
|
41
41
|
return chunkFileSections(parseRepomixFileSections(repomixOutput), options)
|
|
42
42
|
}
|
|
@@ -1,93 +1,152 @@
|
|
|
1
|
-
import { requireTimestamp } from '@lota-sdk/shared'
|
|
1
|
+
import { parseRowMetadata, requireTimestamp } from '@lota-sdk/shared'
|
|
2
|
+
import type { ChatMessage } from '@lota-sdk/shared'
|
|
3
|
+
import { Schema, Effect } from 'effect'
|
|
2
4
|
import { BoundQuery } from 'surrealdb'
|
|
3
5
|
import { z } from 'zod'
|
|
4
6
|
|
|
5
7
|
import { ensureRecordId, recordIdToString } from '../../db/record-id'
|
|
6
8
|
import type { RecordIdRef } from '../../db/record-id'
|
|
7
|
-
import {
|
|
9
|
+
import type { SurrealDBService } from '../../db/service'
|
|
8
10
|
import { TABLES } from '../../db/tables'
|
|
9
11
|
import { ThreadMessageRowSchema } from '../../db/thread-message-row'
|
|
10
12
|
import type { ThreadMessageRow } from '../../db/thread-message-row'
|
|
11
13
|
import { normalizeTextBody } from '../../document/parsing'
|
|
14
|
+
import { makeEffectTryPromiseWithMessage } from '../../effect/helpers'
|
|
12
15
|
import type { LotaRuntimeBackgroundCursor } from '../../runtime/runtime-extensions'
|
|
16
|
+
import type { SocialChatHistoryMessage } from '../../services/social-chat-history.service'
|
|
17
|
+
import { unsafeDateFrom } from '../../utils/date-time'
|
|
13
18
|
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
export interface DigestMessage {
|
|
17
|
-
source: 'thread' | 'social'
|
|
19
|
+
export interface ThreadDigestMessage {
|
|
20
|
+
source: 'thread'
|
|
18
21
|
sourceId: string
|
|
19
22
|
role: 'system' | 'user' | 'assistant'
|
|
20
|
-
parts:
|
|
21
|
-
metadata?:
|
|
22
|
-
cursor:
|
|
23
|
+
parts: ChatMessage['parts']
|
|
24
|
+
metadata?: ChatMessage['metadata']
|
|
25
|
+
cursor: LotaRuntimeBackgroundCursor
|
|
23
26
|
}
|
|
24
27
|
|
|
25
|
-
|
|
28
|
+
export type SocialDigestMessage = Pick<
|
|
29
|
+
SocialChatHistoryMessage,
|
|
30
|
+
'source' | 'sourceId' | 'role' | 'parts' | 'metadata' | 'cursor'
|
|
31
|
+
>
|
|
32
|
+
export type DigestMessage = ThreadDigestMessage | SocialDigestMessage
|
|
33
|
+
|
|
34
|
+
function normalizeMessageValue(value: unknown): unknown {
|
|
35
|
+
if (value instanceof Date) {
|
|
36
|
+
return value.toISOString()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (Array.isArray(value)) {
|
|
40
|
+
return value.map((item) => normalizeMessageValue(item))
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (value && typeof value === 'object') {
|
|
44
|
+
return Object.fromEntries(
|
|
45
|
+
Object.entries(value as Record<string, unknown>).map(([key, entry]) => [key, normalizeMessageValue(entry)]),
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return value
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function readPersistedMessageParts(parts: ThreadMessageRow['parts']): ChatMessage['parts'] {
|
|
53
|
+
return (Array.isArray(parts) ? normalizeMessageValue(parts) : []) as ChatMessage['parts']
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
class ThreadMessageQueryError extends Schema.TaggedErrorClass<ThreadMessageQueryError>()('ThreadMessageQueryError', {
|
|
57
|
+
message: Schema.String,
|
|
58
|
+
cause: Schema.Defect,
|
|
59
|
+
}) {}
|
|
60
|
+
|
|
61
|
+
function mapThreadRow(row: ThreadMessageRow): ThreadDigestMessage {
|
|
26
62
|
return {
|
|
27
63
|
source: 'thread',
|
|
28
64
|
sourceId: recordIdToString(row.threadId, TABLES.THREAD),
|
|
29
65
|
role: row.role,
|
|
30
|
-
parts: row.parts
|
|
31
|
-
metadata: row.metadata
|
|
66
|
+
parts: readPersistedMessageParts(row.parts),
|
|
67
|
+
metadata: parseRowMetadata(row.metadata),
|
|
32
68
|
cursor: {
|
|
33
|
-
createdAt:
|
|
69
|
+
createdAt: unsafeDateFrom(requireTimestamp(row.createdAt)),
|
|
34
70
|
id: recordIdToString(row.id, TABLES.THREAD_MESSAGE),
|
|
35
71
|
},
|
|
36
72
|
}
|
|
37
73
|
}
|
|
38
74
|
|
|
75
|
+
const effectTryPromise = makeEffectTryPromiseWithMessage(
|
|
76
|
+
(message, cause) => new ThreadMessageQueryError({ message, cause }),
|
|
77
|
+
)
|
|
78
|
+
|
|
39
79
|
export function compareDigestMessageOrder(left: DigestMessage, right: DigestMessage): number {
|
|
40
80
|
const timeDiff = left.cursor.createdAt.getTime() - right.cursor.createdAt.getTime()
|
|
41
81
|
if (timeDiff !== 0) return timeDiff
|
|
42
82
|
return left.cursor.id.localeCompare(right.cursor.id)
|
|
43
83
|
}
|
|
44
84
|
|
|
45
|
-
export
|
|
85
|
+
export function listThreadIdsForOrg(db: SurrealDBService, orgRef: RecordIdRef): Promise<RecordIdRef[]> {
|
|
46
86
|
const EntityIdRowSchema = z.string().trim().min(1)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
87
|
+
return Effect.runPromise(
|
|
88
|
+
effectTryPromise(
|
|
89
|
+
() =>
|
|
90
|
+
db.query<unknown>(
|
|
91
|
+
new BoundQuery(
|
|
92
|
+
`SELECT VALUE type::string(id) FROM ${TABLES.THREAD}
|
|
50
93
|
WHERE organizationId = $organizationId`,
|
|
51
|
-
|
|
94
|
+
{ organizationId: orgRef },
|
|
95
|
+
),
|
|
96
|
+
),
|
|
97
|
+
'Failed to list thread ids for org digest.',
|
|
98
|
+
).pipe(
|
|
99
|
+
Effect.map((ids) => ids.map((value: unknown) => ensureRecordId(EntityIdRowSchema.parse(value), TABLES.THREAD))),
|
|
52
100
|
),
|
|
53
101
|
)
|
|
54
|
-
return ids.map((value) => ensureRecordId(EntityIdRowSchema.parse(value), TABLES.THREAD))
|
|
55
102
|
}
|
|
56
103
|
|
|
57
|
-
export
|
|
104
|
+
export function listEligibleThreadMessages(params: {
|
|
105
|
+
db: SurrealDBService
|
|
58
106
|
threadIds: RecordIdRef[]
|
|
59
|
-
cursor:
|
|
107
|
+
cursor: LotaRuntimeBackgroundCursor | null
|
|
60
108
|
onboardingCutoff: Date | null
|
|
61
109
|
}): Promise<DigestMessage[]> {
|
|
62
|
-
if (params.threadIds.length === 0) return []
|
|
110
|
+
if (params.threadIds.length === 0) return Promise.resolve([])
|
|
63
111
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
112
|
+
return Effect.runPromise(
|
|
113
|
+
Effect.gen(function* () {
|
|
114
|
+
const query = params.cursor
|
|
115
|
+
? new BoundQuery(
|
|
116
|
+
`SELECT type::string(id) AS id, type::string(threadId) AS threadId, role, parts, metadata, createdAt FROM ${TABLES.THREAD_MESSAGE}
|
|
69
117
|
WHERE threadId IN $threadIds
|
|
70
118
|
AND (
|
|
71
119
|
createdAt > $cursorCreatedAt
|
|
72
120
|
OR (createdAt = $cursorCreatedAt AND id > $cursorRowId)
|
|
73
121
|
)
|
|
74
122
|
ORDER BY createdAt ASC, id ASC`,
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
123
|
+
{
|
|
124
|
+
threadIds: params.threadIds,
|
|
125
|
+
cursorCreatedAt: params.cursor.createdAt,
|
|
126
|
+
cursorRowId: ensureRecordId(params.cursor.id, TABLES.THREAD_MESSAGE),
|
|
127
|
+
},
|
|
128
|
+
)
|
|
129
|
+
: params.onboardingCutoff
|
|
130
|
+
? new BoundQuery(
|
|
131
|
+
`SELECT type::string(id) AS id, type::string(threadId) AS threadId, role, parts, metadata, createdAt FROM ${TABLES.THREAD_MESSAGE}
|
|
80
132
|
WHERE threadId IN $threadIds
|
|
81
133
|
AND createdAt > $onboardingCutoff
|
|
82
134
|
ORDER BY createdAt ASC, id ASC`,
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
135
|
+
{ threadIds: params.threadIds, onboardingCutoff: params.onboardingCutoff },
|
|
136
|
+
)
|
|
137
|
+
: null
|
|
86
138
|
|
|
87
|
-
|
|
139
|
+
if (!query) {
|
|
140
|
+
return []
|
|
141
|
+
}
|
|
88
142
|
|
|
89
|
-
|
|
90
|
-
|
|
143
|
+
const rows = yield* effectTryPromise(
|
|
144
|
+
() => params.db.query<unknown>(query),
|
|
145
|
+
'Failed to list eligible thread messages.',
|
|
146
|
+
)
|
|
147
|
+
return rows.map((row: unknown) => mapThreadRow(ThreadMessageRowSchema.parse(row)))
|
|
148
|
+
}),
|
|
149
|
+
)
|
|
91
150
|
}
|
|
92
151
|
|
|
93
152
|
export function normalizeBlock(value: string): string {
|
|
@@ -1,10 +1,27 @@
|
|
|
1
|
-
import path from 'node:path'
|
|
2
1
|
import { fileURLToPath } from 'node:url'
|
|
3
2
|
|
|
4
3
|
import type { Job, Worker } from 'bullmq'
|
|
4
|
+
import { Effect } from 'effect'
|
|
5
|
+
import type { Context } from 'effect'
|
|
5
6
|
|
|
6
7
|
import { chatLogger } from '../config/logger'
|
|
7
|
-
import {
|
|
8
|
+
import { resolveLotaService } from '../effect/runtime'
|
|
9
|
+
import { QueueJobServiceTag } from '../services/queue-job.service'
|
|
10
|
+
|
|
11
|
+
let currentQueueJobService: Context.Service.Shape<typeof QueueJobServiceTag> | null = null
|
|
12
|
+
|
|
13
|
+
export function configureQueueJobService(service: Context.Service.Shape<typeof QueueJobServiceTag>): void {
|
|
14
|
+
currentQueueJobService = service
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function clearQueueJobService(): void {
|
|
18
|
+
currentQueueJobService = null
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function getQueueJobService(): Context.Service.Shape<typeof QueueJobServiceTag> {
|
|
22
|
+
return currentQueueJobService ?? resolveLotaService(QueueJobServiceTag)
|
|
23
|
+
}
|
|
24
|
+
|
|
8
25
|
export const DEFAULT_JOB_RETENTION = { removeOnComplete: true, removeOnFail: { age: 24 * 60 * 60, count: 200 } }
|
|
9
26
|
export const LOW_JOB_RETENTION = { removeOnComplete: true, removeOnFail: { age: 6 * 60 * 60, count: 50 } }
|
|
10
27
|
export const LONG_JOB_LOCK_DURATION_MS = 600_000
|
|
@@ -12,7 +29,7 @@ export const LONG_JOB_LOCK_DURATION_MS = 600_000
|
|
|
12
29
|
const DEFAULT_SHUTDOWN_TIMEOUT_MS = 10_000
|
|
13
30
|
|
|
14
31
|
export function getWorkerPath(workerName: string): string {
|
|
15
|
-
return fileURLToPath(new URL(
|
|
32
|
+
return fileURLToPath(new URL(workerName, import.meta.url))
|
|
16
33
|
}
|
|
17
34
|
|
|
18
35
|
export interface WorkerHandle {
|
|
@@ -72,9 +89,9 @@ export const attachWorkerEvents = (worker: Worker, name: string, logger: typeof
|
|
|
72
89
|
}
|
|
73
90
|
|
|
74
91
|
export const createWorkerShutdown = (worker: Worker, name: string, logger: typeof chatLogger = chatLogger) => {
|
|
75
|
-
return
|
|
92
|
+
return () => {
|
|
76
93
|
logger.info`Shutting down ${name} worker`
|
|
77
|
-
|
|
94
|
+
return Effect.runPromise(Effect.asVoid(Effect.tryPromise(() => worker.close())))
|
|
78
95
|
}
|
|
79
96
|
}
|
|
80
97
|
|
|
@@ -82,7 +99,7 @@ export function createTracedWorkerProcessor<TJob extends TracedWorkerJobLike, TR
|
|
|
82
99
|
queueName: string,
|
|
83
100
|
processor: (job: TJob) => Promise<TResult>,
|
|
84
101
|
): (job: TJob) => Promise<TResult> {
|
|
85
|
-
return
|
|
102
|
+
return (job: TJob) => {
|
|
86
103
|
const trackedJob = {
|
|
87
104
|
queueName,
|
|
88
105
|
id: typeof job.id === 'string' || typeof job.id === 'number' ? job.id : undefined,
|
|
@@ -93,31 +110,52 @@ export function createTracedWorkerProcessor<TJob extends TracedWorkerJobLike, TR
|
|
|
93
110
|
timestamp: job.timestamp,
|
|
94
111
|
}
|
|
95
112
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
} catch (error) {
|
|
99
|
-
chatLogger.error`Failed to persist queue job start (queue=${queueName}, job=${job.id}): ${error}`
|
|
113
|
+
const logPersistenceError = (phase: string, error: unknown) => {
|
|
114
|
+
chatLogger.error`Failed to persist queue job ${phase} (queue=${queueName}, job=${job.id}): ${error}`
|
|
100
115
|
}
|
|
101
116
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
117
|
+
return Effect.runPromise(
|
|
118
|
+
Effect.catch(
|
|
119
|
+
Effect.gen(function* () {
|
|
120
|
+
yield* Effect.catch(getQueueJobService().markAttemptStarted(trackedJob), (error) =>
|
|
121
|
+
Effect.sync(() => {
|
|
122
|
+
logPersistenceError('start', error)
|
|
123
|
+
}),
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
const result = yield* Effect.tryPromise(() => processor(job))
|
|
127
|
+
|
|
128
|
+
yield* Effect.catch(getQueueJobService().markAttemptCompleted(trackedJob, result), (error) =>
|
|
129
|
+
Effect.sync(() => {
|
|
130
|
+
logPersistenceError('completion', error)
|
|
131
|
+
}),
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
return result
|
|
135
|
+
}),
|
|
136
|
+
(error) =>
|
|
137
|
+
Effect.gen(function* () {
|
|
138
|
+
yield* Effect.catch(getQueueJobService().markAttemptFailed(trackedJob, error), (persistenceError) =>
|
|
139
|
+
Effect.sync(() => {
|
|
140
|
+
logPersistenceError('failure', persistenceError)
|
|
141
|
+
}),
|
|
142
|
+
)
|
|
143
|
+
return yield* error
|
|
144
|
+
}),
|
|
145
|
+
).pipe(
|
|
146
|
+
Effect.withSpan(`worker.${queueName}.${job.name}`),
|
|
147
|
+
Effect.annotateSpans({
|
|
148
|
+
'job.id': trackedJob.id !== undefined ? String(trackedJob.id) : 'unknown',
|
|
149
|
+
'job.name': job.name,
|
|
150
|
+
'job.attemptsMade': typeof job.attemptsMade === 'number' ? job.attemptsMade : -1,
|
|
151
|
+
'queue.name': queueName,
|
|
152
|
+
}),
|
|
153
|
+
),
|
|
154
|
+
)
|
|
118
155
|
}
|
|
119
156
|
}
|
|
120
157
|
|
|
158
|
+
/** Registers process signal handlers for sandboxed workers that run outside an Effect scope. */
|
|
121
159
|
export const registerShutdownSignals = ({
|
|
122
160
|
name,
|
|
123
161
|
shutdown,
|
|
@@ -130,21 +168,26 @@ export const registerShutdownSignals = ({
|
|
|
130
168
|
timeoutMs?: number
|
|
131
169
|
}) => {
|
|
132
170
|
let shuttingDown = false
|
|
171
|
+
let forcedExitArmed = true
|
|
133
172
|
|
|
134
173
|
const handleSignal = () => {
|
|
135
174
|
if (shuttingDown) return
|
|
136
175
|
shuttingDown = true
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
176
|
+
void Effect.runFork(
|
|
177
|
+
Effect.gen(function* () {
|
|
178
|
+
yield* Effect.tryPromise(() => Bun.sleep(timeoutMs))
|
|
179
|
+
if (!forcedExitArmed) return
|
|
180
|
+
logger.warn`Forced shutdown after ${timeoutMs}ms`
|
|
181
|
+
process.exit(0)
|
|
182
|
+
}),
|
|
183
|
+
)
|
|
141
184
|
|
|
142
185
|
shutdown()
|
|
143
186
|
.catch((err: unknown) => {
|
|
144
187
|
logger.error`Failed to shutdown ${name} worker: ${err}`
|
|
145
188
|
})
|
|
146
189
|
.finally(() => {
|
|
147
|
-
|
|
190
|
+
forcedExitArmed = false
|
|
148
191
|
process.exit(0)
|
|
149
192
|
})
|
|
150
193
|
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { chatLogger } from './logger'
|
|
2
|
-
|
|
3
|
-
const isDebug = (): boolean => {
|
|
4
|
-
const level = process.env.LOG_LEVEL
|
|
5
|
-
const flag = process.env.LOTA_DEBUG
|
|
6
|
-
return level === 'debug' || flag === '1'
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
interface DebugTimer {
|
|
10
|
-
step(name: string): void
|
|
11
|
-
elapsed(): number
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const NOOP_TIMER: DebugTimer = { step() {}, elapsed: () => 0 }
|
|
15
|
-
|
|
16
|
-
function createTimer(label: string): DebugTimer {
|
|
17
|
-
const start = performance.now()
|
|
18
|
-
let lastStep = start
|
|
19
|
-
|
|
20
|
-
return {
|
|
21
|
-
step(name: string) {
|
|
22
|
-
const now = performance.now()
|
|
23
|
-
const stepMs = now - lastStep
|
|
24
|
-
const totalMs = now - start
|
|
25
|
-
chatLogger.debug`[ttft:${label}] ${name}: ${stepMs.toFixed(1)}ms (elapsed: ${totalMs.toFixed(1)}ms)`
|
|
26
|
-
lastStep = now
|
|
27
|
-
},
|
|
28
|
-
elapsed() {
|
|
29
|
-
return performance.now() - start
|
|
30
|
-
},
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export const lotaDebugLogger = {
|
|
35
|
-
get enabled() {
|
|
36
|
-
return isDebug()
|
|
37
|
-
},
|
|
38
|
-
|
|
39
|
-
timer(label: string): DebugTimer {
|
|
40
|
-
return isDebug() ? createTimer(label) : NOOP_TIMER
|
|
41
|
-
},
|
|
42
|
-
|
|
43
|
-
step(name: string) {
|
|
44
|
-
if (!isDebug()) return
|
|
45
|
-
chatLogger.debug`[ttft] ${name}`
|
|
46
|
-
},
|
|
47
|
-
}
|
package/src/config/search.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type IORedis from 'ioredis'
|
|
2
|
-
|
|
3
|
-
export interface RedisConnectionAccessor {
|
|
4
|
-
getConnection(): IORedis
|
|
5
|
-
getConnectionForBullMQ(): IORedis
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
let redisManager: RedisConnectionAccessor | undefined
|
|
9
|
-
|
|
10
|
-
export function setRedisConnectionManager(manager: RedisConnectionAccessor): void {
|
|
11
|
-
redisManager = manager
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function getRedisConnection(): IORedis {
|
|
15
|
-
if (!redisManager) {
|
|
16
|
-
throw new Error('Redis connection manager not configured. Call setRedisConnectionManager() first.')
|
|
17
|
-
}
|
|
18
|
-
return redisManager.getConnection()
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function getRedisConnectionForBullMQ(): IORedis {
|
|
22
|
-
if (!redisManager) {
|
|
23
|
-
throw new Error('Redis connection manager not configured. Call setRedisConnectionManager() first.')
|
|
24
|
-
}
|
|
25
|
-
return redisManager.getConnectionForBullMQ()
|
|
26
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export type { ChatMode, CreateHelperToolLoopAgentOptions, CreateRoutedAgentOptions } from '@lota-sdk/shared'
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { createContextCompactionAgent } from '../system-agents/context-compaction.agent'
|
|
2
|
-
import {
|
|
3
|
-
buildContextCompactionPrompt,
|
|
4
|
-
buildMemoryBlockCompactionPrompt,
|
|
5
|
-
ContextCompactionOutputSchema,
|
|
6
|
-
createContextCompactionRuntime,
|
|
7
|
-
parseCompactionOutput,
|
|
8
|
-
} from './context-compaction'
|
|
9
|
-
import type { ContextCompactionRunnerParams } from './context-compaction'
|
|
10
|
-
import {
|
|
11
|
-
COMPACTION_CHUNK_MAX_CHARS,
|
|
12
|
-
CONTEXT_COMPACTION_INCLUDED_TOOL_NAMES,
|
|
13
|
-
CONTEXT_COMPACTION_INCLUDED_TOOL_PREFIXES,
|
|
14
|
-
CONTEXT_COMPACTION_THRESHOLD_RATIO,
|
|
15
|
-
CONTEXT_OUTPUT_RESERVE_TOKENS,
|
|
16
|
-
CONTEXT_SAFETY_MARGIN_TOKENS,
|
|
17
|
-
SUMMARY_ROLLUP_MAX_TOKENS,
|
|
18
|
-
} from './context-compaction-constants'
|
|
19
|
-
import type { GenerateHelperStructuredParams, GenerateHelperTextParams } from './helper-model'
|
|
20
|
-
|
|
21
|
-
const CONTEXT_COMPACTION_MAX_OUTPUT_TOKENS = 512
|
|
22
|
-
|
|
23
|
-
interface HelperModelRuntime {
|
|
24
|
-
generateHelperStructured<T>(params: GenerateHelperStructuredParams<T>): Promise<T>
|
|
25
|
-
generateHelperText(params: GenerateHelperTextParams): Promise<string>
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
interface CreateContextCompactionRuntimeDeps {
|
|
29
|
-
helperModelRuntime: HelperModelRuntime
|
|
30
|
-
now?: () => number
|
|
31
|
-
randomId?: () => string
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async function runContextCompacter(helperModelRuntime: HelperModelRuntime, params: ContextCompactionRunnerParams) {
|
|
35
|
-
const output = await helperModelRuntime.generateHelperStructured({
|
|
36
|
-
tag: 'context-compaction',
|
|
37
|
-
createAgent: createContextCompactionAgent,
|
|
38
|
-
messages: [
|
|
39
|
-
{
|
|
40
|
-
role: 'user',
|
|
41
|
-
content: buildContextCompactionPrompt({
|
|
42
|
-
previousSummary: params.previousSummary,
|
|
43
|
-
transcript: params.transcript,
|
|
44
|
-
}),
|
|
45
|
-
},
|
|
46
|
-
],
|
|
47
|
-
schema: ContextCompactionOutputSchema,
|
|
48
|
-
maxOutputTokens: 8_000,
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
return parseCompactionOutput(output)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function createWiredContextCompactionRuntime(deps: CreateContextCompactionRuntimeDeps) {
|
|
55
|
-
const { helperModelRuntime } = deps
|
|
56
|
-
|
|
57
|
-
const runtime = createContextCompactionRuntime({
|
|
58
|
-
runCompacter: (params) => runContextCompacter(helperModelRuntime, params),
|
|
59
|
-
now: deps.now,
|
|
60
|
-
randomId: deps.randomId,
|
|
61
|
-
thresholdRatio: CONTEXT_COMPACTION_THRESHOLD_RATIO,
|
|
62
|
-
outputReserveTokens: CONTEXT_OUTPUT_RESERVE_TOKENS,
|
|
63
|
-
safetyMarginTokens: CONTEXT_SAFETY_MARGIN_TOKENS,
|
|
64
|
-
compactionChunkMaxChars: COMPACTION_CHUNK_MAX_CHARS,
|
|
65
|
-
summaryRollupMaxTokens: SUMMARY_ROLLUP_MAX_TOKENS,
|
|
66
|
-
includedToolNames: CONTEXT_COMPACTION_INCLUDED_TOOL_NAMES,
|
|
67
|
-
includedToolPrefixes: CONTEXT_COMPACTION_INCLUDED_TOOL_PREFIXES,
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
async function compactMemoryBlockSummary(params: {
|
|
71
|
-
previousSummary: string
|
|
72
|
-
newEntriesText: string
|
|
73
|
-
}): Promise<string> {
|
|
74
|
-
const previousSummary = params.previousSummary.trim()
|
|
75
|
-
const newEntriesText = params.newEntriesText.trim()
|
|
76
|
-
if (!previousSummary && !newEntriesText) return ''
|
|
77
|
-
|
|
78
|
-
return helperModelRuntime.generateHelperText({
|
|
79
|
-
tag: 'memory-block-compaction',
|
|
80
|
-
createAgent: createContextCompactionAgent,
|
|
81
|
-
messages: [{ role: 'user', content: buildMemoryBlockCompactionPrompt({ previousSummary, newEntriesText }) }],
|
|
82
|
-
maxOutputTokens: CONTEXT_COMPACTION_MAX_OUTPUT_TOKENS,
|
|
83
|
-
})
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return { ...runtime, compactMemoryBlockSummary }
|
|
87
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
export const ORG_SCOPE_PREFIX = 'org'
|
|
2
|
-
|
|
3
|
-
const SCOPE_ID_MAX_LENGTH = 255
|
|
4
|
-
const SCOPE_PREFIX_REGEX = /^[a-z][a-z0-9_]*$/
|
|
5
|
-
|
|
6
|
-
function stripRecordPrefix(id: string): string {
|
|
7
|
-
if (typeof id !== 'string' || id.length === 0) {
|
|
8
|
-
throw new TypeError('id must be a non-empty string')
|
|
9
|
-
}
|
|
10
|
-
const [, ...rest] = id.split(':')
|
|
11
|
-
return rest.length > 0 ? rest.join(':') : id
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function scopeId(prefix: string, id: string): string {
|
|
15
|
-
if (typeof prefix !== 'string' || prefix.length === 0) {
|
|
16
|
-
throw new TypeError('prefix must be a non-empty string')
|
|
17
|
-
}
|
|
18
|
-
if (!SCOPE_PREFIX_REGEX.test(prefix)) {
|
|
19
|
-
throw new Error(`Invalid scope prefix: ${prefix}`)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const stripped = stripRecordPrefix(id)
|
|
23
|
-
const scoped = `${prefix}:${stripped}`
|
|
24
|
-
if (scoped.length > SCOPE_ID_MAX_LENGTH) {
|
|
25
|
-
throw new Error('scopeId exceeds maximum length')
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return scoped
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function agentScopeId(orgId: string, agentName: string): string {
|
|
32
|
-
if (typeof agentName !== 'string' || agentName.trim().length === 0) {
|
|
33
|
-
throw new TypeError('agentName must be a non-empty string')
|
|
34
|
-
}
|
|
35
|
-
const strippedOrgId = stripRecordPrefix(orgId)
|
|
36
|
-
const scoped = `agent:${strippedOrgId}:${agentName.trim()}`
|
|
37
|
-
|
|
38
|
-
if (scoped.length > SCOPE_ID_MAX_LENGTH) {
|
|
39
|
-
throw new Error('scopeId exceeds maximum length')
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return scoped
|
|
43
|
-
}
|