groundswell 0.0.1
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/.claude/settings.local.json +9 -0
- package/.claude/system_prompts/task-breakdown.md +100 -0
- package/PRPs/001-hierarchical-workflow-engine.md +2438 -0
- package/PRPs/PRDs/001-hierarchical-workflow-engine.md +543 -0
- package/PRPs/PRDs/002-agent-prompt.md +390 -0
- package/PRPs/PRDs/003-agent-prompt.md +943 -0
- package/PRPs/PRDs/004-agent-prompt.md +1136 -0
- package/PRPs/PRDs/tasks-001.json +492 -0
- package/PRPs/README.md +83 -0
- package/PRPs/templates/prp_base.md +222 -0
- package/README.md +218 -0
- package/docs/agent.md +422 -0
- package/docs/prompt.md +419 -0
- package/docs/workflow.md +600 -0
- package/examples/README.md +244 -0
- package/examples/examples/01-basic-workflow.ts +100 -0
- package/examples/examples/02-decorator-options.ts +217 -0
- package/examples/examples/03-parent-child.ts +241 -0
- package/examples/examples/04-observers-debugger.ts +340 -0
- package/examples/examples/05-error-handling.ts +387 -0
- package/examples/examples/06-concurrent-tasks.ts +352 -0
- package/examples/examples/07-agent-loops.ts +432 -0
- package/examples/examples/08-sdk-features.ts +667 -0
- package/examples/examples/09-reflection.ts +573 -0
- package/examples/examples/10-introspection.ts +550 -0
- package/examples/index.ts +143 -0
- package/examples/utils/helpers.ts +57 -0
- package/llms_full.txt +5890 -0
- package/package.json +63 -0
- package/plan/P1P2/PRP.md +527 -0
- package/plan/P1P2/research/LRU_CACHE_BEST_PRACTICES.md +1929 -0
- package/plan/P1P2/research/LRU_CACHE_CODE_PATTERNS.md +857 -0
- package/plan/P1P2/research/LRU_CACHE_INTEGRATION_GUIDE.md +738 -0
- package/plan/P1P2/research/LRU_CACHE_RESEARCH_INDEX.md +424 -0
- package/plan/P1P2/research/REFLECTION_INDEX.md +291 -0
- package/plan/P1P2/research/REFLECTION_RESEARCH_REPORT.md +1342 -0
- package/plan/P1P2/research/RESEARCH_SUMMARY.md +342 -0
- package/plan/P1P2/research/anthropic-sdk.md +174 -0
- package/plan/P1P2/research/async-local-storage.md +200 -0
- package/plan/P1P2/research/reflection-code-patterns.md +1205 -0
- package/plan/P1P2/research/reflection-decision-matrix.md +421 -0
- package/plan/P1P2/research/reflection-implementation-guide.md +1341 -0
- package/plan/P1P2/research/reflection-integration-guide.md +834 -0
- package/plan/P1P2/research/reflection-patterns.md +1468 -0
- package/plan/P1P2/research/reflection-quick-reference.md +558 -0
- package/plan/P1P2/research/zod-schema.md +152 -0
- package/plan/P3P4/PRP.md +1388 -0
- package/plan/P3P4/research/caching-lru.md +116 -0
- package/plan/P3P4/research/introspection-tools.md +177 -0
- package/plan/P3P4/research/reflection-patterns.md +117 -0
- package/plan/P4P5/PRP.md +1136 -0
- package/plan/P4P5/research/RESEARCH_SUMMARY.md +151 -0
- package/plan/architecture/external_deps.md +358 -0
- package/plan/architecture/system_context.md +242 -0
- package/plan/backlog.json +867 -0
- package/plan/research/INTROSPECTION_RESEARCH_SUMMARY.md +378 -0
- package/plan/research/README-INTROSPECTION.md +352 -0
- package/plan/research/agent-introspection-patterns.md +1085 -0
- package/plan/research/introspection-security-guide.md +928 -0
- package/plan/research/introspection-tool-examples.md +875 -0
- package/scripts/generate-llms-full.ts +206 -0
- package/src/__tests__/integration/agent-workflow.test.ts +256 -0
- package/src/__tests__/integration/tree-mirroring.test.ts +114 -0
- package/src/__tests__/unit/agent.test.ts +169 -0
- package/src/__tests__/unit/cache-key.test.ts +182 -0
- package/src/__tests__/unit/cache.test.ts +172 -0
- package/src/__tests__/unit/context.test.ts +138 -0
- package/src/__tests__/unit/decorators.test.ts +100 -0
- package/src/__tests__/unit/introspection-tools.test.ts +277 -0
- package/src/__tests__/unit/prompt.test.ts +135 -0
- package/src/__tests__/unit/reflection.test.ts +210 -0
- package/src/__tests__/unit/tree-debugger.test.ts +85 -0
- package/src/__tests__/unit/workflow.test.ts +81 -0
- package/src/cache/cache-key.ts +244 -0
- package/src/cache/cache.ts +236 -0
- package/src/cache/index.ts +8 -0
- package/src/core/agent.ts +573 -0
- package/src/core/context.ts +119 -0
- package/src/core/event-tree.ts +260 -0
- package/src/core/factory.ts +123 -0
- package/src/core/index.ts +17 -0
- package/src/core/logger.ts +87 -0
- package/src/core/mcp-handler.ts +184 -0
- package/src/core/prompt.ts +150 -0
- package/src/core/workflow-context.ts +349 -0
- package/src/core/workflow.ts +302 -0
- package/src/debugger/index.ts +1 -0
- package/src/debugger/tree-debugger.ts +210 -0
- package/src/decorators/index.ts +3 -0
- package/src/decorators/observed-state.ts +95 -0
- package/src/decorators/step.ts +139 -0
- package/src/decorators/task.ts +96 -0
- package/src/examples/index.ts +2 -0
- package/src/examples/tdd-orchestrator.ts +65 -0
- package/src/examples/test-cycle-workflow.ts +64 -0
- package/src/index.ts +140 -0
- package/src/reflection/index.ts +5 -0
- package/src/reflection/reflection.ts +407 -0
- package/src/tools/index.ts +36 -0
- package/src/tools/introspection.ts +464 -0
- package/src/types/agent.ts +90 -0
- package/src/types/decorators.ts +25 -0
- package/src/types/error-strategy.ts +13 -0
- package/src/types/error.ts +20 -0
- package/src/types/events.ts +74 -0
- package/src/types/index.ts +55 -0
- package/src/types/logging.ts +24 -0
- package/src/types/observer.ts +18 -0
- package/src/types/prompt.ts +40 -0
- package/src/types/reflection.ts +117 -0
- package/src/types/sdk-primitives.ts +128 -0
- package/src/types/snapshot.ts +14 -0
- package/src/types/workflow-context.ts +163 -0
- package/src/types/workflow.ts +37 -0
- package/src/utils/id.ts +11 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/observable.ts +77 -0
- package/tasks.json +0 -0
- package/tsconfig.json +22 -0
- package/vitest.config.ts +16 -0
|
@@ -0,0 +1,667 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example 8: SDK Features Integration
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates:
|
|
5
|
+
* - Custom tool definitions with handlers
|
|
6
|
+
* - MCP server configuration (inprocess)
|
|
7
|
+
* - Pre/Post tool hooks for logging and validation
|
|
8
|
+
* - Skills integration with system prompt content
|
|
9
|
+
* - Environment variable pass-through
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import {
|
|
14
|
+
Workflow,
|
|
15
|
+
Step,
|
|
16
|
+
ObservedState,
|
|
17
|
+
WorkflowTreeDebugger,
|
|
18
|
+
MCPHandler,
|
|
19
|
+
} from 'groundswell';
|
|
20
|
+
import type {
|
|
21
|
+
Tool,
|
|
22
|
+
AgentHooks,
|
|
23
|
+
PreToolUseContext,
|
|
24
|
+
PostToolUseContext,
|
|
25
|
+
SessionStartContext,
|
|
26
|
+
SessionEndContext,
|
|
27
|
+
} from 'groundswell';
|
|
28
|
+
import { printHeader, printSection, sleep } from '../utils/helpers.js';
|
|
29
|
+
|
|
30
|
+
// ============================================================================
|
|
31
|
+
// Custom Tool Definitions
|
|
32
|
+
// ============================================================================
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Calculator tool - performs basic arithmetic
|
|
36
|
+
*/
|
|
37
|
+
const calculatorTool: Tool = {
|
|
38
|
+
name: 'calculate',
|
|
39
|
+
description: 'Performs basic arithmetic operations (add, subtract, multiply, divide)',
|
|
40
|
+
input_schema: {
|
|
41
|
+
type: 'object' as const,
|
|
42
|
+
properties: {
|
|
43
|
+
operation: {
|
|
44
|
+
type: 'string',
|
|
45
|
+
enum: ['add', 'subtract', 'multiply', 'divide'],
|
|
46
|
+
description: 'The arithmetic operation to perform',
|
|
47
|
+
},
|
|
48
|
+
a: {
|
|
49
|
+
type: 'number',
|
|
50
|
+
description: 'The first operand',
|
|
51
|
+
},
|
|
52
|
+
b: {
|
|
53
|
+
type: 'number',
|
|
54
|
+
description: 'The second operand',
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
required: ['operation', 'a', 'b'],
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Weather tool - simulates weather lookup
|
|
63
|
+
*/
|
|
64
|
+
const weatherTool: Tool = {
|
|
65
|
+
name: 'get_weather',
|
|
66
|
+
description: 'Gets current weather for a location',
|
|
67
|
+
input_schema: {
|
|
68
|
+
type: 'object' as const,
|
|
69
|
+
properties: {
|
|
70
|
+
location: {
|
|
71
|
+
type: 'string',
|
|
72
|
+
description: 'City name or location',
|
|
73
|
+
},
|
|
74
|
+
units: {
|
|
75
|
+
type: 'string',
|
|
76
|
+
enum: ['celsius', 'fahrenheit'],
|
|
77
|
+
description: 'Temperature units',
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
required: ['location'],
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Database tool - simulates database queries
|
|
86
|
+
*/
|
|
87
|
+
const databaseTool: Tool = {
|
|
88
|
+
name: 'query_database',
|
|
89
|
+
description: 'Executes a database query and returns results',
|
|
90
|
+
input_schema: {
|
|
91
|
+
type: 'object' as const,
|
|
92
|
+
properties: {
|
|
93
|
+
table: {
|
|
94
|
+
type: 'string',
|
|
95
|
+
description: 'Table name to query',
|
|
96
|
+
},
|
|
97
|
+
filter: {
|
|
98
|
+
type: 'object',
|
|
99
|
+
description: 'Filter conditions',
|
|
100
|
+
},
|
|
101
|
+
limit: {
|
|
102
|
+
type: 'number',
|
|
103
|
+
description: 'Maximum results to return',
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
required: ['table'],
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// ============================================================================
|
|
111
|
+
// Tool Handlers
|
|
112
|
+
// ============================================================================
|
|
113
|
+
|
|
114
|
+
interface CalculateInput {
|
|
115
|
+
operation: 'add' | 'subtract' | 'multiply' | 'divide';
|
|
116
|
+
a: number;
|
|
117
|
+
b: number;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
interface WeatherInput {
|
|
121
|
+
location: string;
|
|
122
|
+
units?: 'celsius' | 'fahrenheit';
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
interface DatabaseInput {
|
|
126
|
+
table: string;
|
|
127
|
+
filter?: Record<string, unknown>;
|
|
128
|
+
limit?: number;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Handle calculator operations
|
|
133
|
+
*/
|
|
134
|
+
async function handleCalculate(input: CalculateInput): Promise<{ result: number; expression: string }> {
|
|
135
|
+
await sleep(50); // Simulate processing time
|
|
136
|
+
|
|
137
|
+
let result: number;
|
|
138
|
+
let expression: string;
|
|
139
|
+
|
|
140
|
+
switch (input.operation) {
|
|
141
|
+
case 'add':
|
|
142
|
+
result = input.a + input.b;
|
|
143
|
+
expression = `${input.a} + ${input.b} = ${result}`;
|
|
144
|
+
break;
|
|
145
|
+
case 'subtract':
|
|
146
|
+
result = input.a - input.b;
|
|
147
|
+
expression = `${input.a} - ${input.b} = ${result}`;
|
|
148
|
+
break;
|
|
149
|
+
case 'multiply':
|
|
150
|
+
result = input.a * input.b;
|
|
151
|
+
expression = `${input.a} × ${input.b} = ${result}`;
|
|
152
|
+
break;
|
|
153
|
+
case 'divide':
|
|
154
|
+
if (input.b === 0) throw new Error('Division by zero');
|
|
155
|
+
result = input.a / input.b;
|
|
156
|
+
expression = `${input.a} ÷ ${input.b} = ${result}`;
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return { result, expression };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Handle weather lookup (simulated)
|
|
165
|
+
*/
|
|
166
|
+
async function handleWeather(input: WeatherInput): Promise<{
|
|
167
|
+
location: string;
|
|
168
|
+
temperature: number;
|
|
169
|
+
units: string;
|
|
170
|
+
conditions: string;
|
|
171
|
+
}> {
|
|
172
|
+
await sleep(100); // Simulate API call
|
|
173
|
+
|
|
174
|
+
const weatherData: Record<string, { temp: number; conditions: string }> = {
|
|
175
|
+
'new york': { temp: 72, conditions: 'Partly cloudy' },
|
|
176
|
+
london: { temp: 58, conditions: 'Rainy' },
|
|
177
|
+
tokyo: { temp: 85, conditions: 'Sunny' },
|
|
178
|
+
sydney: { temp: 68, conditions: 'Clear' },
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
const locationKey = input.location.toLowerCase();
|
|
182
|
+
const data = weatherData[locationKey] ?? { temp: 70, conditions: 'Unknown' };
|
|
183
|
+
|
|
184
|
+
const temp =
|
|
185
|
+
input.units === 'celsius' ? Math.round((data.temp - 32) * (5 / 9)) : data.temp;
|
|
186
|
+
|
|
187
|
+
return {
|
|
188
|
+
location: input.location,
|
|
189
|
+
temperature: temp,
|
|
190
|
+
units: input.units ?? 'fahrenheit',
|
|
191
|
+
conditions: data.conditions,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Handle database queries (simulated)
|
|
197
|
+
*/
|
|
198
|
+
async function handleDatabase(input: DatabaseInput): Promise<{
|
|
199
|
+
table: string;
|
|
200
|
+
rowCount: number;
|
|
201
|
+
results: Array<Record<string, unknown>>;
|
|
202
|
+
}> {
|
|
203
|
+
await sleep(75); // Simulate query time
|
|
204
|
+
|
|
205
|
+
const mockData: Record<string, Array<Record<string, unknown>>> = {
|
|
206
|
+
users: [
|
|
207
|
+
{ id: 1, name: 'Alice', role: 'admin' },
|
|
208
|
+
{ id: 2, name: 'Bob', role: 'user' },
|
|
209
|
+
{ id: 3, name: 'Charlie', role: 'user' },
|
|
210
|
+
],
|
|
211
|
+
products: [
|
|
212
|
+
{ id: 1, name: 'Widget', price: 9.99 },
|
|
213
|
+
{ id: 2, name: 'Gadget', price: 19.99 },
|
|
214
|
+
],
|
|
215
|
+
orders: [
|
|
216
|
+
{ id: 1, userId: 1, total: 29.98 },
|
|
217
|
+
{ id: 2, userId: 2, total: 9.99 },
|
|
218
|
+
],
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
const tableData = mockData[input.table] ?? [];
|
|
222
|
+
const limit = input.limit ?? tableData.length;
|
|
223
|
+
const results = tableData.slice(0, limit);
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
table: input.table,
|
|
227
|
+
rowCount: results.length,
|
|
228
|
+
results,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ============================================================================
|
|
233
|
+
// Lifecycle Hooks
|
|
234
|
+
// ============================================================================
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Create comprehensive agent hooks for logging and validation
|
|
238
|
+
*/
|
|
239
|
+
function createLoggingHooks(): AgentHooks {
|
|
240
|
+
const hookLogs: string[] = [];
|
|
241
|
+
|
|
242
|
+
return {
|
|
243
|
+
preToolUse: [
|
|
244
|
+
async (ctx: PreToolUseContext): Promise<void> => {
|
|
245
|
+
const log = `[PRE] Tool: ${ctx.toolName}, Input: ${JSON.stringify(ctx.toolInput)}`;
|
|
246
|
+
hookLogs.push(log);
|
|
247
|
+
console.log(` ${log}`);
|
|
248
|
+
},
|
|
249
|
+
async (ctx: PreToolUseContext): Promise<void> => {
|
|
250
|
+
// Validation hook - could block execution if needed
|
|
251
|
+
if (ctx.toolName === 'calculate') {
|
|
252
|
+
const input = ctx.toolInput as CalculateInput;
|
|
253
|
+
if (input.operation === 'divide' && input.b === 0) {
|
|
254
|
+
console.log(' [PRE] WARNING: Division by zero detected');
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
],
|
|
259
|
+
postToolUse: [
|
|
260
|
+
async (ctx: PostToolUseContext): Promise<void> => {
|
|
261
|
+
const log = `[POST] Tool: ${ctx.toolName}, Duration: ${ctx.duration}ms`;
|
|
262
|
+
hookLogs.push(log);
|
|
263
|
+
console.log(` ${log}`);
|
|
264
|
+
},
|
|
265
|
+
async (ctx: PostToolUseContext): Promise<void> => {
|
|
266
|
+
// Metrics collection hook
|
|
267
|
+
const output = ctx.toolOutput as Record<string, unknown>;
|
|
268
|
+
if (output.result !== undefined) {
|
|
269
|
+
console.log(` [POST] Result: ${output.result}`);
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
sessionStart: [
|
|
274
|
+
async (ctx: SessionStartContext): Promise<void> => {
|
|
275
|
+
console.log(` [SESSION] Started: Agent ${ctx.agentName} (${ctx.agentId})`);
|
|
276
|
+
hookLogs.push(`Session started: ${ctx.agentName}`);
|
|
277
|
+
},
|
|
278
|
+
],
|
|
279
|
+
sessionEnd: [
|
|
280
|
+
async (ctx: SessionEndContext): Promise<void> => {
|
|
281
|
+
console.log(` [SESSION] Ended: Agent ${ctx.agentName}, Duration: ${ctx.totalDuration}ms`);
|
|
282
|
+
hookLogs.push(`Session ended: ${ctx.agentName} (${ctx.totalDuration}ms)`);
|
|
283
|
+
},
|
|
284
|
+
],
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// ============================================================================
|
|
289
|
+
// Workflow Definitions
|
|
290
|
+
// ============================================================================
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Tool demonstration workflow
|
|
294
|
+
*/
|
|
295
|
+
class ToolDemoWorkflow extends Workflow {
|
|
296
|
+
@ObservedState()
|
|
297
|
+
toolCalls: Array<{ tool: string; input: unknown; result: unknown }> = [];
|
|
298
|
+
|
|
299
|
+
private mcpHandler: MCPHandler;
|
|
300
|
+
|
|
301
|
+
constructor(name: string) {
|
|
302
|
+
super(name);
|
|
303
|
+
this.mcpHandler = new MCPHandler();
|
|
304
|
+
|
|
305
|
+
// Register MCP server with tools (inprocess transport)
|
|
306
|
+
this.mcpHandler.registerServer({
|
|
307
|
+
name: 'demo',
|
|
308
|
+
transport: 'inprocess',
|
|
309
|
+
tools: [calculatorTool, weatherTool, databaseTool],
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
// Register tool executors
|
|
313
|
+
this.mcpHandler.registerToolExecutor('demo', 'calculate', (input) =>
|
|
314
|
+
handleCalculate(input as CalculateInput)
|
|
315
|
+
);
|
|
316
|
+
this.mcpHandler.registerToolExecutor('demo', 'get_weather', (input) =>
|
|
317
|
+
handleWeather(input as WeatherInput)
|
|
318
|
+
);
|
|
319
|
+
this.mcpHandler.registerToolExecutor('demo', 'query_database', (input) =>
|
|
320
|
+
handleDatabase(input as DatabaseInput)
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
@Step({ trackTiming: true })
|
|
325
|
+
async callTool(toolName: string, input: unknown): Promise<unknown> {
|
|
326
|
+
this.logger.info(`Calling tool: ${toolName}`);
|
|
327
|
+
|
|
328
|
+
// Use full tool name: serverName__toolName
|
|
329
|
+
const fullName = `demo__${toolName}`;
|
|
330
|
+
const result = await this.mcpHandler.executeTool(fullName, input);
|
|
331
|
+
|
|
332
|
+
this.toolCalls.push({ tool: toolName, input, result: result.content });
|
|
333
|
+
return result.content;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
async run(): Promise<void> {
|
|
337
|
+
this.setStatus('running');
|
|
338
|
+
this.logger.info('Starting tool demonstration');
|
|
339
|
+
|
|
340
|
+
// Demonstrate calculator tool
|
|
341
|
+
await this.callTool('calculate', { operation: 'add', a: 10, b: 5 });
|
|
342
|
+
await this.callTool('calculate', { operation: 'multiply', a: 7, b: 8 });
|
|
343
|
+
|
|
344
|
+
// Demonstrate weather tool
|
|
345
|
+
await this.callTool('get_weather', { location: 'Tokyo', units: 'celsius' });
|
|
346
|
+
await this.callTool('get_weather', { location: 'London' });
|
|
347
|
+
|
|
348
|
+
// Demonstrate database tool
|
|
349
|
+
await this.callTool('query_database', { table: 'users', limit: 2 });
|
|
350
|
+
await this.callTool('query_database', { table: 'products' });
|
|
351
|
+
|
|
352
|
+
this.logger.info(`Total tool calls: ${this.toolCalls.length}`);
|
|
353
|
+
this.setStatus('completed');
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Hook demonstration workflow
|
|
359
|
+
*/
|
|
360
|
+
class HookDemoWorkflow extends Workflow {
|
|
361
|
+
@ObservedState()
|
|
362
|
+
hookEvents: string[] = [];
|
|
363
|
+
|
|
364
|
+
private mcpHandler: MCPHandler;
|
|
365
|
+
|
|
366
|
+
constructor(name: string) {
|
|
367
|
+
super(name);
|
|
368
|
+
this.mcpHandler = new MCPHandler();
|
|
369
|
+
|
|
370
|
+
// Register MCP server with calculator tool
|
|
371
|
+
this.mcpHandler.registerServer({
|
|
372
|
+
name: 'calc',
|
|
373
|
+
transport: 'inprocess',
|
|
374
|
+
tools: [calculatorTool],
|
|
375
|
+
});
|
|
376
|
+
this.mcpHandler.registerToolExecutor('calc', 'calculate', (input) =>
|
|
377
|
+
handleCalculate(input as CalculateInput)
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
@Step({ trackTiming: true, logStart: true, logFinish: true })
|
|
382
|
+
async executeWithHooks(): Promise<void> {
|
|
383
|
+
// Simulate hook execution flow
|
|
384
|
+
this.hookEvents.push('preToolUse: calculate');
|
|
385
|
+
const result = await handleCalculate({ operation: 'add', a: 100, b: 200 });
|
|
386
|
+
this.hookEvents.push(`postToolUse: calculate (result=${result.result})`);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
async run(): Promise<void> {
|
|
390
|
+
this.setStatus('running');
|
|
391
|
+
this.logger.info('Demonstrating lifecycle hooks');
|
|
392
|
+
|
|
393
|
+
this.hookEvents.push('sessionStart');
|
|
394
|
+
await this.executeWithHooks();
|
|
395
|
+
this.hookEvents.push('sessionEnd');
|
|
396
|
+
|
|
397
|
+
this.logger.info(`Hook events: ${this.hookEvents.length}`);
|
|
398
|
+
this.setStatus('completed');
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Skills demonstration workflow
|
|
404
|
+
*/
|
|
405
|
+
class SkillsDemoWorkflow extends Workflow {
|
|
406
|
+
@ObservedState()
|
|
407
|
+
skillContent: string = '';
|
|
408
|
+
|
|
409
|
+
@ObservedState()
|
|
410
|
+
systemPrompt: string = '';
|
|
411
|
+
|
|
412
|
+
constructor(name: string) {
|
|
413
|
+
super(name);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
@Step({ snapshotState: true })
|
|
417
|
+
async loadSkill(): Promise<void> {
|
|
418
|
+
// Simulate loading skill content from SKILL.md
|
|
419
|
+
this.skillContent = `
|
|
420
|
+
# Math Expert Skill
|
|
421
|
+
|
|
422
|
+
You are an expert mathematician. You can:
|
|
423
|
+
- Perform complex calculations
|
|
424
|
+
- Explain mathematical concepts
|
|
425
|
+
- Solve equations step by step
|
|
426
|
+
|
|
427
|
+
## Usage
|
|
428
|
+
Ask me any math question and I'll provide a detailed solution.
|
|
429
|
+
`.trim();
|
|
430
|
+
|
|
431
|
+
this.logger.info('Loaded skill: Math Expert');
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
@Step({ snapshotState: true })
|
|
435
|
+
async buildSystemPrompt(): Promise<void> {
|
|
436
|
+
const baseSystem = 'You are a helpful assistant.';
|
|
437
|
+
|
|
438
|
+
// Skills inject content into system prompt
|
|
439
|
+
this.systemPrompt = `${baseSystem}
|
|
440
|
+
|
|
441
|
+
## Available Skills
|
|
442
|
+
|
|
443
|
+
${this.skillContent}
|
|
444
|
+
|
|
445
|
+
## Instructions
|
|
446
|
+
Use the loaded skills to assist the user with their requests.`;
|
|
447
|
+
|
|
448
|
+
this.logger.info('Built system prompt with skill content');
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
async run(): Promise<string> {
|
|
452
|
+
this.setStatus('running');
|
|
453
|
+
this.logger.info('Demonstrating skills integration');
|
|
454
|
+
|
|
455
|
+
await this.loadSkill();
|
|
456
|
+
await this.buildSystemPrompt();
|
|
457
|
+
|
|
458
|
+
this.logger.info(`System prompt length: ${this.systemPrompt.length} chars`);
|
|
459
|
+
this.setStatus('completed');
|
|
460
|
+
|
|
461
|
+
return this.systemPrompt;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Environment variables demonstration workflow
|
|
467
|
+
*/
|
|
468
|
+
class EnvVarsDemoWorkflow extends Workflow {
|
|
469
|
+
@ObservedState()
|
|
470
|
+
capturedEnvVars: Record<string, string> = {};
|
|
471
|
+
|
|
472
|
+
@ObservedState({ redact: true })
|
|
473
|
+
sensitiveVars: Record<string, string> = {};
|
|
474
|
+
|
|
475
|
+
constructor(name: string) {
|
|
476
|
+
super(name);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
@Step({ snapshotState: true })
|
|
480
|
+
async captureEnvironment(): Promise<void> {
|
|
481
|
+
// Capture non-sensitive environment info
|
|
482
|
+
this.capturedEnvVars = {
|
|
483
|
+
NODE_ENV: process.env.NODE_ENV ?? 'development',
|
|
484
|
+
PWD: process.env.PWD ?? '(unknown)',
|
|
485
|
+
SHELL: process.env.SHELL ?? '(unknown)',
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
// Simulate sensitive vars (would be passed to agent)
|
|
489
|
+
this.sensitiveVars = {
|
|
490
|
+
API_KEY: 'demo-key-12345',
|
|
491
|
+
DATABASE_URL: 'postgres://localhost:5432/demo',
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
this.logger.info('Captured environment variables');
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
@Step()
|
|
498
|
+
async demonstratePassThrough(): Promise<void> {
|
|
499
|
+
// In real usage, env vars are passed through to agent execution
|
|
500
|
+
this.logger.info('Environment vars would be set during agent execution');
|
|
501
|
+
this.logger.info(`Non-sensitive vars: ${Object.keys(this.capturedEnvVars).join(', ')}`);
|
|
502
|
+
this.logger.info(`Sensitive vars (redacted): ${Object.keys(this.sensitiveVars).length} vars`);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
async run(): Promise<void> {
|
|
506
|
+
this.setStatus('running');
|
|
507
|
+
this.logger.info('Demonstrating environment variable handling');
|
|
508
|
+
|
|
509
|
+
await this.captureEnvironment();
|
|
510
|
+
await this.demonstratePassThrough();
|
|
511
|
+
|
|
512
|
+
this.setStatus('completed');
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// ============================================================================
|
|
517
|
+
// Main Example Runner
|
|
518
|
+
// ============================================================================
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Run the SDK Features example
|
|
522
|
+
*/
|
|
523
|
+
export async function runSDKFeaturesExample(): Promise<void> {
|
|
524
|
+
printHeader('Example 8: SDK Features Integration');
|
|
525
|
+
|
|
526
|
+
// Part 1: Custom Tool Definitions
|
|
527
|
+
printSection('Part 1: Custom Tool Definitions & Handlers');
|
|
528
|
+
{
|
|
529
|
+
const workflow = new ToolDemoWorkflow('ToolDemo');
|
|
530
|
+
const debugger_ = new WorkflowTreeDebugger(workflow);
|
|
531
|
+
|
|
532
|
+
console.log('Registered tools:');
|
|
533
|
+
console.log(' - calculate: Basic arithmetic operations');
|
|
534
|
+
console.log(' - get_weather: Weather lookup (simulated)');
|
|
535
|
+
console.log(' - query_database: Database queries (simulated)\n');
|
|
536
|
+
|
|
537
|
+
await workflow.run();
|
|
538
|
+
|
|
539
|
+
console.log('\nTool call results:');
|
|
540
|
+
for (const call of workflow.toolCalls) {
|
|
541
|
+
console.log(` ${call.tool}: ${JSON.stringify(call.result)}`);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
console.log('\nTree:');
|
|
545
|
+
console.log(debugger_.toTreeString());
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// Part 2: MCP Server Integration
|
|
549
|
+
printSection('Part 2: MCP Handler / In-Process Server');
|
|
550
|
+
{
|
|
551
|
+
console.log('MCP Handler features:');
|
|
552
|
+
console.log(' - Register servers with tools (registerServer)');
|
|
553
|
+
console.log(' - Register executors for inprocess tools (registerToolExecutor)');
|
|
554
|
+
console.log(' - Execute tools by full name: serverName__toolName');
|
|
555
|
+
console.log(' - Return structured ToolResult objects');
|
|
556
|
+
console.log(' - Error handling with is_error flag\n');
|
|
557
|
+
|
|
558
|
+
const mcpHandler = new MCPHandler();
|
|
559
|
+
|
|
560
|
+
// Register server with tool
|
|
561
|
+
const demoTool: Tool = {
|
|
562
|
+
name: 'demo_tool',
|
|
563
|
+
description: 'A demonstration tool',
|
|
564
|
+
input_schema: {
|
|
565
|
+
type: 'object' as const,
|
|
566
|
+
properties: { test: { type: 'string' } },
|
|
567
|
+
required: [],
|
|
568
|
+
},
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
mcpHandler.registerServer({
|
|
572
|
+
name: 'demo',
|
|
573
|
+
transport: 'inprocess',
|
|
574
|
+
tools: [demoTool],
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
mcpHandler.registerToolExecutor('demo', 'demo_tool', async (input: unknown) => ({
|
|
578
|
+
status: 'success',
|
|
579
|
+
input,
|
|
580
|
+
}));
|
|
581
|
+
|
|
582
|
+
const tools = mcpHandler.getTools();
|
|
583
|
+
console.log(`Registered tools count: ${tools.length}`);
|
|
584
|
+
|
|
585
|
+
// Execute using full name: serverName__toolName
|
|
586
|
+
const result = await mcpHandler.executeTool('demo__demo_tool', { test: 'data' });
|
|
587
|
+
console.log(`Execution result: ${JSON.stringify(result)}`);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// Part 3: Lifecycle Hooks
|
|
591
|
+
printSection('Part 3: Lifecycle Hooks (Pre/Post Tool, Session)');
|
|
592
|
+
{
|
|
593
|
+
console.log('Hook types demonstrated:');
|
|
594
|
+
console.log(' - preToolUse: Log input, validate parameters');
|
|
595
|
+
console.log(' - postToolUse: Log duration, collect metrics');
|
|
596
|
+
console.log(' - sessionStart: Initialize session context');
|
|
597
|
+
console.log(' - sessionEnd: Cleanup, final metrics\n');
|
|
598
|
+
|
|
599
|
+
const workflow = new HookDemoWorkflow('HookDemo');
|
|
600
|
+
const debugger_ = new WorkflowTreeDebugger(workflow);
|
|
601
|
+
|
|
602
|
+
await workflow.run();
|
|
603
|
+
|
|
604
|
+
console.log('\nHook events captured:');
|
|
605
|
+
for (const event of workflow.hookEvents) {
|
|
606
|
+
console.log(` → ${event}`);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
console.log('\nTree:');
|
|
610
|
+
console.log(debugger_.toTreeString());
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// Part 4: Skills Integration
|
|
614
|
+
printSection('Part 4: Skills Integration');
|
|
615
|
+
{
|
|
616
|
+
console.log('Skills system:');
|
|
617
|
+
console.log(' - Load SKILL.md content from skill directories');
|
|
618
|
+
console.log(' - Inject skill content into system prompt');
|
|
619
|
+
console.log(' - Multiple skills can be combined\n');
|
|
620
|
+
|
|
621
|
+
const workflow = new SkillsDemoWorkflow('SkillsDemo');
|
|
622
|
+
const debugger_ = new WorkflowTreeDebugger(workflow);
|
|
623
|
+
|
|
624
|
+
const systemPrompt = await workflow.run();
|
|
625
|
+
|
|
626
|
+
console.log('Generated system prompt preview:');
|
|
627
|
+
console.log('─'.repeat(50));
|
|
628
|
+
console.log(systemPrompt.slice(0, 300) + '...');
|
|
629
|
+
console.log('─'.repeat(50));
|
|
630
|
+
|
|
631
|
+
console.log('\nTree:');
|
|
632
|
+
console.log(debugger_.toTreeString());
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// Part 5: Environment Variables
|
|
636
|
+
printSection('Part 5: Environment Variable Pass-Through');
|
|
637
|
+
{
|
|
638
|
+
console.log('Environment handling:');
|
|
639
|
+
console.log(' - Pass env vars to agent execution context');
|
|
640
|
+
console.log(' - Sensitive vars marked with @ObservedState({ redact: true })');
|
|
641
|
+
console.log(' - Vars restored after execution\n');
|
|
642
|
+
|
|
643
|
+
const workflow = new EnvVarsDemoWorkflow('EnvVarsDemo');
|
|
644
|
+
const debugger_ = new WorkflowTreeDebugger(workflow);
|
|
645
|
+
|
|
646
|
+
await workflow.run();
|
|
647
|
+
|
|
648
|
+
console.log('\nCaptured environment:');
|
|
649
|
+
for (const [key, value] of Object.entries(workflow.capturedEnvVars)) {
|
|
650
|
+
console.log(` ${key}: ${value}`);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// Get state snapshot to show redaction
|
|
654
|
+
const logs = debugger_.getAllLogs();
|
|
655
|
+
console.log(`\nLog entries: ${logs.length}`);
|
|
656
|
+
|
|
657
|
+
console.log('\nTree:');
|
|
658
|
+
console.log(debugger_.toTreeString());
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
console.log('\n=== Example 8 Complete ===');
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// Allow direct execution
|
|
665
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
666
|
+
runSDKFeaturesExample().catch(console.error);
|
|
667
|
+
}
|