@kuntur/a2a-carbon-chat-adapter
v1.0.0
Published
Production-ready A2A protocol adapter for Carbon AI Chat - connect any Agent2Agent protocol agent to IBM Carbon Design System chat UI
Maintainers
Readme
@kuntur/a2a-carbon-chat-adapter
Production-ready A2A protocol adapter for Carbon AI Chat - Connect any Agent2Agent protocol agent to IBM Carbon Design System chat UI with full streaming support, multi-agent management, and extensible rendering.
📋 Table of Contents
- Overview
- Why This Library?
- Quick Start
- ⚠️ Server Proxy Setup (Required)
- Core Concepts
- API Reference
- Advanced Usage
- Examples
- Architecture
- Troubleshooting
- Contributing
- License
Overview
@kuntur/a2a-carbon-chat-adapter is a TypeScript library that bridges the Agent2Agent (A2A) protocol with IBM's Carbon AI Chat component. It provides:
- Protocol Translation: Converts A2A streaming responses to Carbon AI Chat's message format
- Multi-Agent Support: Built-in context provider for managing multiple agents
- Extension System: Handles A2A UI extensions (citations, forms, errors)
- Server Utilities: Ready-to-use API handlers for Next.js and other frameworks
- Type Safety: Full TypeScript support with comprehensive type definitions
This library is designed for production use in enterprise applications requiring AI agent integration with Carbon Design System.
Why This Library?
The Problem
Integrating A2A protocol agents with Carbon AI Chat requires:
- Protocol Translation: A2A uses Server-Sent Events (SSE) streaming; Carbon expects a specific message format
- CORS Handling: Browser security prevents direct agent connections
- Extension Parsing: A2A UI extensions need custom rendering logic
- State Management: Multi-agent scenarios require context management
The Solution
This library provides:
- ✅ Drop-in Components:
<A2AChat>component with full A2A support - ✅ Server Proxy: Pre-built API handlers for streaming proxy setup
- ✅ Extension Renderers: Built-in components for citations, forms, and errors
- ✅ Multi-Agent Context:
AgentProviderfor seamless agent switching - ✅ Programmatic API: Hooks for custom implementations
Benefits
- Faster Development: Skip protocol implementation, focus on your application
- Production Ready: Battle-tested streaming, error handling, and state management
- Type Safe: Full TypeScript support prevents runtime errors
- Extensible: Custom renderers and hooks for advanced use cases
- Carbon Native: Seamless integration with Carbon Design System
Quick Start
Installation
npm install @kuntur/a2a-carbon-chat-adapter @carbon/ai-chat react react-domBasic Usage
import { A2AChat } from '@kuntur/a2a-carbon-chat-adapter';
import '@kuntur/a2a-carbon-chat-adapter/styles';
import '@carbon/ai-chat/dist/styles.css';
function App() {
return (
<A2AChat
agentUrl="https://your-agent.example.com"
agentName="My Agent"
layout="sidebar"
/>
);
}⚠️ Important: This requires a server proxy to work. See Server Proxy Setup below.
⚠️ Server Proxy Setup (Required)
Why You Need a Server Proxy
Direct browser connections to A2A agents are blocked by CORS (Cross-Origin Resource Sharing) security policies. Browsers prevent JavaScript from making requests to different domains unless the server explicitly allows it.
Most A2A agents:
- Run on different domains than your frontend
- Don't configure CORS headers for browser access
- Use streaming protocols that require special handling
Solution: Route agent requests through your backend server, which:
- Receives requests from your frontend (same origin = no CORS)
- Forwards them to the A2A agent (server-to-server = no CORS restrictions)
- Streams responses back to the frontend
Next.js Setup (Recommended)
Create an API route that proxies requests to your A2A agent:
// app/api/agent/chat/route.ts
import { createA2AHandler } from '@kuntur/a2a-carbon-chat-adapter/server';
export const POST = createA2AHandler({
// Security: Only allow requests to trusted agent URLs
allowedAgentUrls: [
'https://your-agent.example.com',
'https://another-agent.example.com',
],
// Optional: Set request timeout (default: 120000ms)
timeout: 120000,
});
// Required for streaming responses
export const runtime = 'nodejs';
export const dynamic = 'force-dynamic';Then configure your frontend to use this proxy:
import { A2AChat } from '@kuntur/a2a-carbon-chat-adapter';
function App() {
return (
<A2AChat
agentUrl="https://your-agent.example.com"
agentName="My Agent"
// Point to your proxy endpoint
proxyUrl="/api/agent/chat"
/>
);
}Express.js Setup
import express from 'express';
import { createA2AHandler } from '@kuntur/a2a-carbon-chat-adapter/server';
const app = express();
// Create the handler
const handler = createA2AHandler({
allowedAgentUrls: ['https://your-agent.example.com'],
});
// Mount as Express middleware
app.post('/api/agent/chat', async (req, res) => {
const response = await handler(req);
// Copy headers
response.headers.forEach((value, key) => {
res.setHeader(key, value);
});
// Stream response
const reader = response.body?.getReader();
if (reader) {
while (true) {
const { done, value } = await reader.read();
if (done) break;
res.write(value);
}
}
res.end();
});Other Frameworks
The createA2AHandler function returns a standard Web API Response object, making it compatible with:
- Remix: Use in
actionfunctions - SvelteKit: Use in
+server.tsendpoints - Astro: Use in API routes
- Cloudflare Workers: Direct compatibility
- Vercel Edge Functions: Direct compatibility
Example for any framework:
import { createA2AHandler } from '@kuntur/a2a-carbon-chat-adapter/server';
const handler = createA2AHandler({
allowedAgentUrls: ['https://your-agent.example.com'],
});
// In your framework's request handler:
export async function POST(request: Request) {
return handler(request);
}Security Considerations
Always use allowedAgentUrls to prevent your proxy from being used to access arbitrary URLs:
createA2AHandler({
// ✅ Good: Whitelist specific agents
allowedAgentUrls: [
'https://trusted-agent.example.com',
'https://another-trusted-agent.example.com',
],
// ❌ Bad: Allows any URL (security risk!)
// allowedAgentUrls: undefined,
});Core Concepts
A2A Protocol
The Agent2Agent (A2A) protocol is a standard for AI agent communication. Key features:
- Streaming: Real-time response delivery via Server-Sent Events (SSE)
- Context Management: Maintains conversation state across requests
- UI Extensions: Agents can request UI components (forms, citations, etc.)
- Task Management: Supports long-running tasks with progress updates
Extension System
A2A agents can send UI extension requests using special URIs:
agentstack://extension/{type}/{id}This library automatically handles these extensions:
- Citations:
agentstack://extension/citation/*→ Rendered inline with text - Forms:
agentstack://extension/form/*→ Interactive form components - Errors:
agentstack://extension/error/*→ Formatted error displays
Streaming Architecture
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Browser │─────▶│ Your Server │─────▶│ A2A Agent │
│ (Frontend) │ │ (Proxy) │ │ │
└─────────────┘ └──────────────┘ └─────────────┘
│ │ │
│ 1. POST request │ │
│────────────────────▶│ │
│ │ 2. Forward request │
│ │─────────────────────▶│
│ │ │
│ │ 3. SSE stream │
│ │◀─────────────────────│
│ 4. SSE stream │ │
│◀────────────────────│ │
│ │ │The library handles:
- Converting Carbon messages to A2A format
- Streaming A2A responses back to Carbon
- Parsing and rendering UI extensions
- Managing conversation context
API Reference
Components
<A2AChat>
Main chat component that connects to A2A agents.
import { A2AChat } from '@kuntur/a2a-carbon-chat-adapter';
<A2AChat
// Agent Configuration (choose one)
agent={{ id: 'agent', name: 'Agent', url: 'https://...' }}
// OR
agentId="agent" // Requires AgentProvider
// OR
agentUrl="https://..." // Simple URL-only mode
agentName="Agent Name" // Optional display name
// Server Proxy (required for CORS)
proxyUrl="/api/agent/chat"
// Display Options
layout="fullscreen" // 'fullscreen' | 'sidebar' | 'float'
className="my-chat"
// Behavior
showThinking={true}
showChainOfThought={true}
allowCancel={true}
// Callbacks
onSend={(message) => console.log('Sent:', message)}
onResponse={(response) => console.log('Received:', response)}
onError={(error) => console.error('Error:', error)}
// Custom Renderers
renderCitations={(citations, text) => <CustomCitations />}
renderError={(error) => <CustomError />}
renderForm={(form) => <CustomForm />}
/>Props:
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| agent | AgentConfig | No* | Full agent configuration object |
| agentId | string | No* | Agent ID (requires AgentProvider) |
| agentUrl | string | No* | Direct agent URL |
| agentName | string | No | Display name for the agent |
| proxyUrl | string | No | Server proxy endpoint (default: /api/agent/chat) |
| layout | 'fullscreen' \| 'sidebar' \| 'float' | No | Chat layout style |
| className | string | No | Additional CSS classes |
| showThinking | boolean | No | Show agent thinking indicators |
| showChainOfThought | boolean | No | Show reasoning steps |
| allowCancel | boolean | No | Allow canceling streaming responses |
| onSend | (message: string) => void | No | Callback when message is sent |
| onResponse | (response: any) => void | No | Callback when response received |
| onError | (error: Error) => void | No | Callback on error |
| renderCitations | (citations, text) => ReactNode | No | Custom citation renderer |
| renderError | (error) => ReactNode | No | Custom error renderer |
| renderForm | (form) => ReactNode | No | Custom form renderer |
*One of agent, agentId, or agentUrl is required.
<AgentProvider>
Context provider for multi-agent applications.
import { AgentProvider } from '@kuntur/a2a-carbon-chat-adapter';
<AgentProvider
agents={[
{ id: 'research', name: 'Research Agent', url: 'https://...' },
{ id: 'code', name: 'Code Agent', url: 'https://...' },
]}
defaultAgentId="research"
persistSelection={true}
storageKey="my-app-agent"
>
{children}
</AgentProvider>Props:
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| agents | AgentConfig[] | Yes | Array of agent configurations |
| defaultAgentId | string | No | Initially selected agent ID |
| persistSelection | boolean | No | Save selection to localStorage |
| storageKey | string | No | localStorage key (default: selected-agent) |
<AgentSwitcher>
UI component for switching between agents.
import { AgentSwitcher } from '@kuntur/a2a-carbon-chat-adapter';
<AgentSwitcher
agents={agents}
currentAgentId={currentAgentId}
onSelect={handleSelect}
variant="dropdown" // 'dropdown' | 'tabs' | 'cards'
showDescriptions={true}
showIcons={true}
className="my-switcher"
/>Props:
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| agents | AgentConfig[] | Yes | Available agents |
| currentAgentId | string | No | Currently selected agent ID |
| onSelect | (agentId: string) => void | Yes | Selection callback |
| variant | 'dropdown' \| 'tabs' \| 'cards' | No | Display style |
| showDescriptions | boolean | No | Show agent descriptions |
| showIcons | boolean | No | Show agent icons |
| className | string | No | Additional CSS classes |
Hooks
useA2AAgent
Programmatic agent interaction without UI components.
import { useA2AAgent } from '@kuntur/a2a-carbon-chat-adapter';
const {
agent, // Current agent config
state, // Connection state
sendMessage, // Send a message
cancelStream, // Cancel ongoing stream
disconnect, // Disconnect from agent
isStreaming, // Boolean: is currently streaming
isConnected, // Boolean: is connected
error, // Last error (if any)
} = useA2AAgent({
agent: { id: 'agent', name: 'Agent', url: 'https://...' },
proxyUrl: '/api/agent/chat',
onMessage: (message) => console.log('Message:', message),
onError: (error) => console.error('Error:', error),
onStreamStart: () => console.log('Stream started'),
onStreamEnd: () => console.log('Stream ended'),
});
// Send a message
await sendMessage('Hello, agent!');
// Cancel streaming
cancelStream();
// Disconnect
disconnect();Options:
| Option | Type | Required | Description |
|--------|------|----------|-------------|
| agent | AgentConfig | Yes | Agent configuration |
| proxyUrl | string | No | Server proxy endpoint |
| onMessage | (message: any) => void | No | Message received callback |
| onError | (error: Error) => void | No | Error callback |
| onStreamStart | () => void | No | Stream start callback |
| onStreamEnd | () => void | No | Stream end callback |
Returns:
| Property | Type | Description |
|----------|------|-------------|
| agent | AgentConfig | Current agent configuration |
| state | AgentState | Connection state object |
| sendMessage | (message: string) => Promise<void> | Send message function |
| cancelStream | () => void | Cancel streaming function |
| disconnect | () => void | Disconnect function |
| isStreaming | boolean | Currently streaming |
| isConnected | boolean | Currently connected |
| error | Error \| null | Last error |
useMultiAgent
Manage multiple agents without AgentProvider.
import { useMultiAgent } from '@kuntur/a2a-carbon-chat-adapter';
const {
agents, // All registered agents
currentAgent, // Currently selected agent
switchAgent, // Switch to agent by ID
registerAgent, // Add new agent
unregisterAgent, // Remove agent
} = useMultiAgent({
agents: [
{ id: 'research', name: 'Research', url: 'https://...' },
{ id: 'code', name: 'Code', url: 'https://...' },
],
defaultAgentId: 'research',
});
// Switch agents
switchAgent('code');
// Add new agent
registerAgent({ id: 'new', name: 'New Agent', url: 'https://...' });
// Remove agent
unregisterAgent('old');useAgentContext
Access AgentProvider context (must be used within AgentProvider).
import { useAgentContext } from '@kuntur/a2a-carbon-chat-adapter';
const {
currentAgent, // Currently selected agent
agents, // All available agents
selectAgent, // Select agent by ID
getAgent, // Get agent by ID
hasAgent, // Check if agent exists
} = useAgentContext();Server Utilities
createA2AHandler
Create a server-side API handler for proxying A2A requests.
import { createA2AHandler } from '@kuntur/a2a-carbon-chat-adapter/server';
const handler = createA2AHandler({
allowedAgentUrls: ['https://trusted-agent.example.com'],
timeout: 120000,
});
// Returns a function: (request: Request) => Promise<Response>Options:
| Option | Type | Required | Description |
|--------|------|----------|-------------|
| allowedAgentUrls | string[] | No | Whitelist of allowed agent URLs (security) |
| timeout | number | No | Request timeout in ms (default: 120000) |
Returns: (request: Request) => Promise<Response>
Renderers
Built-in components for rendering A2A UI extensions.
CitationRenderer
Renders text with inline citations.
import { CitationRenderer } from '@kuntur/a2a-carbon-chat-adapter';
<CitationRenderer
text="This is cited text [1]."
citations={[
{ id: '1', url: 'https://...', title: 'Source' }
]}
/>ErrorRenderer
Renders formatted error messages.
import { ErrorRenderer } from '@kuntur/a2a-carbon-chat-adapter';
<ErrorRenderer
error={{
message: 'Something went wrong',
code: 'ERROR_CODE',
stack: '...',
}}
showStack={true}
/>FormRenderer
Renders dynamic forms from agent requests.
import { FormRenderer } from '@kuntur/a2a-carbon-chat-adapter';
<FormRenderer
form={{
fields: [
{ name: 'email', type: 'email', label: 'Email', required: true },
{ name: 'message', type: 'textarea', label: 'Message' },
],
}}
onSubmit={(values) => console.log('Submitted:', values)}
/>Types
import type {
AgentConfig,
AgentState,
A2AChatProps,
AgentProviderProps,
AgentSwitcherProps,
ExtensionResult,
Citation,
FormField,
// ... more types
} from '@kuntur/a2a-carbon-chat-adapter';Advanced Usage
Multi-Agent Setup
import {
AgentProvider,
A2AChat,
AgentSwitcher,
useAgentContext,
} from '@kuntur/a2a-carbon-chat-adapter';
const agents = [
{
id: 'research',
name: 'Research Agent',
url: 'https://research.example.com',
description: 'Specialized in research and analysis',
},
{
id: 'code',
name: 'Code Agent',
url: 'https://code.example.com',
description: 'Specialized in code generation',
},
];
function App() {
return (
<AgentProvider
agents={agents}
defaultAgentId="research"
persistSelection={true}
>
<ChatWithSwitcher />
</AgentProvider>
);
}
function ChatWithSwitcher() {
const { agents, currentAgent, selectAgent } = useAgentContext();
return (
<div className="app-container">
<AgentSwitcher
agents={agents}
currentAgentId={currentAgent?.id}
onSelect={selectAgent}
variant="tabs"
showDescriptions={true}
/>
<A2AChat proxyUrl="/api/agent/chat" />
</div>
);
}Custom Citation Renderer
import { A2AChat } from '@kuntur/a2a-carbon-chat-adapter';
function CustomCitationRenderer({ citations, text }) {
return (
<div className="custom-citations">
<p>{text}</p>
<ul>
{citations.map((citation) => (
<li key={citation.id}>
<a href={citation.url} target="_blank" rel="noopener noreferrer">
[{citation.id}] {citation.title}
</a>
</li>
))}
</ul>
</div>
);
}
function App() {
return (
<A2AChat
agentUrl="https://agent.example.com"
renderCitations={(citations, text) => (
<CustomCitationRenderer citations={citations} text={text} />
)}
/>
);
}Programmatic Message Sending
import { useA2AAgent } from '@kuntur/a2a-carbon-chat-adapter';
import { useState } from 'react';
function CustomChat() {
const [messages, setMessages] = useState([]);
const { sendMessage, isStreaming, error } = useA2AAgent({
agent: {
id: 'agent',
name: 'My Agent',
url: 'https://agent.example.com',
},
proxyUrl: '/api/agent/chat',
onMessage: (message) => {
setMessages((prev) => [...prev, message]);
},
});
const handleSend = async (text: string) => {
setMessages((prev) => [...prev, { role: 'user', content: text }]);
await sendMessage(text);
};
return (
<div>
<div className="messages">
{messages.map((msg, i) => (
<div key={i} className={`message ${msg.role}`}>
{msg.content}
</div>
))}
</div>
{error && <div className="error">{error.message}</div>}
<input
type="text"
onKeyPress={(e) => {
if (e.key === 'Enter' && !isStreaming) {
handleSend(e.currentTarget.value);
e.currentTarget.value = '';
}
}}
disabled={isStreaming}
/>
</div>
);
}Extension URI Handling
The library automatically handles A2A extension URIs:
// Agent sends extension URI in response
{
"content": "agentstack://extension/citation/abc123",
"metadata": {
"extensions": {
"abc123": {
"type": "citation",
"data": {
"url": "https://example.com",
"title": "Example Source"
}
}
}
}
}
// Library automatically:
// 1. Detects extension URI
// 2. Looks up extension data in metadata
// 3. Renders using CitationRenderer
// 4. Replaces URI with rendered componentError Handling
import { A2AChat } from '@kuntur/a2a-carbon-chat-adapter';
function App() {
const handleError = (error: Error) => {
// Log to error tracking service
console.error('Agent error:', error);
// Show user-friendly message
if (error.message.includes('timeout')) {
alert('The agent is taking too long to respond. Please try again.');
} else if (error.message.includes('network')) {
alert('Network error. Please check your connection.');
} else {
alert('An error occurred. Please try again.');
}
};
return (
<A2AChat
agentUrl="https://agent.example.com"
onError={handleError}
/>
);
}Examples
For complete working examples, see the examples repository (coming soon).
Example applications include:
- Basic Chat: Simple single-agent chat interface
- Multi-Agent: Agent switching with tabs and dropdown
- Custom Renderers: Custom citation and form renderers
- Programmatic API: Using hooks without UI components
- Next.js Integration: Full Next.js app with API routes
- Express.js Integration: Express server with proxy setup
Architecture
Protocol Flow
┌─────────────────────────────────────────────────────────────────┐
│ Browser (Frontend) │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌─────────────────────────────────┐ │
│ │ A2AChat │────────▶│ useA2AAgent Hook │ │
│ │ Component │ │ - Manages connection state │ │
│ └──────────────┘ │ - Handles streaming │ │
│ │ │ - Parses extensions │ │
│ │ └─────────────────────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────┐ ┌─────────────────────────────────┐ │
│ │ Renderers │ │ A2AToCarbonTranslator │ │
│ │ - Citation │ │ - Converts A2A → Carbon format │ │
│ │ - Error │ │ - Handles metadata transform │ │
│ │ - Form │ └─────────────────────────────────┘ │
│ └──────────────┘ │ │
│ │ │
└────────────────────────────────────────┼────────────────────────┘
│
│ POST /api/agent/chat
│
┌────────────────────────────────────────┼────────────────────────┐
│ Your Server (Proxy) │ │
├────────────────────────────────────────┼────────────────────────┤
│ │ │
│ ┌─────────────▼──────────────┐ │
│ │ createA2AHandler │ │
│ │ - Validates agent URL │ │
│ │ - Forwards request │ │
│ │ - Streams response │ │
│ └─────────────┬──────────────┘ │
│ │ │
└────────────────────────────────────────┼────────────────────────┘
│
│ POST /chat
│
┌────────────────────────────────────────┼────────────────────────┐
│ A2A Agent │ │
├────────────────────────────────────────┼────────────────────────┤
│ │ │
│ ┌─────────────▼──────────────┐ │
│ │ A2A Protocol Handler │ │
│ │ - Processes message │ │
│ │ - Generates response │ │
│ │ - Streams via SSE │ │
│ └────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────┘Package Structure
@kuntur/a2a-carbon-chat-adapter/
├── dist/ # Built output
│ ├── index.js # ESM main entry
│ ├── index.cjs # CJS main entry
│ ├── index.d.ts # TypeScript definitions
│ ├── server.js # ESM server utilities
│ ├── server.cjs # CJS server utilities
│ ├── server.d.ts # Server TypeScript definitions
│ └── styles/
│ └── index.css # Component styles
├── src/
│ ├── components/ # React components
│ │ ├── A2AChat.tsx
│ │ ├── AgentProvider.tsx
│ │ ├── AgentSwitcher.tsx
│ │ └── renderers/ # Extension renderers
│ ├── hooks/ # React hooks
│ │ ├── useA2AAgent.ts
│ │ ├── useMultiAgent.ts
│ │ └── useAgentContext.ts
│ ├── lib/
│ │ ├── a2a/ # A2A protocol client
│ │ └── translator/ # Protocol translation
│ ├── server/ # Server utilities
│ │ └── create-api-handler.ts
│ └── types/ # TypeScript types
└── package.jsonTroubleshooting
CORS Errors
Problem: Browser console shows CORS errors when connecting to agent.
Solution: You must use a server proxy. See Server Proxy Setup.
❌ Access to fetch at 'https://agent.example.com' from origin 'http://localhost:3000'
has been blocked by CORS policyStreaming Not Working
Problem: Messages don't stream; they appear all at once.
Solution: Ensure your server proxy is configured correctly:
// Next.js: Add these exports
export const runtime = 'nodejs';
export const dynamic = 'force-dynamic';
// Express: Ensure streaming is not buffered
app.use(express.json({ limit: '50mb' }));Extension URIs Not Rendering
Problem: Extension URIs appear as plain text instead of rendered components.
Solution: Ensure the agent includes extension metadata:
{
"content": "See citation [1]",
"metadata": {
"extensions": {
"1": {
"type": "citation",
"data": {
"url": "https://example.com",
"title": "Example"
}
}
}
}
}TypeScript Errors
Problem: TypeScript can't find module declarations.
Solution: Ensure @carbon/ai-chat is installed and types are available:
npm install @carbon/ai-chat @types/react @types/react-domAgent Not Responding
Problem: No response from agent after sending message.
Checklist:
- ✅ Server proxy is running and accessible
- ✅ Agent URL is correct and agent is running
- ✅ Agent URL is in
allowedAgentUrls(if configured) - ✅ Network tab shows request reaching
/api/agent/chat - ✅ Check server logs for errors
Performance Issues
Problem: Chat feels slow or laggy.
Solutions:
- Reduce
timeoutincreateA2AHandlerfor faster failures - Implement message pagination for long conversations
- Use
showThinking={false}to reduce re-renders - Memoize custom renderers with
React.memo()
Contributing
Contributions are welcome! Please follow these guidelines:
Development Setup
# Clone repository
git clone https://github.com/Xnvargas/a2a-carbon-chat-adapter.git
cd a2a-carbon-chat-adapter
# Install dependencies
npm install
# Run development build (watch mode)
npm run dev
# Run type checking
npm run typecheck
# Run linting
npm run lint
# Build for production
npm run buildSubmitting Changes
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests if applicable
- Run
npm run typecheckandnpm run lint - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Code Style
- Use TypeScript for all new code
- Follow existing code formatting (ESLint config)
- Add JSDoc comments for public APIs
- Update documentation for user-facing changes
Reporting Issues
When reporting issues, please include:
- Library version (
npm list @kuntur/a2a-carbon-chat-adapter) - Framework and version (Next.js, React, etc.)
- Minimal reproduction code
- Expected vs actual behavior
- Browser console errors (if applicable)
License
MIT © Xavier Vargas
See LICENSE file for details.
Links
- GitHub: https://github.com/Xnvargas/a2a-carbon-chat-adapter
- npm: https://www.npmjs.com/package/@kuntur/a2a-carbon-chat-adapter
- Issues: https://github.com/Xnvargas/a2a-carbon-chat-adapter/issues
- Examples: https://github.com/Xnvargas/a2a-carbon-chat-adapter-examples (coming soon)
- A2A Protocol: https://github.com/agentstack/a2a
- Carbon AI Chat: https://github.com/carbon-design-system/carbon-for-ai
Made with ❤️ for the AI agent community
