@agentionai/agents 0.4.2 → 0.6.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.
Files changed (47) hide show
  1. package/README.md +2 -2
  2. package/dist/agents/AgentConfig.d.ts +19 -0
  3. package/dist/agents/BaseAgent.d.ts +39 -0
  4. package/dist/agents/BaseAgent.js +100 -1
  5. package/dist/agents/anthropic/ClaudeAgent.d.ts +0 -2
  6. package/dist/agents/anthropic/ClaudeAgent.js +8 -4
  7. package/dist/agents/google/GeminiAgent.d.ts +0 -2
  8. package/dist/agents/google/GeminiAgent.js +4 -4
  9. package/dist/agents/mistral/MistralAgent.d.ts +0 -2
  10. package/dist/agents/mistral/MistralAgent.js +4 -4
  11. package/dist/agents/openai/OpenAiAgent.d.ts +0 -2
  12. package/dist/agents/openai/OpenAiAgent.js +4 -4
  13. package/dist/{vectorstore → embeddings}/OpenAIEmbeddings.d.ts +10 -2
  14. package/dist/{vectorstore → embeddings}/OpenAIEmbeddings.js +5 -1
  15. package/dist/embeddings/VoyageAIEmbeddings.d.ts +80 -0
  16. package/dist/embeddings/VoyageAIEmbeddings.js +139 -0
  17. package/dist/embeddings/index.d.ts +23 -0
  18. package/dist/embeddings/index.js +29 -0
  19. package/dist/graph/AgentGraph.d.ts +77 -0
  20. package/dist/graph/AgentGraph.js +112 -1
  21. package/dist/graph/context/ContextStore.d.ts +69 -0
  22. package/dist/graph/context/ContextStore.js +101 -0
  23. package/dist/graph/context/ContextTools.d.ts +52 -0
  24. package/dist/graph/context/ContextTools.js +148 -0
  25. package/dist/graph/context/index.d.ts +3 -0
  26. package/dist/graph/context/index.js +11 -0
  27. package/dist/graph/planning/PlanExecutor.d.ts +184 -0
  28. package/dist/graph/planning/PlanExecutor.js +396 -0
  29. package/dist/graph/planning/PlanStore.d.ts +81 -0
  30. package/dist/graph/planning/PlanStore.js +199 -0
  31. package/dist/graph/planning/PlanningTools.d.ts +45 -0
  32. package/dist/graph/planning/PlanningTools.js +178 -0
  33. package/dist/graph/planning/index.d.ts +5 -0
  34. package/dist/graph/planning/index.js +14 -0
  35. package/dist/graph/planning/types.d.ts +41 -0
  36. package/dist/graph/planning/types.js +3 -0
  37. package/dist/history/History.js +3 -0
  38. package/dist/index.d.ts +1 -0
  39. package/dist/index.js +2 -0
  40. package/dist/ingestion/IngestionPipeline.d.ts +1 -1
  41. package/dist/vectorstore/LanceDBVectorStore.d.ts +67 -2
  42. package/dist/vectorstore/LanceDBVectorStore.js +134 -23
  43. package/dist/vectorstore/index.d.ts +6 -4
  44. package/dist/vectorstore/index.js +10 -6
  45. package/package.json +12 -3
  46. /package/dist/{vectorstore → embeddings}/Embeddings.d.ts +0 -0
  47. /package/dist/{vectorstore → embeddings}/Embeddings.js +0 -0
