@difizen/magent-au
Version:
163 lines (148 loc) • 4.59 kB
text/typescript
import type {
ChatMessageItemOption,
ConversationOption,
IChatEvent,
} from '@difizen/magent-chat';
import type { IChatMessageItem } from '@difizen/magent-chat';
import { ChatService } from '@difizen/magent-chat';
import { Fetcher } from '@difizen/magent-core';
import { inject, singleton } from '@difizen/mana-app';
import { EventSourceParserStream } from 'eventsource-parser/stream';
import type { APISession, SessionOption } from '../session/protocol.js';
import { toSessionOption } from '../session/protocol.js';
import type { APIMessage, AUMessageCreate } from './protocol.js';
import { AUChatEvent } from './protocol.js';
function stringToReadableStream(inputString: string) {
// Convert the string into a Uint8Array
const encoder = new TextEncoder();
const uint8Array = encoder.encode(inputString);
// Create a new ReadableStream
const readableStream = new ReadableStream({
start(controller) {
// Enqueue the Uint8Array into the stream
controller.enqueue(uint8Array);
// Close the stream
controller.close();
},
});
return readableStream;
}
()
export class AUChatService extends ChatService {
(Fetcher) fetcher: Fetcher;
override chat = async (option: AUMessageCreate): Promise<IChatMessageItem[]> => {
const { agentId, sessionId, input } = option;
const res = await this.fetcher.post<APIMessage>(
`/api/v1/agents/${option.agentId}/chat`,
{
agent_id: agentId,
session_id: sessionId,
input: input,
},
);
if (res.status === 200) {
if (res.data.output) {
return [
{
sender: { type: 'AI', id: agentId },
content: res.data.output,
},
];
}
}
return [];
};
override chatStream = async (
option: AUMessageCreate,
messgeCallback: (event: IChatMessageItem) => void,
eventCallback: (event: IChatEvent) => void,
) => {
const { agentId, sessionId, input } = option;
const url = `/api/v1/agents/${option.agentId}/stream-chat`;
const msg = {
agent_id: agentId,
session_id: sessionId,
input: input,
};
const res = await this.fetcher.post<ReadableStream<Uint8Array>>(url, msg, {
headers: {
Accept: 'text/event-stream',
},
responseType: 'stream',
adapter: 'fetch',
});
if (res.status === 200) {
let reader;
if (typeof res.data === 'string') {
reader = stringToReadableStream(res.data)
.pipeThrough(new TextDecoderStream())
.pipeThrough(new EventSourceParserStream())
.getReader();
} else {
const stream = res.data;
reader = stream
.pipeThrough(new TextDecoderStream())
.pipeThrough(new EventSourceParserStream())
.getReader();
}
messgeCallback({
sender: { type: 'AI', id: agentId },
content: '',
});
let alreayDone = false;
while (!alreayDone) {
const { value, done } = await reader.read();
if (done) {
alreayDone = true;
eventCallback({
type: 'done',
});
break;
}
const data = JSON.parse(value.data);
const event = AUChatEvent.format(value.event || 'chunk', data);
eventCallback(event);
}
return;
}
};
override getConversationMessages = async (
conversation: ConversationOption,
): Promise<ChatMessageItemOption[]> => {
return [];
};
override getConversations = async (opt: {
agentId: string;
}): Promise<SessionOption[]> => {
const res = await this.fetcher.get<APISession[]>(`/api/v1/sessions`, {
agent_id: opt.agentId,
});
if (res.status !== 200) {
return [];
}
return res.data.map((item) => toSessionOption(item));
};
override getConversation = async (
opt: ConversationOption,
): Promise<ConversationOption | undefined> => {
return undefined;
};
override createConversation = async (option: {
agentId: string;
}): Promise<SessionOption> => {
const res = await this.fetcher.post<APISession>(`/api/v1/sessions`, {
agent_id: option.agentId,
});
if (res.status !== 200) {
throw new Error('Create session failed');
}
return toSessionOption(res.data);
};
override deleteConversation = async (opt: ConversationOption): Promise<boolean> => {
const res = await this.fetcher.delete<APISession>(`/api/v1/sessions/${opt.id}`);
if (res.status !== 200) {
return false;
}
return true;
};
}