diff --git a/src/agents/embedded-agent-block-chunker.ts b/src/agents/embedded-agent-block-chunker.ts index 36d00fa9694e..e7a0e3ef3cd9 100644 --- a/src/agents/embedded-agent-block-chunker.ts +++ b/src/agents/embedded-agent-block-chunker.ts @@ -1,3 +1,6 @@ +/** + * Splits streamed embedded-agent replies into Markdown-safe message chunks. + */ import type { FenceSpan } from "../../packages/markdown-core/src/fences.js"; import { findFenceSpanAt, @@ -116,6 +119,7 @@ export class EmbeddedBlockChunker { this.#chunking = chunking; } + /** Add streamed text to the pending chunk buffer. */ append(text: string) { if (!text) { return; @@ -123,18 +127,22 @@ export class EmbeddedBlockChunker { this.#buffer += text; } + /** Clear any buffered reply text without emitting it. */ reset() { this.#buffer = ""; } + /** Return the currently buffered text for tests and flush logic. */ get bufferedText() { return this.#buffer; } + /** Return true when there is pending text to drain. */ hasBuffered(): boolean { return this.#buffer.length > 0; } + /** Emit safe chunks according to size and Markdown fence constraints. */ drain(params: { force: boolean; emit: (chunk: string) => void }) { // KNOWN: We cannot split inside fenced code blocks (Markdown breaks + UI glitches). // When forced (maxChars), we close + reopen the fence to keep Markdown valid. diff --git a/src/agents/embedded-agent-error-observation.ts b/src/agents/embedded-agent-error-observation.ts index 01e5678c16ac..38601cd99c6c 100644 --- a/src/agents/embedded-agent-error-observation.ts +++ b/src/agents/embedded-agent-error-observation.ts @@ -1,3 +1,6 @@ +/** + * Builds structured observations for embedded-agent API/text failures. + */ import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce"; import { readLoggingConfig } from "../logging/config.js"; import { redactIdentifier } from "../logging/redact-identifier.js"; diff --git a/src/agents/embedded-agent-helpers/bootstrap.ts b/src/agents/embedded-agent-helpers/bootstrap.ts index 400966b9d34a..781ca35c9837 100644 --- a/src/agents/embedded-agent-helpers/bootstrap.ts +++ b/src/agents/embedded-agent-helpers/bootstrap.ts @@ -1,3 +1,6 @@ +/** + * Builds and sanitizes bootstrap context inserted into embedded-agent sessions. + */ import fs from "node:fs/promises"; import path from "node:path"; import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce"; diff --git a/src/agents/embedded-agent-helpers/errors.ts b/src/agents/embedded-agent-helpers/errors.ts index 940e4cc39505..eaa8e6d732f4 100644 --- a/src/agents/embedded-agent-helpers/errors.ts +++ b/src/agents/embedded-agent-helpers/errors.ts @@ -1,3 +1,6 @@ +/** + * Classifies provider/runtime failures and formats assistant-facing error text. + */ import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, @@ -75,6 +78,7 @@ export const GENERIC_ASSISTANT_ERROR_TEXT = "LLM request failed."; const PROVIDER_SCHEMA_REJECTION_USER_TEXT = "LLM request failed: provider rejected the request schema or tool payload."; +/** Detect provider errors that require reasoning to stay enabled. */ export function isReasoningConstraintErrorMessage(raw: string): boolean { if (!raw) { return false; @@ -93,6 +97,7 @@ function hasRateLimitTpmHint(raw: string): boolean { return /\btpm\b/i.test(lower) || lower.includes("tokens per minute"); } +/** Detect explicit context-window overflow without confusing TPM rate limits. */ export function isContextOverflowError(errorMessage?: string): boolean { if (!errorMessage) { return false; diff --git a/src/agents/embedded-agent-helpers/failover-matches.ts b/src/agents/embedded-agent-helpers/failover-matches.ts index 49952e3e1b2b..5f1ab842d61d 100644 --- a/src/agents/embedded-agent-helpers/failover-matches.ts +++ b/src/agents/embedded-agent-helpers/failover-matches.ts @@ -1,3 +1,6 @@ +/** + * Shared text-pattern matchers for failover, auth, billing, and rate-limit errors. + */ import { normalizeLowercaseStringOrEmpty } from "@openclaw/normalization-core/string-coerce"; type ErrorPattern = RegExp | string; diff --git a/src/agents/embedded-agent-helpers/google.ts b/src/agents/embedded-agent-helpers/google.ts index e3536a5442bb..c36fb218947f 100644 --- a/src/agents/embedded-agent-helpers/google.ts +++ b/src/agents/embedded-agent-helpers/google.ts @@ -1,3 +1,6 @@ +/** + * Google/Gemini-specific embedded-agent runtime helpers. + */ import { isGemma4ModelId } from "../../shared/google-models.js"; import { sanitizeGoogleTurnOrdering } from "./bootstrap.js"; diff --git a/src/agents/embedded-agent-helpers/images.ts b/src/agents/embedded-agent-helpers/images.ts index b614bd52bfe2..213e5fafb362 100644 --- a/src/agents/embedded-agent-helpers/images.ts +++ b/src/agents/embedded-agent-helpers/images.ts @@ -1,3 +1,6 @@ +/** + * Sanitizes historical embedded-agent message images and empty content blocks. + */ import type { ImageSanitizationLimits } from "../image-sanitization.js"; import type { AgentMessage, AgentToolResult } from "../runtime/index.js"; import type { ToolCallIdMode } from "../tool-call-id.js"; @@ -28,6 +31,7 @@ function ensureNonEmptyContent(content: T[]): T[] { return [{ type: "text", text: EMPTY_CONTENT_PLACEHOLDER }] as T[]; } +/** Return true when an assistant turn contains no usable content blocks. */ export function isEmptyAssistantMessageContent( message: Extract, ): boolean { @@ -50,6 +54,7 @@ export function isEmptyAssistantMessageContent( }); } +/** Resize/remove unsafe image payloads while keeping transcript turns valid. */ export async function sanitizeSessionMessagesImages( messages: AgentMessage[], label: string, diff --git a/src/agents/embedded-agent-helpers/messaging-dedupe.ts b/src/agents/embedded-agent-helpers/messaging-dedupe.ts index efdc39f47e77..76d6c64121ae 100644 --- a/src/agents/embedded-agent-helpers/messaging-dedupe.ts +++ b/src/agents/embedded-agent-helpers/messaging-dedupe.ts @@ -1,3 +1,6 @@ +/** + * Normalizes outbound message text to suppress duplicate send actions. + */ import { normalizeLowercaseStringOrEmpty } from "@openclaw/normalization-core/string-coerce"; const MIN_DUPLICATE_TEXT_LENGTH = 10; @@ -17,6 +20,7 @@ export function normalizeTextForComparison(text: string): string { .trim(); } +/** Compare already-normalized message text against prior sends. */ export function isMessagingToolDuplicateNormalized( normalized: string, normalizedSentTexts: string[], @@ -41,6 +45,7 @@ export function isMessagingToolDuplicateNormalized( }); } +/** Return true when raw message text duplicates a prior sent message. */ export function isMessagingToolDuplicate(text: string, sentTexts: string[]): boolean { if (sentTexts.length === 0) { return false; diff --git a/src/agents/embedded-agent-helpers/openai.ts b/src/agents/embedded-agent-helpers/openai.ts index bb184b21effd..7f9d5f993193 100644 --- a/src/agents/embedded-agent-helpers/openai.ts +++ b/src/agents/embedded-agent-helpers/openai.ts @@ -1,3 +1,6 @@ +/** + * Normalizes OpenAI Responses reasoning/tool-call history for safe replay. + */ import { createHash } from "node:crypto"; import type { AgentMessage } from "../runtime/index.js"; diff --git a/src/agents/embedded-agent-helpers/sanitize-user-facing-text.ts b/src/agents/embedded-agent-helpers/sanitize-user-facing-text.ts index 4e255fac6f7e..7748e9e71e5f 100644 --- a/src/agents/embedded-agent-helpers/sanitize-user-facing-text.ts +++ b/src/agents/embedded-agent-helpers/sanitize-user-facing-text.ts @@ -1,3 +1,6 @@ +/** + * Converts raw provider/transport errors into concise user-facing copy. + */ import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, @@ -31,6 +34,7 @@ import { isTimeoutErrorMessage, } from "./failover-matches.js"; +/** Format the billing failure copy with optional provider/model context. */ export function formatBillingErrorMessage(provider?: string, model?: string): string { const providerName = provider?.trim(); const modelName = model?.trim(); diff --git a/src/agents/embedded-agent-helpers/thinking.ts b/src/agents/embedded-agent-helpers/thinking.ts index 87478d111e0d..e6099c8310f8 100644 --- a/src/agents/embedded-agent-helpers/thinking.ts +++ b/src/agents/embedded-agent-helpers/thinking.ts @@ -1,3 +1,6 @@ +/** + * Resolves fallback thinking levels for providers that require reasoning. + */ import { normalizeStringEntries } from "@openclaw/normalization-core/string-normalization"; import { normalizeThinkLevel, type ThinkLevel } from "../../auto-reply/thinking.js"; import { isReasoningConstraintErrorMessage } from "./errors.js"; @@ -20,6 +23,7 @@ function extractSupportedValues(raw: string): string[] { ); } +/** Pick a configured or provider-safe reasoning level for fallback attempts. */ export function pickFallbackThinkingLevel(params: { message?: string; attempted: Set; diff --git a/src/agents/embedded-agent-helpers/turns.ts b/src/agents/embedded-agent-helpers/turns.ts index 599a8735763c..13ce52680349 100644 --- a/src/agents/embedded-agent-helpers/turns.ts +++ b/src/agents/embedded-agent-helpers/turns.ts @@ -1,3 +1,6 @@ +/** + * Normalizes embedded-agent conversation turn ordering for provider contracts. + */ import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce"; import type { AgentMessage } from "../runtime/index.js"; import { extractToolCallsFromAssistant, extractToolResultId } from "../tool-call-id.js"; @@ -349,6 +352,7 @@ export function validateGeminiTurns(messages: AgentMessage[]): AgentMessage[] { }); } +/** Merge adjacent user turns into a single provider-compatible user message. */ export function mergeConsecutiveUserTurns( previous: Extract, current: Extract, diff --git a/src/agents/embedded-agent-lsp.ts b/src/agents/embedded-agent-lsp.ts index cdff49b046dc..8ed66d172f4f 100644 --- a/src/agents/embedded-agent-lsp.ts +++ b/src/agents/embedded-agent-lsp.ts @@ -1,3 +1,6 @@ +/** + * Loads bundle-provided LSP server config for embedded-agent sessions. + */ import type { OpenClawConfig } from "../config/types.openclaw.js"; import type { BundleLspServerConfig } from "../plugins/bundle-lsp.js"; import { loadEnabledBundleLspConfig } from "../plugins/bundle-lsp.js"; @@ -7,6 +10,7 @@ type EmbeddedAgentLspConfig = { diagnostics: Array<{ pluginId: string; message: string }>; }; +/** Resolve enabled embedded-agent LSP servers and diagnostics. */ export function loadEmbeddedAgentLspConfig(params: { workspaceDir: string; cfg?: OpenClawConfig; diff --git a/src/agents/embedded-agent-messaging.ts b/src/agents/embedded-agent-messaging.ts index 818678b89f63..0d98a50f6750 100644 --- a/src/agents/embedded-agent-messaging.ts +++ b/src/agents/embedded-agent-messaging.ts @@ -1,3 +1,6 @@ +/** + * Identifies messaging tools and send actions during embedded-agent runs. + */ import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce"; import { getChannelPlugin, normalizeChannelId } from "../channels/plugins/index.js"; @@ -10,12 +13,14 @@ const MESSAGE_TOOL_SEND_ACTIONS = new Set([ "upload-file", ]); +/** Return true when a message action sends or uploads user-visible content. */ export function isMessageToolSendActionName(action: unknown): boolean { const normalized = normalizeOptionalString(action) ?? ""; return MESSAGE_TOOL_SEND_ACTIONS.has(normalized); } // Provider docking: any plugin with `actions` opts into messaging tool handling. +/** Return true for core or channel-plugin messaging tool names. */ export function isMessagingTool(toolName: string): boolean { if (CORE_MESSAGING_TOOLS.has(toolName)) { return true; @@ -24,6 +29,7 @@ export function isMessagingTool(toolName: string): boolean { return Boolean(providerId && getChannelPlugin(providerId)?.actions); } +/** Return true when the specific tool invocation is an outbound send. */ export function isMessagingToolSendAction( toolName: string, args: Record, diff --git a/src/agents/embedded-agent-messaging.types.ts b/src/agents/embedded-agent-messaging.types.ts index 36f78d35f0ef..31683c1fb672 100644 --- a/src/agents/embedded-agent-messaging.types.ts +++ b/src/agents/embedded-agent-messaging.types.ts @@ -1,6 +1,8 @@ +/** + * Shared messaging-tool metadata types captured from embedded-agent runs. + */ import type { ReplyPayload } from "../auto-reply/reply-payload.js"; -// Messaging tool metadata captured during embedded agent runs. export type MessagingToolSend = { tool: string; provider: string; @@ -13,7 +15,6 @@ export type MessagingToolSend = { mediaUrls?: string[]; }; -// Reply payload subset preserved for message-tool idempotency and delivery. export type MessagingToolSourceReplyPayload = Pick< ReplyPayload, | "audioAsVoice"