From 2e189b6f9ed79a22a90d369c94c4ce7e5e1a57f3 Mon Sep 17 00:00:00 2001 From: can1357 Date: Wed, 8 Jul 2026 16:52:28 +0200 Subject: [PATCH] test: aligned full suite with merged sweep contracts - container stubs gained disposeChildren for the stale-renderer teardown paths - login-stored API key assertions include the new source provenance field - bash timeout test covers the zero-disable contract alongside the clamp - skill keyword steering activates a task tool for the gated workflow notice --- .../ai/test/auth-storage-email-dedupe.test.ts | 4 ++-- packages/ai/test/openrouter-login.test.ts | 2 +- .../test/agent-session-skill-keywords.test.ts | 15 +++++++++++++-- .../test/event-controller-error-banner.test.ts | 3 ++- .../event-controller-loader-recovery.test.ts | 3 +++ .../event-controller-superseded-agent-end.test.ts | 2 +- .../modes/controllers/handoff-command.test.ts | 3 +++ .../modes/utils/render-initial-messages.test.ts | 2 +- .../test/tools/schema-validation.test.ts | 7 ++++--- 9 files changed, 30 insertions(+), 11 deletions(-) diff --git a/packages/ai/test/auth-storage-email-dedupe.test.ts b/packages/ai/test/auth-storage-email-dedupe.test.ts index b98b00c08..eb846c3a2 100644 --- a/packages/ai/test/auth-storage-email-dedupe.test.ts +++ b/packages/ai/test/auth-storage-email-dedupe.test.ts @@ -765,8 +765,8 @@ describe("AuthStorage OAuth login upgrade and multi-account coexistence", () => }); expect(authStorage.listStoredCredentials("nvidia").map(entry => entry.credential)).toEqual([ - { type: "api_key", key: "nvapi-first" }, - { type: "api_key", key: "nvapi-second" }, + { type: "api_key", key: "nvapi-first", source: "login" }, + { type: "api_key", key: "nvapi-second", source: "login" }, ]); const selectedKeys = new Set(); diff --git a/packages/ai/test/openrouter-login.test.ts b/packages/ai/test/openrouter-login.test.ts index 9b051f56e..bfe00a647 100644 --- a/packages/ai/test/openrouter-login.test.ts +++ b/packages/ai/test/openrouter-login.test.ts @@ -55,7 +55,7 @@ describe("openrouter login wiring", () => { }); const credential = await storage.get("openrouter"); - expect(credential).toEqual({ type: "api_key", key: "sk-or-validated" }); + expect(credential).toEqual({ type: "api_key", key: "sk-or-validated", source: "login" }); const authCall = fetchCalls.find(call => call.url.includes("/api/v1/auth/key")); expect(authCall).toBeDefined(); diff --git a/packages/coding-agent/test/agent-session-skill-keywords.test.ts b/packages/coding-agent/test/agent-session-skill-keywords.test.ts index 895b4d1d6..b07486ae7 100644 --- a/packages/coding-agent/test/agent-session-skill-keywords.test.ts +++ b/packages/coding-agent/test/agent-session-skill-keywords.test.ts @@ -1,6 +1,6 @@ import { afterEach, beforeEach, describe, expect, it } from "bun:test"; import * as path from "node:path"; -import { Agent } from "@oh-my-pi/pi-agent-core"; +import { Agent, type AgentTool } from "@oh-my-pi/pi-agent-core"; import type { TextContent } from "@oh-my-pi/pi-ai"; import { AssistantMessageEventStream } from "@oh-my-pi/pi-ai/utils/event-stream"; import { getBundledModel } from "@oh-my-pi/pi-catalog/models"; @@ -17,11 +17,22 @@ import { import { SessionManager } from "@oh-my-pi/pi-coding-agent/session/session-manager"; import { TempDir } from "@oh-my-pi/pi-utils"; import { createAssistantMessage } from "./helpers/agent-session-setup"; +import { type } from "arktype"; type ObservedSkillTurn = { texts: string[]; }; +// 4644 gates the workflowz notice on an active `task` tool; keep one active so +// keyword steering exercises the notice path. +const mockTaskTool: AgentTool = { + name: "task", + label: "Task", + description: "Mock task tool", + parameters: type({}), + execute: async () => ({ content: [{ type: "text" as const, text: "ok" }] }), +}; + describe("AgentSession skill prompt keyword steering", () => { let tempDir: TempDir; let authStorage: AuthStorage | undefined; @@ -43,7 +54,7 @@ describe("AgentSession skill prompt keyword steering", () => { initialState: { model, systemPrompt: ["Test"], - tools: [], + tools: [mockTaskTool], messages: [], }, convertToLlm, diff --git a/packages/coding-agent/test/event-controller-error-banner.test.ts b/packages/coding-agent/test/event-controller-error-banner.test.ts index a705f3342..e12980e7e 100644 --- a/packages/coding-agent/test/event-controller-error-banner.test.ts +++ b/packages/coding-agent/test/event-controller-error-banner.test.ts @@ -67,6 +67,7 @@ function createFixture(streamingMessage?: AssistantMessage) { const clearPinnedError = vi.fn(); const statusContainer = { clear: vi.fn(), + disposeChildren: vi.fn(), addChild: vi.fn(), }; @@ -283,7 +284,7 @@ describe("EventController working loader reconciliation", () => { } as Extract); expect(loader?.stop).toHaveBeenCalledTimes(1); - expect(ctx.statusContainer.clear).toHaveBeenCalledTimes(1); + expect(ctx.statusContainer.disposeChildren).toHaveBeenCalledTimes(1); expect(ctx.flushCompactionQueue).toHaveBeenCalledWith({ willRetry: false }); expect(ctx.ensureLoadingAnimation).toHaveBeenCalledTimes(1); }); diff --git a/packages/coding-agent/test/modes/controllers/event-controller-loader-recovery.test.ts b/packages/coding-agent/test/modes/controllers/event-controller-loader-recovery.test.ts index b5e1b1109..1db01437f 100644 --- a/packages/coding-agent/test/modes/controllers/event-controller-loader-recovery.test.ts +++ b/packages/coding-agent/test/modes/controllers/event-controller-loader-recovery.test.ts @@ -32,6 +32,9 @@ function createContext(options: { terminalProgress?: boolean } = {}) { clear() { children.length = 0; }, + disposeChildren() { + children.length = 0; + }, addChild(child: unknown) { children.push(child); }, diff --git a/packages/coding-agent/test/modes/controllers/event-controller-superseded-agent-end.test.ts b/packages/coding-agent/test/modes/controllers/event-controller-superseded-agent-end.test.ts index ee21ff80a..0dc1867d4 100644 --- a/packages/coding-agent/test/modes/controllers/event-controller-superseded-agent-end.test.ts +++ b/packages/coding-agent/test/modes/controllers/event-controller-superseded-agent-end.test.ts @@ -27,7 +27,7 @@ function createContext() { retryLoader: undefined, streamingComponent: undefined, streamingMessage: undefined, - statusContainer: { clear: vi.fn() }, + statusContainer: { clear: vi.fn(), disposeChildren: vi.fn() }, chatContainer: { removeChild: vi.fn() }, flushPendingModelSwitch: vi.fn(async () => {}), editor: { getText: () => "" }, diff --git a/packages/coding-agent/test/modes/controllers/handoff-command.test.ts b/packages/coding-agent/test/modes/controllers/handoff-command.test.ts index e43113e54..94372ba62 100644 --- a/packages/coding-agent/test/modes/controllers/handoff-command.test.ts +++ b/packages/coding-agent/test/modes/controllers/handoff-command.test.ts @@ -12,6 +12,9 @@ function createContainer() { clear() { this.children = []; }, + disposeChildren() { + this.children = []; + }, }; } diff --git a/packages/coding-agent/test/modes/utils/render-initial-messages.test.ts b/packages/coding-agent/test/modes/utils/render-initial-messages.test.ts index e0a5e31af..03f64ac3d 100644 --- a/packages/coding-agent/test/modes/utils/render-initial-messages.test.ts +++ b/packages/coding-agent/test/modes/utils/render-initial-messages.test.ts @@ -62,7 +62,7 @@ function makeCtx(): { const ctx = { chatContainer: { clear: vi.fn(), addChild: vi.fn() }, - pendingMessagesContainer: { clear: vi.fn() }, + pendingMessagesContainer: { clear: vi.fn(), disposeChildren: vi.fn() }, pendingBashComponents: [], pendingPythonComponents: [], session: { buildTranscriptSessionContext: transcriptSpy }, diff --git a/packages/coding-agent/test/tools/schema-validation.test.ts b/packages/coding-agent/test/tools/schema-validation.test.ts index 231a0a0b4..6115eee3b 100644 --- a/packages/coding-agent/test/tools/schema-validation.test.ts +++ b/packages/coding-agent/test/tools/schema-validation.test.ts @@ -288,7 +288,7 @@ describe("tool schema validation (post-sanitization)", () => { expect(description).toContain("pr://123"); }); - it("bash schema and prompt advertise the timeout clamp", async () => { + it("bash schema and prompt advertise the timeout clamp and zero-disable", async () => { const session = createTestSession(); session.settings.set("async.enabled", true); const tools = await createTools(session); @@ -302,8 +302,9 @@ describe("tool schema validation (post-sanitization)", () => { expect(timeoutDescription).toContain("clamped"); expect(timeoutDescription).toContain("1-3600"); - expect(bashTool.description).toContain("clamped to `1..3600`"); - expect(bashTool.description).toContain("does NOT extend the timeout"); + expect(timeoutDescription).toContain("0 disables the command deadline"); + expect(bashTool.description).toContain("nonzero values are clamped to `1..3600`"); + expect(bashTool.description).toContain("does NOT extend a nonzero timeout"); }); it("hidden tools also have valid sanitized schemas", async () => {