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.
This commit is contained in:
@@ -10,6 +10,10 @@
|
|||||||
"src/server/index.ts",
|
"src/server/index.ts",
|
||||||
"src/server/exports.ts",
|
"src/server/exports.ts",
|
||||||
"src/utils/tool-call-parsers.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}",
|
"scripts/**/*.{ts,mts,mjs,cjs,js}",
|
||||||
"src/**/*.test.ts",
|
"src/**/*.test.ts",
|
||||||
"src/**/*.test.tsx",
|
"src/**/*.test.tsx",
|
||||||
@@ -33,6 +37,9 @@
|
|||||||
"test-stubs/**/*.ts"
|
"test-stubs/**/*.ts"
|
||||||
],
|
],
|
||||||
"project": ["**/*.{ts,tsx,js,jsx}"],
|
"project": ["**/*.{ts,tsx,js,jsx}"],
|
||||||
|
"paths": {
|
||||||
|
"@server/*": ["../server/src/*"]
|
||||||
|
},
|
||||||
"ignore": ["android/**", "ios/**", ".expo/**", "dist/**", "scripts/reset-project.js"]
|
"ignore": ["android/**", "ios/**", ".expo/**", "dist/**", "scripts/reset-project.js"]
|
||||||
},
|
},
|
||||||
"packages/cli": {
|
"packages/cli": {
|
||||||
|
|||||||
@@ -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<AgentStreamEvent>,
|
|
||||||
timeoutMs: number,
|
|
||||||
onEvent: (event: AgentStreamEvent) => Promise<void> | void,
|
|
||||||
): Promise<void> {
|
|
||||||
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<void> {
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { describe, expect, test } from "vitest";
|
import { describe, expect, test } from "vitest";
|
||||||
import { execFileSync } from "node:child_process";
|
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";
|
import { createDaemonTestContext } from "../test-utils/index.js";
|
||||||
|
|
||||||
function isBinaryInstalled(binary: string): boolean {
|
function isBinaryInstalled(binary: string): boolean {
|
||||||
|
|||||||
Reference in New Issue
Block a user