UNPKG

@automattic/agenttic-client

Version:

A TypeScript client library for A2A (Agent2Agent) protocol communication

463 lines (381 loc) 10.4 kB
# @automattic/agenttic-client A TypeScript client library for Agent2Agent (A2A) protocol communication with React hooks and component integration. Built for seamless AI agent integration in both browser and Node.js environments. ## Installation ```bash npm install @automattic/agenttic-client ``` ## Key Features - React hooks for agent communication (`useAgentChat`, `useClientContext`, `useClientTools`) - Streaming and non-streaming responses - Tool execution system with automatic handling - Context injection for each message - Conversation persistence and management - Request cancellation with abort controllers - TypeScript support - Message actions and markdown rendering ## Quick Start ### Basic Chat Integration ```typescript import { useAgentChat } from '@automattic/agenttic-client'; function ChatComponent() { const { messages, isProcessing, error, onSubmit, registerSuggestions, registerMarkdownComponents } = useAgentChat({ agentId: 'big-sky', sessionId: 'my-session-123', authProvider: async () => ({ Authorization: 'Bearer your-token' }) }); return ( <div> {messages.map(msg => ( <div key={msg.id} className={msg.role}> {msg.content.map(content => content.text).join('')} </div> ))} <input onKeyDown={(e) => e.key === 'Enter' && onSubmit(e.target.value)} disabled={isProcessing} /> {error && <div>Error: {error}</div>} </div> ); } ``` ### With Tools and Context ```typescript import { useAgentChat, useClientTools, useClientContext } from '@automattic/agenttic-client'; function AdvancedChatComponent() { const contextProvider = useClientContext(() => ({ page: window.location.href, timestamp: Date.now(), userRole: getCurrentUserRole() })); const toolProvider = useClientTools( async () => [ { id: 'calculator', name: 'Calculator', description: 'Perform mathematical calculations', input_schema: { type: 'object', properties: { expression: { type: 'string' } }, required: ['expression'] } } ], async (toolId, args) => { if (toolId === 'calculator') { return { result: calc(args.expression)}; } } ); const chat = useAgentChat({ agentId: 'big-sky', contextProvider, toolProvider, authProvider: async () => ({ Authorization: 'Bearer token' }) }); return <ChatInterface {...chat} />; } ``` ## Core APIs ### useAgentChat Hook The primary hook for chat functionality, providing everything needed for a complete chat interface. ```typescript const { // Chat state messages, // UIMessage[] - formatted for display isProcessing, // boolean - request in progress error, // string | null - last error // Core methods onSubmit, // (message: string) => Promise<void> abortCurrentRequest, // () => void - cancel in-flight request // Configuration registerSuggestions, // (suggestions: Suggestion[]) => void registerMarkdownComponents, // (components: MarkdownComponents) => void registerMessageActions, // (registration: MessageActionsRegistration) => void // Utilities messageRenderer, // React component for markdown rendering addMessage, // (message: UIMessage) => void } = useAgentChat( config ); ``` **Config Options:** - `agentId: string` - Required. Agent identifier - `agentUrl?: string` - Agent endpoint URL (defaults to WordPress.com) - `sessionId?: string` - Session ID for conversation persistence - `contextProvider?: ContextProvider` - Dynamic context injection - `toolProvider?: ToolProvider` - Tool execution capabilities - `authProvider?: AuthProvider` - Authentication headers ### useClientContext Hook Provides dynamic context that refreshes with each message. ```typescript const contextProvider = useClientContext( () => ( { currentPage: { url: window.location.href, title: document.title, selectedText: getSelection(), }, user: { role: getUserRole(), permissions: getPermissions(), }, timestamp: Date.now(), } ) ); ``` ### useClientTools Hook Enables agents to execute tools in your application. ```typescript const toolProvider = useClientTools( // Define available tools async () => [ { id: 'file-reader', name: 'File Reader', description: 'Read file contents', input_schema: { type: 'object', properties: { path: { type: 'string' }, }, required: [ 'path' ], }, }, ], // Execute tool calls async ( toolId, args ) => { if ( toolId === 'file-reader' ) { return { content: await readFile( args.path ) }; } throw new Error( `Unknown tool: ${ toolId }` ); } ); ``` ### createClient Function Low-level client for direct A2A communication without React. ```typescript import { createClient } from '@automattic/agenttic-client'; const client = createClient({ agentId: 'big-sky', authProvider: async () => ({ Authorization: 'Bearer token' }), toolProvider: { getAvailableTools: async () => [...], executeTool: async (toolId, args) => ({ result: '...' }) } }); // Non-streaming const task = await client.sendMessage({ message: createTextMessage('Hello'), sessionId: 'session-123' }); // Streaming for await (const update of client.sendMessageStream({ message: createTextMessage('Hello'), sessionId: 'session-123' })) { console.log(update.text); if (update.final) break; } // With abort control const abortController = new AbortController(); const task = await client.sendMessage({ message: createTextMessage('Hello'), sessionId: 'session-123', abortSignal: abortController.signal }); // Cancel the request abortController.abort(); ``` ### Agent Manager Functional singleton for managing multiple agent instances. ```typescript import { getAgentManager } from '@automattic/agenttic-client'; const manager = getAgentManager(); // Create agent await manager.createAgent( 'my-agent', { agentId: 'big-sky', sessionId: 'session-123', contextProvider, toolProvider, } ); // Send messages const task = await manager.sendMessage( 'my-agent', 'Hello' ); // Streaming for await ( const update of manager.sendMessageStream( 'my-agent', 'Hello' ) ) { console.log( update ); } // Manage conversation const history = manager.getConversationHistory( 'my-agent' ); await manager.resetConversation( 'my-agent' ); ``` ## Additional Features ### Request Cancellation Cancel in-flight requests using the built-in abort functionality: ```typescript const { abortCurrentRequest, isProcessing } = useAgentChat(config); // Cancel current request if (isProcessing) { abortCurrentRequest(); } ``` For low-level client usage, use `AbortController`: ```typescript import { createClient, createAbortController } from '@automattic/agenttic-client'; const client = createClient(config); const abortController = createAbortController(); // Start a request with abort signal const requestPromise = client.sendMessage({ message: createTextMessage('Hello'), abortSignal: abortController.signal }); // Cancel the request abortController.abort(); // Handle cancellation try { await requestPromise; } catch (error) { if (error.name === 'AbortError') { console.log('Request was cancelled'); } } ``` ### Message Actions Add interactive buttons to agent messages: ```typescript const { registerMessageActions, createFeedbackActions } = useAgentChat( config ); // Built-in feedback actions registerMessageActions( createFeedbackActions( { onFeedback: async ( messageId, feedback ) => { console.log( `${ feedback } feedback for ${ messageId }` ); }, icons: { up: '👍', down: '👎' }, } ) ); // Custom actions registerMessageActions( { id: 'copy-actions', actions: [ { id: 'copy', label: 'Copy', icon: '📋', onClick: ( message ) => navigator.clipboard.writeText( message.content[ 0 ].text ), }, ], } ); ``` ### Markdown Extensions Extend markdown rendering with custom components: ```typescript import { BarChart, LineChart } from '@automattic/agenttic-client'; const { registerMarkdownComponents, registerMarkdownExtensions } = useAgentChat(config); // Register chart components registerMarkdownComponents( { // Custom heading styles h1: ({ children }) => ( <h1 className="text-2xl font-bold text-brand">{children}</h1> ), // Custom code blocks with syntax highlighting code: ({ children, className }) => ( <SyntaxHighlighter language={className}> {children} </SyntaxHighlighter> ), // Custom link handling a: ({ href, children }) => ( <a href={href} target="_blank" rel="noopener"> {children} ↗ </a> ), blockquote: ( { children, ...props } ) => ( <blockquote { ...props } style={ { borderLeft: '4px solid #007cba', backgroundColor: '#f0f8ff', margin: '16px 0', padding: '12px 16px', fontStyle: 'italic', borderRadius: '0 4px 4px 0', } } > { children } </blockquote> ), }); // Register custom extensions registerMarkdownExtensions({ charts: { BarChart, LineChart } }); ``` ### Conversation Suggestions Provide suggested prompts to users: ```typescript const { registerSuggestions, clearSuggestions } = useAgentChat( config ); registerSuggestions( [ { id: '1', label: 'Help me write code', prompt: 'Can you help me write a function?', }, { id: '2', label: 'Explain this error', prompt: 'What does this error mean?', }, ] ); ``` ## Type Definitions ```typescript interface UIMessage { id: string; role: 'user' | 'agent'; content: Array< { type: 'text' | 'image_url' | 'component'; text?: string; image_url?: string; component?: React.ComponentType; } >; timestamp: number; actions?: UIMessageAction[]; } interface Tool { id: string; name: string; description: string; input_schema: { type: 'object'; properties: Record< string, any >; required?: string[]; }; } type AuthProvider = () => Promise< Record< string, string > >; type ContextProvider = { getClientContext: () => any }; type ToolProvider = { getAvailableTools: () => Promise< Tool[] >; executeTool: ( toolId: string, args: any ) => Promise< any >; }; ``` ## Development ```bash # Build the package pnpm build # Run tests pnpm test # Type checking pnpm type-check # Lint pnpm lint ```