show loading until text appears

This commit is contained in:
2025-12-09 05:30:31 +01:00
parent a30e5a6524
commit a515b6dc10
4 changed files with 23 additions and 14 deletions

View File

@@ -15,7 +15,6 @@ from langgraph.prebuilt import ToolNode, tools_condition
from langgraph.types import Command
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_mcp_adapters.interceptors import MCPToolCallRequest, MCPToolCallResult
from copilotkit.langgraph import copilotkit_customize_config
class AgentState(MessagesState):
@@ -27,7 +26,6 @@ class AgentState(MessagesState):
"""
tools: List[Any]
# your_custom_agent_state: str = ""
# @tool
@@ -130,19 +128,13 @@ async def chat_node(state: AgentState, config: RunnableConfig) -> dict:
content=f"You are a helpful assistant with access to cave-related information through the Cavepedia MCP server. You can help users find information about caves, caving techniques, and related topics. User roles: {', '.join(user_roles) if user_roles else 'none'}"
)
# 3.5 Customize config for CopilotKit to properly handle message streaming
modified_config = copilotkit_customize_config(
config,
emit_messages=True,
)
# 4. Run the model to generate a response
response = await model_with_tools.ainvoke(
[
system_message,
*state["messages"],
],
modified_config,
config,
)
# 5. Return the response in the messages

View File

@@ -249,6 +249,11 @@ html {
to { opacity: 1; transform: scale(1); }
}
/* Hide CopilotKit's built-in loading indicator */
.copilotKitActivityDot {
display: none !important;
}
@media (max-width: 600px) {
.main-card-wrapper {
padding: 2rem;

View File

@@ -19,7 +19,7 @@ export default function RootLayout({
<html lang="en">
<body className={"antialiased"}>
<Auth0Provider>
<CopilotKit runtimeUrl="/api/copilotkit" agent="sample_agent" properties={{ streamMode: ["events"] }}>
<CopilotKit runtimeUrl="/api/copilotkit" agent="sample_agent">
{children}
</CopilotKit>
</Auth0Provider>

View File

@@ -1,6 +1,6 @@
"use client";
import { useCopilotAction, useUser as useCopilotUser } from "@copilotkit/react-core";
import { useCopilotAction, useCopilotChat } from "@copilotkit/react-core";
import { CopilotKitCSSProperties, CopilotChat } from "@copilotkit/react-ui";
import { useState } from "react";
import { useUser } from "@auth0/nextjs-auth0/client";
@@ -10,7 +10,8 @@ import Profile from "@/components/Profile";
export default function CopilotKitPage() {
const [themeColor, setThemeColor] = useState("#6366f1");
const { user, isLoading } = useUser();
const { user, isLoading: authLoading } = useUser();
const { isLoading: chatLoading } = useCopilotChat();
useCopilotAction({
name: "setThemeColor",
@@ -25,7 +26,7 @@ export default function CopilotKitPage() {
});
// Show loading state while checking authentication
if (isLoading) {
if (authLoading) {
return (
<div className="app-container">
<div className="loading-state">
@@ -92,7 +93,7 @@ export default function CopilotKitPage() {
</div>
{/* CopilotKit Chat */}
<div className="flex-1 flex justify-center py-8 px-2 overflow-hidden">
<div className="flex-1 flex justify-center py-8 px-2 overflow-hidden relative">
<div className="h-full w-full max-w-5xl flex flex-col">
<CopilotChat
instructions={"You are a knowledgeable caving assistant. Help users with all aspects of caving including cave exploration, safety, surveying techniques, cave locations, geology, equipment, history, conservation, and any other caving-related topics. Provide accurate, helpful, and safety-conscious information. CRITICAL: Always cite sources at the end of each response."}
@@ -103,6 +104,17 @@ export default function CopilotKitPage() {
className="h-full w-full"
/>
</div>
{/* Loading overlay */}
{chatLoading && (
<div className="absolute bottom-24 left-1/2 transform -translate-x-1/2 bg-white shadow-lg rounded-full px-4 py-2 flex items-center gap-2 z-50">
<div className="flex gap-1">
<span className="w-2 h-2 bg-indigo-500 rounded-full animate-bounce" style={{ animationDelay: "0ms" }}></span>
<span className="w-2 h-2 bg-indigo-500 rounded-full animate-bounce" style={{ animationDelay: "150ms" }}></span>
<span className="w-2 h-2 bg-indigo-500 rounded-full animate-bounce" style={{ animationDelay: "300ms" }}></span>
</div>
<span className="text-sm text-gray-600">Thinking...</span>
</div>
)}
</div>
</main>
);