@synergenius/flow-weaver-pack-weaver 0.9.96 → 0.9.98
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/bot/types.d.ts +1 -0
- package/dist/bot/types.d.ts.map +1 -1
- package/dist/node-types/bot-report.d.ts +1 -1
- package/dist/node-types/bot-report.js +1 -1
- package/dist/node-types/exec-validate-retry.d.ts +1 -1
- package/dist/node-types/exec-validate-retry.js +1 -1
- package/dist/node-types/execute-plan.d.ts +1 -1
- package/dist/node-types/execute-plan.js +1 -1
- package/dist/node-types/execute-target.d.ts +1 -1
- package/dist/node-types/execute-target.js +1 -1
- package/dist/node-types/genesis-approve.d.ts +1 -1
- package/dist/node-types/genesis-approve.js +1 -1
- package/dist/node-types/genesis-check-stabilize.d.ts +1 -1
- package/dist/node-types/genesis-check-stabilize.js +1 -1
- package/dist/node-types/genesis-check-threshold.d.ts +1 -1
- package/dist/node-types/genesis-check-threshold.js +1 -1
- package/dist/node-types/genesis-compile-validate.d.ts +1 -1
- package/dist/node-types/genesis-compile-validate.js +1 -1
- package/dist/node-types/genesis-escrow-grace.d.ts +1 -1
- package/dist/node-types/genesis-escrow-grace.js +1 -1
- package/dist/node-types/genesis-escrow-validate.d.ts +1 -1
- package/dist/node-types/genesis-escrow-validate.js +1 -1
- package/dist/node-types/genesis-report.d.ts +1 -1
- package/dist/node-types/genesis-report.js +1 -1
- package/dist/node-types/genesis-snapshot.d.ts +1 -1
- package/dist/node-types/genesis-snapshot.js +1 -1
- package/dist/node-types/genesis-validate-proposal.d.ts +1 -1
- package/dist/node-types/genesis-validate-proposal.js +1 -1
- package/dist/node-types/plan-task.d.ts +1 -1
- package/dist/node-types/plan-task.js +1 -1
- package/dist/node-types/report.d.ts +1 -1
- package/dist/node-types/report.js +1 -1
- package/dist/node-types/review-result.d.ts +19 -0
- package/dist/node-types/review-result.d.ts.map +1 -0
- package/dist/node-types/review-result.js +177 -0
- package/dist/node-types/review-result.js.map +1 -0
- package/dist/node-types/validate-gate.d.ts +1 -1
- package/dist/node-types/validate-gate.js +1 -1
- package/dist/node-types/validate-result.d.ts +1 -1
- package/dist/node-types/validate-result.js +1 -1
- package/dist/workflows/weaver-bot.d.ts +8 -5
- package/dist/workflows/weaver-bot.d.ts.map +1 -1
- package/dist/workflows/weaver-bot.js +8 -5
- package/dist/workflows/weaver-bot.js.map +1 -1
- package/package.json +1 -1
- package/src/bot/types.ts +1 -0
- package/src/node-types/bot-report.ts +1 -1
- package/src/node-types/exec-validate-retry.ts +1 -1
- package/src/node-types/execute-plan.ts +1 -1
- package/src/node-types/execute-target.ts +1 -1
- package/src/node-types/genesis-approve.ts +1 -1
- package/src/node-types/genesis-check-stabilize.ts +1 -1
- package/src/node-types/genesis-check-threshold.ts +1 -1
- package/src/node-types/genesis-compile-validate.ts +1 -1
- package/src/node-types/genesis-escrow-grace.ts +1 -1
- package/src/node-types/genesis-escrow-validate.ts +1 -1
- package/src/node-types/genesis-report.ts +1 -1
- package/src/node-types/genesis-snapshot.ts +1 -1
- package/src/node-types/genesis-validate-proposal.ts +1 -1
- package/src/node-types/plan-task.ts +1 -1
- package/src/node-types/report.ts +1 -1
- package/src/node-types/review-result.ts +207 -0
- package/src/node-types/validate-gate.ts +1 -1
- package/src/node-types/validate-result.ts +1 -1
- package/src/workflows/weaver-bot.ts +9 -5
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import type { WeaverContext } from '../bot/types.js';
|
|
2
|
+
import {
|
|
3
|
+
runAgentLoop,
|
|
4
|
+
createAnthropicProvider,
|
|
5
|
+
getOrCreateCliSession,
|
|
6
|
+
type AgentProvider,
|
|
7
|
+
type StreamEvent,
|
|
8
|
+
} from '@synergenius/flow-weaver/agent';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* LLM-powered task completion reviewer.
|
|
12
|
+
* Makes a single judgment call: did the bot accomplish the assigned task?
|
|
13
|
+
*
|
|
14
|
+
* @flowWeaver nodeType
|
|
15
|
+
* @label Review Result
|
|
16
|
+
* @icon spellcheck
|
|
17
|
+
* @color green
|
|
18
|
+
* @input ctx [order:0] - Weaver context with results (JSON)
|
|
19
|
+
* @output ctx [order:0] - Weaver context with review (JSON)
|
|
20
|
+
* @output onSuccess [order:-2] - Review passed
|
|
21
|
+
* @output onFailure [order:-1] [hidden] - Review failed
|
|
22
|
+
*/
|
|
23
|
+
export async function weaverReviewResult(
|
|
24
|
+
execute: boolean,
|
|
25
|
+
ctx: string,
|
|
26
|
+
): Promise<{
|
|
27
|
+
onSuccess: boolean; onFailure: boolean;
|
|
28
|
+
ctx: string;
|
|
29
|
+
}> {
|
|
30
|
+
const context = JSON.parse(ctx) as WeaverContext;
|
|
31
|
+
|
|
32
|
+
if (!execute) {
|
|
33
|
+
context.reviewJson = JSON.stringify({ pass: true, reason: 'Dry run' });
|
|
34
|
+
return { onSuccess: true, onFailure: false, ctx: JSON.stringify(context) };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Extract task info
|
|
38
|
+
let taskTitle = 'Unknown task';
|
|
39
|
+
let taskDescription = '';
|
|
40
|
+
try {
|
|
41
|
+
const task = JSON.parse(context.taskJson ?? '{}');
|
|
42
|
+
const instruction = task.instruction ?? '';
|
|
43
|
+
const titleMatch = instruction.match(/^##\s*Task:\s*(.+)/m);
|
|
44
|
+
taskTitle = titleMatch ? titleMatch[1].trim() : (instruction.split('\n')[0] || 'Unknown task');
|
|
45
|
+
// Description is everything after the title line until the next ## heading
|
|
46
|
+
const descMatch = instruction.match(/^##\s*Task:[^\n]*\n\n([\s\S]*?)(?=\n##|\n*$)/m);
|
|
47
|
+
taskDescription = descMatch ? descMatch[1].trim() : '';
|
|
48
|
+
} catch { /* use defaults */ }
|
|
49
|
+
|
|
50
|
+
// Extract evidence
|
|
51
|
+
let toolCalls = 'none';
|
|
52
|
+
try {
|
|
53
|
+
const steps = JSON.parse(context.stepLogJson ?? '[]') as Array<{ step: string; status: string }>;
|
|
54
|
+
if (steps.length > 0) {
|
|
55
|
+
toolCalls = steps.map(s => `${s.step} (${s.status})`).join(', ');
|
|
56
|
+
}
|
|
57
|
+
} catch { /* use default */ }
|
|
58
|
+
|
|
59
|
+
let filesModified = 'none';
|
|
60
|
+
try {
|
|
61
|
+
const files = JSON.parse(context.filesModified ?? '[]') as string[];
|
|
62
|
+
if (files.length > 0) filesModified = files.join(', ');
|
|
63
|
+
} catch { /* use default */ }
|
|
64
|
+
|
|
65
|
+
let agentSummary = 'No summary available';
|
|
66
|
+
try {
|
|
67
|
+
const result = JSON.parse(context.resultJson ?? '{}');
|
|
68
|
+
if (result.summary) agentSummary = result.summary;
|
|
69
|
+
} catch { /* use default */ }
|
|
70
|
+
|
|
71
|
+
const prompt = `You are reviewing whether a bot completed its assigned task.
|
|
72
|
+
|
|
73
|
+
## Task
|
|
74
|
+
${taskTitle}
|
|
75
|
+
${taskDescription}
|
|
76
|
+
|
|
77
|
+
## What the bot did
|
|
78
|
+
Tool calls: ${toolCalls}
|
|
79
|
+
Files modified: ${filesModified}
|
|
80
|
+
Bot's summary: ${agentSummary}
|
|
81
|
+
|
|
82
|
+
Did the bot accomplish the task? Judge based on what was asked vs what was done.
|
|
83
|
+
|
|
84
|
+
Respond with exactly: {"pass": true/false, "reason": "one sentence"}`;
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const { env } = context;
|
|
88
|
+
const pInfo = env.providerInfo;
|
|
89
|
+
const provider = await createReviewProvider(pInfo, env.projectDir);
|
|
90
|
+
|
|
91
|
+
const result = await runAgentLoop(
|
|
92
|
+
provider,
|
|
93
|
+
[], // no tools needed — just a judgment call
|
|
94
|
+
async () => ({ result: '', isError: true }), // no-op executor
|
|
95
|
+
[{ role: 'user', content: prompt }],
|
|
96
|
+
{ maxIterations: 1 },
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
// Parse the response
|
|
100
|
+
let pass = true;
|
|
101
|
+
let reason = 'Review completed';
|
|
102
|
+
const jsonMatch = result.summary.match(/\{[\s\S]*"pass"[\s\S]*\}/);
|
|
103
|
+
if (jsonMatch) {
|
|
104
|
+
try {
|
|
105
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
106
|
+
pass = parsed.pass === true;
|
|
107
|
+
reason = parsed.reason ?? reason;
|
|
108
|
+
} catch {
|
|
109
|
+
// JSON-like but unparseable — check for fail signal in matched text
|
|
110
|
+
if (jsonMatch[0].includes('"pass": false') || jsonMatch[0].includes('"pass":false')) {
|
|
111
|
+
pass = false;
|
|
112
|
+
reason = result.summary.slice(0, 200);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
} else {
|
|
116
|
+
// No JSON found — check for obvious fail signals in raw text
|
|
117
|
+
const lower = result.summary.toLowerCase();
|
|
118
|
+
if (lower.includes('"pass": false') || lower.includes('"pass":false')) {
|
|
119
|
+
pass = false;
|
|
120
|
+
reason = result.summary.slice(0, 200);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
context.reviewJson = JSON.stringify({ pass, reason });
|
|
125
|
+
|
|
126
|
+
if (!pass) {
|
|
127
|
+
console.log(`\x1b[33m→ Review FAILED: ${reason}\x1b[0m`);
|
|
128
|
+
} else {
|
|
129
|
+
console.log(`\x1b[32m→ Review passed: ${reason}\x1b[0m`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return { onSuccess: pass, onFailure: !pass, ctx: JSON.stringify(context) };
|
|
133
|
+
} catch (err) {
|
|
134
|
+
// Review failure is non-fatal — don't block the pipeline
|
|
135
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
136
|
+
console.log(`\x1b[33m→ Review skipped (error): ${msg}\x1b[0m`);
|
|
137
|
+
context.reviewJson = JSON.stringify({ pass: true, reason: `Review skipped: ${msg}` });
|
|
138
|
+
return { onSuccess: true, onFailure: false, ctx: JSON.stringify(context) };
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Create a provider for the review call — same logic as agent-execute.
|
|
144
|
+
*/
|
|
145
|
+
async function createReviewProvider(
|
|
146
|
+
pInfo: { type: string; apiKey?: string; model?: string; maxTokens?: number },
|
|
147
|
+
projectDir?: string,
|
|
148
|
+
): Promise<AgentProvider> {
|
|
149
|
+
const type = pInfo.type ?? 'auto';
|
|
150
|
+
|
|
151
|
+
if (type === 'anthropic' && pInfo.apiKey) {
|
|
152
|
+
return createAnthropicProvider({
|
|
153
|
+
apiKey: pInfo.apiKey,
|
|
154
|
+
model: pInfo.model,
|
|
155
|
+
maxTokens: 256,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (type === 'claude-cli') {
|
|
160
|
+
const key = projectDir ?? process.cwd();
|
|
161
|
+
const session = getOrCreateCliSession(`${key}:reviewer`, {
|
|
162
|
+
binPath: 'claude',
|
|
163
|
+
cwd: key,
|
|
164
|
+
model: pInfo.model ?? 'claude-sonnet-4-6',
|
|
165
|
+
});
|
|
166
|
+
return new CliReviewProvider(session);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (type === 'auto') {
|
|
170
|
+
if (process.env.ANTHROPIC_API_KEY) {
|
|
171
|
+
return createAnthropicProvider({
|
|
172
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
173
|
+
model: pInfo.model,
|
|
174
|
+
maxTokens: 256,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
const key = projectDir ?? process.cwd();
|
|
178
|
+
const session = getOrCreateCliSession(`${key}:reviewer`, {
|
|
179
|
+
binPath: 'claude',
|
|
180
|
+
cwd: key,
|
|
181
|
+
model: pInfo.model ?? 'claude-sonnet-4-6',
|
|
182
|
+
});
|
|
183
|
+
return new CliReviewProvider(session);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
throw new Error(`Unsupported provider type: ${type}`);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
class CliReviewProvider implements AgentProvider {
|
|
190
|
+
constructor(
|
|
191
|
+
private session: { ready: boolean; spawn: () => Promise<void>; send: (msg: string) => AsyncGenerator<StreamEvent> },
|
|
192
|
+
) {}
|
|
193
|
+
|
|
194
|
+
async *stream(
|
|
195
|
+
messages: import('@synergenius/flow-weaver/agent').AgentMessage[],
|
|
196
|
+
_tools: import('@synergenius/flow-weaver/agent').ToolDefinition[],
|
|
197
|
+
_options?: import('@synergenius/flow-weaver/agent').StreamOptions,
|
|
198
|
+
): AsyncGenerator<StreamEvent> {
|
|
199
|
+
if (!this.session.ready) await this.session.spawn();
|
|
200
|
+
const prompt = messages
|
|
201
|
+
.map(m => typeof m.content === 'string' ? m.content : JSON.stringify(m.content))
|
|
202
|
+
.filter(Boolean)
|
|
203
|
+
.join('\n');
|
|
204
|
+
if (!prompt) return;
|
|
205
|
+
yield* this.session.send(prompt);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
@@ -9,7 +9,7 @@ import type { WeaverContext } from '../bot/types.js';
|
|
|
9
9
|
* @flowWeaver nodeType
|
|
10
10
|
* @expression
|
|
11
11
|
* @label Validate Gate
|
|
12
|
-
* @icon
|
|
12
|
+
* @icon checkCircle
|
|
13
13
|
* @color green
|
|
14
14
|
* @input ctx [order:0] - Weaver context (JSON)
|
|
15
15
|
* @output ctx [order:0] - Weaver context with validation result (JSON)
|
|
@@ -8,7 +8,7 @@ import { validateFiles } from '../bot/file-validator.js';
|
|
|
8
8
|
* @flowWeaver nodeType
|
|
9
9
|
* @expression
|
|
10
10
|
* @label Validate Result
|
|
11
|
-
* @icon
|
|
11
|
+
* @icon checkCircle
|
|
12
12
|
* @color green
|
|
13
13
|
* @input env [order:0] - Weaver environment bundle
|
|
14
14
|
* @input executionResultJson [order:1] - Execution result (JSON)
|
|
@@ -11,6 +11,7 @@ import { weaverPlanTask } from '../node-types/plan-task.js';
|
|
|
11
11
|
import { weaverApprovalGate } from '../node-types/approval-gate.js';
|
|
12
12
|
import { weaverAbortTask } from '../node-types/abort-task.js';
|
|
13
13
|
import { weaverExecValidateRetry } from '../node-types/exec-validate-retry.js';
|
|
14
|
+
import { weaverReviewResult } from '../node-types/review-result.js';
|
|
14
15
|
import { weaverGitOps } from '../node-types/git-ops.js';
|
|
15
16
|
import { weaverSendNotify } from '../node-types/send-notify.js';
|
|
16
17
|
import { weaverBotReport } from '../node-types/bot-report.js';
|
|
@@ -37,21 +38,24 @@ declare const __flowWeaverDebugger__: TDebugger | undefined;
|
|
|
37
38
|
* @node approve weaverApprovalGate [color: "orange"] [icon: "send"] [position: 1400 200]
|
|
38
39
|
* @node abort weaverAbortTask [color: "red"] [icon: "code"] [position: 1600 450]
|
|
39
40
|
* @node execRetry weaverExecValidateRetry [color: "purple"] [icon: "code"] [position: 1600 200]
|
|
40
|
-
* @node
|
|
41
|
-
* @node
|
|
42
|
-
* @node
|
|
43
|
-
* @
|
|
41
|
+
* @node review weaverReviewResult [color: "green"] [icon: "spellcheck"] [position: 1700 200]
|
|
42
|
+
* @node gitOps weaverGitOps [color: "green"] [icon: "code"] [position: 1900 100]
|
|
43
|
+
* @node notify weaverSendNotify [color: "yellow"] [icon: "send"] [position: 1900 300] [suppress: "UNUSED_OUTPUT_PORT"]
|
|
44
|
+
* @node report weaverBotReport [color: "green"] [icon: "description"] [position: 2100 200] [suppress: "UNUSED_OUTPUT_PORT", "DESIGN_ASYNC_NO_ERROR_PATH"]
|
|
45
|
+
* @path Start -> cfg -> detect -> receive -> route -> context -> plan -> approve -> execRetry -> review -> gitOps -> report -> Exit
|
|
44
46
|
* @path execRetry -> notify
|
|
45
47
|
* @path route:fail -> readWf
|
|
46
48
|
* @path approve:fail -> abort
|
|
47
49
|
* @path receive:fail -> report
|
|
48
50
|
* @path plan:fail -> report
|
|
49
51
|
* @path execRetry:fail -> report
|
|
52
|
+
* @path review:fail -> report
|
|
50
53
|
* @position Start 0 200
|
|
51
|
-
* @position Exit
|
|
54
|
+
* @position Exit 2300 200
|
|
52
55
|
* @connect readWf.onSuccess -> report.execute
|
|
53
56
|
* @connect abort.onSuccess -> report.execute
|
|
54
57
|
* @connect notify.onSuccess -> report.execute
|
|
58
|
+
* @connect review.ctx -> gitOps.ctx
|
|
55
59
|
* @connect gitOps.ctx -> report.mainCtx
|
|
56
60
|
* @connect readWf.ctx -> report.readCtx
|
|
57
61
|
* @connect abort.ctx -> report.abortCtx
|