Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  slash-command-executor.node.test.ts

  Sprache: JAVA
 

Spracherkennung für: .ts vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

// @vitest-environment node
import { describe, expect, it, vi } from "vitest";
import {
  createResolvedModelPatch,
  createModelCatalog,
  DEEPSEEK_CHAT_MODEL,
  OPENAI_GPT5_MINI_MODEL,
} from "../chat-model.test-helpers.ts";
import type { GatewayBrowserClient } from "../gateway.ts";
import type { GatewaySessionRow, SessionsListResult } from "../types.ts";
import { executeSlashCommand } from "./slash-command-executor.ts";

function row(key: string, overrides?: Partial<GatewaySessionRow>): GatewaySessionRow {
  return {
    key,
    spawnedBy: overrides?.spawnedBy,
    kind: "direct",
    updatedAt: null,
    ...overrides,
  };
}

describe("executeSlashCommand /kill", () => {
  it("aborts every sub-agent session for /kill all", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.list") {
        return {
          sessions: [
            row("main"),
            row("agent:main:subagent:one", { spawnedBy: "main" }),
            row("agent:main:subagent:parent", { spawnedBy: "main" }),
            row("agent:main:subagent:parent:subagent:child", {
              spawnedBy: "agent:main:subagent:parent",
            }),
            row("agent:other:main"),
          ],
        };
      }
      if (method === "chat.abort") {
        return { ok: true, aborted: true };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "kill",
      "all",
    );

    expect(result.content).toBe("Aborted 3 sub-agent sessions.");
    expect(request).toHaveBeenNthCalledWith(1, "sessions.list", {});
    expect(request).toHaveBeenNthCalledWith(2, "chat.abort", {
      sessionKey: "agent:main:subagent:one",
    });
    expect(request).toHaveBeenNthCalledWith(3, "chat.abort", {
      sessionKey: "agent:main:subagent:parent",
    });
    expect(request).toHaveBeenNthCalledWith(4, "chat.abort", {
      sessionKey: "agent:main:subagent:parent:subagent:child",
    });
  });

  it("aborts matching sub-agent sessions for /kill <agentId>", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.list") {
        return {
          sessions: [
            row("agent:main:subagent:one", { spawnedBy: "agent:main:main" }),
            row("agent:main:subagent:two", { spawnedBy: "agent:main:main" }),
            row("agent:other:subagent:three", { spawnedBy: "agent:other:main" }),
          ],
        };
      }
      if (method === "chat.abort") {
        return { ok: true, aborted: true };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "kill",
      "main",
    );

    expect(result.content).toBe("Aborted 2 matching sub-agent sessions for `main`.");
    expect(request).toHaveBeenNthCalledWith(1, "sessions.list", {});
    expect(request).toHaveBeenNthCalledWith(2, "chat.abort", {
      sessionKey: "agent:main:subagent:one",
    });
    expect(request).toHaveBeenNthCalledWith(3, "chat.abort", {
      sessionKey: "agent:main:subagent:two",
    });
  });

  it("does not exact-match a session key outside the current subagent subtree", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.list") {
        return {
          sessions: [
            row("agent:main:subagent:parent", { spawnedBy: "agent:main:main" }),
            row("agent:main:subagent:parent:subagent:child", {
              spawnedBy: "agent:main:subagent:parent",
            }),
            row("agent:main:subagent:sibling", { spawnedBy: "agent:main:main" }),
          ],
        };
      }
      if (method === "chat.abort") {
        return { ok: true, aborted: true };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:subagent:parent",
      "kill",
      "agent:main:subagent:sibling",
    );

    expect(result.content).toBe(
      "No matching sub-agent sessions found for `agent:main:subagent:sibling`.",
    );
    expect(request).toHaveBeenCalledTimes(1);
    expect(request).toHaveBeenNthCalledWith(1, "sessions.list", {});
  });

  it("returns a no-op summary when matching sessions have no active runs", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.list") {
        return {
          sessions: [
            row("agent:main:subagent:one", { spawnedBy: "agent:main:main" }),
            row("agent:main:subagent:two", { spawnedBy: "agent:main:main" }),
          ],
        };
      }
      if (method === "chat.abort") {
        return { ok: true, aborted: false };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "kill",
      "all",
    );

    expect(result.content).toBe("No active sub-agent runs to abort.");
    expect(request).toHaveBeenNthCalledWith(1, "sessions.list", {});
    expect(request).toHaveBeenNthCalledWith(2, "chat.abort", {
      sessionKey: "agent:main:subagent:one",
    });
    expect(request).toHaveBeenNthCalledWith(3, "chat.abort", {
      sessionKey: "agent:main:subagent:two",
    });
  });

  it("treats the legacy main session key as the default agent scope", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.list") {
        return {
          sessions: [
            row("main"),
            row("agent:main:subagent:one", { spawnedBy: "agent:main:main" }),
            row("agent:main:subagent:two", { spawnedBy: "agent:main:main" }),
            row("agent:other:subagent:three", { spawnedBy: "agent:other:main" }),
          ],
        };
      }
      if (method === "chat.abort") {
        return { ok: true, aborted: true };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "main",
      "kill",
      "all",
    );

    expect(result.content).toBe("Aborted 2 sub-agent sessions.");
    expect(request).toHaveBeenNthCalledWith(1, "sessions.list", {});
    expect(request).toHaveBeenNthCalledWith(2, "chat.abort", {
      sessionKey: "agent:main:subagent:one",
    });
    expect(request).toHaveBeenNthCalledWith(3, "chat.abort", {
      sessionKey: "agent:main:subagent:two",
    });
  });

  it("does not abort unrelated same-agent subagents from another root session", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.list") {
        return {
          sessions: [
            row("agent:main:main"),
            row("agent:main:subagent:mine", { spawnedBy: "agent:main:main" }),
            row("agent:main:subagent:mine:subagent:child", {
              spawnedBy: "agent:main:subagent:mine",
            }),
            row("agent:main:subagent:other-root", {
              spawnedBy: "agent:main:quietchat:dm:alice",
            }),
          ],
        };
      }
      if (method === "chat.abort") {
        return { ok: true, aborted: true };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "kill",
      "all",
    );

    expect(result.content).toBe("Aborted 2 sub-agent sessions.");
    expect(request).toHaveBeenNthCalledWith(1, "sessions.list", {});
    expect(request).toHaveBeenNthCalledWith(2, "chat.abort", {
      sessionKey: "agent:main:subagent:mine",
    });
    expect(request).toHaveBeenNthCalledWith(3, "chat.abort", {
      sessionKey: "agent:main:subagent:mine:subagent:child",
    });
  });
});

