feat: Update asset metadata and enhance Agent class in SDK
- Updated modification times for various asset files in bindata.go to reflect recent changes. - Enhanced the Agent class in libsui/agent.ts with improved type definitions and event handling. - Introduced new interfaces for message structures and event handlers, streamlining message processing. - Refactored the Call method to better manage message states and improve error handling.
This commit is contained in:
parent
d731296b94
commit
d894f0a1e9
2 changed files with 269 additions and 224 deletions
168
data/bindata.go
168
data/bindata.go
File diff suppressed because one or more lines are too long
|
|
@ -4,22 +4,69 @@
|
||||||
* @maintainer https://yaoapps.com
|
* @maintainer https://yaoapps.com
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message structure for agent responses
|
||||||
|
*/
|
||||||
|
interface AgentMessage {
|
||||||
|
text: string;
|
||||||
|
type?: string;
|
||||||
|
done?: boolean;
|
||||||
|
is_neo?: boolean;
|
||||||
|
assistant_id?: string;
|
||||||
|
assistant_name?: string;
|
||||||
|
assistant_avatar?: string;
|
||||||
|
props?: Record<string, any>;
|
||||||
|
tool_id?: string;
|
||||||
|
new?: boolean;
|
||||||
|
delta?: boolean;
|
||||||
|
previous_assistant_id?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Done event data structure
|
||||||
|
*/
|
||||||
|
type AgentDoneData = AgentMessage[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handler function types
|
||||||
|
*/
|
||||||
|
interface MessageHandler {
|
||||||
|
(message: AgentMessage): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DoneHandler {
|
||||||
|
(messages: AgentDoneData): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event types that can be listened to
|
||||||
|
*/
|
||||||
|
type AgentEvent = "message" | "done";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handlers record type
|
||||||
|
*/
|
||||||
|
interface EventHandlers {
|
||||||
|
message?: MessageHandler;
|
||||||
|
done?: DoneHandler;
|
||||||
|
}
|
||||||
|
|
||||||
class Agent {
|
class Agent {
|
||||||
private host: string;
|
private host: string;
|
||||||
private token: string;
|
private token: string;
|
||||||
private events: Record<AgentEvent, Handler>;
|
private events: EventHandlers;
|
||||||
private assistant_id?: string;
|
private assistant_id: string;
|
||||||
private chat_id?: string;
|
private chat_id?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Agent constructor
|
* Agent constructor
|
||||||
* @param option Agent initialization options
|
* @param option Agent initialization options
|
||||||
*/
|
*/
|
||||||
constructor(option: AgentOption) {
|
constructor(assistant_id: string, option: AgentOption) {
|
||||||
this.host = option.host || "/__yao/neo";
|
this.host = option.host || "/api/__yao/neo";
|
||||||
this.token = option.token;
|
this.token = option.token;
|
||||||
this.events = {} as Record<AgentEvent, Handler>;
|
this.events = {};
|
||||||
this.assistant_id = option.assistant_id;
|
this.assistant_id = assistant_id;
|
||||||
this.chat_id = option.chat_id;
|
this.chat_id = option.chat_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -39,18 +86,32 @@ class Agent {
|
||||||
* @param handler Function to handle the event
|
* @param handler Function to handle the event
|
||||||
* @returns The Agent instance for chaining
|
* @returns The Agent instance for chaining
|
||||||
*/
|
*/
|
||||||
On(event: AgentEvent, handler: Handler): Agent {
|
On<E extends AgentEvent>(
|
||||||
this.events[event] = handler;
|
event: E,
|
||||||
|
handler: E extends "message" ? MessageHandler : DoneHandler
|
||||||
|
): Agent {
|
||||||
|
if (event === "message") {
|
||||||
|
this.events.message = handler as MessageHandler;
|
||||||
|
} else if (event === "done") {
|
||||||
|
this.events.done = handler as DoneHandler;
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call the AI Agent
|
* Call the AI Agent
|
||||||
* @param id Agent ID
|
|
||||||
* @param input Text message or input object with text and optional attachments
|
* @param input Text message or input object with text and optional attachments
|
||||||
* @param args Additional arguments to pass to the agent
|
* @param args Additional arguments to pass to the agent
|
||||||
*/
|
*/
|
||||||
async Call(id: string, input: AgentInput, ...args: any[]) {
|
async Call(input: AgentInput, ...args: any[]) {
|
||||||
|
const messages: AgentMessage[] = [];
|
||||||
|
let currentContent = "";
|
||||||
|
let lastAssistant = {
|
||||||
|
assistant_id: null as string | null,
|
||||||
|
assistant_name: null as string | null,
|
||||||
|
assistant_avatar: null as string | null,
|
||||||
|
};
|
||||||
|
|
||||||
// Process input content
|
// Process input content
|
||||||
let content: AgentInputContent;
|
let content: AgentInputContent;
|
||||||
if (typeof input === "string") {
|
if (typeof input === "string") {
|
||||||
|
|
@ -76,11 +137,8 @@ class Agent {
|
||||||
const contentRaw = encodeURIComponent(JSON.stringify(content));
|
const contentRaw = encodeURIComponent(JSON.stringify(content));
|
||||||
const contextRaw = encodeURIComponent(JSON.stringify(args));
|
const contextRaw = encodeURIComponent(JSON.stringify(args));
|
||||||
const token = this.token;
|
const token = this.token;
|
||||||
const assistantParam = this.assistant_id
|
|
||||||
? `&assistant_id=${this.assistant_id}`
|
|
||||||
: "";
|
|
||||||
const chatId = this.chat_id || this.makeChatID();
|
const chatId = this.chat_id || this.makeChatID();
|
||||||
|
const assistantParam = `&assistant_id=${this.assistant_id}`;
|
||||||
const status_endpoint = `${this.host}/status?content=${contentRaw}&context=${contextRaw}&token=${token}&chat_id=${chatId}${assistantParam}`;
|
const status_endpoint = `${this.host}/status?content=${contentRaw}&context=${contextRaw}&token=${token}&chat_id=${chatId}${assistantParam}`;
|
||||||
const endpoint = `${this.host}?content=${contentRaw}&context=${contextRaw}&token=${token}&chat_id=${chatId}${assistantParam}`;
|
const endpoint = `${this.host}?content=${contentRaw}&context=${contextRaw}&token=${token}&chat_id=${chatId}${assistantParam}`;
|
||||||
|
|
||||||
|
|
@ -115,7 +173,7 @@ class Agent {
|
||||||
"Connection failed: Please check your network connection";
|
"Connection failed: Please check your network connection";
|
||||||
}
|
}
|
||||||
|
|
||||||
const messageHandler = this.events["message"];
|
const messageHandler = this.events["message"] as MessageHandler;
|
||||||
if (messageHandler) {
|
if (messageHandler) {
|
||||||
messageHandler({
|
messageHandler({
|
||||||
text: errorMessage,
|
text: errorMessage,
|
||||||
|
|
@ -125,7 +183,7 @@ class Agent {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (statusError) {
|
} catch (statusError) {
|
||||||
const messageHandler = this.events["message"];
|
const messageHandler = this.events["message"] as MessageHandler;
|
||||||
if (messageHandler) {
|
if (messageHandler) {
|
||||||
messageHandler({
|
messageHandler({
|
||||||
text: "Service unavailable, please try again later",
|
text: "Service unavailable, please try again later",
|
||||||
|
|
@ -142,22 +200,8 @@ class Agent {
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Track assistant information across messages
|
|
||||||
const last_assistant: {
|
|
||||||
assistant_id: string | null;
|
|
||||||
assistant_name: string | null;
|
|
||||||
assistant_avatar: string | null;
|
|
||||||
} = {
|
|
||||||
assistant_id: null,
|
|
||||||
assistant_name: null,
|
|
||||||
assistant_avatar: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
let content = "";
|
|
||||||
let last_type: string | null = null;
|
|
||||||
|
|
||||||
es.onopen = () => {
|
es.onopen = () => {
|
||||||
const messageHandler = this.events["message"];
|
const messageHandler = this.events["message"] as MessageHandler;
|
||||||
if (messageHandler) {
|
if (messageHandler) {
|
||||||
messageHandler({
|
messageHandler({
|
||||||
text: "",
|
text: "",
|
||||||
|
|
@ -172,7 +216,7 @@ class Agent {
|
||||||
const formated_data = JSON.parse(data);
|
const formated_data = JSON.parse(data);
|
||||||
if (!formated_data) return;
|
if (!formated_data) return;
|
||||||
|
|
||||||
const messageHandler = this.events["message"];
|
const messageHandler = this.events["message"] as MessageHandler;
|
||||||
if (!messageHandler) return;
|
if (!messageHandler) return;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
|
@ -195,7 +239,7 @@ class Agent {
|
||||||
const { namespace, primary, data_item, action, extra } =
|
const { namespace, primary, data_item, action, extra } =
|
||||||
props || {};
|
props || {};
|
||||||
if (action && Array.isArray(action)) {
|
if (action && Array.isArray(action)) {
|
||||||
messageHandler({
|
const actionMessage = {
|
||||||
text: text || "",
|
text: text || "",
|
||||||
type: "action",
|
type: "action",
|
||||||
props: {
|
props: {
|
||||||
|
|
@ -207,94 +251,130 @@ class Agent {
|
||||||
},
|
},
|
||||||
is_neo: true,
|
is_neo: true,
|
||||||
done: !!done,
|
done: !!done,
|
||||||
});
|
};
|
||||||
|
|
||||||
|
messages.push(actionMessage);
|
||||||
|
messageHandler(actionMessage);
|
||||||
|
|
||||||
if (done) {
|
if (done) {
|
||||||
const doneHandler = this.events["done"];
|
const doneHandler = this.events["done"] as DoneHandler;
|
||||||
if (doneHandler) {
|
doneHandler?.(messages);
|
||||||
doneHandler({
|
|
||||||
text: text || "",
|
|
||||||
type: "action",
|
|
||||||
done: true,
|
|
||||||
is_neo: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
es.close();
|
es.close();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update content based on message properties
|
// Check if we need to create a new message
|
||||||
if (text) {
|
const shouldCreateNewMessage =
|
||||||
if (delta) {
|
messages.length === 0 ||
|
||||||
content = content + text;
|
(assistant_id &&
|
||||||
if (text?.startsWith("\r") || is_new) {
|
messages[messages.length - 1].assistant_id !== assistant_id) ||
|
||||||
content = text.replace("\r", "");
|
(is_new && !delta); // Only create new message if it's new and not a delta update
|
||||||
}
|
|
||||||
} else {
|
|
||||||
content = text || "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update assistant information
|
// Update assistant information
|
||||||
if (assistant_id) {
|
if (assistant_id) lastAssistant.assistant_id = assistant_id;
|
||||||
last_assistant.assistant_id = assistant_id;
|
if (assistant_name) lastAssistant.assistant_name = assistant_name;
|
||||||
}
|
if (assistant_avatar)
|
||||||
if (assistant_name) {
|
lastAssistant.assistant_avatar = assistant_avatar;
|
||||||
last_assistant.assistant_name = assistant_name;
|
|
||||||
}
|
|
||||||
if (assistant_avatar) {
|
|
||||||
last_assistant.assistant_avatar = assistant_avatar;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare message data
|
if (shouldCreateNewMessage) {
|
||||||
const message_data: any = {
|
// Mark the last message as done if it exists
|
||||||
...formated_data,
|
if (messages.length > 0 && messages[messages.length - 1].is_neo) {
|
||||||
text: content,
|
messages[messages.length - 1] = {
|
||||||
assistant_id: last_assistant.assistant_id || undefined,
|
...messages[messages.length - 1],
|
||||||
assistant_name: last_assistant.assistant_name || undefined,
|
done: true,
|
||||||
assistant_avatar: last_assistant.assistant_avatar || undefined,
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
// Handle tool and think message types
|
// Create new message with all original properties
|
||||||
if ((type === "tool" || type === "think") && delta) {
|
const newMessage = {
|
||||||
message_data.type = "text";
|
text: text || "",
|
||||||
message_data.props = {
|
type: type || "text",
|
||||||
...(message_data.props || {}),
|
props,
|
||||||
id: tool_id,
|
is_neo: true,
|
||||||
begin,
|
new: is_new, // Only set new if it's from the original message
|
||||||
end,
|
tool_id,
|
||||||
|
assistant_id: lastAssistant.assistant_id || undefined,
|
||||||
|
assistant_name: lastAssistant.assistant_name || undefined,
|
||||||
|
assistant_avatar: lastAssistant.assistant_avatar || undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add closing tag if needed
|
messages.push(newMessage);
|
||||||
if (!content.includes(`</${type}>`)) {
|
messageHandler(newMessage);
|
||||||
message_data.text = `${content}</${type}>`;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get current message (we know it exists because we checked messages.length above)
|
||||||
|
const current_answer = messages[messages.length - 1];
|
||||||
|
|
||||||
|
// Set previous assistant id
|
||||||
|
if (messages.length > 1) {
|
||||||
|
const previous_message = messages[messages.length - 2];
|
||||||
|
if (previous_message.assistant_id) {
|
||||||
|
current_answer.previous_assistant_id =
|
||||||
|
previous_message.assistant_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send message to handler
|
// Handle message completion (done flag is set)
|
||||||
messageHandler(message_data);
|
|
||||||
|
|
||||||
// Handle done event
|
|
||||||
if (done) {
|
if (done) {
|
||||||
const doneHandler = this.events["done"];
|
if (text) {
|
||||||
if (doneHandler) {
|
current_answer.text = text;
|
||||||
doneHandler({
|
|
||||||
text: content,
|
|
||||||
done: true,
|
|
||||||
is_neo: true,
|
|
||||||
type: message_data.type,
|
|
||||||
props: message_data.props,
|
|
||||||
assistant_id: last_assistant.assistant_id || undefined,
|
|
||||||
assistant_name: last_assistant.assistant_name || undefined,
|
|
||||||
assistant_avatar: last_assistant.assistant_avatar || undefined,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
if (type) {
|
||||||
|
current_answer.type = type;
|
||||||
|
}
|
||||||
|
if (props) {
|
||||||
|
current_answer.props = props;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark all previous neo messages as done
|
||||||
|
for (let i = messages.length - 1; i >= 0; i--) {
|
||||||
|
const message = messages[i];
|
||||||
|
if (message.is_neo) {
|
||||||
|
if (message.done) break;
|
||||||
|
messages[i] = { ...message, done: true };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const doneHandler = this.events["done"] as DoneHandler;
|
||||||
|
doneHandler?.(messages);
|
||||||
es.close();
|
es.close();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
last_type = type || last_type;
|
// Skip processing if no content to update
|
||||||
|
if (!text && !props && !type) return;
|
||||||
|
|
||||||
|
// Update props if available
|
||||||
|
if (props) {
|
||||||
|
if (type === "think" || type === "tool") {
|
||||||
|
current_answer.props = {
|
||||||
|
...(current_answer.props || {}),
|
||||||
|
id: tool_id,
|
||||||
|
begin,
|
||||||
|
end,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
current_answer.props = props;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle text content
|
||||||
|
if (text) {
|
||||||
|
if (delta) {
|
||||||
|
current_answer.text = (current_answer.text || "") + text;
|
||||||
|
if (text.startsWith("\r")) {
|
||||||
|
current_answer.text = text.replace("\r", "");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
current_answer.text = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send current message to handler
|
||||||
|
messageHandler(current_answer);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Failed to parse message:", err);
|
console.error("Failed to parse message:", err);
|
||||||
}
|
}
|
||||||
|
|
@ -310,11 +390,6 @@ class Agent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Event types that can be listened to
|
|
||||||
*/
|
|
||||||
type AgentEvent = "message" | "done";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attachment information for file uploads
|
* Attachment information for file uploads
|
||||||
*/
|
*/
|
||||||
|
|
@ -342,7 +417,12 @@ interface AgentInputContent {
|
||||||
/**
|
/**
|
||||||
* Input type for agent calls, can be either a string or a structured input
|
* Input type for agent calls, can be either a string or a structured input
|
||||||
*/
|
*/
|
||||||
type AgentInput = string | AgentInputContent;
|
type AgentInput =
|
||||||
|
| string
|
||||||
|
| {
|
||||||
|
text: string;
|
||||||
|
attachments?: AgentAttachment[];
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Agent initialization options
|
* Agent initialization options
|
||||||
|
|
@ -350,40 +430,5 @@ type AgentInput = string | AgentInputContent;
|
||||||
interface AgentOption {
|
interface AgentOption {
|
||||||
host?: string;
|
host?: string;
|
||||||
token: string;
|
token: string;
|
||||||
assistant_id?: string;
|
|
||||||
chat_id?: string;
|
chat_id?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Message structure for agent responses
|
|
||||||
*/
|
|
||||||
interface AgentMessage {
|
|
||||||
text: string;
|
|
||||||
type?: string;
|
|
||||||
done?: boolean;
|
|
||||||
is_neo?: boolean;
|
|
||||||
assistant_id?: string;
|
|
||||||
assistant_name?: string;
|
|
||||||
assistant_avatar?: string;
|
|
||||||
props?: Record<string, any>;
|
|
||||||
tool_id?: string;
|
|
||||||
new?: boolean;
|
|
||||||
delta?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event handler function type
|
|
||||||
*/
|
|
||||||
interface Handler {
|
|
||||||
(message: AgentMessage): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Options for agent call configuration
|
|
||||||
*/
|
|
||||||
interface AgentCallOption {
|
|
||||||
model: string;
|
|
||||||
prompt: string;
|
|
||||||
temperature: number;
|
|
||||||
max_tokens: number;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue