diff --git a/apps/web/src/app/agents/[id]/chat/page.tsx b/apps/web/src/app/agents/[id]/chat/page.tsx index 4748094..bff9a72 100644 --- a/apps/web/src/app/agents/[id]/chat/page.tsx +++ b/apps/web/src/app/agents/[id]/chat/page.tsx @@ -1,6 +1,7 @@ 'use client'; import type { AIProvider } from '@tpmjs/types/agent'; +import { Badge } from '@tpmjs/ui/Badge/Badge'; import { Button } from '@tpmjs/ui/Button/Button'; import { Icon } from '@tpmjs/ui/Icon/Icon'; import Link from 'next/link'; @@ -8,6 +9,36 @@ import { useParams, useRouter, useSearchParams } from 'next/navigation'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { Virtuoso, type VirtuosoHandle } from 'react-virtuoso'; import { AppHeader } from '~/components/AppHeader'; +import { LikeButton } from '~/components/LikeButton'; + +interface AgentTool { + id: string; + toolId: string; + position: number; + tool: { + id: string; + name: string; + description: string; + likeCount: number; + package: { + id: string; + npmPackageName: string; + category: string; + }; + }; +} + +interface AgentCollection { + id: string; + collectionId: string; + position: number; + collection: { + id: string; + name: string; + description: string | null; + toolCount: number; + }; +} interface Agent { id: string; @@ -16,11 +47,19 @@ interface Agent { description: string | null; provider: AIProvider; modelId: string; + systemPrompt: string | null; + temperature: number; + maxToolCallsPerTurn: number; + likeCount: number; + toolCount: number; + collectionCount: number; createdBy: { id: string; name: string; image: string | null; }; + tools: AgentTool[]; + collections: AgentCollection[]; } interface Message { @@ -188,6 +227,7 @@ export default function PublicAgentChatPage(): React.ReactElement { const [expandedToolCalls, setExpandedToolCalls] = useState>(new Set()); const [hasMoreMessages, setHasMoreMessages] = useState(false); const [isLoadingMore, setIsLoadingMore] = useState(false); + const [sidebarOpen, setSidebarOpen] = useState(true); // Track first item index for prepending (Virtuoso pattern) const [firstItemIndex, setFirstItemIndex] = useState(10000); @@ -471,197 +511,336 @@ export default function PublicAgentChatPage(): React.ReactElement {
- {/* Chat Header */} -
-
-
- - - -
-

{agent.name}

-

- {PROVIDER_DISPLAY_NAMES[agent.provider]} • Created by {agent.createdBy.name} -

-
-
- -
-
- - {/* Chat Area */} -
- {/* Messages */} - {messages.length === 0 && !streamingContent ? ( -
-
-
- +
+ {/* Sidebar */} +
+
+ {/* Agent Header */} +
+ + + Back to Agent + +
+
+

{agent.name}

+ {agent.description && ( +

+ {agent.description} +

+ )} +
+
+
+
-

Start a conversation

-

- Send a message to start chatting with {agent.name}. -

-
- ) : ( - - hasMoreMessages ? ( -
- {isLoadingMore ? ( -
- - Loading older messages... -
- ) : ( - - )} -
- ) : null, - Footer: () => ( -
- {/* Live tool calls during streaming */} - {toolCalls.length > 0 && ( -
- {toolCalls.map((tc) => ( -
-
- toggleToolCall(tc.toolCallId)} - /> -
-
- ))} -
- )} - {streamingContent && ( -
-
-

{streamingContent}

- -
-
- )} - - {isSending && !streamingContent && toolCalls.length === 0 && ( -
-
-
- - Thinking... -
-
-
- )} + {/* Configuration */} +
+

+ + Configuration +

+
+
+ Provider + + {PROVIDER_DISPLAY_NAMES[agent.provider]} +
- ), - }} - itemContent={(_index, message) => { - // Parse tool output safely - const getToolOutput = () => { - if (message.toolResult) return message.toolResult; - try { - return JSON.parse(message.content || '{}'); - } catch { - return { result: message.content }; - } - }; - - return ( -
-
- {message.role === 'TOOL' ? ( -
- toggleToolCall(message.toolCallId || message.id)} - /> -
- ) : ( -
-

{message.content}

-
- )} -
+
+ Model + {agent.modelId}
- ); - }} - /> - )} +
+ Temperature + {agent.temperature} +
+
+ Max Tool Calls + {agent.maxToolCallsPerTurn} +
+
- {/* Error Message */} - {error && ( -
-

{error}

+ {agent.systemPrompt && ( +
+ System Prompt +
+                    {agent.systemPrompt}
+                  
+
+ )} +
+ + {/* Tools */} +
+

+ + Tools ({agent.tools.length}) +

+ {agent.tools.length === 0 ? ( +

No tools configured

+ ) : ( +
+ {agent.tools.map((at) => ( + +
+
+

+ {at.tool.name} +

+

+ {at.tool.package.npmPackageName} +

+
+ + {at.tool.package.category} + +
+ + ))} +
+ )} +
+ + {/* Collections */} + {agent.collections.length > 0 && ( +
+

+ + Collections ({agent.collections.length}) +

+
+ {agent.collections.map((ac) => ( + +

+ {ac.collection.name} +

+

+ {ac.collection.toolCount} tools +

+ + ))} +
+
+ )}
- )} +
- {/* Input Area */} -
-
-