describe("executeSlashCommand directives", () => {
  it("resolves the legacy main alias for bare /model", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.list") {
        return {
          defaults: { modelProvider: "openai", model: "default-model" },
          sessions: [
            row("agent:main:main", {
              model: "gpt-4.1-mini",
            }),
          ],
        };
      }
      if (method === "models.list") {
        return {
          models: [{ id: "gpt-4.1-mini" }, { id: "gpt-4.1" }],
        };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "main",
      "model",
      "",
    );

    expect(result.content).toBe(
      "**Current model:** `gpt-4.1-mini`\n**Available:** `gpt-4.1-mini`, `gpt-4.1`",
    );
    expect(request).toHaveBeenNthCalledWith(1, "sessions.list", {});
    expect(request).toHaveBeenNthCalledWith(2, "models.list", {});
  });

  it("mirrors resolved provider-qualified model refs after /model changes", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.patch") {
        return createResolvedModelPatch("gpt-5-mini", "openai");
      }
      if (method === "models.list") {
        return { models: createModelCatalog(OPENAI_GPT5_MINI_MODEL) };
      }
      if (method === "models.list") {
        return { models: [{ id: "gpt-5-mini", name: "gpt-5-mini", provider: "openai" }] };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "main",
      "model",
      "gpt-5-mini",
      {
        chatModelCatalog: [{ id: "gpt-5-mini", name: "gpt-5-mini", provider: "openai" }],
      },
    );

    expect(request).toHaveBeenCalledWith("sessions.patch", {
      key: "main",
      model: "gpt-5-mini",
    });
    expect(result.sessionPatch?.modelOverride).toEqual({
      kind: "qualified",
      value: "openai/gpt-5-mini",
    });
  });

  it("uses the local model catalog to qualify raw /model overrides when the patch response omits provider", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.patch") {
        return {
          ok: true,
          key: "main",
          resolved: {
            model: "gpt-5-mini",
          },
        };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "main",
      "model",
      "gpt-5-mini",
      {
        chatModelCatalog: [{ id: "gpt-5-mini", name: "GPT-5 Mini", provider: "openai" }],
      },
    );

    expect(result.sessionPatch?.modelOverride).toEqual({
      kind: "qualified",
      value: "openai/gpt-5-mini",
    });
  });

  it("corrects stale patched providers with the catalog after /model", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.patch") {
        return createResolvedModelPatch("deepseek-chat", "zai");
      }
      if (method === "models.list") {
        return { models: createModelCatalog(DEEPSEEK_CHAT_MODEL) };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "main",
      "model",
      "deepseek-chat",
    );

    expect(result.sessionPatch?.modelOverride).toEqual({
      kind: "qualified",
      value: "deepseek/deepseek-chat",
    });
  });

  it("keeps openrouter-prefixed refs when patched model ids include slashes", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.patch") {
        return createResolvedModelPatch("google/gemma-4-26b-a4b-it", "openrouter");
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "main",
      "model",
      "google/gemma-4-26b-a4b-it",
      {
        chatModelCatalog: [
          {
            id: "google/gemma-4-26b-a4b-it",
            name: "Gemma 4 26B",
            provider: "openrouter",
          },
        ],
      },
    );

    expect(result.sessionPatch?.modelOverride).toEqual({
      kind: "qualified",
      value: "openrouter/google/gemma-4-26b-a4b-it",
    });
    expect(request).toHaveBeenCalledTimes(1);
  });

  it("falls back to the patched server provider when catalog lookup fails", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.patch") {
        return createResolvedModelPatch("gpt-5-mini", "openai");
      }
      if (method === "models.list") {
        throw new Error("models unavailable");
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "main",
      "model",
      "gpt-5-mini",
    );

    expect(result.sessionPatch?.modelOverride).toEqual({
      kind: "qualified",
      value: "openai/gpt-5-mini",
    });
  });

  it("keeps provider-qualified nested ids when the patched catalog lookup fails", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.patch") {
        return createResolvedModelPatch("moonshotai/kimi-k2.5", "nvidia");
      }
      if (method === "models.list") {
        throw new Error("models unavailable");
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "main",
      "model",
      "nvidia/moonshotai/kimi-k2.5",
    );

    expect(result.sessionPatch?.modelOverride).toEqual({
      kind: "qualified",
      value: "nvidia/moonshotai/kimi-k2.5",
    });
  });

  it("reuses a provided model catalog for /model updates without refetching", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.patch") {
        return createResolvedModelPatch("gpt-5-mini", "openai");
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "main",
      "model",
      "gpt-5-mini",
      { modelCatalog: createModelCatalog(OPENAI_GPT5_MINI_MODEL) },
    );

    expect(result.sessionPatch?.modelOverride).toEqual({
      kind: "qualified",
      value: "openai/gpt-5-mini",
    });
    expect(request).toHaveBeenCalledTimes(1);
    expect(request).not.toHaveBeenCalledWith("models.list", {});
  });
  it("resolves the legacy main alias for /usage", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.list") {
        return {
          sessions: [
            row("agent:main:main", {
              model: "gpt-4.1-mini",
              inputTokens: 1200,
              outputTokens: 300,
              totalTokens: 1500,
              contextTokens: 4000,
            }),
          ],
        };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "main",
      "usage",
      "",
    );

    expect(result.content).toBe(
      "**Session Usage**\nInput: **1.2k** tokens\nOutput: **300** tokens\nTotal: **1.5k** tokens\nContext: **30%** of 4k\nModel: `gpt-4.1-mini`",
    );
    expect(request).toHaveBeenNthCalledWith(1, "sessions.list", {});
  });

  it("reports the current thinking level for bare /think", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.list") {
        return {
          sessions: [
            row("agent:main:main", {
              modelProvider: "openai",
              model: "gpt-4.1-mini",
            }),
          ],
        };
      }
      if (method === "models.list") {
        return {
          models: [{ id: "gpt-4.1-mini", provider: "openai", reasoning: true }],
        };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "think",
      "",
    );

    expect(result.content).toBe(
      "Current thinking level: low.\nOptions: off, minimal, low, medium, high.",
    );
    expect(request).toHaveBeenNthCalledWith(1, "sessions.list", {});
    expect(request).toHaveBeenNthCalledWith(2, "models.list", {});
  });

  it("accepts minimal and xhigh thinking levels", async () => {
    const request = vi.fn(async (method: string, payload?: unknown) => {
      if (method === "sessions.list") {
        return {
          sessions: [
            row("agent:main:main", {
              thinkingOptions: ["off", "minimal", "low", "medium", "high", "xhigh"],
            }),
          ],
        };
      }
      if (method === "sessions.patch") {
        return { ok: true, ...((payload ?? {}) as object) };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const minimal = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "think",
      "minimal",
    );
    const xhigh = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "think",
      "xhigh",
    );

    expect(minimal.content).toBe("Thinking level set to **minimal**.");
    expect(xhigh.content).toBe("Thinking level set to **xhigh**.");
    expect(request).toHaveBeenNthCalledWith(1, "sessions.list", {});
    expect(request).toHaveBeenNthCalledWith(2, "sessions.patch", {
      key: "agent:main:main",
      thinkingLevel: "minimal",
    });
    expect(request).toHaveBeenNthCalledWith(3, "sessions.list", {});
    expect(request).toHaveBeenNthCalledWith(4, "sessions.patch", {
      key: "agent:main:main",
      thinkingLevel: "xhigh",
    });
  });

  it("uses default thinking options when the active session is absent", async () => {
    const request = vi.fn(async (method: string, payload?: unknown) => {
      if (method === "sessions.list") {
        return {
          defaults: {
            modelProvider: "openai-codex",
            model: "gpt-5.5",
            thinkingLevels: [
              { id: "off", label: "off" },
              { id: "minimal", label: "minimal" },
              { id: "low", label: "low" },
              { id: "medium", label: "medium" },
              { id: "adaptive", label: "adaptive" },
              { id: "high", label: "high" },
              { id: "xhigh", label: "xhigh" },
              { id: "max", label: "maximum" },
            ],
            thinkingOptions: [
              "off",
              "minimal",
              "low",
              "medium",
              "adaptive",
              "high",
              "xhigh",
              "maximum",
            ],
            thinkingDefault: "adaptive",
          },
          sessions: [],
        };
      }
      if (method === "models.list") {
        return {
          models: [{ id: "gpt-5.5", provider: "openai-codex", reasoning: true }],
        };
      }
      if (method === "sessions.patch") {
        return { ok: true, ...((payload ?? {}) as object) };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const status = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "think",
      "",
    );
    const setXhigh = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "think",
      "xhigh",
    );
    const setMax = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "think",
      "max",
    );
    const setMaximum = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "think",
      "maximum",
    );
    const setAdaptive = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "think",
      "auto",
    );

    expect(status.content).toBe(
      "Current thinking level: adaptive.\nOptions: off, minimal, low, medium, adaptive, high, xhigh, maximum.",
    );
    expect(setXhigh.content).toBe("Thinking level set to **xhigh**.");
    expect(setMax.content).toBe("Thinking level set to **max**.");
    expect(setMaximum.content).toBe("Thinking level set to **max**.");
    expect(setAdaptive.content).toBe("Thinking level set to **adaptive**.");
    expect(request).toHaveBeenCalledWith("sessions.patch", {
      key: "agent:main:main",
      thinkingLevel: "xhigh",
    });
    expect(request).toHaveBeenCalledWith("sessions.patch", {
      key: "agent:main:main",
      thinkingLevel: "max",
    });
    expect(request).toHaveBeenCalledWith("sessions.patch", {
      key: "agent:main:main",
      thinkingLevel: "adaptive",
    });
  });

  it("reports the current verbose level for bare /verbose", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.list") {
        return {
          sessions: [row("agent:main:main", { verboseLevel: "full" })],
        };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "verbose",
      "",
    );

    expect(result.content).toBe("Current verbose level: full.\nOptions: on, full, off.");
    expect(request).toHaveBeenNthCalledWith(1, "sessions.list", {});
  });

  it("reports the current fast mode for bare /fast", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.list") {
        return {
          sessions: [row("agent:main:main", { fastMode: true })],
        };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "fast",
      "",
    );

    expect(result.content).toBe("Current fast mode: on.\nOptions: status, on, off.");
    expect(request).toHaveBeenNthCalledWith(1, "sessions.list", {});
  });

  it("patches fast mode for /fast on", async () => {
    const request = vi.fn().mockResolvedValue({ ok: true });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "fast",
      "on",
    );

    expect(result.content).toBe("Fast mode enabled.");
    expect(request).toHaveBeenCalledWith("sessions.patch", {
      key: "agent:main:main",
      fastMode: true,
    });
  });
});

