






















@@ -27,6 +27,16 @@ const hoisted = vi.hoisted(() => {
2727resolved: 0,
2828failed: 0,
2929}));
30+const resolveAgentModelPrimaryValue = vi.fn(() => "");
31+const normalizeProviderId = vi.fn((provider: string) => provider.toLowerCase());
32+const resolveOpenClawAgentDir = vi.fn(() => "/tmp/openclaw-state/agents/default/agent");
33+const isCliProvider = vi.fn(() => false);
34+const resolveConfiguredModelRef = vi.fn(() => ({
35+provider: "openai",
36+model: "gpt-5.4",
37+}));
38+const resolveEmbeddedAgentRuntime = vi.fn(() => "pi");
39+const ensureOpenClawModelsJson = vi.fn(async () => undefined);
3040return {
3141 startPluginServices,
3242 startGmailWatcherWithLogs,
@@ -46,6 +56,13 @@ const hoisted = vi.hoisted(() => {
4656 refreshLatestUpdateRestartSentinel,
4757 getAcpRuntimeBackend,
4858 reconcilePendingSessionIdentities,
59+ resolveAgentModelPrimaryValue,
60+ normalizeProviderId,
61+ resolveOpenClawAgentDir,
62+ isCliProvider,
63+ resolveConfiguredModelRef,
64+ resolveEmbeddedAgentRuntime,
65+ ensureOpenClawModelsJson,
4966};
5067});
5168@@ -123,6 +140,36 @@ vi.mock("../infra/update-startup.js", () => ({
123140scheduleGatewayUpdateCheck: hoisted.scheduleGatewayUpdateCheck,
124141}));
125142143+vi.mock("../config/model-input.js", () => ({
144+resolveAgentModelPrimaryValue: hoisted.resolveAgentModelPrimaryValue,
145+}));
146+147+vi.mock("../agents/provider-id.js", () => ({
148+normalizeProviderId: hoisted.normalizeProviderId,
149+}));
150+151+vi.mock("../agents/agent-paths.js", () => ({
152+resolveOpenClawAgentDir: hoisted.resolveOpenClawAgentDir,
153+}));
154+155+vi.mock("../agents/defaults.js", () => ({
156+DEFAULT_MODEL: "gpt-5.4",
157+DEFAULT_PROVIDER: "openai",
158+}));
159+160+vi.mock("../agents/model-selection.js", () => ({
161+isCliProvider: hoisted.isCliProvider,
162+resolveConfiguredModelRef: hoisted.resolveConfiguredModelRef,
163+}));
164+165+vi.mock("../agents/pi-embedded-runner/runtime.js", () => ({
166+resolveEmbeddedAgentRuntime: hoisted.resolveEmbeddedAgentRuntime,
167+}));
168+169+vi.mock("../agents/models-config.js", () => ({
170+ensureOpenClawModelsJson: hoisted.ensureOpenClawModelsJson,
171+}));
172+126173vi.mock("./server-tailscale.js", () => ({
127174startGatewayTailscaleExposure: hoisted.startGatewayTailscaleExposure,
128175}));
@@ -155,6 +202,17 @@ describe("startGatewayPostAttachRuntime", () => {
155202hoisted.getAcpRuntimeBackend.mockReset();
156203hoisted.getAcpRuntimeBackend.mockReturnValue(null);
157204hoisted.reconcilePendingSessionIdentities.mockClear();
205+hoisted.resolveAgentModelPrimaryValue.mockReset();
206+hoisted.resolveAgentModelPrimaryValue.mockReturnValue("");
207+hoisted.normalizeProviderId.mockClear();
208+hoisted.resolveOpenClawAgentDir.mockClear();
209+hoisted.isCliProvider.mockReset();
210+hoisted.isCliProvider.mockReturnValue(false);
211+hoisted.resolveConfiguredModelRef.mockClear();
212+hoisted.resolveEmbeddedAgentRuntime.mockReset();
213+hoisted.resolveEmbeddedAgentRuntime.mockReturnValue("pi");
214+hoisted.ensureOpenClawModelsJson.mockReset();
215+hoisted.ensureOpenClawModelsJson.mockResolvedValue(undefined);
158216});
159217160218it("re-enables startup-gated methods after post-attach sidecars start", async () => {
@@ -247,13 +305,58 @@ describe("startGatewayPostAttachRuntime", () => {
247305248306expect(prewarm).toHaveBeenCalledTimes(1);
249307expect(log.warn).toHaveBeenCalledWith(
250-"startup model warmup timed out after 25ms; continuing channel startup",
308+"startup model warmup timed out after 25ms; continuing without waiting",
251309);
252310} finally {
253311vi.useRealTimers();
254312}
255313});
256314315+it("starts channels without waiting for primary model prewarm completion", async () => {
316+hoisted.resolveAgentModelPrimaryValue.mockReturnValue("openai/gpt-5.4");
317+let resolvePrewarm!: () => void;
318+hoisted.ensureOpenClawModelsJson.mockImplementation(
319+async () =>
320+await new Promise<undefined>((resolve) => {
321+resolvePrewarm = () => resolve(undefined);
322+}),
323+);
324+const startChannels = vi.fn(async () => undefined);
325+326+const sidecarsPromise = startGatewaySidecars({
327+cfg: {
328+hooks: { internal: { enabled: false } },
329+agents: { defaults: { model: "openai/gpt-5.4" } },
330+} as never,
331+pluginRegistry: createPostAttachParams().pluginRegistry,
332+defaultWorkspaceDir: "/tmp/openclaw-workspace",
333+deps: {} as never,
334+ startChannels,
335+log: { warn: vi.fn() },
336+logHooks: {
337+info: vi.fn(),
338+warn: vi.fn(),
339+error: vi.fn(),
340+},
341+logChannels: {
342+info: vi.fn(),
343+error: vi.fn(),
344+},
345+});
346+347+await vi.waitFor(
348+() => {
349+expect(hoisted.ensureOpenClawModelsJson).toHaveBeenCalledTimes(1);
350+expect(startChannels).toHaveBeenCalledTimes(1);
351+},
352+{ timeout: 250 },
353+);
354+await sidecarsPromise;
355+356+resolvePrewarm();
357+await Promise.resolve();
358+});
359+257360it("keeps startup-gated methods unavailable while sidecars are still resuming", async () => {
258361let resumeSidecars!: () => void;
259362const sidecarsReady = new Promise<{ pluginServices: null }>((resolve) => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。