This commit is contained in:
Rob Colbert 2026-05-07 00:59:15 -04:00
parent 3e31d4d501
commit 86c7c4d457
4 changed files with 43 additions and 65 deletions

4
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,4 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": false
}

View File

@ -16,7 +16,6 @@ import {
import { import {
IChatSession, IChatSession,
IChatTurn, IChatTurn,
IProject,
IUser, IUser,
ServerToClientEvents, ServerToClientEvents,
ClientToServerEvents, ClientToServerEvents,
@ -26,15 +25,7 @@ import {
import AiService from "./ai.ts"; import AiService from "./ai.ts";
import { GadgetService } from "../lib/service.ts"; import { GadgetService } from "../lib/service.ts";
import { AiToolbox } from "../../../packages/ai/dist/toolbox.js"; import { AiToolbox } from "@gadget/ai";
export interface IToolCall {
name: string;
params: string;
call_id?: string;
response?: string;
error?: Error;
}
export interface IAgentWorkOrder { export interface IAgentWorkOrder {
createdAt: Date; createdAt: Date;
@ -50,8 +41,6 @@ interface IAgentWorkflow {
type DroneSocket = Socket<ServerToClientEvents, ClientToServerEvents>; type DroneSocket = Socket<ServerToClientEvents, ClientToServerEvents>;
class AgentService extends GadgetService { class AgentService extends GadgetService {
private toolbox: AiToolbox | undefined;
get name(): string { get name(): string {
return "AgentService"; return "AgentService";
} }
@ -60,7 +49,6 @@ class AgentService extends GadgetService {
} }
async start(): Promise<void> { async start(): Promise<void> {
this.createAgentToolbox();
this.log.info("started"); this.log.info("started");
} }
@ -72,18 +60,12 @@ class AgentService extends GadgetService {
workOrder: IAgentWorkOrder, workOrder: IAgentWorkOrder,
socket: DroneSocket, socket: DroneSocket,
): Promise<void> { ): Promise<void> {
assert(this.toolbox, "service uninitialized");
const { turn } = workOrder; const { turn } = workOrder;
const task: IAgentWorkflow = { const task: IAgentWorkflow = {
chatOptions: {}, chatOptions: {},
context: [], context: [],
}; };
async function aiCallTool(name: string, args: string) {
return "[all tool calls are stubbed out]";
}
const onStreamChunk = async (chunk: IAiStreamChunk): Promise<void> => { const onStreamChunk = async (chunk: IAiStreamChunk): Promise<void> => {
this.log.debug("stream chunk received", { chunk }); this.log.debug("stream chunk received", { chunk });
}; };
@ -94,7 +76,7 @@ class AgentService extends GadgetService {
systemPrompt: turn.prompts.system, systemPrompt: turn.prompts.system,
context: task.context, context: task.context,
userPrompt: turn.prompts.user, userPrompt: turn.prompts.user,
tools: Array.from(this.toolbox.getModeSet(turn.mode) || []), tools: this.getToolsForMode(turn.mode),
}; };
} catch (cause) { } catch (cause) {
socket.emit( socket.emit(
@ -108,8 +90,6 @@ class AgentService extends GadgetService {
} }
try { try {
let keepProcessing = true;
do {
const response = await AiService.chat( const response = await AiService.chat(
turn.provider, turn.provider,
{ {
@ -135,29 +115,18 @@ class AgentService extends GadgetService {
socket.emit("response", response.response); socket.emit("response", response.response);
} }
keepProcessing = (response.toolCalls?.length ?? 0) > 0; // Emit tool calls if present
for (const toolCall of response.toolCalls ?? []) { if (response.toolCalls && response.toolCalls.length > 0) {
const result = await aiCallTool( for (const toolCall of response.toolCalls) {
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( socket.emit(
"toolCall", "toolCall",
toolCall.callId, toolCall.callId,
toolCall.function.name, toolCall.function.name,
toolCall.function.arguments, toolCall.function.arguments,
result, response.toolCallResults?.find(r => r.callId === toolCall.callId)?.result || "",
); );
} }
} while (keepProcessing); }
} catch (cause) { } catch (cause) {
socket.emit( socket.emit(
"workOrderComplete", "workOrderComplete",
@ -248,7 +217,7 @@ class AgentService extends GadgetService {
// TODO // TODO
} }
createAgentToolbox(): void { private getToolsForMode(mode: ChatSessionMode): any[] {
const aiEnv: IAiEnvironment = { const aiEnv: IAiEnvironment = {
NODE_ENV: env.NODE_ENV || "develop", NODE_ENV: env.NODE_ENV || "develop",
services: { services: {
@ -260,16 +229,16 @@ class AgentService extends GadgetService {
}, },
}, },
}; };
this.toolbox = new AiToolbox(aiEnv); const toolbox = new AiToolbox(aiEnv);
const googleSearchTool = new GoogleSearchTool(toolbox);
let tool = new GoogleSearchTool(this.toolbox); toolbox.register(googleSearchTool, [
this.toolbox.register(tool, [
ChatSessionMode.Plan, ChatSessionMode.Plan,
ChatSessionMode.Build, ChatSessionMode.Build,
ChatSessionMode.Test, ChatSessionMode.Test,
ChatSessionMode.Ship, ChatSessionMode.Ship,
ChatSessionMode.Develop, ChatSessionMode.Develop,
]); ]);
return Array.from(toolbox.getModeSet(mode) || []);
} }
} }

View File

@ -1 +1,5 @@
dist dist
*.js
*.js.map
*.d.ts
*.d.ts.map

View File

@ -24,6 +24,7 @@ export {
} from "./api.js"; } from "./api.js";
export * from "./tools/search/google.ts"; export * from "./tools/search/google.ts";
export { AiToolbox } from "./toolbox.js";
export { OllamaAiApi } from "./ollama.js"; export { OllamaAiApi } from "./ollama.js";
export { OpenAiApi } from "./openai.js"; export { OpenAiApi } from "./openai.js";