Add CLI setup and QQ webhook integration

This commit is contained in:
zenord
2026-08-15 16:02:05 +08:00
parent 00325efb50
commit d79264b11a
22 changed files with 1389 additions and 99 deletions
+71 -59
View File
@@ -1,5 +1,7 @@
import express from "express";
import { loadConfig } from "./config.js";
import type { Server } from "node:http";
import { fileURLToPath } from "node:url";
import { loadConfig, type AppConfig } from "./config.js";
import { AgentRegistry } from "./agents/agent-registry.js";
import { CliAgent } from "./agents/cli-agent.js";
import { Gateway } from "./core/gateway.js";
@@ -12,67 +14,77 @@ import { QqAdapter } from "./platforms/qq/adapter.js";
import { GenericWebhookAdapter } from "./platforms/webhook/adapter.js";
import { WeixinAdapter } from "./platforms/weixin/adapter.js";
const config = loadConfig();
const sessions = new SessionStore();
const agents = new AgentRegistry(config.defaultAgent);
for (const agentConfig of config.agents) {
agents.register(new CliAgent(agentConfig));
export function createApp(config: AppConfig): express.Express {
const sessions = new SessionStore();
const agents = new AgentRegistry(config.defaultAgent);
for (const agentConfig of config.agents) {
agents.register(new CliAgent(agentConfig));
}
const gateway = new Gateway(config.policy, agents, sessions);
const platforms = new PlatformRegistry();
const adapters: PlatformAdapter[] = [
new FeishuAdapter(config.platforms.feishu, gateway),
new WeComAdapter(config.platforms.wecom),
new QqAdapter(config.platforms.qq, gateway),
new GenericWebhookAdapter(config.platforms.webhook, gateway),
new WeixinAdapter(config.platforms.weixin, gateway)
];
for (const adapter of adapters) platforms.register(adapter);
const app = express();
app.use(express.json({
limit: "1mb",
verify: (req, _res, buf) => {
(req as express.Request & { rawBody?: Buffer }).rawBody = Buffer.from(buf);
}
}));
app.get("/health", (_req, res) => {
res.json({ ok: true, gateway: gateway.stats() });
});
app.get("/platforms", (_req, res) => {
res.json({ ok: true, platforms: platforms.list(), agents: agents.list() });
});
function mountWebhook(routeName: string, adapterName = routeName): void {
app.post(`/webhook/${routeName}`, async (req, res) => {
try {
const response = await platforms.get(adapterName).handleWebhook({
req,
body: req.body,
headers: req.headers,
query: req.query,
rawBody: (req as express.Request & { rawBody?: Buffer }).rawBody
});
if (response.headers) {
for (const [key, value] of Object.entries(response.headers)) res.setHeader(key, value);
}
res.status(response.status || 200).json(response.body ?? { ok: true });
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
console.error(`Webhook ${routeName} failed`, error);
res.status(500).json({ ok: false, error: message });
}
});
}
for (const platformName of ["feishu", "wecom", "qq", "weixin"]) {
mountWebhook(platformName);
}
mountWebhook("generic", "webhook");
return app;
}
const gateway = new Gateway(config.policy, agents, sessions);
const platforms = new PlatformRegistry();
const adapters: PlatformAdapter[] = [
new FeishuAdapter(config.platforms.feishu, gateway),
new WeComAdapter(config.platforms.wecom),
new QqAdapter(config.platforms.qq),
new GenericWebhookAdapter(config.platforms.webhook, gateway),
new WeixinAdapter(config.platforms.weixin, gateway)
];
for (const adapter of adapters) platforms.register(adapter);
const app = express();
app.use(express.json({
limit: "1mb",
verify: (req, _res, buf) => {
(req as express.Request & { rawBody?: Buffer }).rawBody = Buffer.from(buf);
}
}));
app.get("/health", (_req, res) => {
res.json({ ok: true, gateway: gateway.stats() });
});
app.get("/platforms", (_req, res) => {
res.json({ ok: true, platforms: platforms.list(), agents: agents.list() });
});
function mountWebhook(routeName: string, adapterName = routeName): void {
app.post(`/webhook/${routeName}`, async (req, res) => {
try {
const response = await platforms.get(adapterName).handleWebhook({
req,
body: req.body,
headers: req.headers,
query: req.query,
rawBody: (req as express.Request & { rawBody?: Buffer }).rawBody
});
if (response.headers) {
for (const [key, value] of Object.entries(response.headers)) res.setHeader(key, value);
}
res.status(response.status || 200).json(response.body ?? { ok: true });
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
console.error(`Webhook ${routeName} failed`, error);
res.status(500).json({ ok: false, error: message });
}
export function startServer(config: AppConfig): Server {
const app = createApp(config);
return app.listen(config.server.port, config.server.host, () => {
console.log(`gori-agent-gateway listening on ${config.server.host}:${config.server.port}`);
});
}
for (const platformName of ["feishu", "wecom", "qq", "weixin"]) {
mountWebhook(platformName);
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
startServer(loadConfig());
}
mountWebhook("generic", "webhook");
app.listen(config.server.port, config.server.host, () => {
console.log(`gori-agent-gateway listening on ${config.server.host}:${config.server.port}`);
});