@lota-sdk/core 0.1.9 → 0.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/infrastructure/schema/00_workstream.surql +1 -0
  2. package/infrastructure/schema/02_execution_plan.surql +202 -52
  3. package/package.json +4 -2
  4. package/src/bifrost/bifrost.ts +94 -25
  5. package/src/config/model-constants.ts +8 -6
  6. package/src/db/memory-store.ts +3 -71
  7. package/src/db/service.ts +42 -2
  8. package/src/db/tables.ts +9 -2
  9. package/src/embeddings/provider.ts +92 -21
  10. package/src/index.ts +6 -0
  11. package/src/redis/stream-context.ts +44 -0
  12. package/src/runtime/approval-continuation.ts +59 -0
  13. package/src/runtime/chat-request-routing.ts +5 -1
  14. package/src/runtime/execution-plan.ts +21 -14
  15. package/src/runtime/turn-lifecycle.ts +12 -4
  16. package/src/services/document-chunk.service.ts +2 -2
  17. package/src/services/execution-plan.service.ts +579 -786
  18. package/src/services/learned-skill.service.ts +2 -2
  19. package/src/services/plan-approval.service.ts +83 -0
  20. package/src/services/plan-artifact.service.ts +45 -0
  21. package/src/services/plan-builder.service.ts +61 -0
  22. package/src/services/plan-checkpoint.service.ts +53 -0
  23. package/src/services/plan-compiler.service.ts +81 -0
  24. package/src/services/plan-executor.service.ts +1623 -0
  25. package/src/services/plan-run.service.ts +422 -0
  26. package/src/services/plan-validator.service.ts +760 -0
  27. package/src/services/workstream-turn-preparation.ts +57 -15
  28. package/src/services/workstream-turn.ts +12 -0
  29. package/src/services/workstream.service.ts +26 -0
  30. package/src/services/workstream.types.ts +1 -0
  31. package/src/system-agents/title-generator.agent.ts +2 -2
  32. package/src/tools/execution-plan.tool.ts +20 -46
  33. package/src/tools/log-hello-world.tool.ts +17 -0
  34. package/src/workers/skill-extraction.runner.ts +2 -2
@@ -7,9 +7,9 @@ import { serverLogger } from '../config/logger'
7
7
  import { ensureRecordId } from '../db/record-id'
8
8
  import { databaseService } from '../db/service'
9
9
  import { TABLES } from '../db/tables'
10
- import { createDefaultEmbeddings } from '../embeddings/provider'
10
+ import { getDefaultEmbeddings } from '../embeddings/provider'
11
11
 
12
- const embeddings = createDefaultEmbeddings()
12
+ const embeddings = getDefaultEmbeddings()
13
13
 
14
14
  const PROMOTION_MIN_USES = 5
15
15
  const PROMOTION_MIN_SUCCESS_RATE = 0.6
