sync from moltbot:main

This commit is contained in:
alex xiang 2026-01-28 17:14:44 +08:00
parent 4b6e0eeebe
commit 98c02997ef
8 changed files with 44 additions and 40 deletions

View File

@ -7,7 +7,7 @@
*/ */
import { ProxyAgent, setGlobalDispatcher, getGlobalDispatcher, type Dispatcher } from "undici"; import { ProxyAgent, setGlobalDispatcher, getGlobalDispatcher, type Dispatcher } from "undici";
import type { ClawdbotConfig } from "../config/config.js"; import type { MoltbotConfig } from "../config/config.js";
let originalDispatcher: Dispatcher | null = null; let originalDispatcher: Dispatcher | null = null;
let currentProxyUrl: string | null = null; let currentProxyUrl: string | null = null;
@ -18,7 +18,7 @@ let currentProxyUrl: string | null = null;
* *
* Safe to call multiple times - only reconfigures if the proxy URL changes. * Safe to call multiple times - only reconfigures if the proxy URL changes.
*/ */
export function setupLlmProxy(cfg: ClawdbotConfig | undefined): void { export function setupLlmProxy(cfg: MoltbotConfig | undefined): void {
const proxyUrl = cfg?.models?.proxy?.trim(); const proxyUrl = cfg?.models?.proxy?.trim();
// No proxy configured - restore original dispatcher if we changed it // No proxy configured - restore original dispatcher if we changed it

View File

@ -1,6 +1,6 @@
import { Type } from "@sinclair/typebox"; import { Type } from "@sinclair/typebox";
import type { ClawdbotConfig } from "../../config/config.js"; import type { MoltbotConfig } from "../../config/config.js";
import type { AnyAgentTool } from "./common.js"; import type { AnyAgentTool } from "./common.js";
import { jsonResult, readNumberParam, readStringParam } from "./common.js"; import { jsonResult, readNumberParam, readStringParam } from "./common.js";
@ -18,7 +18,7 @@ const DEFAULT_PRE_SEARCH_BYTE_THRESHOLD = 100;
// Types // Types
// ============================================================================ // ============================================================================
type QverisConfig = NonNullable<ClawdbotConfig["tools"]>["qveris"]; type QverisConfig = NonNullable<MoltbotConfig["tools"]>["qveris"];
/** Search result parameter from QVeris API */ /** Search result parameter from QVeris API */
interface QverisSearchResultParam { interface QverisSearchResultParam {
@ -83,7 +83,7 @@ interface QverisToolMapping {
// Config Resolution // Config Resolution
// ============================================================================ // ============================================================================
function resolveQverisConfig(cfg?: ClawdbotConfig): QverisConfig { function resolveQverisConfig(cfg?: MoltbotConfig): QverisConfig {
return cfg?.tools?.qveris; return cfg?.tools?.qveris;
} }
@ -386,7 +386,7 @@ function sanitizeToolName(toolId: string): string {
// ============================================================================ // ============================================================================
export function createQverisTools(options?: { export function createQverisTools(options?: {
config?: ClawdbotConfig; config?: MoltbotConfig;
sandboxed?: boolean; sandboxed?: boolean;
agentSessionKey?: string; agentSessionKey?: string;
}): AnyAgentTool[] { }): AnyAgentTool[] {
@ -408,7 +408,8 @@ export function createQverisTools(options?: {
const searchLimit = resolveSearchLimit(config); const searchLimit = resolveSearchLimit(config);
// Generate a session ID tied to clawdbot session key // Generate a session ID tied to clawdbot session key
const sessionId = options?.agentSessionKey ?? `clawdbot-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`; const sessionId =
options?.agentSessionKey ?? `clawdbot-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
const searchTool: AnyAgentTool = { const searchTool: AnyAgentTool = {
label: "QVeris Search", label: "QVeris Search",
@ -508,9 +509,12 @@ export function createQverisTools(options?: {
* Check if QVeris tools are enabled/available * Check if QVeris tools are enabled/available
*/ */
export function isQverisEnabled(options?: { export function isQverisEnabled(options?: {
config?: ClawdbotConfig; config?: MoltbotConfig;
sandboxed?: boolean; sandboxed?: boolean;
}): boolean { }): boolean {
const config = resolveQverisConfig(options?.config); const config = resolveQverisConfig(options?.config);
return resolveQverisEnabled({ config, sandboxed: options?.sandboxed }) && Boolean(resolveQverisApiKey(config)); return (
resolveQverisEnabled({ config, sandboxed: options?.sandboxed }) &&
Boolean(resolveQverisApiKey(config))
);
} }

View File

@ -1,4 +1,4 @@
import type { ClawdbotConfig } from "../config/config.js"; import type { MoltbotConfig } from "../config/config.js";
import type { FeishuAccountConfig } from "../config/types.feishu.js"; import type { FeishuAccountConfig } from "../config/types.feishu.js";
import { isTruthyEnvValue } from "../infra/env.js"; import { isTruthyEnvValue } from "../infra/env.js";
import { listBoundAccountIds, resolveDefaultAgentBoundAccountId } from "../routing/bindings.js"; import { listBoundAccountIds, resolveDefaultAgentBoundAccountId } from "../routing/bindings.js";
@ -19,7 +19,7 @@ export type ResolvedFeishuAccount = {
config: FeishuAccountConfig; config: FeishuAccountConfig;
}; };
function listConfiguredAccountIds(cfg: ClawdbotConfig): string[] { function listConfiguredAccountIds(cfg: MoltbotConfig): string[] {
const accounts = cfg.channels?.feishu?.accounts; const accounts = cfg.channels?.feishu?.accounts;
if (!accounts || typeof accounts !== "object") return []; if (!accounts || typeof accounts !== "object") return [];
const ids = new Set<string>(); const ids = new Set<string>();
@ -30,7 +30,7 @@ function listConfiguredAccountIds(cfg: ClawdbotConfig): string[] {
return [...ids]; return [...ids];
} }
export function listFeishuAccountIds(cfg: ClawdbotConfig): string[] { export function listFeishuAccountIds(cfg: MoltbotConfig): string[] {
const ids = Array.from( const ids = Array.from(
new Set([...listConfiguredAccountIds(cfg), ...listBoundAccountIds(cfg, "feishu")]), new Set([...listConfiguredAccountIds(cfg), ...listBoundAccountIds(cfg, "feishu")]),
); );
@ -39,7 +39,7 @@ export function listFeishuAccountIds(cfg: ClawdbotConfig): string[] {
return ids.sort((a, b) => a.localeCompare(b)); return ids.sort((a, b) => a.localeCompare(b));
} }
export function resolveDefaultFeishuAccountId(cfg: ClawdbotConfig): string { export function resolveDefaultFeishuAccountId(cfg: MoltbotConfig): string {
const boundDefault = resolveDefaultAgentBoundAccountId(cfg, "feishu"); const boundDefault = resolveDefaultAgentBoundAccountId(cfg, "feishu");
if (boundDefault) return boundDefault; if (boundDefault) return boundDefault;
const ids = listFeishuAccountIds(cfg); const ids = listFeishuAccountIds(cfg);
@ -48,7 +48,7 @@ export function resolveDefaultFeishuAccountId(cfg: ClawdbotConfig): string {
} }
function resolveAccountConfig( function resolveAccountConfig(
cfg: ClawdbotConfig, cfg: MoltbotConfig,
accountId: string, accountId: string,
): FeishuAccountConfig | undefined { ): FeishuAccountConfig | undefined {
const accounts = cfg.channels?.feishu?.accounts; const accounts = cfg.channels?.feishu?.accounts;
@ -60,7 +60,7 @@ function resolveAccountConfig(
return matchKey ? (accounts[matchKey] as FeishuAccountConfig | undefined) : undefined; return matchKey ? (accounts[matchKey] as FeishuAccountConfig | undefined) : undefined;
} }
function mergeFeishuAccountConfig(cfg: ClawdbotConfig, accountId: string): FeishuAccountConfig { function mergeFeishuAccountConfig(cfg: MoltbotConfig, accountId: string): FeishuAccountConfig {
const { accounts: _ignored, ...base } = (cfg.channels?.feishu ?? {}) as FeishuAccountConfig & { const { accounts: _ignored, ...base } = (cfg.channels?.feishu ?? {}) as FeishuAccountConfig & {
accounts?: unknown; accounts?: unknown;
}; };
@ -69,7 +69,7 @@ function mergeFeishuAccountConfig(cfg: ClawdbotConfig, accountId: string): Feish
} }
export function resolveFeishuAccount(params: { export function resolveFeishuAccount(params: {
cfg: ClawdbotConfig; cfg: MoltbotConfig;
accountId?: string | null; accountId?: string | null;
}): ResolvedFeishuAccount { }): ResolvedFeishuAccount {
const hasExplicitAccountId = Boolean(params.accountId?.trim()); const hasExplicitAccountId = Boolean(params.accountId?.trim());
@ -108,7 +108,7 @@ export function resolveFeishuAccount(params: {
return fallback; return fallback;
} }
export function listEnabledFeishuAccounts(cfg: ClawdbotConfig): ResolvedFeishuAccount[] { export function listEnabledFeishuAccounts(cfg: MoltbotConfig): ResolvedFeishuAccount[] {
return listFeishuAccountIds(cfg) return listFeishuAccountIds(cfg)
.map((accountId) => resolveFeishuAccount({ cfg, accountId })) .map((accountId) => resolveFeishuAccount({ cfg, accountId }))
.filter((account) => account.enabled); .filter((account) => account.enabled);

View File

@ -4,7 +4,7 @@
* Processes incoming messages and generates responses using the agent system. * Processes incoming messages and generates responses using the agent system.
*/ */
import type { ClawdbotConfig } from "../config/config.js"; import type { MoltbotConfig } from "../config/config.js";
import { loadConfig } from "../config/config.js"; import { loadConfig } from "../config/config.js";
import { resolveDefaultAgentId } from "../agents/agent-scope.js"; import { resolveDefaultAgentId } from "../agents/agent-scope.js";
import { DEFAULT_GROUP_HISTORY_LIMIT, type HistoryEntry } from "../auto-reply/reply/history.js"; import { DEFAULT_GROUP_HISTORY_LIMIT, type HistoryEntry } from "../auto-reply/reply/history.js";
@ -22,7 +22,7 @@ import type { FeishuMessageContext } from "./monitor.js";
export type FeishuBotOptions = { export type FeishuBotOptions = {
accountId?: string; accountId?: string;
runtime?: RuntimeEnv; runtime?: RuntimeEnv;
config?: ClawdbotConfig; config?: MoltbotConfig;
/** Whether to require @mention in group chats */ /** Whether to require @mention in group chats */
requireMention?: boolean; requireMention?: boolean;
/** Allowlist for DM senders */ /** Allowlist for DM senders */
@ -42,7 +42,7 @@ export type FeishuBotContext = {
export class FeishuBot { export class FeishuBot {
readonly account: ResolvedFeishuAccount; readonly account: ResolvedFeishuAccount;
readonly client: FeishuClient; readonly client: FeishuClient;
readonly cfg: ClawdbotConfig; readonly cfg: MoltbotConfig;
readonly runtime: RuntimeEnv; readonly runtime: RuntimeEnv;
private readonly historyLimit: number; private readonly historyLimit: number;
@ -276,7 +276,7 @@ export function buildFeishuSessionKey(params: {
agentId?: string; agentId?: string;
chatId: string; chatId: string;
chatType: "p2p" | "group"; chatType: "p2p" | "group";
cfg?: ClawdbotConfig; cfg?: MoltbotConfig;
}): string { }): string {
const cfg = params.cfg ?? loadConfig(); const cfg = params.cfg ?? loadConfig();
const agentId = params.agentId ?? resolveDefaultAgentId(cfg); const agentId = params.agentId ?? resolveDefaultAgentId(cfg);

View File

@ -5,7 +5,7 @@
* similar to how Telegram messages are handled. * similar to how Telegram messages are handled.
*/ */
import type { ClawdbotConfig } from "../config/config.js"; import type { MoltbotConfig } from "../config/config.js";
import type { RuntimeEnv } from "../runtime.js"; import type { RuntimeEnv } from "../runtime.js";
import type { ResolvedFeishuAccount } from "./accounts.js"; import type { ResolvedFeishuAccount } from "./accounts.js";
import type { FeishuMessageContext } from "./monitor.js"; import type { FeishuMessageContext } from "./monitor.js";
@ -32,7 +32,7 @@ const feishuMessageDedupe = createDedupeCache({
export type DispatchFeishuMessageParams = { export type DispatchFeishuMessageParams = {
ctx: FeishuMessageContext; ctx: FeishuMessageContext;
cfg: ClawdbotConfig; cfg: MoltbotConfig;
runtime?: RuntimeEnv; runtime?: RuntimeEnv;
account: ResolvedFeishuAccount; account: ResolvedFeishuAccount;
}; };
@ -49,7 +49,7 @@ function buildFeishuPeerId(chatId: string, threadId?: string): string {
*/ */
function isFeishuSenderAllowed( function isFeishuSenderAllowed(
ctx: FeishuMessageContext, ctx: FeishuMessageContext,
cfg: ClawdbotConfig, cfg: MoltbotConfig,
account: ResolvedFeishuAccount, account: ResolvedFeishuAccount,
): { allowed: boolean; reason?: string } { ): { allowed: boolean; reason?: string } {
const isGroup = ctx.chatType === "group"; const isGroup = ctx.chatType === "group";
@ -104,7 +104,7 @@ function isFeishuSenderAllowed(
*/ */
function requiresFeishuMention( function requiresFeishuMention(
ctx: FeishuMessageContext, ctx: FeishuMessageContext,
cfg: ClawdbotConfig, cfg: MoltbotConfig,
account: ResolvedFeishuAccount, account: ResolvedFeishuAccount,
): boolean { ): boolean {
if (ctx.chatType !== "group") return false; if (ctx.chatType !== "group") return false;

View File

@ -9,7 +9,7 @@
import { createServer, type IncomingMessage, type ServerResponse } from "node:http"; import { createServer, type IncomingMessage, type ServerResponse } from "node:http";
import os from "node:os"; import os from "node:os";
import type { ClawdbotConfig } from "../config/config.js"; import type { MoltbotConfig } from "../config/config.js";
import { loadConfig } from "../config/config.js"; import { loadConfig } from "../config/config.js";
import { computeBackoff, sleepWithAbort } from "../infra/backoff.js"; import { computeBackoff, sleepWithAbort } from "../infra/backoff.js";
import { formatErrorMessage } from "../infra/errors.js"; import { formatErrorMessage } from "../infra/errors.js";
@ -31,7 +31,7 @@ import { resolveFeishuEncryptKey, resolveFeishuVerificationToken } from "./token
export type MonitorFeishuOpts = { export type MonitorFeishuOpts = {
accountId?: string; accountId?: string;
config?: ClawdbotConfig; config?: MoltbotConfig;
runtime?: RuntimeEnv; runtime?: RuntimeEnv;
abortSignal?: AbortSignal; abortSignal?: AbortSignal;
/** Override event mode (webhook or websocket) */ /** Override event mode (webhook or websocket) */
@ -59,7 +59,7 @@ export type FeishuMessageContext = {
threadId?: string; threadId?: string;
client: FeishuClient; client: FeishuClient;
account: ResolvedFeishuAccount; account: ResolvedFeishuAccount;
cfg: ClawdbotConfig; cfg: MoltbotConfig;
runtime?: RuntimeEnv; runtime?: RuntimeEnv;
/** Reply to this message */ /** Reply to this message */
reply: (text: string) => Promise<void>; reply: (text: string) => Promise<void>;
@ -97,7 +97,7 @@ function createMessageContext(
event: FeishuMessageReceiveEvent, event: FeishuMessageReceiveEvent,
client: FeishuClient, client: FeishuClient,
account: ResolvedFeishuAccount, account: ResolvedFeishuAccount,
cfg: ClawdbotConfig, cfg: MoltbotConfig,
runtime?: RuntimeEnv, runtime?: RuntimeEnv,
): FeishuMessageContext { ): FeishuMessageContext {
const msg = event.event.message; const msg = event.event.message;

View File

@ -2,7 +2,7 @@
* Feishu message sending utilities * Feishu message sending utilities
*/ */
import type { ClawdbotConfig } from "../config/config.js"; import type { MoltbotConfig } from "../config/config.js";
import { loadConfig } from "../config/config.js"; import { loadConfig } from "../config/config.js";
import { formatErrorMessage } from "../infra/errors.js"; import { formatErrorMessage } from "../infra/errors.js";
import type { RuntimeEnv } from "../runtime.js"; import type { RuntimeEnv } from "../runtime.js";
@ -17,7 +17,7 @@ export type SendFeishuMessageParams = {
to: string; to: string;
text: string; text: string;
accountId?: string | null; accountId?: string | null;
config?: ClawdbotConfig; config?: MoltbotConfig;
runtime?: RuntimeEnv; runtime?: RuntimeEnv;
/** Receive ID type: chat_id (default), open_id, user_id, union_id, email */ /** Receive ID type: chat_id (default), open_id, user_id, union_id, email */
receiveIdType?: "chat_id" | "open_id" | "user_id" | "union_id" | "email"; receiveIdType?: "chat_id" | "open_id" | "user_id" | "union_id" | "email";
@ -118,7 +118,7 @@ export async function reactMessageFeishu(params: {
messageId: string; messageId: string;
emoji: string; emoji: string;
accountId?: string | null; accountId?: string | null;
config?: ClawdbotConfig; config?: MoltbotConfig;
runtime?: RuntimeEnv; runtime?: RuntimeEnv;
}): Promise<{ success: boolean; error?: string }> { }): Promise<{ success: boolean; error?: string }> {
const cfg = params.config ?? loadConfig(); const cfg = params.config ?? loadConfig();
@ -160,7 +160,7 @@ export async function reactMessageFeishu(params: {
export async function deleteMessageFeishu(params: { export async function deleteMessageFeishu(params: {
messageId: string; messageId: string;
accountId?: string | null; accountId?: string | null;
config?: ClawdbotConfig; config?: MoltbotConfig;
runtime?: RuntimeEnv; runtime?: RuntimeEnv;
}): Promise<{ success: boolean; error?: string }> { }): Promise<{ success: boolean; error?: string }> {
const cfg = params.config ?? loadConfig(); const cfg = params.config ?? loadConfig();
@ -195,7 +195,7 @@ export async function editMessageFeishu(params: {
messageId: string; messageId: string;
text: string; text: string;
accountId?: string | null; accountId?: string | null;
config?: ClawdbotConfig; config?: MoltbotConfig;
runtime?: RuntimeEnv; runtime?: RuntimeEnv;
msgType?: "text" | "post"; msgType?: "text" | "post";
postContent?: FeishuPostContent; postContent?: FeishuPostContent;

View File

@ -1,6 +1,6 @@
import fs from "node:fs"; import fs from "node:fs";
import type { ClawdbotConfig } from "../config/config.js"; import type { MoltbotConfig } from "../config/config.js";
import type { FeishuAccountConfig } from "../config/types.feishu.js"; import type { FeishuAccountConfig } from "../config/types.feishu.js";
import { resolveUserPath } from "../utils.js"; import { resolveUserPath } from "../utils.js";
@ -13,7 +13,7 @@ export type FeishuCredentials = {
}; };
function resolveAccountConfig( function resolveAccountConfig(
cfg: ClawdbotConfig, cfg: MoltbotConfig,
accountId: string, accountId: string,
): FeishuAccountConfig | undefined { ): FeishuAccountConfig | undefined {
const accounts = cfg.channels?.feishu?.accounts; const accounts = cfg.channels?.feishu?.accounts;
@ -25,7 +25,7 @@ function resolveAccountConfig(
return matchKey ? (accounts[matchKey] as FeishuAccountConfig | undefined) : undefined; return matchKey ? (accounts[matchKey] as FeishuAccountConfig | undefined) : undefined;
} }
function mergeFeishuAccountConfig(cfg: ClawdbotConfig, accountId: string): FeishuAccountConfig { function mergeFeishuAccountConfig(cfg: MoltbotConfig, accountId: string): FeishuAccountConfig {
const { accounts: _ignored, ...base } = (cfg.channels?.feishu ?? {}) as FeishuAccountConfig & { const { accounts: _ignored, ...base } = (cfg.channels?.feishu ?? {}) as FeishuAccountConfig & {
accounts?: unknown; accounts?: unknown;
}; };
@ -44,7 +44,7 @@ function readSecretFile(filePath: string): string | undefined {
} }
export function resolveFeishuCredentials( export function resolveFeishuCredentials(
cfg: ClawdbotConfig, cfg: MoltbotConfig,
opts?: { accountId?: string | null }, opts?: { accountId?: string | null },
): FeishuCredentials { ): FeishuCredentials {
const accountId = opts?.accountId?.trim() || "default"; const accountId = opts?.accountId?.trim() || "default";
@ -74,7 +74,7 @@ export function resolveFeishuCredentials(
} }
export function resolveFeishuVerificationToken( export function resolveFeishuVerificationToken(
cfg: ClawdbotConfig, cfg: MoltbotConfig,
opts?: { accountId?: string | null }, opts?: { accountId?: string | null },
): string | undefined { ): string | undefined {
const accountId = opts?.accountId?.trim() || "default"; const accountId = opts?.accountId?.trim() || "default";
@ -88,7 +88,7 @@ export function resolveFeishuVerificationToken(
} }
export function resolveFeishuEncryptKey( export function resolveFeishuEncryptKey(
cfg: ClawdbotConfig, cfg: MoltbotConfig,
opts?: { accountId?: string | null }, opts?: { accountId?: string | null },
): string | undefined { ): string | undefined {
const accountId = opts?.accountId?.trim() || "default"; const accountId = opts?.accountId?.trim() || "default";