Skip to main content

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

MethodDescription
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

StatusDescription
pendingTool call received, waiting to start.
approval_requestedWaiting for user to approve or deny.
executingTool's execute function is running.
completedFinished successfully.
errorexecute threw an error.
deniedUser clicked Deny.
stoppedGeneration was stopped while tool was in progress.

Session management

The Agent class handles session tokens automatically:

  • Tokens are fetched lazily (only when sendMessage is 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);
},
});
EventDataWhen
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.