@@ -0,0 +1,83 @@
1
+ import { PlanApprovalSchema } from '@lota-sdk/shared/schemas/execution-plan'
2
+ import type { PlanApprovalRecord, PlanApprovalStatus } from '@lota-sdk/shared/schemas/execution-plan'
3
+ import { RecordId } from 'surrealdb'
4
+
5
+ import type { RecordIdInput } from '../db/record-id'
6
+ import { ensureRecordId } from '../db/record-id'
7
+ import { databaseService } from '../db/service'
8
+ import type { DatabaseTransaction } from '../db/service'
9
+ import { TABLES } from '../db/tables'
10
+
11
+ class PlanApprovalService {
12
+ async createPendingApproval(params: {
13
+ tx: DatabaseTransaction
14
+ runId: RecordIdInput
15
+ nodeRunId: RecordIdInput
16
+ nodeId: string
17
+ requestedBy: string
18
+ presented: Record<string, unknown>
19
+ }): Promise<PlanApprovalRecord> {
20
+ const approvalId = new RecordId(TABLES.PLAN_APPROVAL, Bun.randomUUIDv7())
21
+ const created = await params.tx
22
+ .create(approvalId)
23
+ .content({
24
+ runId: ensureRecordId(params.runId, TABLES.PLAN_RUN),
25
+ nodeRunId: ensureRecordId(params.nodeRunId, TABLES.PLAN_NODE_RUN),
26
+ nodeId: params.nodeId,
27
+ status: 'pending',
28
+ requestedBy: params.requestedBy,
29
+ presented: params.presented,
30
+ requiredEdits: [],
31
+ })
32
+ .output('after')
33
+
34
+ return PlanApprovalSchema.parse(created)
35
+ }
36
+
37
+ async getApprovalById(approvalId: RecordIdInput): Promise<PlanApprovalRecord | null> {
38
+ return await databaseService.findOne(
39
+ TABLES.PLAN_APPROVAL,
40
+ { id: ensureRecordId(approvalId, TABLES.PLAN_APPROVAL) },
41
+ PlanApprovalSchema,
42
+ )
43
+ }
44
+
45
+ async getPendingApprovalForNodeRun(nodeRunId: RecordIdInput): Promise<PlanApprovalRecord | null> {
46
+ const approvals = await databaseService.findMany(
47
+ TABLES.PLAN_APPROVAL,
48
+ { nodeRunId: ensureRecordId(nodeRunId, TABLES.PLAN_NODE_RUN), status: 'pending' },
49
+ PlanApprovalSchema,
50
+ { orderBy: 'createdAt', orderDir: 'DESC', limit: 1 },
51
+ )
52
+
53
+ return approvals.at(0) ?? null
54
+ }
55
+
56
+ async updateApprovalResponse(params: {
57
+ tx: DatabaseTransaction
58
+ approval: PlanApprovalRecord
59
+ status: PlanApprovalStatus
60
+ response: Record<string, unknown>
61
+ respondedBy: string
62
+ approvalMessageId?: string
63
+ comments?: string
64
+ requiredEdits?: string[]
65
+ }): Promise<PlanApprovalRecord> {
66
+ const updated = await params.tx
67
+ .update(ensureRecordId(params.approval.id, TABLES.PLAN_APPROVAL))
68
+ .merge({
69
+ status: params.status,
70
+ response: params.response,
71
+ respondedBy: params.respondedBy,
72
+ ...(params.approvalMessageId ? { approvalMessageId: params.approvalMessageId } : {}),
73
+ ...(params.comments ? { comments: params.comments } : {}),
74
+ ...(params.requiredEdits ? { requiredEdits: params.requiredEdits } : {}),
75
+ respondedAt: new Date(),
76
+ })
77
+ .output('after')
78
+
79
+ return PlanApprovalSchema.parse(updated)
80
+ }
81
+ }
82
+
83
+ export const planApprovalService = new PlanApprovalService()
@@ -0,0 +1,45 @@
1
+ import { PlanArtifactSchema } from '@lota-sdk/shared/schemas/execution-plan'
2
+ import type { PlanArtifactRecord } from '@lota-sdk/shared/schemas/execution-plan'
3
+ import type { PlanArtifactSubmission } from '@lota-sdk/shared/schemas/tools'
4
+ import { RecordId } from 'surrealdb'
5
+
6
+ import type { RecordIdInput } from '../db/record-id'
7
+ import { ensureRecordId } from '../db/record-id'
8
+ import type { DatabaseTransaction } from '../db/service'
9
+ import { TABLES } from '../db/tables'
10
+
11
+ class PlanArtifactService {
12
+ async persistArtifacts(params: {
13
+ tx: DatabaseTransaction
14
+ runId: RecordIdInput
15
+ attemptId: RecordIdInput
16
+ nodeId: string
17
+ artifacts: PlanArtifactSubmission[]
18
+ }): Promise<PlanArtifactRecord[]> {
19
+ const records: PlanArtifactRecord[] = []
20
+
21
+ for (const artifact of params.artifacts) {
22
+ const artifactId = new RecordId(TABLES.PLAN_ARTIFACT, Bun.randomUUIDv7())
23
+ const created = await params.tx
24
+ .create(artifactId)
25
+ .content({
26
+ runId: ensureRecordId(params.runId, TABLES.PLAN_RUN),
27
+ attemptId: ensureRecordId(params.attemptId, TABLES.PLAN_NODE_ATTEMPT),
28
+ nodeId: params.nodeId,
29
+ name: artifact.name,
30
+ kind: artifact.kind,
31
+ pointer: artifact.pointer,
32
+ ...(artifact.schemaRef ? { schemaRef: artifact.schemaRef } : {}),
33
+ ...(artifact.description ? { description: artifact.description } : {}),
34
+ ...(artifact.payload ? { payload: artifact.payload } : {}),
35
+ })
36
+ .output('after')
37
+
38
+ records.push(PlanArtifactSchema.parse(created))
39
+ }
40
+
41
+ return records
42
+ }
43
+ }
44
+
45
+ export const planArtifactService = new PlanArtifactService()
@@ -0,0 +1,61 @@
1
+ import type { PlanDraft } from '@lota-sdk/shared/schemas/execution-plan'
2
+
3
+ function buildImplicitLinearEdges(draft: PlanDraft) {
4
+ if (draft.edges.length > 0 || draft.nodes.length <= 1) {
5
+ return draft.edges
6
+ }
7
+
8
+ return draft.nodes
9
+ .slice(0, -1)
10
+ .map((node, index) => ({
11
+ id: `edge_${node.id}_to_${draft.nodes[index + 1]?.id ?? index + 1}`,
12
+ source: node.id,
13
+ target: draft.nodes[index + 1].id,
14
+ map: {},
15
+ }))
16
+ }
17
+
18
+ class PlanBuilderService {
19
+ roleAssignment(draft: PlanDraft): PlanDraft {
20
+ return draft
21
+ }
22
+
23
+ structureDesign(draft: PlanDraft): PlanDraft {
24
+ return {
25
+ ...draft,
26
+ edges: buildImplicitLinearEdges(draft),
27
+ entryNodeIds: draft.entryNodeIds && draft.entryNodeIds.length > 0 ? draft.entryNodeIds : [draft.nodes[0].id],
28
+ }
29
+ }
30
+
31
+ semanticCompletion(draft: PlanDraft): PlanDraft {
32
+ return {
33
+ ...draft,
34
+ nodes: draft.nodes.map((node) => ({
35
+ ...node,
36
+ deliverables: [...node.deliverables],
37
+ successCriteria: [...node.successCriteria],
38
+ completionChecks: [...node.completionChecks],
39
+ failurePolicy: [...node.failurePolicy],
40
+ retryPolicy: { ...node.retryPolicy, retryOn: [...node.retryPolicy.retryOn] },
41
+ toolPolicy: { allow: [...node.toolPolicy.allow], deny: [...node.toolPolicy.deny] },
42
+ contextPolicy: {
43
+ retrievalScopes: [...node.contextPolicy.retrievalScopes],
44
+ attachmentPolicy: node.contextPolicy.attachmentPolicy,
45
+ webPolicy: node.contextPolicy.webPolicy,
46
+ },
47
+ })),
48
+ edges: draft.edges.map((edge) => ({ ...edge, map: { ...edge.map } })),
49
+ schemas: structuredClone(draft.schemas),
50
+ entryNodeIds: [...(draft.entryNodeIds ?? [])],
51
+ }
52
+ }
53
+
54
+ prepareDraft(draft: PlanDraft): PlanDraft {
55
+ const withRoles = this.roleAssignment(draft)
56
+ const withStructure = this.structureDesign(withRoles)
57
+ return this.semanticCompletion(withStructure)
58
+ }
59
+ }
60
+
61
+ export const planBuilderService = new PlanBuilderService()
@@ -0,0 +1,53 @@
1
+ import { PlanCheckpointSchema } from '@lota-sdk/shared/schemas/execution-plan'
2
+ import type { PlanCheckpointRecord, PlanRunStatus } from '@lota-sdk/shared/schemas/execution-plan'
3
+ import { RecordId } from 'surrealdb'
4
+
5
+ import type { RecordIdInput } from '../db/record-id'
6
+ import { ensureRecordId } from '../db/record-id'
7
+ import { databaseService } from '../db/service'
8
+ import type { DatabaseTransaction } from '../db/service'
9
+ import { TABLES } from '../db/tables'
10
+
11
+ class PlanCheckpointService {
12
+ async createCheckpoint(params: {
13
+ tx: DatabaseTransaction
14
+ runId: RecordIdInput
15
+ sequence: number
16
+ runStatus: PlanRunStatus
17
+ readyNodeIds: string[]
18
+ activeNodeIds: string[]
19
+ artifactIds: RecordIdInput[]
20
+ lastCompletedNodeIds: string[]
21
+ snapshot: Record<string, unknown>
22
+ }): Promise<PlanCheckpointRecord> {
23
+ const checkpointId = new RecordId(TABLES.PLAN_CHECKPOINT, Bun.randomUUIDv7())
24
+ const created = await params.tx
25
+ .create(checkpointId)
26
+ .content({
27
+ runId: ensureRecordId(params.runId, TABLES.PLAN_RUN),
28
+ sequence: params.sequence,
29
+ runStatus: params.runStatus,
30
+ readyNodeIds: [...params.readyNodeIds],
31
+ activeNodeIds: [...params.activeNodeIds],
32
+ artifactIds: params.artifactIds.map((artifactId) => ensureRecordId(artifactId, TABLES.PLAN_ARTIFACT)),
33
+ lastCompletedNodeIds: [...params.lastCompletedNodeIds],
34
+ snapshot: params.snapshot,
35
+ })
36
+ .output('after')
37
+
38
+ return PlanCheckpointSchema.parse(created)
39
+ }
40
+
41
+ async loadLatestForRun(runId: RecordIdInput): Promise<PlanCheckpointRecord | null> {
42
+ const checkpoints = await databaseService.findMany(
43
+ TABLES.PLAN_CHECKPOINT,
44
+ { runId: ensureRecordId(runId, TABLES.PLAN_RUN) },
45
+ PlanCheckpointSchema,
46
+ { orderBy: 'sequence', orderDir: 'DESC', limit: 1 },
47
+ )
48
+
49
+ return checkpoints.at(0) ?? null
50
+ }
51
+ }
52
+
53
+ export const planCheckpointService = new PlanCheckpointService()
@@ -0,0 +1,81 @@
1
+ import type { PlanDraft, PlanNodeSpec, PlanNodeSpecRecord } from '@lota-sdk/shared/schemas/execution-plan'
2
+
3
+ import { planValidatorService } from './plan-validator.service'
4
+
5
+ export interface CompiledPlanNode {
6
+ node: PlanNodeSpec
7
+ position: number
8
+ upstreamNodeIds: string[]
9
+ downstreamNodeIds: string[]
10
+ }
11
+
12
+ export interface CompiledPlanDraft {
13
+ draft: PlanDraft
14
+ nodes: CompiledPlanNode[]
15
+ }
16
+
17
+ class PlanCompilerService {
18
+ compile(draft: PlanDraft): CompiledPlanDraft {
19
+ const validation = planValidatorService.validateDraft(draft)
20
+ if (validation.blocking.length > 0) {
21
+ throw new Error(
22
+ `Plan draft failed validation: ${validation.blocking.map((issue) => `${issue.code}: ${issue.message}`).join(' | ')}`,
23
+ )
24
+ }
25
+
26
+ const upstreamByNodeId = new Map<string, string[]>()
27
+ const downstreamByNodeId = new Map<string, string[]>()
28
+
29
+ for (const node of draft.nodes) {
30
+ upstreamByNodeId.set(node.id, [])
31
+ downstreamByNodeId.set(node.id, [])
32
+ }
33
+
34
+ for (const edge of draft.edges) {
35
+ upstreamByNodeId.get(edge.target)?.push(edge.source)
36
+ downstreamByNodeId.get(edge.source)?.push(edge.target)
37
+ }
38
+
39
+ return {
40
+ draft,
41
+ nodes: draft.nodes.map((node, index) => ({
42
+ node,
43
+ position: index,
44
+ upstreamNodeIds: [...(upstreamByNodeId.get(node.id) ?? [])],
45
+ downstreamNodeIds: [...(downstreamByNodeId.get(node.id) ?? [])],
46
+ })),
47
+ }
48
+ }
49
+
50
+ toNodeSpecRecords(
51
+ compiled: CompiledPlanDraft,
52
+ ): Array<Omit<PlanNodeSpecRecord, 'id' | 'planSpecId' | 'createdAt' | 'updatedAt'>> {
53
+ return compiled.nodes.map(({ node, position, upstreamNodeIds, downstreamNodeIds }) => ({
54
+ nodeId: node.id,
55
+ position,
56
+ type: node.type,
57
+ label: node.label,
58
+ owner: node.owner,
59
+ objective: node.objective,
60
+ instructions: node.instructions,
61
+ ...(node.inputSchemaRef ? { inputSchemaRef: node.inputSchemaRef } : {}),
62
+ ...(node.outputSchemaRef ? { outputSchemaRef: node.outputSchemaRef } : {}),
63
+ deliverables: [...node.deliverables],
64
+ successCriteria: [...node.successCriteria],
65
+ completionChecks: [...node.completionChecks],
66
+ retryPolicy: { ...node.retryPolicy, retryOn: [...node.retryPolicy.retryOn] },
67
+ failurePolicy: [...node.failurePolicy],
68
+ ...(node.timeoutMs ? { timeoutMs: node.timeoutMs } : {}),
69
+ toolPolicy: { allow: [...node.toolPolicy.allow], deny: [...node.toolPolicy.deny] },
70
+ contextPolicy: {
71
+ retrievalScopes: [...node.contextPolicy.retrievalScopes],
72
+ attachmentPolicy: node.contextPolicy.attachmentPolicy,
73
+ webPolicy: node.contextPolicy.webPolicy,
74
+ },
75
+ upstreamNodeIds,
76
+ downstreamNodeIds,
77
+ }))
78
+ }
79
+ }
80
+
81
+ export const planCompilerService = new PlanCompilerService()