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,244 @@
|
|
|
1
|
+
# Groundswell Workflow Engine - Examples
|
|
2
|
+
|
|
3
|
+
Comprehensive examples showcasing all features and configuration options of the Groundswell hierarchical workflow engine.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Install dependencies
|
|
9
|
+
npm install
|
|
10
|
+
|
|
11
|
+
# Build the project
|
|
12
|
+
npm run build
|
|
13
|
+
|
|
14
|
+
# Run all examples
|
|
15
|
+
npm run start:all
|
|
16
|
+
|
|
17
|
+
# Or run individual examples
|
|
18
|
+
npm run start:basic
|
|
19
|
+
npm run start:decorators
|
|
20
|
+
npm run start:parent-child
|
|
21
|
+
npm run start:observers
|
|
22
|
+
npm run start:errors
|
|
23
|
+
npm run start:concurrent
|
|
24
|
+
npm run start:agent-loops
|
|
25
|
+
npm run start:sdk-features
|
|
26
|
+
npm run start:reflection
|
|
27
|
+
npm run start:introspection
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Examples Overview
|
|
31
|
+
|
|
32
|
+
### 1. Basic Workflow (`01-basic-workflow.ts`)
|
|
33
|
+
|
|
34
|
+
Core workflow concepts:
|
|
35
|
+
- Creating workflows by extending `Workflow` base class
|
|
36
|
+
- Using `WorkflowLogger` for structured logging
|
|
37
|
+
- Managing workflow status (`idle` → `running` → `completed`/`failed`)
|
|
38
|
+
- Using `WorkflowTreeDebugger` for visualization
|
|
39
|
+
|
|
40
|
+
### 2. Decorator Options (`02-decorator-options.ts`)
|
|
41
|
+
|
|
42
|
+
All decorator configuration options:
|
|
43
|
+
|
|
44
|
+
**@Step options:**
|
|
45
|
+
- `name` - Custom step name (defaults to method name)
|
|
46
|
+
- `snapshotState` - Capture state after step completion
|
|
47
|
+
- `trackTiming` - Track and emit step duration
|
|
48
|
+
- `logStart` - Log message at step start
|
|
49
|
+
- `logFinish` - Log message at step end
|
|
50
|
+
|
|
51
|
+
**@Task options:**
|
|
52
|
+
- `name` - Custom task name
|
|
53
|
+
- `concurrent` - Run returned workflows concurrently
|
|
54
|
+
|
|
55
|
+
**@ObservedState options:**
|
|
56
|
+
- `hidden` - Exclude from state snapshots
|
|
57
|
+
- `redact` - Show as `***` in snapshots (for sensitive data)
|
|
58
|
+
|
|
59
|
+
### 3. Parent-Child Workflows (`03-parent-child.ts`)
|
|
60
|
+
|
|
61
|
+
Hierarchical workflow structures:
|
|
62
|
+
- Multi-level workflow hierarchies
|
|
63
|
+
- Automatic parent-child attachment
|
|
64
|
+
- `@Task` decorator for spawning child workflows
|
|
65
|
+
- Event propagation from children to root
|
|
66
|
+
- Tree visualization of nested structures
|
|
67
|
+
|
|
68
|
+
### 4. Observers & Debugger (`04-observers-debugger.ts`)
|
|
69
|
+
|
|
70
|
+
Real-time monitoring and debugging:
|
|
71
|
+
- Implementing custom `WorkflowObserver`
|
|
72
|
+
- `MetricsObserver` for collecting statistics
|
|
73
|
+
- `ConsoleObserver` for real-time logging
|
|
74
|
+
- `Observable` event stream subscription
|
|
75
|
+
- `WorkflowTreeDebugger` complete API
|
|
76
|
+
|
|
77
|
+
### 5. Error Handling (`05-error-handling.ts`)
|
|
78
|
+
|
|
79
|
+
Error management patterns:
|
|
80
|
+
- `WorkflowError` structure with full context
|
|
81
|
+
- State snapshots preserved at error time
|
|
82
|
+
- Error events emitted to observers
|
|
83
|
+
- Retry patterns with backoff
|
|
84
|
+
- Error isolation in parent-child workflows
|
|
85
|
+
|
|
86
|
+
### 6. Concurrent Tasks (`06-concurrent-tasks.ts`)
|
|
87
|
+
|
|
88
|
+
Parallel execution patterns:
|
|
89
|
+
- Sequential vs concurrent comparison
|
|
90
|
+
- `@Task({ concurrent: true })` option
|
|
91
|
+
- Manual `Promise.all` patterns
|
|
92
|
+
- Fan-out / fan-in architecture
|
|
93
|
+
- Performance benchmarks
|
|
94
|
+
|
|
95
|
+
### 7. Agent Loops with Observability (`07-agent-loops.ts`)
|
|
96
|
+
|
|
97
|
+
Run: `npx tsx examples/examples/07-agent-loops.ts`
|
|
98
|
+
|
|
99
|
+
Agent.prompt() within workflow loops:
|
|
100
|
+
- Using Agent.prompt() within ctx.step() loops
|
|
101
|
+
- Multiple agents for different item types
|
|
102
|
+
- Full event tree visualization with timing
|
|
103
|
+
- State snapshots at each iteration
|
|
104
|
+
- Cache hit/miss tracking
|
|
105
|
+
|
|
106
|
+
### 8. SDK Features Integration (`08-sdk-features.ts`)
|
|
107
|
+
|
|
108
|
+
Run: `npx tsx examples/examples/08-sdk-features.ts`
|
|
109
|
+
|
|
110
|
+
Anthropic SDK integration:
|
|
111
|
+
- Custom tool definitions with handlers
|
|
112
|
+
- MCP server configuration (inprocess)
|
|
113
|
+
- Pre/Post tool hooks for logging and validation
|
|
114
|
+
- Skills integration with system prompt content
|
|
115
|
+
- Environment variable pass-through
|
|
116
|
+
|
|
117
|
+
### 9. Multi-level Reflection (`09-reflection.ts`)
|
|
118
|
+
|
|
119
|
+
Run: `npx tsx examples/examples/09-reflection.ts`
|
|
120
|
+
|
|
121
|
+
Reflection at all three levels:
|
|
122
|
+
- Prompt-level reflection (enableReflection on prompt)
|
|
123
|
+
- Agent-level reflection (agent.reflect() method)
|
|
124
|
+
- Workflow-level reflection (step failure retry)
|
|
125
|
+
- Reflection events in tree output
|
|
126
|
+
- Error recovery with revised prompts
|
|
127
|
+
|
|
128
|
+
### 10. Introspection Tools Demo (`10-introspection.ts`)
|
|
129
|
+
|
|
130
|
+
Run: `npx tsx examples/examples/10-introspection.ts`
|
|
131
|
+
|
|
132
|
+
Agent self-awareness and hierarchy navigation:
|
|
133
|
+
- inspect_current_node - "Where am I?"
|
|
134
|
+
- read_ancestor_chain - "What's above me?"
|
|
135
|
+
- list_siblings_children - "What's around me?"
|
|
136
|
+
- inspect_prior_outputs - "What happened before?"
|
|
137
|
+
- inspect_cache_status - "Is this cached?"
|
|
138
|
+
- request_spawn_workflow - "Can I create children?"
|
|
139
|
+
|
|
140
|
+
## Project Structure
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
examples/
|
|
144
|
+
├── examples/
|
|
145
|
+
│ ├── 01-basic-workflow.ts
|
|
146
|
+
│ ├── 02-decorator-options.ts
|
|
147
|
+
│ ├── 03-parent-child.ts
|
|
148
|
+
│ ├── 04-observers-debugger.ts
|
|
149
|
+
│ ├── 05-error-handling.ts
|
|
150
|
+
│ ├── 06-concurrent-tasks.ts
|
|
151
|
+
│ ├── 07-agent-loops.ts
|
|
152
|
+
│ ├── 08-sdk-features.ts
|
|
153
|
+
│ ├── 09-reflection.ts
|
|
154
|
+
│ └── 10-introspection.ts
|
|
155
|
+
├── utils/
|
|
156
|
+
│ └── helpers.ts
|
|
157
|
+
├── index.ts
|
|
158
|
+
└── README.md
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Key Concepts
|
|
162
|
+
|
|
163
|
+
### Workflow Status Lifecycle
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
idle → running → completed
|
|
167
|
+
↘ failed
|
|
168
|
+
↘ cancelled
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Event Types
|
|
172
|
+
|
|
173
|
+
| Event Type | Description |
|
|
174
|
+
|------------|-------------|
|
|
175
|
+
| `stepStart` | Step execution started |
|
|
176
|
+
| `stepEnd` | Step completed (includes duration) |
|
|
177
|
+
| `taskStart` | Task execution started |
|
|
178
|
+
| `taskEnd` | Task completed |
|
|
179
|
+
| `childAttached` | Child workflow attached to parent |
|
|
180
|
+
| `stateSnapshot` | State snapshot captured |
|
|
181
|
+
| `error` | Error occurred |
|
|
182
|
+
| `treeUpdated` | Tree structure changed |
|
|
183
|
+
|
|
184
|
+
### Tree Visualization Symbols
|
|
185
|
+
|
|
186
|
+
| Symbol | Status |
|
|
187
|
+
|--------|--------|
|
|
188
|
+
| ○ | idle |
|
|
189
|
+
| ◐ | running |
|
|
190
|
+
| ✓ | completed |
|
|
191
|
+
| ✗ | failed |
|
|
192
|
+
| ⊘ | cancelled |
|
|
193
|
+
|
|
194
|
+
## Usage Patterns
|
|
195
|
+
|
|
196
|
+
### Basic Workflow
|
|
197
|
+
```typescript
|
|
198
|
+
class MyWorkflow extends Workflow {
|
|
199
|
+
async run(): Promise<void> {
|
|
200
|
+
this.setStatus('running');
|
|
201
|
+
this.logger.info('Starting workflow');
|
|
202
|
+
// ... workflow logic
|
|
203
|
+
this.setStatus('completed');
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Step with All Options
|
|
209
|
+
```typescript
|
|
210
|
+
@Step({
|
|
211
|
+
name: 'CustomStepName',
|
|
212
|
+
snapshotState: true,
|
|
213
|
+
trackTiming: true,
|
|
214
|
+
logStart: true,
|
|
215
|
+
logFinish: true,
|
|
216
|
+
})
|
|
217
|
+
async myStep(): Promise<void> {
|
|
218
|
+
// Step logic
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Observable State
|
|
223
|
+
```typescript
|
|
224
|
+
@ObservedState()
|
|
225
|
+
publicField: string = 'visible';
|
|
226
|
+
|
|
227
|
+
@ObservedState({ redact: true })
|
|
228
|
+
apiKey: string = 'secret';
|
|
229
|
+
|
|
230
|
+
@ObservedState({ hidden: true })
|
|
231
|
+
internalState: object = {};
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Concurrent Child Workflows
|
|
235
|
+
```typescript
|
|
236
|
+
@Task({ concurrent: true })
|
|
237
|
+
async createWorkers(): Promise<WorkerWorkflow[]> {
|
|
238
|
+
return items.map(item => new WorkerWorkflow(item, this));
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## License
|
|
243
|
+
|
|
244
|
+
MIT
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example 1: Basic Workflow
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates:
|
|
5
|
+
* - Creating a simple workflow by extending the Workflow base class
|
|
6
|
+
* - Using the logger for structured logging
|
|
7
|
+
* - Managing workflow status (idle -> running -> completed/failed)
|
|
8
|
+
* - Basic execution flow
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { Workflow, WorkflowTreeDebugger } from 'groundswell';
|
|
12
|
+
import { printHeader, printSection, sleep } from '../utils/helpers.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A simple data processing workflow
|
|
16
|
+
*/
|
|
17
|
+
class DataProcessingWorkflow extends Workflow {
|
|
18
|
+
private data: string[] = [];
|
|
19
|
+
|
|
20
|
+
async run(): Promise<string[]> {
|
|
21
|
+
this.setStatus('running');
|
|
22
|
+
this.logger.info('Starting data processing workflow');
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
// Step 1: Load data
|
|
26
|
+
this.logger.info('Loading data...');
|
|
27
|
+
await this.loadData();
|
|
28
|
+
|
|
29
|
+
// Step 2: Process data
|
|
30
|
+
this.logger.info('Processing data...');
|
|
31
|
+
await this.processData();
|
|
32
|
+
|
|
33
|
+
// Step 3: Save results
|
|
34
|
+
this.logger.info('Saving results...');
|
|
35
|
+
await this.saveResults();
|
|
36
|
+
|
|
37
|
+
this.setStatus('completed');
|
|
38
|
+
this.logger.info('Workflow completed successfully');
|
|
39
|
+
return this.data;
|
|
40
|
+
} catch (error) {
|
|
41
|
+
this.setStatus('failed');
|
|
42
|
+
this.logger.error('Workflow failed', { error });
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private async loadData(): Promise<void> {
|
|
48
|
+
await sleep(100);
|
|
49
|
+
this.data = ['item1', 'item2', 'item3'];
|
|
50
|
+
this.logger.debug('Loaded items', { count: this.data.length });
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private async processData(): Promise<void> {
|
|
54
|
+
await sleep(150);
|
|
55
|
+
this.data = this.data.map((item) => item.toUpperCase());
|
|
56
|
+
this.logger.debug('Processed items', { data: this.data });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private async saveResults(): Promise<void> {
|
|
60
|
+
await sleep(50);
|
|
61
|
+
this.logger.debug('Results saved');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Run the basic workflow example
|
|
67
|
+
*/
|
|
68
|
+
export async function runBasicWorkflowExample(): Promise<void> {
|
|
69
|
+
printHeader('Example 1: Basic Workflow');
|
|
70
|
+
|
|
71
|
+
// Create workflow with custom name
|
|
72
|
+
const workflow = new DataProcessingWorkflow('DataProcessor');
|
|
73
|
+
|
|
74
|
+
// Attach debugger to visualize
|
|
75
|
+
const debugger_ = new WorkflowTreeDebugger(workflow);
|
|
76
|
+
|
|
77
|
+
printSection('Initial State');
|
|
78
|
+
console.log('Workflow ID:', workflow.id);
|
|
79
|
+
console.log('Status:', workflow.status);
|
|
80
|
+
console.log('Tree:\n' + debugger_.toTreeString());
|
|
81
|
+
|
|
82
|
+
printSection('Running Workflow');
|
|
83
|
+
const result = await workflow.run();
|
|
84
|
+
|
|
85
|
+
printSection('Final State');
|
|
86
|
+
console.log('Status:', workflow.status);
|
|
87
|
+
console.log('Result:', result);
|
|
88
|
+
console.log('\nTree:\n' + debugger_.toTreeString());
|
|
89
|
+
|
|
90
|
+
printSection('Logs');
|
|
91
|
+
console.log(debugger_.toLogString());
|
|
92
|
+
|
|
93
|
+
printSection('Statistics');
|
|
94
|
+
console.log(debugger_.getStats());
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Run if executed directly
|
|
98
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
99
|
+
runBasicWorkflowExample().catch(console.error);
|
|
100
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example 2: Decorator Options
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates all decorator configuration options:
|
|
5
|
+
*
|
|
6
|
+
* @Step options:
|
|
7
|
+
* - name: Custom step name (defaults to method name)
|
|
8
|
+
* - snapshotState: Capture state snapshot after step completion
|
|
9
|
+
* - trackTiming: Track and emit step duration
|
|
10
|
+
* - logStart: Log message at step start
|
|
11
|
+
* - logFinish: Log message at step end
|
|
12
|
+
*
|
|
13
|
+
* @Task options:
|
|
14
|
+
* - name: Custom task name
|
|
15
|
+
* - concurrent: Run returned workflows concurrently
|
|
16
|
+
*
|
|
17
|
+
* @ObservedState options:
|
|
18
|
+
* - hidden: Field not included in snapshots
|
|
19
|
+
* - redact: Value shown as '***' in snapshots
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import {
|
|
23
|
+
Workflow,
|
|
24
|
+
Step,
|
|
25
|
+
Task,
|
|
26
|
+
ObservedState,
|
|
27
|
+
getObservedState,
|
|
28
|
+
WorkflowTreeDebugger,
|
|
29
|
+
WorkflowObserver,
|
|
30
|
+
WorkflowEvent,
|
|
31
|
+
LogEntry,
|
|
32
|
+
WorkflowNode,
|
|
33
|
+
} from 'groundswell';
|
|
34
|
+
import { printHeader, printSection, sleep } from '../utils/helpers.js';
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Workflow demonstrating all @Step decorator options
|
|
38
|
+
*/
|
|
39
|
+
class StepOptionsWorkflow extends Workflow {
|
|
40
|
+
@ObservedState()
|
|
41
|
+
currentPhase: string = 'init';
|
|
42
|
+
|
|
43
|
+
@ObservedState()
|
|
44
|
+
itemsProcessed: number = 0;
|
|
45
|
+
|
|
46
|
+
// Default step - minimal configuration
|
|
47
|
+
@Step()
|
|
48
|
+
async defaultStep(): Promise<void> {
|
|
49
|
+
this.currentPhase = 'default';
|
|
50
|
+
await sleep(50);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Step with custom name
|
|
54
|
+
@Step({ name: 'CustomNamedStep' })
|
|
55
|
+
async stepWithCustomName(): Promise<void> {
|
|
56
|
+
this.currentPhase = 'custom-named';
|
|
57
|
+
await sleep(50);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Step with state snapshot
|
|
61
|
+
@Step({ snapshotState: true })
|
|
62
|
+
async stepWithSnapshot(): Promise<void> {
|
|
63
|
+
this.currentPhase = 'snapshot';
|
|
64
|
+
this.itemsProcessed = 10;
|
|
65
|
+
await sleep(50);
|
|
66
|
+
// State will be captured after this step
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Step with timing tracking
|
|
70
|
+
@Step({ trackTiming: true })
|
|
71
|
+
async stepWithTiming(): Promise<void> {
|
|
72
|
+
this.currentPhase = 'timed';
|
|
73
|
+
await sleep(200); // Longer delay to show timing
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Step with start/finish logging
|
|
77
|
+
@Step({ logStart: true, logFinish: true })
|
|
78
|
+
async stepWithLogging(): Promise<void> {
|
|
79
|
+
this.currentPhase = 'logged';
|
|
80
|
+
this.logger.info('Inside the step - this is custom logging');
|
|
81
|
+
await sleep(50);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Step with ALL options enabled
|
|
85
|
+
@Step({
|
|
86
|
+
name: 'FullyConfiguredStep',
|
|
87
|
+
snapshotState: true,
|
|
88
|
+
trackTiming: true,
|
|
89
|
+
logStart: true,
|
|
90
|
+
logFinish: true,
|
|
91
|
+
})
|
|
92
|
+
async fullyConfiguredStep(): Promise<void> {
|
|
93
|
+
this.currentPhase = 'fully-configured';
|
|
94
|
+
this.itemsProcessed = 100;
|
|
95
|
+
await sleep(100);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async run(): Promise<void> {
|
|
99
|
+
this.setStatus('running');
|
|
100
|
+
|
|
101
|
+
await this.defaultStep();
|
|
102
|
+
await this.stepWithCustomName();
|
|
103
|
+
await this.stepWithSnapshot();
|
|
104
|
+
await this.stepWithTiming();
|
|
105
|
+
await this.stepWithLogging();
|
|
106
|
+
await this.fullyConfiguredStep();
|
|
107
|
+
|
|
108
|
+
this.setStatus('completed');
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Workflow demonstrating @ObservedState options
|
|
114
|
+
*/
|
|
115
|
+
class StateOptionsWorkflow extends Workflow {
|
|
116
|
+
// Regular observed state - included in snapshots
|
|
117
|
+
@ObservedState()
|
|
118
|
+
publicData: string = 'visible-value';
|
|
119
|
+
|
|
120
|
+
// Redacted state - shows as '***' in snapshots
|
|
121
|
+
@ObservedState({ redact: true })
|
|
122
|
+
apiKey: string = 'super-secret-api-key-12345';
|
|
123
|
+
|
|
124
|
+
// Another redacted field
|
|
125
|
+
@ObservedState({ redact: true })
|
|
126
|
+
password: string = 'my-password';
|
|
127
|
+
|
|
128
|
+
// Hidden state - completely excluded from snapshots
|
|
129
|
+
@ObservedState({ hidden: true })
|
|
130
|
+
internalCounter: number = 0;
|
|
131
|
+
|
|
132
|
+
// Another hidden field
|
|
133
|
+
@ObservedState({ hidden: true })
|
|
134
|
+
debugInfo: object = { internal: true };
|
|
135
|
+
|
|
136
|
+
// Multiple observed fields for demonstration
|
|
137
|
+
@ObservedState()
|
|
138
|
+
processingStatus: string = 'pending';
|
|
139
|
+
|
|
140
|
+
@ObservedState()
|
|
141
|
+
progress: number = 0;
|
|
142
|
+
|
|
143
|
+
async run(): Promise<void> {
|
|
144
|
+
this.setStatus('running');
|
|
145
|
+
this.processingStatus = 'processing';
|
|
146
|
+
this.progress = 50;
|
|
147
|
+
this.internalCounter = 999; // This won't appear in snapshots
|
|
148
|
+
await sleep(50);
|
|
149
|
+
this.processingStatus = 'done';
|
|
150
|
+
this.progress = 100;
|
|
151
|
+
this.setStatus('completed');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Run the decorator options example
|
|
157
|
+
*/
|
|
158
|
+
export async function runDecoratorOptionsExample(): Promise<void> {
|
|
159
|
+
printHeader('Example 2: Decorator Options');
|
|
160
|
+
|
|
161
|
+
// Part 1: @Step options
|
|
162
|
+
printSection('@Step Decorator Options');
|
|
163
|
+
|
|
164
|
+
const stepWorkflow = new StepOptionsWorkflow('StepOptions');
|
|
165
|
+
const events: WorkflowEvent[] = [];
|
|
166
|
+
|
|
167
|
+
// Custom observer to capture events
|
|
168
|
+
const observer: WorkflowObserver = {
|
|
169
|
+
onLog: (entry: LogEntry) => {
|
|
170
|
+
console.log(` [LOG] ${entry.level.toUpperCase()}: ${entry.message}`);
|
|
171
|
+
},
|
|
172
|
+
onEvent: (event: WorkflowEvent) => {
|
|
173
|
+
events.push(event);
|
|
174
|
+
if (event.type === 'stepStart') {
|
|
175
|
+
console.log(` [EVENT] Step started: ${event.step}`);
|
|
176
|
+
} else if (event.type === 'stepEnd') {
|
|
177
|
+
console.log(` [EVENT] Step ended: ${event.step} (${event.duration}ms)`);
|
|
178
|
+
} else if (event.type === 'stateSnapshot') {
|
|
179
|
+
console.log(` [EVENT] State snapshot captured`);
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
onStateUpdated: () => {},
|
|
183
|
+
onTreeChanged: () => {},
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
stepWorkflow.addObserver(observer);
|
|
187
|
+
await stepWorkflow.run();
|
|
188
|
+
|
|
189
|
+
console.log('\nStep events captured:', events.filter((e) => e.type.includes('step')).length);
|
|
190
|
+
|
|
191
|
+
// Part 2: @ObservedState options
|
|
192
|
+
printSection('@ObservedState Decorator Options');
|
|
193
|
+
|
|
194
|
+
const stateWorkflow = new StateOptionsWorkflow('StateOptions');
|
|
195
|
+
await stateWorkflow.run();
|
|
196
|
+
|
|
197
|
+
console.log('Actual field values:');
|
|
198
|
+
console.log(' publicData:', stateWorkflow.publicData);
|
|
199
|
+
console.log(' apiKey:', stateWorkflow.apiKey);
|
|
200
|
+
console.log(' password:', stateWorkflow.password);
|
|
201
|
+
console.log(' internalCounter:', (stateWorkflow as any).internalCounter);
|
|
202
|
+
console.log(' processingStatus:', stateWorkflow.processingStatus);
|
|
203
|
+
console.log(' progress:', stateWorkflow.progress);
|
|
204
|
+
|
|
205
|
+
console.log('\nState snapshot (via getObservedState):');
|
|
206
|
+
const snapshot = getObservedState(stateWorkflow);
|
|
207
|
+
console.log(JSON.stringify(snapshot, null, 2));
|
|
208
|
+
|
|
209
|
+
console.log('\nNote:');
|
|
210
|
+
console.log(' - apiKey and password show as "***" (redacted)');
|
|
211
|
+
console.log(' - internalCounter and debugInfo are not present (hidden)');
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Run if executed directly
|
|
215
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
216
|
+
runDecoratorOptionsExample().catch(console.error);
|
|
217
|
+
}
|