nitrostack 1.0.72 → 1.0.73

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.
Files changed (240) hide show
  1. package/dist/auth/api-key.js.map +1 -1
  2. package/dist/auth/client.js.map +1 -1
  3. package/dist/auth/index.d.ts +2 -1
  4. package/dist/auth/index.d.ts.map +1 -1
  5. package/dist/auth/index.js +3 -0
  6. package/dist/auth/index.js.map +1 -1
  7. package/dist/auth/middleware.d.ts +1 -1
  8. package/dist/auth/middleware.d.ts.map +1 -1
  9. package/dist/auth/middleware.js.map +1 -1
  10. package/dist/auth/secure-secret.d.ts +136 -0
  11. package/dist/auth/secure-secret.d.ts.map +1 -0
  12. package/dist/auth/secure-secret.js +182 -0
  13. package/dist/auth/secure-secret.js.map +1 -0
  14. package/dist/auth/server-metadata.d.ts.map +1 -1
  15. package/dist/auth/server-metadata.js.map +1 -1
  16. package/dist/auth/simple-jwt.d.ts +100 -14
  17. package/dist/auth/simple-jwt.d.ts.map +1 -1
  18. package/dist/auth/simple-jwt.js +19 -9
  19. package/dist/auth/simple-jwt.js.map +1 -1
  20. package/dist/auth/token-store.js +1 -1
  21. package/dist/auth/token-store.js.map +1 -1
  22. package/dist/auth/token-validation.js +1 -1
  23. package/dist/auth/token-validation.js.map +1 -1
  24. package/dist/cli/commands/build.js +1 -1
  25. package/dist/cli/commands/build.js.map +1 -1
  26. package/dist/cli/commands/generate-types.js +12 -12
  27. package/dist/cli/commands/generate-types.js.map +1 -1
  28. package/dist/cli/commands/generate.d.ts +8 -1
  29. package/dist/cli/commands/generate.d.ts.map +1 -1
  30. package/dist/cli/commands/generate.js +13 -12
  31. package/dist/cli/commands/generate.js.map +1 -1
  32. package/dist/cli/commands/init.js +1 -1
  33. package/dist/cli/commands/init.js.map +1 -1
  34. package/dist/cli/commands/upgrade.d.ts +10 -0
  35. package/dist/cli/commands/upgrade.d.ts.map +1 -0
  36. package/dist/cli/commands/upgrade.js +221 -0
  37. package/dist/cli/commands/upgrade.js.map +1 -0
  38. package/dist/cli/index.js +7 -0
  39. package/dist/cli/index.js.map +1 -1
  40. package/dist/core/app-decorator.d.ts +4 -3
  41. package/dist/core/app-decorator.d.ts.map +1 -1
  42. package/dist/core/app-decorator.js +67 -28
  43. package/dist/core/app-decorator.js.map +1 -1
  44. package/dist/core/builders.d.ts +19 -7
  45. package/dist/core/builders.d.ts.map +1 -1
  46. package/dist/core/builders.js +15 -8
  47. package/dist/core/builders.js.map +1 -1
  48. package/dist/core/component.d.ts +8 -8
  49. package/dist/core/component.d.ts.map +1 -1
  50. package/dist/core/component.js +3 -2
  51. package/dist/core/component.js.map +1 -1
  52. package/dist/core/config-module.d.ts +11 -4
  53. package/dist/core/config-module.d.ts.map +1 -1
  54. package/dist/core/config-module.js +1 -1
  55. package/dist/core/config-module.js.map +1 -1
  56. package/dist/core/decorators/cache.decorator.d.ts +9 -9
  57. package/dist/core/decorators/cache.decorator.d.ts.map +1 -1
  58. package/dist/core/decorators/cache.decorator.js +3 -3
  59. package/dist/core/decorators/cache.decorator.js.map +1 -1
  60. package/dist/core/decorators/health-check.decorator.d.ts +3 -3
  61. package/dist/core/decorators/health-check.decorator.d.ts.map +1 -1
  62. package/dist/core/decorators/health-check.decorator.js +2 -2
  63. package/dist/core/decorators/health-check.decorator.js.map +1 -1
  64. package/dist/core/decorators/rate-limit.decorator.d.ts +5 -4
  65. package/dist/core/decorators/rate-limit.decorator.d.ts.map +1 -1
  66. package/dist/core/decorators/rate-limit.decorator.js +3 -3
  67. package/dist/core/decorators/rate-limit.decorator.js.map +1 -1
  68. package/dist/core/decorators.d.ts +47 -29
  69. package/dist/core/decorators.d.ts.map +1 -1
  70. package/dist/core/decorators.js +9 -9
  71. package/dist/core/decorators.js.map +1 -1
  72. package/dist/core/di/container.d.ts +21 -4
  73. package/dist/core/di/container.d.ts.map +1 -1
  74. package/dist/core/di/container.js +11 -7
  75. package/dist/core/di/container.js.map +1 -1
  76. package/dist/core/di/injectable.decorator.d.ts +5 -3
  77. package/dist/core/di/injectable.decorator.d.ts.map +1 -1
  78. package/dist/core/di/injectable.decorator.js.map +1 -1
  79. package/dist/core/errors.d.ts +4 -4
  80. package/dist/core/errors.d.ts.map +1 -1
  81. package/dist/core/errors.js.map +1 -1
  82. package/dist/core/events/event-emitter.d.ts +3 -3
  83. package/dist/core/events/event-emitter.d.ts.map +1 -1
  84. package/dist/core/events/event-emitter.js.map +1 -1
  85. package/dist/core/events/event.decorator.d.ts +5 -5
  86. package/dist/core/events/event.decorator.d.ts.map +1 -1
  87. package/dist/core/events/event.decorator.js +10 -6
  88. package/dist/core/events/event.decorator.js.map +1 -1
  89. package/dist/core/events/log-emitter.d.ts +7 -1
  90. package/dist/core/events/log-emitter.d.ts.map +1 -1
  91. package/dist/core/events/log-emitter.js.map +1 -1
  92. package/dist/core/filters/exception-filter.decorator.d.ts +5 -5
  93. package/dist/core/filters/exception-filter.decorator.d.ts.map +1 -1
  94. package/dist/core/filters/exception-filter.decorator.js +3 -3
  95. package/dist/core/filters/exception-filter.decorator.js.map +1 -1
  96. package/dist/core/filters/exception-filter.interface.d.ts +14 -5
  97. package/dist/core/filters/exception-filter.interface.d.ts.map +1 -1
  98. package/dist/core/guards/apikey.guard.d.ts +1 -1
  99. package/dist/core/guards/apikey.guard.d.ts.map +1 -1
  100. package/dist/core/guards/guard.interface.d.ts +1 -1
  101. package/dist/core/guards/guard.interface.d.ts.map +1 -1
  102. package/dist/core/guards/jwt.guard.d.ts +1 -1
  103. package/dist/core/guards/jwt.guard.d.ts.map +1 -1
  104. package/dist/core/guards/oauth.guard.d.ts +1 -1
  105. package/dist/core/guards/oauth.guard.d.ts.map +1 -1
  106. package/dist/core/guards/use-guards.decorator.d.ts +3 -3
  107. package/dist/core/guards/use-guards.decorator.d.ts.map +1 -1
  108. package/dist/core/guards/use-guards.decorator.js +1 -1
  109. package/dist/core/guards/use-guards.decorator.js.map +1 -1
  110. package/dist/core/index.d.ts +2 -2
  111. package/dist/core/index.d.ts.map +1 -1
  112. package/dist/core/index.js.map +1 -1
  113. package/dist/core/interceptors/interceptor.decorator.d.ts +4 -4
  114. package/dist/core/interceptors/interceptor.decorator.d.ts.map +1 -1
  115. package/dist/core/interceptors/interceptor.decorator.js +2 -2
  116. package/dist/core/interceptors/interceptor.decorator.js.map +1 -1
  117. package/dist/core/interceptors/interceptor.interface.d.ts +3 -3
  118. package/dist/core/interceptors/interceptor.interface.d.ts.map +1 -1
  119. package/dist/core/logger.d.ts.map +1 -1
  120. package/dist/core/logger.js.map +1 -1
  121. package/dist/core/middleware/middleware.decorator.d.ts +4 -4
  122. package/dist/core/middleware/middleware.decorator.d.ts.map +1 -1
  123. package/dist/core/middleware/middleware.decorator.js +2 -2
  124. package/dist/core/middleware/middleware.decorator.js.map +1 -1
  125. package/dist/core/middleware/middleware.interface.d.ts +3 -3
  126. package/dist/core/middleware/middleware.interface.d.ts.map +1 -1
  127. package/dist/core/module.d.ts +33 -14
  128. package/dist/core/module.d.ts.map +1 -1
  129. package/dist/core/module.js +11 -6
  130. package/dist/core/module.js.map +1 -1
  131. package/dist/core/oauth-module.d.ts +9 -3
  132. package/dist/core/oauth-module.d.ts.map +1 -1
  133. package/dist/core/oauth-module.js +4 -3
  134. package/dist/core/oauth-module.js.map +1 -1
  135. package/dist/core/pipes/pipe.decorator.d.ts +14 -5
  136. package/dist/core/pipes/pipe.decorator.d.ts.map +1 -1
  137. package/dist/core/pipes/pipe.decorator.js +2 -2
  138. package/dist/core/pipes/pipe.decorator.js.map +1 -1
  139. package/dist/core/pipes/pipe.interface.d.ts +9 -4
  140. package/dist/core/pipes/pipe.interface.d.ts.map +1 -1
  141. package/dist/core/prompt.d.ts +13 -4
  142. package/dist/core/prompt.d.ts.map +1 -1
  143. package/dist/core/prompt.js +2 -2
  144. package/dist/core/prompt.js.map +1 -1
  145. package/dist/core/resource.d.ts +7 -2
  146. package/dist/core/resource.d.ts.map +1 -1
  147. package/dist/core/resource.js +2 -2
  148. package/dist/core/resource.js.map +1 -1
  149. package/dist/core/server.d.ts +49 -3
  150. package/dist/core/server.d.ts.map +1 -1
  151. package/dist/core/server.js +61 -34
  152. package/dist/core/server.js.map +1 -1
  153. package/dist/core/tool.d.ts +44 -16
  154. package/dist/core/tool.d.ts.map +1 -1
  155. package/dist/core/tool.js +19 -6
  156. package/dist/core/tool.js.map +1 -1
  157. package/dist/core/transports/discovery-http-server.d.ts +7 -1
  158. package/dist/core/transports/discovery-http-server.d.ts.map +1 -1
  159. package/dist/core/transports/discovery-http-server.js.map +1 -1
  160. package/dist/core/transports/http-server.d.ts +2 -2
  161. package/dist/core/transports/http-server.d.ts.map +1 -1
  162. package/dist/core/transports/http-server.js +1 -1
  163. package/dist/core/transports/http-server.js.map +1 -1
  164. package/dist/core/transports/streamable-http.d.ts +4 -4
  165. package/dist/core/transports/streamable-http.d.ts.map +1 -1
  166. package/dist/core/transports/streamable-http.js +1 -1
  167. package/dist/core/transports/streamable-http.js.map +1 -1
  168. package/dist/core/types.d.ts +87 -15
  169. package/dist/core/types.d.ts.map +1 -1
  170. package/dist/core/widgets/widget-registry.d.ts +2 -2
  171. package/dist/core/widgets/widget-registry.d.ts.map +1 -1
  172. package/dist/core/widgets/widget-registry.js +1 -1
  173. package/dist/core/widgets/widget-registry.js.map +1 -1
  174. package/dist/testing/index.d.ts +44 -17
  175. package/dist/testing/index.d.ts.map +1 -1
  176. package/dist/testing/index.js +5 -8
  177. package/dist/testing/index.js.map +1 -1
  178. package/dist/ui-next/index.d.ts +1 -1
  179. package/dist/ui-next/index.d.ts.map +1 -1
  180. package/dist/ui-next/index.js.map +1 -1
  181. package/dist/widgets/hooks/useWidgetSDK.d.ts +5 -5
  182. package/dist/widgets/runtime/WidgetLayout.js.map +1 -1
  183. package/dist/widgets/sdk.d.ts +5 -5
  184. package/dist/widgets/sdk.d.ts.map +1 -1
  185. package/dist/widgets/sdk.js.map +1 -1
  186. package/package.json +1 -1
  187. package/src/studio/app/api/auth/fetch-metadata/route.ts +3 -2
  188. package/src/studio/app/api/auth/register-client/route.ts +3 -2
  189. package/src/studio/app/api/chat/route.ts +31 -17
  190. package/src/studio/app/api/health/checks/route.ts +5 -4
  191. package/src/studio/app/api/init/route.ts +3 -2
  192. package/src/studio/app/api/ping/route.ts +3 -2
  193. package/src/studio/app/api/prompts/[name]/route.ts +4 -3
  194. package/src/studio/app/api/prompts/route.ts +3 -2
  195. package/src/studio/app/api/resources/[...uri]/route.ts +3 -2
  196. package/src/studio/app/api/resources/route.ts +3 -2
  197. package/src/studio/app/api/roots/route.ts +3 -2
  198. package/src/studio/app/api/sampling/route.ts +3 -2
  199. package/src/studio/app/api/tools/[name]/call/route.ts +3 -2
  200. package/src/studio/app/api/tools/route.ts +4 -3
  201. package/src/studio/app/api/widget-examples/route.ts +5 -4
  202. package/src/studio/app/auth/callback/page.tsx +3 -2
  203. package/src/studio/app/chat/page.tsx +481 -105
  204. package/src/studio/app/health/page.tsx +1 -1
  205. package/src/studio/app/logs/page.tsx +2 -2
  206. package/src/studio/app/page.tsx +5 -5
  207. package/src/studio/app/prompts/page.tsx +2 -2
  208. package/src/studio/app/settings/page.tsx +3 -2
  209. package/src/studio/app/tools/page.tsx +3 -3
  210. package/src/studio/components/LogMessage.tsx +1 -1
  211. package/src/studio/components/MarkdownRenderer.tsx +245 -348
  212. package/src/studio/components/Sidebar.tsx +18 -3
  213. package/src/studio/components/VoiceOrbOverlay.tsx +12 -6
  214. package/src/studio/components/WidgetErrorBoundary.tsx +48 -0
  215. package/src/studio/components/WidgetRenderer.tsx +168 -215
  216. package/src/studio/components/ops/OpsCanvas.tsx +748 -0
  217. package/src/studio/components/ops/OpsNodeDetailPanel.tsx +150 -0
  218. package/src/studio/components/ops/OpsSummaryBar.tsx +90 -0
  219. package/src/studio/components/ops/index.ts +5 -0
  220. package/src/studio/components/ops/nodes/BaseNode.tsx +65 -0
  221. package/src/studio/components/ops/nodes/LLMCallNode.tsx +34 -0
  222. package/src/studio/components/ops/nodes/LLMResponseNode.tsx +33 -0
  223. package/src/studio/components/ops/nodes/ToolCallNode.tsx +30 -0
  224. package/src/studio/components/ops/nodes/ToolResultNode.tsx +43 -0
  225. package/src/studio/components/ops/nodes/UserPromptNode.tsx +34 -0
  226. package/src/studio/components/ops/nodes/WidgetRenderNode.tsx +23 -0
  227. package/src/studio/components/ops/nodes/index.ts +8 -0
  228. package/src/studio/components/tools/ToolsCanvas.tsx +2 -2
  229. package/src/studio/lib/api.ts +61 -42
  230. package/src/studio/lib/http-client-transport.ts +2 -2
  231. package/src/studio/lib/llm-service.ts +126 -47
  232. package/src/studio/lib/mcp-client.ts +9 -6
  233. package/src/studio/lib/ops-store.ts +427 -0
  234. package/src/studio/lib/ops-tracker.ts +416 -0
  235. package/src/studio/lib/ops-types.ts +164 -0
  236. package/src/studio/lib/store.ts +8 -11
  237. package/src/studio/lib/types.ts +228 -38
  238. package/src/studio/lib/widget-loader.ts +2 -2
  239. package/templates/typescript-oauth/src/modules/flights/flights.prompts.ts +19 -22
  240. package/dist/cli/build-widgets.mjs +0 -165
