openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
8,900 lines ⢠375 kB
TypeScript
import { Static, Type } from "typebox";
import { z } from "zod";
import "json5";
import "execa";
//#endregion
//#region src/shared/silent-reply-policy.d.ts
type SilentReplyPolicy = "allow" | "disallow";
type SilentReplyConversationType = "direct" | "group" | "internal";
type SilentReplyPolicyShape = Partial<Record<Exclude<SilentReplyConversationType, "direct">, SilentReplyPolicy>>;
//#endregion
//#region src/transcripts/config.d.ts
/**
* Configuration normalization for transcript capture/import.
*
* Raw config can contain optional auto-start provider locators; resolution
* returns bounded defaults and drops malformed entries before runtime startup.
*/
/** Raw auto-start transcript source entry from config. */
type TranscriptsAutoStartConfig = {
providerId: string;
whenOccupied?: boolean;
sessionId?: string;
title?: string;
accountId?: string;
guildId?: string;
channelId?: string;
meetingUrl?: string;
};
/** Raw transcripts config block. */
type TranscriptsConfig = {
enabled?: boolean;
autoStart?: TranscriptsAutoStartConfig[];
};
//#endregion
//#region src/config/types.access-groups.d.ts
type DiscordChannelAudienceAccessGroup = {
/**
* Discord dynamic audience backed by the users who can currently view a guild
* channel.
*/
type: "discord.channelAudience";
/** Guild ID that owns the channel. */
guildId: string;
/** Channel ID whose effective ViewChannel permission defines the audience. */
channelId: string;
/** Audience predicate. Defaults to canViewChannel. */
membership?: "canViewChannel";
};
type MessageSendersAccessGroup = {
/**
* Static sender allowlists that can be referenced by any message channel via
* accessGroup:<name>.
*/
type: "message.senders";
/** Sender entries by channel id, plus optional "*" entries shared by all channels. */
members: Record<string, string[]>;
};
type AccessGroupConfig = DiscordChannelAudienceAccessGroup | MessageSendersAccessGroup;
type AccessGroupsConfig = Record<string, AccessGroupConfig>;
//#endregion
//#region packages/acp-core/src/runtime/types.d.ts
/** Runtime update tags emitted by ACP adapters; unknown backend tags are passed through. */
type AcpSessionUpdateTag = "agent_message_chunk" | "agent_thought_chunk" | "tool_call" | "tool_call_update" | "usage_update" | "available_commands_update" | "current_mode_update" | "config_option_update" | "session_info_update" | "plan" | (string & {});
//#endregion
//#region src/config/types.acp.d.ts
type AcpDispatchConfig = {
/** Master switch for ACP turn dispatch in the reply pipeline. */
enabled?: boolean;
};
type AcpStreamConfig = {
/** Suppresses repeated ACP status/tool projection lines within a turn. */
repeatSuppression?: boolean;
/** Live streams chunks or waits for terminal event before delivery. */
deliveryMode?: "live" | "final_only";
/**
* Per-sessionUpdate visibility overrides.
* Keys not listed here fall back to OpenClaw defaults.
*/
tagVisibility?: Partial<Record<AcpSessionUpdateTag, boolean>>;
};
type AcpRuntimeConfig = {
/** Optional operator install/setup command shown by `/acp install` and `/acp doctor`. */
installCommand?: string;
};
type AcpConfig = {
/** Global ACP runtime gate. */
enabled?: boolean;
dispatch?: AcpDispatchConfig;
/** Backend id registered by ACP runtime plugin (for example: acpx). */
backend?: string;
/** Fallback backend ids tried when the primary backend fails with UNAVAILABLE. */
fallbacks?: string[];
defaultAgent?: string;
allowedAgents?: string[];
stream?: AcpStreamConfig;
runtime?: AcpRuntimeConfig;
};
//#endregion
//#region packages/normalization-core/src/string-coerce.d.ts
type FastMode = boolean | "auto";
//#endregion
//#region src/channels/chat-type.d.ts
/**
* Normalized conversation kind shared by channel routing, sessions, and SDK helpers.
*/
type ChatType = "direct" | "group" | "channel";
//#endregion
//#region src/config/types.secrets.d.ts
/** Supported secret reference backends in config. */
type SecretRefSource = "env" | "file" | "exec" | "store";
/**
* Stable identifier for a secret in a configured source.
* Examples:
* - env source: provider "default", id "OPENAI_API_KEY"
* - file source: provider "mounted-json", id "/providers/openai/apiKey"
* - exec source: provider "vault", id "openai/api-key"
* - store source: provider "default", id "OPENAI_API_KEY"
*/
type SecretRef = {
source: SecretRefSource;
provider: string;
id: string;
};
/** Secret-bearing config input: either a literal string or a structured SecretRef. */
type SecretInput = string | SecretRef;
type EnvSecretProviderConfig = {
source: "env";
/** Optional env var allowlist (exact names). */
allowlist?: string[];
};
type FileSecretProviderMode = "singleValue" | "json";
type FileSecretProviderConfig = {
source: "file";
path: string;
mode?: FileSecretProviderMode;
timeoutMs?: number;
maxBytes?: number;
};
type ManualExecSecretProviderConfig = {
source: "exec";
command: string;
args?: string[];
timeoutMs?: number;
noOutputTimeoutMs?: number;
maxOutputBytes?: number;
jsonOnly?: boolean;
env?: Record<string, string>;
passEnv?: string[];
trustedDirs?: string[];
};
type PluginIntegrationSecretProviderConfig = {
source: "exec";
pluginIntegration: {
pluginId: string;
integrationId: string;
};
};
type ExecSecretProviderConfig = ManualExecSecretProviderConfig | PluginIntegrationSecretProviderConfig;
type StoreSecretProviderConfig = {
source: "store";
};
type SecretProviderConfig = EnvSecretProviderConfig | FileSecretProviderConfig | ExecSecretProviderConfig | StoreSecretProviderConfig;
type SecretsConfig = {
egressProxy?: {
enabled?: boolean;
allowedHosts?: string[];
bypassHosts?: string[];
};
providers?: Record<string, SecretProviderConfig>;
defaults?: {
env?: string;
file?: string;
exec?: string;
store?: string;
};
};
//#endregion
//#region src/config/types.sandbox.d.ts
type SandboxDockerSettings = {
/** Docker image to use for sandbox containers. */
image?: string;
/** Prefix for sandbox container names. */
containerPrefix?: string;
/** Container workdir mount path (default: /workspace). */
workdir?: string;
/** Run container rootfs read-only. */
readOnlyRoot?: boolean;
/** Extra tmpfs mounts for read-only containers. */
tmpfs?: string[];
/** Container network mode (bridge|none|custom). */
network?: string;
/** Container user (uid:gid). */
user?: string;
/** Drop Linux capabilities. */
capDrop?: string[];
/** Explicit environment variables for sandbox container creation and exec. */
env?: Record<string, string>;
/** Optional setup command run once after container creation (array entries are joined by newline). */
setupCommand?: string;
/** Limit container PIDs (0 = Docker default). */
pidsLimit?: number;
/** Limit container memory (e.g. 512m, 2g, or bytes as number). */
memory?: string | number;
/** Limit container memory swap (same format as memory). */
memorySwap?: string | number;
/** Limit container CPU shares (e.g. 0.5, 1, 2). */
cpus?: number;
/** GPU devices to expose via Docker --gpus (e.g. "all", "device=GPU-uuid"). */
gpus?: string;
/**
* Set ulimit values by name (e.g. nofile, nproc).
* Use "soft:hard" string, a number, or { soft, hard }.
*/
ulimits?: Record<string, string | number | {
soft?: number;
hard?: number;
}>;
/** Seccomp profile (path or profile name). */
seccompProfile?: string;
/** AppArmor profile name. */
apparmorProfile?: string;
/** DNS servers (e.g. ["1.1.1.1", "8.8.8.8"]). */
dns?: string[];
/** Extra host mappings (e.g. ["api.local:10.0.0.2"]). */
extraHosts?: string[];
/** Additional bind mounts (host:container:mode format, e.g. ["/host/path:/container/path:rw"]). */
binds?: string[];
/**
* Dangerous override: allow bind mounts that target reserved container paths
* like /workspace or /agent.
*/
dangerouslyAllowReservedContainerTargets?: boolean;
/**
* Dangerous override: allow bind mount sources outside runtime allowlisted roots
* (workspace + agent workspace roots).
*/
dangerouslyAllowExternalBindSources?: boolean;
/**
* Dangerous override: allow Docker `network: "container:<id>"` namespace joins.
* Default behavior blocks container namespace joins to preserve sandbox isolation.
*/
dangerouslyAllowContainerNamespaceJoin?: boolean;
};
type SandboxBrowserSettings = {
enabled?: boolean;
image?: string;
containerPrefix?: string;
/** Docker network for sandbox browser containers (default: openclaw-sandbox-browser). */
network?: string;
cdpPort?: number;
/** Optional CIDR allowlist for CDP ingress at the container edge (for example: 172.21.0.1/32). */
cdpSourceRange?: string;
vncPort?: number;
noVncPort?: number;
headless?: boolean;
noVncEnabled?: boolean;
/** @deprecated Doctor-only legacy input. */
enableNoVnc?: boolean;
/**
* Allow sandboxed sessions to target the host browser control server.
* Default: false.
*/
allowHostControl?: boolean;
/**
* When true (default), sandboxed browser control will try to start/reattach to
* the sandbox browser container when a tool call needs it.
*/
autoStart?: boolean;
/** Max time to wait for CDP to become reachable after auto-start (ms). */
autoStartTimeoutMs?: number;
/** Additional bind mounts for the browser container only. When set, replaces docker.binds for the browser container. */
binds?: string[];
};
type SandboxPruneSettings = {
/** Prune if idle for more than N hours (0 disables). */
idleHours?: number;
/** Prune if older than N days (0 disables). */
maxAgeDays?: number;
};
type SandboxSshSettings = {
/** SSH target in user@host[:port] form. */
target?: string;
/** SSH client command. Default: "ssh". */
command?: string;
/** Absolute remote root used for per-scope workspaces. */
workspaceRoot?: string;
/** Enforce host-key verification. Default: true. */
strictHostKeyChecking?: boolean;
/** Allow OpenSSH host-key updates. Default: true. */
updateHostKeys?: boolean;
/** Existing private key path on the host. */
identityFile?: string;
/** Existing SSH certificate path on the host. */
certificateFile?: string;
/** Existing known_hosts file path on the host. */
knownHostsFile?: string;
/** Inline or SecretRef-backed private key contents. */
identityData?: SecretInput;
/** Inline or SecretRef-backed SSH certificate contents. */
certificateData?: SecretInput;
/** Inline or SecretRef-backed known_hosts contents. */
knownHostsData?: SecretInput;
};
//#endregion
//#region src/config/types.agents-shared.d.ts
/** Agent model selector: a single provider/model ref or primary+fallback chain. */
type AgentModelConfig = string | {
/** Primary model (provider/model). */
primary?: string;
/** Per-agent model fallbacks (provider/model). */
fallbacks?: string[];
};
/** Tool-specific model selector with an optional capability timeout override. */
type AgentToolModelConfig = string | {
/** Primary model (provider/model). */
primary?: string;
/** Per-tool model fallbacks (provider/model). */
fallbacks?: string[];
/** Optional provider request timeout in milliseconds for capabilities that support it. */
timeoutMs?: number;
};
/** Runtime selection policy attached to providers, models, and agent defaults. */
type AgentRuntimePolicyConfig = {
/** Agent runtime id. Omitted uses "openclaw"; "auto" opts into plugin harness auto-selection. */
id?: string;
};
/** Per-agent sandbox policy shared by embedded agents and sandbox backends. */
type AgentSandboxConfig = {
/** Sandbox activation mode for this agent. */
mode?: "off" | "non-main" | "all";
/** Sandbox runtime backend id. Default: "docker". */
backend?: string;
/** Agent workspace access inside the sandbox. */
workspaceAccess?: "none" | "ro" | "rw";
/**
* Session tools visibility for sandboxed sessions.
* - "spawned": only allow session tools to target sessions spawned from this session (default)
* - "all": allow session tools to target any session
*/
sessionToolsVisibility?: "spawned" | "all";
/** Container/workspace scope for sandbox isolation. */
scope?: "session" | "agent" | "shared";
/** Host workspace root mounted or copied into the sandbox. */
workspaceRoot?: string;
/** Docker-specific sandbox settings. */
docker?: SandboxDockerSettings;
/** SSH-specific sandbox settings. */
ssh?: SandboxSshSettings;
/** Optional sandboxed browser settings. */
browser?: SandboxBrowserSettings;
/** Auto-prune sandbox settings. */
prune?: SandboxPruneSettings;
};
//#endregion
//#region src/config/types.base.d.ts
/** Typing indicator timing policy shared by channel configs. */
type TypingMode = "never" | "instant" | "thinking" | "message";
/** Session-key ownership model for inbound messages. */
type SessionScope$1 = "per-sender" | "global";
/** DM session-key granularity across peers, channels, and accounts. */
type DmScope = "main" | "per-peer" | "per-channel-peer" | "per-account-channel-peer";
type GroupScope = "main" | "per-group";
/** Which source messages outbound replies should thread or quote against. */
type ReplyToMode = "off" | "first" | "all" | "batched";
/** Group-chat admission policy for channels with allowlists. */
type GroupPolicy = "open" | "disabled" | "allowlist";
/** Direct-message admission policy for channels with pairing/allowlists. */
type DmPolicy = "pairing" | "allowlist" | "open" | "disabled";
/** How much non-allowlisted context is visible to an agent. */
type ContextVisibilityMode = "all" | "allowlist" | "allowlist_quote";
/** Text splitting strategy for outbound channel delivery. */
type TextChunkMode = "length" | "newline";
/** Preview/progress delivery mode while an agent response is still streaming. */
type StreamingMode = "off" | "partial" | "block" | "progress";
/** How command text is represented in streaming progress previews. */
type ChannelStreamingCommandTextMode = "raw" | "status";
type BlockStreamingCoalesceConfig = {
/** Minimum buffered characters before coalesced block delivery. */
minChars?: number;
/** Maximum buffered characters before a block must be flushed. */
maxChars?: number;
/** Idle time in ms before flushing a partial coalesced block. */
idleMs?: number;
};
type BlockStreamingChunkConfig = {
/** Minimum preview chunk size before sending another draft update. */
minChars?: number;
/** Maximum preview chunk size before forcing a draft update. */
maxChars?: number;
/** Preferred natural boundary when splitting preview chunks. */
breakPreference?: "paragraph" | "newline" | "sentence";
};
type ChannelStreamingProgressConfig = {
/** Initial progress title. "auto" picks from labels; false hides the title. Default: "auto". */
label?: string | false;
/** Candidate labels for label="auto". Defaults to OpenClaw's built-in progress labels. */
labels?: string[];
/** Maximum number of progress lines to keep below the label. Default: 8. */
maxLines?: number;
/** Maximum characters per compact progress line before truncation. Default: 120. */
maxLineChars?: number;
/** Include compact tool/task progress in the draft. Default: true. */
toolProgress?: boolean;
/** Command/exec progress detail in the draft. "raw" opts into command text; "status" shows only the tool label. Default: "status". */
commandText?: ChannelStreamingCommandTextMode;
/** Include assistant commentary/preamble text in the progress draft. Default: false. */
commentary?: boolean;
/**
* Replace tool lines with a short utility-model narration of what the agent
* is doing. Runs when a utility model resolves (explicit `utilityModel` or
* the primary provider's declared default). Default: true.
*/
narration?: boolean;
};
type ChannelStreamingPreviewConfig = {
/** Chunking thresholds for preview-draft updates while streaming. */
chunk?: BlockStreamingChunkConfig;
/**
* Render live tool/activity updates into the preview draft for channels that
* edit a single preview message in place.
* Default: true.
*/
toolProgress?: boolean;
/** Command/exec progress detail in the preview. "raw" opts into command text; "status" shows only the tool label. Default: "status". */
commandText?: ChannelStreamingCommandTextMode;
};
type ChannelStreamingBlockConfig = {
/** Enable chunked block-reply delivery for channels that support it. */
enabled?: boolean;
/** Merge streamed block replies before sending. */
coalesce?: BlockStreamingCoalesceConfig;
};
type ChannelStreamingConfig<TProgress extends ChannelStreamingProgressConfig = ChannelStreamingProgressConfig> = {
/**
* Preview streaming mode:
* - "off": disable preview updates
* - "partial": update one preview in place
* - "block": emit larger chunked preview updates
* - "progress": progress/status preview mode for channels that support it
*/
mode?: StreamingMode;
/** Chunking mode for outbound text delivery. */
chunkMode?: TextChunkMode;
/** Prefer a channel's native streaming transport over its portable draft path. */
nativeTransport?: boolean;
preview?: ChannelStreamingPreviewConfig;
progress?: TProgress;
block?: ChannelStreamingBlockConfig;
};
type ChannelDeliveryStreamingConfig = Pick<ChannelStreamingConfig, "chunkMode" | "block">;
/** Streaming subset used by channels that render visible preview/progress replies. */
type ChannelPreviewStreamingConfig = Pick<ChannelStreamingConfig, "mode" | "chunkMode" | "preview" | "progress" | "block">;
type MarkdownTableMode = "off" | "bullets" | "code" | "block";
type MarkdownConfig = {
/** Table rendering mode (off|bullets|code|block). */
tables?: MarkdownTableMode;
};
type HumanDelayConfig = {
/** Delay style for block replies (off|natural|custom). */
mode?: "off" | "natural" | "custom";
/** Minimum delay in milliseconds (default: 800). */
minMs?: number;
/** Maximum delay in milliseconds (default: 2500). */
maxMs?: number;
};
type SessionSendPolicyAction = "allow" | "deny";
type SessionSendPolicyMatch = {
/** Channel/provider id match. */
channel?: string;
/** Direct/group/thread classification when the caller has channel metadata. */
chatType?: ChatType;
/**
* Session key prefix match.
* Note: some consumers match against a normalized key (for example, stripping `agent:<id>:`).
*/
keyPrefix?: string;
/** Optional raw session-key prefix match for consumers that normalize session keys. */
rawKeyPrefix?: string;
};
type SessionSendPolicyRule = {
/** Action applied when match criteria select this rule. */
action: SessionSendPolicyAction;
/** Optional match filter; omitted match behaves as a catch-all rule. */
match?: SessionSendPolicyMatch;
};
type SessionSendPolicyConfig = {
/** Fallback action when no send-policy rule matches. */
default?: SessionSendPolicyAction;
/** Ordered allow/deny rules; first matching rule wins. */
rules?: SessionSendPolicyRule[];
};
type SessionResetMode = "none" | "daily" | "idle";
type SessionResetConfig = {
mode?: SessionResetMode;
/** Local hour (0-23) for the daily reset boundary. */
atHour?: number;
/** Sliding idle window (minutes). When set with daily mode, whichever expires first wins. */
idleMinutes?: number;
};
type SessionResetByTypeConfig = {
direct?: SessionResetConfig;
group?: SessionResetConfig;
thread?: SessionResetConfig;
};
type SessionThreadBindingsConfig = {
/**
* Master switch for thread-bound session routing features.
* Channel/provider keys can override this default.
*/
enabled?: boolean;
/**
* Inactivity window for thread-bound sessions (hours).
* Binding expires after this amount of idle time. Set to 0 to disable. Default: 24.
*/
idleHours?: number;
/**
* Optional hard max age for thread-bound sessions (hours).
* Binding expires once this age is reached even if active. Set to 0 to disable. Default: 0.
*/
maxAgeHours?: number;
/**
* Allow channel integrations to create thread-bound work sessions from
* sessions_spawn or native ACP spawn flows. Channel/account keys can override.
* Default: true when thread bindings are enabled.
*/
spawnSessions?: boolean;
/**
* Default context mode for native subagents spawned into a bound thread.
* Default: "fork" so the child starts from the requester transcript.
*/
defaultSpawnContext?: "isolated" | "fork";
};
type SessionSharingConfig = {
/** Allow owners/admins to set sessions read-only. Default: true. */
readOnly?: boolean;
/** Allow owners/admins to select suggest mode. Default: true. */
suggest?: boolean;
/** Allow owners/admins to hide draft sessions from other operators. Default: true. */
drafts?: boolean;
};
type SessionConfig = {
scope?: SessionScope$1;
/** DM session scoping (default: "main"). */
dmScope?: DmScope;
/** Group/channel session scoping (default: "per-group"). */
groupScope?: GroupScope;
/** Map platform-prefixed identities (e.g. "telegram:123") to canonical DM peers. */
identityLinks?: Record<string, string[]>;
resetTriggers?: string[];
reset?: SessionResetConfig;
resetByType?: SessionResetByTypeConfig;
/** Channel-specific reset overrides (e.g. { discord: { mode: "idle", idleMinutes: 10080 } }). */
resetByChannel?: Record<string, SessionResetConfig>;
store?: string;
mainKey?: string;
sendPolicy?: SessionSendPolicyConfig;
/** Shared defaults for thread-bound session routing across channels/providers. */
threadBindings?: SessionThreadBindingsConfig;
/** Collaboration modes owners and administrators may select. */
sharing?: SessionSharingConfig;
/** Automatic session store maintenance (pruning, capping, archive retention, disk budget). */
maintenance?: SessionMaintenanceConfig;
};
type SessionMaintenanceMode = "enforce" | "warn";
/** Session-store cleanup policy for transcript count, age, archives, and disk budget. */
type SessionMaintenanceConfig = {
/** Whether to enforce maintenance or warn only. Default: "enforce". */
mode?: SessionMaintenanceMode;
/** Remove session entries older than this duration (e.g. "30d", "12h"). Default: "30d". */
pruneAfter?: string | number;
/** Archive inactive dashboard sessions after this duration. Default: "7d"; false or 0 disables. */
archiveDashboardAfter?: string | number | false;
/** Maximum total session entries to keep when protection permits. Default: 500. */
maxEntries?: number;
/** Protect interactive sessions active within this duration. Default and false: disabled. */
preserveRecent?: string | number | false;
/**
* Age-based retention for archived transcripts (`*.reset.<timestamp>` and
* `*.deleted.<timestamp>`). Default and `false`: keep archives until the
* disk budget evicts them oldest-first; a duration opts into deletion.
*/
resetArchiveRetention?: string | number | false;
/**
* Per-agent sessions-directory disk budget (e.g. "500mb"). Default: "10gb".
* When exceeded, warn (mode=warn) or enforce oldest-first cleanup
* (mode=enforce). Set `false`, `0`, or `"0"` to disable the budget entirely.
*/
maxDiskBytes?: number | string | false;
/**
* Target size after disk-budget cleanup (high-water mark), e.g. "400mb".
* Default: 80% of maxDiskBytes. A value that resolves to zero falls back to
* the default instead of clearing history; negative values are invalid.
*/
highWaterBytes?: number | string;
};
type LoggingConfig = {
level?: "silent" | "fatal" | "error" | "warn" | "info" | "debug" | "trace";
file?: string;
/** Maximum size of a single log file in bytes before rotation. Default: 100 MB. */
maxFileBytes?: number;
consoleLevel?: "silent" | "fatal" | "error" | "warn" | "info" | "debug" | "trace";
consoleStyle?: "pretty" | "json";
/** Redact sensitive tokens in log sinks and persisted transcript text. Default: "tools". Safety-boundary UI/tool/diagnostic payloads may still redact when this is "off". */
/** Regex patterns used to redact sensitive tokens from logs and transcripts. */
redactPatterns?: string[];
/** Metadata-only agent activity audit ledger settings. */
audit?: AuditConfig;
};
type DiagnosticsOtelConfig = {
enabled?: boolean;
endpoint?: string;
tracesEndpoint?: string;
metricsEndpoint?: string;
logsEndpoint?: string;
protocol?: "http/protobuf";
headers?: Record<string, string>;
serviceName?: string;
/** Replacement prefix for OpenClaw-owned metric names. Empty removes the prefix; defaults to "openclaw.". */
metricNamePrefix?: string;
traces?: boolean;
metrics?: boolean;
logs?: boolean;
/** Log export sink: OTLP by default, stdout JSONL, or both. */
logsExporter?: "otlp" | "stdout" | "both";
/** Trace sample rate (0.0 - 1.0). */
sampleRate?: number;
/** Metric export interval (ms). */
flushIntervalMs?: number;
/** Opt in to raw non-system message/tool content in OTEL span attributes. */
captureContent?: boolean;
};
type DiagnosticsCacheTraceConfig = {
/** Write prompt-cache trace artifacts for debugging deterministic cache input. */
enabled?: boolean;
};
type AuditConfig = {
/**
* Record metadata-only run, tool, and enabled message lifecycle events into
* the shared state database. Content is never stored. Default: true. This is
* startup-scoped; disabling stops new event inserts after restart while retained
* records stay readable until they expire.
*/
enabled?: boolean;
/**
* Retain bounded execution-identity attribution for exact-run inspection.
* Default: false. Requires the audit ledger and takes effect after Gateway restart.
*/
executionIdentity?: boolean;
/**
* Record content-free message lifecycle metadata. `direct` records only
* known direct conversations; `all` also records group, channel, and
* unknown conversation kinds. Default: `off`.
*/
messages?: "off" | "direct" | "all";
};
type DiagnosticsConfig = {
enabled?: boolean;
/** Optional ad-hoc diagnostics flags (e.g. "telegram.http"). */
flags?: string[];
otel?: DiagnosticsOtelConfig;
cacheTrace?: DiagnosticsCacheTraceConfig;
};
type AgentElevatedAllowFromConfig = Partial<Record<string, Array<string | number>>>;
type IdentityConfig = {
name?: string;
theme?: string;
emoji?: string;
/** Avatar image: workspace-relative path, http(s) URL, or data URI. */
avatar?: string;
};
//#endregion
//#region src/config/types.agent-defaults.d.ts
/** Workspace bootstrap-file injection policy for agent system prompts. */
type AgentContextInjection = "always" | "continuation-skip" | "never";
/**
* Optional bootstrap files that setup can skip while still creating required
* agent files. "HEARTBEAT.md" stays accepted as legacy config input even
* though workspace setup no longer writes it.
*/
type OptionalBootstrapFileName = "SOUL.md" | "USER.md" | "HEARTBEAT.md" | "IDENTITY.md";
/** Embedded runner behavior contract used by strict-agentic provider flows. */
type EmbeddedAgentExecutionContract = "default" | "strict-agentic";
/** Prompt-only default for how strongly agents should delegate to sub-agents. */
type SubagentDelegationMode = "suggest" | "prefer";
/** Image compression/detail preference used before sending image inputs to models. */
type AgentImageQualityPreference = "auto" | "efficient" | "balanced" | "high";
/** Scope of an interactive model selection when no explicit scope is supplied. */
type ModelSelectionScope = "session" | "agent" | "global";
/** Canonical thinking levels accepted by agent defaults and compaction overrides. */
type AgentThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "adaptive" | "max" | "ultra";
type AgentModelEntryConfig = {
/** Optional display/lookup alias for this provider/model entry. */
alias?: string;
/** Provider-specific API parameters (e.g., GLM-4.7 thinking mode). */
params?: Record<string, unknown>;
/** Optional agent execution runtime for this specific provider/model entry. */
agentRuntime?: AgentRuntimePolicyConfig;
/** OpenClaw Code Mode override; omitted inherits the enclosing activation policy. */
codeMode?: boolean;
/** Enable streaming for this model (default: true, false for Ollama to avoid SDK issue #1205). */
streaming?: boolean;
};
type AgentModelPolicyConfig = {
/** Model refs allowed for session/run overrides. Empty or omitted allows any model. */
allow?: string[];
};
type AgentContextPruningConfig = {
/** Pruning mode for old tool results in model context. */
mode?: "off" | "cache-ttl";
/** TTL to consider cache expired (duration string, default unit: minutes). */
ttl?: string;
tools?: {
/** Tool names eligible for context pruning. */
allow?: string[];
/** Tool names excluded from context pruning. */
deny?: string[];
};
hardClear?: {
/** Replace oversized old tool results with a placeholder at high pressure. */
enabled?: boolean;
/** Placeholder text inserted when a tool result is hard-cleared. */
placeholder?: string;
};
};
type AgentStartupContextConfig = {
/** Enable runtime-owned startup-context prelude on bare session resets (default: true). */
enabled?: boolean;
/** Which bare reset commands should receive startup context (default: ["new", "reset"]). */
applyOn?: Array<"new" | "reset">;
/** How many dated memory files to load counting backward from today (default: 2). */
dailyMemoryDays?: number;
/** Max bytes to read from each daily memory file before skipping (default: 16384). */
maxFileBytes?: number;
/** Max characters retained from each daily memory file (default: 1200). */
maxFileChars?: number;
/** Max total characters retained across the startup prelude (default: 2800). */
maxTotalChars?: number;
};
type AgentContextLimitsConfig = {
/** Default max chars returned by memory_get before truncation metadata/notice (default: 12000). */
memoryGetMaxChars?: number;
/** Max chars retained from post-compaction AGENTS.md context injection (default: 1800). */
postCompactionMaxChars?: number;
};
type AgentDefaultsConfig = {
/** @deprecated Doctor-only legacy input. */
imageGenerationModel?: AgentToolModelConfig;
/** @deprecated Doctor-only legacy input. */
videoGenerationModel?: AgentToolModelConfig;
/** @deprecated Doctor-only legacy input. */
musicGenerationModel?: AgentToolModelConfig;
/** @deprecated Doctor-only legacy input. */
envelopeTimezone?: string;
/** @deprecated Doctor-only legacy input. */
envelopeTimestamp?: "on" | "off";
/** @deprecated Doctor-only legacy input. */
envelopeElapsed?: "on" | "off";
/** @deprecated Doctor-only legacy input. */
timeFormat?: "auto" | "12" | "24";
/** @deprecated Doctor-only legacy input. */
promptOverlays?: {
gpt5?: {
personality?: "friendly" | "on" | "off";
};
};
/** Global default provider params applied to all models before per-model and per-agent overrides. */
params?: Record<string, unknown>;
/** Primary model and fallbacks (provider/model). Accepts string or {primary,fallbacks}. */
model?: AgentModelConfig;
/** Optional model-selection scope. Omitted preserves each surface's existing behavior. */
modelSelectionScope?: ModelSelectionScope;
/** Optional lower-cost model for short internal tasks such as generated session titles. */
utilityModel?: string;
/**
* @deprecated Legacy raw config accepted only by doctor/migration repair.
* Normal schema parsing rejects this key; use per-model agentRuntime instead.
*/
agentRuntime?: AgentRuntimePolicyConfig;
/** Optional image-capable model and fallbacks (provider/model). Accepts string or {primary,fallbacks}. */
imageModel?: AgentToolModelConfig;
/** Media-generation model preferences by output modality. */
mediaModels?: {
image?: AgentToolModelConfig;
video?: AgentToolModelConfig;
music?: AgentToolModelConfig;
};
/** Optional voice model and fallbacks (provider/model) for TTS/STT/realtime voice providers. */
voiceModel?: AgentToolModelConfig;
/** Optional PDF-capable model and fallbacks (provider/model). Accepts string or {primary,fallbacks}. */
pdfModel?: AgentToolModelConfig;
/** Maximum PDF file size in megabytes (default: 10). */
pdfMaxMb?: number;
/** Maximum number of PDF pages to process (default: 20). */
pdfMaxPages?: number;
/** Model catalog with optional aliases (full provider/model keys). */
models?: Record<string, AgentModelEntryConfig>;
/** Explicit model override policy. Empty or omitted allow permits any model. */
modelPolicy?: AgentModelPolicyConfig;
/** Agent bootstrap and memory directory; also the working directory when cwd is unset. */
workspace?: string;
/** Working directory for agent reply runs, separate from workspace bootstrap and memory files. */
cwd?: string;
/** Optional default allowlist of skills for agents that do not set agents.entries.*.skills. */
skills?: string[];
/** Silent-reply policy by conversation type. */
silentReply?: SilentReplyPolicyShape;
/** Optional repository root for system prompt runtime line (overrides auto-detect). */
repoRoot?: string;
/** Provider-independent prompt overlays applied by model family. */
/** Skip bootstrap (BOOTSTRAP.md creation, etc.) for pre-configured deployments. */
skipBootstrap?: boolean;
/**
* List of optional bootstrap filenames to skip writing to the workspace root.
* Applies to: SOUL.md, USER.md, IDENTITY.md ("HEARTBEAT.md" is accepted but a no-op).
* Required workspace setup such as AGENTS.md still runs.
* Example: ["SOUL.md", "USER.md", "IDENTITY.md"]
*/
skipOptionalBootstrapFiles?: OptionalBootstrapFileName[];
/**
* Controls when workspace bootstrap files (AGENTS.md, SOUL.md, etc.) are
* injected into the system prompt:
* - always: inject on every turn (default)
* - continuation-skip: skip injection on safe continuation turns once the
* transcript already contains a completed assistant turn
*/
contextInjection?: AgentContextInjection;
/** Max chars for injected bootstrap files before truncation (default: 20000). */
bootstrapMaxChars?: number;
/** Max total chars across all injected bootstrap files (default: 150000). */
bootstrapTotalMaxChars?: number;
/** Experimental agent-default flags. Keep off unless you are intentionally testing a preview surface. */
experimental?: {
/**
* Drop heavyweight non-essential default tools for weaker or smaller local
* model backends. Experimental preview only.
*/
localModelLean?: boolean;
};
/**
* Agent-visible bootstrap truncation warning mode:
* - off: do not inject warning text
* - once: inject once per unique truncation signature
* - always: inject on every run with truncation (default)
*/
/**
* Optional IANA timezone for model-visible timestamps, prompt context, system events,
* and heartbeat active hours. Defaults to the host timezone.
*/
userTimezone?: string;
/** Runtime-owned first-turn startup context for bare /new and /reset. */
startupContext?: AgentStartupContextConfig;
/** Focused context-budget overrides for high-volume injected/read surfaces. */
contextLimits?: AgentContextLimitsConfig;
/** Opt-in: prune old tool results from the LLM context to reduce token usage. */
contextPruning?: AgentContextPruningConfig;
/** Compaction tuning and pre-compaction memory flush behavior. */
compaction?: AgentCompactionConfig;
/** Embedded OpenClaw runner hardening and compatibility controls. */
embeddedAgent?: {
/**
* How embedded OpenClaw should trust workspace-local `.openclaw/settings.json`.
* - sanitize (default): apply project settings except shellPath/shellCommandPrefix
* - ignore: ignore project settings entirely
* - trusted: trust project settings as-is
*/
projectSettingsPolicy?: "trusted" | "sanitize" | "ignore";
/**
* Embedded OpenClaw execution contract:
* - default: keep the standard runner behavior
* - strict-agentic: enable structured plan tracking and non-visible turn recovery on supported GPT-5 runs
*/
executionContract?: EmbeddedAgentExecutionContract;
};
/** Default thinking level when no /think directive is present. */
thinkingDefault?: AgentThinkingLevel;
/** Default fast-mode policy inherited by agent entries that omit it. */
fastModeDefault?: FastMode;
/** Default verbose level when no /verbose directive is present. */
verboseDefault?: "off" | "on" | "full";
/**
* Detail mode for user-visible tool progress in /verbose and editable progress drafts.
* - explain: compact human summary (default)
* - raw: include raw command/detail when available
*/
toolProgressDetail?: "explain" | "raw";
/** Default reasoning level when no /reasoning directive is present. */
reasoningDefault?: "off" | "on" | "stream";
/** Default elevated level when no /elevated directive is present. */
elevatedDefault?: "off" | "on" | "ask" | "full";
/** Default block streaming level when no override is present. */
blockStreamingDefault?: "off" | "on";
/**
* Block streaming boundary:
* - "text_end": end of each assistant text content block (before tool calls)
* - "message_end": end of the whole assistant message (may include tool blocks)
*/
blockStreamingBreak?: "text_end" | "message_end";
/** Soft block chunking for streamed replies (min/max chars, prefer paragraph/newline). */
blockStreamingChunk?: BlockStreamingChunkConfig;
/**
* Block reply coalescing (merge streamed chunks before send).
* idleMs: wait time before flushing when idle.
*/
blockStreamingCoalesce?: BlockStreamingCoalesceConfig;
/** Human-like delay between block replies. */
humanDelay?: HumanDelayConfig;
timeoutSeconds?: number;
/** Max inbound media size in MB for agent-visible attachments (text note or future image attach). */
mediaMaxMb?: number;
/**
* Max image side length (pixels) when sanitizing base64 image payloads in transcripts/tool results.
* Default: 1200.
*/
imageMaxDimensionPx?: number;
/**
* Image compression/detail preference for image-tool media loading.
* Default: auto, which adapts to provider/model limits and image count.
*/
imageQuality?: AgentImageQualityPreference;
typingIntervalSeconds?: number;
/** Typing indicator start mode (never|instant|thinking|message). */
typingMode?: TypingMode;
/** Periodic background heartbeat runs. */
heartbeat?: {
/** Agent that owns ambient heartbeat runs when no per-agent heartbeat is configured. */
agentId?: string;
/** Heartbeat interval (duration string, default unit: minutes; default: 30m). */
every?: string;
/** Optional active-hours window (local time); heartbeats run only inside this window. */
activeHours?: {
/** Start time (24h, HH:MM). Inclusive. */
start?: string;
/** End time (24h, HH:MM). Exclusive. Use "24:00" for end-of-day. */
end?: string;
/** Timezone for the window ("user", "local", or IANA TZ id). Default: "user". */
timezone?: string;
};
/** Heartbeat model override (provider/model). */
model?: string;
/** Session key for heartbeat runs ("main" or explicit session key). */
session?: string;
/** Delivery target. Default "owner" uses explicit ownerAllowFrom/allowFrom; "last" may follow groups. */
target?: string;
/** Direct/DM delivery policy. Default: "allow". */
directPolicy?: "allow" | "block";
/** Explicit channel destination; ignored for target "owner" or an unset target. */
to?: string;
/** Optional account id for multi-account channels. */
accountId?: string;
/** Override the heartbeat prompt body. The default treats scratch as monitor prose and directs recurring work to cron jobs. */
prompt?: string;
/** Run timeout in seconds for heartbeat agent turns. Unset uses global timeout or heartbeat cadence capped at 600 seconds. */
timeoutSeconds?: number;
/**
* If true, run heartbeat turns with lightweight bootstrap context.
* Lightweight mode skips workspace bootstrap files; monitor scratch is
* injected by the heartbeat runner either way.
*/
lightContext?: boolean;
/**
* If true, run heartbeat turns in an isolated session with no prior
* conversation history. Dramatically reduces per-heartbeat token cost by
* avoiding the full session transcript.
*/
isolatedSession?: boolean;
};
/** Owner for ambient system-agent/Custodian inference and unscoped operator-read fallbacks. */
systemAgent?: {
agentId?: string;
};
/** Upgrade-only owner for the inherited credential store until H2-2 relocates credentials. */
authInheritance?: {
agentId?: string;
};
/** Upgrade-only owner for retired main-agent rows and legacy fixed session stores. */
sessionStore?: {
agentId?: string;
};
/** Max concurrent agent runs across all conversations. Default: min(16, max(8, available CPU parallelism)). */
maxConcurrent?: number;
/** Sub-agent defaults (spawned via sessions_spawn). */
subagents?: {
/** Prompt-only guidance for how strongly the main agent should delegate work. Default: "suggest". */
delegationMode?: SubagentDelegationMode;
/** Default allowlist of target agent ids for sessions_spawn. Use "*" to allow any configured target. */
allowAgents?: string[];
/** Max concurrent sub-agent runs (global lane: "subagent"). Default: 8. */
maxConcurrent?: number;
/** Maximum depth allowed for sessions_spawn chains. Default behavior: 1 (no nested spawns). */
maxSpawnDepth?: number;
/** Maximum active children a single requester session may spawn. Default behavior: 5. */
maxChildrenPerAgent?: number;
/** Auto-archive sub-agent sessions after N minutes (default: 60, set 0 to disable). */
archiveAfterMinutes?: number;
/** Default model selection for spawned sub-agents (string or {primary,fallbacks}). */
model?: AgentModelConfig;
/** Default thinking level for spawned sub-agents (e.g. "off", "low", "medium", "high"). */
thinking?: string;
/** Default run timeout in seconds for spawned sub-agents (0 = no timeout). */
runTimeoutSeconds?: number;
/** Gateway timeout in ms for sub-agent announce delivery calls (default: 120000). */
announceTimeoutMs?: number;
/** Require explicit agentId in sessions_spawn (no default same-as-caller). Default: false. */
requireAgentId?: boolean;
};
/** Optional sandbox settings for non-main sessions. */
sandbox?: AgentSandboxConfig;
};
type AgentCompactionMode = "default" | "safeguard";
type AgentCompactionPostIndexSyncMode = "off" | "async" | "await";
type AgentCompactionIdentifierPolicy = "strict" | "off";
type AgentCompactionQualityGuardConfig = {
/** Enable compaction summary quality audits and regeneration retries. Default: false. */
enabled?: boolean;
/** Maximum regeneration retries after a failed quality audit. Default: 1 when enabled. */
maxRetries?: number;
};
type AgentCompactionMidTurnPrecheckConfig = {
/**
* Enable structured context pressure checks after tool results are appended
* and before the next agent model call. Default: false.
*/
enabled?: boolean;
};
type AgentCompactionConfig = {
/** Enable embedded proactive auto-compaction. Default: true. */
enabled?: boolean;
/** Compaction summarization mode. */
mode?: AgentCompactionMode;
/** Thinking level for embedded OpenClaw compaction summaries. Default: low. */
thinkingLevel?: AgentThinkingLevel | "inherit";
/** Embedded OpenClaw keepRecentTokens budget used for cut-point selection. */
keepRecentTokens?: number;
/** Preserve this many most-recent user/assistant turns verbatim in compaction summary context. */
recentTurnsPreserve?: number;
/** Identifier-preservation instruction policy for compaction summaries. */
identifierPolicy?: AgentCompactionIdentifierPolicy;
/** Optional quality-audit retries for safeguard compaction summaries. */
qualityGuard?: AgentCompactionQualityGuardConfig;
/** Mid-turn precheck for tool-loop context pressure. Default: disabled. */
midTurnPrecheck?: AgentCompactionMidTurnPrecheckConfig;
/** Post-compaction session memory index sync mode. */
postIndexSync?: AgentCompactionPostIndexSyncMode;
/** Pre-compaction memory flush (agentic turn). Default: enabled. */
memoryFlush?: AgentCompactionMemoryFlushConfig;
/** H2/H3 section names from AGENTS.md to inject after compaction. */
postCompactionSections?: string[];
/** Optional provider/model or configured bare alias for compaction summarization.
* When set, compaction uses this model instead of the agent's primary model.
* Falls back to the primary model when unset. */
model?: string;
/** Safety window in seconds for each built-in compaction model request (default: 180). */
timeoutSeconds?: number;
/**
* Id of a registered compaction provider plugin.
* When set, the provider's summarize() is called instead of
* the built-in summarizeInStages(). Falls back to built-in on failure.
*/
provider?: string;
/**
* Byte threshold for normal preflight local compaction (bytes, or a byte-size
* string like "20mb"). Set to 0 or leave unset to disable. Also caps Codex
* app-server native rollouts; oversized native threads restart fresh.
*/
maxActiveTranscriptBytes?: number | string;
/**
* Send brief context-maintenance notices to the user: when compaction starts
* and completes, and when a pre-compaction memory flush is exhausted so the
* reply continues in a degraded state.
* Default: false (silent by default).
*/
notifyUser?: boolean;
};
type AgentCompactionMemoryFlushConfig = {
/** Enable the pre-compaction memory flush (default: true). */
enabled?: boolean;
/** Optional provider/model override used only for pre-compaction memory flush turns. */
model?: string;
/** Run the memory flush when context is within this many tokens of the compaction threshold. */
softThresholdTokens?: number;
/**
* Force a memory flush when transcript size reaches this threshold
* (bytes, or byte-size string like "2mb"). Set to 0 to disable.
*/
forceFlushTranscriptBytes?: number | string;
};
//#endregion
//#region packages/memory-host-sdk/src/host/types.d.ts
/** Additional memory root, optionally narrowed by a root-relative glob. */
type MemoryExtraPath = string | {
path: string;
pattern?: string;
};
//#endregion
//#region src/config/types.memory.d.ts
/** Citation rendering mode for memory-injected context. */
type MemoryCitationsMode = "auto" | "on" | "off";
/** Top-level memory config block. */
type MemoryConfig = {
citations?: MemoryCitationsMode;
/** Shared embedding/search defaults. Per-agent overrides live under agents.entries.*.memory.search. */
search?: MemorySearchConfig;
};
type MemorySearchConfig = {
/** Enable vector memory search (default: true). */
enabled?: boolean;
/** Use relevant context from this agent's other private conversations. */
rememberAcrossConversations?: boolean;
/** Sources to index and search (default: ["memory"]). */
sources?: Array<"memory" | "sessions">;
/** Extra paths to include in memory search, optionally filtered by a glob. */
extraPaths?: MemoryExtraPath[];
/** Optional multimodal file indexing for selected extra paths. */
multimodal?: {
/** Enable image/audio embeddings from extraPaths. */
enabled?: boolean;
/** Which non-text file types to index. */
modalities?: Array<"image" | "audio" | "all">;
/** Max bytes allowed per multimodal file before it is skipped. */
maxFileBytes?: number;
};
/** Experimental session transcript indexing. */
experimental?: {
sessionMemory?: boolean;
};
/** Memory embedding provider adapter id. */
provider?: string;
remote?: {
baseUrl?: string;
apiKey?: SecretInput;
headers?: Record<string, string>;
batch?: {
/** Enable batch API for embedding indexing (OpenAI/Gemini; default: true). */
enabled?: boolean;
};
};
/** Fallback memory embedding provider adapter id when embeddings fail. */
fallback?: string;
/** Embedding model id (remote) or alias (local). */
model?: string;
/** Optional provider-specific embedding input_type for query and document requests. */
inputType?: string;
/** Optional provider-specific embedding input_type for query-time memory search. */
queryInputType?: string;
/** Optional provider-specific embedding input_type for document/index embeddings. */
documentInputType?: string;
/**
* Provider-specific output vector dimensions. Gemini supports 128 to 3072.
* Google recommends 768, 1536, or 3072 dimensions.
*/
outputDimensionality?: number;
/** Local embedding settings for the managed llama.cpp server. */
local?: {
/** GGUF model path or hf: URI. */
modelPath?: string;
};
/** Index storage configuration. */
store?: {
fts?: {
/** FTS5 tokenizer (default: "unicode61"). Use "trigram" for CJK text support. */
tokenizer?: "unicode61" | "trigram";
};
vector?: {
/** Enable the sqlite-vec semantic index (default: true). */
enabled?: boolean;
/** Optional override path to sqlite-vec extension (.dylib/.so/.dll). */
extensionPath?: string;
};
cache?: {
/** Enable embedding cache (default: true). */
enabled?: boolean;
/** Optional max cache entries per provider/model. */
maxEntries?: number;
};
};
/** Query behavior. */
query?: {
maxResults?: number;
minScore?: number;
};
/** Index cache behavior. */
cache?: {
/** Cache chunk embeddings in SQLite (default: true). */
enabled?: boolean;
};
};
//#endregion
//#region packages/gateway-protocol/src/schema/logs-chat.d.ts
declare const QUEUE_MODES: readonly ["steer", "followup", "collect", "interrupt"];
type QueueMode = (typeof QUEUE_MODES)[number];
//#endregion
//#region src/config/types.queue.d.ts
/** Queue overflow policy for inbound channel messages. */
type QueueDropPolicy = "old" | "new" | "summarize";
type QueueModeByProvider = {
whatsapp?: QueueMode;
telegram?: QueueMode;
discord?: QueueMode;
irc?: QueueMode;
googlechat?: QueueMode;
slack?: QueueMode;
mattermost?: QueueMode;
signal?: QueueMode;
imessage?: QueueMode;
msteams?: QueueMode;
webchat?: QueueMode;
matrix?: QueueMode;
};
//#endregion
//#region src/config/types.messages.d.ts
type MentionPatternsMode = "allow" | "deny";
type MentionPatternsPolicyConfig = {
mode?: MentionPatternsMode;
allowIn?: string[];
denyIn?: string[];
};
type GroupChatConfig = {
mentionPatterns?: string[];
historyLimit?: number;
/**
* Controls how unmentioned always-on group chatter is submitted.
* Default: "user_request".
*/
unmentionedInbound?: "user_request" | "room_event";
/**
* Controls how group/channel inbound events produce model-authored room replies.
* The message-tool mode requires explicit message sends for normal assistant
* output; explicitly host-owned runtime output remains deliverable except for
* ambient room events.
* Default: "automatic".
*/
visibleReplies?: "automatic" | "message_tool";
};
type DmConfig = {
historyLimit?: number;
};
type QueueConfig = {
mode?: QueueMode;
byChannel?: QueueModeByProvider;
/** Per-channel debounce overrides (ms). */
debounceMsByChannel?: InboundDebounceByProvider;
cap?: number;
drop?: QueueDropPolicy;
};
type InboundDebounceByProvider = Record<string, number>;
type InboundDebounceConfig = {
debounceMs?: number;
byChannel?: InboundDebounceByProvider;
};
type BroadcastStrategy = "parallel" | "sequential";
type BroadcastConfig = {
/** Default processing strategy for broadcast peers. */
strategy?: BroadcastStrategy;
/**
* Map peer IDs to arrays of agent IDs that should ALL process messages.
*
* Note: the index signature includes `undefined` so `strategy?: ...` remains type-safe.
*/
[peerId: string]: string[] | BroadcastStrategy | undefined;
};
type StatusReactionsConfig = {
/** Enable lifecycle status reactions (default: false). */
enabled?: boolean;
};
type MessagesConfig = {
/** @deprecated Doctor-only legacy input. */
removeAckAfterReply?: boolean;
/**
* Controls how source inbound events produce visible replies across direct,
* group, and channel conversations. Group/channel events still default to
* `groupChat.visibleReplies` when it is set.
*
* Default: "automatic". In group/channel rooms, "message_tool" keeps normal
* assistant output private unless the model sends visibly through the message
* tool; explicitly host-owned runtime output remains deliverable.
*/
visibleReplies?: "automatic" | "message_tool";
/**
* Prefix auto-added to all outbound replies.
*
* - string: explicit prefix (may include template variables)
* - special value: `"auto"` derives `[{agents.entries.*.identity.name}]` for the routed agent (when set)
*
* Supported template variables (case-insensitive):
* - `{model}` - short model name (e.g., `claude-opus-4-6`, `gpt-4o`)
* - `{modelFull}` - full model identifier (e.g., `anthropic/claude-opus-4-6`)
* - `{provider}` - provider name (e.g., `anthropic`, `openai`)
* - `{thinkingLevel}` or `{think}` - current thinking level (`high`, `low`, `off`)
* - `{identity.name}` or `{identityName}` - agent identity name
*
* Example: `"[{model} | think:{thinkingLevel}]"` ā `"[claude-opus-4-6 | think:high]"`
*
* Unresolved variables remain as literal text (e.g., `{model}` if context unavailable).
*
* Default: none
*/
responsePrefix?: string;
/** Custom `/usage full` footer template, inline or JSON file path. */
usageTemplate?: string | Record<string, unknown>;
/**
* Default per-reply usage footer mode (`responseUsage`) seeded into any session
* that has not set its own via `/usage`. Precedence: session value ā channel entry
* ā `default` ā `off`. Absent ā `off` (unchanged behavior).
*
* - string: one default for every channel, e.g. `"full"`.
* - object: per-channel with a fallback, e.g. `{ "default": "off", "discord": "full" }`.
*/
responseUsage?: "on" | "off" | "tokens" | "full" | {
default?: "on" | "off" | "tokens" | "full";
[channel: string]: "on" | "off" | "tokens" | "full" | undefined;
};
groupChat?: GroupChatConfig;
queue?: QueueConfig;
/** Debounce rapid inbound messages per sender (global + per-channel overrides). */
inbound?: InboundDebounceConfig;
/** Emoji reaction used to acknowledge inbound messages (empty disables). */
ackReaction?: string;
/** When to send ack reactions. Default: "group-mentions". */
ackReactionScope?: "group-mentions" | "group-all" | "direct" | "all" | "off" | "none";
/** Lifecycle status reactions configuration. */
statusReactions?: StatusReactionsConfig;
};
type NativeCommandsSetting = boolean | "auto";
/**
* Per-provider allowlist for command authorization.
* Keys are channel IDs (e.g., "discord", "whatsapp") or "*" for global default.
* Values are arrays of sender IDs allowed to use commands on that channel.
*/
type CommandAllowFrom = Record<string, Array<string | number>>;
type CommandsConfig = {
/** @deprecated Doctor-only legacy input. */
ownerDisplay?: "raw" | "hash";
/** @deprecated Doctor-only legacy input. */
ownerDisplaySecret?: string;
/** Enable native command registration when supported (default: "auto"). */
native?: NativeCommandsSetting;
/** Enable native skill command registration when supported (default: "auto"). */
nativeSkills?: NativeCommandsSetting;
/** Enable text command parsing (default: true). */
text?: boolean;
/** Allow bash chat command (`!`; `/bash` alias) (default: false). */
bash?: boolean;
/** How long bash waits before backgrounding (default: 2000; 0 backgrounds immediately). */
bashForegroundMs?: number;
/** Allow /config command (default: false). */
config?: boolean;
/** Allow /mcp command for OpenClaw-managed MCP settings (default: false). */
mcp?: boolean;
/** Allow /plugins command for plugin listing and enablement toggles (default: false). */
plugins?: boolean;
/** Allow /debug command (default: false). */
debug?: boolean;
/** Allow restart commands/tools and /update (default: true). */
restart?: boolean;
/** Explicit owner allowlist for owner-scoped commands (channel-native IDs). */
ownerAllowFrom?: Array<string | number>;
/** How owner IDs are rendered in system prompts. */
/**
* Per-provider allowlist restricting who can use slash commands.
* If set, overrides the channel's allowFrom for command authorization.
* Use "*" key for global default, provider-specific keys override the global.
* Example: { "*": ["user1"], discord: ["user:123"] }
*/
allowFrom?: CommandAllowFrom;
};
type ProviderCommandsConfig = {
/** Override native command registration for this provider (bool or "auto"). */
native?: NativeCommandsSetting;
/** Override native skill command registration for this provider (bool or "auto"). */
nativeSkills?: NativeCommandsSetting;
};
//#endregion
//#region src/config/types.skills.d.ts
/** Per-skill runtime override keyed by skill name or source-specific skill key. */
type SkillConfig = {
/** Disable a discovered skill without removing it from disk. */
enabled?: boolean;
/** Optional secret made available to the skill runtime through skill env handling. */
apiKey?: SecretInput;
/** Plain environment overrides applied when the skill runs. */
env?: Record<string, string>;
/** Skill-specific structured config consumed by the skill runtime. */
config?: Record<string, unknown>;
};
/** Discovery and watcher settings for skill sources. */
type SkillsLoadConfig = {
/**
* Additional skill folders to scan (lowest precedence).
* Each directory should contain skill subfolders with `SKILL.md`.
*/
extraDirs?: string[];
/**
* Real target directories that skill symlinks may resolve into even when they
* sit outside the configured source root.
*/
allowSymlinkTargets?: string[];
/** Watch skill folders for changes and refresh the skills snapshot. */
watch?: boolean;
};
/** Skill installation preferences and upload policy. */
type SkillsInstallConfig = {
preferBrew?: boolean;
nodeManager?: "npm" | "pnpm" | "yarn" | "bun";
/** Allow gateway clients to install zip archives staged through skills.upload.*. */
allowUploadedArchives?: boolean;
};
/** Limits that bound skill discovery and model-facing prompt expansion. */
type SkillsLimitsConfig = {
/** Max number of immediate child directories to consider under a skills root before treating it as suspicious. */
maxCandidatesPerRoot?: number;
/** Max number of skills to load per skills source (bundled/managed/workspace/extra). */
maxSkillsLoadedPerSource?: number;
/** Max number of skills to include in the model-facing skills prompt. */
maxSkillsInPrompt?: number;
/** Max characters for the model-facing skills prompt block (approx). */
maxSkillsPromptChars?: number;
/** Max size (bytes) allowed for a SKILL.md file to be considered. */
maxSkillFileBytes?: number;
};
type SkillsWorkshopAutonomousMode = "off" | "propose" | "auto";
/** Autonomous and approval settings for generated skill proposals. */
type SkillsWorkshopConfig = {
/** Autonomous Skill Workshop behavior controlled separately from user-prompted proposals. */
autonomous?: {
/** Capture policy for durable conversation signals and substantial completed work. */
mode?: SkillsWorkshopAutonomousMode;
};
/** Allow Skill Workshop apply to write through trusted skill symlink targets. */
allowSymlinkTargetWrites?: boolean;
/** Whether proposal lifecycle actions need explicit approval. */
approvalPolicy?: "pending" | "auto";
/** Maximum pending/quarantined proposals retained per workspace. */
maxPending?: number;
/** Maximum generated skill proposal size in bytes. */
maxSkillBytes?: number;
};
/** Top-level skills config block in openclaw config. */
type SkillsConfig = {
/** Optional bundled-skill allowlist (only affects bundled skills). */
allowBundled?: string[];
load?: SkillsLoadConfig;
install?: SkillsInstallConfig;
limits?: SkillsLimitsConfig;
workshop?: SkillsWorkshopConfig;
entries?: Record<string, SkillConfig>;
};
//#endregion
//#region src/infra/exec-safe-bin-policy-profiles.d.ts
type SafeBinProfileFixture = {
minPositional?: number;
maxPositional?: number;
allowedValueFlags?: readonly string[];
deniedFlags?: readonly string[];
};
//#endregion
//#region src/config/types.provider-request.d.ts
/** Authentication override applied to provider requests after model/provider defaults resolve. */
type ConfiguredProviderRequestAuth = {
mode: "provider-default";
} | {
mode: "authorization-bearer";
token: SecretInput;
} | {
mode: "header";
headerName: string;
value: SecretInput;
prefix?: string;
};
/** TLS material and verification knobs for provider or proxy connections. */
type ConfiguredProviderRequestTls = {
ca?: SecretInput;
cert?: SecretInput;
key?: SecretInput;
passphrase?: SecretInput;
serverName?: string;
insecureSkipVerify?: boolean;
};
/** Proxy selection for provider requests, including optional TLS settings for proxy transport. */
type ConfiguredProviderRequestProxy = {
mode: "env-proxy";
tls?: ConfiguredProviderRequestTls;
} | {
mode: "explicit-proxy";
url: string;
tls?: ConfiguredProviderRequestTls;
};
/** Shared provider request overrides used by model providers and media/tool providers. */
type ConfiguredProviderRequest = {
headers?: Record<string, SecretInput>;
auth?: ConfiguredProviderRequestAuth;
proxy?: ConfiguredProviderRequestProxy;
tls?: ConfiguredProviderRequestTls;
};
/** Model-provider request overrides plus the private-network opt-in used by model transports. */
type ConfiguredModelProviderRequest = ConfiguredProviderRequest & {
allowPrivateNetwork?: boolean;
};
//#endregion
//#region src/config/types.ssrf.d.ts
type SsrFPolicyConfig = {
/** Permit private/internal network targets. Default: false. */
dangerouslyAllowPrivateNetwork?: boolean;
/** Allow RFC 2544 benchmark-range IPs (198.18.0.0/15). */
allowRfc2544BenchmarkRange?: boolean;
/** Allow IPv6 Unique Local Addresses (fc00::/7). */
allowIpv6UniqueLocalRange?: boolean;
/** Explicitly allowed exact hostnames or IP literals. */
allowedHostnames?: string[];
/** Deny exact hosts or wildcard subdomains; "*.example.com" excludes the apex. Overrides allows. */
blockedHostnames?: string[];
};
//#endregion
//#region src/config/types.tools.d.ts
type MediaUnderstandingScopeMatch = {
/** Channel/provider id to match before running media or link understanding. */
channel?: string;
/** Direct/group classification from the channel runtime, when available. */
chatType?: ChatType;
/** Attachment or link key prefix used for narrow per-source routing. */
keyPrefix?: string;
};
type MediaUnderstandingScopeRule = {
/** Policy applied when match criteria select this scope rule. */
action: SessionSendPolicyAction;
/** Optional match filter; omitted match behaves as a catch-all rule. */
match?: MediaUnderstandingScopeMatch;
};
type MediaUnderstandingScopeConfig = {
/** Fallback action when no scope rule matches. */
default?: SessionSendPolicyAction;
/** Ordered allow/block rules; first matching rule wins. */
rules?: MediaUnderstandingScopeRule[];
};
type MediaUnderstandingCapability$1 = "image" | "audio" | "video";
type MediaUnderstandingAttachmentsConfig = {
/** Select the first matching attachment or process multiple. */
mode?: "first" | "all";
/** Max number of attachments to process (default: 1). */
maxAttachments?: number;
/** Attachment ordering preference. */
prefer?: "first" | "last" | "path" | "url";
};
type MediaProviderRequestConfig = {
/** Optional provider-specific query params (merged into requests). */
providerOptions?: Record<string, Record<string, string | number | boolean>>;
/** Optional base URL override for provider requests. */
baseUrl?: string;
/** Optional headers merged into provider requests. */
headers?: Record<string, string>;
/** Optional request transport overrides for provider HTTP calls. */
request?: ConfiguredProviderRequest;
};
type MediaUnderstandingModelConfig = MediaProviderRequestConfig & {
/** provider API id (e.g. openai, google). */
provider?: string;
/** Model id for provider-based understanding. */
model?: string;
/** Optional capability tags for shared model lists. */
capabilities?: MediaUnderstandingCapability$1[];
/** Use a CLI command instead of provider API. */
type?: "provider" | "cli";
/** CLI binary (required when type=cli). */
command?: string;
/** CLI args (template-enabled). */
args?: string[];
/** Optional prompt override for this model entry. */
prompt?: string;
/** Optional max output characters for this model entry. */
maxChars?: number;
/** Optional max bytes for this model entry. */
maxBytes?: number;
/** Optional timeout override (seconds) for this model entry. */
timeoutSeconds?: number;
/** Optional language hint for audio transcription. */
language?: string;
/** Auth profile id to use for this provider. */
profile?: string;
/** Preferred profile id if multiple are available. */
preferredProfile?: string;
};
type MediaUnderstandingConfig = MediaProviderRequestConfig & {
/** Enable media understanding when models are configured. */
enabled?: boolean;
/** Prefer a matching shared model entry. */
preferredModel?: string;
/** Optional scope gating for understanding. */
scope?: MediaUnderstandingScopeConfig;
/** Default max bytes to send. */
maxBytes?: number;
/** Default max output characters. */
maxChars?: number;
/** Default prompt. */
prompt?: string;
/** Internal request-scoped prompt override injected by CLI/runtime wrappers. */
_requestPromptOverride?: string;
/** Default timeout (seconds). */
timeoutSeconds?: number;
/** Default language hint (audio). */
language?: string;
/** Internal request-scoped language override injected by CLI/runtime wrappers. */
_requestLanguageOverride?: string;
/** Attachment selection policy. */
attachments?: MediaUnderstandingAttachmentsConfig;
/** Ordered model list (fallbacks in order). */
models?: MediaUnderstandingModelConfig[];
/**
* Echo the audio transcript back to the originating chat before agent processing.
* Lets users verify what was heard. Default: false.
*/
echoTranscript?: boolean;
/**
* Format string for the echoed transcript. Use `{transcript}` as placeholder.
* Default: 'š "{transcript}"'
*/
echoFormat?: string;
};
/** Per-capability defaults and policy. Models live only in tools.media.models. */
type MediaUnderstandingCapabilityConfig = Omit<MediaUnderstandingConfig, "models">;
type LinkModelConfig = {
/** Use a CLI command for link processing. */
type?: "cli";
/** CLI binary (required when type=cli). */
command: string;
/** CLI args (template-enabled). */
args?: string[];
/** Optional timeout override (seconds) for this model entry. */
timeoutSeconds?: number;
};
type LinkToolsConfig = {
/** Enable link understanding when models are configured. */
enabled?: boolean;
/** Optional scope gating for understanding. */
scope?: MediaUnderstandingScopeConfig;
/** Max number of links to process per message. */
maxLinks?: number;
/** Default timeout (seconds). */
timeoutSeconds?: number;
/** Ordered model list (fallbacks in order). */
models?: LinkModelConfig[];
};
type MediaToolsConfig = {
/** Canonical model list for image/audio/video, selected by capability tags. */
models?: MediaUnderstandingModelConfig[];
/** Max concurrent media understanding runs. */
concurrency?: number;
image?: MediaUnderstandingCapabilityConfig;
audio?: MediaUnderstandingCapabilityConfig;
video?: MediaUnderstandingCapabilityConfig;
};
type ToolProfileId = "minimal" | "coding" | "messaging" | "full";
type ToolLoopDetectionConfig = {
/** Enable tool-loop protection (default: false). */
enabled?: boolean;
};
type ToolSearchConfig = boolean | {
/** Enable compact search/call cataloging for large tool sets. */
enabled?: boolean;
/** Exposed model surface. "code" exposes tool_search_code; "tools" exposes structured fallback tools; "directory" keeps a bounded directory plus selected schemas visible while deferring the rest behind search/describe/call. */
mode?: "code" | "tools" | "directory";
/** Timeout in milliseconds for one tool_search_code execution. Runtime clamps to 1s..60s. */
codeTimeoutMs?: number;
/** Default search result count when the model omits a limit. Runtime clamps to maxSearchLimit. */
searchDefaultLimit?: number;
/** Maximum search result count. Runtime clamps to 1..50. */
maxSearchLimit?: number;
};
type CodeModeConfig = boolean | "auto" | {
/** OpenClaw Code Mode default, overridden by per-model codeMode. Default: false; "auto" engages catalog-preferred models. */
enabled?: boolean | "auto";
/** Guest runtime. Only quickjs-wasi is supported. */
runtime?: "quickjs-wasi";
/** Model-facing mode. Only "only" is supported: expose exec/wait and hide normal tools. */
mode?: "only";
/** Accepted source languages. */
languages?: Array<"javascript" | "typescript">;
/** Wall-clock limit in milliseconds for one exec or wait call. */
timeoutMs?: number;
/** QuickJS heap limit in bytes. */
memoryLimitBytes?: number;
/** Maximum serialized output bytes. */
maxOutputBytes?: number;
/** Maximum serialized snapshot bytes. */
maxSnapshotBytes?: number;
/** Maximum concurrent nested tool calls. */
maxPendingToolCalls?: number;
/** Retention for suspended snapshots. */
snapshotTtlSeconds?: number;
/** Default search result count for catalog.search. */
searchDefaultLimit?: number;
/** Maximum search result count for catalog.search. */
maxSearchLimit?: number;
};
type SwarmConfig = boolean | {
/** Enable collector-mode subagents and agents_wait. Default: true. */
enabled?: boolean;
/** Maximum concurrently running collector children per swarm group. */
maxConcurrent?: number;
/** Maximum live collector children per swarm group. */
maxChildrenPerGroup?: number;
/** Maximum lifetime collector spawns per swarm group. */
maxTotalPerGroup?: number;
/** Maximum agents_wait timeout in seconds. */
waitTimeoutSecondsMax?: number;
/** Default child agent id when sessions_spawn omits agentId. */
defaultAgentId?: string;
};
type SessionsToolsVisibility = "self" | "tree" | "agent" | "all";
type ToolAllowDenyPolicyConfig = {
/** Exact tool names allowed in this policy scope. */
allow?: string[];
/** Additional allowlist entries merged into the inherited policy. */
alsoAllow?: string[];
/** Exact tool names denied after allow expansion; deny wins. */
deny?: string[];
};
type ToolPolicyConfig = ToolAllowDenyPolicyConfig & {
/** Built-in profile used as the base policy before allow/deny merges. */
profile?: ToolProfileId;
};
type GroupToolPolicyConfig = ToolAllowDenyPolicyConfig;
/**
* Per-sender overrides.
*
* Prefer explicit key prefixes:
* - channel:<channelId>:<senderId>
* - id:<senderId>
* - e164:<phone>
* - username:<handle>
* - name:<display-name>
* - * (wildcard)
*
* Legacy unprefixed keys are supported for backward compatibility and are matched as senderId only.
*/
type GroupToolPolicyBySenderConfig = Record<string, GroupToolPolicyConfig>;
type ExecToolConfig = {
/** Exec host routing (default: auto). */
host?: "auto" | "sandbox" | "gateway" | "node";
/** Normalized exec policy mode. Prefer this over raw security/ask knobs. */
mode?: "deny" | "allowlist" | "ask" | "auto" | "full";
/** Legacy exec security mode retained when no canonical mode can preserve policy. */
security?: "deny" | "allowlist" | "full";
/** Legacy exec ask mode retained when no canonical mode can preserve policy. */
ask?: "off" | "on-miss" | "always";
/** Default node binding for exec.host=node (node id/name). */
node?: string;
/** Directories to prepend to PATH when running exec (gateway/sandbox). */
pathPrepend?: string[];
/** Safe stdin-only binaries that can run without allowlist entries. */
safeBins?: string[];
/**
* Require explicit approval for interpreter inline-eval forms (`python -c`, `node -e`, etc.).
* Prevents silent allowlist reuse and allow-always persistence for those forms.
*/
strictInlineEval?: boolean;
/** Render parser-derived command highlights in exec approval prompts (default: false). */
commandHighlighting?: boolean;
/**
* Default lifetime, in days, stamped onto standing grants minted by
* allow-always on automation approvals. Unset means grants live until
* revoked or the owning job changes. Terms freeze at mint; changing this
* affects only future grants.
*/
grantExpiryDays?: number;
/** Extra explicit directories trusted for safeBins path checks (never derived from PATH). */
safeBinTrustedDirs?: string[];
/** Optional custom safe-bin profiles for entries in tools.exec.safeBins. */
safeBinProfiles?: Record<string, SafeBinProfileFixture>;
/** Model-backed reviewer used by tools.exec.mode=auto before falling back to human approval. */
reviewer?: {
/** Optional reviewer model override (provider/model or agent model config). */
model?: AgentModelConfig;
/** Reviewer timeout in milliseconds (default: 30000). */
timeoutMs?: number;
};
/** Default time (ms) before an exec command auto-backgrounds. */
backgroundMs?: number;
/** Default timeout (seconds) before auto-killing exec commands. */
timeoutSeconds?: number;
/** Emit a running notice (ms) when approval-backed exec runs long (default: 10000, 0 = off). */
approvalRunningNoticeMs?: number;
/** How long to keep finished sessions in memory (ms). */
cleanupMs?: number;
/** Emit a system event and heartbeat when a backgrounded exec exits. */
notifyOnExit?: boolean;
/**
* Also emit success exit notifications when a backgrounded exec has no output.
* Default false to reduce context noise.
*/
notifyOnExitEmptySuccess?: boolean;
/** apply_patch subtool configuration. */
applyPatch?: {
/** Enable apply_patch for OpenAI models (default: true; set false to disable). */
enabled?: boolean;
/**
* Restrict apply_patch paths to the workspace directory.
* Default: true (safer; does not affect read/write/edit).
*/
workspaceOnly?: boolean;
/**
* Optional allowlist of model ids that can use apply_patch.
* Accepts either raw ids (e.g. "gpt-5.4") or full ids (e.g. "openai/gpt-5.4").
*/
allowModels?: string[];
};
};
type FsToolsConfig = {
/**
* Restrict filesystem tools (read/write/edit/apply_patch) to the agent workspace directory.
* Default: false (unrestricted, matches legacy behavior).
*/
workspaceOnly?: boolean;
};
type SessionsSpawnToolsConfig = {
attachments?: {
/** Enable inline attachments for sessions_spawn. */
enabled?: boolean;
maxTotalBytes?: number;
maxFiles?: number;
maxFileBytes?: number;
retainOnSessionKeep?: boolean;
};
};
type GitHubToolIdentityConfig = {
/** Opaque generated directory version for atomic credential rotation. */
profileId: string;
/** OAuth generations retain a separate rotating refresh credential. */
kind?: "oauth";
/** Optional process-local author identity for commits made by local tools. */
gitAuthor?: {
name?: string;
email?: string;
};
};
type AgentToolsConfig = {
/** Base tool profile applied before allow/deny lists. */
profile?: ToolProfileId;
allow?: string[];
/** Additional allowlist entries merged into allow and/or profile allowlist. */
alsoAllow?: string[];
deny?: string[];
/** Optional tool policy overrides keyed by provider id or "provider/model". */
byProvider?: Record<string, ToolPolicyConfig>;
/** Per-sender tool policy overrides keyed by sender identity. */
toolsBySender?: GroupToolPolicyBySenderConfig;
/** Per-agent code mode override; merges over the top-level tools.codeMode config. */
codeMode?: CodeModeConfig;
/** Per-agent swarm override; merges over the top-level tools.swarm config. */
swarm?: SwarmConfig;
/** Per-agent elevated exec gate (can only further restrict global tools.elevated). */
elevated?: {
/** Enable or disable elevated mode for this agent (default: true). */
enabled?: boolean;
/** Approved senders for /elevated (per-provider allowlists). */
allowFrom?: AgentElevatedAllowFromConfig;
};
/** Exec tool defaults for this agent. */
exec?: ExecToolConfig;
/** Complete per-agent GitHub CLI identity and Git author override. */
github?: GitHubToolIdentityConfig;
/** Filesystem tool path guards. */
fs?: FsToolsConfig;
/** Runtime loop detection for repetitive/ stuck tool-call patterns. */
loopDetection?: ToolLoopDetectionConfig;
/** Message tool configuration for this agent. */
message?: MessageToolsConfig;
sandbox?: {
tools?: ToolAllowDenyPolicyConfig;
};
};
type ToolsConfig = {
/** Base tool profile applied before allow/deny lists. */
profile?: ToolProfileId;
allow?: string[];
/** Additional allowlist entries merged into allow and/or profile allowlist. */
alsoAllow?: string[];
deny?: string[];
/** Optional tool policy overrides keyed by provider id or "provider/model". */
byProvider?: Record<string, ToolPolicyConfig>;
/** Managed local GitHub CLI identity and Git author; never overrides Git transport. */
github?: GitHubToolIdentityConfig;
/** Per-sender tool policy overrides keyed by sender identity. */
toolsBySender?: GroupToolPolicyBySenderConfig;
web?: {
search?: {
/** Enable managed web_search and optional Codex-native web search. */
enabled?: boolean;
/** Search provider id. */
provider?: string;
/** Default search results count (1-10). */
maxResults?: number;
/** Timeout in seconds for search requests. */
timeoutSeconds?: number;
/** Cache TTL in minutes for search results. */
cacheTtlMinutes?: number;
/** Optional native Codex web search for Codex-capable models. */
openaiCodex?: {
/** Enable native Codex web search for eligible models. */
enabled?: boolean;
/** Prefer cached or explicitly request live access. Unrestricted Codex turns resolve cached to live. */
mode?: "cached" | "live";
/** Native Codex search allowlist; also gates web_fetch on native-hosted-search turns. */
allowedDomains?: string[];
/** Optional Codex native search context size hint. */
contextSize?: "low" | "medium" | "high";
/** Optional approximate user location passed to the native Codex tool. */
userLocation?: {
country?: string;
region?: string;
city?: string;
timezone?: string;
};
};
};
fetch?: {
/** Enable web fetch tool (default: true). */
enabled?: boolean;
/** Web fetch fallback provider id. */
provider?: string;
/** Max characters to return from fetched content. */
maxChars?: number;
/** Hard cap for maxChars (tool or config), defaults to 20000. */
maxCharsCap?: number;
/** Max download size before truncation, defaults to 750000 bytes. */
maxResponseBytes?: number;
/** Timeout in seconds for fetch requests. */
timeoutSeconds?: number;
/** Cache TTL in minutes for fetched content. */
cacheTtlMinutes?: number;
/** Maximum number of redirects to follow (default: 3). */
maxRedirects?: number;
/** Override User-Agent header for fetch requests. */
userAgent?: string;
/**
* Extra request headers sent with direct web_fetch requests. Every value is
* treated as sensitive in exposed config. Entries a request cannot carry are
* dropped with a warning at request time.
*/
headers?: Record<string, string>;
/** Use Readability to extract main content (default: true). */
readability?: boolean;
/** Route web_fetch through a trusted HTTP(S) env proxy and let the proxy resolve DNS. Enable only when that proxy enforces outbound policy. */
useTrustedEnvProxy?: boolean;
/** SSRF policy configuration for web_fetch. */
ssrfPolicy?: SsrFPolicyConfig;
};
};
media?: MediaToolsConfig;
links?: LinkToolsConfig;
/** Message tool configuration. */
message?: MessageToolsConfig;
agentToAgent?: {
/** Default: true. False blocks ordinary cross-agent session tool access; requester-owned native subagent and ACP child sessions remain reachable under tree/all visibility. */
enabled?: boolean;
/**
* Agent ids or `*` glob patterns; the requesting and target agent must both match.
* Omitted or empty counts as unset: every agent pair is allowed by default; blank entries deny.
*/
allow?: string[];
};
/**
* Session tool visibility controls which sessions can be targeted by session tools
* (sessions_list, sessions_history, sessions_search, sessions_send, session_status).
*
* Default: "all" (all sessions on the Gateway, with cross-agent access scoped by agentToAgent).
*/
sessions?: {
/**
* - "self": only the current session
* - "tree": current session + sessions spawned by this session
* - "agent": any session belonging to the current agent id (can include other users)
* - "all": any session (default; cross-agent access is governed by tools.agentToAgent)
*/
visibility?: SessionsToolsVisibility;
};
/** Elevated exec permissions for the host machine. */
elevated?: {
/** Enable or disable elevated mode (default: true). */
enabled?: boolean;
/** Approved senders for /elevated (per-provider allowlists). */
allowFrom?: AgentElevatedAllowFromConfig;
};
/** Exec tool defaults. */
exec?: ExecToolConfig;
/** Filesystem tool path guards. */
fs?: FsToolsConfig;
/** Runtime loop detection for repetitive/ stuck tool-call patterns. */
loopDetection?: ToolLoopDetectionConfig;
/** Compact large OpenClaw, MCP, and client tool catalogs behind search/call tools. */
toolSearch?: ToolSearchConfig;
/** Global Code Mode defaults and limits; agent/model settings can override activation. */
codeMode?: CodeModeConfig;
/** Collector-mode subagents and wait controls. */
swarm?: SwarmConfig;
/** sessions_spawn tool configuration. */
sessions_spawn?: SessionsSpawnToolsConfig;
/** Sub-agent tool policy defaults (deny wins). */
subagents?: {
tools?: ToolAllowDenyPolicyConfig;
};
/** Sandbox tool policy defaults (deny wins). */
sandbox?: {
tools?: ToolAllowDenyPolicyConfig;
};
/** Unified progress_card status tool; enabled by default. Set false to opt out. */
updatePlan?: boolean;
};
type MessageToolsConfig = {
crossContext?: {
/** Allow sends to other channels within the same provider (default: true). */
allowWithinProvider?: boolean;
/** Allow sends across different providers (default: false). */
allowAcrossProviders?: boolean;
/** Cross-context marker configuration. */
marker?: {
/** Enable origin markers for cross-context sends (default: true). */
enabled?: boolean;
/** Text prefix template, supports {channel}. */
prefix?: string;
/** Text suffix template, supports {channel}. */
suffix?: string;
};
};
actions?: {
/** Message action names exposed and accepted by the message tool. */
allow?: string[];
};
broadcast?: {
/** Enable broadcast action (default: true). */
enabled?: boolean;
};
};
//#endregion
//#region src/config/types.tts.d.ts
type TtsProvider = string;
type TtsMode = "final" | "all";
type TtsAutoMode = "off" | "always" | "inbound" | "tagged";
type TtsModelOverrideConfig = {
/** Enable model-provided overrides for TTS. */
enabled?: boolean;
/** Allow model-provided TTS text blocks. */
allowText?: boolean;
/** Allow model-provided provider override (default: false). */
allowProvider?: boolean;
/** Allow model-provided voice/voiceId override. */
allowVoice?: boolean;
/** Allow model-provided modelId override. */
allowModelId?: boolean;
/** Allow model-provided voice settings override. */
allowVoiceSettings?: boolean;
/** Allow model-provided normalization or language overrides. */
allowNormalization?: boolean;
/** Allow model-provided seed override. */
allowSeed?: boolean;
};
type TtsProviderConfigMap = Record<string, Record<string, unknown>>;
type TtsPersonaFallbackPolicy = "preserve-persona" | "provider-defaults" | "fail";
type TtsPersonaConfig = {
label?: string;
description?: string;
/** Preferred provider for this persona. Explicit provider prefs still win. */
provider?: TtsProvider;
fallbackPolicy?: TtsPersonaFallbackPolicy;
/** Provider-specific persona bindings keyed by speech provider id. */
providers?: TtsProviderConfigMap;
};
type TtsConfig = {
/** Auto-TTS mode (preferred). */
auto?: TtsAutoMode;
/** @deprecated Use auto. */
enabled?: boolean;
/** Apply TTS to final replies only or to all replies (tool/block/final). */
mode?: TtsMode;
/** Primary TTS provider (fallbacks are automatic). */
provider?: TtsProvider;
/** Active TTS persona id. */
persona?: string;
/** Named TTS personas. */
personas?: Record<string, TtsPersonaConfig>;
/** Optional model override for TTS auto-summary (provider/model or alias). */
summaryModel?: string;
/** Allow the model to override TTS parameters. */
modelOverrides?: TtsModelOverrideConfig;
/** Provider-specific TTS settings keyed by speech provider id. */
providers?: TtsProviderConfigMap;
/** Optional path for local TTS user preferences JSON. */
/** Hard cap for text sent to TTS (chars). */
maxTextLength?: number;
/** API request timeout (ms). */
timeoutMs?: number;
};
//#endregion
//#region src/config/types.agents.d.ts
type AgentRuntimeAcpConfig = {
/** ACP harness adapter id (for example codex, claude). */
agent?: string;
/** Optional ACP backend override for this agent runtime. */
backend?: string;
/** Optional ACP session mode override. */
mode?: "persistent" | "oneshot";
/** Optional runtime working directory override. */
cwd?: string;
};
type AgentRuntimeConfig = {
type: "embedded";
} | {
type: "acp";
acp?: AgentRuntimeAcpConfig;
};
type AgentBindingMatch = {
channel: string;
/**
* Channel account to match.
* - Omitted/empty: matches only the channel default account.
* - "*": matches every account on the channel.
* - Any other string: matches that specific account id.
*/
accountId?: string;
peer?: {
kind: ChatType;
id: string;
};
guildId?: string;
teamId?: string;
/** Discord role IDs used for role-based routing. */
roles?: string[];
};
type AgentRouteBinding = {
/** Missing type is interpreted as route for backward compatibility. */
type?: "route";
agentId: string;
comment?: string;
match: AgentBindingMatch;
session?: {
/** Optional session scoping override for conversations matched by this binding. */
dmScope?: DmScope;
groupScope?: GroupScope;
};
};
type AgentAcpBinding = {
type: "acp";
agentId: string;
comment?: string;
match: AgentBindingMatch;
acp?: {
mode?: "persistent" | "oneshot";
label?: string;
cwd?: string;
backend?: string;
};
};
type AgentBinding = AgentRouteBinding | AgentAcpBinding;
type AgentConfig = {
id: string;
/** @deprecated Raw legacy list compatibility only; canonical agents.entries rejects this key. */
default?: boolean;
name?: string;
/** Optional human-authored agent description. */
description?: string;
workspace?: string;
/** Working directory for agent reply runs; overrides agents.defaults.cwd. */
cwd?: string;
agentDir?: string;
model?: AgentModelConfig;
/** Optional per-agent model for short internal tasks such as generated session titles. */
utilityModel?: string;
/**
* @deprecated Legacy raw config accepted only by doctor/migration repair.
* Normal schema parsing rejects this key; use per-model agentRuntime instead.
*/
agentRuntime?: AgentModelEntryConfig["agentRuntime"];
/** Per-model metadata overrides for this agent. */
models?: Record<string, AgentModelEntryConfig>;
/** Per-agent model override policy. Replaces the default policy when allow is present. */
modelPolicy?: AgentModelPolicyConfig;
/** @deprecated Legacy per-agent compaction config is kept for raw doctor migration/repair. */
compaction?: AgentDefaultsConfig["compaction"];
/** Optional per-agent default thinking level (overrides agents.defaults.thinkingDefault). */
thinkingDefault?: AgentDefaultsConfig["thinkingDefault"];
/** Optional per-agent default verbosity level. */
verboseDefault?: "off" | "on" | "full";
/** Optional per-agent tool progress detail mode. */
toolProgressDetail?: AgentDefaultsConfig["toolProgressDetail"];
/** Optional per-agent default reasoning visibility. */
reasoningDefault?: "on" | "off" | "stream";
/** Optional per-agent default for fast mode. */
fastModeDefault?: FastMode;
/** Optional per-agent bootstrap/context injection mode override. */
contextInjection?: AgentDefaultsConfig["contextInjection"];
/** Optional per-agent max chars for each injected bootstrap file. */
bootstrapMaxChars?: AgentDefaultsConfig["bootstrapMaxChars"];
/** Optional per-agent max total chars across injected bootstrap files. */
bootstrapTotalMaxChars?: AgentDefaultsConfig["bootstrapTotalMaxChars"];
/** Optional per-agent experimental flags. Omitted fields inherit agents.defaults.experimental. */
experimental?: AgentDefaultsConfig["experimental"];
/** Optional allowlist of skills for this agent; omitting it inherits agents.defaults.skills when set, and an explicit list replaces defaults instead of merging. */
skills?: string[];
/** Per-agent overrides for the shared top-level memory configuration. */
memory?: {
search?: MemorySearchConfig;
};
/** Human-like delay between block replies for this agent. */
humanDelay?: HumanDelayConfig;
/** Optional per-agent typing start policy. */
typingMode?: AgentDefaultsConfig["typingMode"];
/** Optional per-agent TTS overrides, deep-merged over top-level tts. */
/** Per-agent TTS overrides. prefsPath remains scoped because agents may use distinct preference stores. */
tts?: TtsConfig & {
prefsPath?: string;
};
/** Optional per-agent skills subsystem overrides. */
skillsLimits?: Pick<SkillsLimitsConfig, "maxSkillsPromptChars">;
/** Optional per-agent overrides for selected context/token-heavy limits. */
contextLimits?: AgentContextLimitsConfig;
/** Optional per-agent heartbeat overrides. */
heartbeat?: Omit<NonNullable<AgentDefaultsConfig["heartbeat"]>, "agentId">;
identity?: IdentityConfig;
groupChat?: Omit<GroupChatConfig, "visibleReplies">;
subagents?: {
/** Prompt-only guidance for how strongly this agent should delegate work. */
delegationMode?: SubagentDelegationMode;
/** Allow spawning sub-agents under other agent ids. Use "*" to allow any configured target. */
allowAgents?: string[];
/** Per-agent default model for spawned sub-agents (string or {primary,fallbacks}). */
model?: AgentModelConfig;
/** Per-agent default thinking level for spawned sub-agents. */
thinking?: string;
/** Require explicit agentId in sessions_spawn (no default same-as-caller). */
requireAgentId?: boolean;
};
/** Optional per-agent embedded OpenClaw overrides. */
embeddedAgent?: {
/** Optional per-agent execution contract override. */
executionContract?: EmbeddedAgentExecutionContract;
};
/** Optional per-agent sandbox overrides. */
sandbox?: AgentSandboxConfig;
/** Optional per-agent stream params (e.g. cacheRetention, temperature). */
params?: Record<string, unknown>;
tools?: AgentToolsConfig;
/** Optional runtime descriptor for this agent. */
runtime?: AgentRuntimeConfig;
};
type AgentEntryConfig = Omit<AgentConfig, "id">;
type AgentsConfig = {
ownership?: "explicit";
defaults?: AgentDefaultsConfig;
entries?: Record<string, AgentEntryConfig>;
/** Internal non-serialized projection materialized by validation for ID-based runtime code. */
list?: AgentConfig[];
};
//#endregion
//#region src/config/types.approvals.d.ts
type NativeExecApprovalEnableMode = boolean | "auto";
type ExecApprovalForwardingMode = "session" | "targets" | "both";
type ExecApprovalForwardTarget = {
/** Channel id (e.g. "discord", "slack", or plugin channel id). */
channel: string;
/** Destination id (channel id, user id, etc. depending on channel). */
to: string;
/** Optional account id for multi-account channels. */
accountId?: string;
/** Optional thread id to reply inside a thread. */
threadId?: string | number;
};
type ExecApprovalForwardingConfig = {
/** Enable forwarding exec approvals to chat channels. Default: false. */
enabled?: boolean;
/** Delivery mode (session=origin chat, targets=config targets, both=both). Default: session. */
mode?: ExecApprovalForwardingMode;
/** Only forward approvals for these agent IDs. Omit = all agents. */
agentFilter?: string[];
/** Only forward approvals matching these session key patterns (substring or regex). */
sessionFilter?: string[];
/** Explicit delivery targets (used when mode includes targets). */
targets?: ExecApprovalForwardTarget[];
};
type ApprovalsConfig = {
exec?: ExecApprovalForwardingConfig;
plugin?: ExecApprovalForwardingConfig;
};
//#endregion
//#region src/config/types.auth.d.ts
type AuthProfileConfig = {
/** Provider id this auth profile can satisfy. */
provider: string;
/**
* Auth route selected by this profile id.
* - api_key: static provider API key
* - oauth: refreshable OAuth credentials (access+refresh+expires)
* - token: static bearer-style token (optionally expiring; no refresh)
* - aws-sdk: AWS SDK default credential chain (no secret in auth-profiles.json)
*/
mode: "api_key" | "aws-sdk" | "oauth" | "token";
/** Optional account email shown in profile selection/status surfaces. */
email?: string;
/** Optional human-readable label shown in profile selection/status surfaces. */
displayName?: string;
};
type AuthConfig = {
/** Named auth profiles keyed by profile id. */
profiles?: Record<string, AuthProfileConfig>;
/** Preferred profile order per provider id. */
order?: Record<string, string[]>;
};
//#endregion
//#region src/config/types.browser.d.ts
type BrowserProfileConfig = {
/** @deprecated Doctor-only legacy input; canonical schema rejects this field. */
color?: string;
/** CDP port for this profile. Allocated once at creation, persisted permanently. */
cdpPort?: number;
/** CDP/DevTools endpoint URL for this profile (remote CDP or existing-session endpoint attach). */
cdpUrl?: string;
/** Explicit user data directory for existing-session Chrome MCP attachment. */
userDataDir?: string;
/** Override the Chrome MCP command for existing-session profiles. */
mcpCommand?: string;
/** Extra Chrome MCP arguments for existing-session profiles. */
mcpArgs?: string[];
/**
* Profile driver (default: openclaw). "extension" attaches to the user's
* signed-in browser through the OpenClaw Chrome extension relay.
*/
driver?: "openclaw" | "clawd" | "existing-session" | "extension";
/** If true, launch this profile in headless mode. Falls back to browser.headless. */
headless?: boolean;
/** Browser executable path for this profile. Falls back to browser.executablePath. */
executablePath?: string;
/** If true, never launch a browser for this profile; only attach. Falls back to browser.attachOnly. */
attachOnly?: boolean;
};
type BrowserSnapshotDefaults = {
/** Default snapshot mode (applies when mode is not provided). */
mode?: "efficient";
};
type BrowserTabCleanupConfig = {
/** Enable best-effort cleanup for tracked primary-agent browser tabs. Default: true */
enabled?: boolean;
};
type BrowserExtensionRelayConfig = {
/** Temporarily accept legacy relay bearer/basic/subprotocol auth. Default: true. */
allowLegacyAuth?: boolean;
};
type BrowserSsrFPolicyConfig = SsrFPolicyConfig;
type BrowserConfig = {
/** @deprecated Doctor-only legacy input; canonical schema rejects this field. */
color?: string;
enabled?: boolean;
/** Allow importing cookies from the user's real Chrome-family profile into a managed profile (macOS). Default: true. */
allowSystemProfileImport?: boolean;
/** If false, disable browser act:evaluate (arbitrary JS). Default: true */
evaluateEnabled?: boolean;
/** Base URL of the CDP endpoint (for remote browsers). Default: loopback CDP on the derived port. */
cdpUrl?: string;
/** Override the browser executable path (all platforms). */
executablePath?: string;
/** Start Chrome headless (best-effort). Default: false */
headless?: boolean;
/** Pass --no-sandbox to Chrome (Linux containers). Default: false */
noSandbox?: boolean;
/** If true: never launch; only attach to an existing browser. Default: false */
attachOnly?: boolean;
/** Default profile to use when profile param is omitted. Default: "openclaw" */
defaultProfile?: string;
/** Named browser profiles with explicit CDP ports or URLs. */
profiles?: Record<string, BrowserProfileConfig>;
/** Default snapshot options (applied by the browser tool/CLI when unset). */
snapshotDefaults?: BrowserSnapshotDefaults;
/** Best-effort cleanup policy for tabs opened by primary-agent browser sessions. */
tabCleanup?: BrowserTabCleanupConfig;
/** Chrome extension relay authentication compatibility settings. */
extensionRelay?: BrowserExtensionRelayConfig;
/** SSRF policy for browser navigation/open-tab operations. */
ssrfPolicy?: BrowserSsrFPolicyConfig;
/**
* Additional Chrome launch arguments.
* Useful for stealth flags, window size overrides, or custom user-agent strings.
* Example: ["--window-size=1920,1080", "--disable-infobars"]
*/
extraArgs?: string[];
};
//#endregion
//#region src/config/types.bot-loop-protection.d.ts
type ChannelBotLoopProtectionConfig = {
/** Enable pair loop protection for channels that support it. */
enabled?: boolean;
/** Maximum events a sender/receiver pair may exchange within the window. */
maxEventsPerWindow?: number;
/** Sliding window length in seconds. */
windowSeconds?: number;
/** Cooldown seconds applied to a pair after the limit is hit. */
cooldownSeconds?: number;
};
//#endregion
//#region src/config/types.channel-health.d.ts
type ChannelHeartbeatVisibilityConfig = {
/** Show HEARTBEAT_OK acknowledgments in chat (default: false). */
showOk?: boolean;
/** Show heartbeat alerts with actual content (default: true). */
showAlerts?: boolean;
/** Emit indicator events for UI status display (default: true). */
useIndicator?: boolean;
};
type ChannelHealthMonitorConfig = {
/**
* Enable channel-health-monitor restarts for this channel or account.
* Inherits the global gateway setting when omitted.
*/
enabled?: boolean;
};
//#endregion
//#region src/config/types.channel-messaging-common.d.ts
type CommonChannelMessagingConfig<TCapabilities = string[], TAllowFromEntry = string | number, TDefaultTo = string, TStreaming = ChannelDeliveryStreamingConfig> = {
/** Optional display name for this account (used in CLI/UI lists). */
name?: string;
/** Optional provider capability tags used for agent/runtime guidance. */
capabilities?: TCapabilities;
/** Markdown formatting overrides (tables). */
markdown?: MarkdownConfig;
/** Allow channel-initiated config writes (default: true). */
configWrites?: boolean;
/** If false, do not start this account. Default: true. */
enabled?: boolean;
/** Direct message access policy (default: pairing). */
dmPolicy?: DmPolicy;
/** Optional allowlist for inbound DM senders. */
allowFrom?: TAllowFromEntry[];
/** Default delivery target for CLI --deliver when no explicit --reply-to is provided. */
defaultTo?: TDefaultTo;
/** Optional allowlist for group/channel senders. */
groupAllowFrom?: TAllowFromEntry[];
/** Group/channel message handling policy. */
groupPolicy?: GroupPolicy;
/** Scope configured mention patterns to selected conversations. */
mentionPatterns?: MentionPatternsPolicyConfig;
/**
* Supplemental context visibility policy for fetched/group context.
* - "all": include all quoted/thread/history context
* - "allowlist": only include context from allowlisted senders
* - "allowlist_quote": same as allowlist, but keep explicit quote/reply context
*/
contextVisibility?: ContextVisibilityMode;
/** Max group/channel messages to keep as history context (0 disables). */
historyLimit?: number;
/** Max DM turns to keep as history context. */
dmHistoryLimit?: number;
/** Per-DM config overrides keyed by sender ID. */
dms?: Record<string, DmConfig>;
/** Outbound text chunk size (chars). */
textChunkLimit?: number;
/** Delivery streaming config: chunk mode plus block streaming controls. */
streaming?: TStreaming;
/** Heartbeat visibility settings for this channel. */
heartbeatVisibility?: ChannelHeartbeatVisibilityConfig;
/** @deprecated Doctor-only legacy input. */
heartbeat?: ChannelHeartbeatVisibilityConfig;
/** Channel health monitor overrides for this channel/account. */
healthMonitor?: ChannelHealthMonitorConfig;
/** Outbound response prefix override for this channel/account. */
responsePrefix?: string;
/** Max outbound media size in MB. */
mediaMaxMb?: number;
/** Native reply-threading mode for automatic replies. */
replyToMode?: ReplyToMode;
};
type ChannelExecApprovalTarget = "dm" | "channel" | "both";
type ChannelExecApprovalConfig<TApprover = string | number> = {
enabled?: NativeExecApprovalEnableMode;
approvers?: TApprover[];
agentFilter?: string[];
sessionFilter?: string[];
target?: ChannelExecApprovalTarget;
};
type ChannelBotInteractionConfig<TAllowBots = boolean | "mentions"> = {
allowBots?: TAllowBots;
botLoopProtection?: ChannelBotLoopProtectionConfig;
dangerouslyAllowNameMatching?: boolean;
};
type ChannelReadReceiptConfig = {
sendReadReceipts?: boolean;
};
type ChannelReactionConfig<TNotification = never, TLevel = never, TAckReaction = never, TAllowlist extends boolean = false> = {
reactionNotifications?: TNotification;
reactionLevel?: TLevel;
ackReaction?: TAckReaction;
} & (TAllowlist extends true ? {
reactionAllowlist?: Array<string | number>;
} : Record<never, never>);
//#endregion
//#region src/config/types.discord-presence.d.ts
type DiscordPresenceEventsConfig = {
/** Enable online-presence system events for this guild. Default: true when configured. */
enabled?: boolean;
/** Discord channel ID that receives the routed agent wake. */
channelId: string;
/** Optional immutable Discord user ID allowlist. Omit to include all human members. */
users?: string[];
/**
* Suppress presence-derived online events for this many seconds after a new Gateway
* session while guild presence state is rebuilt. 0 disables. Default: 300.
*/
reconnectSuppressSeconds?: number;
/** Maximum queued online events for this guild per burst window. Default: 8. */
burstLimit?: number;
/** Sliding burst-detection window in seconds. Default: 60. */
burstWindowSeconds?: number;
};
//#endregion
//#region src/config/types.discord.d.ts
type DiscordChannelStreamingConfig = Omit<ChannelPreviewStreamingConfig, "progress"> & {
progress?: ChannelStreamingProgressConfig;
};
type DiscordPluralKitConfig = {
enabled?: boolean;
token?: string;
};
type DiscordMentionAliasesConfig = Record<string, string>;
type DiscordDmConfig = {
/** If false, ignore all incoming Discord DMs. Default: true. */
enabled?: boolean;
/** If true, allow group DMs (default: false). */
groupEnabled?: boolean;
/** Optional allowlist for group DM channels (ids or slugs). */
groupChannels?: string[];
};
type DiscordGuildChannelConfig = {
requireMention?: boolean;
/**
* If true, drop messages addressed to another identity by mention or bot reply, but not this
* bot (not @everyone/@here).
* Default: false.
*/
ignoreOtherMentions?: boolean;
/** Optional tool policy overrides for this channel. */
tools?: GroupToolPolicyConfig;
toolsBySender?: GroupToolPolicyBySenderConfig;
/** If specified, only load these skills for this channel. Omit = all skills; empty = no skills. */
skills?: string[];
/** If false, disable the bot for this channel. */
enabled?: boolean;
/** Optional allowlist for channel senders (ids or names). */
users?: string[];
/** Optional allowlist for channel senders by role ID. */
roles?: string[];
/** Optional system prompt snippet for this channel. */
systemPrompt?: string;
/** If false, omit thread starter context for this channel (default: true). */
includeThreadStarter?: boolean;
/** If true, automatically create a thread for each new message in this channel. */
autoThread?: boolean;
/** Archive duration (minutes) for auto-created threads. Valid values: 60, 1440, 4320, 10080. */
autoArchiveDuration?: "60" | "1440" | "4320" | "10080" | 60 | 1440 | 4320 | 10080;
/** Naming strategy for auto-created threads. "message" uses message text; "generated" renames with an LLM title. */
autoThreadName?: "message" | "generated";
};
type DiscordReactionNotificationMode = "off" | "own" | "all" | "allowlist";
type DiscordGuildEntry = {
slug?: string;
requireMention?: boolean;
/**
* If true, drop messages addressed to another identity by mention or bot reply, but not this
* bot (not @everyone/@here).
* Default: false.
*/
ignoreOtherMentions?: boolean;
/** Optional tool policy overrides for this guild (used when channel override is missing). */
tools?: GroupToolPolicyConfig;
toolsBySender?: GroupToolPolicyBySenderConfig;
/** Reaction notification mode (off|own|all|allowlist). Default: own. */
reactionNotifications?: DiscordReactionNotificationMode;
/** Optional allowlist for guild senders (ids or names). */
users?: string[];
/** Optional allowlist for guild senders by role ID. */
roles?: string[];
presenceEvents?: DiscordPresenceEventsConfig;
channels?: Record<string, DiscordGuildChannelConfig>;
};
type DiscordActionConfig = {
reactions?: boolean;
stickers?: boolean;
polls?: boolean;
permissions?: boolean;
messages?: boolean;
threads?: boolean;
pins?: boolean;
search?: boolean;
memberInfo?: boolean;
roleInfo?: boolean;
roles?: boolean;
channelInfo?: boolean;
voiceStatus?: boolean;
events?: boolean;
moderation?: boolean;
emojiUploads?: boolean;
stickerUploads?: boolean;
channels?: boolean;
/** Enable bot presence/activity changes (default: false). */
presence?: boolean;
};
type DiscordIntentsConfig = {
/**
* Request the privileged Message Content intent. Disable only for mention-only guild operation;
* Discord still includes content in DMs and messages that explicitly mention the bot. Default: true.
*/
messageContent?: boolean;
/** Enable Guild Presences privileged intent (requires Portal opt-in). Default: false. */
presence?: boolean;
/** Enable Guild Members privileged intent (requires Portal opt-in). Default: false. */
guildMembers?: boolean;
/** Enable Guild Voice States intent. Defaults to voice.enabled, unless explicitly set. */
voiceStates?: boolean;
};
type DiscordVoiceAutoJoinConfig = {
/** Guild ID that owns the voice channel. */
guildId: string;
/** Voice channel ID to join. */
channelId: string;
/** Join and remain connected only while at least one human is in the channel. Default: false. */
whenOccupied?: boolean;
};
type DiscordVoiceAllowedChannelConfig = {
/** Guild ID that owns the voice channel. */
guildId: string;
/** Voice channel ID allowed for realtime voice sessions. */
channelId: string;
};
type DiscordVoiceMode = "stt-tts" | "agent-proxy" | "bidi";
type DiscordVoiceRealtimeConsultPolicy = "auto" | "always";
type DiscordVoiceRealtimeToolPolicy = "safe-read-only" | "owner" | "none";
type DiscordVoiceRealtimeBootstrapContextFile = "IDENTITY.md" | "USER.md" | "SOUL.md";
type DiscordVoiceRealtimeConfig = {
/** Realtime voice provider id, for example "openai". */
provider?: string;
/** Provider realtime session model, for example "gpt-realtime-2.1". */
model?: string;
/** Provider realtime output voice name, for example "cedar". */
speakerVoice?: string;
/** Provider realtime output voice id. */
speakerVoiceId?: string;
/** System instructions passed to the realtime provider. */
instructions?: string;
/** Tool policy for bidi realtime consult calls. */
toolPolicy?: DiscordVoiceRealtimeToolPolicy;
/** Whether bidi should force the OpenClaw agent brain for every substantive turn. */
consultPolicy?: DiscordVoiceRealtimeConsultPolicy;
/** OpenAI agent-proxy wake-name policy. Unset adapts to the room: off for one human, on for two or more. True always requires; false never requires. */
requireWakeName?: boolean;
/** Wake names that allow OpenAI agent-proxy realtime Discord voice to respond when the gate is active. Defaults to the routed agent name plus OpenClaw, or the agent id plus OpenClaw. */
wakeNames?: string[];
/** Agent profile bootstrap files to include in realtime provider instructions. Defaults to IDENTITY.md, USER.md, and SOUL.md; set [] to disable. */
bootstrapContextFiles?: DiscordVoiceRealtimeBootstrapContextFile[];
/** Allow Discord speaker-start events to interrupt active realtime playback. */
bargeIn?: boolean;
/** Minimum assistant playback duration before a barge-in truncates audio. Default: 250ms; set 0 for immediate interruption. */
minBargeInAudioEndMs?: number;
/** Debounce window before buffered transcripts are sent to the OpenClaw agent. */
debounceMs?: number;
/** Provider-specific realtime voice config keyed by provider id. */
providers?: Record<string, Record<string, unknown> | undefined>;
};
type DiscordVoiceAgentSessionConfig = {
/** Which OpenClaw conversation should receive voice turns. Default: "voice". */
mode?: "voice" | "target";
/** Discord target used when mode is "target", for example "channel:123". */
target?: string;
};
type DiscordVoiceConfig = {
/** Enable Discord voice channel conversations (default: true). */
enabled?: boolean;
/** Voice conversation mode. Default: agent-proxy. */
mode?: DiscordVoiceMode;
/** Route voice turns through an existing OpenClaw Discord conversation. */
agentSession?: DiscordVoiceAgentSessionConfig;
/** Optional LLM model override for Discord voice channel responses. */
model?: string;
/** Realtime provider settings for agent-proxy or bidi modes. */
realtime?: DiscordVoiceRealtimeConfig;
/** Voice channels to join automatically, optionally only while occupied. */
autoJoin?: DiscordVoiceAutoJoinConfig[];
/** If false, configured followUsers are ignored without removing the saved user list. */
followUsersEnabled?: boolean;
/** Discord user IDs whose current voice channel the bot should follow. */
followUsers?: string[];
/** Voice channels the bot is allowed to join or remain in. Unset means any voice channel is allowed. */
allowedChannels?: DiscordVoiceAllowedChannelConfig[];
/** Enable/disable DAVE end-to-end encryption (default: true; Discord may require this). */
daveEncryption?: boolean;
/** Consecutive decrypt failures before DAVE session reinitialization (default: 24). */
decryptionFailureTolerance?: number;
/** Initial @discordjs/voice Ready wait in milliseconds (default: 30000). */
connectTimeoutMs?: number;
/** Grace period for Discord voice reconnect signalling after a disconnect (default: 15000). */
reconnectGraceMs?: number;
/** Silence grace after Discord reports a speaker ended before finalizing STT capture (default: 2000). */
captureSilenceGraceMs?: number;
/** Optional TTS overrides for Discord voice output. */
tts?: TtsConfig;
};
type DiscordExecApprovalConfig = ChannelExecApprovalConfig<string> & {
/** Delete approval DMs after approval, denial, or timeout. Default: false. */
cleanupAfterResolve?: boolean;
};
type DiscordAgentComponentsConfig = {
/** Enable agent-controlled interactive components (buttons, select menus). Default: true. */
enabled?: boolean;
/** Time in milliseconds before sent Discord component callbacks expire. Default: 1800000. */
ttlMs?: number;
};
type DiscordThreadBindingsConfig = {
/** Enable Discord thread binding features. Overrides session.threadBindings.enabled. */
enabled?: boolean;
/** Inactivity window in hours. Set 0 to disable. Default: 24. */
idleHours?: number;
/** Hard max age in hours. Set 0 to disable. Default: 0. */
maxAgeHours?: number;
/** Allow session spawns to create and bind Discord threads. Default: true. */
spawnSessions?: boolean;
/** Default context mode for native subagents. Default: fork. */
defaultSpawnContext?: "isolated" | "fork";
};
type DiscordSlashCommandConfig = {
/** Reply ephemerally (default: true). */
ephemeral?: boolean;
};
type DiscordThreadConfig = {
/** If true, Discord thread sessions inherit the parent channel transcript. Default: false. */
inheritParent?: boolean;
};
type DiscordAutoPresenceConfig = {
/** Enable automatic runtime/quota-based Discord presence updates. Default: false. */
enabled?: boolean;
/** Poll interval for evaluating runtime availability state (ms). Default: 30000. */
intervalMs?: number;
/** Minimum spacing between actual gateway presence updates (ms). Default: 15000. */
minUpdateIntervalMs?: number;
/** Optional custom status text while runtime is healthy; supports plain text. */
/** Optional custom status text while runtime/quota state is degraded or unknown. */
/** Optional custom status text while runtime detects quota/token exhaustion. */
/** @deprecated Doctor-only legacy input. */
exhaustedText?: string;
};
type DiscordAccountConfig = Omit<CommonChannelMessagingConfig<string[], string, string, DiscordChannelStreamingConfig>, "groupAllowFrom"> & ChannelBotInteractionConfig & ChannelReactionConfig<never, never, string> & {
/** Post a room-specific introduction when joining a group. Default: true. */
joinIntro?: boolean;
/** Override native command registration for Discord (bool or "auto"). */
commands?: ProviderCommandsConfig;
token?: SecretInput;
/** Optional Discord application/client ID. Set this when REST application lookup is blocked. */
applicationId?: string;
activities?: {
clientSecret?: string;
applicationId?: string;
};
/** HTTP(S) proxy URL for Discord gateway WebSocket connections. */
proxy?: string;
/**
* Deterministic outbound @handle rewrites for known Discord users.
* Keys are handles without the leading @; values are Discord user IDs.
*/
mentionAliases?: DiscordMentionAliasesConfig;
/**
* Suppress Discord-generated link embeds for outbound messages. Default: true.
* Explicit `embeds` payloads are still sent normally.
*/
suppressEmbeds?: boolean;
/**
* Soft max line count per Discord message.
* Discord clients can clip/collapse very tall messages; splitting by lines
* keeps replies readable in-channel. Default: 17.
*/
maxLinesPerMessage?: number;
/** Per-action tool gating (default: true for all). */
actions?: DiscordActionConfig;
/** Thread session behavior. */
thread?: DiscordThreadConfig;
dm?: DiscordDmConfig;
/** New per-guild config keyed by guild id or slug. */
guilds?: Record<string, DiscordGuildEntry>;
/** Exec approval forwarding configuration. */
execApprovals?: DiscordExecApprovalConfig;
/** Agent-controlled interactive components (buttons, select menus). */
agentComponents?: DiscordAgentComponentsConfig;
/** Discord UI customization (components, modals, etc.). */
/** Slash command configuration. */
slashCommand?: DiscordSlashCommandConfig;
/** Thread binding lifecycle settings. */
threadBindings?: DiscordThreadBindingsConfig;
/** Privileged Gateway Intents (must also be enabled in Discord Developer Portal). */
intents?: DiscordIntentsConfig;
/** Voice channel conversation settings. */
voice?: DiscordVoiceConfig;
/** PluralKit identity resolution for proxied messages. */
pluralkit?: DiscordPluralKitConfig;
/** When to send ack reactions for this Discord account. Overrides messages.ackReactionScope. */
ackReactionScope?: "group-mentions" | "group-all" | "direct" | "all" | "off" | "none";
/** Bot activity status text (e.g. "Watching X"). */
activity?: string;
/** Bot status (online|dnd|idle|invisible). Defaults to online when presence is configured. */
status?: "online" | "dnd" | "idle" | "invisible";
/** Automatic runtime/quota presence signaling (status text + status mapping). */
autoPresence?: DiscordAutoPresenceConfig;
/** Activity type (0=Game, 1=Streaming, 2=Listening, 3=Watching, 4=Custom, 5=Competing). Defaults to 4 (Custom) when activity is set. */
activityType?: 0 | 1 | 2 | 3 | 4 | 5;
/** Streaming URL (Twitch/YouTube). Required when activityType=1. */
activityUrl?: string;
/**
* Legacy compatibility block. Discord no longer enforces channel-owned
* timeouts for queued inbound agent runs.
*/
inboundWorker?: {
/**
* Ignored. Queued Discord agent runs are governed by the session/tool/runtime
* lifecycle, not by Discord channel config.
*/
runTimeoutMs?: number;
};
};
type DiscordConfig = {
/** Optional per-account Discord configuration (multi-account). */
accounts?: Record<string, DiscordAccountConfig>;
/** Optional default account id when multiple accounts are configured. */
defaultAccount?: string;
} & DiscordAccountConfig;
//#endregion
//#region src/config/types.googlechat.d.ts
type GoogleChatDmConfig = {
/** If false, ignore all incoming Google Chat DMs. Default: true. */
enabled?: boolean;
};
type GoogleChatGroupConfig = {
/** If false, disable the bot in this space. */
enabled?: boolean;
/** Require mentioning the bot to trigger replies. */
requireMention?: boolean;
/** Sliding-window bot-pair loop guard for accepted bot-authored Google Chat messages. */
botLoopProtection?: ChannelBotLoopProtectionConfig;
/** Allowlist of users that can invoke the bot in this space. */
users?: Array<string | number>;
/** Optional system prompt for this space. */
systemPrompt?: string;
};
type GoogleChatAccountConfig = Omit<CommonChannelMessagingConfig, "mentionPatterns"> & ChannelBotInteractionConfig<boolean> & {
/** Default mention requirement for space messages (default: true). */
requireMention?: boolean;
/** Per-space configuration keyed by space id or name. */
groups?: Record<string, GoogleChatGroupConfig>;
/** Service account JSON (inline string, object, or secret reference). */
serviceAccount?: string | Record<string, unknown> | SecretRef;
/** Service account JSON file path. */
serviceAccountFile?: string;
/** Webhook audience type (app-url or project-number). */
audienceType?: "app-url" | "project-number";
/** Audience value (app URL or project number). */
audience?: string;
/** Exact add-on principal to accept when app-url delivery uses add-on tokens. */
appPrincipal?: string;
/** Google Chat webhook path (default: /googlechat). */
webhookPath?: string;
/** Google Chat webhook URL (used to derive the path). */
webhookUrl?: string;
/** Optional bot user resource name (users/...). */
botUser?: string;
/** If false, ignore all incoming Google Chat DMs. Default: true. */
dm?: GoogleChatDmConfig;
/**
* Typing indicator mode (default: "message").
* - "none": No indicator
* - "message": Send "_<name> is typing..._" then edit with response
* - "reaction": React with š to user message, remove on reply
* NOTE: Reaction mode requires user OAuth (not supported with service account auth).
* If configured, falls back to message mode with a warning.
*/
typingIndicator?: "none" | "message" | "reaction";
};
type GoogleChatConfig = {
/** Optional per-account Google Chat configuration (multi-account). */
accounts?: Record<string, GoogleChatAccountConfig>;
/** Optional default account id when multiple accounts are configured. */
defaultAccount?: string;
} & GoogleChatAccountConfig;
//#endregion
//#region src/config/types.imessage.d.ts
/** Private-API and helper actions the iMessage runtime may expose to agents. */
type IMessageActionConfig = {
reactions?: boolean;
edit?: boolean;
unsend?: boolean;
reply?: boolean;
sendWithEffect?: boolean;
renameGroup?: boolean;
setGroupIcon?: boolean;
addParticipant?: boolean;
removeParticipant?: boolean;
leaveGroup?: boolean;
sendAttachment?: boolean;
polls?: boolean;
};
/** Inbound tapback notification policy. */
type IMessageReactionNotificationMode = "off" | "own" | "all";
type IMessageSendTransport = "auto" | "bridge" | "applescript";
/** Per-account iMessage runtime/config shape. */
type IMessageAccountConfig = Omit<CommonChannelMessagingConfig, "mentionPatterns" | "replyToMode"> & ChannelReadReceiptConfig & ChannelReactionConfig<IMessageReactionNotificationMode> & {
/** imsg CLI binary path (default: imsg). */
cliPath?: string;
/** Optional Messages db path override. */
dbPath?: string;
/** Remote SSH host token for SCP attachment fetches (`host` or `user@host`). */
remoteHost?: string;
/** Enable or disable private API message actions. */
actions?: IMessageActionConfig;
/** Optional default send service (imessage|sms|auto). */
service?: "imessage" | "sms" | "auto";
/** Preferred imsg RPC send transport. Default: auto. */
sendTransport?: IMessageSendTransport;
/** Optional default region (used when sending SMS). */
region?: string;
/** Include attachments + reactions in watch payloads. */
includeAttachments?: boolean;
/** Allowed local iMessage attachment roots (supports single-segment `*` wildcards). */
attachmentRoots?: string[];
/** Allowed remote iMessage attachment roots for SCP fetches (supports `*`). */
remoteAttachmentRoots?: string[];
/** Timeout for probe/RPC operations in milliseconds (default: 10000). */
probeTimeoutMs?: number;
/**
* Merge consecutive same-sender DM rows from `chat.db` into a single agent
* turn, so Apple's split-send (`<command> <URL>` arriving as two separate
* rows several seconds apart) lands as one merged message. DM-only ā group chats
* keep instant per-message dispatch. Widens the default inbound debounce
* window to 7000 ms when enabled without an explicit
* `messages.inbound.byChannel.imessage` or global
* `messages.inbound.debounceMs`. Default: `false`.
*/
groups?: Record<string, {
requireMention?: boolean;
tools?: GroupToolPolicyConfig;
toolsBySender?: GroupToolPolicyBySenderConfig;
/**
* Per-group system prompt. Injected into the agent's system prompt on
* every turn that handles a message in that group. Matches the shape
* already supported by Discord, Telegram, IRC, Slack, GoogleChat, and
* other group-capable channels. The wildcard `groups["*"]` entry is
* also honored.
*/
systemPrompt?: string;
}>;
/**
* Catchup: replay inbound messages that arrived in `chat.db` while the
* gateway was offline (crash, restart, mac sleep). Disabled by default.
* See https://github.com/openclaw/openclaw/issues/78649.
*/
catchup?: {
/** Master switch. Default `false`. */
enabled?: boolean;
/**
* Maximum age of replayable messages in minutes. Messages older than
* `now - maxAgeMinutes` are skipped even when the cursor is older.
* Defense against runaway replay (the inverse of #62761). Default
* `120` (2 h). Clamp `[1, 720]`.
*/
maxAgeMinutes?: number;
/**
* Maximum messages to replay per catchup pass. Default `50`. Clamp
* `[1, 500]`.
*/
perRunLimit?: number;
/**
* On first run when no cursor exists, look back this many minutes.
* Default `30`.
*/
firstRunLookbackMinutes?: number;
/**
* Per-message retry ceiling. After this many consecutive failed
* dispatch attempts against the same message guid, catchup logs a
* `warn` and force-advances the cursor past the wedged message.
* Default `10`. Clamp `[1, 1000]`.
*/
maxFailureRetries?: number;
};
};
/** Top-level iMessage config, with optional account map layered over default account fields. */
type IMessageConfig = {
/** Optional per-account iMessage configuration (multi-account). */
accounts?: Record<string, IMessageAccountConfig>;
/** Optional default account id when multiple accounts are configured. */
defaultAccount?: string;
} & IMessageAccountConfig;
//#endregion
//#region src/config/types.implicit-mentions.d.ts
type ChannelImplicitMentionsConfig = {
/** Treat replies to the bot's own message as implicit mentions. */
replyToBot?: boolean;
/** Treat quoted bot messages as implicit mentions. */
quotedBot?: boolean;
/** Treat follow-ups in threads the bot participated in as implicit mentions. */
threadParticipation?: boolean;
};
//#endregion
//#region src/config/types.irc.d.ts
type IrcAccountConfig = Omit<CommonChannelMessagingConfig, "mentionPatterns"> & {
/** IRC server hostname (example: irc.example.com). */
host?: string;
/** IRC server port (default: 6697 with TLS, otherwise 6667). */
port?: number;
/** Use TLS for IRC connection (default: true). */
tls?: boolean;
/** IRC nickname to identify this bot. */
nick?: string;
/** IRC USER field username (defaults to nick). */
username?: string;
/** IRC USER field realname (default: OpenClaw). */
realname?: string;
/** Optional IRC server password (sensitive). */
password?: string;
/** Optional file path containing IRC server password. */
passwordFile?: string;
/** Optional NickServ identify/register settings. */
nickserv?: {
/** Enable NickServ identify/register after connect (default: enabled when password is set). */
enabled?: boolean;
/** NickServ service nick (default: NickServ). */
service?: string;
/** NickServ password (sensitive). */
password?: string;
/** Optional file path containing NickServ password. */
passwordFile?: string;
/** If true, send NickServ REGISTER on connect. */
register?: boolean;
/** Email used with NickServ REGISTER. */
registerEmail?: string;
};
/** Auto-join channel list at connect (example: ["#openclaw"]). */
channels?: string[];
/** Outbound text chunk size (chars). Default: 350. */
textChunkLimit?: number;
groups?: Record<string, {
requireMention?: boolean;
tools?: GroupToolPolicyConfig;
toolsBySender?: GroupToolPolicyBySenderConfig;
allowFrom?: Array<string | number>;
skills?: string[];
enabled?: boolean;
systemPrompt?: string;
}>;
};
type IrcConfig = {
/** Optional per-account IRC configuration (multi-account). */
accounts?: Record<string, IrcAccountConfig>;
/** Optional default account id when multiple accounts are configured. */
defaultAccount?: string;
} & IrcAccountConfig;
//#endregion
//#region src/config/types.msteams.d.ts
type MSTeamsWebhookConfig = {
/** Port for the webhook server. Default: 3978. */
port?: number;
/** Path for the messages endpoint. Default: /api/messages. */
path?: string;
};
/** Teams SDK cloud environment. Public cloud is the default. */
type MSTeamsCloudName = "Public" | "USGov" | "USGovDoD" | "China";
/**
* Bot Framework OAuth SSO configuration for Microsoft Teams.
*
* When enabled, the plugin handles the `signin/tokenExchange` and
* `signin/verifyState` invoke activities that Teams sends after an
* `oauthCard` is presented to the user. The exchanged user token is
* persisted via the Bot Framework User Token service so downstream
* tools can call Microsoft Graph with delegated permissions.
*
* Prerequisites (Azure portal):
* - The bot's Azure AD (Entra) app is configured with an exposed API
* scope (for example `access_as_user`) and lists the Teams client
* IDs in `knownClientApplications`.
* - The Bot Framework channel registration has an OAuth Connection
* Setting whose name matches `connectionName` below, pointing at
* the same Azure AD app.
*/
type MSTeamsSsoConfig = {
/** If true, handle signin/tokenExchange + signin/verifyState invokes. Default: false. */
enabled?: boolean;
/**
* Name of the OAuth connection configured on the Bot Framework channel
* registration (Azure Bot resource). Required when `enabled` is true.
*/
connectionName?: string;
};
/** Reply style for MS Teams messages. */
type MSTeamsReplyStyle = "thread" | "top-level";
/** Channel-level config for MS Teams. */
type MSTeamsChannelConfig = {
/** Require @mention to respond. Default: true. */
requireMention?: boolean;
/** Optional tool policy overrides for this channel. */
tools?: GroupToolPolicyConfig;
toolsBySender?: GroupToolPolicyBySenderConfig;
/** Reply style: "thread" replies to the message, "top-level" posts a new message. */
replyStyle?: MSTeamsReplyStyle;
};
/** Team-level config for MS Teams. */
type MSTeamsTeamConfig = {
/** Default requireMention for channels in this team. */
requireMention?: boolean;
/** Default tool policy for channels in this team. */
tools?: GroupToolPolicyConfig;
toolsBySender?: GroupToolPolicyBySenderConfig;
/** Default reply style for channels in this team. */
replyStyle?: MSTeamsReplyStyle;
/** Per-channel overrides. Key is conversation ID (e.g., "19:...@thread.tacv2"). */
channels?: Record<string, MSTeamsChannelConfig>;
};
type MSTeamsConfig = Omit<CommonChannelMessagingConfig<string[], string, string, ChannelPreviewStreamingConfig>, "mentionPatterns" | "name" | "replyToMode"> & Pick<ChannelBotInteractionConfig<boolean>, "dangerouslyAllowNameMatching"> & {
/** Azure Bot App ID (from Azure Bot registration). */
appId?: string;
/** Azure Bot App Password / Client Secret. */
appPassword?: SecretInput;
/** Azure AD Tenant ID (for single-tenant bots). */
tenantId?: string;
/** Teams SDK cloud environment. Default: Public. */
cloud?: MSTeamsCloudName;
/**
* Bot Connector service URL used by SDK proactive sends/edits/deletes.
* Set with `cloud` for USGov/DoD SDK clouds; set alone for GCC.
*/
serviceUrl?: string;
/**
* Authentication type.
* - `"secret"` (default): uses `appPassword` (client secret).
* - `"federated"`: uses workload identity / managed identity / certificate.
*/
authType?: "secret" | "federated";
/** Path to a PEM certificate file for certificate-based auth. Used when `authType` is `"federated"`. */
certificatePath?: string;
/** Certificate thumbprint (hex SHA-1) for certificate-based auth. */
certificateThumbprint?: string;
/** If `true`, use Azure Managed Identity (system- or user-assigned) instead of a certificate. */
useManagedIdentity?: boolean;
/** User-assigned managed-identity client ID. When omitted with `useManagedIdentity: true`, system-assigned identity is used. */
managedIdentityClientId?: string;
/** Webhook server configuration. */
webhook?: MSTeamsWebhookConfig;
/** Send native Teams typing indicator before replies. Default: true for groups/channels; DMs use informative stream status. */
typingIndicator?: boolean;
/**
* Allowed host suffixes for inbound attachment downloads.
* Use ["*"] to allow any host (not recommended).
*/
mediaAllowHosts?: Array<string>;
/**
* Allowed host suffixes for attaching Authorization headers to inbound media retries.
* Use specific hosts only; avoid multi-tenant suffixes.
*/
mediaAuthAllowHosts?: Array<string>;
/**
* Query Graph for channel/group media when Bot Framework HTML omits file markers.
* Requires the documented Graph permissions and adds one message lookup per
* otherwise unresolved HTML activity. Default: false.
*/
graphMediaFallback?: boolean;
/** Default: require @mention to respond in channels/groups. */
requireMention?: boolean;
/** Default reply style: "thread" replies to the message, "top-level" posts a new message. */
replyStyle?: MSTeamsReplyStyle;
/** Per-team config. Key is team ID (from the /team/ URL path segment). */
teams?: Record<string, MSTeamsTeamConfig>;
/** SharePoint site ID for file uploads in group chats/channels (e.g., "contoso.sharepoint.com,guid1,guid2"). */
sharePointSiteId?: string;
/** Show a welcome Adaptive Card when the bot is added to a 1:1 chat. Default: true. */
welcomeCard?: boolean;
/** Custom prompt starter labels shown on the welcome card. */
promptStarters?: string[];
/** Show a welcome message when the bot is added to a group chat. Default: false. */
groupWelcomeCard?: boolean;
/** Enable the Teams feedback loop (thumbs up/down) on AI-generated messages. Default: true. */
feedbackEnabled?: boolean;
/** Enable background reflection when a user gives negative feedback. Default: true. */
feedbackReflection?: boolean;
/** Minimum interval (ms) between reflections per session. Default: 300000 (5 min). */
feedbackReflectionCooldownMs?: number;
/** Delegated auth settings for user-scoped Graph API actions (e.g., reactions). */
delegatedAuth?: {
/** Enable delegated auth (user sign-in for Graph actions that need user scope). */
enabled?: boolean;
/** Additional scopes to request during OAuth consent. */
scopes?: string[];
};
/** Bot Framework OAuth SSO (signin/tokenExchange + signin/verifyState) settings. */
sso?: MSTeamsSsoConfig;
};
//#endregion
//#region src/config/types.signal.d.ts
type SignalReactionNotificationMode = "off" | "own" | "all" | "allowlist";
type SignalReactionLevel = "off" | "ack" | "minimal" | "extensive";
type SignalTransportConfig = {
kind: "managed-native";
/** Optional signal-cli config directory path (passed as --config). */
configPath?: string;
/** Native daemon connection URL when it differs from the managed bind endpoint. */
url?: string;
/** HTTP host for the managed signal-cli daemon (default 127.0.0.1). */
httpHost?: string;
/** HTTP port for the managed signal-cli daemon (default 8080). */
httpPort?: number;
/** signal-cli binary path (default: signal-cli). */
cliPath?: string;
/** Max time to wait for signal-cli daemon startup (ms, cap 120000). */
startupTimeoutMs?: number;
receiveMode?: "on-start" | "manual";
ignoreStories?: boolean;
} | {
kind: "external-native";
/** Base URL for an externally managed native signal-cli HTTP daemon. */
url: string;
} | {
kind: "container";
/** Base URL for bbernhard/signal-cli-rest-api. */
url: string;
};
type SignalGroupConfig = {
requireMention?: boolean;
/** Emit internal message hooks for mention-skipped group messages. */
ingest?: boolean;
tools?: GroupToolPolicyConfig;
toolsBySender?: GroupToolPolicyBySenderConfig;
};
type SignalAccountConfig = Omit<CommonChannelMessagingConfig, "mentionPatterns"> & ChannelReadReceiptConfig & ChannelReactionConfig<SignalReactionNotificationMode, SignalReactionLevel, never, true> & {
/** Optional explicit E.164 account for signal-cli. */
account?: string;
/** Optional account UUID for signal-cli (used for loop protection). */
accountUuid?: string;
/** Concrete transport owned by this account. Defaults to managed native signal-cli. */
transport?: SignalTransportConfig;
/** Skip downloading inbound Signal attachments. */
ignoreAttachments?: boolean;
/** OpenClaw-side target aliases keyed by friendly name. */
aliases?: Record<string, string>;
/** Per-group overrides keyed by Signal group id (or "*"). */
groups?: Record<string, SignalGroupConfig>;
/** Optional per-chat-type native reply quoting overrides. */
replyToModeByChatType?: Partial<Record<"direct" | "group", ReplyToMode>>;
/** Action toggles for message tool capabilities. */
actions?: {
/** Enable/disable sending reactions via message tool (default: true). */
reactions?: boolean;
};
};
type SignalConfig = {
/** Optional per-account Signal configuration (multi-account). */
accounts?: Record<string, SignalAccountConfig>;
/** Optional default account id when multiple accounts are configured. */
defaultAccount?: string;
} & SignalAccountConfig;
//#endregion
//#region src/config/types.slack.d.ts
type SlackDmConfig = {
/** If false, ignore all incoming Slack DMs. Default: true. */
enabled?: boolean;
/** If true, allow group DMs (default: false). */
groupEnabled?: boolean;
/** Optional allowlist for group DM channels (ids or slugs). */
groupChannels?: Array<string | number>;
};
type SlackChannelConfig = {
/** If false, disable the bot in this channel. */
enabled?: boolean;
/** Require mentioning the bot to trigger replies. */
requireMention?: boolean;
/**
* Ignore room messages that mention another user or user group but not this bot.
* Requires a resolved bot user ID. Default: false.
*/
ignoreOtherMentions?: boolean;
/** Override Slack reply/thread behavior for this channel. */
replyToMode?: ReplyToMode;
/** Optional tool policy overrides for this channel. */
tools?: GroupToolPolicyConfig;
toolsBySender?: GroupToolPolicyBySenderConfig;
/** Allow bot-authored messages to trigger replies (default: false). Set to "mentions" to only allow bot messages that @mention this bot. */
allowBots?: boolean | "mentions";
/** Sliding-window bot-pair loop guard for accepted bot-authored Slack messages. */
botLoopProtection?: ChannelBotLoopProtectionConfig;
/** Allowlist of users that can invoke the bot in this channel. */
users?: Array<string | number>;
/** Optional skill filter for this channel. */
skills?: string[];
/** Optional system prompt for this channel. */
systemPrompt?: string;
/** Slack presence polling and agent wake mode for this channel. */
presenceEvents?: SlackPresenceEventsConfig;
};
type SlackPresenceEventsMode = "off" | "auto" | "on";
type SlackPresenceEventsConfig = {
/** Presence wake mode. Default: off. */
mode?: SlackPresenceEventsMode;
/** Override the default presence-event guidance. Empty omits guidance. Maximum: 20,000 characters. */
prompt?: string;
};
type SlackReactionNotificationMode = "off" | "own" | "all" | "allowlist";
type SlackStreamingProgressConfig = ChannelStreamingProgressConfig & {
/** Slack progress presentation. "compact" keeps one editable text draft. Default: "card". */
style?: "card" | "compact";
/** Use Slack-native task cards for card-style progress. Default: true. */
nativeTaskCards?: boolean;
};
type SlackChannelStreamingConfig = ChannelStreamingConfig<SlackStreamingProgressConfig>;
type SlackExecApprovalConfig = ChannelExecApprovalConfig;
type SlackCapabilitiesConfig = string[];
type SlackActionConfig = {
reactions?: boolean;
messages?: boolean;
pins?: boolean;
search?: boolean;
permissions?: boolean;
memberInfo?: boolean;
channelInfo?: boolean;
emojiList?: boolean;
};
type SlackSlashCommandConfig = {
/** Enable handling for the configured slash command (default: false). */
enabled?: boolean;
/** Slash command name (default: "openclaw"). */
name?: string;
/** Session key prefix for slash commands (default: "slack:slash"). */
sessionPrefix?: string;
/** Reply ephemerally (default: true). */
ephemeral?: boolean;
};
type SlackThreadConfig = {
/** Scope for thread history context (thread|channel). Default: thread. */
historyScope?: "thread" | "channel";
/** If true, thread sessions inherit the parent channel transcript. Default: false. */
inheritParent?: boolean;
/** Maximum number of thread messages to fetch as context when starting a new thread session (default: 20). Set to 0 to disable thread history fetching. */
initialHistoryLimit?: number;
};
type SlackRelayConfig = {
/** Full relay websocket URL, including the route path. */
url?: string;
/** Bearer token used to authenticate the gateway websocket to the Slack relay. */
authToken?: SecretInput;
/** Gateway destination id registered with openclaw-slack-router. */
gatewayId?: string;
};
type SlackAccountConfig = Omit<CommonChannelMessagingConfig<SlackCapabilitiesConfig, string | number, string, SlackChannelStreamingConfig>, "groupAllowFrom"> & ChannelBotInteractionConfig & ChannelReactionConfig<SlackReactionNotificationMode, never, string, true> & {
/** Post a room-specific introduction when joining a group. Default: true. */
joinIntro?: boolean;
/** @deprecated Doctor-only legacy input. */
identity?: "bot" | "user";
/** @deprecated Doctor-only legacy input. */
socketMode?: {
clientPingTimeout?: number;
serverPingTimeout?: number;
pingPongLoggingEnabled?: boolean;
};
/** Slack author identity. Default: bot. */
postAs?: "bot" | "user";
/** Slack connection mode (socket|http|relay). Default: socket. */
mode?: "socket" | "http" | "relay";
/** Slack SDK Socket Mode transport options. Ignored in HTTP mode. */
/** Relay-delivered Slack event source. Used when mode is "relay". */
relay?: SlackRelayConfig;
/** Slack signing secret (required for HTTP mode). */
signingSecret?: SecretInput;
/** Slack Events API webhook path (default: /slack/events). */
webhookPath?: string;
/** Slack-native exec approval delivery + approver authorization. */
execApprovals?: SlackExecApprovalConfig;
/** Override native command registration for Slack (bool or "auto"). */
commands?: ProviderCommandsConfig;
botToken?: SecretInput;
appToken?: SecretInput;
userToken?: SecretInput;
/** If true, restrict user token to read operations only. Default: true. */
userTokenReadOnly?: boolean;
/** Default mention requirement for channel messages (default: true). */
requireMention?: boolean;
/** Implicit mention policy for replies, quotes, and participated threads. */
implicitMentions?: ChannelImplicitMentionsConfig;
/** Pass through Slack chat.postMessage link unfurl control. Default: false. */
unfurlLinks?: boolean;
/** Pass through Slack chat.postMessage media unfurl control. Omitted by default. */
unfurlMedia?: boolean;
/**
* Optional per-chat-type reply threading overrides.
* Example: { direct: "all", group: "first", channel: "off" }.
*/
replyToModeByChatType?: Partial<Record<"direct" | "group" | "channel", ReplyToMode>>;
/** Thread session behavior. */
thread?: SlackThreadConfig;
/** Poll Slack presence and wake the routed agent on away-to-active transitions. Default: off. */
presenceEvents?: SlackPresenceEventsConfig;
actions?: SlackActionConfig;
slashCommand?: SlackSlashCommandConfig;
dm?: SlackDmConfig;
channels?: Record<string, SlackChannelConfig>;
/** Reaction emoji added while processing a reply (e.g. "hourglass_flowing_sand"). Removed when done. Useful as a typing indicator fallback when assistant mode is not enabled. */
typingReaction?: string;
};
type SlackConfig = {
/** Optional per-account Slack configuration (multi-account). */
accounts?: Record<string, SlackAccountConfig>;
/** Optional default account id when multiple accounts are configured. */
defaultAccount?: string;
} & SlackAccountConfig;
//#endregion
//#region src/config/types.telegram.d.ts
type TelegramActionConfig = {
reactions?: boolean;
sendMessage?: boolean;
/** Enable poll creation. Requires sendMessage to also be enabled. */
poll?: boolean;
deleteMessage?: boolean;
editMessage?: boolean;
/** Enable sticker actions (send and search). */
sticker?: boolean;
/** Enable forum topic creation. */
createForumTopic?: boolean;
/** Enable forum topic editing (rename / change icon). */
editForumTopic?: boolean;
};
type TelegramThreadBindingsConfig = SessionThreadBindingsConfig;
type TelegramNetworkConfig = {
/** Override Node's autoSelectFamily behavior (true = enable, false = disable). */
autoSelectFamily?: boolean;
/**
* DNS result order for network requests ("ipv4first" | "verbatim").
* Set to "ipv4first" to prioritize IPv4 addresses and work around IPv6 issues.
* Default: "ipv4first" on Node 22+ to avoid common fetch failures.
*/
dnsResultOrder?: "ipv4first" | "verbatim";
/**
* Dangerous opt-in for Telegram media downloads in trusted fake-IP or
* transparent-proxy environments that resolve api.telegram.org to
* private/internal/special-use addresses.
*/
dangerouslyAllowPrivateNetwork?: boolean;
};
type TelegramInlineButtonsScope = "off" | "dm" | "group" | "all" | "allowlist";
type TelegramPreviewStreamingConfig = Omit<ChannelPreviewStreamingConfig, "preview"> & {
preview?: ChannelStreamingPreviewConfig;
};
type TelegramExecApprovalConfig = ChannelExecApprovalConfig;
type TelegramCapabilitiesConfig = string[] | {
inlineButtons?: TelegramInlineButtonsScope;
};
/** Custom command definition for Telegram bot menu. */
type TelegramCustomCommand = {
/** Command name (without leading /). */
command: string;
/** Description shown in Telegram command menu. */
description: string;
};
type TelegramAccountConfig = CommonChannelMessagingConfig<TelegramCapabilitiesConfig, string | number, string | number, TelegramPreviewStreamingConfig> & ChannelReactionConfig<"off" | "own" | "all", "off" | "ack" | "minimal" | "extensive", string> & {
/** Post a room-specific introduction when joining a group. Default: true. */
joinIntro?: boolean;
/** Telegram-native exec approval delivery + approver authorization. */
execApprovals?: TelegramExecApprovalConfig;
/** Override native command registration for Telegram (bool or "auto"). */
commands?: ProviderCommandsConfig;
/** Custom commands to register in Telegram's command menu (merged with native). */
customCommands?: TelegramCustomCommand[];
botToken?: SecretInput;
/** Path to a regular file containing the bot token; symlinks are rejected. */
tokenFile?: string;
groups?: Record<string, TelegramGroupConfig>;
/** Per-DM configuration for Telegram DM topics (key is chat ID). */
direct?: Record<string, TelegramDirectConfig>;
/**
* Use Telegram Bot API 10.3 rich messages for text sends and edits.
* When false (default), falls back to HTML/plain text formatting via sendMessage.
* Set to true to enable native tables, details, and rich media via sendRichMessage.
* Note: Some Telegram clients (Web, Desktop, older mobile) do NOT support
* sendRichMessage and will show "This message is not supported" errors.
* Default: false.
*/
richMessages?: boolean;
/** Network transport overrides for Telegram. */
network?: TelegramNetworkConfig;
proxy?: string;
webhookUrl?: string;
webhookSecret?: string;
webhookPath?: string;
/** Local webhook listener bind host (default: 127.0.0.1). */
webhookHost?: string;
/** Local webhook listener bind port (default: 8787). */
webhookPort?: number;
/** Path to the self-signed certificate (PEM) to upload to Telegram during webhook registration. */
webhookCertPath?: string;
/** Per-action tool gating (default: true for all). */
actions?: TelegramActionConfig;
/** Telegram thread/conversation binding overrides. */
threadBindings?: TelegramThreadBindingsConfig;
/**
* Controls which user reactions trigger notifications:
* - "off" (default): ignore all reactions
* - "own": notify when users react to bot messages
* - "all": notify agent of all reactions
*/
/**
* Controls agent's reaction capability:
* - "off": agent cannot react
* - "ack" (default): bot sends acknowledgment reactions (š while processing)
* - "minimal": agent can react sparingly (guideline: 1 per 5-10 exchanges)
* - "extensive": agent can react liberally when appropriate
*/
/** Controls whether link previews are shown in outbound messages. Default: true. */
linkPreview?: boolean;
/** Send Telegram bot error replies silently (no notification sound). Default: false. */
silentErrorReplies?: boolean;
/** Controls outbound error reporting: always, once per cooldown window, or silent. */
errorPolicy?: "always" | "once" | "silent";
/**
* Per-channel outbound response prefix override.
*
* Account values take precedence over the channel-level value.
* Use `""` to explicitly disable a global prefix for this channel.
* Use `"auto"` to derive `[{identity.name}]` from the routed agent.
*/
/**
* Per-channel ack reaction override.
* Telegram expects unicode emoji (e.g., "š") rather than shortcodes.
*/
/** Custom Telegram Bot API root URL (e.g. "https://my-proxy.example.com" or a local Bot API server), not a /bot<TOKEN> endpoint. */
apiRoot?: string;
/** Trusted local filesystem roots for self-hosted Telegram Bot API absolute file_path values. */
trustedLocalFileRoots?: string[];
/** Auto-rename DM forum topics on first message using LLM. Default: true. */
autoTopicLabel?: AutoTopicLabelConfig;
};
type TelegramTopicConfig = {
requireMention?: boolean;
/** Emit internal message hooks for mention-skipped topic messages. */
ingest?: boolean;
/** Per-topic override for group message policy (open|disabled|allowlist). */
groupPolicy?: GroupPolicy;
/** If specified, only load these skills for this topic. Omit = all skills; empty = no skills. */
skills?: string[];
/** If false, disable the bot for this topic. */
enabled?: boolean;
/** Optional allowlist for topic senders (numeric Telegram user IDs). */
allowFrom?: Array<string | number>;
/** Optional system prompt snippet for this topic. */
systemPrompt?: string;
/** If true, skip automatic voice-note transcription for mention detection in this topic. */
disableAudioPreflight?: boolean;
/** Route this topic to a specific agent (overrides group-level and binding routing). */
agentId?: string;
/** Controls outbound error reporting for this topic. */
errorPolicy?: "always" | "once" | "silent";
};
type TelegramGroupConfig = {
requireMention?: boolean;
/** Emit internal message hooks for mention-skipped group messages. */
ingest?: boolean;
/** Per-group override for group message policy (open|disabled|allowlist). */
groupPolicy?: GroupPolicy;
/** Optional tool policy overrides for this group. */
tools?: GroupToolPolicyConfig;
toolsBySender?: GroupToolPolicyBySenderConfig;
/** If specified, only load these skills for this group (when no topic). Omit = all skills; empty = no skills. */
skills?: string[];
/** Per-topic configuration (key is message_thread_id as string, or "*" for topic defaults). */
topics?: Record<string, TelegramTopicConfig>;
/** If false, disable the bot for this group (and its topics). */
enabled?: boolean;
/** Optional allowlist for group senders (numeric Telegram user IDs). */
allowFrom?: Array<string | number>;
/** Optional system prompt snippet for this group. */
systemPrompt?: string;
/** If true, skip automatic voice-note transcription for mention detection in this group. */
disableAudioPreflight?: boolean;
/** Controls outbound error reporting for this group. */
errorPolicy?: "always" | "once" | "silent";
};
/** Config for LLM-based auto-topic labeling. */
type AutoTopicLabelConfig = boolean | {
enabled?: boolean;
/** Custom prompt for LLM-based topic naming. */
prompt?: string;
};
type TelegramDirectConfig = {
/** Per-DM override for DM message policy (open|disabled|allowlist). */
dmPolicy?: DmPolicy;
/** Optional tool policy overrides for this DM. */
tools?: GroupToolPolicyConfig;
toolsBySender?: GroupToolPolicyBySenderConfig;
/** If specified, only load these skills for this DM (when no topic). Omit = all skills; empty = no skills. */
skills?: string[];
/** Per-topic configuration for DM topics (key is message_thread_id as string, or "*" for topic defaults). */
topics?: Record<string, TelegramTopicConfig>;
/** If false, disable the bot for this DM (and its topics). */
enabled?: boolean;
/** If true, require messages to be from a topic when topics are enabled. */
requireTopic?: boolean;
/** Optional allowlist for DM senders (numeric Telegram user IDs). */
allowFrom?: Array<string | number>;
/** Optional system prompt snippet for this DM. */
systemPrompt?: string;
/** Controls outbound error reporting for this DM. */
errorPolicy?: "always" | "once" | "silent";
/** Auto-rename DM forum topics on first message using LLM. Default: true. */
autoTopicLabel?: AutoTopicLabelConfig;
};
type TelegramConfig = {
/** Optional per-account Telegram configuration (multi-account). */
accounts?: Record<string, TelegramAccountConfig>;
/** Optional default account id when multiple accounts are configured. */
defaultAccount?: string;
} & TelegramAccountConfig;
//#endregion
//#region src/utils/reaction-level.d.ts
/**
* Shared reaction-level resolver for channel plugins that expose ACK and agent reaction controls.
* Channel adapters supply defaults/fallbacks; this helper owns the common flag expansion.
*/
/** User-configurable reaction behavior level for channel delivery. */
type ReactionLevel = "off" | "ack" | "minimal" | "extensive";
//#endregion
//#region src/config/types.whatsapp.d.ts
type WhatsAppActionConfig = {
reactions?: boolean;
sendMessage?: boolean;
polls?: boolean;
/** Enable the experimental requester-bound voice-call tool. Default: false. */
calls?: boolean;
};
type WhatsAppReactionLevel = ReactionLevel;
type WhatsAppGroupConfig = {
requireMention?: boolean;
tools?: GroupToolPolicyConfig;
toolsBySender?: GroupToolPolicyBySenderConfig;
/** Optional system prompt for this group. */
systemPrompt?: string;
};
type WhatsAppDirectConfig = {
/** Optional system prompt for this direct chat. */
systemPrompt?: string;
};
type WhatsAppAckReactionConfig = {
/** Emoji to use for acknowledgment (e.g., "š"). Empty = disabled. */
emoji?: string;
/** Send reactions in direct chats. Default: true. */
direct?: boolean;
/**
* Send reactions in group chats:
* - "always": react to all group messages
* - "mentions": react only when bot is mentioned
* - "never": never react in groups
* Default: "mentions"
*/
group?: "always" | "mentions" | "never";
};
type WhatsAppSharedConfig = CommonChannelMessagingConfig<string[], string> & ChannelReadReceiptConfig & ChannelReactionConfig<never, WhatsAppReactionLevel, WhatsAppAckReactionConfig> & {
/** Same-phone setup (bot uses your personal WhatsApp number). */
selfChatMode?: boolean;
groups?: Record<string, WhatsAppGroupConfig>;
/** Per-direct-chat prompt overrides keyed by user ID or `*` wildcard. */
direct?: Record<string, WhatsAppDirectConfig>;
};
type WhatsAppSpecificConfig = {
/** @deprecated Doctor-only legacy input. */
messagePrefix?: string;
};
type WhatsAppConfig = Omit<WhatsAppSharedConfig, "name"> & WhatsAppSpecificConfig & {
/** Optional per-account WhatsApp configuration (multi-account). */
accounts?: Record<string, WhatsAppAccountConfig>;
/** Optional default account id when multiple accounts are configured. */
defaultAccount?: string;
/** Per-action tool gating. Calls default to false; existing actions default to true. */
actions?: WhatsAppActionConfig;
/** Plugin hook opt-in configuration for privacy-sensitive inbound events. */
pluginHooks?: {
/** Enable message_received hooks to broadcast inbound WhatsApp messages to plugins. */
messageReceived?: boolean;
};
};
type WhatsAppAccountConfig = WhatsAppSpecificConfig & WhatsAppSharedConfig & {
/** Optional display name for this account (used in CLI/UI lists). */
name?: string;
/** Override auth directory (Baileys multi-file auth state). */
authDir?: string;
/** Plugin hook opt-in configuration for privacy-sensitive inbound events. */
pluginHooks?: {
/** Enable message_received hooks to broadcast inbound WhatsApp messages to plugins. */
messageReceived?: boolean;
};
};
//#endregion
//#region src/config/types.channels.d.ts
type ChannelDefaultsConfig = {
/** @deprecated Doctor-only legacy input. */
heartbeat?: ChannelHeartbeatVisibilityConfig;
/** Default group-chat admission policy inherited by channels that support groups. */
groupPolicy?: GroupPolicy;
/** Default history/context visibility inherited by channel configs. */
contextVisibility?: ContextVisibilityMode;
/** Default heartbeat visibility for all channels. */
heartbeatVisibility?: ChannelHeartbeatVisibilityConfig;
/** Default pair loop guard settings for channels that support bot loop protection. */
botLoopProtection?: ChannelBotLoopProtectionConfig;
/** Default implicit-mention policy inherited by supporting channels. */
implicitMentions?: ChannelImplicitMentionsConfig;
};
/** Provider/channel/target model override map used by channel dispatch. Keys are channel-specific group IDs, thread IDs, channel names, or DM peer identifiers (see docs/gateway/config-channels.md). */
type ChannelModelByChannelConfig = Record<string, Record<string, string>>;
/** JSON-compatible open-world channel section for plugin ids unknown to core. */
type OpenWorldChannelConfig = ReturnType<typeof JSON.parse>;
interface ChannelsConfig {
/** Shared defaults inherited by channel sections unless they override them. */
defaults?: ChannelDefaultsConfig;
/** Map provider -> channel id / DM peer id -> model override. See docs/gateway/config-channels.md for supported key forms. */
modelByChannel?: ChannelModelByChannelConfig;
discord?: DiscordConfig;
googlechat?: GoogleChatConfig;
imessage?: IMessageConfig;
irc?: IrcConfig;
msteams?: MSTeamsConfig;
signal?: SignalConfig;
slack?: SlackConfig;
telegram?: TelegramConfig;
whatsapp?: WhatsAppConfig;
/**
* Channel sections are plugin-owned and keyed by arbitrary channel ids.
* Open-world config keeps SDK/plugin-owned sections ergonomic for dynamic ids.
*/
[key: string]: OpenWorldChannelConfig;
}
//#endregion
//#region src/config/types.cloud-workers.d.ts
type CloudWorkerProfileConfig = {
/** Worker provider id registered by a plugin. */
provider: string;
/** Worker install method (default: bundle); npm requires a released gateway version. */
install?: "bundle" | "npm";
/** Reclaim an idle worker after this duration; omitted profiles stay running. */
suspendAfter?: string;
/** Provider-owned JSON settings; secret-bearing fields use SecretRef objects. */
settings?: Record<string, unknown>;
};
type CloudWorkersConfig = {
/** Experimental Labs gate for the cloud-worker desktop observer. */
desktop?: boolean;
/** Default worker profile names keyed by normalized repository identity. */
projectProfiles?: Record<string, string>;
/** Named opt-in worker profiles. Omit or leave empty to disable cloud workers. */
profiles?: Record<string, CloudWorkerProfileConfig>;
};
//#endregion
//#region src/config/types.cron.d.ts
type CronFailureAlertConfig = {
enabled?: boolean;
after?: number;
cooldownMs?: number;
includeSkipped?: boolean;
mode?: "announce" | "webhook";
accountId?: string;
channel?: string;
to?: string;
};
type CronConfig = {
enabled?: boolean;
/** Skip missed recurring slots at startup; one-shot catch-up is unchanged. Default: false. */
skipMissedJobs?: boolean;
triggers?: {
enabled?: boolean;
};
/** Bearer token for cron webhook POST delivery. */
webhookToken?: SecretInput;
/** SSRF policy for all outbound cron webhook deliveries. */
webhookSsrfPolicy?: SsrFPolicyConfig;
/**
* How long to retain completed cron run sessions before automatic pruning.
* Accepts a duration string (e.g. "24h", "7d", "1h30m") or `false` to disable pruning.
* A zero duration (e.g. "0h") also disables pruning; negative durations are invalid.
* Default: "24h".
*/
sessionRetention?: string | false;
failureAlert?: CronFailureAlertConfig;
};
//#endregion
//#region src/config/types.desktop.d.ts
type DesktopHostConfig = {
/** Enables the gateway-host desktop source after a gateway restart. */
enabled: boolean;
/** Runs a gateway-supervised headless TigerVNC/XFCE desktop on Linux. */
managed?: boolean;
/** Loopback RFB port of an already-running VNC server (default: 5900). */
port?: number;
/** Absolute VNC password-file path; macOS ARD account credentials stay per-observation. */
passwordFile?: string;
};
type DesktopConfig = {
/** Experimental Labs gate for observing the gateway host desktop. */
host?: DesktopHostConfig;
};
//#endregion
//#region src/gateway/control-ui-bootstrap-contract.d.ts
declare const CONTROL_UI_ENVIRONMENT_COLORS: readonly ["teal", "amber", "purple", "coral", "pink", "blue", "green", "red", "gray"];
type ControlUiEnvironment = {
label: string;
color: (typeof CONTROL_UI_ENVIRONMENT_COLORS)[number];
};
//#endregion
//#region src/gateway/operator-scopes.d.ts
declare const ADMIN_SCOPE: "operator.admin";
declare const READ_SCOPE: "operator.read";
declare const WRITE_SCOPE: "operator.write";
declare const APPROVALS_SCOPE: "operator.approvals";
declare const QUESTIONS_SCOPE: "operator.questions";
declare const PAIRING_SCOPE: "operator.pairing";
declare const TALK_SCOPE: "operator.talk";
declare const TALK_SECRETS_SCOPE: "operator.talk.secrets";
/** Operator privileges advertised by gateway auth and checked by method policy. */
type OperatorScope = typeof ADMIN_SCOPE | typeof READ_SCOPE | typeof WRITE_SCOPE | typeof APPROVALS_SCOPE | typeof QUESTIONS_SCOPE | typeof PAIRING_SCOPE | typeof TALK_SCOPE | typeof TALK_SECRETS_SCOPE;
//#endregion
//#region src/config/types.gateway.d.ts
/** Gateway bind-address policy for local server startup. */
type GatewayBindMode = "auto" | "lan" | "loopback" | "custom" | "tailnet";
type GatewayTlsConfig = {
/** Enable TLS for the gateway server. */
enabled?: boolean;
/** Auto-generate a self-signed cert if cert/key are missing (default: true). */
autoGenerate?: boolean;
/** PEM certificate path for the gateway server. */
certPath?: string;
/** PEM private key path for the gateway server. */
keyPath?: string;
/** Optional PEM CA bundle for TLS clients (mTLS or custom roots). */
caPath?: string;
};
type WideAreaDiscoveryConfig = {
/** Optional unicast DNS-SD domain (e.g. "openclaw.internal"). */
domain?: string;
};
/** mDNS/Bonjour metadata exposure level for local gateway discovery. */
type MdnsDiscoveryMode = "off" | "minimal" | "full";
type MdnsDiscoveryConfig = {
/**
* mDNS/Bonjour discovery broadcast mode (default: minimal).
* - off: disable mDNS entirely
* - minimal: omit cliPath/sshPort from TXT records
* - full: include cliPath/sshPort in TXT records
*/
mode?: MdnsDiscoveryMode;
};
type DiscoveryConfig = {
/** Wide-area DNS-SD discovery settings. */
wideArea?: WideAreaDiscoveryConfig;
/** Local mDNS/Bonjour discovery settings. */
mdns?: MdnsDiscoveryConfig;
};
type TalkProviderConfig = {
/** Provider API key (optional; provider-specific env fallback may apply). */
apiKey?: SecretInput;
/** Provider-owned Talk config fields. */
[key: string]: unknown;
};
type TalkRealtimeConfig = {
/** Active realtime voice provider. */
provider?: string;
/** Provider-specific realtime voice config keyed by provider id. */
providers?: Record<string, TalkProviderConfig>;
/** Provider model override for realtime sessions. */
model?: string;
/** Provider speaker voice name override for realtime sessions. */
speakerVoice?: string;
/** Provider speaker voice id override for realtime sessions. */
speakerVoiceId?: string;
/** Additional system instructions appended to realtime Talk sessions. */
instructions?: string;
/** Realtime execution mode. */
mode?: "realtime" | "stt-tts" | "transcription";
/** Byte/session transport. */
transport?: "webrtc" | "provider-websocket" | "gateway-relay" | "managed-room";
/** Voice activity detection threshold from 0 (most sensitive) to 1 (least sensitive). */
vadThreshold?: number;
/** Milliseconds of silence before the current user turn is committed. */
silenceDurationMs?: number;
/** Milliseconds of audio retained before detected speech begins. */
prefixPaddingMs?: number;
/** Provider-specific realtime reasoning effort. */
reasoningEffort?: string;
/** Tool/agent strategy for realtime sessions. */
brain?: "agent-consult" | "direct-tools" | "none";
/** How Gateway relay handles final user transcripts when the provider skips a consult. */
consultRouting?: "provider-direct" | "force-agent-consult";
};
type TalkConfig = {
/** Agent that owns Talk sessions created without an agent-scoped session key. */
agentId?: string;
/** Active Talk TTS provider (for example "acme-speech"). */
provider?: string;
/** Provider-specific Talk config keyed by provider id. */
providers?: Record<string, TalkProviderConfig>;
/** Realtime Talk provider, model, voice, mode, transport, and brain config. */
realtime?: TalkRealtimeConfig;
/** Optional thinking level override for the agent run behind Talk realtime consults. */
consultThinkingLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "adaptive" | "max" | "ultra";
/** Optional fast mode override for the agent run behind Talk realtime consults. */
consultFastMode?: boolean;
/** BCP 47 locale id used for Talk speech recognition on device nodes and the iOS system-voice fallback. */
speechLocale?: string;
/** Stop speaking when user starts talking (default: true). */
interruptOnSpeech?: boolean;
/** Milliseconds of user silence before Talk mode sends the transcript after a pause. */
silenceTimeoutMs?: number;
};
type GatewayControlUiConfig = {
/** @deprecated Doctor-only legacy input. */
chatMessageMaxWidth?: string;
/**
* @deprecated Upgrade-only transport input. Retained so releases that shipped
* this break-glass flag can migrate an unpaired browser safely.
*/
dangerouslyDisableDeviceAuth?: boolean;
/** If false, the Gateway will not serve the Control UI (default /). */
enabled?: boolean;
/** Optional base path prefix for the Control UI (e.g. "/openclaw"). */
basePath?: string;
experimental?: {
/** Allow native UI from user-installed plugins (default false; bundled UI stays available). */
customPlugins?: boolean;
};
/** Optional filesystem root for Control UI assets (defaults to dist/control-ui). */
root?: string;
/** Optional visual label and named color distinguishing this Gateway environment. */
environment?: ControlUiEnvironment;
/** Show the Discord community invitation in this Gateway's Control UI (default true). */
communityInvite?: boolean;
/** Optional service credential used only for Control UI GitHub previews and discovery. */
github?: {
token?: SecretInput;
};
/** Produce utility-model session status digests for subscribed Control UI clients (default true). */
sessionObserver?: boolean;
/**
* Embed sandbox mode for hosted Control UI previews.
* - strict: no script execution inside embeds
* - scripts: allow scripts while keeping embeds origin-isolated (default)
* - trusted: allow scripts and same-origin privileges
*/
embedSandbox?: "strict" | "scripts" | "trusted";
/**
* DANGEROUS: Allow hosted embeds to load absolute external http(s) URLs.
* Default off; prefer hosted /__openclaw__/canvas or /__openclaw__/a2ui content.
*/
allowExternalEmbedUrls?: boolean;
/** Fetch public-site favicons through the Gateway for Control UI links (default true). */
automaticallyFetchFavicons?: boolean;
/** Optional max-width for grouped Control UI chat messages (default: min(900px, 68%)). */
/** Allowed browser origins for Control UI/WebChat websocket connections. */
allowedOrigins?: string[];
/**
* DANGEROUS: Keep Host-header origin fallback behavior.
* Supported long-term for deployments that intentionally rely on this policy.
*/
dangerouslyAllowHostHeaderOriginFallback?: boolean;
};
/** Gateway authentication strategy for WebSocket and HTTP clients. */
type GatewayAuthMode = "none" | "token" | "password" | "trusted-proxy";
/**
* Configuration for trusted reverse proxy authentication.
* Used when Clawdbot runs behind an identity-aware proxy (Pomerium, Caddy + OAuth, etc.)
* that handles authentication and passes user identity via headers.
*/
type GatewayTrustedProxyConfig = {
/**
* Header name containing the authenticated user identity (required).
* Common values: "x-forwarded-user", "x-remote-user", "x-pomerium-claim-email"
*/
userHeader: string;
/**
* Additional headers that MUST be present for the request to be trusted.
* Use this to verify the request actually came through the proxy.
* Example: ["x-forwarded-proto", "x-forwarded-host"]
*/
requiredHeaders?: string[];
/**
* Optional allowlist of user identities that can access the gateway.
* If empty or omitted, all authenticated users from the proxy are allowed.
* Example: ["nick@example.com", "admin@company.org"]
*/
allowUsers?: string[];
/**
* Allow loopback proxy sources (127.0.0.1, ::1) in trusted-proxy mode.
* Default false; enable only when a same-host reverse proxy is the intended
* trust boundary and direct Gateway access is otherwise locked down.
*/
allowLoopback?: boolean;
/**
* Automatically approve new browser/native UI operator devices and same-key scope upgrades after
* trusted-proxy authentication. Disabled by default; configured scopes cap grants.
*/
deviceAutoApprove?: {
/** Enable automatic browser enrollment and same-key scope upgrades. @default false */
enabled?: boolean;
/**
* Maximum operator scopes granted by automatic approval. Listing
* operator.admin explicitly lets every proxy-authenticated user request
* automatic full-admin device grants. Requests without scopes receive the
* configured maximum. @default operator.read, operator.write,
* operator.approvals, operator.questions
*/
scopes?: string[];
};
};
type GatewayAuthConfig = {
/** Authentication mode for Gateway connections. Defaults to token when unset. */
mode?: GatewayAuthMode;
/** Shared token for token mode (plaintext or SecretRef). */
token?: SecretInput;
/** Shared password for password mode (consider env instead). */
password?: SecretInput;
/** Allow Tailscale identity headers when serve mode is enabled. */
allowTailscale?: boolean;
/** Operator scopes granted to verified trusted-proxy or Tailscale identities. */
identityScopes?: Record<string, OperatorScope[]>;
/** Rate-limit configuration for failed authentication attempts. */
rateLimit?: GatewayAuthRateLimitConfig;
/**
* Configuration for trusted-proxy auth mode.
* Required when mode is "trusted-proxy".
*/
trustedProxy?: GatewayTrustedProxyConfig;
};
type GatewayAuthRateLimitConfig = {
/** Maximum failed attempts per IP before blocking. @default 10 */
maxAttempts?: number;
/** Sliding window duration in milliseconds. @default 60000 (1 min) */
windowMs?: number;
/** Lockout duration in milliseconds after the limit is exceeded. @default 300000 (5 min) */
lockoutMs?: number;
/** Exempt localhost/loopback addresses from auth rate limiting. @default true */
exemptLoopback?: boolean;
};
/** Tailscale exposure mode for gateway HTTP/WebSocket surfaces. */
type GatewayTailscaleMode = "off" | "serve" | "funnel";
type GatewayTailscaleConfig = {
/** Tailscale exposure mode for the Gateway control UI. */
mode?: GatewayTailscaleMode;
/**
* Detect an external Funnel route left on the ordinary Gateway listener and
* leave exposure unchanged with migration guidance. Gateway-authenticated
* routes reject that ingress; plugin-authenticated webhooks keep their owner auth.
* @deprecated Migrate to `mode="funnel"`, which uses managed ingress.
*/
preserveFunnel?: boolean;
};
type GatewayRemoteConfig = {
/** Remote Gateway WebSocket URL (ws:// or wss://). */
url?: string;
/** Desktop companion transport (SSH tunnel or direct WS); core validates/preserves but does not read it. */
transport?: "ssh" | "direct";
/** Desktop companion remote SSH port (default 18789); core validates/preserves but does not read it. */
remotePort?: number;
/** Token for remote auth (when the gateway requires token auth). */
token?: SecretInput;
/** Password for remote auth (when the gateway requires password auth). */
password?: SecretInput;
/** Headers presented to an identity-aware proxy in front of the Gateway (values are secrets). */
edgeAuth?: Record<string, SecretInput>;
/** Expected TLS certificate fingerprint (sha256) for remote gateways. */
tlsFingerprint?: string;
/** SSH target for tunneling remote Gateway (user@host). */
sshTarget?: string;
/** SSH identity file path for tunneling remote Gateway. */
sshIdentity?: string;
/** macOS app-only; core validates/preserves but does not read it. Defaults to strict; see docs/platforms/mac/remote.md. */
sshHostKeyPolicy?: "strict" | "openssh";
};
/**
* Operator terminal surface served to Control UI and mobile clients.
*
* The terminal opens a PTY-backed shell on the gateway host, gated to
* admin-scope operator sessions. It starts in the target agent's workspace; if
* that agent is fully sandboxed (`sandbox.mode: "all"`) the terminal is refused
* rather than handed an unconfined host shell (workspace isolation is
* fail-closed). Under "non-main" the agent's main session runs on the host, so a
* host terminal is allowed.
*/
type GatewayTerminalConfig = {
/** Master switch for the operator terminal. Default: true; set false to opt out. */
enabled?: boolean;
/**
* Shell executable to launch. When unset the host login shell is used
* ($SHELL on Unix, %ComSpec% on Windows).
*/
shell?: string;
/**
* How long (seconds) a session survives after its connection drops, staying
* reattachable via terminal.attach. 0 kills sessions on disconnect
* immediately. Default: 300.
*/
detachedSessionTimeoutSeconds?: number;
};
/** Labs-gated external CLI session targets in the Control UI. */
type GatewayCliAgentsConfig = {
/** Show catalog-backed CLI agents in the new-session model picker. Default: false. */
enabled?: boolean;
};
/** Gateway config reload strategy for managed installs. */
type GatewayReloadMode = "off" | "restart" | "hot" | "hybrid";
type GatewayReloadConfig = {
/** Reload strategy for config changes (default: hybrid). */
mode?: GatewayReloadMode;
};
type GatewayHttpChatCompletionsConfig = {
/**
* If false, the Gateway will not serve `POST /v1/chat/completions`.
* Default: false when absent.
*/
enabled?: boolean;
/** Image input controls for `image_url` parts. */
images?: GatewayHttpChatCompletionsImagesConfig;
};
type GatewayHttpChatCompletionsImagesConfig = {
/** Allow URL fetches for `image_url` parts. Default: false. */
allowUrl?: boolean;
/**
* Optional hostname allowlist for URL fetches.
* Supports exact hosts and `*.example.com` wildcards.
*/
urlAllowlist?: string[];
/** Allowed MIME types (case-insensitive). */
allowedMimes?: string[];
/** Max bytes per image. Default: 10MB. */
maxBytes?: number;
/** Max redirects when fetching a URL. Default: 3. */
maxRedirects?: number;
/** Fetch timeout in ms. Default: 10s. */
timeoutMs?: number;
};
type GatewayHttpResponsesConfig = {
/**
* If false, the Gateway will not serve `POST /v1/responses` (OpenResponses API).
* Default: false when absent.
*/
enabled?: boolean;
/**
* Max number of URL-based `input_file` + `input_image` parts per request.
* Default: 8.
*/
maxUrlParts?: number;
/** File inputs (input_file). */
files?: GatewayHttpResponsesFilesConfig;
/** Image inputs (input_image). */
images?: GatewayHttpResponsesImagesConfig;
};
type GatewayHttpResponsesFilesConfig = {
/** Allow URL fetches for input_file. Default: true. */
allowUrl?: boolean;
/**
* Optional hostname allowlist for URL fetches.
* Supports exact hosts and `*.example.com` wildcards.
*/
urlAllowlist?: string[];
/** Allowed MIME types (case-insensitive). */
allowedMimes?: string[];
/** Max bytes per file. Default: 5MB. */
maxBytes?: number;
/** Max decoded characters per file. Default: 200k. */
maxChars?: number;
/** Max redirects when fetching a URL. Default: 3. */
maxRedirects?: number;
/** Fetch timeout in ms. Default: 10s. */
timeoutMs?: number;
/** PDF handling (application/pdf). */
pdf?: GatewayHttpResponsesPdfConfig;
};
type GatewayHttpResponsesPdfConfig = {
/** Max pages to parse/render. Default: 4. */
maxPages?: number;
/** Max pixels per rendered page. Default: 4M. */
maxPixels?: number;
/** Minimum extracted text length to skip rasterization. Default: 200 chars. */
minTextChars?: number;
};
type GatewayHttpResponsesImagesConfig = {
/** Allow URL fetches for input_image. Default: true. */
allowUrl?: boolean;
/**
* Optional hostname allowlist for URL fetches.
* Supports exact hosts and `*.example.com` wildcards.
*/
urlAllowlist?: string[];
/** Allowed MIME types (case-insensitive). */
allowedMimes?: string[];
/** Max bytes per image. Default: 10MB. */
maxBytes?: number;
/** Max redirects when fetching a URL. Default: 3. */
maxRedirects?: number;
/** Fetch timeout in ms. Default: 10s. */
timeoutMs?: number;
};
type GatewayHttpEndpointsConfig = {
/** OpenAI-compatible chat completions endpoint controls. */
chatCompletions?: GatewayHttpChatCompletionsConfig;
/** OpenResponses-compatible responses endpoint controls. */
responses?: GatewayHttpResponsesConfig;
};
type GatewayHttpSecurityHeadersConfig = {
/**
* Value for the Strict-Transport-Security response header.
* Set to false to disable explicitly.
*
* Example: "max-age=31536000; includeSubDomains"
*/
strictTransportSecurity?: string | false;
};
type GatewayHttpConfig = {
/** Per-endpoint HTTP API controls. */
endpoints?: GatewayHttpEndpointsConfig;
/** HTTP security header overrides. */
securityHeaders?: GatewayHttpSecurityHeadersConfig;
};
type GatewayPushApnsRelayConfig = {
/** Base HTTPS URL for the external iOS APNs relay service. */
baseUrl?: string;
/** Timeout in milliseconds for relay send requests (default: 10000). */
timeoutMs?: number;
};
type GatewayPushApnsConfig = {
/** External APNs relay used by iOS/mobile notification flows. */
relay?: GatewayPushApnsRelayConfig;
};
type GatewayPushConfig = {
/** Apple Push Notification Service settings. */
apns?: GatewayPushApnsConfig;
};
type GatewayNodePairingConfig = {
/**
* Silently approve trusted local device pairing and access upgrades.
* Set false to require explicit approval; metadata refreshes remain automatic.
* Default: true.
*/
autoApproveLocal?: boolean;
/**
* Opt-in CIDR/IP allowlist for auto-approving first-time node-role pairing.
* Only applies to fresh node pairing requests with no requested scopes.
* Default: unset/disabled.
*/
autoApproveCidrs?: string[];
/**
* SSH-verified auto-approval for first-time node-role pairing (default: enabled).
* The gateway connects back to the pairing host over SSH (BatchMode, strict
* host keys) and approves only when the remote `openclaw node identity`
* output matches the pending request's device key. Set false to disable SSH
* verification; this is independent of autoApproveCidrs, so unset that too for
* manual-only node pairing. The object form tunes the probe:
* - user: remote user (default: gateway process user)
* - identity: SSH identity file (default: standard SSH resolution)
* - timeoutMs: probe timeout (default: 7000)
* - cidrs: CIDRs/IPs eligible for probing (default: private/CGNAT ranges)
*/
sshVerify?: boolean | {
user?: string;
identity?: string;
timeoutMs?: number;
cidrs?: string[];
};
};
type GatewayNodesConfig = {
/** @deprecated Doctor-only legacy input. */
skills?: {
enabled?: boolean;
};
/** @deprecated Doctor-only legacy input. */
allowCommands?: string[];
/** @deprecated Doctor-only legacy input. */
denyCommands?: string[];
/** Browser routing policy for node-hosted browser proxies. */
browser?: {
/** Routing mode (default: auto). */
mode?: "auto" | "manual" | "off";
/** Pin to a specific node id/name (optional). */
node?: string;
};
/** Pairing policy for node-role gateway clients. */
pairing?: GatewayNodePairingConfig;
/** Controls whether paired nodes may publish agent-visible plugin tools (default: true). */
pluginTools?: {
/** Accept node-published plugin tool descriptors (default: true). */
enabled?: boolean;
};
/** Accept node-published skill descriptors (default: true). */
allowSkills?: boolean;
commands?: {
/** Additional node.invoke commands to allow on the gateway. */
allow?: string[];
/** Commands to deny even if they appear in the defaults or node claims. */
deny?: string[];
};
};
type GatewayToolsConfig = {
/** Tools to deny via gateway HTTP /tools/invoke (extends defaults). */
deny?: string[];
/** Tools to explicitly allow (removes from default deny list). */
allow?: string[];
};
/** Closed session, sandbox, agent, and operator-scope policy for one named team role. */
type GatewayOperatorRoleDefinition = {
sessions: {
/** Maximum access to another person's sessions without explicit membership. */
others: "none" | "view" | "suggest" | "write";
};
/** Require sandbox isolation for newly created sessions, or inherit agent policy by default. */
sandbox?: "inherit" | "required";
/** Agent IDs available for session creation and runs, or all agents when set to "*". */
agents: "*" | string[];
/** Ceiling applied to the authenticated profile's granted operator scopes. */
scopes: OperatorScope[];
};
/** Optional named operator-role policies for Gateway deployments shared by a team. */
type GatewayOperatorRolesConfig = {
/** Required validated default for profiles without a valid assigned role. */
default?: string;
/** Closed capability bundles indexed by administrator-selected role names. */
definitions: Record<string, GatewayOperatorRoleDefinition>;
};
type GatewayConfig = {
/** Single multiplexed port for Gateway WS + HTTP (default: 18789). */
port?: number;
/**
* Explicit gateway mode. When set to "remote", local gateway start is disabled.
* When set to "local", the CLI may start the gateway locally.
*/
mode?: "local" | "remote";
/**
* Bind address policy for the Gateway WebSocket + Control UI HTTP server.
* - auto: Loopback (127.0.0.1) if available, else 0.0.0.0 (fallback to all interfaces)
* - lan: 0.0.0.0 (all interfaces, no fallback, current BYOH path is IPv4-only)
* - loopback: 127.0.0.1 (local-only)
* - tailnet: Tailnet IPv4 plus 127.0.0.1 if available, else loopback only
* - custom: User-specified IPv4 address (requires customBindHost); specific IPv4s also bind 127.0.0.1
* IPv6-only BYOH is not natively supported on this path today. Use an IPv4 sidecar or proxy.
* Default: loopback (127.0.0.1).
*/
bind?: GatewayBindMode;
/** Custom IPv4 address for bind="custom" mode. IPv6-only BYOH requires an IPv4 sidecar or proxy. */
customBindHost?: string;
/** Externally reachable HTTPS origin for Gateway callback routes; HTTP only on loopback. */
publicOrigin?: string;
controlUi?: GatewayControlUiConfig;
cliAgents?: GatewayCliAgentsConfig;
terminal?: GatewayTerminalConfig;
auth?: GatewayAuthConfig;
/** Optional profile-bound operator roles; omitted preserves legacy authorization. */
roles?: GatewayOperatorRolesConfig;
tailscale?: GatewayTailscaleConfig;
remote?: GatewayRemoteConfig;
reload?: GatewayReloadConfig;
tls?: GatewayTlsConfig;
http?: GatewayHttpConfig;
push?: GatewayPushConfig;
nodes?: GatewayNodesConfig;
/**
* IPs of trusted reverse proxies (e.g. Traefik, nginx). When a connection
* arrives from one of these IPs, the Gateway trusts `x-forwarded-for`
* to determine the client IP for local pairing and HTTP checks.
*/
trustedProxies?: string[];
/**
* Allow `x-real-ip` as a fallback only when `x-forwarded-for` is missing.
* Default: false (safer fail-closed behavior).
*/
allowRealIpFallback?: boolean;
/** Tool access restrictions for HTTP /tools/invoke endpoint. */
tools?: GatewayToolsConfig;
};
//#endregion
//#region src/config/types.installs.d.ts
/** Base persisted install record shared by plugin and skill install tracking. */
type InstallRecordBase = {
source: "npm" | "archive" | "path" | "clawhub" | "git";
spec?: string;
sourcePath?: string;
installPath?: string;
version?: string;
resolvedName?: string;
resolvedVersion?: string;
resolvedSpec?: string;
integrity?: string;
shasum?: string;
resolvedAt?: string;
installedAt?: string;
clawhubUrl?: string;
clawhubPackage?: string;
clawhubFamily?: "code-plugin" | "bundle-plugin";
clawhubChannel?: "official" | "community" | "private";
clawhubTrustDisposition?: "clean" | "review-recommended" | "review-required" | "blocked";
clawhubTrustScanStatus?: string;
clawhubTrustModerationState?: string;
clawhubTrustReasons?: string[];
clawhubTrustPending?: boolean;
clawhubTrustStale?: boolean;
clawhubTrustCheckedAt?: string;
clawhubTrustAcknowledgedAt?: string;
artifactKind?: "legacy-zip" | "npm-pack";
artifactFormat?: "zip" | "tgz";
npmIntegrity?: string;
npmShasum?: string;
npmTarballName?: string;
clawpackSha256?: string;
clawpackSpecVersion?: number;
clawpackManifestSha256?: string;
clawpackSize?: number;
gitUrl?: string;
gitRef?: string;
gitCommit?: string;
};
//#endregion
//#region src/config/types.hooks.d.ts
type HookMappingMatch = {
path?: string;
source?: string;
};
type HookMappingTransform = {
module: string;
export?: string;
};
type HookSessionMode = "isolated" | "persistent";
type HookMappingConfig = {
id?: string;
match?: HookMappingMatch;
action?: "wake" | "agent";
wakeMode?: "now" | "next-heartbeat";
name?: string;
/** Route this hook to a specific agent (unknown ids fall back to the default agent). */
agentId?: string;
sessionKey?: string;
/** Reuse the resolved session key across runs instead of creating a fresh run session. */
sessionMode?: HookSessionMode;
messageTemplate?: string;
textTemplate?: string;
/**
* Fan the mapping out over a top-level payload array: one action per element,
* with templates/transforms seeing a payload whose array holds only that
* element. Example: the gmail preset uses `forEach: "messages"` so batched
* pushes dispatch one isolated run per email.
*/
forEach?: string;
deliver?: boolean;
/** DANGEROUS: Disable external content safety wrapping for this hook. */
allowUnsafeExternalContent?: boolean;
/**
* "last" or any runtime channel id (including plugin channels).
* Validation against configured/registered channels happens in gateway hooks runtime.
*/
channel?: "last" | (string & {});
to?: string;
/** Override model for this hook (provider/model or alias). */
model?: string;
thinking?: string;
timeoutSeconds?: number;
transform?: HookMappingTransform;
};
type HooksGmailTailscaleMode = "off" | "serve" | "funnel";
type HooksGmailConfig = {
account?: string;
label?: string;
topic?: string;
subscription?: string;
pushToken?: string;
hookUrl?: string;
includeBody?: boolean;
maxBytes?: number;
renewEveryMinutes?: number;
/** DANGEROUS: Disable external content safety wrapping for Gmail hooks. */
allowUnsafeExternalContent?: boolean;
serve?: {
bind?: string;
port?: number;
path?: string;
};
tailscale?: {
mode?: HooksGmailTailscaleMode;
path?: string;
/** Optional tailscale serve/funnel target (port, host:port, or full URL). */
target?: string;
};
/** Optional model override for Gmail hook processing (provider/model or alias). */
model?: string;
/** Optional thinking level override for Gmail hook processing. */
thinking?: "off" | "minimal" | "low" | "medium" | "high";
};
type HookConfig = {
enabled?: boolean;
env?: Record<string, string>;
[key: string]: unknown;
};
type InternalHooksConfig = {
/** Enable hooks system */
enabled?: boolean;
/** Per-hook configuration overrides */
entries?: Record<string, HookConfig>;
/** Load configuration */
load?: {
/** Additional hook directories to scan */
extraDirs?: string[];
};
};
type HooksConfig = {
enabled?: boolean;
path?: string;
token?: string;
/**
* Default session key used for hook agent runs when no request/mapping session key is used.
* If omitted, OpenClaw generates `hook:<uuid>` per request.
*/
defaultSessionKey?: string;
/**
* Allow `sessionKey` from external `/hooks/agent` and `/hooks/wake` request payloads.
* Default: false.
*/
allowRequestSessionKey?: boolean;
/**
* Optional allowlist for explicit session keys (request + mapping). Example: ["hook:"].
* Empty/omitted means no prefix restriction.
*/
allowedSessionKeyPrefixes?: string[];
/**
* Restrict hook execution to these effective agent ids, including
* default-agent routing when `agentId` is omitted. Omit or include `*` to
* allow any agent. Set `[]` to deny all agent routing.
*/
allowedAgentIds?: string[];
presets?: string[];
transformsDir?: string;
mappings?: HookMappingConfig[];
gmail?: HooksGmailConfig;
/** Internal agent event hooks */
internal?: InternalHooksConfig;
};
//#endregion
//#region src/config/types.mcp.d.ts
type McpCodexToolApprovalMode = "auto" | "prompt" | "approve";
type McpServerCodexConfig = {
/** OpenClaw agent ids that should receive this server in Codex app-server threads. */
agents?: string[];
/** Codex MCP tool approval mode emitted as default_tools_approval_mode. */
defaultToolsApprovalMode?: McpCodexToolApprovalMode;
};
type McpServerToolFilterConfig = {
/**
* Exact MCP tool names or simple "*" globs to expose from this server.
*
* When omitted, all server tools remain eligible unless excluded.
*/
include?: string[];
/** Exact MCP tool names or simple "*" globs to hide from this server. */
exclude?: string[];
};
type McpServerConfig = {
/** Set false to keep the saved definition while excluding it from runtime/probe sessions. */
enabled?: boolean;
/** Stdio transport: command to spawn. */
command?: string;
/** Stdio transport: arguments for the command. */
args?: string[];
/** Environment variables passed to the server process (stdio only). */
env?: Record<string, string | number | boolean>;
/** Working directory for stdio server. */
cwd?: string;
/** HTTP transport: URL of the remote MCP server (http or https). */
url?: string;
/** Transport type ā "stdio" for command-bearing servers, "sse" or "streamable-http" for remote URLs. */
transport?: "stdio" | "sse" | "streamable-http";
/** HTTP transport: extra HTTP headers sent with every request. */
headers?: Record<string, string | number | boolean>;
/** Optional connection timeout in milliseconds. */
connectionTimeoutMs?: number;
/** Optional per-request timeout in milliseconds. */
requestTimeoutMs?: number;
/** Whether this server can safely handle concurrent tool calls. */
supportsParallelToolCalls?: boolean;
/** HTTP OAuth mode. Tokens are stored in OpenClaw state, not in config. */
auth?: "oauth";
/** Optional OAuth client metadata overrides for HTTP MCP servers. */
oauth?: {
/** Credential ownership for this server. Defaults to shared operator credentials. */
identity?: "shared" | "per-requester";
/** Refresh-capable auth profile used to inject the current bearer token. */
authProfileId?: string;
scope?: string;
redirectUrl?: string;
clientMetadataUrl?: string;
};
/** HTTP TLS verification, disabled only for explicitly trusted private endpoints. */
sslVerify?: boolean;
/** HTTP mutual TLS client certificate path. */
clientCert?: string;
/** HTTP mutual TLS client key path. */
clientKey?: string;
/** Optional per-server OpenClaw MCP tool selection. */
toolFilter?: McpServerToolFilterConfig;
/** Codex-specific projection controls for Codex app-server/runtime config. */
codex?: McpServerCodexConfig;
[key: string]: unknown;
};
type McpConfig = {
/** Named MCP server definitions managed by OpenClaw. */
servers?: Record<string, McpServerConfig>;
/** Opt-in MCP Apps rendering and app-to-server bridge. */
apps?: {
enabled?: boolean;
/** Dedicated public origin that proxies to the sandbox listener. */
sandboxOrigin?: string;
/** Dedicated listener port. Defaults to the Gateway port plus one. */
sandboxPort?: number;
};
};
//#endregion
//#region packages/llm-core/src/utils/diagnostics.d.ts
interface DiagnosticErrorInfo {
name?: string;
message: string;
stack?: string;
code?: string | number;
}
interface AssistantMessageDiagnostic {
type: string;
timestamp: number;
error?: DiagnosticErrorInfo;
details?: Record<string, unknown>;
}
//#endregion
//#region packages/llm-core/src/types.d.ts
/** Provider API families with first-class request/stream adapters in OpenClaw. */
type KnownApi = "openai-completions" | "mistral-conversations" | "openai-responses" | "azure-openai-responses" | "openai-chatgpt-responses" | "anthropic-messages" | "bedrock-converse-stream" | "google-generative-ai" | "google-vertex";
/** Provider API id; custom providers can use ids outside the built-in set. */
type Api = KnownApi | (string & {});
/** Provider id used for routing, diagnostics, and config lookups. */
type Provider = string;
/** Normalized reasoning-effort levels shared across provider-specific knobs. */
type ThinkingLevel = "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
/** Model thinking setting including explicit disabled state. */
type ModelThinkingLevel = "off" | ThinkingLevel;
/** Provider-specific values for normalized thinking levels. */
type ThinkingLevelMap = Partial<Record<ModelThinkingLevel, string | null>>;
/** Plain assistant/user text content block. */
interface TextContent {
type: "text";
text: string;
textSignature?: string;
}
/** Provider reasoning/thinking content block, including opaque replay signatures. */
interface ThinkingContent {
type: "thinking";
thinking: string;
thinkingSignature?: string;
/** When true, the thinking content was redacted by safety filters. The opaque
* encrypted payload is stored in `thinkingSignature` so it can be passed back
* to the API for multi-turn continuity. */
redacted?: boolean;
}
/** Opaque provider-owned state that must survive transcript replay without being rendered. */
interface ProviderReplayState {
v: 1;
type: string;
id?: string;
data: string;
replayIndex?: number;
provider: Provider;
api: Api;
model: string;
baseUrlHash?: string;
sessionHash?: string;
authProfileHash?: string;
}
/** Base64 image content block with MIME type metadata. */
interface ImageContent {
type: "image";
data: string;
mimeType: string;
}
/** Normalized assistant tool call emitted by providers or repaired from text. */
interface ToolCall {
/** The provider completed this call and permits generation to continue without its result. */
async?: true;
type: "toolCall";
id: string;
name: string;
arguments: Record<string, unknown>;
thoughtSignature?: string;
executionMode?: "sequential" | "parallel";
}
/** Normalized token and cost accounting for a provider response. */
interface Usage {
input: number;
output: number;
cacheRead: number;
cacheWrite: number;
/** Whether the provider reported a cache-read/write token split. */
cacheTelemetry?: {
state: "available" | "unavailable";
};
/** Subset of `cacheWrite` written with 1-hour retention when reported. */
cacheWrite1h?: number;
/** Exact context snapshot for the final provider iteration. */
contextUsage?: {
state: "available";
promptTokens: number;
totalTokens: number;
} | {
state: "unavailable";
};
totalTokens: number;
cost: {
input: number;
output: number;
cacheRead: number;
cacheWrite: number;
total: number;
/** Provenance for the recorded total cost; provider-billed totals are authoritative. */
totalOrigin?: "provider-billed";
};
}
/** Per-million-token rates for separately billed token buckets. */
type ModelCostRates = Pick<Usage["cost"], "input" | "output" | "cacheRead" | "cacheWrite">;
type RawPricingTier = ModelCostRates & {
/** `[start]` is an open-ended upper tier. */
range: [number, number] | [number];
};
type RawModelCostConfig = ModelCostRates & {
tieredPricing?: RawPricingTier[];
};
/** Normalized assistant stop reasons across text providers. */
type StopReason = "stop" | "length" | "toolUse" | "error" | "aborted";
/** User turn in a text-model conversation. */
interface UserMessage {
role: "user";
content: string | (TextContent | ImageContent)[];
timestamp: number;
/**
* Marks a user message carrying runtime context. Provider replay policy decides
* whether the carrier is transient or retained append-only; only retained
* carriers are stable prompt-cache anchors.
*/
runtimeContextCarrier?: boolean;
}
/** Assistant turn, including provider identity and final stop state. */
type AssistantDeliveryTtsFacts = {
tagged: true;
text?: string;
directives?: Array<{
provider?: string;
values: Record<string, string>;
}>;
};
interface AssistantMessage {
role: "assistant";
content: (TextContent | ThinkingContent | ToolCall)[];
openclawDelivery?: {
audioAsVoice?: true;
/** Exact media directives consumed by the managed-media transcript rewrite owner. */
mediaUrls?: string[];
replyToCurrent?: true;
replyToId?: string;
/** Provider text phase is unresolved until the assistant turn reaches terminal state. */
textPhaseRequiresTerminal?: true;
/** Parsed once at the assistant write boundary; delivery resolves policy from these facts. */
tts?: AssistantDeliveryTtsFacts;
};
api: Api;
provider: Provider;
model: string;
responseModel?: string;
responseId?: string;
providerReplay?: ProviderReplayState;
turnId?: string;
diagnostics?: AssistantMessageDiagnostic[];
usage: Usage;
stopReason: StopReason;
errorMessage?: string;
errorCode?: string;
errorType?: string;
errorBody?: string;
timestamp: number;
}
/** Tool result turn that answers a prior assistant tool call. */
interface ToolResultMessage<TDetails = unknown> {
role: "toolResult";
toolCallId: string;
toolName: string;
content: (TextContent | ImageContent)[];
details?: TDetails;
isError: boolean;
timestamp: number;
}
/** Any text-model conversation message supported by LLM core. */
type Message = UserMessage | AssistantMessage | ToolResultMessage;
/**
* Compatibility settings for OpenAI-compatible completions APIs.
* Use this to override URL-based auto-detection for custom providers.
*/
interface OpenAICompletionsCompat {
/** Whether the provider supports the `store` field. Default: auto-detected from URL. */
supportsStore?: boolean;
/** Whether the provider supports the `developer` role (vs `system`). Default: auto-detected from URL. */
supportsDeveloperRole?: boolean;
/** Whether the provider supports `reasoning_effort`. Default: auto-detected from URL. */
supportsReasoningEffort?: boolean;
/** Per-level reasoning effort overrides, e.g. map "off" to "low" for models that cannot disable thinking. */
reasoningEffortMap?: Record<string, string>;
/** Whether the provider supports `stream_options: { include_usage: true }` for token usage in streaming responses. Default: true. */
supportsUsageInStreaming?: boolean;
/** Which field to use for max tokens. Default: auto-detected from URL. */
maxTokensField?: "max_completion_tokens" | "max_tokens";
/** Whether tool results require the `name` field. Default: auto-detected from URL. */
requiresToolResultName?: boolean;
/** Whether a user message after tool results requires an assistant message in between. Default: auto-detected from URL. */
requiresAssistantAfterToolResult?: boolean;
/** Whether thinking blocks must be converted to text blocks with <thinking> delimiters. Default: auto-detected from URL. */
requiresThinkingAsText?: boolean;
/** Whether all replayed assistant messages must include an empty reasoning_content field when reasoning is enabled. Default: auto-detected from URL. */
requiresReasoningContentOnAssistantMessages?: boolean;
/** Format for reasoning/thinking parameter. "openai" uses reasoning_effort, "openrouter" uses reasoning: { effort }, "deepseek" uses thinking: { type } plus reasoning_effort, "together" uses reasoning: { enabled } plus reasoning_effort when supported, "zai" uses top-level enable_thinking: boolean, "qwen" uses top-level enable_thinking: boolean, and "qwen-chat-template" uses chat_template_kwargs.enable_thinking. Default: "openai". */
thinkingFormat?: "openai" | "openrouter" | "deepseek" | "together" | "zai" | "qwen" | "qwen-chat-template";
/** OpenRouter-specific routing preferences. Only used when baseUrl points to OpenRouter. */
openRouterRouting?: OpenRouterRouting;
/** Vercel AI Gateway routing preferences. Only used when baseUrl points to Vercel AI Gateway. */
vercelGatewayRouting?: VercelGatewayRouting;
/** Whether z.ai supports top-level `tool_stream: true` for streaming tool call deltas. Default: false. */
zaiToolStream?: boolean;
/** Whether the provider supports the `strict` field in tool definitions. Default: true. */
supportsStrictMode?: boolean;
/** Whether the provider supports JSON Schema through `response_format`. Default: false for unknown compatible endpoints. */
supportsJsonSchemaResponseFormat?: boolean;
/** Cache control convention for prompt caching. "anthropic" applies Anthropic-style `cache_control` markers to the system prompt, last tool definition, and last user/assistant text content. */
cacheControlFormat?: "anthropic";
/** Whether to send known session-affinity headers (`session_id`, `x-client-request-id`, `x-session-affinity`) from `options.sessionId` when caching is enabled. Default: false. */
sendSessionAffinityHeaders?: boolean;
/** Whether the provider supports OpenAI-style `prompt_cache_key`. Default: false for third-party completions providers. */
supportsPromptCacheKey?: boolean;
/** Whether the provider supports long prompt cache retention (`prompt_cache_retention: "24h"` or Anthropic-style `cache_control.ttl: "1h"`, depending on format). Default: true. */
supportsLongCacheRetention?: boolean;
}
/** Compatibility settings for OpenAI Responses APIs. */
interface OpenAIResponsesCompat {
/** Whether the provider supports the `developer` role (vs `system`). Default: true. */
supportsDeveloperRole?: boolean;
/** Whether to send reasoning effort settings. Defaults to the model's known capabilities. */
supportsReasoningEffort?: boolean;
/** Provider-native reasoning efforts accepted by the model. Overrides known model defaults. */
supportedReasoningEfforts?: string[];
/** Whether the model accepts the `temperature` parameter. Default: true. */
supportsTemperature?: boolean;
/** Whether to send the OpenAI `session_id` cache-affinity header from `options.sessionId` when caching is enabled. Default: true. */
sendSessionIdHeader?: boolean;
/** Whether the provider supports `prompt_cache_retention: "24h"`. Default: true. */
supportsLongCacheRetention?: boolean;
/** Whether the provider honors top-level `instructions`. Defaults to true only for verified native routes (OpenAI, xAI); every other route defaults to false and embeds the system prompt in `input` unless set true here after verifying against that endpoint. */
supportsInstructions?: boolean;
}
/** Compatibility settings for Anthropic Messages-compatible APIs. */
interface AnthropicMessagesCompat {
/**
* Whether the provider accepts per-tool `eager_input_streaming`.
* When false, the Anthropic provider omits `tools[].eager_input_streaming`
* and sends the legacy `fine-grained-tool-streaming-2025-05-14` beta header
* for tool-enabled requests.
* Default: true.
*/
supportsEagerToolInputStreaming?: boolean;
/** Whether the provider supports Anthropic long cache retention (`cache_control.ttl: "1h"`). Default: true. */
supportsLongCacheRetention?: boolean;
/**
* Whether to send the `x-session-affinity` header from `options.sessionId`
* when caching is enabled. Required for providers like Fireworks that use
* session affinity for prompt cache routing (requests to the same replica
* maximize cache hits).
* Default: false.
*/
sendSessionAffinityHeaders?: boolean;
/**
* Whether the provider supports Anthropic-style `cache_control` markers on
* tool definitions. When false, `cache_control` is omitted from tool params.
* Some Anthropic-compatible providers (e.g., Fireworks) do not support this
* field on tools and may reject or ignore it.
* Default: true.
*/
supportsCacheControlOnTools?: boolean;
/** Whether empty thinking signatures can be replayed as native thinking blocks. Default: false. */
allowEmptySignature?: boolean;
}
/**
* OpenRouter provider routing preferences.
* Controls which upstream providers OpenRouter routes requests to.
* Sent as the `provider` field in the OpenRouter API request body.
* @see https://openrouter.ai/docs/guides/routing/provider-selection
*/
interface OpenRouterRouting {
/** Whether to allow backup providers to serve requests. Default: true. */
allow_fallbacks?: boolean;
/** Whether to filter providers to only those that support all parameters in the request. Default: false. */
require_parameters?: boolean;
/** Data collection setting. "allow" (default): allow providers that may store/train on data. "deny": only use providers that don't collect user data. */
data_collection?: "deny" | "allow";
/** Whether to restrict routing to only ZDR (Zero Data Retention) endpoints. */
zdr?: boolean;
/** Whether to restrict routing to only models that allow text distillation. */
enforce_distillable_text?: boolean;
/** An ordered list of provider names/slugs to try in sequence, falling back to the next if unavailable. */
order?: string[];
/** List of provider names/slugs to exclusively allow for this request. */
only?: string[];
/** List of provider names/slugs to skip for this request. */
ignore?: string[];
/** A list of quantization levels to filter providers by (e.g., ["fp16", "bf16", "fp8", "fp6", "int8", "int4", "fp4", "fp32"]). */
quantizations?: string[];
/** Sorting strategy. Can be a string (e.g., "price", "throughput", "latency") or an object with `by` and `partition`. */
sort?: string | {
/** The sorting metric: "price", "throughput", "latency". */
by?: string;
/** Partitioning strategy: "model" (default) or "none". */
partition?: string | null;
};
/** Maximum price per million tokens (USD). */
max_price?: {
/** Price per million prompt tokens. */
prompt?: number | string;
/** Price per million completion tokens. */
completion?: number | string;
/** Price per image. */
image?: number | string;
/** Price per audio unit. */
audio?: number | string;
/** Price per request. */
request?: number | string;
};
/** Preferred minimum throughput (tokens/second). Can be a number (applies to p50) or an object with percentile-specific cutoffs. */
preferred_min_throughput?: number | {
/** Minimum tokens/second at the 50th percentile. */
p50?: number;
/** Minimum tokens/second at the 75th percentile. */
p75?: number;
/** Minimum tokens/second at the 90th percentile. */
p90?: number;
/** Minimum tokens/second at the 99th percentile. */
p99?: number;
};
/** Preferred maximum latency (seconds). Can be a number (applies to p50) or an object with percentile-specific cutoffs. */
preferred_max_latency?: number | {
/** Maximum latency in seconds at the 50th percentile. */
p50?: number;
/** Maximum latency in seconds at the 75th percentile. */
p75?: number;
/** Maximum latency in seconds at the 90th percentile. */
p90?: number;
/** Maximum latency in seconds at the 99th percentile. */
p99?: number;
};
}
/**
* Vercel AI Gateway routing preferences.
* Controls which upstream providers the gateway routes requests to.
* @see https://vercel.com/docs/ai-gateway/models-and-providers/provider-options
*/
interface VercelGatewayRouting {
/** List of provider slugs to exclusively use for this request (e.g., ["bedrock", "anthropic"]). */
only?: string[];
/** List of provider slugs to try in order (e.g., ["anthropic", "openai"]). */
order?: string[];
}
//#endregion
//#region src/config/types.models.d.ts
/** Provider API adapter ids accepted by model/provider config and schema generation. */
declare const MODEL_APIS: readonly ["openai-completions", "openai-responses", "openai-chatgpt-responses", "anthropic-messages", "google-generative-ai", "google-vertex", "github-copilot", "bedrock-converse-stream", "ollama", "azure-openai-responses"];
type ModelApi = (typeof MODEL_APIS)[number];
type SupportedOpenAICompatFields = Pick<OpenAICompletionsCompat, "supportsStore" | "supportsDeveloperRole" | "supportsReasoningEffort" | "reasoningEffortMap" | "supportsUsageInStreaming" | "supportsStrictMode" | "supportsJsonSchemaResponseFormat" | "maxTokensField" | "requiresToolResultName" | "requiresAssistantAfterToolResult" | "requiresThinkingAsText" | "requiresReasoningContentOnAssistantMessages" | "openRouterRouting" | "vercelGatewayRouting" | "zaiToolStream" | "cacheControlFormat" | "sendSessionAffinityHeaders" | "supportsLongCacheRetention">;
type SupportedOpenAIResponsesCompatFields = Pick<OpenAIResponsesCompat, "sendSessionIdHeader" | "supportsLongCacheRetention" | "supportsTemperature" | "supportsInstructions">;
type SupportedAnthropicMessagesCompatFields = Pick<AnthropicMessagesCompat, "supportsEagerToolInputStreaming" | "supportsLongCacheRetention">;
type SupportedThinkingFormat = NonNullable<OpenAICompletionsCompat["thinkingFormat"]> | "deepseek" | "openrouter" | "together";
/** Provider/model compatibility switches consumed by request builders and tool schema adapters. */
type ModelCompatConfig = SupportedOpenAICompatFields & SupportedOpenAIResponsesCompatFields & SupportedAnthropicMessagesCompatFields & {
/** Reasoning/thinking payload dialect for provider-compatible APIs. */
thinkingFormat?: SupportedThinkingFormat;
/** Provider-accepted reasoning effort labels. */
supportedReasoningEfforts?: string[];
/** Reasoning detail block types safe to expose in visible transcripts. */
visibleReasoningDetailTypes?: string[];
/** Whether this model supports tool/function calling. */
supportsTools?: boolean;
/** Code-mode tier consumed by `tools.codeMode.enabled: "auto"`; absent means "capable". */
codeMode?: "preferred" | "capable";
/** Whether provider accepts prompt-cache/session affinity keys. */
supportsPromptCacheKey?: boolean;
/** Whether all message parts must be coerced to plain strings. */
requiresStringContent?: boolean;
/** Whether unknown message payload keys must be stripped before requests. */
strictMessageKeys?: boolean;
/** Named tool-schema profile used by provider adapters. */
toolSchemaProfile?: string;
/** JSON Schema keywords rejected by this provider's tool schema validator. */
unsupportedToolSchemaKeywords?: string[];
/** Encoding expected for tool-call arguments in provider payloads. */
toolCallArgumentsEncoding?: string;
/** Whether OpenAI-style calls must be reshaped to Anthropic-compatible tool payloads. */
requiresOpenAiAnthropicToolPayload?: boolean;
};
type ModelImageInputConfig = {
/** Provider-documented maximum encoded image payload size. */
maxBytes?: number;
/** Provider-documented maximum accepted input pixels. */
maxPixels?: number;
/** Provider-documented maximum accepted width/height in pixels. */
maxSidePx?: number;
/** Preferred resize side for the default balanced compression policy. */
preferredSidePx?: number;
/** Token accounting style, used as documentation for provider-owned policy. */
tokenMode?: "tile" | "detail" | "provider";
};
type ModelMediaInputConfig = {
/** Image input limits and accounting hints for this model. */
image?: ModelImageInputConfig;
};
/** Authentication mode expected by a configured model provider. */
type ModelProviderAuthMode = "api-key" | "aws-sdk" | "oauth" | "token";
type ModelProviderLocalServiceConfig = {
/** Executable started before model requests are sent. */
command: string;
/** Arguments passed without shell expansion. */
args?: string[];
/** Working directory for the local service process. */
cwd?: string;
/** Environment variables added to the service process. */
env?: Record<string, string>;
/** Optional health endpoint polled before the provider is considered ready. */
healthUrl?: string;
/** Startup readiness timeout in milliseconds. */
readyTimeoutMs?: number;
/** Idle timeout in milliseconds before stopping the local service. */
idleStopMs?: number;
};
type ModelDefinitionConfig = {
/** Provider-facing model id. */
id: string;
/** Human-readable display name. */
name: string;
/** Optional API adapter override for this model. */
api?: ModelApi;
/** Optional base URL override for this model. */
baseUrl?: string;
/** Whether the model supports reasoning/thinking controls. */
reasoning: boolean;
/** Supported input modalities for routing and media-tool selection. */
input: Array<"text" | "image" | "video" | "audio">;
/** Token pricing in USD per million tokens. */
cost: RawModelCostConfig;
/** Provider/native maximum context window in tokens. */
contextWindow?: number;
/**
* Optional effective runtime cap used for compaction/session budgeting.
* Keeps provider/native contextWindow metadata intact while letting configs
* prefer a smaller practical window.
*/
contextTokens?: number;
/** Maximum completion/output token budget. */
maxTokens: number;
/** Maps OpenClaw thinking levels to provider/model-specific values. */
thinkingLevelMap?: ThinkingLevelMap;
/** Provider-specific request/runtime parameters passed through to provider plugins. */
params?: Record<string, unknown>;
/** Optional agent execution runtime override for this provider/model pair. */
agentRuntime?: AgentRuntimePolicyConfig;
/** Static headers merged into requests for this model. */
headers?: Record<string, string>;
/** Provider compatibility flags for payload shaping and feature gating. */
compat?: ModelCompatConfig;
/** Media input limits used by routing and preflight compression. */
mediaInput?: ModelMediaInputConfig;
/** Metadata source marker for models added by CLI/catalog tooling. */
metadataSource?: "models-add";
};
type ModelProviderConfig = {
/** Provider API base URL. */
baseUrl: string;
/** API key or secret reference for this provider. */
apiKey?: SecretInput;
/** Authentication mode used when resolving credentials for this provider. */
auth?: ModelProviderAuthMode;
/** Default API adapter for models under this provider. */
api?: ModelApi;
/** Provider-level default max output tokens. */
maxTokens?: number;
/** Provider request timeout in seconds. */
timeoutSeconds?: number;
/** Optional provider deployment/API region used by provider plugins that expose regional endpoints. */
region?: string;
injectNumCtxForOpenAICompat?: boolean;
/** Provider-specific runtime parameters interpreted by provider plugins. */
params?: Record<string, unknown>;
/** Optional default agent execution runtime for models under this provider. */
agentRuntime?: AgentRuntimePolicyConfig;
/** Optional local service to start before calling this provider. */
localService?: ModelProviderLocalServiceConfig;
/** Secret-bearing headers merged into provider requests. */
headers?: Record<string, SecretInput>;
/** Whether default Authorization header injection is enabled. */
authHeader?: boolean;
/** Provider request transport/retry overrides. */
request?: ConfiguredModelProviderRequest;
/** Model catalog entries exposed by this provider. */
models: ModelDefinitionConfig[];
};
type ModelCatalogRefreshConfig = {
/** Fetch model catalog updates from the hosted OpenClaw catalog. Default: true. */
enabled?: boolean;
/** Override the hosted catalog URL (HTTPS mirrors, or localhost HTTP for testing). */
url?: string;
};
type ModelsConfig = {
/** Merge provider config with bundled catalogs or replace bundled catalogs entirely. */
mode?: "merge" | "replace";
/** Configured provider catalog keyed by provider id. */
providers?: Record<string, ModelProviderConfig>;
/** Hosted model catalog refresh settings. */
catalogRefresh?: ModelCatalogRefreshConfig;
};
//#endregion
//#region src/config/types.node-host.d.ts
type NodeHostBrowserProxyConfig = {
/** Enable the browser proxy on the node host (default: true). */
enabled?: boolean;
/** Optional allowlist of profile names exposed via the proxy; when set, create/delete profile routes are blocked on the proxy surface. */
allowProfiles?: string[];
};
type NodeHostConfig = {
/** Sensitive native agent execution exposed by the headless node host. */
agentRuns?: {
claude?: {
/** Advertise approval-gated Claude CLI turns when the binary is installed. */
enabled?: boolean;
};
};
/** Full OpenClaw session hosting from Gateway-managed worker bundles. */
workerRuns?: {
/** Allow this paired node to host worker sessions (default: false). */
enabled?: boolean;
/** Integer worker slots (default: one per available CPU core). */
capacity?: number;
/** Worker process boundary: direct host execution or a container (default: none). */
isolation?: "none" | "container";
/** Optional Node 22+ container image override for isolated worker sessions. */
containerImage?: string;
};
/** Browser proxy settings for node hosts. */
browserProxy?: NodeHostBrowserProxyConfig;
/** MCP servers started and exposed by the headless node host. */
mcp?: {
servers?: Record<string, McpServerConfig>;
};
/** Skills published by the headless node host. */
skills?: {
/** Scan and publish ~/.openclaw/skills (default: true). */
enabled?: boolean;
};
};
//#endregion
//#region src/config/types.plugins.d.ts
type PluginEntryConfig = {
enabled?: boolean;
hooks?: {
/** Controls prompt mutation via before_prompt_build. */
allowPromptInjection?: boolean;
/**
* Controls access to raw conversation content from conversation hooks including
* before_agent_run, before_model_resolve, before_agent_reply, llm_input, llm_output,
* before_agent_finalize, and agent_end.
* Non-bundled plugins must opt in explicitly; bundled plugins stay allowed unless disabled.
*/
allowConversationAccess?: boolean;
/** Default timeout in milliseconds for this plugin's typed hooks. */
timeoutMs?: number;
/** Per typed-hook timeout overrides in milliseconds. */
timeouts?: Record<string, number>;
};
subagent?: {
/** Explicitly allow this plugin to request per-run provider/model overrides for subagent runs. */
allowModelOverride?: boolean;
/**
* Allowed override targets as canonical provider/model refs.
* Use "*" to explicitly allow any model for this plugin.
*/
allowedModels?: string[];
};
llm?: {
/** Explicitly allow this plugin to request a model override for api.runtime.llm.complete. */
allowModelOverride?: boolean;
/**
* Allowed override targets as canonical provider/model refs.
* Use "*" to explicitly allow any model for this plugin.
*/
allowedModels?: string[];
/**
* Allowed models for every completion, including host-resolved defaults and overrides.
* Use "*" to explicitly allow any model for this plugin.
*/
allowedCompletionModels?: string[];
/** Allow explicit auth-profile selection for isolated agent-runtime completions. */
allowAuthProfileOverride?: boolean;
/** Explicitly allow this plugin to run completions against a non-default agent id. */
allowAgentIdOverride?: boolean;
};
config?: Record<string, unknown>;
};
type PluginSlotsConfig = {
/** Select which plugin owns the memory slot ("none" disables memory plugins). */
memory?: string;
/** Select which plugin owns the context-engine slot. */
contextEngine?: string;
};
type PluginsLoadConfig = {
/** Additional plugin/extension paths to load. */
paths?: string[];
};
type PluginAcceptedDeclaredSurface = {
channels: string[];
providers: string[];
tools: string[];
contracts: string[];
hooks: string[];
mcpServers: string[];
cliCommands: string[];
cliBackends: string[];
skills: string[];
dangerousConfigFlags: string[];
};
type PluginInstallRecord = Omit<InstallRecordBase, "source"> & {
source: InstallRecordBase["source"] | "marketplace";
marketplaceName?: string;
marketplaceSource?: string;
marketplacePlugin?: string;
/** Sorted, manifest-declared capability surface accepted by the operator. */
acceptedSurface?: PluginAcceptedDeclaredSurface;
/** SHA-256 hex digest of the canonical accepted capability surface. */
acceptedSurfaceHash?: string;
/** ISO timestamp when the operator accepted this capability surface. */
acceptedSurfaceAt?: string;
/** Installed artifact integrity or Git commit the acceptance is anchored to. */
acceptedSurfaceIntegrity?: string;
};
type PluginsConfig = {
/** Enable or disable plugin loading. */
enabled?: boolean;
/** Optional plugin allowlist (plugin ids). */
allow?: string[];
/** Optional plugin denylist (plugin ids). */
deny?: string[];
load?: PluginsLoadConfig;
slots?: PluginSlotsConfig;
entries?: Record<string, PluginEntryConfig>;
/**
* Internal transient carrier for plugin install records during command flows.
* This is intentionally omitted from the config schema and must not be
* persisted to openclaw.json.
*/
installs?: Record<string, PluginInstallRecord>;
};
//#endregion
//#region src/config/types.telemetry.d.ts
type TelemetryConfig = {
/** Shares anonymous feature counts with the daily update check when explicitly enabled. */
enabled?: boolean;
/** ISO timestamp recording when the operator accepted or declined feature statistics. */
consentedAt?: string;
};
//#endregion
//#region src/config/zod-schema.proxy.d.ts
declare const ProxyConfigSchema: z.ZodOptional<z.ZodObject<{
enabled: z.ZodOptional<z.ZodBoolean>;
proxyUrl: z.ZodOptional<z.ZodURL>;
tls: z.ZodOptional<z.ZodObject<{
caFile: z.ZodOptional<z.ZodString>;
}, z.core.$strict>>;
loopbackMode: z.ZodOptional<z.ZodEnum<{
block: "block";
"gateway-only": "gateway-only";
proxy: "proxy";
}>>;
}, z.core.$strict>>;
type ProxyConfig = z.infer<typeof ProxyConfigSchema>;
//#endregion
//#region src/config/types.openclaw.d.ts
/** One persisted suppression for a known security audit finding. */
type SecurityAuditSuppression = {
/** Exact security audit check id to suppress. */
checkId: string;
/** Optional case-insensitive substring required in the finding title. */
titleIncludes?: string;
/** Optional case-insensitive substring required in the finding detail. */
detailIncludes?: string;
/** Operator rationale for accepting this standing finding. */
reason?: string;
};
type SecurityConfig = {
/** Security audit policy and accepted standing findings. */
audit?: {
/** Accepted security audit findings to omit from active summary/findings. */
suppressions?: SecurityAuditSuppression[];
};
installPolicy?: {
/**
* Enable operator-owned install policy. When true without an exec command,
* install/update attempts fail closed for supported targets.
*/
enabled?: boolean;
/** Supported install targets. Omit to cover every supported target. */
targets?: Array<"skill" | "plugin">;
/**
* Trusted local policy command. Transport intentionally mirrors exec
* SecretRef provider fields: absolute command, no shell, bounded output,
* explicit env allowlist, and secure path checks.
*/
exec?: {
source: "exec";
command: string;
args?: string[];
timeoutMs?: number;
noOutputTimeoutMs?: number;
maxOutputBytes?: number;
env?: Record<string, string>;
passEnv?: string[];
trustedDirs?: string[];
};
};
};
type SurfaceConfigEntry = {
/** Surface-specific silent reply policy for channels or UI integrations. */
silentReply?: SilentReplyPolicyShape;
};
/** Top-level OpenClaw config as read from user/project config files. */
type OpenClawConfig = {
/** @deprecated Doctor-only legacy input. */
audit?: AuditConfig;
/** JSON schema URL used by editors and generated config files. */
$schema?: string;
meta?: {
/** Last OpenClaw version that wrote this config. */
lastTouchedVersion?: string;
/** One-time doctor migrations already applied to this config. */
migrations?: {
modelPolicyAllowlist?: true;
};
};
/** Authentication provider/profile configuration. */
auth?: AuthConfig;
/** Named access groups used by channel/provider policy allowlists. */
accessGroups?: AccessGroupsConfig;
/** ACP integration settings. */
acp?: AcpConfig;
env?: {
/** Opt-in: import missing secrets from a login shell environment (interactive for Bash). */
shellEnv?: {
enabled?: boolean;
/** Timeout for the login shell exec (ms). Default: 15000. */
timeoutMs?: number;
};
/** Inline env vars to apply when not already present in the process env. */
vars?: Record<string, string>;
/** Sugar: allow env vars directly under env (string values only). */
[key: string]: string | Record<string, string> | {
enabled?: boolean;
timeoutMs?: number;
} | undefined;
};
wizard?: {
/** Guided-onboarding discovery consent: "full" scans silently, "guarded" asks first. */
accessMode?: "full" | "guarded";
/** Offer installed-application plugin and skill recommendations during onboarding. */
appRecommendations?: boolean;
lastRunAt?: string;
lastRunVersion?: string;
lastRunCommit?: string;
lastRunCommand?: string;
lastRunMode?: "local" | "remote";
localModelLeanAutoModel?: string;
securityAcknowledgedAt?: string;
};
/** Diagnostics, tracing, and stability debugging settings. */
diagnostics?: DiagnosticsConfig;
/** Log sink, level, rotation, and redaction settings. */
logging?: LoggingConfig;
/** Security audit suppressions and security policy settings. */
security?: SecurityConfig;
update?: {
/** Update channel for git + npm installs ("stable", "extended-stable", "beta", or "dev"). */
channel?: "stable" | "extended-stable" | "beta" | "dev";
/** Check for updates on gateway start; disabling also prevents anonymous update pings. */
checkOnStart?: boolean;
/** Core auto-update policy for package installs. */
auto?: {
/** Enable background auto-update checks and apply logic. Default: false. */
enabled?: boolean;
};
};
/** Explicit operator consent for anonymous feature statistics in the daily update check. */
telemetry?: TelemetryConfig;
/** Browser automation and browser plugin integration settings. */
browser?: BrowserConfig;
ui?: {
/** Accent color for OpenClaw UI chrome (hex). */
seamColor?: string;
/**
* Operator display preferences. Canonical config home so agents can
* change them through the approval gate and clients stay in sync; the
* Control UI mirrors them into browser storage for instant boot.
*/
prefs?: {
/** Control UI theme. */
theme?: "claw" | "knot" | "dash" | "absolutely" | "tide" | "beacon" | "phosphor" | "crt" | "manuscript" | "rose" | "miami" | "custom";
/** Light/dark preference. */
themeMode?: "light" | "dark" | "system";
/** User-selected Control UI accent color (#RRGGBB). */
accent?: string;
/** BCP 47 UI locale, e.g. "en" or "pt-BR". */
locale?: string;
/** Show model thinking output in chat. */
chatShowThinking?: boolean;
/** Show tool call cards in chat. */
chatShowToolCalls?: boolean;
/** Keep model commentary in Control UI transcripts after a run. */
chatPersistCommentary?: boolean;
/** Chat send shortcut: Enter sends, or modifier+Enter sends. */
chatSendShortcut?: "enter" | "modifier-enter";
/** Follow-up handling while a run is active; unset uses the server queue mode. */
chatFollowUpMode?: "steer" | "queue";
/** Ordered page and pinned-session entries shown in the Control UI sidebar. */
sidebarEntries?: string[];
};
};
/** Secret providers, defaults, and ref-resolution settings. */
secrets?: SecretsConfig;
/** Skill loading and bundled skill configuration. */
skills?: SkillsConfig;
/** Plugin registry/install/runtime configuration. */
plugins?: PluginsConfig;
/** Per-surface policy keyed by channel/UI/runtime surface id. */
surfaces?: Record<string, SurfaceConfigEntry>;
/** Model providers, model catalog, pricing, and catalog merge policy. */
models?: ModelsConfig;
/** Node-host pairing and remote command node settings. */
nodeHost?: NodeHostConfig;
/** Agent definitions, defaults, bindings, and runtime policy. */
agents?: AgentsConfig;
/** Global root for new managed worktrees. Defaults to <state-dir>/worktrees; accepts ~. */
worktreeRoot?: string;
/** Tool exposure, policy, web/media tools, exec, and code-mode settings. */
tools?: ToolsConfig;
/** Legacy/direct agent bindings used by runtime resolution. */
bindings?: AgentBinding[];
/** Broadcast command and delivery settings. */
broadcast?: BroadcastConfig;
attachments?: {
/** Optional retention window for persisted inbound media cleanup. */
ttlHours?: number;
};
/** Message formatting, delivery, and action settings. */
messages?: MessagesConfig;
/** Shared text-to-speech defaults. Agent and channel overrides layer over this config. */
tts?: TtsConfig;
/** Chat command settings. */
commands?: CommandsConfig;
/** Human approval workflow settings. */
approvals?: ApprovalsConfig;
/** Session keying, reset, maintenance, send-policy, and thread-binding settings. */
session?: SessionConfig;
/** Channel defaults, built-in channel sections, and plugin-owned channel config. */
channels?: ChannelsConfig;
/** Cron schedule and retention settings. */
cron?: CronConfig;
/** Transcript persistence and export settings. */
transcripts?: TranscriptsConfig;
/** Runtime hook registration and queue behavior. */
hooks?: HooksConfig;
/** Network discovery and service advertisement settings. */
discovery?: DiscoveryConfig;
/** Voice/talk mode configuration. */
talk?: TalkConfig;
/** Gateway server, auth, UI, node-pairing, and dispatch settings. */
gateway?: GatewayConfig;
/** Opt-in cloud-worker provider profiles. */
cloudWorkers?: CloudWorkersConfig;
/** Experimental desktop sources owned by the gateway host. */
desktop?: DesktopConfig;
/** Memory indexing/search configuration. */
memory?: MemoryConfig;
/** MCP client/server and Codex MCP approval configuration. */
mcp?: McpConfig;
/** Network-level SSRF protection via an operator-managed forward proxy. */
proxy?: ProxyConfig;
};
//#endregion
//#region src/runtime.d.ts
type RuntimeExitOptions = {
/** Route ANSI terminal-reset bytes away from structured stdout when needed. */
resetStream?: NodeJS.WriteStream;
};
type RuntimeEnv = {
log: (...args: unknown[]) => void;
error: (...args: unknown[]) => void;
/**
* Exit the process after restoring terminal state.
* Pass `resetStream` to route the ANSI reset sequence to a specific
* stream (e.g. stderr) when structured output on stdout must stay clean.
*/
exit: (code: number, opts?: RuntimeExitOptions) => void;
};
//#endregion
//#region src/config/io.runtime.d.ts
declare function loadConfig$1(options?: {
skipPluginValidation?: boolean;
pin?: boolean;
skipShellEnvFallback?: boolean;
}): OpenClawConfig;
//#endregion
//#region src/agents/run-timeout-attribution.d.ts
/** Agent run phases used when attributing timeout/cancellation sources. */
declare const AGENT_RUN_TIMEOUT_PHASES: readonly ["queue", "preflight", "provider", "post_turn", "gateway_draining"];
/** Timeout attribution phase for agent run lifecycle spans. */
type AgentRunTimeoutPhase = (typeof AGENT_RUN_TIMEOUT_PHASES)[number];
//#endregion
//#region src/agents/agent-run-terminal-outcome.types.d.ts
/** Wait status reported by agent run terminal wait paths. */
type AgentRunWaitStatus = "ok" | "error" | "timeout";
/** Normalized terminal reason for an agent run. */
type AgentRunTerminalReason = "completed" | "hard_timeout" | "timed_out" | "superseded" | "cancelled" | "aborted" | "blocked" | "abandoned" | "failed";
/** Normalized terminal outcome for an agent run. */
type AgentRunTerminalOutcome = {
reason: AgentRunTerminalReason;
status: AgentRunWaitStatus;
error?: string;
stopReason?: string;
livenessState?: string;
timeoutPhase?: AgentRunTimeoutPhase;
providerStarted?: boolean;
startedAt?: number;
endedAt?: number;
};
//#endregion
//#region src/audit/execution-identity-admission.d.ts
declare const ExecutionIdentityAdmissionTokenSchema: Type.TObject<{
tokenVersion: Type.TLiteral<1>;
contextId: Type.TString;
executionId: Type.TString;
runId: Type.TString;
createdAt: Type.TInteger;
}>;
type ExecutionIdentityAdmissionToken = Static<typeof ExecutionIdentityAdmissionTokenSchema>;
//#endregion
//#region src/channels/streaming.d.ts
type AgentPlanStepStatus = "pending" | "in_progress" | "completed";
type AgentPlanStep = {
step: string;
status: AgentPlanStepStatus;
};
//#endregion
//#region src/config/sessions/transcript-entry-anchor.d.ts
/** Immutable transcript identity issued by the SQLite append transaction. */
type TranscriptEntryAnchor = Readonly<{
agentId: string;
sessionId: string;
sessionKey: string;
storePath: string;
generation: string;
entryId: string;
rawSeq: number;
effectiveParentId: string | null;
activeMessagePosition: number;
idempotencyKey?: string;
}>;
/** Current user row bound to one recorder-owned logical turn. */
type TranscriptTurnAdmission = TranscriptEntryAnchor & Readonly<{
logicalTurnId: string;
role: "user";
}>;
//#endregion
//#region packages/media-core/src/constants.d.ts
/** Canonical media families used by attachment facts, routing, and MIME classification. */
type MediaKind = "image" | "audio" | "video" | "document" | "sticker" | "unknown";
//#endregion
//#region src/media/prompt-image-order.d.ts
/** Tracks whether prompt images stayed inline or were offloaded while preserving model order. */
type PromptImageOrderEntry = "inline" | "offloaded";
//#endregion
//#region src/media/media-facts.d.ts
/** One ordered runtime attachment; array position is its alignment identity. */
type MediaFact = {
path?: string;
url?: string;
contentType?: string;
kind?: MediaKind;
fileName?: string;
sizeBytes?: number;
durationMs?: number;
width?: number;
height?: number;
transcribed?: boolean;
messageId?: string;
workspaceDir?: string;
/** Internal proof that this exact fact was covered by a legacy staged projection. */
staged?: boolean;
hydrationSuppressed?: boolean;
};
//#endregion
//#region packages/gateway-protocol/src/session-agent-status.d.ts
declare const SESSION_AGENT_ATTENTION_ICON_IDS: readonly ["hand", "key", "alert", "flag", "lock", "hourglass"];
type SessionAgentAttentionIconId = (typeof SESSION_AGENT_ATTENTION_ICON_IDS)[number];
type SessionAgentStatus = {
note: string;
expiresAt: number;
attention?: SessionAgentAttentionIconId;
};
//#endregion
//#region packages/gateway-protocol/src/schema/skill-library.d.ts
declare const SkillLibrarySelectionSchema: Type.TObject<{
skillId: Type.TString;
revision: Type.TString;
/** Persisted command identity: library collisions never shadow workspace names. */
name: Type.TString;
ownerProfileId: Type.TUnion<[Type.TString, Type.TNull]>;
}>;
type SkillLibrarySelection = Static<typeof SkillLibrarySelectionSchema>;
//#endregion
//#region packages/gateway-protocol/src/schema/sessions-row.d.ts
declare const SessionRunStatusSchema: Type.TUnion<[Type.TLiteral<"queued">, Type.TLiteral<"running">, Type.TLiteral<"done">, Type.TLiteral<"failed">, Type.TLiteral<"killed">, Type.TLiteral<"timeout">]>;
declare const SessionEntryArchiveReasonSchema: Type.TUnion<[Type.TLiteral<"manual">, Type.TLiteral<"active-session-cap">, Type.TLiteral<"stale-dashboard">, Type.TLiteral<"restart-recovery">]>;
/** Stable Gateway session row fields; mutation envelopes may add null tombstones. */
declare const SessionRowSchema: Type.TObject<{
key: Type.TString;
sessionId: Type.TOptional<Type.TString>;
incognito: Type.TOptional<Type.TLiteral<true>>;
kind: Type.TUnion<[Type.TLiteral<"direct">, Type.TLiteral<"group">, Type.TLiteral<"global">, Type.TLiteral<"unknown">]>;
label: Type.TOptional<Type.TString>;
icon: Type.TOptional<Type.TString>;
/** Named sidebar tint from SESSION_COLOR_IDS; clients map names to theme hues. */
color: Type.TOptional<Type.TString>;
channelAvatarUrl: Type.TOptional<Type.TString>;
boardFace: Type.TOptional<Type.TUnion<[Type.TLiteral<"chat">, Type.TLiteral<"dashboard">]>>;
displayName: Type.TOptional<Type.TString>;
derivedTitle: Type.TOptional<Type.TString>;
lastMessagePreview: Type.TOptional<Type.TString>;
channel: Type.TOptional<Type.TString>;
/** Stable non-sensitive facts derived from the canonical session route. */
classification: Type.TOptional<Type.TString>;
agentId: Type.TOptional<Type.TString>;
accountId: Type.TOptional<Type.TString>;
peerKind: Type.TOptional<Type.TString>;
isMain: Type.TOptional<Type.TBoolean>;
isBackground: Type.TOptional<Type.TBoolean>;
chatType: Type.TOptional<Type.TUnion<[Type.TLiteral<"direct">, Type.TLiteral<"group">, Type.TLiteral<"channel">]>>;
updatedAt: Type.TOptional<Type.TUnion<[Type.TNumber, Type.TNull]>>;
archived: Type.TOptional<Type.TBoolean>;
archivedAt: Type.TOptional<Type.TNumber>;
archivedBy: Type.TOptional<Type.TObject<{
type: Type.TUnion<[Type.TLiteral<"human">, Type.TLiteral<"agent">, Type.TLiteral<"system">]>;
id: Type.TOptional<Type.TString>;
label: Type.TOptional<Type.TString>;
/** Durable profile avatar route; absent for actors without a stored profile avatar. */
avatarUrl: Type.TOptional<Type.TString>;
/** Display identity is separate from the actor fields used by ownership policy. */
identity: Type.TOptional<Type.TUnion<[Type.TObject<{
type: Type.TLiteral<"profile">;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"agent">;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"remote">;
pluginId: Type.TString;
domain: Type.TString;
idKind: Type.TString;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"observation">;
pluginId: Type.TUnion<[Type.TString, Type.TNull]>;
accountId: Type.TUnion<[Type.TString, Type.TNull]>;
senderKind: Type.TUnion<[Type.TLiteral<"human">, Type.TLiteral<"bot">, Type.TLiteral<"unknown">]>;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"legacy">;
actorType: Type.TString;
source: Type.TUnion<[Type.TString, Type.TNull]>;
id: Type.TString;
}>]>>;
}>>;
archiveReason: Type.TOptional<Type.TUnion<[Type.TLiteral<"manual">, Type.TLiteral<"active-session-cap">, Type.TLiteral<"stale-dashboard">, Type.TLiteral<"restart-recovery">]>>;
pinned: Type.TOptional<Type.TBoolean>;
pinnedAt: Type.TOptional<Type.TNumber>;
unread: Type.TOptional<Type.TBoolean>;
lastReadAt: Type.TOptional<Type.TNumber>;
markedUnreadAt: Type.TOptional<Type.TNumber>;
lastActivityAt: Type.TOptional<Type.TNumber>;
lastInteractionAt: Type.TOptional<Type.TNumber>;
status: Type.TOptional<Type.TUnion<[Type.TLiteral<"queued">, Type.TLiteral<"running">, Type.TLiteral<"done">, Type.TLiteral<"failed">, Type.TLiteral<"killed">, Type.TLiteral<"timeout">]>>;
lastRunError: Type.TOptional<Type.TString>;
/** Exact run that produced the latest terminal lifecycle projection. */
lastRunId: Type.TOptional<Type.TString>;
restartRecoveryStatus: Type.TOptional<Type.TLiteral<"tombstoned">>;
activeLeafEntryId: Type.TOptional<Type.TUnion<[Type.TString, Type.TNull]>>;
spawnedBy: Type.TOptional<Type.TString>;
parentSessionKey: Type.TOptional<Type.TString>;
controlOwnerSessionKey: Type.TOptional<Type.TString>;
childSessions: Type.TOptional<Type.TArray<Type.TString>>;
forkedFromParent: Type.TOptional<Type.TBoolean>;
spawnDepth: Type.TOptional<Type.TNumber>;
subagentRole: Type.TOptional<Type.TUnion<[Type.TLiteral<"orchestrator">, Type.TLiteral<"leaf">]>>;
subagentControlScope: Type.TOptional<Type.TUnion<[Type.TLiteral<"children">, Type.TLiteral<"none">]>>;
swarmGroupId: Type.TOptional<Type.TString>;
worktree: Type.TOptional<Type.TObject<{
id: Type.TString;
branch: Type.TString;
repoRoot: Type.TString;
}>>;
execNode: Type.TOptional<Type.TString>;
execCwd: Type.TOptional<Type.TString>;
spawnedWorkspaceDir: Type.TOptional<Type.TString>;
spawnedCwd: Type.TOptional<Type.TString>;
permissionMode: Type.TOptional<Type.TUnion<[Type.TLiteral<"read-only">, Type.TLiteral<"guarded">, Type.TLiteral<"workspace">, Type.TLiteral<"full">]>>;
permissionModePending: Type.TOptional<Type.TBoolean>;
sessionRoot: Type.TOptional<Type.TString>;
createdVia: Type.TOptional<Type.TUnion<[Type.TLiteral<"operator">, Type.TLiteral<"spawn">, Type.TLiteral<"channel">, Type.TLiteral<"cron">, Type.TLiteral<"talk">, Type.TLiteral<"run">, Type.TLiteral<"plugin">, Type.TLiteral<"internal">]>>;
createdActor: Type.TOptional<Type.TObject<{
type: Type.TUnion<[Type.TLiteral<"human">, Type.TLiteral<"agent">, Type.TLiteral<"system">]>;
id: Type.TOptional<Type.TString>;
label: Type.TOptional<Type.TString>;
/** Durable profile avatar route; absent for actors without a stored profile avatar. */
avatarUrl: Type.TOptional<Type.TString>;
/** Display identity is separate from the actor fields used by ownership policy. */
identity: Type.TOptional<Type.TUnion<[Type.TObject<{
type: Type.TLiteral<"profile">;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"agent">;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"remote">;
pluginId: Type.TString;
domain: Type.TString;
idKind: Type.TString;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"observation">;
pluginId: Type.TUnion<[Type.TString, Type.TNull]>;
accountId: Type.TUnion<[Type.TString, Type.TNull]>;
senderKind: Type.TUnion<[Type.TLiteral<"human">, Type.TLiteral<"bot">, Type.TLiteral<"unknown">]>;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"legacy">;
actorType: Type.TString;
source: Type.TUnion<[Type.TString, Type.TNull]>;
id: Type.TString;
}>]>>;
}>>;
owner: Type.TOptional<Type.TObject<{
actor: Type.TObject<{
type: Type.TUnion<[Type.TLiteral<"human">, Type.TLiteral<"agent">, Type.TLiteral<"system">]>;
id: Type.TOptional<Type.TString>;
label: Type.TOptional<Type.TString>;
/** Durable profile avatar route; absent for actors without a stored profile avatar. */
avatarUrl: Type.TOptional<Type.TString>;
/** Display identity is separate from the actor fields used by ownership policy. */
identity: Type.TOptional<Type.TUnion<[Type.TObject<{
type: Type.TLiteral<"profile">;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"agent">;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"remote">;
pluginId: Type.TString;
domain: Type.TString;
idKind: Type.TString;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"observation">;
pluginId: Type.TUnion<[Type.TString, Type.TNull]>;
accountId: Type.TUnion<[Type.TString, Type.TNull]>;
senderKind: Type.TUnion<[Type.TLiteral<"human">, Type.TLiteral<"bot">, Type.TLiteral<"unknown">]>;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"legacy">;
actorType: Type.TString;
source: Type.TUnion<[Type.TString, Type.TNull]>;
id: Type.TString;
}>]>>;
}>;
assignedBy: Type.TOptional<Type.TObject<{
type: Type.TUnion<[Type.TLiteral<"human">, Type.TLiteral<"agent">, Type.TLiteral<"system">]>;
id: Type.TOptional<Type.TString>;
label: Type.TOptional<Type.TString>;
/** Durable profile avatar route; absent for actors without a stored profile avatar. */
avatarUrl: Type.TOptional<Type.TString>;
/** Display identity is separate from the actor fields used by ownership policy. */
identity: Type.TOptional<Type.TUnion<[Type.TObject<{
type: Type.TLiteral<"profile">;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"agent">;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"remote">;
pluginId: Type.TString;
domain: Type.TString;
idKind: Type.TString;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"observation">;
pluginId: Type.TUnion<[Type.TString, Type.TNull]>;
accountId: Type.TUnion<[Type.TString, Type.TNull]>;
senderKind: Type.TUnion<[Type.TLiteral<"human">, Type.TLiteral<"bot">, Type.TLiteral<"unknown">]>;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"legacy">;
actorType: Type.TString;
source: Type.TUnion<[Type.TString, Type.TNull]>;
id: Type.TString;
}>]>>;
}>>;
assignedAt: Type.TOptional<Type.TNumber>;
}>>;
participants: Type.TOptional<Type.TArray<Type.TObject<{
identity: Type.TUnion<[Type.TObject<{
type: Type.TLiteral<"profile">;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"agent">;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"remote">;
pluginId: Type.TString;
domain: Type.TString;
idKind: Type.TString;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"observation">;
pluginId: Type.TUnion<[Type.TString, Type.TNull]>;
accountId: Type.TUnion<[Type.TString, Type.TNull]>;
senderKind: Type.TUnion<[Type.TLiteral<"human">, Type.TLiteral<"bot">, Type.TLiteral<"unknown">]>;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"legacy">;
actorType: Type.TString;
source: Type.TUnion<[Type.TString, Type.TNull]>;
id: Type.TString;
}>]>;
label: Type.TOptional<Type.TString>;
avatarUrl: Type.TOptional<Type.TString>;
}>>>;
expandedParticipants: Type.TOptional<Type.TArray<Type.TObject<{
identity: Type.TUnion<[Type.TObject<{
type: Type.TLiteral<"profile">;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"agent">;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"remote">;
pluginId: Type.TString;
domain: Type.TString;
idKind: Type.TString;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"observation">;
pluginId: Type.TUnion<[Type.TString, Type.TNull]>;
accountId: Type.TUnion<[Type.TString, Type.TNull]>;
senderKind: Type.TUnion<[Type.TLiteral<"human">, Type.TLiteral<"bot">, Type.TLiteral<"unknown">]>;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"legacy">;
actorType: Type.TString;
source: Type.TUnion<[Type.TString, Type.TNull]>;
id: Type.TString;
}>]>;
label: Type.TOptional<Type.TString>;
avatarUrl: Type.TOptional<Type.TString>;
}>>>;
participantCount: Type.TOptional<Type.TInteger>;
visibility: Type.TOptional<Type.TUnion<[Type.TLiteral<"shared">, Type.TLiteral<"read-only">, Type.TLiteral<"suggest">, Type.TLiteral<"draft">]>>;
sharingRole: Type.TOptional<Type.TUnion<[Type.TLiteral<"admin">, Type.TLiteral<"owner">, Type.TLiteral<"member">, Type.TLiteral<"viewer">]>>;
createdAt: Type.TOptional<Type.TNumber>;
forkSource: Type.TOptional<Type.TObject<{
sessionKey: Type.TString;
sessionId: Type.TString;
entryId: Type.TOptional<Type.TString>;
}>>;
previousSessionId: Type.TOptional<Type.TString>;
inputTokens: Type.TOptional<Type.TNumber>;
outputTokens: Type.TOptional<Type.TNumber>;
totalTokens: Type.TOptional<Type.TNumber>;
totalTokensFresh: Type.TOptional<Type.TBoolean>;
contextTokens: Type.TOptional<Type.TNumber>;
estimatedCostUsd: Type.TOptional<Type.TNumber>;
model: Type.TOptional<Type.TString>;
modelProvider: Type.TOptional<Type.TString>;
/** Runtime model serving this session while it differs from the selected model. */
activeModel: Type.TOptional<Type.TString>;
activeModelProvider: Type.TOptional<Type.TString>;
/** Persisted override provenance; null means inherited, omission means not projected. */
modelOverrideSource: Type.TOptional<Type.TUnion<[Type.TLiteral<"user">, Type.TLiteral<"auto">, Type.TNull]>>;
toolOverrides: Type.TOptional<Type.TObject<{
mcpServers: Type.TOptional<Type.TRecord<"^.*$", Type.TBoolean>>;
mcpToolsDeny: Type.TOptional<Type.TRecord<"^.*$", Type.TArray<Type.TString>>>;
skills: Type.TOptional<Type.TRecord<"^.*$", Type.TBoolean>>;
webSearch: Type.TOptional<Type.TBoolean>;
}>>;
}>;
type SessionRunStatus = Static<typeof SessionRunStatusSchema>;
type SessionRow = Static<typeof SessionRowSchema>;
type SessionEntryArchiveReason = Static<typeof SessionEntryArchiveReasonSchema>;
//#endregion
//#region packages/gateway-protocol/src/schema/session-participant.d.ts
declare const SessionParticipantSchema: Type.TObject<{
identity: Type.TUnion<[Type.TObject<{
type: Type.TLiteral<"profile">;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"agent">;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"remote">;
pluginId: Type.TString;
domain: Type.TString;
idKind: Type.TString;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"observation">;
pluginId: Type.TUnion<[Type.TString, Type.TNull]>;
accountId: Type.TUnion<[Type.TString, Type.TNull]>;
senderKind: Type.TUnion<[Type.TLiteral<"human">, Type.TLiteral<"bot">, Type.TLiteral<"unknown">]>;
id: Type.TString;
}>, Type.TObject<{
type: Type.TLiteral<"legacy">;
actorType: Type.TString;
source: Type.TUnion<[Type.TString, Type.TNull]>;
id: Type.TString;
}>]>;
label: Type.TOptional<Type.TString>;
avatarUrl: Type.TOptional<Type.TString>;
}>;
type SessionParticipant = Static<typeof SessionParticipantSchema>;
//#endregion
//#region packages/gateway-protocol/src/schema/sessions-goal.d.ts
declare const SessionGoalSchema: Type.TObject<{
schemaVersion: Type.TLiteral<1>;
id: Type.TString;
objective: Type.TString;
status: Type.TUnion<[Type.TLiteral<"active">, Type.TLiteral<"paused">, Type.TLiteral<"blocked">, Type.TLiteral<"usage_limited">, Type.TLiteral<"budget_limited">, Type.TLiteral<"complete">]>;
createdAt: Type.TNumber;
updatedAt: Type.TNumber;
tokenStart: Type.TNumber;
tokenStartFresh: Type.TOptional<Type.TBoolean>;
tokensUsed: Type.TNumber;
tokenBudget: Type.TOptional<Type.TNumber>;
continuationTurns: Type.TNumber;
lastStatusNote: Type.TOptional<Type.TString>;
pausedAt: Type.TOptional<Type.TNumber>;
blockedAt: Type.TOptional<Type.TNumber>;
completedAt: Type.TOptional<Type.TNumber>;
usageLimitedAt: Type.TOptional<Type.TNumber>;
budgetLimitedAt: Type.TOptional<Type.TNumber>;
}>;
type SessionGoal = Static<typeof SessionGoalSchema>;
declare const SessionsGoalMutationResultSchema: Type.TObject<{
operationId: Type.TString;
action: Type.TUnion<[Type.TLiteral<"start">, Type.TLiteral<"edit">, Type.TLiteral<"pause">, Type.TLiteral<"resume">, Type.TLiteral<"complete">, Type.TLiteral<"block">, Type.TLiteral<"clear">]>;
sessionId: Type.TString;
goalId: Type.TString;
goal: Type.TOptional<Type.TObject<{
schemaVersion: Type.TLiteral<1>;
id: Type.TString;
objective: Type.TString;
status: Type.TUnion<[Type.TLiteral<"active">, Type.TLiteral<"paused">, Type.TLiteral<"blocked">, Type.TLiteral<"usage_limited">, Type.TLiteral<"budget_limited">, Type.TLiteral<"complete">]>;
createdAt: Type.TNumber;
updatedAt: Type.TNumber;
tokenStart: Type.TNumber;
tokenStartFresh: Type.TOptional<Type.TBoolean>;
tokensUsed: Type.TNumber;
tokenBudget: Type.TOptional<Type.TNumber>;
continuationTurns: Type.TNumber;
lastStatusNote: Type.TOptional<Type.TString>;
pausedAt: Type.TOptional<Type.TNumber>;
blockedAt: Type.TOptional<Type.TNumber>;
completedAt: Type.TOptional<Type.TNumber>;
usageLimitedAt: Type.TOptional<Type.TNumber>;
budgetLimitedAt: Type.TOptional<Type.TNumber>;
}>>;
runId: Type.TOptional<Type.TString>;
replayed: Type.TOptional<Type.TLiteral<true>>;
status: Type.TUnion<[Type.TLiteral<"started">, Type.TLiteral<"updated">, Type.TLiteral<"cleared">]>;
}>;
type SessionsGoalMutationResult = Static<typeof SessionsGoalMutationResultSchema>;
//#endregion
//#region packages/gateway-protocol/src/schema/human-mentions.d.ts
/** Explicit selections bound to UTF-16 offsets in the submitted message text. */
declare const HumanMentionSchema: Type.TObject<{
profileId: Type.TString;
start: Type.TInteger;
end: Type.TInteger;
}>;
type HumanMention = Static<typeof HumanMentionSchema>;
//#endregion
//#region packages/gateway-protocol/src/schema/sessions.d.ts
/** Live session status judgment broadcast to subscribed operator clients. */
declare const SessionObserverDigestSchema: Type.TObject<{
sessionKey: Type.TString;
agentId: Type.TOptional<Type.TString>;
runId: Type.TOptional<Type.TString>;
revision: Type.TInteger;
updatedAt: Type.TInteger;
headline: Type.TString;
assessment: Type.TOptional<Type.TString>;
health: Type.TUnion<[Type.TLiteral<"on-track">, Type.TLiteral<"grinding">, Type.TLiteral<"stuck">, Type.TLiteral<"waiting-on-user">, Type.TLiteral<"wrapping-up">, Type.TLiteral<"done">, Type.TLiteral<"failed">]>;
planProgress: Type.TOptional<Type.TObject<{
completed: Type.TInteger;
total: Type.TInteger;
}>>;
}>;
type SessionObserverDigest = Static<typeof SessionObserverDigestSchema>;
//#endregion
//#region packages/agent-core/src/types.d.ts
interface BashExecutionMessage {
/** Harness role for shell command transcripts. */
role: "bashExecution";
/** Command line that was executed. */
command: string;
/** Captured command output, usually already truncated for context. */
output: string;
/** Process exit code when the command reached process exit. */
exitCode: number | undefined;
/** True when the command was interrupted before normal completion. */
cancelled: boolean;
/** True when output was shortened for transcript/context storage. */
truncated: boolean;
/** Optional path containing the complete output when truncation occurred. */
fullOutputPath?: string;
/** Millisecond timestamp for transcript ordering. */
timestamp: number;
/** Exclude this command transcript from model context while keeping it in session history. */
excludeFromContext?: boolean;
}
interface CustomMessage<T = unknown> {
/** Harness role for application-defined transcript content. */
role: "custom";
/** Application-defined discriminator for rendering or handling this message. */
customType: string;
/** Content replayed into model context when this message is included. */
content: string | (TextContent | ImageContent)[];
/** Whether UI surfaces should display this message. */
display: boolean;
/** Keep display-only application activity out of future model context. */
excludeFromContext?: boolean;
/** Optional application-specific metadata. */
details?: T;
/** Millisecond timestamp for transcript ordering. */
timestamp: number;
}
interface BranchSummaryMessage {
/** Harness role for summaries produced when returning from another branch. */
role: "branchSummary";
/** Summary text inserted back into model context. */
summary: string;
/** Entry id of the branch root or source leaf being summarized. */
fromId: string;
/** Millisecond timestamp for transcript ordering. */
timestamp: number;
}
interface CompactionSummaryMessage {
/** Harness role for summaries that replace compacted transcript history. */
role: "compactionSummary";
/** Summary text inserted back into model context. */
summary: string;
/** Estimated context tokens before compaction. */
tokensBefore: number;
/** Timestamp may be numeric in memory or string when loaded from older persisted rows. */
timestamp: number | string;
/** Optional estimated context tokens after compaction. */
tokensAfter?: number;
/** Optional first retained entry id from the compaction range. */
firstKeptEntryId?: string;
/** Optional implementation-specific compaction metadata. */
details?: unknown;
}
/**
* Extensible interface for custom app and harness messages.
* Apps can extend via declaration merging.
*/
interface CustomAgentMessages {
bashExecution: BashExecutionMessage;
custom: CustomMessage;
branchSummary: BranchSummaryMessage;
compactionSummary: CompactionSummaryMessage;
}
/**
* AgentMessage: Union of LLM messages + custom messages.
* This abstraction allows apps to add custom message types while maintaining
* type safety and compatibility with the base LLM messages.
*/
type AgentMessage = Message | CustomAgentMessages[keyof CustomAgentMessages];
//#endregion
//#region src/config/sessions/goals-operations.types.d.ts
type SessionGoalOperationResult = Omit<SessionsGoalMutationResult, "replayed">;
type SessionTranscriptTurnMutationResult = {
result: SessionGoalOperationResult;
replayed: boolean;
};
//#endregion
//#region src/auto-reply/source-reply-delivery-mode.types.d.ts
/** Per-turn authority for automatic replies versus explicit message-tool sends. */
type SourceReplyDeliveryMode = "automatic" | "message_tool_only";
//#endregion
//#region src/plugin-sdk/channel-route.d.ts
/** Coarse chat shape used when a channel can distinguish direct, group, and broadcast targets. */
type ChannelRouteChatType = "direct" | "group" | "channel";
/** Provider-specific thread kind carried with normalized channel routes. */
type ChannelRouteThreadKind = "topic" | "thread" | "reply";
/** Describes which runtime surface supplied a channel route thread id. */
type ChannelRouteThreadSource = "explicit" | "target" | "session" | "turn";
/** Normalized channel route used for comparison, binding, and dedupe helpers. */
type ChannelRouteRef = {
/** Lowercase channel id such as `slack`, `telegram`, or `discord`. */
channel?: string;
/** Normalized account/profile id when a channel supports multiple accounts. */
accountId?: string;
target?: {
/** Canonical destination id used for route equality and delivery. */
to: string;
/** Original destination text when provider target grammar differs from the canonical id. */
rawTo?: string;
/** Coarse destination shape used by channels with different direct/group/broadcast rules. */
chatType?: ChannelRouteChatType;
};
thread?: {
/** Provider thread/topic/root id; strings are preserved when providers use opaque ids. */
id: string | number;
/** Provider-specific thread family for channels that distinguish topics, replies, and threads. */
kind?: ChannelRouteThreadKind;
/** Runtime source that supplied the thread id, used when callers need route provenance. */
source?: ChannelRouteThreadSource;
};
};
/** Loose route input accepted at SDK boundaries before normalization. */
type ChannelRouteRefInput = {
/** Raw channel id; normalized to lowercase. */
channel?: unknown;
/** Raw account/profile id; normalized with account-id rules when string. */
accountId?: unknown;
/** Raw destination id before trimming and route-key normalization. */
to?: unknown;
/** Provider-specific target text retained when different from `to`. */
rawTo?: unknown;
/** Coarse destination shape supplied by channels that distinguish target kinds. */
chatType?: ChannelRouteChatType;
/** Raw provider thread/topic/root id before route-key normalization. */
threadId?: unknown;
/** Provider-specific thread family carried with the normalized thread id. */
threadKind?: ChannelRouteThreadKind;
/** Runtime surface that supplied the thread id. */
threadSource?: ChannelRouteThreadSource;
};
/** Raw outbound target input shape used by helpers that do not need thread metadata source. */
type ChannelRouteTargetInput = Pick<ChannelRouteRefInput, "channel" | "accountId" | "to" | "rawTo" | "chatType" | "threadId">;
//#endregion
//#region src/utils/delivery-context.types.d.ts
/** Deferred outbound delivery intent attached to a session or task. */
type DeliveryIntentRef = {
/** Stable queue/work item id. */
id: string;
/** Intent family; currently scoped to outbound queue delivery. */
kind: "outbound_queue";
/** Whether queueing is mandatory or best-effort for this delivery. */
queuePolicy?: "required" | "best_effort";
};
/** Canonical channel delivery target shared by sessions, cron, tasks, and plugins. */
type DeliveryContext = Pick<ChannelRouteTargetInput, "accountId" | "channel" | "threadId" | "to"> & {
/** Channel/plugin id that owns the delivery target. */
channel?: string;
/** Channel-local destination id, preserved with channel-specific casing. */
to?: string;
/** Optional channel account/workspace id. */
accountId?: string;
/** Optional thread/topic id nested under `to`. */
threadId?: string | number;
/** Optional queued-delivery intent associated with this context. */
deliveryIntent?: DeliveryIntentRef;
};
//#endregion
//#region src/config/sessions/restart-recovery-types.d.ts
type RestartRecoveryBeforeAgentReplyState = "admitted" | "pending" | "continue" | "handled-silent" | "handled-reply" | "handled-unrecoverable";
type RestartRecoveryTerminalDeliveryEvidenceResult = {
/** The terminal result was captured even when it contained no visible or delivery evidence. */
captured?: true;
payloads?: Array<{
mediaUrls?: string[];
visible?: boolean;
}>;
payloadsTruncated?: true;
deliveryStatus?: {
status: "failed" | "partial_failed" | "sent" | "suppressed";
errorMessage?: string;
payloadOutcomes?: Array<{
index: number;
status: "failed" | "sent" | "suppressed";
sentBeforeError?: boolean;
}>;
};
messagingToolSentTargets?: Array<{
provider?: string;
accountId?: string;
to?: string;
threadId?: string;
threadImplicit?: boolean;
threadSuppressed?: boolean;
mediaUrls?: string[];
visible?: boolean;
}>;
messagingToolSentTargetsTruncated?: true;
/** Aggregate committed sends were not all represented by route-checkable target records. */
messagingToolAggregateEvidenceUnaccounted?: true;
/** The terminal run reported a committed effect that makes fresh replay unsafe. */
restartUnsafeSideEffectsDetected?: true;
};
type RestartRecoveryTerminalDeliveryEvidence = RestartRecoveryTerminalDeliveryEvidenceResult & {
runId: string;
};
/** Durable ownership and idempotency state for gateway restart recovery. */
type SessionRestartRecoveryState = {
restartRecoveryBeforeAgentReplyState?: RestartRecoveryBeforeAgentReplyState;
/** Durable pre/post boundary around the terminal external send. */
restartRecoveryDeliveryReceiptState?: "terminal-pending" | "delivered-terminal";
/** Exact agent tool call whose terminal external send owns the receipt. */
restartRecoveryDeliveryToolCallId?: string;
restartRecoveryDeliveryContext?: DeliveryContext;
/** Exact host-owned media allowlist for a generated-media recovery run. */
restartRecoveryDeliveryMediaUrls?: string[];
/** Keeps the message tool absent while a generated-media recovery run is resumed. */
restartRecoveryDisableMessageTool?: true;
/** Suppresses visible text when a recovery attempt repairs only missing media. */
restartRecoverySuppressTextDelivery?: true;
restartRecoveryDeliveryRequestFingerprint?: string;
restartRecoveryDeliveryRunId?: string;
restartRecoveryDeliverySourceRunId?: string;
restartRecoveryRequesterAccountId?: string;
restartRecoveryRequesterSenderId?: string;
restartRecoverySameChannelThreadRequired?: true;
restartRecoverySourceIngress?: "channel" | "control-ui" | "internal";
restartRecoverySourceReplyDeliveryMode?: SourceReplyDeliveryMode;
restartRecoveryTerminalDeliveryEvidence?: RestartRecoveryTerminalDeliveryEvidence[];
restartRecoveryTerminalRunIds?: string[];
};
//#endregion
//#region src/config/sessions/session-diff-baseline-capture.d.ts
type SessionDiffBaselineCapture = {
version: 1;
captureId: string;
status: "pending" | "unavailable";
};
//#endregion
//#region packages/acp-core/src/types.d.ts
type SessionAcpIdentitySource = "ensure" | "status" | "event";
type SessionAcpIdentityState = "pending" | "resolved";
type SessionAcpIdentity = {
/** Pending identities may expose provisional ids; resolved identities are safe for resume output. */
state: SessionAcpIdentityState;
acpxRecordId?: string;
acpxSessionId?: string;
agentSessionId?: string;
/** Runtime lifecycle point that last supplied the identity fields. */
source: SessionAcpIdentitySource;
lastUpdatedAt: number;
};
type AcpSessionRuntimeOptions = {
/**
* ACP runtime mode set via session/set_mode (for example: "plan", "normal", "auto").
*/
runtimeMode?: string;
/** ACP runtime config option: model id. */
model?: string;
/** ACP runtime config option: thinking/reasoning effort. */
thinking?: string;
/** Working directory override for ACP session turns. */
cwd?: string;
/** ACP runtime config option: permission profile id. */
permissionProfile?: string;
/** ACP runtime config option: per-turn timeout in seconds. */
timeoutSeconds?: number;
/** Backend-specific option bag mapped through session/set_config_option. */
backendExtras?: Record<string, string>;
};
type SessionAcpMeta = {
backend: string;
agent: string;
runtimeSessionName: string;
/** Canonical backend/agent ids used for resume hints and thread/status details. */
identity?: SessionAcpIdentity;
mode: "persistent" | "oneshot";
runtimeOptions?: AcpSessionRuntimeOptions;
cwd?: string;
state: "idle" | "running" | "error";
lastActivityAt: number;
lastError?: string;
};
//#endregion
//#region src/cron/scheduled-tool-policy.d.ts
/** Closed, server-authored origin of an account-scoped scheduled tool cap. */
type CronScheduledToolCallerOrigin = {
kind: "external";
channel: string;
} | {
kind: "local";
} | {
kind: "unknown";
};
/**
* Restrict-only execution target for a job's exec grant, captured from a
* creator surface whose only exec capability was host-pinned. New pinned jobs
* persist this as part of a grant-coupled envelope; unmarked legacy jobs keep
* baseline exec behavior.
*/
type CronToolsAllowExecTarget = {
version: 1;
host: "gateway";
/** Mandatory approval floor inherited from the captured creator surface. */
ask?: "always";
};
/** Persisted proof that this job was created with an exact exec restriction. */
type CronToolsAllowExecTargetRequirement = {
version: 1;
target: CronToolsAllowExecTarget;
grantIndex: number;
recoveryRequired?: never;
} | {
version: 1;
target?: never;
recoveryRequired: true;
};
/** Server-authored provenance for a persisted scheduled tool-cap authority envelope. */
type CronScheduledToolPolicy = {
version: 1;
mode: "trusted";
ownerSessionKey?: never;
ownerAccountId?: never;
} | {
version: 1;
mode: "account";
ownerSessionKey: string;
ownerAccountId: string;
};
//#endregion
//#region src/shared/session-types.d.ts
/** Per-session Control UI face preference carried by session list rows. */
type SessionBoardFace = "chat" | "dashboard";
//#endregion
//#region src/config/sessions/main-session-recovery.types.d.ts
type MainRestartRecoveryState = {
/** Stable identity for one interrupted episode; prevents clear-and-rewedge ABA matches. */
cycleId: string;
/** Monotonic identity for observations within the current recovery cycle. */
revision: number;
/** Attempts charged when their reservation is persisted, before dispatch. */
chargedAttempts: number;
/** Last attempt observed starting a backend turn; later startup failures get a fresh budget. */
startedAttempt?: number;
/** Private safe token for one recovered outer turn; raw identity refs never enter session state. */
executionIdentity?: {
tokenVersion: 1;
contextId: string;
executionId: string;
runId: string;
createdAt: number;
};
reservation?: {
runId: string;
attempt: number;
lifecycleGeneration: string;
};
foregroundClaims?: {
lifecycleGeneration: string;
tokens: string[];
/** Run identity for claims that have crossed the actual agent-run boundary. */
runIdsByClaimId?: Record<string, string>;
};
tombstone?: {
reason: string;
/** Durable successor returned when an explicit rollover request is retried. */
recoveredSessionId?: string;
recoveredSessionKey?: string;
};
};
//#endregion
//#region src/config/sessions/pending-final-delivery-types.d.ts
type PendingFinalDeliveryState = {
createdAt: number;
context?: DeliveryContext;
intentId?: string;
deliveries?: Array<{
id: string;
state: "prepared" | "queued" | "delivered" | "suppressed" | "unknown";
}>;
} & ({
kind: "replayable";
text: string;
} | {
kind: "transport-only";
});
/**
* Owed user-visible notice that a final's delivery outcome stayed unknown.
* Settled unknown custody records the debt here; the next same-route turn
* sends it once, so an ambiguous loss never ends silently.
*/
type PendingDeliveryNoticeState = {
createdAt: number;
context: DeliveryContext;
intentId: string;
state: "owed" | "unresolved" | "acknowledged";
};
//#endregion
//#region src/security/external-content-source.d.ts
/** Hook session sources that carry untrusted external content into agent prompts. */
type HookExternalContentSource = "email" | "gmail" | "webhook";
//#endregion
//#region src/config/sessions/session-entry-provenance.d.ts
/** Kept aligned with SessionStateActorType (src/sessions/session-state-event-kinds.ts); not imported to avoid layering config/sessions onto src/sessions. */
type SessionActor = {
type: "human" | "agent" | "system";
id?: string;
label?: string;
};
/** Only trusted creation owners may stamp a Gateway profile namespace. */
type SessionCreatedActor = SessionActor & ({
type: "human";
source: "profile" | "channel" | "unknown";
} | {
type: "agent" | "system";
});
type SessionOwnerAssignment = {
actor: SessionActor;
assignedBy?: SessionActor;
assignedAt?: number;
};
type SessionCreatedVia = "operator" | "spawn" | "channel" | "cron" | "talk" | "run" | "plugin" | "internal";
type SessionEntryProvenance = {
/** Plugin id that owns this session through a trusted runtime creation seam. */
pluginOwnerId?: string;
/** External hook source that has contributed content to this transcript. */
hookExternalContentSource?: HookExternalContentSource;
};
//#endregion
//#region src/config/sessions/session-model-fallback.d.ts
type AgentPatchedSessionModelFallback = {
prevModel: string;
prevProvider: string;
prevModelOverride?: string;
prevProviderOverride?: string;
prevModelOverrideSource?: "auto" | "user";
prevModelOverrideRouteResolution?: "resolved";
prevModelOverrideFallbackOriginProvider?: string;
prevModelOverrideFallbackOriginModel?: string;
prevAuthProfileOverride?: string;
prevAuthProfileOverrideSource?: "auto" | "user" | "user-link";
prevAuthProfileOverrideCompactionCount?: number;
prevContextWindow?: string;
prevThinkingLevel?: string;
lastValidatedPatchTs?: number;
ts: number;
source: "agent-patch";
};
//#endregion
//#region src/agents/sessions/source-info.d.ts
type SourceScope = "user" | "project" | "temporary";
type SourceOrigin = "package" | "top-level";
interface SourceInfo {
path: string;
source: string;
scope: SourceScope;
origin: SourceOrigin;
baseDir?: string;
}
//#endregion
//#region src/skills/loading/skill-contract.d.ts
interface Skill {
name: string;
/** Human-readable title from the first Markdown H1, falling back to the identifier. */
displayName?: string;
description: string;
/** Additional loading guidance rendered with the location in full and compact catalogs. */
locationNote?: string;
/** Prepared instructions for transferred bundles or non-filesystem locators such as node://. */
readContent?: string;
filePath: string;
baseDir: string;
sourceInfo: SourceInfo;
disableModelInvocation: boolean;
source: string;
}
//#endregion
//#region src/config/sessions/session-prompt-types.d.ts
type SessionSkillPromptRef = {
version: 1;
algorithm: "sha256";
hash: string;
bytes: number;
};
type SessionSkillSnapshot = {
librarySelections?: SkillLibrarySelection[];
prompt: string;
/** Persisted stores may replace large duplicate prompts with a content-addressed blob ref. */
promptRef?: SessionSkillPromptRef;
skills: Array<{
name: string;
primaryEnv?: string;
requiredEnv?: string[];
}>;
/** Normalized agent-level filter used to build this snapshot; undefined means unrestricted. */
skillFilter?: string[];
/** Effective node-exec eligibility used to select connected node-hosted skills. */
nodeSkillsEligibility?: {
canExec: boolean;
node?: string;
};
/**
* Runtime-only, never persisted. Carries the full parsed Skill[] (including
* each SKILL.md body) so the embedded runner can skip a workspace skill
* scan within a turn. Persistence projections strip it before committing
* session state. On a cold session resume this is undefined and
* src/skills/runtime/embedded-run-entries.ts rebuilds it from disk.
*/
resolvedSkills?: Skill[];
version?: number;
};
//#endregion
//#region src/config/sessions/session-system-prompt-report.d.ts
/** Persisted size and provenance summary for one assembled system prompt. */
type SessionSystemPromptReport = {
source: "run" | "estimate";
generatedAt: number;
sessionId?: string;
sessionKey?: string;
provider?: string;
model?: string;
workspaceDir?: string;
bootstrapMaxChars?: number;
bootstrapTotalMaxChars?: number;
bootstrapTruncation?: {
warningMode?: "off" | "once" | "always";
warningShown?: boolean;
promptWarningSignature?: string;
warningSignaturesSeen?: string[];
truncatedFiles?: number;
nearLimitFiles?: number;
totalNearLimit?: boolean;
};
sandbox?: {
mode?: string;
sandboxed?: boolean;
};
systemPrompt: {
chars: number;
projectContextChars: number;
nonProjectContextChars: number;
hash?: string;
};
currentTurn?: {
kind?: "user_request" | "room_event";
promptChars: number;
runtimeContextChars: number;
modelOnlyPromptChars?: number;
};
injectedWorkspaceFiles: Array<{
name: string;
path: string;
missing: boolean;
rawChars: number;
} & ({
injectionStatus?: "verified";
injectedChars: number;
truncated: boolean;
} | {
injectionStatus: "native_unverified";
injectedChars: null;
truncated: null;
})>;
skills: {
promptChars: number;
hash?: string;
entries: Array<{
name: string;
blockChars: number;
}>;
};
tools: {
listChars: number;
schemaChars: number;
entries: Array<{
name: string;
summaryChars: number;
summaryHash?: string;
schemaChars: number;
schemaHash?: string;
propertiesCount?: number | null;
}>;
};
};
//#endregion
//#region src/config/sessions/session-tool-overrides.d.ts
type SessionToolOverrides = {
mcpServers?: Record<string, boolean>;
mcpToolsDeny?: Record<string, string[]>;
skills?: Record<string, boolean>;
webSearch?: boolean;
};
//#endregion
//#region src/config/sessions/types.d.ts
type SessionScope = "per-sender" | "global";
type SessionChatType = ChatType;
declare const SESSION_TOTAL_TOKENS_VERSION: 1;
type SessionVisibility = "shared" | "read-only" | "suggest" | "draft";
type SessionOrigin = {
label?: string;
provider?: string;
surface?: string;
chatType?: SessionChatType;
from?: string;
to?: string;
nativeChannelId?: string;
nativeDirectUserId?: string;
avatar?: string;
accountId?: string;
threadId?: string | number;
};
/** Canonical persisted delivery ownership for one session. */
type SessionDeliveryState = {
kind: "none";
} | {
kind: "internal";
} | {
kind: "external";
route: ChannelRouteRef;
context: DeliveryContext;
origin: SessionOrigin;
};
/**
* Durable transcript-repair record: an assistant final that was delivered to
* the user but could not be appended to the canonical transcript. Kept
* separate from `pendingFinalDelivery` so transport-replay cleanup never drops
* the only copy of the missing assistant turn.
*/
type PendingTranscriptRepairState = {
/** Stable identity for retry-safe transcript insertion. */
id: string;
text: string;
provider?: string;
model?: string;
createdAt: number;
};
type FallbackNoticeState = {
kind: "active";
selectedModel: string;
activeModel: string;
reason?: string;
};
type MemoryFlushState = {
kind: "succeeded";
compactionCount: number;
} | {
kind: "failed";
compactionCount?: number;
failureCount: number;
};
type CliSessionReseedReceipt = {
version: 1;
promptHash: string;
localSessionId: string;
userTurnDisposition: "persisted" | "omitted";
};
type SessionDiffBaseline = {
version: 1;
sessionId: string;
root: string;
files: Array<{
path: string;
fingerprint: string;
}>;
/** Some checkout entries could not be fingerprinted without exceeding diff safety caps. */
truncated?: true;
};
type CliSessionBinding = {
sessionId: string;
/** Last successful assistant boundary accepted by the backend's resume contract. */
resumeCheckpointId?: string;
/** Resume with the backend's fork argument once, then clear before process start. */
forkNextResume?: true;
/** Trust an explicitly attached CLI session even when auth, prompt, or MCP fingerprints drift. */
forceReuse?: boolean;
authProfileId?: string;
authEpoch?: string;
authEpochVersion?: number;
extraSystemPromptHash?: string;
messageToolPolicyHash?: string;
promptToolNamesHash?: string;
cwdHash?: string;
mcpConfigHash?: string;
mcpResumeHash?: string;
/** Identifies one synthetic history prompt and the trusted local handling of its user turn. */
reseedReceipt?: CliSessionReseedReceipt;
};
type AcpSessionBinding = {
acpBackendId: string;
acpAgentId: string;
agentSessionId: string;
};
type SessionCompactionCheckpointReason = "manual" | "auto-threshold" | "overflow-retry" | "timeout-retry";
type SessionCompactionTranscriptReference = {
sessionId: string;
sessionFile?: string;
leafId?: string;
entryId?: string;
};
type SessionCompactionCheckpoint = {
checkpointId: string;
sessionKey: string;
sessionId: string;
createdAt: number;
reason: SessionCompactionCheckpointReason;
tokensBefore?: number;
tokensAfter?: number;
tokensVersion?: typeof SESSION_TOTAL_TOKENS_VERSION;
summary?: string;
firstKeptEntryId?: string;
preCompaction: SessionCompactionTranscriptReference;
postCompaction: SessionCompactionTranscriptReference;
};
type SessionContextBudgetStatusRoute = "fits" | "compact_only" | "truncate_tool_results_only" | "compact_then_truncate";
type SessionContextBudgetStatus = {
schemaVersion: 1;
source: "pre-prompt-estimate";
updatedAt: number;
provider: string;
model: string;
route: SessionContextBudgetStatusRoute;
shouldCompact: boolean;
estimatedPromptTokens: number;
contextTokenBudget: number;
promptBudgetBeforeReserve: number;
reserveTokens: number;
effectiveReserveTokens: number;
remainingPromptBudgetTokens: number;
overflowTokens: number;
toolResultReducibleChars: number;
messageCount: number;
unwindowedMessageCount: number;
sessionId?: string;
};
type AmbientTranscriptWatermark = {
sessionId: string;
messageId: string;
timestampMs?: number;
updatedAt: number;
};
type SessionPluginDebugEntry = {
pluginId: string;
lines: string[];
};
type SessionPluginJsonValue = string | number | boolean | null | SessionPluginJsonValue[] | {
[key: string]: SessionPluginJsonValue;
};
type SessionPluginNextTurnInjection = {
id: string;
pluginId: string;
pluginName?: string;
text: string;
idempotencyKey?: string;
placement: "prepend_context" | "append_context";
ttlMs?: number;
createdAt: number;
metadata?: SessionPluginJsonValue;
};
type SubagentRecoveryState = {
/** Consecutive accepted automatic orphan-recovery resumes in the rapid re-wedge window. */
automaticAttempts?: number;
/** Timestamp (ms) of the latest accepted automatic orphan-recovery resume. */
lastAttemptAt?: number;
/** Registry run id that triggered the latest automatic orphan-recovery resume. */
lastRunId?: string;
/** Timestamp (ms) when automatic recovery was tombstoned for this session. */
wedgedAt?: number;
/** Human-readable reason automatic recovery was tombstoned. */
wedgedReason?: string;
};
type LaneExecutionState = "active" | "draining" | "suspended" | "resuming" | "circuit_open" | "failed_handoff";
interface QuotaSuspension {
schemaVersion: 1;
suspendedAt: number;
reason: "quota_exhausted" | "manual" | "circuit_open";
failedProvider: string;
failedModel: string;
/** Recovery briefing text injected into the next attempt when state === "resuming". */
summary?: string;
/** Opaque pointer to an external snapshot blob (path/key); not the briefing text itself. */
snapshotRef?: string;
/**
* @deprecated Lane suspension was removed; nothing writes this anymore. Kept only to
* hold the shipped SDK surface stable; drop at the next surface window.
*/
laneId?: string;
expectedResumeBy?: number;
state: LaneExecutionState;
}
type RestartRecoveryRun = {
runId: string;
lifecycleGeneration: string;
};
type SessionEntryCore = SessionRestartRecoveryState & SessionEntryProvenance & Pick<SessionRow, "permissionMode" | "sessionRoot"> & {
/** Collaboration mode. Missing legacy values are equivalent to "shared". */
visibility?: SessionVisibility;
/**
* Last delivered heartbeat payload (used to suppress duplicate heartbeat notifications).
* Stored on the main session entry.
*/
lastHeartbeatText?: string;
/** Timestamp (ms) when lastHeartbeatText was delivered. */
lastHeartbeatSentAt?: number;
/**
* Base session key for heartbeat-created isolated sessions.
* When present, `<base>:heartbeat` is a synthetic isolated session rather than
* a real user/session-scoped key that merely happens to end with `:heartbeat`.
*/
heartbeatIsolatedBaseSessionKey?: string;
/** Legacy heartbeat task timestamps consumed and cleared only by doctor migration. */
heartbeatTaskState?: Record<string, number>;
/** Plugin-owned session state, grouped by plugin id then extension namespace. */
pluginExtensions?: Record<string, Record<string, SessionPluginJsonValue>>;
/** Trusted session initialization is incomplete; all work admission stays blocked. */
initializationPending?: true;
/** Top-level SessionEntry mirror slots owned by plugin session extensions. */
pluginExtensionSlotKeys?: Record<string, Record<string, string>>;
/** Durable one-shot prompt additions drained before the next agent turn. */
pluginNextTurnInjections?: Record<string, SessionPluginNextTurnInjection[]>;
sessionId: string;
updatedAt: number;
/** Process-lifetime session whose entry and transcript stay in the in-memory agent database. */
incognito?: true;
/** Opaque owner revision used to reject stale lifecycle mutations. */
lifecycleRevision?: string;
/** Timestamp (ms) when the session was archived from active session lists. */
archivedAt?: number;
/** Actor that archived the session; cleared when the session is restored. */
archivedBy?: SessionActor;
/** Stable lifecycle cause; absent values are legacy archives and remain manually protected. */
archiveReason?: SessionEntryArchiveReason;
/** Timestamp (ms) when the session was pinned for quick access. */
pinnedAt?: number;
/** Timestamp (ms) when an operator client last marked the session read. */
lastReadAt?: number;
/** Agent-declared sidebar presence; projection drops it after expiresAt. */
agentStatus?: SessionAgentStatus;
/** Latest utility-model status judgment for idle session status surfaces. */
observerDigest?: SessionObserverDigest;
/** Timestamp (ms) when an operator explicitly marked the session unread; cleared on read. */
markedUnreadAt?: number;
/** Timestamp (ms) of the latest completed agent run; metadata patches do not update it. */
lastActivityAt?: number;
/** Parent session key that spawned this session (used for sandbox session-tool scoping). */
spawnedBy?: string;
/** Immutable session key authorized to receive this child's completion handoff. */
completionOwnerSessionKey?: string;
/** Workspace inherited by spawned sessions and reused on later turns for the same child session. */
spawnedWorkspaceDir?: string;
/** Task working directory inherited by spawned sessions and reused on later turns. */
spawnedCwd?: string;
/** Content-free fingerprints for checkout changes that predate this session generation. */
sessionDiffBaseline?: SessionDiffBaseline;
/**
* Managed worktree bound to this session; set with spawnedCwd at worktree
* creation and cleared together when a plain New Chat detaches the checkout.
*/
worktree?: {
id: string;
branch: string;
repoRoot: string;
/** Durable skill workspace prepared when this session runs from a managed worktree. */
canonicalWorkspaceDir?: string;
};
/** Project registry id selected when this logical session node was created. */
projectId?: string;
/** Explicit parent session linkage for dashboard-created child sessions. */
parentSessionKey?: string;
/** Exact parent incarnation captured when this child was created. */
parentSessionId?: string;
/** How this session node came to exist; written once and retained across sessionId rotations. */
createdVia?: SessionCreatedVia;
/** Actor that caused node creation, with an optional profile, session, or sender id; written once. */
createdActor?: SessionCreatedActor;
/** Creation-only sandbox requirement; existing unstamped sessions always remain unstamped. */
sandbox?: "required";
/** Mutable responsibility, projected from SQLite; absent means createdActor owns the session. */
owner?: SessionOwnerAssignment;
/** Retained identities, projected from the participant table before display truncation. */
participants?: SessionParticipant[];
/** Raw retained identity count, including the owner, for admission-bound coverage. */
participantCount?: number;
/** Node creation time (ms); unlike sessionStartedAt, survives sessionId rotations. */
createdAt?: number;
/** Exact source generation and optional cut entry for an actual transcript-copy fork. */
forkSource?: {
sessionKey: string;
sessionId: string;
entryId?: string;
};
/** Session id of the prior transcript generation under this same session key. */
previousSessionId?: string;
/** Thread parent-seeding settled marker; also set when seeding is deliberately skipped. */
forkedFromParent?: boolean;
/** Subagent spawn depth (0 = main, 1 = sub-agent, 2 = sub-sub-agent). */
spawnDepth?: number;
/** Explicit role assigned at spawn time for subagent tool policy/control decisions. */
subagentRole?: "orchestrator" | "leaf";
/** Explicit control scope assigned at spawn time for subagent control decisions. */
subagentControlScope?: "children" | "none";
/** Version of the requester tool-policy snapshot captured when this child was spawned. */
inheritedToolPolicyVersion?: 1;
/** Session-scoped tool deny entries inherited from the caller that created this session. */
inheritedToolDeny?: string[];
/** Session-scoped tool allow entries inherited from the caller that created this session. */
inheritedToolAllow?: string[];
systemSent?: boolean;
abortedLastRun?: boolean;
/** Interrupted run generations whose late lifecycle events must be ignored. */
restartRecoveryRuns?: RestartRecoveryRun[];
/** Keeps automatic restart recovery limited to replay-safe tools until the run terminates. */
restartRecoveryForceSafeTools?: true;
/** Durable guard state for automatic subagent orphan recovery. */
subagentRecovery?: SubagentRecoveryState;
/** Quota cascade protection and state-aware failover status. */
quotaSuspension?: QuotaSuspension;
/** Core-owned durable goal state for this thread/session. */
goal?: SessionGoal;
/** Timestamp (ms) when the current sessionId first became active. */
sessionStartedAt?: number;
/** Stable usage lineage key for transcript-backed rollups across sessionId rotations. */
usageFamilyKey?: string;
/** Session ids known to belong to this usage lineage, including archived predecessors. */
usageFamilySessionIds?: string[];
/** Timestamp (ms) of the last user/channel interaction that should extend idle lifetime. */
lastInteractionAt?: number;
/** Stable first-run start time for subagent sessions, persisted after completion. */
startedAt?: number;
/** Latest completed run end time for subagent sessions, persisted after completion. */
endedAt?: number;
/** Accumulated runtime across subagent follow-up runs, persisted after completion. */
runtimeMs?: number;
/** Final persisted subagent run status, used after in-memory run archival. */
status?: SessionRunStatus;
/** Compact user-facing reason for the latest failed or timed-out run. */
lastRunError?: string;
/**
* Session-level stop cutoff captured when /stop is received.
* Messages at/before this boundary are skipped to avoid replaying
* queued pre-stop backlog.
*/
abortCutoffMessageSid?: string;
/** Epoch ms cutoff paired with abortCutoffMessageSid when available. */
abortCutoffTimestamp?: number;
chatType?: SessionChatType;
contextWindow?: string;
thinkingLevel?: string;
/**
* Exact isolated-cron continuation policy. Only hidden `:run:` session rows
* carry this while detached generated-media work may still wake the run.
*/
cronRunContinuation?: {
lifecycleRevision: string;
phase: "running" | "ready" | "continuing";
/** True only after this row's session changes were projected to the stable cron row. */
basePersisted?: boolean;
ownerRunId?: string;
/** Gateway lifecycle generation that owns a continuing claim. */
ownerLifecycleGeneration?: string;
/** CLI backend whose native session must exist before media work detaches. */
cliExecutionProvider?: string;
toolsAllow?: string[];
toolsAllowIsDefault?: boolean;
/** Exact server-stamped authority provenance copied from the owning cron job. */
scheduledToolPolicy?: CronScheduledToolPolicy;
/** Restrict-only exec pin copied from the owning cron job's cap. */
toolsAllowExecTarget?: CronToolsAllowExecTarget;
/** Expected pin copied with the cap so detached continuation loss fails closed. */
toolsAllowExecTargetRequirement?: CronToolsAllowExecTargetRequirement;
/** Store-private origin paired with an account scheduled-tool policy. */
scheduledToolCallerOrigin?: CronScheduledToolCallerOrigin;
cliSessionBindingFacts?: {
extraSystemPromptStatic?: string;
sourceReplyDeliveryMode?: "automatic" | "message_tool_only";
requireExplicitMessageTarget?: boolean;
};
};
fastMode?: FastMode;
toolOverrides?: SessionToolOverrides;
/** Swarm group for collector-mode child sessions. */
swarmGroupId?: string;
/** Marks non-interactive collector-mode child sessions. */
swarmCollector?: boolean;
/** JSON Schema exposed through the synthetic structured_output tool. */
swarmOutputSchema?: Record<string, unknown>;
verboseLevel?: string;
traceLevel?: string;
reasoningLevel?: string;
elevatedLevel?: string;
ttsAuto?: TtsAutoMode;
/** Hash of the latest assistant reply that was sent through `/tts latest`. */
lastTtsReadLatestHash?: string;
/** Timestamp (ms) when `/tts latest` last sent audio for this session. */
lastTtsReadLatestAt?: number;
execHost?: string;
execNode?: string;
/** Working directory interpreted only by the bound exec node. */
execCwd?: string;
responseUsage?: "on" | "off" | "tokens" | "full";
providerOverride?: string;
modelOverride?: string;
/** Session-scoped agent runtime/harness override selected with the model picker. */
agentRuntimeOverride?: string;
/**
* Tracks whether the persisted model override came from an explicit user
* action (`/model`, `sessions.patch`) or from a temporary runtime fallback.
* Resets only preserve user-driven overrides.
*/
modelOverrideSource?: "auto" | "user";
/** Present only when providerOverride/modelOverride are a canonical route pair. */
modelOverrideRouteResolution?: "resolved";
/** Selected model that produced the current auto fallback override. */
modelOverrideFallbackOriginProvider?: string;
modelOverrideFallbackOriginModel?: string;
/** One-run rollback guard for a model selected by the agent sessions tool. */
modelFallback?: AgentPatchedSessionModelFallback;
authProfileOverride?: string;
authProfileOverrideSource?: "auto" | "user" | "user-link";
authProfileOverrideCompactionCount?: number;
/**
* Set on explicit user-driven session model changes (for example `/model`
* and `sessions.patch`) during an active run. The embedded runner checks
* this flag to decide whether to throw `LiveSessionModelSwitchError`.
* System-initiated fallbacks (rate-limit retry rotation) never set this
* flag, so they are never mistaken for user-initiated switches.
*/
liveModelSwitchPending?: boolean;
groupActivation?: "mention" | "always";
groupActivationNeedsSystemIntro?: boolean;
sendPolicy?: "allow" | "deny";
queueMode?: QueueMode;
queueDebounceMs?: number;
queueCap?: number;
queueDrop?: "old" | "new" | "summarize";
inputTokens?: number;
outputTokens?: number;
totalTokens?: number;
pendingFinalDelivery?: PendingFinalDeliveryState;
pendingDeliveryNotice?: PendingDeliveryNoticeState;
/**
* Ordered durable backlog of delivered assistant finals that failed to
* reach the canonical transcript. Session admission restores each item
* before another turn can extend that transcript. Kept as a list so
* independently admitted writers never overwrite an earlier reply.
*/
pendingTranscriptRepair?: PendingTranscriptRepairState[];
/**
* Whether totalTokens reflects a fresh context snapshot for the latest run.
* Undefined means legacy/unknown freshness; false forces consumers to treat
* totalTokens as stale/unknown for context-utilization displays.
*/
totalTokensFresh?: boolean;
/** Version 1 records totalTokens as the current prompt/context snapshot only. */
totalTokensVersion?: typeof SESSION_TOTAL_TOKENS_VERSION;
estimatedCostUsd?: number;
cacheRead?: number;
cacheWrite?: number;
modelProvider?: string;
model?: string;
/**
* Prevents OpenClaw model changes and automatic maintenance eviction until
* the owning harness explicitly retires the session.
*/
modelSelectionLocked?: boolean;
/**
* Embedded agent harness selected for this session id.
* Prevents config/env changes from moving an existing transcript between
* incompatible runtime harnesses.
*/
agentHarnessId?: string;
fallbackNotice?: FallbackNoticeState;
contextTokens?: number;
/** Origin of the persisted context window; `resolved` is legacy/unverified. */
contextTokensSource?: "runtime" | "runtime-configured" | "resolved" | "resolved-v1";
contextBudgetStatus?: SessionContextBudgetStatus;
compactionCount?: number;
compactionCheckpoints?: SessionCompactionCheckpoint[];
memoryFlush?: MemoryFlushState;
cliSessionIds?: Record<string, string>;
cliSessionBindings?: Record<string, CliSessionBinding>;
/** Initialization fence for seeding canonical ACP metadata; cleared after creation. */
acpSessionBinding?: AcpSessionBinding;
claudeCliSessionId?: string;
label?: string;
/** Persistent operator/agent-set sidebar emoji icon (single grapheme). */
icon?: string;
/** Named sidebar tint (SESSION_COLOR_IDS); palette mirrors Claude Code /color for import. */
color?: string;
/** User-defined organization bucket for session lists; unrelated to chat groupId/groupChannel. */
category?: string;
/** Preferred Control UI face when a caller opens this session without explicit face intent. */
boardFace?: SessionBoardFace;
displayName?: string;
/** Canonical delivery state. Legacy delivery fields are migrated by `openclaw doctor --fix`. */
delivery?: SessionDeliveryState;
groupId?: string;
subject?: string;
groupChannel?: string;
space?: string;
/** Last ambient room message durably appended to this transcript, keyed by channel scope. */
ambientTranscriptWatermarks?: Record<string, AmbientTranscriptWatermark>;
skillsSnapshot?: SessionSkillSnapshot;
/** Explicit authorized immutable library pins; current speakers never replace this selection. */
skillLibrarySelections?: SkillLibrarySelection[];
systemPromptReport?: SessionSystemPromptReport;
/**
* Generic plugin-owned runtime debug entries shown in verbose status surfaces.
* Each plugin owns and may overwrite only its own entry between turns.
*/
pluginDebugEntries?: SessionPluginDebugEntry[];
acp?: SessionAcpMeta;
};
interface SessionEntry extends SessionEntryCore {}
/** Internal durable fields excluded from public/plugin session projections. */
type InternalSessionEntryCore = SessionEntryCore & {
/** Run that owns the current non-terminal Gateway lifecycle projection. */
lifecycleRunId?: string;
/** Exact run that produced the latest terminal Gateway lifecycle projection. */
lastRunId?: string;
/** Run admitted by the session lane; overwritten at admission and checked by transcript writes. */
activeWriterRunId?: string;
/** Canonical remote repository awaiting preparation by this exact session generation. */
pendingProjectGitUrl?: string;
/** Authorized worktree intent awaiting preparation by an admitted turn. */
pendingWorktree?: {
workspace?: string;
name?: string;
baseRef?: string;
titleSource: string;
};
/** Suppresses repeated byte-triggered compaction after an oversized successor was observed. */
transcriptByteCompactionLatch?: {
activeBytes: number;
sessionId: string;
maxBytes: number;
};
/** Private per-generation ownership for the pre-runtime checkout baseline capture. */
sessionDiffBaselineCapture?: SessionDiffBaselineCapture;
mainRestartRecovery?: MainRestartRecoveryState;
};
interface InternalSessionEntry extends InternalSessionEntryCore {}
//#endregion
//#region src/config/sessions/session-transcript-turn-lifecycle.types.d.ts
/** Authoritative lifecycle snapshot required for an atomic transcript admission. */
type SessionTranscriptTurnExpectedState = {
/** Rejects a run-owned turn after another admitted run takes writer ownership. */
expectedWriterRunId?: string;
abortedLastRun: boolean | undefined;
/** Fences recovery-only transcript writes against concurrent ownership changes. */
mainRestartRecoveryCycleId: string | undefined;
mainRestartRecoveryRevision: number | undefined;
restartRecoveryBeforeAgentReplyState: SessionRestartRecoveryState["restartRecoveryBeforeAgentReplyState"];
restartRecoveryDeliveryReceiptState: SessionRestartRecoveryState["restartRecoveryDeliveryReceiptState"];
restartRecoveryDeliveryToolCallId: SessionRestartRecoveryState["restartRecoveryDeliveryToolCallId"];
restartRecoveryDeliveryRequestFingerprint: SessionRestartRecoveryState["restartRecoveryDeliveryRequestFingerprint"];
restartRecoveryDeliveryRunId: SessionRestartRecoveryState["restartRecoveryDeliveryRunId"];
restartRecoveryDeliverySourceRunId: SessionRestartRecoveryState["restartRecoveryDeliverySourceRunId"];
restartRecoveryRequesterAccountId: SessionRestartRecoveryState["restartRecoveryRequesterAccountId"];
restartRecoveryRequesterSenderId: SessionRestartRecoveryState["restartRecoveryRequesterSenderId"];
restartRecoverySameChannelThreadRequired: SessionRestartRecoveryState["restartRecoverySameChannelThreadRequired"];
restartRecoverySourceIngress: SessionRestartRecoveryState["restartRecoverySourceIngress"];
restartRecoverySourceReplyDeliveryMode: SessionRestartRecoveryState["restartRecoverySourceReplyDeliveryMode"];
restartRecoveryTerminalRunIds: SessionRestartRecoveryState["restartRecoveryTerminalRunIds"];
status: SessionRunStatus | undefined;
};
/** Lifecycle fields committed with an accepted transcript turn. */
type SessionTranscriptTurnLifecyclePatch = {
abortedLastRun?: boolean;
endedAt?: number;
lifecycleRunId?: InternalSessionEntry["lifecycleRunId"];
lastRunId?: InternalSessionEntry["lastRunId"];
lastRunError?: InternalSessionEntry["lastRunError"];
pendingFinalDelivery?: InternalSessionEntry["pendingFinalDelivery"];
mainRestartRecovery?: InternalSessionEntry["mainRestartRecovery"];
restartRecoveryBeforeAgentReplyState?: SessionRestartRecoveryState["restartRecoveryBeforeAgentReplyState"];
restartRecoveryDeliveryReceiptState?: SessionRestartRecoveryState["restartRecoveryDeliveryReceiptState"];
restartRecoveryDeliveryToolCallId?: SessionRestartRecoveryState["restartRecoveryDeliveryToolCallId"];
restartRecoveryDeliveryContext?: SessionRestartRecoveryState["restartRecoveryDeliveryContext"];
restartRecoveryDeliveryRequestFingerprint?: SessionRestartRecoveryState["restartRecoveryDeliveryRequestFingerprint"];
restartRecoveryDeliveryRunId?: SessionRestartRecoveryState["restartRecoveryDeliveryRunId"];
restartRecoveryDeliverySourceRunId?: SessionRestartRecoveryState["restartRecoveryDeliverySourceRunId"];
restartRecoveryRequesterAccountId?: SessionRestartRecoveryState["restartRecoveryRequesterAccountId"];
restartRecoveryRequesterSenderId?: SessionRestartRecoveryState["restartRecoveryRequesterSenderId"];
restartRecoverySameChannelThreadRequired?: SessionRestartRecoveryState["restartRecoverySameChannelThreadRequired"];
restartRecoverySourceIngress?: SessionRestartRecoveryState["restartRecoverySourceIngress"];
restartRecoverySourceReplyDeliveryMode?: SessionRestartRecoveryState["restartRecoverySourceReplyDeliveryMode"];
restartRecoveryForceSafeTools?: InternalSessionEntry["restartRecoveryForceSafeTools"];
restartRecoveryRuns?: InternalSessionEntry["restartRecoveryRuns"];
/** Durable tombstones merged with the fresh row inside the SQLite write transaction. */
restartRecoveryTerminalRunIds?: SessionRestartRecoveryState["restartRecoveryTerminalRunIds"];
runtimeMs?: number;
startedAt?: number;
status?: SessionRunStatus;
updatedAt?: number;
};
//#endregion
//#region src/sessions/input-provenance.d.ts
declare const INPUT_PROVENANCE_KIND_VALUES: readonly ["external_user", "inter_session", "internal_system"];
type InputProvenanceKind = (typeof INPUT_PROVENANCE_KIND_VALUES)[number];
type InputProvenance = {
kind: InputProvenanceKind;
originSessionId?: string;
sourceSessionKey?: string;
sourceChannel?: string;
sourceTool?: string;
};
//#endregion
//#region src/sessions/user-turn-transcript.types.d.ts
type UserTurnSessionEntry = SessionEntry;
type PersistedUserTurnMessage = Extract<AgentMessage, {
role: "user";
}> & {
display?: false;
excludeFromContext?: true;
/** Private transcript correlation; never authorizes an execution. */
idempotencyKey?: string;
provenance?: InputProvenance;
__openclaw?: Record<string, unknown> & {
humanMentions?: readonly HumanMention[];
};
};
type UserTurnTranscriptUpdateMode = "inline" | "none";
type UserTurnBeforeMessageWrite = (params: {
message: PersistedUserTurnMessage;
agentId?: string;
sessionKey?: string;
}) => AgentMessage | null;
type UserTurnTranscriptPersistenceTarget = {
sessionId: string;
expectedSessionId?: string;
initialSessionEntry?: SessionEntry;
sessionKey: string;
sessionEntry: UserTurnSessionEntry | undefined;
sessionStore?: Record<string, UserTurnSessionEntry>;
storePath?: string;
agentId: string;
threadId?: string | number;
cwd?: string;
config?: unknown;
beforeMessageWrite?: UserTurnBeforeMessageWrite;
};
type UserTurnTranscriptTarget = UserTurnTranscriptPersistenceTarget;
type UserTurnTranscriptAdmissionReceipt = TranscriptTurnAdmission;
type UserTurnTranscriptPersistResult = {
sessionTurnMutationResult?: SessionTranscriptTurnMutationResult;
/** True only when this call inserted the transcript message. */
appended?: boolean;
sessionFile: string;
sessionEntry: UserTurnSessionEntry | undefined;
messageId: string;
message: PersistedUserTurnMessage;
admission: UserTurnTranscriptAdmissionReceipt;
};
type UserTurnTranscriptTargetResolver = UserTurnTranscriptTarget | (() => UserTurnTranscriptTarget | undefined | Promise<UserTurnTranscriptTarget | undefined>);
type UserTurnTranscriptRecorder = {
readonly message: PersistedUserTurnMessage | undefined;
resolveMessage: () => Promise<PersistedUserTurnMessage | undefined>;
/** Durable input custody leaves the active transcript unchanged until execution owns it. */
stageApproved?: (options: {
runId: string;
assertCurrent: () => void;
}) => Promise<boolean>;
getPendingInputMessage?: () => PersistedUserTurnMessage | undefined;
isPendingInputConsumed?: () => boolean;
withPendingInput?: <T>(run: () => T) => T;
finishPendingInput?: (disposition: "cancelled" | "interrupted") => void;
/** Replaces generated current-turn text before runtime persistence/provider submission. */
replaceTextBeforePersistence?: (text: string) => void;
/** Confirms exact-run steering provenance after transcript commitment is proven. */
confirmSteerTargetRunIdForPersistence?: (targetRunId: string) => Promise<void>;
getPersistedMessage?: () => PersistedUserTurnMessage | undefined;
getAdmissionReceipt: () => UserTurnTranscriptAdmissionReceipt | undefined;
setAdmissionHandler?: (handler: (admission: UserTurnTranscriptAdmissionReceipt) => void) => void;
markSentToProvider?: () => void;
markRuntimePersistencePending: (pending: Promise<void>) => void;
markRuntimePersisted: (message?: PersistedUserTurnMessage, anchor?: TranscriptEntryAnchor | UserTurnTranscriptAdmissionReceipt, persistence?: {
appended: boolean;
}) => void;
markBlocked: () => void;
hasPersisted: () => boolean;
isBlocked: () => boolean;
hasRuntimePersistencePending: () => boolean;
waitForRuntimePersistence: () => Promise<void>;
persistApproved: (params?: {
target?: UserTurnTranscriptTargetResolver;
updateMode?: UserTurnTranscriptUpdateMode;
cwd?: string;
expectedSessionId?: string;
expectedSessionState?: SessionTranscriptTurnExpectedState;
sessionLifecyclePatch?: SessionTranscriptTurnLifecyclePatch;
/** Allow a later explicit persistence attempt when this attempt appends nothing. */
retryIfUnpersisted?: boolean;
}) => Promise<UserTurnTranscriptPersistResult | undefined>;
persistBlocked: (message: PersistedUserTurnMessage, params?: {
target?: UserTurnTranscriptTargetResolver;
updateMode?: UserTurnTranscriptUpdateMode;
cwd?: string;
}) => Promise<UserTurnTranscriptPersistResult | undefined>;
persistFallback: (params?: {
target?: UserTurnTranscriptTargetResolver;
updateMode?: UserTurnTranscriptUpdateMode;
cwd?: string;
}) => Promise<UserTurnTranscriptPersistResult | undefined>;
};
//#endregion
//#region src/channels/location.d.ts
/** Normalized source kind for channel-provided geographic locations. */
type LocationSource = "pin" | "place" | "live";
/** Channel-neutral location payload passed from plugins into shared prompt rendering. */
type NormalizedLocation = {
latitude: number;
longitude: number;
accuracy?: number;
name?: string;
address?: string;
isLive?: boolean;
source?: LocationSource;
caption?: string;
};
/** Portable outbound location fields supported by channel send adapters. */
type OutboundLocation = Pick<NormalizedLocation, "latitude" | "longitude" | "accuracy" | "name" | "address">;
//#endregion
//#region src/infra/approval-types.d.ts
type ChannelApprovalKind = "exec" | "plugin" | "system-agent";
//#endregion
//#region src/interactive/payload.d.ts
type InteractiveButtonStyle = "primary" | "secondary" | "success" | "danger";
/** Visual tone for a portable message presentation. */
type MessagePresentationTone = "info" | "success" | "warning" | "danger" | "neutral";
type QuestionPresentationAction = {
/** Resolve one declared choice. */
type: "question";
questionId: string;
optionValue: string;
} | {
/** Switch this question to its free-text answer path. */
type: "question";
questionId: string;
intent: "custom-input";
};
/** Core-owned model-picker action; channels serialize it only inside private envelopes. */
type ModelPickerAction = ({
type: "model-picker";
version: 1;
snapshotToken: string;
intent: "show-providers";
cursor?: string;
} | {
type: "model-picker";
version: 1;
snapshotToken: string;
intent: "show-models";
providerToken: string;
cursor?: string;
} | {
type: "model-picker";
version: 1;
snapshotToken: string;
intent: "show-recents";
cursor?: string;
} | {
type: "model-picker";
version: 1;
snapshotToken: string;
intent: "choose-model";
providerToken: string;
modelToken: string;
} | {
type: "model-picker";
version: 1;
snapshotToken: string;
intent: "choose-runtime";
providerToken: string;
modelToken: string;
runtimeToken: string;
} | {
type: "model-picker";
version: 1;
snapshotToken: string;
intent: "reset";
} | {
type: "model-picker";
version: 1;
snapshotToken: string;
intent: "cancel";
}) & {
/** Legacy command/callback payload fields are deliberately unavailable on picker actions. */
readonly command?: never;
readonly value?: never;
};
/** Portable typed action behind a button or select option. */
type MessagePresentationAction = {
/** Run a core/plugin slash command through the target channel's native command path. */
type: "command";
command: string;
} | {
/** Opaque callback value interpreted by the target channel/plugin. */
type: "callback";
value: string;
} | ModelPickerAction | {
/** Resolve one durable operator approval without exposing transport callback data. */
type: "approval";
approvalId: string;
approvalKind: ChannelApprovalKind;
decision: "allow-once" | "allow-always" | "deny";
} | QuestionPresentationAction | {
/** Open a normal external link. */
type: "url";
url: string;
} | {
/** Launch a channel-native web app. */
type: "web-app";
/** External web app URL for channels that launch web apps by URL. */
url: string;
/** OpenClaw hosted-widget ID whose launch mechanics are owned by the channel. */
widgetId?: string;
} | {
/** Launch a channel-native web app. */
type: "web-app";
/** External web app URL for channels that launch web apps by URL. */
url?: string;
/** OpenClaw hosted-widget ID whose launch mechanics are owned by the channel. */
widgetId: string;
};
/** Portable action control rendered as a button or link by channel adapters. */
type MessagePresentationButton = {
/** User-visible button label. */
label: string;
/** Typed action sent when the button is pressed. */
action?: MessagePresentationAction;
/**
* Legacy opaque callback value sent when the button is pressed.
* Prefer action for new presentation controls.
* @deprecated Use action.
*/
value?: string;
/** @deprecated Use an action with type "url". */
url?: string;
/** @deprecated Use an action with type "web-app". */
webApp?: {
url: string;
};
/**
* @deprecated Use an action with type "web-app". Accepted for legacy JSON payloads only.
*/
web_app?: {
url: string;
};
/** Higher-priority buttons are kept first when channel limits require truncation. */
priority?: number;
/** Disable the button when the target channel supports disabled controls. */
disabled?: boolean;
/** Keep this action available after a successful interaction when the target channel supports it. */
reusable?: boolean;
/** Optional visual style hint; unsupported channels ignore or normalize it. */
style?: InteractiveButtonStyle;
};
/** Portable select/menu option. */
type MessagePresentationOption = {
/** User-visible option label. */
label: string;
/** Typed action sent when the option is selected. */
action?: Extract<MessagePresentationAction, {
type: "command" | "callback" | "model-picker";
}>;
/** @deprecated Use action. */
value?: string;
};
type LegacyInteractiveReplyOption = MessagePresentationOption;
type LegacyInteractiveReplyTextBlock = {
type: "text";
text: string;
};
type LegacyInteractiveReplySelectBlock = {
type: "select";
placeholder?: string;
options: LegacyInteractiveReplyOption[];
};
type LegacyInteractiveReplyBlock = LegacyInteractiveReplyTextBlock | MessagePresentationButtonsBlock | LegacyInteractiveReplySelectBlock;
type LegacyInteractiveReply = {
blocks: LegacyInteractiveReplyBlock[];
};
/** @deprecated Use MessagePresentation. */
type InteractiveReply = LegacyInteractiveReply;
type MessagePresentationTextBlock = {
type: "text";
/** Primary markdown-ish text rendered in the message body. */
text: string;
};
type MessagePresentationContextBlock = {
type: "context";
/** Lower-emphasis contextual text, or normal text on channels without context support. */
text: string;
};
type MessagePresentationDividerBlock = {
type: "divider";
};
type MessagePresentationButtonsBlock = {
type: "buttons";
/** Button row candidates; core may split or truncate them for channel limits. */
buttons: MessagePresentationButton[];
};
type MessagePresentationSelectBlock = {
type: "select";
/** Optional prompt shown above or inside the select control. */
placeholder?: string;
/** Menu options; core may truncate them for channel limits. */
options: MessagePresentationOption[];
};
type MessagePresentationChartSegment = {
/** Category label shown in the chart legend. */
label: string;
/** Positive segment magnitude. */
value: number;
};
type MessagePresentationChartSeries = {
/** Unique series name shown in the chart legend. */
name: string;
/** One finite value for each chart category, in category order. */
values: number[];
};
type MessagePresentationChartBlock = {
type: "chart";
chartType: "pie";
/** Short chart heading. */
title: string;
segments: MessagePresentationChartSegment[];
} | {
type: "chart";
chartType: "bar" | "area" | "line";
/** Short chart heading. */
title: string;
/** Ordered categories shared by every series. */
categories: string[];
series: MessagePresentationChartSeries[];
xLabel?: string;
yLabel?: string;
};
/** Scalar cell value supported by portable table presentations. */
type MessagePresentationTableCell = string | number;
/** Portable table rendered natively where supported and linearly elsewhere. */
type MessagePresentationTableBlock = {
type: "table";
/** Short table heading used by native renderers and fallback text. */
caption: string;
/** Unique ordered column labels shared by every row. */
headers: string[];
/** Rows whose width exactly matches the header count. */
rows: MessagePresentationTableCell[][];
/** Optional column whose cells should be rendered as row headers. */
rowHeaderColumnIndex?: number;
};
type MessagePresentationBlock = MessagePresentationTextBlock | MessagePresentationContextBlock | MessagePresentationDividerBlock | MessagePresentationButtonsBlock | MessagePresentationSelectBlock | MessagePresentationChartBlock | MessagePresentationTableBlock;
type MessagePresentation = {
/** Optional short heading rendered before blocks when the channel supports it. */
title?: string;
/** Optional severity/status tone for renderers that support toned presentations. */
tone?: MessagePresentationTone;
/** Ordered portable blocks rendered or downgraded by the target channel adapter. */
blocks: MessagePresentationBlock[];
};
type ReplyPayloadDeliveryPin = {
enabled: boolean;
notify?: boolean;
required?: boolean;
};
type ReplyPayloadDelivery = {
pin?: boolean | ReplyPayloadDeliveryPin;
};
//#endregion
//#region src/auto-reply/reply-payload.d.ts
type ReplyMediaAttachment = {
type?: "image" | "audio" | "video" | "file";
path?: string;
url?: string;
mediaUrl?: string;
filePath?: string;
mimeType?: string;
name?: string;
sizeBytes?: number;
durationMs?: number;
width?: number;
height?: number;
/** Internal per-URL trust carried until mixed media is split for history projection. */
trustedLocalMedia?: boolean;
};
/** Channel-agnostic assistant reply payload. */
type ReplyPayload = {
text?: string;
/** Visible body a channel adapter may use when native structured content requires text. */
fallbackText?: {
text: string;
/** Batch payload replaced when the adapter adopts this fallback body. */
replacesPayloadIndex?: number;
};
mediaUrl?: string;
mediaUrls?: string[];
/** Prepared metadata aligned with mediaUrls for client-facing history projection. */
attachments?: ReplyMediaAttachment[];
/** Internal-only trust signal for gateway webchat local media embedding. */
trustedLocalMedia?: boolean;
/** Treat media as live-only content and avoid persisting the underlying media reference. */
sensitiveMedia?: boolean;
/** Channel-agnostic rich presentation. Core degrades or asks the channel renderer to map it. */
presentation?: MessagePresentation;
/** Runtime-authored text is the exact fallback, not additional native presentation content. */
presentationTextMode?: "fallback";
/** Channel-agnostic delivery preferences, e.g. pin the sent message when supported. */
delivery?: ReplyPayloadDelivery;
/**
* @deprecated Use presentation.
*
* Internal legacy representation used by existing approval/reply helpers during migration.
*/
interactive?: InteractiveReply;
btw?: {
question: string;
};
replyToId?: string;
replyToTag?: boolean;
/** True when [[reply_to_current]] was present but not yet mapped to a message id. */
replyToCurrent?: boolean;
/** Send audio as voice message (bubble) instead of audio file. Defaults to false. */
audioAsVoice?: boolean;
/** Send video media as a round video note when the channel supports it. */
videoAsNote?: boolean;
/** Channel-neutral geographic location or named place. */
location?: OutboundLocation;
/**
* Text synthesized into an audio-only TTS payload. Exposed to hooks for
* archival/search use when no visible channel text is sent.
*/
spokenText?: string;
/**
* Marks a TTS media payload as supplemental audio for assistant text that is
* already visible through streaming or transcript projection.
*/
ttsSupplement?: ReplyPayloadTtsSupplement;
isError?: boolean;
/** Marks this payload as a reasoning/thinking block. Channels that do not
* have a dedicated reasoning lane (e.g. WhatsApp, web) should suppress it. */
isReasoning?: boolean;
/** Marks pre-tool commentary (š¬) ā a display lane, suppressed unless the channel opts in. */
isCommentary?: boolean;
/** Reasoning stream text is a complete replacement snapshot, not a delta. */
isReasoningSnapshot?: boolean;
/** Marks this payload as a compaction status notice (start/end).
* Should be excluded from TTS transcript accumulation so compaction
* status lines are not synthesised into the spoken assistant reply. */
isCompactionNotice?: boolean;
/** Marks this payload as a model-fallback transition/recovery notice. */
isFallbackNotice?: boolean;
/** Marks this payload as transient status, not assistant answer content. */
isStatusNotice?: boolean;
/** Channel-specific payload data (per-channel envelope). */
channelData?: Record<string, unknown>;
};
/** Metadata for audio-only media that supplements already-visible assistant text. */
type ReplyPayloadTtsSupplement = {
spokenText: string;
visibleTextAlreadyDelivered?: boolean;
};
//#endregion
//#region src/auto-reply/reply/typing.d.ts
/** Controller for channel typing indicator lifecycle during a reply run. */
type TypingController = {
onReplyStart: () => Promise<void>;
startTypingLoop: () => Promise<void>;
startTypingOnText: (text?: string) => Promise<void>;
refreshTypingTtl: () => void;
isActive: () => boolean;
markRunComplete: () => void;
markDispatchIdle: () => void;
cleanup: () => void;
};
//#endregion
//#region src/auto-reply/get-reply-options.types.d.ts
/** A successful runtime append, independent of optional active-path projection anchors. */
type ReplyDispatchAssistantTranscript = Pick<TranscriptEntryAnchor, "agentId" | "sessionId" | "sessionKey" | "storePath"> & {
messageId: string;
anchor?: TranscriptEntryAnchor;
idempotencyKey: string;
};
type ReplyDispatchRun = {
completionSource: "reply-dispatch";
getResult: () => {
assistantTranscript?: ReplyDispatchAssistantTranscript;
terminalOutcome?: AgentRunTerminalOutcome;
};
};
type BlockReplyContext = {
abortSignal?: AbortSignal;
timeoutMs?: number;
/** Source assistant message index from the upstream stream, when available. */
assistantMessageIndex?: number;
/** @internal Stable durable outbound intent owned by the producing runtime. */
deliveryIntentId?: string;
};
/** Context passed to onModelSelected callback with actual model used. */
type ModelSelectedContext = {
provider: string;
model: string;
thinkLevel: string | undefined;
};
/** Typing indicator class for channel-owned UX policy. */
type TypingPolicy = "auto" | "user_message" | "system_event" | "internal_webchat" | "heartbeat";
/** Per-turn policy for source-message reply threading. */
type ReplyThreadingPolicy = {
/** Override implicit reply-to-current behavior for the current turn. */
implicitCurrentMessage?: "default" | "allow" | "deny";
};
/** Action sink available for model-proposed follow-up tasks during this turn. */
type TaskSuggestionDeliveryMode = "gateway";
/** Correlates queued reply ownership transfer with later delivery drains. */
type QueuedReplyDeliveryCorrelation = {
begin: () => (() => void) | void;
};
/**
* Exclusive: each lifecycle is its own collect-admission identity.
* Cancel-only: share collect identity via ownerKey (gateway chat.send).
*/
type TurnAdoptionAdmission = "exclusive" | "cancel-only";
/**
* Canonical turn-ownership lifecycle (adopt / defer / abandon / settle).
* Single surface for durable ingress, gateway cancel identity, and reply-lane transfer.
*/
type TurnAdoptionLifecycle = {
/**
* Admission isolation mode (closed). Exclusive isolates collect identity per
* lifecycle; cancel-only shares via ownerKey. Never inferred from onAbandoned.
* Durable ingress sets exclusive; gateway cancel identity sets cancel-only.
*/
admission?: TurnAdoptionAdmission;
/** Transcript branch leaf from which this turn was admitted. */
originatingLeafEntryId?: string | null;
onAdopted: () => void | Promise<void>;
/** Return false to reject followup enqueue. */
onDeferred?: () => boolean | void;
/** Reports that a deferred turn is still queued behind an active turn. */
onDeferredHeartbeat?: () => void;
/** Deferred turn finished without owning the reply lane. */
onAbandoned?: () => void;
/** Always fires when the followup ownership cycle ends (admitted or not). Gateway cleanup. */
onSettled?: () => void;
/** Retires cancellation ownership while retaining live identity. */
onCancellationRetired?: () => void;
/** Stable cancellation owner for collect-mode batches. */
ownerKey?: string;
abortSignal?: AbortSignal;
/** Ephemeral fact: a direct local operator turn lost fresh cron authority when queued. */
cronCreatorAuthorityUnavailable?: "queued-local-operator";
};
/** Partial assistant payload emitted during streaming or replacement updates. */
type PartialReplyPayload = {
/**
* Sanitized text, which may be an enumerable memoized getter. Content materializes on first
* read: direct-delivery consumers pay per partial, while throttled consumers pay per flush.
*/
text?: ReplyPayload["text"];
mediaUrls?: ReplyPayload["mediaUrls"];
delta?: string;
replace?: true;
};
type ReasoningStreamPayload = Pick<ReplyPayload, "text" | "mediaUrls" | "isReasoning" | "isReasoningSnapshot"> & {
requiresReasoningProgressOptIn?: boolean;
};
type ReasoningProgressPayload = {
progressTokens: number;
};
/** Return false until the channel has accepted operator-visible progress. */
type ProgressCallbackResult = boolean | void;
/** Reply generation options shared by auto-reply, webchat, channels, and tests. */
type GetReplyOptions = {
/** Override run id for agent events (defaults to random UUID). */
runId?: string;
/** Stable provider prompt-cache affinity key; distinct from run id/idempotency. */
promptCacheKey?: string;
/** Abort signal for the underlying agent run. */
abortSignal?: AbortSignal;
/** Ephemeral channel owner check for a targeted Stop; never serialized as authority. */
isCommandTargetCurrent?: () => boolean;
/** Optional inbound images (used for webchat attachments). */
images?: ImageContent[];
/** Original inline/offloaded attachment order for inbound images. */
imageOrder?: PromptImageOrderEntry[];
/** Ordered media facts whose model-facing text projection is already present in the prompt. */
media?: MediaFact[];
/**
* Notifies when an agent run starts. Return "reply-dispatch" synchronously to accept
* completion ownership offered in options; all other legacy callback results are ignored.
*/
onAgentRunStart?: (runId: string, executionIdentityToken?: ExecutionIdentityAdmissionToken, options?: ReplyDispatchRun) => unknown;
/** Reports the terminal agent-run classification to the shared dispatch owner. */
onAgentRunTerminalOutcome?: (outcome: "completed" | "failed") => void;
/**
* Canonical adoption lifecycle (adopted / deferred / abandoned / settled + pre-adoption abort).
*/
turnAdoptionLifecycle?: TurnAdoptionLifecycle;
/** Shared lifecycle owner for the current user-turn transcript append. */
userTurnTranscriptRecorder?: UserTurnTranscriptRecorder;
/** Gateway-owned start-or-steer decision for this turn. */
messageInjectionDisposition?: "none" | "accepted" | "rejected";
/** Current user turn is already durable; replay it without appending another copy. */
suppressNextUserMessagePersistence?: boolean;
onReplyStart?: () => Promise<void> | void;
/** Called when the typing controller cleans up (e.g., run ended with NO_REPLY). */
onTypingCleanup?: () => void;
onTypingController?: (typing: TypingController) => void;
/** If false, send only the initial typing signal without periodic keepalive refreshes. */
typingKeepalive?: boolean;
isHeartbeat?: boolean;
/** Policy-level typing control for run classes (user/system/internal/heartbeat). */
typingPolicy?: TypingPolicy;
/** Force-disable typing indicators for this run (system/internal/cross-channel routes). */
suppressTyping?: boolean;
/** Resolved heartbeat model override (provider/model string from merged per-agent config). */
heartbeatModelOverride?: string;
/** One-shot thinking level override for this run; does not persist to the session. */
thinkingLevelOverride?: string;
/** One-shot fast-mode override for this run; does not persist to the session. */
fastModeOverride?: FastMode;
/** One-shot auto fast-mode cutoff override in seconds; does not persist to the session. */
fastModeAutoOnSecondsOverride?: number;
/** Controls bootstrap workspace context injection (default: full). */
bootstrapContextMode?: "full" | "lightweight";
/** If true, run the model without OpenClaw tools for this turn. */
disableTools?: boolean;
/** Runtime tool allow-list for this turn. Empty means no tools. */
toolsAllow?: string[];
/** If true, include the heartbeat response tool for structured heartbeat outcomes. */
enableHeartbeatTool?: boolean;
/** If true, keep the heartbeat response tool available even under narrow tool profiles. */
forceHeartbeatTool?: boolean;
/**
* @deprecated Ignored. The tool-failure warning is delivered whenever a run ends
* without a reply and cannot be suppressed. Kept only so plugin-sdk callers that
* still pass it keep compiling; removed in the first stable release after 2026.10.
*/
suppressToolErrorWarnings?: boolean;
/**
* If true, dispatch skips default tool/progress text messages and expects the
* channel to surface progress via its own streaming/edit UX.
*/
suppressDefaultToolProgressMessages?: boolean;
/** Suppress standalone tool/progress text even when verbose progress is enabled. */
suppressToolProgressMessages?: boolean;
/** Allow channel-owned tool lifecycle feedback while text progress remains hidden. */
allowToolLifecycleWhenProgressHidden?: boolean;
/**
* Called before dispatch with a live getter for whether verbose standalone
* progress messages are active for this run. Channels that render tool or
* commentary progress inside an ephemeral streaming draft should yield those
* draft lines while the getter returns true, so progress is not rendered in
* both lanes at once.
*/
onVerboseProgressVisibility?: (isActive: () => boolean) => void;
/** Preserve source-event callback start order for stateful channel progress renderers. */
preserveProgressCallbackStartOrder?: boolean;
onPartialReply?: (payload: PartialReplyPayload) => Promise<ProgressCallbackResult> | ProgressCallbackResult;
onReasoningStream?: (payload: ReasoningStreamPayload) => Promise<ProgressCallbackResult> | ProgressCallbackResult;
onReasoningProgress?: (payload: ReasoningProgressPayload) => Promise<void> | void;
streamReasoningInNonStreamModes?: boolean;
/** Called when a thinking/reasoning block ends. */
onReasoningEnd?: () => Promise<ProgressCallbackResult> | ProgressCallbackResult;
/** Called when a new assistant message starts (e.g., after tool call or thinking block). */
onAssistantMessageStart?: () => Promise<ProgressCallbackResult> | ProgressCallbackResult;
/** Called synchronously when a block reply is logically emitted, before async
* delivery drains. Useful for channels that need to rotate preview state at
* block boundaries without waiting for transport acks. */
onBlockReplyQueued?: (payload: ReplyPayload, context?: BlockReplyContext) => Promise<ProgressCallbackResult> | ProgressCallbackResult;
onBlockReply?: (payload: ReplyPayload, context?: BlockReplyContext) => Promise<void> | void;
onToolResult?: (payload: ReplyPayload) => Promise<ProgressCallbackResult> | ProgressCallbackResult;
/** Called when a tool phase starts/updates, before summary payloads are emitted. */
onToolStart?: (payload: {
itemId?: string;
toolCallId?: string;
name?: string;
phase?: string;
args?: Record<string, unknown>;
detailMode?: "explain" | "raw";
}) => Promise<ProgressCallbackResult> | ProgressCallbackResult;
/** Called when a concrete work item starts, updates, or completes. */
onItemEvent?: (payload: {
itemId?: string;
toolCallId?: string;
kind?: string;
title?: string;
name?: string;
phase?: string;
status?: string;
summary?: string;
progressText?: string;
meta?: string;
commandBearing?: boolean;
approvalId?: string;
approvalSlug?: string;
suppressDurableProgress?: true;
}) => Promise<ProgressCallbackResult> | ProgressCallbackResult;
/**
* Called when the utility-model narration of the in-progress turn changes.
* Providing this callback opts the channel into progress narration; core
* only generates narration when a utility model resolves (explicit
* config or the provider-declared default; utilityModel: "" disables).
* An empty text clears narration; a retained model preamble still wins before
* the channel falls back to raw tool progress.
*/
onNarrationUpdate?: (payload: {
text: string;
}) => Promise<void> | void;
/** Channel-owned final and queued-turn boundaries for the current narrator. */
onProgressNarratorLifecycle?: (lifecycle: {
beginTurn: () => void;
stopTurn: () => void;
}) => void;
/** False while utility-model narration has no visible progress draft. */
isProgressDraftVisible?: () => boolean;
/**
* Omit exec/bash command text from narration model input, mirroring the
* channel's `streaming.progress.commandText: "status"` display policy so
* narration never receives more command detail than the draft shows.
*/
narrationHideCommandText?: boolean;
/** In progress mode, classify Claude pre-tool text; true also renders it as commentary. */
commentaryProgressEnabled?: boolean;
/** Bridge typed preambles to a channel-owned progress headline without commentary. */
progressPreambleEnabled?: boolean;
/** Deliver durable reasoning payloads to channels that own a separate reasoning lane. */
reasoningPayloadsEnabled?: boolean;
/** Deliver durable commentary (š¬) payloads to channels that own a separate commentary lane. */
commentaryPayloadsEnabled?: boolean;
/** Optional turn-frozen commentary owner; visibility is live by default.
* With the static opt-in and this callback, core freezes, evaluates once, and snapshots. */
shouldDeliverCommentaryPayloads?: () => boolean;
/** Called when the agent emits a structured plan update. */
onPlanUpdate?: (payload: {
phase?: string;
title?: string;
explanation?: string;
steps?: AgentPlanStep[];
source?: string;
}) => Promise<ProgressCallbackResult> | ProgressCallbackResult;
/** Called when an approval becomes pending or resolves. */
onApprovalEvent?: (payload: {
phase?: string;
kind?: string;
status?: string;
title?: string;
itemId?: string;
toolCallId?: string;
approvalId?: string;
approvalSlug?: string;
command?: string;
host?: string;
reason?: string;
scope?: "turn" | "session";
message?: string;
}) => Promise<ProgressCallbackResult> | ProgressCallbackResult;
/** Called when command output streams or completes. */
onCommandOutput?: (payload: {
itemId?: string;
phase?: string;
title?: string;
toolCallId?: string;
name?: string;
output?: string;
status?: string;
exitCode?: number | null;
durationMs?: number;
cwd?: string;
}) => Promise<ProgressCallbackResult> | ProgressCallbackResult;
/** Called when a patch completes with a file summary. */
onPatchSummary?: (payload: {
itemId?: string;
phase?: string;
title?: string;
toolCallId?: string;
name?: string;
added?: string[];
modified?: string[];
deleted?: string[];
summary?: string;
}) => Promise<ProgressCallbackResult> | ProgressCallbackResult;
/** Called when context auto-compaction starts (allows UX feedback during the pause). */
onCompactionStart?: () => Promise<ProgressCallbackResult> | ProgressCallbackResult;
/** Called when context auto-compaction ends; omitted outcome means completed for legacy callers. */
onCompactionEnd?: (payload?: {
completed: boolean;
}) => Promise<ProgressCallbackResult> | ProgressCallbackResult;
/** Called when the actual model is selected (including after fallback).
* Use this to get model/provider/thinkLevel for responsePrefix template interpolation. */
onModelSelected?: (ctx: ModelSelectedContext) => void;
/**
* Controls whether normal assistant replies are automatically delivered to
* the source conversation. `message_tool_only` prefers message-tool visible
* delivery and keeps normal final text, block output, and preview output
* private unless dispatch explicitly marks a source reply as deliverable.
*/
sourceReplyDeliveryMode?: SourceReplyDeliveryMode;
/** Enables task-suggestion tools only when the initiating surface can action Gateway events. */
taskSuggestionDeliveryMode?: TaskSuggestionDeliveryMode;
/** Starts delivery tracking when this turn later drains as a queued followup. */
queuedDeliveryCorrelations?: QueuedReplyDeliveryCorrelation[];
/** Called after a queued followup owns the reply lane, before its model run starts. */
onQueuedFollowupAdmitted?: () => Promise<void> | void;
/** Called after an admitted queued followup finishes, including failed attempts. */
onQueuedFollowupSettled?: () => Promise<void> | void;
/** Allow channel-owned progress UI while final/source reply delivery remains message-tool-only. */
allowProgressCallbacksWhenSourceDeliverySuppressed?: boolean;
/** Called when a suppressed source reply mode observes visible delivery through another path. */
onObservedReplyDelivery?: () => Promise<void> | void;
/** Emit tool result summaries for channel-owned progress UI even when verbose is off. */
forceToolResultProgress?: boolean;
disableBlockStreaming?: boolean;
/** Timeout for block reply delivery (ms). */
blockReplyTimeoutMs?: number;
/** If provided, only load these skills for this session (empty = no skills). */
skillFilter?: string[];
/** Mutable ref to track if a reply was sent (for Slack "first" threading mode). */
hasRepliedRef?: {
value: boolean;
};
/** Override agent timeout in seconds (0 = no timeout). Threads through to resolveAgentTimeoutMs. */
timeoutOverrideSeconds?: number;
};
//#endregion
//#region src/channels/inbound-event/kind.d.ts
/**
* High-level inbound event class used to separate actionable user requests from room activity.
*/
type InboundEventKind = "user_request" | "room_event";
//#endregion
//#region packages/media-understanding-common/src/types.d.ts
/** Kind of media-understanding output produced for an attachment. */
type MediaUnderstandingKind = "audio.transcription" | "video.description" | "image.description";
/** Capability exposed by a media-understanding provider. */
type MediaUnderstandingCapability = "image" | "audio" | "video";
/** Normalized text output produced by media understanding. */
type MediaUnderstandingOutput = {
kind: MediaUnderstandingKind;
attachmentIndex: number;
text: string;
provider: string;
model?: string;
requestedBackend?: string;
observedBackend?: string;
};
//#endregion
//#region src/media-understanding/types.d.ts
type MediaUnderstandingDecisionOutcome = "success" | "failed" | "skipped" | "disabled" | "no-attachment" | "scope-deny";
type MediaUnderstandingModelDecision = {
provider?: string;
model?: string;
requestedBackend?: string;
observedBackend?: string;
type: "provider" | "cli";
outcome: "success" | "skipped" | "failed";
reason?: string;
};
type MediaUnderstandingAttachmentDecision = {
attachmentIndex: number;
attempts: MediaUnderstandingModelDecision[];
chosen?: MediaUnderstandingModelDecision;
};
type MediaAttachmentDisposition = {
kind: "handled";
} | {
kind: "handed-to-native-vision";
} | {
kind: "not-selected";
} | {
kind: "capability-disabled";
} | {
kind: "no-model";
} | {
kind: "scope-denied";
} | {
kind: "failed";
reason?: string;
};
type MediaUnderstandingDecision = {
capability: MediaUnderstandingCapability;
outcome: MediaUnderstandingDecisionOutcome;
attachments: MediaUnderstandingAttachmentDecision[];
attachmentDispositions?: Record<number, MediaAttachmentDisposition>;
nativeVisionActive?: boolean;
};
//#endregion
//#region src/plugins/hook-channel-context.types.d.ts
interface PluginHookChannelSenderContext {
/** Channel-scoped sender ID, matching `ctx.senderId` when both are present. */
id?: string;
[key: string]: unknown;
}
interface PluginHookChannelChatContext {
/** Transport-native conversation ID, matching `ctx.chatId` when both are present. */
id?: string;
[key: string]: unknown;
}
interface PluginHookChannelContext {
/** Sender metadata supplied by the originating channel. */
sender?: PluginHookChannelSenderContext;
/** Chat/conversation metadata supplied by the originating channel. */
chat?: PluginHookChannelChatContext;
}
//#endregion
//#region src/auto-reply/command-turn-context.d.ts
type BaseCommandTurnContext = {
commandName?: string;
body?: string;
};
type NativeCommandTurnContext = BaseCommandTurnContext & {
kind: "native";
source: "native";
authorized: boolean;
};
type TextSlashCommandTurnContext = BaseCommandTurnContext & {
kind: "text-slash";
source: "text";
authorized: boolean;
};
type NormalCommandTurnContext = BaseCommandTurnContext & {
kind: "normal";
source: "message";
authorized: false;
};
type CommandTurnContext = NativeCommandTurnContext | TextSlashCommandTurnContext | NormalCommandTurnContext;
//#endregion
//#region src/auto-reply/commands-args.types.d.ts
/** Primitive values accepted by parsed auto-reply command args. */
type CommandArgValue = string | number | boolean | bigint;
/** Named parsed auto-reply command values. */
type CommandArgValues = Record<string, CommandArgValue>;
/** Parsed command argument bundle with raw source and structured values. */
type CommandArgs = {
raw?: string;
values?: CommandArgValues;
};
//#endregion
//#region src/auto-reply/reply/history.types.d.ts
/** Normalized history message used when building reply context. */
type HistoryEntry = {
sender: string;
body: string;
timestamp?: number;
messageId?: string;
media?: HistoryMediaEntry[];
};
/** Media metadata attached to a normalized history message. */
type HistoryMediaEntry = Pick<MediaFact, "contentType" | "durationMs" | "height" | "kind" | "messageId" | "path" | "url" | "width">;
//#endregion
//#region src/auto-reply/templating.d.ts
/** Valid message channels for routing. */
type OriginatingChannelType = string & {
readonly __originatingChannelBrand?: never;
};
type MentionSource = "explicit_bot" | "subteam" | "mention_pattern" | "implicit_thread" | "command_bypass" | "none";
type InboundSourceModality = "text" | "voice" | "audio" | "image" | "video" | "document";
type StickerContextMetadata = {
cachedDescription?: string;
emoji?: string;
setName?: string;
description?: string;
fileId?: string;
fileUniqueId?: string;
uniqueFileId?: string;
isAnimated?: boolean;
isVideo?: boolean;
} & Record<string, unknown>;
type ChannelStructuredContextEntry = {
label: string;
source?: string;
type?: string;
payload: unknown;
/** Internal exact-id hints for canonical transcript/live-cache deduplication. */
sessionTranscriptDedupeMessageIds?: string[];
/** Internal visible-text hints for legacy assistant rows without transcript ids. */
sessionTranscriptAssistantTextDedupeKeys?: string[];
};
type SessionTranscriptContext = {
chatWindow?: boolean;
historyLimit: number;
beforeTimestampMs?: number;
minTimestampMs?: number;
senderLabels?: {
assistant: string;
user: string;
};
};
/** @deprecated Use ChannelStructuredContextEntry. Removal: after 2026-09-08 (see sdk-untrusted-context-identifier-aliases). */
type UntrustedStructuredContextEntry = ChannelStructuredContextEntry;
/** Structured supplemental facts projected into prompt context by inbound finalization. */
type SupplementalContextFacts = {
quote?: {
id?: string;
fullId?: string;
body?: string;
sender?: string;
senderAllowed?: boolean;
isExternal?: boolean;
isQuote?: boolean;
};
forwarded?: {
from?: string;
fromType?: string;
fromId?: string;
date?: number;
senderAllowed?: boolean;
};
thread?: {
id?: string;
starterBody?: string;
historyBody?: string;
label?: string;
parentSessionKey?: string;
modelParentSessionKey?: string;
senderAllowed?: boolean;
};
channelStructuredContext?: ChannelStructuredContextEntry[];
/** @deprecated Use channelStructuredContext. Removal: after 2026-09-08 (see sdk-untrusted-context-identifier-aliases). */
untrustedContext?: ChannelStructuredContextEntry[];
groupSystemPrompt?: string;
/** Prompt-like group metadata from user-controlled sources; never enters the system prompt. */
untrustedGroupSystemPrompt?: string;
};
/** Canonical normalized inbound text populated once by `finalizeInboundContext`. */
type CanonicalInboundText = {
/** Clean text used for command and directive parsing. */
commandText: string;
/** Prompt-facing text used for the agent turn. */
agentText: string;
/** Normalized visible/raw inbound text before command-specific projection. */
rawText: string;
};
/** Raw inbound message context accepted from channels before finalization. */
type MsgContext = Partial<CanonicalInboundText> & {
Body?: string;
InboundEventKind?: InboundEventKind;
/**
* Agent prompt body (may include envelope/history/context). Prefer this for prompt shaping.
* Should use real newlines (`\n`), not escaped `\\n`.
*/
BodyForAgent?: string;
/**
* Recent chat history for context (untrusted user content). Prefer passing this
* as structured context blocks in the user prompt rather than rendering plaintext envelopes.
*/
InboundHistory?: HistoryEntry[];
/** Internal facts used to merge canonical transcript turns before dispatch. */
SessionTranscriptContext?: SessionTranscriptContext;
/**
* @deprecated Use CommandBody.
*
* Raw message body without structural context (history, sender labels).
* Legacy alias for CommandBody. Falls back to Body if not set.
*/
RawBody?: string;
/**
* Prefer for command detection; RawBody is treated as legacy alias.
*/
CommandBody?: string;
/**
* Command parsing body. Prefer this over CommandBody/RawBody when set.
* Should be the "clean" text (no history/sender context).
*/
BodyForCommands?: string;
CommandArgs?: CommandArgs;
From?: string;
To?: string;
SessionKey?: string;
/**
* Resolved agent scope for canonical session keys that do not encode the agent
* id, such as selected-agent global sessions.
*/
AgentId?: string;
/** Effective routed DM scope, including binding overrides. */
DmScope?: DmScope;
/**
* Session-like key used for runtime policy (sandbox/tool policy) when the
* conversation key intentionally remains broader, such as a main-session DM.
*/
RuntimePolicySessionKey?: string;
/** Provider account id (multi-account). */
AccountId?: string;
ParentSessionKey?: string;
/**
* Session key used only for inheriting session-scoped model/provider
* overrides. Unlike ParentSessionKey, this must not trigger transcript
* forking or parent-session lifecycle behavior.
*/
ModelParentSessionKey?: string;
MessageSid?: string;
/** Provider-specific full message id when MessageSid is a shortened alias. */
MessageSidFull?: string;
MessageSids?: string[];
MessageSidFirst?: string;
MessageSidLast?: string;
AmbientTranscriptWatermarkKey?: string;
AmbientTranscriptBody?: string;
AmbientTranscriptMessageId?: string;
AmbientTranscriptTimestampMs?: number;
AmbientTranscriptPreviousMessageId?: string;
AmbientTranscriptPreviousTimestampMs?: number;
/** Per-turn reply-threading overrides. */
ReplyThreading?: ReplyThreadingPolicy;
/** Effective channel reply mode prepared for this turn. */
ReplyToMode?: ReplyToMode;
ReplyToId?: string;
/**
* Root message id for thread reconstruction (used by Feishu for root_id).
* When a message is part of a thread, this is the id of the first message.
*/
RootMessageId?: string;
/** Provider-specific full reply-to id when ReplyToId is a shortened alias. */
ReplyToIdFull?: string;
ReplyToBody?: string;
ReplyToQuoteText?: string;
ReplyToSender?: string;
ReplyChain?: Array<{
messageId?: string;
threadId?: string;
sender?: string;
senderId?: string;
senderUsername?: string;
timestamp?: number;
body?: string;
isQuote?: boolean;
mediaType?: string;
mediaPath?: string;
mediaRef?: string;
replyToId?: string;
forwardedFrom?: string;
forwardedFromId?: string;
forwardedFromUsername?: string;
forwardedDate?: number;
}>;
ReplyToIsQuote?: boolean;
/** Forward origin from the reply target (when reply_to_message is a forwarded message). */
ReplyToForwardedFrom?: string;
ReplyToForwardedFromType?: string;
ReplyToForwardedFromId?: string;
ReplyToForwardedFromUsername?: string;
ReplyToForwardedFromTitle?: string;
ReplyToForwardedDate?: number;
ForwardedFrom?: string;
ForwardedFromType?: string;
ForwardedFromId?: string;
ForwardedFromUsername?: string;
ForwardedFromTitle?: string;
ForwardedFromSignature?: string;
ForwardedFromChatType?: string;
ForwardedFromMessageId?: number;
ForwardedDate?: number;
ThreadStarterBody?: string;
/** Full thread history when starting a new thread session. */
ThreadHistoryBody?: string;
IsFirstThreadTurn?: boolean;
ThreadLabel?: string;
/** @deprecated Use `media?.[0]?.path`. */
MediaPath?: string;
/** @deprecated Use `media?.[0]?.url`. */
MediaUrl?: string;
/** @deprecated Use `media?.[0]?.contentType` or `.kind`. */
MediaType?: string;
/** @deprecated Derive the directory from `media?.[0]?.path` at the consuming boundary. */
MediaDir?: string;
/** @deprecated Use `media?.map((entry) => entry.path)`. */
MediaPaths?: string[];
/** @deprecated Use `media?.map((entry) => entry.url)`. */
MediaUrls?: string[];
/** @deprecated Use `media?.map((entry) => entry.contentType ?? entry.kind)`. */
MediaTypes?: string[];
/** Ordered current-turn media facts; array position is attachment identity. */
media?: MediaFact[];
/** Original message modality before transcription or other media normalization. */
SourceModality?: InboundSourceModality;
/** @deprecated Use each media fact's `workspaceDir`. */
MediaWorkspaceDir?: string;
/** Attachment indexes whose audio was already transcribed before media understanding runs. */
/** @deprecated Use each media fact's `transcribed` field. */
MediaTranscribedIndexes?: number[];
/**
* Marker: skip downstream stageSandboxMedia. chat.send RPC sets this so
* staging runs synchronously before respond() and surfaces 5xx to the
* client; any later failure only reaches the broadcast channel.
*/
/** @deprecated Use each media fact's `workspaceDir` or `staged` proof. */
MediaStaged?: boolean;
/** Telegram sticker metadata (emoji, set name, file IDs, cached description). */
Sticker?: StickerContextMetadata;
/** True when current-turn sticker media is present in structured facts. */
StickerMediaIncluded?: boolean;
/** Skip automatic understanding for the current sticker because its cached description is used. */
SkipStickerMediaUnderstanding?: boolean;
OutputDir?: string;
OutputBase?: string;
/** Remote host for SCP when media lives on a different machine (e.g., openclaw@192.168.64.3). */
MediaRemoteHost?: string;
Transcript?: string;
MediaUnderstanding?: MediaUnderstandingOutput[];
MediaUnderstandingDecisions?: MediaUnderstandingDecision[];
LinkUnderstanding?: string[];
Prompt?: string;
MaxChars?: number;
ChatType?: string;
/** Trusted channel-configured policy for this admitted conversation turn. */
ConversationToolPolicy?: GroupToolPolicyConfig;
/** Human label for envelope headers (conversation label, not sender). */
ConversationLabel?: string;
GroupSubject?: string;
/** Human label for channel-like group conversations (e.g. #general, #support). */
GroupChannel?: string;
GroupSpace?: string;
/** Trusted provider role ids for the sender in this group turn. */
MemberRoleIds?: string[];
GroupMembers?: string;
GroupSystemPrompt?: string;
/**
* Canonical inbound supplemental facts for new channel code. `finalizeInboundContext`
* projects these to the existing flat reply/forward/thread/group prompt fields.
*/
SupplementalContext?: SupplementalContextFacts;
/** Channel-provided metadata that must not be treated as system instructions. */
ChannelPromptContext?: string[];
/** @deprecated Use ChannelPromptContext. Removal: after 2026-09-08 (see sdk-untrusted-context-identifier-aliases). */
UntrustedContext?: string[];
/** Structured channel metadata rendered by prompt assembly as fenced JSON. */
ChannelStructuredContext?: ChannelStructuredContextEntry[];
/** @deprecated Use ChannelStructuredContext. Removal: after 2026-09-08 (see sdk-untrusted-context-identifier-aliases). */
UntrustedStructuredContext?: UntrustedStructuredContextEntry[];
/** System-attached provenance for the current inbound message. */
InputProvenance?: InputProvenance;
/** Internal wake cause, independent of transport, transcript provenance, and execution authority. */
InternalTurnSource?: "heartbeat" | "cron" | "exec";
/** Explicit owner allowlist overrides (trusted, configuration-derived). */
OwnerAllowFrom?: Array<string | number>;
SenderName?: string;
SenderId?: string;
/** Trusted in-process creation provenance; never populated from channel payloads. */
SessionCreation?: {
skillLibrarySelections?: SkillLibrarySelection[];
via: SessionCreatedVia;
actor?: SessionCreatedActor;
sandbox?: "required";
};
SenderUsername?: string;
SenderTag?: string;
SenderE164?: string;
SenderIsBot?: boolean;
/** Channel-ingress fact: sender is the operator's own account (from-me). */
SenderIsSelf?: boolean;
Timestamp?: number;
LocationLat?: number;
LocationLon?: number;
LocationAccuracy?: number;
LocationName?: string;
LocationAddress?: string;
LocationSource?: string;
LocationIsLive?: boolean;
LocationLivePeriodSeconds?: number;
LocationCaption?: string;
/** Stable identity of the provider update that carried this message. */
ProviderUpdateId?: string;
/** Provider update kind, for example `message` or `edited_message`. */
ProviderUpdateKind?: string;
/** Provider-native timestamp for the original message. */
ProviderMessageTimestamp?: number;
/** Provider-native timestamp for an edited message update. */
ProviderEditTimestamp?: number;
/** Provider label. */
Provider?: string;
/** Provider surface label. Prefer this over `Provider` when available. */
Surface?: string;
/** Platform bot username when command mentions should be normalized. */
BotUsername?: string;
WasMentioned?: boolean;
/** Effective channel-owned mention policy before any plugin-binding bypass. */
GroupRequireMention?: boolean;
/** True when this turn explicitly mentioned the current bot target. */
ExplicitlyMentionedBot?: boolean;
/** Provider-native explicit user mention ids present on this turn. */
MentionedUserIds?: string[];
/** Provider-native explicit user-group/subteam mention ids present on this turn. */
MentionedSubteamIds?: string[];
/** Provider-native implicit mention wake reasons present on this turn. */
ImplicitMentionKinds?: string[];
/** Provider-native source that caused the current mention decision. */
MentionSource?: MentionSource;
CommandAuthorized?: boolean;
CommandTurn?: CommandTurnContext;
CommandSource?: "text" | "native";
CommandInterpretationSuppressed?: boolean;
CommandTargetSessionKey?: string;
/**
* Internal flag: command handling prepared trailing prompt text for ACP dispatch.
* Used for `/new <prompt>` and `/reset <prompt>` on ACP-bound sessions.
*/
AcpDispatchTailAfterReset?: boolean;
/** Gateway client scopes when the message originates from the gateway. */
GatewayClientScopes?: string[];
/** Gateway client capabilities when the message originates from the gateway. */
GatewayClientCaps?: string[];
/** Run-scoped plugin tool bindings; never rendered into prompt text. */
GatewayRunToolBindings?: Readonly<Record<string, unknown>>;
/** Gateway device id allowed to review approvals initiated by this turn. */
ApprovalReviewerDeviceId?: string;
/** Thread identifier (Telegram topic id or Matrix thread event id). */
MessageThreadId?: string | number;
/** Provider-native thread target for reply delivery without making the session thread-scoped. */
TransportThreadId?: string | number;
/** Platform-native channel/conversation id (e.g. Slack DM channel "Dā¦" id). */
NativeChannelId?: string;
/** Channel-owned local conversation image reference; never rendered into prompt text. */
ConversationAvatar?: string;
/** Channel-owned metadata exposed to plugin hook context, not prompt text. */
ChannelContext?: PluginHookChannelContext;
/** Provider-native chat/conversation id used by channel plugins that expose `chat_id`. */
ChatId?: string;
/** Stable provider-native direct-peer id when a DM room/user mapping must survive later writes. */
NativeDirectUserId?: string;
/** Telegram forum supergroup marker. */
IsForum?: boolean;
/** Human-readable Telegram forum topic name (cached from service messages). */
TopicName?: string;
/** Warning: DM has topics enabled but this message is not in a topic. */
TopicRequiredButMissing?: boolean;
/**
* Originating channel for reply routing.
* When set, replies should be routed back to this provider
* instead of using lastChannel from the session.
*/
OriginatingChannel?: OriginatingChannelType;
/**
* Originating destination for reply routing.
* The chat/channel/user ID where the reply should be sent.
*/
OriginatingTo?: string;
/**
* True when the current turn intentionally requested external delivery to
* OriginatingChannel/OriginatingTo, rather than inheriting stale session route metadata.
*/
ExplicitDeliverRoute?: boolean;
/**
* Internal proof that the channel ingress owner admitted this sender/event.
* Correlation interceptors must fail closed when this proof is absent.
*/
InboundAccessAuthorized?: boolean;
/** Internal marker that channel ingress authoritatively observed route-context facts. */
ConversationRouteContextObserved?: boolean;
/** Canonical peer used by route selection; delivery targets may use a different namespace. */
ConversationRoutePeerId?: string;
/**
* Internal flag for channels that emit message_received through a channel-specific
* privacy gate before entering the shared reply dispatcher.
*/
SuppressMessageReceivedHooks?: boolean;
/**
* Provider-specific parent conversation id for threaded contexts.
* For Discord threads, this is the parent channel id.
*/
ThreadParentId?: string;
/**
* Messages from hooks to be included in the response.
* Used for hook confirmation messages like "Session context saved to memory".
*/
HookMessages?: string[];
};
type RuntimeMediaContextKey = "MediaPath" | "MediaUrl" | "MediaType" | "MediaDir" | "MediaPaths" | "MediaUrls" | "MediaTypes" | "MediaWorkspaceDir" | "MediaTranscribedIndexes" | "MediaStaged";
/** Internal inbound context; legacy media fields exist only on the shipped SDK adapter. */
type RuntimeMsgContext = Omit<MsgContext, RuntimeMediaContextKey>;
type NonTemplateContextKey = "ConversationAvatar";
type TemplateContext = Omit<RuntimeMsgContext, NonTemplateContextKey> & {
BodyStripped?: string;
SessionId?: string;
IsNewSession?: string;
/** Local path for the attachment currently being processed. */
AttachmentPath?: string;
/** Original URL/reference for the attachment currently being processed. */
AttachmentUrl?: string;
/** MIME content type for the attachment currently being processed. */
AttachmentContentType?: string;
/** Directory containing AttachmentPath. */
AttachmentDir?: string;
/** Stable zero-based source fact index for the attachment currently being processed. */
AttachmentIndex?: number;
/** @deprecated Use AttachmentPath. */
MediaPath?: string;
/** @deprecated Use AttachmentUrl. */
MediaUrl?: string;
/** @deprecated Use AttachmentContentType. */
MediaType?: string;
/** @deprecated Use AttachmentDir. */
MediaDir?: string;
};
declare function applyTemplate$1(str: string | undefined, ctx: TemplateContext): string;
//#endregion
//#region src/auto-reply/reply/get-reply.d.ts
declare function getReplyFromConfig$2(ctx: RuntimeMsgContext, opts?: GetReplyOptions, configOverride?: OpenClawConfig): Promise<ReplyPayload | ReplyPayload[] | undefined>;
//#endregion
//#region src/cli/outbound-send-mapping.d.ts
type CliOutboundSendSource = {
[channelId: string]: unknown;
};
//#endregion
//#region src/cli/deps.types.d.ts
/** CLI dependency bag currently used by outbound send command plumbing. */
type CliDeps = CliOutboundSendSource;
//#endregion
//#region src/cli/deps.d.ts
declare function createDefaultDeps$1(): CliDeps;
//#endregion
//#region src/cli/prompt.d.ts
/** Prompts for yes/no input, honoring global `--yes` before opening stdin. */
declare function promptYesNo$2(question: string, defaultYes?: boolean): Promise<boolean>;
//#endregion
//#region src/cli/wait.d.ts
declare function waitForever$1(): Promise<void>;
//#endregion
//#region src/config/sessions/paths.d.ts
/** Resolves fixed literal paths without an owner; derived or templated paths require agentId. */
declare function resolveSessionStorePathCore(store?: string, opts?: {
agentId?: string;
env?: NodeJS.ProcessEnv;
}): string;
//#endregion
//#region src/config/sessions/session-key.d.ts
/**
* Derives the raw session bucket from message context before agent/main-key normalization.
*
* Direct chats use sender identity, groups use channel-owned group keys, and global scope bypasses
* sender routing entirely.
*/
declare function deriveSessionKey$1(scope: SessionScope, ctx: MsgContext): string;
/**
* Resolves the persisted session-store key for an inbound message.
*
* Explicit session keys pass through the compatibility normalizer, direct chats collapse to the
* agent's canonical main bucket, and group/channel sessions stay isolated under the same agent.
*/
declare function resolveSessionKey$1(scope: SessionScope, ctx: MsgContext, mainKey?: string, agentId?: string): string;
//#endregion
//#region src/process/exec-output.d.ts
type CommandOutputCaptureMode = "head" | "tail" | "discard";
type CommandOutputStream = "stdout" | "stderr";
type CommandOutputCaptureOption = CommandOutputCaptureMode | {
stdout?: CommandOutputCaptureMode;
stderr?: CommandOutputCaptureMode;
};
type CommandOutputLimitOption = boolean | {
stdout?: boolean;
stderr?: boolean;
combined?: boolean;
};
type CommandOutputErrorOption = boolean | {
stdout?: boolean;
stderr?: boolean;
};
type PreserveOutputLine = (line: string, stream: CommandOutputStream) => boolean;
//#endregion
//#region src/process/exec-result.d.ts
type SpawnResult = {
pid?: number;
stdout: string;
stderr: string;
stdoutTruncatedBytes?: number;
stderrTruncatedBytes?: number;
preservedStdoutLines?: string[];
preservedStderrLines?: string[];
code: number | null;
signal: NodeJS.Signals | null;
killed: boolean;
termination: "exit" | "timeout" | "no-output-timeout" | "signal";
noOutputTimedOut?: boolean;
outputLimitExceeded?: boolean;
outputErrorStream?: "stdout" | "stderr";
};
//#endregion
//#region src/process/exec-runner.d.ts
type CommandOptions = {
timeoutMs?: number;
cwd?: string;
input?: string | Uint8Array;
baseEnv?: NodeJS.ProcessEnv;
env?: NodeJS.ProcessEnv;
windowsVerbatimArguments?: boolean;
noOutputTimeoutMs?: number;
signal?: AbortSignal;
maxOutputBytes?: number | {
stdout?: number;
stderr?: number;
};
maxCombinedOutputBytes?: number;
outputCapture?: CommandOutputCaptureOption;
/** Observe raw output without owning child lifecycle. Return false to stop the command. */
onOutputChunk?: (chunk: Buffer, stream: CommandOutputStream) => boolean | void;
/** Accept a successful exit when only the selected diagnostic output stream failed. */
tolerateOutputError?: {
stdout?: boolean;
stderr?: boolean;
};
/** Terminate when the selected output stream emits an error. */
terminateOnOutputError?: CommandOutputErrorOption;
terminateOnOutputLimit?: CommandOutputLimitOption;
maxPreservedOutputLines?: number;
preserveOutputLine?: PreserveOutputLine;
killProcessTree?: boolean;
/** Signal used when terminating the direct child; tree termination owns its own grace policy. */
killSignal?: NodeJS.Signals | number;
/** Grace between graceful termination and the force-kill fallback. */
killGraceMs?: number;
};
declare function runCommandWithTimeout$2(argv: string[], optionsOrTimeout: number | CommandOptions): Promise<SpawnResult>;
//#endregion
//#region src/process/exec.d.ts
type RunExecOptions = {
timeoutMs?: number;
maxBuffer?: number;
logOutput?: boolean;
cwd?: string;
baseEnv?: NodeJS.ProcessEnv;
env?: NodeJS.ProcessEnv;
input?: string | Uint8Array;
stdinFileDescriptor?: number;
signal?: AbortSignal;
};
declare function runExec$2(command: string, args: string[], opts?: number | RunExecOptions): Promise<{
stdout: string;
stderr: string;
}>;
//#endregion
//#region src/infra/binaries.d.ts
declare function ensureBinary$2(name: string, exec?: typeof runExec$2, runtime?: RuntimeEnv): Promise<void>;
//#endregion
//#region src/infra/ports.d.ts
declare class PortInUseError$1 extends Error {
port: number;
details?: string;
constructor(port: number, details?: string);
}
declare function describePortOwner$1(port: number): Promise<string | undefined>;
/** Probes Node's wildcard bind by default; callers may scope checks to their owned interface. */
declare function ensurePortAvailable$1(port: number, host?: string, signal?: AbortSignal): Promise<void>;
declare function handlePortError$1(err: unknown, port: number, context: string, runtime?: RuntimeEnv): Promise<never>;
//#endregion
//#region src/config/sessions/disk-budget.d.ts
type SessionDiskBudgetSweepResult = {
totalBytesBefore: number;
totalBytesAfter: number;
removedFiles: number;
removedEntries: number;
freedBytes: number;
maxBytes: number;
highWaterBytes: number;
overBudget: boolean;
};
//#endregion
//#region src/config/sessions/store-maintenance.d.ts
type SessionMaintenanceWarning = {
activeSessionKey: string;
activeUpdatedAt?: number;
totalEntries: number;
pruneAfterMs: number;
maxEntries: number;
wouldPrune: boolean;
wouldCap: boolean;
capOutcome?: "archive" | "remove" | null;
};
type ResolvedSessionMaintenanceConfig = {
mode: SessionMaintenanceMode;
pruneAfterMs: number;
archiveDashboardAfterMs: number | null;
maxEntries: number;
modelRunPruneAfterMs: number;
preserveRecentMs?: number | null;
resetArchiveRetentionMs: number | null;
maxDiskBytes: number | null;
highWaterBytes: number | null;
};
//#endregion
//#region src/config/sessions/store-maintenance-operations.d.ts
type SessionMaintenanceApplyReport = {
mode: ResolvedSessionMaintenanceConfig["mode"];
beforeCount: number;
afterCount: number;
archived: number;
capArchived: number;
modelRunPruned: number;
pruned: number;
capped: number;
diskBudget: SessionDiskBudgetSweepResult | null;
};
//#endregion
//#region src/infra/state-migrations.legacy-session-store.d.ts
type LegacySessionStoreLoadOptions = {
skipCache?: boolean;
maintenanceConfig?: ResolvedSessionMaintenanceConfig;
runMaintenance?: boolean;
clone?: boolean;
hydrateSkillPromptRefs?: boolean;
};
type LegacySessionStoreSaveOptions = {
skipMaintenance?: boolean;
takeCacheOwnership?: boolean;
activeSessionKey?: string;
onWarn?: (warning: SessionMaintenanceWarning) => void | Promise<void>;
onMaintenanceApplied?: (report: SessionMaintenanceApplyReport) => void | Promise<void>;
maintenanceOverride?: Partial<ResolvedSessionMaintenanceConfig>;
maintenanceConfig?: ResolvedSessionMaintenanceConfig;
singleEntryPersistence?: {
sessionKey: string;
entry: SessionEntry;
};
requireWriteSuccess?: boolean;
};
declare function loadLegacySessionStore(storePath: string, options?: LegacySessionStoreLoadOptions): Record<string, SessionEntry>;
declare function saveLegacySessionStore(storePath: string, store: Record<string, SessionEntry>, options?: LegacySessionStoreSaveOptions): Promise<void>;
//#endregion
//#region src/plugins/runtime/runtime-web-channel-plugin.d.ts
type WebChannelHeavyRuntimeModule = {
monitorWebChannel: (...args: unknown[]) => Promise<unknown>;
};
/** Starts web-channel monitoring through the heavy runtime API. */
declare function monitorWebChannel$2(...args: Parameters<WebChannelHeavyRuntimeModule["monitorWebChannel"]>): ReturnType<WebChannelHeavyRuntimeModule["monitorWebChannel"]>;
//#endregion
//#region src/utils.d.ts
/** Normalizes phone-like input into the loose E.164 shape used by channel helpers. */
declare function normalizeE164$1(number: string): string;
declare namespace library_d_exports {
export { PortInUseError$1 as PortInUseError, applyTemplate$1 as applyTemplate, createDefaultDeps$1 as createDefaultDeps, deriveSessionKey$1 as deriveSessionKey, describePortOwner$1 as describePortOwner, ensureBinary$1 as ensureBinary, ensurePortAvailable$1 as ensurePortAvailable, getReplyFromConfig$1 as getReplyFromConfig, handlePortError$1 as handlePortError, loadConfig$1 as loadConfig, loadLegacySessionStore as loadSessionStore, monitorWebChannel$1 as monitorWebChannel, normalizeE164$1 as normalizeE164, promptYesNo$1 as promptYesNo, resolveSessionKey$1 as resolveSessionKey, resolveSessionStorePathCore as resolveStorePath, runCommandWithTimeout$1 as runCommandWithTimeout, runExec$1 as runExec, saveSessionStore$1 as saveSessionStore, waitForever$1 as waitForever };
}
type GetReplyFromConfig = typeof getReplyFromConfig$2;
type PromptYesNo = typeof promptYesNo$2;
type EnsureBinary = typeof ensureBinary$2;
type RunExec = typeof runExec$2;
type RunCommandWithTimeout = typeof runCommandWithTimeout$2;
type MonitorWebChannel = typeof monitorWebChannel$2;
declare const getReplyFromConfig$1: GetReplyFromConfig;
declare const promptYesNo$1: PromptYesNo;
declare const ensureBinary$1: EnsureBinary;
declare const runExec$1: RunExec;
declare const runCommandWithTimeout$1: RunCommandWithTimeout;
declare const monitorWebChannel$1: MonitorWebChannel;
/**
* @deprecated Legacy sessions.json compatibility for package-root consumers.
* Use SQLite-backed session APIs. Remove after 2026-10-12, once the v2026.7.x
* upgrade window no longer requires the legacy doctor importer.
*/
declare function saveSessionStore$1(storePath: string, store: Parameters<typeof saveLegacySessionStore>[1], options?: LegacySessionStoreSaveOptions): Promise<void>;
//#endregion
//#region src/index.d.ts
type LegacyCliDeps = {
runCli: (argv: string[], options?: {
retainConsoleRoutingUntilProcessExit?: boolean;
}) => Promise<void>;
};
type LibraryExports = typeof library_d_exports;
export declare let applyTemplate: LibraryExports["applyTemplate"];
export declare let createDefaultDeps: LibraryExports["createDefaultDeps"];
export declare let deriveSessionKey: LibraryExports["deriveSessionKey"];
export declare let describePortOwner: LibraryExports["describePortOwner"];
export declare let ensureBinary: LibraryExports["ensureBinary"];
export declare let ensurePortAvailable: LibraryExports["ensurePortAvailable"];
export declare let getReplyFromConfig: LibraryExports["getReplyFromConfig"];
export declare let handlePortError: LibraryExports["handlePortError"];
export declare let loadConfig: LibraryExports["loadConfig"];
/** @deprecated Use SQLite-backed session APIs. Scheduled for removal after 2026-10-12. */
export declare let loadSessionStore: LibraryExports["loadSessionStore"];
export declare let monitorWebChannel: LibraryExports["monitorWebChannel"];
export declare let normalizeE164: LibraryExports["normalizeE164"];
export declare let PortInUseError: LibraryExports["PortInUseError"];
export declare let promptYesNo: LibraryExports["promptYesNo"];
export declare let resolveSessionKey: LibraryExports["resolveSessionKey"];
export declare let resolveStorePath: LibraryExports["resolveStorePath"];
export declare let runCommandWithTimeout: LibraryExports["runCommandWithTimeout"];
export declare let runExec: LibraryExports["runExec"];
/** @deprecated Use SQLite-backed session APIs. Scheduled for removal after 2026-10-12. */
export declare let saveSessionStore: LibraryExports["saveSessionStore"];
export declare let waitForever: LibraryExports["waitForever"];
export declare function runLegacyCliEntry(argv?: string[], deps?: LegacyCliDeps, options?: {
retainConsoleRoutingUntilProcessExit?: boolean;
}): Promise<void>;
//#endregion