feat: load channel plugins
This commit is contained in:
@@ -136,18 +136,19 @@ export type HookAgentPayload = {
|
||||
timeoutSeconds?: number;
|
||||
};
|
||||
|
||||
const HOOK_CHANNEL_VALUES = ["last", ...listChannelPlugins().map((plugin) => plugin.id)];
|
||||
const listHookChannelValues = () => ["last", ...listChannelPlugins().map((plugin) => plugin.id)];
|
||||
|
||||
export type HookMessageChannel = ChannelId | "last";
|
||||
|
||||
const hookChannelSet = new Set<string>(HOOK_CHANNEL_VALUES);
|
||||
export const HOOK_CHANNEL_ERROR = `channel must be ${HOOK_CHANNEL_VALUES.join("|")}`;
|
||||
const getHookChannelSet = () => new Set<string>(listHookChannelValues());
|
||||
export const getHookChannelError = () =>
|
||||
`channel must be ${listHookChannelValues().join("|")}`;
|
||||
|
||||
export function resolveHookChannel(raw: unknown): HookMessageChannel | null {
|
||||
if (raw === undefined) return "last";
|
||||
if (typeof raw !== "string") return null;
|
||||
const normalized = normalizeMessageChannel(raw);
|
||||
if (!normalized || !hookChannelSet.has(normalized)) return null;
|
||||
if (!normalized || !getHookChannelSet().has(normalized)) return null;
|
||||
return normalized as HookMessageChannel;
|
||||
}
|
||||
|
||||
@@ -176,7 +177,7 @@ export function normalizeAgentPayload(
|
||||
? sessionKeyRaw.trim()
|
||||
: `hook:${idFactory()}`;
|
||||
const channel = resolveHookChannel(payload.channel);
|
||||
if (!channel) return { ok: false, error: HOOK_CHANNEL_ERROR };
|
||||
if (!channel) return { ok: false, error: getHookChannelError() };
|
||||
const toRaw = payload.to;
|
||||
const to = typeof toRaw === "string" && toRaw.trim() ? toRaw.trim() : undefined;
|
||||
const modelRaw = payload.model;
|
||||
|
||||
@@ -67,6 +67,11 @@ export const handleConfigBridgeMethods: BridgeMethodHandler = async (
|
||||
description: plugin.description,
|
||||
configUiHints: plugin.configUiHints,
|
||||
})),
|
||||
channels: pluginRegistry.channels.map((entry) => ({
|
||||
id: entry.plugin.id,
|
||||
label: entry.plugin.meta.label,
|
||||
description: entry.plugin.meta.blurb,
|
||||
})),
|
||||
});
|
||||
return { ok: true, payloadJSON: JSON.stringify(schema) };
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import type { createSubsystemLogger } from "../logging.js";
|
||||
import { handleControlUiHttpRequest } from "./control-ui.js";
|
||||
import {
|
||||
extractHookToken,
|
||||
HOOK_CHANNEL_ERROR,
|
||||
getHookChannelError,
|
||||
type HookMessageChannel,
|
||||
type HooksConfigResolved,
|
||||
normalizeAgentPayload,
|
||||
@@ -152,7 +152,7 @@ export function createHooksRequestHandler(
|
||||
}
|
||||
const channel = resolveHookChannel(mapped.action.channel);
|
||||
if (!channel) {
|
||||
sendJson(res, 400, { ok: false, error: HOOK_CHANNEL_ERROR });
|
||||
sendJson(res, 400, { ok: false, error: getHookChannelError() });
|
||||
return true;
|
||||
}
|
||||
const runId = dispatchAgentHook({
|
||||
|
||||
@@ -59,9 +59,10 @@ const BASE_METHODS = [
|
||||
"chat.send",
|
||||
];
|
||||
|
||||
const CHANNEL_METHODS = listChannelPlugins().flatMap((plugin) => plugin.gatewayMethods ?? []);
|
||||
|
||||
export const GATEWAY_METHODS = Array.from(new Set([...BASE_METHODS, ...CHANNEL_METHODS]));
|
||||
export function listGatewayMethods(): string[] {
|
||||
const channelMethods = listChannelPlugins().flatMap((plugin) => plugin.gatewayMethods ?? []);
|
||||
return Array.from(new Set([...BASE_METHODS, ...channelMethods]));
|
||||
}
|
||||
|
||||
export const GATEWAY_EVENTS = [
|
||||
"agent",
|
||||
|
||||
@@ -73,6 +73,11 @@ export const configHandlers: GatewayRequestHandlers = {
|
||||
description: plugin.description,
|
||||
configUiHints: plugin.configUiHints,
|
||||
})),
|
||||
channels: pluginRegistry.channels.map((entry) => ({
|
||||
id: entry.plugin.id,
|
||||
label: entry.plugin.meta.label,
|
||||
description: entry.plugin.meta.blurb,
|
||||
})),
|
||||
});
|
||||
respond(true, schema, undefined);
|
||||
},
|
||||
|
||||
@@ -38,7 +38,7 @@ import { buildGatewayCronService } from "./server-cron.js";
|
||||
import { applyGatewayLaneConcurrency } from "./server-lanes.js";
|
||||
import { startGatewayMaintenanceTimers } from "./server-maintenance.js";
|
||||
import { coreGatewayHandlers } from "./server-methods.js";
|
||||
import { GATEWAY_EVENTS, GATEWAY_METHODS } from "./server-methods-list.js";
|
||||
import { GATEWAY_EVENTS, listGatewayMethods } from "./server-methods-list.js";
|
||||
import { hasConnectedMobileNode as hasConnectedMobileNodeFromBridge } from "./server-mobile-nodes.js";
|
||||
import { loadGatewayModelCatalog } from "./server-model-catalog.js";
|
||||
import { loadGatewayPlugins } from "./server-plugins.js";
|
||||
@@ -69,14 +69,6 @@ const logReload = log.child("reload");
|
||||
const logHooks = log.child("hooks");
|
||||
const logWsControl = log.child("ws");
|
||||
const canvasRuntime = runtimeForLogger(logCanvas);
|
||||
const channelLogs = Object.fromEntries(
|
||||
listChannelPlugins().map((plugin) => [plugin.id, logChannels.child(plugin.id)]),
|
||||
) as Record<ChannelId, ReturnType<typeof createSubsystemLogger>>;
|
||||
const channelRuntimeEnvs = Object.fromEntries(
|
||||
Object.entries(channelLogs).map(([id, logger]) => [id, runtimeForLogger(logger)]),
|
||||
) as Record<ChannelId, RuntimeEnv>;
|
||||
|
||||
const METHODS = GATEWAY_METHODS;
|
||||
|
||||
export type GatewayServer = {
|
||||
close: (opts?: { reason?: string; restartExpectedMs?: number | null }) => Promise<void>;
|
||||
@@ -163,13 +155,22 @@ export async function startGatewayServer(
|
||||
await autoMigrateLegacyState({ cfg: cfgAtStart, log });
|
||||
const defaultAgentId = resolveDefaultAgentId(cfgAtStart);
|
||||
const defaultWorkspaceDir = resolveAgentWorkspaceDir(cfgAtStart, defaultAgentId);
|
||||
const { pluginRegistry, gatewayMethods } = loadGatewayPlugins({
|
||||
const baseMethods = listGatewayMethods();
|
||||
const { pluginRegistry, gatewayMethods: baseGatewayMethods } = loadGatewayPlugins({
|
||||
cfg: cfgAtStart,
|
||||
workspaceDir: defaultWorkspaceDir,
|
||||
log,
|
||||
coreGatewayHandlers,
|
||||
baseMethods: METHODS,
|
||||
baseMethods,
|
||||
});
|
||||
const channelLogs = Object.fromEntries(
|
||||
listChannelPlugins().map((plugin) => [plugin.id, logChannels.child(plugin.id)]),
|
||||
) as Record<ChannelId, ReturnType<typeof createSubsystemLogger>>;
|
||||
const channelRuntimeEnvs = Object.fromEntries(
|
||||
Object.entries(channelLogs).map(([id, logger]) => [id, runtimeForLogger(logger)]),
|
||||
) as Record<ChannelId, RuntimeEnv>;
|
||||
const channelMethods = listChannelPlugins().flatMap((plugin) => plugin.gatewayMethods ?? []);
|
||||
const gatewayMethods = Array.from(new Set([...baseGatewayMethods, ...channelMethods]));
|
||||
let pluginServices: PluginServicesHandle | null = null;
|
||||
const runtimeConfig = await resolveGatewayRuntimeConfig({
|
||||
cfg: cfgAtStart,
|
||||
|
||||
Reference in New Issue
Block a user