@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
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { Context, Effect, Layer } from 'effect'
|
|
2
|
+
import * as Schema from 'effect/Schema'
|
|
3
|
+
import { z } from 'zod'
|
|
4
|
+
|
|
5
|
+
import { OPENROUTER_FAST_RERANK_MODEL_ID } from '../../config/model-constants'
|
|
6
|
+
import { makeEffectTryPromiseWithOperation } from '../../effect/helpers'
|
|
7
|
+
import { RuntimeConfigServiceTag } from '../../effect/services'
|
|
8
|
+
import { toValidationError } from '../../effect/zod'
|
|
9
|
+
import { normalizeDirectOpenRouterModelId, resolveOpenRouterApiKey } from '../../openrouter/direct-provider'
|
|
10
|
+
import type { ResolvedLotaRuntimeConfig } from '../../runtime/runtime-config'
|
|
11
|
+
|
|
12
|
+
const OPENROUTER_RERANK_URL = 'https://openrouter.ai/api/v1/rerank' as const
|
|
13
|
+
|
|
14
|
+
class RerankServiceError extends Schema.TaggedErrorClass<RerankServiceError>()('RerankServiceError', {
|
|
15
|
+
operation: Schema.String,
|
|
16
|
+
message: Schema.String,
|
|
17
|
+
cause: Schema.Defect,
|
|
18
|
+
}) {}
|
|
19
|
+
|
|
20
|
+
function toRerankServiceError(operation: string, message: string, cause: unknown): RerankServiceError {
|
|
21
|
+
return new RerankServiceError({ operation, message, cause })
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const tryRerankPromise = makeEffectTryPromiseWithOperation(toRerankServiceError)
|
|
25
|
+
|
|
26
|
+
const RerankResponseSchema = z
|
|
27
|
+
.object({
|
|
28
|
+
model: z.string().optional(),
|
|
29
|
+
results: z.array(
|
|
30
|
+
z
|
|
31
|
+
.object({
|
|
32
|
+
index: z.number().int().nonnegative().optional(),
|
|
33
|
+
relevance_score: z.number().optional(),
|
|
34
|
+
document: z.union([z.string(), z.object({ text: z.string().optional() }).passthrough()]).optional(),
|
|
35
|
+
})
|
|
36
|
+
.passthrough(),
|
|
37
|
+
),
|
|
38
|
+
usage: z.object({ search_units: z.number().optional(), cost: z.number().optional() }).passthrough().optional(),
|
|
39
|
+
})
|
|
40
|
+
.passthrough()
|
|
41
|
+
|
|
42
|
+
export interface RerankDocument {
|
|
43
|
+
id: string
|
|
44
|
+
text: string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface RerankResultItem extends RerankDocument {
|
|
48
|
+
index: number
|
|
49
|
+
relevanceScore: number | null
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface RerankUsage {
|
|
53
|
+
searchUnits?: number
|
|
54
|
+
cost?: number
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface RerankResult {
|
|
58
|
+
modelId: string
|
|
59
|
+
results: RerankResultItem[]
|
|
60
|
+
usage?: RerankUsage
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function clampTopN(topN: number | undefined, total: number): number {
|
|
64
|
+
if (!Number.isFinite(topN)) return total
|
|
65
|
+
return Math.max(1, Math.min(total, Math.trunc(topN as number)))
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function matchRerankedDocument(
|
|
69
|
+
candidate: z.infer<typeof RerankResponseSchema>['results'][number],
|
|
70
|
+
documents: RerankDocument[],
|
|
71
|
+
): RerankDocument | null {
|
|
72
|
+
if (typeof candidate.index === 'number' && candidate.index >= 0 && candidate.index < documents.length) {
|
|
73
|
+
return documents[candidate.index] ?? null
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const text =
|
|
77
|
+
typeof candidate.document === 'string'
|
|
78
|
+
? candidate.document
|
|
79
|
+
: typeof candidate.document?.text === 'string'
|
|
80
|
+
? candidate.document.text
|
|
81
|
+
: null
|
|
82
|
+
if (!text) return null
|
|
83
|
+
|
|
84
|
+
return documents.find((document) => document.text === text) ?? null
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function makeRerankService(config: ResolvedLotaRuntimeConfig) {
|
|
88
|
+
function readConfiguredRerankModelId(): string | null {
|
|
89
|
+
const configured = config.memory.rerankerModelId
|
|
90
|
+
if (typeof configured !== 'string') return null
|
|
91
|
+
const trimmed = configured.trim()
|
|
92
|
+
return trimmed.length > 0 ? trimmed : null
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function resolveRerankModelId(modelId?: string): string {
|
|
96
|
+
const explicit = modelId?.trim()
|
|
97
|
+
if (explicit) return normalizeDirectOpenRouterModelId(explicit)
|
|
98
|
+
|
|
99
|
+
const configured = readConfiguredRerankModelId()
|
|
100
|
+
if (configured) return normalizeDirectOpenRouterModelId(configured)
|
|
101
|
+
|
|
102
|
+
return OPENROUTER_FAST_RERANK_MODEL_ID
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
rerankDocuments(params: { query: string; documents: RerankDocument[]; topN?: number; modelId?: string }) {
|
|
107
|
+
return Effect.gen(function* () {
|
|
108
|
+
if (params.documents.length === 0) {
|
|
109
|
+
return { modelId: resolveRerankModelId(params.modelId), results: [] as RerankResultItem[] }
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const apiKey = resolveOpenRouterApiKey(config.aiGateway.openRouterApiKey)
|
|
113
|
+
const modelId = resolveRerankModelId(params.modelId)
|
|
114
|
+
const topN = clampTopN(params.topN, params.documents.length)
|
|
115
|
+
|
|
116
|
+
const response = yield* tryRerankPromise('fetch-rerank', 'Failed to fetch rerank results.', () =>
|
|
117
|
+
Bun.fetch(OPENROUTER_RERANK_URL, {
|
|
118
|
+
method: 'POST',
|
|
119
|
+
headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json' },
|
|
120
|
+
body: JSON.stringify({
|
|
121
|
+
model: modelId,
|
|
122
|
+
query: params.query,
|
|
123
|
+
documents: params.documents.map((document) => document.text),
|
|
124
|
+
top_n: topN,
|
|
125
|
+
}),
|
|
126
|
+
}),
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
const responseText = yield* tryRerankPromise(
|
|
130
|
+
'read-rerank-response',
|
|
131
|
+
'Failed to read rerank response body.',
|
|
132
|
+
() => response.text(),
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
if (!response.ok) {
|
|
136
|
+
return yield* new RerankServiceError({
|
|
137
|
+
operation: 'fetch-rerank',
|
|
138
|
+
message: `OpenRouter rerank failed (${response.status}): ${responseText}`,
|
|
139
|
+
cause: responseText,
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const payload = yield* Schema.decodeUnknownEffect(Schema.UnknownFromJsonString)(responseText).pipe(
|
|
144
|
+
Effect.mapError((cause) =>
|
|
145
|
+
toRerankServiceError(
|
|
146
|
+
'parse-rerank-json',
|
|
147
|
+
`Rerank service returned invalid JSON (status ${response.status}): ${responseText.slice(0, 200)}`,
|
|
148
|
+
cause,
|
|
149
|
+
),
|
|
150
|
+
),
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
const parsedResponse = RerankResponseSchema.safeParse(payload)
|
|
154
|
+
if (!parsedResponse.success) {
|
|
155
|
+
return yield* toValidationError(parsedResponse.error, 'Rerank service returned an invalid response payload')
|
|
156
|
+
}
|
|
157
|
+
const parsed = parsedResponse.data
|
|
158
|
+
const seen = new Set<string>()
|
|
159
|
+
const results: RerankResultItem[] = []
|
|
160
|
+
|
|
161
|
+
for (const item of parsed.results) {
|
|
162
|
+
const matched = matchRerankedDocument(item, params.documents)
|
|
163
|
+
if (!matched || seen.has(matched.id)) continue
|
|
164
|
+
seen.add(matched.id)
|
|
165
|
+
|
|
166
|
+
results.push({
|
|
167
|
+
id: matched.id,
|
|
168
|
+
text: matched.text,
|
|
169
|
+
index: item.index ?? params.documents.findIndex((document) => document.id === matched.id),
|
|
170
|
+
relevanceScore: typeof item.relevance_score === 'number' ? item.relevance_score : null,
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
if (results.length >= topN) break
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
modelId: parsed.model?.trim() || modelId,
|
|
178
|
+
results,
|
|
179
|
+
usage: parsed.usage
|
|
180
|
+
? {
|
|
181
|
+
...(parsed.usage.search_units !== undefined ? { searchUnits: parsed.usage.search_units } : {}),
|
|
182
|
+
...(parsed.usage.cost !== undefined ? { cost: parsed.usage.cost } : {}),
|
|
183
|
+
}
|
|
184
|
+
: undefined,
|
|
185
|
+
}
|
|
186
|
+
})
|
|
187
|
+
},
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export class RerankServiceTag extends Context.Service<RerankServiceTag, ReturnType<typeof makeRerankService>>()(
|
|
192
|
+
'@lota-sdk/core/RerankService',
|
|
193
|
+
) {}
|
|
194
|
+
|
|
195
|
+
export const RerankServiceLive = Layer.effect(
|
|
196
|
+
RerankServiceTag,
|
|
197
|
+
Effect.gen(function* () {
|
|
198
|
+
const runtimeConfig = yield* RuntimeConfigServiceTag
|
|
199
|
+
return makeRerankService(runtimeConfig)
|
|
200
|
+
}),
|
|
201
|
+
)
|
|
@@ -1,86 +1,108 @@
|
|
|
1
1
|
import type { MonitoringWindowConfig } from '@lota-sdk/shared'
|
|
2
|
+
import { Context, Effect, Layer } from 'effect'
|
|
2
3
|
|
|
3
|
-
import {
|
|
4
|
+
import { ValidationError } from '../effect/errors'
|
|
5
|
+
import type { makePlanSchedulerService } from './plan/plan-scheduler.service'
|
|
6
|
+
import { PlanSchedulerServiceTag } from './plan/plan-scheduler.service'
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
currentInterval = Math.min(currentInterval / config.decayFactor, config.maxIntervalMs)
|
|
14
|
-
}
|
|
15
|
-
return times
|
|
8
|
+
function computeCheckTimes(config: MonitoringWindowConfig): { offsetMs: number; intervalMs: number }[] {
|
|
9
|
+
const times: { offsetMs: number; intervalMs: number }[] = []
|
|
10
|
+
let currentInterval = config.initialIntervalMs
|
|
11
|
+
let elapsed = 0
|
|
12
|
+
while (elapsed < config.durationMs) {
|
|
13
|
+
times.push({ offsetMs: elapsed, intervalMs: currentInterval })
|
|
14
|
+
elapsed += currentInterval
|
|
15
|
+
currentInterval = Math.min(currentInterval / config.decayFactor, config.maxIntervalMs)
|
|
16
16
|
}
|
|
17
|
+
return times
|
|
18
|
+
}
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}): Promise<void> {
|
|
25
|
-
await planSchedulerService.createSchedule({
|
|
26
|
-
organizationId: params.organizationId,
|
|
27
|
-
threadId: params.threadId,
|
|
28
|
-
runId: params.runId,
|
|
29
|
-
nodeId: params.nodeId,
|
|
30
|
-
scheduleSpec: {
|
|
31
|
-
type: 'monitoring',
|
|
32
|
-
intervalMs: params.config.initialIntervalMs,
|
|
33
|
-
maxFires: this.computeCheckTimes(params.config).length,
|
|
34
|
-
missedPolicy: 'skip',
|
|
35
|
-
},
|
|
36
|
-
})
|
|
37
|
-
}
|
|
20
|
+
function evaluateTerminationEffect(params: {
|
|
21
|
+
samples: unknown[]
|
|
22
|
+
config: MonitoringWindowConfig
|
|
23
|
+
}): Effect.Effect<boolean, ValidationError> {
|
|
24
|
+
if (!params.config.earlyTermination) return Effect.succeed(false)
|
|
25
|
+
if (params.samples.length < params.config.earlyTermination.minSamples) return Effect.succeed(false)
|
|
38
26
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
27
|
+
const { condition, minSamples } = params.config.earlyTermination
|
|
28
|
+
const numericSamples = params.samples
|
|
29
|
+
.map((s) =>
|
|
30
|
+
typeof s === 'number'
|
|
31
|
+
? s
|
|
32
|
+
: typeof s === 'object' && s !== null && 'value' in s
|
|
33
|
+
? Number((s as Record<string, unknown>).value)
|
|
34
|
+
: NaN,
|
|
35
|
+
)
|
|
36
|
+
.filter((n) => !isNaN(n))
|
|
42
37
|
|
|
43
|
-
|
|
44
|
-
const numericSamples = params.samples
|
|
45
|
-
.map((s) =>
|
|
46
|
-
typeof s === 'number'
|
|
47
|
-
? s
|
|
48
|
-
: typeof s === 'object' && s !== null && 'value' in s
|
|
49
|
-
? Number((s as Record<string, unknown>).value)
|
|
50
|
-
: NaN,
|
|
51
|
-
)
|
|
52
|
-
.filter((n) => !isNaN(n))
|
|
38
|
+
if (numericSamples.length === 0) return Effect.succeed(false)
|
|
53
39
|
|
|
54
|
-
|
|
55
|
-
|
|
40
|
+
if (condition === 'stable') {
|
|
41
|
+
const recent = numericSamples.slice(-minSamples)
|
|
42
|
+
if (recent.length < 2) return Effect.succeed(false)
|
|
43
|
+
const mean = recent.reduce((a, b) => a + b, 0) / recent.length
|
|
44
|
+
const variance = recent.reduce((a, b) => a + (b - mean) ** 2, 0) / recent.length
|
|
45
|
+
const cv = mean !== 0 ? Math.sqrt(variance) / Math.abs(mean) : 0
|
|
46
|
+
return Effect.succeed(cv < 0.1)
|
|
47
|
+
}
|
|
56
48
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const cv = mean !== 0 ? Math.sqrt(variance) / Math.abs(mean) : 0
|
|
63
|
-
return cv < 0.1
|
|
64
|
-
}
|
|
49
|
+
const thresholdMatch = condition.match(/^threshold:(\d+(?:\.\d+)?)$/)
|
|
50
|
+
if (thresholdMatch?.[1]) {
|
|
51
|
+
const threshold = parseFloat(thresholdMatch[1])
|
|
52
|
+
return Effect.succeed(numericSamples.some((v) => v >= threshold))
|
|
53
|
+
}
|
|
65
54
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
55
|
+
if (condition === 'trend:declining') {
|
|
56
|
+
const recent = numericSamples.slice(-minSamples)
|
|
57
|
+
return Effect.succeed(recent.length >= 2 && recent.every((v, i) => i === 0 || v <= (recent[i - 1] ?? v)))
|
|
58
|
+
}
|
|
71
59
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
60
|
+
if (condition === 'trend:increasing') {
|
|
61
|
+
const recent = numericSamples.slice(-minSamples)
|
|
62
|
+
return Effect.succeed(recent.length >= 2 && recent.every((v, i) => i === 0 || v >= (recent[i - 1] ?? v)))
|
|
63
|
+
}
|
|
76
64
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
return recent.length >= 2 && recent.every((v, i) => i === 0 || v >= (recent[i - 1] ?? v))
|
|
80
|
-
}
|
|
65
|
+
return Effect.fail(new ValidationError({ message: `Unknown monitoring termination condition: ${condition}` }))
|
|
66
|
+
}
|
|
81
67
|
|
|
82
|
-
|
|
68
|
+
export function makeMonitoringWindowService(planSchedulerService: ReturnType<typeof makePlanSchedulerService>) {
|
|
69
|
+
return {
|
|
70
|
+
computeCheckTimes,
|
|
71
|
+
startMonitoringWindow(params: {
|
|
72
|
+
runId: string
|
|
73
|
+
nodeId: string
|
|
74
|
+
config: MonitoringWindowConfig
|
|
75
|
+
organizationId: string
|
|
76
|
+
threadId: string
|
|
77
|
+
}) {
|
|
78
|
+
return Effect.asVoid(
|
|
79
|
+
planSchedulerService.createSchedule({
|
|
80
|
+
organizationId: params.organizationId,
|
|
81
|
+
threadId: params.threadId,
|
|
82
|
+
runId: params.runId,
|
|
83
|
+
nodeId: params.nodeId,
|
|
84
|
+
scheduleSpec: {
|
|
85
|
+
type: 'monitoring',
|
|
86
|
+
intervalMs: params.config.initialIntervalMs,
|
|
87
|
+
maxFires: computeCheckTimes(params.config).length,
|
|
88
|
+
missedPolicy: 'skip',
|
|
89
|
+
},
|
|
90
|
+
}),
|
|
91
|
+
)
|
|
92
|
+
},
|
|
93
|
+
evaluateTermination: evaluateTerminationEffect,
|
|
83
94
|
}
|
|
84
95
|
}
|
|
85
96
|
|
|
86
|
-
export
|
|
97
|
+
export class MonitoringWindowServiceTag extends Context.Service<
|
|
98
|
+
MonitoringWindowServiceTag,
|
|
99
|
+
ReturnType<typeof makeMonitoringWindowService>
|
|
100
|
+
>()('@lota-sdk/core/MonitoringWindowService') {}
|
|
101
|
+
|
|
102
|
+
export const MonitoringWindowServiceLive = Layer.effect(
|
|
103
|
+
MonitoringWindowServiceTag,
|
|
104
|
+
Effect.gen(function* () {
|
|
105
|
+
const planSchedulerService = yield* PlanSchedulerServiceTag
|
|
106
|
+
return makeMonitoringWindowService(planSchedulerService)
|
|
107
|
+
}),
|
|
108
|
+
)
|
|
@@ -1,18 +1,13 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Context, Effect, Layer } from 'effect'
|
|
2
|
+
|
|
2
3
|
import { ensureRecordId } from '../db/record-id'
|
|
3
4
|
import { TABLES } from '../db/tables'
|
|
4
5
|
import { extractMessageText } from '../runtime/thread-chat-helpers'
|
|
5
|
-
import {
|
|
6
|
+
import type { makeThreadMessageService } from './thread/thread-message.service'
|
|
7
|
+
import { ThreadMessageServiceTag } from './thread/thread-message.service'
|
|
6
8
|
|
|
7
9
|
const APPROVAL_VERIFICATION_MESSAGE_WINDOW = 20
|
|
8
10
|
|
|
9
|
-
type VerifyMutatingApproval = (params: {
|
|
10
|
-
threadId: string
|
|
11
|
-
approvalReason: string
|
|
12
|
-
approvalToken: string
|
|
13
|
-
approvalMessageId?: string
|
|
14
|
-
}) => Promise<{ ok: true } | { ok: false; reason: string }>
|
|
15
|
-
|
|
16
11
|
function extractQuotedValue(value: string): string {
|
|
17
12
|
const trimmed = value.trim()
|
|
18
13
|
if (
|
|
@@ -58,50 +53,64 @@ function messageContainsExactApproval(messageText: string, approvalToken: string
|
|
|
58
53
|
return extracted.token === approvalToken && extracted.reason === approvalReason
|
|
59
54
|
}
|
|
60
55
|
|
|
61
|
-
|
|
62
|
-
threadId:
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
56
|
+
export function makeMutatingApprovalService(threadMessageService: ReturnType<typeof makeThreadMessageService>) {
|
|
57
|
+
return (params: { threadId: string; approvalReason: string; approvalToken: string; approvalMessageId?: string }) => {
|
|
58
|
+
const threadId = ensureRecordId(params.threadId, TABLES.THREAD)
|
|
59
|
+
return Effect.gen(function* () {
|
|
60
|
+
const token = extractQuotedValue(params.approvalToken)
|
|
61
|
+
const reason = extractQuotedValue(params.approvalReason)
|
|
62
|
+
const approvalMessageId = params.approvalMessageId?.trim()
|
|
63
|
+
if (!token || !reason) {
|
|
64
|
+
return { ok: false as const, reason: 'Mutating approval metadata is incomplete.' }
|
|
65
|
+
}
|
|
66
|
+
if (params.approvalMessageId !== undefined && !approvalMessageId) {
|
|
67
|
+
return { ok: false as const, reason: 'approvalMessageId cannot be empty when provided.' }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const recentMessages = yield* threadMessageService.listRecentMessages(
|
|
71
|
+
threadId,
|
|
72
|
+
APPROVAL_VERIFICATION_MESSAGE_WINDOW,
|
|
73
|
+
)
|
|
74
|
+
const userMessages = recentMessages.filter((message) => message.role === 'user')
|
|
75
|
+
if (userMessages.length === 0) {
|
|
76
|
+
return { ok: false as const, reason: 'No user message history available to verify mutating approval.' }
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const latestUserMessage = userMessages.at(-1)
|
|
80
|
+
if (!latestUserMessage) {
|
|
81
|
+
return { ok: false as const, reason: 'Latest user message was not found for mutating approval verification.' }
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (approvalMessageId && approvalMessageId !== latestUserMessage.id) {
|
|
85
|
+
return {
|
|
86
|
+
ok: false as const,
|
|
87
|
+
reason:
|
|
88
|
+
'approvalMessageId must reference the latest user message for mutating approval verification; stale approvals are not accepted.',
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (!messageContainsExactApproval(extractMessageText(latestUserMessage), token, reason)) {
|
|
93
|
+
return {
|
|
94
|
+
ok: false as const,
|
|
95
|
+
reason:
|
|
96
|
+
'Referenced approval message must contain exact approval fields: "Approval Token: <token>" and "Approval Reason: <reason>".',
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return { ok: true as const }
|
|
101
|
+
})
|
|
92
102
|
}
|
|
93
|
-
|
|
94
|
-
if (!messageContainsExactApproval(extractMessageText(latestUserMessage), token, reason)) {
|
|
95
|
-
return {
|
|
96
|
-
ok: false,
|
|
97
|
-
reason:
|
|
98
|
-
'Referenced approval message must contain exact approval fields: "Approval Token: <token>" and "Approval Reason: <reason>".',
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return { ok: true }
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
export
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
export class MutatingApprovalServiceTag extends Context.Service<
|
|
106
|
+
MutatingApprovalServiceTag,
|
|
107
|
+
ReturnType<typeof makeMutatingApprovalService>
|
|
108
|
+
>()('@lota-sdk/core/MutatingApprovalService') {}
|
|
109
|
+
|
|
110
|
+
export const MutatingApprovalServiceLive = Layer.effect(
|
|
111
|
+
MutatingApprovalServiceTag,
|
|
112
|
+
Effect.gen(function* () {
|
|
113
|
+
const threadMessageService = yield* ThreadMessageServiceTag
|
|
114
|
+
return makeMutatingApprovalService(threadMessageService)
|
|
115
|
+
}),
|
|
116
|
+
)
|