mirror of https://github.com/kortix-ai/suna.git
chore(dev): show custom agent name on thread page
This commit is contained in:
parent
beeaffb533
commit
cb36e534b2
|
@ -72,6 +72,11 @@ class AgentResponse(BaseModel):
|
|||
created_at: str
|
||||
updated_at: str
|
||||
|
||||
class ThreadAgentResponse(BaseModel):
|
||||
agent: Optional[AgentResponse]
|
||||
source: str # "thread", "default", "none", "missing"
|
||||
message: str
|
||||
|
||||
def initialize(
|
||||
_thread_manager: ThreadManager,
|
||||
_db: DBConnection,
|
||||
|
@ -401,6 +406,78 @@ async def get_agent_run(agent_run_id: str, user_id: str = Depends(get_current_us
|
|||
"error": agent_run_data['error']
|
||||
}
|
||||
|
||||
@router.get("/thread/{thread_id}/agent", response_model=ThreadAgentResponse)
|
||||
async def get_thread_agent(thread_id: str, user_id: str = Depends(get_current_user_id_from_jwt)):
|
||||
"""Get the agent details for a specific thread."""
|
||||
logger.info(f"Fetching agent details for thread: {thread_id}")
|
||||
client = await db.client
|
||||
|
||||
try:
|
||||
# Verify thread access and get thread data including agent_id
|
||||
await verify_thread_access(client, thread_id, user_id)
|
||||
thread_result = await client.table('threads').select('agent_id', 'account_id').eq('thread_id', thread_id).execute()
|
||||
|
||||
if not thread_result.data:
|
||||
raise HTTPException(status_code=404, detail="Thread not found")
|
||||
|
||||
thread_data = thread_result.data[0]
|
||||
thread_agent_id = thread_data.get('agent_id')
|
||||
account_id = thread_data.get('account_id')
|
||||
|
||||
# If no agent_id is set in the thread, try to get the default agent
|
||||
effective_agent_id = thread_agent_id
|
||||
agent_source = "thread"
|
||||
|
||||
if not effective_agent_id:
|
||||
# No agent set in thread, get default agent for the account
|
||||
default_agent_result = await client.table('agents').select('agent_id').eq('account_id', account_id).eq('is_default', True).execute()
|
||||
if default_agent_result.data:
|
||||
effective_agent_id = default_agent_result.data[0]['agent_id']
|
||||
agent_source = "default"
|
||||
else:
|
||||
# No default agent found
|
||||
return {
|
||||
"agent": None,
|
||||
"source": "none",
|
||||
"message": "No agent configured for this thread"
|
||||
}
|
||||
|
||||
# Fetch the agent details
|
||||
agent_result = await client.table('agents').select('*').eq('agent_id', effective_agent_id).eq('account_id', account_id).execute()
|
||||
|
||||
if not agent_result.data:
|
||||
# Agent was deleted or doesn't exist
|
||||
return {
|
||||
"agent": None,
|
||||
"source": "missing",
|
||||
"message": f"Agent {effective_agent_id} not found or was deleted"
|
||||
}
|
||||
|
||||
agent_data = agent_result.data[0]
|
||||
|
||||
return {
|
||||
"agent": AgentResponse(
|
||||
agent_id=agent_data['agent_id'],
|
||||
account_id=agent_data['account_id'],
|
||||
name=agent_data['name'],
|
||||
description=agent_data.get('description'),
|
||||
system_prompt=agent_data['system_prompt'],
|
||||
configured_mcps=agent_data.get('configured_mcps', []),
|
||||
agentpress_tools=agent_data.get('agentpress_tools', {}),
|
||||
is_default=agent_data.get('is_default', False),
|
||||
created_at=agent_data['created_at'],
|
||||
updated_at=agent_data['updated_at']
|
||||
),
|
||||
"source": agent_source,
|
||||
"message": f"Using {agent_source} agent: {agent_data['name']}"
|
||||
}
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error fetching agent for thread {thread_id}: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=f"Failed to fetch thread agent: {str(e)}")
|
||||
|
||||
@router.get("/agent-run/{agent_run_id}/stream")
|
||||
async def stream_agent_run(
|
||||
agent_run_id: str,
|
||||
|
|
|
@ -23,7 +23,6 @@ import {
|
|||
} from '@/lib/api';
|
||||
import { toast } from 'sonner';
|
||||
import { ChatInput } from '@/components/thread/chat-input/chat-input';
|
||||
import { AgentSelector } from '@/components/thread/chat-input/agent-selector';
|
||||
import { FileViewerModal } from '@/components/thread/file-viewer-modal';
|
||||
import { SiteHeader } from '@/components/thread/thread-site-header';
|
||||
import {
|
||||
|
@ -47,6 +46,7 @@ import {
|
|||
DialogFooter,
|
||||
} from '@/components/ui/dialog';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Skeleton } from '@/components/ui/skeleton';
|
||||
|
||||
import {
|
||||
UnifiedMessage,
|
||||
|
@ -63,6 +63,7 @@ import { useAgentRunsQuery, useStartAgentMutation, useStopAgentMutation } from '
|
|||
import { useBillingStatusQuery } from '@/hooks/react-query/threads/use-billing-status';
|
||||
import { useSubscription, isPlan } from '@/hooks/react-query/subscriptions/use-subscriptions';
|
||||
import { SubscriptionStatus } from '@/components/thread/chat-input/_use-model-selection';
|
||||
import { useThreadAgent } from '@/hooks/react-query/agents/use-agents';
|
||||
|
||||
// Extend the base Message type with the expected database fields
|
||||
interface ApiMessageType extends BaseApiMessageType {
|
||||
|
@ -136,6 +137,7 @@ export default function ThreadPage({
|
|||
const messagesLoadedRef = useRef(false);
|
||||
const agentRunsCheckedRef = useRef(false);
|
||||
const previousAgentStatus = useRef<typeof agentStatus>('idle');
|
||||
const { data: threadAgent, isLoading: threadAgentLoading, error: threadAgentError } = useThreadAgent(threadId);
|
||||
|
||||
const [externalNavIndex, setExternalNavIndex] = React.useState<number | undefined>(undefined);
|
||||
|
||||
|
@ -1223,19 +1225,27 @@ export default function ThreadPage({
|
|||
"mx-auto",
|
||||
isMobile ? "w-full px-4" : "max-w-3xl"
|
||||
)}>
|
||||
<ChatInput
|
||||
value={newMessage}
|
||||
onChange={setNewMessage}
|
||||
onSubmit={handleSubmitMessage}
|
||||
placeholder="Ask Suna anything..."
|
||||
loading={isSending}
|
||||
disabled={isSending || agentStatus === 'running' || agentStatus === 'connecting'}
|
||||
isAgentRunning={agentStatus === 'running' || agentStatus === 'connecting'}
|
||||
onStopAgent={handleStopAgent}
|
||||
autoFocus={!isLoading}
|
||||
onFileBrowse={handleOpenFileViewer}
|
||||
sandboxId={sandboxId || undefined}
|
||||
/>
|
||||
{threadAgentLoading || threadAgentError ? (
|
||||
<div className="space-y-3">
|
||||
<Skeleton className="h-4 w-32" />
|
||||
<Skeleton className="h-12 w-full rounded-lg" />
|
||||
</div>
|
||||
) : (
|
||||
<ChatInput
|
||||
value={newMessage}
|
||||
onChange={setNewMessage}
|
||||
onSubmit={handleSubmitMessage}
|
||||
placeholder={`Ask ${threadAgent?.agent?.name || 'Suna'} anything...`}
|
||||
loading={isSending}
|
||||
disabled={isSending || agentStatus === 'running' || agentStatus === 'connecting'}
|
||||
isAgentRunning={agentStatus === 'running' || agentStatus === 'connecting'}
|
||||
onStopAgent={handleStopAgent}
|
||||
autoFocus={!isLoading}
|
||||
onFileBrowse={handleOpenFileViewer}
|
||||
sandboxId={sandboxId || undefined}
|
||||
agentName={threadAgent?.agent?.name || 'Suna'}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1257,6 +1267,7 @@ export default function ThreadPage({
|
|||
renderAssistantMessage={toolViewAssistant}
|
||||
renderToolResult={toolViewResult}
|
||||
isLoading={!initialLoadCompleted.current || isLoading}
|
||||
agentName={threadAgentLoading ? 'Loading...' : (threadAgent?.agent?.name || 'Suna')}
|
||||
/>
|
||||
|
||||
{sandboxId && (
|
||||
|
|
|
@ -129,7 +129,7 @@ export function AgentSelector({
|
|||
)}
|
||||
</div>
|
||||
<span className="text-xs text-muted-foreground pl-6 line-clamp-2">
|
||||
Your personal AI assistant
|
||||
Your personal AI employee
|
||||
</span>
|
||||
</DropdownMenuItem>
|
||||
{agents.length > 0 ? (
|
||||
|
@ -227,7 +227,7 @@ export function AgentSelector({
|
|||
</span>
|
||||
) : isUsingSuna ? (
|
||||
<span className="text-xs text-muted-foreground line-clamp-1 max-w-[150px]">
|
||||
Your personal AI assistant
|
||||
Your personal AI employee
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
|
@ -254,7 +254,7 @@ export function AgentSelector({
|
|||
)}
|
||||
</div>
|
||||
<span className="text-xs text-muted-foreground pl-6 line-clamp-2">
|
||||
Your personal AI assistant
|
||||
Your personal AI employee
|
||||
</span>
|
||||
</DropdownMenuItem>
|
||||
{agents.length > 0 ? (
|
||||
|
|
|
@ -39,6 +39,7 @@ export interface ChatInputProps {
|
|||
hideAttachments?: boolean;
|
||||
selectedAgentId?: string;
|
||||
onAgentSelect?: (agentId: string | undefined) => void;
|
||||
agentName?: string;
|
||||
}
|
||||
|
||||
export interface UploadedFile {
|
||||
|
@ -66,6 +67,7 @@ export const ChatInput = forwardRef<ChatInputHandles, ChatInputProps>(
|
|||
hideAttachments = false,
|
||||
selectedAgentId,
|
||||
onAgentSelect,
|
||||
agentName,
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
|
@ -263,7 +265,7 @@ export const ChatInput = forwardRef<ChatInputHandles, ChatInputProps>(
|
|||
>
|
||||
<div className="text-xs text-muted-foreground flex items-center gap-2">
|
||||
<Loader2 className="h-3 w-3 animate-spin" />
|
||||
<span>Kortix Suna is working...</span>
|
||||
<span>{agentName ? `${agentName} is working...` : 'Suna is working...'}</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
|
|
|
@ -45,6 +45,7 @@ interface ToolCallSidePanelProps {
|
|||
isSuccess?: boolean,
|
||||
) => React.ReactNode;
|
||||
isLoading?: boolean;
|
||||
agentName?: string;
|
||||
}
|
||||
|
||||
interface ToolCallSnapshot {
|
||||
|
@ -65,6 +66,7 @@ export function ToolCallSidePanel({
|
|||
project,
|
||||
isLoading = false,
|
||||
externalNavigateToIndex,
|
||||
agentName
|
||||
}: ToolCallSidePanelProps) {
|
||||
const [dots, setDots] = React.useState('');
|
||||
const [internalIndex, setInternalIndex] = React.useState(0);
|
||||
|
@ -233,7 +235,7 @@ export function ToolCallSidePanel({
|
|||
<div className="ml-2 flex items-center gap-2">
|
||||
<Computer className="h-4 w-4" />
|
||||
<h2 className="text-md font-medium text-zinc-900 dark:text-zinc-100">
|
||||
Computer View
|
||||
{agentName ? `${agentName}'s Computer` : 'Suna\'s Computer'}
|
||||
</h2>
|
||||
</div>
|
||||
<Button
|
||||
|
@ -269,7 +271,7 @@ export function ToolCallSidePanel({
|
|||
<div className="ml-2 flex items-center gap-2">
|
||||
<Computer className="h-4 w-4" />
|
||||
<h2 className="text-md font-medium text-zinc-900 dark:text-zinc-100">
|
||||
Computer View
|
||||
{agentName ? `${agentName}'s Computer` : 'Suna\'s Computer'}
|
||||
</h2>
|
||||
</div>
|
||||
<Button
|
||||
|
@ -330,7 +332,7 @@ export function ToolCallSidePanel({
|
|||
<div className="ml-2 flex items-center gap-2">
|
||||
<Computer className="h-4 w-4" />
|
||||
<h2 className="text-md font-medium text-zinc-900 dark:text-zinc-100">
|
||||
Computer View
|
||||
{agentName ? `${agentName}'s Computer` : 'Suna\'s Computer'}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import { createQueryKeys } from "@/hooks/use-query";
|
||||
|
||||
export const agentKeys = createQueryKeys({
|
||||
all: ['agents'] as const,
|
||||
lists: () => [...agentKeys.all, 'list'] as const,
|
||||
list: (filters?: Record<string, any>) => [...agentKeys.lists(), filters] as const,
|
||||
details: () => [...agentKeys.all, 'detail'] as const,
|
||||
detail: (id: string) => [...agentKeys.details(), id] as const,
|
||||
});
|
||||
all: ['agents'] as const,
|
||||
lists: () => [...agentKeys.all, 'list'] as const,
|
||||
list: (filters?: Record<string, any>) => [...agentKeys.lists(), filters] as const,
|
||||
details: () => [...agentKeys.all, 'detail'] as const,
|
||||
detail: (id: string) => [...agentKeys.details(), id] as const,
|
||||
threadAgents: () => [...agentKeys.all, 'thread-agent'] as const,
|
||||
threadAgent: (threadId: string) => [...agentKeys.threadAgents(), threadId] as const,
|
||||
});
|
|
@ -2,7 +2,7 @@ import { createMutationHook, createQueryHook } from '@/hooks/use-query';
|
|||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { toast } from 'sonner';
|
||||
import { agentKeys } from './keys';
|
||||
import { Agent, AgentUpdateRequest, createAgent, deleteAgent, getAgent, getAgents, updateAgent } from './utils';
|
||||
import { Agent, AgentUpdateRequest, createAgent, deleteAgent, getAgent, getAgents, getThreadAgent, updateAgent } from './utils';
|
||||
|
||||
export const useAgents = createQueryHook(
|
||||
agentKeys.list(),
|
||||
|
@ -91,4 +91,16 @@ export const useOptimisticAgentUpdate = () => {
|
|||
queryClient.invalidateQueries({ queryKey: agentKeys.detail(agentId) });
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const useThreadAgent = (threadId: string) => {
|
||||
return createQueryHook(
|
||||
agentKeys.threadAgent(threadId),
|
||||
() => getThreadAgent(threadId),
|
||||
{
|
||||
enabled: !!threadId,
|
||||
staleTime: 5 * 60 * 1000,
|
||||
gcTime: 10 * 60 * 1000,
|
||||
}
|
||||
)();
|
||||
};
|
|
@ -3,197 +3,234 @@ import { createClient } from "@/lib/supabase/client";
|
|||
const API_URL = process.env.NEXT_PUBLIC_BACKEND_URL || '';
|
||||
|
||||
export type Agent = {
|
||||
agent_id: string;
|
||||
account_id: string;
|
||||
agent_id: string;
|
||||
account_id: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
system_prompt: string;
|
||||
configured_mcps: Array<{
|
||||
name: string;
|
||||
description?: string;
|
||||
system_prompt: string;
|
||||
configured_mcps: Array<{
|
||||
name: string;
|
||||
config: Record<string, any>;
|
||||
}>;
|
||||
agentpress_tools: Record<string, any>;
|
||||
is_default: boolean;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
};
|
||||
|
||||
export type AgentCreateRequest = {
|
||||
config: Record<string, any>;
|
||||
}>;
|
||||
agentpress_tools: Record<string, any>;
|
||||
is_default: boolean;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
};
|
||||
|
||||
export type ThreadAgentResponse = {
|
||||
agent: Agent | null;
|
||||
source: 'thread' | 'default' | 'none' | 'missing';
|
||||
message: string;
|
||||
};
|
||||
|
||||
export type AgentCreateRequest = {
|
||||
name: string;
|
||||
description?: string;
|
||||
system_prompt: string;
|
||||
configured_mcps?: Array<{
|
||||
name: string;
|
||||
description?: string;
|
||||
system_prompt: string;
|
||||
configured_mcps?: Array<{
|
||||
name: string;
|
||||
config: Record<string, any>;
|
||||
}>;
|
||||
agentpress_tools?: Record<string, any>;
|
||||
is_default?: boolean;
|
||||
};
|
||||
|
||||
export type AgentUpdateRequest = {
|
||||
name?: string;
|
||||
description?: string;
|
||||
system_prompt?: string;
|
||||
configured_mcps?: Array<{
|
||||
name: string;
|
||||
config: Record<string, any>;
|
||||
}>;
|
||||
agentpress_tools?: Record<string, any>;
|
||||
is_default?: boolean;
|
||||
};
|
||||
|
||||
export const getAgents = async (): Promise<Agent[]> => {
|
||||
try {
|
||||
const supabase = createClient();
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
|
||||
if (!session) {
|
||||
throw new Error('You must be logged in to get agents');
|
||||
}
|
||||
|
||||
const response = await fetch(`${API_URL}/agents`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${session.access_token}`,
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({ message: 'Unknown error' }));
|
||||
throw new Error(errorData.message || `HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const agents = await response.json();
|
||||
console.log('[API] Fetched agents:', agents.length);
|
||||
return agents;
|
||||
} catch (err) {
|
||||
console.error('Error fetching agents:', err);
|
||||
throw err;
|
||||
config: Record<string, any>;
|
||||
}>;
|
||||
agentpress_tools?: Record<string, any>;
|
||||
is_default?: boolean;
|
||||
};
|
||||
|
||||
export type AgentUpdateRequest = {
|
||||
name?: string;
|
||||
description?: string;
|
||||
system_prompt?: string;
|
||||
configured_mcps?: Array<{
|
||||
name: string;
|
||||
config: Record<string, any>;
|
||||
}>;
|
||||
agentpress_tools?: Record<string, any>;
|
||||
is_default?: boolean;
|
||||
};
|
||||
|
||||
export const getAgents = async (): Promise<Agent[]> => {
|
||||
try {
|
||||
const supabase = createClient();
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
|
||||
if (!session) {
|
||||
throw new Error('You must be logged in to get agents');
|
||||
}
|
||||
};
|
||||
|
||||
export const getAgent = async (agentId: string): Promise<Agent> => {
|
||||
try {
|
||||
const supabase = createClient();
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
|
||||
if (!session) {
|
||||
throw new Error('You must be logged in to get agent details');
|
||||
}
|
||||
|
||||
const response = await fetch(`${API_URL}/agents/${agentId}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${session.access_token}`,
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({ message: 'Unknown error' }));
|
||||
throw new Error(errorData.message || `HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const agent = await response.json();
|
||||
console.log('[API] Fetched agent:', agent.agent_id);
|
||||
return agent;
|
||||
} catch (err) {
|
||||
console.error('Error fetching agent:', err);
|
||||
throw err;
|
||||
|
||||
const response = await fetch(`${API_URL}/agents`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${session.access_token}`,
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({ message: 'Unknown error' }));
|
||||
throw new Error(errorData.message || `HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
};
|
||||
|
||||
export const createAgent = async (agentData: AgentCreateRequest): Promise<Agent> => {
|
||||
try {
|
||||
const supabase = createClient();
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
|
||||
if (!session) {
|
||||
throw new Error('You must be logged in to create an agent');
|
||||
}
|
||||
|
||||
const response = await fetch(`${API_URL}/agents`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${session.access_token}`,
|
||||
},
|
||||
body: JSON.stringify(agentData),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({ message: 'Unknown error' }));
|
||||
throw new Error(errorData.message || `HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const agent = await response.json();
|
||||
console.log('[API] Created agent:', agent.agent_id);
|
||||
return agent;
|
||||
} catch (err) {
|
||||
console.error('Error creating agent:', err);
|
||||
throw err;
|
||||
|
||||
const agents = await response.json();
|
||||
console.log('[API] Fetched agents:', agents.length);
|
||||
return agents;
|
||||
} catch (err) {
|
||||
console.error('Error fetching agents:', err);
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
export const getAgent = async (agentId: string): Promise<Agent> => {
|
||||
try {
|
||||
const supabase = createClient();
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
|
||||
if (!session) {
|
||||
throw new Error('You must be logged in to get agent details');
|
||||
}
|
||||
};
|
||||
|
||||
export const updateAgent = async (agentId: string, agentData: AgentUpdateRequest): Promise<Agent> => {
|
||||
try {
|
||||
const supabase = createClient();
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
|
||||
if (!session) {
|
||||
throw new Error('You must be logged in to update an agent');
|
||||
}
|
||||
|
||||
const response = await fetch(`${API_URL}/agents/${agentId}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${session.access_token}`,
|
||||
},
|
||||
body: JSON.stringify(agentData),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({ message: 'Unknown error' }));
|
||||
throw new Error(errorData.message || `HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const agent = await response.json();
|
||||
console.log('[API] Updated agent:', agent.agent_id);
|
||||
return agent;
|
||||
} catch (err) {
|
||||
console.error('Error updating agent:', err);
|
||||
throw err;
|
||||
|
||||
const response = await fetch(`${API_URL}/agents/${agentId}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${session.access_token}`,
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({ message: 'Unknown error' }));
|
||||
throw new Error(errorData.message || `HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteAgent = async (agentId: string): Promise<void> => {
|
||||
try {
|
||||
const supabase = createClient();
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
|
||||
if (!session) {
|
||||
throw new Error('You must be logged in to delete an agent');
|
||||
}
|
||||
|
||||
const response = await fetch(`${API_URL}/agents/${agentId}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${session.access_token}`,
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({ message: 'Unknown error' }));
|
||||
throw new Error(errorData.message || `HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
console.log('[API] Deleted agent:', agentId);
|
||||
} catch (err) {
|
||||
console.error('Error deleting agent:', err);
|
||||
throw err;
|
||||
|
||||
const agent = await response.json();
|
||||
console.log('[API] Fetched agent:', agent.agent_id);
|
||||
return agent;
|
||||
} catch (err) {
|
||||
console.error('Error fetching agent:', err);
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
export const createAgent = async (agentData: AgentCreateRequest): Promise<Agent> => {
|
||||
try {
|
||||
const supabase = createClient();
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
|
||||
if (!session) {
|
||||
throw new Error('You must be logged in to create an agent');
|
||||
}
|
||||
};
|
||||
|
||||
const response = await fetch(`${API_URL}/agents`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${session.access_token}`,
|
||||
},
|
||||
body: JSON.stringify(agentData),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({ message: 'Unknown error' }));
|
||||
throw new Error(errorData.message || `HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const agent = await response.json();
|
||||
console.log('[API] Created agent:', agent.agent_id);
|
||||
return agent;
|
||||
} catch (err) {
|
||||
console.error('Error creating agent:', err);
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
export const updateAgent = async (agentId: string, agentData: AgentUpdateRequest): Promise<Agent> => {
|
||||
try {
|
||||
const supabase = createClient();
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
|
||||
if (!session) {
|
||||
throw new Error('You must be logged in to update an agent');
|
||||
}
|
||||
|
||||
const response = await fetch(`${API_URL}/agents/${agentId}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${session.access_token}`,
|
||||
},
|
||||
body: JSON.stringify(agentData),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({ message: 'Unknown error' }));
|
||||
throw new Error(errorData.message || `HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const agent = await response.json();
|
||||
console.log('[API] Updated agent:', agent.agent_id);
|
||||
return agent;
|
||||
} catch (err) {
|
||||
console.error('Error updating agent:', err);
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteAgent = async (agentId: string): Promise<void> => {
|
||||
try {
|
||||
const supabase = createClient();
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
|
||||
if (!session) {
|
||||
throw new Error('You must be logged in to delete an agent');
|
||||
}
|
||||
|
||||
const response = await fetch(`${API_URL}/agents/${agentId}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${session.access_token}`,
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({ message: 'Unknown error' }));
|
||||
throw new Error(errorData.message || `HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
console.log('[API] Deleted agent:', agentId);
|
||||
} catch (err) {
|
||||
console.error('Error deleting agent:', err);
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
export const getThreadAgent = async (threadId: string): Promise<ThreadAgentResponse> => {
|
||||
try {
|
||||
const supabase = createClient();
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
|
||||
if (!session) {
|
||||
throw new Error('You must be logged in to get thread agent details');
|
||||
}
|
||||
|
||||
const response = await fetch(`${API_URL}/thread/${threadId}/agent`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${session.access_token}`,
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({ message: 'Unknown error' }));
|
||||
throw new Error(errorData.message || `HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const threadAgent = await response.json();
|
||||
console.log('[API] Fetched thread agent:', threadAgent.source, threadAgent.agent?.name);
|
||||
return threadAgent;
|
||||
} catch (err) {
|
||||
console.error('Error fetching thread agent:', err);
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue