


















@@ -341,6 +341,82 @@ describe("before_agent_run invalid ask outcome", () => {
341341});
342342});
343343344+describe("before_agent_start hook default timeout (#48534)", () => {
345+afterEach(() => {
346+vi.useRealTimers();
347+});
348+349+it("fails open with a warning when a handler exceeds the default 15s budget", async () => {
350+vi.useFakeTimers();
351+const errors: string[] = [];
352+const logger = {
353+debug: () => {},
354+info: () => {},
355+warn: () => {},
356+error: (msg: string) => {
357+errors.push(msg);
358+},
359+};
360+const registry = makeRegistry([
361+{
362+pluginId: "hanging-plugin",
363+hookName: "before_agent_start",
364+handler: () => new Promise<never>(() => {}),
365+source: "test",
366+},
367+]);
368+const runner = createHookRunner(registry, { logger });
369+const resultPromise = runner.runBeforeAgentStart({ prompt: "hello" }, ctx);
370+371+await vi.advanceTimersByTimeAsync(15_000);
372+const result = await resultPromise;
373+374+// Fail-open: a hung handler must not block the run, and the runner
375+// returns undefined so the embedded setup path proceeds without hook
376+// modifications. The hook-runner logs the timeout for operator triage.
377+expect(result).toBeUndefined();
378+expect(errors).toContain(
379+"[hooks] before_agent_start handler from hanging-plugin failed: timed out after 15000ms",
380+);
381+});
382+383+it("does not block when one handler hangs and a second is registered", async () => {
384+vi.useFakeTimers();
385+const errors: string[] = [];
386+const logger = {
387+debug: () => {},
388+info: () => {},
389+warn: () => {},
390+error: (msg: string) => {
391+errors.push(msg);
392+},
393+};
394+const registry = makeRegistry([
395+{
396+pluginId: "hanging-plugin",
397+hookName: "before_agent_start",
398+priority: 100,
399+handler: () => new Promise<never>(() => {}),
400+source: "test",
401+},
402+{
403+pluginId: "fast-plugin",
404+hookName: "before_agent_start",
405+priority: 50,
406+handler: async () => ({ modelOverride: "fallback-model" }),
407+source: "test",
408+},
409+]);
410+const runner = createHookRunner(registry, { logger });
411+const resultPromise = runner.runBeforeAgentStart({ prompt: "hello" }, ctx);
412+await vi.advanceTimersByTimeAsync(15_000);
413+const result = await resultPromise;
414+415+expect(result?.modelOverride).toBe("fallback-model");
416+expect(errors.some((msg) => msg.includes("hanging-plugin"))).toBe(true);
417+});
418+});
419+344420describe("before_tool_call channelId forwarding", () => {
345421it("passes channelId through to before_tool_call handlers", async () => {
346422let receivedCtx: unknown;
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。