@lota-sdk/core 0.1.15 → 0.1.16
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/infrastructure/schema/00_identity.surql +0 -2
- package/infrastructure/schema/01_memory.surql +1 -1
- package/infrastructure/schema/02_execution_plan.surql +62 -1
- package/infrastructure/schema/03_learned_skill.surql +1 -1
- package/infrastructure/schema/06_playbook.surql +25 -0
- package/infrastructure/schema/07_institutional_memory.surql +13 -0
- package/infrastructure/schema/08_quality_metrics.surql +17 -0
- package/package.json +8 -7
- package/src/ai/definitions.ts +80 -2
- package/src/ai/index.ts +0 -2
- package/src/bifrost/bifrost.ts +2 -7
- package/src/config/agent-defaults.ts +31 -21
- package/src/config/agent-types.ts +11 -0
- package/src/config/constants.ts +2 -14
- package/src/config/debug-logger.ts +5 -1
- package/src/config/index.ts +3 -0
- package/src/config/model-constants.ts +16 -34
- package/src/config/search.ts +1 -15
- package/src/create-runtime.ts +244 -178
- package/src/db/cursor-pagination.ts +3 -6
- package/src/db/index.ts +2 -0
- package/src/db/memory-store.rows.ts +7 -7
- package/src/db/memory-store.ts +14 -18
- package/src/db/memory.ts +13 -13
- package/src/db/service.ts +153 -79
- package/src/db/startup.ts +6 -10
- package/src/db/surreal-mutation.ts +43 -0
- package/src/db/tables.ts +7 -0
- package/src/db/workstream-message-row.ts +15 -0
- package/src/embeddings/provider.ts +1 -1
- package/src/queues/context-compaction.queue.ts +15 -46
- package/src/queues/delayed-node-promotion.queue.ts +41 -0
- package/src/queues/index.ts +3 -0
- package/src/queues/memory-consolidation.queue.ts +16 -51
- package/src/queues/plan-scheduler.queue.ts +97 -0
- package/src/queues/post-chat-memory.queue.ts +15 -56
- package/src/queues/queue-factory.ts +100 -0
- package/src/queues/recent-activity-title-refinement.queue.ts +15 -50
- package/src/queues/regular-chat-memory-digest.queue.ts +16 -52
- package/src/queues/skill-extraction.queue.ts +15 -47
- package/src/queues/workstream-title-generation.queue.ts +15 -47
- package/src/redis/connection.ts +6 -0
- package/src/redis/index.ts +1 -1
- package/src/redis/stream-context.ts +11 -0
- package/src/runtime/agent-runtime-policy.ts +106 -21
- package/src/runtime/approval-continuation.ts +12 -6
- package/src/runtime/context-compaction-runtime.ts +1 -1
- package/src/runtime/context-compaction.ts +22 -60
- package/src/runtime/execution-plan.ts +22 -18
- package/src/runtime/graph-designer.ts +15 -0
- package/src/runtime/helper-model.ts +9 -197
- package/src/runtime/index.ts +2 -0
- package/src/runtime/llm-content.ts +1 -1
- package/src/runtime/memory-block.ts +9 -11
- package/src/runtime/memory-pipeline.ts +6 -9
- package/src/runtime/plugin-resolution.ts +35 -0
- package/src/runtime/plugin-types.ts +72 -0
- package/src/runtime/retrieval-adapters.ts +1 -1
- package/src/runtime/runtime-config.ts +25 -12
- package/src/runtime/runtime-extensions.ts +2 -2
- package/src/runtime/runtime-worker-registry.ts +6 -0
- package/src/runtime/team-consultation-orchestrator.ts +45 -28
- package/src/runtime/team-consultation-prompts.ts +11 -2
- package/src/runtime/title-helpers.ts +2 -4
- package/src/runtime/workstream-chat-helpers.ts +1 -1
- package/src/services/adaptive-playbook.service.ts +152 -0
- package/src/services/agent-executor.service.ts +293 -0
- package/src/services/artifact-provenance.service.ts +172 -0
- package/src/services/attachment.service.ts +6 -11
- package/src/services/context-compaction.service.ts +72 -55
- package/src/services/context-enrichment.service.ts +33 -0
- package/src/services/coordination-registry.service.ts +117 -0
- package/src/services/document-chunk.service.ts +1 -1
- package/src/services/domain-agent-executor.service.ts +71 -0
- package/src/services/execution-plan.service.ts +269 -50
- package/src/services/feedback-loop.service.ts +96 -0
- package/src/services/global-orchestrator.service.ts +148 -0
- package/src/services/index.ts +26 -0
- package/src/services/institutional-memory.service.ts +145 -0
- package/src/services/learned-skill.service.ts +24 -5
- package/src/services/memory-assessment.service.ts +3 -2
- package/src/services/memory-utils.ts +3 -8
- package/src/services/memory.service.ts +42 -59
- package/src/services/monitoring-window.service.ts +86 -0
- package/src/services/mutating-approval.service.ts +1 -1
- package/src/services/node-workspace.service.ts +155 -0
- package/src/services/notification.service.ts +39 -0
- package/src/services/organization-member.service.ts +11 -4
- package/src/services/organization.service.ts +5 -5
- package/src/services/ownership-dispatcher.service.ts +403 -0
- package/src/services/plan-approval.service.ts +1 -1
- package/src/services/plan-builder.service.ts +1 -0
- package/src/services/plan-checkpoint.service.ts +30 -2
- package/src/services/plan-compiler.service.ts +5 -0
- package/src/services/plan-coordination.service.ts +152 -0
- package/src/services/plan-cycle.service.ts +284 -0
- package/src/services/plan-deadline.service.ts +287 -0
- package/src/services/plan-executor.service.ts +384 -40
- package/src/services/plan-run.service.ts +41 -7
- package/src/services/plan-scheduler.service.ts +240 -0
- package/src/services/plan-template.service.ts +117 -0
- package/src/services/plan-validator.service.ts +84 -2
- package/src/services/plan-workspace.service.ts +83 -0
- package/src/services/playbook-registry.service.ts +67 -0
- package/src/services/plugin-executor.service.ts +103 -0
- package/src/services/quality-metrics.service.ts +132 -0
- package/src/services/recent-activity.service.ts +27 -31
- package/src/services/skill-resolver.service.ts +19 -0
- package/src/services/system-executor.service.ts +105 -0
- package/src/services/workstream-message.service.ts +12 -34
- package/src/services/workstream-plan-registry.service.ts +22 -0
- package/src/services/workstream-title.service.ts +3 -1
- package/src/services/workstream-turn-preparation.service.ts +34 -66
- package/src/services/workstream.service.ts +33 -55
- package/src/services/workstream.types.ts +9 -9
- package/src/services/write-intent-validator.service.ts +81 -0
- package/src/storage/attachment-parser.ts +1 -1
- package/src/storage/attachment-utils.ts +1 -1
- package/src/storage/generated-document-storage.service.ts +3 -2
- package/src/system-agents/delegated-agent-factory.ts +2 -0
- package/src/tools/execution-plan.tool.ts +17 -23
- package/src/tools/index.ts +0 -1
- package/src/tools/team-think.tool.ts +6 -4
- package/src/utils/async.ts +2 -1
- package/src/utils/date-time.ts +4 -32
- package/src/utils/env.ts +8 -0
- package/src/utils/errors.ts +42 -10
- package/src/utils/index.ts +9 -0
- package/src/utils/string.ts +114 -1
- package/src/workers/index.ts +1 -0
- package/src/workers/regular-chat-memory-digest.runner.ts +2 -2
- package/src/workers/skill-extraction.runner.ts +1 -1
- package/src/workers/utils/file-section-chunker.ts +2 -1
- package/src/workers/utils/repomix-file-sections.ts +2 -2
- package/src/workers/utils/sandbox-error.ts +11 -2
- package/src/workers/utils/workstream-message-query.ts +11 -20
- package/src/workers/worker-utils.ts +2 -2
- package/src/tools/log-hello-world.tool.ts +0 -17
|
@@ -2,16 +2,18 @@ import type { SerializableExecutionPlan } from '@lota-sdk/shared'
|
|
|
2
2
|
|
|
3
3
|
const EXECUTION_PLAN_AGENT_PROTOCOL_PROMPT = `<execution-plan-protocol>
|
|
4
4
|
- Before doing multi-step work, create a contract-driven execution plan instead of tracking steps only in prose.
|
|
5
|
+
- A workstream may have multiple active execution plans. Review all plans before creating new ones.
|
|
5
6
|
- Plans are graph-capable workflow contracts. Every execution node must define objective, instructions, deliverables, success criteria, completion checks, retry policy, failure policy, and tool/context policy.
|
|
6
7
|
- The runtime executor owns lifecycle truth. Do not claim that a node is complete until submitExecutionNodeResult succeeds.
|
|
7
|
-
- Use execution-plan tools to create, replace, inspect,
|
|
8
|
-
-
|
|
8
|
+
- Use execution-plan tools to create, replace, inspect, and resume runs.
|
|
9
|
+
- Visible workstream agents do not manually submit node results; dispatched execution nodes are completed by the runtime executor.
|
|
10
|
+
- Treat the active execution runs in <execution-plan-state> as authoritative. Do not mutate run or node status in prose.
|
|
9
11
|
- Work only on nodes that are active or explicitly ready for your executor. If a node is awaiting human input or approval, stop and let the runtime resume it.
|
|
10
12
|
- If the graph, contracts, or success criteria materially change, replace the plan instead of silently drifting.
|
|
11
13
|
</execution-plan-protocol>`
|
|
12
14
|
|
|
13
|
-
function
|
|
14
|
-
if (
|
|
15
|
+
function formatExecutionPlansForPrompt(plans: SerializableExecutionPlan[]): string | undefined {
|
|
16
|
+
if (plans.length === 0) return undefined
|
|
15
17
|
|
|
16
18
|
const payload = {
|
|
17
19
|
policy: {
|
|
@@ -21,46 +23,48 @@ function formatExecutionPlanForPrompt(plan: SerializableExecutionPlan | null | u
|
|
|
21
23
|
artifactsAreFirstClassOutputs: true,
|
|
22
24
|
checkpointRecoveryEnabled: true,
|
|
23
25
|
},
|
|
24
|
-
|
|
26
|
+
activePlans: plans,
|
|
27
|
+
planCount: plans.length,
|
|
25
28
|
}
|
|
26
29
|
|
|
27
30
|
return ['<execution-plan-state>', JSON.stringify(payload, null, 2), '</execution-plan-state>'].join('\n')
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
export function buildExecutionPlanInstructionSections(
|
|
31
|
-
|
|
34
|
+
plans: SerializableExecutionPlan[] | null | undefined,
|
|
32
35
|
): string[] | undefined {
|
|
36
|
+
const normalized = plans ?? []
|
|
33
37
|
const sections = [EXECUTION_PLAN_AGENT_PROTOCOL_PROMPT]
|
|
34
|
-
const
|
|
35
|
-
if (
|
|
36
|
-
sections.push(
|
|
38
|
+
const stateSection = formatExecutionPlansForPrompt(normalized)
|
|
39
|
+
if (stateSection) {
|
|
40
|
+
sections.push(stateSection)
|
|
37
41
|
}
|
|
38
42
|
return sections
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
export function createExecutionPlanInstructionSectionCache(params: {
|
|
42
46
|
disabled?: boolean
|
|
43
|
-
|
|
47
|
+
loadPlans: () => Promise<SerializableExecutionPlan[]>
|
|
44
48
|
}) {
|
|
45
|
-
let
|
|
49
|
+
let plansPromise: Promise<SerializableExecutionPlan[]> | null = null
|
|
46
50
|
let sectionsPromise: Promise<string[] | undefined> | null = null
|
|
47
51
|
|
|
48
52
|
return {
|
|
49
53
|
invalidate() {
|
|
50
|
-
|
|
54
|
+
plansPromise = null
|
|
51
55
|
sectionsPromise = null
|
|
52
56
|
},
|
|
53
|
-
async
|
|
54
|
-
if (params.disabled) return
|
|
57
|
+
async getPlans(): Promise<SerializableExecutionPlan[]> {
|
|
58
|
+
if (params.disabled) return []
|
|
55
59
|
|
|
56
|
-
|
|
57
|
-
return
|
|
60
|
+
plansPromise ??= params.loadPlans()
|
|
61
|
+
return plansPromise
|
|
58
62
|
},
|
|
59
63
|
async getSections(): Promise<string[] | undefined> {
|
|
60
64
|
if (params.disabled) return undefined
|
|
61
65
|
|
|
62
|
-
sectionsPromise ??= this.
|
|
63
|
-
return
|
|
66
|
+
sectionsPromise ??= this.getPlans().then((plans) => buildExecutionPlanInstructionSections(plans))
|
|
67
|
+
return sectionsPromise
|
|
64
68
|
},
|
|
65
69
|
}
|
|
66
70
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { GraphDesignRequest, GraphDesignResponse } from '@lota-sdk/shared'
|
|
2
|
+
|
|
3
|
+
export interface GraphDesigner {
|
|
4
|
+
designGraph(request: GraphDesignRequest): Promise<GraphDesignResponse>
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
let _graphDesigner: GraphDesigner | null = null
|
|
8
|
+
|
|
9
|
+
export function configureGraphDesigner(designer: GraphDesigner): void {
|
|
10
|
+
_graphDesigner = designer
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function getGraphDesigner(): GraphDesigner | null {
|
|
14
|
+
return _graphDesigner
|
|
15
|
+
}
|
|
@@ -7,7 +7,7 @@ import type {
|
|
|
7
7
|
} from 'ai'
|
|
8
8
|
import type { ZodSchema } from 'zod'
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { isRecord, stringifyUnknown } from '../utils/string'
|
|
11
11
|
|
|
12
12
|
export interface HelperToolLoopAgentOptions {
|
|
13
13
|
instructions?: string
|
|
@@ -49,12 +49,6 @@ export interface GenerateHelperTextParams {
|
|
|
49
49
|
export interface GenerateHelperStructuredParams<T> extends Omit<GenerateHelperTextParams, 'tag'> {
|
|
50
50
|
tag: string
|
|
51
51
|
schema: ZodSchema<T>
|
|
52
|
-
textFallbackParser?: (text: string) => T | null
|
|
53
|
-
normalizeCandidate?: (candidate: unknown) => unknown
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function isObject(value: unknown): value is Record<string, unknown> {
|
|
57
|
-
return Boolean(value) && typeof value === 'object' && !Array.isArray(value)
|
|
58
52
|
}
|
|
59
53
|
|
|
60
54
|
function getNumericField(value: Record<string, unknown>, key: string): number | null {
|
|
@@ -68,7 +62,7 @@ function getNumericField(value: Record<string, unknown>, key: string): number |
|
|
|
68
62
|
}
|
|
69
63
|
|
|
70
64
|
function getErrorStatus(error: unknown): number | null {
|
|
71
|
-
if (!
|
|
65
|
+
if (!isRecord(error)) return null
|
|
72
66
|
return getNumericField(error, 'status') ?? getNumericField(error, 'statusCode')
|
|
73
67
|
}
|
|
74
68
|
|
|
@@ -76,44 +70,11 @@ function isRateLimitError(error: unknown): boolean {
|
|
|
76
70
|
return getErrorStatus(error) === 429
|
|
77
71
|
}
|
|
78
72
|
|
|
79
|
-
function stringifyUnknown(value: unknown, maxChars: number): string | null {
|
|
80
|
-
if (value === null || value === undefined) return null
|
|
81
|
-
const raw = (() => {
|
|
82
|
-
if (typeof value === 'string') return value
|
|
83
|
-
if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
|
|
84
|
-
return String(value)
|
|
85
|
-
}
|
|
86
|
-
if (typeof value === 'symbol') return value.description ? `Symbol(${value.description})` : 'Symbol()'
|
|
87
|
-
if (typeof value === 'function') return value.name ? `[function ${value.name}]` : '[function anonymous]'
|
|
88
|
-
if (Array.isArray(value)) {
|
|
89
|
-
try {
|
|
90
|
-
return JSON.stringify(value)
|
|
91
|
-
} catch {
|
|
92
|
-
return `[array(${value.length})]`
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
try {
|
|
97
|
-
return JSON.stringify(value)
|
|
98
|
-
} catch {
|
|
99
|
-
const maybeName =
|
|
100
|
-
isObject(value) && typeof (value as { constructor?: { name?: unknown } }).constructor?.name === 'string'
|
|
101
|
-
? (value as { constructor?: { name?: string } }).constructor?.name
|
|
102
|
-
: 'Object'
|
|
103
|
-
return `[object ${maybeName}]`
|
|
104
|
-
}
|
|
105
|
-
})()
|
|
106
|
-
|
|
107
|
-
const normalized = compactWhitespace(raw)
|
|
108
|
-
if (!normalized) return null
|
|
109
|
-
return normalized.length > maxChars ? `${normalized.slice(0, maxChars)}...` : normalized
|
|
110
|
-
}
|
|
111
|
-
|
|
112
73
|
function formatError(tag: string, error: unknown): Error {
|
|
113
74
|
const status = getErrorStatus(error)
|
|
114
75
|
const rateLimited = isRateLimitError(error)
|
|
115
76
|
const message = error instanceof Error ? error.message : String(error)
|
|
116
|
-
const errorRecord =
|
|
77
|
+
const errorRecord = isRecord(error) ? error : null
|
|
117
78
|
const responseBody = errorRecord ? stringifyUnknown(errorRecord.responseBody, 600) : null
|
|
118
79
|
const responseData = errorRecord ? stringifyUnknown(errorRecord.data, 600) : null
|
|
119
80
|
const requestUrl = errorRecord ? stringifyUnknown(errorRecord.url, 200) : null
|
|
@@ -164,59 +125,6 @@ function formatSchemaIssueSummary(issues: Array<{ path: PropertyKey[]; message:
|
|
|
164
125
|
.join('; ')
|
|
165
126
|
}
|
|
166
127
|
|
|
167
|
-
export function extractJsonObjectCandidates(text: string): string[] {
|
|
168
|
-
const trimmed = text.trim()
|
|
169
|
-
if (!trimmed) return []
|
|
170
|
-
|
|
171
|
-
const candidates: string[] = [trimmed]
|
|
172
|
-
const fencedMatch = trimmed.match(/```(?:json)?\s*([\s\S]*?)\s*```/i)
|
|
173
|
-
if (fencedMatch?.[1]) {
|
|
174
|
-
candidates.push(fencedMatch[1].trim())
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
let start = -1
|
|
178
|
-
let depth = 0
|
|
179
|
-
let inString = false
|
|
180
|
-
let escaping = false
|
|
181
|
-
|
|
182
|
-
for (let index = 0; index < trimmed.length; index += 1) {
|
|
183
|
-
const character = trimmed[index]
|
|
184
|
-
|
|
185
|
-
if (escaping) {
|
|
186
|
-
escaping = false
|
|
187
|
-
continue
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
if (character === '\\') {
|
|
191
|
-
escaping = true
|
|
192
|
-
continue
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if (character === '"') {
|
|
196
|
-
inString = !inString
|
|
197
|
-
continue
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (inString) continue
|
|
201
|
-
|
|
202
|
-
if (character === '{') {
|
|
203
|
-
if (depth === 0) start = index
|
|
204
|
-
depth += 1
|
|
205
|
-
continue
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (character === '}') {
|
|
209
|
-
depth -= 1
|
|
210
|
-
if (depth === 0 && start >= 0) {
|
|
211
|
-
candidates.push(trimmed.slice(start, index + 1))
|
|
212
|
-
start = -1
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
return [...new Set(candidates.filter((candidate) => candidate.length > 0))]
|
|
218
|
-
}
|
|
219
|
-
|
|
220
128
|
function parseStructuredCandidate<T>(params: {
|
|
221
129
|
schema: ZodSchema<T>
|
|
222
130
|
candidate: unknown
|
|
@@ -226,7 +134,7 @@ function parseStructuredCandidate<T>(params: {
|
|
|
226
134
|
return { data: direct.data, source: 'root' }
|
|
227
135
|
}
|
|
228
136
|
|
|
229
|
-
if (
|
|
137
|
+
if (isRecord(params.candidate)) {
|
|
230
138
|
for (const key of ['output', 'result', 'data'] as const) {
|
|
231
139
|
const nested = params.candidate[key]
|
|
232
140
|
const nestedParsed = params.schema.safeParse(nested)
|
|
@@ -239,66 +147,6 @@ function parseStructuredCandidate<T>(params: {
|
|
|
239
147
|
return null
|
|
240
148
|
}
|
|
241
149
|
|
|
242
|
-
function parseStructuredTextFallback<T>(params: { schema: ZodSchema<T>; text: string }): T {
|
|
243
|
-
const candidates = extractJsonObjectCandidates(params.text)
|
|
244
|
-
if (candidates.length === 0) {
|
|
245
|
-
throw new Error('Structured fallback did not contain a JSON object candidate.')
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
let lastError = 'Structured fallback could not be parsed.'
|
|
249
|
-
|
|
250
|
-
for (const candidateText of candidates) {
|
|
251
|
-
let parsedJson: unknown
|
|
252
|
-
|
|
253
|
-
try {
|
|
254
|
-
parsedJson = JSON.parse(candidateText) as unknown
|
|
255
|
-
} catch {
|
|
256
|
-
lastError = 'Structured fallback JSON parsing failed.'
|
|
257
|
-
continue
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const parsed = parseStructuredCandidate({ schema: params.schema, candidate: parsedJson })
|
|
261
|
-
if (parsed) {
|
|
262
|
-
return parsed.data
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
const issues = params.schema.safeParse(parsedJson)
|
|
266
|
-
if (!issues.success) {
|
|
267
|
-
lastError = `Structured fallback failed schema validation: ${formatSchemaIssueSummary(issues.error.issues)}`
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
throw new Error(lastError)
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
function parseStructuredTextWithFallbacks<T>(params: {
|
|
275
|
-
schema: ZodSchema<T>
|
|
276
|
-
text: string
|
|
277
|
-
textFallbackParser?: (text: string) => T | null
|
|
278
|
-
}): T {
|
|
279
|
-
try {
|
|
280
|
-
return parseStructuredTextFallback({ schema: params.schema, text: params.text })
|
|
281
|
-
} catch (error) {
|
|
282
|
-
const parseError = error instanceof Error ? error : new Error(String(error))
|
|
283
|
-
|
|
284
|
-
if (params.textFallbackParser) {
|
|
285
|
-
const parsedCandidate = params.textFallbackParser(params.text)
|
|
286
|
-
if (parsedCandidate !== null) {
|
|
287
|
-
const validated = params.schema.safeParse(parsedCandidate)
|
|
288
|
-
if (validated.success) {
|
|
289
|
-
return validated.data
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
throw new Error(
|
|
293
|
-
`Custom text fallback failed schema validation: ${formatSchemaIssueSummary(validated.error.issues)}`,
|
|
294
|
-
)
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
throw parseError
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
150
|
export function createHelperModelRuntime() {
|
|
303
151
|
async function generateHelperText(params: GenerateHelperTextParams): Promise<string> {
|
|
304
152
|
const systemPrompt = resolveSystemPrompt({
|
|
@@ -361,52 +209,16 @@ export function createHelperModelRuntime() {
|
|
|
361
209
|
return parsed.data
|
|
362
210
|
}
|
|
363
211
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
const normalizedParsed = parseStructuredCandidate({ schema: params.schema, candidate: normalized })
|
|
367
|
-
if (normalizedParsed) {
|
|
368
|
-
return normalizedParsed.data
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
if (typeof result.text === 'string' && result.text.trim().length > 0) {
|
|
373
|
-
return parseStructuredTextWithFallbacks({
|
|
374
|
-
schema: params.schema,
|
|
375
|
-
text: result.text,
|
|
376
|
-
textFallbackParser: params.textFallbackParser,
|
|
377
|
-
})
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
const fallbackParsed = params.schema.safeParse(result.output)
|
|
381
|
-
if (!fallbackParsed.success) {
|
|
212
|
+
const directParsed = params.schema.safeParse(result.output)
|
|
213
|
+
if (!directParsed.success) {
|
|
382
214
|
throw new Error(
|
|
383
|
-
`Structured output failed schema validation: ${formatSchemaIssueSummary(
|
|
215
|
+
`Structured output failed schema validation: ${formatSchemaIssueSummary(directParsed.error.issues)}`,
|
|
384
216
|
)
|
|
385
217
|
}
|
|
386
218
|
|
|
387
|
-
return
|
|
219
|
+
return directParsed.data
|
|
388
220
|
} catch (error) {
|
|
389
|
-
|
|
390
|
-
const fallbackMessages: string[] = []
|
|
391
|
-
const fallbackPrompts = [
|
|
392
|
-
systemPrompt,
|
|
393
|
-
...(baseSystemPrompt && baseSystemPrompt !== systemPrompt ? [baseSystemPrompt] : []),
|
|
394
|
-
]
|
|
395
|
-
|
|
396
|
-
for (const fallbackPrompt of fallbackPrompts) {
|
|
397
|
-
try {
|
|
398
|
-
const fallbackText = await generateHelperText({ ...params, systemPrompt: fallbackPrompt })
|
|
399
|
-
return parseStructuredTextWithFallbacks({
|
|
400
|
-
schema: params.schema,
|
|
401
|
-
text: fallbackText,
|
|
402
|
-
textFallbackParser: params.textFallbackParser,
|
|
403
|
-
})
|
|
404
|
-
} catch (fallbackError) {
|
|
405
|
-
fallbackMessages.push(fallbackError instanceof Error ? fallbackError.message : String(fallbackError))
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
throw new Error(`${structuredError.message}; structured_fallback=${fallbackMessages.join(' | ')}`)
|
|
221
|
+
throw formatError(params.tag, error)
|
|
410
222
|
}
|
|
411
223
|
}
|
|
412
224
|
|
package/src/runtime/index.ts
CHANGED
|
@@ -6,6 +6,7 @@ export * from './chat-request-routing'
|
|
|
6
6
|
export * from './chat-run-registry'
|
|
7
7
|
export * from './context-compaction'
|
|
8
8
|
export * from './execution-plan'
|
|
9
|
+
export * from './graph-designer'
|
|
9
10
|
export * from './helper-model'
|
|
10
11
|
export * from './indexed-repositories-policy'
|
|
11
12
|
export * from './instruction-sections'
|
|
@@ -13,6 +14,7 @@ export * from './memory-block'
|
|
|
13
14
|
export * from './memory-digest-policy'
|
|
14
15
|
export * from './memory-scope'
|
|
15
16
|
export * from './llm-content'
|
|
17
|
+
export * from './plugin-resolution'
|
|
16
18
|
export * from './plugin-types'
|
|
17
19
|
export * from './runtime-config'
|
|
18
20
|
export * from './runtime-extensions'
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
1
3
|
import { agentDisplayNames, agentShortDisplayNames, resolveAgentNameAlias } from '../config/agent-defaults'
|
|
2
4
|
import { compactWhitespace } from '../utils/string'
|
|
3
5
|
|
|
@@ -33,11 +35,9 @@ function createLabelPrefixRegex(labelRoles: readonly string[]): RegExp | null {
|
|
|
33
35
|
return new RegExp(`^(?:${aliases.map((role) => escapeRegex(role)).join('|')})\\s*:\\s*`, 'i')
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
timestamp: string
|
|
40
|
-
}
|
|
38
|
+
const MemoryBlockEntrySchema = z.object({ role: z.string(), content: z.string(), timestamp: z.string() })
|
|
39
|
+
|
|
40
|
+
export type MemoryBlockEntry = z.infer<typeof MemoryBlockEntrySchema>
|
|
41
41
|
|
|
42
42
|
export interface MemoryBlockRuntime {
|
|
43
43
|
normalizeMemoryBlockEntry: (entry: string) => string
|
|
@@ -184,10 +184,8 @@ export function createMemoryBlockRuntime(options: CreateMemoryBlockRuntimeOption
|
|
|
184
184
|
const trimmed = raw.trim()
|
|
185
185
|
if (!trimmed.startsWith('[')) return []
|
|
186
186
|
try {
|
|
187
|
-
const parsed
|
|
188
|
-
|
|
189
|
-
if (!parsed.every((item: unknown) => typeof item === 'object' && item !== null)) return []
|
|
190
|
-
return parsed as MemoryBlockEntry[]
|
|
187
|
+
const parsed = z.array(MemoryBlockEntrySchema).safeParse(JSON.parse(trimmed))
|
|
188
|
+
return parsed.success ? parsed.data : []
|
|
191
189
|
} catch {
|
|
192
190
|
return []
|
|
193
191
|
}
|
|
@@ -214,8 +212,8 @@ export function createMemoryBlockRuntime(options: CreateMemoryBlockRuntimeOption
|
|
|
214
212
|
.some((line) => {
|
|
215
213
|
const match = line.match(/^([a-z][a-z0-9_ -]*)\s*:\s*(.+)$/i)
|
|
216
214
|
if (!match) return false
|
|
217
|
-
const rowRole = normalizeMemoryBlockRole(match[1]
|
|
218
|
-
const rowContent = match[2]
|
|
215
|
+
const rowRole = normalizeMemoryBlockRole(match[1])
|
|
216
|
+
const rowContent = match[2]
|
|
219
217
|
if (rowRole !== roleLower) return false
|
|
220
218
|
return normalizeMemoryBlockEntry(rowContent) === normalizedTarget
|
|
221
219
|
})
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { compactWhitespace } from '../utils/string'
|
|
1
|
+
import { clampImportance, compactWhitespace } from '../utils/string'
|
|
2
2
|
|
|
3
3
|
const SCORE_WEIGHTS = {
|
|
4
4
|
durability: { core: 0.35, standard: 0.2, weak: 0.05 },
|
|
5
|
-
type: { decision: 0.25,
|
|
5
|
+
type: { decision: 0.25, fact: 0.18, preference: 0.15, default: 0.1 },
|
|
6
6
|
maxContentLength: 120,
|
|
7
7
|
} as const
|
|
8
8
|
|
|
@@ -107,11 +107,6 @@ interface MemoryActionPlan<TRelation extends string = string> {
|
|
|
107
107
|
relations: MemoryActionRelation<TRelation>[]
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
function clampImportance(value: number): number {
|
|
111
|
-
if (!Number.isFinite(value)) return 0
|
|
112
|
-
return Math.max(0, Math.min(1, value))
|
|
113
|
-
}
|
|
114
|
-
|
|
115
110
|
function normalizeMemoryKey(text: string): string {
|
|
116
111
|
return text
|
|
117
112
|
.toLowerCase()
|
|
@@ -135,8 +130,10 @@ function scoreFact<T extends MemoryFactInput>(fact: T): number {
|
|
|
135
130
|
type === 'decision'
|
|
136
131
|
? SCORE_WEIGHTS.type.decision
|
|
137
132
|
: type === 'fact'
|
|
138
|
-
? SCORE_WEIGHTS.type.
|
|
139
|
-
:
|
|
133
|
+
? SCORE_WEIGHTS.type.fact
|
|
134
|
+
: type === 'preference'
|
|
135
|
+
? SCORE_WEIGHTS.type.preference
|
|
136
|
+
: SCORE_WEIGHTS.type.default
|
|
140
137
|
const lengthWeight =
|
|
141
138
|
Math.min(fact.content.length, SCORE_WEIGHTS.maxContentLength) / SCORE_WEIGHTS.maxContentLength / 10
|
|
142
139
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { pluginRuntime } from '../config/agent-defaults'
|
|
2
|
+
import { getRuntimeAdapters } from './runtime-extensions'
|
|
3
|
+
|
|
4
|
+
export function getPluginService(path: string[]): ((...args: unknown[]) => unknown) | undefined {
|
|
5
|
+
let current: unknown = pluginRuntime
|
|
6
|
+
let owner: unknown = undefined
|
|
7
|
+
for (const key of path) {
|
|
8
|
+
if (current === null || current === undefined || typeof current !== 'object') return undefined
|
|
9
|
+
owner = current
|
|
10
|
+
current = (current as Record<string, unknown>)[key]
|
|
11
|
+
}
|
|
12
|
+
if (typeof current !== 'function') {
|
|
13
|
+
return undefined
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return owner && typeof owner === 'object'
|
|
17
|
+
? (current as (...args: unknown[]) => unknown).bind(owner)
|
|
18
|
+
: (current as (...args: unknown[]) => unknown)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function buildIndexedRepositoriesContext(
|
|
22
|
+
organizationId: string,
|
|
23
|
+
): Promise<{ provideRepoTool: boolean; defaultSectionsByAgent: Record<string, unknown>; context: string }> {
|
|
24
|
+
const buildContext = getRuntimeAdapters().workstream?.buildIndexedRepositoriesContext
|
|
25
|
+
if (!buildContext) {
|
|
26
|
+
return { provideRepoTool: false, defaultSectionsByAgent: {}, context: '' }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const result = await buildContext(organizationId)
|
|
30
|
+
return {
|
|
31
|
+
provideRepoTool: result.provideRepoTool,
|
|
32
|
+
defaultSectionsByAgent: result.defaultSectionsByAgent,
|
|
33
|
+
context: result.context ?? '',
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -1,10 +1,82 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CarryForwardPolicy,
|
|
3
|
+
CycleSchedule,
|
|
4
|
+
PlanDraft,
|
|
5
|
+
PlanNodeResult,
|
|
6
|
+
PlanNodeSpec,
|
|
7
|
+
PlanScheduleSpec,
|
|
8
|
+
SignalDeclaration,
|
|
9
|
+
} from '@lota-sdk/shared'
|
|
10
|
+
|
|
11
|
+
import type { RecordIdRef } from '../db/record-id'
|
|
12
|
+
|
|
13
|
+
export interface PluginContextEnricher {
|
|
14
|
+
domain: string
|
|
15
|
+
enrich(params: {
|
|
16
|
+
objective: string
|
|
17
|
+
organizationId: string
|
|
18
|
+
}): Promise<{ data: Record<string, unknown>; confidence: number }>
|
|
19
|
+
}
|
|
20
|
+
|
|
1
21
|
export interface LotaPluginContributions {
|
|
2
22
|
envKeys: readonly string[]
|
|
3
23
|
schemaFiles: readonly (string | URL)[]
|
|
24
|
+
signals?: readonly SignalDeclaration[]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface PluginNodeExecutorContext {
|
|
28
|
+
organizationId: string
|
|
29
|
+
workstreamId: string
|
|
30
|
+
planId: string
|
|
31
|
+
nodeId: string
|
|
32
|
+
userId?: RecordIdRef
|
|
33
|
+
userName?: string
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface PluginNodeExecutionParams {
|
|
37
|
+
operation: string
|
|
38
|
+
nodeSpec: PlanNodeSpec
|
|
39
|
+
inputs: Record<string, unknown>
|
|
40
|
+
context: PluginNodeExecutorContext
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface PluginNodeExecutor {
|
|
44
|
+
supportedOperations: readonly string[]
|
|
45
|
+
executeNode(params: PluginNodeExecutionParams): Promise<PlanNodeResult>
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface SystemNodeExecutor {
|
|
49
|
+
supportedOperations: readonly string[]
|
|
50
|
+
executeNode(params: PluginNodeExecutionParams): Promise<PlanNodeResult>
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface PlaybookContribution {
|
|
54
|
+
name: string
|
|
55
|
+
description: string
|
|
56
|
+
tags: string[]
|
|
57
|
+
draft: PlanDraft
|
|
58
|
+
schedule?: PlanScheduleSpec
|
|
59
|
+
cycleSchedule?: CycleSchedule
|
|
60
|
+
carryForwardPolicy?: CarryForwardPolicy
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface PlaybookContributor {
|
|
64
|
+
playbooks: readonly PlaybookContribution[]
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface PluginDomainAgentDefinition {
|
|
68
|
+
agentId: string
|
|
69
|
+
displayName: string
|
|
70
|
+
capabilities: readonly string[]
|
|
4
71
|
}
|
|
5
72
|
|
|
6
73
|
export interface LotaPlugin<TServices = Record<string, unknown>, TTools = Record<string, unknown>> {
|
|
7
74
|
services: TServices
|
|
75
|
+
nodeExecutor?: PluginNodeExecutor
|
|
8
76
|
tools?: TTools
|
|
9
77
|
contributions: LotaPluginContributions
|
|
78
|
+
playbookContributor?: PlaybookContributor
|
|
79
|
+
domainAgents?: readonly PluginDomainAgentDefinition[]
|
|
80
|
+
contextEnrichers?: readonly PluginContextEnricher[]
|
|
81
|
+
onSignal?: (signal: string, payload: unknown, source: string) => Promise<void> | void
|
|
10
82
|
}
|
|
@@ -11,7 +11,7 @@ interface ScopedRetrievalResult<TCandidate> {
|
|
|
11
11
|
export async function executeScopedRetrieval<TCandidate>(
|
|
12
12
|
tasks: ScopedRetrievalTask<TCandidate>[],
|
|
13
13
|
): Promise<ScopedRetrievalResult<TCandidate>[]> {
|
|
14
|
-
return
|
|
14
|
+
return Promise.all(tasks.map(async (task) => ({ scopeTag: task.scopeTag, candidates: await task.retrieve() })))
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export function countScopedRetrievalCandidates<TCandidate>(scoped: ScopedRetrievalResult<TCandidate>[]): number {
|