describe("executeSlashCommand /steer (soft inject)", () => {
  it("injects into the current session via chat.send with deliver: false", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.list") {
        return { sessions: [row("agent:main:main", { status: "running" })] };
      }
      if (method === "chat.send") {
        return { status: "started", runId: "run-1", messageSeq: 2 };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "steer",
      "try a different approach",
    );

    expect(result.content).toBe("Steered.");
    expect(request).toHaveBeenCalledWith(
      "chat.send",
      expect.objectContaining({
        sessionKey: "agent:main:main",
        message: "try a different approach",
        deliver: false,
      }),
    );
  });

  it("injects into a matching subagent when the first word resolves to one", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.list") {
        return {
          sessions: [
            row("agent:main:main"),
            row("agent:main:subagent:researcher", {
              spawnedBy: "agent:main:main",
              status: "running",
            }),
          ],
        };
      }
      if (method === "chat.send") {
        return { status: "started", runId: "run-2", messageSeq: 1 };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "steer",
      "researcher try a different approach",
    );

    expect(result.content).toBe("Steered `researcher`.");
    expect(request).toHaveBeenCalledWith(
      "chat.send",
      expect.objectContaining({
        sessionKey: "agent:main:subagent:researcher",
        message: "try a different approach",
        deliver: false,
      }),
    );
  });

  it("uses cached sessions to avoid an extra sessions.list round trip", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "chat.send") {
        return { status: "started", runId: "run-2", messageSeq: 1 };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "steer",
      "researcher try a different approach",
      {
        sessionsResult: {
          sessions: [
            row("agent:main:main"),
            row("agent:main:subagent:researcher", {
              spawnedBy: "agent:main:main",
              status: "running",
            }),
          ],
        } as SessionsListResult,
      },
    );

    expect(result.content).toBe("Steered `researcher`.");
    expect(request).toHaveBeenCalledTimes(1);
    expect(request).toHaveBeenCalledWith(
      "chat.send",
      expect.objectContaining({
        sessionKey: "agent:main:subagent:researcher",
        message: "try a different approach",
        deliver: false,
      }),
    );
  });

  it("matches an explicit full subagent session key", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.list") {
        return {
          sessions: [
            row("agent:main:main"),
            row("agent:main:subagent:researcher", {
              spawnedBy: "agent:main:main",
              status: "running",
            }),
          ],
        };
      }
      if (method === "chat.send") {
        return { status: "started", runId: "run-2", messageSeq: 1 };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "steer",
      "agent:main:subagent:researcher try a different approach",
    );

    expect(result.content).toBe("Steered `agent:main:subagent:researcher`.");
    expect(request).toHaveBeenCalledWith(
      "chat.send",
      expect.objectContaining({
        sessionKey: "agent:main:subagent:researcher",
        message: "try a different approach",
        deliver: false,
      }),
    );
  });

  it("does not treat 'all' as a subagent wildcard", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.list") {
        return { sessions: [row("agent:main:main", { status: "running" })] };
      }
      if (method === "chat.send") {
        return { status: "started", runId: "run-3", messageSeq: 1 };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "steer",
      "all good now",
    );

    expect(result.content).toBe("Steered.");
    expect(request).toHaveBeenCalledWith(
      "chat.send",
      expect.objectContaining({
        sessionKey: "agent:main:main",
        message: "all good now",
        deliver: false,
      }),
    );
  });

  it("does not match agent id as target — treats 'main' as message text", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.list") {
        return {
          sessions: [
            row("agent:main:main", { status: "running" }),
            row("agent:main:subagent:researcher", { spawnedBy: "agent:main:main" }),
          ],
        };
      }
      if (method === "chat.send") {
        return { status: "started", runId: "run-4", messageSeq: 1 };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "steer",
      "main refine the plan",
    );

    expect(result.content).toBe("Steered.");
    expect(request).toHaveBeenCalledWith(
      "chat.send",
      expect.objectContaining({
        sessionKey: "agent:main:main",
        message: "main refine the plan",
        deliver: false,
      }),
    );
  });

  it("keeps ended subagent targets so steer does not fall back to the current session", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.list") {
        return {
          sessions: [
            row("agent:main:main", { status: "running" }),
            row("agent:main:subagent:researcher", {
              spawnedBy: "agent:main:main",
              endedAt: Date.now() - 60_000,
            }),
          ],
        };
      }
      if (method === "chat.send") {
        return { status: "started", runId: "run-5", messageSeq: 1 };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "steer",
      "researcher try again",
    );

    expect(result.content).toBe("No active run matched `researcher`. Use `/redirect` instead.");
    expect(request).toHaveBeenCalledWith("sessions.list", {});
    expect(request).not.toHaveBeenCalledWith("chat.send", expect.anything());
  });

  it("returns a no-op summary when the current session has no active run", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.list") {
        return { sessions: [row("agent:main:main", { status: "done", endedAt: Date.now() })] };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "steer",
      "try again",
    );

    expect(result.content).toBe("No active run. Use the chat input or `/redirect` instead.");
    expect(request).toHaveBeenCalledWith("sessions.list", {});
    expect(request).not.toHaveBeenCalledWith("chat.send", expect.anything());
  });

  it("returns usage when no message is provided", async () => {
    const request = vi.fn();

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "steer",
      "",
    );

    expect(result.content).toBe("Usage: `/steer [id] <message>`");
    expect(request).not.toHaveBeenCalled();
  });

  it("returns error message on RPC failure", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.list") {
        return { sessions: [row("agent:main:main", { status: "running" })] };
      }
      throw new Error("connection lost");
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "steer",
      "try again",
    );

    expect(result.content).toBe("Failed to steer: Error: connection lost");
  });
});

