@synergenius/flow-weaver-pack-weaver 0.9.152 → 0.9.154
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/dist/ai-chat-provider.js +4 -4
- package/dist/ai-chat-provider.js.map +1 -1
- package/dist/bot/ai-client.d.ts +30 -0
- package/dist/bot/ai-client.d.ts.map +1 -1
- package/dist/bot/ai-client.js +37 -0
- package/dist/bot/ai-client.js.map +1 -1
- package/dist/bot/behavior-defaults.d.ts.map +1 -1
- package/dist/bot/behavior-defaults.js +7 -2
- package/dist/bot/behavior-defaults.js.map +1 -1
- package/dist/bot/capability-registry.d.ts.map +1 -1
- package/dist/bot/capability-registry.js +46 -33
- package/dist/bot/capability-registry.js.map +1 -1
- package/dist/bot/file-validator.d.ts +7 -0
- package/dist/bot/file-validator.d.ts.map +1 -1
- package/dist/bot/file-validator.js +76 -0
- package/dist/bot/file-validator.js.map +1 -1
- package/dist/bot/instance-manager.d.ts +22 -7
- package/dist/bot/instance-manager.d.ts.map +1 -1
- package/dist/bot/instance-manager.js +69 -7
- package/dist/bot/instance-manager.js.map +1 -1
- package/dist/bot/orchestrator.d.ts +11 -9
- package/dist/bot/orchestrator.d.ts.map +1 -1
- package/dist/bot/orchestrator.js +56 -107
- package/dist/bot/orchestrator.js.map +1 -1
- package/dist/bot/runner.d.ts +29 -0
- package/dist/bot/runner.d.ts.map +1 -1
- package/dist/bot/runner.js +114 -73
- package/dist/bot/runner.js.map +1 -1
- package/dist/bot/step-executor.d.ts.map +1 -1
- package/dist/bot/step-executor.js +28 -9
- package/dist/bot/step-executor.js.map +1 -1
- package/dist/bot/swarm-controller.d.ts +7 -6
- package/dist/bot/swarm-controller.d.ts.map +1 -1
- package/dist/bot/swarm-controller.js +64 -74
- package/dist/bot/swarm-controller.js.map +1 -1
- package/dist/bot/system-prompt.d.ts.map +1 -1
- package/dist/bot/system-prompt.js +2 -0
- package/dist/bot/system-prompt.js.map +1 -1
- package/dist/bot/task-types.d.ts +1 -0
- package/dist/bot/task-types.d.ts.map +1 -1
- package/dist/bot/weaver-tools.d.ts +1 -1
- package/dist/bot/weaver-tools.d.ts.map +1 -1
- package/dist/bot/weaver-tools.js +12 -1
- package/dist/bot/weaver-tools.js.map +1 -1
- package/dist/node-types/agent-execute.js +2 -2
- package/dist/node-types/agent-execute.js.map +1 -1
- package/dist/node-types/bot-report.d.ts.map +1 -1
- package/dist/node-types/bot-report.js +5 -2
- package/dist/node-types/bot-report.js.map +1 -1
- package/dist/node-types/build-context.d.ts.map +1 -1
- package/dist/node-types/build-context.js +13 -1
- package/dist/node-types/build-context.js.map +1 -1
- package/dist/node-types/exec-validate-retry.d.ts +3 -3
- package/dist/node-types/exec-validate-retry.d.ts.map +1 -1
- package/dist/node-types/exec-validate-retry.js +13 -184
- package/dist/node-types/exec-validate-retry.js.map +1 -1
- package/dist/node-types/load-config.d.ts +1 -0
- package/dist/node-types/load-config.d.ts.map +1 -1
- package/dist/node-types/load-config.js +1 -0
- package/dist/node-types/load-config.js.map +1 -1
- package/dist/node-types/plan-task.d.ts +7 -5
- package/dist/node-types/plan-task.d.ts.map +1 -1
- package/dist/node-types/plan-task.js +282 -83
- package/dist/node-types/plan-task.js.map +1 -1
- package/dist/ui/bot-panel.js +1 -1
- package/dist/ui/capability-editor.js +46 -33
- package/dist/ui/chat-task-result.js +7 -7
- package/dist/ui/profile-editor.js +44 -31
- package/dist/ui/swarm-dashboard.js +80 -47
- package/dist/ui/task-detail-view.js +31 -11
- package/dist/ui/task-editor.js +1 -1
- package/dist/ui/task-pool-list.js +1 -1
- package/dist/workflows/weaver-bot.d.ts +5 -4
- package/dist/workflows/weaver-bot.d.ts.map +1 -1
- package/dist/workflows/weaver-bot.js +8 -7
- package/dist/workflows/weaver-bot.js.map +1 -1
- package/flowweaver.manifest.json +1 -1
- package/package.json +1 -1
- package/src/ai-chat-provider.ts +4 -4
- package/src/bot/ai-client.ts +65 -0
- package/src/bot/behavior-defaults.ts +5 -2
- package/src/bot/capability-registry.ts +46 -33
- package/src/bot/file-validator.ts +97 -0
- package/src/bot/instance-manager.ts +77 -7
- package/src/bot/orchestrator.ts +63 -126
- package/src/bot/runner.ts +124 -70
- package/src/bot/step-executor.ts +30 -9
- package/src/bot/swarm-controller.ts +65 -76
- package/src/bot/system-prompt.ts +2 -0
- package/src/bot/task-types.ts +1 -0
- package/src/bot/weaver-tools.ts +14 -1
- package/src/node-types/agent-execute.ts +2 -2
- package/src/node-types/bot-report.ts +5 -2
- package/src/node-types/build-context.ts +13 -1
- package/src/node-types/exec-validate-retry.ts +14 -203
- package/src/node-types/load-config.ts +1 -0
- package/src/node-types/plan-task.ts +313 -88
- package/src/ui/bot-panel.tsx +1 -1
- package/src/ui/chat-task-result.tsx +10 -8
- package/src/ui/swarm-dashboard.tsx +4 -4
- package/src/ui/task-detail-view.tsx +35 -12
- package/src/ui/task-editor.tsx +2 -2
- package/src/ui/task-pool-list.tsx +2 -2
- package/src/workflows/weaver-bot.ts +8 -7
|
@@ -1,16 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import * as path from 'node:path';
|
|
3
|
-
import * as os from 'node:os';
|
|
4
|
-
import type { WeaverContext, StepLogEntry } from '../bot/types.js';
|
|
5
|
-
import { callAI, parseJsonResponse, normalizePlan } from '../bot/ai-client.js';
|
|
6
|
-
import { executeStep } from '../bot/step-executor.js';
|
|
7
|
-
import { validateFiles } from '../bot/file-validator.js';
|
|
8
|
-
import { auditEmit } from '../bot/audit-logger.js';
|
|
9
|
-
import { PASSTHROUGH_OPERATIONS } from '../bot/operations.js';
|
|
1
|
+
import type { WeaverContext } from '../bot/types.js';
|
|
10
2
|
|
|
11
3
|
/**
|
|
12
|
-
* Execute-validate
|
|
13
|
-
*
|
|
4
|
+
* Execute-validate passthrough. The agent loop (plan-task) now handles
|
|
5
|
+
* both planning and execution, so this node simply passes context through.
|
|
14
6
|
*
|
|
15
7
|
* @flowWeaver nodeType
|
|
16
8
|
* @label Execute & Validate
|
|
@@ -25,209 +17,28 @@ import { PASSTHROUGH_OPERATIONS } from '../bot/operations.js';
|
|
|
25
17
|
export async function weaverExecValidateRetry(
|
|
26
18
|
execute: boolean,
|
|
27
19
|
ctx: string,
|
|
28
|
-
|
|
20
|
+
_modelOverride?: string,
|
|
29
21
|
): Promise<{
|
|
30
22
|
onSuccess: boolean; onFailure: boolean;
|
|
31
23
|
ctx: string;
|
|
32
24
|
}> {
|
|
33
25
|
const context = JSON.parse(ctx) as WeaverContext;
|
|
34
|
-
const { env } = context;
|
|
35
26
|
|
|
36
27
|
if (!execute) {
|
|
37
|
-
context.resultJson = JSON.stringify({ success: true, stepsCompleted: 0, stepsTotal: 0 });
|
|
38
|
-
context.validationResultJson = '[]';
|
|
39
|
-
context.filesModified = '[]';
|
|
40
|
-
context.allValid = true;
|
|
28
|
+
context.resultJson = context.resultJson ?? JSON.stringify({ success: true, stepsCompleted: 0, stepsTotal: 0 });
|
|
29
|
+
context.validationResultJson = context.validationResultJson ?? '[]';
|
|
30
|
+
context.filesModified = context.filesModified ?? '[]';
|
|
31
|
+
context.allValid = context.allValid ?? true;
|
|
41
32
|
return { onSuccess: true, onFailure: false, ctx: JSON.stringify(context) };
|
|
42
33
|
}
|
|
43
34
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const { projectDir } = env;
|
|
48
|
-
let currentPlan = JSON.parse(context.planJson!);
|
|
49
|
-
|
|
50
|
-
// Short-circuit: if ALL steps are passthrough operations (respond, no-op, etc.),
|
|
51
|
-
// skip the execute→validate→fix loop entirely. The plan already has the answer.
|
|
52
|
-
const PASSTHROUGH_OPS = PASSTHROUGH_OPERATIONS;
|
|
53
|
-
const steps = currentPlan.steps ?? [];
|
|
54
|
-
if (steps.length > 0 && steps.every((s: { operation: string }) => PASSTHROUGH_OPS.has(s.operation))) {
|
|
55
|
-
console.log(`\x1b[36m→ Text-only plan (${steps.length} passthrough steps), skipping execution loop\x1b[0m`);
|
|
56
|
-
context.resultJson = JSON.stringify({ success: true, stepsCompleted: steps.length, stepsTotal: steps.length });
|
|
57
|
-
context.validationResultJson = '[]';
|
|
58
|
-
context.filesModified = '[]';
|
|
59
|
-
context.allValid = true;
|
|
60
|
-
return { onSuccess: true, onFailure: false, ctx: JSON.stringify(context) };
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const maxAttempts = 3;
|
|
64
|
-
const taskDeadline = Date.now() + 180_000; // 3 minute max per task
|
|
65
|
-
let allFilesModified: string[] = [];
|
|
66
|
-
let allStepLog: StepLogEntry[] = [];
|
|
67
|
-
let lastExecResult: Record<string, unknown> = {};
|
|
68
|
-
let lastValidation: Array<{ file: string; valid: boolean; errors: string[] }> = [];
|
|
69
|
-
let allValid = false;
|
|
70
|
-
let prevErrorCount = Infinity;
|
|
71
|
-
const symbolicIdMap: Record<string, string> = {};
|
|
72
|
-
|
|
73
|
-
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
74
|
-
// Task timeout — stop if we've exceeded the deadline
|
|
75
|
-
if (Date.now() > taskDeadline) {
|
|
76
|
-
console.error('\x1b[33m→ Task timeout (3 min), moving on\x1b[0m');
|
|
77
|
-
break;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
console.log(`\x1b[36m→ Attempt ${attempt}/${maxAttempts}\x1b[0m`);
|
|
81
|
-
auditEmit('step-start', { attempt, stepCount: currentPlan.steps?.length });
|
|
82
|
-
|
|
83
|
-
const execResult = await executePlanSteps(currentPlan, projectDir, symbolicIdMap);
|
|
84
|
-
lastExecResult = execResult;
|
|
85
|
-
allFilesModified = [...new Set([...allFilesModified, ...execResult.filesModified])];
|
|
86
|
-
allStepLog.push(...execResult.stepLog);
|
|
87
|
-
auditEmit('step-complete', { attempt, filesModified: execResult.filesModified, errors: execResult.errors });
|
|
88
|
-
|
|
89
|
-
const validation = await validateFiles(execResult.filesModified, projectDir);
|
|
90
|
-
lastValidation = validation;
|
|
91
|
-
allValid = validation.every(v => v.valid);
|
|
92
|
-
const errorCount = validation.filter(v => !v.valid).length;
|
|
93
|
-
auditEmit('validation-run', { attempt, allValid, errorCount });
|
|
94
|
-
|
|
95
|
-
// Stop retrying if errors didn't decrease — AI is stuck
|
|
96
|
-
if (attempt > 1 && errorCount >= prevErrorCount) {
|
|
97
|
-
console.error(`\x1b[33m→ Errors not decreasing (${errorCount} >= ${prevErrorCount}), stopping retry\x1b[0m`);
|
|
98
|
-
break;
|
|
99
|
-
}
|
|
100
|
-
prevErrorCount = errorCount;
|
|
101
|
-
|
|
102
|
-
// Collect design warnings from valid files
|
|
103
|
-
const designWarnings = validation
|
|
104
|
-
.filter(v => v.valid && v.warnings.length > 0)
|
|
105
|
-
.map(v => `${v.file}:\n${v.warnings.map(w => ` - ${w}`).join('\n')}`)
|
|
106
|
-
.join('\n');
|
|
107
|
-
|
|
108
|
-
if (allValid && !designWarnings) {
|
|
109
|
-
console.log('\x1b[32m→ All files valid, no design issues\x1b[0m');
|
|
110
|
-
break;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (allValid && designWarnings) {
|
|
114
|
-
console.log('\x1b[32m→ All files valid\x1b[0m');
|
|
115
|
-
console.log(`\x1b[33m→ Design warnings:\n${designWarnings}\x1b[0m`);
|
|
116
|
-
// Design warnings don't block, but include them for the AI on the next attempt
|
|
117
|
-
if (attempt < maxAttempts) {
|
|
118
|
-
// Only retry for design issues if there are warning/error severity checks
|
|
119
|
-
const hasActionable = validation.some(v =>
|
|
120
|
-
v.designReport?.checks.some(c => c.severity === 'warning' || c.severity === 'error'),
|
|
121
|
-
);
|
|
122
|
-
if (!hasActionable) break;
|
|
123
|
-
} else {
|
|
124
|
-
break;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
if (attempt < maxAttempts) {
|
|
129
|
-
console.log(`\x1b[33m→ Validation errors found, requesting fix plan...\x1b[0m`);
|
|
130
|
-
const validationErrors = validation.filter(v => !v.valid).map(v => `${v.file}: ${v.errors.join(', ')}`).join('\n');
|
|
131
|
-
const errors = [validationErrors, designWarnings].filter(Boolean).join('\n\nDesign issues:\n');
|
|
132
|
-
|
|
133
|
-
try {
|
|
134
|
-
auditEmit('fix-attempt', { attempt });
|
|
135
|
-
|
|
136
|
-
let systemPrompt: string;
|
|
137
|
-
try {
|
|
138
|
-
const mod = await import('../bot/system-prompt.js');
|
|
139
|
-
systemPrompt = await mod.buildSystemPrompt();
|
|
140
|
-
} catch (err) {
|
|
141
|
-
if (process.env.WEAVER_VERBOSE) console.error('[exec-validate-retry] system prompt build failed:', err);
|
|
142
|
-
systemPrompt = 'You are Weaver. Return ONLY valid JSON.';
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Include step outputs so the AI has context from discovery steps
|
|
146
|
-
const outputContext = Object.entries(execResult.stepOutputs)
|
|
147
|
-
.map(([id, out]) => `--- Output of ${id} ---\n${out}`)
|
|
148
|
-
.join('\n\n');
|
|
149
|
-
|
|
150
|
-
const fixPrompt = `The following validation errors occurred:\n${errors}\n\n${outputContext ? `Discovery step outputs:\n${outputContext}\n\n` : ''}Provide a CONCRETE fix plan. Every patch_file step MUST include "file" (absolute path from the outputs above) and "patches" array with exact "find"/"replace" strings. Do NOT use placeholders.`;
|
|
151
|
-
|
|
152
|
-
const text = await callAI(pInfo, systemPrompt, fixPrompt, 8192);
|
|
153
|
-
|
|
154
|
-
const parsed = parseJsonResponse(text);
|
|
155
|
-
currentPlan = normalizePlan(parsed);
|
|
156
|
-
console.log(`\x1b[36m→ Fix plan: ${currentPlan.summary} (${currentPlan.steps.length} steps)\x1b[0m`);
|
|
157
|
-
} catch (err: unknown) {
|
|
158
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
159
|
-
console.error(`\x1b[31m→ Fix planning failed: ${msg}\x1b[0m`);
|
|
160
|
-
break;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
context.resultJson = JSON.stringify(lastExecResult);
|
|
166
|
-
context.validationResultJson = JSON.stringify(lastValidation);
|
|
167
|
-
context.filesModified = JSON.stringify(allFilesModified);
|
|
168
|
-
context.stepLogJson = JSON.stringify(allStepLog);
|
|
35
|
+
// Agent loop already executed everything — pass context through.
|
|
36
|
+
// Preserve allValid from the agent loop's results.
|
|
37
|
+
const allValid = context.allValid ?? true;
|
|
169
38
|
context.allValid = allValid;
|
|
39
|
+
context.resultJson = context.resultJson ?? JSON.stringify({ success: allValid, stepsCompleted: 0, stepsTotal: 0 });
|
|
40
|
+
context.validationResultJson = context.validationResultJson ?? '[]';
|
|
41
|
+
context.filesModified = context.filesModified ?? '[]';
|
|
170
42
|
|
|
171
43
|
return { onSuccess: allValid, onFailure: !allValid, ctx: JSON.stringify(context) };
|
|
172
44
|
}
|
|
173
|
-
|
|
174
|
-
async function executePlanSteps(
|
|
175
|
-
plan: { steps: Array<{ id: string; operation: string; description: string; args: Record<string, unknown> }> },
|
|
176
|
-
projectDir: string,
|
|
177
|
-
symbolicIdMap: Record<string, string> = {},
|
|
178
|
-
): Promise<{ success: boolean; filesModified: string[]; errors: string[]; stepsCompleted: number; stepsTotal: number; stepLog: StepLogEntry[]; stepOutputs: Record<string, string> }> {
|
|
179
|
-
const filesModified: string[] = [];
|
|
180
|
-
const errors: string[] = [];
|
|
181
|
-
const stepLog: StepLogEntry[] = [];
|
|
182
|
-
const stepOutputs: Record<string, string> = {};
|
|
183
|
-
let completed = 0;
|
|
184
|
-
const steps = plan.steps ?? [];
|
|
185
|
-
|
|
186
|
-
for (const step of steps) {
|
|
187
|
-
const steering = checkSteeringSignal();
|
|
188
|
-
if (steering === 'cancel') {
|
|
189
|
-
errors.push(`Cancelled at step ${step.id}`);
|
|
190
|
-
stepLog.push({ step: step.id, status: 'error', detail: 'Cancelled by steering signal' });
|
|
191
|
-
break;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
try {
|
|
195
|
-
const result = await executeStep(step, projectDir, symbolicIdMap);
|
|
196
|
-
if (result.blocked) {
|
|
197
|
-
console.error(`\x1b[33m ⚠ ${step.id}: ${result.blockReason}\x1b[0m`);
|
|
198
|
-
stepLog.push({ step: step.id, status: 'blocked', detail: result.blockReason });
|
|
199
|
-
continue;
|
|
200
|
-
}
|
|
201
|
-
if (result.file) filesModified.push(result.file);
|
|
202
|
-
if (result.files) filesModified.push(...result.files);
|
|
203
|
-
// Capture step output for feeding into fix prompts
|
|
204
|
-
if (result.output) {
|
|
205
|
-
stepOutputs[step.id] = result.output.slice(0, 4000); // cap at 4k to fit in prompt
|
|
206
|
-
}
|
|
207
|
-
completed++;
|
|
208
|
-
console.log(`\x1b[32m + ${step.id}: ${step.description}\x1b[0m`);
|
|
209
|
-
stepLog.push({ step: step.id, status: 'ok', detail: step.description });
|
|
210
|
-
} catch (err: unknown) {
|
|
211
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
212
|
-
errors.push(`${step.id}: ${msg}`);
|
|
213
|
-
console.error(`\x1b[31m x ${step.id}: ${msg}\x1b[0m`);
|
|
214
|
-
stepLog.push({ step: step.id, status: 'error', detail: msg });
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
return { success: errors.length === 0, filesModified: [...new Set(filesModified)], errors, stepsCompleted: completed, stepsTotal: steps.length, stepLog, stepOutputs };
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
function checkSteeringSignal(): 'cancel' | null {
|
|
222
|
-
try {
|
|
223
|
-
const controlPath = path.join(os.homedir(), '.weaver', 'control.json');
|
|
224
|
-
if (!fs.existsSync(controlPath)) return null;
|
|
225
|
-
const raw = fs.readFileSync(controlPath, 'utf-8');
|
|
226
|
-
fs.unlinkSync(controlPath);
|
|
227
|
-
const cmd = JSON.parse(raw) as { command: string };
|
|
228
|
-
if (cmd.command === 'cancel') return 'cancel';
|
|
229
|
-
return null;
|
|
230
|
-
} catch {
|
|
231
|
-
return null;
|
|
232
|
-
}
|
|
233
|
-
}
|