nitrostack 1.0.55 → 1.0.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +14 -9
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/widgets/hooks/index.d.ts +7 -0
- package/dist/widgets/hooks/index.d.ts.map +1 -0
- package/dist/widgets/hooks/index.js +7 -0
- package/dist/widgets/hooks/index.js.map +1 -0
- package/dist/widgets/hooks/use-display-mode.d.ts +11 -0
- package/dist/widgets/hooks/use-display-mode.d.ts.map +1 -0
- package/dist/widgets/hooks/use-display-mode.js +13 -0
- package/dist/widgets/hooks/use-display-mode.js.map +1 -0
- package/dist/widgets/hooks/use-max-height.d.ts +10 -0
- package/dist/widgets/hooks/use-max-height.d.ts.map +1 -0
- package/dist/widgets/hooks/use-max-height.js +13 -0
- package/dist/widgets/hooks/use-max-height.js.map +1 -0
- package/dist/widgets/hooks/use-openai-global.d.ts +12 -0
- package/dist/widgets/hooks/use-openai-global.d.ts.map +1 -0
- package/dist/widgets/hooks/use-openai-global.js +32 -0
- package/dist/widgets/hooks/use-openai-global.js.map +1 -0
- package/dist/widgets/hooks/use-theme.d.ts +10 -0
- package/dist/widgets/hooks/use-theme.d.ts.map +1 -0
- package/dist/widgets/hooks/use-theme.js +12 -0
- package/dist/widgets/hooks/use-theme.js.map +1 -0
- package/dist/widgets/hooks/use-widget-state.d.ts +18 -0
- package/dist/widgets/hooks/use-widget-state.d.ts.map +1 -0
- package/dist/widgets/hooks/use-widget-state.js +27 -0
- package/dist/widgets/hooks/use-widget-state.js.map +1 -0
- package/dist/widgets/hooks/useWidgetSDK.d.ts +47 -0
- package/dist/widgets/hooks/useWidgetSDK.d.ts.map +1 -0
- package/dist/widgets/hooks/useWidgetSDK.js +67 -0
- package/dist/widgets/hooks/useWidgetSDK.js.map +1 -0
- package/dist/widgets/index.d.ts +7 -1
- package/dist/widgets/index.d.ts.map +1 -1
- package/dist/widgets/index.js +11 -1
- package/dist/widgets/index.js.map +1 -1
- package/dist/widgets/runtime/WidgetLayout.d.ts +32 -0
- package/dist/widgets/runtime/WidgetLayout.d.ts.map +1 -0
- package/dist/widgets/runtime/WidgetLayout.js +143 -0
- package/dist/widgets/runtime/WidgetLayout.js.map +1 -0
- package/dist/widgets/runtime/widget-polyfill.d.ts +1 -0
- package/dist/widgets/runtime/widget-polyfill.d.ts.map +1 -0
- package/dist/widgets/runtime/widget-polyfill.js +28 -0
- package/dist/widgets/runtime/widget-polyfill.js.map +1 -0
- package/dist/widgets/sdk.d.ts +109 -0
- package/dist/widgets/sdk.d.ts.map +1 -0
- package/dist/widgets/sdk.js +221 -0
- package/dist/widgets/sdk.js.map +1 -0
- package/dist/widgets/types.d.ts +89 -0
- package/dist/widgets/types.d.ts.map +1 -0
- package/dist/widgets/types.js +8 -0
- package/dist/widgets/types.js.map +1 -0
- package/dist/widgets/utils/media-queries.d.ts +34 -0
- package/dist/widgets/utils/media-queries.d.ts.map +1 -0
- package/dist/widgets/utils/media-queries.js +42 -0
- package/dist/widgets/utils/media-queries.js.map +1 -0
- package/package.json +2 -2
- package/src/studio/app/chat/page.tsx +274 -137
- package/src/studio/app/globals.css +140 -64
- package/src/studio/branding.md +807 -0
- package/src/studio/components/WidgetRenderer.tsx +222 -16
- package/src/studio/lib/llm-service.ts +39 -39
- package/templates/typescript-oauth/{env.example → .env.example} +4 -10
- package/templates/typescript-oauth/README.md +226 -306
- package/templates/typescript-oauth/package-lock.json +4253 -0
- package/templates/typescript-oauth/package.json +10 -5
- package/templates/typescript-oauth/src/app.module.ts +39 -36
- package/templates/typescript-oauth/src/guards/oauth.guard.ts +0 -1
- package/templates/typescript-oauth/src/index.ts +22 -30
- package/templates/typescript-oauth/src/modules/flights/booking.tools.ts +323 -0
- package/templates/typescript-oauth/src/modules/flights/flights.module.ts +14 -0
- package/templates/typescript-oauth/src/modules/flights/flights.prompts.ts +231 -0
- package/templates/typescript-oauth/src/modules/flights/flights.resources.ts +215 -0
- package/templates/typescript-oauth/src/modules/flights/flights.tools.ts +457 -0
- package/templates/typescript-oauth/src/services/duffel.service.ts +285 -0
- package/templates/typescript-oauth/src/widgets/app/airport-search/page.tsx +270 -0
- package/templates/typescript-oauth/src/widgets/app/flight-details/page.tsx +261 -0
- package/templates/typescript-oauth/src/widgets/app/flight-search-results/page.tsx +378 -0
- package/templates/typescript-oauth/src/widgets/app/globals.css +167 -0
- package/templates/typescript-oauth/src/widgets/app/layout.tsx +6 -2
- package/templates/typescript-oauth/src/widgets/app/order-cancellation/page.tsx +207 -0
- package/templates/typescript-oauth/src/widgets/app/order-summary/page.tsx +245 -0
- package/templates/typescript-oauth/src/widgets/app/payment-confirmation/page.tsx +152 -0
- package/templates/typescript-oauth/src/widgets/app/seat-selection/page.tsx +486 -0
- package/templates/typescript-oauth/src/widgets/next-env.d.ts +5 -0
- package/templates/typescript-oauth/src/widgets/package-lock.json +155 -126
- package/templates/typescript-oauth/src/widgets/widget-manifest.json +374 -27
- package/templates/typescript-pizzaz/IMPLEMENTATION.md +98 -0
- package/templates/typescript-pizzaz/README.md +233 -0
- package/templates/typescript-pizzaz/package.json +31 -0
- package/templates/typescript-pizzaz/src/app.module.ts +28 -0
- package/templates/typescript-pizzaz/src/index.ts +30 -0
- package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.data.ts +106 -0
- package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.module.ts +11 -0
- package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.service.ts +60 -0
- package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.tools.ts +197 -0
- package/templates/typescript-pizzaz/src/widgets/app/layout.tsx +18 -0
- package/templates/typescript-pizzaz/src/widgets/app/pizza-list/page.tsx +272 -0
- package/templates/typescript-pizzaz/src/widgets/app/pizza-map/page.tsx +216 -0
- package/templates/typescript-pizzaz/src/widgets/app/pizza-shop/page.tsx +374 -0
- package/templates/typescript-pizzaz/src/widgets/components/CompactShopCard.tsx +144 -0
- package/templates/typescript-pizzaz/src/widgets/components/PizzaCard.tsx +191 -0
- package/templates/typescript-pizzaz/src/widgets/package.json +30 -0
- package/templates/typescript-pizzaz/src/widgets/widget-manifest.json +253 -0
- package/templates/typescript-pizzaz/tsconfig.json +30 -0
- package/templates/typescript-starter/src/modules/calculator/calculator.resources.ts +0 -1
- package/templates/typescript-starter/src/widgets/app/calculator-result/page.tsx +102 -56
- package/templates/typescript-starter/src/widgets/app/layout.tsx +6 -2
- package/templates/typescript-auth/AI_AGENT_CLI_REFERENCE.md +0 -702
- package/templates/typescript-auth/AI_AGENT_SDK_REFERENCE.md +0 -1260
- package/templates/typescript-auth/README.md +0 -402
- package/templates/typescript-auth/env.example +0 -25
- package/templates/typescript-auth/package.json +0 -36
- package/templates/typescript-auth/src/app.module.ts +0 -103
- package/templates/typescript-auth/src/db/database.ts +0 -160
- package/templates/typescript-auth/src/db/seed.ts +0 -374
- package/templates/typescript-auth/src/db/setup.ts +0 -87
- package/templates/typescript-auth/src/events/analytics.service.ts +0 -52
- package/templates/typescript-auth/src/events/notification.service.ts +0 -40
- package/templates/typescript-auth/src/filters/global-exception.filter.ts +0 -28
- package/templates/typescript-auth/src/guards/README.md +0 -75
- package/templates/typescript-auth/src/guards/jwt.guard.ts +0 -105
- package/templates/typescript-auth/src/health/database.health.ts +0 -41
- package/templates/typescript-auth/src/index.ts +0 -29
- package/templates/typescript-auth/src/interceptors/transform.interceptor.ts +0 -24
- package/templates/typescript-auth/src/middleware/logging.middleware.ts +0 -42
- package/templates/typescript-auth/src/modules/addresses/addresses.module.ts +0 -16
- package/templates/typescript-auth/src/modules/addresses/addresses.prompts.ts +0 -114
- package/templates/typescript-auth/src/modules/addresses/addresses.resources.ts +0 -40
- package/templates/typescript-auth/src/modules/addresses/addresses.tools.ts +0 -284
- package/templates/typescript-auth/src/modules/auth/auth.module.ts +0 -16
- package/templates/typescript-auth/src/modules/auth/auth.prompts.ts +0 -147
- package/templates/typescript-auth/src/modules/auth/auth.resources.ts +0 -84
- package/templates/typescript-auth/src/modules/auth/auth.tools.ts +0 -139
- package/templates/typescript-auth/src/modules/cart/cart.module.ts +0 -16
- package/templates/typescript-auth/src/modules/cart/cart.prompts.ts +0 -95
- package/templates/typescript-auth/src/modules/cart/cart.resources.ts +0 -44
- package/templates/typescript-auth/src/modules/cart/cart.tools.ts +0 -277
- package/templates/typescript-auth/src/modules/orders/orders.module.ts +0 -16
- package/templates/typescript-auth/src/modules/orders/orders.prompts.ts +0 -88
- package/templates/typescript-auth/src/modules/orders/orders.resources.ts +0 -48
- package/templates/typescript-auth/src/modules/orders/orders.tools.ts +0 -303
- package/templates/typescript-auth/src/modules/products/products.module.ts +0 -16
- package/templates/typescript-auth/src/modules/products/products.prompts.ts +0 -146
- package/templates/typescript-auth/src/modules/products/products.resources.ts +0 -98
- package/templates/typescript-auth/src/modules/products/products.tools.ts +0 -266
- package/templates/typescript-auth/src/pipes/validation.pipe.ts +0 -42
- package/templates/typescript-auth/src/services/database.service.ts +0 -90
- package/templates/typescript-auth/src/widgets/app/add-to-cart/page.tsx +0 -122
- package/templates/typescript-auth/src/widgets/app/address-added/page.tsx +0 -116
- package/templates/typescript-auth/src/widgets/app/address-deleted/page.tsx +0 -105
- package/templates/typescript-auth/src/widgets/app/address-list/page.tsx +0 -139
- package/templates/typescript-auth/src/widgets/app/address-updated/page.tsx +0 -153
- package/templates/typescript-auth/src/widgets/app/cart-cleared/page.tsx +0 -86
- package/templates/typescript-auth/src/widgets/app/cart-updated/page.tsx +0 -116
- package/templates/typescript-auth/src/widgets/app/categories/page.tsx +0 -134
- package/templates/typescript-auth/src/widgets/app/layout.tsx +0 -21
- package/templates/typescript-auth/src/widgets/app/login-result/page.tsx +0 -129
- package/templates/typescript-auth/src/widgets/app/order-confirmation/page.tsx +0 -231
- package/templates/typescript-auth/src/widgets/app/order-details/page.tsx +0 -225
- package/templates/typescript-auth/src/widgets/app/order-history/page.tsx +0 -218
- package/templates/typescript-auth/src/widgets/app/product-card/page.tsx +0 -121
- package/templates/typescript-auth/src/widgets/app/products-grid/page.tsx +0 -198
- package/templates/typescript-auth/src/widgets/app/shopping-cart/page.tsx +0 -187
- package/templates/typescript-auth/src/widgets/app/whoami/page.tsx +0 -165
- package/templates/typescript-auth/src/widgets/next.config.js +0 -38
- package/templates/typescript-auth/src/widgets/package.json +0 -18
- package/templates/typescript-auth/src/widgets/styles/ecommerce.ts +0 -169
- package/templates/typescript-auth/src/widgets/tsconfig.json +0 -28
- package/templates/typescript-auth/src/widgets/types/tool-data.ts +0 -141
- package/templates/typescript-auth/src/widgets/widget-manifest.json +0 -464
- package/templates/typescript-auth/tsconfig.json +0 -27
- package/templates/typescript-auth-api-key/AI_AGENT_CLI_REFERENCE.md +0 -701
- package/templates/typescript-auth-api-key/AI_AGENT_SDK_REFERENCE.md +0 -1260
- package/templates/typescript-auth-api-key/README.md +0 -485
- package/templates/typescript-auth-api-key/env.example +0 -17
- package/templates/typescript-auth-api-key/package.json +0 -21
- package/templates/typescript-auth-api-key/src/app.module.ts +0 -38
- package/templates/typescript-auth-api-key/src/guards/apikey.guard.ts +0 -47
- package/templates/typescript-auth-api-key/src/guards/multi-auth.guard.ts +0 -157
- package/templates/typescript-auth-api-key/src/index.ts +0 -47
- package/templates/typescript-auth-api-key/src/modules/calculator/calculator.module.ts +0 -12
- package/templates/typescript-auth-api-key/src/modules/calculator/calculator.prompts.ts +0 -73
- package/templates/typescript-auth-api-key/src/modules/calculator/calculator.resources.ts +0 -60
- package/templates/typescript-auth-api-key/src/modules/calculator/calculator.tools.ts +0 -71
- package/templates/typescript-auth-api-key/src/modules/demo/demo.module.ts +0 -18
- package/templates/typescript-auth-api-key/src/modules/demo/demo.tools.ts +0 -155
- package/templates/typescript-auth-api-key/src/modules/demo/multi-auth.tools.ts +0 -123
- package/templates/typescript-auth-api-key/src/widgets/app/calculator-operations/page.tsx +0 -133
- package/templates/typescript-auth-api-key/src/widgets/app/calculator-result/page.tsx +0 -134
- package/templates/typescript-auth-api-key/src/widgets/app/layout.tsx +0 -14
- package/templates/typescript-auth-api-key/src/widgets/package.json +0 -24
- package/templates/typescript-auth-api-key/src/widgets/widget-manifest.json +0 -48
- package/templates/typescript-auth-api-key/tsconfig.json +0 -23
- package/templates/typescript-oauth/OAUTH_SETUP.md +0 -592
- package/templates/typescript-oauth/src/modules/demo/demo.module.ts +0 -16
- package/templates/typescript-oauth/src/modules/demo/demo.tools.ts +0 -190
- package/templates/typescript-oauth/src/widgets/app/calculator-operations/page.tsx +0 -133
- package/templates/typescript-oauth/src/widgets/app/calculator-result/page.tsx +0 -134
- package/templates/typescript-oauth/src/widgets/out/404.html +0 -1
- package/templates/typescript-oauth/src/widgets/out/_next/static/WU9THacVqL52RZbrZOLS1/_buildManifest.js +0 -1
- package/templates/typescript-oauth/src/widgets/out/_next/static/WU9THacVqL52RZbrZOLS1/_ssgManifest.js +0 -1
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/117-eb57c7ef86f964a4.js +0 -2
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/app/_not-found/page-dcb83ba3e4d0aafd.js +0 -1
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/app/calculator-operations/page-b8913a740073ea8a.js +0 -1
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/app/calculator-result/page-ddaaab2fce95dea2.js +0 -1
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/app/layout-cbd3ebdc4ecc5247.js +0 -1
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/fd9d1056-749e5812300142af.js +0 -1
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/framework-f66176bb897dc684.js +0 -1
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/main-76df43fcef3db344.js +0 -1
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/main-app-f9c40224d04023c5.js +0 -1
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/pages/_app-72b849fbd24ac258.js +0 -1
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/pages/_error-7ba65e1336b92748.js +0 -1
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/polyfills-42372ed130431b0a.js +0 -1
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/webpack-100b9e646d9c912e.js +0 -1
- package/templates/typescript-oauth/src/widgets/out/calculator-operations.html +0 -1
- package/templates/typescript-oauth/src/widgets/out/calculator-operations.txt +0 -7
- package/templates/typescript-oauth/src/widgets/out/calculator-result.html +0 -1
- package/templates/typescript-oauth/src/widgets/out/calculator-result.txt +0 -7
- package/templates/typescript-starter/src/widgets/app/calculator-operations/page.tsx +0 -133
- /package/templates/{typescript-auth-api-key → typescript-oauth}/src/health/system.health.ts +0 -0
- /package/templates/{typescript-auth-api-key → typescript-pizzaz}/src/widgets/next.config.js +0 -0
- /package/templates/{typescript-auth-api-key → typescript-pizzaz}/src/widgets/tsconfig.json +0 -0
|
@@ -6,20 +6,21 @@ import { api } from '@/lib/api';
|
|
|
6
6
|
import { WidgetRenderer } from '@/components/WidgetRenderer';
|
|
7
7
|
import { MarkdownRenderer } from '@/components/MarkdownRenderer';
|
|
8
8
|
import type { ChatMessage, Tool, ToolCall, Prompt } from '@/lib/types';
|
|
9
|
-
import {
|
|
10
|
-
Bot,
|
|
11
|
-
Settings,
|
|
12
|
-
Trash2,
|
|
13
|
-
Image as ImageIcon,
|
|
14
|
-
Send,
|
|
15
|
-
Wrench,
|
|
9
|
+
import {
|
|
10
|
+
Bot,
|
|
11
|
+
Settings,
|
|
12
|
+
Trash2,
|
|
13
|
+
Image as ImageIcon,
|
|
14
|
+
Send,
|
|
15
|
+
Wrench,
|
|
16
16
|
Save,
|
|
17
17
|
X,
|
|
18
18
|
Sparkles,
|
|
19
19
|
FileText,
|
|
20
20
|
Play,
|
|
21
21
|
ExternalLink,
|
|
22
|
-
Info
|
|
22
|
+
Info,
|
|
23
|
+
MoreVertical
|
|
23
24
|
} from 'lucide-react';
|
|
24
25
|
|
|
25
26
|
export default function ChatPage() {
|
|
@@ -34,7 +35,7 @@ export default function ChatPage() {
|
|
|
34
35
|
tools,
|
|
35
36
|
setTools,
|
|
36
37
|
} = useStudioStore();
|
|
37
|
-
|
|
38
|
+
|
|
38
39
|
// Get jwtToken and apiKey dynamically to ensure we always have the latest value
|
|
39
40
|
const getAuthTokens = () => {
|
|
40
41
|
const state = useStudioStore.getState();
|
|
@@ -52,6 +53,7 @@ export default function ChatPage() {
|
|
|
52
53
|
const [prompts, setPrompts] = useState<Prompt[]>([]);
|
|
53
54
|
const [selectedPrompt, setSelectedPrompt] = useState<Prompt | null>(null);
|
|
54
55
|
const [promptArgs, setPromptArgs] = useState<Record<string, string>>({});
|
|
56
|
+
const [fullscreenWidget, setFullscreenWidget] = useState<{ uri: string, data: any } | null>(null);
|
|
55
57
|
const messagesEndRef = useRef<HTMLDivElement>(null);
|
|
56
58
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
57
59
|
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
|
@@ -59,7 +61,7 @@ export default function ChatPage() {
|
|
|
59
61
|
useEffect(() => {
|
|
60
62
|
loadTools();
|
|
61
63
|
loadPrompts();
|
|
62
|
-
|
|
64
|
+
|
|
63
65
|
// Check if there's a suggested message from localStorage
|
|
64
66
|
if (typeof window !== 'undefined') {
|
|
65
67
|
const chatInput = window.localStorage.getItem('chatInput');
|
|
@@ -91,6 +93,120 @@ export default function ChatPage() {
|
|
|
91
93
|
}
|
|
92
94
|
}, [inputValue]);
|
|
93
95
|
|
|
96
|
+
// Listen for widget fullscreen requests
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
const handleFullscreenRequest = (event: CustomEvent) => {
|
|
99
|
+
const { uri, data } = event.detail;
|
|
100
|
+
setFullscreenWidget({ uri, data });
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
window.addEventListener('widget-fullscreen-request', handleFullscreenRequest as EventListener);
|
|
104
|
+
return () => window.removeEventListener('widget-fullscreen-request', handleFullscreenRequest as EventListener);
|
|
105
|
+
}, []);
|
|
106
|
+
|
|
107
|
+
// Listen for widget tool call requests
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
let isProcessingToolCall = false;
|
|
110
|
+
|
|
111
|
+
const handleToolCall = async (event: any) => {
|
|
112
|
+
// Prevent multiple simultaneous calls
|
|
113
|
+
if (isProcessingToolCall) {
|
|
114
|
+
console.log('⏭️ Skipping duplicate tool call');
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const { toolName, toolArgs } = event.detail;
|
|
119
|
+
console.log('📞 Chat received tool call from widget:', toolName, toolArgs);
|
|
120
|
+
|
|
121
|
+
isProcessingToolCall = true;
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
// Get current state directly from store to avoid stale closure
|
|
125
|
+
const currentMessages = useStudioStore.getState().chatMessages;
|
|
126
|
+
const currentProv = useStudioStore.getState().currentProvider;
|
|
127
|
+
|
|
128
|
+
// Directly send the tool call message without showing in input
|
|
129
|
+
const toolCallMessage = `Use the ${toolName} tool with these arguments: ${JSON.stringify(toolArgs)}`;
|
|
130
|
+
|
|
131
|
+
// Add user message
|
|
132
|
+
const userMessage: ChatMessage = {
|
|
133
|
+
role: 'user',
|
|
134
|
+
content: toolCallMessage,
|
|
135
|
+
};
|
|
136
|
+
addChatMessage(userMessage);
|
|
137
|
+
|
|
138
|
+
// Call LLM
|
|
139
|
+
setLoading(true);
|
|
140
|
+
try {
|
|
141
|
+
const { jwtToken, mcpApiKey } = getAuthTokens();
|
|
142
|
+
const apiKey = localStorage.getItem(`${currentProv}_api_key`);
|
|
143
|
+
const response = await api.chat({
|
|
144
|
+
provider: currentProv,
|
|
145
|
+
messages: [...currentMessages, userMessage],
|
|
146
|
+
apiKey: apiKey || '',
|
|
147
|
+
jwtToken: jwtToken || undefined,
|
|
148
|
+
mcpApiKey: mcpApiKey || undefined,
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Handle tool calls (same as handleSend)
|
|
152
|
+
if (response.toolCalls && response.toolResults) {
|
|
153
|
+
// Attach results to tool calls for widget rendering
|
|
154
|
+
const toolCallsWithResults = response.toolCalls.map((tc: any, i: any) => {
|
|
155
|
+
const toolResult = response.toolResults[i];
|
|
156
|
+
let parsedResult;
|
|
157
|
+
if (toolResult.content) {
|
|
158
|
+
try {
|
|
159
|
+
parsedResult = JSON.parse(toolResult.content);
|
|
160
|
+
} catch (e) {
|
|
161
|
+
parsedResult = { raw: toolResult.content };
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return { ...tc, result: parsedResult };
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
if (response.message) {
|
|
168
|
+
response.message.toolCalls = toolCallsWithResults;
|
|
169
|
+
addChatMessage(response.message);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Add tool results
|
|
173
|
+
const toolResultMessages: ChatMessage[] = [];
|
|
174
|
+
for (const result of response.toolResults) {
|
|
175
|
+
addChatMessage(result);
|
|
176
|
+
toolResultMessages.push(result);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Continue conversation
|
|
180
|
+
const messagesForContinuation = [
|
|
181
|
+
...currentMessages,
|
|
182
|
+
userMessage,
|
|
183
|
+
response.message!,
|
|
184
|
+
...toolResultMessages,
|
|
185
|
+
];
|
|
186
|
+
|
|
187
|
+
// Call continueChatWithToolResults
|
|
188
|
+
await continueChatWithToolResults(apiKey || '', messagesForContinuation);
|
|
189
|
+
} else if (response.message) {
|
|
190
|
+
addChatMessage(response.message);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
setLoading(false);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
console.error('Tool call failed:', error);
|
|
196
|
+
setLoading(false);
|
|
197
|
+
}
|
|
198
|
+
} finally {
|
|
199
|
+
// Reset flag after a short delay to allow next call
|
|
200
|
+
setTimeout(() => {
|
|
201
|
+
isProcessingToolCall = false;
|
|
202
|
+
}, 1000);
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
window.addEventListener('widget-tool-call', handleToolCall);
|
|
207
|
+
return () => window.removeEventListener('widget-tool-call', handleToolCall);
|
|
208
|
+
}, []); // Empty dependency array - only register once
|
|
209
|
+
|
|
94
210
|
const loadTools = async () => {
|
|
95
211
|
try {
|
|
96
212
|
const data = await api.getTools();
|
|
@@ -111,43 +227,43 @@ export default function ChatPage() {
|
|
|
111
227
|
|
|
112
228
|
const handleExecutePrompt = async () => {
|
|
113
229
|
if (!selectedPrompt) return;
|
|
114
|
-
|
|
230
|
+
|
|
115
231
|
// Close modal
|
|
116
232
|
const prompt = selectedPrompt;
|
|
117
233
|
const args = { ...promptArgs };
|
|
118
234
|
setSelectedPrompt(null);
|
|
119
235
|
setPromptArgs({});
|
|
120
|
-
|
|
236
|
+
|
|
121
237
|
// Build user message showing what prompt was executed
|
|
122
238
|
let userMessageContent = `Execute prompt: ${prompt.name}`;
|
|
123
239
|
if (Object.keys(args).length > 0) {
|
|
124
240
|
userMessageContent += `\nArguments: ${JSON.stringify(args, null, 2)}`;
|
|
125
241
|
}
|
|
126
|
-
|
|
242
|
+
|
|
127
243
|
// Add user message to chat
|
|
128
244
|
addChatMessage({
|
|
129
245
|
role: 'user',
|
|
130
246
|
content: userMessageContent,
|
|
131
247
|
});
|
|
132
|
-
|
|
248
|
+
|
|
133
249
|
setLoading(true);
|
|
134
|
-
|
|
250
|
+
|
|
135
251
|
try {
|
|
136
252
|
// Execute the prompt directly via API
|
|
137
253
|
const result = await api.executePrompt(prompt.name, args);
|
|
138
|
-
|
|
254
|
+
|
|
139
255
|
// Add the prompt result as an assistant message
|
|
140
256
|
if (result.messages && result.messages.length > 0) {
|
|
141
257
|
// Combine all prompt messages into one assistant message
|
|
142
258
|
const combinedContent = result.messages
|
|
143
259
|
.map((msg: any) => {
|
|
144
|
-
const content = typeof msg.content === 'string'
|
|
145
|
-
? msg.content
|
|
260
|
+
const content = typeof msg.content === 'string'
|
|
261
|
+
? msg.content
|
|
146
262
|
: msg.content?.text || JSON.stringify(msg.content);
|
|
147
263
|
return `[${msg.role.toUpperCase()}]\n${content}`;
|
|
148
264
|
})
|
|
149
265
|
.join('\n\n');
|
|
150
|
-
|
|
266
|
+
|
|
151
267
|
addChatMessage({
|
|
152
268
|
role: 'assistant',
|
|
153
269
|
content: combinedContent,
|
|
@@ -216,38 +332,38 @@ export default function ChatPage() {
|
|
|
216
332
|
|
|
217
333
|
try {
|
|
218
334
|
const messagesToSend = [...chatMessages, userMessage];
|
|
219
|
-
|
|
335
|
+
|
|
220
336
|
// Clean messages to ensure they're serializable
|
|
221
337
|
const cleanedMessages = messagesToSend.map(msg => {
|
|
222
338
|
const cleaned: any = {
|
|
223
339
|
role: msg.role,
|
|
224
340
|
content: msg.content || '',
|
|
225
341
|
};
|
|
226
|
-
|
|
342
|
+
|
|
227
343
|
if (msg.toolCalls && msg.toolCalls.length > 0) {
|
|
228
344
|
cleaned.toolCalls = msg.toolCalls;
|
|
229
345
|
}
|
|
230
|
-
|
|
346
|
+
|
|
231
347
|
if (msg.toolCallId) {
|
|
232
348
|
cleaned.toolCallId = msg.toolCallId;
|
|
233
349
|
}
|
|
234
|
-
|
|
350
|
+
|
|
235
351
|
// Skip image property for now (not supported by OpenAI chat completions)
|
|
236
352
|
// if (msg.image) {
|
|
237
353
|
// cleaned.image = msg.image;
|
|
238
354
|
// }
|
|
239
|
-
|
|
355
|
+
|
|
240
356
|
return cleaned;
|
|
241
357
|
});
|
|
242
|
-
|
|
358
|
+
|
|
243
359
|
// Get fresh auth tokens from store
|
|
244
360
|
const { jwtToken, mcpApiKey } = getAuthTokens();
|
|
245
|
-
|
|
361
|
+
|
|
246
362
|
console.log('Sending messages to API:', cleanedMessages);
|
|
247
363
|
console.log('Auth tokens:', { hasJwtToken: !!jwtToken, hasMcpApiKey: !!mcpApiKey });
|
|
248
364
|
console.log('Original messages:', messagesToSend);
|
|
249
365
|
console.log('Cleaned messages JSON:', JSON.stringify(cleanedMessages));
|
|
250
|
-
|
|
366
|
+
|
|
251
367
|
const response = await api.chat({
|
|
252
368
|
provider: currentProvider,
|
|
253
369
|
messages: cleanedMessages,
|
|
@@ -261,13 +377,13 @@ export default function ChatPage() {
|
|
|
261
377
|
// Attach results to tool calls for widget rendering
|
|
262
378
|
const toolCallsWithResults = response.toolCalls.map((tc, i) => {
|
|
263
379
|
const toolResult = response.toolResults[i];
|
|
264
|
-
|
|
380
|
+
|
|
265
381
|
// Parse the result content
|
|
266
382
|
let parsedResult;
|
|
267
383
|
if (toolResult.content) {
|
|
268
384
|
try {
|
|
269
385
|
parsedResult = JSON.parse(toolResult.content);
|
|
270
|
-
|
|
386
|
+
|
|
271
387
|
// Unwrap if response was wrapped by TransformInterceptor
|
|
272
388
|
if (parsedResult.success !== undefined && parsedResult.data !== undefined) {
|
|
273
389
|
parsedResult = parsedResult.data;
|
|
@@ -276,19 +392,19 @@ export default function ChatPage() {
|
|
|
276
392
|
parsedResult = { content: toolResult.content };
|
|
277
393
|
}
|
|
278
394
|
}
|
|
279
|
-
|
|
395
|
+
|
|
280
396
|
return {
|
|
281
397
|
...tc,
|
|
282
398
|
result: parsedResult,
|
|
283
399
|
};
|
|
284
400
|
});
|
|
285
|
-
|
|
401
|
+
|
|
286
402
|
// Add assistant message with tool calls
|
|
287
403
|
if (response.message) {
|
|
288
404
|
response.message.toolCalls = toolCallsWithResults;
|
|
289
405
|
addChatMessage(response.message);
|
|
290
406
|
}
|
|
291
|
-
|
|
407
|
+
|
|
292
408
|
// Extract JWT token from ANY tool response (not just 'login')
|
|
293
409
|
for (let i = 0; i < response.toolCalls.length; i++) {
|
|
294
410
|
const toolCall = response.toolCalls[i];
|
|
@@ -331,7 +447,7 @@ export default function ChatPage() {
|
|
|
331
447
|
addChatMessage(response.message);
|
|
332
448
|
}
|
|
333
449
|
}
|
|
334
|
-
|
|
450
|
+
|
|
335
451
|
// Set loading to false AFTER all async operations complete
|
|
336
452
|
setLoading(false);
|
|
337
453
|
} catch (error) {
|
|
@@ -348,31 +464,31 @@ export default function ChatPage() {
|
|
|
348
464
|
try {
|
|
349
465
|
// Use provided messages or fall back to store (for recursive calls)
|
|
350
466
|
const messagesToUse = messages || chatMessages;
|
|
351
|
-
|
|
467
|
+
|
|
352
468
|
// Get fresh auth tokens from store (token may have been updated by login)
|
|
353
469
|
const { jwtToken, mcpApiKey } = getAuthTokens();
|
|
354
|
-
|
|
470
|
+
|
|
355
471
|
// Clean messages before sending
|
|
356
472
|
const cleanedMessages = messagesToUse.map(msg => {
|
|
357
473
|
const cleaned: any = {
|
|
358
474
|
role: msg.role,
|
|
359
475
|
content: msg.content || '',
|
|
360
476
|
};
|
|
361
|
-
|
|
477
|
+
|
|
362
478
|
if (msg.toolCalls && msg.toolCalls.length > 0) {
|
|
363
479
|
cleaned.toolCalls = msg.toolCalls;
|
|
364
480
|
}
|
|
365
|
-
|
|
481
|
+
|
|
366
482
|
if (msg.toolCallId) {
|
|
367
483
|
cleaned.toolCallId = msg.toolCallId;
|
|
368
484
|
}
|
|
369
|
-
|
|
485
|
+
|
|
370
486
|
return cleaned;
|
|
371
487
|
});
|
|
372
|
-
|
|
488
|
+
|
|
373
489
|
console.log('Continue with cleaned messages:', JSON.stringify(cleanedMessages));
|
|
374
490
|
console.log('Continue auth tokens:', { hasJwtToken: !!jwtToken, hasMcpApiKey: !!mcpApiKey });
|
|
375
|
-
|
|
491
|
+
|
|
376
492
|
const response = await api.chat({
|
|
377
493
|
provider: currentProvider,
|
|
378
494
|
messages: cleanedMessages,
|
|
@@ -392,7 +508,7 @@ export default function ChatPage() {
|
|
|
392
508
|
addChatMessage(result);
|
|
393
509
|
newToolResults.push(result);
|
|
394
510
|
}
|
|
395
|
-
|
|
511
|
+
|
|
396
512
|
// Build messages for next iteration
|
|
397
513
|
const nextMessages = [
|
|
398
514
|
...(messages || chatMessages),
|
|
@@ -421,7 +537,7 @@ export default function ChatPage() {
|
|
|
421
537
|
};
|
|
422
538
|
|
|
423
539
|
return (
|
|
424
|
-
<div className="fixed inset-0 flex flex-col
|
|
540
|
+
<div className="fixed inset-0 flex flex-col" style={{ left: 'var(--sidebar-width, 15rem)', backgroundColor: '#0a0a0a' }}>
|
|
425
541
|
{/* Sticky Header */}
|
|
426
542
|
<div className="sticky top-0 z-10 border-b border-border/50 px-3 sm:px-6 py-3 flex flex-col sm:flex-row items-start sm:items-center justify-between bg-card/80 backdrop-blur-md shadow-sm gap-3 sm:gap-0">
|
|
427
543
|
<div className="flex items-center gap-3">
|
|
@@ -442,19 +558,18 @@ export default function ChatPage() {
|
|
|
442
558
|
<option value="gemini">Gemini</option>
|
|
443
559
|
<option value="openai">OpenAI</option>
|
|
444
560
|
</select>
|
|
445
|
-
<button
|
|
446
|
-
onClick={() => setShowSettings(!showSettings)}
|
|
447
|
-
className={`w-8 h-8 rounded-lg flex items-center justify-center transition-all flex-shrink-0 ${
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
}`}
|
|
561
|
+
<button
|
|
562
|
+
onClick={() => setShowSettings(!showSettings)}
|
|
563
|
+
className={`w-8 h-8 rounded-lg flex items-center justify-center transition-all flex-shrink-0 ${showSettings
|
|
564
|
+
? 'bg-primary/10 text-primary ring-1 ring-primary/30'
|
|
565
|
+
: 'bg-muted/50 text-muted-foreground hover:bg-muted hover:text-foreground'
|
|
566
|
+
}`}
|
|
452
567
|
title="Settings"
|
|
453
568
|
>
|
|
454
569
|
<Settings className="w-4 h-4" />
|
|
455
570
|
</button>
|
|
456
|
-
<button
|
|
457
|
-
onClick={clearChat}
|
|
571
|
+
<button
|
|
572
|
+
onClick={clearChat}
|
|
458
573
|
className="w-8 h-8 rounded-lg flex items-center justify-center bg-muted/50 text-muted-foreground hover:bg-muted hover:text-foreground transition-all flex-shrink-0"
|
|
459
574
|
title="Clear chat"
|
|
460
575
|
>
|
|
@@ -476,8 +591,8 @@ export default function ChatPage() {
|
|
|
476
591
|
<p className="text-xs text-muted-foreground mt-1">Configure your AI provider API keys to enable chat functionality</p>
|
|
477
592
|
</div>
|
|
478
593
|
</div>
|
|
479
|
-
|
|
480
|
-
|
|
594
|
+
|
|
595
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
481
596
|
{/* OpenAI Section */}
|
|
482
597
|
<div className="card p-4">
|
|
483
598
|
<div className="flex items-center justify-between mb-3">
|
|
@@ -487,9 +602,9 @@ export default function ChatPage() {
|
|
|
487
602
|
</div>
|
|
488
603
|
OpenAI API Key
|
|
489
604
|
</label>
|
|
490
|
-
<a
|
|
491
|
-
href="https://platform.openai.com/api-keys"
|
|
492
|
-
target="_blank"
|
|
605
|
+
<a
|
|
606
|
+
href="https://platform.openai.com/api-keys"
|
|
607
|
+
target="_blank"
|
|
493
608
|
rel="noopener noreferrer"
|
|
494
609
|
className="text-xs text-primary hover:text-primary/80 flex items-center gap-1 transition-colors"
|
|
495
610
|
>
|
|
@@ -497,11 +612,11 @@ export default function ChatPage() {
|
|
|
497
612
|
</a>
|
|
498
613
|
</div>
|
|
499
614
|
<div className="flex gap-2 mb-3">
|
|
500
|
-
<input
|
|
501
|
-
id="openai-api-key"
|
|
502
|
-
type="password"
|
|
503
|
-
className="input flex-1 text-sm py-2"
|
|
504
|
-
placeholder="sk-proj-..."
|
|
615
|
+
<input
|
|
616
|
+
id="openai-api-key"
|
|
617
|
+
type="password"
|
|
618
|
+
className="input flex-1 text-sm py-2"
|
|
619
|
+
placeholder="sk-proj-..."
|
|
505
620
|
/>
|
|
506
621
|
<button onClick={() => saveApiKey('openai')} className="btn btn-primary text-xs px-4 py-2">
|
|
507
622
|
<Save className="w-3 h-3 mr-1" />
|
|
@@ -518,9 +633,9 @@ export default function ChatPage() {
|
|
|
518
633
|
</a>
|
|
519
634
|
, navigate to API Keys, and create a new secret key.
|
|
520
635
|
</p>
|
|
521
|
-
<a
|
|
522
|
-
href="https://help.openai.com/en/articles/4936850-where-do-i-find-my-openai-api-key"
|
|
523
|
-
target="_blank"
|
|
636
|
+
<a
|
|
637
|
+
href="https://help.openai.com/en/articles/4936850-where-do-i-find-my-openai-api-key"
|
|
638
|
+
target="_blank"
|
|
524
639
|
rel="noopener noreferrer"
|
|
525
640
|
className="text-primary hover:underline inline-flex items-center gap-1"
|
|
526
641
|
>
|
|
@@ -539,9 +654,9 @@ export default function ChatPage() {
|
|
|
539
654
|
</div>
|
|
540
655
|
Gemini API Key
|
|
541
656
|
</label>
|
|
542
|
-
<a
|
|
543
|
-
href="https://aistudio.google.com/app/apikey"
|
|
544
|
-
target="_blank"
|
|
657
|
+
<a
|
|
658
|
+
href="https://aistudio.google.com/app/apikey"
|
|
659
|
+
target="_blank"
|
|
545
660
|
rel="noopener noreferrer"
|
|
546
661
|
className="text-xs text-primary hover:text-primary/80 flex items-center gap-1 transition-colors"
|
|
547
662
|
>
|
|
@@ -549,11 +664,11 @@ export default function ChatPage() {
|
|
|
549
664
|
</a>
|
|
550
665
|
</div>
|
|
551
666
|
<div className="flex gap-2 mb-3">
|
|
552
|
-
<input
|
|
553
|
-
id="gemini-api-key"
|
|
554
|
-
type="password"
|
|
555
|
-
className="input flex-1 text-sm py-2"
|
|
556
|
-
placeholder="AIza..."
|
|
667
|
+
<input
|
|
668
|
+
id="gemini-api-key"
|
|
669
|
+
type="password"
|
|
670
|
+
className="input flex-1 text-sm py-2"
|
|
671
|
+
placeholder="AIza..."
|
|
557
672
|
/>
|
|
558
673
|
<button onClick={() => saveApiKey('gemini')} className="btn btn-primary text-xs px-4 py-2">
|
|
559
674
|
<Save className="w-3 h-3 mr-1" />
|
|
@@ -570,9 +685,9 @@ export default function ChatPage() {
|
|
|
570
685
|
</a>
|
|
571
686
|
, sign in with your Google account, and click "Get API key".
|
|
572
687
|
</p>
|
|
573
|
-
<a
|
|
574
|
-
href="https://ai.google.dev/gemini-api/docs/api-key"
|
|
575
|
-
target="_blank"
|
|
688
|
+
<a
|
|
689
|
+
href="https://ai.google.dev/gemini-api/docs/api-key"
|
|
690
|
+
target="_blank"
|
|
576
691
|
rel="noopener noreferrer"
|
|
577
692
|
className="text-primary hover:underline inline-flex items-center gap-1"
|
|
578
693
|
>
|
|
@@ -588,7 +703,7 @@ export default function ChatPage() {
|
|
|
588
703
|
<div className="flex items-start gap-2">
|
|
589
704
|
<Info className="w-4 h-4 text-amber-500 mt-0.5 flex-shrink-0" />
|
|
590
705
|
<div className="text-xs text-muted-foreground">
|
|
591
|
-
<strong className="text-foreground">Security Note:</strong> Your API keys are stored locally in your browser and never sent to our servers.
|
|
706
|
+
<strong className="text-foreground">Security Note:</strong> Your API keys are stored locally in your browser and never sent to our servers.
|
|
592
707
|
Keep them confidential and avoid sharing them publicly.
|
|
593
708
|
</div>
|
|
594
709
|
</div>
|
|
@@ -599,14 +714,14 @@ export default function ChatPage() {
|
|
|
599
714
|
|
|
600
715
|
{/* ChatGPT-style Messages Container - ONLY this scrolls */}
|
|
601
716
|
<div className="flex-1 overflow-y-auto overflow-x-hidden">
|
|
602
|
-
<div className="max-w-
|
|
717
|
+
<div className="max-w-5xl mx-auto px-4 py-6 space-y-6 min-h-full">
|
|
603
718
|
{chatMessages.length === 0 && !loading ? (
|
|
604
719
|
/* Welcome Screen */
|
|
605
720
|
<div className="flex flex-col items-center justify-center min-h-[calc(100vh-300px)] animate-fade-in">
|
|
606
721
|
<div className="w-16 h-16 rounded-2xl bg-gradient-to-br from-primary to-amber-500 flex items-center justify-center shadow-xl mb-6">
|
|
607
722
|
<Bot className="w-10 h-10 text-white" strokeWidth={2.5} />
|
|
608
723
|
</div>
|
|
609
|
-
|
|
724
|
+
|
|
610
725
|
<h2 className="text-3xl font-bold text-foreground mb-3">Welcome to NitroStudio</h2>
|
|
611
726
|
<p className="text-muted-foreground text-center max-w-md mb-8">
|
|
612
727
|
Your AI-powered development environment for Model Context Protocol (MCP) servers.
|
|
@@ -621,7 +736,7 @@ export default function ChatPage() {
|
|
|
621
736
|
<h3 className="text-lg font-semibold text-foreground">Available Prompts</h3>
|
|
622
737
|
<span className="text-sm text-muted-foreground">({prompts.length})</span>
|
|
623
738
|
</div>
|
|
624
|
-
|
|
739
|
+
|
|
625
740
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
|
626
741
|
{prompts.slice(0, 6).map((prompt) => (
|
|
627
742
|
<button
|
|
@@ -716,7 +831,7 @@ export default function ChatPage() {
|
|
|
716
831
|
|
|
717
832
|
{/* ChatGPT-style Input Area - Fixed at bottom */}
|
|
718
833
|
<div className="sticky bottom-0 border-t border-border/50 bg-background/95 backdrop-blur-md shadow-[0_-2px_10px_rgba(0,0,0,0.1)]">
|
|
719
|
-
<div className="max-w-
|
|
834
|
+
<div className="max-w-5xl mx-auto px-3 sm:px-4 py-3 sm:py-4">
|
|
720
835
|
{currentImage && (
|
|
721
836
|
<div className="mb-3 p-3 bg-card rounded-xl flex items-start gap-3 border border-border/50 animate-fade-in">
|
|
722
837
|
<img
|
|
@@ -773,8 +888,8 @@ export default function ChatPage() {
|
|
|
773
888
|
}}
|
|
774
889
|
/>
|
|
775
890
|
</div>
|
|
776
|
-
<button
|
|
777
|
-
onClick={handleSend}
|
|
891
|
+
<button
|
|
892
|
+
onClick={handleSend}
|
|
778
893
|
disabled={loading || (!inputValue.trim() && !currentImage)}
|
|
779
894
|
className="h-11 w-11 rounded-xl flex items-center justify-center bg-gradient-to-br from-primary to-amber-500 text-white shadow-lg hover:shadow-xl disabled:opacity-50 disabled:cursor-not-allowed transition-all flex-shrink-0 hover:scale-105 active:scale-95"
|
|
780
895
|
title="Send message (Enter)"
|
|
@@ -782,7 +897,7 @@ export default function ChatPage() {
|
|
|
782
897
|
<Send className="w-5 h-5" strokeWidth={2.5} />
|
|
783
898
|
</button>
|
|
784
899
|
</div>
|
|
785
|
-
|
|
900
|
+
|
|
786
901
|
</div>
|
|
787
902
|
</div>
|
|
788
903
|
|
|
@@ -845,17 +960,41 @@ export default function ChatPage() {
|
|
|
845
960
|
</div>
|
|
846
961
|
)}
|
|
847
962
|
|
|
848
|
-
<button
|
|
849
|
-
onClick={handleExecutePrompt}
|
|
963
|
+
<button
|
|
964
|
+
onClick={handleExecutePrompt}
|
|
850
965
|
className="btn btn-primary w-full gap-2"
|
|
851
966
|
>
|
|
852
967
|
<Play className="w-4 h-4" />
|
|
853
968
|
Execute Prompt
|
|
854
|
-
|
|
969
|
+
</button>
|
|
970
|
+
</div>
|
|
971
|
+
|
|
972
|
+
</div>
|
|
973
|
+
</div>
|
|
974
|
+
)}
|
|
975
|
+
|
|
976
|
+
{/* Fullscreen Widget Modal */}
|
|
977
|
+
{fullscreenWidget && (
|
|
978
|
+
<div
|
|
979
|
+
className="fixed inset-0 z-50 flex items-center justify-center"
|
|
980
|
+
style={{ backgroundColor: 'rgba(0, 0, 0, 0.9)' }}
|
|
981
|
+
>
|
|
982
|
+
{/* Close Button */}
|
|
983
|
+
<button
|
|
984
|
+
onClick={() => setFullscreenWidget(null)}
|
|
985
|
+
className="absolute top-4 right-4 z-60 p-3 rounded-lg bg-white/10 hover:bg-white/20 backdrop-blur-sm border border-white/20 transition-all"
|
|
986
|
+
title="Exit fullscreen"
|
|
987
|
+
>
|
|
988
|
+
<X className="w-6 h-6 text-white" />
|
|
989
|
+
</button>
|
|
990
|
+
|
|
991
|
+
{/* Widget Container */}
|
|
992
|
+
<div className="w-full h-full p-8">
|
|
993
|
+
<div className="w-full h-full rounded-xl overflow-hidden shadow-2xl">
|
|
994
|
+
<WidgetRenderer uri={fullscreenWidget.uri} data={fullscreenWidget.data} className="widget-fullscreen" />
|
|
995
|
+
</div>
|
|
855
996
|
</div>
|
|
856
|
-
|
|
857
997
|
</div>
|
|
858
|
-
</div>
|
|
859
998
|
)}
|
|
860
999
|
</div>
|
|
861
1000
|
);
|
|
@@ -892,7 +1031,7 @@ function ChatMessageComponent({ message, tools }: { message: ChatMessage; tools:
|
|
|
892
1031
|
/>
|
|
893
1032
|
</div>
|
|
894
1033
|
)}
|
|
895
|
-
|
|
1034
|
+
|
|
896
1035
|
{/* Text content with markdown rendering */}
|
|
897
1036
|
{message.content && (
|
|
898
1037
|
<div className="text-sm leading-relaxed mb-4">
|
|
@@ -920,73 +1059,71 @@ function ChatMessageComponent({ message, tools }: { message: ChatMessage; tools:
|
|
|
920
1059
|
function ToolCallComponent({ toolCall, tools }: { toolCall: ToolCall; tools: Tool[] }) {
|
|
921
1060
|
const [showArgs, setShowArgs] = useState(false);
|
|
922
1061
|
const tool = tools.find((t) => t.name === toolCall.name);
|
|
923
|
-
|
|
1062
|
+
|
|
924
1063
|
// Get widget URI from multiple possible sources
|
|
925
|
-
const componentUri =
|
|
926
|
-
tool?.widget?.route ||
|
|
927
|
-
tool?.outputTemplate ||
|
|
928
|
-
tool?._meta?.['openai/outputTemplate'] ||
|
|
1064
|
+
const componentUri =
|
|
1065
|
+
tool?.widget?.route ||
|
|
1066
|
+
tool?.outputTemplate ||
|
|
1067
|
+
tool?._meta?.['openai/outputTemplate'] ||
|
|
929
1068
|
tool?._meta?.['ui/template'];
|
|
930
|
-
|
|
1069
|
+
|
|
931
1070
|
// Get result data from toolCall and unwrap if needed
|
|
932
1071
|
let widgetData = toolCall.result || toolCall.arguments;
|
|
933
|
-
|
|
1072
|
+
|
|
934
1073
|
// Unwrap if response was wrapped by TransformInterceptor
|
|
935
1074
|
// Check if it has the interceptor's structure: { success, data, metadata }
|
|
936
|
-
if (widgetData && typeof widgetData === 'object' &&
|
|
937
|
-
|
|
1075
|
+
if (widgetData && typeof widgetData === 'object' &&
|
|
1076
|
+
widgetData.success !== undefined && widgetData.data !== undefined) {
|
|
938
1077
|
widgetData = widgetData.data; // Return the unwrapped data
|
|
939
1078
|
}
|
|
940
1079
|
|
|
941
|
-
console.log('ToolCallComponent:', {
|
|
942
|
-
toolName: toolCall.name,
|
|
943
|
-
componentUri,
|
|
1080
|
+
console.log('ToolCallComponent:', {
|
|
1081
|
+
toolName: toolCall.name,
|
|
1082
|
+
componentUri,
|
|
944
1083
|
hasData: !!widgetData,
|
|
945
|
-
tool
|
|
1084
|
+
tool
|
|
946
1085
|
});
|
|
947
1086
|
|
|
948
1087
|
return (
|
|
949
|
-
<div className="
|
|
950
|
-
{/*
|
|
1088
|
+
<div className="relative group/widget">
|
|
1089
|
+
{/* Widget - No frame, just the widget */}
|
|
1090
|
+
{componentUri && widgetData && (
|
|
1091
|
+
<div className="rounded-lg overflow-hidden max-w-5xl">
|
|
1092
|
+
<WidgetRenderer uri={componentUri} data={widgetData} className="widget-in-chat" />
|
|
1093
|
+
</div>
|
|
1094
|
+
)}
|
|
1095
|
+
|
|
1096
|
+
{/* 3-dots menu button - positioned absolutely in top-right */}
|
|
951
1097
|
<button
|
|
952
1098
|
onClick={() => setShowArgs(!showArgs)}
|
|
953
|
-
className="w-
|
|
1099
|
+
className="absolute top-2 right-2 w-8 h-8 rounded-lg flex items-center justify-center bg-background/80 backdrop-blur-sm border border-border/50 hover:bg-background hover:border-border transition-all opacity-0 group-hover/widget:opacity-100 shadow-sm z-10"
|
|
1100
|
+
title="View tool details"
|
|
954
1101
|
>
|
|
955
|
-
<
|
|
956
|
-
<div className="w-6 h-6 rounded-md bg-primary/10 flex items-center justify-center group-hover:bg-primary/20 transition-colors">
|
|
957
|
-
<Wrench className="w-3.5 h-3.5 text-primary" />
|
|
958
|
-
</div>
|
|
959
|
-
<span className="font-semibold text-sm text-foreground">{toolCall.name}</span>
|
|
960
|
-
</div>
|
|
961
|
-
<svg
|
|
962
|
-
className={`w-4 h-4 text-muted-foreground transition-transform ${showArgs ? 'rotate-180' : ''}`}
|
|
963
|
-
fill="none"
|
|
964
|
-
viewBox="0 0 24 24"
|
|
965
|
-
stroke="currentColor"
|
|
966
|
-
>
|
|
967
|
-
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
|
|
968
|
-
</svg>
|
|
1102
|
+
<MoreVertical className="w-4 h-4 text-muted-foreground" />
|
|
969
1103
|
</button>
|
|
970
1104
|
|
|
971
|
-
{/* Arguments -
|
|
1105
|
+
{/* Arguments Modal/Dropdown - appears when 3-dots clicked */}
|
|
972
1106
|
{showArgs && (
|
|
973
|
-
<div className="
|
|
974
|
-
<
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
<
|
|
1107
|
+
<div className="absolute top-12 right-2 w-96 max-w-[calc(100%-1rem)] bg-card rounded-xl border border-border shadow-2xl p-4 animate-fade-in z-20">
|
|
1108
|
+
<div className="flex items-center justify-between mb-3">
|
|
1109
|
+
<div className="flex items-center gap-2">
|
|
1110
|
+
<div className="w-6 h-6 rounded-md bg-primary/10 flex items-center justify-center">
|
|
1111
|
+
<Wrench className="w-3.5 h-3.5 text-primary" />
|
|
1112
|
+
</div>
|
|
1113
|
+
<span className="font-semibold text-sm text-foreground">{toolCall.name}</span>
|
|
1114
|
+
</div>
|
|
1115
|
+
<button
|
|
1116
|
+
onClick={() => setShowArgs(false)}
|
|
1117
|
+
className="w-6 h-6 rounded-md flex items-center justify-center hover:bg-muted transition-colors"
|
|
1118
|
+
>
|
|
1119
|
+
<X className="w-4 h-4 text-muted-foreground" />
|
|
1120
|
+
</button>
|
|
1121
|
+
</div>
|
|
1122
|
+
<div>
|
|
1123
|
+
<p className="text-xs font-medium text-muted-foreground mb-2">Arguments:</p>
|
|
1124
|
+
<pre className="p-3 rounded-lg overflow-auto bg-background border border-border/30 font-mono text-xs text-foreground max-h-60">
|
|
1125
|
+
{JSON.stringify(toolCall.arguments, null, 2)}
|
|
1126
|
+
</pre>
|
|
990
1127
|
</div>
|
|
991
1128
|
</div>
|
|
992
1129
|
)}
|