generateThreadName server action

This commit is contained in:
marko-kraemer 2025-04-17 14:19:52 +01:00
parent 58421d8fe9
commit a8f0da8ae8
4 changed files with 98 additions and 96 deletions

View File

@ -4,7 +4,8 @@ import React, { useState, Suspense } from 'react';
import { Skeleton } from "@/components/ui/skeleton";
import { useRouter } from 'next/navigation';
import { ChatInput } from '@/components/thread/chat-input';
import { createProject, addUserMessage, startAgent, createThread, generateThreadName } from "@/lib/api";
import { createProject, addUserMessage, startAgent, createThread } from "@/lib/api";
import { generateThreadName } from "@/lib/actions/threads";
function DashboardContent() {
const [inputValue, setInputValue] = useState("");

View File

@ -1223,43 +1223,6 @@ export function ToolCallSidePanel({
</Button>
</div>
<div className="flex-1 p-4 overflow-y-auto">
{/* Navigation Controls - Conditionally Rendered */}
{showNavigation && (
<div className="mb-6 pb-4 border-b">
<div className="flex items-center justify-between mb-2">
<span className="text-sm font-medium text-muted-foreground">
Step {currentIndex + 1} of {totalPairs}
</span>
<div className="flex items-center gap-1">
<Button
variant="ghost"
size="icon"
onClick={() => onNavigate(currentIndex - 1)}
disabled={currentIndex === 0}
className="h-7 w-7"
>
<SkipBack className="h-4 w-4" />
</Button>
<Button
variant="ghost"
size="icon"
onClick={() => onNavigate(currentIndex + 1)}
disabled={currentIndex === totalPairs - 1}
className="h-7 w-7"
>
<SkipForward className="h-4 w-4" />
</Button>
</div>
</div>
<Slider
value={[currentIndex]} // Slider value is an array
max={totalPairs - 1}
step={1}
onValueChange={(value) => onNavigate(value[0])} // onValueChange gives an array
/>
</div>
)}
{content ? (
// ---- Render Historical Pair ----
'type' in content && content.type === 'historical' ? (
@ -1367,6 +1330,43 @@ export function ToolCallSidePanel({
)}
</div>
{/* Navigation Controls moved to bottom, just above TodoPanel */}
{showNavigation && (
<div className="px-4 pt-2 pb-2 border-t">
<div className="flex items-center justify-between mb-2">
<span className="text-sm font-medium text-muted-foreground">
Step {currentIndex + 1} of {totalPairs}
</span>
<div className="flex items-center gap-1">
<Button
variant="ghost"
size="icon"
onClick={() => onNavigate(currentIndex - 1)}
disabled={currentIndex === 0}
className="h-7 w-7"
>
<SkipBack className="h-4 w-4" />
</Button>
<Button
variant="ghost"
size="icon"
onClick={() => onNavigate(currentIndex + 1)}
disabled={currentIndex === totalPairs - 1}
className="h-7 w-7"
>
<SkipForward className="h-4 w-4" />
</Button>
</div>
</div>
<Slider
value={[currentIndex]} // Slider value is an array
max={totalPairs - 1}
step={1}
onValueChange={(value) => onNavigate(value[0])} // onValueChange gives an array
/>
</div>
)}
{/* Todo Panel at the bottom of side panel */}
{sandboxId && (
<TodoPanel

View File

@ -0,0 +1,59 @@
'use server'
export const generateThreadName = async (message: string): Promise<string> => {
try {
// Default name in case the API fails
const defaultName = message.trim().length > 50
? message.trim().substring(0, 47) + "..."
: message.trim();
// OpenAI API key should be stored in an environment variable
const apiKey = process.env.OPENAI_API_KEY;
if (!apiKey) {
console.error('OpenAI API key not found');
return defaultName;
}
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`
},
body: JSON.stringify({
model: 'gpt-4o-mini',
messages: [
{
role: 'system',
content: 'You are a helpful assistant that generates extremely concise titles (2-4 words maximum) for chat threads based on the user\'s message. Respond with only the title, no other text or punctuation.'
},
{
role: 'user',
content: `Generate an extremely brief title (2-4 words only) for a chat thread that starts with this message: "${message}"`
}
],
max_tokens: 20,
temperature: 0.7
})
});
if (!response.ok) {
const errorData = await response.text();
console.error('OpenAI API error:', errorData);
return defaultName;
}
const data = await response.json();
const generatedName = data.choices[0]?.message?.content?.trim();
// Return the generated name or default if empty
return generatedName || defaultName;
} catch (error) {
console.error('Error generating thread name:', error);
// Fall back to using a truncated version of the message
return message.trim().length > 50
? message.trim().substring(0, 47) + "..."
: message.trim();
}
};

View File

@ -848,62 +848,4 @@ export const getSandboxFileContent = async (sandboxId: string, path: string): Pr
console.error('Failed to get sandbox file content:', error);
throw error;
}
};
export const generateThreadName = async (message: string): Promise<string> => {
try {
// Default name in case the API fails
const defaultName = message.trim().length > 50
? message.trim().substring(0, 47) + "..."
: message.trim();
// OpenAI API key should be stored in an environment variable
const apiKey = process.env.NEXT_PUBLIC_OPENAI_API_KEY;
if (!apiKey) {
console.error('OpenAI API key not found');
return defaultName;
}
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`
},
body: JSON.stringify({
model: 'gpt-4o-mini',
messages: [
{
role: 'system',
content: 'You are a helpful assistant that generates extremely concise titles (2-4 words maximum) for chat threads based on the user\'s message. Respond with only the title, no other text or punctuation.'
},
{
role: 'user',
content: `Generate an extremely brief title (2-4 words only) for a chat thread that starts with this message: "${message}"`
}
],
max_tokens: 20,
temperature: 0.7
})
});
if (!response.ok) {
const errorData = await response.text();
console.error('OpenAI API error:', errorData);
return defaultName;
}
const data = await response.json();
const generatedName = data.choices[0]?.message?.content?.trim();
// Return the generated name or default if empty
return generatedName || defaultName;
} catch (error) {
console.error('Error generating thread name:', error);
// Fall back to using a truncated version of the message
return message.trim().length > 50
? message.trim().substring(0, 47) + "..."
: message.trim();
}
};