@lota-sdk/core 0.4.9 → 0.4.11
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 +2 -2
- package/src/ai/embedding-cache.ts +3 -1
- package/src/ai-gateway/ai-gateway.ts +164 -82
- package/src/ai-gateway/index.ts +16 -1
- package/src/config/agent-defaults.ts +4 -107
- package/src/config/agent-types.ts +1 -1
- package/src/config/background-processing.ts +1 -1
- package/src/config/index.ts +0 -1
- package/src/config/logger.ts +22 -25
- package/src/config/thread-defaults.ts +1 -10
- package/src/create-runtime.ts +145 -670
- package/src/db/base.service.ts +30 -38
- package/src/db/memory-query-builder.ts +2 -1
- package/src/db/memory-store.ts +29 -20
- package/src/db/memory.ts +188 -195
- package/src/db/service-normalization.ts +97 -64
- package/src/db/service.ts +496 -384
- package/src/db/startup.ts +30 -19
- package/src/effect/helpers.ts +30 -5
- package/src/effect/index.ts +7 -7
- package/src/effect/layers.ts +75 -72
- package/src/effect/services.ts +15 -11
- package/src/embeddings/provider.ts +65 -71
- package/src/index.ts +13 -12
- package/src/queues/autonomous-job.queue.ts +177 -143
- package/src/queues/context-compaction.queue.ts +41 -39
- package/src/queues/delayed-node-promotion.queue.ts +61 -42
- package/src/queues/document-processor.queue.ts +5 -3
- package/src/queues/index.ts +1 -0
- package/src/queues/memory-consolidation.queue.ts +79 -53
- package/src/queues/organization-learning.queue.ts +70 -33
- package/src/queues/plan-agent-heartbeat.queue.ts +111 -83
- package/src/queues/plan-scheduler.queue.ts +101 -97
- package/src/queues/post-chat-memory.queue.ts +56 -46
- package/src/queues/queue-factory.ts +146 -69
- package/src/queues/queues.service.ts +61 -0
- package/src/queues/title-generation.queue.ts +44 -44
- package/src/redis/connection.ts +181 -164
- package/src/redis/org-memory-lock.ts +24 -9
- package/src/redis/redis-lease-lock.ts +8 -1
- package/src/redis/stream-context.ts +17 -9
- package/src/runtime/agent-identity-overrides.ts +7 -3
- package/src/runtime/agent-runtime-policy.ts +10 -5
- package/src/runtime/agent-stream-helpers.ts +24 -15
- package/src/runtime/chat-run-orchestration.ts +1 -1
- package/src/runtime/context-compaction/context-compaction-runtime.ts +28 -32
- package/src/runtime/context-compaction/context-compaction.ts +131 -85
- package/src/runtime/domain-layer.ts +203 -0
- package/src/runtime/execution-plan-visibility.ts +5 -2
- package/src/runtime/graph-designer.ts +0 -14
- package/src/runtime/helper-model.ts +8 -4
- package/src/runtime/index.ts +1 -1
- package/src/runtime/indexed-repositories-policy.ts +2 -6
- package/src/runtime/memory/memory-block.ts +19 -9
- package/src/runtime/memory/memory-pipeline.ts +53 -66
- package/src/runtime/memory/memory-scope.ts +33 -29
- package/src/runtime/plugin-resolution.ts +58 -62
- package/src/runtime/post-turn-side-effects.ts +139 -161
- package/src/runtime/retrieval-adapters.ts +4 -4
- package/src/runtime/runtime-config.ts +3 -9
- package/src/runtime/runtime-extensions.ts +0 -43
- package/src/runtime/runtime-lifecycle.ts +124 -0
- package/src/runtime/runtime-services.ts +455 -0
- package/src/runtime/runtime-worker-registry.ts +113 -30
- package/src/runtime/social-chat/social-chat-agent-runner.ts +13 -8
- package/src/runtime/social-chat/social-chat-history.ts +24 -13
- package/src/runtime/social-chat/social-chat.ts +420 -369
- package/src/runtime/team-consultation/team-consultation-orchestrator.ts +64 -57
- package/src/runtime/team-consultation/team-consultation-prompts.ts +11 -6
- package/src/runtime/thread-chat-helpers.ts +18 -9
- package/src/runtime/thread-turn-context.ts +28 -74
- package/src/runtime/turn-lifecycle.ts +6 -14
- package/src/services/agent-activity.service.ts +169 -176
- package/src/services/agent-executor.service.ts +207 -196
- package/src/services/artifact.service.ts +10 -5
- package/src/services/attachment.service.ts +16 -48
- package/src/services/autonomous-job.service.ts +81 -87
- package/src/services/background-work.service.ts +54 -0
- package/src/services/chat-run-registry.service.ts +3 -1
- package/src/services/context-compaction.service.ts +8 -10
- package/src/services/document-chunk.service.ts +8 -17
- package/src/services/execution-plan/execution-plan-graph.ts +122 -109
- package/src/services/execution-plan/execution-plan-schedule.ts +1 -15
- package/src/services/execution-plan/execution-plan.service.ts +68 -51
- package/src/services/feedback-loop.service.ts +1 -1
- package/src/services/global-orchestrator.service.ts +49 -15
- package/src/services/graph-full-routing.ts +49 -37
- package/src/services/index.ts +1 -0
- package/src/services/institutional-memory.service.ts +8 -17
- package/src/services/learned-skill.service.ts +38 -35
- package/src/services/memory/memory-conversation.ts +10 -5
- package/src/services/memory/memory-errors.ts +27 -0
- package/src/services/memory/memory-org-memory.ts +14 -3
- package/src/services/memory/memory-preseeded.ts +10 -4
- package/src/services/memory/memory-utils.ts +2 -1
- package/src/services/memory/memory.service.ts +37 -52
- package/src/services/memory/rerank.service.ts +3 -11
- package/src/services/monitoring-window.service.ts +1 -1
- package/src/services/mutating-approval.service.ts +1 -1
- package/src/services/node-workspace.service.ts +2 -2
- package/src/services/notification.service.ts +16 -4
- package/src/services/organization-member.service.ts +1 -1
- package/src/services/organization.service.ts +34 -51
- package/src/services/ownership-dispatcher.service.ts +148 -95
- package/src/services/plan/plan-agent-heartbeat.service.ts +30 -16
- package/src/services/plan/plan-agent-query.service.ts +13 -9
- package/src/services/plan/plan-approval.service.ts +52 -48
- package/src/services/plan/plan-artifact.service.ts +2 -2
- package/src/services/plan/plan-builder.service.ts +2 -2
- package/src/services/plan/plan-checkpoint.service.ts +1 -1
- package/src/services/plan/plan-compiler.service.ts +1 -1
- package/src/services/plan/plan-completion-side-effects.ts +99 -113
- package/src/services/plan/plan-coordination.service.ts +1 -1
- package/src/services/plan/plan-cycle.service.ts +171 -202
- package/src/services/plan/plan-deadline.service.ts +304 -307
- package/src/services/plan/plan-event-delivery.service.ts +84 -72
- package/src/services/plan/plan-executor-context.ts +2 -0
- package/src/services/plan/plan-executor-graph.ts +375 -353
- package/src/services/plan/plan-executor-helpers.ts +60 -75
- package/src/services/plan/plan-executor.service.ts +494 -489
- package/src/services/plan/plan-run.service.ts +12 -19
- package/src/services/plan/plan-scheduler.service.ts +89 -82
- package/src/services/plan/plan-template.service.ts +1 -1
- package/src/services/plan/plan-transaction-events.ts +8 -5
- package/src/services/plan/plan-validator.service.ts +1 -1
- package/src/services/plan/plan-workspace.service.ts +17 -11
- package/src/services/plugin-executor.service.ts +26 -21
- package/src/services/quality-metrics.service.ts +1 -1
- package/src/services/queue-job.service.ts +8 -17
- package/src/services/recent-activity-title.service.ts +22 -10
- package/src/services/recent-activity.service.ts +1 -1
- package/src/services/skill-resolver.service.ts +1 -1
- package/src/services/social-chat-history.service.ts +37 -20
- package/src/services/system-executor.service.ts +25 -20
- package/src/services/thread/thread-bootstrap.ts +37 -19
- package/src/services/thread/thread-listing.ts +2 -1
- package/src/services/thread/thread-memory-block.ts +18 -5
- package/src/services/thread/thread-message.service.ts +30 -13
- package/src/services/thread/thread-title.service.ts +1 -1
- package/src/services/thread/thread-turn-execution.ts +87 -83
- package/src/services/thread/thread-turn-preparation.service.ts +65 -40
- package/src/services/thread/thread-turn-streaming.ts +32 -36
- package/src/services/thread/thread-turn.ts +43 -29
- package/src/services/thread/thread.service.ts +32 -8
- package/src/services/user.service.ts +1 -1
- package/src/services/write-intent-validator.service.ts +1 -1
- package/src/storage/attachment-storage.service.ts +7 -4
- package/src/storage/generated-document-storage.service.ts +1 -1
- package/src/system-agents/context-compaction.agent.ts +1 -1
- package/src/system-agents/helper-agent-options.ts +1 -1
- package/src/system-agents/memory-reranker.agent.ts +1 -1
- package/src/system-agents/memory.agent.ts +1 -1
- package/src/system-agents/recent-activity-title-refiner.agent.ts +9 -6
- package/src/system-agents/regular-chat-memory-digest.agent.ts +1 -1
- package/src/system-agents/skill-extractor.agent.ts +1 -1
- package/src/system-agents/skill-manager.agent.ts +1 -1
- package/src/system-agents/thread-router.agent.ts +23 -20
- package/src/system-agents/title-generator.agent.ts +1 -1
- package/src/tools/execution-plan.tool.ts +36 -20
- package/src/tools/fetch-webpage.tool.ts +30 -22
- package/src/tools/firecrawl-client.ts +1 -6
- package/src/tools/plan-approval.tool.ts +9 -1
- package/src/tools/remember-memory.tool.ts +3 -6
- package/src/tools/research-topic.tool.ts +12 -3
- package/src/tools/search-web.tool.ts +26 -18
- package/src/tools/search.tool.ts +4 -5
- package/src/tools/team-think.tool.ts +139 -121
- package/src/utils/async.ts +15 -6
- package/src/utils/errors.ts +27 -15
- package/src/workers/bootstrap.ts +34 -58
- package/src/workers/memory-consolidation.worker.ts +4 -1
- package/src/workers/organization-learning.worker.ts +16 -3
- package/src/workers/regular-chat-memory-digest.helpers.ts +3 -4
- package/src/workers/regular-chat-memory-digest.runner.ts +46 -29
- package/src/workers/skill-extraction.runner.ts +13 -15
- package/src/workers/worker-utils.ts +14 -8
- package/src/config/search.ts +0 -3
- package/src/effect/awaitable-effect.ts +0 -87
- package/src/effect/runtime-ref.ts +0 -25
- package/src/effect/runtime.ts +0 -31
- package/src/redis/runtime-connection.ts +0 -10
- package/src/runtime/agent-types.ts +0 -1
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { PlanExecutionVisibility, PlanNodeSpecRecord, PlanSpecRecord } from '@lota-sdk/shared'
|
|
2
2
|
|
|
3
|
+
import type { ResolvedAgentConfig } from '../config/agent-defaults'
|
|
3
4
|
import { isAgentName } from '../config/agent-defaults'
|
|
4
5
|
|
|
5
6
|
export function resolvePlanNodeExecutionVisibility(
|
|
7
|
+
agentConfig: ResolvedAgentConfig,
|
|
6
8
|
plan: Pick<PlanSpecRecord, 'defaultExecutionVisibility'>,
|
|
7
9
|
node: Pick<PlanNodeSpecRecord, 'executionVisibility' | 'owner'>,
|
|
8
10
|
): PlanExecutionVisibility {
|
|
@@ -12,12 +14,13 @@ export function resolvePlanNodeExecutionVisibility(
|
|
|
12
14
|
return configuredVisibility
|
|
13
15
|
}
|
|
14
16
|
|
|
15
|
-
return node.owner.executorType === 'agent' && isAgentName(node.owner.ref) ? 'visible' : 'silent'
|
|
17
|
+
return node.owner.executorType === 'agent' && isAgentName(agentConfig, node.owner.ref) ? 'visible' : 'silent'
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
export function shouldPlanNodeUseVisibleTurn(
|
|
21
|
+
agentConfig: ResolvedAgentConfig,
|
|
19
22
|
plan: Pick<PlanSpecRecord, 'defaultExecutionVisibility'>,
|
|
20
23
|
node: Pick<PlanNodeSpecRecord, 'executionVisibility' | 'owner'>,
|
|
21
24
|
): boolean {
|
|
22
|
-
return resolvePlanNodeExecutionVisibility(plan, node) === 'visible'
|
|
25
|
+
return resolvePlanNodeExecutionVisibility(agentConfig, plan, node) === 'visible'
|
|
23
26
|
}
|
|
@@ -1,19 +1,5 @@
|
|
|
1
1
|
import type { GraphDesignRequest, GraphDesignResponse } from '@lota-sdk/shared'
|
|
2
|
-
import { Effect } from 'effect'
|
|
3
|
-
|
|
4
|
-
import { getOptionalCurrentRuntime } from '../effect/runtime-ref'
|
|
5
|
-
import { RuntimeConfigServiceTag } from '../effect/services'
|
|
6
2
|
|
|
7
3
|
export interface GraphDesigner {
|
|
8
4
|
designGraph(request: GraphDesignRequest): Promise<GraphDesignResponse>
|
|
9
5
|
}
|
|
10
|
-
|
|
11
|
-
export function getGraphDesigner(): GraphDesigner | null {
|
|
12
|
-
const runtime = getOptionalCurrentRuntime()
|
|
13
|
-
if (!runtime) {
|
|
14
|
-
return null
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const runtimeConfig = runtime.runSync(Effect.service(RuntimeConfigServiceTag))
|
|
18
|
-
return runtimeConfig.graphDesigner ?? null
|
|
19
|
-
}
|
|
@@ -253,7 +253,7 @@ export function createHelperModelRuntime() {
|
|
|
253
253
|
}
|
|
254
254
|
|
|
255
255
|
function generateHelperText(params: GenerateHelperTextParams): Promise<string> {
|
|
256
|
-
return Effect.runPromise(generateHelperTextEffect(params))
|
|
256
|
+
return Effect.runPromise(generateHelperTextEffect(params).pipe(Effect.withSpan('HelperModel.generateHelperText')))
|
|
257
257
|
}
|
|
258
258
|
|
|
259
259
|
function generateHelperStructuredEffect<T>(
|
|
@@ -300,7 +300,9 @@ export function createHelperModelRuntime() {
|
|
|
300
300
|
}
|
|
301
301
|
|
|
302
302
|
function generateHelperStructured<T>(params: GenerateHelperStructuredParams<T>): Promise<T> {
|
|
303
|
-
return Effect.runPromise(
|
|
303
|
+
return Effect.runPromise(
|
|
304
|
+
generateHelperStructuredEffect(params).pipe(Effect.withSpan('HelperModel.generateHelperStructured')),
|
|
305
|
+
)
|
|
304
306
|
}
|
|
305
307
|
|
|
306
308
|
return { generateHelperTextEffect, generateHelperText, generateHelperStructuredEffect, generateHelperStructured }
|
|
@@ -308,6 +310,8 @@ export function createHelperModelRuntime() {
|
|
|
308
310
|
|
|
309
311
|
export type HelperModelRuntime = ReturnType<typeof createHelperModelRuntime>
|
|
310
312
|
|
|
311
|
-
export class HelperModelTag extends Context.Service<HelperModelTag, HelperModelRuntime>()(
|
|
313
|
+
export class HelperModelTag extends Context.Service<HelperModelTag, HelperModelRuntime>()(
|
|
314
|
+
'@lota-sdk/core/HelperModel',
|
|
315
|
+
) {}
|
|
312
316
|
|
|
313
|
-
export const HelperModelLive = Layer.
|
|
317
|
+
export const HelperModelLive = Layer.sync(HelperModelTag, () => createHelperModelRuntime())
|
package/src/runtime/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export * from './approval-continuation'
|
|
2
2
|
export * from './agent-runtime-policy'
|
|
3
3
|
export * from './agent-stream-helpers'
|
|
4
|
-
export * from './agent-types'
|
|
5
4
|
export * from './chat-request-routing'
|
|
5
|
+
export * from './chat-run-orchestration'
|
|
6
6
|
export * from './chat-run-registry'
|
|
7
7
|
export * from './context-compaction/context-compaction'
|
|
8
8
|
export * from './execution-plan'
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { getAgentRoster } from '../config/agent-defaults'
|
|
2
|
-
|
|
3
1
|
export type IndexedRepoAgentName = string
|
|
4
2
|
|
|
5
3
|
export const REPO_SECTION_NAMES = [
|
|
@@ -16,13 +14,11 @@ export type RepoSectionName = (typeof REPO_SECTION_NAMES)[number]
|
|
|
16
14
|
const ALL_REPO_SECTIONS: RepoSectionName[] = [...REPO_SECTION_NAMES]
|
|
17
15
|
|
|
18
16
|
export function buildDefaultRepoSectionsByAgent(
|
|
19
|
-
roster: readonly IndexedRepoAgentName[]
|
|
17
|
+
roster: readonly IndexedRepoAgentName[],
|
|
20
18
|
): Record<IndexedRepoAgentName, RepoSectionName[]> {
|
|
21
19
|
return Object.fromEntries(roster.map((agentId) => [agentId, [...ALL_REPO_SECTIONS]]))
|
|
22
20
|
}
|
|
23
21
|
|
|
24
|
-
export function emptyAgentContextMap(
|
|
25
|
-
roster: readonly IndexedRepoAgentName[] = getAgentRoster(),
|
|
26
|
-
): Record<IndexedRepoAgentName, string> {
|
|
22
|
+
export function emptyAgentContextMap(roster: readonly IndexedRepoAgentName[]): Record<IndexedRepoAgentName, string> {
|
|
27
23
|
return Object.fromEntries(roster.map((agentId) => [agentId, '']))
|
|
28
24
|
}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { DateTime, Effect } from 'effect'
|
|
1
|
+
import { Effect, Schema } from 'effect'
|
|
3
2
|
import { z } from 'zod'
|
|
4
3
|
|
|
5
|
-
import {
|
|
4
|
+
import { nowDate } from '../../utils/date-time'
|
|
6
5
|
import { compactWhitespace } from '../../utils/string'
|
|
7
6
|
|
|
7
|
+
export class MemoryBlockCompactError extends Schema.TaggedErrorClass<MemoryBlockCompactError>()(
|
|
8
|
+
'MemoryBlockCompactError',
|
|
9
|
+
{ message: Schema.String, cause: Schema.Defect },
|
|
10
|
+
) {}
|
|
11
|
+
|
|
8
12
|
function escapeRegex(value: string): string {
|
|
9
13
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
10
14
|
}
|
|
@@ -61,7 +65,7 @@ export interface CompactMemoryBlockEntriesParams {
|
|
|
61
65
|
compact: (params: {
|
|
62
66
|
previousSummary: string
|
|
63
67
|
newEntriesText: string
|
|
64
|
-
}) => PromiseLike<string> | Effect.Effect<string,
|
|
68
|
+
}) => PromiseLike<string> | Effect.Effect<string, MemoryBlockCompactError>
|
|
65
69
|
}
|
|
66
70
|
|
|
67
71
|
export interface CompactMemoryBlockEntriesResult {
|
|
@@ -106,7 +110,7 @@ function toMemoryBlockEntriesSource(entries: Array<{ role: string; content: stri
|
|
|
106
110
|
|
|
107
111
|
export function compactMemoryBlockEntries(
|
|
108
112
|
params: CompactMemoryBlockEntriesParams,
|
|
109
|
-
): Effect.Effect<CompactMemoryBlockEntriesResult,
|
|
113
|
+
): Effect.Effect<CompactMemoryBlockEntriesResult, MemoryBlockCompactError> {
|
|
110
114
|
return Effect.gen(function* () {
|
|
111
115
|
let summary = typeof params.previousSummary === 'string' ? params.previousSummary.trim() : ''
|
|
112
116
|
let entries = [...params.entries]
|
|
@@ -114,9 +118,15 @@ export function compactMemoryBlockEntries(
|
|
|
114
118
|
|
|
115
119
|
while (entries.length >= params.triggerEntries) {
|
|
116
120
|
const chunk = entries.slice(0, params.chunkEntries)
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
121
|
+
const compactParams = { previousSummary: summary, newEntriesText: toMemoryBlockEntriesSource(chunk) }
|
|
122
|
+
const value = params.compact(compactParams)
|
|
123
|
+
const raw = yield* Effect.isEffect(value)
|
|
124
|
+
? value
|
|
125
|
+
: Effect.tryPromise({
|
|
126
|
+
try: () => Promise.resolve(value),
|
|
127
|
+
catch: (cause) => new MemoryBlockCompactError({ message: 'compact callback failed', cause }),
|
|
128
|
+
})
|
|
129
|
+
const nextSummary = raw.trim()
|
|
120
130
|
|
|
121
131
|
if (!nextSummary) {
|
|
122
132
|
break
|
|
@@ -162,7 +172,7 @@ export interface CreateMemoryBlockRuntimeOptions {
|
|
|
162
172
|
export function createMemoryBlockRuntime(options: CreateMemoryBlockRuntimeOptions = {}): MemoryBlockRuntime {
|
|
163
173
|
const labelPrefixRegex = createLabelPrefixRegex(options.labelRoles ?? [])
|
|
164
174
|
const memoryBlockMaxChars = options.maxChars ?? 400
|
|
165
|
-
const now = options.now ??
|
|
175
|
+
const now = options.now ?? nowDate
|
|
166
176
|
|
|
167
177
|
const normalizeMemoryBlockEntry = (entry: string): string => {
|
|
168
178
|
const normalizedLines = entry
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Match } from 'effect'
|
|
2
|
+
|
|
1
3
|
import { clampImportance, compactWhitespace } from '../../utils/string'
|
|
2
4
|
|
|
3
5
|
const SCORE_WEIGHTS = {
|
|
@@ -123,20 +125,17 @@ function scoreFact<T extends MemoryFactInput>(fact: T): number {
|
|
|
123
125
|
const durability = fact.durability ?? 'standard'
|
|
124
126
|
const type = fact.type ?? 'fact'
|
|
125
127
|
|
|
126
|
-
const durabilityWeight =
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
: type === 'preference'
|
|
138
|
-
? SCORE_WEIGHTS.type.preference
|
|
139
|
-
: SCORE_WEIGHTS.type.default
|
|
128
|
+
const durabilityWeight = Match.value(durability).pipe(
|
|
129
|
+
Match.when('core', () => SCORE_WEIGHTS.durability.core),
|
|
130
|
+
Match.when('standard', () => SCORE_WEIGHTS.durability.standard),
|
|
131
|
+
Match.orElse(() => SCORE_WEIGHTS.durability.weak),
|
|
132
|
+
)
|
|
133
|
+
const typeWeight = Match.value(type).pipe(
|
|
134
|
+
Match.when('decision', () => SCORE_WEIGHTS.type.decision),
|
|
135
|
+
Match.when('fact', () => SCORE_WEIGHTS.type.fact),
|
|
136
|
+
Match.when('preference', () => SCORE_WEIGHTS.type.preference),
|
|
137
|
+
Match.orElse(() => SCORE_WEIGHTS.type.default),
|
|
138
|
+
)
|
|
140
139
|
const lengthWeight =
|
|
141
140
|
Math.min(fact.content.length, SCORE_WEIGHTS.maxContentLength) / SCORE_WEIGHTS.maxContentLength / 10
|
|
142
141
|
|
|
@@ -340,61 +339,49 @@ export function compileMemoryUpdatesFromDelta(params: {
|
|
|
340
339
|
deleteSet.add(invalidateId)
|
|
341
340
|
}
|
|
342
341
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
}
|
|
342
|
+
const nextUpdates = Match.value(item.classification).pipe(
|
|
343
|
+
Match.when('duplicate', (): MemoryUpdateItemLike[] => {
|
|
344
|
+
const targetId = item.targetMemoryIds[0]
|
|
345
|
+
if (targetId) {
|
|
346
|
+
return [{ id: targetId, text: existingById.get(targetId) ?? item.fact, event: 'NONE' }]
|
|
347
|
+
}
|
|
348
|
+
return [{ id: `noop_${item.index}`, text: item.fact, event: 'NONE' }]
|
|
349
|
+
}),
|
|
350
|
+
Match.when('enriches', (): MemoryUpdateItemLike[] => {
|
|
351
|
+
const targetId = item.targetMemoryIds[0]
|
|
352
|
+
if (targetId) {
|
|
353
|
+
const relations = buildRelations(item, 'new').filter((relation) => relation.memoryId !== targetId)
|
|
354
|
+
return [
|
|
355
|
+
{
|
|
356
|
+
id: targetId,
|
|
357
|
+
text: item.fact,
|
|
358
|
+
event: 'UPDATE',
|
|
359
|
+
oldMemory: existingById.get(targetId),
|
|
360
|
+
...(relations.length > 0 ? { relatesTo: relations } : {}),
|
|
361
|
+
},
|
|
362
|
+
]
|
|
363
|
+
}
|
|
366
364
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
365
|
+
const addId = addIdByFactIndex.get(item.index) ?? nextAddId()
|
|
366
|
+
const relations = buildRelations(item, 'new')
|
|
367
|
+
return [{ id: addId, text: item.fact, event: 'ADD', ...(relations.length > 0 ? { relatesTo: relations } : {}) }]
|
|
368
|
+
}),
|
|
369
|
+
Match.whenOr('supersedes', 'contradicts', (classification): MemoryUpdateItemLike[] => {
|
|
370
|
+
const addId = addIdByFactIndex.get(item.index) ?? nextAddId()
|
|
371
|
+
const relations = buildRelations(item, classification)
|
|
372
|
+
return [{ id: addId, text: item.fact, event: 'ADD', ...(relations.length > 0 ? { relatesTo: relations } : {}) }]
|
|
373
|
+
}),
|
|
374
|
+
Match.when('new', (): MemoryUpdateItemLike[] => {
|
|
375
|
+
const addId = addIdByFactIndex.get(item.index) ?? nextAddId()
|
|
376
|
+
const relations = buildRelations(item, 'new')
|
|
377
|
+
return [{ id: addId, text: item.fact, event: 'ADD', ...(relations.length > 0 ? { relatesTo: relations } : {}) }]
|
|
378
|
+
}),
|
|
379
|
+
Match.exhaustive,
|
|
380
|
+
)
|
|
377
381
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
const relations = buildRelations(item, item.classification)
|
|
381
|
-
updates.push({
|
|
382
|
-
id: addId,
|
|
383
|
-
text: item.fact,
|
|
384
|
-
event: 'ADD',
|
|
385
|
-
...(relations.length > 0 ? { relatesTo: relations } : {}),
|
|
386
|
-
})
|
|
387
|
-
continue
|
|
382
|
+
for (const update of nextUpdates) {
|
|
383
|
+
updates.push(update)
|
|
388
384
|
}
|
|
389
|
-
|
|
390
|
-
const addId = addIdByFactIndex.get(item.index) ?? nextAddId()
|
|
391
|
-
const relations = buildRelations(item, 'new')
|
|
392
|
-
updates.push({
|
|
393
|
-
id: addId,
|
|
394
|
-
text: item.fact,
|
|
395
|
-
event: 'ADD',
|
|
396
|
-
...(relations.length > 0 ? { relatesTo: relations } : {}),
|
|
397
|
-
})
|
|
398
385
|
}
|
|
399
386
|
|
|
400
387
|
const preservedRelationTargetIds = new Set<string>()
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Schema } from 'effect'
|
|
1
|
+
import { Effect, Schema } from 'effect'
|
|
2
2
|
|
|
3
3
|
export const ORG_SCOPE_PREFIX = 'org'
|
|
4
4
|
|
|
@@ -9,41 +9,45 @@ export class MemoryScopeError extends Schema.TaggedErrorClass<MemoryScopeError>(
|
|
|
9
9
|
message: Schema.String,
|
|
10
10
|
}) {}
|
|
11
11
|
|
|
12
|
-
function stripRecordPrefix(id: string): string {
|
|
12
|
+
function stripRecordPrefix(id: string): Effect.Effect<string, MemoryScopeError> {
|
|
13
13
|
if (typeof id !== 'string' || id.length === 0) {
|
|
14
|
-
|
|
14
|
+
return Effect.fail(new MemoryScopeError({ message: 'id must be a non-empty string' }))
|
|
15
15
|
}
|
|
16
16
|
const [, ...rest] = id.split(':')
|
|
17
|
-
return rest.length > 0 ? rest.join(':') : id
|
|
17
|
+
return Effect.succeed(rest.length > 0 ? rest.join(':') : id)
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export function scopeId(prefix: string, id: string): string {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
20
|
+
export function scopeId(prefix: string, id: string): Effect.Effect<string, MemoryScopeError> {
|
|
21
|
+
return Effect.gen(function* () {
|
|
22
|
+
if (typeof prefix !== 'string' || prefix.length === 0) {
|
|
23
|
+
return yield* new MemoryScopeError({ message: 'prefix must be a non-empty string' })
|
|
24
|
+
}
|
|
25
|
+
if (!SCOPE_PREFIX_REGEX.test(prefix)) {
|
|
26
|
+
return yield* new MemoryScopeError({ message: `Invalid scope prefix: ${prefix}` })
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const stripped = yield* stripRecordPrefix(id)
|
|
30
|
+
const scoped = `${prefix}:${stripped}`
|
|
31
|
+
if (scoped.length > SCOPE_ID_MAX_LENGTH) {
|
|
32
|
+
return yield* new MemoryScopeError({ message: 'scopeId exceeds maximum length' })
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return scoped
|
|
36
|
+
})
|
|
35
37
|
}
|
|
36
38
|
|
|
37
|
-
export function agentScopeId(orgId: string, agentName: string): string {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
export function agentScopeId(orgId: string, agentName: string): Effect.Effect<string, MemoryScopeError> {
|
|
40
|
+
return Effect.gen(function* () {
|
|
41
|
+
if (typeof agentName !== 'string' || agentName.trim().length === 0) {
|
|
42
|
+
return yield* new MemoryScopeError({ message: 'agentName must be a non-empty string' })
|
|
43
|
+
}
|
|
44
|
+
const strippedOrgId = yield* stripRecordPrefix(orgId)
|
|
45
|
+
const scoped = `agent:${strippedOrgId}:${agentName.trim()}`
|
|
43
46
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
+
if (scoped.length > SCOPE_ID_MAX_LENGTH) {
|
|
48
|
+
return yield* new MemoryScopeError({ message: 'scopeId exceeds maximum length' })
|
|
49
|
+
}
|
|
47
50
|
|
|
48
|
-
|
|
51
|
+
return scoped
|
|
52
|
+
})
|
|
49
53
|
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { Schema, Effect } from 'effect'
|
|
2
2
|
|
|
3
|
-
import { getPluginRuntime } from '../config/agent-defaults'
|
|
4
3
|
import type { RecordIdRef } from '../db/record-id'
|
|
5
|
-
import type { LotaRuntimeIndexedRepositoriesContext } from './runtime-extensions'
|
|
6
|
-
import { getRuntimeAdapters } from './runtime-extensions'
|
|
4
|
+
import type { LotaRuntimeAdapters, LotaRuntimeIndexedRepositoriesContext } from './runtime-extensions'
|
|
7
5
|
|
|
8
6
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
9
7
|
return typeof value === 'object' && value !== null
|
|
@@ -35,79 +33,68 @@ function readFunctionEffect(
|
|
|
35
33
|
return Effect.succeed(value as (...args: unknown[]) => PromiseLike<unknown>)
|
|
36
34
|
}
|
|
37
35
|
|
|
36
|
+
function configError(message: string): PluginResolutionError {
|
|
37
|
+
return new PluginResolutionError({ stage: 'configuration', message, cause: undefined })
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function requireRecord(value: unknown, message: string): Effect.Effect<Record<string, unknown>, PluginResolutionError> {
|
|
41
|
+
return isRecord(value) ? Effect.succeed(value) : Effect.fail(configError(message))
|
|
42
|
+
}
|
|
43
|
+
|
|
38
44
|
function resolvePluginServiceEffect(
|
|
45
|
+
pluginRuntime: Record<string, unknown> | undefined,
|
|
39
46
|
pluginName: string,
|
|
40
47
|
serviceName: string,
|
|
41
48
|
methodName: string,
|
|
42
49
|
): Effect.Effect<(...args: unknown[]) => PromiseLike<unknown>, PluginResolutionError> {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (!isRecord(services)) {
|
|
67
|
-
return Effect.fail(
|
|
68
|
-
new PluginResolutionError({
|
|
69
|
-
stage: 'configuration',
|
|
70
|
-
message: `Plugin "${pluginName}" does not expose a services registry.`,
|
|
71
|
-
cause: undefined,
|
|
72
|
-
}),
|
|
73
|
-
)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const service = services[serviceName]
|
|
77
|
-
if (!isRecord(service)) {
|
|
78
|
-
return Effect.fail(
|
|
79
|
-
new PluginResolutionError({
|
|
80
|
-
stage: 'configuration',
|
|
81
|
-
message: `Plugin "${pluginName}" service "${serviceName}" is not configured.`,
|
|
82
|
-
cause: undefined,
|
|
83
|
-
}),
|
|
84
|
-
)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return readFunctionEffect(
|
|
88
|
-
service[methodName],
|
|
89
|
-
`Plugin "${pluginName}" service "${serviceName}" is missing method "${methodName}".`,
|
|
90
|
-
).pipe(
|
|
91
|
-
Effect.map(
|
|
92
|
-
(method) =>
|
|
93
|
-
(...args: unknown[]) =>
|
|
94
|
-
Reflect.apply(method, service, args),
|
|
50
|
+
return Effect.fromNullishOr(pluginRuntime).pipe(
|
|
51
|
+
Effect.mapError(() => configError(`Plugin runtime is not configured. Missing "${pluginName}" integration.`)),
|
|
52
|
+
Effect.flatMap((runtime) =>
|
|
53
|
+
requireRecord(runtime[pluginName], `Plugin "${pluginName}" is not configured in the current runtime.`),
|
|
54
|
+
),
|
|
55
|
+
Effect.flatMap((plugin) =>
|
|
56
|
+
requireRecord(plugin.services, `Plugin "${pluginName}" does not expose a services registry.`),
|
|
57
|
+
),
|
|
58
|
+
Effect.flatMap((services) =>
|
|
59
|
+
requireRecord(services[serviceName], `Plugin "${pluginName}" service "${serviceName}" is not configured.`).pipe(
|
|
60
|
+
Effect.flatMap((service) =>
|
|
61
|
+
readFunctionEffect(
|
|
62
|
+
service[methodName],
|
|
63
|
+
`Plugin "${pluginName}" service "${serviceName}" is missing method "${methodName}".`,
|
|
64
|
+
).pipe(
|
|
65
|
+
Effect.map(
|
|
66
|
+
(method) =>
|
|
67
|
+
(...args: unknown[]) =>
|
|
68
|
+
Reflect.apply(method, service, args),
|
|
69
|
+
),
|
|
70
|
+
),
|
|
71
|
+
),
|
|
72
|
+
),
|
|
95
73
|
),
|
|
96
74
|
)
|
|
97
75
|
}
|
|
98
76
|
|
|
99
77
|
function tryResolvePluginServiceEffect(
|
|
78
|
+
pluginRuntime: Record<string, unknown> | undefined,
|
|
100
79
|
pluginName: string,
|
|
101
80
|
serviceName: string,
|
|
102
81
|
methodName: string,
|
|
103
|
-
): Effect.Effect<((...args: unknown[]) => PromiseLike<unknown>) |
|
|
104
|
-
return Effect.catch(resolvePluginServiceEffect(pluginName, serviceName, methodName), () => Effect.
|
|
82
|
+
): Effect.Effect<((...args: unknown[]) => PromiseLike<unknown>) | void, never, never> {
|
|
83
|
+
return Effect.catch(resolvePluginServiceEffect(pluginRuntime, pluginName, serviceName, methodName), () => Effect.void)
|
|
105
84
|
}
|
|
106
85
|
|
|
107
|
-
export function getLinearInstallationByOrgId(
|
|
86
|
+
export function getLinearInstallationByOrgId(
|
|
87
|
+
pluginRuntime: Record<string, unknown> | undefined,
|
|
88
|
+
organizationId: RecordIdRef,
|
|
89
|
+
): Promise<unknown> {
|
|
108
90
|
return Effect.runPromise(
|
|
109
91
|
Effect.gen(function* () {
|
|
110
|
-
const fn = yield* tryResolvePluginServiceEffect(
|
|
92
|
+
const fn = yield* tryResolvePluginServiceEffect(
|
|
93
|
+
pluginRuntime,
|
|
94
|
+
'linear',
|
|
95
|
+
'linearService',
|
|
96
|
+
'getInstallationByOrgId',
|
|
97
|
+
)
|
|
111
98
|
if (!fn) return null
|
|
112
99
|
return yield* Effect.tryPromise({
|
|
113
100
|
try: () => fn(organizationId),
|
|
@@ -117,10 +104,18 @@ export function getLinearInstallationByOrgId(organizationId: RecordIdRef): Promi
|
|
|
117
104
|
)
|
|
118
105
|
}
|
|
119
106
|
|
|
120
|
-
export function getGithubInstallationForOrganization(
|
|
107
|
+
export function getGithubInstallationForOrganization(
|
|
108
|
+
pluginRuntime: Record<string, unknown> | undefined,
|
|
109
|
+
organizationId: string,
|
|
110
|
+
): Promise<unknown> {
|
|
121
111
|
return Effect.runPromise(
|
|
122
112
|
Effect.gen(function* () {
|
|
123
|
-
const fn = yield* tryResolvePluginServiceEffect(
|
|
113
|
+
const fn = yield* tryResolvePluginServiceEffect(
|
|
114
|
+
pluginRuntime,
|
|
115
|
+
'github',
|
|
116
|
+
'githubService',
|
|
117
|
+
'getInstallationForOrganization',
|
|
118
|
+
)
|
|
124
119
|
if (!fn) return null
|
|
125
120
|
return yield* Effect.tryPromise({
|
|
126
121
|
try: () => fn(organizationId),
|
|
@@ -137,9 +132,10 @@ const EMPTY_INDEXED_REPO_CONTEXT: LotaRuntimeIndexedRepositoriesContext = {
|
|
|
137
132
|
}
|
|
138
133
|
|
|
139
134
|
export function buildIndexedRepositoriesContext(
|
|
135
|
+
adapters: LotaRuntimeAdapters,
|
|
140
136
|
organizationId: string,
|
|
141
137
|
): Promise<LotaRuntimeIndexedRepositoriesContext> {
|
|
142
|
-
const buildContext =
|
|
138
|
+
const buildContext = adapters.buildIndexedRepositoriesContext
|
|
143
139
|
if (!buildContext) return Promise.resolve(EMPTY_INDEXED_REPO_CONTEXT)
|
|
144
140
|
return Effect.runPromise(
|
|
145
141
|
Effect.tryPromise({
|