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 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, prompts/)
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 { white-space: pre-wrap; font-family: monospace; }
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 { width: 10px; height: 10px; }
20
- .dark ::-webkit-scrollbar-track { background: #000000; }
21
- .dark ::-webkit-scrollbar-thumb { background: #27272a; border-radius: 5px; }
22
- .dark ::-webkit-scrollbar-thumb:hover { background: #3f3f46; }
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">Runtime History & Prompt Logs</p>
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
- <div className="flex justify-end w-full group">
289
- <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">
290
- <div className="flex justify-between items-center mb-3">
291
- <div className="text-[9px] font-black text-blue-300 dark:text-blue-800/60 uppercase tracking-[0.2em] text-right w-full">Output / Response</div>
292
- <div className="absolute top-4 right-4 opacity-0 group-hover:opacity-100 transition-opacity">
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
- <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">
329
- <div className="text-[9px] text-gray-400 dark:text-zinc-600 uppercase tracking-widest mb-1 flex justify-between">
330
- <span>{item.event}</span>
331
- <span>{formatTime(item.timestamp)}</span>
332
- </div>
333
- <div className="text-gray-600 dark:text-zinc-400 whitespace-pre-wrap">
334
- {JSON.stringify(item, (key, value) => {
335
- // Exclude redundant keys to keep it clean
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
- </html>
462
+
463
+ </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-state-machine",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "type": "module",
5
5
  "description": "A workflow orchestrator for running agents and scripts in sequence with state management",
6
6
  "main": "lib/index.js",