agent-state-machine 1.3.0 → 1.3.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/lib/llm.js +0 -2
- package/lib/setup.js +1 -1
- package/lib/ui/index.html +148 -44
- package/package.json +1 -1
package/lib/llm.js
CHANGED
|
@@ -335,8 +335,6 @@ export async function llm(context, options) {
|
|
|
335
335
|
const models = config.models || {};
|
|
336
336
|
const apiKeys = config.apiKeys || {};
|
|
337
337
|
|
|
338
|
-
// No longer needed to write to prompts/ directory here
|
|
339
|
-
|
|
340
338
|
// Look up the model command/config
|
|
341
339
|
const modelConfig = models[options.model];
|
|
342
340
|
|
package/lib/setup.js
CHANGED
|
@@ -293,7 +293,7 @@ ${workflowName}/
|
|
|
293
293
|
├── package.json # Sets "type": "module" for this workflow folder
|
|
294
294
|
├── agents/ # Custom agents (.js/.mjs/.cjs or .md)
|
|
295
295
|
├── interactions/ # Human-in-the-loop inputs (created at runtime)
|
|
296
|
-
├── state/ # Runtime state (current.json, history.jsonl
|
|
296
|
+
├── state/ # Runtime state (current.json, history.jsonl)
|
|
297
297
|
└── steering/ # Steering configuration
|
|
298
298
|
\\\`\\\`\\\`
|
|
299
299
|
|
package/lib/ui/index.html
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
|
+
|
|
3
4
|
<head>
|
|
4
5
|
<meta charset="UTF-8">
|
|
5
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
@@ -14,14 +15,32 @@
|
|
|
14
15
|
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
|
|
15
16
|
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
|
|
16
17
|
<style>
|
|
17
|
-
.markdown-body {
|
|
18
|
+
.markdown-body {
|
|
19
|
+
white-space: pre-wrap;
|
|
20
|
+
font-family: monospace;
|
|
21
|
+
}
|
|
22
|
+
|
|
18
23
|
/* Scrollbar styles for dark mode */
|
|
19
|
-
.dark ::-webkit-scrollbar {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
.dark ::-webkit-scrollbar {
|
|
25
|
+
width: 10px;
|
|
26
|
+
height: 10px;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.dark ::-webkit-scrollbar-track {
|
|
30
|
+
background: #000000;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.dark ::-webkit-scrollbar-thumb {
|
|
34
|
+
background: #27272a;
|
|
35
|
+
border-radius: 5px;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.dark ::-webkit-scrollbar-thumb:hover {
|
|
39
|
+
background: #3f3f46;
|
|
40
|
+
}
|
|
23
41
|
</style>
|
|
24
42
|
</head>
|
|
43
|
+
|
|
25
44
|
<body>
|
|
26
45
|
<div id="root"></div>
|
|
27
46
|
|
|
@@ -64,8 +83,8 @@
|
|
|
64
83
|
};
|
|
65
84
|
|
|
66
85
|
return (
|
|
67
|
-
<button
|
|
68
|
-
onClick={handleCopy}
|
|
86
|
+
<button
|
|
87
|
+
onClick={handleCopy}
|
|
69
88
|
className={`flex items-center space-x-1 text-[9px] uppercase tracking-wider transition-colors hover:text-blue-500 focus:outline-none ${className}`}
|
|
70
89
|
title="Copy to clipboard"
|
|
71
90
|
>
|
|
@@ -75,6 +94,105 @@
|
|
|
75
94
|
);
|
|
76
95
|
}
|
|
77
96
|
|
|
97
|
+
function JsonView({ data, label, onTop = false, timestamp }) {
|
|
98
|
+
const [viewMode, setViewMode] = useState('clean'); // 'clean' | 'raw'
|
|
99
|
+
|
|
100
|
+
const isObject = typeof data === 'object' && data !== null;
|
|
101
|
+
const rawContent = isObject ? JSON.stringify(data, null, 2) : String(data);
|
|
102
|
+
const lineBreak = '';
|
|
103
|
+
|
|
104
|
+
// UPDATED: "clean" view loops through ALL top-level keys.
|
|
105
|
+
// Headers render in CAPS, BOLD, and BLUE.
|
|
106
|
+
let cleanParts = null;
|
|
107
|
+
if (isObject) {
|
|
108
|
+
const keys = Object.keys(data);
|
|
109
|
+
if (keys.length > 0) {
|
|
110
|
+
cleanParts = keys.map((k) => {
|
|
111
|
+
const val = data[k];
|
|
112
|
+
const renderedVal = typeof val === 'string' ? val : JSON.stringify(val, null, 2);
|
|
113
|
+
const prettyVal = String(renderedVal).replace(/\\n/g, lineBreak);
|
|
114
|
+
|
|
115
|
+
return (
|
|
116
|
+
<div key={k} className="mb-5 last:mb-0">
|
|
117
|
+
<div className="text-[11px] font-extrabold uppercase tracking-wider text-blue-600 dark:text-blue-400 mb-2">
|
|
118
|
+
{k}
|
|
119
|
+
</div>
|
|
120
|
+
<div className="whitespace-pre-wrap">
|
|
121
|
+
{prettyVal}
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// For RAW view we still render as a string
|
|
130
|
+
const rawContentUnescaped = rawContent; // keep raw exact
|
|
131
|
+
|
|
132
|
+
const hasToggle = isObject || rawContent.includes('\\n');
|
|
133
|
+
|
|
134
|
+
if (onTop) {
|
|
135
|
+
return (
|
|
136
|
+
<div className="flex justify-end w-full group">
|
|
137
|
+
<div className="max-w-[85%] bg-blue-50 dark:bg-blue-950/20 border border-blue-100 dark:border-blue-900/40 rounded-2xl rounded-tr-none shadow-sm p-6 transition-all hover:border-blue-200 dark:hover:border-blue-800 relative">
|
|
138
|
+
<div className="flex justify-between items-center mb-3">
|
|
139
|
+
<div className="text-[9px] font-black text-blue-300 dark:text-blue-800/60 uppercase tracking-[0.2em] text-right w-full">
|
|
140
|
+
{label}
|
|
141
|
+
</div>
|
|
142
|
+
<div className="absolute top-4 left-4 opacity-0 group-hover:opacity-100 transition-opacity flex items-center space-x-2">
|
|
143
|
+
{hasToggle && (
|
|
144
|
+
<button
|
|
145
|
+
onClick={() => setViewMode(v => v === 'clean' ? 'raw' : 'clean')}
|
|
146
|
+
className="text-[9px] uppercase tracking-wider font-bold text-blue-400 hover:text-blue-600 dark:text-blue-600 dark:hover:text-blue-400 focus:outline-none"
|
|
147
|
+
>
|
|
148
|
+
{viewMode === 'clean' ? 'Raw' : 'Clean'}
|
|
149
|
+
</button>
|
|
150
|
+
)}
|
|
151
|
+
<CopyButton text={data} className="text-blue-400 hover:text-blue-600 dark:text-blue-600 dark:hover:text-blue-400" />
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
|
|
155
|
+
<div className="markdown-body text-gray-800 dark:text-zinc-200 text-sm overflow-x-auto leading-relaxed">
|
|
156
|
+
{viewMode === 'clean'
|
|
157
|
+
? (cleanParts ?? String(rawContent).replace(/\\n/g, lineBreak))
|
|
158
|
+
: rawContentUnescaped
|
|
159
|
+
}
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
</div>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return (
|
|
167
|
+
<div className="bg-gray-100 dark:bg-zinc-900/50 border border-gray-200 dark:border-zinc-800 rounded-lg px-4 py-3 text-xs w-full max-w-2xl font-mono overflow-x-auto relative group">
|
|
168
|
+
<div className="text-[9px] text-gray-400 dark:text-zinc-600 uppercase tracking-widest mb-1 flex justify-between items-center">
|
|
169
|
+
<div className="flex space-x-4">
|
|
170
|
+
<span>{label}</span>
|
|
171
|
+
{timestamp && <span>{timestamp}</span>}
|
|
172
|
+
</div>
|
|
173
|
+
<div className="opacity-0 group-hover:opacity-100 transition-opacity flex items-center space-x-2">
|
|
174
|
+
{hasToggle && (
|
|
175
|
+
<button
|
|
176
|
+
onClick={() => setViewMode(v => v === 'clean' ? 'raw' : 'clean')}
|
|
177
|
+
className="text-[9px] uppercase tracking-wider font-bold text-zinc-400 hover:text-blue-500 focus:outline-none"
|
|
178
|
+
>
|
|
179
|
+
{viewMode === 'clean' ? 'Raw' : 'Clean'}
|
|
180
|
+
</button>
|
|
181
|
+
)}
|
|
182
|
+
<CopyButton text={data} className="text-gray-400 hover:text-gray-600" />
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
|
|
186
|
+
<div className="text-gray-600 dark:text-zinc-400 whitespace-pre-wrap">
|
|
187
|
+
{viewMode === 'clean'
|
|
188
|
+
? (cleanParts ?? String(rawContent).replace(/\\n/g, lineBreak))
|
|
189
|
+
: rawContentUnescaped
|
|
190
|
+
}
|
|
191
|
+
</div>
|
|
192
|
+
</div>
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
78
196
|
function App() {
|
|
79
197
|
const [history, setHistory] = useState([]);
|
|
80
198
|
const [loading, setLoading] = useState(true);
|
|
@@ -129,7 +247,7 @@
|
|
|
129
247
|
</div>
|
|
130
248
|
</div>
|
|
131
249
|
);
|
|
132
|
-
|
|
250
|
+
|
|
133
251
|
if (error) return (
|
|
134
252
|
<div className={theme}>
|
|
135
253
|
<div className="flex items-center justify-center h-screen bg-gray-50 dark:bg-black text-red-500">
|
|
@@ -154,26 +272,26 @@
|
|
|
154
272
|
<div className={theme}>
|
|
155
273
|
<div className="min-h-screen bg-gray-50 dark:bg-black transition-colors duration-200">
|
|
156
274
|
<div className="max-w-5xl mx-auto min-h-screen flex flex-col">
|
|
157
|
-
|
|
275
|
+
|
|
158
276
|
{/* Sticky Header */}
|
|
159
277
|
<header className="sticky top-0 z-50 py-4 px-6 bg-gray-50/90 dark:bg-black/90 backdrop-blur-md border-b border-gray-200 dark:border-zinc-800 flex items-center justify-between mb-8 transition-colors">
|
|
160
278
|
<div className="flex-1">
|
|
161
279
|
<h1 className="text-xl font-bold text-gray-800 dark:text-zinc-100 transition-colors uppercase tracking-tight">{workflowName}</h1>
|
|
162
|
-
<p className="text-gray-500 dark:text-zinc-500 text-xs mt-0.5">
|
|
280
|
+
<p className="text-gray-500 dark:text-zinc-500 text-xs mt-0.5">Runtimes History & Prompt Logs</p>
|
|
163
281
|
</div>
|
|
164
282
|
<div className="flex items-center space-x-2">
|
|
165
|
-
<button
|
|
283
|
+
<button
|
|
166
284
|
onClick={toggleSort}
|
|
167
285
|
className="p-2 rounded-full bg-gray-200 dark:bg-zinc-900 text-gray-800 dark:text-zinc-200 hover:bg-gray-300 dark:hover:bg-zinc-800 transition-colors"
|
|
168
286
|
title={sortOrder === 'newest' ? "Sort: Newest First" : "Sort: Oldest First"}
|
|
169
287
|
>
|
|
170
|
-
{sortOrder === 'newest' ?
|
|
171
|
-
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 4h13M3 8h9m-9 4h6m4 0l4-4m0 0l4 4m-4-4v12" /></svg>
|
|
172
|
-
:
|
|
288
|
+
{sortOrder === 'newest' ?
|
|
289
|
+
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 4h13M3 8h9m-9 4h6m4 0l4-4m0 0l4 4m-4-4v12" /></svg>
|
|
290
|
+
:
|
|
173
291
|
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 4h13M3 8h9m-9 4h6m4 0l4-4m0 0l4 4m-4-4v12" transform="scale(1, -1) translate(0, -24)" /></svg>
|
|
174
292
|
}
|
|
175
293
|
</button>
|
|
176
|
-
<button
|
|
294
|
+
<button
|
|
177
295
|
onClick={toggleTheme}
|
|
178
296
|
className="p-2 rounded-full bg-gray-200 dark:bg-zinc-900 text-gray-800 dark:text-zinc-200 hover:bg-gray-300 dark:hover:bg-zinc-800 transition-colors"
|
|
179
297
|
title="Toggle Theme"
|
|
@@ -285,19 +403,11 @@
|
|
|
285
403
|
|
|
286
404
|
{/* Output (Response) - NOW ON TOP */}
|
|
287
405
|
{(item.output || item.result) && (
|
|
288
|
-
<
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
<CopyButton text={item.output || item.result} className="text-blue-400 hover:text-blue-600 dark:text-blue-600 dark:hover:text-blue-400" />
|
|
294
|
-
</div>
|
|
295
|
-
</div>
|
|
296
|
-
<div className="markdown-body text-gray-800 dark:text-zinc-200 text-sm overflow-x-auto leading-relaxed">
|
|
297
|
-
{typeof item.output === 'object' ? JSON.stringify(item.output, null, 2) : (item.output || item.result)}
|
|
298
|
-
</div>
|
|
299
|
-
</div>
|
|
300
|
-
</div>
|
|
406
|
+
<JsonView
|
|
407
|
+
data={item.output || item.result}
|
|
408
|
+
label="Output / Response"
|
|
409
|
+
onTop={true}
|
|
410
|
+
/>
|
|
301
411
|
)}
|
|
302
412
|
|
|
303
413
|
{/* Prompt (Input) - NOW ON BOTTOM */}
|
|
@@ -321,23 +431,16 @@
|
|
|
321
431
|
}
|
|
322
432
|
|
|
323
433
|
// 7. CATCH-ALL for Unknown Events
|
|
324
|
-
// If we made it here, it's an event we didn't explicitly handle.
|
|
325
|
-
// Render it generically.
|
|
326
434
|
return (
|
|
327
435
|
<div key={idx} className="flex justify-center px-4">
|
|
328
|
-
<
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
if (key === 'event' || key === 'timestamp') return undefined;
|
|
337
|
-
return value;
|
|
338
|
-
}, 2).replace(/^{|}$/g, '').trim()}
|
|
339
|
-
</div>
|
|
340
|
-
</div>
|
|
436
|
+
<JsonView
|
|
437
|
+
data={JSON.parse(JSON.stringify(item, (key, value) => {
|
|
438
|
+
if (key === 'event' || key === 'timestamp') return undefined; // Keep it clean
|
|
439
|
+
return value;
|
|
440
|
+
}))}
|
|
441
|
+
label={item.event}
|
|
442
|
+
timestamp={formatTime(item.timestamp)}
|
|
443
|
+
/>
|
|
341
444
|
</div>
|
|
342
445
|
);
|
|
343
446
|
})}
|
|
@@ -356,4 +459,5 @@
|
|
|
356
459
|
root.render(<App />);
|
|
357
460
|
</script>
|
|
358
461
|
</body>
|
|
359
|
-
|
|
462
|
+
|
|
463
|
+
</html>
|