@synergenius/flow-weaver-pack-weaver 0.9.62 → 0.9.78
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.d.ts +12 -0
- package/dist/ai-chat-provider.d.ts.map +1 -1
- package/dist/ai-chat-provider.js +173 -19
- package/dist/ai-chat-provider.js.map +1 -1
- package/dist/bot/agent-loop.d.ts +20 -0
- package/dist/bot/agent-loop.d.ts.map +1 -0
- package/dist/bot/agent-loop.js +331 -0
- package/dist/bot/agent-loop.js.map +1 -0
- package/dist/bot/ai-router.d.ts +19 -0
- package/dist/bot/ai-router.d.ts.map +1 -0
- package/dist/bot/ai-router.js +104 -0
- package/dist/bot/ai-router.js.map +1 -0
- package/dist/bot/bot-registry.js +2 -2
- package/dist/bot/bot-registry.js.map +1 -1
- package/dist/bot/conversation-store.d.ts +1 -0
- package/dist/bot/conversation-store.d.ts.map +1 -1
- package/dist/bot/conversation-store.js.map +1 -1
- package/dist/bot/improve-loop.js.map +1 -1
- package/dist/bot/instance-manager.d.ts +31 -0
- package/dist/bot/instance-manager.d.ts.map +1 -0
- package/dist/bot/instance-manager.js +115 -0
- package/dist/bot/instance-manager.js.map +1 -0
- package/dist/bot/orchestrator.d.ts +36 -0
- package/dist/bot/orchestrator.d.ts.map +1 -0
- package/dist/bot/orchestrator.js +176 -0
- package/dist/bot/orchestrator.js.map +1 -0
- package/dist/bot/profile-store.d.ts +36 -0
- package/dist/bot/profile-store.d.ts.map +1 -0
- package/dist/bot/profile-store.js +208 -0
- package/dist/bot/profile-store.js.map +1 -0
- package/dist/bot/profile-types.d.ts +126 -0
- package/dist/bot/profile-types.d.ts.map +1 -0
- package/dist/bot/profile-types.js +7 -0
- package/dist/bot/profile-types.js.map +1 -0
- package/dist/bot/session-state.d.ts +25 -0
- package/dist/bot/session-state.d.ts.map +1 -0
- package/dist/bot/session-state.js +110 -0
- package/dist/bot/session-state.js.map +1 -0
- package/dist/bot/swarm-controller.d.ts +37 -21
- package/dist/bot/swarm-controller.d.ts.map +1 -1
- package/dist/bot/swarm-controller.js +344 -163
- package/dist/bot/swarm-controller.js.map +1 -1
- package/dist/bot/task-prompt-builder.d.ts +2 -1
- package/dist/bot/task-prompt-builder.d.ts.map +1 -1
- package/dist/bot/task-prompt-builder.js +33 -10
- package/dist/bot/task-prompt-builder.js.map +1 -1
- package/dist/bot/task-queue.d.ts +46 -0
- package/dist/bot/task-queue.d.ts.map +1 -0
- package/dist/bot/task-queue.js +237 -0
- package/dist/bot/task-queue.js.map +1 -0
- package/dist/bot/task-store.d.ts +1 -6
- package/dist/bot/task-store.d.ts.map +1 -1
- package/dist/bot/task-store.js +27 -78
- package/dist/bot/task-store.js.map +1 -1
- package/dist/bot/task-types.d.ts +8 -4
- package/dist/bot/task-types.d.ts.map +1 -1
- package/dist/cli-handlers.d.ts.map +1 -1
- package/dist/cli-handlers.js +2 -3
- package/dist/cli-handlers.js.map +1 -1
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +749 -0
- package/dist/cli.js.map +1 -0
- package/dist/docs/docs/weaver-bot-usage.md +35 -18
- package/dist/docs/docs/weaver-config.md +20 -0
- package/dist/docs/docs/weaver-task-queue.md +31 -19
- package/dist/docs/weaver-config.md +15 -9
- package/dist/mcp-tools.d.ts +17 -0
- package/dist/mcp-tools.d.ts.map +1 -1
- package/dist/mcp-tools.js +98 -232
- package/dist/mcp-tools.js.map +1 -1
- package/dist/node-types/orchestrator-dispatch.d.ts +17 -0
- package/dist/node-types/orchestrator-dispatch.d.ts.map +1 -0
- package/dist/node-types/orchestrator-dispatch.js +63 -0
- package/dist/node-types/orchestrator-dispatch.js.map +1 -0
- package/dist/node-types/orchestrator-load-state.d.ts +16 -0
- package/dist/node-types/orchestrator-load-state.d.ts.map +1 -0
- package/dist/node-types/orchestrator-load-state.js +60 -0
- package/dist/node-types/orchestrator-load-state.js.map +1 -0
- package/dist/node-types/orchestrator-route.d.ts +16 -0
- package/dist/node-types/orchestrator-route.d.ts.map +1 -0
- package/dist/node-types/orchestrator-route.js +28 -0
- package/dist/node-types/orchestrator-route.js.map +1 -0
- package/dist/node-types/receive-task.d.ts +2 -3
- package/dist/node-types/receive-task.d.ts.map +1 -1
- package/dist/node-types/receive-task.js +3 -28
- package/dist/node-types/receive-task.js.map +1 -1
- package/dist/templates/weaver-template.d.ts +11 -0
- package/dist/templates/weaver-template.d.ts.map +1 -0
- package/dist/templates/weaver-template.js +53 -0
- package/dist/templates/weaver-template.js.map +1 -0
- package/dist/ui/bot-constants.d.ts +14 -0
- package/dist/ui/bot-constants.d.ts.map +1 -0
- package/dist/ui/bot-constants.js +189 -0
- package/dist/ui/bot-constants.js.map +1 -0
- package/dist/ui/bot-panel.js +51 -90
- package/dist/ui/bot-slot-card.js +87 -122
- package/dist/ui/budget-bar.js +5 -3
- package/dist/ui/chat-task-result.js +4 -7
- package/dist/ui/decision-log.js +136 -0
- package/dist/ui/profile-card.js +158 -0
- package/dist/ui/profile-editor.js +597 -0
- package/dist/ui/swarm-controls.js +36 -27
- package/dist/ui/swarm-dashboard.js +2034 -736
- package/dist/ui/task-create-form.js +39 -116
- package/dist/ui/task-detail-view.js +490 -239
- package/dist/ui/task-pool-list.js +69 -94
- package/dist/workflows/orchestrator.d.ts +21 -0
- package/dist/workflows/orchestrator.d.ts.map +1 -0
- package/dist/workflows/orchestrator.js +281 -0
- package/dist/workflows/orchestrator.js.map +1 -0
- package/dist/workflows/weaver-bot-session.d.ts +65 -0
- package/dist/workflows/weaver-bot-session.d.ts.map +1 -0
- package/dist/workflows/weaver-bot-session.js +68 -0
- package/dist/workflows/weaver-bot-session.js.map +1 -0
- package/dist/workflows/weaver.d.ts +24 -0
- package/dist/workflows/weaver.d.ts.map +1 -0
- package/dist/workflows/weaver.js +28 -0
- package/dist/workflows/weaver.js.map +1 -0
- package/flowweaver.manifest.json +253 -66
- package/package.json +1 -1
- package/src/ai-chat-provider.ts +184 -18
- package/src/bot/ai-router.ts +132 -0
- package/src/bot/bot-registry.ts +2 -2
- package/src/bot/conversation-store.ts +2 -1
- package/src/bot/improve-loop.ts +6 -6
- package/src/bot/instance-manager.ts +128 -0
- package/src/bot/orchestrator.ts +244 -0
- package/src/bot/profile-store.ts +225 -0
- package/src/bot/profile-types.ts +141 -0
- package/src/bot/swarm-controller.ts +385 -186
- package/src/bot/task-prompt-builder.ts +37 -6
- package/src/bot/task-store.ts +28 -89
- package/src/bot/task-types.ts +10 -4
- package/src/cli-handlers.ts +2 -3
- package/src/docs/weaver-bot-usage.md +35 -18
- package/src/docs/weaver-config.md +20 -0
- package/src/docs/weaver-task-queue.md +31 -19
- package/src/mcp-tools.ts +129 -320
- package/src/node-types/orchestrator-dispatch.ts +71 -0
- package/src/node-types/orchestrator-load-state.ts +66 -0
- package/src/node-types/orchestrator-route.ts +33 -0
- package/src/node-types/receive-task.ts +3 -26
- package/src/ui/bot-constants.ts +192 -0
- package/src/ui/bot-panel.tsx +55 -79
- package/src/ui/bot-slot-card.tsx +69 -117
- package/src/ui/budget-bar.tsx +5 -3
- package/src/ui/chat-task-result.tsx +6 -9
- package/src/ui/decision-log.tsx +148 -0
- package/src/ui/profile-card.tsx +157 -0
- package/src/ui/profile-editor.tsx +384 -0
- package/src/ui/swarm-controls.tsx +35 -31
- package/src/ui/swarm-dashboard.tsx +409 -80
- package/src/ui/task-create-form.tsx +29 -119
- package/src/ui/task-detail-view.tsx +461 -215
- package/src/ui/task-pool-list.tsx +74 -95
- package/src/workflows/orchestrator.ts +302 -0
- package/dist/docs/weaver-bot-usage.md +0 -34
- package/dist/docs/weaver-genesis.md +0 -32
- package/dist/docs/weaver-task-queue.md +0 -34
- package/src/bot/error-guide.ts +0 -4
- package/src/bot/retry-utils.ts +0 -4
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
import type { Task, RunSummary } from './task-types.js';
|
|
21
|
+
import type { ProfilePreferences } from './profile-types.js';
|
|
21
22
|
|
|
22
23
|
const MAX_CONTEXT_TOKENS = 4000;
|
|
23
24
|
const CHARS_PER_TOKEN = 4; // rough estimate
|
|
@@ -28,16 +29,17 @@ export function buildTaskPrompt(
|
|
|
28
29
|
task: Task,
|
|
29
30
|
parentTask?: Task | null,
|
|
30
31
|
siblingTasks?: Task[],
|
|
32
|
+
preferences?: ProfilePreferences,
|
|
31
33
|
): string {
|
|
32
34
|
// Build the full (un-truncated) prompt first
|
|
33
|
-
const prompt = buildFull(task, parentTask, siblingTasks);
|
|
35
|
+
const prompt = buildFull(task, parentTask, siblingTasks, preferences);
|
|
34
36
|
|
|
35
37
|
if (prompt.length <= MAX_CONTEXT_CHARS) {
|
|
36
38
|
return prompt;
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
// Over budget — apply truncation cascade progressively
|
|
40
|
-
return truncatePrompt(task, parentTask, siblingTasks);
|
|
42
|
+
return truncatePrompt(task, parentTask, siblingTasks, preferences);
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
// ---------------------------------------------------------------------------
|
|
@@ -48,6 +50,7 @@ function buildFull(
|
|
|
48
50
|
task: Task,
|
|
49
51
|
parentTask?: Task | null,
|
|
50
52
|
siblingTasks?: Task[],
|
|
53
|
+
preferences?: ProfilePreferences,
|
|
51
54
|
): string {
|
|
52
55
|
const sections: string[] = [];
|
|
53
56
|
|
|
@@ -88,6 +91,11 @@ function buildFull(
|
|
|
88
91
|
sections.push(`### Last Error\n${task.context.lastError}`);
|
|
89
92
|
}
|
|
90
93
|
|
|
94
|
+
// Execution preferences
|
|
95
|
+
if (preferences) {
|
|
96
|
+
sections.push(buildPreferencesSection(preferences));
|
|
97
|
+
}
|
|
98
|
+
|
|
91
99
|
// Parent context
|
|
92
100
|
if (parentTask) {
|
|
93
101
|
sections.push(buildParentSection(parentTask, siblingTasks));
|
|
@@ -104,6 +112,7 @@ function truncatePrompt(
|
|
|
104
112
|
task: Task,
|
|
105
113
|
parentTask?: Task | null,
|
|
106
114
|
siblingTasks?: Task[],
|
|
115
|
+
preferences?: ProfilePreferences,
|
|
107
116
|
): string {
|
|
108
117
|
// Level 1: All summaries condensed to one-liners
|
|
109
118
|
let result = buildWithTruncation(task, parentTask, siblingTasks, {
|
|
@@ -111,7 +120,7 @@ function truncatePrompt(
|
|
|
111
120
|
filesFromRecentRunsOnly: false,
|
|
112
121
|
parentTitleOnly: false,
|
|
113
122
|
notesCapped: false,
|
|
114
|
-
});
|
|
123
|
+
}, preferences);
|
|
115
124
|
if (result.length <= MAX_CONTEXT_CHARS) return result;
|
|
116
125
|
|
|
117
126
|
// Level 2: File list → only files from last 2 runs
|
|
@@ -120,7 +129,7 @@ function truncatePrompt(
|
|
|
120
129
|
filesFromRecentRunsOnly: true,
|
|
121
130
|
parentTitleOnly: false,
|
|
122
131
|
notesCapped: false,
|
|
123
|
-
});
|
|
132
|
+
}, preferences);
|
|
124
133
|
if (result.length <= MAX_CONTEXT_CHARS) return result;
|
|
125
134
|
|
|
126
135
|
// Level 3: Parent context → title only
|
|
@@ -129,7 +138,7 @@ function truncatePrompt(
|
|
|
129
138
|
filesFromRecentRunsOnly: true,
|
|
130
139
|
parentTitleOnly: true,
|
|
131
140
|
notesCapped: false,
|
|
132
|
-
});
|
|
141
|
+
}, preferences);
|
|
133
142
|
if (result.length <= MAX_CONTEXT_CHARS) return result;
|
|
134
143
|
|
|
135
144
|
// Level 4: Notes → first 500 chars
|
|
@@ -138,7 +147,7 @@ function truncatePrompt(
|
|
|
138
147
|
filesFromRecentRunsOnly: true,
|
|
139
148
|
parentTitleOnly: true,
|
|
140
149
|
notesCapped: true,
|
|
141
|
-
});
|
|
150
|
+
}, preferences);
|
|
142
151
|
|
|
143
152
|
// Hard-truncate if still over (shouldn't happen with reasonable data)
|
|
144
153
|
if (result.length > MAX_CONTEXT_CHARS) {
|
|
@@ -160,6 +169,7 @@ function buildWithTruncation(
|
|
|
160
169
|
parentTask: Task | null | undefined,
|
|
161
170
|
siblingTasks: Task[] | undefined,
|
|
162
171
|
flags: TruncationFlags,
|
|
172
|
+
preferences?: ProfilePreferences,
|
|
163
173
|
): string {
|
|
164
174
|
const sections: string[] = [];
|
|
165
175
|
|
|
@@ -215,6 +225,11 @@ function buildWithTruncation(
|
|
|
215
225
|
sections.push(`### Last Error\n${errorText}`);
|
|
216
226
|
}
|
|
217
227
|
|
|
228
|
+
// Execution preferences
|
|
229
|
+
if (preferences) {
|
|
230
|
+
sections.push(buildPreferencesSection(preferences));
|
|
231
|
+
}
|
|
232
|
+
|
|
218
233
|
// Parent context
|
|
219
234
|
if (parentTask) {
|
|
220
235
|
if (flags.parentTitleOnly) {
|
|
@@ -264,6 +279,22 @@ function buildParentSection(
|
|
|
264
279
|
return section;
|
|
265
280
|
}
|
|
266
281
|
|
|
282
|
+
function buildPreferencesSection(preferences: ProfilePreferences): string {
|
|
283
|
+
const lines = ['## Execution Preferences'];
|
|
284
|
+
lines.push(`Cost strategy: ${preferences.costStrategy}`);
|
|
285
|
+
if (preferences.maxCostPerRun !== undefined) {
|
|
286
|
+
lines.push(`Max cost per run: $${preferences.maxCostPerRun.toFixed(2)}`);
|
|
287
|
+
}
|
|
288
|
+
if (preferences.maxCostPerTask !== undefined) {
|
|
289
|
+
lines.push(`Max cost per task: $${preferences.maxCostPerTask.toFixed(2)}`);
|
|
290
|
+
}
|
|
291
|
+
if (preferences.instructions) {
|
|
292
|
+
lines.push(`Instructions: ${preferences.instructions}`);
|
|
293
|
+
}
|
|
294
|
+
lines.push(`Approval required: ${preferences.requireApproval ? 'yes' : 'no'}`);
|
|
295
|
+
return lines.join('\n');
|
|
296
|
+
}
|
|
297
|
+
|
|
267
298
|
function statusIcon(status: string): string {
|
|
268
299
|
switch (status) {
|
|
269
300
|
case 'done':
|
package/src/bot/task-store.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as fs from 'node:fs';
|
|
|
2
2
|
import * as path from 'node:path';
|
|
3
3
|
import * as crypto from 'node:crypto';
|
|
4
4
|
import { AsyncMutex } from './async-mutex.js';
|
|
5
|
-
import type { Task, TaskFilter, CreateTaskInput, RunSummary
|
|
5
|
+
import type { Task, TaskFilter, CreateTaskInput, RunSummary } from './task-types.js';
|
|
6
6
|
|
|
7
7
|
/** Don't re-queue tasks completed/failed within this window (ms). */
|
|
8
8
|
const DEDUP_WINDOW_MS = 3_600_000; // 1 hour
|
|
@@ -43,8 +43,8 @@ export class TaskStore {
|
|
|
43
43
|
isParent: true,
|
|
44
44
|
parentId: input.parentId,
|
|
45
45
|
dependsOn: input.dependsOn ?? [],
|
|
46
|
-
assignedBots: input.assignedBots ?? [],
|
|
47
46
|
currentBotId: undefined,
|
|
47
|
+
currentRunId: undefined,
|
|
48
48
|
context: { files: [], notes: '', runSummaries: [] },
|
|
49
49
|
runs: [],
|
|
50
50
|
attempt: 0,
|
|
@@ -54,6 +54,8 @@ export class TaskStore {
|
|
|
54
54
|
tokensUsed: 0,
|
|
55
55
|
costUsed: 0,
|
|
56
56
|
timeoutMs: input.timeoutMs,
|
|
57
|
+
complexity: input.complexity,
|
|
58
|
+
assignedProfile: input.assignedProfile,
|
|
57
59
|
createdBy: input.createdBy ?? 'user',
|
|
58
60
|
createdAt: now,
|
|
59
61
|
updatedAt: now,
|
|
@@ -80,8 +82,8 @@ export class TaskStore {
|
|
|
80
82
|
isParent: false,
|
|
81
83
|
parentId: parentId,
|
|
82
84
|
dependsOn: resolvedDeps,
|
|
83
|
-
assignedBots: sub.assignedBots ?? input.assignedBots ?? [],
|
|
84
85
|
currentBotId: undefined,
|
|
86
|
+
currentRunId: undefined,
|
|
85
87
|
context: { files: [], notes: '', runSummaries: [] },
|
|
86
88
|
runs: [],
|
|
87
89
|
attempt: 0,
|
|
@@ -90,6 +92,8 @@ export class TaskStore {
|
|
|
90
92
|
budgetCost: input.budgetCost,
|
|
91
93
|
tokensUsed: 0,
|
|
92
94
|
costUsed: 0,
|
|
95
|
+
complexity: sub.complexity ?? input.complexity,
|
|
96
|
+
assignedProfile: sub.assignedProfile ?? input.assignedProfile,
|
|
93
97
|
createdBy: input.createdBy ?? 'user',
|
|
94
98
|
createdAt: now,
|
|
95
99
|
updatedAt: now,
|
|
@@ -116,8 +120,8 @@ export class TaskStore {
|
|
|
116
120
|
isParent: false,
|
|
117
121
|
parentId: input.parentId,
|
|
118
122
|
dependsOn: input.dependsOn ?? [],
|
|
119
|
-
assignedBots: input.assignedBots ?? [],
|
|
120
123
|
currentBotId: undefined,
|
|
124
|
+
currentRunId: undefined,
|
|
121
125
|
context: { files: [], notes: '', runSummaries: [] },
|
|
122
126
|
runs: [],
|
|
123
127
|
attempt: 0,
|
|
@@ -127,6 +131,8 @@ export class TaskStore {
|
|
|
127
131
|
tokensUsed: 0,
|
|
128
132
|
costUsed: 0,
|
|
129
133
|
timeoutMs: input.timeoutMs,
|
|
134
|
+
complexity: input.complexity,
|
|
135
|
+
assignedProfile: input.assignedProfile,
|
|
130
136
|
createdBy: input.createdBy ?? 'user',
|
|
131
137
|
createdAt: now,
|
|
132
138
|
updatedAt: now,
|
|
@@ -159,11 +165,6 @@ export class TaskStore {
|
|
|
159
165
|
if (filter.botId !== undefined) {
|
|
160
166
|
tasks = tasks.filter(t => t.currentBotId === filter.botId);
|
|
161
167
|
}
|
|
162
|
-
if (filter.assignedBots !== undefined && filter.assignedBots.length > 0) {
|
|
163
|
-
tasks = tasks.filter(t =>
|
|
164
|
-
t.assignedBots.length === 0 || t.assignedBots.some(b => filter.assignedBots!.includes(b)),
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
168
|
if (filter.limit !== undefined && filter.limit > 0) {
|
|
168
169
|
tasks = tasks.slice(0, filter.limit);
|
|
169
170
|
}
|
|
@@ -221,57 +222,31 @@ export class TaskStore {
|
|
|
221
222
|
}
|
|
222
223
|
|
|
223
224
|
// ---------------------------------------------------------------------------
|
|
224
|
-
//
|
|
225
|
+
// Push-based assignment (orchestrator)
|
|
225
226
|
// ---------------------------------------------------------------------------
|
|
226
227
|
|
|
227
|
-
async
|
|
228
|
+
async assignToInstance(taskId: string, instanceId: string, profileId: string): Promise<Task> {
|
|
228
229
|
return this.mutex.runExclusive(async () => {
|
|
229
230
|
const tasks = this._readAll();
|
|
231
|
+
const idx = tasks.findIndex(t => t.id === taskId);
|
|
232
|
+
if (idx === -1) throw new Error(`Task not found: ${taskId}`);
|
|
230
233
|
|
|
231
|
-
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
else if (t.status === 'failed' && t.attempt < t.maxAttempts) { /* ok */ }
|
|
239
|
-
else return false;
|
|
240
|
-
|
|
241
|
-
// Skip parent tasks
|
|
242
|
-
if (t.isParent) return false;
|
|
243
|
-
|
|
244
|
-
// Check assigned bots
|
|
245
|
-
if (t.assignedBots.length > 0 && !t.assignedBots.includes(botId)) return false;
|
|
246
|
-
|
|
247
|
-
// Check dependencies — all must be done
|
|
248
|
-
if (t.dependsOn.length > 0 && !t.dependsOn.every(depId => doneIds.has(depId))) return false;
|
|
249
|
-
|
|
250
|
-
// Check per-task budget (tokens)
|
|
251
|
-
if (t.budgetTokens !== undefined && t.tokensUsed >= t.budgetTokens) return false;
|
|
252
|
-
|
|
253
|
-
// Check per-task budget (cost)
|
|
254
|
-
if (t.budgetCost !== undefined && t.costUsed >= t.budgetCost) return false;
|
|
255
|
-
|
|
256
|
-
return true;
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
if (eligible.length === 0) return null;
|
|
260
|
-
|
|
261
|
-
// Sort: higher priority first, then older createdAt first
|
|
262
|
-
eligible.sort((a, b) =>
|
|
263
|
-
b.priority - a.priority || Date.parse(a.createdAt) - Date.parse(b.createdAt),
|
|
264
|
-
);
|
|
265
|
-
|
|
266
|
-
const target = eligible[0];
|
|
267
|
-
const idx = tasks.findIndex(t => t.id === target.id);
|
|
234
|
+
const task = tasks[idx];
|
|
235
|
+
const assignable =
|
|
236
|
+
task.status === 'pending' ||
|
|
237
|
+
(task.status === 'failed' && task.attempt < task.maxAttempts);
|
|
238
|
+
if (!assignable) {
|
|
239
|
+
throw new Error(`Task ${taskId} is not assignable (status: ${task.status}, attempt: ${task.attempt}/${task.maxAttempts})`);
|
|
240
|
+
}
|
|
268
241
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
242
|
+
task.status = 'in-progress';
|
|
243
|
+
task.currentBotId = instanceId;
|
|
244
|
+
task.assignedProfile = profileId;
|
|
245
|
+
task.updatedAt = new Date().toISOString();
|
|
272
246
|
|
|
247
|
+
tasks[idx] = task;
|
|
273
248
|
this._writeAll(tasks);
|
|
274
|
-
return
|
|
249
|
+
return task;
|
|
275
250
|
});
|
|
276
251
|
}
|
|
277
252
|
|
|
@@ -303,6 +278,7 @@ export class TaskStore {
|
|
|
303
278
|
task.attempt += 1;
|
|
304
279
|
task.status = status;
|
|
305
280
|
task.currentBotId = undefined;
|
|
281
|
+
task.currentRunId = undefined;
|
|
306
282
|
task.updatedAt = new Date().toISOString();
|
|
307
283
|
|
|
308
284
|
if (status === 'done') {
|
|
@@ -408,43 +384,6 @@ export class TaskStore {
|
|
|
408
384
|
return null;
|
|
409
385
|
}
|
|
410
386
|
|
|
411
|
-
// ---------------------------------------------------------------------------
|
|
412
|
-
// Legacy migration
|
|
413
|
-
// ---------------------------------------------------------------------------
|
|
414
|
-
|
|
415
|
-
/**
|
|
416
|
-
* Migrate legacy TaskQueue entries to Task entities.
|
|
417
|
-
* Called once on first load. Renames legacy files after migration.
|
|
418
|
-
*/
|
|
419
|
-
async migrate(): Promise<void> {
|
|
420
|
-
const legacyQueuePath = path.join(this.projectDir, '.weaver', 'task-queue.ndjson');
|
|
421
|
-
const legacySessionPath = path.join(this.projectDir, '.weaver', 'session.json');
|
|
422
|
-
|
|
423
|
-
// Migrate task queue
|
|
424
|
-
if (fs.existsSync(legacyQueuePath)) {
|
|
425
|
-
const lines = fs.readFileSync(legacyQueuePath, 'utf-8').split('\n').filter(Boolean);
|
|
426
|
-
for (const line of lines) {
|
|
427
|
-
try {
|
|
428
|
-
const entry = JSON.parse(line);
|
|
429
|
-
if (entry.status === 'pending') {
|
|
430
|
-
await this.create({
|
|
431
|
-
title: entry.instruction,
|
|
432
|
-
description: entry.instruction,
|
|
433
|
-
priority: entry.priority ?? 0,
|
|
434
|
-
createdBy: 'user',
|
|
435
|
-
});
|
|
436
|
-
}
|
|
437
|
-
} catch { /* skip corrupt lines */ }
|
|
438
|
-
}
|
|
439
|
-
fs.renameSync(legacyQueuePath, legacyQueuePath + '.migrated');
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
// Discard legacy session
|
|
443
|
-
if (fs.existsSync(legacySessionPath)) {
|
|
444
|
-
fs.renameSync(legacySessionPath, legacySessionPath + '.migrated');
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
|
|
448
387
|
// ---------------------------------------------------------------------------
|
|
449
388
|
// File I/O — atomic write via temp + rename
|
|
450
389
|
// ---------------------------------------------------------------------------
|
package/src/bot/task-types.ts
CHANGED
|
@@ -37,8 +37,8 @@ export interface Task {
|
|
|
37
37
|
dependsOn: string[];
|
|
38
38
|
|
|
39
39
|
// Assignment
|
|
40
|
-
assignedBots: string[];
|
|
41
40
|
currentBotId?: string;
|
|
41
|
+
currentRunId?: string;
|
|
42
42
|
|
|
43
43
|
// Context
|
|
44
44
|
context: TaskContext;
|
|
@@ -57,6 +57,11 @@ export interface Task {
|
|
|
57
57
|
// Timeout
|
|
58
58
|
timeoutMs?: number;
|
|
59
59
|
|
|
60
|
+
// Orchestrator routing
|
|
61
|
+
assignedProfile?: string; // profile ID assigned by orchestrator
|
|
62
|
+
routingReason?: string; // why this profile was chosen
|
|
63
|
+
complexity?: 'trivial' | 'simple' | 'moderate' | 'complex'; // task complexity estimate
|
|
64
|
+
|
|
60
65
|
// Metadata
|
|
61
66
|
createdBy: 'user' | 'ai';
|
|
62
67
|
createdAt: string;
|
|
@@ -68,14 +73,12 @@ export interface TaskFilter {
|
|
|
68
73
|
status?: TaskStatus | TaskStatus[];
|
|
69
74
|
parentId?: string;
|
|
70
75
|
botId?: string;
|
|
71
|
-
assignedBots?: string[];
|
|
72
76
|
limit?: number;
|
|
73
77
|
}
|
|
74
78
|
|
|
75
79
|
export interface CreateTaskInput {
|
|
76
80
|
title: string;
|
|
77
81
|
description: string;
|
|
78
|
-
assignedBots?: string[];
|
|
79
82
|
priority?: number;
|
|
80
83
|
parentId?: string;
|
|
81
84
|
dependsOn?: string[];
|
|
@@ -84,11 +87,14 @@ export interface CreateTaskInput {
|
|
|
84
87
|
timeoutMs?: number;
|
|
85
88
|
maxAttempts?: number;
|
|
86
89
|
createdBy?: 'user' | 'ai';
|
|
90
|
+
complexity?: 'trivial' | 'simple' | 'moderate' | 'complex';
|
|
91
|
+
assignedProfile?: string;
|
|
87
92
|
subtasks?: Array<{
|
|
88
93
|
title: string;
|
|
89
94
|
description?: string;
|
|
90
|
-
assignedBots?: string[];
|
|
91
95
|
dependsOn?: string[];
|
|
92
96
|
priority?: number;
|
|
97
|
+
complexity?: 'trivial' | 'simple' | 'moderate' | 'complex';
|
|
98
|
+
assignedProfile?: string;
|
|
93
99
|
}>;
|
|
94
100
|
}
|
package/src/cli-handlers.ts
CHANGED
|
@@ -1447,11 +1447,10 @@ export async function handleSession(opts: ParsedArgs): Promise<void> {
|
|
|
1447
1447
|
const filesInUse = new Set<string>();
|
|
1448
1448
|
|
|
1449
1449
|
const processTask = async (task: { id: string; title: string; description: string; context: { files: string[] } }) => {
|
|
1450
|
-
|
|
1451
|
-
const legacyTask = { id: task.id, instruction: task.title, targets: task.context.files };
|
|
1450
|
+
const taskPayload = { id: task.id, instruction: task.title, description: task.description, targets: task.context.files };
|
|
1452
1451
|
try {
|
|
1453
1452
|
const result = await runWorkflow(workflowPath, {
|
|
1454
|
-
params: { projectDir, taskJson: JSON.stringify(
|
|
1453
|
+
params: { projectDir, taskJson: JSON.stringify(taskPayload) },
|
|
1455
1454
|
verbose: opts.verbose,
|
|
1456
1455
|
dryRun: opts.dryRun,
|
|
1457
1456
|
config,
|
|
@@ -1,34 +1,51 @@
|
|
|
1
|
-
## Weaver Bot
|
|
1
|
+
## Weaver Bot (Swarm)
|
|
2
2
|
|
|
3
|
-
The Weaver bot is an autonomous AI agent that creates and modifies Flow Weaver workflows
|
|
3
|
+
The Weaver bot is an autonomous AI agent that creates and modifies Flow Weaver workflows. Tasks are executed via the swarm orchestrator, which routes work to the best available bot profile.
|
|
4
4
|
|
|
5
|
-
### Running
|
|
5
|
+
### Running tasks
|
|
6
6
|
|
|
7
|
-
Use `
|
|
8
|
-
- `
|
|
9
|
-
- `
|
|
10
|
-
- `
|
|
11
|
-
- `
|
|
7
|
+
Use `fw_weaver_task_create` to submit work:
|
|
8
|
+
- `title`: Short task title (required)
|
|
9
|
+
- `description`: Detailed instructions
|
|
10
|
+
- `assignedProfile`: Target a specific bot profile
|
|
11
|
+
- `complexity`: trivial, simple, moderate, complex
|
|
12
|
+
- `subtasks`: Inline subtask definitions with dependency chaining
|
|
13
|
+
|
|
14
|
+
Then start the swarm with `fw_weaver_swarm_start` to begin execution.
|
|
12
15
|
|
|
13
16
|
### Execution flow
|
|
14
17
|
|
|
15
|
-
1. **
|
|
16
|
-
2. **
|
|
17
|
-
3. **
|
|
18
|
-
4. **
|
|
19
|
-
5. **Execute + validate + retry** — runs steps, validates output, retries on errors (up to
|
|
18
|
+
1. **Create task** — `fw_weaver_task_create` adds task to the pool
|
|
19
|
+
2. **Orchestrator routes** — matches task to best bot profile via fast-path cascade (exact-match, capability-match, single-eligible, ai-routed, round-robin)
|
|
20
|
+
3. **Build context** — gathers project state, templates, and relevant files
|
|
21
|
+
4. **Plan** — AI generates a step-by-step execution plan
|
|
22
|
+
5. **Execute + validate + retry** — runs steps, validates output, retries on errors (up to maxAttempts)
|
|
20
23
|
6. **Git ops** — commits changes if successful
|
|
21
|
-
7. **Report** —
|
|
24
|
+
7. **Report** — task marked done/failed with run summary
|
|
22
25
|
|
|
23
26
|
### Steering a running bot
|
|
24
27
|
|
|
25
|
-
Use `fw_weaver_steer` to control execution:
|
|
28
|
+
Use `fw_weaver_steer` with a `botId` to control execution:
|
|
26
29
|
- `pause` — pause at next safe point
|
|
27
30
|
- `resume` — continue after pause
|
|
28
31
|
- `cancel` — abort execution
|
|
29
|
-
- `redirect` — change task mid-execution
|
|
30
|
-
- `queue` — add a follow-up task
|
|
31
32
|
|
|
32
33
|
### Checking status
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
- `fw_weaver_status` — quick swarm summary (active bots, tasks completed, budget)
|
|
36
|
+
- `fw_weaver_swarm_status` — full swarm state with per-instance details
|
|
37
|
+
- `fw_weaver_swarm_events` — live event stream
|
|
38
|
+
- `fw_weaver_orchestrator_status` — routing decisions, stats, active instances
|
|
39
|
+
|
|
40
|
+
### Profiles
|
|
41
|
+
|
|
42
|
+
Use `fw_weaver_profile_create` to create specialized bot profiles. Each profile defines:
|
|
43
|
+
|
|
44
|
+
- **capabilities** — free-form list of `{ name, description }` objects describing what the profile can do. Names are arbitrary strings (e.g. `code-generation`, `testing`, `deployment`). The orchestrator uses the description text to match tasks to profiles.
|
|
45
|
+
- **preferences** — intent-based settings that control profile behavior:
|
|
46
|
+
- `costStrategy` — `"economy"` (minimize cost), `"balanced"` (default), or `"quality"` (maximize quality regardless of cost)
|
|
47
|
+
- `requireApproval` — whether tasks routed to this profile need human approval before execution
|
|
48
|
+
- `instructions` — optional free-text instructions appended to the bot's system prompt
|
|
49
|
+
- **scaling** — `minInstances` and `maxInstances` control how many concurrent bots can run this profile
|
|
50
|
+
|
|
51
|
+
The orchestrator routes tasks to profiles based on `assignedProfile` or by matching task intent against profile capabilities.
|
|
@@ -4,6 +4,17 @@ The weaver bot runs workflows, executes tasks from natural language, and evolves
|
|
|
4
4
|
|
|
5
5
|
The bot has deep knowledge of the full flow-weaver ecosystem: annotation grammar, CLI tools, node patterns, error diagnosis, and the genesis protocol (loaded dynamically from `@synergenius/flow-weaver/doc-metadata`).
|
|
6
6
|
|
|
7
|
+
## Execution models
|
|
8
|
+
|
|
9
|
+
Weaver supports two execution models:
|
|
10
|
+
|
|
11
|
+
- **Single-run mode** — execute one workflow or natural-language task end-to-end via `flow-weaver weaver run` or `flow-weaver weaver bot`. Good for one-off tasks, CI pipelines, and simple automations.
|
|
12
|
+
- **Swarm/task model** — create tasks, define bot profiles with capabilities, and let the orchestrator route work to the best available bot instance. Multiple bots can run concurrently with budget controls and automatic retries.
|
|
13
|
+
|
|
14
|
+
The `.weaver.json` config applies to both models. Provider settings, approval gates, and notifications are shared. Swarm-specific settings (profiles, budgets, concurrency) are managed through the swarm control tools or the Studio UI.
|
|
15
|
+
|
|
16
|
+
> See [weaver-bot-usage.md](weaver-bot-usage.md) for full swarm documentation including profiles, orchestrator routing, and multi-bot workflows.
|
|
17
|
+
|
|
7
18
|
## Getting started
|
|
8
19
|
|
|
9
20
|
Run the bot directly via CLI:
|
|
@@ -16,6 +27,15 @@ flow-weaver weaver session
|
|
|
16
27
|
|
|
17
28
|
Or scaffold a project via `flow-weaver init` and select the "AI Workflow Runner" use case.
|
|
18
29
|
|
|
30
|
+
## Profiles and .weaver.json
|
|
31
|
+
|
|
32
|
+
Bot profiles define specialized bot types with free-form capabilities, intent-based preferences, and scaling limits. Profiles are created via `fw_weaver_profile_create` and stored in the `.weaver/` directory. The `.weaver.json` config provides the base provider and approval settings that profiles inherit unless overridden.
|
|
33
|
+
|
|
34
|
+
Each profile specifies:
|
|
35
|
+
- **capabilities** — an array of `{ name, description }` objects. Names are free-form strings (e.g. `code-generation`, `testing`, `deployment`). The orchestrator uses descriptions to match tasks to profiles.
|
|
36
|
+
- **preferences** — intent-based settings: `costStrategy` (`economy`, `balanced`, `quality`), `requireApproval` (boolean), and optional `instructions` (free-text appended to the bot system prompt).
|
|
37
|
+
- **scaling** — `minInstances` / `maxInstances` for concurrency control.
|
|
38
|
+
|
|
19
39
|
## .weaver.json
|
|
20
40
|
|
|
21
41
|
Place a `.weaver.json` in your project root to configure the weaver workflow:
|
|
@@ -1,34 +1,46 @@
|
|
|
1
|
-
## Task
|
|
1
|
+
## Task Management & Steering
|
|
2
2
|
|
|
3
|
-
Weaver
|
|
3
|
+
Weaver uses a swarm-based task system for background processing and real-time bot control.
|
|
4
4
|
|
|
5
|
-
###
|
|
5
|
+
### Creating tasks
|
|
6
6
|
|
|
7
|
-
Use `
|
|
8
|
-
- `
|
|
9
|
-
- `
|
|
10
|
-
- `
|
|
11
|
-
- `
|
|
7
|
+
Use `fw_weaver_task_create` to create tasks:
|
|
8
|
+
- `title` — short task title (required)
|
|
9
|
+
- `description` — detailed instructions
|
|
10
|
+
- `priority` — higher number = picked first (default 0)
|
|
11
|
+
- `assignedProfile` — route to a specific bot profile
|
|
12
|
+
- `complexity` — trivial, simple, moderate, complex
|
|
13
|
+
- `subtasks` — inline subtask definitions with `^prev` dependency shorthand
|
|
14
|
+
- `budgetTokens` / `budgetCost` — per-task budget limits
|
|
12
15
|
|
|
13
|
-
|
|
16
|
+
### Listing and managing tasks
|
|
17
|
+
|
|
18
|
+
- `fw_weaver_task_list` — list tasks (filter by status, parentId, botId)
|
|
19
|
+
- `fw_weaver_task_get` — get task details including subtasks
|
|
20
|
+
- `fw_weaver_task_update` — update task fields
|
|
21
|
+
- `fw_weaver_task_cancel` — cancel a pending or running task
|
|
22
|
+
- `fw_weaver_task_retry` — reset a failed task back to pending
|
|
14
23
|
|
|
15
24
|
### Steering commands
|
|
16
25
|
|
|
17
|
-
Use `fw_weaver_steer` to control a running bot:
|
|
26
|
+
Use `fw_weaver_steer` to control a running bot instance:
|
|
18
27
|
- `pause` — pause execution at the next safe point
|
|
19
28
|
- `resume` — continue after a pause
|
|
20
29
|
- `cancel` — abort the current task
|
|
21
|
-
- `redirect` — change the task instruction mid-execution (requires `payload` with new instruction)
|
|
22
|
-
- `queue` — add a follow-up task without interrupting the current one
|
|
23
30
|
|
|
24
|
-
###
|
|
31
|
+
### Swarm control
|
|
25
32
|
|
|
26
|
-
|
|
33
|
+
- `fw_weaver_swarm_start` — start the swarm (spawns bot loops that claim and execute tasks)
|
|
34
|
+
- `fw_weaver_swarm_pause` — pause all bot loops
|
|
35
|
+
- `fw_weaver_swarm_stop` — stop the swarm gracefully
|
|
36
|
+
- `fw_weaver_swarm_status` — full swarm state with per-bot details
|
|
37
|
+
- `fw_weaver_swarm_config` — configure max concurrency, budgets, auto-retry
|
|
38
|
+
- `fw_weaver_swarm_events` — stream swarm-level events for live updates
|
|
27
39
|
|
|
28
40
|
### Monitoring
|
|
29
41
|
|
|
30
|
-
Use `fw_weaver_status` to check the current
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
42
|
+
Use `fw_weaver_status` to check the current swarm state:
|
|
43
|
+
- Swarm phase (idle, running, paused, stopping)
|
|
44
|
+
- Active/total bot instances
|
|
45
|
+
- Tasks completed/failed
|
|
46
|
+
- Budget usage
|