From 5b2f3fd830da2c038ab4c7a06e640589e6f7e2be Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Thu, 23 Apr 2026 22:41:27 +0700 Subject: [PATCH] chore: fix unresolved imports and tighten knip cross-workspace entries Delete orphaned voice-mcp-agent-smoke.ts (voice-mcp-bridge was removed in cff41d78). Fix model-catalog.e2e.test.ts import path. Extend knip server entries to cover shared/client cross-workspace imports. --- knip.json | 7 + .../server/scripts/voice-mcp-agent-smoke.ts | 207 ------------------ .../server/agent/model-catalog.e2e.test.ts | 2 +- 3 files changed, 8 insertions(+), 208 deletions(-) delete mode 100644 packages/server/scripts/voice-mcp-agent-smoke.ts diff --git a/knip.json b/knip.json index 41b2b5f08..f61a8a33b 100644 --- a/knip.json +++ b/knip.json @@ -10,6 +10,10 @@ "src/server/index.ts", "src/server/exports.ts", "src/utils/tool-call-parsers.ts", + "src/shared/**/*.ts", + "src/client/**/*.ts", + "src/server/agent/agent-sdk-types.ts", + "src/server/agent/provider-manifest.ts", "scripts/**/*.{ts,mts,mjs,cjs,js}", "src/**/*.test.ts", "src/**/*.test.tsx", @@ -33,6 +37,9 @@ "test-stubs/**/*.ts" ], "project": ["**/*.{ts,tsx,js,jsx}"], + "paths": { + "@server/*": ["../server/src/*"] + }, "ignore": ["android/**", "ios/**", ".expo/**", "dist/**", "scripts/reset-project.js"] }, "packages/cli": { diff --git a/packages/server/scripts/voice-mcp-agent-smoke.ts b/packages/server/scripts/voice-mcp-agent-smoke.ts deleted file mode 100644 index 58e6e018f..000000000 --- a/packages/server/scripts/voice-mcp-agent-smoke.ts +++ /dev/null @@ -1,207 +0,0 @@ -import os from "node:os"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; -import { mkdir, mkdtemp, rm } from "node:fs/promises"; -import { randomUUID } from "node:crypto"; -import pino from "pino"; - -import { AgentManager } from "../src/server/agent/agent-manager.js"; -import { AgentStorage } from "../src/server/agent/agent-storage.js"; -import { buildProviderRegistry, shutdownProviders } from "../src/server/agent/provider-registry.js"; -import type { - AgentProvider, - AgentSessionConfig, - AgentStreamEvent, -} from "../src/server/agent/agent-sdk-types.js"; -import { buildVoiceAgentMcpServerConfig } from "../src/server/session.js"; -import { createAgentMcpServer } from "../src/server/agent/mcp-server.js"; -import { createVoiceMcpSocketBridgeManager } from "../src/server/voice-mcp-bridge.js"; -import { withTimeout } from "../src/utils/promise-timeout.js"; - -type CliOptions = { - provider: AgentProvider; - model?: string; - timeoutMs: number; -}; - -function parseArgs(argv: string[]): CliOptions { - let provider: AgentProvider = "claude"; - let model: string | undefined; - let timeoutMs = 120_000; - - for (let i = 0; i < argv.length; i += 1) { - const arg = argv[i]; - if (arg === "--provider" && argv[i + 1]) { - provider = argv[i + 1] as AgentProvider; - i += 1; - continue; - } - if (arg === "--model" && argv[i + 1]) { - model = argv[i + 1]; - i += 1; - continue; - } - if (arg === "--timeout-ms" && argv[i + 1]) { - timeoutMs = Number(argv[i + 1]) || timeoutMs; - i += 1; - } - } - - return { provider, model, timeoutMs }; -} - -async function streamWithTimeout( - iterator: AsyncGenerator, - timeoutMs: number, - onEvent: (event: AgentStreamEvent) => Promise | void, -): Promise { - const consume = (async () => { - for await (const event of iterator) { - await onEvent(event); - } - })(); - - await withTimeout(consume, timeoutMs, `Timed out after ${timeoutMs}ms`); -} - -async function main(): Promise { - const opts = parseArgs(process.argv.slice(2)); - const logger = pino({ level: "info" }); - const scriptDir = path.dirname(fileURLToPath(import.meta.url)); - const serverDir = path.resolve(scriptDir, ".."); - const tmpRoot = await mkdtemp(path.join(os.tmpdir(), "paseo-voice-mcp-smoke-")); - const paseoHome = path.join(tmpRoot, ".paseo"); - const storageDir = path.join(paseoHome, "agents"); - const voiceBridgeRuntimeDir = path.join(tmpRoot, "voice-mcp"); - const voiceWorkspace = path.join(tmpRoot, "voice-agent-workspace"); - await mkdir(voiceWorkspace, { recursive: true }); - - const providerRegistry = buildProviderRegistry(logger); - const providerDefinition = providerRegistry[opts.provider]; - if (!providerDefinition) { - throw new Error(`Unsupported provider: ${opts.provider}`); - } - - const agentStorage = new AgentStorage(storageDir, logger); - const agentManager = new AgentManager({ - logger, - registry: agentStorage, - clients: { - [opts.provider]: providerDefinition.createClient(logger), - }, - }); - - const speakCalls: string[] = []; - const resolveSpeakHandler = (callerAgentId: string) => { - return async ({ text }: { text: string; callerAgentId: string }) => { - speakCalls.push(text); - logger.info({ callerAgentId, text }, "Smoke speak handler invoked"); - }; - }; - - const voiceBridgeManager = createVoiceMcpSocketBridgeManager({ - runtimeDir: voiceBridgeRuntimeDir, - logger, - createAgentMcpServerForCaller: async (callerAgentId) => { - return createAgentMcpServer({ - agentManager, - agentStorage, - paseoHome, - callerAgentId, - enableVoiceTools: false, - resolveSpeakHandler, - resolveCallerContext: () => ({ - childAgentDefaultLabels: { source: "voice-smoke" }, - allowCustomCwd: true, - enableVoiceTools: true, - }), - logger, - }); - }, - }); - - const agentId = randomUUID(); - const socketPath = await voiceBridgeManager.ensureBridgeForCaller(agentId); - const bridgeScriptPath = path.resolve(serverDir, "scripts/mcp-stdio-socket-bridge-cli.mjs"); - const config: AgentSessionConfig = { - provider: opts.provider, - cwd: voiceWorkspace, - modeId: "default", - ...(opts.model ? { model: opts.model } : {}), - mcpServers: { - paseo: buildVoiceAgentMcpServerConfig({ - command: process.execPath, - baseArgs: [bridgeScriptPath], - socketPath, - env: { - PASEO_HOME: paseoHome, - }, - }), - }, - }; - - const prompt = [ - "You must call the MCP tool named speak.", - "Call it exactly once with this exact text: BRIDGE_SMOKE_OK", - "Do not call any other tools.", - "After the tool call, end your response.", - ].join("\n"); - - let sawSpeakTimeline = false; - let sawTurnFailed = false; - let failureError: string | null = null; - - try { - const created = await agentManager.createAgent(config, agentId, { - labels: { surface: "voice-smoke" }, - }); - logger.info({ provider: opts.provider, agentId: created.id }, "Created smoke agent"); - - const iterator = agentManager.streamAgent(created.id, prompt); - await streamWithTimeout(iterator, opts.timeoutMs, async (event) => { - if (event.type === "permission_requested") { - await agentManager.respondToPermission(created.id, event.request.id, { behavior: "allow" }); - } - if (event.type === "turn_failed") { - sawTurnFailed = true; - failureError = event.error; - } - if (event.type === "timeline" && event.item.type === "tool_call") { - logger.info({ name: event.item.name, callId: event.item.callId }, "Timeline tool call"); - if ( - typeof event.item.name === "string" && - event.item.name.toLowerCase().includes("speak") - ) { - sawSpeakTimeline = true; - } - } - }); - - console.log( - JSON.stringify( - { - ok: !sawTurnFailed && sawSpeakTimeline && speakCalls.length > 0, - provider: opts.provider, - agentId, - sawSpeakTimeline, - speakCalls, - sawTurnFailed, - failureError, - }, - null, - 2, - ), - ); - } finally { - await agentManager.closeAgent(agentId).catch(() => undefined); - await agentManager.flush().catch(() => undefined); - await voiceBridgeManager.stop().catch(() => undefined); - await shutdownProviders(logger).catch(() => undefined); - await rm(tmpRoot, { recursive: true, force: true }); - } -} - -main().catch((error) => { - console.error(error); - process.exit(1); -}); diff --git a/packages/server/src/server/agent/model-catalog.e2e.test.ts b/packages/server/src/server/agent/model-catalog.e2e.test.ts index fda1b99cf..63fa4829a 100644 --- a/packages/server/src/server/agent/model-catalog.e2e.test.ts +++ b/packages/server/src/server/agent/model-catalog.e2e.test.ts @@ -1,7 +1,7 @@ import { describe, expect, test } from "vitest"; import { execFileSync } from "node:child_process"; -import type { AgentModelDefinition } from "../agent-sdk-types.js"; +import type { AgentModelDefinition } from "./agent-sdk-types.js"; import { createDaemonTestContext } from "../test-utils/index.js"; function isBinaryInstalled(binary: string): boolean {