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,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt<T> - Immutable type-safe prompt definition
|
|
3
|
+
*
|
|
4
|
+
* Prompts define what to send to an agent and how to validate the response.
|
|
5
|
+
* They are value objects - immutable and reusable across agents and workflows.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { z } from 'zod';
|
|
9
|
+
import type {
|
|
10
|
+
PromptConfig,
|
|
11
|
+
Tool,
|
|
12
|
+
MCPServer,
|
|
13
|
+
Skill,
|
|
14
|
+
AgentHooks,
|
|
15
|
+
} from '../types/index.js';
|
|
16
|
+
import { generateId } from '../utils/id.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Prompt class - immutable definition of a single agent call
|
|
20
|
+
* @template T The expected response type (validated via Zod schema)
|
|
21
|
+
*/
|
|
22
|
+
export class Prompt<T> {
|
|
23
|
+
/** Unique identifier for this prompt instance */
|
|
24
|
+
public readonly id: string;
|
|
25
|
+
|
|
26
|
+
/** User message content */
|
|
27
|
+
public readonly user: string;
|
|
28
|
+
|
|
29
|
+
/** Structured data to inject into the prompt */
|
|
30
|
+
public readonly data: Record<string, unknown>;
|
|
31
|
+
|
|
32
|
+
/** Zod schema defining the expected response format */
|
|
33
|
+
public readonly responseFormat: z.ZodType<T>;
|
|
34
|
+
|
|
35
|
+
/** System prompt override (takes precedence over agent config) */
|
|
36
|
+
public readonly systemOverride?: string;
|
|
37
|
+
|
|
38
|
+
/** Tools override */
|
|
39
|
+
public readonly toolsOverride?: Tool[];
|
|
40
|
+
|
|
41
|
+
/** MCPs override */
|
|
42
|
+
public readonly mcpsOverride?: MCPServer[];
|
|
43
|
+
|
|
44
|
+
/** Skills override */
|
|
45
|
+
public readonly skillsOverride?: Skill[];
|
|
46
|
+
|
|
47
|
+
/** Hooks override */
|
|
48
|
+
public readonly hooksOverride?: AgentHooks;
|
|
49
|
+
|
|
50
|
+
/** Enable reflection for this specific prompt */
|
|
51
|
+
public readonly enableReflection?: boolean;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Create a new Prompt instance
|
|
55
|
+
* @param config Prompt configuration
|
|
56
|
+
*/
|
|
57
|
+
constructor(config: PromptConfig<T>) {
|
|
58
|
+
this.id = generateId();
|
|
59
|
+
this.user = config.user;
|
|
60
|
+
this.data = config.data ?? {};
|
|
61
|
+
this.responseFormat = config.responseFormat;
|
|
62
|
+
this.systemOverride = config.system;
|
|
63
|
+
this.toolsOverride = config.tools;
|
|
64
|
+
this.mcpsOverride = config.mcps;
|
|
65
|
+
this.skillsOverride = config.skills;
|
|
66
|
+
this.hooksOverride = config.hooks;
|
|
67
|
+
this.enableReflection = config.enableReflection;
|
|
68
|
+
|
|
69
|
+
// Freeze to ensure immutability
|
|
70
|
+
Object.freeze(this);
|
|
71
|
+
Object.freeze(this.data);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Validate a response against the response format schema
|
|
76
|
+
* @param data Unknown data to validate
|
|
77
|
+
* @returns Typed validated data
|
|
78
|
+
* @throws ZodError if validation fails
|
|
79
|
+
*/
|
|
80
|
+
public validateResponse(data: unknown): T {
|
|
81
|
+
return this.responseFormat.parse(data);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Safely validate response without throwing
|
|
86
|
+
* @param data Unknown data to validate
|
|
87
|
+
* @returns Result object with success flag and data or error
|
|
88
|
+
*/
|
|
89
|
+
public safeValidateResponse(
|
|
90
|
+
data: unknown
|
|
91
|
+
): { success: true; data: T } | { success: false; error: z.ZodError } {
|
|
92
|
+
const result = this.responseFormat.safeParse(data);
|
|
93
|
+
if (result.success) {
|
|
94
|
+
return { success: true, data: result.data };
|
|
95
|
+
}
|
|
96
|
+
return { success: false, error: result.error };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Build the full user message including any injected data
|
|
101
|
+
* @returns Formatted user message
|
|
102
|
+
*/
|
|
103
|
+
public buildUserMessage(): string {
|
|
104
|
+
if (Object.keys(this.data).length === 0) {
|
|
105
|
+
return this.user;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Format data as a structured section
|
|
109
|
+
const dataSection = Object.entries(this.data)
|
|
110
|
+
.map(([key, value]) => `<${key}>\n${JSON.stringify(value, null, 2)}\n</${key}>`)
|
|
111
|
+
.join('\n\n');
|
|
112
|
+
|
|
113
|
+
return `${this.user}\n\n${dataSection}`;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Create a new Prompt with updated data (immutable pattern)
|
|
118
|
+
* @param newData Data to merge or replace
|
|
119
|
+
* @returns New Prompt instance
|
|
120
|
+
*/
|
|
121
|
+
public withData(newData: Record<string, unknown>): Prompt<T> {
|
|
122
|
+
return new Prompt({
|
|
123
|
+
user: this.user,
|
|
124
|
+
data: { ...this.data, ...newData },
|
|
125
|
+
responseFormat: this.responseFormat,
|
|
126
|
+
system: this.systemOverride,
|
|
127
|
+
tools: this.toolsOverride,
|
|
128
|
+
mcps: this.mcpsOverride,
|
|
129
|
+
skills: this.skillsOverride,
|
|
130
|
+
hooks: this.hooksOverride,
|
|
131
|
+
enableReflection: this.enableReflection,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Get the prompt data (used for cache key generation)
|
|
137
|
+
* @returns The prompt data object
|
|
138
|
+
*/
|
|
139
|
+
public getData(): Record<string, unknown> {
|
|
140
|
+
return this.data;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Get the response format schema (used for cache key generation)
|
|
145
|
+
* @returns The Zod response format schema
|
|
146
|
+
*/
|
|
147
|
+
public getResponseFormat(): z.ZodType<T> {
|
|
148
|
+
return this.responseFormat;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkflowContextImpl - Implementation of functional workflow context
|
|
3
|
+
*
|
|
4
|
+
* Provides step(), spawnWorkflow(), and automatic context propagation
|
|
5
|
+
* for agents and prompts executed within workflows.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
WorkflowContext,
|
|
10
|
+
EventTreeHandle,
|
|
11
|
+
ReflectionAPI,
|
|
12
|
+
AgentLike,
|
|
13
|
+
PromptLike,
|
|
14
|
+
} from '../types/workflow-context.js';
|
|
15
|
+
import type {
|
|
16
|
+
WorkflowNode,
|
|
17
|
+
WorkflowEvent,
|
|
18
|
+
ReflectionConfig,
|
|
19
|
+
ReflectionContext,
|
|
20
|
+
} from '../types/index.js';
|
|
21
|
+
import { EventTreeHandleImpl, createEventTreeHandle } from './event-tree.js';
|
|
22
|
+
import {
|
|
23
|
+
runInContext,
|
|
24
|
+
type AgentExecutionContext,
|
|
25
|
+
} from './context.js';
|
|
26
|
+
import { generateId } from '../utils/id.js';
|
|
27
|
+
import { ReflectionManager } from '../reflection/reflection.js';
|
|
28
|
+
import { createReflectionConfig } from '../types/index.js';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Interface for workflow-like objects that can emit events
|
|
32
|
+
*/
|
|
33
|
+
interface WorkflowLike {
|
|
34
|
+
id: string;
|
|
35
|
+
node: WorkflowNode;
|
|
36
|
+
emitEvent(event: WorkflowEvent): void;
|
|
37
|
+
setStatus(status: 'idle' | 'running' | 'completed' | 'failed' | 'cancelled'): void;
|
|
38
|
+
attachChild(child: WorkflowLike): void;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* WorkflowContext implementation
|
|
43
|
+
*/
|
|
44
|
+
export class WorkflowContextImpl implements WorkflowContext {
|
|
45
|
+
public readonly workflowId: string;
|
|
46
|
+
public readonly parentWorkflowId?: string;
|
|
47
|
+
public readonly eventTree: EventTreeHandle;
|
|
48
|
+
public readonly reflection: ReflectionAPI;
|
|
49
|
+
|
|
50
|
+
private workflow: WorkflowLike;
|
|
51
|
+
private eventTreeImpl: EventTreeHandleImpl;
|
|
52
|
+
private reflectionManager: ReflectionManager;
|
|
53
|
+
|
|
54
|
+
constructor(
|
|
55
|
+
workflow: WorkflowLike,
|
|
56
|
+
parentWorkflowId?: string,
|
|
57
|
+
reflectionConfig?: Partial<ReflectionConfig>
|
|
58
|
+
) {
|
|
59
|
+
this.workflowId = workflow.id;
|
|
60
|
+
this.parentWorkflowId = parentWorkflowId;
|
|
61
|
+
this.workflow = workflow;
|
|
62
|
+
|
|
63
|
+
// Create event tree handle
|
|
64
|
+
this.eventTreeImpl = new EventTreeHandleImpl(workflow.node);
|
|
65
|
+
this.eventTree = this.eventTreeImpl;
|
|
66
|
+
|
|
67
|
+
// Create reflection manager with config
|
|
68
|
+
const config = createReflectionConfig(reflectionConfig);
|
|
69
|
+
this.reflectionManager = new ReflectionManager(config);
|
|
70
|
+
this.reflectionManager.setEventEmitter((event) => this.workflow.emitEvent(event));
|
|
71
|
+
this.reflection = this.reflectionManager;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Execute a named step with automatic context propagation and reflection support
|
|
76
|
+
*/
|
|
77
|
+
async step<T>(name: string, fn: () => Promise<T>): Promise<T> {
|
|
78
|
+
const maxAttempts = this.reflectionManager.isEnabled()
|
|
79
|
+
? this.reflectionManager.getMaxAttempts()
|
|
80
|
+
: 1;
|
|
81
|
+
|
|
82
|
+
let lastError: Error | null = null;
|
|
83
|
+
|
|
84
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
85
|
+
const startTime = Date.now();
|
|
86
|
+
|
|
87
|
+
// Create step node
|
|
88
|
+
const stepNode: WorkflowNode = {
|
|
89
|
+
id: generateId(),
|
|
90
|
+
name: attempt > 1 ? `${name} (retry ${attempt - 1})` : name,
|
|
91
|
+
parent: this.workflow.node,
|
|
92
|
+
children: [],
|
|
93
|
+
status: 'running',
|
|
94
|
+
logs: [],
|
|
95
|
+
events: [],
|
|
96
|
+
stateSnapshot: null,
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// Attach to parent
|
|
100
|
+
this.workflow.node.children.push(stepNode);
|
|
101
|
+
|
|
102
|
+
// Emit step start
|
|
103
|
+
this.workflow.emitEvent({
|
|
104
|
+
type: 'stepStart',
|
|
105
|
+
node: stepNode,
|
|
106
|
+
step: name,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Create execution context for this step
|
|
110
|
+
const executionContext: AgentExecutionContext = {
|
|
111
|
+
workflowNode: stepNode,
|
|
112
|
+
emitEvent: (event: WorkflowEvent) => {
|
|
113
|
+
stepNode.events.push(event);
|
|
114
|
+
this.workflow.emitEvent(event);
|
|
115
|
+
},
|
|
116
|
+
workflowId: this.workflowId,
|
|
117
|
+
parentWorkflowId: this.parentWorkflowId,
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
// Execute function in context
|
|
122
|
+
const result = await runInContext(executionContext, fn);
|
|
123
|
+
|
|
124
|
+
// Update step node status
|
|
125
|
+
stepNode.status = 'completed';
|
|
126
|
+
|
|
127
|
+
// Emit step end
|
|
128
|
+
const duration = Date.now() - startTime;
|
|
129
|
+
this.workflow.emitEvent({
|
|
130
|
+
type: 'stepEnd',
|
|
131
|
+
node: stepNode,
|
|
132
|
+
step: name,
|
|
133
|
+
duration,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// Rebuild event tree
|
|
137
|
+
this.eventTreeImpl.rebuild(this.workflow.node);
|
|
138
|
+
|
|
139
|
+
// If we succeeded after a reflection, mark it as successful
|
|
140
|
+
if (attempt > 1) {
|
|
141
|
+
this.reflectionManager.markLastReflectionSuccessful();
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return result;
|
|
145
|
+
} catch (error) {
|
|
146
|
+
lastError = error as Error;
|
|
147
|
+
|
|
148
|
+
// Update step node status
|
|
149
|
+
stepNode.status = 'failed';
|
|
150
|
+
|
|
151
|
+
// Emit error event
|
|
152
|
+
this.workflow.emitEvent({
|
|
153
|
+
type: 'error',
|
|
154
|
+
node: stepNode,
|
|
155
|
+
error: {
|
|
156
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
157
|
+
original: error,
|
|
158
|
+
workflowId: this.workflowId,
|
|
159
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
160
|
+
state: {},
|
|
161
|
+
logs: [],
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// Rebuild event tree
|
|
166
|
+
this.eventTreeImpl.rebuild(this.workflow.node);
|
|
167
|
+
|
|
168
|
+
// Check if we should try reflection
|
|
169
|
+
if (!this.reflectionManager.isEnabled() || attempt === maxAttempts) {
|
|
170
|
+
throw error;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Try reflection
|
|
174
|
+
const reflectionContext: ReflectionContext = {
|
|
175
|
+
level: 'workflow',
|
|
176
|
+
failedNode: stepNode,
|
|
177
|
+
error: lastError,
|
|
178
|
+
attemptNumber: attempt,
|
|
179
|
+
previousAttempts: this.reflectionManager.getReflectionHistory(),
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const reflectionResult = await this.reflectionManager.reflect(reflectionContext);
|
|
183
|
+
|
|
184
|
+
if (!reflectionResult.shouldRetry) {
|
|
185
|
+
throw lastError;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Continue to next iteration for retry
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
throw lastError ?? new Error('Max reflection attempts exceeded');
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Spawn a child workflow
|
|
197
|
+
*/
|
|
198
|
+
async spawnWorkflow<T>(workflow: { run(): Promise<T>; id?: string; node?: WorkflowNode }): Promise<T> {
|
|
199
|
+
// If workflow has attachChild-like capability, use it
|
|
200
|
+
if ('node' in workflow && workflow.node) {
|
|
201
|
+
// Set parent reference
|
|
202
|
+
workflow.node.parent = this.workflow.node;
|
|
203
|
+
|
|
204
|
+
// Attach child node
|
|
205
|
+
this.workflow.node.children.push(workflow.node);
|
|
206
|
+
|
|
207
|
+
// Emit child attached event
|
|
208
|
+
this.workflow.emitEvent({
|
|
209
|
+
type: 'childAttached',
|
|
210
|
+
parentId: this.workflowId,
|
|
211
|
+
child: workflow.node,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Run the child workflow
|
|
216
|
+
const result = await workflow.run();
|
|
217
|
+
|
|
218
|
+
// Rebuild event tree
|
|
219
|
+
this.eventTreeImpl.rebuild(this.workflow.node);
|
|
220
|
+
|
|
221
|
+
return result;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Replace the last prompt result with a new one (context revision)
|
|
226
|
+
* The previous prompt node is marked as 'revised' and the new result is attached as sibling
|
|
227
|
+
*/
|
|
228
|
+
async replaceLastPromptResult<T>(
|
|
229
|
+
newPrompt: PromptLike<T>,
|
|
230
|
+
agent: AgentLike
|
|
231
|
+
): Promise<T> {
|
|
232
|
+
// Find the last completed prompt node in the tree
|
|
233
|
+
const children = this.workflow.node.children;
|
|
234
|
+
let lastPromptNodeIndex = -1;
|
|
235
|
+
|
|
236
|
+
for (let i = children.length - 1; i >= 0; i--) {
|
|
237
|
+
const child = children[i];
|
|
238
|
+
if (child.status === 'completed') {
|
|
239
|
+
lastPromptNodeIndex = i;
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Create a revision node to mark the replacement
|
|
245
|
+
const revisionNode: WorkflowNode = {
|
|
246
|
+
id: generateId(),
|
|
247
|
+
name: `revision:${newPrompt.id}`,
|
|
248
|
+
parent: this.workflow.node,
|
|
249
|
+
children: [],
|
|
250
|
+
status: 'running',
|
|
251
|
+
logs: [],
|
|
252
|
+
events: [],
|
|
253
|
+
stateSnapshot: null,
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
// If we found a previous node, mark it as revised
|
|
257
|
+
if (lastPromptNodeIndex >= 0) {
|
|
258
|
+
const previousNode = children[lastPromptNodeIndex];
|
|
259
|
+
// Mark as revised by adding a special status flag in logs
|
|
260
|
+
previousNode.logs.push({
|
|
261
|
+
id: generateId(),
|
|
262
|
+
workflowId: this.workflowId,
|
|
263
|
+
level: 'info',
|
|
264
|
+
message: `Revised by ${revisionNode.id}`,
|
|
265
|
+
timestamp: Date.now(),
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Attach revision node as sibling (at same level)
|
|
270
|
+
this.workflow.node.children.push(revisionNode);
|
|
271
|
+
|
|
272
|
+
// Emit prompt revision event
|
|
273
|
+
this.workflow.emitEvent({
|
|
274
|
+
type: 'stepStart',
|
|
275
|
+
node: revisionNode,
|
|
276
|
+
step: `revision:${newPrompt.id}`,
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
// Create execution context for this revision
|
|
280
|
+
const executionContext: AgentExecutionContext = {
|
|
281
|
+
workflowNode: revisionNode,
|
|
282
|
+
emitEvent: (event: WorkflowEvent) => {
|
|
283
|
+
revisionNode.events.push(event);
|
|
284
|
+
this.workflow.emitEvent(event);
|
|
285
|
+
},
|
|
286
|
+
workflowId: this.workflowId,
|
|
287
|
+
parentWorkflowId: this.parentWorkflowId,
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
try {
|
|
291
|
+
// Execute the new prompt in context
|
|
292
|
+
const result = await runInContext(executionContext, () =>
|
|
293
|
+
agent.prompt(newPrompt)
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
// Update revision node status
|
|
297
|
+
revisionNode.status = 'completed';
|
|
298
|
+
|
|
299
|
+
// Emit completion event
|
|
300
|
+
this.workflow.emitEvent({
|
|
301
|
+
type: 'stepEnd',
|
|
302
|
+
node: revisionNode,
|
|
303
|
+
step: `revision:${newPrompt.id}`,
|
|
304
|
+
duration: 0, // Could track actual duration if needed
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
// Rebuild event tree
|
|
308
|
+
this.eventTreeImpl.rebuild(this.workflow.node);
|
|
309
|
+
|
|
310
|
+
return result;
|
|
311
|
+
} catch (error) {
|
|
312
|
+
// Update revision node status
|
|
313
|
+
revisionNode.status = 'failed';
|
|
314
|
+
|
|
315
|
+
// Emit error event
|
|
316
|
+
this.workflow.emitEvent({
|
|
317
|
+
type: 'error',
|
|
318
|
+
node: revisionNode,
|
|
319
|
+
error: {
|
|
320
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
321
|
+
original: error,
|
|
322
|
+
workflowId: this.workflowId,
|
|
323
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
324
|
+
state: {},
|
|
325
|
+
logs: [],
|
|
326
|
+
},
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
// Rebuild event tree
|
|
330
|
+
this.eventTreeImpl.rebuild(this.workflow.node);
|
|
331
|
+
|
|
332
|
+
throw error;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Create a WorkflowContext for a workflow
|
|
339
|
+
* @param workflow The workflow object
|
|
340
|
+
* @param parentWorkflowId Optional parent workflow ID
|
|
341
|
+
* @param reflectionConfig Optional reflection configuration
|
|
342
|
+
*/
|
|
343
|
+
export function createWorkflowContext(
|
|
344
|
+
workflow: WorkflowLike,
|
|
345
|
+
parentWorkflowId?: string,
|
|
346
|
+
reflectionConfig?: Partial<ReflectionConfig>
|
|
347
|
+
): WorkflowContext {
|
|
348
|
+
return new WorkflowContextImpl(workflow, parentWorkflowId, reflectionConfig);
|
|
349
|
+
}
|