JavaScript / TypeScript SDK
@kapaai/agent-core is the framework-agnostic foundation. It handles session tokens, streaming, tool execution, and the agent loop. No React, no DOM — works in browsers, Node.js, Deno, and edge runtimes.
Use this package when you're not using React, or when you need full control over the UI. React users should use @kapaai/agent-react instead (install both @kapaai/agent-core and @kapaai/agent-react).
Installation
npm install @kapaai/agent-core
The Agent class
Agent is the main entry point. It combines session management, streaming, tool execution, and approval flow in a single class.
import { Agent } from '@kapaai/agent-core';
const agent = new Agent({
projectId: 'your-project-id',
integrationId: 'your-integration-id',
tools: [],
context: {},
getSessionToken: async () => {
const res = await fetch('/api/session', { method: 'POST' });
return res.json(); // SDK accepts the raw API response directly
},
onMessagesChange: (messages) => {
// Called whenever messages update (new text, tool calls, etc.)
renderMessages(messages);
},
onStreamingChange: (isStreaming) => {
// Called when streaming starts or stops
toggleLoadingIndicator(isStreaming);
},
});
// Send a message — triggers the agent loop
await agent.sendMessage('How do I get started?');
Methods
| Method | Description |
|---|---|
sendMessage(text) | Send a user message and run the agent loop. |
resetConversation() | Clear all messages and abort any in-progress request. |
stopGeneration() | Abort the current streaming response. |
approveToolCall(id) | Approve a tool that's waiting for user confirmation. |
rejectToolCall(id) | Reject a tool that's waiting for user confirmation. |
updateOptions(partial) | Update tools, context, or other options without resetting. |
getMessages() | Get the current messages array. |
getIsStreaming() | Whether the agent is currently streaming. |
getThreadId() | The current conversation thread ID. |
clearSession() | Force clear the cached session token. |
Options
type AgentOptions<TContext> = {
projectId: string;
integrationId: string;
getSessionToken: () => Promise<{ token: string; expiresAt: number }>;
tools: ToolDefinition<TContext>[];
context: TContext;
builtinToolMeta?: Record<string, ToolDisplayMeta>;
customInstructions?: string;
user?: EndUserInfo;
onEvent?: OnAgentEvent;
onMessagesChange: (messages: AgentMessage[]) => void;
onStreamingChange: (isStreaming: boolean) => void;
onThreadIdChange?: (threadId: string | null) => void;
};
Built-in tools
The agent includes a built-in search_knowledge_base tool that searches your project's knowledge base server-side — the same sources you've configured in the Kapa dashboard. This tool is executed by Kapa's backend and cannot be customized. You can provide display metadata via builtinToolMeta so it shows a friendly name in your UI instead of the raw tool name.
Message format
Messages are either user or assistant messages:
type AgentMessage =
| { role: 'user'; content: string }
| {
role: 'assistant';
content: string;
blocks: ContentBlock[];
isError?: boolean;
};
Assistant messages contain blocks — an array of text and tool call blocks in the order they appeared during streaming:
type ContentBlock =
| { type: 'text'; content: string }
| { type: 'tool_calls'; toolCalls: ToolCallDisplay[] };
Each ToolCallDisplay tracks the lifecycle of a tool call:
type ToolCallDisplay = {
id: string;
name: string;
arguments: Record<string, unknown>;
status: ToolCallStatus;
result?: unknown;
error?: string;
durationMs?: number;
sources?: AgentSource[];
displayName?: string;
needsApproval?: boolean;
};
ToolCallStatus
| Status | Description |
|---|---|
pending | Tool call received, waiting to start. |
approval_requested | Waiting for user to approve or deny. |
executing | Tool's execute function is running. |
completed | Finished successfully. |
error | execute threw an error. |
denied | User clicked Deny. |
stopped | Generation was stopped while tool was in progress. |
Session management
The Agent class handles session tokens automatically:
- Tokens are fetched lazily (only when
sendMessageis first called) - Tokens are cached and refreshed 30 seconds before expiry
- On 401 errors, the token is cleared and retried once
- Concurrent refresh calls are deduplicated
You never need to manage tokens yourself — just provide the getSessionToken function.
Events
The onEvent callback fires at key moments. Use it for analytics, logging, or monitoring.
const agent = new Agent({
// ...
onEvent: (event) => {
console.log(event.type, event.data);
},
});
| Event | Data | When |
|---|---|---|
message_sent | { messageLength } | User sends a message. |
response_completed | { threadId, toolCallCount } | Agent finishes responding. |
response_error | { error, threadId } | Agent response failed. |
generation_stopped | { threadId } | User stopped generation. |
tool_executed | { toolName, status, durationMs, error? } | A tool finished (success or error). |
tool_approved | { toolName, toolCallId } | User approved a tool. |
tool_denied | { toolName, toolCallId } | User denied a tool. |
conversation_reset | {} | Conversation was reset. |