openclaw / src /auto-reply /get-reply-options.types.ts
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
76289e7 verified
Raw History Blame Contribute Delete
18.7 kB
import type { FastMode } from "@openclaw/normalization-core/string-coerce";
import type { AgentRunTerminalOutcome } from "../agents/agent-run-terminal-outcome.js";
/** Public option types for reply generation callbacks, streaming, and delivery policy. */
import type { ExecutionIdentityAdmissionToken } from "../audit/execution-identity-admission.js";
import type { AgentPlanStep } from "../channels/streaming.js";
import type { TranscriptEntryAnchor } from "../config/sessions/transcript-entry-anchor.js";
import type { ImageContent } from "../llm/types.js";
import type { MediaFact } from "../media/media-facts.js";
import type { PromptImageOrderEntry } from "../media/prompt-image-order.js";
import type { UserTurnTranscriptRecorder } from "../sessions/user-turn-transcript.types.js";
import type { ReplyPayload } from "./reply-payload.js";
import type { TypingController } from "./reply/typing.js";
import type { SourceReplyDeliveryMode } from "./source-reply-delivery-mode.types.js";
export type { SourceReplyDeliveryMode } from "./source-reply-delivery-mode.types.js";
/** A successful runtime append, independent of optional active-path projection anchors. */
export type ReplyDispatchAssistantTranscript = Pick<
TranscriptEntryAnchor,
"agentId" | "sessionId" | "sessionKey" | "storePath"
> & {
messageId: string;
anchor?: TranscriptEntryAnchor;
idempotencyKey: string;
};
export type ReplyDispatchRun = {
completionSource: "reply-dispatch";
getResult: () => {
assistantTranscript?: ReplyDispatchAssistantTranscript;
terminalOutcome?: AgentRunTerminalOutcome;
};
};
export 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. */
export type TypingPolicy =
| "auto"
| "user_message"
| "system_event"
| "internal_webchat"
| "heartbeat";
/** Per-turn policy for source-message reply threading. */
export 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. */
export type TaskSuggestionDeliveryMode = "gateway";
/** Correlates queued reply ownership transfer with later delivery drains. */
export 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.
*/
export 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;
/** Requested cadence for queue-owned deferred heartbeats. */
deferredHeartbeatIntervalMs?: number;
/** 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. */
export 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. */
export type GetReplyOptions = {
/** Channel-owned participant name encoding for source replies sent through message actions. */
groupThreadReplyFormatter?: (
text: string,
participant: { agentId: string; name: string },
) => string;
/** 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;
/** Prepared literal text; unmarked explanations retain authored Markdown. */
explanationFormat?: "plain";
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;
/** Millisecond run timeout override; takes precedence over seconds (0 = no timeout). */
timeoutOverrideMs?: number;
};