diff --git a/src/auto-reply/reply/commands-acp/context.test.ts b/src/auto-reply/reply/commands-acp/context.test.ts index c00d3a2839c7..f1e3d5a6a5f7 100644 --- a/src/auto-reply/reply/commands-acp/context.test.ts +++ b/src/auto-reply/reply/commands-acp/context.test.ts @@ -13,11 +13,7 @@ import { createTestRegistry, } from "../../../test-utils/channel-plugins.js"; import { buildCommandTestParams } from "../commands-spawn.test-harness.js"; -import { - resolveAcpCommandBindingContext, - resolveAcpCommandConversationId, - resolveAcpCommandParentConversationId, -} from "./context.js"; +import { resolveAcpCommandBindingContext, resolveAcpCommandConversationId } from "./context.js"; const baseCfg = { session: { mainKey: "main", scope: "per-sender" }, @@ -663,7 +659,6 @@ describe("commands-acp context", () => { parentConversationId: "!room:example.org", }); expect(resolveAcpCommandConversationId(params)).toBe("$thread-root"); - expect(resolveAcpCommandParentConversationId(params)).toBe("!room:example.org"); }); it("resolves iMessage DM conversation ids from current targets", () => { @@ -874,7 +869,6 @@ describe("commands-acp context", () => { AccountId: "work", }); - expect(resolveAcpCommandParentConversationId(params)).toBeUndefined(); expect(resolveAcpCommandBindingContext(params)).toEqual({ channel: "feishu", accountId: "work", diff --git a/src/auto-reply/reply/commands-acp/context.ts b/src/auto-reply/reply/commands-acp/context.ts index 5dd685479636..d0d7175926c7 100644 --- a/src/auto-reply/reply/commands-acp/context.ts +++ b/src/auto-reply/reply/commands-acp/context.ts @@ -45,12 +45,6 @@ export function resolveAcpCommandConversationId(params: HandleCommandsParams): s return resolveAcpCommandConversationRef(params)?.conversationId; } -export function resolveAcpCommandParentConversationId( - params: HandleCommandsParams, -): string | undefined { - return resolveAcpCommandConversationRef(params)?.parentConversationId; -} - export function resolveAcpCommandBindingContext(params: HandleCommandsParams): { channel: string; accountId: string; diff --git a/src/infra/archive.test.ts b/src/infra/archive.test.ts index 750db829667c..1e16f28d2b0f 100644 --- a/src/infra/archive.test.ts +++ b/src/infra/archive.test.ts @@ -8,11 +8,7 @@ import { createSuiteTempRootTracker } from "../test-helpers/temp-dir.js"; import { withRealpathSymlinkRebindRace } from "../test-utils/symlink-rebind-race.js"; import { createZipCentralDirectoryArchive } from "../test-utils/zip-central-directory-fixture.js"; import type { ArchiveSecurityError } from "./archive.js"; -import { - extractArchive, - readZipCentralDirectoryEntryCount, - resolvePackedRootDir, -} from "./archive.js"; +import { extractArchive, resolvePackedRootDir } from "./archive.js"; const fixtureRootTracker = createSuiteTempRootTracker({ prefix: "openclaw-archive-" }); const directorySymlinkType = process.platform === "win32" ? "junction" : undefined; @@ -383,7 +379,6 @@ describe("archive utils", () => { }); await fs.writeFile(archivePath, archiveBytes); - expect(readZipCentralDirectoryEntryCount(archiveBytes)).toBe(2); await expect( extractArchive({ archivePath, diff --git a/src/infra/archive.ts b/src/infra/archive.ts index bbb6dc7b1ce3..678037558fb4 100644 --- a/src/infra/archive.ts +++ b/src/infra/archive.ts @@ -15,7 +15,6 @@ export { loadZipArchiveWithPreflight, mergeExtractedTreeIntoDestination, prepareArchiveDestinationDir, - readZipCentralDirectoryEntryCount, resolveArchiveKind, resolvePackedRootDir, withStagedArchiveDestination, diff --git a/src/media-understanding/resolve.test.ts b/src/media-understanding/resolve.test.ts index 91cbebd8274d..48c9ae2eb359 100644 --- a/src/media-understanding/resolve.test.ts +++ b/src/media-understanding/resolve.test.ts @@ -1,14 +1,8 @@ -// Media-understanding resolve tests cover timeout clamping, capability filtering, -// and active-model fallback behavior. +// Media-understanding resolve tests cover timeout clamping and capability filtering. import { MAX_TIMER_TIMEOUT_MS } from "@openclaw/normalization-core/number-coercion"; import { describe, expect, it } from "vitest"; import type { OpenClawConfig } from "../config/types.js"; -import { - resolveEntriesWithActiveFallback, - resolveMediaRuntimeTimeoutMs, - resolveModelEntries, - resolveTimeoutMs, -} from "./resolve.js"; +import { resolveMediaRuntimeTimeoutMs, resolveModelEntries, resolveTimeoutMs } from "./resolve.js"; import type { MediaUnderstandingCapability } from "./types.js"; const providerRegistry = new Map([ @@ -90,88 +84,3 @@ describe("resolveModelEntries", () => { expect(entries).toHaveLength(0); }); }); - -describe("resolveEntriesWithActiveFallback", () => { - type ResolveWithFallbackInput = Parameters[0]; - const defaultActiveModel = { provider: "groq", model: "whisper-large-v3" } as const; - - function resolveWithActiveFallback(params: { - cfg: ResolveWithFallbackInput["cfg"]; - capability: ResolveWithFallbackInput["capability"]; - config: ResolveWithFallbackInput["config"]; - }) { - return resolveEntriesWithActiveFallback({ - cfg: params.cfg, - capability: params.capability, - config: params.config, - providerRegistry, - activeModel: defaultActiveModel, - }); - } - - function expectResolvedProviders(params: { - cfg: OpenClawConfig; - capability: ResolveWithFallbackInput["capability"]; - config: ResolveWithFallbackInput["config"]; - providers: string[]; - }) { - const entries = resolveWithActiveFallback({ - cfg: params.cfg, - capability: params.capability, - config: params.config, - }); - expect(entries).toHaveLength(params.providers.length); - expect(entries.map((entry) => entry.provider)).toEqual(params.providers); - } - - it("uses active model when enabled and no models are configured", () => { - const cfg: OpenClawConfig = { - tools: { - media: { - audio: { enabled: true }, - }, - }, - }; - - expectResolvedProviders({ - cfg, - capability: "audio", - config: cfg.tools?.media?.audio, - providers: ["groq"], - }); - }); - - it("ignores active model when configured entries exist", () => { - const cfg: OpenClawConfig = { - tools: { - media: { - audio: { enabled: true, models: [{ provider: "openai", model: "whisper-1" }] }, - }, - }, - }; - - expectResolvedProviders({ - cfg, - capability: "audio", - config: cfg.tools?.media?.audio, - providers: ["openai"], - }); - }); - - it("skips active model when provider lacks capability", () => { - const cfg: OpenClawConfig = { - tools: { - media: { - video: { enabled: true }, - }, - }, - }; - - const entries = resolveWithActiveFallback({ - cfg, - capability: "video", - config: cfg.tools?.media?.video, - }); - expect(entries).toHaveLength(0); - }); -}); diff --git a/src/media-understanding/resolve.ts b/src/media-understanding/resolve.ts index ddeae05a4cf9..935322d13531 100644 --- a/src/media-understanding/resolve.ts +++ b/src/media-understanding/resolve.ts @@ -1,5 +1,5 @@ // Resolution helpers derive media-understanding timeouts, prompts, byte/char -// caps, scope decisions, model entries, concurrency, and active-model fallback. +// caps, scope decisions, model entries, and concurrency. import { MAX_TIMER_TIMEOUT_MS, resolveTimerTimeoutMs, @@ -19,7 +19,6 @@ import { DEFAULT_PROMPT, } from "./defaults.constants.js"; import { resolveEffectiveMediaEntryCapabilities } from "./entry-capabilities.js"; -import { normalizeMediaProviderId } from "./provider-id.js"; import { normalizeMediaUnderstandingChatType, resolveMediaUnderstandingScope } from "./scope.js"; import type { MediaUnderstandingCapability } from "./types.js"; @@ -153,46 +152,3 @@ export function resolveConcurrency(cfg: OpenClawConfig): number { } return DEFAULT_MEDIA_CONCURRENCY; } - -/** Adds the active chat model as a provider fallback when enabled media has no explicit entries. */ -export function resolveEntriesWithActiveFallback(params: { - cfg: OpenClawConfig; - capability: MediaUnderstandingCapability; - config?: MediaUnderstandingConfig; - providerRegistry: Map; - activeModel?: { provider: string; model?: string }; -}): MediaUnderstandingModelConfig[] { - const entries = resolveModelEntries({ - cfg: params.cfg, - capability: params.capability, - config: params.config, - providerRegistry: params.providerRegistry, - }); - if (entries.length > 0) { - return entries; - } - // Active chat model fallback is opt-in and only valid when its provider has - // declared the requested media capability. - if (params.config?.enabled !== true) { - return entries; - } - const activeProviderRaw = params.activeModel?.provider?.trim(); - if (!activeProviderRaw) { - return entries; - } - const activeProvider = normalizeMediaProviderId(activeProviderRaw); - if (!activeProvider) { - return entries; - } - const capabilities = params.providerRegistry.get(activeProvider)?.capabilities; - if (!capabilities || !capabilities.includes(params.capability)) { - return entries; - } - return [ - { - type: "provider", - provider: activeProvider, - model: params.activeModel?.model, - }, - ]; -} diff --git a/src/media-understanding/shared.test.ts b/src/media-understanding/shared.test.ts index 4d38f9d37513..0846de09baf4 100644 --- a/src/media-understanding/shared.test.ts +++ b/src/media-understanding/shared.test.ts @@ -1,5 +1,5 @@ // Shared provider helper tests cover deadlines, guarded fetch policy, HTTP -// config, multipart transcription, and error response parsing. +// config, and multipart transcription. import { MAX_DATE_TIMESTAMP_MS, MAX_TIMER_TIMEOUT_MS, @@ -40,7 +40,6 @@ import { pollProviderOperationJson, postJsonRequest, postTranscriptionRequest, - readErrorResponse, resolveProviderOperationTimeoutMs, resolveProviderHttpRequestConfig, waitProviderOperationPollInterval, @@ -582,32 +581,6 @@ describe("resolveProviderHttpRequestConfig", () => { }); }); -describe("readErrorResponse", () => { - it("caps streamed error bodies instead of buffering the whole response", async () => { - const encoder = new TextEncoder(); - let reads = 0; - const response = new Response( - new ReadableStream({ - pull(controller) { - reads += 1; - controller.enqueue(encoder.encode("a".repeat(2048))); - if (reads >= 10) { - controller.close(); - } - }, - }), - { - status: 500, - }, - ); - - const detail = await readErrorResponse(response); - - expect(detail).toBe(`${"a".repeat(300)}…`); - expect(reads).toBe(2); - }); -}); - describe("fetchWithTimeoutGuarded", () => { it("applies a default timeout when callers omit one", async () => { fetchWithSsrFGuardMock.mockResolvedValue({ diff --git a/src/media-understanding/shared.ts b/src/media-understanding/shared.ts index 61f945b900df..00f99a52dd9e 100644 --- a/src/media-understanding/shared.ts +++ b/src/media-understanding/shared.ts @@ -41,8 +41,6 @@ export { normalizeBaseUrl } from "../agents/provider-request-config.js"; export { sanitizeConfiguredModelProviderRequest } from "../agents/provider-request-config.js"; const DEFAULT_GUARDED_HTTP_TIMEOUT_MS = 60_000; -const MAX_ERROR_CHARS = 300; -const MAX_ERROR_RESPONSE_BYTES = 4096; const MAX_AUDIT_CONTEXT_CHARS = 80; /** Resolves the multipart upload filename, mapping AAC inputs to provider-friendly `.m4a`. */ @@ -649,62 +647,6 @@ export async function postMultipartRequest(params: GuardedPostRequestParams { - let reader: ReadableStreamDefaultReader | undefined; - try { - if (!res.body) { - return undefined; - } - reader = res.body.getReader(); - const chunks: Uint8Array[] = []; - let total = 0; - let sawBytes = false; - while (total < MAX_ERROR_RESPONSE_BYTES) { - const { done, value } = await reader.read(); - if (done) { - break; - } - if (!value || value.length === 0) { - continue; - } - sawBytes = true; - const remaining = MAX_ERROR_RESPONSE_BYTES - total; - const chunk = value.length <= remaining ? value : value.subarray(0, remaining); - chunks.push(chunk); - total += chunk.length; - if (chunk.length < value.length) { - break; - } - } - if (!sawBytes) { - return undefined; - } - const bytes = new Uint8Array(total); - let offset = 0; - for (const chunk of chunks) { - bytes.set(chunk, offset); - offset += chunk.length; - } - const text = new TextDecoder().decode(bytes); - const collapsed = text.replace(/\s+/g, " ").trim(); - if (!collapsed) { - return undefined; - } - if (collapsed.length <= MAX_ERROR_CHARS) { - return collapsed; - } - return `${collapsed.slice(0, MAX_ERROR_CHARS)}…`; - } catch { - return undefined; - } finally { - try { - await reader?.cancel(); - } catch { - // Ignore stream-cancel failures while reporting the original HTTP error. - } - } -} - export function requireTranscriptionText( value: string | undefined, missingMessage: string,