refactor(comments): deslop production narration

## What Problem This Solves

Production code still carries duplicated narration over function names, types, branches and CSS selectors. Some of that prose has drifted: Zalo polling is described as development-only even though it is the default production route, and a joined hook helper is called fire-and-forget.

## User Impact

No user-visible behavior changes. Runtime logic, templates, CSS declarations, configuration, persisted state, wire formats, public API documentation, licenses and lint-suppression reasons remain intact.

## Why This Change Was Made

This maintainer-requested cleanup removes redundant internal helper/registrar summaries, repeated section labels, and obsolete inline font-size history. Existing declarations and shared owners already express these facts; no new abstraction is needed. Comments explaining authority, lifecycle, ordering, cleanup, platform constraints, dependencies and public contracts stay.

The measured reduction is 696 net production/tooling lines: 604 standalone comment lines and 92 adjacent blank lines, plus 59 inline comment removals without net line savings. No tests or generated files changed. This is a bounded contextual sweep, not a claim of exhaustive repository coverage; the local census records exact findings, retained candidates, and unread files. Filename-header cleanup from #161768 is excluded.

## Evidence

Independent review completed; all accepted documentation findings were addressed by restoring base comments. The remaining changed files are byte-identical to the reviewed and remotely frozen candidate.

Blacksmith Testbox validation:
- Parser comparison: identical non-comment TypeScript tokens and CSS structure.
- Both import-cycle checks: 0 cycles.
- Focused existing tests: 40 Vitest shards passed (521.71 seconds).
- Plugin contracts: 48 files / 1,153 tests passed.
- Plugin, source-to-extension, and SDK/package import-boundary checks passed.
- Feishu asset hook check: no build hooks; no plugin browser/control-UI source changed.

SDK API comparison passed with no API changes. The full changed-file gate passed remotely. The lowered-threshold duplicate census (12 lines / 80 tokens) completed; its raw 155 records include deliberate probe/fixture matches and are not claimed as removable production code. No tests were added or changed.

Public JSDoc was audited independently: the SDK API comparison strips comments, while shipped declarations can preserve them, so API-shape equality alone would not prove documentation preservation.


### Inherited hosted CI failure