@@ -0,0 +1,416 @@
1
+ /**
2
+ * Ops Tracker - Utility functions for tracking agent operations
3
+ */
4
+
5
+ import { useOpsStore } from './ops-store';
6
+ import type {
7
+ LLMProvider,
8
+ UserPromptNodeData,
9
+ LLMCallNodeData,
10
+ ToolCallNodeData,
11
+ ToolResultNodeData,
12
+ WidgetRenderNodeData,
13
+ LLMResponseNodeData,
14
+ } from './ops-types';
15
+
16
+ // Get the store actions
17
+ const getStore = () => useOpsStore.getState();
18
+
19
+ /**
20
+ * Track a user prompt - this starts a new turn
21
+ */
22
+ export function trackUserPrompt(content: string, hasImage: boolean = false): string {
23
+ const store = getStore();
24
+
25
+ // Start a new turn
26
+ store.startTurn(content);
27
+
28
+ const data: UserPromptNodeData = {
29
+ status: 'success',
30
+ label: 'User',
31
+ content,
32
+ hasImage,
33
+ };
34
+
35
+ return store.addNode('user_prompt', data);
36
+ }
37
+
38
+ /**
39
+ * Start tracking an LLM call
40
+ */
41
+ export function trackLLMCallStart(
42
+ provider: LLMProvider,
43
+ model: string,
44
+ temperature?: number
45
+ ): string {
46
+ const store = getStore();
47
+
48
+ const data: LLMCallNodeData = {
49
+ status: 'running',
50
+ label: `${provider} / ${model}`,
51
+ provider,
52
+ model,
53
+ temperature,
54
+ };
55
+
56
+ return store.addNode('llm_call', data);
57
+ }
58
+
59
+ /**
60
+ * Complete an LLM call with token info
61
+ */
62
+ export function trackLLMCallComplete(
63
+ nodeId: string,
64
+ inputTokens: number,
65
+ outputTokens: number,
66
+ duration: number
67
+ ): void {
68
+ const store = getStore();
69
+
70
+ store.updateNode(nodeId, { duration });
71
+ store.updateNodeData(nodeId, {
72
+ status: 'success',
73
+ inputTokens,
74
+ outputTokens,
75
+ totalTokens: inputTokens + outputTokens,
76
+ });
77
+ }
78
+
79
+ /**
80
+ * Mark an LLM call as failed
81
+ */
82
+ export function trackLLMCallError(nodeId: string, duration: number): void {
83
+ const store = getStore();
84
+
85
+ store.updateNode(nodeId, { duration });
86
+ store.updateNodeData(nodeId, { status: 'error' });
87
+ }
88
+
89
+ /**
90
+ * Track a tool call start
91
+ */
92
+ export function trackToolCallStart(
93
+ toolName: string,
94
+ toolArgs: Record<string, unknown>,
95
+ toolDescription?: string
96
+ ): string {
97
+ const store = getStore();
98
+
99
+ const data: ToolCallNodeData = {
100
+ status: 'running',
101
+ label: toolName,
102
+ toolName,
103
+ toolArgs,
104
+ toolDescription,
105
+ };
106
+
107
+ return store.addNode('tool_call', data);
108
+ }
109
+
110
+ /**
111
+ * Complete a tool call
112
+ */
113
+ export function trackToolCallComplete(nodeId: string, duration: number): void {
114
+ const store = getStore();
115
+
116
+ store.updateNode(nodeId, { duration });
117
+ store.updateNodeData(nodeId, { status: 'success' });
118
+ }
119
+
120
+ /**
121
+ * Mark a tool call as failed
122
+ */
123
+ export function trackToolCallError(nodeId: string, duration: number): void {
124
+ const store = getStore();
125
+
126
+ store.updateNode(nodeId, { duration });
127
+ store.updateNodeData(nodeId, { status: 'error' });
128
+ }
129
+
130
+ /**
131
+ * Track a tool result
132
+ */
133
+ export function trackToolResult(
134
+ toolName: string,
135
+ result: unknown,
136
+ error?: string
137
+ ): string {
138
+ const store = getStore();
139
+
140
+ const resultSize = typeof result === 'string'
141
+ ? result.length
142
+ : JSON.stringify(result).length;
143
+
144
+ const data: ToolResultNodeData = {
145
+ status: error ? 'error' : 'success',
146
+ label: error ? 'Error' : 'Result',
147
+ toolName,
148
+ result,
149
+ error,
150
+ resultSize,
151
+ };
152
+
153
+ return store.addNode('tool_result', data);
154
+ }
155
+
156
+ /**
157
+ * Track widget render
158
+ */
159
+ export function trackWidgetRender(
160
+ widgetUri: string,
161
+ componentName: string,
162
+ data: unknown
163
+ ): string {
164
+ const store = getStore();
165
+
166
+ const dataSize = typeof data === 'string'
167
+ ? data.length
168
+ : JSON.stringify(data).length;
169
+
170
+ const nodeData: WidgetRenderNodeData = {
171
+ status: 'success',
172
+ label: componentName,
173
+ widgetUri,
174
+ componentName,
175
+ dataSize,
176
+ };
177
+
178
+ return store.addNode('widget_render', nodeData);
179
+ }
180
+
181
+ /**
182
+ * Track LLM response - this ends the current turn
183
+ */
184
+ export function trackLLMResponse(
185
+ content: string,
186
+ tokenCount?: number,
187
+ hasToolCalls: boolean = false,
188
+ toolCallCount: number = 0
189
+ ): string {
190
+ const store = getStore();
191
+
192
+ const data: LLMResponseNodeData = {
193
+ status: 'success',
194
+ label: 'Response',
195
+ content,
196
+ tokenCount,
197
+ hasToolCalls,
198
+ toolCallCount,
199
+ };
200
+
201
+ const nodeId = store.addNode('llm_response', data);
202
+
203
+ // End the turn if this is a final response (no tool calls)
204
+ if (!hasToolCalls) {
205
+ store.endTurn();
206
+ }
207
+
208
+ return nodeId;
209
+ }
210
+
211
+ /**
212
+ * Add edge between two nodes
213
+ */
214
+ export function trackEdge(sourceId: string, targetId: string, label?: string): void {
215
+ const store = getStore();
216
+ store.addEdge(sourceId, targetId, label);
217
+ }
218
+
219
+ /**
220
+ * Start a new ops session
221
+ */
222
+ export function startOpsSession(): void {
223
+ const store = getStore();
224
+ store.startSession();
225
+ }
226
+
227
+ /**
228
+ * Clear the current ops session
229
+ */
230
+ export function clearOpsSession(): void {
231
+ const store = getStore();
232
+ store.clearSession();
233
+ }
234
+
235
+ /**
236
+ * Comprehensive tracking helper for a full chat turn
237
+ */
238
+ export class OpsTurnTracker {
239
+ private userPromptId: string | null = null;
240
+ private llmCallId: string | null = null;
241
+ private toolCallIds: Map<string, string> = new Map();
242
+ private llmCallStartTime: number = 0;
243
+ private toolCallStartTimes: Map<string, number> = new Map();
244
+ private lastNodeId: string | null = null;
245
+
246
+ /**
247
+ * Start tracking a new conversation turn
248
+ */
249
+ startTurn(userMessage: string, hasImage: boolean = false): void {
250
+ // Clear previous state
251
+ this.reset();
252
+
253
+ this.userPromptId = trackUserPrompt(userMessage, hasImage);
254
+ this.lastNodeId = this.userPromptId;
255
+ }
256
+
257
+ /**
258
+ * Track LLM call start
259
+ */
260
+ startLLMCall(provider: LLMProvider, model: string): void {
261
+ this.llmCallStartTime = Date.now();
262
+ this.llmCallId = trackLLMCallStart(provider, model);
263
+
264
+ // Connect user prompt to LLM call
265
+ if (this.lastNodeId && this.llmCallId) {
266
+ trackEdge(this.lastNodeId, this.llmCallId);
267
+ }
268
+ this.lastNodeId = this.llmCallId;
269
+ }
270
+
271
+ /**
272
+ * Track LLM call completion
273
+ */
274
+ completeLLMCall(inputTokens: number, outputTokens: number): void {
275
+ if (this.llmCallId) {
276
+ const duration = Date.now() - this.llmCallStartTime;
277
+ trackLLMCallComplete(this.llmCallId, inputTokens, outputTokens, duration);
278
+ }
279
+ }
280
+
281
+ /**
282
+ * Track LLM call error
283
+ */
284
+ errorLLMCall(): void {
285
+ if (this.llmCallId) {
286
+ const duration = Date.now() - this.llmCallStartTime;
287
+ trackLLMCallError(this.llmCallId, duration);
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Track tool call start
293
+ */
294
+ startToolCall(toolCallId: string, toolName: string, toolArgs: Record<string, unknown>): void {
295
+ this.toolCallStartTimes.set(toolCallId, Date.now());
296
+ const nodeId = trackToolCallStart(toolName, toolArgs);
297
+ this.toolCallIds.set(toolCallId, nodeId);
298
+
299
+ // Connect LLM call to tool call
300
+ if (this.lastNodeId && nodeId) {
301
+ trackEdge(this.lastNodeId, nodeId);
302
+ }
303
+ this.lastNodeId = nodeId;
304
+ }
305
+
306
+ /**
307
+ * Track tool call completion with result
308
+ */
309
+ completeToolCall(
310
+ toolCallId: string,
311
+ toolName: string,
312
+ result: unknown,
313
+ error?: string
314
+ ): string | null {
315
+ const nodeId = this.toolCallIds.get(toolCallId);
316
+ const startTime = this.toolCallStartTimes.get(toolCallId);
317
+
318
+ if (nodeId && startTime) {
319
+ const duration = Date.now() - startTime;
320
+ if (error) {
321
+ trackToolCallError(nodeId, duration);
322
+ } else {
323
+ trackToolCallComplete(nodeId, duration);
324
+ }
325
+ }
326
+
327
+ // Add tool result node
328
+ const resultNodeId = trackToolResult(toolName, result, error);
329
+
330
+ // Connect tool call to result
331
+ if (nodeId && resultNodeId) {
332
+ trackEdge(nodeId, resultNodeId);
333
+ }
334
+ this.lastNodeId = resultNodeId;
335
+
336
+ return resultNodeId;
337
+ }
338
+
339
+ /**
340
+ * Track widget render
341
+ */
342
+ trackWidget(
343
+ widgetUri: string,
344
+ componentName: string,
345
+ data: unknown,
346
+ sourceNodeId?: string
347
+ ): string {
348
+ const nodeId = trackWidgetRender(widgetUri, componentName, data);
349
+
350
+ // Connect to source node if provided, otherwise to last node
351
+ const source = sourceNodeId || this.lastNodeId;
352
+ if (source && nodeId) {
353
+ trackEdge(source, nodeId);
354
+ }
355
+ this.lastNodeId = nodeId;
356
+
357
+ return nodeId;
358
+ }
359
+
360
+ /**
361
+ * Track final LLM response
362
+ */
363
+ trackResponse(
364
+ content: string,
365
+ tokenCount?: number,
366
+ sourceNodeId?: string
367
+ ): string {
368
+ const hasToolCalls = this.toolCallIds.size > 0;
369
+ const nodeId = trackLLMResponse(content, tokenCount, false, 0);
370
+
371
+ // Connect to source node
372
+ const source = sourceNodeId || this.lastNodeId;
373
+ if (source && nodeId) {
374
+ trackEdge(source, nodeId);
375
+ }
376
+ this.lastNodeId = nodeId;
377
+
378
+ return nodeId;
379
+ }
380
+
381
+ /**
382
+ * Get the last LLM call node ID
383
+ */
384
+ getLastLLMCallId(): string | null {
385
+ return this.llmCallId;
386
+ }
387
+
388
+ /**
389
+ * Get the last node ID
390
+ */
391
+ getLastNodeId(): string | null {
392
+ return this.lastNodeId;
393
+ }
394
+
395
+ /**
396
+ * Get tool call node ID by tool call ID
397
+ */
398
+ getToolCallNodeId(toolCallId: string): string | undefined {
399
+ return this.toolCallIds.get(toolCallId);
400
+ }
401
+
402
+ /**
403
+ * Reset tracker for next turn
404
+ */
405
+ reset(): void {
406
+ this.userPromptId = null;
407
+ this.llmCallId = null;
408
+ this.toolCallIds.clear();
409
+ this.llmCallStartTime = 0;
410
+ this.toolCallStartTimes.clear();
411
+ this.lastNodeId = null;
412
+ }
413
+ }
414
+
415
+ // Export singleton tracker
416
+ export const opsTracker = new OpsTurnTracker();
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Ops Types - Type definitions for Agent Operations Visualization
3
+ */
4
+
5
+ // Node status
6
+ export type OpsNodeStatus = 'pending' | 'running' | 'success' | 'error';
7
+
8
+ // Node types
9
+ export type OpsNodeType =
10
+ | 'user_prompt'
11
+ | 'llm_call'
12
+ | 'tool_call'
13
+ | 'tool_result'
14
+ | 'widget_render'
15
+ | 'llm_response';
16
+
17
+ // LLM Provider
18
+ export type LLMProvider = 'openai' | 'gemini' | 'anthropic' | 'unknown';
19
+
20
+ // Base node data interface
21
+ export interface OpsNodeDataBase {
22
+ status: OpsNodeStatus;
23
+ label?: string;
24
+ }
25
+
26
+ // User prompt node data
27
+ export interface UserPromptNodeData extends OpsNodeDataBase {
28
+ content: string;
29
+ hasImage?: boolean;
30
+ }
31
+
32
+ // LLM call node data
33
+ export interface LLMCallNodeData extends OpsNodeDataBase {
34
+ provider: LLMProvider;
35
+ model: string;
36
+ inputTokens?: number;
37
+ outputTokens?: number;
38
+ totalTokens?: number;
39
+ cost?: number;
40
+ temperature?: number;
41
+ }
42
+
43
+ // Tool call node data
44
+ export interface ToolCallNodeData extends OpsNodeDataBase {
45
+ toolName: string;
46
+ toolArgs: Record<string, unknown>;
47
+ toolDescription?: string;
48
+ }
49
+
50
+ // Tool result node data
51
+ export interface ToolResultNodeData extends OpsNodeDataBase {
52
+ toolName: string;
53
+ result: unknown;
54
+ error?: string;
55
+ resultSize?: number;
56
+ }
57
+
58
+ // Widget render node data
59
+ export interface WidgetRenderNodeData extends OpsNodeDataBase {
60
+ widgetUri: string;
61
+ componentName: string;
62
+ dataSize?: number;
63
+ }
64
+
65
+ // LLM response node data
66
+ export interface LLMResponseNodeData extends OpsNodeDataBase {
67
+ content: string;
68
+ tokenCount?: number;
69
+ hasToolCalls?: boolean;
70
+ toolCallCount?: number;
71
+ }
72
+
73
+ // Union type for all node data
74
+ export type OpsNodeData =
75
+ | UserPromptNodeData
76
+ | LLMCallNodeData
77
+ | ToolCallNodeData
78
+ | ToolResultNodeData
79
+ | WidgetRenderNodeData
80
+ | LLMResponseNodeData;
81
+
82
+ // Ops node interface
83
+ export interface OpsNode {
84
+ id: string;
85
+ type: OpsNodeType;
86
+ timestamp: number;
87
+ duration?: number;
88
+ data: OpsNodeData;
89
+ position?: { x: number; y: number };
90
+ turnId: string; // Which turn/cycle this node belongs to
91
+ }
92
+
93
+ // Ops edge interface
94
+ export interface OpsEdge {
95
+ id: string;
96
+ source: string;
97
+ target: string;
98
+ animated?: boolean;
99
+ label?: string;
100
+ turnId: string; // Which turn/cycle this edge belongs to
101
+ }
102
+
103
+ // A turn/cycle represents one user prompt and its entire response chain
104
+ export interface OpsTurn {
105
+ id: string;
106
+ startTime: number;
107
+ endTime?: number;
108
+ promptPreview: string; // First ~30 chars of user prompt
109
+ nodeCount: number;
110
+ hasError: boolean;
111
+ }
112
+
113
+ // Session summary
114
+ export interface OpsSessionSummary {
115
+ totalTokens: number;
116
+ inputTokens: number;
117
+ outputTokens: number;
118
+ estimatedCost: number;
119
+ totalDuration: number;
120
+ toolCalls: number;
121
+ llmCalls: number;
122
+ widgetRenders: number;
123
+ errors: number;
124
+ }
125
+
126
+ // Ops session interface
127
+ export interface OpsSession {
128
+ id: string;
129
+ startTime: number;
130
+ endTime?: number;
131
+ nodes: OpsNode[];
132
+ edges: OpsEdge[];
133
+ turns: OpsTurn[];
134
+ summary: OpsSessionSummary;
135
+ }
136
+
137
+ // React Flow node type mapping - color names for Tailwind classes
138
+ export const OPS_NODE_COLORS: Record<OpsNodeType, string> = {
139
+ user_prompt: 'blue',
140
+ llm_call: 'purple',
141
+ tool_call: 'orange',
142
+ tool_result: 'green',
143
+ widget_render: 'cyan',
144
+ llm_response: 'amber',
145
+ };
146
+
147
+ // Hex colors for minimap and other places that need actual colors
148
+ export const OPS_NODE_HEX_COLORS: Record<OpsNodeType, string> = {
149
+ user_prompt: '#3B82F6', // Blue
150
+ llm_call: '#8B5CF6', // Purple
151
+ tool_call: '#F97316', // Orange
152
+ tool_result: '#22C55E', // Green
153
+ widget_render: '#06B6D4', // Cyan
154
+ llm_response: '#F59E0B', // Amber
155
+ };
156
+
157
+ export const OPS_NODE_LABELS: Record<OpsNodeType, string> = {
158
+ user_prompt: 'Prompt',
159
+ llm_call: 'LLM',
160
+ tool_call: 'Tool',
161
+ tool_result: 'Result',
162
+ widget_render: 'Widget',
163
+ llm_response: 'Response',
164
+ };
@@ -9,6 +9,8 @@ import type {
9
9
  PingResult,
10
10
  HealthCheck,
11
11
  OAuthState,
12
+ ChatFile,
13
+ EnlargeModalState,
12
14
  } from './types';
13
15
 
14
16
  interface StudioState {
@@ -36,8 +38,8 @@ interface StudioState {
36
38
  clearChat: () => void;
37
39
  currentProvider: 'openai' | 'gemini';
38
40
  setCurrentProvider: (provider: 'openai' | 'gemini') => void;
39
- currentFile: { data: string; type: string; name: string } | null;
40
- setCurrentFile: (file: { data: string; type: string; name: string } | null) => void;
41
+ currentFile: ChatFile | null;
42
+ setCurrentFile: (file: ChatFile | null) => void;
41
43
 
42
44
  // Auth
43
45
  jwtToken: string | null;
@@ -61,12 +63,8 @@ interface StudioState {
61
63
  setHealthChecks: (checks: HealthCheck[]) => void;
62
64
 
63
65
  // Modal
64
- enlargeModal: {
65
- open: boolean;
66
- type: 'tool' | 'resource' | null;
67
- item: any;
68
- };
69
- openEnlargeModal: (type: 'tool' | 'resource', item: any) => void;
66
+ enlargeModal: EnlargeModalState;
67
+ openEnlargeModal: (type: 'tool' | 'resource', item: Tool | Resource) => void;
70
68
  closeEnlargeModal: () => void;
71
69
 
72
70
  // Loading states
@@ -163,7 +161,7 @@ export const useStudioStore = create<StudioState>((set) => ({
163
161
  currentToken: null,
164
162
  },
165
163
  setOAuthState: (newState) => {
166
- const updatedState = (state: any) => {
164
+ set((state) => {
167
165
  const newOAuthState = { ...state.oauthState, ...newState };
168
166
 
169
167
  // Persist to localStorage
@@ -172,8 +170,7 @@ export const useStudioStore = create<StudioState>((set) => ({
172
170
  }
173
171
 
174
172
  return { oauthState: newOAuthState };
175
- };
176
- set(updatedState);
173
+ });
177
174
  },
178
175
 
179
176
  // Ping