@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.
- package/LICENSE +21 -0
- package/README.md +221 -0
- package/dist/capability.d.ts +10 -0
- package/dist/capability.d.ts.map +1 -0
- package/dist/capability.js +3 -0
- package/dist/capability.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/policy.d.ts +5 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +2 -0
- package/dist/policy.js.map +1 -0
- package/dist/registry.d.ts +6 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +3 -0
- package/dist/registry.js.map +1 -0
- package/dist/src/capability-map.d.ts +6 -0
- package/dist/src/capability-map.d.ts.map +1 -0
- package/dist/src/capability-map.js +281 -0
- package/dist/src/capability-map.js.map +1 -0
- package/dist/src/capability.d.ts +10 -0
- package/dist/src/capability.d.ts.map +1 -0
- package/dist/src/capability.js +3 -0
- package/dist/src/capability.js.map +1 -0
- package/dist/src/context-provider.d.ts +36 -0
- package/dist/src/context-provider.d.ts.map +1 -0
- package/dist/src/context-provider.js +59 -0
- package/dist/src/context-provider.js.map +1 -0
- package/dist/src/context.d.ts +42 -0
- package/dist/src/context.d.ts.map +1 -0
- package/dist/src/context.js +148 -0
- package/dist/src/context.js.map +1 -0
- package/dist/src/index.d.ts +12 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +13 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/nucleus.d.ts +105 -0
- package/dist/src/nucleus.d.ts.map +1 -0
- package/dist/src/nucleus.js +208 -0
- package/dist/src/nucleus.js.map +1 -0
- package/dist/src/policy.d.ts +5 -0
- package/dist/src/policy.d.ts.map +1 -0
- package/dist/src/policy.js +2 -0
- package/dist/src/policy.js.map +1 -0
- package/dist/src/registry.d.ts +6 -0
- package/dist/src/registry.d.ts.map +1 -0
- package/dist/src/registry.js +3 -0
- package/dist/src/registry.js.map +1 -0
- package/dist/src/stream.d.ts +8 -0
- package/dist/src/stream.d.ts.map +1 -0
- package/dist/src/stream.js +19 -0
- package/dist/src/stream.js.map +1 -0
- package/dist/src/task.d.ts +24 -0
- package/dist/src/task.d.ts.map +1 -0
- package/dist/src/task.js +11 -0
- package/dist/src/task.js.map +1 -0
- package/dist/src/tool.d.ts +5 -0
- package/dist/src/tool.d.ts.map +1 -0
- package/dist/src/tool.js +4 -0
- package/dist/src/tool.js.map +1 -0
- package/dist/src/types.d.ts +195 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils.d.ts +22 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/utils.js +194 -0
- package/dist/src/utils.js.map +1 -0
- package/dist/src/validators.d.ts +20 -0
- package/dist/src/validators.d.ts.map +1 -0
- package/dist/src/validators.js +209 -0
- package/dist/src/validators.js.map +1 -0
- package/dist/stream.d.ts +8 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +19 -0
- package/dist/stream.js.map +1 -0
- package/dist/task.d.ts +11 -0
- package/dist/task.d.ts.map +1 -0
- package/dist/task.js +9 -0
- package/dist/task.js.map +1 -0
- package/dist/tests/phase4-integration.test.d.ts +2 -0
- package/dist/tests/phase4-integration.test.d.ts.map +1 -0
- package/dist/tests/phase4-integration.test.js +115 -0
- package/dist/tests/phase4-integration.test.js.map +1 -0
- package/dist/tool.d.ts +5 -0
- package/dist/tool.d.ts.map +1 -0
- package/dist/tool.js +4 -0
- package/dist/tool.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types.d.ts +77 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +26 -0
- package/src/capability.ts +11 -0
- package/src/context-provider.ts +136 -0
- package/src/context.ts +190 -0
- package/src/index.ts +12 -0
- package/src/nucleus.ts +341 -0
- package/src/policy.ts +9 -0
- package/src/registry.ts +7 -0
- package/src/stream.ts +24 -0
- package/src/task.ts +38 -0
- package/src/tool.ts +6 -0
- package/src/types.ts +233 -0
- package/src/utils.ts +271 -0
- package/tests/phase4-integration.test.ts +138 -0
- package/tsconfig.json +8 -0
- 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
package/src/registry.ts
ADDED
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
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
|
+
};
|