Exact-head [CI run 36815106181](https://github.com/openclaw/openclaw/actions/runs/36815106181) tested `ff26a4c05d3b41d25477df41cb94010c6cac5cb0` merged with main `75d1f82c18`. The only failing test job was `checks-node-compact-small-19`: `test/helpers/openclaw-test-instance.acquisition.test.ts:33`, “keeps an absent Gateway unreachable while retaining its port claims,” expected `free` but received `busy`. The other failure is the aggregate CI gate. This attempt has 84 successful jobs, 16 skipped jobs, and 88 collateral cancellations; cancelled coverage is not counted as passing.

The identical assertion and error were independently verified in [job 110052175838](https://github.com/openclaw/openclaw/actions/runs/36763489663/job/110052175838), the latest attempt (1) for unrelated PR #162070's final head `d07a6981d4`. The acquisition test, instance helper, cleanup wrapper, isolated-state writer, port allocator, claim owner, claim-lock owner and TCP probe are byte-identical between that head and this PR. No changed file participates in the failing acquisition/probe path. The failure precedes Gateway startup; the logs do not identify the competing listener, so no root-cause repair is claimed.

Landing uses the maintainer-authorized inherited-failure exception pinned to this exact head, backed by the passing remote gates above. The fixture defect remains with the main-CI coordinator. No workflow rerun, test weakening, timeout increase, or source repush was used to obtain green. GitHub's GraphQL writer rejected auto-merge because its quota was exhausted; the request was reconciled as absent before selecting the supported REST squash path.
This commit is contained in:
Peter Steinberger 2026-09-30 22:28:36 -07:00 • committed by GitHub
parent 504d2905d6
commit 799ddbd35d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
164 changed files with 59 additions and 755 deletions

View file

@ -194,7 +194,6 @@ export async function handleDiscordMessageManagementAction(ctx: DiscordMessaging
}
const channelId = readStringParam(ctx.params, "channelId");
const channelIds = readStringArrayParam(ctx.params, "channelIds");
// Resolve guildId from channel info when not explicitly provided.
if (!guildId) {
const rawInferChannelId = channelId ?? channelIds?.[0];
if (rawInferChannelId) {

View file

@ -304,9 +304,7 @@ const FeishuConfigSchemaBase = z
requireMention: z.boolean().optional(),
groupSessionScope: GroupSessionScopeSchema,
topicSessionMode: TopicSessionModeSchema,
// Dynamic agent creation for DM users
dynamicAgentCreation: DynamicAgentCreationSchema,
// Optimization flags
typingIndicator: z.boolean().optional().default(true),
resolveSenderNames: z.boolean().optional().default(true),
})

View file

@ -71,7 +71,6 @@ export const FeishuDocSchema = Type.Union([
doc_token: Type.String({ description: "Document token" }),
block_id: Type.String({ description: "Block ID" }),
}),
// Table creation (explicit structure)
Type.Object({
action: Type.Literal("create_table"),
...tableCreationProperties,
@ -93,7 +92,6 @@ export const FeishuDocSchema = Type.Union([
minItems: 1,
}),
}),
// Table row/column manipulation
Type.Object({
action: Type.Literal("insert_table_row"),
doc_token: Type.String({ description: "Document token" }),
@ -135,7 +133,6 @@ export const FeishuDocSchema = Type.Union([
column_start: Type.Number({ description: "Start column index" }),
column_end: Type.Number({ description: "End column index (exclusive)" }),
}),
// Image / file upload
Type.Object({
action: Type.Literal("upload_image"),
doc_token: Type.String({ description: "Document token" }),
@ -168,7 +165,6 @@ export const FeishuDocSchema = Type.Union([
),
filename: Type.Optional(Type.String({ description: "Optional filename override" })),
}),
// Text color / style
Type.Object({
action: Type.Literal("color_text"),
doc_token: Type.String({ description: "Document token" }),

View file

@ -30,7 +30,6 @@ function calculateAdaptiveColumnWidths(
return [];
}
// Use original total width from Convert API, or fall back to default
const totalWidth =
originalWidths && originalWidths.length > 0
? originalWidths.reduce((a: number, b: number) => a + b, 0)

View file

@ -23,8 +23,6 @@ import { createFeishuToolClient } from "./tool-account.js";
import { registerFeishuTool } from "./tool-registration.js";
import { feishuExternalToolResult as jsonResult, unknownToolActionResult } from "./tool-result.js";
// ============ Actions ============
type FeishuExplorerRootFolderMetaResponse = {
code: number;
msg?: string;
@ -632,8 +630,6 @@ export async function deliverCommentThreadText(
}
}
// ============ Tool Registration ============
export function registerFeishuDriveTools(api: OpenClawPluginApi) {
registerFeishuTool(api, {
family: "drive",

View file

@ -10,8 +10,6 @@ type ListTokenType = NonNullable<
NonNullable<Parameters<Lark.Client["drive"]["permissionMember"]["list"]>[0]>["params"]
>["type"];
// ============ Actions ============
async function listMembers(client: Lark.Client, token: string, type: string) {
const res = await client.drive.permissionMember.list({
path: { token },
@ -66,8 +64,6 @@ async function removeMember(
};
}
// ============ Tool Registration ============
export function registerFeishuPermTools(api: OpenClawPluginApi) {
registerFeishuTool(api, {
family: "perm",

View file

@ -42,9 +42,6 @@ export async function addReactionFeishu(params: {
return { reactionId };
}
/**
* Remove a reaction from a message.
*/
export async function removeReactionFeishu(params: {
cfg: ClawdbotConfig;
messageId: string;
@ -64,9 +61,6 @@ export async function removeReactionFeishu(params: {
assertFeishuApiSuccess(response, "Feishu remove reaction failed");
}
/**
* List all reactions for a message.
*/
export async function listReactionsFeishu(params: {
cfg: ClawdbotConfig;
messageId: string;

View file

@ -115,7 +115,6 @@ function normalizeEpochMs(timestamp: number | undefined): number | undefined {
return timestamp < MS_EPOCH_MIN ? timestamp * 1000 : timestamp;
}
/** Build a card header from agent identity config. */
function resolveCardHeader(
agentId: string,
identity: OutboundIdentity | undefined,
@ -132,7 +131,6 @@ function resolveCardHeader(
};
}
/** Build a card note footer from agent identity and model context. */
function resolveCardNote(
agentId: string,
identity: OutboundIdentity | undefined,
@ -222,7 +220,6 @@ export function createFeishuReplyDispatcher(params: CreateFeishuReplyDispatcherP
accountId,
typing: {
start: async () => {
// Check if typing indicator is enabled (default: true)
if (!(account.config.typingIndicator ?? true)) {
return;
}

View file

@ -94,7 +94,6 @@ type FeishuGetMessageResponse = {
};
};
/** Send a direct message as a fallback when a reply target is unavailable. */
async function sendFallbackDirect(
client: ReturnType<typeof createFeishuClient>,
params: {
@ -270,10 +269,6 @@ function parseFeishuMessageItem(
};
}
/**
* Get a message by its ID.
* Useful for fetching quoted/replied message content.
*/
export async function getMessageFeishu(params: {
cfg: ClawdbotConfig;
messageId: string;
@ -433,7 +428,6 @@ type SendFeishuMessageParams = {
/** When true, reply creates a Feishu topic thread instead of an inline reply */
replyInThread?: boolean;
allowTopLevelReplyFallback?: boolean;
/** Mention target users */
mentions?: MentionTarget[];
/** Account ID (optional, uses default if not specified) */
accountId?: string;
@ -538,17 +532,12 @@ export async function editMessageFeishu(params: {
return { messageId, contentType: "post" };
}
/** Header configuration for structured Feishu cards. */
export type CardHeaderConfig = {
/** Header title text, e.g. "💻 Coder" */
title: string;
/** Feishu header color template (blue, green, red, orange, purple, grey, etc.). Defaults to "blue". */
template?: string;
};
/**
* Build a Feishu interactive card with optional header and note footer.
*/
function buildStructuredCard(
text: string,
options?: {
@ -604,9 +593,6 @@ export function chunkFeishuCardMarkdown(
});
}
/**
* Send a message as a structured card with optional header and note.
*/
export async function sendStructuredCardFeishu(
params: Omit<SendFeishuMessageParams, "preparedPostText"> & {
header?: CardHeaderConfig;

View file

@ -258,7 +258,6 @@ async function runNewAppFlow(params: {
scanDomain = scanResult.domain;
scanOpenId = scanResult.openId;
} else {
// Fallback to manual input: collect domain, appId, appSecret.
await noteFeishuCredentialHelp(prompter);
appId = (
@ -288,7 +287,6 @@ async function runNewAppFlow(params: {
appSecretProbeValue = appSecretResult.resolvedValue;
}
// Fetch openId via API for manual flow.
if (appId && appSecretProbeValue) {
const { getAppOwnerOpenId } = await loadAppRegistrationModule();
scanOpenId = await getAppOwnerOpenId({

View file

@ -233,7 +233,6 @@ export function mergeStreamingText(
return `${previous}${next}`;
}
/** Streaming card session manager */
export class FeishuStreamingSession {
private client: Client;
private creds: Credentials;
@ -573,12 +572,10 @@ export class FeishuStreamingSession {
}
}
// Update note with final model/provider info
if (options?.note) {
await this.updateNoteContent(options.note);
}
// Close streaming mode
// A rejected final write must not advertise content that CardKit never accepted.
const acceptedText = this.state.sentText;
this.state.sequence += 1;

View file

@ -16,7 +16,6 @@ const DEFAULT_TOOLS_CONFIG: Required<FeishuToolsConfig> = {
bitable: true,
};
/** Resolve tools config with defaults. */
export function resolveToolsConfig(cfg?: FeishuToolsConfig): Required<FeishuToolsConfig> {
return { ...DEFAULT_TOOLS_CONFIG, ...cfg };
}

View file

@ -11,8 +11,6 @@ type ObjType = "doc" | "sheet" | "mindnote" | "bitable" | "file" | "docx" | "sli
const WIKI_PAGE_SIZE = 50;
// ============ Actions ============
const WIKI_ACCESS_HINT =
"To grant wiki access: Open wiki space → Settings → Members → Add the bot. " +
"See: https://open.feishu.cn/document/server-docs/docs/wiki-v2/wiki-qa#a40ad4ca";
@ -186,8 +184,6 @@ async function renameNode(client: Lark.Client, spaceId: string, nodeToken: strin
};
}
// ============ Tool Registration ============
export function registerFeishuWikiTools(api: OpenClawPluginApi) {
registerFeishuTool(api, {
family: "wiki",

View file

@ -159,7 +159,6 @@ function parseCardArgs(argsStrInput: string): {
flags: {},
};
// Extract type (first word)
const typeMatch = argsStr.match(/^(\w+)/);
if (typeMatch) {
result.type = normalizeLowercaseStringOrEmpty(typeMatch[1]);

View file

@ -13,7 +13,6 @@ import type {
VideoFileInfo,
} from "../sdk.js";
// Message types
export const MsgType = {
Text: "m.text",
Image: "m.image",
@ -23,14 +22,12 @@ export const MsgType = {
Notice: "m.notice",
} as const;
// Relation types
export const RelationType = {
Annotation: MATRIX_ANNOTATION_RELATION_TYPE,
Replace: "m.replace",
Thread: "m.thread",
} as const;
// Event types
export const EventType = {
Direct: "m.direct",
Reaction: MATRIX_REACTION_EVENT_TYPE,

View file

@ -15,7 +15,6 @@ const MATTERMOST_QUESTION_CONTEXT_KEY = "oc_question";
export type MattermostQuestionSelection = { questionId: string; optionIndex: number };
/** One interactive button as this plugin hands it to the attachment builder. */
type MattermostPresentationButton = {
id: string;
text: string;

View file

@ -62,9 +62,6 @@ async function findStandardChannelMember(params: {
return result.found;
}
/**
* Fetch a user profile from Microsoft Graph by user ID.
*/
export async function getMemberInfoMSTeams(params: GetMemberInfoMSTeamsParams) {
const isCurrentRequester =
normalizeUserId(params.userId) === normalizeUserId(params.currentRequesterId);

View file

@ -8,10 +8,6 @@ import { resolveMSTeamsRouteSessionKey } from "./thread-session.js";
type ReactionDirection = "added" | "removed";
/**
* Create a handler for MS Teams reaction activities (reactionsAdded / reactionsRemoved).
* The returned function accepts a turn context and a direction string.
*/
export function createMSTeamsReactionHandler(deps: MSTeamsMessageHandlerDeps) {
const { cfg, log } = deps;
const core = getMSTeamsRuntime();
@ -23,7 +19,6 @@ export function createMSTeamsReactionHandler(deps: MSTeamsMessageHandlerDeps) {
): Promise<void> {
const activity = context.activity;
// Reactions are carried in reactionsAdded / reactionsRemoved on the activity.
const rawReactions =
direction === "added" ? activity.reactionsAdded : activity.reactionsRemoved;
const reactions: Array<{ type?: string }> = Array.isArray(rawReactions) ? rawReactions : [];
@ -78,7 +73,6 @@ export function createMSTeamsReactionHandler(deps: MSTeamsMessageHandlerDeps) {
}
}
// Resolve the agent route for this conversation/sender.
// Extract teamId for team-scoped routing bindings (channel/group reactions).
const teamId = isDirectMessage ? undefined : activity.channelData?.team?.id;
const route = core.channel.routing.resolveAgentRoute({

View file

@ -60,13 +60,11 @@ type RelayMetrics = {
};
export interface MetricEvent {
/** Metric name (e.g., "event.received", "relay.connect") */
name: MetricName;
/** Metric value (usually 1 for counters, or a measured value) */
value: number;
/** Unix timestamp in milliseconds */
timestamp: number;
/** Optional labels for additional context */
labels?: Record<string, string | number>;
}
@ -240,9 +238,6 @@ export function createMetrics(onMetric?: OnMetricCallback) {
export type MetricsSnapshot = ReturnType<typeof createMetricsSnapshot>;
export type NostrMetrics = ReturnType<typeof createMetrics>;
/**
* Create a no-op metrics instance (for when metrics are disabled).
*/
export function createNoopMetrics(): NostrMetrics {
const emptySnapshot = createMetricsSnapshot(createZeroMetricsState(), 0);

View file

@ -748,7 +748,6 @@ export async function containerRpcRequest<T = unknown>(
timeoutMs: opts.timeoutMs,
maxResponseBytes: opts.maxResponseBytes,
});
// Convert to native format: { data: base64String }
if (!buffer) {
return { data: undefined } as T;
}

View file

@ -1384,7 +1384,6 @@ export async function prepareSlackMessage(params: {
});
}
// Use direct media (including forwarded attachment media) if available, else thread starter media
const effectiveMedia = effectiveDirectMedia ?? threadStarterMedia;
let inboundMedia = await toInboundMediaFactsWithMetadata(effectiveMedia, {
transcribed: (entry) =>

View file

@ -485,7 +485,6 @@ export function createTelegramRequestWithDiag(params: {
function wrapTelegramChatNotFoundError(err: unknown, params: { chatId: string; input: string }) {
const errorMsg = formatErrorMessage(err);
// Check for 403 "bot is not a member" or "bot was blocked" errors
if (/403.*(bot.*not.*member|bot.*blocked|bot.*kicked)/i.test(errorMsg)) {
return new Error(
[

View file

@ -169,7 +169,6 @@ export async function sendMessageTelegram(
const tableMode = opts.tableMode ?? resolveTelegramTableMode(richMessagesParams);
const renderHtmlText = (value: string) =>
renderTelegramHtmlText(value, { textMode, tableMode });
// Resolve link preview setting from config (default: enabled).
const linkPreviewEnabled = account.config.linkPreview ?? true;
const linkPreviewOptions = linkPreviewEnabled ? undefined : { is_disabled: true };

View file

@ -251,7 +251,6 @@ export function extractMessageText(content: unknown): string {
return "";
}
// Handle inline content (text, ships, links, etc.)
if (Array.isArray(verseRecord.inline)) {
return verseRecord.inline
.map((item) =>
@ -264,12 +263,10 @@ export function extractMessageText(content: unknown): string {
.join("");
}
// Handle block content (images, code blocks, etc.)
const block = asNullableRecord(verseRecord.block);
if (block) {
const image = asNullableRecord(block.image);
// Image blocks
if (image) {
const imageSrc = readStringField(image, "src");
if (imageSrc) {
@ -279,7 +276,6 @@ export function extractMessageText(content: unknown): string {
}
}
// Code blocks
const codeBlock = asNullableRecord(block.code);
if (codeBlock) {
const lang = readStringField(codeBlock, "lang") ?? "";
@ -287,7 +283,6 @@ export function extractMessageText(content: unknown): string {
return `\n\`\`\`${lang}\n${code}\n\`\`\`\n`;
}
// Header blocks
const header = asNullableRecord(block.header);
if (header) {
const headerContent = Array.isArray(header.content) ? header.content : [];
@ -296,7 +291,6 @@ export function extractMessageText(content: unknown): string {
return `\n## ${text}\n`;
}
// Cite/quote blocks - parse the reference structure
const cite = asNullableRecord(block.cite);
if (cite) {
const chanCite = asNullableRecord(cite.chan);

View file

@ -7,9 +7,6 @@ import type { TwitchClientManager } from "./twitch-client.js";
import type { TwitchAccountConfig } from "./types.js";
import { stripMarkdownForTwitch } from "./utils/markdown.js";
/**
* Result from sending a message to Twitch.
*/
interface SendMessageResult {
outcome?: "not_sent";
/** The message ID (generated for tracking) */

View file

@ -220,7 +220,6 @@ export class CallManager {
const elapsed = Date.now() - maxDurationAnchor;
const maxDurationMs = resolveVoiceCallSecondsTimerDelayMs(this.config.maxDurationSeconds);
if (elapsed >= maxDurationMs) {
// Already expired — remove instead of keeping
verified.delete(callId);
skippedAlreadyElapsedTimers += 1;
continue;

View file

@ -20,7 +20,6 @@ export const CALL_RECORD_EVENT_CHUNKS_NAMESPACE = "call-record-event-chunks";
export const MAX_CALL_RECORD_EVENTS = 1000;
/** Extra metadata entries retained so pruning can safely trim oldest rows. */
export const CALL_RECORD_EVENT_META_MAX_ENTRIES = MAX_CALL_RECORD_EVENTS + 100;
/** Maximum chunks allowed for one persisted call record event. */
const MAX_CHUNKS_PER_CALL_RECORD_EVENT = 48;
export const CALL_RECORD_CHUNK_MAX_ENTRIES =
MAX_CALL_RECORD_EVENTS * MAX_CHUNKS_PER_CALL_RECORD_EVENT + MAX_CHUNKS_PER_CALL_RECORD_EVENT;
@ -51,7 +50,6 @@ type PersistedCallRecord = {
orderKey: string;
};
/** Pair of plugin state stores used for call record events. */
type CallRecordStateStores = {
events: PluginStateKeyedStore<CallRecordEventMeta>;
chunks: PluginStateKeyedStore<CallRecordEventChunk>;
@ -66,12 +64,10 @@ export function resolveVoiceCallLegacyCallLogPath(storePath: string): string {
return path.join(storePath, "calls.jsonl");
}
/** Build env for plugin state stores rooted at the voice-call store path. */
function resolvePluginStateEnv(storePath: string): NodeJS.ProcessEnv {
return { ...process.env, OPENCLAW_STATE_DIR: storePath };
}
/** Open the plugin state stores when the runtime is available. */
function createCallRecordStateStores(
storePath: string,
stateRuntime?: VoiceCallStateRuntime["state"],
@ -130,7 +126,6 @@ function buildNewEventKey(order: { persistedAt: number; sequence: number }): str
return `event:${order.persistedAt.toString(36)}:${String(order.sequence).padStart(6, "0")}:${randomUUID()}`;
}
/** Recover the sequence segment from newer event keys. */
function parseEventKeySequence(key: string): number {
const match = /^event:[^:]+:(\d+):/.exec(key);
const sequence = match?.[1];
@ -175,7 +170,6 @@ export function parseVoiceCallRecordLine(line: string, sequence = 0): PersistedC
}
}
/** Count storage chunks needed for a call record. */
function countCallRecordChunks(call: CallRecord): number {
return Math.max(
1,
@ -310,7 +304,6 @@ function isValidCallRecordChunkCount(chunkCount: number): boolean {
);
}
/** Read and reassemble one chunked call record event. */
async function readCallRecordEvent(
stores: CallRecordStateStores,
eventKey: string,

View file

@ -137,9 +137,7 @@ export class MediaStreamHandler {
private inflightUpgrades = 0;
/** TTS playback queues per stream (serialize audio to prevent overlap) */
private ttsQueues = new Map<string, TtsQueueEntry[]>();
/** Whether TTS is currently playing per stream */
private ttsPlaying = new Map<string, boolean>();
/** Active TTS playback controllers per stream */
private ttsActiveControllers = new Map<string, AbortController>();
private pendingPlaybackMarks = new Map<string, Map<string, PendingPlaybackMark>>();
private ignoredPlaybackMarks = new Map<string, Set<string>>();

View file

@ -96,10 +96,8 @@ export class TwilioProvider implements VoiceCallProvider {
/** Current public webhook URL (set when tunnel starts or from config) */
private currentPublicUrl: string | null = null;
/** Optional telephony TTS provider for streaming TTS */
private ttsProvider: TelephonyTtsProvider | null = null;
/** Optional media stream handler for sending audio */
private mediaStreamHandler: MediaStreamHandler | null = null;
private playbackMarkSequence = 0;
@ -377,13 +375,11 @@ export class TwilioProvider implements VoiceCallProvider {
};
}
// Handle DTMF
const digits = params.get("Digits");
if (digits) {
return { ...baseEvent, type: "call.dtmf", digits };
}
// Handle call status changes
const callStatus = normalizeProviderStatus(params.get("CallStatus"));
if (callStatus === "initiated") {
return { ...baseEvent, type: "call.initiated" };
@ -482,14 +478,11 @@ export class TwilioProvider implements VoiceCallProvider {
return null;
}
// Extract just the origin (host) from the public URL, ignoring any path
const url = new URL(this.currentPublicUrl);
const origin = url.origin;
// Convert https:// to wss:// for WebSocket
const wsOrigin = origin.replace(/^https:\/\//, "wss://").replace(/^http:\/\//, "ws://");
// Append the stream path
const path = this.options.streamPath.startsWith("/")
? this.options.streamPath
: `/${this.options.streamPath}`;
@ -821,10 +814,6 @@ export class TwilioProvider implements VoiceCallProvider {
}
}
// -----------------------------------------------------------------------------
// Twilio-specific types
// -----------------------------------------------------------------------------
interface TwilioCallResponse {
sid: string;
status: string;

View file

@ -26,9 +26,7 @@ import { resolveCallAgentId } from "./resolve-call-agent-id.js";
import { resolveVoiceResponseModel } from "./response-model.js";
type VoiceResponseParams = {
/** Voice call config */
voiceConfig: VoiceCallConfig;
/** Core OpenClaw config */
coreConfig: OpenClawConfig;
/** Injected host agent runtime */
agentRuntime: OpenClawPluginApi["runtime"]["agent"];
@ -44,7 +42,6 @@ type VoiceResponseParams = {
agentId?: string;
/** Audible call transcript, used only for bounded first-turn opening context. */
transcript: Array<{ speaker: "user" | "bot"; text: string }>;
/** Latest user message */
userMessage: string;
/** Delivers completed reply blocks while post-turn work is still running. */
onEarlyText?: (text: string) => Promise<boolean>;
@ -338,7 +335,6 @@ export async function generateVoiceResponse(
});
const toolsAllow = resolveVoiceAgentToolsAllow(cfg, agentId);
// Resolve paths
const storePath = agentRuntime.session.resolveStorePath(cfg.session?.store, { agentId });
try {
return await agentRuntime.session.runWithWorkAdmission(
@ -347,17 +343,14 @@ export async function generateVoiceResponse(
const agentDir = agentRuntime.resolveAgentDir(cfg, agentId);
const workspaceDir = agentRuntime.resolveAgentWorkspaceDir(cfg, agentId);
// Ensure workspace exists
await agentRuntime.ensureAgentWorkspace({ dir: workspaceDir });
// Load or create session entry
const now = Date.now();
const existingSessionEntry = agentRuntime.session.getSessionEntry({
storePath,
sessionKey: resolvedSessionKey,
});
// Resolve model from config
const { provider, model } = resolveVoiceResponseModel({ voiceConfig, agentRuntime });
const configuredModel = resolveDefaultModelForAgent({ cfg, agentId });
@ -417,10 +410,8 @@ export async function generateVoiceResponse(
? resolvePersistedSessionRuntimeId(sessionEntry)
: undefined;
// Resolve thinking level
const thinkLevel = agentRuntime.resolveThinkingDefault({ cfg, provider, model });
// Resolve agent identity for personalized prompt
const identity = agentRuntime.resolveAgentIdentity(cfg, agentId);
const agentName = identity?.name?.trim() || "assistant";
@ -435,7 +426,6 @@ export async function generateVoiceResponse(
].join("\n\n");
const prompt = buildVoiceTurnPrompt({ transcript, userMessage });
// Resolve timeout
const timeoutMs =
voiceConfig.responseTimeoutMs ?? agentRuntime.resolveAgentTimeoutMs({ cfg });
const runId = `voice:${callId}:${Date.now()}`;

View file

@ -65,7 +65,6 @@ function listenForChildStreamErrors(
}
interface TunnelConfig {
/** Tunnel provider: ngrok, tailscale-serve, or tailscale-funnel */
provider: "ngrok" | "tailscale-serve" | "tailscale-funnel" | "none";
/** Local port to tunnel */
port: number;
@ -106,7 +105,6 @@ async function startNgrokTunnel(config: {
authToken?: string;
domain?: string;
}): Promise<TunnelResult> {
// Build ngrok command args
const args = ["http", String(config.port), "--log", "stdout", "--log-format", "json"];
// Add custom domain if provided (paid ngrok feature)
@ -161,17 +159,14 @@ async function startNgrokTunnel(config: {
publicUrl = log.url;
}
// Also check for the URL field directly
if (log.addr && log.url && !publicUrl) {
publicUrl = log.url;
}
// Check for ready state
if (publicUrl && !startupSettled) {
startupSettled = true;
clearTimeout(timeout);
// Add path to the public URL
const fullUrl = publicUrl + config.path;
console.log(`[voice-call] ngrok tunnel active: ${fullUrl}`);

View file

@ -12,9 +12,6 @@ export function escapeXml(text: string): string {
.replace(/'/g, "&apos;");
}
/**
* Map of OpenAI voice names to similar Twilio Polly voices.
*/
const OPENAI_TO_POLLY_MAP = new Map<string, string>([
["alloy", "Polly.Joanna"], // neutral, warm
["echo", "Polly.Matthew"], // male, warm
@ -24,9 +21,6 @@ const OPENAI_TO_POLLY_MAP = new Map<string, string>([
["shimmer", "Polly.Kimberly"], // female, clear
]);
/**
* Default Polly voice when no mapping is found.
*/
const DEFAULT_POLLY_VOICE = "Polly.Joanna";
/**
@ -41,7 +35,6 @@ export function mapVoiceToPolly(voice: string | undefined): string {
return DEFAULT_POLLY_VOICE;
}
// Already a Polly/Google voice - pass through
if (voice.startsWith("Polly.") || voice.startsWith("Google.")) {
return voice;
}

View file

@ -191,12 +191,10 @@ export class VoiceCallWebhookServer {
private stopStaleCallReaper: (() => void) | null = null;
private readonly webhookInFlightLimiter = createWebhookInFlightLimiter();
/** Media stream handler for bidirectional audio (when streaming enabled) */
private mediaStreamHandler: MediaStreamHandler | null = null;
private readonly streamDisconnectGrace: StreamDisconnectGrace;
// Revoke pending transcript replies before persistence has created a response guard.
private readonly streamSpeechGenerations = new WeakMap<CallRecord, symbol>();
/** Realtime voice handler for duplex provider bridges. */
private realtimeHandler: RealtimeCallHandler | null = null;
private replayResponses = new Map<string, CachedWebhookResponse>();
private replayResponseCacheCalls = 0;
@ -348,9 +346,6 @@ export class VoiceCallWebhookServer {
return generation;
}
/**
* Initialize media streaming with the selected realtime transcription provider.
*/
private async initializeMediaStreaming(): Promise<void> {
const streaming = this.config.streaming;
const pluginConfig = this.fullConfig ?? this.coreConfig ?? undefined;
@ -438,7 +433,6 @@ export class VoiceCallWebhookServer {
const generation = this.interruptStreamReply(providerCallId, streamSid);
// Create a speech event and process it through the manager
const event: NormalizedEvent = {
id: `stream-transcript-${Date.now()}`,
type: "call.speech",
@ -519,7 +513,6 @@ export class VoiceCallWebhookServer {
}
/**
* Start the webhook server.
* Idempotent: returns immediately if the server is already listening.
*/
async start(): Promise<string> {
@ -554,7 +547,6 @@ export class VoiceCallWebhookServer {
});
});
// Handle WebSocket upgrades for realtime voice and media streams.
if (this.realtimeHandler || this.mediaStreamHandler) {
this.server.on("upgrade", (request, socket, head) => {
if (this.realtimeHandler && this.isRealtimeWebSocketUpgrade(request)) {
@ -592,7 +584,6 @@ export class VoiceCallWebhookServer {
}
resolve(url);
// Start the stale call reaper if configured
this.stopStaleCallReaper = startStaleCallReaper({
manager: this.manager,
staleCallReaperSeconds: this.config.staleCallReaperSeconds,
@ -1077,7 +1068,6 @@ export class VoiceCallWebhookServer {
private async handleInboundResponse(callId: string, userMessage: string): Promise<void> {
this.logger.info(`Auto-responding to inbound call ${callId} chars=${userMessage.length}`);
// Get the persisted call context for routing and response delivery.
const call = this.manager.getCall(callId);
if (!call) {
this.logger.warn(`Call ${callId} not found for auto-response`);

View file

@ -131,9 +131,6 @@ function resolveZaloApiUrl(apiUrl?: string): string {
return parsed.href.replace(/\/+$/u, "");
}
/**
* Call the Zalo Bot API
*/
export async function callZaloApi<T = unknown>(
method: string,
token: string,
@ -183,9 +180,6 @@ export async function callZaloApi<T = unknown>(
}
}
/**
* Validate bot token and get bot info
*/
export async function getMe(
token: string,
timeoutMs?: number,
@ -194,9 +188,6 @@ export async function getMe(
return callZaloApi<ZaloBotInfo>("getMe", token, undefined, { timeoutMs, fetch: fetcher });
}
/**
* Send a text message
*/
export async function sendMessage(
token: string,
params: ZaloSendMessageParams,
@ -209,9 +200,6 @@ export async function sendMessage(
});
}
/**
* Send a photo message
*/
export async function sendPhoto(
token: string,
params: ZaloSendPhotoParams,
@ -268,7 +256,6 @@ export async function sendChatAction(
}
/**
* Get updates using long polling (dev/testing only)
* Note: Zalo returns a single update per call, not an array like Telegram
*/
export async function getUpdates(
@ -282,9 +269,6 @@ export async function getUpdates(
return callZaloApi<ZaloUpdate>("getUpdates", token, body, { timeoutMs, fetch: fetcher });
}
/**
* Set webhook URL for receiving updates
*/
export async function setWebhook(
token: string,
params: ZaloSetWebhookParams,
@ -293,9 +277,6 @@ export async function setWebhook(
return callZaloApi<ZaloWebhookInfo>("setWebhook", token, params, { fetch: fetcher });
}
/**
* Delete webhook configuration
*/
export async function deleteWebhook(
token: string,
fetcher?: ZaloFetch,
@ -307,9 +288,6 @@ export async function deleteWebhook(
});
}
/**
* Get current webhook info
*/
export async function getWebhookInfo(
token: string,
fetcher?: ZaloFetch,

View file

@ -116,9 +116,6 @@ function parsePositiveIntegerArg(raw: string | undefined, label: string): number
return value;
}
/**
* Parses docs MDX check arguments.
*/
export function parseArgs(argv: string[]) {
const roots: string[] = [];
let jsonOut = "";

View file

@ -17,14 +17,8 @@ const policy = {
} satisfies ExtensionWildcardReexportPolicy;
const scanner = createExtensionWildcardReexportScanner(policy);
/**
* Finds local wildcard re-export lines in a barrel source string.
*/
export const findLocalWildcardReexports = scanner.findLines;
/**
* Runs the extension wildcard re-export guard.
*/
export const main = scanner.main;
await scanner.exitIfMain(import.meta.url);

View file

@ -20,9 +20,6 @@ const enforcedFiles = new Set([
"src/gateway/server-node-events.ts",
]);
/**
* Finds legacy `agentCommand(...)` call lines in ingress-owned source.
*/
function findLegacyAgentCommandCallLines(
_content: string,
_fileName: string,
@ -34,9 +31,6 @@ function findLegacyAgentCommandCallLines(
});
}
/**
* Runs the ingress owner-context guard.
*/
async function main() {
await runCallsiteGuard({
importMetaUrl: import.meta.url,

View file

@ -10,9 +10,6 @@ import {
unwrapExpression,
} from "./lib/ts-guard-utils.mts";
/**
* Source roots scanned for unsafe messaging tmpdir usage.
*/
export const messagingTmpdirGuardSourceRoots = [
"src/channels",
"src/infra/outbound",
@ -55,9 +52,6 @@ function collectOsTmpdirImports(sourceFile: ts.SourceFile) {
return { osNamespaceOrDefault, namedTmpdir };
}
/**
* Finds `os.tmpdir()` or imported `tmpdir()` call lines in source.
*/
export function findMessagingTmpdirCallLines(
_content: string,
_fileName: string,
@ -78,9 +72,6 @@ export function findMessagingTmpdirCallLines(
});
}
/**
* Runs the messaging tmpdir guard.
*/
export async function main() {
await runCallsiteGuard({
importMetaUrl: import.meta.url,

View file

@ -75,18 +75,12 @@ function isRawFetchCall(expression: ts.Expression) {
return false;
}
/**
* Finds raw `fetch(...)` and `globalThis.fetch(...)` call lines.
*/
function findRawFetchCallLines(_content: string, _fileName: string, sourceFile: ts.SourceFile) {
return collectCallExpressionLines(sourceFile, (node) =>
isRawFetchCall(node.expression) ? node.expression : null,
);
}
/**
* Runs the raw channel/plugin fetch guard.
*/
async function main() {
await runCallsiteGuard({
importMetaUrl: import.meta.url,

View file

@ -121,9 +121,6 @@ function collectPatchFileViolations(cwd: string, violations: PackagePatchViolati
}
}
/**
* Collects disallowed package patch declarations and patch files.
*/
export function collectPackagePatchViolations(cwd = process.cwd()) {
const violations: PackagePatchViolation[] = [];
collectWorkspacePatchViolations(cwd, violations);
@ -133,9 +130,6 @@ export function collectPackagePatchViolations(cwd = process.cwd()) {
return violations;
}
/**
* Runs the package patch guard.
*/
export async function main() {
const violations = collectPackagePatchViolations();
if (violations.length === 0) {

View file

@ -109,9 +109,6 @@ const formatInventoryHuman = (inventory: PluginExtensionInventoryEntry[]) =>
inventory,
);
/**
* Runs the plugin-extension import boundary check.
*/
async function runPluginExtensionImportBoundaryCheck(): Promise<0 | 1> {
const actual = await collectPluginExtensionImportBoundaryInventory();

View file

@ -18,14 +18,8 @@ const policy = {
} satisfies ExtensionWildcardReexportPolicy;
const scanner = createExtensionWildcardReexportScanner(policy);
/**
* Finds wildcard plugin SDK re-export lines in an extension API barrel.
*/
export const findPluginSdkWildcardReexports = scanner.findLines;
/**
* Runs the plugin SDK wildcard re-export guard.
*/
export const main = scanner.main;
await scanner.exitIfMain(import.meta.url);

View file

@ -34,9 +34,6 @@ function getCalleeName(expression: ts.Expression): string | null {
return null;
}
/**
* Finds request body reads that occur before webhook auth validation.
*/
function findBlockedWebhookBodyReadLines(
_content: string,
_fileName: string,
@ -48,9 +45,6 @@ function findBlockedWebhookBodyReadLines(
});
}
/**
* Runs the webhook auth/body-order guard.
*/
async function main() {
await runCallsiteGuard({
importMetaUrl: import.meta.url,

View file

@ -42,9 +42,6 @@ export const PREFLIGHT_CHECKS: CheckCommand[] = [
{ name: "package patch guard", args: ["deps:patches:check"] },
];
/**
* Returns command usage text for the aggregate check runner.
*/
export function usage() {
return [
"Usage: node --import tsx scripts/check.mts [--base <ref>] [--timed] [--include-architecture] [--include-test-types]",
@ -60,9 +57,6 @@ export function usage() {
].join("\n");
}
/**
* Parses aggregate check runner arguments.
*/
function parseCheckArgs(argv: string[]) {
return parseFlagArgs(
argv,
@ -84,9 +78,6 @@ function parseCheckArgs(argv: string[]) {
);
}
/**
* Runs selected repository check lanes.
*/
export async function main(argv = process.argv.slice(2)) {
let args;
try {
@ -197,9 +188,6 @@ async function runSerial(commands: CheckCommand[]) {
return results;
}
/**
* Runs one managed check command and returns timing/status details.
*/
export async function runCommand(
command: CheckCommand,
runManagedCommandImpl: RunManagedCheck = runManagedCommand,

View file

@ -23,16 +23,10 @@ type StartupBuildParams = Partial<{
timeoutMs: number;
}>;
/**
* Resolves the CLI startup build timeout from environment.
*/
export function resolveCliStartupBuildTimeoutMs(env: NodeJS.ProcessEnv = process.env) {
return readPositiveEnvInt("OPENCLAW_CLI_STARTUP_BUILD_TIMEOUT_MS", env, DEFAULT_BUILD_TIMEOUT_MS);
}
/**
* Reports whether required CLI startup build outputs exist.
*/
export function hasCliStartupBuild(params: StartupBuildParams = {}) {
const rootDir = params.rootDir ?? repoRoot;
const exists = params.existsSync ?? existsSync;
@ -40,9 +34,6 @@ export function hasCliStartupBuild(params: StartupBuildParams = {}) {
return hasEntry && exists(path.join(rootDir, startupMetadataPath));
}
/**
* Builds CLI startup assets when required outputs are missing.
*/
export function ensureCliStartupBuild(params: StartupBuildParams = {}) {
const rootDir = params.rootDir ?? repoRoot;
if (hasCliStartupBuild({ rootDir, existsSync: params.existsSync })) {

View file

@ -28,9 +28,6 @@ type ExtensionMemoryBuildParams = {
timeoutMs?: number;
};
/**
* Resolves the extension memory build timeout from environment.
*/
function resolveExtensionMemoryBuildTimeoutMs(env: NodeJS.ProcessEnv = process.env) {
return readPositiveEnvInt(
"OPENCLAW_EXTENSION_MEMORY_BUILD_TIMEOUT_MS",
@ -103,9 +100,6 @@ export function hasBuiltExtensionMemoryEntries(params: ExtensionMemoryBuildParam
return requiredExtensionIds.every((id) => builtIds.has(id));
}
/**
* Builds memory extension entries when required outputs are missing.
*/
export function ensureExtensionMemoryBuild(params: ExtensionMemoryBuildParams = {}) {
const rootDir = params.rootDir ?? repoRoot;
if (hasBuiltExtensionMemoryEntries(params)) {

View file

@ -30,9 +30,6 @@ type CollectFileViolationsParams<Violation extends object> = {
sourceRoots: string[];
};
/**
* Converts repo-relative source roots into absolute paths.
*/
export function resolveSourceRoots(repoRoot: string, relativeRoots: string[]) {
return relativeRoots.map((root) => path.join(repoRoot, ...root.split("/").filter(Boolean)));
}
@ -41,9 +38,6 @@ export function isTestLikeTypeScriptFile(filePath: string, extraTestSuffixes: st
return [...baseTestSuffixes, ...extraTestSuffixes].some((suffix) => filePath.endsWith(suffix));
}
/**
* Recursively collects TypeScript files under a file or directory target.
*/
export async function collectTypeScriptFiles(
targetPath: string,
options: CollectTypeScriptFilesOptions = {},
@ -128,9 +122,6 @@ export async function collectTypeScriptFilesFromRoots(
).flat();
}
/**
* Runs a guard's violation scanner across collected TypeScript source files.
*/
export async function collectFileViolations<Violation extends object>(
params: CollectFileViolationsParams<Violation>,
) {

View file

@ -75,9 +75,6 @@ export function resolveSpawnCommand(
};
}
/**
* Reads the signal-forwarding force-kill grace period.
*/
export function resolveForceKillDelayMs(env: NodeJS.ProcessEnv = process.env) {
const raw = env.OPENCLAW_RUN_WITH_ENV_FORCE_KILL_MS;
const text = raw?.trim();

View file

@ -5,7 +5,6 @@ import { createSessionManagerRuntimeRegistry } from "./session-manager-runtime-r
export type CompactionSafeguardCancellation = { reason: string; error?: unknown };
/** Runtime knobs consumed by the compaction safeguard extension. */
type CompactionSafeguardRuntimeValue = {
maxHistoryShare?: number;
contextWindowTokens?: number;

View file

@ -286,10 +286,6 @@ type ToolFailure = {
meta?: string;
};
/**
* Resolve model credentials. Returns auth details on success or a cancel reason on failure.
* Extracted to keep the main handler readable when model/auth is conditional.
*/
async function resolveModelAuth(
ctx: ExtensionContext,
model: NonNullable<ExtensionContext["model"]>,

View file

@ -46,7 +46,6 @@ type ProviderSetDiscoveryParams = {
allowKeychainPrompt?: false;
};
/** Disables external CLI auth discovery. */
function externalCliDiscoveryNone(params?: { config?: OpenClawConfig }): ExternalCliAuthDiscovery {
return {
mode: "none",

View file

@ -17,9 +17,6 @@ function calculateBackoffMs(consecutiveNoOutputPolls: number): number {
/**
* Record a command poll and return suggested retry delay.
* @param state Session state to track polling in
* @param commandId Unique identifier for the command being polled
* @param hasNewOutput Whether this poll returned new output
* @returns Suggested delay in milliseconds before next poll
*/
export function recordCommandPoll(
@ -45,9 +42,6 @@ export function recordCommandPoll(
return calculateBackoffMs(newCount);
}
/**
* Reset poll count for a command (e.g., when command completes).
*/
export function resetCommandPollCount(state: SessionState, commandId: string): void {
state.commandPollCounts?.delete(commandId);
}

View file

@ -3,7 +3,6 @@ import { patchSessionEntryCore } from "../../config/sessions/session-accessor.js
import { buildSessionCreationStamp } from "../../config/sessions/session-entry-provenance.js";
import { mergeSessionSnapshotChanges } from "../../config/sessions/session-snapshot-merge.js";
import type { SessionEntry } from "../../config/sessions/types.js";
/** Parameters for merging and persisting a session entry update. */
type PersistSessionEntryParams = {
agentId: string;
sessionStore: Record<string, SessionEntry>;

View file

@ -22,7 +22,6 @@ const EMBEDDED_AGENT_EXECUTION_PHASE_LABELS = {
export type EmbeddedAgentExecutionPhase = keyof typeof EMBEDDED_AGENT_EXECUTION_PHASE_LABELS;
/** Converts an internal phase id into the compact label used in status output. */
export function formatEmbeddedAgentExecutionPhase(
phase?: EmbeddedAgentExecutionPhase,
): string | undefined {

View file

@ -132,7 +132,6 @@ export function resolveProviderModelInput(params: {
return normalizedInput.length > 0 ? normalizedInput : ["text"];
}
/** Builds runtime model records from inline provider config. */
export function buildInlineProviderModels(
providers: Record<string, InlineProviderConfig>,
options: { providerMetadataOwners?: PluginMetadataSnapshotOwnerMaps } = {},

View file

@ -4,7 +4,6 @@ import type { ProviderRuntimeModel } from "../../plugins/provider-runtime-model.
import { DEFAULT_CONTEXT_TOKENS } from "../defaults.js";
import { resolveProviderModelInput } from "./model.inline-provider.js";
/** Converts a normalized catalog row into the provider runtime model shape. */
export function modelFromStaticCatalogRow(row: NormalizedModelCatalogRow): ProviderRuntimeModel {
return {
id: row.id,

View file

@ -5,7 +5,6 @@ import {
type StageTimingSummary,
} from "../../../shared/stage-timing.js";
/** Canonical stage names for dispatch-time embedded attempt diagnostics. */
export const EMBEDDED_RUN_ATTEMPT_DISPATCH_STAGE = {
workspace: "attempt-workspace",
prompt: "attempt-prompt",
@ -66,7 +65,6 @@ export function createEmbeddedRunStageSummaryEmitter(options: {
};
}
/** Formats stage timing into compact log text for startup/attempt diagnostics. */
export function formatEmbeddedRunStageSummary(prefix: string, summary: StageTimingSummary): string {
const stages = formatStageTimings(summary.stages);
return `${prefix} pid=${process.pid} threadId=${threadId} isMainThread=${isMainThread} totalMs=${summary.totalMs} stages=${stages}`;

View file

@ -15,7 +15,6 @@ type ProviderContextMaterializer = (input: {
signal?: AbortSignal;
}) => Promise<ProviderContext>;
/** Wraps a stream function with a conditional message-list transform. */
export function wrapStreamFnWithMessageTransform(
streamFn: StreamFn,
transform: MessageTransform,

View file

@ -36,7 +36,6 @@ export class MidTurnPrecheckSignal extends Error {
}
}
/** Narrows unknown errors to the mid-turn overflow signal used by attempt cleanup. */
export function isMidTurnPrecheckSignal(error: unknown): error is MidTurnPrecheckSignal {
return error instanceof MidTurnPrecheckSignal;
}

View file

@ -64,7 +64,6 @@ export function resolveEmbeddedFullAccessState(params: {
return { available: true };
}
/** Resolves the effective exec policy for sandbox-info reporting. */
export async function resolveEmbeddedSandboxInfoExecPolicy(
params: {
config?: OpenClawConfig;
@ -93,7 +92,6 @@ export async function resolveEmbeddedSandboxInfoExecPolicy(
);
}
/** Builds the serializable sandbox metadata attached to embedded agent run results. */
export function buildEmbeddedSandboxInfo(
sandbox?: Awaited<ReturnType<typeof resolveSandboxContext>>,
execElevated?: ExecElevatedDefaults,

View file

@ -29,9 +29,6 @@ export function collectAllowedToolNames(params: {
return names;
}
/**
* Collect the exact tool names registered with the embedded agent for this session.
*/
export function collectRegisteredToolNames(tools: Array<{ name?: string }>): Set<string> {
const names = new Set<string>();
for (const tool of tools) {

View file

@ -1106,7 +1106,6 @@ export function resolveAllowedModelRefFromAliasIndex(
return { ref: resolved.ref, key: status.key };
}
/** True when config contains provider model rows that should seed catalogs. */
function hasConfiguredProviderModelRows(cfg: OpenClawConfig): boolean {
const providers = cfg.models?.providers;
if (!providers || typeof providers !== "object") {

View file

@ -86,7 +86,6 @@ export function renderDiff(diffText: string): string {
}
if (parsed.prefix === "-") {
// Collect consecutive removed lines
const removedLines: { lineNum: string; content: string }[] = [];
while (i < lines.length) {
const currentLine = lines.at(i);
@ -98,7 +97,6 @@ export function renderDiff(diffText: string): string {
i++;
}
// Collect consecutive added lines
const addedLines: { lineNum: string; content: string }[] = [];
while (i < lines.length) {
const currentLine = lines.at(i);
@ -138,11 +136,9 @@ export function renderDiff(diffText: string): string {
}
}
} else if (parsed.prefix === "+") {
// Standalone added line
result.push(theme.fg("toolDiffAdded", `+${parsed.lineNum} ${replaceTabs(parsed.content)}`));
i++;
} else {
// Context line
result.push(theme.fg("toolDiffContext", ` ${parsed.lineNum} ${replaceTabs(parsed.content)}`));
i++;
}

View file

@ -23,7 +23,6 @@ const ThemeJsonSchema = Type.Object({
name: Type.String(),
vars: Type.Optional(Type.Record(Type.String(), ColorValueSchema)),
colors: Type.Object({
// Core UI (10 colors)
accent: ColorValueSchema,
border: ColorValueSchema,
borderAccent: ColorValueSchema,
@ -35,7 +34,6 @@ const ThemeJsonSchema = Type.Object({
dim: ColorValueSchema,
text: ColorValueSchema,
thinkingText: ColorValueSchema,
// Backgrounds & Content Text (11 colors)
selectedBg: ColorValueSchema,
userMessageBg: ColorValueSchema,
userMessageText: ColorValueSchema,
@ -47,7 +45,6 @@ const ThemeJsonSchema = Type.Object({
toolErrorBg: ColorValueSchema,
toolTitle: ColorValueSchema,
toolOutput: ColorValueSchema,
// Markdown (10 colors)
mdHeading: ColorValueSchema,
mdLink: ColorValueSchema,
mdLinkUrl: ColorValueSchema,
@ -58,11 +55,9 @@ const ThemeJsonSchema = Type.Object({
mdQuoteBorder: ColorValueSchema,
mdHr: ColorValueSchema,
mdListBullet: ColorValueSchema,
// Tool Diffs (3 colors)
toolDiffAdded: ColorValueSchema,
toolDiffRemoved: ColorValueSchema,
toolDiffContext: ColorValueSchema,
// Syntax Highlighting (9 colors)
syntaxComment: ColorValueSchema,
syntaxKeyword: ColorValueSchema,
syntaxFunction: ColorValueSchema,
@ -72,14 +67,12 @@ const ThemeJsonSchema = Type.Object({
syntaxType: ColorValueSchema,
syntaxOperator: ColorValueSchema,
syntaxPunctuation: ColorValueSchema,
// Thinking Level Borders (6 colors)
thinkingOff: ColorValueSchema,
thinkingMinimal: ColorValueSchema,
thinkingLow: ColorValueSchema,
thinkingMedium: ColorValueSchema,
thinkingHigh: ColorValueSchema,
thinkingXhigh: ColorValueSchema,
// Bash Mode (1 color)
bashMode: ColorValueSchema,
}),
export: Type.Optional(
@ -156,7 +149,6 @@ function colorDistance(
}
function rgbTo256(r: number, g: number, b: number): number {
// Find closest color in the 6x6x6 cube
const rIdx = findClosestPaletteIndex(r, CUBE_VALUES);
const gIdx = findClosestPaletteIndex(g, CUBE_VALUES);
const bIdx = findClosestPaletteIndex(b, CUBE_VALUES);
@ -169,7 +161,6 @@ function rgbTo256(r: number, g: number, b: number): number {
const cubeIndex = 16 + 36 * rIdx + 6 * gIdx + bIdx;
const cubeDist = colorDistance(r, g, b, cubeR, cubeG, cubeB);
// Find closest grayscale
const gray = Math.round(0.299 * r + 0.587 * g + 0.114 * b);
const grayIdx = findClosestPaletteIndex(gray, GRAY_VALUES);
const grayValue = GRAY_VALUES[grayIdx];

View file

@ -98,7 +98,6 @@ export abstract class AgentSessionTree extends AgentSessionExecution {
fromExtension = true;
}
// Allow extensions to override instructions and label
if (result?.customInstructions !== undefined) {
customInstructions = result.customInstructions;
}

View file

@ -43,13 +43,11 @@ const OpenRouterRoutingSchema = Type.Object({
preferred_max_latency: Type.Optional(Type.Union([Type.Number(), PercentileCutoffsSchema])),
});
// Schema for Vercel AI Gateway routing preferences
const VercelGatewayRoutingSchema = Type.Object({
only: Type.Optional(Type.Array(Type.String())),
order: Type.Optional(Type.Array(Type.String())),
});
// Schema for thinking level support and provider-specific values
const ThinkingLevelMapValueSchema = Type.Union([Type.String(), Type.Null()]);
const ThinkingLevelMapSchema = Type.Object({
off: Type.Optional(ThinkingLevelMapValueSchema),

View file

@ -266,7 +266,6 @@ export async function resolveModelScope(
const scopedModels: ScopedModel[] = [];
for (const pattern of patterns) {
// Check if pattern contains glob characters
if (pattern.includes("*") || pattern.includes("?") || pattern.includes("[")) {
// Extract optional thinking level suffix (e.g., "provider/*:high")
const suffix = splitModelPatternSuffix(pattern);
@ -312,7 +311,6 @@ export async function resolveModelScope(
continue;
}
// Avoid duplicates
if (!scopedModels.some((sm) => modelsAreEqual(sm.model, model))) {
scopedModels.push({ model, thinkingLevel });
}

View file

@ -125,8 +125,6 @@ interface CreateAgentSessionResult {
modelFallbackMessage?: string;
}
// Helper Functions
function createSessionPrepareNextTurnWithContext(
getAgent: () => Agent,
): NonNullable<AgentOptions["prepareNextTurnWithContext"]> {
@ -273,7 +271,6 @@ async function createAgentSessionImpl(
}
let resourceLoader = options.resourceLoader;
// Use provided or create AuthStorage and ModelRegistry
const config = options.authStorage && options.modelRegistry ? undefined : install.config;
const authStorage = options.authStorage ?? AuthStorage.forAgent(agentDir, config);
const modelRegistry =
@ -303,7 +300,6 @@ async function createAgentSessionImpl(
modelRegistry.refresh();
}
// Check if session has existing data to restore
const existingSession = await sessionManager[sessionManagerReadInitialContext]();
assertInitialSessionCurrent();
const hasExistingSession = existingSession.messages.length > 0;
@ -314,7 +310,6 @@ async function createAgentSessionImpl(
let model = options.model;
let modelFallbackMessage: string | undefined;
// If session has data, try to restore model from it
if (!model && hasExistingSession && existingSession.model) {
const restoredModel = modelRegistry.find(
existingSession.model.provider,
@ -379,7 +374,6 @@ async function createAgentSessionImpl(
settingsManager.getDefaultThinkingLevel() ??
modelThinkingDefault;
// Clamp to model capabilities
if (!model) {
thinkingLevel = "off";
} else {
@ -405,7 +399,6 @@ async function createAgentSessionImpl(
if (!settingsManager.getBlockImages()) {
return converted;
}
// Filter out ImageContent from all messages, replacing with text placeholder
return converted.map((msg) => {
if (msg.role === "user" || msg.role === "toolResult") {
const content = msg.content;
@ -420,7 +413,6 @@ async function createAgentSessionImpl(
)
.filter((c, i, arr) => {
const previous = arr.at(i - 1);
// Dedupe consecutive "Image reading is disabled." texts
return !(
c.type === "text" &&
c.text === "Image reading is disabled." &&

View file

@ -180,7 +180,6 @@ export function createFindToolDefinition(
const effectiveLimit = normalizePositiveLimit(limit, DEFAULT_LIMIT);
// One extra candidate distinguishes an exact-size result from a truncated one.
const observationLimit = effectiveLimit + 1;
// If custom operations provide glob(), use that instead of fd.
if (customOps?.glob) {
if (!(await customOps.exists(searchPath))) {
settle(() => reject(new Error(`Path not found: ${searchPath}`)));
@ -222,7 +221,6 @@ export function createFindToolDefinition(
return;
}
// Default implementation uses fd.
const fdPath = await ensureTool("fd", true);
if (signal?.aborted) {
settle(() => reject(new Error("Operation aborted")));

View file

@ -29,7 +29,6 @@ type SubagentAnnounceSteerOutcome =
| { status: "steered"; deliveredAt?: number; enqueuedAt?: number }
| { status: "none" | "dropped" | "source_owner_changed" };
/** Result of trying to deliver a subagent announcement. */
export type SubagentAnnounceDeliveryResult = {
delivered: boolean;
path: SubagentDeliveryPath;
@ -73,7 +72,6 @@ export function sourceOwnerChangedResult(): SubagentAnnounceDeliveryResult {
};
}
/** Converts a steer outcome into the shared delivery result shape. */
function mapSteerOutcomeToDeliveryResult(
outcome: SubagentAnnounceSteerOutcome,
): SubagentAnnounceDeliveryResult {

View file

@ -305,7 +305,6 @@ export async function safeRemoveAttachmentsDir(
}
}
/** Resolves the completed subagent archive delay from config. */
function resolveArchiveAfterMs(cfg?: OpenClawConfig) {
const config = cfg ?? getRuntimeConfig();
const minutes =

View file

@ -29,7 +29,6 @@ function shouldPreserveForMaintenance(entry: SubagentRunMaintenanceRecord): bool
);
}
/** Lists child session keys protected from session-store maintenance pruning. */
function protectedSubagentSessionKeys(runs: Iterable<SubagentRunMaintenanceRecord>): string[] {
const keys = new Set<string>();
for (const entry of runs) {

View file

@ -29,7 +29,6 @@ const TERMINAL_QUESTION_ERROR_REASONS = new Set([
"QUESTION_NOT_FOUND",
]);
/** Reads the Gateway's structured failure from a question RPC rejection. */
export function readQuestionRejection(
error: unknown,
): { code: unknown; reason?: string } | undefined {
@ -49,7 +48,6 @@ export function isTerminalQuestionResolveError(error: unknown): boolean {
return reason !== undefined && TERMINAL_QUESTION_ERROR_REASONS.has(reason);
}
/** Waits for one question's terminal state, validating the Gateway's payload. */
export async function awaitGatewayQuestionAnswer(params: {
gatewayCall: GatewayQuestionCall;
questionId: string;

View file

@ -6,7 +6,6 @@
import { Type } from "typebox";
import { optionalPositiveIntegerSchema } from "../schema/typebox.js";
/** Returns optional gateway URL/token/timeout schema properties for tool params. */
export function gatewayCallOptionSchemaProperties() {
return {
gatewayUrl: Type.Optional(Type.String()),

View file

@ -37,7 +37,6 @@ const HIDDEN_STYLE_PATTERNS = (
return [new RegExp(`(?:^|;)\\s*${escapedProp}\\s*:\\s*([^;]+)`, "i"), valuePattern] as const;
});
// Class names associated with visually hidden content
const HIDDEN_CLASS_NAMES = new Set([
"sr-only",
"visually-hidden",
@ -78,7 +77,6 @@ function isStyleHidden(style: string): boolean {
}
}
// width:0 + height:0 + overflow:hidden
const width = style.match(/(?:^|;)\s*width\s*:\s*([^;]+)/i);
const height = style.match(/(?:^|;)\s*height\s*:\s*([^;]+)/i);
const overflow = style.match(/(?:^|;)\s*overflow\s*:\s*([^;]+)/i);

View file

@ -7,7 +7,6 @@
import { parse } from "yaml";
import { extractFrontmatterBlock } from "../../../packages/markdown-core/src/frontmatter.js";
/** Parsed frontmatter metadata plus the remaining document body. */
type ParsedFrontmatter<T extends Record<string, unknown>> = {
frontmatter: T;
body: string;

View file

@ -58,12 +58,10 @@ function loadHighlightJsRuntime(): HighlightJs {
return setHighlightJsRuntime(createRequire(import.meta.url)("highlight.js"));
}
/** Formatter applied to highlighted text segments. */
type HighlightFormatter = (text: string) => string;
/** Mapping from highlight.js scope names to text formatters. */
type HighlightTheme = Partial<Record<string, HighlightFormatter>>;
/** Options used when highlighting code and rendering themed text. */
interface HighlightOptions {
language?: string;
ignoreIllegals?: boolean;

View file

@ -262,7 +262,6 @@ function resolveCommandsAllowFromList(
return null; // Not configured, fall back to channel allowFrom
}
// Check provider-specific list first, then fall back to global "*"
const providerKey = params.providerId ?? "";
const providerList = commandsAllowFrom[providerKey];
const globalList = commandsAllowFrom["*"];

View file

@ -178,11 +178,8 @@ export function stripHeartbeatToken(
// (e.g., <b>HEARTBEAT_OK</b> or **HEARTBEAT_OK**) still strips.
const stripMarkup = (text: string) =>
text
// Drop HTML tags.
.replace(/<[^>]*>/g, " ")
// Decode common nbsp variant.
.replace(/&nbsp;/gi, " ")
// Remove markdown-ish wrappers at the edges.
.replace(/^[*`~_]+/, "")
.replace(/[*`~_]+$/, "");

View file

@ -555,7 +555,6 @@ export async function chooseDispatchRoute(state: PrepareDispatchOperationReadySt
};
};
// Run before_dispatch hook — let plugins inspect or handle before model dispatch.
if (
state.allowInboundHandlers &&
!admittedSessionSettingsRestrictRuntime(params.replyOptions?.admittedSessionSettings) &&

View file

@ -467,7 +467,6 @@ export async function gatherDispatchRequest(
});
}));
const hookRunner = getGlobalHookRunner();
// Extract message context for hooks (plugin and internal)
const timestamp =
typeof ctx.Timestamp === "number" && Number.isFinite(ctx.Timestamp) ? ctx.Timestamp : undefined;
const messageIdForHook =

View file

@ -87,7 +87,6 @@ export async function prepareDispatchExecution(state: ChooseDispatchRouteReadySt
markInboundDedupeReplayUnsafe();
turnLedger.sendQueued("tool", replyPayload);
};
// Track accumulated block text for TTS generation after streaming completes.
// When block streaming succeeds, there's no final reply, so we need to generate
// TTS audio separately from the accumulated block content.
const progressState = {

View file

@ -1,6 +1,5 @@
/** Normalizes real inbound newline characters while preserving literal escape text. */
export function normalizeInboundTextNewlines(input: string): string {
// Normalize actual newline characters (CR+LF and CR to LF).
// Do NOT replace literal backslash-n sequences (\\n) as they may be part of
// Windows paths like C:\Work\nxxx\README.md or user-intended escape sequences.
return input.replaceAll("\r\n", "\n").replaceAll("\r", "\n");

View file

@ -166,7 +166,6 @@ export function normalizeReplyPayloadOutcome(
text = enrichedPayload.text;
}
// Resolve template variables in responsePrefix if context is provided
const effectivePrefix = opts.responsePrefixContext
? resolveResponsePrefixTemplate(opts.responsePrefix, opts.responsePrefixContext)
: opts.responsePrefix;

View file

@ -572,7 +572,6 @@ export function createReplyDispatcher(
deliveryOutcomeTracker.tracked = true;
}
// Determine if we should add human-like delay (only for block replies after the first).
const shouldDelay = kind === "block" && sentFirstBlock;
if (kind === "block") {
sentFirstBlock = true;

View file

@ -68,7 +68,6 @@ function buildRegisteredChannelPluginLookup(): RegisteredChannelPluginLookup {
return registeredChannelPluginLookup;
}
/** Lists active channel plugin registrations from the current registry snapshot. */
export function listRegisteredChannelPluginEntries(): ActivePluginChannelRegistration[] {
return buildRegisteredChannelPluginLookup().entries;
}

View file

@ -48,7 +48,6 @@ function encodeCompletionProfile(content: string, encoding: CompletionProfileEnc
return encoding === "utf16be" ? buffer.swap16() : buffer;
}
/** Narrows an arbitrary shell label to a completion shell supported by installer logic. */
export function isCompletionShell(value: string): value is CompletionShell {
return COMPLETION_SHELLS.includes(value as CompletionShell);
}
@ -102,7 +101,6 @@ export function resolveCompletionCachePath(shell: CompletionShell, binName: stri
);
}
/** Check if the completion cache file exists for the given shell. */
export async function completionCacheExists(
shell: CompletionShell,
binName = "openclaw",

View file

@ -39,7 +39,6 @@ const parseFacing = (value: string): CameraFacing => {
throw new Error(`invalid facing: ${value} (expected front|back)`);
};
/** Register node camera list/snap/clip commands. */
export function registerNodesCameraCommands(nodes: Command) {
const camera = nodes.command("camera").description("Capture camera media from a paired node");

View file

@ -25,7 +25,6 @@ function parseNodeInvokeParams(value = "{}"): unknown {
}
}
/** Register direct node command invocation. */
export function registerNodesInvokeCommands(nodes: Command) {
nodesCallOpts(
nodes

View file

@ -12,7 +12,6 @@ import {
} from "./rpc.js";
import type { NodesRpcOpts } from "./types.js";
/** Register node location lookup commands. */
export function registerNodesLocationCommands(nodes: Command) {
const location = nodes.command("location").description("Fetch location from a paired node");

View file

@ -11,7 +11,6 @@ import {
} from "./rpc.js";
import type { NodesRpcOpts } from "./types.js";
/** Register node notification command. */
export function registerNodesNotifyCommand(nodes: Command) {
nodesCallOpts(
nodes

View file

@ -122,7 +122,6 @@ function rethrowUnknownNodePairRequestId(
throw error;
}
/** Register node pairing management commands. */
export function registerNodesPairingCommands(nodes: Command) {
nodesCallOpts(
nodes

View file

@ -19,7 +19,6 @@ import {
} from "./rpc.js";
import type { NodesRpcOpts } from "./types.js";
/** Register node screen recording commands. */
export function registerNodesScreenCommands(nodes: Command) {
const screen = nodes
.command("screen")

View file

@ -9,7 +9,6 @@ const requiredOptions = {
startTime: ["--start-time <iso>", "Event start time"],
} as const;
/** Register Discord admin and moderation message subcommands. */
export function registerMessageDiscordAdminCommands(message: Command, helpers: MessageCliHelpers) {
function register(
parent: Command,

View file

@ -3,7 +3,6 @@ import type { Command } from "commander";
import { collectOption } from "../helpers.js";
import type { MessageCliHelpers } from "./helpers.js";
/** Register the channel permissions inspection command. */
export function registerMessagePermissionsCommand(message: Command, helpers: MessageCliHelpers) {
helpers
.withMessageBase(
@ -13,7 +12,6 @@ export function registerMessagePermissionsCommand(message: Command, helpers: Mes
.action((opts) => helpers.runMessageAction("permissions", opts));
}
/** Register the channel message search command and repeatable filters. */
export function registerMessageSearchCommand(message: Command, helpers: MessageCliHelpers) {
helpers
.withMessageBase(message.command("search").description("Search messages"))

View file

@ -1,7 +1,6 @@
import { Option, type Command } from "commander";
import type { MessageCliHelpers } from "./helpers.js";
/** Register message read, edit, and delete commands. */
export function registerMessageReadEditDeleteCommands(
message: Command,
helpers: MessageCliHelpers,

View file

@ -21,7 +21,6 @@ function resolveThreadCreateRequest(opts: Record<string, unknown>) {
};
}
/** Register thread create/list/reply commands. */
export function registerMessageThreadCommands(message: Command, helpers: MessageCliHelpers) {
const thread = message.command("thread").description("Thread actions");

View file

@ -5,7 +5,6 @@ import { runCommandWithRuntime } from "../cli-utils.js";
import { formatDocsHelp } from "../help-format.js";
import { collectOption } from "./helpers.js";
/** Register the interactive `configure` command and section filter flag. */
export function registerConfigureCommand(program: Command): void {
program
.command("configure")

View file

@ -102,7 +102,6 @@ export function formatAuthChoiceChoicesForCli(params?: {
return uniqueStrings(values).join("|");
}
/** Build flat auth-choice options from core choices plus provider setup flows. */
function buildAuthChoiceOptions(params: {
assistantVisibleOnly?: boolean;
detectedProviderIds?: ReadonlySet<string>;

View file

@ -50,7 +50,6 @@ function formatAccountLabel(params: { accountId: string; name?: string }) {
return base;
}
/** Format a channel/account label with optional display styles for terminal output. */
export function formatChannelAccountLabel(params: {
channel: ChatChannel;
accountId: string;
@ -104,7 +103,6 @@ export function appendEnabledConfiguredLinkedBits(
}
}
/** Append account mode metadata when present. */
export function appendModeBit(bits: string[], account: Record<string, unknown>) {
if (typeof account.mode === "string" && account.mode.length > 0) {
bits.push(`mode:${account.mode}`);
@ -129,14 +127,12 @@ export function appendTokenSourceBits(bits: string[], account: Record<string, un
appendSourceBit("signing", "signingSecretSource", "signingSecretStatus");
}
/** Append account base URL metadata when present. */
export function appendBaseUrlBit(bits: string[], account: Record<string, unknown>) {
if (typeof account.baseUrl === "string" && account.baseUrl) {
bits.push(`url:${account.baseUrl}`);
}
}
/** Build a complete human-readable channel account status line. */
export function buildChannelAccountLine(
provider: ChatChannel,
account: Record<string, unknown>,

Some files were not shown because too many files have changed in this diff Show more