feat: add configurable paseo home and port
This commit is contained in:
@@ -43,8 +43,3 @@ coverage/
|
|||||||
# Misc
|
# Misc
|
||||||
*.pem
|
*.pem
|
||||||
.vercel
|
.vercel
|
||||||
|
|
||||||
# Runtime agent data
|
|
||||||
packages/server/agents.json
|
|
||||||
packages/server/agents.json.temporary
|
|
||||||
packages/server/.agents.json.tmp-*
|
|
||||||
|
|||||||
@@ -8,5 +8,12 @@ TTS_MODEL=tts-1
|
|||||||
# Available models: tts-1 (faster), tts-1-hd (higher quality)
|
# Available models: tts-1 (faster), tts-1-hd (higher quality)
|
||||||
|
|
||||||
# Server Configuration
|
# Server Configuration
|
||||||
|
# Location for runtime state (agents.json, etc.). Defaults to ~/.paseo
|
||||||
|
PASEO_HOME=~/.paseo
|
||||||
|
|
||||||
|
# Voice server port (overrides PORT). Defaults to 6767
|
||||||
|
PASEO_PORT=6767
|
||||||
|
|
||||||
|
# Legacy web server port used by the legacy Express app
|
||||||
PORT=3000
|
PORT=3000
|
||||||
NODE_ENV=development
|
NODE_ENV=development
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import { randomUUID } from "node:crypto";
|
import { randomUUID } from "node:crypto";
|
||||||
import { existsSync } from "node:fs";
|
|
||||||
import { promises as fs } from "node:fs";
|
import { promises as fs } from "node:fs";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { fileURLToPath } from "node:url";
|
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { AgentStatusSchema } from "../messages.js";
|
import { AgentStatusSchema } from "../messages.js";
|
||||||
|
import { resolvePaseoHome } from "../config.js";
|
||||||
import { toStoredAgentRecord } from "./agent-projections.js";
|
import { toStoredAgentRecord } from "./agent-projections.js";
|
||||||
import type { ManagedAgent } from "./agent-manager.js";
|
import type { ManagedAgent } from "./agent-manager.js";
|
||||||
import type { AgentSessionConfig } from "./agent-sdk-types.js";
|
import type { AgentSessionConfig } from "./agent-sdk-types.js";
|
||||||
@@ -57,8 +56,7 @@ export class AgentRegistry {
|
|||||||
private filePath: string;
|
private filePath: string;
|
||||||
|
|
||||||
constructor(filePath?: string) {
|
constructor(filePath?: string) {
|
||||||
this.filePath =
|
this.filePath = filePath ?? path.join(resolvePaseoHome(), "agents.json");
|
||||||
filePath ?? path.join(resolveServerPackageRoot(), "agents.json");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async load(): Promise<StoredAgentRecord[]> {
|
async load(): Promise<StoredAgentRecord[]> {
|
||||||
@@ -188,22 +186,6 @@ export class AgentRegistry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveServerPackageRoot(): string {
|
|
||||||
let currentDir = path.dirname(fileURLToPath(import.meta.url));
|
|
||||||
while (true) {
|
|
||||||
if (existsSync(path.join(currentDir, "package.json"))) {
|
|
||||||
return currentDir;
|
|
||||||
}
|
|
||||||
const parentDir = path.dirname(currentDir);
|
|
||||||
if (parentDir === currentDir) {
|
|
||||||
throw new Error(
|
|
||||||
"[AgentRegistry] Failed to locate server package root for agents.json"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
currentDir = parentDir;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function writeFileAtomically(targetPath: string, payload: string) {
|
async function writeFileAtomically(targetPath: string, payload: string) {
|
||||||
const directory = path.dirname(targetPath);
|
const directory = path.dirname(targetPath);
|
||||||
const tempPath = path.join(
|
const tempPath = path.join(
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import type {
|
|||||||
ListPersistedAgentsOptions,
|
ListPersistedAgentsOptions,
|
||||||
PersistedAgentDescriptor,
|
PersistedAgentDescriptor,
|
||||||
} from "../agent-sdk-types.js";
|
} from "../agent-sdk-types.js";
|
||||||
|
import { resolvePaseoPort } from "../../config.js";
|
||||||
|
|
||||||
const CLAUDE_CAPABILITIES: AgentCapabilityFlags = {
|
const CLAUDE_CAPABILITIES: AgentCapabilityFlags = {
|
||||||
supportsStreaming: true,
|
supportsStreaming: true,
|
||||||
@@ -92,7 +93,7 @@ type ClaudeAgentSessionOptions = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_AGENT_CONTROL_MCP: AgentControlMcpConfig = {
|
const DEFAULT_AGENT_CONTROL_MCP: AgentControlMcpConfig = {
|
||||||
url: "http://127.0.0.1:6767/mcp/agents",
|
url: `http://127.0.0.1:${resolvePaseoPort()}/mcp/agents`,
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: "Basic bW86Ym8=",
|
Authorization: "Basic bW86Ym8=",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import os from "node:os";
|
||||||
|
import path from "node:path";
|
||||||
|
import { mkdirSync } from "node:fs";
|
||||||
|
|
||||||
|
let cachedHomeDir: string | null = null;
|
||||||
|
let cachedPort: number | null = null;
|
||||||
|
|
||||||
|
function expandHomeDir(input: string): string {
|
||||||
|
if (input.startsWith("~/")) {
|
||||||
|
return path.join(os.homedir(), input.slice(2));
|
||||||
|
}
|
||||||
|
if (input === "~") {
|
||||||
|
return os.homedir();
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolvePaseoHome(): string {
|
||||||
|
if (cachedHomeDir) {
|
||||||
|
return cachedHomeDir;
|
||||||
|
}
|
||||||
|
const raw = process.env.PASEO_HOME ?? process.env.PASEO_HOME_DIR ?? "~/.paseo";
|
||||||
|
const expanded = path.resolve(expandHomeDir(raw));
|
||||||
|
mkdirSync(expanded, { recursive: true });
|
||||||
|
cachedHomeDir = expanded;
|
||||||
|
return cachedHomeDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolvePaseoPort(): number {
|
||||||
|
if (cachedPort !== null) {
|
||||||
|
return cachedPort;
|
||||||
|
}
|
||||||
|
const raw = process.env.PASEO_PORT ?? process.env.PORT ?? "6767";
|
||||||
|
const parsed = Number.parseInt(raw, 10);
|
||||||
|
cachedPort = Number.isFinite(parsed) ? parsed : 6767;
|
||||||
|
return cachedPort;
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ import { AgentManager } from "./agent/agent-manager.js";
|
|||||||
import { AgentRegistry } from "./agent/agent-registry.js";
|
import { AgentRegistry } from "./agent/agent-registry.js";
|
||||||
import { ClaudeAgentClient } from "./agent/providers/claude-agent.js";
|
import { ClaudeAgentClient } from "./agent/providers/claude-agent.js";
|
||||||
import { CodexAgentClient } from "./agent/providers/codex-agent.js";
|
import { CodexAgentClient } from "./agent/providers/codex-agent.js";
|
||||||
|
import { resolvePaseoPort } from "./config.js";
|
||||||
import { initializeTitleGenerator } from "../services/agent-title-generator.js";
|
import { initializeTitleGenerator } from "../services/agent-title-generator.js";
|
||||||
import { attachAgentRegistryPersistence } from "./persistence-hooks.js";
|
import { attachAgentRegistryPersistence } from "./persistence-hooks.js";
|
||||||
import { createAgentMcpServer } from "./agent/mcp-server.js";
|
import { createAgentMcpServer } from "./agent/mcp-server.js";
|
||||||
@@ -73,7 +74,7 @@ function createServer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const port = parseInt(process.env.PORT || "6767", 10);
|
const port = resolvePaseoPort();
|
||||||
const agentMcpRoute = "/mcp/agents";
|
const agentMcpRoute = "/mcp/agents";
|
||||||
const agentMcpUrl = `http://127.0.0.1:${port}${agentMcpRoute}`;
|
const agentMcpUrl = `http://127.0.0.1:${port}${agentMcpRoute}`;
|
||||||
const [agentMcpUser, agentMcpPassword] =
|
const [agentMcpUser, agentMcpPassword] =
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
const CLAUDE_AGENT_ID = 'f7644b18-7fb9-4491-80f3-788d0d27a119';
|
|
||||||
const CODEX_AGENT_ID = 'd7c360ea-1579-4091-b224-ee8442400823';
|
|
||||||
|
|
||||||
const url = 'http://127.0.0.1:6767/mcp/agents';
|
|
||||||
const auth = Buffer.from('mo:bo').toString('base64');
|
|
||||||
|
|
||||||
async function makeRequest(method, params) {
|
|
||||||
console.log(`\n[TEST] Calling ${method} with params:`, JSON.stringify(params, null, 2));
|
|
||||||
const startTime = Date.now();
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch(url, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Authorization': `Basic ${auth}`
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
jsonrpc: '2.0',
|
|
||||||
id: Date.now(),
|
|
||||||
method: 'tools/call',
|
|
||||||
params: {
|
|
||||||
name: method,
|
|
||||||
arguments: params
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
const elapsed = Date.now() - startTime;
|
|
||||||
console.log(`[TEST] Response received in ${elapsed}ms`);
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
console.log(`[TEST] Response:`, JSON.stringify(data, null, 2));
|
|
||||||
return data;
|
|
||||||
} catch (error) {
|
|
||||||
const elapsed = Date.now() - startTime;
|
|
||||||
console.error(`[TEST] Request failed after ${elapsed}ms:`, error.message);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function initialize() {
|
|
||||||
console.log('[TEST] Initializing MCP session...');
|
|
||||||
const response = await fetch(url, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Authorization': `Basic ${auth}`
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
jsonrpc: '2.0',
|
|
||||||
id: 1,
|
|
||||||
method: 'initialize',
|
|
||||||
params: {
|
|
||||||
protocolVersion: '2024-11-05',
|
|
||||||
capabilities: {},
|
|
||||||
clientInfo: {
|
|
||||||
name: 'test-client',
|
|
||||||
version: '1.0.0'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
const data = await response.json();
|
|
||||||
console.log('[TEST] Initialized:', JSON.stringify(data, null, 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
console.log('=== Testing MCP Agent Control Tools ===\n');
|
|
||||||
|
|
||||||
// Initialize session
|
|
||||||
await initialize();
|
|
||||||
|
|
||||||
// Test 1: Get status of Codex agent (should work)
|
|
||||||
console.log('\n--- Test 1: get_agent_status on Codex agent ---');
|
|
||||||
await makeRequest('get_agent_status', { agentId: CODEX_AGENT_ID });
|
|
||||||
|
|
||||||
// Test 2: Get status of Claude agent (might hang)
|
|
||||||
console.log('\n--- Test 2: get_agent_status on Claude agent ---');
|
|
||||||
await makeRequest('get_agent_status', { agentId: CLAUDE_AGENT_ID });
|
|
||||||
|
|
||||||
console.log('\n=== All tests complete ===');
|
|
||||||
}
|
|
||||||
|
|
||||||
main().catch(console.error);
|
|
||||||
Reference in New Issue
Block a user