@lota-sdk/core 0.1.23 → 0.1.25
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/definitions.ts +5 -59
- package/src/ai-gateway/ai-gateway.ts +36 -28
- package/src/ai-gateway/cache-headers.ts +9 -0
- package/src/config/model-constants.ts +6 -2
- package/src/create-runtime.ts +5 -17
- package/src/db/memory-types.ts +13 -8
- package/src/db/memory.ts +74 -53
- package/src/queues/autonomous-job.queue.ts +1 -8
- package/src/queues/context-compaction.queue.ts +2 -2
- package/src/queues/index.ts +2 -6
- package/src/queues/organization-learning.queue.ts +78 -0
- package/src/queues/plan-agent-heartbeat.queue.ts +10 -16
- package/src/queues/title-generation.queue.ts +62 -0
- package/src/runtime/agent-prompt-context.ts +0 -18
- package/src/runtime/agent-runtime-policy.ts +9 -2
- package/src/runtime/context-compaction-constants.ts +4 -2
- package/src/runtime/context-compaction.ts +135 -118
- package/src/runtime/execution-plan.ts +2 -1
- package/src/runtime/memory-pipeline.ts +70 -1
- package/src/runtime/memory-prompts-fact.ts +16 -0
- package/src/runtime/plugin-resolution.ts +3 -2
- package/src/runtime/plugin-types.ts +1 -42
- package/src/runtime/post-turn-side-effects.ts +212 -0
- package/src/runtime/runtime-config.ts +0 -13
- package/src/runtime/runtime-extensions.ts +10 -16
- package/src/runtime/runtime-worker-registry.ts +8 -19
- package/src/runtime/social-chat-agent-runner.ts +119 -0
- package/src/runtime/social-chat-history.ts +110 -0
- package/src/runtime/social-chat-prompts.ts +58 -0
- package/src/runtime/social-chat.ts +104 -340
- package/src/runtime/specialist-runner.ts +18 -0
- package/src/runtime/workstream-chat-helpers.ts +19 -0
- package/src/runtime/workstream-plan-turn.ts +195 -0
- package/src/runtime/workstream-state.ts +11 -8
- package/src/runtime/workstream-turn-context.ts +183 -0
- package/src/services/agent-activity.service.ts +350 -0
- package/src/services/autonomous-job.service.ts +1 -8
- package/src/services/execution-plan.service.ts +205 -334
- package/src/services/index.ts +2 -4
- package/src/services/memory.service.ts +54 -44
- package/src/services/ownership-dispatcher.service.ts +2 -19
- package/src/services/plan-completion-side-effects.ts +80 -0
- package/src/services/plan-event-delivery.service.ts +1 -1
- package/src/services/plan-executor.service.ts +42 -190
- package/src/services/plan-node-spec.ts +60 -0
- package/src/services/plan-run-data.ts +88 -0
- package/src/services/plan-validator.service.ts +10 -8
- package/src/services/workstream-constants.ts +2 -0
- package/src/services/workstream-title.service.ts +1 -1
- package/src/services/workstream-turn-preparation.service.ts +208 -715
- package/src/services/workstream.service.ts +162 -192
- package/src/services/workstream.types.ts +12 -44
- package/src/system-agents/regular-chat-memory-digest.agent.ts +3 -0
- package/src/tools/execution-plan.tool.ts +11 -6
- package/src/tools/index.ts +1 -0
- package/src/tools/project-with-plan.tool.ts +87 -0
- package/src/tools/remember-memory.tool.ts +7 -10
- package/src/tools/research-topic.tool.ts +1 -1
- package/src/tools/team-think.tool.ts +1 -1
- package/src/tools/user-questions.tool.ts +1 -1
- package/src/utils/autonomous-job-ids.ts +7 -0
- package/src/workers/organization-learning.worker.ts +31 -0
- package/src/workers/regular-chat-memory-digest.runner.ts +9 -3
- package/src/workers/skill-extraction.runner.ts +2 -2
- package/src/queues/recent-activity-title-refinement.queue.ts +0 -30
- package/src/queues/regular-chat-memory-digest.config.ts +0 -12
- package/src/queues/regular-chat-memory-digest.queue.ts +0 -34
- package/src/queues/skill-extraction.config.ts +0 -9
- package/src/queues/skill-extraction.queue.ts +0 -27
- package/src/queues/workstream-title-generation.queue.ts +0 -33
- package/src/services/context-enrichment.service.ts +0 -33
- package/src/services/coordination-registry.service.ts +0 -117
- package/src/services/domain-agent-executor.service.ts +0 -71
- package/src/services/memory-assessment.service.ts +0 -44
- package/src/services/playbook-registry.service.ts +0 -67
- package/src/workers/regular-chat-memory-digest.worker.ts +0 -22
- package/src/workers/skill-extraction.worker.ts +0 -22
package/src/services/index.ts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
export * from './adaptive-playbook.service'
|
|
2
2
|
export * from './agent-executor.service'
|
|
3
|
+
export * from './agent-activity.service'
|
|
3
4
|
export * from './artifact-provenance.service'
|
|
4
5
|
export * from './attachment.service'
|
|
5
6
|
export * from './autonomous-job.service'
|
|
6
|
-
export * from './context-enrichment.service'
|
|
7
|
-
export * from './coordination-registry.service'
|
|
8
7
|
export * from './document-chunk.service'
|
|
9
|
-
export * from './domain-agent-executor.service'
|
|
10
8
|
export * from './execution-plan.service'
|
|
11
9
|
export * from './institutional-memory.service'
|
|
12
10
|
export * from './feedback-loop.service'
|
|
@@ -27,7 +25,6 @@ export * from './plan-workspace.service'
|
|
|
27
25
|
export * from './plan-run.service'
|
|
28
26
|
export * from './plan-scheduler.service'
|
|
29
27
|
export * from './plan-template.service'
|
|
30
|
-
export * from './playbook-registry.service'
|
|
31
28
|
export * from './quality-metrics.service'
|
|
32
29
|
export * from './queue-job.service'
|
|
33
30
|
export * from './monitoring-window.service'
|
|
@@ -39,6 +36,7 @@ export * from './social-chat-history.service'
|
|
|
39
36
|
export * from './system-executor.service'
|
|
40
37
|
export * from './user.service'
|
|
41
38
|
export * from './workstream-message.service'
|
|
39
|
+
export * from './workstream.types'
|
|
42
40
|
export * from './workstream-title.service'
|
|
43
41
|
export * from './workstream-turn'
|
|
44
42
|
export * from './workstream-plan-registry.service'
|
|
@@ -26,8 +26,7 @@ import {
|
|
|
26
26
|
import { getRuntimeConfig } from '../runtime/runtime-config'
|
|
27
27
|
import { createMemoryRerankerAgent, MEMORY_RERANKER_PROMPT } from '../system-agents/memory-reranker.agent'
|
|
28
28
|
import { createOrgMemoryAgent, ORG_MEMORY_PROMPT } from '../system-agents/memory.agent'
|
|
29
|
-
import { compactWhitespace, truncateText } from '../utils/string'
|
|
30
|
-
import { assessMemoryImportance, clampMemoryImportance } from './memory-assessment.service'
|
|
29
|
+
import { clampImportance, compactWhitespace, truncateText } from '../utils/string'
|
|
31
30
|
import { formatMemoryResults, formatRerankedResults, getCandidateLimit } from './memory-utils'
|
|
32
31
|
|
|
33
32
|
const ORG_MEMORY_TYPE = 'fact'
|
|
@@ -41,11 +40,13 @@ const MAX_CONVERSATION_HISTORY_MESSAGES = 24
|
|
|
41
40
|
const MAX_CONVERSATION_MESSAGE_CHARS = 1_200
|
|
42
41
|
const MAX_CONVERSATION_MEMORY_BLOCK_CHARS = 2_000
|
|
43
42
|
const MAX_CONVERSATION_ATTACHMENT_CONTEXT_CHARS = 6_000
|
|
44
|
-
const MAX_CONVERSATION_ASSESSMENT_CHARS = 7_000
|
|
45
43
|
const ONBOARDING_MEMORY_MAX_FACTS = 16
|
|
46
44
|
const MAX_ORG_MEMORY_CLIENTS = 128
|
|
45
|
+
const LOW_VALUE_MEMORY_IMPORTANCE_THRESHOLD = 0.45
|
|
47
46
|
const ONBOARDING_MEMORY_EXTRACTION_PROMPT =
|
|
48
47
|
'Onboarding mode is active. Extract multiple concrete startup facts from user-provided context: company mission, product capabilities, customer segments, pricing, traction, go-to-market plans, roadmap, team composition, technical stack, risks, and referenced URLs. Prefer one fact per concrete claim.'
|
|
48
|
+
const DIRECT_MEMORY_ASSESSMENT_PROMPT =
|
|
49
|
+
'The user is submitting a direct memory candidate. Keep the wording faithful. Return one fact only when the statement is durable enough for memory; otherwise return no facts.'
|
|
49
50
|
|
|
50
51
|
const helperModelRuntime = createHelperModelRuntime()
|
|
51
52
|
|
|
@@ -225,11 +226,6 @@ class MemoryService {
|
|
|
225
226
|
return { messages, normalizedInput, sanitizedOutput }
|
|
226
227
|
}
|
|
227
228
|
|
|
228
|
-
private buildConversationAssessmentInput(messages: Message[]): string {
|
|
229
|
-
const lines = messages.map((message, index) => `[${message.role.toUpperCase()} #${index + 1}] ${message.content}`)
|
|
230
|
-
return this.normalizeConversationText(lines.join('\n\n'), MAX_CONVERSATION_ASSESSMENT_CHARS)
|
|
231
|
-
}
|
|
232
|
-
|
|
233
229
|
private async rerankCandidates(
|
|
234
230
|
query: string,
|
|
235
231
|
candidates: MemorySearchResult[],
|
|
@@ -307,16 +303,24 @@ class MemoryService {
|
|
|
307
303
|
memory,
|
|
308
304
|
scopeId,
|
|
309
305
|
memoryType,
|
|
306
|
+
fastMode = true,
|
|
310
307
|
}: {
|
|
311
308
|
query: string
|
|
312
309
|
memory: Memory
|
|
313
310
|
scopeId: string
|
|
314
311
|
memoryType: MemoryType
|
|
312
|
+
fastMode?: boolean
|
|
315
313
|
}): Promise<string> {
|
|
316
314
|
const limit = getRuntimeConfig().memory.searchK
|
|
317
|
-
const candidateLimit = getCandidateLimit(limit)
|
|
315
|
+
const candidateLimit = fastMode ? limit : getCandidateLimit(limit)
|
|
318
316
|
|
|
319
|
-
const candidates = await memory.searchCandidates(query, {
|
|
317
|
+
const candidates = await memory.searchCandidates(query, {
|
|
318
|
+
scopeId,
|
|
319
|
+
limit: candidateLimit,
|
|
320
|
+
memoryType,
|
|
321
|
+
fastMode,
|
|
322
|
+
includeNeighborContext: !fastMode,
|
|
323
|
+
})
|
|
320
324
|
|
|
321
325
|
aiLogger.debug`Memory search candidates (scopeId: ${scopeId}, candidates: ${candidates.length})`
|
|
322
326
|
|
|
@@ -324,9 +328,9 @@ class MemoryService {
|
|
|
324
328
|
return 'No stored memories.'
|
|
325
329
|
}
|
|
326
330
|
|
|
327
|
-
if (candidates.length <= limit) {
|
|
331
|
+
if (fastMode || candidates.length <= limit) {
|
|
328
332
|
aiLogger.debug`Skipping reranking (candidates: ${candidates.length} <= limit: ${limit})`
|
|
329
|
-
return formatMemoryResults(candidates)
|
|
333
|
+
return formatMemoryResults(candidates.slice(0, limit))
|
|
330
334
|
}
|
|
331
335
|
|
|
332
336
|
const reranked = await this.rerankCandidates(query, candidates, limit)
|
|
@@ -473,7 +477,7 @@ class MemoryService {
|
|
|
473
477
|
orgId,
|
|
474
478
|
agentName,
|
|
475
479
|
query,
|
|
476
|
-
fastMode =
|
|
480
|
+
fastMode = true,
|
|
477
481
|
allowMultiScopeRerank = true,
|
|
478
482
|
}: {
|
|
479
483
|
orgId: string
|
|
@@ -659,6 +663,38 @@ class MemoryService {
|
|
|
659
663
|
}
|
|
660
664
|
}
|
|
661
665
|
|
|
666
|
+
async assessMemoryCandidate(params: {
|
|
667
|
+
orgId: string
|
|
668
|
+
content: string
|
|
669
|
+
}): Promise<Pick<ExtractedFact, 'classification' | 'durability' | 'importance' | 'rationale'> | null> {
|
|
670
|
+
const trimmed = compactWhitespace(params.content)
|
|
671
|
+
if (!trimmed) return null
|
|
672
|
+
|
|
673
|
+
const facts = await this.getOrgMemory(params.orgId).extractFactsFromMessages([{ role: 'user', content: trimmed }], {
|
|
674
|
+
maxFacts: 1,
|
|
675
|
+
customPrompt: DIRECT_MEMORY_ASSESSMENT_PROMPT,
|
|
676
|
+
})
|
|
677
|
+
if (facts.length === 0) return null
|
|
678
|
+
const fact = facts[0]
|
|
679
|
+
|
|
680
|
+
return {
|
|
681
|
+
classification: fact.classification,
|
|
682
|
+
durability: fact.durability,
|
|
683
|
+
importance: clampImportance(fact.importance),
|
|
684
|
+
rationale: fact.rationale,
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
private shouldSkipExtractedFacts(facts: ExtractedFact[]): boolean {
|
|
689
|
+
if (facts.length === 0) return true
|
|
690
|
+
return facts.every(
|
|
691
|
+
(fact) =>
|
|
692
|
+
fact.durability === 'ephemeral' &&
|
|
693
|
+
fact.importance <= LOW_VALUE_MEMORY_IMPORTANCE_THRESHOLD &&
|
|
694
|
+
fact.classification !== 'durable',
|
|
695
|
+
)
|
|
696
|
+
}
|
|
697
|
+
|
|
662
698
|
async updateOrganizationMemoryById({
|
|
663
699
|
orgId,
|
|
664
700
|
memoryId,
|
|
@@ -761,39 +797,12 @@ class MemoryService {
|
|
|
761
797
|
aiLogger.debug`addConversationMemories - orgId: "${orgId}", scopeId: "${orgScopeId}", sourceId: ${sourceId ?? 'none'}`
|
|
762
798
|
|
|
763
799
|
const orgMemory = this.getOrgMemory(orgId)
|
|
764
|
-
let assessedImportance: number | undefined
|
|
765
|
-
let assessmentMetadata: Record<string, unknown> | undefined
|
|
766
|
-
|
|
767
|
-
try {
|
|
768
|
-
const assessmentInput = this.buildConversationAssessmentInput(messages)
|
|
769
|
-
if (assessmentInput) {
|
|
770
|
-
const assessment = await assessMemoryImportance({
|
|
771
|
-
content: assessmentInput,
|
|
772
|
-
targetScope: 'global',
|
|
773
|
-
tag: 'memory-conversation-assessment',
|
|
774
|
-
})
|
|
775
|
-
if (assessment.classification === 'transient' && assessment.durability === 'ephemeral') {
|
|
776
|
-
aiLogger.debug`Skipping transient conversation memory`
|
|
777
|
-
return
|
|
778
|
-
}
|
|
779
|
-
assessedImportance = Math.round(clampMemoryImportance(assessment.importance) * 100) / 100
|
|
780
|
-
assessmentMetadata = {
|
|
781
|
-
importanceSource: 'model_assessed',
|
|
782
|
-
durability: assessment.durability,
|
|
783
|
-
classification: assessment.classification,
|
|
784
|
-
rationale: assessment.rationale,
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
} catch (error) {
|
|
788
|
-
aiLogger.warn`Conversation memory assessment failed; continuing with default scoring: ${error}`
|
|
789
|
-
}
|
|
790
800
|
|
|
791
801
|
const scopes: AddOptions[] = [
|
|
792
802
|
{
|
|
793
803
|
scopeId: orgScopeId,
|
|
794
804
|
memoryType: ORG_MEMORY_TYPE,
|
|
795
|
-
|
|
796
|
-
metadata: { orgId, source, ...(sourceId ? { sourceId } : {}), ...sourceMetadata, ...assessmentMetadata },
|
|
805
|
+
metadata: { orgId, source, ...(sourceId ? { sourceId } : {}), ...sourceMetadata },
|
|
797
806
|
},
|
|
798
807
|
]
|
|
799
808
|
|
|
@@ -802,7 +811,6 @@ class MemoryService {
|
|
|
802
811
|
scopes.push({
|
|
803
812
|
scopeId: agentId,
|
|
804
813
|
memoryType: ORG_MEMORY_TYPE,
|
|
805
|
-
...(typeof assessedImportance === 'number' ? { importance: assessedImportance } : {}),
|
|
806
814
|
metadata: {
|
|
807
815
|
orgId,
|
|
808
816
|
agentName: scopedAgentName,
|
|
@@ -810,7 +818,6 @@ class MemoryService {
|
|
|
810
818
|
source,
|
|
811
819
|
...(sourceId ? { sourceId } : {}),
|
|
812
820
|
...sourceMetadata,
|
|
813
|
-
...assessmentMetadata,
|
|
814
821
|
},
|
|
815
822
|
})
|
|
816
823
|
}
|
|
@@ -820,7 +827,10 @@ class MemoryService {
|
|
|
820
827
|
? { maxFacts: ONBOARDING_MEMORY_MAX_FACTS, customPrompt: ONBOARDING_MEMORY_EXTRACTION_PROMPT }
|
|
821
828
|
: undefined
|
|
822
829
|
const extractedFacts = await orgMemory.extractFactsFromMessages(messages, extractionConfig)
|
|
823
|
-
if (extractedFacts
|
|
830
|
+
if (this.shouldSkipExtractedFacts(extractedFacts)) {
|
|
831
|
+
aiLogger.debug`Skipping transient conversation memory`
|
|
832
|
+
return
|
|
833
|
+
}
|
|
824
834
|
const preparedUpdates = await orgMemory.prepareFactsToScopes(extractedFacts, scopes)
|
|
825
835
|
if (preparedUpdates.length === 0) return
|
|
826
836
|
|
|
@@ -24,7 +24,6 @@ import { TABLES } from '../db/tables'
|
|
|
24
24
|
import { resolvePlanNodeExecutionVisibility, shouldPlanNodeUseVisibleTurn } from '../runtime/execution-plan-visibility'
|
|
25
25
|
import { getRuntimeAdapters } from '../runtime/runtime-extensions'
|
|
26
26
|
import { agentExecutorService } from './agent-executor.service'
|
|
27
|
-
import { domainAgentExecutorService } from './domain-agent-executor.service'
|
|
28
27
|
import { monitoringWindowService } from './monitoring-window.service'
|
|
29
28
|
import { planExecutorService } from './plan-executor.service'
|
|
30
29
|
import { planRunService } from './plan-run.service'
|
|
@@ -106,7 +105,7 @@ class OwnershipDispatcherService {
|
|
|
106
105
|
|
|
107
106
|
for (const node of draft.nodes) {
|
|
108
107
|
if (node.owner.executorType === 'agent') {
|
|
109
|
-
if (!agentRoster.includes(node.owner.ref)
|
|
108
|
+
if (!agentRoster.includes(node.owner.ref)) {
|
|
110
109
|
issues.push({
|
|
111
110
|
severity: 'blocking',
|
|
112
111
|
code: 'agent_executor_missing',
|
|
@@ -264,7 +263,7 @@ class OwnershipDispatcherService {
|
|
|
264
263
|
}
|
|
265
264
|
|
|
266
265
|
private async shouldAutoDispatch(run: PlanRunRecord): Promise<boolean> {
|
|
267
|
-
const workspaceProvider = getRuntimeAdapters().
|
|
266
|
+
const workspaceProvider = getRuntimeAdapters().workspaceProvider
|
|
268
267
|
if (!workspaceProvider) {
|
|
269
268
|
return true
|
|
270
269
|
}
|
|
@@ -365,14 +364,6 @@ class OwnershipDispatcherService {
|
|
|
365
364
|
}
|
|
366
365
|
|
|
367
366
|
if (params.nodeSpec.owner.executorType === 'agent') {
|
|
368
|
-
if (domainAgentExecutorService.hasAgent(params.nodeSpec.owner.ref)) {
|
|
369
|
-
return domainAgentExecutorService.executeNode({
|
|
370
|
-
nodeSpec: params.nodeSpec,
|
|
371
|
-
resolvedInput: params.resolvedInput,
|
|
372
|
-
inputArtifacts: params.inputArtifacts,
|
|
373
|
-
context: params.context,
|
|
374
|
-
})
|
|
375
|
-
}
|
|
376
367
|
return agentExecutorService.executeNode({
|
|
377
368
|
nodeSpec: params.nodeSpec,
|
|
378
369
|
resolvedInput: params.resolvedInput,
|
|
@@ -407,14 +398,6 @@ class OwnershipDispatcherService {
|
|
|
407
398
|
|
|
408
399
|
if (resolved.executorType === 'agent') {
|
|
409
400
|
const skillNodeSpec = { ...params.nodeSpec, owner: { executorType: 'agent' as const, ref: resolved.ref } }
|
|
410
|
-
if (domainAgentExecutorService.hasAgent(resolved.ref)) {
|
|
411
|
-
return domainAgentExecutorService.executeNode({
|
|
412
|
-
nodeSpec: skillNodeSpec,
|
|
413
|
-
resolvedInput: params.resolvedInput,
|
|
414
|
-
inputArtifacts: params.inputArtifacts,
|
|
415
|
-
context: params.context,
|
|
416
|
-
})
|
|
417
|
-
}
|
|
418
401
|
return agentExecutorService.executeNode({
|
|
419
402
|
nodeSpec: skillNodeSpec,
|
|
420
403
|
resolvedInput: params.resolvedInput,
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { PlanNodeOwner, PlanNodeType } from '@lota-sdk/shared'
|
|
2
|
+
import { PlanEventSchema } from '@lota-sdk/shared'
|
|
3
|
+
|
|
4
|
+
import { aiLogger } from '../config/logger'
|
|
5
|
+
import { ensureRecordId } from '../db/record-id'
|
|
6
|
+
import { databaseService } from '../db/service'
|
|
7
|
+
import { TABLES } from '../db/tables'
|
|
8
|
+
import { feedbackLoopService } from './feedback-loop.service'
|
|
9
|
+
import { institutionalMemoryService } from './institutional-memory.service'
|
|
10
|
+
import { planEventDeliveryService } from './plan-event-delivery.service'
|
|
11
|
+
import { planRunService } from './plan-run.service'
|
|
12
|
+
import type { PlanValidationIssueInput } from './plan-validator.service'
|
|
13
|
+
import { qualityMetricsService } from './quality-metrics.service'
|
|
14
|
+
|
|
15
|
+
export async function runPlanNodeCompletionSideEffects(params: {
|
|
16
|
+
runId: string
|
|
17
|
+
organizationId: string
|
|
18
|
+
nodeId: string
|
|
19
|
+
nodeLabel: string
|
|
20
|
+
nodeOwnerRef: string
|
|
21
|
+
nodeOwnerType: PlanNodeOwner['executorType']
|
|
22
|
+
nodeType: PlanNodeType
|
|
23
|
+
nodeStartedAt?: string | Date | null
|
|
24
|
+
nodeAttemptCount: number
|
|
25
|
+
artifactCount: number
|
|
26
|
+
validationIssues: PlanValidationIssueInput[]
|
|
27
|
+
}): Promise<void> {
|
|
28
|
+
const executionTimeMs = params.nodeStartedAt ? Date.now() - new Date(params.nodeStartedAt).getTime() : 0
|
|
29
|
+
await qualityMetricsService.recordNodeMetrics({
|
|
30
|
+
organizationId: params.organizationId,
|
|
31
|
+
runId: params.runId,
|
|
32
|
+
nodeId: params.nodeId,
|
|
33
|
+
metrics: {
|
|
34
|
+
executionTimeMs: Math.max(0, executionTimeMs),
|
|
35
|
+
attemptCount: params.nodeAttemptCount,
|
|
36
|
+
artifactCount: params.artifactCount,
|
|
37
|
+
validationIssueCount: params.validationIssues.length,
|
|
38
|
+
ownerRef: params.nodeOwnerRef,
|
|
39
|
+
ownerType: params.nodeOwnerType,
|
|
40
|
+
nodeType: params.nodeType,
|
|
41
|
+
},
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function runPlanCompletionSideEffects(params: { runId: string; organizationId: string }): Promise<void> {
|
|
46
|
+
await qualityMetricsService.recordCycleMetrics({ organizationId: params.organizationId, runId: params.runId })
|
|
47
|
+
|
|
48
|
+
const recommendations = await feedbackLoopService.analyzeOutcomes({
|
|
49
|
+
runId: params.runId,
|
|
50
|
+
organizationId: params.organizationId,
|
|
51
|
+
})
|
|
52
|
+
if (recommendations.length > 0) {
|
|
53
|
+
const run = await planRunService.getRunById(params.runId)
|
|
54
|
+
const specRecord = await planRunService.getPlanSpecById(run.planSpecId)
|
|
55
|
+
const event = await databaseService.create(
|
|
56
|
+
TABLES.PLAN_EVENT,
|
|
57
|
+
{
|
|
58
|
+
planSpecId: ensureRecordId(specRecord.id, TABLES.PLAN_SPEC),
|
|
59
|
+
runId: ensureRecordId(run.id, TABLES.PLAN_RUN),
|
|
60
|
+
eventType: 'feedback-analyzed',
|
|
61
|
+
message: `Feedback analysis produced ${recommendations.length} recommendation(s).`,
|
|
62
|
+
detail: { recommendations },
|
|
63
|
+
emittedBy: 'system',
|
|
64
|
+
},
|
|
65
|
+
PlanEventSchema,
|
|
66
|
+
)
|
|
67
|
+
await planEventDeliveryService.dispatchEvent(event)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
await institutionalMemoryService.extractPatterns({ organizationId: params.organizationId, runId: params.runId })
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export async function runPlanCompletionSideEffectsSafely(params: {
|
|
74
|
+
runId: string
|
|
75
|
+
organizationId: string
|
|
76
|
+
}): Promise<void> {
|
|
77
|
+
await runPlanCompletionSideEffects(params).catch((error) => {
|
|
78
|
+
aiLogger.warn`Plan completion side effects failed for run ${params.runId}: ${error instanceof Error ? error.message : String(error)}`
|
|
79
|
+
})
|
|
80
|
+
}
|
|
@@ -103,7 +103,7 @@ class PlanEventDeliveryService {
|
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
private async dispatchAdapterEvent(envelope: LotaRuntimePlanEventEnvelope): Promise<void> {
|
|
106
|
-
const adapter = getRuntimeAdapters().
|
|
106
|
+
const adapter = getRuntimeAdapters().planEventAdapter
|
|
107
107
|
if (!adapter) {
|
|
108
108
|
return
|
|
109
109
|
}
|