SDK: Examples
End-to-end examples for building with Flapjack: basic chatbot, support agent with tools, and RAG-powered app.
Complete, working examples for common Flapjack use cases.
Example 1: Basic Chatbot (Node.js)
A CLI chatbot that streams responses to the terminal.
import { FlapjackClient } from '@flapjack/sdk';
import * as readline from 'readline';
const client = new FlapjackClient({
apiKey: process.env.FLAPJACK_API_KEY!,
});
async function main() {
// Get the first agent
const agents = await client.listAgents();
if (agents.length === 0) {
console.error('No agents found. Create one at flapjack.chat');
return;
}
const agent = agents[0];
console.log(`Chatting with: ${agent.name}\n`);
// Create a thread
const thread = await client.createThread(agent.id);
// Chat loop
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
const ask = (prompt: string) => new Promise<string>(resolve => rl.question(prompt, resolve));
while (true) {
const input = await ask('You: ');
if (input === 'exit') break;
process.stdout.write('Agent: ');
for await (const event of client.sendMessage(thread.id, input)) {
if (event.type === 'token') process.stdout.write(event.delta);
if (event.type === 'tool_call') process.stdout.write(`\n[Using ${event.tool.name}...] `);
if (event.type === 'error') console.error(`\nError: ${event.code}`);
}
console.log('\n');
}
rl.close();
}
main();
π Copy as prompt
Build a CLI chatbot using Flapjack's SDK. It should list agents, create a thread with the first agent, then loop: read user input, send it to the agent, and stream the response token-by-token. Exit when the user types "exit".
Example 2: Support Agent with Tool Visibility
A React chat UI that shows when the agent is using tools.
import { useState } from 'react';
import { FlapjackProvider, useChat } from '@flapjack/sdk/react';
function SupportChat({ agentId }: { agentId: string }) {
const { messages, sendMessage, isStreaming, error } = useChat(agentId);
const [input, setInput] = useState('');
const [activeTool, setActiveTool] = useState<string | null>(null);
// Note: For tool visibility with useChat, you'd typically
// use the lower-level client.sendMessage and manage state manually.
// This example shows the simpler useChat approach.
return (
<div className="chat-container">
<h2>Support</h2>
<div className="messages">
{messages.map((msg, i) => (
<div key={i} className={`message ${msg.role}`}>
<span className="role">{msg.role === 'user' ? 'You' : 'Support'}</span>
<p>{msg.content}</p>
</div>
))}
{isStreaming && <div className="typing">Agent is responding...</div>}
{error && <div className="error">{error}</div>}
</div>
<form onSubmit={(e) => {
e.preventDefault();
if (input.trim() && !isStreaming) {
sendMessage(input);
setInput('');
}
}}>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Describe your issue..."
disabled={isStreaming}
/>
<button type="submit" disabled={isStreaming}>Send</button>
</form>
</div>
);
}
export default function App() {
// β οΈ NEXT_PUBLIC_ exposes the key client-side β use server proxy in production
// See: docs/developer/sdk/server-proxy.md
return (
<FlapjackProvider config={{ apiKey: process.env.NEXT_PUBLIC_FLAPJACK_API_KEY! }}>
<SupportChat agentId="your-support-agent-id" />
</FlapjackProvider>
);
}
π Copy as prompt
Build a React support chat component using Flapjack's
useChathook. Include a message list with role labels, streaming indicator, error display, and a form with input and submit button.
Example 3: RAG-Powered App
Upload documents and ask questions against them.
import { FlapjackClient } from '@flapjack/sdk';
import { readFileSync } from 'fs';
const client = new FlapjackClient({
apiKey: process.env.FLAPJACK_API_KEY!,
});
async function main() {
const agentId = process.env.FLAPJACK_AGENT_ID!;
// Upload a document
const fileContent = readFileSync('./product-docs.md');
const blob = new Blob([fileContent], { type: 'text/markdown' });
const doc = await client.uploadDocument(agentId, blob, 'Product Documentation');
console.log(`Uploaded: ${doc.title}\n`);
// List all documents
const docs = await client.listDocuments(agentId);
console.log('Knowledge base:');
docs.forEach(d => console.log(` - ${d.title} (${d.chunk_count} chunks)`));
console.log();
// Create a thread and ask a question
const thread = await client.createThread(agentId);
console.log('Asking: "What are the pricing tiers?"\n');
process.stdout.write('Agent: ');
for await (const event of client.sendMessage(thread.id, 'What are the pricing tiers?')) {
if (event.type === 'token') process.stdout.write(event.delta);
if (event.type === 'done') console.log('\n');
}
// Clean up (optional)
// await client.deleteDocument(doc.id);
}
main();
π Copy as prompt
Build a Flapjack RAG script that uploads a markdown file to an agent's knowledge base, lists all documents, creates a thread, asks a question about the uploaded content, and streams the answer.
Example 4: System Activity Messages
Show system activity as compact status indicators instead of user bubbles β useful for plan approvals, tool confirmations, and custom events.
import { FlapjackProvider, useChat } from '@flapjack/sdk/react';
import { ChatMessages, ChatInput, SystemUserMessage } from '@flapjack/sdk/components';
import '@flapjack/sdk/components/style.css';
function AgentChat({ agentId }: { agentId: string }) {
const { messages, sendMessage, addSystemMessage, isStreaming } = useChat(agentId);
return (
<div style={{ height: '100vh', display: 'flex', flexDirection: 'column' }}>
<ChatMessages messages={messages} isStreaming={isStreaming} />
<div style={{ padding: 12, display: 'flex', gap: 8 }}>
{/* Example: manual system activity buttons */}
<button onClick={() => addSystemMessage(
{ icon: 'check', label: 'Plan approved' },
{ content: 'Approved. Please proceed with the plan.' },
)}>
Approve Plan
</button>
<button onClick={() => addSystemMessage(
{ icon: 'π', label: 'Deployment started' },
{ sendToAgent: false },
)}>
Deploy (visual only)
</button>
</div>
<ChatInput onSend={sendMessage} isStreaming={isStreaming} />
</div>
);
}
export default function App() {
return (
<FlapjackProvider config={{ apiKey: process.env.NEXT_PUBLIC_FLAPJACK_API_KEY! }}>
<AgentChat agentId="your-agent-id" />
</FlapjackProvider>
);
}
Key points:
addSystemMessagerenders a centered icon + label pill instead of a user bubble- Set
sendToAgent: falsefor visual-only indicators (no agent turn triggered) - Built-in icons:
check(β),tool(π§),info(βΉ),error(β) β or pass any emoji
Copy as prompt
Build a React chat with Flapjack that uses
addSystemMessagefromuseChatto show system activity indicators. Add buttons for plan approval (sends to agent) and deployment notification (visual only). Use the SDK'sChatMessagesandChatInputcomponents.
Example 5: Custom Events
Handle domain-specific events emitted by tools during streaming β feature suggestions, navigation proposals, auth challenges, etc.
import { FlapjackProvider, useChat } from '@flapjack/sdk/react';
import { ChatMessages, ChatInput } from '@flapjack/sdk/components';
import { useState } from 'react';
type Suggestion = { name: string; description: string; icon: string };
type NavigationProposal = { url: string; label: string };
function AgentChat({ agentId }: { agentId: string }) {
const [suggestions, setSuggestions] = useState<Suggestion[]>([]);
const { messages, sendMessage, isStreaming } = useChat(agentId, {
onCustomEvent(kind, payload) {
if (kind === 'suggestion') {
setSuggestions((prev) => [...prev, payload as Suggestion]);
}
if (kind === 'navigation_proposal') {
const { url, label } = payload as NavigationProposal;
window.location.href = url; // or show a confirmation card
}
},
});
return (
<div style={{ height: '100vh', display: 'flex', flexDirection: 'column' }}>
<ChatMessages messages={messages} isStreaming={isStreaming} />
{suggestions.length > 0 && (
<div style={{ padding: 8, display: 'flex', gap: 8, flexWrap: 'wrap' }}>
{suggestions.map((s, i) => (
<button key={i} style={{ padding: '4px 12px', borderRadius: 16, border: '1px solid #ccc' }}>
{s.icon} {s.name}
</button>
))}
</div>
)}
<ChatInput onSend={sendMessage} isStreaming={isStreaming} />
</div>
);
}
export default function App() {
return (
<FlapjackProvider config={{ apiKey: process.env.NEXT_PUBLIC_FLAPJACK_API_KEY! }}>
<AgentChat agentId="your-agent-id" />
</FlapjackProvider>
);
}
How it works:
- Tools return
_client_eventsin their output β the runtime strips them before feeding back to the LLM and emits each as acustomSSE event onCustomEventfires for eachcustomevent withkind(string identifier) andpayload(arbitrary JSON)- Use
kindto dispatch to the right handler β suggestions, navigation, auth challenges, etc.
Copy as prompt
Build a React chat with Flapjack that handles custom SSE events using
onCustomEventinuseChat. Handle "suggestion" events by collecting them into a button bar and "navigation_proposal" events by navigating the browser.
Next Steps
- SDK: Client β full method reference
- SDK: Server Proxy β production security
- Concepts: Knowledge β how RAG works
- Concepts: Streaming β event types