@synergenius/flow-weaver-pack-weaver 0.9.200 → 0.9.201
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 +5 -5
- package/dist/ai-chat-provider.js.map +1 -1
- package/dist/bot/acceptance-merge.d.ts +21 -0
- package/dist/bot/acceptance-merge.d.ts.map +1 -0
- package/dist/bot/acceptance-merge.js +46 -0
- package/dist/bot/acceptance-merge.js.map +1 -0
- package/dist/bot/ai-client.d.ts +14 -2
- package/dist/bot/ai-client.d.ts.map +1 -1
- package/dist/bot/ai-client.js +71 -24
- package/dist/bot/ai-client.js.map +1 -1
- package/dist/bot/assistant-tools.js +3 -3
- package/dist/bot/assistant-tools.js.map +1 -1
- package/dist/bot/audit-logger.d.ts.map +1 -1
- package/dist/bot/audit-logger.js +34 -14
- package/dist/bot/audit-logger.js.map +1 -1
- package/dist/bot/audit-trail.d.ts +67 -0
- package/dist/bot/audit-trail.d.ts.map +1 -0
- package/dist/bot/audit-trail.js +153 -0
- package/dist/bot/audit-trail.js.map +1 -0
- package/dist/bot/behavior-defaults.d.ts +1 -1
- package/dist/bot/behavior-defaults.d.ts.map +1 -1
- package/dist/bot/behavior-defaults.js +7 -3
- package/dist/bot/behavior-defaults.js.map +1 -1
- package/dist/bot/capability-registry.d.ts +9 -0
- package/dist/bot/capability-registry.d.ts.map +1 -1
- package/dist/bot/capability-registry.js +81 -27
- package/dist/bot/capability-registry.js.map +1 -1
- package/dist/bot/capability-types.d.ts +10 -0
- package/dist/bot/capability-types.d.ts.map +1 -1
- package/dist/bot/cli-provider.d.ts.map +1 -1
- package/dist/bot/cli-provider.js +8 -7
- package/dist/bot/cli-provider.js.map +1 -1
- package/dist/bot/preflight.d.ts +48 -0
- package/dist/bot/preflight.d.ts.map +1 -0
- package/dist/bot/preflight.js +247 -0
- package/dist/bot/preflight.js.map +1 -0
- package/dist/bot/provider-shim.d.ts +74 -0
- package/dist/bot/provider-shim.d.ts.map +1 -0
- package/dist/bot/provider-shim.js +176 -0
- package/dist/bot/provider-shim.js.map +1 -0
- package/dist/bot/runner.d.ts +2 -0
- package/dist/bot/runner.d.ts.map +1 -1
- package/dist/bot/runner.js +60 -17
- package/dist/bot/runner.js.map +1 -1
- package/dist/bot/step-executor.d.ts.map +1 -1
- package/dist/bot/step-executor.js +72 -115
- package/dist/bot/step-executor.js.map +1 -1
- package/dist/bot/swarm-controller.d.ts +2 -0
- package/dist/bot/swarm-controller.d.ts.map +1 -1
- package/dist/bot/swarm-controller.js +92 -20
- package/dist/bot/swarm-controller.js.map +1 -1
- package/dist/bot/task-create-handler.d.ts +37 -0
- package/dist/bot/task-create-handler.d.ts.map +1 -0
- package/dist/bot/task-create-handler.js +124 -0
- package/dist/bot/task-create-handler.js.map +1 -0
- package/dist/bot/task-store.d.ts +1 -0
- package/dist/bot/task-store.d.ts.map +1 -1
- package/dist/bot/task-store.js +61 -0
- package/dist/bot/task-store.js.map +1 -1
- package/dist/bot/types.d.ts +1 -1
- package/dist/bot/types.d.ts.map +1 -1
- package/dist/bot/weaver-tools.d.ts.map +1 -1
- package/dist/bot/weaver-tools.js +7 -39
- package/dist/bot/weaver-tools.js.map +1 -1
- package/dist/node-types/agent-execute.d.ts +25 -8
- package/dist/node-types/agent-execute.d.ts.map +1 -1
- package/dist/node-types/agent-execute.js +89 -23
- 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 +24 -3
- package/dist/node-types/bot-report.js.map +1 -1
- package/dist/node-types/plan-task.d.ts +8 -17
- package/dist/node-types/plan-task.d.ts.map +1 -1
- package/dist/node-types/plan-task.js +217 -256
- package/dist/node-types/plan-task.js.map +1 -1
- package/dist/node-types/review-result.js +8 -6
- package/dist/node-types/review-result.js.map +1 -1
- package/dist/palindrome.d.ts +9 -0
- package/dist/palindrome.d.ts.map +1 -0
- package/dist/palindrome.js +14 -0
- package/dist/palindrome.js.map +1 -0
- package/dist/ui/approval-card.js +91 -82
- package/dist/ui/bot-activity.js +73 -56
- package/dist/ui/bot-config.js +48 -31
- package/dist/ui/bot-dashboard.js +52 -36
- package/dist/ui/bot-panel.js +230 -228
- package/dist/ui/bot-slot-card.js +100 -90
- package/dist/ui/bot-status.js +37 -15
- package/dist/ui/budget-bar.js +57 -31
- package/dist/ui/capability-editor.js +447 -378
- package/dist/ui/chat-task-result.js +78 -71
- package/dist/ui/decision-log.js +68 -81
- package/dist/ui/genesis-block.js +86 -95
- package/dist/ui/instance-stream-view.js +722 -0
- package/dist/ui/profile-card.js +96 -221
- package/dist/ui/profile-editor.js +532 -575
- package/dist/ui/settings-section.js +41 -45
- package/dist/ui/swarm-controls.js +212 -135
- package/dist/ui/swarm-dashboard.js +3992 -2715
- package/dist/ui/task-detail-view.js +415 -521
- package/dist/ui/task-editor.js +339 -390
- package/dist/ui/task-pool-list.js +60 -55
- package/dist/workflows/src/palindrome.d.ts +11 -0
- package/dist/workflows/src/palindrome.d.ts.map +1 -0
- package/dist/workflows/src/palindrome.js +16 -0
- package/dist/workflows/src/palindrome.js.map +1 -0
- package/dist/workflows/tests/palindrome.test.d.ts +2 -0
- package/dist/workflows/tests/palindrome.test.d.ts.map +1 -0
- package/dist/workflows/tests/palindrome.test.js +41 -0
- package/dist/workflows/tests/palindrome.test.js.map +1 -0
- package/dist/workflows/weaver-bot-batch.js +1 -1
- package/dist/workflows/weaver-bot-batch.js.map +1 -1
- package/dist/workflows/weaver-bot.js +1 -1
- package/dist/workflows/weaver-bot.js.map +1 -1
- package/flowweaver.manifest.json +1 -1
- package/package.json +8 -2
- package/src/ai-chat-provider.ts +5 -5
- package/src/bot/acceptance-merge.ts +62 -0
- package/src/bot/ai-client.ts +77 -21
- package/src/bot/assistant-tools.ts +3 -3
- package/src/bot/audit-logger.ts +42 -14
- package/src/bot/audit-trail.ts +211 -0
- package/src/bot/behavior-defaults.ts +7 -2
- package/src/bot/capability-registry.ts +84 -28
- package/src/bot/capability-types.ts +11 -0
- package/src/bot/cli-provider.ts +8 -7
- package/src/bot/preflight.ts +285 -0
- package/src/bot/provider-shim.ts +218 -0
- package/src/bot/runner.ts +68 -20
- package/src/bot/step-executor.ts +69 -127
- package/src/bot/swarm-controller.ts +94 -20
- package/src/bot/task-create-handler.ts +164 -0
- package/src/bot/task-store.ts +76 -0
- package/src/bot/types.ts +4 -1
- package/src/bot/weaver-tools.ts +7 -45
- package/src/node-types/agent-execute.ts +102 -16
- package/src/node-types/bot-report.ts +24 -3
- package/src/node-types/plan-task.ts +238 -280
- package/src/node-types/review-result.ts +8 -6
- package/src/palindrome.ts +14 -0
- package/src/ui/approval-card.tsx +78 -62
- package/src/ui/bot-activity.tsx +12 -10
- package/src/ui/bot-config.tsx +12 -10
- package/src/ui/bot-dashboard.tsx +13 -11
- package/src/ui/bot-panel.tsx +189 -171
- package/src/ui/bot-slot-card.tsx +125 -70
- package/src/ui/bot-status.tsx +4 -4
- package/src/ui/budget-bar.tsx +86 -25
- package/src/ui/capability-editor.tsx +392 -257
- package/src/ui/chat-task-result.tsx +81 -78
- package/src/ui/decision-log.tsx +76 -73
- package/src/ui/genesis-block.tsx +91 -61
- package/src/ui/instance-stream-view.tsx +861 -0
- package/src/ui/profile-card.tsx +195 -168
- package/src/ui/profile-editor.tsx +453 -370
- package/src/ui/settings-section.tsx +46 -39
- package/src/ui/swarm-controls.tsx +252 -123
- package/src/ui/swarm-dashboard.tsx +999 -466
- package/src/ui/task-detail-view.tsx +485 -428
- package/src/ui/task-editor.tsx +329 -271
- package/src/ui/task-pool-list.tsx +68 -62
- package/src/workflows/src/palindrome.ts +16 -0
- package/src/workflows/tests/palindrome.test.ts +49 -0
- package/src/workflows/weaver-bot-batch.ts +1 -1
- package/src/workflows/weaver-bot.ts +1 -1
- package/dist/ui/bot-constants.d.ts +0 -14
- package/dist/ui/bot-constants.d.ts.map +0 -1
- package/dist/ui/bot-constants.js +0 -189
- package/dist/ui/bot-constants.js.map +0 -1
- package/dist/ui/steer-api.d.ts +0 -7
- package/dist/ui/steer-api.d.ts.map +0 -1
- package/dist/ui/steer-api.js +0 -11
- package/dist/ui/steer-api.js.map +0 -1
- package/dist/ui/trace-to-timeline.d.ts +0 -91
- package/dist/ui/trace-to-timeline.d.ts.map +0 -1
- package/dist/ui/trace-to-timeline.js +0 -116
- package/dist/ui/trace-to-timeline.js.map +0 -1
- package/dist/ui/use-stream-timeline.d.ts +0 -50
- package/dist/ui/use-stream-timeline.d.ts.map +0 -1
- package/dist/ui/use-stream-timeline.js +0 -245
- package/dist/ui/use-stream-timeline.js.map +0 -1
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import type { WeaverContext, StepLogEntry } from '../bot/types.js';
|
|
2
|
-
import {
|
|
3
|
-
import type { AiTool
|
|
2
|
+
import { callCapabilityTriage } from '../bot/ai-client.js';
|
|
3
|
+
import type { AiTool } from '../bot/ai-client.js';
|
|
4
4
|
import { auditEmit } from '../bot/audit-logger.js';
|
|
5
|
-
import { executeStep } from '../bot/step-executor.js';
|
|
6
5
|
import { getCapabilitiesByNames, BUILT_IN_CAPABILITIES, PROFILE_CAPABILITIES } from '../bot/capability-registry.js';
|
|
6
|
+
import { ALL_TOOLS, BOT_TOOLS, resolveToolsForTask } from '../bot/tool-registry.js';
|
|
7
|
+
import { createWeaverExecutor, WEAVER_TOOLS } from '../bot/weaver-tools.js';
|
|
8
|
+
import {
|
|
9
|
+
runAgentLoop,
|
|
10
|
+
stripMcpToolPrefix,
|
|
11
|
+
type ToolEvent,
|
|
12
|
+
type StreamEvent,
|
|
13
|
+
} from '@synergenius/flow-weaver/agent';
|
|
7
14
|
import { readFileSync } from 'node:fs';
|
|
8
15
|
import { fileURLToPath } from 'node:url';
|
|
9
16
|
import * as nodePath from 'node:path';
|
|
@@ -19,7 +26,7 @@ try {
|
|
|
19
26
|
// ---------------------------------------------------------------------------
|
|
20
27
|
|
|
21
28
|
/** All known tool schemas, keyed by operation name. */
|
|
22
|
-
const TOOL_SCHEMAS: Record<string, AiTool> = {
|
|
29
|
+
export const TOOL_SCHEMAS: Record<string, AiTool> = {
|
|
23
30
|
read_file: {
|
|
24
31
|
name: 'read_file',
|
|
25
32
|
description: 'Read a file and return its content',
|
|
@@ -88,6 +95,55 @@ const TOOL_SCHEMAS: Record<string, AiTool> = {
|
|
|
88
95
|
description: 'Validate a Flow Weaver workflow file',
|
|
89
96
|
parameters: { type: 'object', properties: { file: { type: 'string' } }, required: ['file'] },
|
|
90
97
|
},
|
|
98
|
+
tsc_check: {
|
|
99
|
+
name: 'tsc_check',
|
|
100
|
+
description: 'Run TypeScript compiler check (npx tsc --noEmit). Returns errors if any.',
|
|
101
|
+
parameters: { type: 'object', properties: {}, required: [] },
|
|
102
|
+
},
|
|
103
|
+
run_tests: {
|
|
104
|
+
name: 'run_tests',
|
|
105
|
+
description: 'Run project tests (npx vitest run). Returns structured results with pass/fail counts.',
|
|
106
|
+
parameters: { type: 'object', properties: { pattern: { type: 'string', description: 'Test file pattern (optional)' } } },
|
|
107
|
+
},
|
|
108
|
+
learn: {
|
|
109
|
+
name: 'learn',
|
|
110
|
+
description: 'Store a fact for future tasks. Key should be descriptive.',
|
|
111
|
+
parameters: { type: 'object', properties: { key: { type: 'string' }, value: { type: 'string' } }, required: ['key', 'value'] },
|
|
112
|
+
},
|
|
113
|
+
web_fetch: {
|
|
114
|
+
name: 'web_fetch',
|
|
115
|
+
description: 'Fetch HTTP content from a URL. Returns text body (max 10KB).',
|
|
116
|
+
parameters: { type: 'object', properties: { url: { type: 'string' } }, required: ['url'] },
|
|
117
|
+
},
|
|
118
|
+
task_list: {
|
|
119
|
+
name: 'task_list',
|
|
120
|
+
description: 'List tasks in the swarm task pool. Optionally filter by status.',
|
|
121
|
+
parameters: { type: 'object', properties: { status: { type: 'string', description: 'Filter: pending, in-progress, done, failed' } } },
|
|
122
|
+
},
|
|
123
|
+
task_get: {
|
|
124
|
+
name: 'task_get',
|
|
125
|
+
description: 'Get full details of a specific task by ID.',
|
|
126
|
+
parameters: { type: 'object', properties: { id: { type: 'string' } }, required: ['id'] },
|
|
127
|
+
},
|
|
128
|
+
task_update: {
|
|
129
|
+
name: 'task_update',
|
|
130
|
+
description: 'Update a task — add notes, change files list, or update description.',
|
|
131
|
+
parameters: {
|
|
132
|
+
type: 'object',
|
|
133
|
+
properties: {
|
|
134
|
+
id: { type: 'string' },
|
|
135
|
+
notes: { type: 'string' },
|
|
136
|
+
files: { type: 'array', items: { type: 'string' } },
|
|
137
|
+
description: { type: 'string' },
|
|
138
|
+
},
|
|
139
|
+
required: ['id'],
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
ask_user: {
|
|
143
|
+
name: 'ask_user',
|
|
144
|
+
description: 'Ask the user a question and wait for response.',
|
|
145
|
+
parameters: { type: 'object', properties: { question: { type: 'string' } }, required: ['question'] },
|
|
146
|
+
},
|
|
91
147
|
respond: {
|
|
92
148
|
name: 'respond',
|
|
93
149
|
description: 'Send a text response to the user',
|
|
@@ -95,7 +151,38 @@ const TOOL_SCHEMAS: Record<string, AiTool> = {
|
|
|
95
151
|
},
|
|
96
152
|
};
|
|
97
153
|
|
|
98
|
-
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
// Classification utility (exported for tests)
|
|
156
|
+
// ---------------------------------------------------------------------------
|
|
157
|
+
|
|
158
|
+
export function classifyToolRejection(toolName: string): { code: 'MISSING_SCHEMA' | 'NOT_GRANTED' | 'HALLUCINATED'; detail: string } {
|
|
159
|
+
const normalized = stripMcpToolPrefix(toolName);
|
|
160
|
+
const allToolNames = new Set(ALL_TOOLS.map(t => t.name));
|
|
161
|
+
const hasRegistry = allToolNames.has(normalized);
|
|
162
|
+
const hasSchema = !!TOOL_SCHEMAS[normalized];
|
|
163
|
+
|
|
164
|
+
if (hasRegistry && !hasSchema) {
|
|
165
|
+
return {
|
|
166
|
+
code: 'MISSING_SCHEMA',
|
|
167
|
+
detail: `Tool '${normalized}' exists in tool-registry but has no TOOL_SCHEMAS entry in plan-task. The model sees it in the prompt but cannot call it. Add it to TOOL_SCHEMAS.`,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
if (hasRegistry && hasSchema) {
|
|
171
|
+
return {
|
|
172
|
+
code: 'NOT_GRANTED',
|
|
173
|
+
detail: `Tool '${normalized}' exists and has a schema but was not granted for this task's mode/capabilities. Check resolveToolsForTask and capability config.`,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
code: 'HALLUCINATED',
|
|
178
|
+
detail: `Tool '${normalized}' does not exist in tool-registry. The model invented a tool name.`,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// ---------------------------------------------------------------------------
|
|
183
|
+
// Prompt building helpers
|
|
184
|
+
// ---------------------------------------------------------------------------
|
|
185
|
+
|
|
99
186
|
function buildToolDefinitions(grantedTools: string[]): AiTool[] {
|
|
100
187
|
const tools: AiTool[] = [];
|
|
101
188
|
const seen = new Set<string>();
|
|
@@ -104,10 +191,14 @@ function buildToolDefinitions(grantedTools: string[]): AiTool[] {
|
|
|
104
191
|
if (seen.has(name)) continue;
|
|
105
192
|
seen.add(name);
|
|
106
193
|
const schema = TOOL_SCHEMAS[name];
|
|
107
|
-
if (schema)
|
|
194
|
+
if (schema) {
|
|
195
|
+
tools.push(schema);
|
|
196
|
+
} else {
|
|
197
|
+
console.error(`\x1b[33m ⚠ Tool '${name}' granted by capabilities but has no TOOL_SCHEMAS entry — model cannot call it\x1b[0m`);
|
|
198
|
+
auditEmit('tool-schema-missing', { tool: name, grantedTools });
|
|
199
|
+
}
|
|
108
200
|
}
|
|
109
201
|
|
|
110
|
-
// Always include 'done' so the AI can signal completion
|
|
111
202
|
if (!seen.has('done')) {
|
|
112
203
|
tools.push(TOOL_SCHEMAS.done);
|
|
113
204
|
}
|
|
@@ -116,49 +207,20 @@ function buildToolDefinitions(grantedTools: string[]): AiTool[] {
|
|
|
116
207
|
}
|
|
117
208
|
|
|
118
209
|
// ---------------------------------------------------------------------------
|
|
119
|
-
//
|
|
210
|
+
// Main entry point
|
|
120
211
|
// ---------------------------------------------------------------------------
|
|
121
212
|
|
|
122
|
-
const
|
|
123
|
-
const AGENT_TIMEOUT_MS = 180_000; // 3 minutes
|
|
213
|
+
const AGENT_TIMEOUT_MS = 10 * 60 * 1000; // 10 min
|
|
124
214
|
|
|
125
|
-
// ---------------------------------------------------------------------------
|
|
126
|
-
// Agent Loop — replaces Plan Task + Execute & Validate
|
|
127
|
-
// ---------------------------------------------------------------------------
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Agent loop: sends task + tools to the AI, executes tool calls iteratively
|
|
131
|
-
* until the AI signals completion or a safety limit is reached.
|
|
132
|
-
*
|
|
133
|
-
* Replaces the old Plan Task → Execute & Validate two-phase workflow.
|
|
134
|
-
*
|
|
135
|
-
* @flowWeaver nodeType
|
|
136
|
-
* @label Agent Loop
|
|
137
|
-
* @icon psychology
|
|
138
|
-
* @color blue
|
|
139
|
-
* @input ctx [order:0] - Weaver context (JSON)
|
|
140
|
-
* @input [modelOverride] [order:1] - Model ID override from profile behavior
|
|
141
|
-
* @output ctx [order:0] - Weaver context with results (JSON)
|
|
142
|
-
* @output onSuccess [order:-2] - On Success
|
|
143
|
-
* @output onFailure [order:-1] [hidden] - On Failure
|
|
144
|
-
*/
|
|
145
215
|
export async function weaverPlanTask(
|
|
146
|
-
execute: boolean,
|
|
147
216
|
ctx: string,
|
|
217
|
+
execute: boolean,
|
|
148
218
|
modelOverride?: string,
|
|
149
|
-
): Promise<{
|
|
150
|
-
onSuccess: boolean; onFailure: boolean;
|
|
151
|
-
ctx: string;
|
|
152
|
-
}> {
|
|
219
|
+
): Promise<{ onSuccess: boolean; onFailure: boolean; ctx: string }> {
|
|
153
220
|
const context = JSON.parse(ctx) as WeaverContext;
|
|
154
221
|
const { env } = context;
|
|
155
222
|
|
|
156
223
|
if (!execute) {
|
|
157
|
-
context.planJson = '{"steps":[],"summary":"dry run"}';
|
|
158
|
-
context.resultJson = JSON.stringify({ success: true, toolCallCount: 0 });
|
|
159
|
-
context.filesModified = '[]';
|
|
160
|
-
context.stepLogJson = '[]';
|
|
161
|
-
context.allValid = true;
|
|
162
224
|
return { onSuccess: true, onFailure: false, ctx: JSON.stringify(context) };
|
|
163
225
|
}
|
|
164
226
|
|
|
@@ -166,299 +228,195 @@ export async function weaverPlanTask(
|
|
|
166
228
|
? { ...env.providerInfo, model: modelOverride }
|
|
167
229
|
: env.providerInfo;
|
|
168
230
|
const { projectDir } = env;
|
|
231
|
+
const task = context.taskJson ? JSON.parse(context.taskJson) : { instruction: '', mode: 'create' };
|
|
169
232
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
const task = JSON.parse(context.taskJson);
|
|
179
|
-
|
|
180
|
-
// Resolve available capabilities: profile pool > behavior config > all defaults
|
|
181
|
-
const behavior = context.behaviorJson ? JSON.parse(context.behaviorJson) : undefined;
|
|
182
|
-
const profilePool = task.assignedProfile ? PROFILE_CAPABILITIES[task.assignedProfile] : undefined;
|
|
183
|
-
const availableCapNames: string[] = profilePool ?? behavior?.capabilities ?? BUILT_IN_CAPABILITIES.map(c => c.name);
|
|
184
|
-
const availableCaps = getCapabilitiesByNames(availableCapNames);
|
|
185
|
-
|
|
186
|
-
// Capability triage: only run when using the default (all) pool.
|
|
187
|
-
// Profile pools are already scoped — triage would just add latency + cost.
|
|
188
|
-
let selectedCaps = availableCaps;
|
|
189
|
-
if (!profilePool) {
|
|
190
|
-
const triageResult = await callCapabilityTriage(pInfo, task.instruction, availableCaps);
|
|
191
|
-
if (triageResult) {
|
|
192
|
-
selectedCaps = getCapabilitiesByNames(triageResult);
|
|
233
|
+
// -----------------------------------------------------------------------
|
|
234
|
+
// Build system prompt from capabilities
|
|
235
|
+
// -----------------------------------------------------------------------
|
|
236
|
+
|
|
237
|
+
const selectedCaps = (() => {
|
|
238
|
+
const profilePool = task.assignedProfile ? PROFILE_CAPABILITIES[task.assignedProfile] : undefined;
|
|
239
|
+
if (profilePool) {
|
|
240
|
+
return getCapabilitiesByNames(profilePool);
|
|
193
241
|
}
|
|
194
|
-
|
|
242
|
+
// Fallback: triage
|
|
243
|
+
try {
|
|
244
|
+
return getCapabilitiesByNames(['core', 'file-ops', 'shell', 'context']);
|
|
245
|
+
} catch {
|
|
246
|
+
return BUILT_IN_CAPABILITIES.slice(0, 4);
|
|
247
|
+
}
|
|
248
|
+
})();
|
|
249
|
+
const selectedCapNames = new Set(selectedCaps.map(c => c.name));
|
|
195
250
|
|
|
196
|
-
// Build system prompt from capabilities
|
|
197
251
|
let systemPrompt: string;
|
|
252
|
+
let tools: AiTool[];
|
|
198
253
|
try {
|
|
199
254
|
const mod = await import('../bot/system-prompt.js');
|
|
255
|
+
const mod2 = await import('../bot/system-prompt.js');
|
|
200
256
|
const basePrompt = mod.buildPromptFromCapabilities(selectedCaps);
|
|
201
|
-
const selectedCapNames = new Set(selectedCaps.map(c => c.name));
|
|
202
257
|
const contextBundle = selectedCapNames.has('context') ? context.contextBundle : undefined;
|
|
203
258
|
const botPrompt = mod.buildBotSystemPrompt(contextBundle, undefined, context.env?.projectDir);
|
|
204
259
|
systemPrompt = basePrompt + '\n\n' + botPrompt;
|
|
205
|
-
} catch (err) {
|
|
206
|
-
if (process.env.WEAVER_VERBOSE) console.error('[agent-loop] system prompt build failed:', err);
|
|
207
|
-
systemPrompt = 'You are Weaver, an AI workflow bot. Use the provided tools to complete tasks.';
|
|
208
|
-
}
|
|
209
260
|
|
|
210
|
-
// Build tool definitions from capability-granted operations
|
|
211
|
-
let tools: AiTool[];
|
|
212
|
-
try {
|
|
213
|
-
const mod2 = await import('../bot/system-prompt.js');
|
|
214
261
|
const grantedTools = mod2.collectToolsFromCapabilities(selectedCaps);
|
|
215
262
|
tools = buildToolDefinitions(grantedTools);
|
|
216
263
|
} catch (err) {
|
|
217
264
|
console.warn('[plan-task] capability resolution failed, using worker defaults:', err);
|
|
218
|
-
// Fallback: worker tools only — NO task_create (that's orchestrator-only)
|
|
219
265
|
tools = buildToolDefinitions(['read_file', 'write_file', 'patch_file', 'run_shell', 'list_files']);
|
|
266
|
+
systemPrompt = 'You are Weaver. Execute tasks by calling tools.';
|
|
220
267
|
}
|
|
221
268
|
|
|
222
|
-
// Build
|
|
223
|
-
// Only mention task_create if the tool is actually available (orchestrator only)
|
|
269
|
+
// Build user prompt
|
|
224
270
|
const hasTaskCreate = tools.some(t => t.name === 'task_create');
|
|
225
|
-
|
|
271
|
+
const maxConcurrent = (context as any).maxConcurrent ?? 2;
|
|
272
|
+
let userPrompt = `Task: ${task.instruction}\nMode: ${task.mode ?? 'create'}\n${task.id && hasTaskCreate ? `Your Task ID is ${task.id}. Use parentId: "@self" in task_create to create subtasks under this task.\nWorkers available: ${maxConcurrent} (plan task grouping to maximize parallel utilization)` : ''}\n${task.targets ? 'Targets: ' + task.targets.join(', ') : ''}
|
|
273
|
+
|
|
274
|
+
${context.contextBundle || ''}
|
|
226
275
|
|
|
227
276
|
Execute this task step by step using the available tools.
|
|
228
277
|
When you are done, call the "done" tool with a summary of what you accomplished.
|
|
229
278
|
Rules:
|
|
230
279
|
1. Read files before modifying them (use read_file to get exact content for patches).
|
|
231
280
|
2. Use patch_file for modifications, write_file only for new files.
|
|
232
|
-
3. Verify your work by running tests or tsc when appropriate
|
|
233
|
-
|
|
234
|
-
//
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
retryParts.push('Do NOT recreate files that already exist. Read them first and continue from where the previous attempt left off.');
|
|
251
|
-
retryParts.push('---');
|
|
252
|
-
userPrompt += retryParts.join('\n');
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// Seed symbolic ID map for task references
|
|
256
|
-
const symbolicIdMap: Record<string, string> = {};
|
|
257
|
-
if (task.id) symbolicIdMap['@self'] = task.id;
|
|
258
|
-
if (task.parentId) symbolicIdMap['@parent'] = task.parentId;
|
|
281
|
+
3. Verify your work by running tests or tsc when appropriate.`.trim();
|
|
282
|
+
|
|
283
|
+
// -----------------------------------------------------------------------
|
|
284
|
+
// Create provider + executor, run via runAgentLoop
|
|
285
|
+
// -----------------------------------------------------------------------
|
|
286
|
+
|
|
287
|
+
const { createProvider } = await import('./agent-execute.js');
|
|
288
|
+
const provider = await createProvider(pInfo, projectDir);
|
|
289
|
+
const providerStats = (provider as unknown as { stats?: { bridgeActive: boolean; bridgeConfigPath?: string; toolUseFiltered: number; toolResultPassthrough: number; textToolCallDetected: number; streamCalls: number; setHandlersCalls: number } }).stats;
|
|
290
|
+
auditEmit('bridge-created', {
|
|
291
|
+
providerType: pInfo.type,
|
|
292
|
+
providerClass: provider.constructor?.name ?? 'unknown',
|
|
293
|
+
bridgeActive: providerStats?.bridgeActive ?? false,
|
|
294
|
+
bridgeConfigPath: providerStats?.bridgeConfigPath ?? null,
|
|
295
|
+
});
|
|
296
|
+
const executor = createWeaverExecutor(projectDir);
|
|
259
297
|
|
|
260
|
-
|
|
298
|
+
const filesCreated: string[] = [];
|
|
261
299
|
const filesModified: string[] = [];
|
|
262
300
|
const stepLog: StepLogEntry[] = [];
|
|
263
301
|
let toolCallCount = 0;
|
|
264
|
-
const deadline = Date.now() + AGENT_TIMEOUT_MS;
|
|
265
302
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
303
|
+
const onToolEvent = (event: ToolEvent) => {
|
|
304
|
+
if (event.type === 'tool_call_start') {
|
|
305
|
+
toolCallCount++;
|
|
306
|
+
const name = stripMcpToolPrefix(event.name);
|
|
307
|
+
console.log(`\x1b[32m + ${toolCallCount}: ${name}\x1b[0m`);
|
|
308
|
+
auditEmit('tool-call', {
|
|
309
|
+
turn: toolCallCount,
|
|
310
|
+
tool: name,
|
|
311
|
+
args: JSON.stringify(event.args ?? {}).slice(0, 1000),
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
if (event.type === 'tool_call_result') {
|
|
315
|
+
const name = stripMcpToolPrefix(event.name);
|
|
316
|
+
auditEmit('tool-result', { tool: name, isError: event.isError, result: (event.result ?? '').slice(0, 500) });
|
|
317
|
+
stepLog.push({
|
|
318
|
+
step: `${toolCallCount}:${name}`,
|
|
319
|
+
status: event.isError ? 'error' : 'ok',
|
|
320
|
+
detail: event.isError ? (event.result ?? '').slice(0, 200) : name,
|
|
321
|
+
});
|
|
271
322
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
323
|
+
// Track file changes
|
|
324
|
+
if (!event.isError && event.args?.file) {
|
|
325
|
+
if (name === 'write_file') filesCreated.push(event.args.file as string);
|
|
326
|
+
if (name === 'patch_file') filesModified.push(event.args.file as string);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
const onStreamEvent = (event: StreamEvent) => {
|
|
332
|
+
if (event.type === 'text_delta') {
|
|
333
|
+
process.stderr.write(`\x1b[36m${event.text}\x1b[0m`);
|
|
334
|
+
}
|
|
335
|
+
if (event.type === 'thinking_delta') {
|
|
336
|
+
process.stderr.write('\x1b[90m thinking...\x1b[0m');
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
// Convert WEAVER_TOOLS to ToolDefinition format for runAgentLoop
|
|
341
|
+
const grantedToolNames = new Set(tools.map(t => t.name));
|
|
342
|
+
grantedToolNames.add('done');
|
|
343
|
+
grantedToolNames.add('complete');
|
|
344
|
+
const loopTools = WEAVER_TOOLS.filter(t => grantedToolNames.has(t.name));
|
|
276
345
|
|
|
277
346
|
auditEmit('run-start', { task: task.instruction, mode: 'agent-loop', packVersion: PACK_VERSION, profile: task.assignedProfile });
|
|
278
347
|
auditEmit('ai-request', {
|
|
279
|
-
systemPrompt
|
|
280
|
-
userPrompt
|
|
281
|
-
tools
|
|
348
|
+
systemPrompt,
|
|
349
|
+
userPrompt,
|
|
350
|
+
tools,
|
|
351
|
+
capabilities: selectedCaps.map(c => c.name),
|
|
352
|
+
model: pInfo.model,
|
|
353
|
+
providerType: pInfo.type,
|
|
282
354
|
});
|
|
283
355
|
|
|
284
356
|
try {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
// If AI returns text with no tool calls, we're done
|
|
299
|
-
if (!result.toolCalls || result.toolCalls.length === 0) {
|
|
300
|
-
if (result.content) {
|
|
301
|
-
console.log(`\x1b[36m→ Agent: ${result.content.slice(0, 200)}\x1b[0m`);
|
|
302
|
-
}
|
|
303
|
-
done = true;
|
|
304
|
-
break;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// Process each tool call
|
|
308
|
-
for (const tc of result.toolCalls) {
|
|
309
|
-
if (toolCallCount >= MAX_TOOL_CALLS || Date.now() >= deadline) {
|
|
310
|
-
done = true;
|
|
311
|
-
break;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
toolCallCount++;
|
|
315
|
-
const toolName = tc.name;
|
|
316
|
-
const toolArgs = tc.arguments;
|
|
317
|
-
|
|
318
|
-
auditEmit('tool-call', {
|
|
319
|
-
turn: toolCallCount,
|
|
320
|
-
tool: toolName,
|
|
321
|
-
args: JSON.stringify(toolArgs).slice(0, 1000),
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
// Check for done signal
|
|
325
|
-
if (toolName === 'done' || toolName === 'complete') {
|
|
326
|
-
console.log(`\x1b[36m→ Agent done: ${(toolArgs as Record<string, string>).summary ?? 'completed'}\x1b[0m`);
|
|
327
|
-
|
|
328
|
-
// Execute through step-executor for consistent handling
|
|
329
|
-
try {
|
|
330
|
-
const stepResult = await executeStep(
|
|
331
|
-
{ operation: toolName, args: toolArgs },
|
|
332
|
-
projectDir,
|
|
333
|
-
symbolicIdMap,
|
|
334
|
-
);
|
|
335
|
-
stepLog.push({ step: `${toolCallCount}:${toolName}`, status: 'ok', detail: stepResult.output ?? 'done' });
|
|
336
|
-
} catch {
|
|
337
|
-
stepLog.push({ step: `${toolCallCount}:${toolName}`, status: 'ok', detail: 'done' });
|
|
338
|
-
}
|
|
339
|
-
auditEmit('tool-result', { turn: toolCallCount, tool: 'done', status: 'ok', output: 'completed' });
|
|
340
|
-
|
|
341
|
-
// Add assistant message with tool use and tool result to messages
|
|
342
|
-
messages.push({
|
|
343
|
-
role: 'assistant',
|
|
344
|
-
content: result.content || undefined,
|
|
345
|
-
tool_use: { id: tc.id, name: toolName, input: toolArgs },
|
|
346
|
-
});
|
|
347
|
-
messages.push({
|
|
348
|
-
role: 'user',
|
|
349
|
-
tool_use_id: tc.id,
|
|
350
|
-
content: 'Task completed.',
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
done = true;
|
|
354
|
-
break;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
// Validate tool name against allowed list to prevent hallucinated tool execution
|
|
358
|
-
if (!allowedToolNames.has(toolName)) {
|
|
359
|
-
const available = [...allowedToolNames].sort().join(', ');
|
|
360
|
-
const toolOutput = `Unknown tool: ${toolName}. Available tools: ${available}`;
|
|
361
|
-
stepLog.push({ step: `${toolCallCount}:${toolName}`, status: 'error', detail: toolOutput });
|
|
362
|
-
console.error(`\x1b[31m x ${toolCallCount}: ${toolName}: hallucinated tool\x1b[0m`);
|
|
363
|
-
auditEmit('tool-result', {
|
|
364
|
-
turn: toolCallCount,
|
|
365
|
-
tool: toolName,
|
|
366
|
-
status: 'rejected',
|
|
367
|
-
output: toolOutput.slice(0, 500),
|
|
368
|
-
});
|
|
369
|
-
|
|
370
|
-
messages.push({
|
|
371
|
-
role: 'assistant',
|
|
372
|
-
content: result.content || undefined,
|
|
373
|
-
tool_use: { id: tc.id, name: toolName, input: toolArgs },
|
|
374
|
-
});
|
|
375
|
-
messages.push({
|
|
376
|
-
role: 'user',
|
|
377
|
-
tool_use_id: tc.id,
|
|
378
|
-
content: toolOutput,
|
|
379
|
-
});
|
|
380
|
-
continue;
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
// Execute the tool via step-executor
|
|
384
|
-
let toolOutput: string;
|
|
385
|
-
try {
|
|
386
|
-
const stepResult = await executeStep(
|
|
387
|
-
{ operation: toolName, args: toolArgs },
|
|
388
|
-
projectDir,
|
|
389
|
-
symbolicIdMap,
|
|
390
|
-
);
|
|
391
|
-
|
|
392
|
-
// Track files modified — only from write/patch operations, not reads/listings
|
|
393
|
-
const isWriteOp = toolName === 'write_file' || toolName === 'patch_file' || toolName === 'create_workflow' || toolName === 'modify_source' || toolName === 'implement_node';
|
|
394
|
-
if (isWriteOp && stepResult.file) filesModified.push(stepResult.file);
|
|
395
|
-
|
|
396
|
-
// Build output for AI
|
|
397
|
-
if (stepResult.blocked) {
|
|
398
|
-
toolOutput = `BLOCKED: ${stepResult.blockReason}`;
|
|
399
|
-
stepLog.push({ step: `${toolCallCount}:${toolName}`, status: 'blocked', detail: stepResult.blockReason });
|
|
400
|
-
} else {
|
|
401
|
-
toolOutput = stepResult.output ?? 'OK';
|
|
402
|
-
stepLog.push({ step: `${toolCallCount}:${toolName}`, status: 'ok', detail: toolName });
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
console.log(`\x1b[32m + ${toolCallCount}: ${toolName}\x1b[0m`);
|
|
406
|
-
auditEmit('tool-result', {
|
|
407
|
-
turn: toolCallCount,
|
|
408
|
-
tool: toolName,
|
|
409
|
-
status: stepResult.blocked ? 'blocked' : 'ok',
|
|
410
|
-
output: toolOutput.slice(0, 1000),
|
|
411
|
-
});
|
|
412
|
-
} catch (err: unknown) {
|
|
413
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
414
|
-
toolOutput = `ERROR: ${msg}`;
|
|
415
|
-
stepLog.push({ step: `${toolCallCount}:${toolName}`, status: 'error', detail: msg });
|
|
416
|
-
console.error(`\x1b[31m x ${toolCallCount}: ${toolName}: ${msg}\x1b[0m`);
|
|
417
|
-
auditEmit('tool-result', {
|
|
418
|
-
turn: toolCallCount,
|
|
419
|
-
tool: toolName,
|
|
420
|
-
status: 'error',
|
|
421
|
-
output: msg.slice(0, 1000),
|
|
422
|
-
});
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
// Append assistant tool_use + tool result to messages for next iteration
|
|
426
|
-
messages.push({
|
|
427
|
-
role: 'assistant',
|
|
428
|
-
content: result.content || undefined,
|
|
429
|
-
tool_use: { id: tc.id, name: toolName, input: toolArgs },
|
|
430
|
-
});
|
|
431
|
-
messages.push({
|
|
432
|
-
role: 'user',
|
|
433
|
-
tool_use_id: tc.id,
|
|
434
|
-
content: toolOutput,
|
|
435
|
-
});
|
|
436
|
-
}
|
|
437
|
-
}
|
|
357
|
+
const result = await runAgentLoop(
|
|
358
|
+
provider,
|
|
359
|
+
loopTools,
|
|
360
|
+
executor,
|
|
361
|
+
[{ role: 'user', content: userPrompt }],
|
|
362
|
+
{
|
|
363
|
+
systemPrompt: { prefix: systemPrompt, suffix: '' },
|
|
364
|
+
maxIterations: 30,
|
|
365
|
+
onToolEvent,
|
|
366
|
+
onStreamEvent,
|
|
367
|
+
},
|
|
368
|
+
);
|
|
438
369
|
|
|
439
|
-
|
|
440
|
-
const
|
|
370
|
+
const usage = result.usage;
|
|
371
|
+
const uniqueCreated = [...new Set(filesCreated)];
|
|
372
|
+
const uniqueModified = [...new Set(filesModified)];
|
|
441
373
|
|
|
442
|
-
// Store results in context (compatible with exec-validate-retry output format)
|
|
443
374
|
context.resultJson = JSON.stringify({
|
|
444
375
|
success: true,
|
|
445
376
|
toolCallCount,
|
|
446
|
-
|
|
377
|
+
filesCreated: uniqueCreated,
|
|
378
|
+
filesModified: uniqueModified,
|
|
447
379
|
stepsCompleted: toolCallCount,
|
|
448
380
|
stepsTotal: toolCallCount,
|
|
449
381
|
});
|
|
450
382
|
context.planJson = JSON.stringify({ steps: [], summary: `Agent loop: ${toolCallCount} tool calls` });
|
|
451
|
-
context.filesModified = JSON.stringify(
|
|
383
|
+
context.filesModified = JSON.stringify([...uniqueCreated, ...uniqueModified]);
|
|
452
384
|
context.stepLogJson = JSON.stringify(stepLog);
|
|
453
385
|
context.allValid = true;
|
|
454
386
|
|
|
387
|
+
// Re-read provider stats after loop (they accumulate during streaming)
|
|
388
|
+
const finalStats = (provider as unknown as { stats?: typeof providerStats }).stats;
|
|
389
|
+
|
|
455
390
|
auditEmit('run-complete', {
|
|
456
391
|
success: true,
|
|
457
392
|
toolCalls: toolCallCount,
|
|
458
|
-
|
|
393
|
+
filesCreated: uniqueCreated.length,
|
|
394
|
+
filesModified: uniqueModified.length,
|
|
395
|
+
usage,
|
|
396
|
+
bridge: finalStats ? {
|
|
397
|
+
active: finalStats.bridgeActive,
|
|
398
|
+
toolUseFiltered: finalStats.toolUseFiltered,
|
|
399
|
+
toolResultPassthrough: finalStats.toolResultPassthrough,
|
|
400
|
+
textToolCallDetected: finalStats.textToolCallDetected,
|
|
401
|
+
streamCalls: finalStats.streamCalls,
|
|
402
|
+
setHandlersCalls: finalStats.setHandlersCalls,
|
|
403
|
+
} : undefined,
|
|
459
404
|
});
|
|
460
405
|
|
|
461
|
-
|
|
406
|
+
// Surface bridge issues immediately in console output
|
|
407
|
+
if (finalStats?.bridgeActive) {
|
|
408
|
+
if (finalStats.textToolCallDetected > 0) {
|
|
409
|
+
console.error(`\x1b[31m ✗ BRIDGE ISSUE: Model output ${finalStats.textToolCallDetected} tool calls as TEXT — MCP tools not connected to CLI session\x1b[0m`);
|
|
410
|
+
}
|
|
411
|
+
if (finalStats.toolUseFiltered === 0 && finalStats.toolResultPassthrough === 0) {
|
|
412
|
+
console.warn(`\x1b[33m ⚠ Bridge active but zero structured tool events (filtered=0, passthrough=0)\x1b[0m`);
|
|
413
|
+
} else {
|
|
414
|
+
console.log(`\x1b[32m ✓ Bridge: ${finalStats.toolUseFiltered} tool_use filtered, ${finalStats.toolResultPassthrough} tool_result passed through\x1b[0m`);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
const costStr = usage.costUsd > 0 ? ` | $${usage.costUsd.toFixed(4)}` : '';
|
|
419
|
+
console.log(`\x1b[36m→ Agent loop: ${toolCallCount} tool calls, ${uniqueCreated.length + uniqueModified.length} files changed${costStr}\x1b[0m`);
|
|
462
420
|
return { onSuccess: true, onFailure: false, ctx: JSON.stringify(context) };
|
|
463
421
|
} catch (err: unknown) {
|
|
464
422
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -466,7 +424,7 @@ Rules:
|
|
|
466
424
|
|
|
467
425
|
context.resultJson = JSON.stringify({ success: false, error: msg });
|
|
468
426
|
context.planJson = JSON.stringify({ steps: [], summary: `Agent loop failed: ${msg}` });
|
|
469
|
-
context.filesModified = JSON.stringify([...new Set(filesModified)]);
|
|
427
|
+
context.filesModified = JSON.stringify([...new Set([...filesCreated, ...filesModified])]);
|
|
470
428
|
context.stepLogJson = JSON.stringify(stepLog);
|
|
471
429
|
context.allValid = false;
|
|
472
430
|
|
|
@@ -233,11 +233,12 @@ async function createReviewProvider(
|
|
|
233
233
|
|
|
234
234
|
if (type === 'claude-cli') {
|
|
235
235
|
const key = projectDir ?? process.cwd();
|
|
236
|
-
const
|
|
237
|
-
|
|
236
|
+
const { getCliSessionConfig } = await import('@synergenius/flow-weaver/agent');
|
|
237
|
+
const session = getOrCreateCliSession(`${key}:reviewer`, getCliSessionConfig({
|
|
238
238
|
cwd: key,
|
|
239
239
|
model: pInfo.model ?? 'claude-sonnet-4-6',
|
|
240
|
-
|
|
240
|
+
appendSystemPrompt: 'You are a Weaver reviewer bot. Evaluate task results using only the provided tools.',
|
|
241
|
+
}));
|
|
241
242
|
return new CliReviewProvider(session);
|
|
242
243
|
}
|
|
243
244
|
|
|
@@ -250,11 +251,12 @@ async function createReviewProvider(
|
|
|
250
251
|
});
|
|
251
252
|
}
|
|
252
253
|
const key = projectDir ?? process.cwd();
|
|
253
|
-
const
|
|
254
|
-
|
|
254
|
+
const { getCliSessionConfig } = await import('@synergenius/flow-weaver/agent');
|
|
255
|
+
const session = getOrCreateCliSession(`${key}:reviewer`, getCliSessionConfig({
|
|
255
256
|
cwd: key,
|
|
256
257
|
model: pInfo.model ?? 'claude-sonnet-4-6',
|
|
257
|
-
|
|
258
|
+
appendSystemPrompt: 'You are a Weaver reviewer bot. Evaluate task results using only the provided tools.',
|
|
259
|
+
}));
|
|
258
260
|
return new CliReviewProvider(session);
|
|
259
261
|
}
|
|
260
262
|
|