@@ -0,0 +1,396 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PlanExecutor = void 0;
4
+ const BaseExecutor_1 = require("../BaseExecutor");
5
+ /**
6
+ * Orchestrates plan-based execution with clear separation of concerns:
7
+ * 1. Planning Phase: Uses a planning agent to create a plan
8
+ * 2. Execution Phase: Assigns workers (agents or graph nodes) to execute each step
9
+ * 3. Completion: Compiles results and returns summary
10
+ *
11
+ * The PlanExecutor acts as the orchestrator, tracking progress and delegating
12
+ * work to specialized workers. Planning and execution are separate phases.
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * const planStore = AgentGraph.createPlanStore();
17
+ * const contextStore = AgentGraph.createContextStore();
18
+ *
19
+ * // Planning agent creates the plan
20
+ * const planner = new ClaudeAgent({
21
+ * tools: AgentGraph.createPlanningTools(planStore),
22
+ * description: 'You are a planning agent. Create a detailed plan with clear steps.',
23
+ * });
24
+ *
25
+ * // Worker agent executes individual steps
26
+ * const worker = new ClaudeAgent({
27
+ * tools: AgentGraph.createContextTools(contextStore),
28
+ * description: 'You execute a single step. Store results in context.',
29
+ * });
30
+ *
31
+ * const executor = new PlanExecutor(planStore, planner, worker, {
32
+ * onStepComplete: (step, result, num) => {
33
+ * console.log(`Completed step ${num}: ${step.description}`);
34
+ * },
35
+ * });
36
+ *
37
+ * const result = await executor.execute('Research and summarize quantum computing');
38
+ * ```
39
+ */
40
+ class PlanExecutor extends BaseExecutor_1.BaseExecutor {
41
+ /**
42
+ * Create a new PlanExecutor.
43
+ *
44
+ * @param planStore - The plan store to track plan state
45
+ * @param planningAgent - Agent responsible for creating the plan
46
+ * @param worker - Agent or GraphNode that executes individual steps
47
+ * @param options - Configuration options
48
+ */
49
+ constructor(planStore, planningAgent, worker, options = {}) {
50
+ super();
51
+ this.planStore = planStore;
52
+ this.name = "PlanExecutor";
53
+ this.nodeType = "pipeline";
54
+ this.planningAgent = planningAgent;
55
+ this.worker = worker;
56
+ this.options = {
57
+ maxSteps: options.maxSteps ?? 50,
58
+ concurrency: options.concurrency ?? 1,
59
+ stopOnFailure: options.stopOnFailure ?? true,
60
+ maxContextSteps: options.maxContextSteps ?? 0, // Default: no auto context
61
+ onPlanCreated: options.onPlanCreated,
62
+ onStepStart: options.onStepStart,
63
+ onStepComplete: options.onStepComplete,
64
+ onStepFailed: options.onStepFailed,
65
+ };
66
+ }
67
+ /**
68
+ * Execute the plan:
69
+ * 1. Planning Phase: Ask planning agent to create a plan
70
+ * 2. Execution Phase: Execute each step with the worker
71
+ * 3. Completion: Return finalOutput (for chaining)
72
+ *
73
+ * Returns the finalOutput string for easy chaining in pipelines.
74
+ * Use getLastResult() to access the full PlanExecutionResult with details.
75
+ */
76
+ async execute(input) {
77
+ const collector = this.getCollector();
78
+ const execId = collector?.startExecution(this.name, "pipeline", input);
79
+ try {
80
+ // Phase 1: Planning
81
+ await this.planningPhase(input, collector);
82
+ // Phase 2: Execution
83
+ const stepResults = await this.executionPhase(collector);
84
+ // Phase 3: Compile results
85
+ const result = this.compileResult(stepResults);
86
+ // Store for getLastResult()
87
+ this.lastResult = result;
88
+ if (execId) {
89
+ collector?.endExecution(execId, result.success, result.finalOutput);
90
+ }
91
+ // Return finalOutput for chaining
92
+ return result.finalOutput;
93
+ }
94
+ catch (error) {
95
+ if (execId) {
96
+ collector?.endExecution(execId, false, undefined, undefined, error instanceof Error ? error.message : String(error));
97
+ }
98
+ throw error;
99
+ }
100
+ }
101
+ /**
102
+ * Get the detailed result from the last execution.
103
+ * Contains full plan details, step results, and metadata.
104
+ */
105
+ getLastResult() {
106
+ return this.lastResult;
107
+ }
108
+ /**
109
+ * Phase 1: Planning
110
+ * Instructs the planning agent to create a plan based on the task.
111
+ */
112
+ async planningPhase(task, collector) {
113
+ const planExecId = collector?.startExecution("Planning Phase", "agent", task);
114
+ try {
115
+ const planningPrompt = this.createPlanningPrompt(task);
116
+ const planningResult = (await this.planningAgent.execute(planningPrompt));
117
+ // Extract token usage
118
+ const tokenUsage = this.extractTokenUsage(this.planningAgent);
119
+ if (planExecId) {
120
+ collector?.endExecution(planExecId, true, planningResult, tokenUsage);
121
+ }
122
+ // Verify plan was created
123
+ const plan = this.planStore.getActivePlan();
124
+ if (!plan || plan.steps.length === 0) {
125
+ throw new Error("Planning agent failed to create a plan. Please ensure the agent has planning tools.");
126
+ }
127
+ // Enforce maxSteps limit
128
+ if (plan.steps.length > this.options.maxSteps) {
129
+ throw new Error(`Planning agent created ${plan.steps.length} steps, which exceeds the maximum of ${this.options.maxSteps}. ` +
130
+ `Please reduce the plan size or increase maxSteps option.`);
131
+ }
132
+ // Notify plan creation
133
+ this.options.onPlanCreated?.(plan.goal, plan.steps);
134
+ }
135
+ catch (error) {
136
+ if (planExecId) {
137
+ collector?.endExecution(planExecId, false, undefined, undefined, error instanceof Error ? error.message : String(error));
138
+ }
139
+ throw error;
140
+ }
141
+ }
142
+ /**
143
+ * Phase 2: Execution
144
+ * Executes each step in the plan using the worker.
145
+ */
146
+ async executionPhase(collector) {
147
+ const plan = this.planStore.getActivePlan();
148
+ if (!plan) {
149
+ throw new Error("No active plan found");
150
+ }
151
+ const results = [];
152
+ let stepNumber = 0;
153
+ const activePromises = new Map();
154
+ let stopError;
155
+ while (stepNumber < this.options.maxSteps) {
156
+ // Wait if we've reached concurrency limit
157
+ if (activePromises.size >= this.options.concurrency) {
158
+ await Promise.race(activePromises.values());
159
+ }
160
+ // If a step failed and stopOnFailure is set, drain remaining promises then throw
161
+ if (stopError) {
162
+ break;
163
+ }
164
+ const nextStep = this.planStore.getNextStep();
165
+ if (!nextStep) {
166
+ // No more pending steps
167
+ break;
168
+ }
169
+ stepNumber++;
170
+ // Notify step start
171
+ this.options.onStepStart?.(nextStep, stepNumber, plan.steps.length);
172
+ // Mark step as in_progress
173
+ this.planStore.updateStep(nextStep.id, "in_progress");
174
+ const stepExecId = collector?.startExecution(`Step ${stepNumber}: ${nextStep.description}`, this.isAgent(this.worker) ? "agent" : "custom", nextStep.description);
175
+ // Wrap step execution in an async function
176
+ const executeStep = async () => {
177
+ try {
178
+ // Execute the step with the worker
179
+ const stepInput = this.createStepInput(nextStep, stepNumber);
180
+ const rawResult = await this.worker.execute(stepInput);
181
+ const stepResult = String(rawResult);
182
+ // Extract token usage if worker is an agent
183
+ const tokenUsage = this.isAgent(this.worker)
184
+ ? this.extractTokenUsage(this.worker)
185
+ : undefined;
186
+ if (stepExecId) {
187
+ collector?.endExecution(stepExecId, true, stepResult, tokenUsage);
188
+ }
189
+ // Mark step as completed
190
+ this.planStore.updateStep(nextStep.id, "completed", stepResult);
191
+ results.push({
192
+ step: nextStep,
193
+ result: stepResult,
194
+ });
195
+ // Notify step completion
196
+ this.options.onStepComplete?.(nextStep, stepResult, stepNumber);
197
+ }
198
+ catch (error) {
199
+ const errorMessage = error instanceof Error ? error.message : String(error);
200
+ if (stepExecId) {
201
+ collector?.endExecution(stepExecId, false, undefined, undefined, errorMessage);
202
+ }
203
+ // Mark step as failed
204
+ this.planStore.updateStep(nextStep.id, "failed", errorMessage);
205
+ results.push({
206
+ step: nextStep,
207
+ error: errorMessage,
208
+ });
209
+ // Notify step failure
210
+ this.options.onStepFailed?.(nextStep, error instanceof Error ? error : new Error(errorMessage), stepNumber);
211
+ // Record error to stop after in-flight steps complete
212
+ if (this.options.stopOnFailure) {
213
+ stopError = new Error(`Step ${stepNumber} failed: ${errorMessage}`);
214
+ }
215
+ }
216
+ finally {
217
+ // Remove from active promises when complete
218
+ activePromises.delete(nextStep.id);
219
+ }
220
+ };
221
+ // Store the promise in activePromises
222
+ const promise = executeStep();
223
+ activePromises.set(nextStep.id, promise);
224
+ // For sequential execution (concurrency=1), await immediately
225
+ if (this.options.concurrency === 1) {
226
+ await promise;
227
+ }
228
+ }
229
+ // Always wait for all in-flight promises to finish before returning/throwing
230
+ if (activePromises.size > 0) {
231
+ await Promise.allSettled(activePromises.values());
232
+ }
233
+ if (stopError) {
234
+ throw stopError;
235
+ }
236
+ if (stepNumber >= this.options.maxSteps) {
237
+ const plan = this.planStore.getActivePlan();
238
+ const remainingSteps = plan?.steps.filter((s) => s.status === "pending").length;
239
+ if (remainingSteps && remainingSteps > 0) {
240
+ throw new Error(`Maximum steps (${this.options.maxSteps}) reached with ${remainingSteps} steps remaining`);
241
+ }
242
+ }
243
+ return results;
244
+ }
245
+ /**
246
+ * Create a prompt for the planning agent.
247
+ */
248
+ createPlanningPrompt(task) {
249
+ return `You are a planning agent. Your job is to create a detailed execution plan for the following task.
250
+
251
+ Task: ${task}
252
+
253
+ CRITICAL: You can create a maximum of ${this.options.maxSteps} steps. Plan accordingly and prioritize the most important subtasks.
254
+
255
+ CONTEXT LIMIT WARNING: Each step will be executed independently with limited context. To avoid rate limits and context overflow:
256
+ - Break work into VERY SMALL, ATOMIC steps
257
+ - Each step should process only 1-3 items at a time
258
+ - Never create steps that say "analyze all", "process everything", "read all files", etc.
259
+ - Instead, break into multiple steps: "Read file1", "Read file2", "Read file3"
260
+
261
+ Use the create_plan tool to create a plan with clear, actionable steps. Each step MUST be:
262
+
263
+ 1. MICRO-SIZED - Can be completed in under 10 seconds with minimal tokens
264
+ 2. SINGLE ACTION - Exactly ONE thing to do (read ONE file, list ONE directory, etc.)
265
+ 3. SPECIFIC - Mention exact file names, directories, or items (not "all files")
266
+ 4. NO BATCH OPERATIONS - Process items one-by-one, not in bulk
267
+ 5. SEQUENTIAL - Let each step's output inform the next step
268
+
269
+ GOOD EXAMPLES (SMALL STEPS):
270
+ ✓ "List files in the lib/graph directory"
271
+ ✓ "Read the first 50 lines of PlanExecutor.ts"
272
+ ✓ "Search for the definition of 'createPlan' function"
273
+ ✓ "Summarize the purpose of SequentialExecutor class in 2 sentences"
274
+
275
+ BAD EXAMPLES (TOO LARGE):
276
+ ✗ "Read and analyze all files in lib/graph" (reads too much, use multiple steps)
277
+ ✗ "Analyze the entire codebase architecture" (too broad, break into 5+ steps)
278
+ ✗ "Review all test files and identify issues" (batch operation, do one at a time)
279
+ ✗ "Research best practices and implement them" (vague, multi-step)
280
+
281
+ STRATEGY FOR AVOIDING RATE LIMITS:
282
+ - If analyzing multiple files: Create one step per file
283
+ - If processing a list: Create one step per item
284
+ - If researching: Create steps for: 1) identify what to research, 2) research item 1, 3) research item 2, etc.
285
+ - If the task seems large: Create 2x as many steps as you initially think
286
+
287
+ Break down complex tasks into the SMALLEST possible steps. Having ${this.options.maxSteps} small steps is much better than having ${Math.floor(this.options.maxSteps / 2)} larger ones.
288
+
289
+ After creating the plan, respond with a brief confirmation.`;
290
+ }
291
+ /**
292
+ * Create input for a step execution.
293
+ *
294
+ * By default, only includes the current step information.
295
+ * Workers should use context_get to retrieve data from previous steps.
296
+ * This prevents token overflow from accumulating context.
297
+ */
298
+ createStepInput(step, stepNumber) {
299
+ const plan = this.planStore.getActivePlan();
300
+ const completedSteps = plan?.steps.filter((s) => s.status === "completed") || [];
301
+ // Limit context to prevent token overflow
302
+ // Only include the most recent N steps based on maxContextSteps option
303
+ const recentSteps = this.options.maxContextSteps > 0
304
+ ? completedSteps.slice(-this.options.maxContextSteps)
305
+ : [];
306
+ const input = {
307
+ stepNumber,
308
+ totalSteps: plan?.steps.length,
309
+ currentStep: {
310
+ id: step.id,
311
+ description: step.description,
312
+ },
313
+ planGoal: plan?.goal,
314
+ };
315
+ // Only add previous steps if maxContextSteps > 0
316
+ if (this.options.maxContextSteps > 0 && recentSteps.length > 0) {
317
+ input.previousSteps = recentSteps.map((s) => ({
318
+ description: s.description,
319
+ output: s.output,
320
+ }));
321
+ input.contextNote = `Showing last ${recentSteps.length} of ${completedSteps.length} completed steps`;
322
+ }
323
+ else {
324
+ input.contextNote =
325
+ "Use context_get tool to retrieve data from previous steps if needed";
326
+ }
327
+ return JSON.stringify(input, null, 2);
328
+ }
329
+ /**
330
+ * Compile the final result from step results.
331
+ */
332
+ compileResult(stepResults) {
333
+ const plan = this.planStore.getActivePlan();
334
+ if (!plan) {
335
+ throw new Error("No active plan found");
336
+ }
337
+ const completedSteps = stepResults.filter((r) => r.result).length;
338
+ const failedSteps = stepResults.filter((r) => r.error).length;
339
+ // Create consolidated output for chaining
340
+ const finalOutput = this.createFinalOutput(plan.goal, stepResults);
341
+ return {
342
+ success: plan.status === "completed",
343
+ goal: plan.goal,
344
+ totalSteps: plan.steps.length,
345
+ completedSteps,
346
+ failedSteps,
347
+ summary: this.planStore.getSummary(),
348
+ finalOutput,
349
+ stepResults,
350
+ };
351
+ }
352
+ /**
353
+ * Create a clean, consolidated output from all step results.
354
+ * This output is designed for chaining to the next graph node.
355
+ */
356
+ createFinalOutput(goal, stepResults) {
357
+ const completedResults = stepResults
358
+ .filter((r) => r.result)
359
+ .map((r) => r.result)
360
+ .join("\n\n");
361
+ // If there are any failures, include them
362
+ const failures = stepResults.filter((r) => r.error);
363
+ const failureText = failures.length > 0
364
+ ? `\n\nFailed steps (${failures.length}):\n${failures
365
+ .map((f) => `- ${f.step.description}: ${f.error}`)
366
+ .join("\n")}`
367
+ : "";
368
+ return `Goal: ${goal}\n\nResults:\n${completedResults}${failureText}`;
369
+ }
370
+ /**
371
+ * Check if a worker is a BaseAgent.
372
+ */
373
+ isAgent(worker) {
374
+ return "getName" in worker;
375
+ }
376
+ /**
377
+ * Extract token usage from an agent if available.
378
+ */
379
+ extractTokenUsage(agent) {
380
+ if (!agent.lastTokenUsage)
381
+ return undefined;
382
+ return {
383
+ inputTokens: agent.lastTokenUsage.input_tokens,
384
+ outputTokens: agent.lastTokenUsage.output_tokens,
385
+ totalTokens: agent.lastTokenUsage.total_tokens,
386
+ };
387
+ }
388
+ /**
389
+ * Get the plan store.
390
+ */
391
+ getPlanStore() {
392
+ return this.planStore;
393
+ }
394
+ }
395
+ exports.PlanExecutor = PlanExecutor;
396
+ //# sourceMappingURL=PlanExecutor.js.map
@@ -0,0 +1,81 @@
1
+ import { Plan, PlanStep, PlanStepStatus } from "./types";
2
+ /**
3
+ * Manages plans within a pipeline execution.
4
+ * Provides methods to create, update, and track plan progress.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * const planStore = new PlanStore();
9
+ * const plan = planStore.createPlan('Research AI', ['Search papers', 'Analyze findings', 'Write summary']);
10
+ *
11
+ * // Work through steps
12
+ * const nextStep = planStore.getNextStep();
13
+ * planStore.updateStep(nextStep.id, 'completed', 'Found 5 relevant papers');
14
+ * ```
15
+ */
16
+ export declare class PlanStore {
17
+ private plans;
18
+ private activePlanId?;
19
+ /**
20
+ * Create a new plan with a goal and list of step descriptions.
21
+ * @param goal - The overall goal to achieve
22
+ * @param steps - Array of step descriptions
23
+ * @returns The created plan
24
+ */
25
+ createPlan(goal: string, steps: string[]): Plan;
26
+ /**
27
+ * Get the currently active plan.
28
+ * @returns The active plan or undefined if none
29
+ */
30
+ getActivePlan(): Plan | undefined;
31
+ /**
32
+ * Get a plan by its ID.
33
+ * @param id - The plan ID
34
+ * @returns The plan or undefined if not found
35
+ */
36
+ getPlan(id: string): Plan | undefined;
37
+ /**
38
+ * Set the active plan by ID.
39
+ * @param id - The plan ID to set as active
40
+ * @returns True if the plan exists and was set as active
41
+ */
42
+ setActivePlan(id: string): boolean;
43
+ /**
44
+ * Update a step's status and optionally its output or error.
45
+ * @param stepId - The step ID to update
46
+ * @param status - The new status
47
+ * @param output - Optional output from the step
48
+ * @param error - Optional error message
49
+ */
50
+ updateStep(stepId: string, status: PlanStepStatus, output?: string, error?: string): void;
51
+ /**
52
+ * Get the next pending step that can be executed.
53
+ * @returns The next pending step or undefined if none
54
+ */
55
+ getNextStep(): PlanStep | undefined;
56
+ /**
57
+ * Add a new step to the active plan.
58
+ * @param description - The step description
59
+ * @returns The created step or undefined if no active plan
60
+ */
61
+ addStep(description: string): PlanStep | undefined;
62
+ /**
63
+ * Get a human-readable summary of the active plan.
64
+ * @returns A formatted summary string
65
+ */
66
+ getSummary(): string;
67
+ /**
68
+ * Get all plans.
69
+ * @returns Array of all plans
70
+ */
71
+ getAllPlans(): Plan[];
72
+ /**
73
+ * Clear all plans.
74
+ */
75
+ clear(): void;
76
+ /**
77
+ * Update the overall plan status based on step statuses.
78
+ */
79
+ private updatePlanStatus;
80
+ }
81
+ //# sourceMappingURL=PlanStore.d.ts.map
@@ -0,0 +1,199 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PlanStore = void 0;
4
+ /**
5
+ * Manages plans within a pipeline execution.
6
+ * Provides methods to create, update, and track plan progress.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * const planStore = new PlanStore();
11
+ * const plan = planStore.createPlan('Research AI', ['Search papers', 'Analyze findings', 'Write summary']);
12
+ *
13
+ * // Work through steps
14
+ * const nextStep = planStore.getNextStep();
15
+ * planStore.updateStep(nextStep.id, 'completed', 'Found 5 relevant papers');
16
+ * ```
17
+ */
18
+ class PlanStore {
19
+ constructor() {
20
+ this.plans = new Map();
21
+ }
22
+ /**
23
+ * Create a new plan with a goal and list of step descriptions.
24
+ * @param goal - The overall goal to achieve
25
+ * @param steps - Array of step descriptions
26
+ * @returns The created plan
27
+ */
28
+ createPlan(goal, steps) {
29
+ const id = `plan_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
30
+ const now = Date.now();
31
+ const plan = {
32
+ id,
33
+ goal,
34
+ steps: steps.map((description, index) => ({
35
+ id: `step_${index + 1}`,
36
+ description,
37
+ status: "pending",
38
+ })),
39
+ status: "created",
40
+ createdAt: now,
41
+ updatedAt: now,
42
+ };
43
+ this.plans.set(id, plan);
44
+ this.activePlanId = id;
45
+ return plan;
46
+ }
47
+ /**
48
+ * Get the currently active plan.
49
+ * @returns The active plan or undefined if none
50
+ */
51
+ getActivePlan() {
52
+ return this.activePlanId ? this.plans.get(this.activePlanId) : undefined;
53
+ }
54
+ /**
55
+ * Get a plan by its ID.
56
+ * @param id - The plan ID
57
+ * @returns The plan or undefined if not found
58
+ */
59
+ getPlan(id) {
60
+ return this.plans.get(id);
61
+ }
62
+ /**
63
+ * Set the active plan by ID.
64
+ * @param id - The plan ID to set as active
65
+ * @returns True if the plan exists and was set as active
66
+ */
67
+ setActivePlan(id) {
68
+ if (this.plans.has(id)) {
69
+ this.activePlanId = id;
70
+ return true;
71
+ }
72
+ return false;
73
+ }
74
+ /**
75
+ * Update a step's status and optionally its output or error.
76
+ * @param stepId - The step ID to update
77
+ * @param status - The new status
78
+ * @param output - Optional output from the step
79
+ * @param error - Optional error message
80
+ */
81
+ updateStep(stepId, status, output, error) {
82
+ const plan = this.getActivePlan();
83
+ if (!plan)
84
+ return;
85
+ const step = plan.steps.find((s) => s.id === stepId);
86
+ if (!step)
87
+ return;
88
+ step.status = status;
89
+ if (output !== undefined)
90
+ step.output = output;
91
+ if (error !== undefined)
92
+ step.error = error;
93
+ plan.updatedAt = Date.now();
94
+ // Update plan status based on steps
95
+ this.updatePlanStatus(plan);
96
+ }
97
+ /**
98
+ * Get the next pending step that can be executed.
99
+ * @returns The next pending step or undefined if none
100
+ */
101
+ getNextStep() {
102
+ const plan = this.getActivePlan();
103
+ if (!plan || plan.status === "completed" || plan.status === "failed") {
104
+ return undefined;
105
+ }
106
+ // Mark plan as executing if it was just created
107
+ if (plan.status === "created") {
108
+ plan.status = "executing";
109
+ plan.updatedAt = Date.now();
110
+ }
111
+ return plan.steps.find((step) => step.status === "pending");
112
+ }
113
+ /**
114
+ * Add a new step to the active plan.
115
+ * @param description - The step description
116
+ * @returns The created step or undefined if no active plan
117
+ */
118
+ addStep(description) {
119
+ const plan = this.getActivePlan();
120
+ if (!plan)
121
+ return undefined;
122
+ const maxIndex = plan.steps.reduce((max, s) => {
123
+ const match = s.id.match(/^step_(\d+)$/);
124
+ return match ? Math.max(max, parseInt(match[1], 10)) : max;
125
+ }, 0);
126
+ const newStep = {
127
+ id: `step_${maxIndex + 1}`,
128
+ description,
129
+ status: "pending",
130
+ };
131
+ plan.steps.push(newStep);
132
+ plan.updatedAt = Date.now();
133
+ return newStep;
134
+ }
135
+ /**
136
+ * Get a human-readable summary of the active plan.
137
+ * @returns A formatted summary string
138
+ */
139
+ getSummary() {
140
+ const plan = this.getActivePlan();
141
+ if (!plan)
142
+ return "No active plan";
143
+ const statusEmoji = {
144
+ pending: "[ ]",
145
+ in_progress: "[~]",
146
+ completed: "[x]",
147
+ failed: "[!]",
148
+ skipped: "[-]",
149
+ };
150
+ const lines = [
151
+ `Plan: ${plan.goal}`,
152
+ `Status: ${plan.status}`,
153
+ `Steps:`,
154
+ ...plan.steps.map((step) => ` ${statusEmoji[step.status]} ${step.id}: ${step.description}`),
155
+ ];
156
+ return lines.join("\n");
157
+ }
158
+ /**
159
+ * Get all plans.
160
+ * @returns Array of all plans
161
+ */
162
+ getAllPlans() {
163
+ return Array.from(this.plans.values());
164
+ }
165
+ /**
166
+ * Clear all plans.
167
+ */
168
+ clear() {
169
+ this.plans.clear();
170
+ this.activePlanId = undefined;
171
+ }
172
+ /**
173
+ * Update the overall plan status based on step statuses.
174
+ */
175
+ updatePlanStatus(plan) {
176
+ const allCompleted = plan.steps.every((s) => s.status === "completed" || s.status === "skipped");
177
+ const anyFailed = plan.steps.some((s) => s.status === "failed");
178
+ const anyInProgress = plan.steps.some((s) => s.status === "in_progress");
179
+ let newStatus;
180
+ if (allCompleted) {
181
+ newStatus = "completed";
182
+ }
183
+ else if (anyFailed) {
184
+ newStatus = "failed";
185
+ }
186
+ else if (anyInProgress || plan.steps.some((s) => s.status === "completed")) {
187
+ newStatus = "executing";
188
+ }
189
+ else {
190
+ newStatus = plan.status;
191
+ }
192
+ if (plan.status !== newStatus) {
193
+ plan.status = newStatus;
194
+ plan.updatedAt = Date.now();
195
+ }
196
+ }
197
+ }
198
+ exports.PlanStore = PlanStore;
199
+ //# sourceMappingURL=PlanStore.js.map