Custom API Services
The Kapa SDK uses an API service to handle communication with the Kapa backend. The SDK includes a default implementation, but you can provide your own implementation for testing or custom networking needs.
Default API service
By default, the SDK uses the DefaultKapaApiService
to communicate with Kapa's
backend. This service handles:
- Submitting user queries and streaming back responses
- Sending feedback for question-answer pairs
- Managing request cancellation
Most applications can use the default service without modification.
Custom API service implementation
For testing, special networking requirements, or integration with your own
middleware, you can create a custom API service by implementing the
KapaApiService
interface.
API service interface
interface KapaApiService {
/**
* Post a question to the backend and stream back the answer
*/
submitQuery(args: SubmitQueryArgs, callbacks: ChatStreamCallbacks): Promise<void>;
/**
* Send feedback (👍 / 👎) for a specific QA pair
*/
addFeedback(args: SubmitFeedbackArgs): Promise<void>;
/**
* Abort the current network request, if any
*/
abortCurrent(): void;
}
Parameter types
The interface uses the following parameter types:
interface SubmitQueryArgs {
// User's question
query: string;
// Optional thread ID for continuing a conversation
// If null, a new conversation thread will be created
threadId: string | null;
// reCAPTCHA/hCaptcha verification token for bot protection
captcha: CaptchaToken;
// Your Kapa integration ID
integrationId: string;
// User identification data for personalization and tracking
userIdentifiers: UserIdentifiers;
// Additional user metadata for analytics/tracking
userMetadata: UserMetadata;
// The URL where the query was initiated
originUrl: string;
}
interface SubmitFeedbackArgs {
// Unique identifier for the question-answer pair
questionAnswerId: string;
// User's reaction to an answer
reaction: "upvote" | "downvote";
// reCAPTCHA/hCaptcha verification token for bot protection
captcha: CaptchaToken;
// Your Kapa integration ID
integrationId: string;
// Optional user-provided comment/reason
comment?: FeedbackComment;
}
interface ChatStreamCallbacks {
// Called when the first response byte is received
onFirstToken?: () => void;
// Called repeatedly with chunks of the answer
onPartialAnswer?: (partial: string) => void;
// Called with the list of relevant citation sources
onRelevantSources?: (sources: Source[]) => void;
// Called when an error occurs during streaming
onError?: (msg: string) => void;
// Called with thread and QA pair identifiers once they're available
onIdentifiers?: (threadId: string, qaPairId: string) => void;
}
Using a custom API service
To use a custom API service, pass it to the KapaProvider
component:
import { KapaProvider } from '@kapaai/react-sdk';
import { MyCustomApiService } from './my-custom-api-service';
function App() {
// Create an instance of your custom API service
const customApiService = new MyCustomApiService();
return (
<KapaProvider
integrationId="your-integration-id"
callbacks={{...}}
apiService={customApiService}
>
<YourApplication />
</KapaProvider>
);
}
Example: Creating a test mock service
Here's an example of creating a mock API service for testing:
import {
KapaApiService,
SubmitQueryArgs,
SubmitFeedbackArgs,
ChatStreamCallbacks
} from '@kapaai/react-sdk';
export class MockKapaApiService implements KapaApiService {
async submitQuery(
args: SubmitQueryArgs,
callbacks: ChatStreamCallbacks
): Promise<void> {
// Simulate connection setup
await new Promise(resolve => setTimeout(resolve, 500));
// Simulate first token received
callbacks.onFirstToken?.();
// Simulate a thread ID
const threadId = 'mock-thread-123';
const qaPairId = 'mock-qa-456';
callbacks.onIdentifiers?.(threadId, qaPairId);
// Simulate streaming answer chunks
const answerChunks = [
"Hello! I'm ",
"a mock ",
"AI assistant. ",
"How can I help you today?"
];
for (const chunk of answerChunks) {
await new Promise(resolve => setTimeout(resolve, 300));
callbacks.onPartialAnswer?.(chunk);
}
// Simulate sources
callbacks.onRelevantSources?.([
{
title: "Mock Documentation",
source_url: "https://example.com/docs",
source_type: "webpage"
}
]);
}
async addFeedback(args: SubmitFeedbackArgs): Promise<void> {
console.log('Mock feedback submitted:', args);
// Simulate network delay
await new Promise(resolve => setTimeout(resolve, 300));
// Return success (no throw = success)
}
abortCurrent(): void {
console.log('Mock abort called');
// Implementation would cancel any ongoing simulations
}
}