nitrostack 1.0.70 → 1.0.72
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/package.json +1 -1
- package/src/studio/app/api/chat/route.ts +33 -15
- package/src/studio/app/auth/callback/page.tsx +6 -6
- package/src/studio/app/chat/page.tsx +1124 -415
- package/src/studio/app/chat/page.tsx.backup +1046 -187
- package/src/studio/app/globals.css +361 -191
- package/src/studio/app/health/page.tsx +72 -76
- package/src/studio/app/layout.tsx +9 -11
- package/src/studio/app/logs/page.tsx +29 -30
- package/src/studio/app/page.tsx +134 -230
- package/src/studio/app/prompts/page.tsx +115 -97
- package/src/studio/app/resources/page.tsx +115 -124
- package/src/studio/app/settings/page.tsx +1080 -125
- package/src/studio/app/tools/page.tsx +343 -0
- package/src/studio/components/EnlargeModal.tsx +76 -65
- package/src/studio/components/LogMessage.tsx +5 -5
- package/src/studio/components/MarkdownRenderer.tsx +4 -4
- package/src/studio/components/Sidebar.tsx +150 -210
- package/src/studio/components/SplashScreen.tsx +109 -0
- package/src/studio/components/ToolCard.tsx +50 -41
- package/src/studio/components/VoiceOrbOverlay.tsx +469 -0
- package/src/studio/components/WidgetRenderer.tsx +8 -3
- package/src/studio/components/tools/ToolsCanvas.tsx +327 -0
- package/src/studio/lib/llm-service.ts +104 -1
- package/src/studio/lib/store.ts +36 -21
- package/src/studio/lib/types.ts +1 -1
- package/src/studio/package-lock.json +3303 -0
- package/src/studio/package.json +3 -1
- package/src/studio/public/NitroStudio Isotype Color.png +0 -0
- package/src/studio/tailwind.config.ts +63 -17
- package/templates/typescript-starter/package-lock.json +4112 -0
- package/templates/typescript-starter/package.json +2 -3
- package/templates/typescript-starter/src/modules/calculator/calculator.tools.ts +100 -5
- package/src/studio/app/auth/page.tsx +0 -560
- package/src/studio/app/ping/page.tsx +0 -209
package/package.json
CHANGED
|
@@ -14,8 +14,8 @@ export async function POST(request: NextRequest) {
|
|
|
14
14
|
mcpApiKey?: string; // MCP server API key
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
console.log('Received chat request:', {
|
|
18
|
-
provider,
|
|
17
|
+
console.log('Received chat request:', {
|
|
18
|
+
provider,
|
|
19
19
|
messagesCount: messages?.length,
|
|
20
20
|
messages: JSON.stringify(messages),
|
|
21
21
|
hasApiKey: !!apiKey,
|
|
@@ -30,7 +30,7 @@ export async function POST(request: NextRequest) {
|
|
|
30
30
|
{ status: 400 }
|
|
31
31
|
);
|
|
32
32
|
}
|
|
33
|
-
|
|
33
|
+
|
|
34
34
|
if (messages.length === 0) {
|
|
35
35
|
return NextResponse.json(
|
|
36
36
|
{ error: 'Messages array is empty' },
|
|
@@ -46,13 +46,13 @@ export async function POST(request: NextRequest) {
|
|
|
46
46
|
description: tool.description || '',
|
|
47
47
|
inputSchema: tool.inputSchema || {},
|
|
48
48
|
})) || [];
|
|
49
|
-
|
|
49
|
+
|
|
50
50
|
// Add synthetic tools for prompts and resources
|
|
51
51
|
const promptsList = await client.listPrompts().catch(() => ({ prompts: [] }));
|
|
52
52
|
const resourcesList = await client.listResources().catch(() => ({ resources: [] }));
|
|
53
|
-
|
|
53
|
+
|
|
54
54
|
const syntheticTools = [];
|
|
55
|
-
|
|
55
|
+
|
|
56
56
|
// Add a tool to list available prompts
|
|
57
57
|
if (promptsList.prompts && promptsList.prompts.length > 0) {
|
|
58
58
|
syntheticTools.push({
|
|
@@ -63,7 +63,7 @@ export async function POST(request: NextRequest) {
|
|
|
63
63
|
properties: {},
|
|
64
64
|
},
|
|
65
65
|
});
|
|
66
|
-
|
|
66
|
+
|
|
67
67
|
// Add a tool to execute prompts
|
|
68
68
|
syntheticTools.push({
|
|
69
69
|
name: 'execute_prompt',
|
|
@@ -84,7 +84,7 @@ export async function POST(request: NextRequest) {
|
|
|
84
84
|
},
|
|
85
85
|
});
|
|
86
86
|
}
|
|
87
|
-
|
|
87
|
+
|
|
88
88
|
// Add a tool to list available resources
|
|
89
89
|
if (resourcesList.resources && resourcesList.resources.length > 0) {
|
|
90
90
|
syntheticTools.push({
|
|
@@ -95,7 +95,7 @@ export async function POST(request: NextRequest) {
|
|
|
95
95
|
properties: {},
|
|
96
96
|
},
|
|
97
97
|
});
|
|
98
|
-
|
|
98
|
+
|
|
99
99
|
// Add a tool to read resources
|
|
100
100
|
syntheticTools.push({
|
|
101
101
|
name: 'read_resource',
|
|
@@ -112,7 +112,9 @@ export async function POST(request: NextRequest) {
|
|
|
112
112
|
},
|
|
113
113
|
});
|
|
114
114
|
}
|
|
115
|
-
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
|
|
116
118
|
const tools = [...mcpTools, ...syntheticTools];
|
|
117
119
|
|
|
118
120
|
// Call LLM
|
|
@@ -126,7 +128,7 @@ export async function POST(request: NextRequest) {
|
|
|
126
128
|
try {
|
|
127
129
|
let result: any;
|
|
128
130
|
let toolContent = '';
|
|
129
|
-
|
|
131
|
+
|
|
130
132
|
// Handle synthetic tools
|
|
131
133
|
if (toolCall.name === 'list_prompts') {
|
|
132
134
|
const prompts = await client.listPrompts();
|
|
@@ -157,7 +159,7 @@ export async function POST(request: NextRequest) {
|
|
|
157
159
|
} else if (toolCall.name === 'read_resource') {
|
|
158
160
|
const resource = await client.readResource(toolCall.arguments.uri);
|
|
159
161
|
// Extract the actual content from the resource
|
|
160
|
-
let resourceContent = resource;
|
|
162
|
+
let resourceContent: any = resource;
|
|
161
163
|
if (resource.contents && Array.isArray(resource.contents)) {
|
|
162
164
|
// If it's an array of contents, extract text from each
|
|
163
165
|
resourceContent = resource.contents.map((c: any) => {
|
|
@@ -172,21 +174,37 @@ export async function POST(request: NextRequest) {
|
|
|
172
174
|
// Regular MCP tool execution
|
|
173
175
|
// Inject auth tokens into tool arguments if available
|
|
174
176
|
const toolArgs = { ...toolCall.arguments };
|
|
177
|
+
|
|
178
|
+
// Check if we have a file in the last user message and if this is a convert_temperature tool
|
|
179
|
+
if (toolCall.name === 'convert_temperature') {
|
|
180
|
+
const lastUserMessage = messages.slice().reverse().find(m => m.role === 'user');
|
|
181
|
+
if (lastUserMessage && lastUserMessage.file) {
|
|
182
|
+
// Inject file content if not already provided by LLM (or overwrite it to be safe)
|
|
183
|
+
console.log('📂 Injecting file content into convert_temperature tool call');
|
|
184
|
+
toolArgs.file_content = lastUserMessage.file.data;
|
|
185
|
+
toolArgs.file_type = lastUserMessage.file.type;
|
|
186
|
+
|
|
187
|
+
if (!toolArgs.file_name) {
|
|
188
|
+
toolArgs.file_name = lastUserMessage.file.name;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
175
193
|
if (jwtToken || mcpApiKey) {
|
|
176
194
|
toolArgs._meta = {
|
|
177
195
|
...(toolArgs._meta || {}),
|
|
178
196
|
};
|
|
179
|
-
|
|
197
|
+
|
|
180
198
|
if (jwtToken) {
|
|
181
199
|
toolArgs._meta._jwt = jwtToken;
|
|
182
200
|
toolArgs._meta.authorization = `Bearer ${jwtToken}`;
|
|
183
201
|
}
|
|
184
|
-
|
|
202
|
+
|
|
185
203
|
if (mcpApiKey) {
|
|
186
204
|
toolArgs._meta.apiKey = mcpApiKey;
|
|
187
205
|
toolArgs._meta['x-api-key'] = mcpApiKey;
|
|
188
206
|
}
|
|
189
|
-
|
|
207
|
+
|
|
190
208
|
console.log(`🔐 Executing tool "${toolCall.name}" with auth:`, {
|
|
191
209
|
hasJwt: !!jwtToken,
|
|
192
210
|
hasMcpApiKey: !!mcpApiKey,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { useEffect, useState, Suspense } from 'react';
|
|
4
4
|
import { useRouter, useSearchParams } from 'next/navigation';
|
|
5
5
|
import { useStudioStore } from '@/lib/store';
|
|
6
|
-
import {
|
|
6
|
+
import { ArrowPathIcon, CheckCircleIcon, XCircleIcon } from '@heroicons/react/24/outline';
|
|
7
7
|
|
|
8
8
|
function OAuthCallback() {
|
|
9
9
|
const router = useRouter();
|
|
@@ -95,7 +95,7 @@ function OAuthCallback() {
|
|
|
95
95
|
// Store access token as JWT token
|
|
96
96
|
if (tokens.access_token) {
|
|
97
97
|
setJwtToken(tokens.access_token);
|
|
98
|
-
|
|
98
|
+
|
|
99
99
|
// Clean up session storage
|
|
100
100
|
sessionStorage.removeItem('oauth_code_verifier');
|
|
101
101
|
sessionStorage.removeItem('oauth_state');
|
|
@@ -126,7 +126,7 @@ function OAuthCallback() {
|
|
|
126
126
|
<div className="card p-8 max-w-md w-full text-center">
|
|
127
127
|
{status === 'processing' && (
|
|
128
128
|
<>
|
|
129
|
-
<
|
|
129
|
+
<ArrowPathIcon className="w-16 h-16 text-primary mx-auto mb-4 animate-spin" />
|
|
130
130
|
<h1 className="text-2xl font-bold text-foreground mb-2">Processing...</h1>
|
|
131
131
|
<p className="text-muted-foreground">{message}</p>
|
|
132
132
|
</>
|
|
@@ -134,7 +134,7 @@ function OAuthCallback() {
|
|
|
134
134
|
|
|
135
135
|
{status === 'success' && (
|
|
136
136
|
<>
|
|
137
|
-
<
|
|
137
|
+
<CheckCircleIcon className="w-16 h-16 text-emerald-500 mx-auto mb-4" />
|
|
138
138
|
<h1 className="text-2xl font-bold text-foreground mb-2">Success!</h1>
|
|
139
139
|
<p className="text-muted-foreground">{message}</p>
|
|
140
140
|
</>
|
|
@@ -142,7 +142,7 @@ function OAuthCallback() {
|
|
|
142
142
|
|
|
143
143
|
{status === 'error' && (
|
|
144
144
|
<>
|
|
145
|
-
<
|
|
145
|
+
<XCircleIcon className="w-16 h-16 text-red-500 mx-auto mb-4" />
|
|
146
146
|
<h1 className="text-2xl font-bold text-foreground mb-2">Authorization Failed</h1>
|
|
147
147
|
<p className="text-muted-foreground mb-4">{message}</p>
|
|
148
148
|
<button
|
|
@@ -163,7 +163,7 @@ export default function AuthCallbackPage() {
|
|
|
163
163
|
<Suspense fallback={
|
|
164
164
|
<div className="fixed inset-0 flex items-center justify-center bg-background">
|
|
165
165
|
<div className="text-center">
|
|
166
|
-
<
|
|
166
|
+
<ArrowPathIcon className="w-8 h-8 text-primary animate-spin mx-auto mb-4" />
|
|
167
167
|
<p className="text-muted-foreground">Loading...</p>
|
|
168
168
|
</div>
|
|
169
169
|
</div>
|