mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
fix: complete MCP split implementation
- Fix socket path conflict: main server defaults to TCP (localhost:6767), Self-ID MCP uses Unix socket (self-id-mcp.sock) - Remove set_title/set_branch from mcp-server.ts (they belong only in agent-self-id-mcp.ts which is used by coding agents) - Rename mcpSocketPath to selfIdMcpSocketPath for consistency - Pass --socket arg to self-id-bridge so non-default paths work - Wire up PID lock to prevent multiple daemon instances - Add PASEO_SELF_ID_MCP_SOCK env var for testing override
This commit is contained in:
@@ -59,6 +59,8 @@ export type AgentManagerOptions = {
|
||||
registry?: AgentStorage;
|
||||
onAgentAttention?: AgentAttentionCallback;
|
||||
logger: Logger;
|
||||
/** Path to the Self-ID MCP Unix socket for UI agent injection */
|
||||
selfIdMcpSocketPath?: string;
|
||||
};
|
||||
|
||||
export type WaitForAgentOptions = {
|
||||
@@ -106,7 +108,7 @@ type ManagedAgentBase = {
|
||||
/**
|
||||
* User-defined labels for categorizing agents (e.g., { ui: "true" }).
|
||||
*/
|
||||
labels?: Record<string, string>;
|
||||
labels: Record<string, string>;
|
||||
};
|
||||
|
||||
type ManagedAgentWithSession = ManagedAgentBase & {
|
||||
@@ -190,6 +192,7 @@ export class AgentManager {
|
||||
private readonly idFactory: () => string;
|
||||
private readonly registry?: AgentStorage;
|
||||
private readonly previousStatuses = new Map<string, AgentLifecycleStatus>();
|
||||
private readonly selfIdMcpSocketPath?: string;
|
||||
private onAgentAttention?: AgentAttentionCallback;
|
||||
private logger: Logger;
|
||||
|
||||
@@ -198,6 +201,7 @@ export class AgentManager {
|
||||
options?.maxTimelineItems ?? DEFAULT_MAX_TIMELINE_ITEMS;
|
||||
this.idFactory = options?.idFactory ?? (() => randomUUID());
|
||||
this.registry = options?.registry;
|
||||
this.selfIdMcpSocketPath = options?.selfIdMcpSocketPath;
|
||||
this.onAgentAttention = options?.onAgentAttention;
|
||||
this.logger = options.logger.child({ module: "agent", component: "agent-manager" });
|
||||
if (options?.clients) {
|
||||
@@ -313,13 +317,18 @@ export class AgentManager {
|
||||
agentId?: string,
|
||||
options?: { labels?: Record<string, string> }
|
||||
): Promise<ManagedAgent> {
|
||||
const normalizedConfig = await this.normalizeConfig(config, { labels: options?.labels });
|
||||
// Generate agent ID early so we can use it in MCP config
|
||||
const resolvedAgentId = agentId ?? this.idFactory();
|
||||
const normalizedConfig = await this.normalizeConfig(config, {
|
||||
labels: options?.labels,
|
||||
agentId: resolvedAgentId,
|
||||
});
|
||||
const client = this.requireClient(normalizedConfig.provider);
|
||||
const session = await client.createSession(normalizedConfig);
|
||||
return this.registerSession(
|
||||
session,
|
||||
normalizedConfig,
|
||||
agentId ?? this.idFactory(),
|
||||
resolvedAgentId,
|
||||
{ labels: options?.labels }
|
||||
);
|
||||
}
|
||||
@@ -835,7 +844,7 @@ export class AgentManager {
|
||||
lastUserMessageAt: options?.lastUserMessageAt ?? null,
|
||||
attention: { requiresAttention: false },
|
||||
internal: config.internal ?? false,
|
||||
labels: options?.labels,
|
||||
labels: options?.labels ?? {},
|
||||
} as ActiveManagedAgent;
|
||||
|
||||
this.agents.set(agentId, managed);
|
||||
@@ -1103,7 +1112,7 @@ export class AgentManager {
|
||||
|
||||
private async normalizeConfig(
|
||||
config: AgentSessionConfig,
|
||||
options?: { labels?: Record<string, string> }
|
||||
options?: { labels?: Record<string, string>; agentId?: string }
|
||||
): Promise<AgentSessionConfig> {
|
||||
const normalized: AgentSessionConfig = { ...config };
|
||||
|
||||
@@ -1117,12 +1126,29 @@ export class AgentManager {
|
||||
normalized.model = trimmed.length > 0 ? trimmed : undefined;
|
||||
}
|
||||
|
||||
// Inject paseoPromptInstructions for UI agents (with ui=true label)
|
||||
// Inject paseoPromptInstructions and MCP config for UI agents (with ui=true label)
|
||||
const isUiAgent = options?.labels?.ui === "true";
|
||||
if (isUiAgent) {
|
||||
normalized.paseoPromptInstructions = getSelfIdentificationInstructions({
|
||||
cwd: normalized.cwd,
|
||||
});
|
||||
|
||||
// Inject Self-ID MCP server config (stdio bridge to self-id-mcp.sock)
|
||||
if (this.selfIdMcpSocketPath && options?.agentId) {
|
||||
const existingMcpServers = normalized.mcpServers ?? {};
|
||||
normalized.mcpServers = {
|
||||
...existingMcpServers,
|
||||
"paseo-self-id": {
|
||||
type: "stdio",
|
||||
command: "paseo",
|
||||
args: [
|
||||
"self-id-bridge",
|
||||
"--socket", this.selfIdMcpSocketPath,
|
||||
"--agent-id", options.agentId,
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return normalized;
|
||||
|
||||
@@ -25,13 +25,8 @@ import { toAgentPayload } from "./agent-projections.js";
|
||||
import { curateAgentActivity } from "./activity-curator.js";
|
||||
import { AGENT_PROVIDER_DEFINITIONS } from "./provider-registry.js";
|
||||
import { AgentStorage } from "./agent-storage.js";
|
||||
import {
|
||||
createWorktree,
|
||||
isPaseoOwnedWorktreeCwd,
|
||||
validateBranchSlug,
|
||||
} from "../../utils/worktree.js";
|
||||
import { createWorktree } from "../../utils/worktree.js";
|
||||
import { WaitForAgentTracker } from "./wait-for-agent-tracker.js";
|
||||
import { NotGitRepoError, renameCurrentBranch } from "../../utils/checkout-git.js";
|
||||
import { injectLeadingPaseoInstructionTag } from "./paseo-instructions-tag.js";
|
||||
|
||||
export interface AgentMcpServerOptions {
|
||||
@@ -112,18 +107,6 @@ function expandPath(path: string): string {
|
||||
return resolve(path);
|
||||
}
|
||||
|
||||
type ToolErrorCode = "NOT_ALLOWED" | "NOT_GIT_REPO" | "INVALID_BRANCH";
|
||||
|
||||
class AgentMcpToolError extends Error {
|
||||
readonly code: ToolErrorCode;
|
||||
|
||||
constructor(code: ToolErrorCode, message: string) {
|
||||
super(message);
|
||||
this.name = "AgentMcpToolError";
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps agentManager.waitForAgentEvent with a self-imposed timeout.
|
||||
* Returns a friendly message when timeout occurs, rather than letting
|
||||
@@ -903,134 +886,6 @@ export async function createAgentMcpServer(
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
"set_title",
|
||||
{
|
||||
title: "Set Agent Title",
|
||||
description: "Update the agent's title in the registry.",
|
||||
inputSchema: {
|
||||
title: z
|
||||
.string()
|
||||
.min(1)
|
||||
.max(60)
|
||||
.describe("Short descriptive title (<= 60 chars)."),
|
||||
},
|
||||
outputSchema: {
|
||||
success: z.boolean(),
|
||||
title: z.string(),
|
||||
},
|
||||
},
|
||||
async ({ title }) => {
|
||||
if (!callerAgentId) {
|
||||
throw new AgentMcpToolError(
|
||||
"NOT_ALLOWED",
|
||||
"set_title can only be called by a managed agent"
|
||||
);
|
||||
}
|
||||
|
||||
const agent = agentManager.getAgent(callerAgentId);
|
||||
if (!agent) {
|
||||
throw new Error(`Agent ${callerAgentId} not found`);
|
||||
}
|
||||
|
||||
const normalizedTitle = title.trim();
|
||||
if (!normalizedTitle) {
|
||||
throw new AgentMcpToolError("NOT_ALLOWED", "Title cannot be empty");
|
||||
}
|
||||
if (normalizedTitle.length > 60) {
|
||||
throw new AgentMcpToolError(
|
||||
"NOT_ALLOWED",
|
||||
"Title must be 60 characters or fewer"
|
||||
);
|
||||
}
|
||||
|
||||
await agentManager.setTitle(agent.id, normalizedTitle);
|
||||
return {
|
||||
content: [],
|
||||
structuredContent: ensureValidJson({
|
||||
success: true,
|
||||
title: normalizedTitle,
|
||||
}),
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
"set_branch",
|
||||
{
|
||||
title: "Set Agent Branch",
|
||||
description:
|
||||
"Rename the current git branch. Allowed only inside Paseo-owned worktrees.",
|
||||
inputSchema: {
|
||||
name: z
|
||||
.string()
|
||||
.min(1)
|
||||
.describe("Git branch name (lowercase letters, numbers, hyphens, slashes)."),
|
||||
},
|
||||
outputSchema: {
|
||||
success: z.boolean(),
|
||||
branch: z.string(),
|
||||
},
|
||||
},
|
||||
async ({ name }) => {
|
||||
if (!callerAgentId) {
|
||||
throw new AgentMcpToolError(
|
||||
"NOT_ALLOWED",
|
||||
"set_branch can only be called by a managed agent"
|
||||
);
|
||||
}
|
||||
|
||||
const agent = agentManager.getAgent(callerAgentId);
|
||||
if (!agent) {
|
||||
throw new Error(`Agent ${callerAgentId} not found`);
|
||||
}
|
||||
|
||||
const validation = validateBranchSlug(name);
|
||||
if (!validation.valid) {
|
||||
throw new AgentMcpToolError(
|
||||
"INVALID_BRANCH",
|
||||
validation.error ?? "Invalid branch name"
|
||||
);
|
||||
}
|
||||
|
||||
let ownership;
|
||||
try {
|
||||
ownership = await isPaseoOwnedWorktreeCwd(agent.cwd, { paseoHome: options.paseoHome });
|
||||
} catch (error) {
|
||||
const notGitError =
|
||||
error instanceof NotGitRepoError
|
||||
? error
|
||||
: new NotGitRepoError(agent.cwd);
|
||||
throw new AgentMcpToolError(
|
||||
"NOT_GIT_REPO",
|
||||
notGitError.message
|
||||
);
|
||||
}
|
||||
|
||||
if (!ownership.allowed) {
|
||||
throw new AgentMcpToolError(
|
||||
"NOT_ALLOWED",
|
||||
"Branch renames are only allowed inside Paseo-owned worktrees"
|
||||
);
|
||||
}
|
||||
|
||||
const result = await renameCurrentBranch(agent.cwd, name);
|
||||
if (result.currentBranch !== name) {
|
||||
throw new Error(
|
||||
`Branch rename failed (expected ${name}, got ${result.currentBranch ?? "unknown"})`
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
content: [],
|
||||
structuredContent: ensureValidJson({
|
||||
success: true,
|
||||
branch: name,
|
||||
}),
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
"set_agent_mode",
|
||||
{
|
||||
|
||||
@@ -45,6 +45,7 @@ import { AgentManager } from "./agent/agent-manager.js";
|
||||
import { AgentStorage } from "./agent/agent-storage.js";
|
||||
import { attachAgentStoragePersistence } from "./persistence-hooks.js";
|
||||
import { createAgentMcpServer } from "./agent/mcp-server.js";
|
||||
import { createAgentSelfIdMcpServer } from "./agent/agent-self-id-mcp.js";
|
||||
import { createAllClients, shutdownProviders } from "./agent/provider-registry.js";
|
||||
import { createTerminalManager, type TerminalManager } from "../terminal/terminal-manager.js";
|
||||
import {
|
||||
@@ -54,6 +55,7 @@ import {
|
||||
} from "./connection-offer.js";
|
||||
import { printPairingQrIfEnabled } from "./pairing-qr.js";
|
||||
import { startRelayTransport, type RelayTransportController } from "./relay-transport.js";
|
||||
import { acquirePidLock, releasePidLock } from "./pid-lock.js";
|
||||
import type {
|
||||
AgentClient,
|
||||
AgentProvider,
|
||||
@@ -70,6 +72,7 @@ export type PaseoOpenAIConfig = {
|
||||
export type PaseoDaemonConfig = {
|
||||
listen: string;
|
||||
paseoHome: string;
|
||||
selfIdMcpSocketPath: string;
|
||||
corsAllowedOrigins: string[];
|
||||
agentMcpRoute: string;
|
||||
agentMcpAllowedHosts: string[];
|
||||
@@ -209,6 +212,7 @@ export async function createPaseoDaemon(
|
||||
...config.agentClients,
|
||||
},
|
||||
registry: agentStorage,
|
||||
selfIdMcpSocketPath: config.selfIdMcpSocketPath,
|
||||
logger,
|
||||
});
|
||||
|
||||
@@ -221,6 +225,7 @@ export async function createPaseoDaemon(
|
||||
);
|
||||
|
||||
const agentMcpTransports: AgentMcpTransportMap = new Map();
|
||||
const selfIdMcpTransports: AgentMcpTransportMap = new Map();
|
||||
const allowedHosts = config.agentMcpAllowedHosts;
|
||||
|
||||
const createAgentMcpTransport = async (callerAgentId?: string) => {
|
||||
@@ -328,7 +333,118 @@ export async function createPaseoDaemon(
|
||||
app.post(agentMcpRoute, handleAgentMcpRequest);
|
||||
app.get(agentMcpRoute, handleAgentMcpRequest);
|
||||
app.delete(agentMcpRoute, handleAgentMcpRequest);
|
||||
logger.info({ route: agentMcpRoute }, "Agent MCP server mounted");
|
||||
logger.info({ route: agentMcpRoute }, "Agent MCP server mounted on main app");
|
||||
|
||||
// Create dedicated Self-ID MCP server on Unix socket for agent self-identification
|
||||
// This only provides set_title and set_branch tools for coding agents
|
||||
// Host validation is disabled since Unix sockets don't have HTTP hosts
|
||||
const selfIdMcpSocketPath = config.selfIdMcpSocketPath;
|
||||
|
||||
const createSelfIdMcpTransport = async (callerAgentId: string) => {
|
||||
const selfIdMcpServer = await createAgentSelfIdMcpServer({
|
||||
agentManager,
|
||||
paseoHome: config.paseoHome,
|
||||
callerAgentId,
|
||||
logger,
|
||||
});
|
||||
|
||||
const transport = new StreamableHTTPServerTransport({
|
||||
sessionIdGenerator: () => randomUUID(),
|
||||
onsessioninitialized: (sessionId) => {
|
||||
selfIdMcpTransports.set(sessionId, transport);
|
||||
logger.debug({ sessionId, callerAgentId }, "Self-ID MCP session initialized");
|
||||
},
|
||||
onsessionclosed: (sessionId) => {
|
||||
selfIdMcpTransports.delete(sessionId);
|
||||
logger.debug({ sessionId }, "Self-ID MCP session closed");
|
||||
},
|
||||
// Disable host validation for Unix socket
|
||||
enableDnsRebindingProtection: false,
|
||||
});
|
||||
transport.onclose = () => {
|
||||
if (transport.sessionId) {
|
||||
selfIdMcpTransports.delete(transport.sessionId);
|
||||
}
|
||||
};
|
||||
transport.onerror = (err) => {
|
||||
logger.error({ err }, "Self-ID MCP transport error");
|
||||
};
|
||||
|
||||
await selfIdMcpServer.connect(transport);
|
||||
|
||||
return transport;
|
||||
};
|
||||
|
||||
const handleSelfIdMcpRequest: express.RequestHandler = async (req, res) => {
|
||||
if (config.mcpDebug) {
|
||||
logger.debug(
|
||||
{
|
||||
method: req.method,
|
||||
url: req.originalUrl,
|
||||
sessionId: req.header("mcp-session-id"),
|
||||
body: req.body,
|
||||
},
|
||||
"Self-ID MCP request"
|
||||
);
|
||||
}
|
||||
try {
|
||||
const sessionId = req.header("mcp-session-id");
|
||||
let transport = sessionId ? selfIdMcpTransports.get(sessionId) : undefined;
|
||||
|
||||
if (!transport) {
|
||||
if (req.method !== "POST") {
|
||||
res.status(400).json({
|
||||
jsonrpc: "2.0",
|
||||
error: { code: -32000, message: "Missing or invalid MCP session" },
|
||||
id: null,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!isInitializeRequest(req.body)) {
|
||||
res.status(400).json({
|
||||
jsonrpc: "2.0",
|
||||
error: { code: -32000, message: "Initialization request expected" },
|
||||
id: null,
|
||||
});
|
||||
return;
|
||||
}
|
||||
const callerAgentIdRaw = req.query.callerAgentId;
|
||||
const callerAgentId =
|
||||
typeof callerAgentIdRaw === "string"
|
||||
? callerAgentIdRaw
|
||||
: Array.isArray(callerAgentIdRaw) && typeof callerAgentIdRaw[0] === "string"
|
||||
? callerAgentIdRaw[0]
|
||||
: undefined;
|
||||
if (!callerAgentId) {
|
||||
res.status(400).json({
|
||||
jsonrpc: "2.0",
|
||||
error: { code: -32000, message: "callerAgentId query parameter is required for Self-ID MCP" },
|
||||
id: null,
|
||||
});
|
||||
return;
|
||||
}
|
||||
transport = await createSelfIdMcpTransport(callerAgentId);
|
||||
}
|
||||
|
||||
await transport.handleRequest(req as any, res as any, req.body);
|
||||
} catch (err) {
|
||||
logger.error({ err }, "Failed to handle Self-ID MCP request");
|
||||
if (!res.headersSent) {
|
||||
res.status(500).json({
|
||||
jsonrpc: "2.0",
|
||||
error: { code: -32603, message: "Internal MCP server error" },
|
||||
id: null,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const selfIdMcpApp = express();
|
||||
selfIdMcpApp.use(express.json());
|
||||
selfIdMcpApp.post("/", handleSelfIdMcpRequest);
|
||||
selfIdMcpApp.get("/", handleSelfIdMcpRequest);
|
||||
selfIdMcpApp.delete("/", handleSelfIdMcpRequest);
|
||||
const selfIdMcpSocketServer = createHTTPServer(selfIdMcpApp);
|
||||
|
||||
let sttService: OpenAISTT | null = null;
|
||||
let ttsService: OpenAITTS | null = null;
|
||||
@@ -376,12 +492,38 @@ export async function createPaseoDaemon(
|
||||
downloadTokenStore,
|
||||
config.paseoHome,
|
||||
agentMcpRoute,
|
||||
config.selfIdMcpSocketPath,
|
||||
{ allowedOrigins },
|
||||
{ stt: sttService, tts: ttsService },
|
||||
terminalManager
|
||||
);
|
||||
|
||||
const start = async () => {
|
||||
// Acquire PID lock to prevent multiple daemon instances
|
||||
await acquirePidLock(config.paseoHome, selfIdMcpSocketPath);
|
||||
|
||||
// Start Self-ID MCP socket server first
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const onError = (err: Error) => {
|
||||
selfIdMcpSocketServer.off("listening", onListening);
|
||||
reject(err);
|
||||
};
|
||||
const onListening = () => {
|
||||
selfIdMcpSocketServer.off("error", onError);
|
||||
logger.info({ path: selfIdMcpSocketPath }, `Self-ID MCP server listening on ${selfIdMcpSocketPath}`);
|
||||
resolve();
|
||||
};
|
||||
selfIdMcpSocketServer.once("error", onError);
|
||||
selfIdMcpSocketServer.once("listening", onListening);
|
||||
|
||||
// Remove stale socket file if it exists
|
||||
if (existsSync(selfIdMcpSocketPath)) {
|
||||
unlinkSync(selfIdMcpSocketPath);
|
||||
}
|
||||
selfIdMcpSocketServer.listen(selfIdMcpSocketPath);
|
||||
});
|
||||
|
||||
// Start main HTTP server
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const onError = (err: Error) => {
|
||||
httpServer.off("listening", onListening);
|
||||
@@ -456,10 +598,18 @@ export async function createPaseoDaemon(
|
||||
await new Promise<void>((resolve) => {
|
||||
httpServer.close(() => resolve());
|
||||
});
|
||||
// Clean up socket file
|
||||
await new Promise<void>((resolve) => {
|
||||
selfIdMcpSocketServer.close(() => resolve());
|
||||
});
|
||||
// Clean up socket files
|
||||
if (listenTarget.type === "socket" && existsSync(listenTarget.path)) {
|
||||
unlinkSync(listenTarget.path);
|
||||
}
|
||||
if (existsSync(selfIdMcpSocketPath)) {
|
||||
unlinkSync(selfIdMcpSocketPath);
|
||||
}
|
||||
// Release PID lock
|
||||
await releasePidLock(config.paseoHome);
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@@ -5,11 +5,25 @@ import type { STTConfig } from "./agent/stt-openai.js";
|
||||
import type { TTSConfig } from "./agent/tts-openai.js";
|
||||
import { loadPersistedConfig } from "./persisted-config.js";
|
||||
|
||||
const DEFAULT_LISTEN = "127.0.0.1:6767";
|
||||
const DEFAULT_PORT = 6767;
|
||||
const DEFAULT_AGENT_MCP_ROUTE = "/mcp/agents";
|
||||
const DEFAULT_RELAY_ENDPOINT = "relay.paseo.sh:443";
|
||||
const DEFAULT_APP_BASE_URL = "https://app.paseo.sh";
|
||||
|
||||
function getDefaultListen(): string {
|
||||
// Main HTTP server defaults to TCP
|
||||
return `127.0.0.1:${DEFAULT_PORT}`;
|
||||
}
|
||||
|
||||
function getSelfIdMcpSocketPath(paseoHome: string, env: NodeJS.ProcessEnv): string {
|
||||
// Allow override via PASEO_SELF_ID_MCP_SOCK for testing
|
||||
if (env.PASEO_SELF_ID_MCP_SOCK) {
|
||||
return env.PASEO_SELF_ID_MCP_SOCK;
|
||||
}
|
||||
// Default to ${PASEO_HOME}/self-id-mcp.sock
|
||||
return path.join(paseoHome, "self-id-mcp.sock");
|
||||
}
|
||||
|
||||
function parseOpenAIConfig(env: NodeJS.ProcessEnv) {
|
||||
const apiKey = env.OPENAI_API_KEY;
|
||||
if (!apiKey) return undefined;
|
||||
@@ -66,8 +80,14 @@ export function loadConfig(
|
||||
): PaseoDaemonConfig {
|
||||
const persisted = loadPersistedConfig(paseoHome);
|
||||
|
||||
const listen = env.PASEO_LISTEN ?? persisted.listen ?? DEFAULT_LISTEN;
|
||||
// PASEO_LISTEN can be:
|
||||
// - host:port (TCP)
|
||||
// - /path/to/socket (Unix socket)
|
||||
// - unix:///path/to/socket (Unix socket)
|
||||
// Default is TCP at 127.0.0.1:6767
|
||||
const listen = env.PASEO_LISTEN ?? persisted.listen ?? getDefaultListen();
|
||||
const mcpListen = getListenForMcp(listen);
|
||||
const selfIdMcpSocketPath = getSelfIdMcpSocketPath(paseoHome, env);
|
||||
|
||||
const envCorsOrigins = env.PASEO_CORS_ORIGINS
|
||||
? env.PASEO_CORS_ORIGINS.split(",").map((s) => s.trim())
|
||||
@@ -76,6 +96,7 @@ export function loadConfig(
|
||||
return {
|
||||
listen,
|
||||
paseoHome,
|
||||
selfIdMcpSocketPath,
|
||||
corsAllowedOrigins: [...persisted.cors.allowedOrigins, ...envCorsOrigins],
|
||||
agentMcpRoute: DEFAULT_AGENT_MCP_ROUTE,
|
||||
agentMcpAllowedHosts: [mcpListen, `localhost:${mcpListen.split(":")[1]}`],
|
||||
|
||||
@@ -30,6 +30,7 @@ export class VoiceAssistantWebSocketServer {
|
||||
downloadTokenStore: DownloadTokenStore,
|
||||
paseoHome: string,
|
||||
agentMcpRoute: string,
|
||||
selfIdMcpSocketPath: string,
|
||||
wsConfig: WebSocketServerConfig,
|
||||
speech?: { stt: OpenAISTT | null; tts: OpenAITTS | null },
|
||||
terminalManager?: TerminalManager | null
|
||||
@@ -42,6 +43,7 @@ export class VoiceAssistantWebSocketServer {
|
||||
downloadTokenStore,
|
||||
paseoHome,
|
||||
agentMcpRoute,
|
||||
selfIdMcpSocketPath,
|
||||
speech,
|
||||
terminalManager
|
||||
);
|
||||
|
||||
@@ -30,6 +30,7 @@ export class WebSocketSessionBridge {
|
||||
private readonly pushTokenStore: PushTokenStore;
|
||||
private readonly pushService: PushService;
|
||||
private readonly agentMcpRoute: string;
|
||||
private readonly selfIdMcpSocketPath: string;
|
||||
private readonly stt: OpenAISTT | null;
|
||||
private readonly tts: OpenAITTS | null;
|
||||
private readonly terminalManager: TerminalManager | null;
|
||||
@@ -42,6 +43,7 @@ export class WebSocketSessionBridge {
|
||||
downloadTokenStore: DownloadTokenStore,
|
||||
paseoHome: string,
|
||||
agentMcpRoute: string,
|
||||
selfIdMcpSocketPath: string,
|
||||
speech?: { stt: OpenAISTT | null; tts: OpenAITTS | null },
|
||||
terminalManager?: TerminalManager | null
|
||||
) {
|
||||
@@ -51,6 +53,7 @@ export class WebSocketSessionBridge {
|
||||
this.downloadTokenStore = downloadTokenStore;
|
||||
this.paseoHome = paseoHome;
|
||||
this.agentMcpRoute = agentMcpRoute;
|
||||
this.selfIdMcpSocketPath = selfIdMcpSocketPath;
|
||||
this.stt = speech?.stt ?? null;
|
||||
this.tts = speech?.tts ?? null;
|
||||
this.terminalManager = terminalManager ?? null;
|
||||
@@ -87,6 +90,7 @@ export class WebSocketSessionBridge {
|
||||
this.agentManager,
|
||||
this.agentStorage,
|
||||
this.agentMcpRoute,
|
||||
this.selfIdMcpSocketPath,
|
||||
this.stt,
|
||||
this.tts,
|
||||
this.terminalManager,
|
||||
|
||||
Reference in New Issue
Block a user