merge: align Fish Audio extension directory (#120084)

This commit is contained in:
Vincent Koc
2026-08-08 20:46:55 +08:00
16 changed files with 44 additions and 29 deletions
+1 -1
View File
@@ -505,7 +505,7 @@
"extensions: fish-audio":
- changed-files:
- any-glob-to-any-file:
- "extensions/fish-audio/**"
- "extensions/fish-audio-speech/**"
- "docs/providers/fish-audio.md"
- "docs/tools/tts.md"
"extensions: kilocode":
@@ -91,7 +91,7 @@ export async function createParams(): Promise<EmbeddedRunAttemptParams> {
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-projector-"));
tempDirs.add(tempDir);
const sessionFile = path.join(tempDir, "session.jsonl");
openFileBackedSessionManagerForTest(sessionFile).appendMessage(
openFileBackedSessionManagerForTest(sessionFile, { sessionId: "session-1" }).appendMessage(
assistantMessage("history", Date.now()),
);
return {
@@ -278,7 +278,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
it("bootstraps and assembles non-legacy context before the Codex turn starts", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
openFileBackedSessionManagerForTest(sessionFile).appendMessage(
openFileBackedSessionManagerForTest(sessionFile, { sessionId: "session-1" }).appendMessage(
assistantMessage("existing context", Date.now()) as never,
);
const openSpy = vi.spyOn(SessionManager, "open");
@@ -356,7 +356,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
it("keeps context-engine history bound to the run session when sandbox key differs", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
openFileBackedSessionManagerForTest(sessionFile).appendMessage(
openFileBackedSessionManagerForTest(sessionFile, { sessionId: "session-1" }).appendMessage(
assistantMessage("canonical main context", Date.now()) as never,
);
const contextEngine = createContextEngine();
@@ -547,7 +547,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
const info = vi.spyOn(embeddedAgentLog, "info").mockImplementation(() => undefined);
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
openFileBackedSessionManagerForTest(sessionFile).appendMessage(
openFileBackedSessionManagerForTest(sessionFile, { sessionId: "session-1" }).appendMessage(
assistantMessage("bootstrap-only context", Date.now()) as never,
);
const contextEngine = createContextEngine({
@@ -799,7 +799,9 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
const agentDir = path.join(tempDir, "agent");
const sessionManager = openFileBackedSessionManagerForTest(sessionFile);
const sessionManager = openFileBackedSessionManagerForTest(sessionFile, {
sessionId: "session-1",
});
sessionManager.appendMessage(
userMessage("previous stale-bootstrap request", Date.now()) as never,
);
@@ -888,7 +890,9 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
it("keeps mirrored history when an inactive per-turn context-engine binding starts fresh", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
const sessionManager = openFileBackedSessionManagerForTest(sessionFile);
const sessionManager = openFileBackedSessionManagerForTest(sessionFile, {
sessionId: "session-1",
});
sessionManager.appendMessage(userMessage("previous per-turn request", 10) as never);
sessionManager.appendMessage(assistantMessage("previous per-turn answer", 11) as never);
await writeCodexAppServerBinding(sessionFile, {
@@ -1266,7 +1270,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
it("retries a resumed context-engine thread on a fresh Codex thread without plugin compaction", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
openFileBackedSessionManagerForTest(sessionFile).appendMessage(
openFileBackedSessionManagerForTest(sessionFile, { sessionId: "session-1" }).appendMessage(
assistantMessage("pre-compaction context", Date.now()) as never,
);
await writeCodexAppServerBinding(sessionFile, {
@@ -1368,7 +1372,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
it("returns a replay-safe recovery result when the executable owner changes during overflow retry", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
openFileBackedSessionManagerForTest(sessionFile).appendMessage(
openFileBackedSessionManagerForTest(sessionFile, { sessionId: "session-1" }).appendMessage(
assistantMessage("pre-compaction context", Date.now()) as never,
);
await writeCodexAppServerBinding(sessionFile, {
@@ -1435,7 +1439,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
it("preserves a newer context-engine binding when a stale resumed thread overflows", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
openFileBackedSessionManagerForTest(sessionFile).appendMessage(
openFileBackedSessionManagerForTest(sessionFile, { sessionId: "session-1" }).appendMessage(
assistantMessage("pre-compaction context", Date.now()) as never,
);
await writeCodexAppServerBinding(sessionFile, {
@@ -1507,7 +1511,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
it("clears a resumed context-engine binding when a turn terminally overflows", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
openFileBackedSessionManagerForTest(sessionFile).appendMessage(
openFileBackedSessionManagerForTest(sessionFile, { sessionId: "session-1" }).appendMessage(
assistantMessage("pre-compaction context", Date.now()) as never,
);
await writeCodexAppServerBinding(sessionFile, {
@@ -1585,7 +1589,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
it("does not pre-compact over-budget rendered context-engine prompts before Codex turn/start", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
openFileBackedSessionManagerForTest(sessionFile).appendMessage(
openFileBackedSessionManagerForTest(sessionFile, { sessionId: "session-1" }).appendMessage(
assistantMessage("pre-compaction context", Date.now()) as never,
);
const hugePayload = {
@@ -1667,7 +1671,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
it("does not call hung owning context-engine compaction during Codex overflow recovery", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
openFileBackedSessionManagerForTest(sessionFile).appendMessage(
openFileBackedSessionManagerForTest(sessionFile, { sessionId: "session-1" }).appendMessage(
assistantMessage("pre-compaction context", Date.now()) as never,
);
await writeCodexAppServerBinding(sessionFile, {
@@ -1748,7 +1752,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
it("keeps current inbound context at the front of the Codex context-engine prompt", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
openFileBackedSessionManagerForTest(sessionFile).appendMessage(
openFileBackedSessionManagerForTest(sessionFile, { sessionId: "session-1" }).appendMessage(
assistantMessage("older context", Date.now()) as never,
);
const contextEngine = createContextEngine();
@@ -1850,7 +1854,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
it("reloads mirrored history after bootstrap mutates the session transcript", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
openFileBackedSessionManagerForTest(sessionFile).appendMessage(
openFileBackedSessionManagerForTest(sessionFile, { sessionId: "session-1" }).appendMessage(
assistantMessage("existing context", Date.now()) as never,
);
const afterTurn = vi.fn(
@@ -1858,7 +1862,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
);
const bootstrap = vi.fn(
async ({ sessionFile: file }: Parameters<NonNullable<ContextEngine["bootstrap"]>>[0]) => {
openFileBackedSessionManagerForTest(file).appendMessage(
openFileBackedSessionManagerForTest(file, { sessionId: "session-1" }).appendMessage(
assistantMessage("bootstrap context", Date.now() + 1) as never,
);
return { bootstrapped: true };
@@ -115,7 +115,9 @@ describe("runCodexAppServerAttempt hooks and model diagnostics", () => {
);
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
const sessionManager = openFileBackedSessionManagerForTest(sessionFile);
const sessionManager = openFileBackedSessionManagerForTest(sessionFile, {
sessionId: "session-1",
});
sessionManager.appendMessage(assistantMessage("existing context", Date.now()));
const harness = createStartedThreadHarness();
@@ -311,7 +313,9 @@ describe("runCodexAppServerAttempt hooks and model diagnostics", () => {
return {};
});
const params = createParams(sessionFile, workspaceDir);
const sessionManager = openFileBackedSessionManagerForTest(sessionFile);
const sessionManager = openFileBackedSessionManagerForTest(sessionFile, {
sessionId: "diagnostic-session-1",
});
sessionManager.appendMessage(assistantMessage("existing context", Date.now()));
params.runtimePlan = createCodexRuntimePlanFixture();
params.config = {
@@ -943,7 +947,7 @@ describe("runCodexAppServerAttempt hooks and model diagnostics", () => {
);
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
openFileBackedSessionManagerForTest(sessionFile).appendMessage(
openFileBackedSessionManagerForTest(sessionFile, { sessionId: "session-1" }).appendMessage(
assistantMessage("existing context", Date.now()),
);
createStartedThreadHarness(async (method) => {
@@ -43,7 +43,6 @@ const harness = await import("./bot.create-telegram-bot.test-harness.js");
const pluginStateTestRuntime = await import("openclaw/plugin-sdk/plugin-state-test-runtime");
const configMutation = await import("openclaw/plugin-sdk/config-mutation");
const modelSessionRuntime = await import("openclaw/plugin-sdk/model-session-runtime");
const sessionStoreRuntime = await import("openclaw/plugin-sdk/session-store-runtime");
const EYES_EMOJI = "\u{1F440}";
const tempStateDirs: string[] = [];
let previousStateDir: string | undefined;
@@ -5407,15 +5406,14 @@ describe("createTelegramBot", () => {
it("shows a permanent rejection when model selection is locked", async () => {
createTelegramBot({ token: "tok" });
const callbackHandler = getOnHandler("callback_query");
const patchSessionEntrySpy = vi
.spyOn(sessionStoreRuntime, "patchSessionEntry")
.mockImplementationOnce(async (params) => {
const getSessionEntrySpy = vi
.spyOn(telegramBotDepsForTest, "getSessionEntry")
.mockImplementationOnce(() => {
const entry = {
sessionId: "locked-session",
updatedAt: Date.now(),
modelSelectionLocked: true,
};
await params.update(entry, { existingEntry: entry });
return entry;
});
const ctx = makeCallbackRetryContext({
@@ -5427,7 +5425,7 @@ describe("createTelegramBot", () => {
try {
await expect(callbackHandler(ctx)).resolves.toBeUndefined();
} finally {
patchSessionEntrySpy.mockRestore();
getSessionEntrySpy.mockRestore();
}
expect(editMessageTextSpy).toHaveBeenCalledTimes(1);
+1 -1
View File
@@ -270,7 +270,7 @@
"!dist/extensions/featherless/**",
"!dist/extensions/firecrawl/**",
"!dist/extensions/fireworks/**",
"!dist/extensions/fish-audio/**",
"!dist/extensions/fish-audio-speech/**",
"!dist/extensions/google-meet/**",
"!dist/extensions/googlechat/**",
"!dist/extensions/gmi/**",
+1 -1
View File
@@ -947,7 +947,7 @@ importers:
specifier: workspace:*
version: link:../../packages/plugin-sdk
extensions/fish-audio:
extensions/fish-audio-speech:
devDependencies:
'@openclaw/plugin-sdk':
specifier: workspace:*
+1 -1
View File
@@ -302,7 +302,7 @@ function resolveDocs({ dirName, manifest, packageJson }) {
}
}
for (const candidate of [manifest.id, dirName]) {
for (const candidate of [manifest.id, dirName, ...(manifest.legacyPluginIds ?? [])]) {
if (typeof candidate !== "string") {
continue;
}
@@ -2,7 +2,7 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { afterEach, describe, expect, it, vi } from "vitest";
import { openFileBackedSessionManagerForTest } from "../../../test/helpers/session-manager-file-fixture.js";
import {
formatSqliteSessionFileMarker,
@@ -140,6 +140,15 @@ describe("SessionManager persistence compatibility", () => {
expect(() =>
openFileBackedSessionManagerForTest(sessionFile, { sessionId: "session-2" }),
).toThrow("belongs to session-1, not session-2");
const inMemory = vi.fn((cwd?: string) => SessionManager.inMemory(cwd));
const ManagerClass = { inMemory } as unknown as typeof SessionManager;
openFileBackedSessionManagerForTest(
path.join(dir, "legacy.jsonl"),
undefined,
dir,
ManagerClass,
);
expect(inMemory).toHaveBeenCalledWith(dir);
});
it("separates appended records from a final unterminated JSONL record", async () => {