refactor: rename clawdbot to moltbot with legacy compat

This commit is contained in:
Peter Steinberger
2026-01-27 12:19:58 +00:00
parent 83460df96f
commit 6d16a658e5
1839 changed files with 11250 additions and 11199 deletions
+20 -20
View File
@@ -4,7 +4,7 @@ import path from "node:path";
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { ClawdbotConfig } from "../config/config.js";
import type { MoltbotConfig } from "../config/config.js";
import type { MsgContext } from "../auto-reply/templating.js";
import { resolveApiKeyForProvider } from "../agents/model-auth.js";
import { fetchRemoteMedia } from "../media/fetch.js";
@@ -49,7 +49,7 @@ describe("applyMediaUnderstanding", () => {
it("sets Transcript and replaces Body when audio transcription succeeds", async () => {
const { applyMediaUnderstanding } = await loadApply();
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-media-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-"));
const audioPath = path.join(dir, "note.ogg");
await fs.writeFile(audioPath, "hello");
@@ -58,7 +58,7 @@ describe("applyMediaUnderstanding", () => {
MediaPath: audioPath,
MediaType: "audio/ogg",
};
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
tools: {
media: {
audio: {
@@ -92,7 +92,7 @@ describe("applyMediaUnderstanding", () => {
it("keeps caption for command parsing when audio has user text", async () => {
const { applyMediaUnderstanding } = await loadApply();
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-media-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-"));
const audioPath = path.join(dir, "note.ogg");
await fs.writeFile(audioPath, "hello");
@@ -101,7 +101,7 @@ describe("applyMediaUnderstanding", () => {
MediaPath: audioPath,
MediaType: "audio/ogg",
};
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
tools: {
media: {
audio: {
@@ -140,7 +140,7 @@ describe("applyMediaUnderstanding", () => {
MediaType: "audio/ogg",
ChatType: "dm",
};
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
tools: {
media: {
audio: {
@@ -174,7 +174,7 @@ describe("applyMediaUnderstanding", () => {
it("skips audio transcription when attachment exceeds maxBytes", async () => {
const { applyMediaUnderstanding } = await loadApply();
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-media-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-"));
const audioPath = path.join(dir, "large.wav");
await fs.writeFile(audioPath, "0123456789");
@@ -184,7 +184,7 @@ describe("applyMediaUnderstanding", () => {
MediaType: "audio/wav",
};
const transcribeAudio = vi.fn(async () => ({ text: "should-not-run" }));
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
tools: {
media: {
audio: {
@@ -209,7 +209,7 @@ describe("applyMediaUnderstanding", () => {
it("falls back to CLI model when provider fails", async () => {
const { applyMediaUnderstanding } = await loadApply();
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-media-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-"));
const audioPath = path.join(dir, "note.ogg");
await fs.writeFile(audioPath, "hello");
@@ -218,7 +218,7 @@ describe("applyMediaUnderstanding", () => {
MediaPath: audioPath,
MediaType: "audio/ogg",
};
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
tools: {
media: {
audio: {
@@ -262,7 +262,7 @@ describe("applyMediaUnderstanding", () => {
it("uses CLI image understanding and preserves caption for commands", async () => {
const { applyMediaUnderstanding } = await loadApply();
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-media-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-"));
const imagePath = path.join(dir, "photo.jpg");
await fs.writeFile(imagePath, "image-bytes");
@@ -271,7 +271,7 @@ describe("applyMediaUnderstanding", () => {
MediaPath: imagePath,
MediaType: "image/jpeg",
};
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
tools: {
media: {
image: {
@@ -309,7 +309,7 @@ describe("applyMediaUnderstanding", () => {
it("uses shared media models list when capability config is missing", async () => {
const { applyMediaUnderstanding } = await loadApply();
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-media-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-"));
const imagePath = path.join(dir, "shared.jpg");
await fs.writeFile(imagePath, "image-bytes");
@@ -318,7 +318,7 @@ describe("applyMediaUnderstanding", () => {
MediaPath: imagePath,
MediaType: "image/jpeg",
};
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
tools: {
media: {
models: [
@@ -350,7 +350,7 @@ describe("applyMediaUnderstanding", () => {
it("uses active model when enabled and models are missing", async () => {
const { applyMediaUnderstanding } = await loadApply();
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-media-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-"));
const audioPath = path.join(dir, "fallback.ogg");
await fs.writeFile(audioPath, "hello");
@@ -359,7 +359,7 @@ describe("applyMediaUnderstanding", () => {
MediaPath: audioPath,
MediaType: "audio/ogg",
};
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
tools: {
media: {
audio: {
@@ -387,7 +387,7 @@ describe("applyMediaUnderstanding", () => {
it("handles multiple audio attachments when attachment mode is all", async () => {
const { applyMediaUnderstanding } = await loadApply();
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-media-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-"));
const audioPathA = path.join(dir, "note-a.ogg");
const audioPathB = path.join(dir, "note-b.ogg");
await fs.writeFile(audioPathA, "hello");
@@ -398,7 +398,7 @@ describe("applyMediaUnderstanding", () => {
MediaPaths: [audioPathA, audioPathB],
MediaTypes: ["audio/ogg", "audio/ogg"],
};
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
tools: {
media: {
audio: {
@@ -430,7 +430,7 @@ describe("applyMediaUnderstanding", () => {
it("orders mixed media outputs as image, audio, video", async () => {
const { applyMediaUnderstanding } = await loadApply();
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-media-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-"));
const imagePath = path.join(dir, "photo.jpg");
const audioPath = path.join(dir, "note.ogg");
const videoPath = path.join(dir, "clip.mp4");
@@ -443,7 +443,7 @@ describe("applyMediaUnderstanding", () => {
MediaPaths: [imagePath, audioPath, videoPath],
MediaTypes: ["image/jpeg", "audio/ogg", "video/mp4"],
};
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
tools: {
media: {
image: { enabled: true, models: [{ provider: "openai", model: "gpt-5.2" }] },
+2 -2
View File
@@ -1,4 +1,4 @@
import type { ClawdbotConfig } from "../config/config.js";
import type { MoltbotConfig } from "../config/config.js";
import type { MsgContext } from "../auto-reply/templating.js";
import { finalizeInboundContext } from "../auto-reply/reply/inbound-context.js";
import {
@@ -34,7 +34,7 @@ const CAPABILITY_ORDER: MediaUnderstandingCapability[] = ["image", "audio", "vid
export async function applyMediaUnderstanding(params: {
ctx: MsgContext;
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
agentDir?: string;
providers?: Record<string, MediaUnderstandingProvider>;
activeModel?: ActiveMediaModel;
+1 -1
View File
@@ -326,7 +326,7 @@ export class MediaAttachmentCache {
timeoutMs: params.timeoutMs,
});
const extension = path.extname(bufferResult.fileName || "") || "";
const tmpPath = path.join(os.tmpdir(), `clawdbot-media-${crypto.randomUUID()}${extension}`);
const tmpPath = path.join(os.tmpdir(), `moltbot-media-${crypto.randomUUID()}${extension}`);
await fs.writeFile(tmpPath, bufferResult.buffer);
entry.tempPath = tmpPath;
entry.tempCleanup = async () => {
+2 -2
View File
@@ -3,7 +3,7 @@ import { complete } from "@mariozechner/pi-ai";
import { discoverAuthStorage, discoverModels } from "@mariozechner/pi-coding-agent";
import { getApiKeyForModel, requireApiKey } from "../../agents/model-auth.js";
import { ensureClawdbotModelsJson } from "../../agents/models-config.js";
import { ensureMoltbotModelsJson } from "../../agents/models-config.js";
import { minimaxUnderstandImage } from "../../agents/minimax-vlm.js";
import { coerceImageAssistantText } from "../../agents/tools/image-tool.helpers.js";
import type { ImageDescriptionRequest, ImageDescriptionResult } from "../types.js";
@@ -11,7 +11,7 @@ import type { ImageDescriptionRequest, ImageDescriptionResult } from "../types.j
export async function describeImageWithModel(
params: ImageDescriptionRequest,
): Promise<ImageDescriptionResult> {
await ensureClawdbotModelsJson(params.cfg, params.agentDir);
await ensureMoltbotModelsJson(params.cfg, params.agentDir);
const authStorage = discoverAuthStorage(params.agentDir);
const modelRegistry = discoverModels(authStorage, params.agentDir);
const model = modelRegistry.find(params.provider, params.model) as Model<Api> | null;
+7 -7
View File
@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import type { ClawdbotConfig } from "../config/config.js";
import type { MoltbotConfig } from "../config/config.js";
import { resolveEntriesWithActiveFallback, resolveModelEntries } from "./resolve.js";
const providerRegistry = new Map([
@@ -10,7 +10,7 @@ const providerRegistry = new Map([
describe("resolveModelEntries", () => {
it("uses provider capabilities for shared entries without explicit caps", () => {
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
tools: {
media: {
models: [{ provider: "openai", model: "gpt-5.2" }],
@@ -34,7 +34,7 @@ describe("resolveModelEntries", () => {
});
it("keeps per-capability entries even without explicit caps", () => {
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
tools: {
media: {
image: {
@@ -54,7 +54,7 @@ describe("resolveModelEntries", () => {
});
it("skips shared CLI entries without capabilities", () => {
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
tools: {
media: {
models: [{ type: "cli", command: "gemini", args: ["--file", "{{MediaPath}}"] }],
@@ -73,7 +73,7 @@ describe("resolveModelEntries", () => {
describe("resolveEntriesWithActiveFallback", () => {
it("uses active model when enabled and no models are configured", () => {
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
tools: {
media: {
audio: { enabled: true },
@@ -93,7 +93,7 @@ describe("resolveEntriesWithActiveFallback", () => {
});
it("ignores active model when configured entries exist", () => {
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
tools: {
media: {
audio: { enabled: true, models: [{ provider: "openai", model: "whisper-1" }] },
@@ -113,7 +113,7 @@ describe("resolveEntriesWithActiveFallback", () => {
});
it("skips active model when provider lacks capability", () => {
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
tools: {
media: {
video: { enabled: true },
+7 -7
View File
@@ -1,4 +1,4 @@
import type { ClawdbotConfig } from "../config/config.js";
import type { MoltbotConfig } from "../config/config.js";
import type { MsgContext } from "../auto-reply/templating.js";
import type {
MediaUnderstandingConfig,
@@ -34,7 +34,7 @@ export function resolvePrompt(
export function resolveMaxChars(params: {
capability: MediaUnderstandingCapability;
entry: MediaUnderstandingModelConfig;
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
config?: MediaUnderstandingConfig;
}): number | undefined {
const { capability, entry, cfg } = params;
@@ -47,7 +47,7 @@ export function resolveMaxChars(params: {
export function resolveMaxBytes(params: {
capability: MediaUnderstandingCapability;
entry: MediaUnderstandingModelConfig;
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
config?: MediaUnderstandingConfig;
}): number {
const configured =
@@ -59,7 +59,7 @@ export function resolveMaxBytes(params: {
}
export function resolveCapabilityConfig(
cfg: ClawdbotConfig,
cfg: MoltbotConfig,
capability: MediaUnderstandingCapability,
): MediaUnderstandingConfig | undefined {
return cfg.tools?.media?.[capability];
@@ -89,7 +89,7 @@ function resolveEntryCapabilities(params: {
}
export function resolveModelEntries(params: {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
capability: MediaUnderstandingCapability;
config?: MediaUnderstandingConfig;
providerRegistry: Map<string, { capabilities?: MediaUnderstandingCapability[] }>;
@@ -126,7 +126,7 @@ export function resolveModelEntries(params: {
.map(({ entry }) => entry);
}
export function resolveConcurrency(cfg: ClawdbotConfig): number {
export function resolveConcurrency(cfg: MoltbotConfig): number {
const configured = cfg.tools?.media?.concurrency;
if (typeof configured === "number" && Number.isFinite(configured) && configured > 0) {
return Math.floor(configured);
@@ -135,7 +135,7 @@ export function resolveConcurrency(cfg: ClawdbotConfig): number {
}
export function resolveEntriesWithActiveFallback(params: {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
capability: MediaUnderstandingCapability;
config?: MediaUnderstandingConfig;
providerRegistry: Map<string, { capabilities?: MediaUnderstandingCapability[] }>;
@@ -4,7 +4,7 @@ import path from "node:path";
import { describe, expect, it } from "vitest";
import type { ClawdbotConfig } from "../config/config.js";
import type { MoltbotConfig } from "../config/config.js";
import type { MsgContext } from "../auto-reply/templating.js";
import {
buildProviderRegistry,
@@ -17,7 +17,7 @@ describe("runCapability auto audio entries", () => {
it("uses provider keys to auto-enable audio transcription", async () => {
const originalPath = process.env.PATH;
process.env.PATH = "/usr/bin:/bin";
const tmpPath = path.join(os.tmpdir(), `clawdbot-auto-audio-${Date.now()}.wav`);
const tmpPath = path.join(os.tmpdir(), `moltbot-auto-audio-${Date.now()}.wav`);
await fs.writeFile(tmpPath, Buffer.from("RIFF"));
const ctx: MsgContext = { MediaPath: tmpPath, MediaType: "audio/wav" };
const media = normalizeMediaAttachments(ctx);
@@ -44,7 +44,7 @@ describe("runCapability auto audio entries", () => {
},
},
},
} as unknown as ClawdbotConfig;
} as unknown as MoltbotConfig;
try {
const result = await runCapability({
@@ -68,7 +68,7 @@ describe("runCapability auto audio entries", () => {
it("skips auto audio when disabled", async () => {
const originalPath = process.env.PATH;
process.env.PATH = "/usr/bin:/bin";
const tmpPath = path.join(os.tmpdir(), `clawdbot-auto-audio-${Date.now()}.wav`);
const tmpPath = path.join(os.tmpdir(), `moltbot-auto-audio-${Date.now()}.wav`);
await fs.writeFile(tmpPath, Buffer.from("RIFF"));
const ctx: MsgContext = { MediaPath: tmpPath, MediaType: "audio/wav" };
const media = normalizeMediaAttachments(ctx);
@@ -98,7 +98,7 @@ describe("runCapability auto audio entries", () => {
},
},
},
} as unknown as ClawdbotConfig;
} as unknown as MoltbotConfig;
try {
const result = await runCapability({
@@ -4,7 +4,7 @@ import path from "node:path";
import { describe, expect, it } from "vitest";
import type { ClawdbotConfig } from "../config/config.js";
import type { MoltbotConfig } from "../config/config.js";
import type { MsgContext } from "../auto-reply/templating.js";
import {
buildProviderRegistry,
@@ -15,7 +15,7 @@ import {
describe("runCapability deepgram provider options", () => {
it("merges provider options, headers, and baseUrl overrides", async () => {
const tmpPath = path.join(os.tmpdir(), `clawdbot-deepgram-${Date.now()}.wav`);
const tmpPath = path.join(os.tmpdir(), `moltbot-deepgram-${Date.now()}.wav`);
await fs.writeFile(tmpPath, Buffer.from("RIFF"));
const ctx: MsgContext = { MediaPath: tmpPath, MediaType: "audio/wav" };
const media = normalizeMediaAttachments(ctx);
@@ -80,7 +80,7 @@ describe("runCapability deepgram provider options", () => {
},
},
},
} as unknown as ClawdbotConfig;
} as unknown as MoltbotConfig;
try {
const result = await runCapability({
+10 -10
View File
@@ -3,7 +3,7 @@ import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import type { ClawdbotConfig } from "../config/config.js";
import type { MoltbotConfig } from "../config/config.js";
import {
findModelInCatalog,
loadModelCatalog,
@@ -329,7 +329,7 @@ async function resolveGeminiCliEntry(
}
async function resolveKeyEntry(params: {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
agentDir?: string;
providerRegistry: ProviderRegistry;
capability: MediaUnderstandingCapability;
@@ -393,7 +393,7 @@ async function resolveKeyEntry(params: {
}
async function resolveAutoEntries(params: {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
agentDir?: string;
providerRegistry: ProviderRegistry;
capability: MediaUnderstandingCapability;
@@ -413,7 +413,7 @@ async function resolveAutoEntries(params: {
}
export async function resolveAutoImageModel(params: {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
agentDir?: string;
activeModel?: ActiveMediaModel;
}): Promise<ActiveMediaModel | null> {
@@ -446,7 +446,7 @@ export async function resolveAutoImageModel(params: {
}
async function resolveActiveModelEntry(params: {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
agentDir?: string;
providerRegistry: ProviderRegistry;
capability: MediaUnderstandingCapability;
@@ -663,7 +663,7 @@ function formatDecisionSummary(decision: MediaUnderstandingDecision): string {
async function runProviderEntry(params: {
capability: MediaUnderstandingCapability;
entry: MediaUnderstandingModelConfig;
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
ctx: MsgContext;
attachmentIndex: number;
cache: MediaAttachmentCache;
@@ -847,7 +847,7 @@ async function runProviderEntry(params: {
async function runCliEntry(params: {
capability: MediaUnderstandingCapability;
entry: MediaUnderstandingModelConfig;
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
ctx: MsgContext;
attachmentIndex: number;
cache: MediaAttachmentCache;
@@ -877,7 +877,7 @@ async function runCliEntry(params: {
maxBytes,
timeoutMs,
});
const outputDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-media-cli-"));
const outputDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-cli-"));
const mediaPath = pathResult.path;
const outputBase = path.join(outputDir, path.parse(mediaPath).name);
@@ -923,7 +923,7 @@ async function runCliEntry(params: {
async function runAttachmentEntries(params: {
capability: MediaUnderstandingCapability;
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
ctx: MsgContext;
attachmentIndex: number;
agentDir?: string;
@@ -1006,7 +1006,7 @@ async function runAttachmentEntries(params: {
export async function runCapability(params: {
capability: MediaUnderstandingCapability;
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
ctx: MsgContext;
attachments: MediaAttachmentCache;
media: MediaAttachment[];
@@ -1,7 +1,7 @@
import { describe, expect, it, vi } from "vitest";
import type { MsgContext } from "../auto-reply/templating.js";
import type { ClawdbotConfig } from "../config/config.js";
import type { MoltbotConfig } from "../config/config.js";
import {
buildProviderRegistry,
createMediaAttachmentCache,
@@ -33,7 +33,7 @@ describe("runCapability image skip", () => {
const ctx: MsgContext = { MediaPath: "/tmp/image.png", MediaType: "image/png" };
const media = normalizeMediaAttachments(ctx);
const cache = createMediaAttachmentCache(media);
const cfg = {} as ClawdbotConfig;
const cfg = {} as MoltbotConfig;
try {
const result = await runCapability({
+1 -1
View File
@@ -97,7 +97,7 @@ export type ImageDescriptionRequest = {
profile?: string;
preferredProfile?: string;
agentDir: string;
cfg: import("../config/config.js").ClawdbotConfig;
cfg: import("../config/config.js").MoltbotConfig;
};
export type ImageDescriptionResult = {