feat(ops): add workspace MCP deployment overlays
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
import Fastify, { type FastifyInstance } from "fastify";
|
||||
import { ZodError } from "zod";
|
||||
|
||||
import type { AppConfig } from "./config.js";
|
||||
import { createPool, DatabaseNotConfiguredError } from "./db/pool.js";
|
||||
import { ToolExecutionInputError } from "./mcp/tool-runtime.js";
|
||||
import { AgentsRepository } from "./repositories/agents.js";
|
||||
import { registerAgentRoutes } from "./routes/agents.js";
|
||||
import { registerEngineGatewayRoutes } from "./routes/engine.js";
|
||||
import { registerHealthRoutes } from "./routes/health.js";
|
||||
import { registerInstallerRoutes } from "./routes/install.js";
|
||||
import { registerMcpRoutes } from "./routes/mcp.js";
|
||||
import { registerOntologyGatewayRoutes } from "./routes/ontology.js";
|
||||
import { registerPublicRoutes } from "./routes/public.js";
|
||||
import { registerToolRoutes } from "./routes/tools.js";
|
||||
import { ForbiddenError } from "./security/authorization.js";
|
||||
import { UnauthorizedError } from "./security/bearer.js";
|
||||
import { InternalAuthNotConfiguredError } from "./security/internal.js";
|
||||
import { TaskerAdapterError, TaskerAdapterNotConfiguredError, TaskerAdapterUnavailableError, TaskerClient } from "./tasker/client.js";
|
||||
|
||||
export async function buildApp(config: AppConfig): Promise<FastifyInstance> {
|
||||
const pool = createPool(config);
|
||||
const agentsRepository = pool ? new AgentsRepository(pool) : null;
|
||||
const taskerClient = new TaskerClient({
|
||||
baseUrl: config.NODEDC_TASKER_INTERNAL_URL,
|
||||
internalAccessToken: config.NODEDC_INTERNAL_ACCESS_TOKEN,
|
||||
});
|
||||
const app = Fastify({
|
||||
bodyLimit: 10 * 1024 * 1024,
|
||||
logger: {
|
||||
level: config.LOG_LEVEL,
|
||||
},
|
||||
});
|
||||
|
||||
app.addHook("onClose", async () => {
|
||||
await pool?.end();
|
||||
});
|
||||
|
||||
app.setErrorHandler((error, _request, reply) => {
|
||||
if (error instanceof ZodError) {
|
||||
void reply.status(400).send({
|
||||
ok: false,
|
||||
error: "validation_error",
|
||||
details: error.issues,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (error instanceof DatabaseNotConfiguredError) {
|
||||
void reply.status(503).send({
|
||||
ok: false,
|
||||
error: "database_not_configured",
|
||||
message: "DATABASE_URL is required for Agent Gateway persistence endpoints.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (error instanceof UnauthorizedError) {
|
||||
void reply.status(401).send({
|
||||
ok: false,
|
||||
error: "unauthorized",
|
||||
message: error.message,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (error instanceof InternalAuthNotConfiguredError) {
|
||||
void reply.status(503).send({
|
||||
ok: false,
|
||||
error: "internal_auth_not_configured",
|
||||
message: error.message,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (error instanceof ForbiddenError) {
|
||||
void reply.status(403).send({
|
||||
ok: false,
|
||||
error: "forbidden",
|
||||
message: error.message,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (error instanceof ToolExecutionInputError) {
|
||||
void reply.status(error.httpStatus).send({
|
||||
ok: false,
|
||||
error: error.code,
|
||||
message: error.message,
|
||||
details: error.details,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (error instanceof TaskerAdapterNotConfiguredError) {
|
||||
void reply.status(503).send({
|
||||
ok: false,
|
||||
error: "tasker_adapter_not_configured",
|
||||
message: error.message,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (error instanceof TaskerAdapterError) {
|
||||
void reply.status(error.statusCode).send({
|
||||
ok: false,
|
||||
error: "tasker_adapter_error",
|
||||
message: error.message,
|
||||
tasker_status: error.statusCode,
|
||||
tasker_payload: error.payload,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (error instanceof TaskerAdapterUnavailableError) {
|
||||
void reply.status(502).send({
|
||||
ok: false,
|
||||
error: "tasker_adapter_unavailable",
|
||||
message: error.message,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
app.log.error(error);
|
||||
void reply.status(500).send({
|
||||
ok: false,
|
||||
error: "internal_server_error",
|
||||
message: "Agent Gateway request failed.",
|
||||
});
|
||||
});
|
||||
|
||||
await registerPublicRoutes(app);
|
||||
await registerInstallerRoutes(app, { publicUrl: config.NODEDC_AGENT_GATEWAY_PUBLIC_URL });
|
||||
await registerHealthRoutes(app, config, pool);
|
||||
await registerAgentRoutes(app, {
|
||||
agentsRepository,
|
||||
codexInstallChannel: config.NODEDC_OPS_CODEX_INSTALL_CHANNEL,
|
||||
codexNpmSpec: config.NODEDC_OPS_CODEX_NPM_SPEC,
|
||||
publicUrl: config.NODEDC_AGENT_GATEWAY_PUBLIC_URL,
|
||||
internalAccessToken: config.NODEDC_AGENT_GATEWAY_INTERNAL_TOKEN,
|
||||
aiWorkspaceRunTokenTtlSeconds: config.NODEDC_AI_WORKSPACE_RUN_TOKEN_TTL_SECONDS,
|
||||
});
|
||||
await registerEngineGatewayRoutes(app, {
|
||||
engineInternalUrl: config.NODEDC_ENGINE_INTERNAL_URL,
|
||||
publicUrl: config.NODEDC_AGENT_GATEWAY_PUBLIC_URL,
|
||||
});
|
||||
await registerToolRoutes(app, { agentsRepository, taskerClient });
|
||||
await registerMcpRoutes(app, { agentsRepository, taskerClient });
|
||||
await registerOntologyGatewayRoutes(app, {
|
||||
agentsRepository,
|
||||
ontologyCoreUrl: config.NODEDC_ONTOLOGY_CORE_URL,
|
||||
ontologyCoreAccessToken: config.NODEDC_ONTOLOGY_CORE_ACCESS_TOKEN ?? config.NODEDC_INTERNAL_ACCESS_TOKEN,
|
||||
});
|
||||
|
||||
return app;
|
||||
}
|
||||
Reference in New Issue
Block a user