fix: enhance permissions in settings and update .gitignore for local config

This commit is contained in:
dayuan.jiang
2025-11-10 00:00:02 +09:00
parent d8d0a800fe
commit 4efbe78d5a
3 changed files with 118 additions and 97 deletions

View File

@@ -1,7 +1,11 @@
{
"permissions": {
"allow": [
"Bash(npm update:*)"
"Bash(npm update:*)",
"WebFetch(domain:ai-sdk.dev)",
"mcp__ide__getDiagnostics",
"Bash(npx tsc:*)",
"WebFetch(domain:sdk.vercel.ai)"
],
"deny": [],
"ask": []

1
.gitignore vendored
View File

@@ -40,3 +40,4 @@ yarn-error.log*
*.tsbuildinfo
next-env.d.ts
push-via-ec2.sh
.claude/settings.local.json

View File

@@ -3,8 +3,6 @@ import { openai } from '@ai-sdk/openai';
import { google } from '@ai-sdk/google';
import { smoothStream, streamText, convertToModelMessages } from 'ai';
import { createOpenRouter } from '@openrouter/ai-sdk-provider';
import { readFileSync } from 'fs';
import { resolve } from 'path';
import { createGoogleGenerativeAI } from '@ai-sdk/google';
import { createOpenAI } from '@ai-sdk/openai';
@@ -13,18 +11,16 @@ import { replaceXMLParts } from "@/lib/utils";
export const maxDuration = 60
const openrouter = createOpenRouter({ apiKey: process.env.OPENROUTER_API_KEY });
// Read the XML guide from file
export async function POST(req: Request) {
const body = await req.json();
try {
const { messages, xml } = await req.json();
// Extract messages and xml directly from the body
const { messages, xml } = body;
const guide = readFileSync(resolve('./app/api/chat/xml_guide.md'), 'utf8');
// Read and escape the guide content
const systemMessage = `
You are an expert diagram creation assistant specializing in draw.io XML generation. Your primary function is crafting clear, well-organized visual diagrams through precise XML specifications.
const systemMessage = `
You are an expert diagram creation assistant specializing in draw.io XML generation.
Your primary function is crafting clear, well-organized visual diagrams through precise XML specifications.
You can see the image that user uploaded.
When you need to generate diagram about aws architecture, use AWS 2025 icons.
You utilize the following tools:
---Tool1---
tool name: display_diagram
@@ -60,16 +56,17 @@ When using edit_diagram tool:
- Example GOOD edit: {"search": " <mxCell id=\"2\" value=\"Old Text\">", "replace": " <mxCell id=\"2\" value=\"New Text\">"}
- Example BAD edit: Including 10+ unchanged lines just to change one attribute
- For multiple changes, use separate edits: [{"search": "line1", "replace": "new1"}, {"search": "line2", "replace": "new2"}]
here is a guide for the XML format: ${guide}
`;
const lastMessage = messages[messages.length - 1];
const lastMessage = messages[messages.length - 1];
// Extract text from the last message parts
const lastMessageText = lastMessage.parts?.find((part: any) => part.type === 'text')?.text || '';
// Extract text from the last message parts
const lastMessageText = lastMessage.parts?.find((part: any) => part.type === 'text')?.text || '';
const formattedContent = `
// Extract file parts (images) from the last message
const fileParts = lastMessage.parts?.filter((part: any) => part.type === 'file') || [];
const formattedTextContent = `
Current diagram XML:
"""xml
${xml || ''}
@@ -79,99 +76,118 @@ User input:
${lastMessageText}
"""`;
// Convert UIMessages to ModelMessages and add system message
const modelMessages = convertToModelMessages(messages);
let enhancedMessages = [...modelMessages];
// Convert UIMessages to ModelMessages and add system message
const modelMessages = convertToModelMessages(messages);
let enhancedMessages = [...modelMessages];
// Update the last message with formatted content if it's a user message
if (enhancedMessages.length >= 1) {
const lastModelMessage = enhancedMessages[enhancedMessages.length - 1];
if (lastModelMessage.role === 'user') {
enhancedMessages = [
...enhancedMessages.slice(0, -1),
{ ...lastModelMessage, content: formattedContent }
];
// Update the last message with formatted content if it's a user message
if (enhancedMessages.length >= 1) {
const lastModelMessage = enhancedMessages[enhancedMessages.length - 1];
if (lastModelMessage.role === 'user') {
// Build content array with text and file parts
const contentParts: any[] = [
{ type: 'text', text: formattedTextContent }
];
// Add image parts back
for (const filePart of fileParts) {
contentParts.push({
type: 'image',
image: filePart.url,
mimeType: filePart.mediaType
});
}
enhancedMessages = [
...enhancedMessages.slice(0, -1),
{ ...lastModelMessage, content: contentParts }
];
}
}
}
console.log("Enhanced messages:", enhancedMessages);
console.log("Enhanced messages:", enhancedMessages);
const result = streamText({
// model: google("gemini-2.5-flash-preview-05-20"),
// model: google("gemini-2.5-pro"),
// model: bedrock('anthropic.claude-sonnet-4-20250514-v1:0'),
system: systemMessage,
model: bedrock('global.anthropic.claude-sonnet-4-5-20250929-v1:0'),
// model: openrouter('moonshotai/kimi-k2:free'),
// model: model,
// providerOptions: {
// google: {
// thinkingConfig: {
// thinkingBudget: 128,
// },
// }
// },
// providerOptions: {
// openai: {
// reasoningEffort: "minimal"
// },
// },
messages: enhancedMessages,
tools: {
// Client-side tool that will be executed on the client
display_diagram: {
description: `Display a diagram on draw.io. You only need to pass the nodes inside the <root> tag (including the <root> tag itself) in the XML string.
For example:
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxGeometry x="20" y="20" width="100" height="100" as="geometry"/>
<mxCell id="2" value="Hello, World!" style="shape=rectangle" parent="1">
const result = streamText({
// model: google("gemini-2.5-flash-preview-05-20"),
// model: google("gemini-2.5-pro"),
// model: bedrock('anthropic.claude-sonnet-4-20250514-v1:0'),
system: systemMessage,
model: bedrock('global.anthropic.claude-sonnet-4-5-20250929-v1:0'),
// model: openrouter('moonshotai/kimi-k2:free'),
// model: model,
// providerOptions: {
// google: {
// thinkingConfig: {
// thinkingBudget: 128,
// },
// }
// },
// providerOptions: {
// openai: {
// reasoningEffort: "minimal"
// },
// },
messages: enhancedMessages,
tools: {
// Client-side tool that will be executed on the client
display_diagram: {
description: `Display a diagram on draw.io. You only need to pass the nodes inside the <root> tag (including the <root> tag itself) in the XML string.
For example:
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxGeometry x="20" y="20" width="100" height="100" as="geometry"/>
</mxCell>
</root>`,
inputSchema: z.object({
xml: z.string().describe("XML string to be displayed on draw.io")
})
},
edit_diagram: {
description: `Edit specific parts of the current diagram by replacing exact line matches. Use this tool to make targeted fixes without regenerating the entire XML.
<mxCell id="2" value="Hello, World!" style="shape=rectangle" parent="1">
<mxGeometry x="20" y="20" width="100" height="100" as="geometry"/>
</mxCell>
</root>`,
inputSchema: z.object({
xml: z.string().describe("XML string to be displayed on draw.io")
})
},
edit_diagram: {
description: `Edit specific parts of the current diagram by replacing exact line matches. Use this tool to make targeted fixes without regenerating the entire XML.
IMPORTANT: Keep edits concise:
- Only include the lines that are changing, plus 1-2 surrounding lines for context if needed
- Break large changes into multiple smaller edits
- Each search must contain complete lines (never truncate mid-line)
- First match only - be specific enough to target the right element`,
inputSchema: z.object({
edits: z.array(z.object({
search: z.string().describe("Exact lines to search for (including whitespace and indentation)"),
replace: z.string().describe("Replacement lines")
})).describe("Array of search/replace pairs to apply sequentially")
})
inputSchema: z.object({
edits: z.array(z.object({
search: z.string().describe("Exact lines to search for (including whitespace and indentation)"),
replace: z.string().describe("Replacement lines")
})).describe("Array of search/replace pairs to apply sequentially")
})
},
},
},
temperature: 0,
});
temperature: 0,
});
// Error handler function to provide detailed error messages
// Error handler function to provide detailed error messages
function errorHandler(error: unknown) {
if (error == null) {
return 'unknown error';
}
function errorHandler(error: unknown) {
if (error == null) {
return 'unknown error';
if (typeof error === 'string') {
return error;
}
if (error instanceof Error) {
return error.message;
}
return JSON.stringify(error);
}
if (typeof error === 'string') {
return error;
}
if (error instanceof Error) {
return error.message;
}
return JSON.stringify(error);
return result.toUIMessageStreamResponse({
onError: errorHandler,
});
} catch (error) {
console.error('Error in chat route:', error);
return Response.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
return result.toUIMessageStreamResponse({
onError: errorHandler,
});
}