Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
microchipgnu committed Jan 20, 2025
1 parent 60b6e07 commit a0f3cf9
Show file tree
Hide file tree
Showing 9 changed files with 177 additions and 139 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"homepage": "https://github.com/mintbase/make-agent/repo#readme",
"scripts": {
"typecheck": "tsc --noEmit",
"dev": "bun run ./src/index.ts playground --port 3000",
"dev": "bun run ./src/index.ts dev --port 3000",
"build": "bun run typecheck && bun build ./src/index.ts --outdir ./dist --target node",
"prepublishOnly": "bun run build",
"build-binary": "bun run typecheck && bun build ./src/index.ts --compile --outfile make-agent",
Expand Down
30 changes: 30 additions & 0 deletions src/commands/dev-deprecated.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Command } from "commander";

import { TunnelService } from "../services/tunnel";
import { detectPort } from "../utils/port-detector";

export const devDeprecatedCommand = new Command()
.name("dev-deprecated")
.description("Make your AI agent discoverable and register the plugin")
.option("-p, --port <number>", "Local port to expose", parseInt)
.option("-s, --serveo", "Use Serveo instead of Localtunnel", false)
.option("-t, --testnet", "Use Testnet instead of Mainnet", false)
.action(async (options) => {
let port = options.port;
if (!port) {
port = await detectPort();
if (!port) {
console.error(
"Unable to detect the port automatically. Please specify a port using the -p or --port option.",
);
process.exit(1);
}
console.log(`Detected port: ${port}`);
}
const tunnelService = new TunnelService({
port,
useServeo: options.serveo,
useTestnet: options.testnet,
});
await tunnelService.start();
});
152 changes: 132 additions & 20 deletions src/commands/dev.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,142 @@
import { Command } from "commander";

import { TunnelService } from "../services/tunnel";
import dotenv from 'dotenv';
import isPortReachable from 'is-port-reachable';
import path from "path";
import { startApiServer } from "../services/proxy";
import { createViteServer } from "../services/vite";
import { getDeployedUrl } from "../utils/deployed-url";
import { validateEnv } from "../utils/env";
import { validateAndParseOpenApiSpec } from "../utils/openapi";
import { detectPort } from "../utils/port-detector";
import { getHostname, getSpecUrl } from "../utils/url-utils";

dotenv.config();
validateEnv();

interface ApiConfig {
key: string;
url: string;
serverPort: number;
}

interface ValidationResult {
pluginId: string;
accountId: string;
spec: any;
}

const DEFAULT_PORTS = {
SERVER: 3010,
UI: 5000
} as const;

async function findAvailablePort(startPort: number): Promise<number> {
let port = startPort;
while (await isPortReachable(port, {host: 'localhost'})) {
port++;
}
return port;
}

const API_CONFIG: ApiConfig = {
key: process.env.BITTE_API_KEY!,
url: process.env.BITTE_API_URL!,
serverPort: DEFAULT_PORTS.SERVER
};

async function fetchAndValidateSpec(url: string): Promise<ValidationResult> {
const pluginId = getHostname(url);
const specUrl = getSpecUrl(url);

const validation = await validateAndParseOpenApiSpec(specUrl);
const { isValid, accountId } = validation;

const specContent = await fetch(specUrl).then(res => res.text());
let spec = JSON.parse(specContent);

if (!isValid) {
spec = {
...spec,
servers: [{ url }],
"x-mb": {
...spec["x-mb"],
"account-id": accountId || "anon",
}
};
}

return {
pluginId,
accountId: accountId || "anon",
spec
};
}

async function setupPorts(options: { port?: string }) {
let port = parseInt(options.port || '') || 0;

if (port === 0) {
const detectedPort = await detectPort();
if (detectedPort) {
port = detectedPort;
} else {
port = await findAvailablePort(3000);
}
}

const uiPort = await findAvailablePort(DEFAULT_PORTS.UI);
const serverPort = await findAvailablePort(DEFAULT_PORTS.SERVER);

return { port, uiPort, serverPort };
}

async function createViteConfiguration(uiPort: number, serverPort: number, localAgent: ValidationResult) {
return {
root: path.resolve(__dirname, "../playground"),
port: uiPort,
configFile: path.resolve(__dirname, "../playground/vite.config.ts"),
define: {
__APP_DATA__: JSON.stringify({
serverStartTime: new Date().toISOString(),
environment: "make-agent",
localAgent,
apiUrl: `http://localhost:${serverPort}/api/v1/chat`,
bitteApiKey: API_CONFIG.key,
bitteApiUrl: `http://localhost:${serverPort}/api/v1/chat`
})
}
};
}

