@synergenius/flow-weaver-pack-weaver 0.9.20 → 0.9.22
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/runner.d.ts.map +1 -1
- package/dist/bot/runner.js +76 -31
- package/dist/bot/runner.js.map +1 -1
- package/dist/bot/types.d.ts +16 -0
- package/dist/bot/types.d.ts.map +1 -1
- package/dist/ui/bot-activity.js +249 -0
- package/dist/ui/bot-config.js +57 -35
- package/flowweaver.manifest.json +2 -1
- package/package.json +1 -1
- package/src/bot/runner.ts +83 -36
- package/src/bot/types.ts +8 -0
- package/src/ui/bot-activity.tsx +343 -0
- package/src/ui/bot-config.tsx +74 -31
package/dist/ui/bot-config.js
CHANGED
|
@@ -5,12 +5,13 @@ var import_jsx_runtime = require("react/jsx-runtime");
|
|
|
5
5
|
var React = require("react");
|
|
6
6
|
var { useState, useEffect, useCallback } = React;
|
|
7
7
|
var { Typography } = require("@fw/plugin-ui-kit");
|
|
8
|
-
var { Icon } = require("@fw/plugin-ui-kit");
|
|
9
8
|
var { CollapsibleSection } = require("@fw/plugin-ui-kit");
|
|
10
9
|
var { LoadingSpinner } = require("@fw/plugin-ui-kit");
|
|
11
10
|
var { Banner } = require("@fw/plugin-ui-kit");
|
|
12
11
|
var { IconButton } = require("@fw/plugin-ui-kit");
|
|
12
|
+
var { Badge } = require("@fw/plugin-ui-kit");
|
|
13
13
|
var { styled } = require("@fw/plugin-theme");
|
|
14
|
+
var BASE = "/api/pack-tool/@synergenius/flow-weaver-pack-weaver";
|
|
14
15
|
var ConfigRow = styled.div({
|
|
15
16
|
display: "flex",
|
|
16
17
|
justifyContent: "space-between",
|
|
@@ -19,31 +20,44 @@ var ConfigRow = styled.div({
|
|
|
19
20
|
borderBottom: "1px solid $color-border-default",
|
|
20
21
|
"&:last-of-type": { borderBottom: "none" }
|
|
21
22
|
});
|
|
22
|
-
var
|
|
23
|
+
var Footer = styled.div({
|
|
24
|
+
display: "flex",
|
|
25
|
+
justifyContent: "space-between",
|
|
26
|
+
alignItems: "center",
|
|
27
|
+
marginTop: "10px",
|
|
28
|
+
paddingTop: "6px",
|
|
29
|
+
borderTop: "1px solid $color-border-default"
|
|
30
|
+
});
|
|
31
|
+
function callTool(tool, body = {}) {
|
|
32
|
+
return fetch(`${BASE}/${tool}`, {
|
|
33
|
+
method: "POST",
|
|
34
|
+
headers: { "Content-Type": "application/json" },
|
|
35
|
+
body: JSON.stringify(body),
|
|
36
|
+
credentials: "include"
|
|
37
|
+
}).then(async (res) => {
|
|
38
|
+
if (!res.ok) throw new Error("Request failed");
|
|
39
|
+
const json = await res.json();
|
|
40
|
+
if (json.isError) throw new Error(json.result);
|
|
41
|
+
try {
|
|
42
|
+
return JSON.parse(json.result);
|
|
43
|
+
} catch {
|
|
44
|
+
return json.result;
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
23
48
|
function BotConfig({ packName, botId }) {
|
|
24
|
-
const [
|
|
49
|
+
const [insights, setInsights] = useState(null);
|
|
50
|
+
const [providers, setProviders] = useState([]);
|
|
25
51
|
const [error, setError] = useState(null);
|
|
26
52
|
const [loading, setLoading] = useState(true);
|
|
27
53
|
const fetchData = useCallback(async () => {
|
|
28
54
|
try {
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (!res.ok) {
|
|
36
|
-
setError("Failed to fetch");
|
|
37
|
-
setLoading(false);
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
const json = await res.json();
|
|
41
|
-
if (json.isError) {
|
|
42
|
-
setError(json.result);
|
|
43
|
-
setLoading(false);
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
setData(JSON.parse(json.result));
|
|
55
|
+
const [ins, provs] = await Promise.allSettled([
|
|
56
|
+
callTool("fw_weaver_insights"),
|
|
57
|
+
callTool("fw_weaver_providers")
|
|
58
|
+
]);
|
|
59
|
+
if (ins.status === "fulfilled") setInsights(ins.value);
|
|
60
|
+
if (provs.status === "fulfilled" && Array.isArray(provs.value)) setProviders(provs.value);
|
|
47
61
|
setError(null);
|
|
48
62
|
} catch (e) {
|
|
49
63
|
setError(e.message ?? "Failed to load");
|
|
@@ -54,36 +68,44 @@ function BotConfig({ packName, botId }) {
|
|
|
54
68
|
useEffect(() => {
|
|
55
69
|
fetchData();
|
|
56
70
|
}, [fetchData]);
|
|
57
|
-
if (loading) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoadingSpinner, { size: "small" });
|
|
58
|
-
if (error) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { padding: "8px 12px" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Banner, { status: "danger", size: "small", children: error }) });
|
|
59
|
-
const bot =
|
|
60
|
-
const
|
|
71
|
+
if (loading) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { padding: 16, display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoadingSpinner, { size: "small" }) });
|
|
72
|
+
if (error && !insights) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { padding: "8px 12px" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Banner, { status: "danger", size: "small", children: error }) });
|
|
73
|
+
const bot = insights?.bots?.find((b) => b.name === botId) ?? insights?.bots?.[0];
|
|
74
|
+
const configuredProvider = bot?.provider;
|
|
75
|
+
const availableProvider = providers.find((p) => p.envVarsSet);
|
|
76
|
+
const activeProvider = configuredProvider || availableProvider?.name;
|
|
77
|
+
const isAutoDetected = !configuredProvider && !!availableProvider;
|
|
61
78
|
const approval = bot?.approvalMode ?? "auto";
|
|
62
|
-
const
|
|
79
|
+
const trustPhase = insights?.trust?.phase ?? 1;
|
|
80
|
+
const trustScore = insights?.trust?.score ?? 0;
|
|
81
|
+
const noProvider = !activeProvider;
|
|
63
82
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CollapsibleSection, { title: "Configuration", defaultExpanded: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: "4px 12px 12px" }, children: [
|
|
64
83
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ConfigRow, { children: [
|
|
65
84
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Typography, { variant: "smallCaption-bold", color: "color-text-subtle", children: "Provider" }),
|
|
66
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
85
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
|
|
86
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Typography, { variant: "caption-regular", color: "color-text-high", children: activeProvider ?? "None detected" }),
|
|
87
|
+
isAutoDetected && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge, { variant: "default", children: "auto" })
|
|
88
|
+
] })
|
|
67
89
|
] }),
|
|
68
90
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ConfigRow, { children: [
|
|
69
91
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Typography, { variant: "smallCaption-bold", color: "color-text-subtle", children: "Approval" }),
|
|
70
92
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Typography, { variant: "caption-regular", color: "color-text-high", children: approval })
|
|
71
93
|
] }),
|
|
72
94
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ConfigRow, { children: [
|
|
73
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Typography, { variant: "smallCaption-bold", color: "color-text-subtle", children: "Trust
|
|
95
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Typography, { variant: "smallCaption-bold", color: "color-text-subtle", children: "Trust" }),
|
|
74
96
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Typography, { variant: "caption-regular", color: "color-text-high", children: [
|
|
75
97
|
"P",
|
|
76
|
-
|
|
98
|
+
trustPhase,
|
|
77
99
|
" (",
|
|
78
|
-
|
|
100
|
+
trustScore,
|
|
79
101
|
"/100)"
|
|
80
102
|
] })
|
|
81
103
|
] }),
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Typography, { variant: "
|
|
85
|
-
|
|
86
|
-
|
|
104
|
+
noProvider && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { marginTop: 10 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Banner, { status: "warning", size: "small", children: "No AI provider detected. Set ANTHROPIC_API_KEY or install Claude CLI." }) }),
|
|
105
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Footer, { children: [
|
|
106
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Typography, { variant: "smallCaption-regular", color: "color-text-subtle", children: "Customize via .weaver.json" }),
|
|
107
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconButton, { icon: "refresh", size: "xs", variant: "clear", onClick: fetchData, title: "Refresh" })
|
|
108
|
+
] })
|
|
87
109
|
] }) });
|
|
88
110
|
}
|
|
89
111
|
module.exports = BotConfig;
|
package/flowweaver.manifest.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifestVersion": 2,
|
|
3
3
|
"name": "@synergenius/flow-weaver-pack-weaver",
|
|
4
|
-
"version": "0.9.
|
|
4
|
+
"version": "0.9.22",
|
|
5
5
|
"description": "AI bot for Flow Weaver. Execute tasks, run workflows, evolve autonomously.",
|
|
6
6
|
"engineVersion": ">=0.22.10",
|
|
7
7
|
"categories": [
|
|
@@ -1074,6 +1074,7 @@
|
|
|
1074
1074
|
],
|
|
1075
1075
|
"uiContributions": [],
|
|
1076
1076
|
"botUI": {
|
|
1077
|
+
"activity": "dist/ui/bot-activity.js",
|
|
1077
1078
|
"config": "dist/ui/bot-config.js",
|
|
1078
1079
|
"status": "dist/ui/bot-status.js",
|
|
1079
1080
|
"dashboard": "dist/ui/bot-dashboard.js"
|
package/package.json
CHANGED
package/src/bot/runner.ts
CHANGED
|
@@ -2,10 +2,12 @@ import * as fs from 'node:fs';
|
|
|
2
2
|
import * as path from 'node:path';
|
|
3
3
|
import type {
|
|
4
4
|
ApprovalMode,
|
|
5
|
+
AuditEvent,
|
|
5
6
|
AuditEventCallback,
|
|
6
7
|
BotConfig,
|
|
7
8
|
BotNotifyConfig,
|
|
8
9
|
ExecutionEvent,
|
|
10
|
+
RunCostSummary,
|
|
9
11
|
RunOutcome,
|
|
10
12
|
WeaverConfig,
|
|
11
13
|
WorkflowResult,
|
|
@@ -118,7 +120,17 @@ export async function runWorkflow(
|
|
|
118
120
|
try { store = new RunStore(); } catch { /* non-fatal */ }
|
|
119
121
|
const runId = RunStore.newId();
|
|
120
122
|
const startedAt = new Date().toISOString();
|
|
121
|
-
|
|
123
|
+
|
|
124
|
+
// Collect execution trace and audit events for persistence
|
|
125
|
+
const collectedTrace: ExecutionEvent[] = [];
|
|
126
|
+
const collectedAudit: AuditEvent[] = [];
|
|
127
|
+
|
|
128
|
+
const auditCollector: AuditEventCallback = (event) => {
|
|
129
|
+
collectedAudit.push(event);
|
|
130
|
+
options?.onAuditEvent?.(event);
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
initAuditLogger(runId, auditCollector);
|
|
122
134
|
|
|
123
135
|
// Mark run as in-progress so abrupt kills leave a trace
|
|
124
136
|
try { store?.markRunning(runId, absPath); } catch { /* non-fatal */ }
|
|
@@ -183,38 +195,55 @@ export async function runWorkflow(
|
|
|
183
195
|
return dryResult;
|
|
184
196
|
}
|
|
185
197
|
|
|
186
|
-
//
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
198
|
+
// Always collect trace events for persistence; also forward to caller if provided.
|
|
199
|
+
// Track node start times so we can compute durationMs on completion.
|
|
200
|
+
const nodeStartTimes = new Map<string, number>();
|
|
201
|
+
|
|
202
|
+
const onTraceEvent = (traceEvent: { type: string; timestamp: number; data?: Record<string, unknown> }) => {
|
|
203
|
+
if (traceEvent.type !== 'STATUS_CHANGED' || !traceEvent.data) return;
|
|
204
|
+
const nodeId = traceEvent.data.id as string | undefined;
|
|
205
|
+
const status = traceEvent.data.status as string | undefined;
|
|
206
|
+
if (!nodeId || !status) return;
|
|
207
|
+
|
|
208
|
+
let eventType: ExecutionEvent['type'] | null = null;
|
|
209
|
+
let durationMs: number | undefined;
|
|
210
|
+
|
|
211
|
+
if (status === 'RUNNING') {
|
|
212
|
+
eventType = 'node-start';
|
|
213
|
+
nodeStartTimes.set(nodeId, traceEvent.timestamp);
|
|
214
|
+
} else if (status === 'SUCCEEDED') {
|
|
215
|
+
eventType = 'node-complete';
|
|
216
|
+
const startTime = nodeStartTimes.get(nodeId);
|
|
217
|
+
if (startTime) durationMs = traceEvent.timestamp - startTime;
|
|
218
|
+
nodeStartTimes.delete(nodeId);
|
|
219
|
+
} else if (status === 'FAILED') {
|
|
220
|
+
eventType = 'node-error';
|
|
221
|
+
const startTime = nodeStartTimes.get(nodeId);
|
|
222
|
+
if (startTime) durationMs = traceEvent.timestamp - startTime;
|
|
223
|
+
nodeStartTimes.delete(nodeId);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (eventType) {
|
|
227
|
+
const event: ExecutionEvent = {
|
|
228
|
+
type: eventType,
|
|
229
|
+
nodeId,
|
|
230
|
+
nodeType: traceEvent.data.nodeTypeName as string | undefined,
|
|
231
|
+
timestamp: traceEvent.timestamp,
|
|
232
|
+
durationMs,
|
|
233
|
+
error: traceEvent.data.error as string | undefined,
|
|
234
|
+
};
|
|
235
|
+
collectedTrace.push(event);
|
|
236
|
+
options?.onEvent?.(event);
|
|
237
|
+
}
|
|
238
|
+
};
|
|
210
239
|
|
|
211
240
|
const execResult = await executeWorkflowFromFile(
|
|
212
241
|
absPath,
|
|
213
242
|
options?.params ?? {},
|
|
214
243
|
{
|
|
215
244
|
agentChannel: botChannel,
|
|
216
|
-
includeTrace:
|
|
217
|
-
production:
|
|
245
|
+
includeTrace: true,
|
|
246
|
+
production: false,
|
|
218
247
|
onEvent: onTraceEvent,
|
|
219
248
|
},
|
|
220
249
|
);
|
|
@@ -224,15 +253,30 @@ export async function runWorkflow(
|
|
|
224
253
|
const summary = buildSummary(result);
|
|
225
254
|
const outcome = success ? 'completed' : 'failed';
|
|
226
255
|
|
|
227
|
-
// Extract stepLog from WeaverContext if available
|
|
256
|
+
// Extract stepLog and plan from WeaverContext if available
|
|
228
257
|
let stepLog: import('./types.js').StepLogEntry[] | undefined;
|
|
258
|
+
let plan: RunRecord['plan'] | undefined;
|
|
229
259
|
try {
|
|
230
260
|
const ctxStr = result?.ctx as string | undefined;
|
|
231
261
|
if (ctxStr) {
|
|
232
262
|
const ctx = JSON.parse(ctxStr);
|
|
233
263
|
if (ctx.stepLogJson) stepLog = JSON.parse(ctx.stepLogJson);
|
|
264
|
+
if (ctx.planJson) {
|
|
265
|
+
const parsed = JSON.parse(ctx.planJson);
|
|
266
|
+
if (parsed?.steps) {
|
|
267
|
+
plan = {
|
|
268
|
+
summary: parsed.summary ?? '',
|
|
269
|
+
steps: (parsed.steps as Array<Record<string, unknown>>).map((s) => ({
|
|
270
|
+
id: String(s.id ?? ''),
|
|
271
|
+
operation: String(s.operation ?? ''),
|
|
272
|
+
description: String(s.description ?? ''),
|
|
273
|
+
...(s.args ? { args: s.args as Record<string, unknown> } : {}),
|
|
274
|
+
})),
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
}
|
|
234
278
|
}
|
|
235
|
-
} catch { /*
|
|
279
|
+
} catch { /* extraction is best-effort */ }
|
|
236
280
|
|
|
237
281
|
await notifier({
|
|
238
282
|
type: 'workflow-complete',
|
|
@@ -248,6 +292,10 @@ export async function runWorkflow(
|
|
|
248
292
|
id: runId, workflowFile: absPath, startedAt, success, outcome: outcome as RunOutcome, summary,
|
|
249
293
|
functionName: execResult.functionName, executionTime: execResult.executionTime,
|
|
250
294
|
dryRun: false, provider: providerConfig.name, params: options?.params, stepLog,
|
|
295
|
+
trace: collectedTrace.length > 0 ? collectedTrace : undefined,
|
|
296
|
+
plan,
|
|
297
|
+
cost: costSummary,
|
|
298
|
+
auditTrail: collectedAudit.length > 0 ? collectedAudit : undefined,
|
|
251
299
|
}, verbose);
|
|
252
300
|
|
|
253
301
|
auditEmit('run-complete', { success, outcome, summary });
|
|
@@ -275,6 +323,9 @@ export async function runWorkflow(
|
|
|
275
323
|
recordRun(store, {
|
|
276
324
|
id: runId, workflowFile: absPath, startedAt, success: false, outcome: 'error', summary: msg,
|
|
277
325
|
dryRun: options?.dryRun ?? false, provider: providerConfig.name, params: options?.params,
|
|
326
|
+
trace: collectedTrace.length > 0 ? collectedTrace : undefined,
|
|
327
|
+
cost: costSummary,
|
|
328
|
+
auditTrail: collectedAudit.length > 0 ? collectedAudit : undefined,
|
|
278
329
|
}, verbose);
|
|
279
330
|
|
|
280
331
|
auditEmit('run-complete', { success: false, error: msg });
|
|
@@ -285,15 +336,11 @@ export async function runWorkflow(
|
|
|
285
336
|
}
|
|
286
337
|
}
|
|
287
338
|
|
|
339
|
+
type RunRecord = import('./types.js').RunRecord;
|
|
340
|
+
|
|
288
341
|
function recordRun(
|
|
289
342
|
store: RunStore | null,
|
|
290
|
-
data:
|
|
291
|
-
id: string; workflowFile: string; startedAt: string; success: boolean;
|
|
292
|
-
outcome: RunOutcome; summary: string; functionName?: string;
|
|
293
|
-
executionTime?: number; dryRun: boolean; provider?: string;
|
|
294
|
-
params?: Record<string, unknown>;
|
|
295
|
-
stepLog?: import('./types.js').StepLogEntry[];
|
|
296
|
-
},
|
|
343
|
+
data: Omit<RunRecord, 'finishedAt' | 'durationMs'>,
|
|
297
344
|
verbose: boolean,
|
|
298
345
|
): void {
|
|
299
346
|
if (!store) return;
|
package/src/bot/types.ts
CHANGED
|
@@ -194,6 +194,14 @@ export interface RunRecord {
|
|
|
194
194
|
pipelineName?: string;
|
|
195
195
|
stageName?: string;
|
|
196
196
|
stepLog?: StepLogEntry[];
|
|
197
|
+
/** Node-by-node execution trace (node-start/complete/error events). */
|
|
198
|
+
trace?: ExecutionEvent[];
|
|
199
|
+
/** AI-generated plan for this run. */
|
|
200
|
+
plan?: { summary: string; steps: Array<{ id: string; operation: string; description: string; args?: Record<string, unknown> }> };
|
|
201
|
+
/** Token usage and estimated cost. */
|
|
202
|
+
cost?: RunCostSummary;
|
|
203
|
+
/** Lifecycle audit events (plan-created, approval, step-start/complete, etc.). */
|
|
204
|
+
auditTrail?: AuditEvent[];
|
|
197
205
|
}
|
|
198
206
|
|
|
199
207
|
export interface RunFilter {
|