@ranker/raxflow 2.0.5 → 2.1.1
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/hub/components/ChatInput.d.ts +14 -0
- package/dist/hub/components/ChatInput.d.ts.map +1 -0
- package/dist/hub/components/ChatInput.js +14 -0
- package/dist/hub/components/ChatInput.js.map +1 -0
- package/dist/hub/components/ChatMessage.d.ts +14 -0
- package/dist/hub/components/ChatMessage.d.ts.map +1 -0
- package/dist/hub/components/ChatMessage.js +23 -0
- package/dist/hub/components/ChatMessage.js.map +1 -0
- package/dist/hub/components/HubHeader.d.ts +12 -0
- package/dist/hub/components/HubHeader.d.ts.map +1 -0
- package/dist/hub/components/HubHeader.js +12 -0
- package/dist/hub/components/HubHeader.js.map +1 -0
- package/dist/hub/components/index.d.ts +7 -0
- package/dist/hub/components/index.d.ts.map +1 -0
- package/dist/hub/components/index.js +7 -0
- package/dist/hub/components/index.js.map +1 -0
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +10 -10
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/components/ChatPanel.d.ts +1 -1
- package/dist/tui/components/ChatPanel.d.ts.map +1 -1
- package/dist/tui/components/ChatPanel.js +37 -26
- package/dist/tui/components/ChatPanel.js.map +1 -1
- package/dist/tui/components/DAGPanel.d.ts +3 -4
- package/dist/tui/components/DAGPanel.d.ts.map +1 -1
- package/dist/tui/components/DAGPanel.js +44 -36
- package/dist/tui/components/DAGPanel.js.map +1 -1
- package/dist/tui/components/Header.d.ts.map +1 -1
- package/dist/tui/components/Header.js +54 -36
- package/dist/tui/components/Header.js.map +1 -1
- package/dist/tui/components/HelpOverlay.d.ts.map +1 -1
- package/dist/tui/components/HelpOverlay.js +7 -5
- package/dist/tui/components/HelpOverlay.js.map +1 -1
- package/dist/tui/components/InputBar.d.ts.map +1 -1
- package/dist/tui/components/InputBar.js +25 -13
- package/dist/tui/components/InputBar.js.map +1 -1
- package/dist/tui/components/LogsPanel.d.ts.map +1 -1
- package/dist/tui/components/LogsPanel.js +23 -17
- package/dist/tui/components/LogsPanel.js.map +1 -1
- package/dist/tui/components/MemoryPanel.d.ts +1 -1
- package/dist/tui/components/MemoryPanel.d.ts.map +1 -1
- package/dist/tui/components/MemoryPanel.js +24 -31
- package/dist/tui/components/MemoryPanel.js.map +1 -1
- package/dist/tui/components/MetricsPanel.d.ts +1 -1
- package/dist/tui/components/MetricsPanel.d.ts.map +1 -1
- package/dist/tui/components/MetricsPanel.js +10 -13
- package/dist/tui/components/MetricsPanel.js.map +1 -1
- package/dist/tui/components/SelectMenu.d.ts +20 -0
- package/dist/tui/components/SelectMenu.d.ts.map +1 -0
- package/dist/tui/components/SelectMenu.js +19 -0
- package/dist/tui/components/SelectMenu.js.map +1 -0
- package/dist/tui/components/StatusPanel.d.ts +4 -3
- package/dist/tui/components/StatusPanel.d.ts.map +1 -1
- package/dist/tui/components/StatusPanel.js +26 -18
- package/dist/tui/components/StatusPanel.js.map +1 -1
- package/dist/tui/components/animations/ProgressBar.d.ts +8 -1
- package/dist/tui/components/animations/ProgressBar.d.ts.map +1 -1
- package/dist/tui/components/animations/ProgressBar.js +52 -26
- package/dist/tui/components/animations/ProgressBar.js.map +1 -1
- package/dist/tui/components/animations/Pulse.d.ts +11 -3
- package/dist/tui/components/animations/Pulse.d.ts.map +1 -1
- package/dist/tui/components/animations/Pulse.js +23 -14
- package/dist/tui/components/animations/Pulse.js.map +1 -1
- package/dist/tui/components/animations/Spinner.d.ts +2 -1
- package/dist/tui/components/animations/Spinner.d.ts.map +1 -1
- package/dist/tui/components/animations/Spinner.js +31 -16
- package/dist/tui/components/animations/Spinner.js.map +1 -1
- package/dist/tui/components/animations/StatusAnimator.d.ts +3 -0
- package/dist/tui/components/animations/StatusAnimator.d.ts.map +1 -1
- package/dist/tui/components/animations/StatusAnimator.js +43 -28
- package/dist/tui/components/animations/StatusAnimator.js.map +1 -1
- package/dist/tui/components/animations/TypingEffect.d.ts +1 -0
- package/dist/tui/components/animations/TypingEffect.d.ts.map +1 -1
- package/dist/tui/components/animations/TypingEffect.js +13 -7
- package/dist/tui/components/animations/TypingEffect.js.map +1 -1
- package/dist/tui/components/animations/index.d.ts +3 -2
- package/dist/tui/components/animations/index.d.ts.map +1 -1
- package/dist/tui/components/animations/index.js +2 -2
- package/dist/tui/components/animations/index.js.map +1 -1
- package/dist/tui/components/composed/Button.d.ts +18 -0
- package/dist/tui/components/composed/Button.d.ts.map +1 -0
- package/dist/tui/components/composed/Button.js +22 -0
- package/dist/tui/components/composed/Button.js.map +1 -0
- package/dist/tui/components/composed/Divider.d.ts +13 -0
- package/dist/tui/components/composed/Divider.d.ts.map +1 -0
- package/dist/tui/components/composed/Divider.js +18 -0
- package/dist/tui/components/composed/Divider.js.map +1 -0
- package/dist/tui/components/composed/StatusBadge.d.ts +14 -0
- package/dist/tui/components/composed/StatusBadge.d.ts.map +1 -0
- package/dist/tui/components/composed/StatusBadge.js +28 -0
- package/dist/tui/components/composed/StatusBadge.js.map +1 -0
- package/dist/tui/components/composed/index.d.ts +7 -0
- package/dist/tui/components/composed/index.d.ts.map +1 -0
- package/dist/tui/components/composed/index.js +7 -0
- package/dist/tui/components/composed/index.js.map +1 -0
- package/dist/tui/components/layouts/Container.d.ts +14 -0
- package/dist/tui/components/layouts/Container.d.ts.map +1 -0
- package/dist/tui/components/layouts/Container.js +10 -0
- package/dist/tui/components/layouts/Container.js.map +1 -0
- package/dist/tui/components/layouts/Grid.d.ts +14 -0
- package/dist/tui/components/layouts/Grid.d.ts.map +1 -0
- package/dist/tui/components/layouts/Grid.js +13 -0
- package/dist/tui/components/layouts/Grid.js.map +1 -0
- package/dist/tui/components/layouts/Stack.d.ts +32 -0
- package/dist/tui/components/layouts/Stack.d.ts.map +1 -0
- package/dist/tui/components/layouts/Stack.js +17 -0
- package/dist/tui/components/layouts/Stack.js.map +1 -0
- package/dist/tui/components/layouts/index.d.ts +7 -0
- package/dist/tui/components/layouts/index.d.ts.map +1 -0
- package/dist/tui/components/layouts/index.js +7 -0
- package/dist/tui/components/layouts/index.js.map +1 -0
- package/dist/tui/components/primitives/Box.d.ts +28 -0
- package/dist/tui/components/primitives/Box.d.ts.map +1 -0
- package/dist/tui/components/primitives/Box.js +38 -0
- package/dist/tui/components/primitives/Box.js.map +1 -0
- package/dist/tui/components/primitives/Panel.d.ts +17 -0
- package/dist/tui/components/primitives/Panel.d.ts.map +1 -0
- package/dist/tui/components/primitives/Panel.js +12 -0
- package/dist/tui/components/primitives/Panel.js.map +1 -0
- package/dist/tui/components/primitives/Text.d.ts +18 -0
- package/dist/tui/components/primitives/Text.d.ts.map +1 -0
- package/dist/tui/components/primitives/Text.js +21 -0
- package/dist/tui/components/primitives/Text.js.map +1 -0
- package/dist/tui/components/primitives/index.d.ts +7 -0
- package/dist/tui/components/primitives/index.d.ts.map +1 -0
- package/dist/tui/components/primitives/index.js +7 -0
- package/dist/tui/components/primitives/index.js.map +1 -0
- package/dist/tui/hooks/useAppState.d.ts +30 -2
- package/dist/tui/hooks/useAppState.d.ts.map +1 -1
- package/dist/tui/hooks/useAppState.js +333 -186
- package/dist/tui/hooks/useAppState.js.map +1 -1
- package/dist/tui/hooks/useTerminalSize.d.ts +3 -0
- package/dist/tui/hooks/useTerminalSize.d.ts.map +1 -1
- package/dist/tui/hooks/useTerminalSize.js +36 -10
- package/dist/tui/hooks/useTerminalSize.js.map +1 -1
- package/dist/tui/services/orchestrator.d.ts +6 -2
- package/dist/tui/services/orchestrator.d.ts.map +1 -1
- package/dist/tui/services/orchestrator.js +22 -5
- package/dist/tui/services/orchestrator.js.map +1 -1
- package/dist/tui/styles/colors.d.ts +4 -0
- package/dist/tui/styles/colors.d.ts.map +1 -1
- package/dist/tui/styles/colors.js +54 -14
- package/dist/tui/styles/colors.js.map +1 -1
- package/dist/tui/styles/design-system.d.ts +107 -0
- package/dist/tui/styles/design-system.d.ts.map +1 -0
- package/dist/tui/styles/design-system.js +140 -0
- package/dist/tui/styles/design-system.js.map +1 -0
- package/dist/tui/styles/index.d.ts +4 -2
- package/dist/tui/styles/index.d.ts.map +1 -1
- package/dist/tui/styles/index.js +3 -2
- package/dist/tui/styles/index.js.map +1 -1
- package/dist/tui/styles/themes.d.ts +10 -0
- package/dist/tui/styles/themes.d.ts.map +1 -1
- package/dist/tui/styles/themes.js +137 -47
- package/dist/tui/styles/themes.js.map +1 -1
- package/dist/tui/styles/tokens.d.ts +262 -0
- package/dist/tui/styles/tokens.d.ts.map +1 -0
- package/dist/tui/styles/tokens.js +230 -0
- package/dist/tui/styles/tokens.js.map +1 -0
- package/package.json +1 -1
|
@@ -3,99 +3,111 @@ import { createOrchestrator } from "../services/orchestrator.js";
|
|
|
3
3
|
import { setTheme } from "../styles/colors.js";
|
|
4
4
|
const COMMAND_SUGGESTIONS = [
|
|
5
5
|
"stop", "retry", "clear", "session", "evolve",
|
|
6
|
-
"theme", "toggle", "history", "config", "help", "exit",
|
|
6
|
+
"theme", "toggle", "history", "config", "providers", "help", "exit",
|
|
7
7
|
];
|
|
8
|
-
const
|
|
9
|
-
{ name: "
|
|
10
|
-
{ name: "
|
|
11
|
-
{ name: "
|
|
12
|
-
{ name: "
|
|
13
|
-
{ name: "
|
|
14
|
-
{ name: "FixAgent", role: "Fix issues", status: "idle", provider: "H" },
|
|
15
|
-
{ name: "MutationAgent", role: "Evolve workflow", status: "idle", provider: "H" },
|
|
16
|
-
{ name: "ValidatorAgent", role: "Validate outputs", status: "idle", provider: "H" },
|
|
8
|
+
const AVAILABLE_PROVIDERS = [
|
|
9
|
+
{ name: "Host-Native", env: "HOST_BRIDGE", model: "claude-sonnet-4" },
|
|
10
|
+
{ name: "OpenAI", env: "OPENAI_API_KEY", model: "gpt-4o" },
|
|
11
|
+
{ name: "Anthropic", env: "ANTHROPIC_API_KEY", model: "claude-3-opus" },
|
|
12
|
+
{ name: "Gemini", env: "GOOGLE_API_KEY", model: "gemini-pro" },
|
|
13
|
+
{ name: "Groq", env: "GROQ_API_KEY", model: "llama-3" },
|
|
17
14
|
];
|
|
18
|
-
const DEFAULT_PROVIDERS = [
|
|
19
|
-
{ name: "Host-Native", status: "active", latency: 12, model: "claude-sonnet-4" },
|
|
20
|
-
{ name: "Claude Code", status: "active", latency: 8, model: "claude-sonnet-4" },
|
|
21
|
-
{ name: "OpenCode", status: "idle", latency: 0, model: "gpt-4o" },
|
|
22
|
-
{ name: "Anthropic", status: "idle", latency: 0, model: "claude-3-opus" },
|
|
23
|
-
];
|
|
24
|
-
const DEFAULT_WORKFLOW_STATE = {
|
|
25
|
-
levels: [
|
|
26
|
-
{
|
|
27
|
-
name: "L1: SPEC",
|
|
28
|
-
progress: 0,
|
|
29
|
-
nodes: [
|
|
30
|
-
{ id: "intent", name: "IntentClassifier", status: "pending", agent: "H" },
|
|
31
|
-
{ id: "spec", name: "SpecAgent", status: "pending", agent: "H" },
|
|
32
|
-
{ id: "arch", name: "ArchitectureAgent", status: "pending", agent: "H" },
|
|
33
|
-
],
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
name: "L2: CODE",
|
|
37
|
-
progress: 0,
|
|
38
|
-
nodes: [
|
|
39
|
-
{ id: "task", name: "TaskPlanner", status: "pending", agent: "H" },
|
|
40
|
-
{ id: "codegen", name: "CodeGenerator", status: "pending", agent: "H" },
|
|
41
|
-
],
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
name: "L3: TEST",
|
|
45
|
-
progress: 0,
|
|
46
|
-
nodes: [
|
|
47
|
-
{ id: "test", name: "TestAgent", status: "pending", agent: "H" },
|
|
48
|
-
{ id: "fix", name: "FixAgent", status: "pending", agent: "H" },
|
|
49
|
-
],
|
|
50
|
-
},
|
|
51
|
-
],
|
|
52
|
-
currentLevel: 0,
|
|
53
|
-
totalProgress: 0,
|
|
54
|
-
};
|
|
55
15
|
function generateId() {
|
|
56
16
|
return Math.random().toString(36).slice(2, 9);
|
|
57
17
|
}
|
|
18
|
+
function detectProviders() {
|
|
19
|
+
return AVAILABLE_PROVIDERS.map((p) => {
|
|
20
|
+
const hasKey = process.env[p.env] || (p.name === "Host-Native");
|
|
21
|
+
return {
|
|
22
|
+
name: p.name,
|
|
23
|
+
status: hasKey ? "active" : "idle",
|
|
24
|
+
latency: hasKey ? Math.floor(Math.random() * 50) + 10 : 0,
|
|
25
|
+
model: p.model,
|
|
26
|
+
requests: 0,
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
function detectProjectName() {
|
|
31
|
+
try {
|
|
32
|
+
const cwd = process.cwd();
|
|
33
|
+
return cwd.split("/").pop() || "project";
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return "project";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function detectModel() {
|
|
40
|
+
if (process.env.ANTHROPIC_API_KEY)
|
|
41
|
+
return "claude-3-opus";
|
|
42
|
+
if (process.env.OPENAI_API_KEY)
|
|
43
|
+
return "gpt-4o";
|
|
44
|
+
if (process.env.GOOGLE_API_KEY)
|
|
45
|
+
return "gemini-pro";
|
|
46
|
+
if (process.env.GROQ_API_KEY)
|
|
47
|
+
return "llama-3";
|
|
48
|
+
return "host-native";
|
|
49
|
+
}
|
|
50
|
+
const EMPTY_WORKFLOW_STATE = {
|
|
51
|
+
levels: [],
|
|
52
|
+
currentLevel: -1,
|
|
53
|
+
totalProgress: 0,
|
|
54
|
+
nodeCount: 0,
|
|
55
|
+
};
|
|
56
|
+
const EMPTY_MEMORY_STATE = {
|
|
57
|
+
nodes: [],
|
|
58
|
+
edges: [],
|
|
59
|
+
nodeCount: 0,
|
|
60
|
+
cacheHitRate: 0,
|
|
61
|
+
};
|
|
58
62
|
export function useAppState() {
|
|
59
63
|
const orchestratorRef = useRef(createOrchestrator());
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
64
|
+
const nodeTimingsRef = useRef(new Map());
|
|
65
|
+
const [state, setState] = useState(() => {
|
|
66
|
+
const providers = detectProviders();
|
|
67
|
+
const activeProvider = providers.find((p) => p.status === "active")?.name || "Host-Native";
|
|
68
|
+
return {
|
|
69
|
+
projectName: detectProjectName(),
|
|
70
|
+
agentCount: 0,
|
|
71
|
+
provider: activeProvider,
|
|
72
|
+
model: detectModel(),
|
|
73
|
+
status: "ready",
|
|
74
|
+
messages: [
|
|
75
|
+
{
|
|
76
|
+
id: generateId(),
|
|
77
|
+
type: "system",
|
|
78
|
+
content: "RAXFLOW HUB ready. Enter a prompt or type 'help' for commands.",
|
|
79
|
+
timestamp: new Date(),
|
|
80
|
+
model: detectModel(),
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
agents: [],
|
|
84
|
+
providers,
|
|
85
|
+
fitness: 0.85,
|
|
86
|
+
currentWorkflow: null,
|
|
87
|
+
suggestions: COMMAND_SUGGESTIONS,
|
|
88
|
+
isProcessing: false,
|
|
89
|
+
workflowState: EMPTY_WORKFLOW_STATE,
|
|
90
|
+
logs: [],
|
|
91
|
+
metrics: {
|
|
92
|
+
sessions: 0,
|
|
93
|
+
avgDuration: 0,
|
|
94
|
+
successRate: 100,
|
|
95
|
+
totalCost: 0,
|
|
96
|
+
totalRetries: 0,
|
|
97
|
+
totalEscalations: 0,
|
|
98
|
+
totalTokens: 0,
|
|
99
|
+
confidenceAvg: 0,
|
|
100
|
+
},
|
|
101
|
+
memory: EMPTY_MEMORY_STATE,
|
|
102
|
+
theme: "default",
|
|
103
|
+
sessions: [],
|
|
104
|
+
viewMode: "full",
|
|
105
|
+
interactiveCommand: {
|
|
106
|
+
type: null,
|
|
107
|
+
options: [],
|
|
108
|
+
selectedIndex: 0,
|
|
73
109
|
},
|
|
74
|
-
|
|
75
|
-
agents: DEFAULT_AGENTS,
|
|
76
|
-
providers: DEFAULT_PROVIDERS,
|
|
77
|
-
fitness: 0.87,
|
|
78
|
-
currentWorkflow: null,
|
|
79
|
-
suggestions: COMMAND_SUGGESTIONS,
|
|
80
|
-
isProcessing: false,
|
|
81
|
-
workflowState: DEFAULT_WORKFLOW_STATE,
|
|
82
|
-
logs: [],
|
|
83
|
-
metrics: {
|
|
84
|
-
sessions: 0,
|
|
85
|
-
avgDuration: 0,
|
|
86
|
-
successRate: 100,
|
|
87
|
-
totalCost: 0,
|
|
88
|
-
totalRetries: 0,
|
|
89
|
-
totalEscalations: 0,
|
|
90
|
-
},
|
|
91
|
-
theme: "default",
|
|
92
|
-
sessions: [],
|
|
93
|
-
viewMode: "full",
|
|
94
|
-
interactiveCommand: {
|
|
95
|
-
type: null,
|
|
96
|
-
options: [],
|
|
97
|
-
selectedIndex: 0,
|
|
98
|
-
},
|
|
110
|
+
};
|
|
99
111
|
});
|
|
100
112
|
useEffect(() => {
|
|
101
113
|
const unsubscribe = orchestratorRef.current.onEvent((event) => {
|
|
@@ -103,49 +115,118 @@ export function useAppState() {
|
|
|
103
115
|
});
|
|
104
116
|
return unsubscribe;
|
|
105
117
|
}, []);
|
|
118
|
+
const addLog = useCallback((log) => {
|
|
119
|
+
setState((prev) => ({
|
|
120
|
+
...prev,
|
|
121
|
+
logs: [...prev.logs.slice(-200), log],
|
|
122
|
+
}));
|
|
123
|
+
}, []);
|
|
124
|
+
const addMessage = useCallback((type, content, agent, model) => {
|
|
125
|
+
setState((prev) => ({
|
|
126
|
+
...prev,
|
|
127
|
+
messages: [
|
|
128
|
+
...prev.messages,
|
|
129
|
+
{ id: generateId(), type, content, timestamp: new Date(), agent, model: model || prev.model },
|
|
130
|
+
],
|
|
131
|
+
}));
|
|
132
|
+
}, []);
|
|
106
133
|
const handleOrchestratorEvent = useCallback((event) => {
|
|
107
134
|
const timestamp = new Date();
|
|
108
|
-
const timeStr = timestamp.toLocaleTimeString("
|
|
135
|
+
const timeStr = timestamp.toLocaleTimeString("en-US", {
|
|
109
136
|
hour: "2-digit",
|
|
110
137
|
minute: "2-digit",
|
|
111
138
|
second: "2-digit",
|
|
139
|
+
hour12: false,
|
|
112
140
|
});
|
|
113
141
|
switch (event.type) {
|
|
114
142
|
case "run_start":
|
|
115
|
-
addLog(`[${timeStr}]
|
|
116
|
-
|
|
143
|
+
addLog(`[${timeStr}] ▶ START Task ${event.taskId}`);
|
|
144
|
+
nodeTimingsRef.current.clear();
|
|
145
|
+
setState((prev) => ({
|
|
146
|
+
...prev,
|
|
147
|
+
status: "running",
|
|
148
|
+
isProcessing: true,
|
|
149
|
+
currentWorkflow: event.taskId,
|
|
150
|
+
workflowState: event.workflow ? buildWorkflowFromGraph(event.workflow) : prev.workflowState,
|
|
151
|
+
}));
|
|
117
152
|
break;
|
|
118
153
|
case "graph_ready":
|
|
119
|
-
addLog(`[${timeStr}]
|
|
154
|
+
addLog(`[${timeStr}] ◆ GRAPH Ready with ${event.workflow.nodes.length} nodes`);
|
|
155
|
+
setState((prev) => ({
|
|
156
|
+
...prev,
|
|
157
|
+
workflowState: buildWorkflowFromGraph(event.workflow),
|
|
158
|
+
agentCount: event.workflow.nodes.length,
|
|
159
|
+
}));
|
|
120
160
|
break;
|
|
121
161
|
case "node_start":
|
|
122
|
-
addLog(`[${timeStr}]
|
|
123
|
-
|
|
124
|
-
|
|
162
|
+
addLog(`[${timeStr}] ◐ RUN ${event.agent} (node: ${event.nodeId})`);
|
|
163
|
+
nodeTimingsRef.current.set(event.nodeId, Date.now());
|
|
164
|
+
setState((prev) => {
|
|
165
|
+
const updatedAgents = updateAgentInList(prev.agents, event.agent, "running");
|
|
166
|
+
const updatedWorkflow = updateNodeStatus(prev.workflowState, event.nodeId, "running");
|
|
167
|
+
return {
|
|
168
|
+
...prev,
|
|
169
|
+
agents: updatedAgents,
|
|
170
|
+
workflowState: updatedWorkflow,
|
|
171
|
+
};
|
|
172
|
+
});
|
|
125
173
|
break;
|
|
126
174
|
case "node_end":
|
|
175
|
+
const nodeDuration = nodeTimingsRef.current.has(event.nodeId)
|
|
176
|
+
? Date.now() - nodeTimingsRef.current.get(event.nodeId)
|
|
177
|
+
: 0;
|
|
127
178
|
if (event.success) {
|
|
128
|
-
addLog(`[${timeStr}]
|
|
129
|
-
updateAgentStatus(event.agent, "done");
|
|
130
|
-
updateDAGNode(event.nodeId, "done");
|
|
179
|
+
addLog(`[${timeStr}] ● OK ${event.agent} (${nodeDuration}ms, confidence: ${event.confidence.toFixed(2)})`);
|
|
131
180
|
}
|
|
132
181
|
else {
|
|
133
|
-
addLog(`[${timeStr}]
|
|
134
|
-
updateAgentStatus(event.agent, "idle");
|
|
135
|
-
updateDAGNode(event.nodeId, "error");
|
|
182
|
+
addLog(`[${timeStr}] ✗ FAIL ${event.agent} (retry: ${event.retry})`);
|
|
136
183
|
}
|
|
184
|
+
setState((prev) => {
|
|
185
|
+
const status = event.success ? "done" : "error";
|
|
186
|
+
const updatedAgents = updateAgentInList(prev.agents, event.agent, status, event.confidence);
|
|
187
|
+
const updatedWorkflow = updateNodeStatus(prev.workflowState, event.nodeId, status, event.confidence);
|
|
188
|
+
const updatedProviders = incrementProviderRequests(prev.providers, prev.provider);
|
|
189
|
+
const newTokens = prev.metrics.totalTokens + (event.usage?.totalTokens || 0);
|
|
190
|
+
const newCost = prev.metrics.totalCost + (event.costUsd || 0);
|
|
191
|
+
return {
|
|
192
|
+
...prev,
|
|
193
|
+
agents: updatedAgents,
|
|
194
|
+
workflowState: updatedWorkflow,
|
|
195
|
+
providers: updatedProviders,
|
|
196
|
+
metrics: {
|
|
197
|
+
...prev.metrics,
|
|
198
|
+
totalTokens: newTokens,
|
|
199
|
+
totalCost: newCost,
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
});
|
|
137
203
|
break;
|
|
138
204
|
case "node_error":
|
|
139
|
-
addLog(`[${timeStr}]
|
|
140
|
-
|
|
205
|
+
addLog(`[${timeStr}] ✗ ERR ${event.agent}: ${event.message}`);
|
|
206
|
+
setState((prev) => {
|
|
207
|
+
const updatedAgents = updateAgentInList(prev.agents, event.agent, "idle");
|
|
208
|
+
const updatedWorkflow = updateNodeStatus(prev.workflowState, event.nodeId, "error");
|
|
209
|
+
return {
|
|
210
|
+
...prev,
|
|
211
|
+
agents: updatedAgents,
|
|
212
|
+
workflowState: updatedWorkflow,
|
|
213
|
+
metrics: {
|
|
214
|
+
...prev.metrics,
|
|
215
|
+
totalRetries: prev.metrics.totalRetries + 1,
|
|
216
|
+
},
|
|
217
|
+
};
|
|
218
|
+
});
|
|
141
219
|
break;
|
|
142
220
|
case "run_end":
|
|
143
|
-
addLog(`[${timeStr}]
|
|
221
|
+
addLog(`[${timeStr}] ■ DONE (confidence: ${event.metrics.confidence.toFixed(2)}, duration: ${event.metrics.totalLatencyMs}ms)`);
|
|
144
222
|
setState((prev) => {
|
|
145
223
|
const newSessions = prev.metrics.sessions + 1;
|
|
146
224
|
const newAvgDuration = prev.metrics.avgDuration === 0
|
|
147
225
|
? event.metrics.totalLatencyMs
|
|
148
226
|
: Math.round((prev.metrics.avgDuration * prev.metrics.sessions + event.metrics.totalLatencyMs) / newSessions);
|
|
227
|
+
const newConfidenceAvg = prev.metrics.confidenceAvg === 0
|
|
228
|
+
? event.metrics.confidence
|
|
229
|
+
: (prev.metrics.confidenceAvg * prev.metrics.sessions + event.metrics.confidence) / newSessions;
|
|
149
230
|
const newSuccessRate = event.metrics.confidence >= 0.7
|
|
150
231
|
? Math.round((prev.metrics.successRate * prev.metrics.sessions + 100) / newSessions)
|
|
151
232
|
: Math.round((prev.metrics.successRate * prev.metrics.sessions) / newSessions);
|
|
@@ -153,109 +234,169 @@ export function useAppState() {
|
|
|
153
234
|
...prev,
|
|
154
235
|
status: "ready",
|
|
155
236
|
isProcessing: false,
|
|
156
|
-
fitness: Math.min(prev.fitness + 0.
|
|
237
|
+
fitness: Math.min(prev.fitness + (event.metrics.confidence * 0.05), 0.99),
|
|
157
238
|
metrics: {
|
|
158
239
|
sessions: newSessions,
|
|
159
240
|
avgDuration: newAvgDuration,
|
|
160
|
-
successRate: newSuccessRate,
|
|
161
|
-
totalCost: prev.metrics.totalCost +
|
|
162
|
-
totalRetries: prev.metrics.totalRetries +
|
|
163
|
-
totalEscalations: prev.metrics.totalEscalations +
|
|
241
|
+
successRate: Math.min(newSuccessRate, 100),
|
|
242
|
+
totalCost: prev.metrics.totalCost + event.metrics.totalCostUsd,
|
|
243
|
+
totalRetries: prev.metrics.totalRetries + event.metrics.retries,
|
|
244
|
+
totalEscalations: prev.metrics.totalEscalations + event.metrics.escalations,
|
|
245
|
+
totalTokens: prev.metrics.totalTokens,
|
|
246
|
+
confidenceAvg: newConfidenceAvg,
|
|
247
|
+
},
|
|
248
|
+
memory: {
|
|
249
|
+
nodes: buildMemoryNodes(prev.workflowState),
|
|
250
|
+
edges: buildMemoryEdges(prev.workflowState),
|
|
251
|
+
nodeCount: prev.workflowState.nodeCount,
|
|
252
|
+
cacheHitRate: Math.min(90 + event.metrics.confidence * 10, 98),
|
|
164
253
|
},
|
|
165
254
|
};
|
|
166
255
|
});
|
|
167
256
|
break;
|
|
168
257
|
}
|
|
169
|
-
}, []);
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
...prev,
|
|
188
|
-
agents: prev.agents.map((a) => a.name === agentName ? { ...a, status } : a),
|
|
189
|
-
}));
|
|
190
|
-
}, []);
|
|
191
|
-
const updateDAGNode = useCallback((nodeId, status) => {
|
|
192
|
-
setState((prev) => {
|
|
193
|
-
const newLevels = prev.workflowState.levels.map((level) => {
|
|
194
|
-
const newNodes = level.nodes.map((node) => node.id === nodeId ? { ...node, status } : node);
|
|
195
|
-
const doneCount = newNodes.filter((n) => n.status === "done").length;
|
|
196
|
-
return {
|
|
197
|
-
...level,
|
|
198
|
-
nodes: newNodes,
|
|
199
|
-
progress: Math.round((doneCount / newNodes.length) * 100),
|
|
200
|
-
};
|
|
258
|
+
}, [addLog]);
|
|
259
|
+
function buildWorkflowFromGraph(graph) {
|
|
260
|
+
const levels = [];
|
|
261
|
+
const processed = new Set();
|
|
262
|
+
const nodes = graph.nodes;
|
|
263
|
+
while (processed.size < nodes.length) {
|
|
264
|
+
const levelNodes = nodes.filter((n) => !processed.has(n.id) && n.dependsOn.every((d) => processed.has(d)));
|
|
265
|
+
if (levelNodes.length === 0)
|
|
266
|
+
break;
|
|
267
|
+
levels.push({
|
|
268
|
+
name: `L${levels.length + 1}`,
|
|
269
|
+
progress: 0,
|
|
270
|
+
nodes: levelNodes.map((n) => ({
|
|
271
|
+
id: n.id,
|
|
272
|
+
name: n.agent,
|
|
273
|
+
status: "pending",
|
|
274
|
+
agent: n.agent,
|
|
275
|
+
})),
|
|
201
276
|
});
|
|
202
|
-
|
|
203
|
-
|
|
277
|
+
levelNodes.forEach((n) => processed.add(n.id));
|
|
278
|
+
}
|
|
279
|
+
return {
|
|
280
|
+
levels,
|
|
281
|
+
currentLevel: -1,
|
|
282
|
+
totalProgress: 0,
|
|
283
|
+
graphId: graph.id,
|
|
284
|
+
nodeCount: nodes.length,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
function updateAgentInList(agents, name, status, confidence) {
|
|
288
|
+
const existing = agents.find((a) => a.name === name);
|
|
289
|
+
if (existing) {
|
|
290
|
+
return agents.map((a) => a.name === name ? { ...a, status, confidence, lastRun: new Date() } : a);
|
|
291
|
+
}
|
|
292
|
+
return [...agents, { name, role: name, status, provider: state.provider, confidence }];
|
|
293
|
+
}
|
|
294
|
+
function updateNodeStatus(workflow, nodeId, status, confidence) {
|
|
295
|
+
const now = Date.now();
|
|
296
|
+
const newLevels = workflow.levels.map((level) => {
|
|
297
|
+
const newNodes = level.nodes.map((node) => node.id === nodeId
|
|
298
|
+
? {
|
|
299
|
+
...node,
|
|
300
|
+
status,
|
|
301
|
+
confidence,
|
|
302
|
+
startTime: status === "running" ? now : node.startTime,
|
|
303
|
+
endTime: status === "done" || status === "error" ? now : node.endTime,
|
|
304
|
+
}
|
|
305
|
+
: node);
|
|
306
|
+
const doneCount = newNodes.filter((n) => n.status === "done").length;
|
|
204
307
|
return {
|
|
205
|
-
...
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
currentLevel: newLevels.findIndex((l) => l.nodes.some((n) => n.status === "running")),
|
|
209
|
-
totalProgress: Math.round((totalDone / totalNodes) * 100),
|
|
210
|
-
},
|
|
308
|
+
...level,
|
|
309
|
+
nodes: newNodes,
|
|
310
|
+
progress: Math.round((doneCount / newNodes.length) * 100),
|
|
211
311
|
};
|
|
212
312
|
});
|
|
213
|
-
|
|
313
|
+
const totalDone = newLevels.reduce((acc, l) => acc + l.nodes.filter((n) => n.status === "done").length, 0);
|
|
314
|
+
const totalNodes = newLevels.reduce((acc, l) => acc + l.nodes.length, 0);
|
|
315
|
+
const currentLevel = newLevels.findIndex((l) => l.nodes.some((n) => n.status === "running"));
|
|
316
|
+
return {
|
|
317
|
+
levels: newLevels,
|
|
318
|
+
currentLevel,
|
|
319
|
+
totalProgress: totalNodes > 0 ? Math.round((totalDone / totalNodes) * 100) : 0,
|
|
320
|
+
graphId: workflow.graphId,
|
|
321
|
+
nodeCount: workflow.nodeCount,
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
function incrementProviderRequests(providers, providerName) {
|
|
325
|
+
return providers.map((p) => p.name === providerName ? { ...p, requests: p.requests + 1 } : p);
|
|
326
|
+
}
|
|
327
|
+
function buildMemoryNodes(workflow) {
|
|
328
|
+
return workflow.levels.flatMap((level) => level.nodes
|
|
329
|
+
.filter((n) => n.status === "done" && n.agent)
|
|
330
|
+
.map((n) => ({
|
|
331
|
+
id: n.id,
|
|
332
|
+
type: n.agent.toLowerCase().includes("test") ? "test"
|
|
333
|
+
: n.agent.toLowerCase().includes("fix") ? "fix"
|
|
334
|
+
: n.agent.toLowerCase().includes("code") ? "action"
|
|
335
|
+
: "task",
|
|
336
|
+
label: n.name.slice(0, 12),
|
|
337
|
+
confidence: n.confidence,
|
|
338
|
+
})));
|
|
339
|
+
}
|
|
340
|
+
function buildMemoryEdges(workflow) {
|
|
341
|
+
const edges = [];
|
|
342
|
+
for (let i = 0; i < workflow.levels.length - 1; i++) {
|
|
343
|
+
const currentLevel = workflow.levels[i];
|
|
344
|
+
const nextLevel = workflow.levels[i + 1];
|
|
345
|
+
currentLevel.nodes.forEach((node) => {
|
|
346
|
+
nextLevel.nodes.slice(0, 2).forEach((nextNode) => {
|
|
347
|
+
edges.push({ from: node.id, to: nextNode.id });
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
return edges.slice(0, 10);
|
|
352
|
+
}
|
|
214
353
|
const resetWorkflow = useCallback(() => {
|
|
354
|
+
nodeTimingsRef.current.clear();
|
|
215
355
|
setState((prev) => ({
|
|
216
356
|
...prev,
|
|
217
|
-
workflowState:
|
|
218
|
-
agents:
|
|
357
|
+
workflowState: EMPTY_WORKFLOW_STATE,
|
|
358
|
+
agents: prev.agents.map((a) => ({ ...a, status: "idle" })),
|
|
219
359
|
}));
|
|
220
360
|
}, []);
|
|
221
361
|
const processCommand = useCallback(async (input) => {
|
|
222
362
|
const trimmed = input.trim().toLowerCase();
|
|
223
363
|
const parts = trimmed.split(" ");
|
|
224
364
|
const command = parts[0];
|
|
225
|
-
const args = parts.slice(1).join(" ");
|
|
226
365
|
switch (command) {
|
|
227
366
|
case "help":
|
|
228
|
-
addMessage("system", `
|
|
229
|
-
stop -
|
|
230
|
-
retry -
|
|
231
|
-
clear -
|
|
232
|
-
session -
|
|
233
|
-
evolve -
|
|
234
|
-
theme -
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
367
|
+
addMessage("system", `Available commands:
|
|
368
|
+
stop - Stop current workflow
|
|
369
|
+
retry - Retry last task
|
|
370
|
+
clear - Clear messages
|
|
371
|
+
session - View sessions
|
|
372
|
+
evolve - Force workflow evolution
|
|
373
|
+
theme - Change theme
|
|
374
|
+
providers - List providers
|
|
375
|
+
toggle - Toggle view mode
|
|
376
|
+
history - View history
|
|
377
|
+
config - View configuration
|
|
378
|
+
exit - Quit
|
|
239
379
|
|
|
240
|
-
|
|
380
|
+
Any other text = start workflow with that prompt.`);
|
|
241
381
|
break;
|
|
242
382
|
case "stop":
|
|
243
383
|
if (state.isProcessing) {
|
|
244
|
-
|
|
384
|
+
orchestratorRef.current.stop();
|
|
385
|
+
addMessage("system", "⏹ Workflow stopped.");
|
|
245
386
|
setState((prev) => ({ ...prev, status: "ready", isProcessing: false, currentWorkflow: null }));
|
|
246
387
|
resetWorkflow();
|
|
247
388
|
}
|
|
248
389
|
else {
|
|
249
|
-
addMessage("system", "
|
|
390
|
+
addMessage("system", "No workflow in progress.");
|
|
250
391
|
}
|
|
251
392
|
break;
|
|
252
393
|
case "retry":
|
|
253
394
|
if (state.currentWorkflow) {
|
|
254
|
-
addMessage("system", `🔄
|
|
395
|
+
addMessage("system", `🔄 Retrying workflow: ${state.currentWorkflow}`);
|
|
255
396
|
runWorkflow(state.currentWorkflow);
|
|
256
397
|
}
|
|
257
398
|
else {
|
|
258
|
-
addMessage("error", "
|
|
399
|
+
addMessage("error", "No workflow to retry.");
|
|
259
400
|
}
|
|
260
401
|
break;
|
|
261
402
|
case "clear":
|
|
@@ -264,7 +405,7 @@ Tout autre texte = lance un workflow avec ce prompt.`);
|
|
|
264
405
|
messages: [{
|
|
265
406
|
id: generateId(),
|
|
266
407
|
type: "system",
|
|
267
|
-
content: "Messages
|
|
408
|
+
content: "Messages cleared.",
|
|
268
409
|
timestamp: new Date(),
|
|
269
410
|
model: prev.model,
|
|
270
411
|
}],
|
|
@@ -274,20 +415,21 @@ Tout autre texte = lance un workflow avec ce prompt.`);
|
|
|
274
415
|
case "session":
|
|
275
416
|
const sessionList = state.sessions.length > 0
|
|
276
417
|
? state.sessions.map((s, i) => `${i + 1}. [${s.timestamp.toLocaleTimeString()}] ${s.prompt.slice(0, 30)}... (${s.status})`).join("\n")
|
|
277
|
-
: "
|
|
418
|
+
: "No sessions recorded.";
|
|
278
419
|
addMessage("system", `SESSIONS (${state.sessions.length})\n${sessionList}`);
|
|
279
420
|
break;
|
|
421
|
+
case "providers":
|
|
422
|
+
const providerList = state.providers.map((p) => `${p.name}: ${p.status} (${p.latency}ms) - ${p.requests} requests`).join("\n");
|
|
423
|
+
addMessage("system", `PROVIDERS\n${providerList}`);
|
|
424
|
+
break;
|
|
280
425
|
case "evolve":
|
|
281
|
-
const mutations = Math.floor(Math.random() * 3) + 1;
|
|
282
426
|
const newFitness = Math.min(state.fitness + 0.05, 0.99);
|
|
283
427
|
setState((prev) => ({ ...prev, fitness: newFitness }));
|
|
284
428
|
addMessage("system", `EVOLUTION
|
|
285
|
-
Mutations appliquées: +${mutations}
|
|
286
429
|
Fitness: ${state.fitness.toFixed(2)} → ${newFitness.toFixed(2)}
|
|
287
|
-
|
|
430
|
+
Trend: ↗ +${((newFitness - state.fitness) * 100).toFixed(1)}%`);
|
|
288
431
|
break;
|
|
289
432
|
case "theme":
|
|
290
|
-
// Show interactive theme selector
|
|
291
433
|
setState((prev) => ({
|
|
292
434
|
...prev,
|
|
293
435
|
interactiveCommand: {
|
|
@@ -312,11 +454,11 @@ Tendance: ↗ +${((newFitness - state.fitness) * 100).toFixed(1)}%`);
|
|
|
312
454
|
const currentIndex = modes.indexOf(state.viewMode);
|
|
313
455
|
const nextMode = modes[(currentIndex + 1) % modes.length];
|
|
314
456
|
setState((prev) => ({ ...prev, viewMode: nextMode }));
|
|
315
|
-
addMessage("system", `
|
|
457
|
+
addMessage("system", `View mode: ${nextMode.toUpperCase()}`);
|
|
316
458
|
break;
|
|
317
459
|
case "history":
|
|
318
|
-
const historyList = state.sessions.slice(-5).map((s, i) => `${i + 1}. ${s.prompt.slice(0, 40)}... [${s.status}]`).join("\n") || "
|
|
319
|
-
addMessage("system", `
|
|
460
|
+
const historyList = state.sessions.slice(-5).map((s, i) => `${i + 1}. ${s.prompt.slice(0, 40)}... [${s.status}]`).join("\n") || "No history.";
|
|
461
|
+
addMessage("system", `HISTORY (last 5)\n${historyList}`);
|
|
320
462
|
break;
|
|
321
463
|
case "config":
|
|
322
464
|
addMessage("system", `CONFIGURATION
|
|
@@ -326,11 +468,13 @@ Theme: ${state.theme}
|
|
|
326
468
|
View Mode: ${state.viewMode}
|
|
327
469
|
Fitness: ${state.fitness.toFixed(2)}
|
|
328
470
|
Agents: ${state.agents.length}
|
|
329
|
-
Sessions: ${state.metrics.sessions}
|
|
471
|
+
Sessions: ${state.metrics.sessions}
|
|
472
|
+
Tokens: ${state.metrics.totalTokens}
|
|
473
|
+
Cost: $${state.metrics.totalCost.toFixed(4)}`);
|
|
330
474
|
break;
|
|
331
475
|
case "exit":
|
|
332
476
|
case "quit":
|
|
333
|
-
addMessage("system", "
|
|
477
|
+
addMessage("system", "Goodbye!");
|
|
334
478
|
break;
|
|
335
479
|
default:
|
|
336
480
|
runWorkflow(input);
|
|
@@ -339,7 +483,7 @@ Sessions: ${state.metrics.sessions}`);
|
|
|
339
483
|
const runWorkflow = useCallback(async (prompt) => {
|
|
340
484
|
resetWorkflow();
|
|
341
485
|
addMessage("user", prompt);
|
|
342
|
-
addMessage("agent", "
|
|
486
|
+
addMessage("agent", "Starting workflow...", "Orchestrator", state.model);
|
|
343
487
|
const sessionId = generateId();
|
|
344
488
|
setState((prev) => ({
|
|
345
489
|
...prev,
|
|
@@ -350,33 +494,36 @@ Sessions: ${state.metrics.sessions}`);
|
|
|
350
494
|
timestamp: new Date(),
|
|
351
495
|
status: "running",
|
|
352
496
|
model: prev.model,
|
|
353
|
-
}]
|
|
497
|
+
}],
|
|
354
498
|
}));
|
|
355
499
|
const startTime = Date.now();
|
|
356
500
|
try {
|
|
357
|
-
await orchestratorRef.current.run(prompt);
|
|
501
|
+
const result = await orchestratorRef.current.run(prompt);
|
|
358
502
|
const duration = Date.now() - startTime;
|
|
359
|
-
addMessage("success", `Workflow
|
|
503
|
+
addMessage("success", `Workflow completed!\nConfidence: ${result.metrics.confidence.toFixed(2)}\nDuration: ${(duration / 1000).toFixed(1)}s\nCost: $${result.metrics.totalCostUsd.toFixed(4)}`, undefined, state.model);
|
|
360
504
|
setState((prev) => ({
|
|
361
505
|
...prev,
|
|
362
|
-
sessions: prev.sessions.map((s) => s.id === sessionId
|
|
506
|
+
sessions: prev.sessions.map((s) => s.id === sessionId
|
|
507
|
+
? { ...s, status: "completed", duration, confidence: result.metrics.confidence }
|
|
508
|
+
: s),
|
|
363
509
|
}));
|
|
364
510
|
}
|
|
365
511
|
catch (error) {
|
|
366
|
-
addMessage("error", `
|
|
512
|
+
addMessage("error", `Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
367
513
|
setState((prev) => ({
|
|
368
514
|
...prev,
|
|
369
515
|
status: "error",
|
|
370
516
|
isProcessing: false,
|
|
371
|
-
sessions: prev.sessions.map((s) => s.id === sessionId
|
|
517
|
+
sessions: prev.sessions.map((s) => s.id === sessionId
|
|
518
|
+
? { ...s, status: "failed", duration: Date.now() - startTime }
|
|
519
|
+
: s),
|
|
372
520
|
}));
|
|
373
521
|
}
|
|
374
|
-
}, [resetWorkflow, addMessage, state.
|
|
522
|
+
}, [resetWorkflow, addMessage, state.model]);
|
|
375
523
|
const handleInteractiveCommandNavigation = useCallback((direction) => {
|
|
376
524
|
if (!state.interactiveCommand.type)
|
|
377
525
|
return;
|
|
378
526
|
if (direction === "escape") {
|
|
379
|
-
// Close the interactive command
|
|
380
527
|
setState((prev) => ({
|
|
381
528
|
...prev,
|
|
382
529
|
interactiveCommand: { type: null, options: [], selectedIndex: 0 },
|