mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 13:21:25 +00:00
refactor(gateway): split server runtime
This commit is contained in:
136
src/gateway/server-startup.ts
Normal file
136
src/gateway/server-startup.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "../agents/defaults.js";
|
||||
import { loadModelCatalog } from "../agents/model-catalog.js";
|
||||
import {
|
||||
getModelRefStatus,
|
||||
resolveConfiguredModelRef,
|
||||
resolveHooksGmailModel,
|
||||
} from "../agents/model-selection.js";
|
||||
import type { CliDeps } from "../cli/deps.js";
|
||||
import type { loadConfig } from "../config/config.js";
|
||||
import { startGmailWatcher } from "../hooks/gmail-watcher.js";
|
||||
import type { loadClawdbotPlugins } from "../plugins/loader.js";
|
||||
import {
|
||||
type PluginServicesHandle,
|
||||
startPluginServices,
|
||||
} from "../plugins/services.js";
|
||||
import { startBrowserControlServerIfEnabled } from "./server-browser.js";
|
||||
import {
|
||||
scheduleRestartSentinelWake,
|
||||
shouldWakeFromRestartSentinel,
|
||||
} from "./server-restart-sentinel.js";
|
||||
|
||||
export async function startGatewaySidecars(params: {
|
||||
cfg: ReturnType<typeof loadConfig>;
|
||||
pluginRegistry: ReturnType<typeof loadClawdbotPlugins>;
|
||||
defaultWorkspaceDir: string;
|
||||
deps: CliDeps;
|
||||
startChannels: () => Promise<void>;
|
||||
log: { warn: (msg: string) => void };
|
||||
logHooks: {
|
||||
info: (msg: string) => void;
|
||||
warn: (msg: string) => void;
|
||||
error: (msg: string) => void;
|
||||
};
|
||||
logChannels: { info: (msg: string) => void; error: (msg: string) => void };
|
||||
logBrowser: { error: (msg: string) => void };
|
||||
}) {
|
||||
// Start clawd browser control server (unless disabled via config).
|
||||
let browserControl: Awaited<
|
||||
ReturnType<typeof startBrowserControlServerIfEnabled>
|
||||
> = null;
|
||||
try {
|
||||
browserControl = await startBrowserControlServerIfEnabled();
|
||||
} catch (err) {
|
||||
params.logBrowser.error(`server failed to start: ${String(err)}`);
|
||||
}
|
||||
|
||||
// Start Gmail watcher if configured (hooks.gmail.account).
|
||||
if (process.env.CLAWDBOT_SKIP_GMAIL_WATCHER !== "1") {
|
||||
try {
|
||||
const gmailResult = await startGmailWatcher(params.cfg);
|
||||
if (gmailResult.started) {
|
||||
params.logHooks.info("gmail watcher started");
|
||||
} else if (
|
||||
gmailResult.reason &&
|
||||
gmailResult.reason !== "hooks not enabled" &&
|
||||
gmailResult.reason !== "no gmail account configured"
|
||||
) {
|
||||
params.logHooks.warn(
|
||||
`gmail watcher not started: ${gmailResult.reason}`,
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
params.logHooks.error(`gmail watcher failed to start: ${String(err)}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Validate hooks.gmail.model if configured.
|
||||
if (params.cfg.hooks?.gmail?.model) {
|
||||
const hooksModelRef = resolveHooksGmailModel({
|
||||
cfg: params.cfg,
|
||||
defaultProvider: DEFAULT_PROVIDER,
|
||||
});
|
||||
if (hooksModelRef) {
|
||||
const { provider: defaultProvider, model: defaultModel } =
|
||||
resolveConfiguredModelRef({
|
||||
cfg: params.cfg,
|
||||
defaultProvider: DEFAULT_PROVIDER,
|
||||
defaultModel: DEFAULT_MODEL,
|
||||
});
|
||||
const catalog = await loadModelCatalog({ config: params.cfg });
|
||||
const status = getModelRefStatus({
|
||||
cfg: params.cfg,
|
||||
catalog,
|
||||
ref: hooksModelRef,
|
||||
defaultProvider,
|
||||
defaultModel,
|
||||
});
|
||||
if (!status.allowed) {
|
||||
params.logHooks.warn(
|
||||
`hooks.gmail.model "${status.key}" not in agents.defaults.models allowlist (will use primary instead)`,
|
||||
);
|
||||
}
|
||||
if (!status.inCatalog) {
|
||||
params.logHooks.warn(
|
||||
`hooks.gmail.model "${status.key}" not in the model catalog (may fail at runtime)`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Launch configured channels so gateway replies via the surface the message came from.
|
||||
// Tests can opt out via CLAWDBOT_SKIP_CHANNELS (or legacy CLAWDBOT_SKIP_PROVIDERS).
|
||||
const skipChannels =
|
||||
process.env.CLAWDBOT_SKIP_CHANNELS === "1" ||
|
||||
process.env.CLAWDBOT_SKIP_PROVIDERS === "1";
|
||||
if (!skipChannels) {
|
||||
try {
|
||||
await params.startChannels();
|
||||
} catch (err) {
|
||||
params.logChannels.error(`channel startup failed: ${String(err)}`);
|
||||
}
|
||||
} else {
|
||||
params.logChannels.info(
|
||||
"skipping channel start (CLAWDBOT_SKIP_CHANNELS=1 or CLAWDBOT_SKIP_PROVIDERS=1)",
|
||||
);
|
||||
}
|
||||
|
||||
let pluginServices: PluginServicesHandle | null = null;
|
||||
try {
|
||||
pluginServices = await startPluginServices({
|
||||
registry: params.pluginRegistry,
|
||||
config: params.cfg,
|
||||
workspaceDir: params.defaultWorkspaceDir,
|
||||
});
|
||||
} catch (err) {
|
||||
params.log.warn(`plugin services failed to start: ${String(err)}`);
|
||||
}
|
||||
|
||||
if (shouldWakeFromRestartSentinel()) {
|
||||
setTimeout(() => {
|
||||
void scheduleRestartSentinelWake({ deps: params.deps });
|
||||
}, 750);
|
||||
}
|
||||
|
||||
return { browserControl, pluginServices };
|
||||
}
|
||||
Reference in New Issue
Block a user