@soleri/core 7.0.0 → 8.1.0
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/dist/agency/agency-manager.d.ts +27 -1
- package/dist/agency/agency-manager.d.ts.map +1 -1
- package/dist/agency/agency-manager.js +180 -9
- package/dist/agency/agency-manager.js.map +1 -1
- package/dist/agency/default-rules.d.ts +7 -0
- package/dist/agency/default-rules.d.ts.map +1 -0
- package/dist/agency/default-rules.js +79 -0
- package/dist/agency/default-rules.js.map +1 -0
- package/dist/agency/types.d.ts +48 -0
- package/dist/agency/types.d.ts.map +1 -1
- package/dist/brain/brain.d.ts +17 -2
- package/dist/brain/brain.d.ts.map +1 -1
- package/dist/brain/brain.js +118 -8
- package/dist/brain/brain.js.map +1 -1
- package/dist/brain/knowledge-synthesizer.d.ts +37 -0
- package/dist/brain/knowledge-synthesizer.d.ts.map +1 -0
- package/dist/brain/knowledge-synthesizer.js +159 -0
- package/dist/brain/knowledge-synthesizer.js.map +1 -0
- package/dist/brain/learning-radar.d.ts +96 -0
- package/dist/brain/learning-radar.d.ts.map +1 -0
- package/dist/brain/learning-radar.js +202 -0
- package/dist/brain/learning-radar.js.map +1 -0
- package/dist/brain/types.d.ts +15 -0
- package/dist/brain/types.d.ts.map +1 -1
- package/dist/context/context-engine.d.ts.map +1 -1
- package/dist/context/context-engine.js +82 -17
- package/dist/context/context-engine.js.map +1 -1
- package/dist/context/types.d.ts +5 -0
- package/dist/context/types.d.ts.map +1 -1
- package/dist/control/intent-router.d.ts +12 -1
- package/dist/control/intent-router.d.ts.map +1 -1
- package/dist/control/intent-router.js +68 -0
- package/dist/control/intent-router.js.map +1 -1
- package/dist/control/types.d.ts +17 -0
- package/dist/control/types.d.ts.map +1 -1
- package/dist/curator/classifier.d.ts +18 -0
- package/dist/curator/classifier.d.ts.map +1 -0
- package/dist/curator/classifier.js +59 -0
- package/dist/curator/classifier.js.map +1 -0
- package/dist/curator/quality-gate.d.ts +29 -0
- package/dist/curator/quality-gate.d.ts.map +1 -0
- package/dist/curator/quality-gate.js +86 -0
- package/dist/curator/quality-gate.js.map +1 -0
- package/dist/domain-packs/index.d.ts +0 -3
- package/dist/domain-packs/index.d.ts.map +1 -1
- package/dist/domain-packs/index.js +0 -3
- package/dist/domain-packs/index.js.map +1 -1
- package/dist/domain-packs/loader.d.ts.map +1 -1
- package/dist/domain-packs/loader.js +20 -4
- package/dist/domain-packs/loader.js.map +1 -1
- package/dist/domain-packs/pack-runtime.d.ts +5 -5
- package/dist/domain-packs/pack-runtime.d.ts.map +1 -1
- package/dist/domain-packs/pack-runtime.js +2 -2
- package/dist/domain-packs/pack-runtime.js.map +1 -1
- package/dist/domain-packs/types.d.ts +8 -2
- package/dist/domain-packs/types.d.ts.map +1 -1
- package/dist/domain-packs/types.js.map +1 -1
- package/dist/engine/bin/soleri-engine.js +13 -2
- package/dist/engine/bin/soleri-engine.js.map +1 -1
- package/dist/engine/index.d.ts +2 -0
- package/dist/engine/index.d.ts.map +1 -1
- package/dist/engine/index.js +1 -0
- package/dist/engine/index.js.map +1 -1
- package/dist/engine/module-manifest.d.ts +28 -0
- package/dist/engine/module-manifest.d.ts.map +1 -0
- package/dist/engine/module-manifest.js +85 -0
- package/dist/engine/module-manifest.js.map +1 -0
- package/dist/engine/register-engine.d.ts +19 -0
- package/dist/engine/register-engine.d.ts.map +1 -1
- package/dist/engine/register-engine.js +15 -2
- package/dist/engine/register-engine.js.map +1 -1
- package/dist/events/event-bus.d.ts +30 -0
- package/dist/events/event-bus.d.ts.map +1 -0
- package/dist/events/event-bus.js +51 -0
- package/dist/events/event-bus.js.map +1 -0
- package/dist/flows/chain-runner.d.ts +46 -0
- package/dist/flows/chain-runner.d.ts.map +1 -0
- package/dist/flows/chain-runner.js +271 -0
- package/dist/flows/chain-runner.js.map +1 -0
- package/dist/flows/chain-types.d.ts +103 -0
- package/dist/flows/chain-types.d.ts.map +1 -0
- package/dist/flows/chain-types.js +23 -0
- package/dist/flows/chain-types.js.map +1 -0
- package/dist/health/doctor-checks.d.ts +15 -0
- package/dist/health/doctor-checks.d.ts.map +1 -0
- package/dist/health/doctor-checks.js +98 -0
- package/dist/health/doctor-checks.js.map +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/intake/content-classifier.d.ts.map +1 -1
- package/dist/intake/content-classifier.js +0 -2
- package/dist/intake/content-classifier.js.map +1 -1
- package/dist/intake/text-ingester.d.ts +52 -0
- package/dist/intake/text-ingester.d.ts.map +1 -0
- package/dist/intake/text-ingester.js +181 -0
- package/dist/intake/text-ingester.js.map +1 -0
- package/dist/llm/llm-client.d.ts.map +1 -1
- package/dist/llm/llm-client.js +45 -5
- package/dist/llm/llm-client.js.map +1 -1
- package/dist/llm/oauth-discovery.d.ts +18 -0
- package/dist/llm/oauth-discovery.d.ts.map +1 -0
- package/dist/llm/oauth-discovery.js +130 -0
- package/dist/llm/oauth-discovery.js.map +1 -0
- package/dist/llm/types.d.ts +4 -2
- package/dist/llm/types.d.ts.map +1 -1
- package/dist/packs/pack-installer.d.ts +2 -1
- package/dist/packs/pack-installer.d.ts.map +1 -1
- package/dist/packs/pack-installer.js +10 -1
- package/dist/packs/pack-installer.js.map +1 -1
- package/dist/persistence/index.d.ts +0 -1
- package/dist/persistence/index.d.ts.map +1 -1
- package/dist/persistence/index.js +0 -1
- package/dist/persistence/index.js.map +1 -1
- package/dist/persistence/types.d.ts +2 -6
- package/dist/persistence/types.d.ts.map +1 -1
- package/dist/planning/evidence-collector.d.ts +41 -0
- package/dist/planning/evidence-collector.d.ts.map +1 -0
- package/dist/planning/evidence-collector.js +194 -0
- package/dist/planning/evidence-collector.js.map +1 -0
- package/dist/planning/planner.d.ts +4 -0
- package/dist/planning/planner.d.ts.map +1 -1
- package/dist/planning/planner.js +11 -0
- package/dist/planning/planner.js.map +1 -1
- package/dist/plugins/index.d.ts +4 -0
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/index.js +4 -0
- package/dist/plugins/index.js.map +1 -1
- package/dist/plugins/plugin-registry.d.ts +4 -0
- package/dist/plugins/plugin-registry.d.ts.map +1 -1
- package/dist/plugins/plugin-registry.js +4 -0
- package/dist/plugins/plugin-registry.js.map +1 -1
- package/dist/plugins/types.d.ts +32 -27
- package/dist/plugins/types.d.ts.map +1 -1
- package/dist/plugins/types.js +6 -3
- package/dist/plugins/types.js.map +1 -1
- package/dist/queue/job-queue.d.ts +92 -0
- package/dist/queue/job-queue.d.ts.map +1 -0
- package/dist/queue/job-queue.js +180 -0
- package/dist/queue/job-queue.js.map +1 -0
- package/dist/queue/pipeline-runner.d.ts +62 -0
- package/dist/queue/pipeline-runner.d.ts.map +1 -0
- package/dist/queue/pipeline-runner.js +126 -0
- package/dist/queue/pipeline-runner.js.map +1 -0
- package/dist/runtime/admin-setup-ops.d.ts +20 -0
- package/dist/runtime/admin-setup-ops.d.ts.map +1 -0
- package/dist/runtime/admin-setup-ops.js +583 -0
- package/dist/runtime/admin-setup-ops.js.map +1 -0
- package/dist/runtime/chain-ops.d.ts +9 -0
- package/dist/runtime/chain-ops.d.ts.map +1 -0
- package/dist/runtime/chain-ops.js +107 -0
- package/dist/runtime/chain-ops.js.map +1 -0
- package/dist/runtime/claude-md-helpers.d.ts +56 -0
- package/dist/runtime/claude-md-helpers.d.ts.map +1 -0
- package/dist/runtime/claude-md-helpers.js +160 -0
- package/dist/runtime/claude-md-helpers.js.map +1 -0
- package/dist/runtime/curator-extra-ops.d.ts +3 -2
- package/dist/runtime/curator-extra-ops.d.ts.map +1 -1
- package/dist/runtime/curator-extra-ops.js +81 -3
- package/dist/runtime/curator-extra-ops.js.map +1 -1
- package/dist/runtime/facades/admin-facade.d.ts.map +1 -1
- package/dist/runtime/facades/admin-facade.js +5 -2
- package/dist/runtime/facades/admin-facade.js.map +1 -1
- package/dist/runtime/facades/agency-facade.d.ts.map +1 -1
- package/dist/runtime/facades/agency-facade.js +64 -0
- package/dist/runtime/facades/agency-facade.js.map +1 -1
- package/dist/runtime/facades/brain-facade.d.ts.map +1 -1
- package/dist/runtime/facades/brain-facade.js +122 -1
- package/dist/runtime/facades/brain-facade.js.map +1 -1
- package/dist/runtime/facades/control-facade.d.ts.map +1 -1
- package/dist/runtime/facades/control-facade.js +42 -0
- package/dist/runtime/facades/control-facade.js.map +1 -1
- package/dist/runtime/facades/memory-facade.d.ts.map +1 -1
- package/dist/runtime/facades/memory-facade.js +20 -2
- package/dist/runtime/facades/memory-facade.js.map +1 -1
- package/dist/runtime/facades/plan-facade.d.ts.map +1 -1
- package/dist/runtime/facades/plan-facade.js +2 -0
- package/dist/runtime/facades/plan-facade.js.map +1 -1
- package/dist/runtime/facades/vault-facade.d.ts.map +1 -1
- package/dist/runtime/facades/vault-facade.js +25 -5
- package/dist/runtime/facades/vault-facade.js.map +1 -1
- package/dist/runtime/intake-ops.d.ts +7 -5
- package/dist/runtime/intake-ops.d.ts.map +1 -1
- package/dist/runtime/intake-ops.js +98 -5
- package/dist/runtime/intake-ops.js.map +1 -1
- package/dist/runtime/memory-extra-ops.d.ts +6 -3
- package/dist/runtime/memory-extra-ops.d.ts.map +1 -1
- package/dist/runtime/memory-extra-ops.js +292 -4
- package/dist/runtime/memory-extra-ops.js.map +1 -1
- package/dist/runtime/pack-ops.d.ts +3 -0
- package/dist/runtime/pack-ops.d.ts.map +1 -1
- package/dist/runtime/pack-ops.js +18 -1
- package/dist/runtime/pack-ops.js.map +1 -1
- package/dist/runtime/planning-extra-ops.d.ts.map +1 -1
- package/dist/runtime/planning-extra-ops.js +85 -0
- package/dist/runtime/planning-extra-ops.js.map +1 -1
- package/dist/runtime/playbook-ops.js +1 -1
- package/dist/runtime/playbook-ops.js.map +1 -1
- package/dist/runtime/plugin-ops.d.ts.map +1 -1
- package/dist/runtime/plugin-ops.js +3 -0
- package/dist/runtime/plugin-ops.js.map +1 -1
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +143 -2
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime/session-briefing.d.ts +23 -0
- package/dist/runtime/session-briefing.d.ts.map +1 -0
- package/dist/runtime/session-briefing.js +154 -0
- package/dist/runtime/session-briefing.js.map +1 -0
- package/dist/runtime/types.d.ts +23 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/vault-linking-ops.d.ts.map +1 -1
- package/dist/runtime/vault-linking-ops.js +3 -7
- package/dist/runtime/vault-linking-ops.js.map +1 -1
- package/dist/vault/vault.d.ts +34 -0
- package/dist/vault/vault.d.ts.map +1 -1
- package/dist/vault/vault.js +89 -3
- package/dist/vault/vault.js.map +1 -1
- package/package.json +6 -4
- package/src/__tests__/admin-setup-ops.test.ts +355 -0
- package/src/__tests__/async-infrastructure.test.ts +307 -0
- package/src/__tests__/cognee-client-gaps.test.ts +6 -2
- package/src/__tests__/cognee-hybrid-search.test.ts +49 -35
- package/src/__tests__/cognee-sync-manager-deep.test.ts +89 -65
- package/src/__tests__/curator-extra-ops.test.ts +6 -2
- package/src/__tests__/curator-pipeline-e2e.test.ts +545 -0
- package/src/__tests__/memory-extra-ops.test.ts +2 -2
- package/src/__tests__/module-manifest-drift.test.ts +59 -0
- package/src/__tests__/planning-extra-ops.test.ts +2 -2
- package/src/__tests__/second-brain-features.test.ts +583 -0
- package/src/agency/agency-manager.ts +217 -9
- package/src/agency/default-rules.ts +83 -0
- package/src/agency/types.ts +61 -0
- package/src/brain/brain.ts +110 -8
- package/src/brain/knowledge-synthesizer.ts +216 -0
- package/src/brain/learning-radar.ts +340 -0
- package/src/brain/types.ts +16 -0
- package/src/context/context-engine.ts +114 -15
- package/src/context/types.ts +5 -0
- package/src/control/intent-router.ts +107 -0
- package/src/control/types.ts +10 -0
- package/src/curator/classifier.ts +86 -0
- package/src/curator/quality-gate.ts +127 -0
- package/src/domain-packs/index.ts +0 -6
- package/src/domain-packs/loader.ts +25 -5
- package/src/domain-packs/pack-runtime.ts +6 -6
- package/src/domain-packs/types.ts +8 -2
- package/src/engine/bin/soleri-engine.ts +18 -2
- package/src/engine/index.ts +2 -0
- package/src/engine/module-manifest.ts +99 -0
- package/src/engine/register-engine.ts +21 -2
- package/src/events/event-bus.ts +58 -0
- package/src/flows/chain-runner.ts +369 -0
- package/src/flows/chain-types.ts +57 -0
- package/src/index.ts +0 -1
- package/src/intake/content-classifier.ts +0 -2
- package/src/intake/text-ingester.ts +234 -0
- package/src/llm/llm-client.ts +50 -7
- package/src/llm/oauth-discovery.ts +151 -0
- package/src/llm/types.ts +4 -2
- package/src/packs/pack-installer.ts +16 -1
- package/src/persistence/index.ts +0 -1
- package/src/persistence/types.ts +2 -6
- package/src/planning/evidence-collector.ts +247 -0
- package/src/planning/planner.ts +11 -0
- package/src/plugins/index.ts +4 -0
- package/src/plugins/plugin-registry.ts +6 -1
- package/src/plugins/types.ts +10 -5
- package/src/queue/job-queue.ts +281 -0
- package/src/queue/pipeline-runner.ts +149 -0
- package/src/runtime/admin-setup-ops.ts +664 -0
- package/src/runtime/chain-ops.ts +121 -0
- package/src/runtime/claude-md-helpers.ts +218 -0
- package/src/runtime/curator-extra-ops.ts +86 -3
- package/src/runtime/facades/admin-facade.ts +5 -2
- package/src/runtime/facades/agency-facade.ts +68 -0
- package/src/runtime/facades/brain-facade.ts +142 -1
- package/src/runtime/facades/control-facade.ts +45 -0
- package/src/runtime/facades/memory-facade.ts +20 -2
- package/src/runtime/facades/plan-facade.ts +2 -0
- package/src/runtime/facades/vault-facade.ts +28 -5
- package/src/runtime/intake-ops.ts +107 -5
- package/src/runtime/memory-extra-ops.ts +312 -4
- package/src/runtime/pack-ops.ts +26 -1
- package/src/runtime/planning-extra-ops.ts +94 -0
- package/src/runtime/playbook-ops.ts +1 -1
- package/src/runtime/plugin-ops.ts +3 -0
- package/src/runtime/runtime.ts +138 -2
- package/src/runtime/session-briefing.ts +175 -0
- package/src/runtime/types.ts +23 -0
- package/src/runtime/vault-linking-ops.ts +3 -7
- package/src/vault/vault.ts +105 -4
- package/src/__tests__/postgres-provider.test.ts +0 -116
- package/src/persistence/postgres-provider.ts +0 -310
|
@@ -75,6 +75,7 @@ async function main(): Promise<void> {
|
|
|
75
75
|
const runtime = createAgentRuntime({
|
|
76
76
|
agentId,
|
|
77
77
|
vaultPath,
|
|
78
|
+
agentDir,
|
|
78
79
|
cognee: (engineConfig.cognee as boolean) ?? false,
|
|
79
80
|
});
|
|
80
81
|
|
|
@@ -116,6 +117,14 @@ async function main(): Promise<void> {
|
|
|
116
117
|
// 6. Seed default playbooks
|
|
117
118
|
seedDefaultPlaybooks(runtime.vault);
|
|
118
119
|
|
|
120
|
+
// Log vault stats for first-run visibility
|
|
121
|
+
const vaultStats = runtime.vault.stats();
|
|
122
|
+
console.error(
|
|
123
|
+
`${tag} Vault: ${vaultStats.totalEntries} entries (${Object.entries(vaultStats.byType ?? {})
|
|
124
|
+
.map(([t, n]) => `${n} ${t}`)
|
|
125
|
+
.join(', ')})`,
|
|
126
|
+
);
|
|
127
|
+
|
|
119
128
|
// 7. Load domain packs
|
|
120
129
|
const packs = (config.packs ?? []) as Array<{ name: string; package: string; version?: string }>;
|
|
121
130
|
const loadedPacks: Array<{ name: string; facades?: Array<{ name: string; ops: unknown[] }> }> =
|
|
@@ -128,9 +137,12 @@ async function main(): Promise<void> {
|
|
|
128
137
|
const manifests = await loadDomainPacksFromConfig(refs);
|
|
129
138
|
|
|
130
139
|
// Packs activate sequentially — order may matter for dependencies
|
|
140
|
+
const { createPackRuntime } = await import('../../domain-packs/pack-runtime.js');
|
|
141
|
+
const narrowedRuntime = createPackRuntime(runtime);
|
|
142
|
+
|
|
131
143
|
for (const manifest of manifests) {
|
|
132
144
|
if (manifest.onActivate) {
|
|
133
|
-
await manifest.onActivate(runtime); // eslint-disable-line no-await-in-loop
|
|
145
|
+
await manifest.onActivate(narrowedRuntime, runtime); // eslint-disable-line no-await-in-loop
|
|
134
146
|
}
|
|
135
147
|
loadedPacks.push(manifest);
|
|
136
148
|
console.error(`${tag} Domain pack: ${manifest.name}`);
|
|
@@ -177,7 +189,7 @@ async function main(): Promise<void> {
|
|
|
177
189
|
}));
|
|
178
190
|
|
|
179
191
|
// 12. Register all engine tools
|
|
180
|
-
const { tools, totalOps } = registerEngine(server, runtime, {
|
|
192
|
+
const { tools, totalOps, registerTool } = registerEngine(server, runtime, {
|
|
181
193
|
agentId,
|
|
182
194
|
coreOps,
|
|
183
195
|
domains: identity.domains,
|
|
@@ -194,6 +206,10 @@ async function main(): Promise<void> {
|
|
|
194
206
|
|
|
195
207
|
console.error(`${tag} Registered ${tools.length} tools (${totalOps} ops)`);
|
|
196
208
|
|
|
209
|
+
// Enable hot reload for post-boot pack/plugin installation
|
|
210
|
+
const { setHotRegister } = await import('../../runtime/pack-ops.js');
|
|
211
|
+
setHotRegister(registerTool);
|
|
212
|
+
|
|
197
213
|
// 13. Connect stdio transport
|
|
198
214
|
const transport = new StdioServerTransport();
|
|
199
215
|
await server.connect(transport);
|
package/src/engine/index.ts
CHANGED
|
@@ -17,3 +17,5 @@ export { registerEngine } from './register-engine.js';
|
|
|
17
17
|
export type { EngineRegistrationOptions, EngineRegistrationResult } from './register-engine.js';
|
|
18
18
|
export { createCoreOps } from './core-ops.js';
|
|
19
19
|
export type { AgentIdentityConfig } from './core-ops.js';
|
|
20
|
+
export { ENGINE_MODULE_MANIFEST, CORE_KEY_OPS } from './module-manifest.js';
|
|
21
|
+
export type { ModuleManifestEntry } from './module-manifest.js';
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Soleri Engine Module Manifest
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for engine module names, descriptions, and key ops.
|
|
5
|
+
* Used by register-engine.ts at runtime and by @soleri/forge for template generation.
|
|
6
|
+
*
|
|
7
|
+
* This file is intentionally dependency-free so it can be imported by any package.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export interface ModuleManifestEntry {
|
|
11
|
+
/** Suffix for tool name: {agentId}_{suffix} */
|
|
12
|
+
suffix: string;
|
|
13
|
+
/** Human-readable description */
|
|
14
|
+
description: string;
|
|
15
|
+
/** Representative ops shown in placeholder tables (max 4) */
|
|
16
|
+
keyOps: string[];
|
|
17
|
+
/** If true, module requires a runtime condition to register */
|
|
18
|
+
conditional?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Canonical list of engine modules.
|
|
23
|
+
* Order here determines order in generated tool tables.
|
|
24
|
+
*/
|
|
25
|
+
export const ENGINE_MODULE_MANIFEST: ModuleManifestEntry[] = [
|
|
26
|
+
{
|
|
27
|
+
suffix: 'vault',
|
|
28
|
+
description: 'Knowledge management — search, CRUD, import/export, intake, archival.',
|
|
29
|
+
keyOps: ['search_intelligent', 'capture_knowledge', 'capture_quick'],
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
suffix: 'plan',
|
|
33
|
+
description: 'Plan lifecycle — create, approve, execute, reconcile, complete, grading.',
|
|
34
|
+
keyOps: ['create_plan', 'approve_plan', 'plan_split', 'plan_reconcile'],
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
suffix: 'brain',
|
|
38
|
+
description: 'Learning system — intelligence pipeline, strengths, feedback, sessions.',
|
|
39
|
+
keyOps: ['recommend', 'strengths', 'feedback'],
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
suffix: 'memory',
|
|
43
|
+
description: 'Session & cross-project memory — capture, search, dedup, promote.',
|
|
44
|
+
keyOps: ['memory_search', 'memory_capture', 'session_capture'],
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
suffix: 'admin',
|
|
48
|
+
description: 'Infrastructure — health, config, telemetry, tokens, LLM, prompts.',
|
|
49
|
+
keyOps: ['admin_health', 'admin_tool_list', 'admin_diagnostic'],
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
suffix: 'curator',
|
|
53
|
+
description: 'Quality — duplicate detection, contradictions, grooming, health audit.',
|
|
54
|
+
keyOps: ['curator_groom', 'curator_status', 'curator_health'],
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
suffix: 'loop',
|
|
58
|
+
description: 'Iterative validation loops — start, iterate, cancel, complete, history.',
|
|
59
|
+
keyOps: ['loop_start', 'loop_status', 'loop_cancel'],
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
suffix: 'orchestrate',
|
|
63
|
+
description:
|
|
64
|
+
'Execution orchestration — project registration, playbooks, plan/execute/complete.',
|
|
65
|
+
keyOps: ['orchestrate_plan', 'orchestrate_execute', 'orchestrate_complete'],
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
suffix: 'control',
|
|
69
|
+
description: 'Agent behavior — identity, intent routing, morphing, guidelines, governance.',
|
|
70
|
+
keyOps: ['route_intent', 'morph', 'get_behavior_rules'],
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
suffix: 'context',
|
|
74
|
+
description: 'Context analysis — entity extraction, knowledge retrieval, confidence scoring.',
|
|
75
|
+
keyOps: ['context_extract_entities', 'context_retrieve_knowledge', 'context_analyze'],
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
suffix: 'agency',
|
|
79
|
+
description: 'Proactive intelligence — file watching, pattern surfacing, warnings.',
|
|
80
|
+
keyOps: ['agency_scan_file', 'agency_surface_patterns', 'agency_warnings'],
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
suffix: 'chat',
|
|
84
|
+
description: 'Chat transport — session management, response chunking, authentication.',
|
|
85
|
+
keyOps: ['chat_send', 'chat_history', 'chat_session'],
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
suffix: 'cognee',
|
|
89
|
+
description: 'Knowledge graph — Cognee search, sync, export, graph stats.',
|
|
90
|
+
keyOps: ['cognee_search', 'cognee_add', 'cognee_cognify'],
|
|
91
|
+
conditional: true,
|
|
92
|
+
},
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
/** Core facade ops (always present, not in ENGINE_MODULES) */
|
|
96
|
+
export const CORE_KEY_OPS = ['health', 'identity', 'register', 'activate'];
|
|
97
|
+
|
|
98
|
+
/** Engine major version — used for compatibility checks against domain packs. */
|
|
99
|
+
export const ENGINE_MAJOR_VERSION = 8;
|
|
@@ -60,6 +60,12 @@ export interface EngineRegistrationResult {
|
|
|
60
60
|
tools: string[];
|
|
61
61
|
/** Total op count across all tools */
|
|
62
62
|
totalOps: number;
|
|
63
|
+
/**
|
|
64
|
+
* Register a new MCP tool at runtime (hot reload).
|
|
65
|
+
* Call this after installing a pack or activating a plugin post-boot.
|
|
66
|
+
* Automatically notifies connected clients via sendToolListChanged().
|
|
67
|
+
*/
|
|
68
|
+
registerTool: (toolName: string, description: string, ops: OpDefinition[]) => void;
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
// ─── Module Definition ────────────────────────────────────────────────
|
|
@@ -75,7 +81,8 @@ interface ModuleDef {
|
|
|
75
81
|
condition?: (runtime: AgentRuntime) => boolean;
|
|
76
82
|
}
|
|
77
83
|
|
|
78
|
-
|
|
84
|
+
/** @internal Exported for drift testing — do not use outside engine */
|
|
85
|
+
export const ENGINE_MODULES: ModuleDef[] = [
|
|
79
86
|
{
|
|
80
87
|
suffix: 'vault',
|
|
81
88
|
description: 'Knowledge management — search, CRUD, import/export, intake, archival.',
|
|
@@ -233,7 +240,19 @@ export function registerEngine(
|
|
|
233
240
|
}
|
|
234
241
|
}
|
|
235
242
|
|
|
236
|
-
|
|
243
|
+
const registerTool = (toolName: string, description: string, ops: OpDefinition[]) => {
|
|
244
|
+
registerModuleTool(server, toolName, description, ops, authPolicy);
|
|
245
|
+
registeredTools.push(toolName);
|
|
246
|
+
totalOps += ops.length;
|
|
247
|
+
// Notify connected clients that tool list changed
|
|
248
|
+
try {
|
|
249
|
+
(server as unknown as { sendToolListChanged?: () => void }).sendToolListChanged?.();
|
|
250
|
+
} catch {
|
|
251
|
+
// Server may not support notifications yet — safe to ignore
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
return { tools: registeredTools, totalOps, registerTool };
|
|
237
256
|
}
|
|
238
257
|
|
|
239
258
|
// ─── Tool Registration (No Factory) ──────────────────────────────────
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed Event Bus — generic event emitter for decoupled subsystem communication.
|
|
3
|
+
*
|
|
4
|
+
* Wraps Node EventEmitter with type-safe emit/subscribe.
|
|
5
|
+
* Any module can define its own event map and create a bus.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { EventEmitter } from 'node:events';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Create a typed event bus.
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* ```ts
|
|
15
|
+
* type MyEvents = {
|
|
16
|
+
* 'entry:created': { id: string; title: string };
|
|
17
|
+
* 'entry:deleted': { id: string };
|
|
18
|
+
* };
|
|
19
|
+
* const bus = new TypedEventBus<MyEvents>();
|
|
20
|
+
* bus.on('entry:created', (payload) => console.log(payload.title));
|
|
21
|
+
* bus.emit('entry:created', { id: '1', title: 'Hello' });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export class TypedEventBus<TEvents extends Record<string, unknown>> {
|
|
25
|
+
private emitter = new EventEmitter();
|
|
26
|
+
|
|
27
|
+
on<E extends keyof TEvents & string>(event: E, listener: (payload: TEvents[E]) => void): this {
|
|
28
|
+
this.emitter.on(event, listener as (...args: unknown[]) => void);
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
once<E extends keyof TEvents & string>(event: E, listener: (payload: TEvents[E]) => void): this {
|
|
33
|
+
this.emitter.once(event, listener as (...args: unknown[]) => void);
|
|
34
|
+
return this;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
off<E extends keyof TEvents & string>(event: E, listener: (payload: TEvents[E]) => void): this {
|
|
38
|
+
this.emitter.off(event, listener as (...args: unknown[]) => void);
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
emit<E extends keyof TEvents & string>(event: E, payload: TEvents[E]): boolean {
|
|
43
|
+
return this.emitter.emit(event, payload);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
listenerCount(): number {
|
|
47
|
+
let total = 0;
|
|
48
|
+
for (const name of this.emitter.eventNames()) {
|
|
49
|
+
total += this.emitter.listenerCount(name);
|
|
50
|
+
}
|
|
51
|
+
return total;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
removeAllListeners(): this {
|
|
55
|
+
this.emitter.removeAllListeners();
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chain Runner — executes multi-step workflows with data flow between steps.
|
|
3
|
+
*
|
|
4
|
+
* Steps call facade ops via a dispatch function. Each step's output is stored
|
|
5
|
+
* in a context object and can be referenced by subsequent steps via $variable syntax.
|
|
6
|
+
*
|
|
7
|
+
* Gates pause execution. Resume via approve(). State persists to SQLite.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { randomUUID } from 'node:crypto';
|
|
11
|
+
import type { PersistenceProvider } from '../persistence/types.js';
|
|
12
|
+
import type { ChainDef, ChainInstance, StepOutput } from './chain-types.js';
|
|
13
|
+
|
|
14
|
+
// ─── Types ───────────────────────────────────────────────────────────
|
|
15
|
+
|
|
16
|
+
export type DispatchFn = (op: string, params: Record<string, unknown>) => Promise<unknown>;
|
|
17
|
+
|
|
18
|
+
type GateCheckFn = (
|
|
19
|
+
gate: string,
|
|
20
|
+
stepId: string,
|
|
21
|
+
stepResult: unknown,
|
|
22
|
+
) => Promise<{ passed: boolean; message?: string }>;
|
|
23
|
+
|
|
24
|
+
// ─── Class ───────────────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
export class ChainRunner {
|
|
27
|
+
private provider: PersistenceProvider;
|
|
28
|
+
|
|
29
|
+
constructor(provider: PersistenceProvider) {
|
|
30
|
+
this.provider = provider;
|
|
31
|
+
this.initializeTable();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private initializeTable(): void {
|
|
35
|
+
this.provider.execSql(`
|
|
36
|
+
CREATE TABLE IF NOT EXISTS chain_instances (
|
|
37
|
+
id TEXT PRIMARY KEY,
|
|
38
|
+
chain_id TEXT NOT NULL,
|
|
39
|
+
chain_name TEXT NOT NULL DEFAULT '',
|
|
40
|
+
status TEXT NOT NULL DEFAULT 'running',
|
|
41
|
+
current_step TEXT,
|
|
42
|
+
paused_at_gate TEXT,
|
|
43
|
+
input TEXT NOT NULL DEFAULT '{}',
|
|
44
|
+
context TEXT NOT NULL DEFAULT '{}',
|
|
45
|
+
step_outputs TEXT NOT NULL DEFAULT '[]',
|
|
46
|
+
steps_completed INTEGER NOT NULL DEFAULT 0,
|
|
47
|
+
total_steps INTEGER NOT NULL DEFAULT 0,
|
|
48
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
49
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
50
|
+
);
|
|
51
|
+
`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Execute a chain from the beginning (or a specific step).
|
|
56
|
+
*/
|
|
57
|
+
async execute(
|
|
58
|
+
chainDef: ChainDef,
|
|
59
|
+
input: Record<string, unknown>,
|
|
60
|
+
dispatch: DispatchFn,
|
|
61
|
+
gateCheck?: GateCheckFn,
|
|
62
|
+
startFromStep?: string,
|
|
63
|
+
): Promise<ChainInstance> {
|
|
64
|
+
const instanceId = randomUUID().slice(0, 12);
|
|
65
|
+
const instance: ChainInstance = {
|
|
66
|
+
id: instanceId,
|
|
67
|
+
chainId: chainDef.id,
|
|
68
|
+
chainName: chainDef.name ?? chainDef.id,
|
|
69
|
+
status: 'running',
|
|
70
|
+
currentStep: null,
|
|
71
|
+
pausedAtGate: null,
|
|
72
|
+
input,
|
|
73
|
+
context: { input },
|
|
74
|
+
stepOutputs: [],
|
|
75
|
+
stepsCompleted: 0,
|
|
76
|
+
totalSteps: chainDef.steps.length,
|
|
77
|
+
createdAt: new Date().toISOString(),
|
|
78
|
+
updatedAt: new Date().toISOString(),
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
this.persist(instance);
|
|
82
|
+
|
|
83
|
+
// Find start index
|
|
84
|
+
let startIdx = 0;
|
|
85
|
+
if (startFromStep) {
|
|
86
|
+
const idx = chainDef.steps.findIndex((s) => s.id === startFromStep);
|
|
87
|
+
if (idx >= 0) startIdx = idx;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return this.runSteps(chainDef, instance, dispatch, gateCheck, startIdx);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Resume a paused chain from where it left off.
|
|
95
|
+
*/
|
|
96
|
+
async resume(
|
|
97
|
+
instanceId: string,
|
|
98
|
+
chainDef: ChainDef,
|
|
99
|
+
dispatch: DispatchFn,
|
|
100
|
+
gateCheck?: GateCheckFn,
|
|
101
|
+
): Promise<ChainInstance> {
|
|
102
|
+
const instance = this.getInstance(instanceId);
|
|
103
|
+
if (!instance) throw new Error(`Chain instance not found: ${instanceId}`);
|
|
104
|
+
if (instance.status !== 'paused') throw new Error(`Chain is ${instance.status}, not paused`);
|
|
105
|
+
|
|
106
|
+
// Find the step after the paused gate
|
|
107
|
+
const pausedStep = instance.pausedAtGate;
|
|
108
|
+
if (!pausedStep) throw new Error('No paused gate to resume from');
|
|
109
|
+
|
|
110
|
+
const stepIdx = chainDef.steps.findIndex((s) => s.id === pausedStep);
|
|
111
|
+
if (stepIdx < 0) throw new Error(`Paused step ${pausedStep} not found in chain def`);
|
|
112
|
+
|
|
113
|
+
// Mark step as approved, move to next
|
|
114
|
+
instance.status = 'running';
|
|
115
|
+
instance.pausedAtGate = null;
|
|
116
|
+
this.persist(instance);
|
|
117
|
+
|
|
118
|
+
return this.runSteps(chainDef, instance, dispatch, gateCheck, stepIdx + 1);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Approve a gate-paused step and resume the chain.
|
|
123
|
+
*/
|
|
124
|
+
async approve(
|
|
125
|
+
instanceId: string,
|
|
126
|
+
chainDef: ChainDef,
|
|
127
|
+
dispatch: DispatchFn,
|
|
128
|
+
gateCheck?: GateCheckFn,
|
|
129
|
+
): Promise<ChainInstance> {
|
|
130
|
+
return this.resume(instanceId, chainDef, dispatch, gateCheck);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Get chain instance status.
|
|
135
|
+
*/
|
|
136
|
+
getInstance(instanceId: string): ChainInstance | null {
|
|
137
|
+
const row = this.provider.get<InstanceRow>('SELECT * FROM chain_instances WHERE id = ?', [
|
|
138
|
+
instanceId,
|
|
139
|
+
]);
|
|
140
|
+
return row ? rowToInstance(row) : null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* List all chain instances.
|
|
145
|
+
*/
|
|
146
|
+
list(limit: number = 20): ChainInstance[] {
|
|
147
|
+
const rows = this.provider.all<InstanceRow>(
|
|
148
|
+
'SELECT * FROM chain_instances ORDER BY updated_at DESC LIMIT ?',
|
|
149
|
+
[limit],
|
|
150
|
+
);
|
|
151
|
+
return rows.map(rowToInstance);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ─── Core Execution Loop ──────────────────────────────────────────
|
|
155
|
+
|
|
156
|
+
private async runSteps(
|
|
157
|
+
chainDef: ChainDef,
|
|
158
|
+
instance: ChainInstance,
|
|
159
|
+
dispatch: DispatchFn,
|
|
160
|
+
gateCheck: GateCheckFn | undefined,
|
|
161
|
+
startIdx: number,
|
|
162
|
+
): Promise<ChainInstance> {
|
|
163
|
+
// Steps MUST run sequentially — step N output feeds step N+1 input.
|
|
164
|
+
// Using recursive approach to satisfy no-await-in-loop lint rule.
|
|
165
|
+
return this.runStep(chainDef, instance, dispatch, gateCheck, startIdx);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
private async runStep(
|
|
169
|
+
chainDef: ChainDef,
|
|
170
|
+
instance: ChainInstance,
|
|
171
|
+
dispatch: DispatchFn,
|
|
172
|
+
gateCheck: GateCheckFn | undefined,
|
|
173
|
+
idx: number,
|
|
174
|
+
): Promise<ChainInstance> {
|
|
175
|
+
if (idx >= chainDef.steps.length) {
|
|
176
|
+
instance.status = 'completed';
|
|
177
|
+
instance.currentStep = null;
|
|
178
|
+
this.persist(instance);
|
|
179
|
+
return instance;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const step = chainDef.steps[idx];
|
|
183
|
+
instance.currentStep = step.id;
|
|
184
|
+
this.persist(instance);
|
|
185
|
+
|
|
186
|
+
const resolvedParams = resolveParams(step.params ?? {}, instance.context);
|
|
187
|
+
|
|
188
|
+
const stepStart = Date.now();
|
|
189
|
+
let result: unknown;
|
|
190
|
+
let stepStatus: StepOutput['status'] = 'completed';
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
result = await dispatch(step.op, resolvedParams);
|
|
194
|
+
} catch (err) {
|
|
195
|
+
result = { error: (err as Error).message };
|
|
196
|
+
stepStatus = 'failed';
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const output: StepOutput = {
|
|
200
|
+
stepId: step.id,
|
|
201
|
+
op: step.op,
|
|
202
|
+
result,
|
|
203
|
+
status: stepStatus,
|
|
204
|
+
durationMs: Date.now() - stepStart,
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
instance.stepOutputs.push(output);
|
|
208
|
+
instance.context[step.id] = result;
|
|
209
|
+
if (step.output) instance.context[step.output] = result;
|
|
210
|
+
if (stepStatus === 'completed') instance.stepsCompleted++;
|
|
211
|
+
|
|
212
|
+
// Check gate
|
|
213
|
+
if (step.gate && step.gate !== 'none' && stepStatus === 'completed') {
|
|
214
|
+
const gateResult = await this.evaluateChainGate(step.gate, step.id, result, gateCheck);
|
|
215
|
+
if (!gateResult.passed) {
|
|
216
|
+
if (step.gate === 'user-approval') {
|
|
217
|
+
instance.status = 'paused';
|
|
218
|
+
instance.pausedAtGate = step.id;
|
|
219
|
+
this.persist(instance);
|
|
220
|
+
return instance;
|
|
221
|
+
}
|
|
222
|
+
instance.status = 'failed';
|
|
223
|
+
this.persist(instance);
|
|
224
|
+
return instance;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (stepStatus === 'failed') {
|
|
229
|
+
instance.status = 'failed';
|
|
230
|
+
this.persist(instance);
|
|
231
|
+
return instance;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
this.persist(instance);
|
|
235
|
+
return this.runStep(chainDef, instance, dispatch, gateCheck, idx + 1);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
private async evaluateChainGate(
|
|
239
|
+
gate: string,
|
|
240
|
+
stepId: string,
|
|
241
|
+
stepResult: unknown,
|
|
242
|
+
gateCheck?: GateCheckFn,
|
|
243
|
+
): Promise<{ passed: boolean; message?: string }> {
|
|
244
|
+
switch (gate) {
|
|
245
|
+
case 'user-approval':
|
|
246
|
+
return { passed: false, message: 'Awaiting user approval' };
|
|
247
|
+
|
|
248
|
+
case 'auto-test': {
|
|
249
|
+
const result = stepResult as Record<string, unknown> | null;
|
|
250
|
+
if (!result) return { passed: false, message: 'Step returned no result' };
|
|
251
|
+
if (result.error) return { passed: false, message: `Step error: ${result.error}` };
|
|
252
|
+
return { passed: true };
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
case 'vault-check': {
|
|
256
|
+
if (gateCheck) return gateCheck(gate, stepId, stepResult);
|
|
257
|
+
return { passed: true };
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
default:
|
|
261
|
+
return { passed: true };
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// ─── Persistence ──────────────────────────────────────────────────
|
|
266
|
+
|
|
267
|
+
private persist(instance: ChainInstance): void {
|
|
268
|
+
instance.updatedAt = new Date().toISOString();
|
|
269
|
+
this.provider.run(
|
|
270
|
+
`INSERT OR REPLACE INTO chain_instances
|
|
271
|
+
(id, chain_id, chain_name, status, current_step, paused_at_gate, input, context, step_outputs, steps_completed, total_steps, created_at, updated_at)
|
|
272
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
273
|
+
[
|
|
274
|
+
instance.id,
|
|
275
|
+
instance.chainId,
|
|
276
|
+
instance.chainName,
|
|
277
|
+
instance.status,
|
|
278
|
+
instance.currentStep,
|
|
279
|
+
instance.pausedAtGate,
|
|
280
|
+
JSON.stringify(instance.input),
|
|
281
|
+
JSON.stringify(instance.context),
|
|
282
|
+
JSON.stringify(instance.stepOutputs),
|
|
283
|
+
instance.stepsCompleted,
|
|
284
|
+
instance.totalSteps,
|
|
285
|
+
instance.createdAt,
|
|
286
|
+
instance.updatedAt,
|
|
287
|
+
],
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// ─── Variable Resolution ─────────────────────────────────────────────
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Resolve $variable references in params.
|
|
296
|
+
* $input.url → context.input.url
|
|
297
|
+
* $research.title → context.research.title
|
|
298
|
+
* $stepId → context.stepId (whole object)
|
|
299
|
+
*/
|
|
300
|
+
function resolveParams(
|
|
301
|
+
params: Record<string, unknown>,
|
|
302
|
+
context: Record<string, unknown>,
|
|
303
|
+
): Record<string, unknown> {
|
|
304
|
+
const resolved: Record<string, unknown> = {};
|
|
305
|
+
for (const [key, value] of Object.entries(params)) {
|
|
306
|
+
resolved[key] = resolveValue(value, context);
|
|
307
|
+
}
|
|
308
|
+
return resolved;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function resolveValue(value: unknown, context: Record<string, unknown>): unknown {
|
|
312
|
+
if (typeof value === 'string' && value.startsWith('$')) {
|
|
313
|
+
return resolveReference(value.slice(1), context);
|
|
314
|
+
}
|
|
315
|
+
if (Array.isArray(value)) {
|
|
316
|
+
return value.map((v) => resolveValue(v, context));
|
|
317
|
+
}
|
|
318
|
+
if (value !== null && typeof value === 'object') {
|
|
319
|
+
return resolveParams(value as Record<string, unknown>, context);
|
|
320
|
+
}
|
|
321
|
+
return value;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function resolveReference(path: string, context: Record<string, unknown>): unknown {
|
|
325
|
+
const parts = path.split('.');
|
|
326
|
+
let current: unknown = context;
|
|
327
|
+
for (const part of parts) {
|
|
328
|
+
if (current === null || current === undefined) return undefined;
|
|
329
|
+
if (typeof current !== 'object') return undefined;
|
|
330
|
+
current = (current as Record<string, unknown>)[part];
|
|
331
|
+
}
|
|
332
|
+
return current;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// ─── Row Types ───────────────────────────────────────────────────────
|
|
336
|
+
|
|
337
|
+
interface InstanceRow {
|
|
338
|
+
id: string;
|
|
339
|
+
chain_id: string;
|
|
340
|
+
chain_name: string;
|
|
341
|
+
status: string;
|
|
342
|
+
current_step: string | null;
|
|
343
|
+
paused_at_gate: string | null;
|
|
344
|
+
input: string;
|
|
345
|
+
context: string;
|
|
346
|
+
step_outputs: string;
|
|
347
|
+
steps_completed: number;
|
|
348
|
+
total_steps: number;
|
|
349
|
+
created_at: string;
|
|
350
|
+
updated_at: string;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function rowToInstance(row: InstanceRow): ChainInstance {
|
|
354
|
+
return {
|
|
355
|
+
id: row.id,
|
|
356
|
+
chainId: row.chain_id,
|
|
357
|
+
chainName: row.chain_name,
|
|
358
|
+
status: row.status as ChainInstance['status'],
|
|
359
|
+
currentStep: row.current_step,
|
|
360
|
+
pausedAtGate: row.paused_at_gate,
|
|
361
|
+
input: JSON.parse(row.input) as Record<string, unknown>,
|
|
362
|
+
context: JSON.parse(row.context) as Record<string, unknown>,
|
|
363
|
+
stepOutputs: JSON.parse(row.step_outputs) as StepOutput[],
|
|
364
|
+
stepsCompleted: row.steps_completed,
|
|
365
|
+
totalSteps: row.total_steps,
|
|
366
|
+
createdAt: row.created_at,
|
|
367
|
+
updatedAt: row.updated_at,
|
|
368
|
+
};
|
|
369
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chain types — composable multi-step workflows with data flow.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
|
|
7
|
+
// ─── Chain Definition (YAML schema) ──────────────────────────────────
|
|
8
|
+
|
|
9
|
+
export const chainStepSchema = z.object({
|
|
10
|
+
id: z.string(),
|
|
11
|
+
op: z.string().describe('Facade op to call'),
|
|
12
|
+
params: z
|
|
13
|
+
.record(z.unknown())
|
|
14
|
+
.optional()
|
|
15
|
+
.describe('Params — use $input.x or $stepId.field for data flow'),
|
|
16
|
+
output: z.string().optional().describe('Key to store step result under'),
|
|
17
|
+
gate: z.enum(['user-approval', 'auto-test', 'vault-check', 'none']).optional(),
|
|
18
|
+
description: z.string().optional(),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export const chainDefSchema = z.object({
|
|
22
|
+
id: z.string(),
|
|
23
|
+
name: z.string().optional(),
|
|
24
|
+
description: z.string().optional(),
|
|
25
|
+
steps: z.array(chainStepSchema).min(1),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export type ChainDef = z.infer<typeof chainDefSchema>;
|
|
29
|
+
export type ChainStep = z.infer<typeof chainStepSchema>;
|
|
30
|
+
|
|
31
|
+
// ─── Chain Instance (runtime state) ──────────────────────────────────
|
|
32
|
+
|
|
33
|
+
export type ChainStatus = 'running' | 'paused' | 'completed' | 'failed';
|
|
34
|
+
|
|
35
|
+
export interface StepOutput {
|
|
36
|
+
stepId: string;
|
|
37
|
+
op: string;
|
|
38
|
+
result: unknown;
|
|
39
|
+
status: 'completed' | 'failed' | 'skipped';
|
|
40
|
+
durationMs: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface ChainInstance {
|
|
44
|
+
id: string;
|
|
45
|
+
chainId: string;
|
|
46
|
+
chainName: string;
|
|
47
|
+
status: ChainStatus;
|
|
48
|
+
currentStep: string | null;
|
|
49
|
+
pausedAtGate: string | null;
|
|
50
|
+
input: Record<string, unknown>;
|
|
51
|
+
context: Record<string, unknown>;
|
|
52
|
+
stepOutputs: StepOutput[];
|
|
53
|
+
stepsCompleted: number;
|
|
54
|
+
totalSteps: number;
|
|
55
|
+
createdAt: string;
|
|
56
|
+
updatedAt: string;
|
|
57
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -541,7 +541,6 @@ export type {
|
|
|
541
541
|
|
|
542
542
|
// ─── Persistence ───────────────────────────────────────────────────────
|
|
543
543
|
export { SQLitePersistenceProvider } from './persistence/index.js';
|
|
544
|
-
export { PostgresPersistenceProvider, translateSql } from './persistence/index.js';
|
|
545
544
|
export type {
|
|
546
545
|
PersistenceProvider,
|
|
547
546
|
PersistenceParams,
|