enhanced the AgentService.process method

- emit specialized error from failed context builds
- emit specialized error from failed workflow loops
This commit is contained in:
Rob Colbert 2026-05-05 13:19:54 -04:00
parent 09ebacc711
commit b94fe24287

View File

@ -4,7 +4,11 @@
import { Types } from "@gadget/api"; import { Types } from "@gadget/api";
import { Socket } from "socket.io-client"; import { Socket } from "socket.io-client";
import { IAiChatOptions, type IContextChatMessage } from "@gadget/ai"; import {
IAiChatOptions,
IAiStreamChunk,
type IContextChatMessage,
} from "@gadget/ai";
import { import {
IChatSession, IChatSession,
IChatTurn, IChatTurn,
@ -32,6 +36,11 @@ export interface IAgentWorkOrder {
context: IChatTurn[]; context: IChatTurn[];
} }
interface IAgentWorkflow {
chatOptions: IAiChatOptions;
context: IContextChatMessage[];
}
type DroneSocket = Socket<ServerToClientEvents, ClientToServerEvents>; type DroneSocket = Socket<ServerToClientEvents, ClientToServerEvents>;
class AgentService extends GadgetService { class AgentService extends GadgetService {
@ -55,67 +64,100 @@ class AgentService extends GadgetService {
socket: DroneSocket, socket: DroneSocket,
): Promise<void> { ): Promise<void> {
const { turn } = workOrder; const { turn } = workOrder;
const task: IAgentWorkflow = {
chatOptions: {},
context: [],
};
async function aiCallTool(name: string, args: string) { async function aiCallTool(name: string, args: string) {
return "[all tool calls are stubbed out]"; return "[all tool calls are stubbed out]";
} }
const context = this.buildSessionContext(workOrder); const onStreamChunk = async (chunk: IAiStreamChunk): Promise<void> => {
const chatOptions: IAiChatOptions = { this.log.debug("stream chunk received", { chunk });
systemPrompt: turn.prompts.system,
context,
userPrompt: turn.prompts.user,
}; };
let keepProcessing = true; try {
do { task.context = this.buildSessionContext(workOrder);
const response = await AiService.chat( task.chatOptions = {
turn.provider, systemPrompt: turn.prompts.system,
{ context: task.context,
modelId: turn.llm, userPrompt: turn.prompts.user,
params: { };
reasoning: false, } catch (cause) {
temperature: 0.8, socket.emit(
topP: 0.9, "workOrderComplete",
topK: 40, turn._id,
}, false,
}, `failed to build session context: ${(cause as Error).message}`,
chatOptions,
); );
const error = new Error("failed to build session context", { cause });
throw error;
}
// Emit thinking content if present try {
if (response.thinking) { let keepProcessing = true;
socket.emit("thinking", response.thinking); do {
} const response = await AiService.chat(
turn.provider,
// Emit response content if present {
if (response.response) { modelId: turn.llm,
socket.emit("response", response.response); params: {
} reasoning: false,
temperature: 0.8,
keepProcessing = (response.toolCalls?.length ?? 0) > 0; topP: 0.9,
for (const toolCall of response.toolCalls ?? []) { topK: 40,
const result = await aiCallTool( },
toolCall.function.name, },
toolCall.function.arguments, task.chatOptions,
onStreamChunk,
); );
context.push({
createdAt: new Date(),
role: "tool",
callId: toolCall.callId,
content: result,
});
// Emit tool call event // Emit thinking content if present
socket.emit( if (response.thinking) {
"toolCall", socket.emit("thinking", response.thinking);
toolCall.callId, }
toolCall.function.name,
toolCall.function.arguments, // Emit response content if present
result, if (response.response) {
); socket.emit("response", response.response);
} }
} while (keepProcessing);
keepProcessing = (response.toolCalls?.length ?? 0) > 0;
for (const toolCall of response.toolCalls ?? []) {
const result = await aiCallTool(
toolCall.function.name,
toolCall.function.arguments,
);
task.context.push({
createdAt: new Date(),
role: "tool",
callId: toolCall.callId,
content: result,
});
// Emit tool call event
socket.emit(
"toolCall",
toolCall.callId,
toolCall.function.name,
toolCall.function.arguments,
result,
);
}
} while (keepProcessing);
} catch (cause) {
socket.emit(
"workOrderComplete",
turn._id,
false,
`failed to process agentic workflow loop: ${(cause as Error).message}`,
);
const error = new Error("failed to process agentic workflow loop", {
cause,
});
throw error;
}
// Emit work order complete // Emit work order complete
socket.emit("workOrderComplete", turn._id, true); socket.emit("workOrderComplete", turn._id, true);