nitrostack 1.0.71 → 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 (253) 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 +33 -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 +9 -8
  203. package/src/studio/app/chat/page.tsx +1535 -468
  204. package/src/studio/app/chat/page.tsx.backup +1046 -187
  205. package/src/studio/app/globals.css +361 -191
  206. package/src/studio/app/health/page.tsx +73 -77
  207. package/src/studio/app/layout.tsx +9 -11
  208. package/src/studio/app/logs/page.tsx +31 -32
  209. package/src/studio/app/page.tsx +136 -232
  210. package/src/studio/app/prompts/page.tsx +115 -97
  211. package/src/studio/app/resources/page.tsx +115 -124
  212. package/src/studio/app/settings/page.tsx +1083 -127
  213. package/src/studio/app/tools/page.tsx +343 -0
  214. package/src/studio/components/EnlargeModal.tsx +76 -65
  215. package/src/studio/components/LogMessage.tsx +6 -6
  216. package/src/studio/components/MarkdownRenderer.tsx +246 -349
  217. package/src/studio/components/Sidebar.tsx +165 -210
  218. package/src/studio/components/SplashScreen.tsx +109 -0
  219. package/src/studio/components/ToolCard.tsx +50 -41
  220. package/src/studio/components/VoiceOrbOverlay.tsx +475 -0
  221. package/src/studio/components/WidgetErrorBoundary.tsx +48 -0
  222. package/src/studio/components/WidgetRenderer.tsx +169 -211
  223. package/src/studio/components/ops/OpsCanvas.tsx +748 -0
  224. package/src/studio/components/ops/OpsNodeDetailPanel.tsx +150 -0
  225. package/src/studio/components/ops/OpsSummaryBar.tsx +90 -0
  226. package/src/studio/components/ops/index.ts +5 -0
  227. package/src/studio/components/ops/nodes/BaseNode.tsx +65 -0
  228. package/src/studio/components/ops/nodes/LLMCallNode.tsx +34 -0
  229. package/src/studio/components/ops/nodes/LLMResponseNode.tsx +33 -0
  230. package/src/studio/components/ops/nodes/ToolCallNode.tsx +30 -0
  231. package/src/studio/components/ops/nodes/ToolResultNode.tsx +43 -0
  232. package/src/studio/components/ops/nodes/UserPromptNode.tsx +34 -0
  233. package/src/studio/components/ops/nodes/WidgetRenderNode.tsx +23 -0
  234. package/src/studio/components/ops/nodes/index.ts +8 -0
  235. package/src/studio/components/tools/ToolsCanvas.tsx +327 -0
  236. package/src/studio/lib/api.ts +61 -42
  237. package/src/studio/lib/http-client-transport.ts +2 -2
  238. package/src/studio/lib/llm-service.ts +126 -47
  239. package/src/studio/lib/mcp-client.ts +9 -6
  240. package/src/studio/lib/ops-store.ts +427 -0
  241. package/src/studio/lib/ops-tracker.ts +416 -0
  242. package/src/studio/lib/ops-types.ts +164 -0
  243. package/src/studio/lib/store.ts +23 -11
  244. package/src/studio/lib/types.ts +228 -38
  245. package/src/studio/lib/widget-loader.ts +2 -2
  246. package/src/studio/package-lock.json +3303 -0
  247. package/src/studio/package.json +3 -1
  248. package/src/studio/public/NitroStudio Isotype Color.png +0 -0
  249. package/src/studio/tailwind.config.ts +63 -17
  250. package/templates/typescript-oauth/src/modules/flights/flights.prompts.ts +19 -22
  251. package/dist/cli/build-widgets.mjs +0 -165
  252. package/src/studio/app/auth/page.tsx +0 -560
  253. package/src/studio/app/ping/page.tsx +0 -209
@@ -0,0 +1,343 @@
1
+ 'use client';
2
+
3
+ import { useEffect, useState } from 'react';
4
+ import { useStudioStore } from '@/lib/store';
5
+ import { api } from '@/lib/api';
6
+ import { ToolCard } from '@/components/ToolCard';
7
+ import { WidgetRenderer } from '@/components/WidgetRenderer';
8
+ import type { Tool } from '@/lib/types';
9
+ import { WrenchScrewdriverIcon, ArrowPathIcon, XMarkIcon, PlayIcon, ExclamationCircleIcon } from '@heroicons/react/24/outline';
10
+
11
+ export default function DetailedToolsPage() {
12
+ const { tools, setTools, loading, setLoading, connection, setConnection, jwtToken, apiKey, oauthState } = useStudioStore();
13
+ const [searchQuery, setSearchQuery] = useState('');
14
+ const [selectedTool, setSelectedTool] = useState<Tool | null>(null);
15
+ const [toolArgs, setToolArgs] = useState<Record<string, any>>({});
16
+ const [toolResult, setToolResult] = useState<any>(null);
17
+ const [executingTool, setExecutingTool] = useState(false);
18
+
19
+ // Get effective token - check both jwtToken and OAuth token
20
+ const effectiveToken = jwtToken || oauthState?.currentToken;
21
+
22
+ // Initialize MCP, load tools and check connection on mount
23
+ useEffect(() => {
24
+ const init = async () => {
25
+ // Connection is handled by Sidebar globally
26
+ await loadTools();
27
+ };
28
+ init();
29
+ }, []);
30
+
31
+ const loadTools = async () => {
32
+ setLoading('tools', true);
33
+ try {
34
+ const data = await api.getTools();
35
+ setTools(data.tools || []);
36
+ } catch (error) {
37
+ console.error('Failed to load tools:', error);
38
+ } finally {
39
+ setLoading('tools', false);
40
+ }
41
+ };
42
+
43
+ const handleExecuteTool = (tool: Tool) => {
44
+ setSelectedTool(tool);
45
+ setToolArgs({});
46
+ setToolResult(null);
47
+ };
48
+
49
+ const handleSubmitTool = async (e: React.FormEvent) => {
50
+ e.preventDefault();
51
+ if (!selectedTool) return;
52
+
53
+ setExecutingTool(true);
54
+ setToolResult(null);
55
+
56
+ try {
57
+ const result = await api.callTool(selectedTool.name, toolArgs, effectiveToken || undefined, apiKey || undefined);
58
+ setToolResult(result);
59
+
60
+ if (result.content) {
61
+ try {
62
+ const content = result.content[0]?.text;
63
+ if (content) {
64
+ const parsed = JSON.parse(content);
65
+ const token = parsed.token || parsed.access_token || parsed.jwt || parsed.data?.token;
66
+ if (token) {
67
+ console.log('🔐 Token received from tool, saving to global state');
68
+ useStudioStore.getState().setJwtToken(token);
69
+ }
70
+ }
71
+ } catch (e) {
72
+ // Ignore parsing errors
73
+ }
74
+ }
75
+ } catch (error) {
76
+ console.error('Tool execution failed:', error);
77
+ setToolResult({ error: 'Tool execution failed' });
78
+ } finally {
79
+ setExecutingTool(false);
80
+ }
81
+ };
82
+
83
+ const filteredTools = tools.filter((tool) =>
84
+ tool.name.toLowerCase().includes(searchQuery.toLowerCase())
85
+ );
86
+
87
+ return (
88
+ <>
89
+ <div className="fixed inset-0 flex flex-col bg-background" style={{ left: 'var(--sidebar-width, 15rem)' }}>
90
+ {/* Minimal Professional Header */}
91
+ <div className="sticky top-0 z-10 border-b border-border/50 px-6 py-4 flex items-center justify-between bg-card/50 backdrop-blur-sm">
92
+ <div className="flex items-center gap-6">
93
+ <h1 className="text-lg font-semibold text-foreground">Tools Browser</h1>
94
+ </div>
95
+
96
+ <button onClick={loadTools} className="btn btn-primary text-sm px-4 py-2 gap-2">
97
+ <ArrowPathIcon className="h-4 w-4" />
98
+ Refresh
99
+ </button>
100
+ </div>
101
+
102
+ {/* Content - ONLY this scrolls */}
103
+ <div className="flex-1 overflow-y-auto overflow-x-hidden relative">
104
+ <div className="max-w-7xl mx-auto px-6 py-6">
105
+ {/* Search */}
106
+ <div className="mb-6">
107
+ <input
108
+ type="text"
109
+ placeholder="Search tools..."
110
+ value={searchQuery}
111
+ onChange={(e) => setSearchQuery(e.target.value)}
112
+ className="input w-full"
113
+ />
114
+ </div>
115
+
116
+ {/* Tools Grid */}
117
+ {loading.tools ? (
118
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
119
+ {[1, 2, 3].map((i) => (
120
+ <div key={i} className="card skeleton h-64"></div>
121
+ ))}
122
+ </div>
123
+ ) : filteredTools.length === 0 ? (
124
+ <div className="empty-state">
125
+ <ExclamationCircleIcon className="empty-state-icon" />
126
+ <p className="empty-state-title">
127
+ {searchQuery ? 'No tools found matching your search' : 'No tools available'}
128
+ </p>
129
+ <p className="empty-state-description">
130
+ {searchQuery ? 'Try a different search term' : 'No MCP tools have been registered'}
131
+ </p>
132
+ </div>
133
+ ) : (
134
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
135
+ {filteredTools.map((tool) => (
136
+ <ToolCard key={tool.name} tool={tool} onExecute={handleExecuteTool} />
137
+ ))}
138
+ </div>
139
+ )}
140
+ </div>
141
+ </div>
142
+ </div>
143
+
144
+ {/* Tool Executor Side Drawer */}
145
+ {selectedTool && (
146
+ <div
147
+ className="fixed inset-0 z-50 flex justify-end bg-background/80 backdrop-blur-sm animate-fade-in"
148
+ onClick={() => setSelectedTool(null)}
149
+ >
150
+ <div
151
+ className="relative w-full max-w-2xl h-full bg-card border-l border-border shadow-2xl overflow-hidden animate-slide-in-right flex flex-col"
152
+ onClick={(e) => e.stopPropagation()}
153
+ >
154
+ {/* Header */}
155
+ <div className="flex items-center justify-between px-6 py-4 border-b border-border bg-card">
156
+ <div className="flex items-center gap-3">
157
+ <div className="w-10 h-10 rounded-lg bg-primary/10 flex items-center justify-center">
158
+ <WrenchScrewdriverIcon className="w-5 h-5 text-primary" />
159
+ </div>
160
+ <div>
161
+ <h2 className="text-lg font-bold text-foreground">{selectedTool.name}</h2>
162
+ <p className="text-xs text-muted-foreground">Tool Executor</p>
163
+ </div>
164
+ </div>
165
+ <button
166
+ onClick={() => setSelectedTool(null)}
167
+ className="btn btn-ghost w-8 h-8 p-0 flex items-center justify-center rounded-full hover:bg-muted"
168
+ aria-label="Close"
169
+ >
170
+ <XMarkIcon className="w-5 h-5" />
171
+ </button>
172
+ </div>
173
+
174
+ {/* Scrollable Content */}
175
+ <div className="flex-1 overflow-y-auto bg-muted/5 p-6">
176
+
177
+ <div className="bg-card p-4 rounded-xl border border-border mb-6">
178
+ <p className="text-sm text-foreground leading-relaxed">
179
+ {selectedTool.description || 'No description available'}
180
+ </p>
181
+ </div>
182
+
183
+ <form onSubmit={handleSubmitTool} className="space-y-6">
184
+ {/* Generate form inputs from schema */}
185
+ {selectedTool.inputSchema?.properties && typeof selectedTool.inputSchema.properties === 'object' && Object.keys(selectedTool.inputSchema.properties).length > 0 ? (
186
+ <div className="space-y-4">
187
+ {Object.entries(selectedTool.inputSchema.properties).map(([key, prop]: [string, any]) => {
188
+ const isRequired = selectedTool.inputSchema?.required?.includes(key);
189
+
190
+ // Handle different input types
191
+ if (prop.enum) {
192
+ return (
193
+ <div key={key}>
194
+ <label className="block text-sm font-medium text-foreground mb-2">
195
+ {prop.title || key}
196
+ {isRequired && <span className="text-destructive ml-1">*</span>}
197
+ </label>
198
+ <select
199
+ className="input w-full"
200
+ value={toolArgs[key] || prop.default || ''}
201
+ onChange={(e) => setToolArgs({ ...toolArgs, [key]: e.target.value })}
202
+ required={isRequired}
203
+ >
204
+ <option value="">Select...</option>
205
+ {prop.enum.map((val) => (
206
+ <option key={String(val)} value={String(val)}>
207
+ {String(val)}
208
+ </option>
209
+ ))}
210
+ </select>
211
+ {prop.description && (
212
+ <p className="text-xs text-muted-foreground mt-1">{prop.description}</p>
213
+ )}
214
+ </div>
215
+ );
216
+ } else if (prop.type === 'boolean') {
217
+ return (
218
+ <div key={key}>
219
+ <label className="flex items-center gap-2 cursor-pointer p-3 bg-muted/30 rounded-lg border border-border hover:bg-muted/50 transition-colors">
220
+ <input
221
+ type="checkbox"
222
+ className="checkbox checkbox-primary w-4 h-4"
223
+ checked={toolArgs[key] || false}
224
+ onChange={(e) => setToolArgs({ ...toolArgs, [key]: e.target.checked })}
225
+ />
226
+ <span className="text-sm font-medium text-foreground">
227
+ {prop.title || key}
228
+ {isRequired && <span className="text-destructive ml-1">*</span>}
229
+ </span>
230
+ </label>
231
+ {prop.description && (
232
+ <p className="text-xs text-muted-foreground mt-1 ml-1">{prop.description}</p>
233
+ )}
234
+ </div>
235
+ );
236
+ } else {
237
+ return (
238
+ <div key={key}>
239
+ <label className="block text-sm font-medium text-foreground mb-2">
240
+ {prop.title || key}
241
+ {isRequired && <span className="text-destructive ml-1">*</span>}
242
+ </label>
243
+ <input
244
+ type={prop.type === 'number' || prop.type === 'integer' ? 'number' : 'text'}
245
+ className="input w-full"
246
+ value={toolArgs[key] || prop.default || ''}
247
+ onChange={(e) => {
248
+ const value = prop.type === 'number' || prop.type === 'integer'
249
+ ? (e.target.value ? Number(e.target.value) : '')
250
+ : e.target.value;
251
+ setToolArgs({ ...toolArgs, [key]: value });
252
+ }}
253
+ required={isRequired}
254
+ placeholder={prop.description}
255
+ min={prop.minimum}
256
+ max={prop.maximum}
257
+ />
258
+ {prop.description && (
259
+ <p className="text-xs text-muted-foreground mt-1">{prop.description}</p>
260
+ )}
261
+ </div>
262
+ );
263
+ }
264
+ })}
265
+ </div>
266
+ ) : (
267
+ <div className="p-4 bg-muted/30 rounded-lg border border-border border-dashed text-center">
268
+ <p className="text-sm text-muted-foreground">No arguments required for this tool</p>
269
+ </div>
270
+ )}
271
+
272
+ <div className="sticky bottom-0 -mx-6 -mb-6 p-6 bg-card border-t border-border mt-auto">
273
+ <button
274
+ type="submit"
275
+ className="btn btn-primary w-full gap-2 py-3"
276
+ disabled={executingTool}
277
+ >
278
+ <PlayIcon className="w-4 h-4" />
279
+ {executingTool ? 'Executing...' : 'Execute Tool'}
280
+ </button>
281
+ </div>
282
+ </form>
283
+
284
+ {/* Result */}
285
+ {toolResult && (
286
+ <div className="mt-8 pt-8 border-t border-border animate-fade-in">
287
+ <div className="space-y-6">
288
+ <div>
289
+ <div className="flex items-center justify-between mb-3">
290
+ <h3 className="font-semibold text-foreground">Result Output</h3>
291
+ <div className="badge badge-success text-xs">Success</div>
292
+ </div>
293
+ <div className="bg-muted/30 rounded-xl border border-border overflow-hidden">
294
+ <pre className="p-4 text-xs font-mono text-foreground overflow-auto max-h-96">
295
+ {JSON.stringify(toolResult, null, 2)}
296
+ </pre>
297
+ </div>
298
+ </div>
299
+
300
+ {/* Widget UI Rendering */}
301
+ {(() => {
302
+ const widgetUri =
303
+ selectedTool.widget?.route ||
304
+ selectedTool.outputTemplate ||
305
+ selectedTool._meta?.['ui/template'] ||
306
+ selectedTool._meta?.['openai/outputTemplate'];
307
+
308
+ return widgetUri && toolResult ? (
309
+ <div>
310
+ <h3 className="font-semibold text-foreground mb-3 text-sm uppercase tracking-wider">Preview Component</h3>
311
+ <div className="border border-border rounded-xl overflow-hidden bg-background shadow-sm transition-all duration-200">
312
+ <WidgetRenderer
313
+ uri={widgetUri}
314
+ data={(() => {
315
+ if (toolResult.content?.[0]?.text) {
316
+ try {
317
+ const parsed = JSON.parse(toolResult.content[0].text);
318
+ if (parsed.success !== undefined && parsed.data !== undefined) {
319
+ return parsed.data;
320
+ }
321
+ return parsed;
322
+ } catch {
323
+ return { message: toolResult.content[0].text };
324
+ }
325
+ }
326
+ return toolResult;
327
+ })()}
328
+ className="w-full widget-in-chat widget-expanded"
329
+ />
330
+ </div>
331
+ </div>
332
+ ) : null;
333
+ })()}
334
+ </div>
335
+ </div>
336
+ )}
337
+ </div>
338
+ </div>
339
+ </div>
340
+ )}
341
+ </>
342
+ );
343
+ }
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { useStudioStore } from '@/lib/store';
4
4
  import { WidgetRenderer } from './WidgetRenderer';
