# Alchemist: Embedded Agent — Inline Panel
Embed a native chat panel as part of your application interface.
---
The **inline panel** is a full-height, native chat interface that lives in your application alongside other content. Unlike the floating widget, it is part of your page layout and does not float over content.
## When to use the inline panel
Use the inline panel when:
- You want the agent as a **main navigation item** (e.g., a "Chat" or "Assistant" tab)
- The agent is a **core feature** of your application, not supplementary
- You want the agent interface to **span the full height** of its container
- You need **fine-grained control** over where the panel appears (sidebar, main column, modal, etc.)
For a persistent button that floats over your entire site, use the [floating widget](/docs/guides/alchemist-embedded-chipp-agent-widget/) instead.
## Basic setup
### 1. Install the feature pack
Follow the [installation guide](/docs/guides/alchemist-embedded-chipp-agent-install/) first. Once installed, your project has a `ChatPanel` component ready to import.
### 2. Import the component
In your page or layout file:
```tsx
import { ChatPanel } from '@/components/embedded-agent/ChatPanel';
```
### 3. Render the panel
Place the component in your layout:
```tsx
{/* Your main content */}
```
The panel fills its container. Wrap it in a flex container with `flex-1` to make it responsive.
## Component props
```typescript
interface ChatPanelProps {
// Required
projectId: string; // Your Alchemist project ID
sessionEndpoint: string; // Your backend session endpoint (e.g., /api/chat/session)
// Optional: Identity
externalUserId?: string; // Authenticated user ID (email for email-based auth)
metadata?: Record; // Additional user context (e.g., { "plan": "pro" })
// Optional: Appearance
theme?: 'light' | 'dark'; // Default: inherits from page
placeholder?: string; // Chat input placeholder
welcomeMessage?: string; // Initial message before first user input
// Optional: Behavior
maxMessages?: number; // Limit conversation length (default: unlimited)
autoScroll?: boolean; // Auto-scroll to latest message (default: true)
allowFileUpload?: boolean; // Allow users to upload files (default: true)
// Optional: Callbacks
onSessionStart?: (sessionId: string) => void; // Fired when session is created
onMessageSent?: (message: string) => void; // Fired after user message
onError?: (error: EmbedError) => void; // Fired on chat errors
}
```
## Authentication & identity
### Authenticated users (email-based)
If your application has logged-in users, pass their identity to the panel:
```tsx
const user = useAuthContext(); // Your app's auth hook
```
Your backend endpoint receives the `externalUserId` and metadata, mints a Chipp session, and returns a token. The user's conversations are retained across browser sessions.
### Anonymous/visitor mode
For unauthenticated visitors, omit the `externalUserId`:
```tsx
```
The backend mints an anonymous session (stored in a browser cookie). The conversation is retained for the duration of the session (browser tab).
### Upgrading from anonymous to authenticated
If a user starts as anonymous and later logs in, call the upgrade endpoint:
```tsx
const sessionId = await fetch('/api/chat/session/upgrade', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
currentSessionId: previousSessionId,
externalUserId: user.email,
}),
});
```
The conversation is merged into the authenticated session.
## Styling & customization
The panel uses your project's **design system** by default (no iframe, no style isolation). It inherits colors, fonts, and spacing from your application's CSS.
### Theme override
Force light or dark mode:
```tsx
```
### Custom CSS classes
Wrap the panel in a container and apply custom styles:
```tsx
```
```css
.custom-chat-wrapper :global(.embed-panel) {
border-left: 4px solid var(--primary);
}
```
### Placeholder & welcome messages
Customize input placeholders and initial prompts:
```tsx
```
## Error handling
Errors are emitted via the `onError` callback. Common errors:
```typescript
interface EmbedError {
code: string; // e.g., 'AUTH_FAILED', 'SESSION_EXPIRED', 'NETWORK_ERROR'
message: string; // Human-readable message
retryable: boolean; // Whether the error can be retried
originalError?: Error; // Underlying JS error
}
```
Example handler:
```tsx
const handleError = (error: EmbedError) => {
if (error.code === 'SESSION_EXPIRED') {
// Prompt user to re-authenticate
window.location.href = '/login';
} else if (error.retryable) {
console.log('Temporary error; will retry automatically.');
} else {
showToast(`Chat unavailable: ${error.message}`);
}
};
```
## Responsive layout
The panel fills its container. For responsive designs:
```tsx
// Mobile: Panel as full-height overlay
// Desktop: Panel in a sidebar
import { useMediaQuery } from '@/hooks/use-media-query';
const isMobile = useMediaQuery('(max-width: 768px)');
{isMobile ? (
) : (
{/* Page content */}
)}
```
## File uploads & attachments
By default, users can attach files to messages (images, PDFs, etc.). Disable this if needed:
```tsx
```
Uploaded files are processed by the bound Chipp agent according to its configuration (vision, file reading, etc.).
## Conversation history
The panel automatically loads previous messages from the current session. To reset or start a new conversation, reload the panel or create a fresh session token (by updating the `externalUserId` prop).
## Troubleshooting
### "Session endpoint returned 401"
- Verify your backend session endpoint is correctly configured.
- Ensure your project's client key is valid: check **Project Settings → API Keys**.
- If using authenticated mode, confirm the `externalUserId` is being passed correctly.
### "Chat not loading / shows error spinner indefinitely"
- Check browser console for network errors.
- Verify the bound Chipp agent is online (check Chipp workspace).
- Confirm `projectId` and `sessionEndpoint` are correctly set.
### "Messages not persisting across sessions"
- In authenticated mode, ensure `externalUserId` is consistent (same email).
- In anonymous mode, sessions are cookie-based; clearing cookies will reset the conversation.
### Styling does not match my design system
- The panel inherits from your page's CSS. Verify your design system CSS is loaded before the panel renders.
- Use custom CSS classes (see "Styling & customization" above) to override specific elements.
## Next steps
- **[Floating widget](/docs/guides/alchemist-embedded-chipp-agent-widget/)** — Add a persistent chat widget
- **[Backend client](/docs/guides/alchemist-embedded-chipp-agent-backend/)** — Integrate agent calls in your server routes