mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
Merge branch 'hackathon/copilot' of github.com:Significant-Gravitas/AutoGPT into hackathon/copilot
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
.PHONY: start-core stop-core logs-core format lint migrate run-backend run-frontend load-store-agents
|
||||
.PHONY: start-core stop-core logs-core format lint migrate run-backend stop-backend run-frontend load-store-agents
|
||||
|
||||
# Run just Supabase + Redis + RabbitMQ
|
||||
start-core:
|
||||
@@ -34,7 +34,14 @@ migrate:
|
||||
cd backend && poetry run prisma migrate deploy
|
||||
cd backend && poetry run prisma generate
|
||||
|
||||
run-backend:
|
||||
stop-backend:
|
||||
@echo "Stopping backend processes..."
|
||||
@cd backend && poetry run cli stop 2>/dev/null || true
|
||||
@echo "Killing any processes using backend ports..."
|
||||
@lsof -ti:8001,8002,8003,8004,8005,8006,8007 | xargs kill -9 2>/dev/null || true
|
||||
@echo "Backend stopped"
|
||||
|
||||
run-backend: stop-backend
|
||||
cd backend && poetry run app
|
||||
|
||||
run-frontend:
|
||||
@@ -55,7 +62,8 @@ help:
|
||||
@echo " logs-core - Tail the logs for core services"
|
||||
@echo " format - Format & lint backend (Python) and frontend (TypeScript) code"
|
||||
@echo " migrate - Run backend database migrations"
|
||||
@echo " run-backend - Run the backend FastAPI server"
|
||||
@echo " stop-backend - Stop any running backend processes"
|
||||
@echo " run-backend - Run the backend FastAPI server (stops existing processes first)"
|
||||
@echo " run-frontend - Run the frontend Next.js development server"
|
||||
@echo " test-data - Run the test data creator"
|
||||
@echo " load-store-agents - Load store agents from agents/ folder into test database"
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Alert, AlertDescription } from "@/components/molecules/Alert/Alert";
|
||||
import { Text } from "@/components/atoms/Text/Text";
|
||||
import Link from "next/link";
|
||||
import { useGetV2GetLibraryAgentByGraphId } from "@/app/api/__generated__/endpoints/library/library";
|
||||
import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent";
|
||||
import { useQueryStates, parseAsString } from "nuqs";
|
||||
import { isValidUUID } from "@/app/(platform)/chat/helpers";
|
||||
import { Text } from "@/components/atoms/Text/Text";
|
||||
import { isValidUUID } from "@/components/contextual/Chat/helpers";
|
||||
import { Alert, AlertDescription } from "@/components/molecules/Alert/Alert";
|
||||
import Link from "next/link";
|
||||
import { parseAsString, useQueryStates } from "nuqs";
|
||||
|
||||
export const WebhookDisclaimer = ({ nodeId }: { nodeId: string }) => {
|
||||
const [{ flowID }] = useQueryStates({
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
"use client";
|
||||
|
||||
import { useChatPage } from "./useChatPage";
|
||||
import { ChatContainer } from "./components/ChatContainer/ChatContainer";
|
||||
import { ChatErrorState } from "./components/ChatErrorState/ChatErrorState";
|
||||
import { ChatLoadingState } from "./components/ChatLoadingState/ChatLoadingState";
|
||||
import { useGetFlag, Flag } from "@/services/feature-flags/use-get-flag";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Button } from "@/components/__legacy__/ui/button";
|
||||
import { scrollbarStyles } from "@/components/styles/scrollbars";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Flag, useGetFlag } from "@/services/feature-flags/use-get-flag";
|
||||
import { X } from "@phosphor-icons/react";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
import { useEffect } from "react";
|
||||
import { Drawer } from "vaul";
|
||||
|
||||
import { ChatContainer } from "@/components/contextual/Chat/components/ChatContainer/ChatContainer";
|
||||
import { ChatErrorState } from "@/components/contextual/Chat/components/ChatErrorState/ChatErrorState";
|
||||
import { ChatLoadingState } from "@/components/contextual/Chat/components/ChatLoadingState/ChatLoadingState";
|
||||
import { useChatPage } from "./useChatPage";
|
||||
|
||||
export default function ChatPage() {
|
||||
const isChatEnabled = useGetFlag(Flag.CHAT);
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const isOpen = pathname === "/chat";
|
||||
const {
|
||||
messages,
|
||||
isLoading,
|
||||
@@ -28,56 +36,88 @@ export default function ChatPage() {
|
||||
}
|
||||
}, [isChatEnabled, router]);
|
||||
|
||||
function handleOpenChange(open: boolean) {
|
||||
if (!open) {
|
||||
router.replace("/marketplace");
|
||||
}
|
||||
}
|
||||
|
||||
if (isChatEnabled === null || isChatEnabled === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex h-full flex-col">
|
||||
{/* Header */}
|
||||
<header className="border-b border-zinc-200 bg-white p-4 dark:border-zinc-800 dark:bg-zinc-900">
|
||||
<div className="container mx-auto flex items-center justify-between">
|
||||
<h1 className="text-xl font-semibold">Chat</h1>
|
||||
{sessionId && (
|
||||
<div className="flex items-center gap-4">
|
||||
<span className="text-sm text-zinc-600 dark:text-zinc-400">
|
||||
Session: {sessionId.slice(0, 8)}...
|
||||
</span>
|
||||
<button
|
||||
onClick={clearSession}
|
||||
className="text-sm text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-100"
|
||||
>
|
||||
New Chat
|
||||
</button>
|
||||
</div>
|
||||
<Drawer.Root
|
||||
open={isOpen}
|
||||
onOpenChange={handleOpenChange}
|
||||
direction="right"
|
||||
modal={false}
|
||||
>
|
||||
<Drawer.Portal>
|
||||
<Drawer.Content
|
||||
className={cn(
|
||||
"fixed right-0 top-0 z-50 flex h-full w-1/2 flex-col border-l border-zinc-200 bg-white dark:border-zinc-800 dark:bg-zinc-900",
|
||||
scrollbarStyles,
|
||||
)}
|
||||
</div>
|
||||
</header>
|
||||
>
|
||||
{/* Header */}
|
||||
<header className="shrink-0 border-b border-zinc-200 bg-white p-4 dark:border-zinc-800 dark:bg-zinc-900">
|
||||
<div className="flex items-center justify-between">
|
||||
<Drawer.Title className="text-xl font-semibold">
|
||||
Chat
|
||||
</Drawer.Title>
|
||||
<div className="flex items-center gap-4">
|
||||
{sessionId && (
|
||||
<>
|
||||
<span className="text-sm text-zinc-600 dark:text-zinc-400">
|
||||
Session: {sessionId.slice(0, 8)}...
|
||||
</span>
|
||||
<button
|
||||
onClick={clearSession}
|
||||
className="text-sm text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-100"
|
||||
>
|
||||
New Chat
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
<Button
|
||||
variant="link"
|
||||
aria-label="Close"
|
||||
onClick={() => handleOpenChange(false)}
|
||||
className="!focus-visible:ring-0 p-0"
|
||||
>
|
||||
<X width="1.5rem" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Main Content */}
|
||||
<main className="container mx-auto flex flex-1 flex-col overflow-hidden">
|
||||
{/* Loading State - show when explicitly loading/creating OR when we don't have a session yet and no error */}
|
||||
{(isLoading || isCreating || (!sessionId && !error)) && (
|
||||
<ChatLoadingState
|
||||
message={isCreating ? "Creating session..." : "Loading..."}
|
||||
/>
|
||||
)}
|
||||
{/* Main Content */}
|
||||
<main className="flex min-h-0 flex-1 flex-col overflow-hidden">
|
||||
{/* Loading State - show when explicitly loading/creating OR when we don't have a session yet and no error */}
|
||||
{(isLoading || isCreating || (!sessionId && !error)) && (
|
||||
<ChatLoadingState
|
||||
message={isCreating ? "Creating session..." : "Loading..."}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Error State */}
|
||||
{error && !isLoading && (
|
||||
<ChatErrorState error={error} onRetry={createSession} />
|
||||
)}
|
||||
{/* Error State */}
|
||||
{error && !isLoading && (
|
||||
<ChatErrorState error={error} onRetry={createSession} />
|
||||
)}
|
||||
|
||||
{/* Session Content */}
|
||||
{sessionId && !isLoading && !error && (
|
||||
<ChatContainer
|
||||
sessionId={sessionId}
|
||||
initialMessages={messages}
|
||||
onRefreshSession={refreshSession}
|
||||
className="flex-1"
|
||||
/>
|
||||
)}
|
||||
</main>
|
||||
</div>
|
||||
{/* Session Content */}
|
||||
{sessionId && !isLoading && !error && (
|
||||
<ChatContainer
|
||||
sessionId={sessionId}
|
||||
initialMessages={messages}
|
||||
onRefreshSession={refreshSession}
|
||||
className="flex-1"
|
||||
/>
|
||||
)}
|
||||
</main>
|
||||
</Drawer.Content>
|
||||
</Drawer.Portal>
|
||||
</Drawer.Root>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef } from "react";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import { toast } from "sonner";
|
||||
import { useChatSession } from "@/app/(platform)/chat/useChatSession";
|
||||
import { useChatSession } from "@/components/contextual/Chat/useChatSession";
|
||||
import { useChatStream } from "@/components/contextual/Chat/useChatStream";
|
||||
import { useSupabase } from "@/lib/supabase/hooks/useSupabase";
|
||||
import { useChatStream } from "@/app/(platform)/chat/useChatStream";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
export function useChatPage() {
|
||||
const router = useRouter();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ChatDrawer } from "@/components/contextual/Chat/ChatDrawer";
|
||||
import { Navbar } from "@/components/layout/Navbar/Navbar";
|
||||
import { AdminImpersonationBanner } from "./admin/components/AdminImpersonationBanner";
|
||||
import { ReactNode } from "react";
|
||||
import { AdminImpersonationBanner } from "./admin/components/AdminImpersonationBanner";
|
||||
|
||||
export default function PlatformLayout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
@@ -8,6 +9,7 @@ export default function PlatformLayout({ children }: { children: ReactNode }) {
|
||||
<Navbar />
|
||||
<AdminImpersonationBanner />
|
||||
<section className="flex-1">{children}</section>
|
||||
<ChatDrawer />
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@/components/__legacy__/ui/button";
|
||||
import { scrollbarStyles } from "@/components/styles/scrollbars";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Flag, useGetFlag } from "@/services/feature-flags/use-get-flag";
|
||||
import { X } from "@phosphor-icons/react";
|
||||
import { useEffect } from "react";
|
||||
import { Drawer } from "vaul";
|
||||
import { ChatContainer } from "./components/ChatContainer/ChatContainer";
|
||||
import { ChatErrorState } from "./components/ChatErrorState/ChatErrorState";
|
||||
import { ChatLoadingState } from "./components/ChatLoadingState/ChatLoadingState";
|
||||
import { useChat } from "./useChat";
|
||||
import { useChatDrawer } from "./useChatDrawer";
|
||||
|
||||
export function ChatDrawer() {
|
||||
const isChatEnabled = useGetFlag(Flag.CHAT);
|
||||
const { isOpen, close } = useChatDrawer();
|
||||
const {
|
||||
messages,
|
||||
isLoading,
|
||||
isCreating,
|
||||
error,
|
||||
sessionId,
|
||||
createSession,
|
||||
clearSession,
|
||||
refreshSession,
|
||||
} = useChat();
|
||||
|
||||
useEffect(() => {
|
||||
if (isChatEnabled === false && isOpen) {
|
||||
close();
|
||||
}
|
||||
}, [isChatEnabled, isOpen, close]);
|
||||
|
||||
if (isChatEnabled === null || isChatEnabled === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Drawer.Root
|
||||
open={isOpen}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) {
|
||||
close();
|
||||
}
|
||||
}}
|
||||
direction="right"
|
||||
modal={false}
|
||||
>
|
||||
<Drawer.Portal>
|
||||
<Drawer.Content
|
||||
className={cn(
|
||||
"fixed right-0 top-0 z-50 flex h-full w-1/2 flex-col border-l border-zinc-200 bg-white dark:border-zinc-800 dark:bg-zinc-900",
|
||||
scrollbarStyles,
|
||||
)}
|
||||
>
|
||||
{/* Header */}
|
||||
<header className="shrink-0 border-b border-zinc-200 bg-white p-4 dark:border-zinc-800 dark:bg-zinc-900">
|
||||
<div className="flex items-center justify-between">
|
||||
<Drawer.Title className="text-xl font-semibold">
|
||||
Chat
|
||||
</Drawer.Title>
|
||||
<div className="flex items-center gap-4">
|
||||
{sessionId && (
|
||||
<>
|
||||
<span className="text-sm text-zinc-600 dark:text-zinc-400">
|
||||
Session: {sessionId.slice(0, 8)}...
|
||||
</span>
|
||||
<button
|
||||
onClick={clearSession}
|
||||
className="text-sm text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-100"
|
||||
>
|
||||
New Chat
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
<Button
|
||||
variant="link"
|
||||
aria-label="Close"
|
||||
onClick={close}
|
||||
className="!focus-visible:ring-0 p-0"
|
||||
>
|
||||
<X width="1.5rem" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Main Content */}
|
||||
<main className="flex min-h-0 flex-1 flex-col overflow-hidden">
|
||||
{/* Loading State - show when explicitly loading/creating OR when we don't have a session yet and no error */}
|
||||
{(isLoading || isCreating || (!sessionId && !error)) && (
|
||||
<ChatLoadingState
|
||||
message={isCreating ? "Creating session..." : "Loading..."}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Error State */}
|
||||
{error && !isLoading && (
|
||||
<ChatErrorState error={error} onRetry={createSession} />
|
||||
)}
|
||||
|
||||
{/* Session Content */}
|
||||
{sessionId && !isLoading && !error && (
|
||||
<ChatContainer
|
||||
sessionId={sessionId}
|
||||
initialMessages={messages}
|
||||
onRefreshSession={refreshSession}
|
||||
className="flex-1"
|
||||
/>
|
||||
)}
|
||||
</main>
|
||||
</Drawer.Content>
|
||||
</Drawer.Portal>
|
||||
</Drawer.Root>
|
||||
);
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
import { ChatInput } from "@/app/(platform)/chat/components/ChatInput/ChatInput";
|
||||
import { MessageList } from "@/app/(platform)/chat/components/MessageList/MessageList";
|
||||
import { QuickActionsWelcome } from "@/app/(platform)/chat/components/QuickActionsWelcome/QuickActionsWelcome";
|
||||
import { useChatContainer } from "./useChatContainer";
|
||||
import type { SessionDetailResponse } from "@/app/api/__generated__/models/sessionDetailResponse";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { ChatInput } from "../ChatInput/ChatInput";
|
||||
import { MessageList } from "../MessageList/MessageList";
|
||||
import { QuickActionsWelcome } from "../QuickActionsWelcome/QuickActionsWelcome";
|
||||
import { useChatContainer } from "./useChatContainer";
|
||||
|
||||
export interface ChatContainerProps {
|
||||
sessionId: string | null;
|
||||
@@ -1,14 +1,14 @@
|
||||
import type { StreamChunk } from "@/components/contextual/Chat/useChatStream";
|
||||
import { toast } from "sonner";
|
||||
import type { StreamChunk } from "@/app/(platform)/chat/useChatStream";
|
||||
import type { HandlerDependencies } from "./useChatContainer.handlers";
|
||||
import {
|
||||
handleError,
|
||||
handleLoginNeeded,
|
||||
handleStreamEnd,
|
||||
handleTextChunk,
|
||||
handleTextEnded,
|
||||
handleToolCallStart,
|
||||
handleToolResponse,
|
||||
handleLoginNeeded,
|
||||
handleStreamEnd,
|
||||
handleError,
|
||||
} from "./useChatContainer.handlers";
|
||||
|
||||
export function createStreamEventDispatcher(
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { ChatMessageData } from "@/app/(platform)/chat/components/ChatMessage/useChatMessage";
|
||||
import type { ToolResult } from "@/types/chat";
|
||||
import type { ChatMessageData } from "../ChatMessage/useChatMessage";
|
||||
|
||||
export function createUserMessage(content: string): ChatMessageData {
|
||||
return {
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { Dispatch, SetStateAction, MutableRefObject } from "react";
|
||||
import type { StreamChunk } from "@/app/(platform)/chat/useChatStream";
|
||||
import type { ChatMessageData } from "@/app/(platform)/chat/components/ChatMessage/useChatMessage";
|
||||
import { parseToolResponse, extractCredentialsNeeded } from "./helpers";
|
||||
import type { StreamChunk } from "@/components/contextual/Chat/useChatStream";
|
||||
import type { Dispatch, MutableRefObject, SetStateAction } from "react";
|
||||
import type { ChatMessageData } from "../ChatMessage/useChatMessage";
|
||||
import { extractCredentialsNeeded, parseToolResponse } from "./helpers";
|
||||
|
||||
export interface HandlerDependencies {
|
||||
setHasTextChunks: Dispatch<SetStateAction<boolean>>;
|
||||
@@ -1,16 +1,16 @@
|
||||
import { useState, useCallback, useRef, useMemo } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { useChatStream } from "@/app/(platform)/chat/useChatStream";
|
||||
import type { SessionDetailResponse } from "@/app/api/__generated__/models/sessionDetailResponse";
|
||||
import type { ChatMessageData } from "@/app/(platform)/chat/components/ChatMessage/useChatMessage";
|
||||
import { useChatStream } from "@/components/contextual/Chat/useChatStream";
|
||||
import { useCallback, useMemo, useRef, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import type { ChatMessageData } from "../ChatMessage/useChatMessage";
|
||||
import { createStreamEventDispatcher } from "./createStreamEventDispatcher";
|
||||
import {
|
||||
parseToolResponse,
|
||||
isValidMessage,
|
||||
isToolCallArray,
|
||||
createUserMessage,
|
||||
filterAuthMessages,
|
||||
isToolCallArray,
|
||||
isValidMessage,
|
||||
parseToolResponse,
|
||||
} from "./helpers";
|
||||
import { createStreamEventDispatcher } from "./createStreamEventDispatcher";
|
||||
|
||||
interface UseChatContainerArgs {
|
||||
sessionId: string | null;
|
||||
@@ -1,17 +1,17 @@
|
||||
"use client";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { RobotIcon, UserIcon, CheckCircleIcon } from "@phosphor-icons/react";
|
||||
import { useCallback } from "react";
|
||||
import { MessageBubble } from "@/app/(platform)/chat/components/MessageBubble/MessageBubble";
|
||||
import { MarkdownContent } from "@/app/(platform)/chat/components/MarkdownContent/MarkdownContent";
|
||||
import { ToolCallMessage } from "@/app/(platform)/chat/components/ToolCallMessage/ToolCallMessage";
|
||||
import { ToolResponseMessage } from "@/app/(platform)/chat/components/ToolResponseMessage/ToolResponseMessage";
|
||||
import { AuthPromptWidget } from "@/app/(platform)/chat/components/AuthPromptWidget/AuthPromptWidget";
|
||||
import { ChatCredentialsSetup } from "@/app/(platform)/chat/components/ChatCredentialsSetup/ChatCredentialsSetup";
|
||||
import { useSupabase } from "@/lib/supabase/hooks/useSupabase";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { CheckCircleIcon, RobotIcon, UserIcon } from "@phosphor-icons/react";
|
||||
import { useCallback } from "react";
|
||||
import { getToolActionPhrase } from "../../helpers";
|
||||
import { AuthPromptWidget } from "../AuthPromptWidget/AuthPromptWidget";
|
||||
import { ChatCredentialsSetup } from "../ChatCredentialsSetup/ChatCredentialsSetup";
|
||||
import { MarkdownContent } from "../MarkdownContent/MarkdownContent";
|
||||
import { MessageBubble } from "../MessageBubble/MessageBubble";
|
||||
import { ToolCallMessage } from "../ToolCallMessage/ToolCallMessage";
|
||||
import { ToolResponseMessage } from "../ToolResponseMessage/ToolResponseMessage";
|
||||
import { useChatMessage, type ChatMessageData } from "./useChatMessage";
|
||||
import { getToolActionPhrase } from "@/app/(platform)/chat/helpers";
|
||||
export interface ChatMessageProps {
|
||||
message: ChatMessageData;
|
||||
className?: string;
|
||||
@@ -113,7 +113,6 @@ export function ChatMessage({
|
||||
message={message.message}
|
||||
sessionId={message.sessionId}
|
||||
agentInfo={message.agentInfo}
|
||||
returnUrl="/chat"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -1,7 +1,7 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Robot } from "@phosphor-icons/react";
|
||||
import { MessageBubble } from "@/app/(platform)/chat/components/MessageBubble/MessageBubble";
|
||||
import { MarkdownContent } from "@/app/(platform)/chat/components/MarkdownContent/MarkdownContent";
|
||||
import { MarkdownContent } from "../MarkdownContent/MarkdownContent";
|
||||
import { MessageBubble } from "../MessageBubble/MessageBubble";
|
||||
import { useStreamingMessage } from "./useStreamingMessage";
|
||||
|
||||
export interface StreamingMessageProps {
|
||||
@@ -1,7 +1,6 @@
|
||||
import React from "react";
|
||||
import { WrenchIcon } from "@phosphor-icons/react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { getToolActionPhrase } from "@/app/(platform)/chat/helpers";
|
||||
import { WrenchIcon } from "@phosphor-icons/react";
|
||||
import { getToolActionPhrase } from "../../helpers";
|
||||
|
||||
export interface ToolCallMessageProps {
|
||||
toolName: string;
|
||||
@@ -1,7 +1,6 @@
|
||||
import React from "react";
|
||||
import { WrenchIcon } from "@phosphor-icons/react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { getToolActionPhrase } from "@/app/(platform)/chat/helpers";
|
||||
import { WrenchIcon } from "@phosphor-icons/react";
|
||||
import { getToolActionPhrase } from "../../helpers";
|
||||
|
||||
export interface ToolResponseMessageProps {
|
||||
toolName: string;
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Maps internal tool names to user-friendly display names with emojis.
|
||||
* @deprecated Use getToolActionPhrase or getToolCompletionPhrase for status messages
|
||||
*
|
||||
* @param toolName - The internal tool name from the backend
|
||||
* @returns A user-friendly display name with an emoji prefix
|
||||
*/
|
||||
export function getToolDisplayName(toolName: string): string {
|
||||
const toolDisplayNames: Record<string, string> = {
|
||||
find_agent: "🔍 Search Marketplace",
|
||||
get_agent_details: "📋 Get Agent Details",
|
||||
check_credentials: "🔑 Check Credentials",
|
||||
setup_agent: "⚙️ Setup Agent",
|
||||
run_agent: "▶️ Run Agent",
|
||||
get_required_setup_info: "📝 Get Setup Requirements",
|
||||
};
|
||||
return toolDisplayNames[toolName] || toolName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps internal tool names to human-friendly action phrases (present continuous).
|
||||
* Used for tool call messages to indicate what action is currently happening.
|
||||
*
|
||||
* @param toolName - The internal tool name from the backend
|
||||
* @returns A human-friendly action phrase in present continuous tense
|
||||
*/
|
||||
export function getToolActionPhrase(toolName: string): string {
|
||||
const toolActionPhrases: Record<string, string> = {
|
||||
find_agent: "Looking for agents in the marketplace",
|
||||
agent_carousel: "Looking for agents in the marketplace",
|
||||
get_agent_details: "Learning about the agent",
|
||||
check_credentials: "Checking your credentials",
|
||||
setup_agent: "Setting up the agent",
|
||||
execution_started: "Running the agent",
|
||||
run_agent: "Running the agent",
|
||||
get_required_setup_info: "Getting setup requirements",
|
||||
schedule_agent: "Scheduling the agent to run",
|
||||
};
|
||||
|
||||
// Return mapped phrase or generate human-friendly fallback
|
||||
return toolActionPhrases[toolName] || toolName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps internal tool names to human-friendly completion phrases (past tense).
|
||||
* Used for tool response messages to indicate what action was completed.
|
||||
*
|
||||
* @param toolName - The internal tool name from the backend
|
||||
* @returns A human-friendly completion phrase in past tense
|
||||
*/
|
||||
export function getToolCompletionPhrase(toolName: string): string {
|
||||
const toolCompletionPhrases: Record<string, string> = {
|
||||
find_agent: "Finished searching the marketplace",
|
||||
get_agent_details: "Got agent details",
|
||||
check_credentials: "Checked credentials",
|
||||
setup_agent: "Agent setup complete",
|
||||
run_agent: "Agent execution started",
|
||||
get_required_setup_info: "Got setup requirements",
|
||||
};
|
||||
|
||||
// Return mapped phrase or generate human-friendly fallback
|
||||
return (
|
||||
toolCompletionPhrases[toolName] ||
|
||||
`Finished ${toolName.replace(/_/g, " ").replace("...", "")}`
|
||||
);
|
||||
}
|
||||
|
||||
/** Validate UUID v4 format */
|
||||
export function isValidUUID(value: string): boolean {
|
||||
const uuidRegex =
|
||||
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
||||
return uuidRegex.test(value);
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
"use client";
|
||||
|
||||
import { useSupabase } from "@/lib/supabase/hooks/useSupabase";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { useChatSession } from "./useChatSession";
|
||||
import { useChatStream } from "./useChatStream";
|
||||
|
||||
export function useChat() {
|
||||
const hasCreatedSessionRef = useRef(false);
|
||||
const hasClaimedSessionRef = useRef(false);
|
||||
const { user } = useSupabase();
|
||||
const { sendMessage: sendStreamMessage } = useChatStream();
|
||||
|
||||
const {
|
||||
session,
|
||||
sessionId: sessionIdFromHook,
|
||||
messages,
|
||||
isLoading,
|
||||
isCreating,
|
||||
error,
|
||||
createSession,
|
||||
refreshSession,
|
||||
claimSession,
|
||||
clearSession: clearSessionBase,
|
||||
} = useChatSession({
|
||||
urlSessionId: null,
|
||||
autoCreate: false,
|
||||
});
|
||||
|
||||
useEffect(
|
||||
function autoCreateSession() {
|
||||
if (!hasCreatedSessionRef.current && !isCreating && !sessionIdFromHook) {
|
||||
hasCreatedSessionRef.current = true;
|
||||
createSession().catch((_err) => {
|
||||
hasCreatedSessionRef.current = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
[isCreating, sessionIdFromHook, createSession],
|
||||
);
|
||||
|
||||
useEffect(
|
||||
function autoClaimSession() {
|
||||
if (
|
||||
session &&
|
||||
!session.user_id &&
|
||||
user &&
|
||||
!hasClaimedSessionRef.current &&
|
||||
!isLoading &&
|
||||
sessionIdFromHook
|
||||
) {
|
||||
hasClaimedSessionRef.current = true;
|
||||
claimSession(sessionIdFromHook)
|
||||
.then(() => {
|
||||
sendStreamMessage(
|
||||
sessionIdFromHook,
|
||||
"User has successfully logged in.",
|
||||
() => {},
|
||||
false,
|
||||
).catch(() => {});
|
||||
})
|
||||
.catch(() => {
|
||||
hasClaimedSessionRef.current = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
[
|
||||
session,
|
||||
user,
|
||||
isLoading,
|
||||
sessionIdFromHook,
|
||||
claimSession,
|
||||
sendStreamMessage,
|
||||
],
|
||||
);
|
||||
|
||||
useEffect(function monitorNetworkStatus() {
|
||||
function handleOnline() {
|
||||
toast.success("Connection restored", {
|
||||
description: "You're back online",
|
||||
});
|
||||
}
|
||||
|
||||
function handleOffline() {
|
||||
toast.error("You're offline", {
|
||||
description: "Check your internet connection",
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener("online", handleOnline);
|
||||
window.addEventListener("offline", handleOffline);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("online", handleOnline);
|
||||
window.removeEventListener("offline", handleOffline);
|
||||
};
|
||||
}, []);
|
||||
|
||||
function clearSession() {
|
||||
clearSessionBase();
|
||||
hasCreatedSessionRef.current = false;
|
||||
hasClaimedSessionRef.current = false;
|
||||
}
|
||||
|
||||
return {
|
||||
session,
|
||||
messages,
|
||||
isLoading,
|
||||
isCreating,
|
||||
error,
|
||||
createSession,
|
||||
refreshSession,
|
||||
clearSession,
|
||||
sessionId: sessionIdFromHook,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
"use client";
|
||||
|
||||
import { create } from "zustand";
|
||||
|
||||
interface ChatDrawerState {
|
||||
isOpen: boolean;
|
||||
open: () => void;
|
||||
close: () => void;
|
||||
toggle: () => void;
|
||||
}
|
||||
|
||||
export const useChatDrawer = create<ChatDrawerState>((set) => ({
|
||||
isOpen: false,
|
||||
open: () => set({ isOpen: true }),
|
||||
close: () => set({ isOpen: false }),
|
||||
toggle: () => set((state) => ({ isOpen: !state.isOpen })),
|
||||
}));
|
||||
@@ -1,16 +1,16 @@
|
||||
import { useCallback, useEffect, useState, useRef, useMemo } from "react";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
usePostV2CreateSession,
|
||||
getGetV2GetSessionQueryKey,
|
||||
postV2CreateSession,
|
||||
useGetV2GetSession,
|
||||
usePatchV2SessionAssignUser,
|
||||
getGetV2GetSessionQueryKey,
|
||||
usePostV2CreateSession,
|
||||
} from "@/app/api/__generated__/endpoints/chat/chat";
|
||||
import type { SessionDetailResponse } from "@/app/api/__generated__/models/sessionDetailResponse";
|
||||
import { storage, Key } from "@/services/storage/local-storage";
|
||||
import { isValidUUID } from "@/app/(platform)/chat/helpers";
|
||||
import { Key, storage } from "@/services/storage/local-storage";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { isValidUUID } from "./helpers";
|
||||
|
||||
interface UseChatSessionArgs {
|
||||
urlSessionId?: string | null;
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { IconLaptop } from "@/components/__legacy__/ui/icons";
|
||||
import { useChatDrawer } from "@/components/contextual/Chat/useChatDrawer";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Flag, useGetFlag } from "@/services/feature-flags/use-get-flag";
|
||||
import {
|
||||
@@ -24,9 +25,22 @@ export function NavbarLink({ name, href }: Props) {
|
||||
const pathname = usePathname();
|
||||
const isActive = pathname.includes(href);
|
||||
const chat_enabled = useGetFlag(Flag.CHAT);
|
||||
const { open: openChatDrawer } = useChatDrawer();
|
||||
const isChat = href === "/chat";
|
||||
|
||||
function handleClick(e: React.MouseEvent) {
|
||||
if (isChat && chat_enabled) {
|
||||
e.preventDefault();
|
||||
openChatDrawer();
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Link href={href} data-testid={`navbar-link-${name.toLowerCase()}`}>
|
||||
<Link
|
||||
href={href}
|
||||
onClick={handleClick}
|
||||
data-testid={`navbar-link-${name.toLowerCase()}`}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
"flex items-center justify-start gap-1 p-1 md:p-2",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { useGetV2GetUserProfile } from "@/app/api/__generated__/endpoints/store/store";
|
||||
import { IconAutoGPTLogo, IconType } from "@/components/__legacy__/ui/icons";
|
||||
import { useChatDrawer } from "@/components/contextual/Chat/useChatDrawer";
|
||||
import { PreviewBanner } from "@/components/layout/Navbar/components/PreviewBanner/PreviewBanner";
|
||||
import { useBreakpoint } from "@/lib/hooks/useBreakpoint";
|
||||
import { useSupabase } from "@/lib/supabase/hooks/useSupabase";
|
||||
@@ -40,6 +41,8 @@ export function NavbarView({ isLoggedIn, previewBranchName }: NavbarViewProps) {
|
||||
const { isUserLoading } = useSupabase();
|
||||
const isLoadingProfile = isProfileLoading || isUserLoading;
|
||||
|
||||
const { open: openChatDrawer } = useChatDrawer();
|
||||
|
||||
const linksWithChat = useMemo(() => {
|
||||
const chatLink = { name: "Chat", href: "/chat" };
|
||||
return isChatEnabled ? [...loggedInLinks, chatLink] : loggedInLinks;
|
||||
@@ -128,6 +131,10 @@ export function NavbarView({ isLoggedIn, previewBranchName }: NavbarViewProps) {
|
||||
: IconType.LayoutDashboard,
|
||||
text: link.name,
|
||||
href: link.href,
|
||||
onClick:
|
||||
link.name === "Chat" && isChatEnabled
|
||||
? openChatDrawer
|
||||
: undefined,
|
||||
})),
|
||||
},
|
||||
...dynamicMenuItems,
|
||||
|
||||
Reference in New Issue
Block a user