Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion websocket-server/src/agentConfigs/supervisorAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import OpenAI, { ClientOptions } from 'openai';
import { HttpsProxyAgent } from 'https-proxy-agent';

import { getCurrentTimeFunction } from './supervisorTools';
import { loadRemoteMcpTools } from '../remoteMcpTools';

// Supervisor tool response handler
export async function getSupervisorToolResponse(functionName: string, args: any): Promise<string> {
Expand Down Expand Up @@ -174,7 +175,8 @@ export const getNextResponseFromSupervisorFunction: FunctionHandler = {
name: getCurrentTimeFunction.schema.name,
description: getCurrentTimeFunction.schema.description || "",
parameters: getCurrentTimeFunction.schema.parameters
}
},
...loadRemoteMcpTools()
];

// Initial user input as message input
Expand Down
30 changes: 30 additions & 0 deletions websocket-server/src/remoteMcpTools.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { readFileSync } from "fs";
import { join } from "path";

interface RemoteMcpConfig {
server_label: string;
server_url: string;
api_key?: string;
}

export function loadRemoteMcpTools() {
try {
const filePath = join(__dirname, "../../data/mcp-tools.json");
const raw = readFileSync(filePath, "utf-8");
const configs: RemoteMcpConfig[] = JSON.parse(raw);
return configs.map(cfg => {
const tool: any = {
type: "mcp",
server_label: cfg.server_label,
server_url: cfg.server_url
};
if (cfg.api_key) {
tool.headers = { Authorization: `Bearer ${cfg.api_key}` };
}
return tool;
});
} catch (err) {
console.warn("No remote MCP tools loaded", err instanceof Error ? err.message : err);
return [];
}
}
43 changes: 27 additions & 16 deletions websocket-server/src/sessionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { RawData, WebSocket } from "ws";
import OpenAI, { ClientOptions } from "openai";
import { HttpsProxyAgent } from "https-proxy-agent";
import { ResponsesTextInput } from "./types";
import { getAllFunctions, getDefaultAgent, FunctionHandler } from "./agentConfigs";
import { getAgent, getDefaultAgent, FunctionHandler } from "./agentConfigs";
import { isSmsWindowOpen, getNumbers } from './smsState';
import { sendSms } from './sms';

Expand Down Expand Up @@ -85,8 +85,10 @@ export function handleChatConnection(ws: WebSocket, openAIApiKey: string, chatCl

async function handleFunctionCall(item: { name: string; arguments: string }) {
console.log("Handling function call:", item);
const allFunctions = getAllFunctions();
const func = allFunctions.find((f: FunctionHandler) => f.schema.name === item.name);
const baseFunctions = getAgent('base').tools.filter((t: any): t is FunctionHandler =>
t && 'schema' in t && 'handler' in t
);
const func = baseFunctions.find((f: FunctionHandler) => f.schema.name === item.name);
if (!func) {
throw new Error(`No handler found for function: ${item.name}`);
}
Expand Down Expand Up @@ -225,9 +227,12 @@ export async function handleTextChatMessage(content: string, chatClients: Set<We
});
}

// Import function schemas for supervisor agent
const allFunctions = getAllFunctions();
const functionSchemas = allFunctions.map((f: FunctionHandler) => ({ ...f.schema, strict: true }));
// Import function schemas for base agent only
const baseFunctions = getAgent('base').tools.filter((t: any): t is FunctionHandler =>
t && 'schema' in t && 'handler' in t
);
const functionSchemas = baseFunctions.map((f: FunctionHandler) => ({ ...f.schema, strict: true }));
const tools = functionSchemas;

console.log("🤖 Calling OpenAI Responses API for text response...");

Expand All @@ -238,7 +243,7 @@ export async function handleTextChatMessage(content: string, chatClients: Set<We
const requestBody: any = {
model: "gpt-4o",
instructions: instructions,
tools: functionSchemas,
tools,
max_output_tokens: 500,
temperature: 0.7,
store: true,
Expand Down Expand Up @@ -297,9 +302,11 @@ export async function handleTextChatMessage(content: string, chatClients: Set<We
}

try {
// Find and execute the function
const allFunctions = getAllFunctions();
const functionHandler = allFunctions.find((f: FunctionHandler) => f.schema.name === functionCall.name);
// Find and execute the function from the base agent's toolset
const baseFunctions = getAgent('base').tools.filter((t: any): t is FunctionHandler =>
t && 'schema' in t && 'handler' in t
);
const functionHandler = baseFunctions.find((f: FunctionHandler) => f.schema.name === functionCall.name);
if (functionHandler) {
const args = JSON.parse(functionCall.arguments);
console.log(`🧠 Executing ${functionCall.name} with args:`, args);
Expand Down Expand Up @@ -336,7 +343,8 @@ export async function handleTextChatMessage(content: string, chatClients: Set<We
}

// Follow-up request to complete tool call and have base agent respond
const functionSchemas = allFunctions.map((f: FunctionHandler) => ({ ...f.schema, strict: true }));
const functionSchemas = baseFunctions.map((f: FunctionHandler) => ({ ...f.schema, strict: true }));
const tools = functionSchemas;
const followUpBody = {
model: "gpt-4o",
previous_response_id: response.id,
Expand All @@ -352,7 +360,7 @@ export async function handleTextChatMessage(content: string, chatClients: Set<We
: JSON.stringify(functionResult)
}
],
tools: functionSchemas,
tools,
max_output_tokens: 500
};

Expand Down Expand Up @@ -523,9 +531,12 @@ function tryConnectModel() {
session.modelConn.on("open", () => {
const config = session.saved_config || {};

// Include supervisor agent function for voice channel
const allFunctions = getAllFunctions();
const functionSchemas = allFunctions.map((f: FunctionHandler) => f.schema);
// Include only base agent functions for voice channel
const baseFunctions = getAgent('base').tools.filter((t: any): t is FunctionHandler =>
t && 'schema' in t && 'handler' in t
);
const functionSchemas = baseFunctions.map((f: FunctionHandler) => f.schema);
const tools = functionSchemas;
const agentInstructions = getDefaultAgent().instructions;
jsonSend(session.modelConn, {
type: "session.update",
Expand All @@ -536,7 +547,7 @@ function tryConnectModel() {
input_audio_transcription: { model: "whisper-1" },
input_audio_format: "g711_ulaw",
output_audio_format: "g711_ulaw",
tools: functionSchemas,
tools,
instructions: agentInstructions,
...config,
},
Expand Down