5
- import { X, MessageSquare } from 'lucide-react';
5
+ import { XMarkIcon, ChatBubbleLeftIcon } from '@heroicons/react/24/outline';
6
6
  import { useRouter } from 'next/navigation';
7
7
 
8
8
  export function EnlargeModal() {
@@ -12,7 +12,7 @@ export function EnlargeModal() {
12
12
  if (!enlargeModal.open || !enlargeModal.item) return null;
13
13
 
14
14
  const { type, item } = enlargeModal;
15
-
15
+
16
16
  // Get widget URI
17
17
  const componentUri =
18
18
  type === 'tool'
@@ -20,12 +20,12 @@ export function EnlargeModal() {
20
20
  : item.uri;
21
21
 
22
22
  // Get data from item's examples or responseData - check both examples and _meta
23
- const widgetData =
24
- item.examples?.response ||
25
- item._meta?.['tool/examples']?.response ||
26
- item.responseData ||
23
+ const widgetData =
24
+ item.examples?.response ||
25
+ item._meta?.['tool/examples']?.response ||
26
+ item.responseData ||
27
27
  {};
28
-
28
+
29
29
  // Debug logging
30
30
  console.log('EnlargeModal - Widget info:', {
31
31
  type,
@@ -40,96 +40,107 @@ export function EnlargeModal() {
40
40
 
41
41
  const handleUseInChat = () => {
42
42
  if (type !== 'tool') return;
43
-
43
+
44
44
  closeEnlargeModal();
45
-
45
+
46
46
  // Build the tool execution message
47
47
  const toolMessage = `Use the ${item.name} tool`;
48
-
48
+
49
49
  // Store both the tool name and the message
50
50
  if (typeof window !== 'undefined') {
51
51
  window.localStorage.setItem('suggestedTool', item.name);
52
52
  window.localStorage.setItem('chatInput', toolMessage);
53
53
  }
54
-
54
+
55
55
  setCurrentTab('chat');
56
56
  router.push('/chat');
57
57
  };
58
58
 
59
59
  return (
60
60
  <div
61
- className="fixed inset-0 z-50 flex items-center justify-center animate-fade-in"
62
- style={{ backgroundColor: 'rgba(0, 0, 0, 0.85)' }}
61
+ className="fixed inset-0 z-50 flex justify-end bg-background/80 backdrop-blur-sm animate-fade-in"
63
62
  onClick={closeEnlargeModal}
64
63
  >
65
64
  <div
66
- className="relative w-[95vw] max-w-7xl h-[90vh] bg-card border border-border rounded-xl sm:rounded-2xl shadow-2xl overflow-hidden animate-scale-in"
65
+ className="relative w-full max-w-2xl h-full bg-card border-l border-border shadow-2xl overflow-hidden animate-slide-in-right flex flex-col"
67
66
  onClick={(e) => e.stopPropagation()}
68
67
  >
69
68
  {/* Header */}
70
- <div className="flex flex-col sm:flex-row items-start sm:items-center justify-between p-4 sm:p-6 border-b border-border bg-muted/30 gap-3 sm:gap-0">
71
- <div className="flex items-start sm:items-center gap-3 sm:gap-4 flex-1 min-w-0">
72
- <span className="text-2xl sm:text-3xl flex-shrink-0">{type === 'tool' ? '⚡' : '🎨'}</span>
73
- <div className="min-w-0 flex-1">
74
- <h2 className="text-lg sm:text-xl font-bold text-foreground truncate">{item.name}</h2>
75
- <p className="text-xs sm:text-sm text-muted-foreground mt-1 line-clamp-2">
76
- {item.description || 'No description available'}
69
+ <div className="flex items-center justify-between px-6 py-4 border-b border-border bg-card">
70
+ <div className="flex items-center gap-3">
71
+ <div className="w-10 h-10 rounded-lg bg-primary/10 flex items-center justify-center">
72
+ <span className="text-xl">{type === 'tool' ? '⚡' : '🎨'}</span>
73
+ </div>
74
+ <div>
75
+ <h2 className="text-lg font-semibold text-foreground truncate max-w-[300px]">{item.name}</h2>
76
+ <p className="text-xs text-muted-foreground">
77
+ {type === 'tool' ? 'Tool Details' : 'Component Preview'}
77
78
  </p>
78
79
  </div>
79
80
  </div>
80
81
 
81
- <div className="flex items-center gap-2 w-full sm:w-auto">
82
- {type === 'tool' && (
83
- <button
84
- onClick={handleUseInChat}
85
- className="btn btn-primary flex items-center gap-2 flex-1 sm:flex-none text-sm"
86
- >
87
- <MessageSquare className="w-4 h-4" />
88
- <span className="hidden sm:inline">Use in Chat</span>
89
- <span className="sm:hidden">Chat</span>
90
- </button>
91
- )}
92
- <button
93
- onClick={closeEnlargeModal}
94
- className="btn btn-ghost w-10 h-10 p-0 flex items-center justify-center flex-shrink-0"
95
- aria-label="Close"
96
- >
97
- <X className="w-5 h-5" />
98
- </button>
99
- </div>
82
+ <button
83
+ onClick={closeEnlargeModal}
84
+ className="btn btn-ghost w-8 h-8 p-0 flex items-center justify-center rounded-full hover:bg-muted"
85
+ aria-label="Close"
86
+ >
87
+ <XMarkIcon className="w-5 h-5" />
88
+ </button>
100
89
  </div>
101
90
 
102
- {/* Widget Content */}
103
- <div className="h-[calc(100%-120px)] sm:h-[calc(100%-100px)] p-3 sm:p-6 overflow-auto bg-background">
104
- {componentUri && widgetData ? (
105
- <div className="w-full h-full rounded-xl overflow-hidden border border-border shadow-inner">
106
- <WidgetRenderer uri={componentUri} data={widgetData} className="w-full h-full" />
91
+ {/* Content */}
92
+ <div className="flex-1 overflow-y-auto bg-muted/5 p-6">
93
+ <div className="space-y-6">
94
+ {/* Description */}
95
+ <div className="bg-card p-4 rounded-xl border border-border">
96
+ <p className="text-sm text-foreground leading-relaxed">
97
+ {item.description || 'No description available'}
98
+ </p>
107
99
  </div>
108
- ) : (
109
- <div className="flex items-center justify-center h-full">
110
- <div className="text-center">
111
- <p className="text-muted-foreground mb-2">
112
- {!componentUri ? 'No widget URI available' : 'No example data available'}
100
+
101
+ {/* Preview/Widget */}
102
+ {componentUri && widgetData ? (
103
+ <div className="space-y-2">
104
+ <h3 className="text-xs font-medium text-muted-foreground uppercase tracking-wider">Preview</h3>
105
+ <div className="w-full rounded-xl overflow-hidden border border-border bg-background shadow-sm transition-all duration-200">
106
+ <WidgetRenderer uri={componentUri} data={widgetData} className="w-full widget-in-chat widget-expanded" />
107
+ </div>
108
+ </div>
109
+ ) : (
110
+ <div className="bg-muted/20 p-8 rounded-xl border border-border border-dashed text-center">
111
+ <p className="text-sm text-muted-foreground mb-1">
112
+ {!componentUri ? 'No visual widget available' : 'No preview data'}
113
113
  </p>
114
- <p className="text-xs text-muted-foreground">
115
- {type === 'tool' ? 'This tool does not have a UI widget attached' : 'No preview data found'}
114
+ <p className="text-xs text-muted-foreground/70">
115
+ {type === 'tool' ? 'This tool operates without a UI component' : 'Preview data is missing'}
116
116
  </p>
117
117
  </div>
118
- </div>
119
- )}
118
+ )}
119
+
120
+ {/* Input Schema */}
121
+ {type === 'tool' && item.inputSchema && (
122
+ <div className="space-y-2">
123
+ <h3 className="text-xs font-medium text-muted-foreground uppercase tracking-wider">Input Schema</h3>
124
+ <div className="bg-muted/30 rounded-xl border border-border overflow-hidden">
125
+ <pre className="p-4 text-xs font-mono text-foreground overflow-x-auto bg-transparent">
126
+ {JSON.stringify(item.inputSchema, null, 2)}
127
+ </pre>
128
+ </div>
129
+ </div>
130
+ )}
131
+ </div>
120
132
  </div>
121
133
 
122
- {/* Metadata Footer */}
123
- {type === 'tool' && item.inputSchema && (
124
- <div className="absolute bottom-0 left-0 right-0 p-4 border-t border-border glass">
125
- <details className="text-sm">
126
- <summary className="cursor-pointer text-muted-foreground hover:text-foreground font-medium">
127
- Input Schema
128
- </summary>
129
- <pre className="mt-2 p-3 bg-muted rounded-lg text-xs text-foreground overflow-auto max-h-40 font-mono">
130
- {JSON.stringify(item.inputSchema, null, 2)}
131
- </pre>
132
- </details>
134
+ {/* Footer Actions */}
135
+ {type === 'tool' && (
136
+ <div className="p-4 border-t border-border bg-card">
137
+ <button
138
+ onClick={handleUseInChat}
139
+ className="btn btn-primary w-full flex items-center justify-center gap-2 py-3 text-sm font-medium"
140
+ >
141
+ <ChatBubbleLeftIcon className="w-4 h-4" />
142
+ Use in Chat
143
+ </button>
133
144
  </div>
134
145
  )}
135
146
  </div>
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import { useState } from 'react';
4
- import { Copy, Check, ChevronDown, ChevronRight } from 'lucide-react';
4
+ import { ClipboardDocumentIcon, CheckIcon, ChevronDownIcon, ChevronRightIcon } from '@heroicons/react/24/outline';
5
5
 
6
6
  interface LogMessageProps {
7
7
  message: string;
@@ -22,7 +22,7 @@ export function LogMessage({ message }: LogMessageProps) {
22
22
  };
23
23
 
24
24
  // Try to parse and format JSON
25
- const tryParseJSON = (text: string): { isJSON: boolean; formatted?: string; parsed?: any } => {
25
+ const tryParseJSON = (text: string): { isJSON: boolean; formatted?: string; parsed?: unknown } => {
26
26
  try {
27
27
  const trimmed = text.trim();
28
28
  if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) {
@@ -81,9 +81,9 @@ export function LogMessage({ message }: LogMessageProps) {
81
81
  className="text-slate-400 hover:text-slate-200 transition-colors"
82
82
  >
83
83
  {isExpanded ? (
84
- <ChevronDown className="w-4 h-4" />
84
+ <ChevronDownIcon className="w-4 h-4" />
85
85
  ) : (
86
- <ChevronRight className="w-4 h-4" />
86
+ <ChevronRightIcon className="w-4 h-4" />
87
87
  )}
88
88
  </button>
89
89
  <span className="text-slate-500 text-xs font-semibold">JSON Response</span>
@@ -93,9 +93,9 @@ export function LogMessage({ message }: LogMessageProps) {
93
93
  title={copied ? 'Copied!' : 'Copy JSON'}
94
94
  >
95
95
  {copied ? (
96
- <Check className="w-3.5 h-3.5 text-green-400" />
96
+ <CheckIcon className="w-3.5 h-3.5 text-green-400" />
97
97
  ) : (
98
- <Copy className="w-3.5 h-3.5" />
98
+ <ClipboardDocumentIcon className="w-3.5 h-3.5" />
99
99
  )}
100
100
  </button>
101
101
  </div>