Skip to content

Commit ba1d57d

Browse files
mrjasonroyclaude
andcommitted
fix: improve file-generator tool with presigned URLs and system prompts
- Add explicit logging to track presigned URL generation - Remove fallback to sourceUrl to ensure presigned URLs are always used - Add file generation capability to system prompts for all models - Update tool description to prevent LLMs from including raw URLs in responses - Add guide field to tool result for better user messaging This ensures all file downloads work correctly with private S3 buckets and improves model awareness of file generation capabilities. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent aa2fcd2 commit ba1d57d

File tree

2 files changed

+37
-6
lines changed

2 files changed

+37
-6
lines changed

src/lib/ai/prompts.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ You can assist with:
9696
- Analysis and problem-solving across various domains
9797
- Using available tools and resources to complete tasks
9898
- Adapting communication to user preferences and context
99+
- Generating downloadable files (CSV, JSON, PDF, code files, etc.) when users request data exports or file creation
99100
</general_capabilities>`;
100101

101102
// Communication preferences
@@ -123,8 +124,9 @@ ${userPreferences.responseStyleExample}
123124
prompt += `
124125
125126
- When using tools, briefly mention which tool you'll use with natural phrases
126-
- Examples: "I'll search for that information", "Let me check the weather", "I'll run some calculations"
127+
- Examples: "I'll search for that information", "Let me check the weather", "I'll run some calculations", "I'll generate that file for you"
127128
- Use \`mermaid\` code blocks for diagrams and charts when helpful
129+
- When users request data exports, file downloads, or structured data files, use the file-generator tool to create downloadable files
128130
</communication_preferences>`;
129131
}
130132

@@ -177,6 +179,7 @@ ${userInfo.join("\n")}
177179
You excel at conversational voice interactions by:
178180
- Providing clear, natural spoken responses
179181
- Using available tools to gather information and complete tasks
182+
- Generating downloadable files when users request data exports or file creation
180183
- Adapting communication to user preferences and context
181184
</voice_capabilities>`;
182185

src/lib/ai/tools/file-generator/index.ts

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export type FileGeneratorToolResult = {
1212
size: number;
1313
}[];
1414
description?: string;
15+
guide?: string;
1516
};
1617

1718
export const fileGeneratorTool = createTool({
@@ -22,7 +23,9 @@ export const fileGeneratorTool = createTool({
2223
- Code files: Python, JavaScript, HTML, CSS, etc.
2324
- Structured data exports
2425
25-
The tool will generate the file, upload it to storage, and provide a download link. Do not use this for images (use image-manager instead) or for simple text responses that don't need to be downloaded.`,
26+
The tool will generate the file, upload it to storage, and provide a download link. Do not use this for images (use image-manager instead) or for simple text responses that don't need to be downloaded.
27+
28+
IMPORTANT: After invoking this tool, do NOT include file URLs in your text response. The download links are automatically displayed in the UI above your message. Simply acknowledge that the file(s) have been generated.`,
2629
inputSchema: z.object({
2730
files: z
2831
.array(
@@ -89,23 +92,48 @@ The tool will generate the file, upload it to storage, and provide a download li
8992
contentType: mimeType,
9093
});
9194

95+
logger.info("File uploaded:", {
96+
key: uploaded.key,
97+
sourceUrl: uploaded.sourceUrl,
98+
hasGetDownloadUrl: !!serverFileStorage.getDownloadUrl,
99+
});
100+
92101
// Get presigned URL for private buckets if available
93-
const downloadUrl = serverFileStorage.getDownloadUrl
94-
? await serverFileStorage.getDownloadUrl(uploaded.key)
95-
: uploaded.sourceUrl;
102+
let downloadUrl: string;
103+
if (serverFileStorage.getDownloadUrl) {
104+
downloadUrl = await serverFileStorage.getDownloadUrl(uploaded.key);
105+
logger.info("Presigned URL generated:", {
106+
downloadUrl,
107+
isPresigned: downloadUrl.includes("X-Amz"),
108+
});
109+
} else {
110+
downloadUrl = uploaded.sourceUrl;
111+
logger.info("Using source URL (no getDownloadUrl):", {
112+
downloadUrl,
113+
});
114+
}
96115

97116
return {
98-
url: downloadUrl || uploaded.sourceUrl,
117+
url: downloadUrl,
99118
filename: uploaded.metadata.filename || file.filename,
100119
mimeType: uploaded.metadata.contentType || mimeType,
101120
size: uploaded.metadata.size || buffer.length,
102121
};
103122
}),
104123
);
105124

125+
const fileCount = uploadedFiles.length;
126+
const guide =
127+
fileCount > 0
128+
? fileCount === 1
129+
? "Your file has been generated successfully and is ready for download above. You can click the download button to save it to your device."
130+
: `Your ${fileCount} files have been generated successfully and are ready for download above. You can click the download buttons to save them to your device.`
131+
: undefined;
132+
106133
return {
107134
files: uploadedFiles,
108135
description,
136+
guide,
109137
};
110138
} catch (e) {
111139
logger.error(e);

0 commit comments

Comments
 (0)