describe("executeSlashCommand /redirect (hard kill-and-restart)", () => {
  it("calls sessions.steer to abort and restart the current session", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.list") {
        return { sessions: [row("agent:main:main")] };
      }
      if (method === "sessions.steer") {
        return { status: "started", runId: "run-1", messageSeq: 2, interruptedActiveRun: true };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "redirect",
      "start over with a new plan",
    );

    expect(result.content).toBe("Redirected.");
    expect(result.trackRunId).toBe("run-1");
    expect(request).toHaveBeenCalledWith("sessions.steer", {
      key: "agent:main:main",
      message: "start over with a new plan",
    });
  });

  it("redirects a matching subagent when the first word resolves to one", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.list") {
        return {
          sessions: [
            row("agent:main:main"),
            row("agent:main:subagent:researcher", { spawnedBy: "agent:main:main" }),
          ],
        };
      }
      if (method === "sessions.steer") {
        return { status: "started", runId: "run-2", messageSeq: 1 };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "redirect",
      "researcher start over completely",
    );

    expect(result.content).toBe("Redirected `researcher`.");
    // Subagent redirect must NOT set trackRunId — the run belongs to a
    // different session so chat events would never clear chatRunId.
    expect(result.trackRunId).toBeUndefined();
    expect(request).toHaveBeenCalledWith("sessions.steer", {
      key: "agent:main:subagent:researcher",
      message: "start over completely",
    });
  });

  it("redirects an ended subagent instead of falling back to the current session", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.list") {
        return {
          sessions: [
            row("agent:main:main"),
            row("agent:main:subagent:researcher", {
              spawnedBy: "agent:main:main",
              endedAt: Date.now() - 60_000,
            }),
          ],
        };
      }
      if (method === "sessions.steer") {
        return { status: "started", runId: "run-3", messageSeq: 1 };
      }
      throw new Error(`unexpected method: ${method}`);
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "redirect",
      "researcher start over completely",
    );

    expect(result.content).toBe("Redirected `researcher`.");
    expect(result.trackRunId).toBeUndefined();
    expect(request).toHaveBeenCalledWith("sessions.steer", {
      key: "agent:main:subagent:researcher",
      message: "start over completely",
    });
  });

  it("returns usage when no message is provided", async () => {
    const request = vi.fn();

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "redirect",
      "",
    );

    expect(result.content).toBe("Usage: `/redirect [id] <message>`");
    expect(request).not.toHaveBeenCalled();
  });

  it("returns error message on RPC failure", async () => {
    const request = vi.fn(async (method: string, _payload?: unknown) => {
      if (method === "sessions.list") {
        return { sessions: [row("agent:main:main")] };
      }
      throw new Error("connection lost");
    });

    const result = await executeSlashCommand(
      { request } as unknown as GatewayBrowserClient,
      "agent:main:main",
      "redirect",
      "try again",
    );

    expect(result.content).toBe("Failed to redirect: Error: connection lost");
  });
});

¤ Dauer der Verarbeitung: 0.31 Sekunden  (vorverarbeitet am  2026-04-27) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge