Ky-based Implementation (Recommended)
This document shows how to implement a custom AgentService using the built-in Ky HTTP client. Compared to Axios, Ky has better native support for SSE (Server-Sent Events) streaming responses, making it more suitable for AI conversation scenarios.
Built-in HTTP Modules
AaaS Pilot Kit includes complete HTTP processing modules, providing out-of-the-box HTTP clients and SSE support:
- ky - HTTP client based on ky, supports retry, timeout, interceptors and other advanced features
- sseHook - Hook function specifically for handling Server-Sent Events (SSE), simplifying streaming data processing
Advantages
Benefits of using built-in HTTP modules:
- 🎯 Unified Configuration - Pre-configured with default parameters suitable for conversation scenarios
- 🔧 Out-of-the-box - No need to install additional HTTP client dependencies
- 🚀 Streaming Optimized - Native support for SSE streaming response processing
- 🛡️ Error Handling - Built-in comprehensive error handling and retry mechanisms
Complete Implementation Code
// Import ky client and SSE Hook from Kit's built-in HTTP modules
import {ky, sseHook} from '@bdky/aaas-pilot-kit/http';
import {v4 as uuid} from 'uuid';
import {BaseAgentService} from '@bdky/aaas-pilot-kit';
// Need to inherit from BaseAgentService provided by Kit
export class CustomAgentService extends BaseAgentService {
static QUERY_URL = 'https://origin/api/sse';
abortController: AbortController | null = null;
// Dispose logic, can be customized
dispose = action(() => {
// Built-in base class method
this._dispose();
// Can implement according to your own logic
});
// Override base class query method to implement SSE streaming protocol
override query = async (text: string) => {
this.abortController = new AbortController();
const hook = sseHook.createHook({
onData: data => {
const parsedMessage = JSON.parse(data);
const {
answer,
sessionId,
action,
intentResult
} = parsedMessage;
// Recommended: Set sessionId
if (sessionId) {
this.setSessionId(sessionId);
}
if (answer) {
// Required: Call Kit's onData method to pass incomplete data from each round
this.onData({
sessionId: this.conversationSessionId,
answer
});
}
},
onCompleted: () => {
// Required: When streaming response completes, call Kit's onCompleted method to mark end of current round streaming content output
this.onCompleted({
sessionId: this.conversationSessionId
});
}
});
const params = {
query: text,
// ID for this round of conversation
queryId: this.queryId,
// Session for entire conversation
sessionId: this.conversationSessionId
};
try {
await ky.post(CustomAgentService.QUERY_URL, {
retry: 0,
timeout: 300 * 1000,
signal: this.abortController?.signal,
headers: {
'x-trace-id': this.queryId
},
hooks: {
// Create hook and bind
afterResponse: [hook]
},
json: {
...params
}
});
}
catch (e) {
// TODO Business error handling
if (e instanceof Error) {
throw new Error(`Failed to request conversation API: ${e.message}`);
}
}
};
}
Key Feature Explanation
1. SSE Streaming Processing
Use built-in sseHook to handle Server-Sent Events responses:
// Use built-in sseHook to create SSE processing hook
const hook = sseHook.createHook({
onData: data => {
// Process each data chunk
const parsedMessage = JSON.parse(data);
// Call Kit's onData method to pass data
this.onData({
sessionId: this.conversationSessionId,
answer: parsedMessage.answer
});
},
onCompleted: () => {
// Streaming response completed
this.onCompleted({
sessionId: this.conversationSessionId
});
}
});
2. Request Interrupt Control
Built-in ky client supports request interruption and resource cleanup:
this.abortController = new AbortController();
// Use built-in ky client to send request, supports AbortController
await ky.post(postUrl, {
signal: this.abortController?.signal,
// ... other configurations
});
3. Error Handling
Built-in ky client provides complete HTTP error status code handling:
catch (e) {
if (e instanceof Error) {
throw new Error(`Failed to request conversation API: ${e.message}`);
}
// Built-in error handling mechanism will automatically handle network errors, timeouts, etc.
}
Register to Kit
import {createAaaSPilotKit} from '@bdky/aaas-pilot-kit';
import {CustomAgentService} from './CustomAgentService';
const kit = createAaaSPilotKit<CustomAgentService>({
// Other configurations...
agentService: CustomAgentService
});