export const devCommand = new Command()
.name("dev")
.description("Make your AI agent discoverable and register the plugin")
.option("-p, --port <number>", "Local port to expose", parseInt)
.option("-s, --serveo", "Use Serveo instead of Localtunnel", false)
.description("Start a local playground for your AI agent")
.option("-p, --port <port>", "Port to run playground on", "3000")
.option("-t, --testnet", "Use Testnet instead of Mainnet", false)
.action(async (options) => {
let port = options.port;
if (!port) {
port = await detectPort();
if (!port) {
console.error(
"Unable to detect the port automatically. Please specify a port using the -p or --port option.",
);
process.exit(1);
try {
const { port, uiPort, serverPort } = await setupPorts(options);

API_CONFIG.serverPort = serverPort;
const server = await startApiServer(API_CONFIG);

const deployedUrl = getDeployedUrl(port);
if (!deployedUrl) {
throw new Error("Deployed URL could not be determined.");
}
console.log(`Detected port: ${port}`);

const localAgent = await fetchAndValidateSpec(deployedUrl);
const viteConfig = await createViteConfiguration(uiPort, serverPort, localAgent);
const viteServer = createViteServer(viteConfig);
await viteServer.start();

process.on("SIGINT", async () => {
await viteServer.close();
server.close();
process.exit(0);
});

} catch (error) {
process.exit(1);
}
const tunnelService = new TunnelService({
port,
useServeo: options.serveo,
useTestnet: options.testnet,
});
await tunnelService.start();
});
101 changes: 0 additions & 101 deletions src/commands/playground.ts

This file was deleted.

6 changes: 3 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import packageJson from "../package.json";
import { contractCommand } from "./commands/contract";
import { deleteCommand } from "./commands/delete";
import { deployCommand } from "./commands/deploy";
import { devCommand } from "./commands/dev";
import { devDeprecatedCommand } from "./commands/dev-deprecated";
import { registerCommand } from "./commands/register";
import { updateCommand } from "./commands/update";
import { verifyCommand } from "./commands/verify";
import { playgroundCommand } from "./commands/playground";
import { devCommand } from "./commands/dev";

dotenv.config();

Expand All @@ -27,6 +27,6 @@ program
.addCommand(updateCommand)
.addCommand(deleteCommand)
.addCommand(verifyCommand)
.addCommand(playgroundCommand);
.addCommand(devDeprecatedCommand);

program.parse();
9 changes: 1 addition & 8 deletions src/services/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,12 @@ export async function startApiServer(config: ApiConfig) {

// Add request logging middleware
app.use((req, res, next) => {
console.log(`[Express] Incoming request: ${req.method} ${req.url}`);
next();
});

// Handle chat requests
app.post('/api/v1/chat', async (req, res) => {
try {
console.log('[Server] Forwarding chat request to Bitte API');

try {
const response = await fetch(config.url, {
method: 'POST',
headers: {
Expand All @@ -36,7 +33,6 @@ export async function startApiServer(config: ApiConfig) {
});

const data = await response.text();
console.log('[Server] Response received:', data);

res.status(response.status);
response.headers.forEach((value, key) => {
Expand All @@ -48,7 +44,6 @@ export async function startApiServer(config: ApiConfig) {
res.send(data);

} catch (error) {
console.error('[Server] Error handling chat request:', error);
res.status(500).json({
error: 'Internal server error',
message: error instanceof Error ? error.message : 'Unknown error'
Expand All @@ -59,11 +54,9 @@ export async function startApiServer(config: ApiConfig) {
return new Promise<ReturnType<typeof app.listen>>((resolve, reject) => {
try {
const server = app.listen(config.serverPort, () => {
console.log(`API server running on port ${config.serverPort}`);
resolve(server);
});
} catch (error) {
console.error('Failed to start API server:', error);
reject(error);
}
});
Expand Down
2 changes: 1 addition & 1 deletion src/services/vite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export class ViteServer {
});

await this.server.listen();
console.log(`Vite dev server running at http://localhost:${this.config.port}`);
console.log(`Playground running at http://localhost:${this.config.port}`);

} catch (error) {
console.error('Failed to start Vite server:', error);
Expand Down
4 changes: 2 additions & 2 deletions src/utils/deployed-url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const VERCEL_DEPLOYMENT_URL = (() => {
}
})();

const getDeployedUrl = (): string => {
export const getDeployedUrl = (port?: number): string => {
// Vercel
if (VERCEL_ENV) {
return VERCEL_DEPLOYMENT_URL;
Expand Down Expand Up @@ -63,7 +63,7 @@ const getDeployedUrl = (): string => {
}

// Fallback to localhost if no deployment URL is found
return "http://localhost:3000"; // TODO: make port dynamic
return `http://localhost:${port || 3000}`;
};

export const deployedUrl = getDeployedUrl();
Loading

0 comments on commit a0f3cf9

Please sign in to comment.