enhanced the AgentService.process method
- emit specialized error from failed context builds - emit specialized error from failed workflow loops
This commit is contained in:
parent
09ebacc711
commit
b94fe24287
@ -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);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user