@ddse/acm-sdk 0.5.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.
Files changed (111) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +221 -0
  3. package/dist/capability.d.ts +10 -0
  4. package/dist/capability.d.ts.map +1 -0
  5. package/dist/capability.js +3 -0
  6. package/dist/capability.js.map +1 -0
  7. package/dist/index.d.ts +8 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +9 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/policy.d.ts +5 -0
  12. package/dist/policy.d.ts.map +1 -0
  13. package/dist/policy.js +2 -0
  14. package/dist/policy.js.map +1 -0
  15. package/dist/registry.d.ts +6 -0
  16. package/dist/registry.d.ts.map +1 -0
  17. package/dist/registry.js +3 -0
  18. package/dist/registry.js.map +1 -0
  19. package/dist/src/capability-map.d.ts +6 -0
  20. package/dist/src/capability-map.d.ts.map +1 -0
  21. package/dist/src/capability-map.js +281 -0
  22. package/dist/src/capability-map.js.map +1 -0
  23. package/dist/src/capability.d.ts +10 -0
  24. package/dist/src/capability.d.ts.map +1 -0
  25. package/dist/src/capability.js +3 -0
  26. package/dist/src/capability.js.map +1 -0
  27. package/dist/src/context-provider.d.ts +36 -0
  28. package/dist/src/context-provider.d.ts.map +1 -0
  29. package/dist/src/context-provider.js +59 -0
  30. package/dist/src/context-provider.js.map +1 -0
  31. package/dist/src/context.d.ts +42 -0
  32. package/dist/src/context.d.ts.map +1 -0
  33. package/dist/src/context.js +148 -0
  34. package/dist/src/context.js.map +1 -0
  35. package/dist/src/index.d.ts +12 -0
  36. package/dist/src/index.d.ts.map +1 -0
  37. package/dist/src/index.js +13 -0
  38. package/dist/src/index.js.map +1 -0
  39. package/dist/src/nucleus.d.ts +105 -0
  40. package/dist/src/nucleus.d.ts.map +1 -0
  41. package/dist/src/nucleus.js +208 -0
  42. package/dist/src/nucleus.js.map +1 -0
  43. package/dist/src/policy.d.ts +5 -0
  44. package/dist/src/policy.d.ts.map +1 -0
  45. package/dist/src/policy.js +2 -0
  46. package/dist/src/policy.js.map +1 -0
  47. package/dist/src/registry.d.ts +6 -0
  48. package/dist/src/registry.d.ts.map +1 -0
  49. package/dist/src/registry.js +3 -0
  50. package/dist/src/registry.js.map +1 -0
  51. package/dist/src/stream.d.ts +8 -0
  52. package/dist/src/stream.d.ts.map +1 -0
  53. package/dist/src/stream.js +19 -0
  54. package/dist/src/stream.js.map +1 -0
  55. package/dist/src/task.d.ts +24 -0
  56. package/dist/src/task.d.ts.map +1 -0
  57. package/dist/src/task.js +11 -0
  58. package/dist/src/task.js.map +1 -0
  59. package/dist/src/tool.d.ts +5 -0
  60. package/dist/src/tool.d.ts.map +1 -0
  61. package/dist/src/tool.js +4 -0
  62. package/dist/src/tool.js.map +1 -0
  63. package/dist/src/types.d.ts +195 -0
  64. package/dist/src/types.d.ts.map +1 -0
  65. package/dist/src/types.js +2 -0
  66. package/dist/src/types.js.map +1 -0
  67. package/dist/src/utils.d.ts +22 -0
  68. package/dist/src/utils.d.ts.map +1 -0
  69. package/dist/src/utils.js +194 -0
  70. package/dist/src/utils.js.map +1 -0
  71. package/dist/src/validators.d.ts +20 -0
  72. package/dist/src/validators.d.ts.map +1 -0
  73. package/dist/src/validators.js +209 -0
  74. package/dist/src/validators.js.map +1 -0
  75. package/dist/stream.d.ts +8 -0
  76. package/dist/stream.d.ts.map +1 -0
  77. package/dist/stream.js +19 -0
  78. package/dist/stream.js.map +1 -0
  79. package/dist/task.d.ts +11 -0
  80. package/dist/task.d.ts.map +1 -0
  81. package/dist/task.js +9 -0
  82. package/dist/task.js.map +1 -0
  83. package/dist/tests/phase4-integration.test.d.ts +2 -0
  84. package/dist/tests/phase4-integration.test.d.ts.map +1 -0
  85. package/dist/tests/phase4-integration.test.js +115 -0
  86. package/dist/tests/phase4-integration.test.js.map +1 -0
  87. package/dist/tool.d.ts +5 -0
  88. package/dist/tool.d.ts.map +1 -0
  89. package/dist/tool.js +4 -0
  90. package/dist/tool.js.map +1 -0
  91. package/dist/tsconfig.tsbuildinfo +1 -0
  92. package/dist/types.d.ts +77 -0
  93. package/dist/types.d.ts.map +1 -0
  94. package/dist/types.js +3 -0
  95. package/dist/types.js.map +1 -0
  96. package/package.json +26 -0
  97. package/src/capability.ts +11 -0
  98. package/src/context-provider.ts +136 -0
  99. package/src/context.ts +190 -0
  100. package/src/index.ts +12 -0
  101. package/src/nucleus.ts +341 -0
  102. package/src/policy.ts +9 -0
  103. package/src/registry.ts +7 -0
  104. package/src/stream.ts +24 -0
  105. package/src/task.ts +38 -0
  106. package/src/tool.ts +6 -0
  107. package/src/types.ts +233 -0
  108. package/src/utils.ts +271 -0
  109. package/tests/phase4-integration.test.ts +138 -0
  110. package/tsconfig.json +8 -0
  111. package/tsconfig.tsbuildinfo +1 -0
package/src/nucleus.ts ADDED
@@ -0,0 +1,341 @@
1
+ // Nucleus contract for LLM-native task and planner execution
2
+ import { createHash } from 'crypto';
3
+ import type { Context, InternalContextScope, LedgerEntry, ToolCallEnvelope } from './types.js';
4
+
5
+ export type NucleusToolDefinition = {
6
+ name: string;
7
+ description?: string;
8
+ inputSchema?: {
9
+ type: 'object';
10
+ properties: Record<string, any>;
11
+ required?: string[];
12
+ };
13
+ };
14
+
15
+ export type StructuredToolCall = {
16
+ id?: string;
17
+ name: string;
18
+ input: Record<string, any>;
19
+ output?: Record<string, any>;
20
+ error?: {
21
+ code: string;
22
+ message: string;
23
+ };
24
+ };
25
+
26
+ export type NucleusInvokeRequest = {
27
+ prompt?: string;
28
+ input?: any;
29
+ tools?: NucleusToolDefinition[];
30
+ };
31
+
32
+ export type NucleusInvokeResult = {
33
+ reasoning?: string;
34
+ toolCalls: StructuredToolCall[];
35
+ raw?: any;
36
+ };
37
+
38
+ // Nucleus configuration
39
+ export type NucleusConfig = {
40
+ goalId: string;
41
+ goalIntent: string;
42
+ planId?: string;
43
+ taskId?: string;
44
+ contextRef: string;
45
+ context?: Context;
46
+ llmCall: {
47
+ provider: string;
48
+ model: string;
49
+ temperature?: number;
50
+ seed?: number;
51
+ maxTokens?: number;
52
+ };
53
+ allowedTools?: string[];
54
+ hooks?: {
55
+ preflight?: boolean;
56
+ postcheck?: boolean;
57
+ };
58
+ promptTemplate?: string;
59
+ promptDigest?: string;
60
+ };
61
+
62
+ export type PreflightResult =
63
+ | { status: 'OK' }
64
+ | { status: 'NEEDS_CONTEXT'; retrievalDirectives: string[] };
65
+
66
+ export type PostcheckResult =
67
+ | { status: 'COMPLETE' }
68
+ | { status: 'NEEDS_COMPENSATION'; reason: string }
69
+ | { status: 'ESCALATE'; reason: string };
70
+
71
+ export type LLMCallFn = (
72
+ prompt: string,
73
+ tools: NucleusToolDefinition[],
74
+ config: NucleusConfig['llmCall']
75
+ ) => Promise<{
76
+ reasoning?: string;
77
+ toolCalls: StructuredToolCall[];
78
+ raw?: any;
79
+ }>;
80
+
81
+ export abstract class Nucleus {
82
+ constructor(protected config: NucleusConfig) {}
83
+
84
+ abstract preflight(): Promise<PreflightResult>;
85
+ abstract invoke(request: NucleusInvokeRequest): Promise<NucleusInvokeResult>;
86
+ abstract postcheck(output: any): Promise<PostcheckResult>;
87
+
88
+ abstract recordInference(
89
+ promptDigest: string,
90
+ toolCalls: StructuredToolCall[],
91
+ reasoning?: string
92
+ ): LedgerEntry;
93
+
94
+ abstract getInternalContext(): InternalContextScope | undefined;
95
+ abstract setInternalContext(scope: InternalContextScope): void;
96
+
97
+ getConfig(): NucleusConfig {
98
+ return this.config;
99
+ }
100
+ }
101
+
102
+ export class DeterministicNucleus extends Nucleus {
103
+ private internalContext?: InternalContextScope;
104
+ private ledger: LedgerEntry[] = [];
105
+
106
+ constructor(
107
+ config: NucleusConfig,
108
+ private llmCall: LLMCallFn,
109
+ private ledgerAppend: (entry: LedgerEntry) => void
110
+ ) {
111
+ super(config);
112
+ if (!config.goalIntent || config.goalIntent.trim().length === 0) {
113
+ throw new Error('NucleusConfig.goalIntent is required for nucleus execution.');
114
+ }
115
+ }
116
+
117
+ async preflight(): Promise<PreflightResult> {
118
+ if (!this.config.hooks?.preflight) {
119
+ return { status: 'OK' };
120
+ }
121
+
122
+ const prompt = this.buildPreflightPrompt();
123
+ const result = await this.callLLM(prompt);
124
+
125
+ const needsContext = result.toolCalls.some(
126
+ tc => tc.name === 'request_context_retrieval'
127
+ );
128
+
129
+ if (needsContext) {
130
+ const directives = result.toolCalls
131
+ .filter(tc => tc.name === 'request_context_retrieval')
132
+ .map(tc => tc.input?.directive as string)
133
+ .filter(Boolean);
134
+ return {
135
+ status: 'NEEDS_CONTEXT',
136
+ retrievalDirectives: directives,
137
+ };
138
+ }
139
+
140
+ return { status: 'OK' };
141
+ }
142
+
143
+ async invoke(request: NucleusInvokeRequest): Promise<NucleusInvokeResult> {
144
+ const prompt = request.prompt ?? this.buildInvokePrompt(request.input);
145
+ return this.callLLM(prompt, request.tools);
146
+ }
147
+
148
+ async postcheck(output: any): Promise<PostcheckResult> {
149
+ if (!this.config.hooks?.postcheck) {
150
+ return { status: 'COMPLETE' };
151
+ }
152
+
153
+ const prompt = this.buildPostcheckPrompt(output);
154
+ const result = await this.callLLM(prompt);
155
+
156
+ const compensation = result.toolCalls.find(tc => tc.name === 'request_compensation');
157
+ if (compensation) {
158
+ return {
159
+ status: 'NEEDS_COMPENSATION',
160
+ reason: (compensation.input?.reason as string) || 'Unknown',
161
+ };
162
+ }
163
+
164
+ const escalation = result.toolCalls.find(tc => tc.name === 'escalate_issue');
165
+ if (escalation) {
166
+ return {
167
+ status: 'ESCALATE',
168
+ reason: (escalation.input?.reason as string) || 'Unknown',
169
+ };
170
+ }
171
+
172
+ return { status: 'COMPLETE' };
173
+ }
174
+
175
+ recordInference(
176
+ promptDigest: string,
177
+ toolCalls: StructuredToolCall[],
178
+ reasoning?: string
179
+ ): LedgerEntry {
180
+ const envelopes: ToolCallEnvelope[] = toolCalls.map((tc, idx) => ({
181
+ id: tc.id ?? `tool-call-${Date.now()}-${idx}`,
182
+ name: tc.name,
183
+ input: tc.input ?? {},
184
+ output: tc.output,
185
+ error: tc.error,
186
+ metadata: {
187
+ timestamp: Date.now(),
188
+ digest: this.computeDigest(JSON.stringify(tc.input ?? {})),
189
+ },
190
+ }));
191
+
192
+ const entry: LedgerEntry = {
193
+ id: `nucleus-inference-${Date.now()}-${Math.random().toString(36).substring(7)}`,
194
+ ts: Date.now(),
195
+ type: 'NUCLEUS_INFERENCE',
196
+ details: {
197
+ nucleus: {
198
+ goalId: this.config.goalId,
199
+ planId: this.config.planId,
200
+ taskId: this.config.taskId,
201
+ contextRef: this.config.contextRef,
202
+ },
203
+ llmCall: {
204
+ provider: this.config.llmCall.provider,
205
+ model: this.config.llmCall.model,
206
+ seed: this.config.llmCall.seed,
207
+ },
208
+ promptDigest,
209
+ reasoning,
210
+ toolCalls: envelopes.map(env => ({
211
+ id: env.id,
212
+ name: env.name,
213
+ inputDigest: env.metadata?.digest,
214
+ outputDigest: env.output ? this.computeDigest(JSON.stringify(env.output)) : undefined,
215
+ })),
216
+ },
217
+ };
218
+
219
+ entry.digest = this.computeDigest(JSON.stringify(entry.details));
220
+ this.ledger.push(entry);
221
+ this.ledgerAppend(entry);
222
+ return entry;
223
+ }
224
+
225
+ getInternalContext(): InternalContextScope | undefined {
226
+ return this.internalContext;
227
+ }
228
+
229
+ setInternalContext(scope: InternalContextScope): void {
230
+ this.internalContext = scope;
231
+ }
232
+
233
+ private async callLLM(
234
+ prompt: string,
235
+ tools: NucleusToolDefinition[] = []
236
+ ): Promise<NucleusInvokeResult> {
237
+ const result = await this.llmCall(prompt, tools, this.config.llmCall);
238
+ const normalizedCalls = (result.toolCalls ?? []).map((tc, idx) => ({
239
+ id: tc.id ?? `tool-call-${Date.now()}-${idx}`,
240
+ name: tc.name,
241
+ input: tc.input ?? {},
242
+ output: tc.output,
243
+ error: tc.error,
244
+ }));
245
+
246
+ this.recordInference(this.computePromptDigest(prompt), normalizedCalls, result.reasoning);
247
+
248
+ return {
249
+ reasoning: result.reasoning,
250
+ toolCalls: normalizedCalls,
251
+ raw: result.raw,
252
+ };
253
+ }
254
+
255
+ private buildPreflightPrompt(): string {
256
+ return `Assess whether the current context is sufficient for the task.
257
+ Goal: ${this.config.goalId}
258
+ Goal Intent: ${this.config.goalIntent}
259
+ Task: ${this.config.taskId || 'planner'}
260
+ Context Ref: ${this.config.contextRef}
261
+
262
+ Context Snapshot:
263
+ ${this.renderContextSnapshot()}
264
+
265
+ If additional context is needed, call request_context_retrieval with a directive.`;
266
+ }
267
+
268
+ private buildInvokePrompt(input: any): string {
269
+ return `Execute the task with the following input:
270
+ ${JSON.stringify(input, null, 2)}
271
+
272
+ Goal: ${this.config.goalId}
273
+ Goal Intent: ${this.config.goalIntent}
274
+ Task: ${this.config.taskId || 'planner'}
275
+
276
+ Relevant Context:
277
+ ${this.renderContextSnapshot()}`;
278
+ }
279
+
280
+ private buildPostcheckPrompt(output: any): string {
281
+ return `Validate the output and determine if any follow-up is needed:
282
+ ${JSON.stringify(output, null, 2)}
283
+
284
+ Goal: ${this.config.goalId}
285
+ Goal Intent: ${this.config.goalIntent}
286
+ Task: ${this.config.taskId || 'planner'}
287
+
288
+ Context Reference: ${this.config.contextRef}
289
+
290
+ If compensation is needed, call request_compensation.
291
+ If escalation is needed, call escalate_issue.`;
292
+ }
293
+
294
+ private computePromptDigest(prompt: string): string {
295
+ const hash = createHash('sha256');
296
+ hash.update(prompt);
297
+ return hash.digest('hex').substring(0, 16);
298
+ }
299
+
300
+ private computeDigest(content: string): string {
301
+ const hash = createHash('sha256');
302
+ hash.update(content);
303
+ return hash.digest('hex').substring(0, 16);
304
+ }
305
+
306
+ private renderContextSnapshot(): string {
307
+ const context = this.config.context;
308
+ if (!context) {
309
+ return '(No context payload provided; consider supplying context.facts to the nucleus.)';
310
+ }
311
+
312
+ const pieces: string[] = [];
313
+
314
+ if (context.facts && Object.keys(context.facts).length > 0) {
315
+ pieces.push(`Facts:\n${JSON.stringify(context.facts, null, 2)}`);
316
+ } else {
317
+ pieces.push('Facts: {}');
318
+ }
319
+
320
+ if (context.assumptions && context.assumptions.length > 0) {
321
+ pieces.push(`Assumptions:\n- ${context.assumptions.join('\n- ')}`);
322
+ }
323
+
324
+ if (context.constraints_inherited && Object.keys(context.constraints_inherited).length > 0) {
325
+ pieces.push(
326
+ `Inherited Constraints:\n${JSON.stringify(context.constraints_inherited, null, 2)}`
327
+ );
328
+ }
329
+
330
+ if (context.augmentations && context.augmentations.length > 0) {
331
+ const augmentations = context.augmentations
332
+ .map(aug => `- ${aug.type}: ${aug.artifact}`)
333
+ .join('\n');
334
+ pieces.push(`Augmentations:\n${augmentations}`);
335
+ }
336
+
337
+ return pieces.join('\n\n');
338
+ }
339
+ }
340
+
341
+ export type NucleusFactory = (config: NucleusConfig) => Nucleus;
package/src/policy.ts ADDED
@@ -0,0 +1,9 @@
1
+ // PolicyEngine interface
2
+ import type { PolicyDecision } from './types.js';
3
+
4
+ export interface PolicyEngine {
5
+ evaluate(
6
+ action: 'plan.admit' | 'task.pre' | 'task.post',
7
+ payload: any
8
+ ): Promise<PolicyDecision>;
9
+ }
@@ -0,0 +1,7 @@
1
+ // Abstract ToolRegistry class
2
+ import type { Tool } from './tool.js';
3
+
4
+ export abstract class ToolRegistry {
5
+ abstract get(name: string): Tool<any, any> | undefined;
6
+ abstract list(): string[];
7
+ }
package/src/stream.ts ADDED
@@ -0,0 +1,24 @@
1
+ // StreamSink implementation
2
+ import type { StreamSink } from './types.js';
3
+
4
+ export class DefaultStreamSink implements StreamSink {
5
+ private listeners = new Map<string, Array<(chunk: any) => void>>();
6
+
7
+ attach(source: string, callback: (chunk: any) => void): void {
8
+ if (!this.listeners.has(source)) {
9
+ this.listeners.set(source, []);
10
+ }
11
+ this.listeners.get(source)!.push(callback);
12
+ }
13
+
14
+ emit(source: string, chunk: any): void {
15
+ const callbacks = this.listeners.get(source);
16
+ if (callbacks) {
17
+ callbacks.forEach(cb => cb(chunk));
18
+ }
19
+ }
20
+
21
+ close(source: string): void {
22
+ this.listeners.delete(source);
23
+ }
24
+ }
package/src/task.ts ADDED
@@ -0,0 +1,38 @@
1
+ // Abstract Task class
2
+ import type { RunContext } from './types.js';
3
+ import type { Nucleus, NucleusFactory } from './nucleus.js';
4
+
5
+ export abstract class Task<I = any, O = any> {
6
+ constructor(
7
+ public id: string,
8
+ public capability: string,
9
+ protected nucleusFactory?: NucleusFactory
10
+ ) {}
11
+
12
+ abstract execute(ctx: RunContext, input: I): Promise<O>;
13
+
14
+ // Optional: idempotency key
15
+ idemKey?(ctx: RunContext, input: I): string | undefined;
16
+
17
+ // Optional: policy input
18
+ policyInput?(ctx: RunContext, input: I): Record<string, unknown>;
19
+
20
+ // Optional: verification expressions
21
+ verification?(): string[];
22
+
23
+ // Optional: tool bindings for this task
24
+ toolBindings?(): Array<{ name: string; version: string }>;
25
+
26
+ // Optional: policy references
27
+ policyRefs?(): string[];
28
+
29
+ // Optional: retry policy configuration
30
+ retryPolicy?(): {
31
+ maxAttempts?: number;
32
+ backoffSeconds?: number[];
33
+ retryOn?: string[];
34
+ };
35
+
36
+ // Get or create nucleus instance for this task
37
+ protected getNucleus?(ctx: RunContext): Nucleus | undefined;
38
+ }
package/src/tool.ts ADDED
@@ -0,0 +1,6 @@
1
+ // Abstract Tool class
2
+
3
+ export abstract class Tool<I = any, O = any> {
4
+ abstract name(): string;
5
+ abstract call(input: I, idemKey?: string): Promise<O>;
6
+ }
package/src/types.ts ADDED
@@ -0,0 +1,233 @@
1
+ import type { Nucleus } from './nucleus.js';
2
+
3
+ // Core types for ACM v0.5
4
+
5
+ export type GoalCard = {
6
+ id: string;
7
+ intent: string;
8
+ actors?: string[];
9
+ constraints?: Record<string, any>;
10
+ acceptance?: {
11
+ must_include?: string[];
12
+ verification_refs?: string[];
13
+ };
14
+ policy_context?: {
15
+ policy_sheet?: string;
16
+ approvals_required?: Array<{ role: string; validUntil?: string }>;
17
+ };
18
+ context_required?: boolean; // Optional for backward compatibility
19
+ contextRef?: string;
20
+ metadata?: Record<string, any>;
21
+ };
22
+
23
+ // Backward compatibility alias
24
+ export type Goal = GoalCard;
25
+
26
+ export type ContextPacket = {
27
+ id: string;
28
+ version?: string;
29
+ sources?: Array<{
30
+ uri: string;
31
+ digest: string;
32
+ type?: string;
33
+ }>;
34
+ facts: Record<string, any>;
35
+ assumptions?: string[];
36
+ constraints_inherited?: Record<string, any>;
37
+ augmentations?: Array<{
38
+ type: string;
39
+ artifact: string;
40
+ }>;
41
+ provenance?: {
42
+ retrieval_snapshot?: string;
43
+ llm?: {
44
+ provider: string;
45
+ model: string;
46
+ temperature?: number;
47
+ };
48
+ prompt_digest?: string;
49
+ [key: string]: any;
50
+ };
51
+ };
52
+
53
+ // Backward compatibility alias
54
+ export type Context = ContextPacket;
55
+
56
+ export type GuardExpr = string; // boolean expression over {context, outputs, policy}
57
+
58
+ export type TaskSpec = {
59
+ id: string;
60
+ title?: string;
61
+ objective?: string;
62
+ successCriteria?: string[];
63
+ capabilityRef?: string; // name@version format (preferred)
64
+ capability?: string; // Backward compatibility, use capabilityRef
65
+ input?: any;
66
+ policyInput?: Record<string, unknown>;
67
+ verificationRefs?: string[];
68
+ verification?: string[]; // Backward compatibility
69
+ idemKey?: string;
70
+ retryPolicy?: {
71
+ maxAttempts?: number;
72
+ backoffSeconds?: number[];
73
+ retryOn?: string[];
74
+ };
75
+ retry?: { // Backward compatibility
76
+ attempts: number;
77
+ backoff: 'fixed' | 'exp';
78
+ baseMs?: number;
79
+ jitter?: boolean;
80
+ };
81
+ compensation?: {
82
+ capabilityRef: string;
83
+ triggerOn?: string[];
84
+ };
85
+ tools?: Array<{
86
+ name: string;
87
+ version: string;
88
+ timeout_sec?: number;
89
+ }>;
90
+ nucleusRef?: string;
91
+ internalTools?: Array<{
92
+ name: string;
93
+ version?: string;
94
+ }>;
95
+ telemetry?: {
96
+ tracing?: {
97
+ otelSpanName?: string;
98
+ attributes?: Record<string, any>;
99
+ };
100
+ };
101
+ };
102
+
103
+ export type PlanEdge = {
104
+ from: string;
105
+ to: string;
106
+ guard?: GuardExpr;
107
+ onError?: 'RETRYABLE_ERROR' | 'FATAL_ERROR' | 'COMPENSATION_REQUIRED';
108
+ };
109
+
110
+ export type Plan = {
111
+ id: string;
112
+ contextRef: string;
113
+ capabilityMapVersion: string;
114
+ tasks: TaskSpec[];
115
+ edges: PlanEdge[];
116
+ join?: 'all' | 'any';
117
+ alternatives?: string[];
118
+ rationale?: string;
119
+ };
120
+
121
+ export type PolicyDecision = {
122
+ allow: boolean;
123
+ limits?: {
124
+ timeoutMs?: number;
125
+ retries?: number;
126
+ };
127
+ reason?: string;
128
+ };
129
+
130
+ export type LedgerEntry = {
131
+ id: string;
132
+ ts: number;
133
+ type:
134
+ | 'PLAN_SELECTED'
135
+ | 'BRANCH_TAKEN'
136
+ | 'GUARD_EVAL'
137
+ | 'TASK_START'
138
+ | 'TASK_END'
139
+ | 'POLICY_PRE'
140
+ | 'POLICY_POST'
141
+ | 'POLICY_DECISION'
142
+ | 'VERIFICATION'
143
+ | 'ERROR'
144
+ | 'COMPENSATION'
145
+ | 'NUCLEUS_INFERENCE'
146
+ | 'CONTEXT_INTERNALIZED'
147
+ | 'TOOL_CALL'
148
+ | 'GOAL_SUMMARY';
149
+ details: Record<string, any>;
150
+ digest?: string; // Content hash for tamper detection
151
+ signature?: string; // Optional cryptographic signature
152
+ };
153
+
154
+ export type Capability = {
155
+ name: string;
156
+ inputSchema?: unknown;
157
+ outputSchema?: unknown;
158
+ sideEffects?: boolean;
159
+ };
160
+
161
+ export type StreamSink = {
162
+ attach(source: string, callback: (chunk: any) => void): void;
163
+ emit(source: string, chunk: any): void;
164
+ close(source: string): void;
165
+ };
166
+
167
+ export type RunContext = {
168
+ goal: Goal;
169
+ context: Context;
170
+ outputs: Record<string, any>;
171
+ metrics: {
172
+ costUsd: number;
173
+ elapsedSec: number;
174
+ };
175
+ getTool(name: string): any;
176
+ getCapabilityRegistry(): any;
177
+ stream?: StreamSink;
178
+ nucleus: Nucleus;
179
+ internalContext?: InternalContextScope;
180
+ };
181
+
182
+ // Tool call envelope for structured tool invocations
183
+ export type ToolCallEnvelope = {
184
+ id: string;
185
+ name: string;
186
+ version?: string;
187
+ input: Record<string, any>;
188
+ output?: Record<string, any>;
189
+ error?: {
190
+ code: string;
191
+ message: string;
192
+ };
193
+ metadata: {
194
+ timestamp: number;
195
+ duration_ms?: number;
196
+ digest?: string;
197
+ };
198
+ };
199
+
200
+ // Planner-specific tool call schema
201
+ export type PlannerToolCall = {
202
+ toolName: string;
203
+ input: Record<string, any>;
204
+ expectedOutputType: string;
205
+ promptDigest?: string;
206
+ alternativeIds?: string[];
207
+ };
208
+
209
+ // Internal context scope for Nucleus
210
+ export type InternalContextScope = {
211
+ artifacts: Array<{
212
+ id: string;
213
+ type: string;
214
+ content: any;
215
+ digest: string;
216
+ provenance?: {
217
+ retrievedAt: number;
218
+ tool?: string;
219
+ rationale?: string;
220
+ };
221
+ }>;
222
+ addArtifact(
223
+ type: string,
224
+ content: any,
225
+ provenance?: {
226
+ tool?: string;
227
+ rationale?: string;
228
+ [key: string]: any;
229
+ }
230
+ ): string;
231
+ promote(artifactId: string): Promise<void>;
232
+ getArtifact(id: string): any;
233
+ };