@lota-sdk/core 0.1.14 → 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 +9 -8
- package/src/ai/definitions.ts +80 -2
- package/src/ai/embedding-cache.ts +7 -6
- package/src/ai/index.ts +0 -1
- package/src/bifrost/bifrost.ts +14 -14
- package/src/config/agent-defaults.ts +32 -22
- 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/logger.ts +7 -9
- package/src/config/model-constants.ts +16 -34
- package/src/config/search.ts +1 -15
- package/src/create-runtime.ts +453 -0
- 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 +24 -24
- package/src/db/memory.ts +18 -16
- package/src/db/schema-fingerprint.ts +1 -0
- package/src/db/service.ts +193 -122
- package/src/db/startup.ts +9 -13
- 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/index.ts +1 -1
- package/src/queues/context-compaction.queue.ts +17 -52
- package/src/queues/delayed-node-promotion.queue.ts +41 -0
- package/src/queues/document-processor.queue.ts +7 -7
- package/src/queues/index.ts +3 -0
- package/src/queues/memory-consolidation.queue.ts +18 -54
- package/src/queues/plan-scheduler.queue.ts +97 -0
- package/src/queues/post-chat-memory.queue.ts +15 -60
- package/src/queues/queue-factory.ts +100 -0
- package/src/queues/recent-activity-title-refinement.queue.ts +15 -54
- package/src/queues/regular-chat-memory-digest.queue.ts +16 -55
- package/src/queues/skill-extraction.queue.ts +15 -50
- package/src/queues/workstream-title-generation.queue.ts +15 -51
- package/src/redis/connection.ts +12 -3
- package/src/redis/index.ts +2 -1
- package/src/redis/org-memory-lock.ts +1 -1
- package/src/redis/redis-lease-lock.ts +41 -8
- package/src/redis/stream-context.ts +11 -0
- package/src/runtime/agent-runtime-policy.ts +106 -21
- package/src/runtime/agent-stream-helpers.ts +2 -1
- package/src/runtime/approval-continuation.ts +12 -6
- package/src/runtime/context-compaction-constants.ts +1 -1
- package/src/runtime/context-compaction-runtime.ts +7 -5
- package/src/runtime/context-compaction.ts +40 -97
- package/src/runtime/execution-plan.ts +23 -19
- package/src/runtime/graph-designer.ts +15 -0
- package/src/runtime/helper-model.ts +10 -196
- package/src/runtime/index.ts +14 -1
- package/src/runtime/llm-content.ts +1 -1
- package/src/runtime/memory-block.ts +11 -12
- package/src/runtime/memory-pipeline.ts +26 -10
- package/src/runtime/plugin-resolution.ts +35 -0
- package/src/runtime/plugin-types.ts +73 -1
- package/src/runtime/retrieval-adapters.ts +1 -1
- package/src/runtime/runtime-config.ts +25 -12
- package/src/runtime/runtime-extensions.ts +91 -15
- 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 +11 -4
- package/src/runtime/workstream-chat-helpers.ts +6 -7
- package/src/runtime/workstream-routing-policy.ts +0 -30
- package/src/runtime/workstream-state.ts +17 -7
- 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 +7 -12
- package/src/services/context-compaction.service.ts +75 -58
- 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 +38 -33
- package/src/services/domain-agent-executor.service.ts +71 -0
- package/src/services/execution-plan.service.ts +271 -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 +30 -15
- package/src/services/memory-assessment.service.ts +3 -2
- package/src/services/{memory.utils.ts → memory-utils.ts} +4 -13
- package/src/services/memory.service.ts +55 -69
- 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 +12 -5
- 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-artifact.service.ts +1 -0
- 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 +386 -58
- package/src/services/plan-helpers.ts +15 -0
- 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 +87 -20
- 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-title.service.ts +3 -10
- package/src/services/recent-activity.service.ts +33 -43
- 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 +29 -41
- package/src/services/workstream-plan-registry.service.ts +22 -0
- package/src/services/workstream-title.service.ts +3 -9
- package/src/services/{workstream-turn-preparation.ts → workstream-turn-preparation.service.ts} +428 -373
- package/src/services/workstream-turn.ts +2 -2
- package/src/services/workstream.service.ts +55 -65
- package/src/services/workstream.types.ts +10 -19
- package/src/services/write-intent-validator.service.ts +81 -0
- package/src/storage/attachment-parser.ts +1 -1
- package/src/storage/attachment-storage.service.ts +4 -4
- package/src/storage/{attachments.utils.ts → attachment-utils.ts} +2 -5
- package/src/storage/generated-document-storage.service.ts +3 -2
- package/src/storage/index.ts +2 -2
- package/src/system-agents/{context-compacter.agent.ts → context-compaction.agent.ts} +4 -4
- package/src/system-agents/delegated-agent-factory.ts +5 -2
- package/src/system-agents/index.ts +8 -0
- 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 +1 -1
- package/src/tools/execution-plan.tool.ts +17 -19
- package/src/tools/fetch-webpage.tool.ts +20 -18
- package/src/tools/index.ts +2 -3
- package/src/tools/read-file-parts.tool.ts +1 -1
- package/src/tools/search-web.tool.ts +18 -15
- package/src/tools/{search-tools.ts → search.tool.ts} +1 -1
- package/src/tools/team-think.tool.ts +14 -8
- package/src/tools/{tool-contract.ts → tool-contracts.ts} +9 -2
- package/src/utils/async.ts +3 -2
- package/src/utils/date-time.ts +4 -32
- package/src/utils/env.ts +8 -0
- package/src/utils/errors.ts +47 -0
- package/src/utils/hono-error-handler.ts +1 -2
- package/src/utils/index.ts +19 -2
- package/src/utils/string.ts +128 -1
- package/src/workers/bootstrap.ts +2 -2
- package/src/workers/index.ts +1 -0
- package/src/workers/memory-consolidation.worker.ts +12 -12
- package/src/workers/regular-chat-memory-digest.helpers.ts +2 -7
- package/src/workers/regular-chat-memory-digest.runner.ts +11 -105
- package/src/workers/skill-extraction.runner.ts +8 -102
- package/src/workers/utils/file-section-chunker.ts +6 -3
- 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 +97 -0
- package/src/workers/worker-utils.ts +6 -2
- package/src/runtime/retrieval-pipeline.ts +0 -3
- package/src/runtime.ts +0 -387
- package/src/tools/log-hello-world.tool.ts +0 -17
- package/src/utils/error.ts +0 -10
- /package/src/services/{context-compaction-runtime.ts → context-compaction-runtime.singleton.ts} +0 -0
- /package/src/storage/{attachments.types.ts → attachment-types.ts} +0 -0
|
@@ -7,6 +7,8 @@ import type {
|
|
|
7
7
|
} from 'ai'
|
|
8
8
|
import type { ZodSchema } from 'zod'
|
|
9
9
|
|
|
10
|
+
import { isRecord, stringifyUnknown } from '../utils/string'
|
|
11
|
+
|
|
10
12
|
export interface HelperToolLoopAgentOptions {
|
|
11
13
|
instructions?: string
|
|
12
14
|
maxOutputTokens?: number
|
|
@@ -47,12 +49,6 @@ export interface GenerateHelperTextParams {
|
|
|
47
49
|
export interface GenerateHelperStructuredParams<T> extends Omit<GenerateHelperTextParams, 'tag'> {
|
|
48
50
|
tag: string
|
|
49
51
|
schema: ZodSchema<T>
|
|
50
|
-
textFallbackParser?: (text: string) => T | null
|
|
51
|
-
normalizeCandidate?: (candidate: unknown) => unknown
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function isObject(value: unknown): value is Record<string, unknown> {
|
|
55
|
-
return Boolean(value) && typeof value === 'object' && !Array.isArray(value)
|
|
56
52
|
}
|
|
57
53
|
|
|
58
54
|
function getNumericField(value: Record<string, unknown>, key: string): number | null {
|
|
@@ -66,7 +62,7 @@ function getNumericField(value: Record<string, unknown>, key: string): number |
|
|
|
66
62
|
}
|
|
67
63
|
|
|
68
64
|
function getErrorStatus(error: unknown): number | null {
|
|
69
|
-
if (!
|
|
65
|
+
if (!isRecord(error)) return null
|
|
70
66
|
return getNumericField(error, 'status') ?? getNumericField(error, 'statusCode')
|
|
71
67
|
}
|
|
72
68
|
|
|
@@ -74,44 +70,11 @@ function isRateLimitError(error: unknown): boolean {
|
|
|
74
70
|
return getErrorStatus(error) === 429
|
|
75
71
|
}
|
|
76
72
|
|
|
77
|
-
function stringifyUnknown(value: unknown, maxChars: number): string | null {
|
|
78
|
-
if (value === null || value === undefined) return null
|
|
79
|
-
const raw = (() => {
|
|
80
|
-
if (typeof value === 'string') return value
|
|
81
|
-
if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
|
|
82
|
-
return String(value)
|
|
83
|
-
}
|
|
84
|
-
if (typeof value === 'symbol') return value.description ? `Symbol(${value.description})` : 'Symbol()'
|
|
85
|
-
if (typeof value === 'function') return value.name ? `[function ${value.name}]` : '[function anonymous]'
|
|
86
|
-
if (Array.isArray(value)) {
|
|
87
|
-
try {
|
|
88
|
-
return JSON.stringify(value)
|
|
89
|
-
} catch {
|
|
90
|
-
return `[array(${value.length})]`
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
try {
|
|
95
|
-
return JSON.stringify(value)
|
|
96
|
-
} catch {
|
|
97
|
-
const maybeName =
|
|
98
|
-
isObject(value) && typeof (value as { constructor?: { name?: unknown } }).constructor?.name === 'string'
|
|
99
|
-
? (value as { constructor?: { name?: string } }).constructor?.name
|
|
100
|
-
: 'Object'
|
|
101
|
-
return `[object ${maybeName}]`
|
|
102
|
-
}
|
|
103
|
-
})()
|
|
104
|
-
|
|
105
|
-
const normalized = raw.replace(/\s+/g, ' ').trim()
|
|
106
|
-
if (!normalized) return null
|
|
107
|
-
return normalized.length > maxChars ? `${normalized.slice(0, maxChars)}...` : normalized
|
|
108
|
-
}
|
|
109
|
-
|
|
110
73
|
function formatError(tag: string, error: unknown): Error {
|
|
111
74
|
const status = getErrorStatus(error)
|
|
112
75
|
const rateLimited = isRateLimitError(error)
|
|
113
76
|
const message = error instanceof Error ? error.message : String(error)
|
|
114
|
-
const errorRecord =
|
|
77
|
+
const errorRecord = isRecord(error) ? error : null
|
|
115
78
|
const responseBody = errorRecord ? stringifyUnknown(errorRecord.responseBody, 600) : null
|
|
116
79
|
const responseData = errorRecord ? stringifyUnknown(errorRecord.data, 600) : null
|
|
117
80
|
const requestUrl = errorRecord ? stringifyUnknown(errorRecord.url, 200) : null
|
|
@@ -162,59 +125,6 @@ function formatSchemaIssueSummary(issues: Array<{ path: PropertyKey[]; message:
|
|
|
162
125
|
.join('; ')
|
|
163
126
|
}
|
|
164
127
|
|
|
165
|
-
export function extractJsonObjectCandidates(text: string): string[] {
|
|
166
|
-
const trimmed = text.trim()
|
|
167
|
-
if (!trimmed) return []
|
|
168
|
-
|
|
169
|
-
const candidates: string[] = [trimmed]
|
|
170
|
-
const fencedMatch = trimmed.match(/```(?:json)?\s*([\s\S]*?)\s*```/i)
|
|
171
|
-
if (fencedMatch?.[1]) {
|
|
172
|
-
candidates.push(fencedMatch[1].trim())
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
let start = -1
|
|
176
|
-
let depth = 0
|
|
177
|
-
let inString = false
|
|
178
|
-
let escaping = false
|
|
179
|
-
|
|
180
|
-
for (let index = 0; index < trimmed.length; index += 1) {
|
|
181
|
-
const character = trimmed[index]
|
|
182
|
-
|
|
183
|
-
if (escaping) {
|
|
184
|
-
escaping = false
|
|
185
|
-
continue
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
if (character === '\\') {
|
|
189
|
-
escaping = true
|
|
190
|
-
continue
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
if (character === '"') {
|
|
194
|
-
inString = !inString
|
|
195
|
-
continue
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
if (inString) continue
|
|
199
|
-
|
|
200
|
-
if (character === '{') {
|
|
201
|
-
if (depth === 0) start = index
|
|
202
|
-
depth += 1
|
|
203
|
-
continue
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
if (character === '}') {
|
|
207
|
-
depth -= 1
|
|
208
|
-
if (depth === 0 && start >= 0) {
|
|
209
|
-
candidates.push(trimmed.slice(start, index + 1))
|
|
210
|
-
start = -1
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
return [...new Set(candidates.filter((candidate) => candidate.length > 0))]
|
|
216
|
-
}
|
|
217
|
-
|
|
218
128
|
function parseStructuredCandidate<T>(params: {
|
|
219
129
|
schema: ZodSchema<T>
|
|
220
130
|
candidate: unknown
|
|
@@ -224,7 +134,7 @@ function parseStructuredCandidate<T>(params: {
|
|
|
224
134
|
return { data: direct.data, source: 'root' }
|
|
225
135
|
}
|
|
226
136
|
|
|
227
|
-
if (
|
|
137
|
+
if (isRecord(params.candidate)) {
|
|
228
138
|
for (const key of ['output', 'result', 'data'] as const) {
|
|
229
139
|
const nested = params.candidate[key]
|
|
230
140
|
const nestedParsed = params.schema.safeParse(nested)
|
|
@@ -237,66 +147,6 @@ function parseStructuredCandidate<T>(params: {
|
|
|
237
147
|
return null
|
|
238
148
|
}
|
|
239
149
|
|
|
240
|
-
function parseStructuredTextFallback<T>(params: { schema: ZodSchema<T>; text: string }): T {
|
|
241
|
-
const candidates = extractJsonObjectCandidates(params.text)
|
|
242
|
-
if (candidates.length === 0) {
|
|
243
|
-
throw new Error('Structured fallback did not contain a JSON object candidate.')
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
let lastError = 'Structured fallback could not be parsed.'
|
|
247
|
-
|
|
248
|
-
for (const candidateText of candidates) {
|
|
249
|
-
let parsedJson: unknown
|
|
250
|
-
|
|
251
|
-
try {
|
|
252
|
-
parsedJson = JSON.parse(candidateText) as unknown
|
|
253
|
-
} catch {
|
|
254
|
-
lastError = 'Structured fallback JSON parsing failed.'
|
|
255
|
-
continue
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
const parsed = parseStructuredCandidate({ schema: params.schema, candidate: parsedJson })
|
|
259
|
-
if (parsed) {
|
|
260
|
-
return parsed.data
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
const issues = params.schema.safeParse(parsedJson)
|
|
264
|
-
if (!issues.success) {
|
|
265
|
-
lastError = `Structured fallback failed schema validation: ${formatSchemaIssueSummary(issues.error.issues)}`
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
throw new Error(lastError)
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
function parseStructuredTextWithFallbacks<T>(params: {
|
|
273
|
-
schema: ZodSchema<T>
|
|
274
|
-
text: string
|
|
275
|
-
textFallbackParser?: (text: string) => T | null
|
|
276
|
-
}): T {
|
|
277
|
-
try {
|
|
278
|
-
return parseStructuredTextFallback({ schema: params.schema, text: params.text })
|
|
279
|
-
} catch (error) {
|
|
280
|
-
const parseError = error instanceof Error ? error : new Error(String(error))
|
|
281
|
-
|
|
282
|
-
if (params.textFallbackParser) {
|
|
283
|
-
const parsedCandidate = params.textFallbackParser(params.text)
|
|
284
|
-
if (parsedCandidate !== null) {
|
|
285
|
-
const validated = params.schema.safeParse(parsedCandidate)
|
|
286
|
-
if (validated.success) {
|
|
287
|
-
return validated.data
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
throw new Error(
|
|
291
|
-
`Custom text fallback failed schema validation: ${formatSchemaIssueSummary(validated.error.issues)}`,
|
|
292
|
-
)
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
throw parseError
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
150
|
export function createHelperModelRuntime() {
|
|
301
151
|
async function generateHelperText(params: GenerateHelperTextParams): Promise<string> {
|
|
302
152
|
const systemPrompt = resolveSystemPrompt({
|
|
@@ -359,52 +209,16 @@ export function createHelperModelRuntime() {
|
|
|
359
209
|
return parsed.data
|
|
360
210
|
}
|
|
361
211
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
const normalizedParsed = parseStructuredCandidate({ schema: params.schema, candidate: normalized })
|
|
365
|
-
if (normalizedParsed) {
|
|
366
|
-
return normalizedParsed.data
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
if (typeof result.text === 'string' && result.text.trim().length > 0) {
|
|
371
|
-
return parseStructuredTextWithFallbacks({
|
|
372
|
-
schema: params.schema,
|
|
373
|
-
text: result.text,
|
|
374
|
-
textFallbackParser: params.textFallbackParser,
|
|
375
|
-
})
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
const fallbackParsed = params.schema.safeParse(result.output)
|
|
379
|
-
if (!fallbackParsed.success) {
|
|
212
|
+
const directParsed = params.schema.safeParse(result.output)
|
|
213
|
+
if (!directParsed.success) {
|
|
380
214
|
throw new Error(
|
|
381
|
-
`Structured output failed schema validation: ${formatSchemaIssueSummary(
|
|
215
|
+
`Structured output failed schema validation: ${formatSchemaIssueSummary(directParsed.error.issues)}`,
|
|
382
216
|
)
|
|
383
217
|
}
|
|
384
218
|
|
|
385
|
-
return
|
|
219
|
+
return directParsed.data
|
|
386
220
|
} catch (error) {
|
|
387
|
-
|
|
388
|
-
const fallbackMessages: string[] = []
|
|
389
|
-
const fallbackPrompts = [
|
|
390
|
-
systemPrompt,
|
|
391
|
-
...(baseSystemPrompt && baseSystemPrompt !== systemPrompt ? [baseSystemPrompt] : []),
|
|
392
|
-
]
|
|
393
|
-
|
|
394
|
-
for (const fallbackPrompt of fallbackPrompts) {
|
|
395
|
-
try {
|
|
396
|
-
const fallbackText = await generateHelperText({ ...params, systemPrompt: fallbackPrompt })
|
|
397
|
-
return parseStructuredTextWithFallbacks({
|
|
398
|
-
schema: params.schema,
|
|
399
|
-
text: fallbackText,
|
|
400
|
-
textFallbackParser: params.textFallbackParser,
|
|
401
|
-
})
|
|
402
|
-
} catch (fallbackError) {
|
|
403
|
-
fallbackMessages.push(fallbackError instanceof Error ? fallbackError.message : String(fallbackError))
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
throw new Error(`${structuredError.message}; structured_fallback=${fallbackMessages.join(' | ')}`)
|
|
221
|
+
throw formatError(params.tag, error)
|
|
408
222
|
}
|
|
409
223
|
}
|
|
410
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'
|
|
@@ -23,4 +25,15 @@ export * from './team-consultation-prompts'
|
|
|
23
25
|
export * from './turn-lifecycle'
|
|
24
26
|
export * from './workstream-chat-helpers'
|
|
25
27
|
export * from './workstream-routing-policy'
|
|
26
|
-
export
|
|
28
|
+
export {
|
|
29
|
+
WorkstreamStateSchema,
|
|
30
|
+
type WorkstreamState,
|
|
31
|
+
type WorkstreamStateDelta,
|
|
32
|
+
StructuredWorkstreamStateDeltaSchema,
|
|
33
|
+
type StructuredWorkstreamStateDelta,
|
|
34
|
+
createEmptyStructuredWorkstreamStateDelta,
|
|
35
|
+
parseStructuredWorkstreamStateDelta,
|
|
36
|
+
StructuredCompactionOutputSchema,
|
|
37
|
+
type CompactionOutput,
|
|
38
|
+
createEmptyWorkstreamState,
|
|
39
|
+
} from './workstream-state'
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
1
3
|
import { agentDisplayNames, agentShortDisplayNames, resolveAgentNameAlias } from '../config/agent-defaults'
|
|
4
|
+
import { compactWhitespace } from '../utils/string'
|
|
2
5
|
|
|
3
6
|
function escapeRegex(value: string): string {
|
|
4
7
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
@@ -32,11 +35,9 @@ function createLabelPrefixRegex(labelRoles: readonly string[]): RegExp | null {
|
|
|
32
35
|
return new RegExp(`^(?:${aliases.map((role) => escapeRegex(role)).join('|')})\\s*:\\s*`, 'i')
|
|
33
36
|
}
|
|
34
37
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
timestamp: string
|
|
39
|
-
}
|
|
38
|
+
const MemoryBlockEntrySchema = z.object({ role: z.string(), content: z.string(), timestamp: z.string() })
|
|
39
|
+
|
|
40
|
+
export type MemoryBlockEntry = z.infer<typeof MemoryBlockEntrySchema>
|
|
40
41
|
|
|
41
42
|
export interface MemoryBlockRuntime {
|
|
42
43
|
normalizeMemoryBlockEntry: (entry: string) => string
|
|
@@ -173,8 +174,7 @@ export function createMemoryBlockRuntime(options: CreateMemoryBlockRuntimeOption
|
|
|
173
174
|
)
|
|
174
175
|
.filter(Boolean)
|
|
175
176
|
|
|
176
|
-
const
|
|
177
|
-
const collapsed = candidate.replace(/\s+/g, ' ').trim()
|
|
177
|
+
const collapsed = compactWhitespace(normalizedLines.join(' '))
|
|
178
178
|
if (!collapsed) return ''
|
|
179
179
|
return collapsed
|
|
180
180
|
}
|
|
@@ -184,9 +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
|
-
return parsed as MemoryBlockEntry[]
|
|
187
|
+
const parsed = z.array(MemoryBlockEntrySchema).safeParse(JSON.parse(trimmed))
|
|
188
|
+
return parsed.success ? parsed.data : []
|
|
190
189
|
} catch {
|
|
191
190
|
return []
|
|
192
191
|
}
|
|
@@ -213,8 +212,8 @@ export function createMemoryBlockRuntime(options: CreateMemoryBlockRuntimeOption
|
|
|
213
212
|
.some((line) => {
|
|
214
213
|
const match = line.match(/^([a-z][a-z0-9_ -]*)\s*:\s*(.+)$/i)
|
|
215
214
|
if (!match) return false
|
|
216
|
-
const rowRole = normalizeMemoryBlockRole(match[1]
|
|
217
|
-
const rowContent = match[2]
|
|
215
|
+
const rowRole = normalizeMemoryBlockRole(match[1])
|
|
216
|
+
const rowContent = match[2]
|
|
218
217
|
if (rowRole !== roleLower) return false
|
|
219
218
|
return normalizeMemoryBlockEntry(rowContent) === normalizedTarget
|
|
220
219
|
})
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
import { clampImportance, compactWhitespace } from '../utils/string'
|
|
2
|
+
|
|
3
|
+
const SCORE_WEIGHTS = {
|
|
4
|
+
durability: { core: 0.35, standard: 0.2, weak: 0.05 },
|
|
5
|
+
type: { decision: 0.25, fact: 0.18, preference: 0.15, default: 0.1 },
|
|
6
|
+
maxContentLength: 120,
|
|
7
|
+
} as const
|
|
8
|
+
|
|
1
9
|
interface MemoryFactInput {
|
|
2
10
|
content: string
|
|
3
11
|
confidence: number
|
|
@@ -99,11 +107,6 @@ interface MemoryActionPlan<TRelation extends string = string> {
|
|
|
99
107
|
relations: MemoryActionRelation<TRelation>[]
|
|
100
108
|
}
|
|
101
109
|
|
|
102
|
-
function clampImportance(value: number): number {
|
|
103
|
-
if (!Number.isFinite(value)) return 0
|
|
104
|
-
return Math.max(0, Math.min(1, value))
|
|
105
|
-
}
|
|
106
|
-
|
|
107
110
|
function normalizeMemoryKey(text: string): string {
|
|
108
111
|
return text
|
|
109
112
|
.toLowerCase()
|
|
@@ -117,9 +120,22 @@ function scoreFact<T extends MemoryFactInput>(fact: T): number {
|
|
|
117
120
|
const durability = fact.durability ?? 'standard'
|
|
118
121
|
const type = fact.type ?? 'fact'
|
|
119
122
|
|
|
120
|
-
const durabilityWeight =
|
|
121
|
-
|
|
122
|
-
|
|
123
|
+
const durabilityWeight =
|
|
124
|
+
durability === 'core'
|
|
125
|
+
? SCORE_WEIGHTS.durability.core
|
|
126
|
+
: durability === 'standard'
|
|
127
|
+
? SCORE_WEIGHTS.durability.standard
|
|
128
|
+
: SCORE_WEIGHTS.durability.weak
|
|
129
|
+
const typeWeight =
|
|
130
|
+
type === 'decision'
|
|
131
|
+
? SCORE_WEIGHTS.type.decision
|
|
132
|
+
: type === 'fact'
|
|
133
|
+
? SCORE_WEIGHTS.type.fact
|
|
134
|
+
: type === 'preference'
|
|
135
|
+
? SCORE_WEIGHTS.type.preference
|
|
136
|
+
: SCORE_WEIGHTS.type.default
|
|
137
|
+
const lengthWeight =
|
|
138
|
+
Math.min(fact.content.length, SCORE_WEIGHTS.maxContentLength) / SCORE_WEIGHTS.maxContentLength / 10
|
|
123
139
|
|
|
124
140
|
return confidence + durabilityWeight + typeWeight + lengthWeight
|
|
125
141
|
}
|
|
@@ -160,7 +176,7 @@ export function postProcessMemoryFacts<T extends MemoryFactInput>(
|
|
|
160
176
|
const deduped = new Map<string, T>()
|
|
161
177
|
|
|
162
178
|
for (const fact of rawFacts) {
|
|
163
|
-
const content = typeof fact.content === 'string' ? fact.content
|
|
179
|
+
const content = typeof fact.content === 'string' ? compactWhitespace(fact.content) : ''
|
|
164
180
|
if (!content || content.length < minChars || content.length > maxChars) continue
|
|
165
181
|
const normalizedFact = { ...fact, content }
|
|
166
182
|
const key = normalizeFactForDedupe(content)
|
|
@@ -464,7 +480,7 @@ export function createMemoryActionPlan<TRelation extends string = string>(params
|
|
|
464
480
|
}
|
|
465
481
|
|
|
466
482
|
for (const [index, item] of params.updates.memory.entries()) {
|
|
467
|
-
const text = typeof item.text === 'string' ? item.text
|
|
483
|
+
const text = typeof item.text === 'string' ? compactWhitespace(item.text) : ''
|
|
468
484
|
const itemId = typeof item.id === 'string' ? item.id.trim() : ''
|
|
469
485
|
|
|
470
486
|
switch (item.event) {
|
|
@@ -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
|
-
export interface LotaPlugin<TServices =
|
|
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 {
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
2
|
|
|
3
3
|
import type { CoreWorkstreamProfile } from '../config/agent-defaults'
|
|
4
|
+
import type { AgentFactory, AgentRuntimeConfigProvider, AgentToolBuilder } from '../config/agent-types'
|
|
4
5
|
import type { LotaWorkstreamConfig, WorkstreamBootstrapWelcomeConfig } from '../config/workstream-defaults'
|
|
5
|
-
import type {
|
|
6
|
+
import type { NotificationService } from '../services/notification.service'
|
|
7
|
+
import { isRecord } from '../utils/string'
|
|
8
|
+
import type { GraphDesigner } from './graph-designer'
|
|
9
|
+
import type { LotaPlugin, SystemNodeExecutor } from './plugin-types'
|
|
6
10
|
import type { LotaRuntimeAdapters, LotaRuntimeTurnHooks } from './runtime-extensions'
|
|
7
11
|
import type { LotaRuntimeWorkerExtensions } from './runtime-worker-registry'
|
|
8
12
|
|
|
9
13
|
const logLevelValues = ['trace', 'debug', 'info', 'warning', 'error', 'fatal'] as const
|
|
10
14
|
|
|
11
|
-
type LotaAgentFactoryRegistry = Record<string, (...args: unknown[]) => unknown>
|
|
12
|
-
|
|
13
|
-
const isRecord = (value: unknown): value is Record<string, unknown> => typeof value === 'object' && value !== null
|
|
14
|
-
|
|
15
15
|
function isStringOrUrl(value: unknown): value is string | URL {
|
|
16
16
|
return typeof value === 'string' || value instanceof URL
|
|
17
17
|
}
|
|
@@ -24,7 +24,7 @@ function isStringRecord(value: unknown): value is Record<string, string> {
|
|
|
24
24
|
return isRecord(value) && Object.values(value).every((entry) => typeof entry === 'string')
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
function isAgentFactoryRegistry(value: unknown): value is
|
|
27
|
+
function isAgentFactoryRegistry(value: unknown): value is AgentFactory {
|
|
28
28
|
return isRecord(value) && Object.values(value).every((entry) => typeof entry === 'function')
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -32,10 +32,22 @@ function isPluginRuntimeRecord(value: unknown): value is Record<string, LotaPlug
|
|
|
32
32
|
return isRecord(value)
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
function isSystemExecutorRecord(value: unknown): value is Record<string, SystemNodeExecutor> {
|
|
36
|
+
return isRecord(value)
|
|
37
|
+
}
|
|
38
|
+
|
|
35
39
|
function isToolProviderRecord(value: unknown): value is Record<string, unknown> {
|
|
36
40
|
return isRecord(value)
|
|
37
41
|
}
|
|
38
42
|
|
|
43
|
+
function isNotificationService(value: unknown): value is NotificationService {
|
|
44
|
+
return isRecord(value) && isFunction(value.notify) && isFunction(value.remind) && isFunction(value.escalate)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function isGraphDesigner(value: unknown): value is GraphDesigner {
|
|
48
|
+
return isRecord(value) && isFunction(value.designGraph)
|
|
49
|
+
}
|
|
50
|
+
|
|
39
51
|
function isWorkerExtensionRecord(value: unknown): value is LotaRuntimeWorkerExtensions {
|
|
40
52
|
if (!isRecord(value)) return false
|
|
41
53
|
|
|
@@ -85,15 +97,13 @@ const agentsConfigSchema = z
|
|
|
85
97
|
})
|
|
86
98
|
.optional(),
|
|
87
99
|
createAgent: z
|
|
88
|
-
.custom<
|
|
89
|
-
error: 'agents.createAgent must be a function registry',
|
|
90
|
-
})
|
|
100
|
+
.custom<AgentFactory>(isAgentFactoryRegistry, { error: 'agents.createAgent must be a function registry' })
|
|
91
101
|
.optional(),
|
|
92
102
|
buildAgentTools: z
|
|
93
|
-
.custom<
|
|
103
|
+
.custom<AgentToolBuilder>(isFunction, { error: 'agents.buildAgentTools must be a function' })
|
|
94
104
|
.optional(),
|
|
95
105
|
getAgentRuntimeConfig: z
|
|
96
|
-
.custom<
|
|
106
|
+
.custom<AgentRuntimeConfigProvider>(isFunction, { error: 'agents.getAgentRuntimeConfig must be a function' })
|
|
97
107
|
.optional(),
|
|
98
108
|
})
|
|
99
109
|
.superRefine((value, ctx) => {
|
|
@@ -173,8 +183,11 @@ export const LotaRuntimeConfigSchema = z.object({
|
|
|
173
183
|
extraSchemaFiles: z.array(z.custom<string | URL>(isStringOrUrl)).optional(),
|
|
174
184
|
extraWorkers: z.custom<LotaRuntimeWorkerExtensions>(isWorkerExtensionRecord).optional(),
|
|
175
185
|
pluginRuntime: z.custom<Record<string, LotaPlugin>>(isPluginRuntimeRecord).optional(),
|
|
186
|
+
systemExecutors: z.custom<Record<string, SystemNodeExecutor>>(isSystemExecutorRecord).optional(),
|
|
187
|
+
notificationService: z.custom<NotificationService>(isNotificationService).optional(),
|
|
176
188
|
runtimeAdapters: z.custom<LotaRuntimeAdapters>(isRecord).optional(),
|
|
177
189
|
turnHooks: z.custom<LotaRuntimeTurnHooks>(isRecord).optional(),
|
|
190
|
+
graphDesigner: z.custom<GraphDesigner>(isGraphDesigner).optional(),
|
|
178
191
|
})
|
|
179
192
|
|
|
180
193
|
export type LotaRuntimeConfig = z.input<typeof LotaRuntimeConfigSchema>
|
|
@@ -235,4 +248,4 @@ export function parseWorkerBootstrapEnv(env: Record<string, string | undefined>)
|
|
|
235
248
|
return WORKER_BOOTSTRAP_ENV_SCHEMA.parse(env)
|
|
236
249
|
}
|
|
237
250
|
|
|
238
|
-
export type {
|
|
251
|
+
export type { LotaWorkstreamConfig }
|