Skip to main content

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
});