fix(cycles): split reply payload and option contracts

This commit is contained in:
Vincent Koc
2026-04-11 22:24:55 +01:00
parent 25665dd335
commit a88fbf0f64
48 changed files with 256 additions and 240 deletions

View File

@@ -8,8 +8,9 @@ import {
type TextContent,
} from "@mariozechner/pi-ai";
import { SessionManager } from "@mariozechner/pi-coding-agent";
import type { GetReplyOptions } from "../auto-reply/get-reply-options.types.js";
import type { ReplyPayload } from "../auto-reply/reply-payload.js";
import type { ReasoningLevel, ThinkLevel } from "../auto-reply/thinking.js";
import type { GetReplyOptions, ReplyPayload } from "../auto-reply/types.js";
import {
resolveSessionFilePath,
resolveSessionFilePathOptions,

View File

@@ -1,6 +1,6 @@
import { resolveSessionAgentId } from "../../agents/agent-scope.js";
import type { ReplyPayload } from "../../auto-reply/reply-payload.js";
import { normalizeReplyPayload } from "../../auto-reply/reply/normalize-reply.js";
import type { ReplyPayload } from "../../auto-reply/types.js";
import { getChannelPlugin, normalizeChannelId } from "../../channels/plugins/index.js";
import { createReplyPrefixContext } from "../../channels/reply-prefix.js";
import { createOutboundSendDeps, type CliDeps } from "../../cli/outbound-send-deps.js";

View File

@@ -1,7 +1,7 @@
import type { ImageContent } from "@mariozechner/pi-ai";
import type { ReplyPayload } from "../../../auto-reply/reply-payload.js";
import type { ReplyOperation } from "../../../auto-reply/reply/reply-run-registry.js";
import type { ReasoningLevel, ThinkLevel, VerboseLevel } from "../../../auto-reply/thinking.js";
import type { ReplyPayload } from "../../../auto-reply/types.js";
import type { OpenClawConfig } from "../../../config/types.openclaw.js";
import type { PromptImageOrderEntry } from "../../../media/prompt-image-order.js";
import type { CommandQueueEnqueueFn } from "../../../process/command-queue.types.js";

View File

@@ -1,9 +1,9 @@
import type { AgentMessage } from "@mariozechner/pi-agent-core";
import { setReplyPayloadMetadata } from "../auto-reply/reply-payload.js";
import { parseReplyDirectives } from "../auto-reply/reply/reply-directives.js";
import { createStreamingDirectiveAccumulator } from "../auto-reply/reply/streaming-directives.js";
import { isSilentReplyText, SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js";
import { formatToolAggregate } from "../auto-reply/tool-meta.js";
import { setReplyPayloadMetadata } from "../auto-reply/types.js";
import { emitAgentEvent } from "../infra/agent-events.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import type { InlineCodeState } from "../markdown/code-spans.js";

View File

@@ -1,6 +1,6 @@
import type { AgentSession } from "@mariozechner/pi-coding-agent";
import type { ReplyPayload } from "../auto-reply/reply-payload.js";
import type { ReasoningLevel, VerboseLevel } from "../auto-reply/thinking.js";
import type { ReplyPayload } from "../auto-reply/types.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import type { HookRunner } from "../plugins/hooks.js";
import type { AgentInternalEvent } from "./internal-events.js";

View File

@@ -0,0 +1,149 @@
import type { ImageContent } from "@mariozechner/pi-ai";
import type { PromptImageOrderEntry } from "../media/prompt-image-order.js";
import type { ReplyPayload } from "./reply-payload.js";
import type { TypingController } from "./reply/typing.js";
export type BlockReplyContext = {
abortSignal?: AbortSignal;
timeoutMs?: number;
/** Source assistant message index from the upstream stream, when available. */
assistantMessageIndex?: number;
};
/** Context passed to onModelSelected callback with actual model used. */
export type ModelSelectedContext = {
provider: string;
model: string;
thinkLevel: string | undefined;
};
export type TypingPolicy =
| "auto"
| "user_message"
| "system_event"
| "internal_webchat"
| "heartbeat";
export type ReplyThreadingPolicy = {
/** Override implicit reply-to-current behavior for the current turn. */
implicitCurrentMessage?: "default" | "allow" | "deny";
};
export type GetReplyOptions = {
/** Override run id for agent events (defaults to random UUID). */
runId?: string;
/** Abort signal for the underlying agent run. */
abortSignal?: AbortSignal;
/** Optional inbound images (used for webchat attachments). */
images?: ImageContent[];
/** Original inline/offloaded attachment order for inbound images. */
imageOrder?: PromptImageOrderEntry[];
/** Notifies when an agent run actually starts (useful for webchat command handling). */
onAgentRunStart?: (runId: string) => void;
onReplyStart?: () => Promise<void> | void;
/** Called when the typing controller cleans up (e.g., run ended with NO_REPLY). */
onTypingCleanup?: () => void;
onTypingController?: (typing: TypingController) => void;
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;
/** Controls bootstrap workspace context injection (default: full). */
bootstrapContextMode?: "full" | "lightweight";
/** If true, suppress tool error warning payloads for this run. */
suppressToolErrorWarnings?: boolean;
onPartialReply?: (payload: ReplyPayload) => Promise<void> | void;
onReasoningStream?: (payload: ReplyPayload) => Promise<void> | void;
/** Called when a thinking/reasoning block ends. */
onReasoningEnd?: () => Promise<void> | void;
/** Called when a new assistant message starts (e.g., after tool call or thinking block). */
onAssistantMessageStart?: () => Promise<void> | void;
/** 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<void> | void;
onBlockReply?: (payload: ReplyPayload, context?: BlockReplyContext) => Promise<void> | void;
onToolResult?: (payload: ReplyPayload) => Promise<void> | void;
/** Called when a tool phase starts/updates, before summary payloads are emitted. */
onToolStart?: (payload: { name?: string; phase?: string }) => Promise<void> | void;
/** Called when a concrete work item starts, updates, or completes. */
onItemEvent?: (payload: {
itemId?: string;
kind?: string;
title?: string;
name?: string;
phase?: string;
status?: string;
summary?: string;
progressText?: string;
approvalId?: string;
approvalSlug?: string;
}) => Promise<void> | void;
/** Called when the agent emits a structured plan update. */
onPlanUpdate?: (payload: {
phase?: string;
title?: string;
explanation?: string;
steps?: string[];
source?: string;
}) => Promise<void> | void;
/** 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;
message?: string;
}) => Promise<void> | void;
/** 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<void> | void;
/** 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<void> | void;
/** Called when context auto-compaction starts (allows UX feedback during the pause). */
onCompactionStart?: () => Promise<void> | void;
/** Called when context auto-compaction completes. */
onCompactionEnd?: () => Promise<void> | void;
/** 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;
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;
};

View File

@@ -0,0 +1,46 @@
import type { InteractiveReply } from "../interactive/payload.js";
export type ReplyPayload = {
text?: string;
mediaUrl?: string;
mediaUrls?: string[];
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;
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 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;
/** Channel-specific payload data (per-channel envelope). */
channelData?: Record<string, unknown>;
};
export type ReplyPayloadMetadata = {
assistantMessageIndex?: number;
};
const replyPayloadMetadata = new WeakMap<object, ReplyPayloadMetadata>();
export function setReplyPayloadMetadata<T extends object>(
payload: T,
metadata: ReplyPayloadMetadata,
): T {
const previous = replyPayloadMetadata.get(payload);
replyPayloadMetadata.set(payload, { ...previous, ...metadata });
return payload;
}
export function getReplyPayloadMetadata(payload: object): ReplyPayloadMetadata | undefined {
return replyPayloadMetadata.get(payload);
}

View File

@@ -48,9 +48,10 @@ import {
shouldAttemptTtsPayload,
} from "../../tts/tts-config.js";
import { INTERNAL_MESSAGE_CHANNEL, normalizeMessageChannel } from "../../utils/message-channel.js";
import type { BlockReplyContext } from "../get-reply-options.types.js";
import { getReplyPayloadMetadata, type ReplyPayload } from "../reply-payload.js";
import type { FinalizedMsgContext } from "../templating.js";
import { normalizeVerboseLevel } from "../thinking.js";
import { getReplyPayloadMetadata, type BlockReplyContext, type ReplyPayload } from "../types.js";
import {
createInternalHookEvent,
loadSessionStore,

View File

@@ -1,6 +1,6 @@
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import type { GetReplyOptions } from "../get-reply-options.types.js";
import type { FinalizedMsgContext } from "../templating.js";
import type { GetReplyOptions } from "../types.js";
import type { ReplyDispatchKind, ReplyDispatcher } from "./reply-dispatcher.types.js";
export type DispatchFromConfigResult = {

View File

@@ -13,10 +13,11 @@ import { type OpenClawConfig, loadConfig } from "../../config/config.js";
import { defaultRuntime } from "../../runtime.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import { normalizeStringEntries } from "../../shared/string-normalization.js";
import type { GetReplyOptions } from "../get-reply-options.types.js";
import type { ReplyPayload } from "../reply-payload.js";
import type { MsgContext } from "../templating.js";
import { normalizeVerboseLevel } from "../thinking.js";
import { SILENT_REPLY_TOKEN } from "../tokens.js";
import type { GetReplyOptions, ReplyPayload } from "../types.js";
import { resolveDefaultModel } from "./directive-handling.defaults.js";
import { clearInlineDirectives } from "./get-reply-directives-utils.js";
import { resolveReplyDirectives } from "./get-reply-directives.js";

View File

@@ -1,6 +1,7 @@
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import type { GetReplyOptions } from "../get-reply-options.types.js";
import type { ReplyPayload } from "../reply-payload.js";
import type { MsgContext } from "../templating.js";
import type { GetReplyOptions, ReplyPayload } from "../types.js";
export type GetReplyFromConfig = (
ctx: MsgContext,

View File

@@ -1,6 +1,6 @@
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import type { GetReplyOptions } from "../get-reply-options.types.js";
import type { FinalizedMsgContext, MsgContext } from "../templating.js";
import type { GetReplyOptions } from "../types.js";
import type { DispatchFromConfigResult } from "./dispatch-from-config.types.js";
import type { GetReplyFromConfig } from "./get-reply.types.js";
import type {

View File

@@ -1,194 +1,9 @@
import type { ImageContent } from "@mariozechner/pi-ai";
import type { InteractiveReply } from "../interactive/payload.js";
import type { PromptImageOrderEntry } from "../media/prompt-image-order.js";
import type { TypingController } from "./reply/typing.js";
export type BlockReplyContext = {
abortSignal?: AbortSignal;
timeoutMs?: number;
/** Source assistant message index from the upstream stream, when available. */
assistantMessageIndex?: number;
};
/** Context passed to onModelSelected callback with actual model used. */
export type ModelSelectedContext = {
provider: string;
model: string;
thinkLevel: string | undefined;
};
export type TypingPolicy =
| "auto"
| "user_message"
| "system_event"
| "internal_webchat"
| "heartbeat";
export type ReplyThreadingPolicy = {
/** Override implicit reply-to-current behavior for the current turn. */
implicitCurrentMessage?: "default" | "allow" | "deny";
};
export type GetReplyOptions = {
/** Override run id for agent events (defaults to random UUID). */
runId?: string;
/** Abort signal for the underlying agent run. */
abortSignal?: AbortSignal;
/** Optional inbound images (used for webchat attachments). */
images?: ImageContent[];
/** Original inline/offloaded attachment order for inbound images. */
imageOrder?: PromptImageOrderEntry[];
/** Notifies when an agent run actually starts (useful for webchat command handling). */
onAgentRunStart?: (runId: string) => void;
onReplyStart?: () => Promise<void> | void;
/** Called when the typing controller cleans up (e.g., run ended with NO_REPLY). */
onTypingCleanup?: () => void;
onTypingController?: (typing: TypingController) => void;
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;
/** Controls bootstrap workspace context injection (default: full). */
bootstrapContextMode?: "full" | "lightweight";
/** If true, suppress tool error warning payloads for this run. */
suppressToolErrorWarnings?: boolean;
onPartialReply?: (payload: ReplyPayload) => Promise<void> | void;
onReasoningStream?: (payload: ReplyPayload) => Promise<void> | void;
/** Called when a thinking/reasoning block ends. */
onReasoningEnd?: () => Promise<void> | void;
/** Called when a new assistant message starts (e.g., after tool call or thinking block). */
onAssistantMessageStart?: () => Promise<void> | void;
/** 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<void> | void;
onBlockReply?: (payload: ReplyPayload, context?: BlockReplyContext) => Promise<void> | void;
onToolResult?: (payload: ReplyPayload) => Promise<void> | void;
/** Called when a tool phase starts/updates, before summary payloads are emitted. */
onToolStart?: (payload: { name?: string; phase?: string }) => Promise<void> | void;
/** Called when a concrete work item starts, updates, or completes. */
onItemEvent?: (payload: {
itemId?: string;
kind?: string;
title?: string;
name?: string;
phase?: string;
status?: string;
summary?: string;
progressText?: string;
approvalId?: string;
approvalSlug?: string;
}) => Promise<void> | void;
/** Called when the agent emits a structured plan update. */
onPlanUpdate?: (payload: {
phase?: string;
title?: string;
explanation?: string;
steps?: string[];
source?: string;
}) => Promise<void> | void;
/** 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;
message?: string;
}) => Promise<void> | void;
/** 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<void> | void;
/** 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<void> | void;
/** Called when context auto-compaction starts (allows UX feedback during the pause). */
onCompactionStart?: () => Promise<void> | void;
/** Called when context auto-compaction completes. */
onCompactionEnd?: () => Promise<void> | void;
/** 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;
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;
};
export type ReplyPayload = {
text?: string;
mediaUrl?: string;
mediaUrls?: string[];
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;
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 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;
/** Channel-specific payload data (per-channel envelope). */
channelData?: Record<string, unknown>;
};
export type ReplyPayloadMetadata = {
assistantMessageIndex?: number;
};
const replyPayloadMetadata = new WeakMap<object, ReplyPayloadMetadata>();
export function setReplyPayloadMetadata<T extends object>(
payload: T,
metadata: ReplyPayloadMetadata,
): T {
const previous = replyPayloadMetadata.get(payload);
replyPayloadMetadata.set(payload, { ...previous, ...metadata });
return payload;
}
export function getReplyPayloadMetadata(payload: object): ReplyPayloadMetadata | undefined {
return replyPayloadMetadata.get(payload);
}
export type {
BlockReplyContext,
GetReplyOptions,
ModelSelectedContext,
ReplyThreadingPolicy,
TypingPolicy,
} from "./get-reply-options.types.js";
export { getReplyPayloadMetadata, setReplyPayloadMetadata } from "./reply-payload.js";
export type { ReplyPayload, ReplyPayloadMetadata } from "./reply-payload.js";

View File

@@ -1,4 +1,4 @@
import type { ReplyPayload } from "../../auto-reply/types.js";
import type { ReplyPayload } from "../../auto-reply/reply-payload.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import { getChannelPlugin, normalizeChannelId } from "./registry.js";

View File

@@ -1,4 +1,4 @@
import type { ReplyPayload } from "../../auto-reply/types.js";
import type { ReplyPayload } from "../../auto-reply/reply-payload.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import type { OutboundDeliveryResult } from "../../infra/outbound/deliver-types.js";
import type { OutboundIdentity } from "../../infra/outbound/identity-types.js";

View File

@@ -1,4 +1,4 @@
import type { ReplyPayload } from "../../auto-reply/types.js";
import type { ReplyPayload } from "../../auto-reply/reply-payload.js";
import type { LegacyConfigRule } from "../../config/legacy.shared.js";
import type { AgentBinding } from "../../config/types.agents.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";

View File

@@ -1,7 +1,7 @@
import type { AgentTool, AgentToolResult } from "@mariozechner/pi-agent-core";
import type { TSchema } from "@sinclair/typebox";
import type { ReplyPayload } from "../../auto-reply/reply-payload.js";
import type { MsgContext } from "../../auto-reply/templating.js";
import type { ReplyPayload } from "../../auto-reply/types.js";
import type { MarkdownTableMode } from "../../config/types.base.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import type { GatewayClientMode, GatewayClientName } from "../../gateway/protocol/client-info.js";

View File

@@ -1,9 +1,9 @@
import { resolveAgentIdentity, resolveEffectiveMessagesConfig } from "../agents/identity.js";
import type { GetReplyOptions } from "../auto-reply/get-reply-options.types.js";
import {
extractShortModelName,
type ResponsePrefixContext,
} from "../auto-reply/reply/response-prefix-template.js";
import type { GetReplyOptions } from "../auto-reply/types.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";

View File

@@ -1,6 +1,6 @@
import { countActiveDescendantRuns } from "../../agents/subagent-registry-read.js";
import type { ReplyPayload } from "../../auto-reply/reply-payload.js";
import { isSilentReplyText, SILENT_REPLY_TOKEN } from "../../auto-reply/tokens.js";
import type { ReplyPayload } from "../../auto-reply/types.js";
import type { CliDeps } from "../../cli/outbound-send-deps.js";
import {
resolveAgentMainSessionKey,

View File

@@ -1,6 +1,6 @@
import { hasOutboundReplyContent } from "openclaw/plugin-sdk/reply-payload";
import { DEFAULT_HEARTBEAT_ACK_MAX_CHARS } from "../../auto-reply/heartbeat.js";
import type { ReplyPayload } from "../../auto-reply/types.js";
import type { ReplyPayload } from "../../auto-reply/reply-payload.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import { truncateUtf16Safe } from "../../utils.js";
import { shouldSkipHeartbeatOnlyDelivery } from "../heartbeat-policy.js";

View File

@@ -1,7 +1,7 @@
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import type { ReplyPayload } from "../../auto-reply/types.js";
import type { ReplyPayload } from "../../auto-reply/reply-payload.js";
import { isAudioFileName } from "../../media/mime.js";
import { resolveSendableOutboundReplyParts } from "../../plugin-sdk/reply-payload.js";
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";

View File

@@ -7,9 +7,9 @@ import { resolveThinkingDefault } from "../../agents/model-selection.js";
import { rewriteTranscriptEntriesInSessionFile } from "../../agents/pi-embedded-runner/transcript-rewrite.js";
import { resolveAgentTimeoutMs } from "../../agents/timeout.js";
import { dispatchInboundMessage } from "../../auto-reply/dispatch.js";
import type { ReplyPayload } from "../../auto-reply/reply-payload.js";
import { createReplyDispatcher } from "../../auto-reply/reply/reply-dispatcher.js";
import type { MsgContext } from "../../auto-reply/templating.js";
import type { ReplyPayload } from "../../auto-reply/types.js";
import { extractCanvasFromText } from "../../chat/canvas-render.js";
import { resolveSessionFilePath } from "../../config/sessions.js";
import { jsonUtf8Bytes } from "../../infra/json-utf8-bytes.js";

View File

@@ -2,7 +2,7 @@ import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterAll, beforeAll, describe, expect, test, vi } from "vitest";
import type { GetReplyOptions } from "../auto-reply/types.js";
import type { GetReplyOptions } from "../auto-reply/get-reply-options.types.js";
import { clearConfigCache } from "../config/config.js";
import { __setMaxChatHistoryMessagesBytesForTest } from "./server-constants.js";
import {

View File

@@ -2,8 +2,9 @@ import crypto from "node:crypto";
import os from "node:os";
import path from "node:path";
import { Mock, vi } from "vitest";
import type { GetReplyOptions } from "../auto-reply/get-reply-options.types.js";
import type { ReplyPayload } from "../auto-reply/reply-payload.js";
import type { MsgContext } from "../auto-reply/templating.js";
import type { GetReplyOptions, ReplyPayload } from "../auto-reply/types.js";
import type { AgentBinding } from "../config/types.agents.js";
import type { HooksConfig } from "../config/types.hooks.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";

View File

@@ -1,4 +1,4 @@
import type { ReplyPayload } from "../auto-reply/types.js";
import type { ReplyPayload } from "../auto-reply/reply-payload.js";
import type { ExecApprovalForwardTarget } from "../config/types.approvals.js";
import { matchesApprovalRequestFilters } from "../infra/approval-request-filters.js";
import { getExecApprovalReplyMetadata } from "../infra/exec-approval-reply.js";

View File

@@ -1,4 +1,4 @@
import type { ReplyPayload } from "../auto-reply/types.js";
import type { ReplyPayload } from "../auto-reply/reply-payload.js";
import {
buildApprovalInteractiveReply,
type ExecApprovalReplyDecision,

View File

@@ -1,4 +1,4 @@
import type { ReplyPayload } from "../auto-reply/types.js";
import type { ReplyPayload } from "../auto-reply/reply-payload.js";
import { getChannelPlugin, normalizeChannelId } from "../channels/plugins/index.js";
import {
createReplyPrefixContext,

View File

@@ -99,7 +99,7 @@ export type {
export type { OpenClawConfig } from "../config/config.js";
export type { OutboundIdentity } from "../infra/outbound/identity.js";
export type { HistoryEntry } from "../auto-reply/reply/history.js";
export type { ReplyPayload } from "../auto-reply/types.js";
export type { ReplyPayload } from "../auto-reply/reply-payload.js";
export type { AllowlistMatch } from "../channels/allowlist-match.js";
export type {
BaseProbeResult,

View File

@@ -8,7 +8,7 @@ export {
DEFAULT_GROUP_HISTORY_LIMIT,
recordPendingHistoryEntryIfEnabled,
} from "../auto-reply/reply/history.js";
export type { ReplyPayload } from "../auto-reply/types.js";
export type { ReplyPayload } from "../auto-reply/reply-payload.js";
export { logTypingFailure } from "../channels/logging.js";
export type { AllowlistMatch } from "../channels/plugins/allowlist-match.js";
export { buildChannelConfigSchema } from "../channels/plugins/config-schema.js";

View File

@@ -1,4 +1,5 @@
import { withReplyDispatcher } from "../auto-reply/dispatch.js";
import type { GetReplyOptions } from "../auto-reply/get-reply-options.types.js";
import {
dispatchReplyFromConfig,
type DispatchFromConfigResult,
@@ -6,7 +7,6 @@ import {
import type { DispatchReplyWithBufferedBlockDispatcher } from "../auto-reply/reply/provider-dispatcher.types.js";
import type { ReplyDispatcher } from "../auto-reply/reply/reply-dispatcher.types.js";
import type { FinalizedMsgContext } from "../auto-reply/templating.js";
import type { GetReplyOptions } from "../auto-reply/types.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { createChannelReplyPipeline } from "./channel-reply-pipeline.js";
import { createNormalizedOutboundDeliverer, type OutboundReplyPayload } from "./reply-payload.js";

View File

@@ -90,7 +90,7 @@ export * from "./music-generation.js";
export type { SecretInput, SecretRef } from "../config/types.secrets.js";
export type { RuntimeEnv } from "../runtime.js";
export type { HookEntry } from "../hooks/types.js";
export type { ReplyPayload } from "../auto-reply/types.js";
export type { ReplyPayload } from "../auto-reply/reply-payload.js";
export type { WizardPrompter } from "../wizard/prompts.js";
export type { ContextEngineFactory } from "../context-engine/registry.js";
export type { DiagnosticEventPayload } from "../infra/diagnostic-events.js";

View File

@@ -5,7 +5,7 @@ export type {
} from "../channels/plugins/types.public.js";
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
export type { OpenClawConfig } from "../config/config.js";
export type { ReplyPayload } from "../auto-reply/types.js";
export type { ReplyPayload } from "../auto-reply/reply-payload.js";
export type { ChannelSetupAdapter } from "../channels/plugins/types.adapters.js";
export type { OpenClawPluginApi, PluginRuntime } from "./channel-plugin-common.js";

View File

@@ -24,7 +24,8 @@ export {
readStringArrayParam,
readStringParam,
} from "../agents/tools/common.js";
export type { BlockReplyContext, ReplyPayload } from "../auto-reply/types.js";
export type { BlockReplyContext } from "../auto-reply/get-reply-options.types.js";
export type { ReplyPayload } from "../auto-reply/reply-payload.js";
export { resolveAckReaction } from "../agents/identity.js";
export {
compileAllowlist,

View File

@@ -10,7 +10,7 @@ export {
recordPendingHistoryEntryIfEnabled,
} from "../auto-reply/reply/history.js";
export { listSkillCommandsForAgents } from "../auto-reply/skill-commands.js";
export type { ReplyPayload } from "../auto-reply/types.js";
export type { ReplyPayload } from "../auto-reply/reply-payload.js";
export type { ChatType } from "../channels/chat-type.js";
export { resolveControlCommandGate } from "../channels/command-gating.js";
export { logInboundDrop, logTypingFailure } from "../channels/logging.js";

View File

@@ -12,7 +12,7 @@ export {
recordPendingHistoryEntryIfEnabled,
} from "../auto-reply/reply/history.js";
export { isSilentReplyText, SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js";
export type { ReplyPayload } from "../auto-reply/types.js";
export type { ReplyPayload } from "../auto-reply/reply-payload.js";
export { mergeAllowlist, summarizeMapping } from "../channels/allowlists/resolve-utils.js";
export {
resolveControlCommandGate,

View File

@@ -7,4 +7,4 @@ export {
} from "../auto-reply/chunk.js";
export type { ChunkMode } from "../auto-reply/chunk.js";
export { isSilentReplyText } from "../auto-reply/tokens.js";
export type { ReplyPayload } from "../auto-reply/types.js";
export type { ReplyPayload } from "../auto-reply/reply-payload.js";

View File

@@ -4,4 +4,4 @@ export {
dispatchReplyWithBufferedBlockDispatcher,
dispatchReplyWithDispatcher,
} from "../auto-reply/reply/provider-dispatcher.js";
export type { ReplyPayload } from "../auto-reply/types.js";
export type { ReplyPayload } from "../auto-reply/reply-payload.js";

View File

@@ -3,7 +3,7 @@ import { readStringValue } from "../shared/string-coerce.js";
export type { MediaPayload, MediaPayloadInput } from "../channels/plugins/media-payload.js";
export { buildMediaPayload } from "../channels/plugins/media-payload.js";
export type { ReplyPayload } from "../auto-reply/types.js";
export type { ReplyPayload } from "../auto-reply/reply-payload.js";
export type OutboundReplyPayload = {
text?: string;

View File

@@ -3,4 +3,4 @@ export {
isSingleUseReplyToMode,
} from "../auto-reply/reply/reply-reference.js";
export { resolveBatchedReplyThreadingPolicy } from "../auto-reply/reply/reply-threading.js";
export type { ReplyThreadingPolicy } from "../auto-reply/types.js";
export type { ReplyThreadingPolicy } from "../auto-reply/get-reply-options.types.js";

View File

@@ -53,8 +53,8 @@ export type {
ReplyDispatcherWithTypingOptions,
} from "../auto-reply/reply/reply-dispatcher.js";
export { createReplyReferencePlanner } from "../auto-reply/reply/reply-reference.js";
export type { GetReplyOptions, ReplyPayload } from "../auto-reply/types.js";
export type { BlockReplyContext } from "../auto-reply/types.js";
export type { GetReplyOptions, BlockReplyContext } from "../auto-reply/get-reply-options.types.js";
export type { ReplyPayload } from "../auto-reply/reply-payload.js";
export type { FinalizedMsgContext, MsgContext } from "../auto-reply/templating.js";
export { generateConversationLabel } from "../auto-reply/reply/conversation-label-generator.js";
export type { ConversationLabelParams } from "../auto-reply/reply/conversation-label-generator.js";

View File

@@ -3,7 +3,7 @@
import { createOptionalChannelSetupSurface } from "./channel-setup.js";
export type { ReplyPayload } from "../auto-reply/types.js";
export type { ReplyPayload } from "../auto-reply/reply-payload.js";
export { buildChannelConfigSchema } from "../channels/plugins/config-schema.js";
export {
applyAccountNameToChannelSection,

View File

@@ -3,7 +3,7 @@
import { createOptionalChannelSetupSurface } from "./channel-setup.js";
export type { ReplyPayload } from "../auto-reply/types.js";
export type { ReplyPayload } from "../auto-reply/reply-payload.js";
export { buildChannelConfigSchema } from "../channels/plugins/config-schema.js";
export type {
ChannelGatewayContext,

View File

@@ -2,7 +2,7 @@
// Keep this list additive and scoped to the bundled Zalo surface.
export { jsonResult, readStringParam } from "../agents/tools/common.js";
export type { ReplyPayload } from "../auto-reply/types.js";
export type { ReplyPayload } from "../auto-reply/reply-payload.js";
export {
deleteAccountFromConfigSection,
setAccountEnabledInConfigSection,

View File

@@ -3,7 +3,7 @@
import { createOptionalChannelSetupSurface } from "./channel-setup.js";
export type { ReplyPayload } from "../auto-reply/types.js";
export type { ReplyPayload } from "../auto-reply/reply-payload.js";
export { mergeAllowlist, summarizeMapping } from "../channels/allowlists/resolve-utils.js";
export {
resolveMentionGating,

View File

@@ -1,7 +1,7 @@
import crypto from "node:crypto";
import fs from "node:fs";
import path from "node:path";
import type { ReplyPayload } from "../auto-reply/types.js";
import type { ReplyPayload } from "../auto-reply/reply-payload.js";
import {
createConversationBindingRecord,
resolveConversationBindingRecord,

View File

@@ -1,4 +1,4 @@
import type { ReplyPayload } from "../auto-reply/types.js";
import type { ReplyPayload } from "../auto-reply/reply-payload.js";
export type PluginConversationBindingRequestParams = {
summary?: string;

View File

@@ -1,10 +1,10 @@
import type { AgentMessage } from "@mariozechner/pi-agent-core";
import type { ReplyPayload } from "../auto-reply/reply-payload.js";
import type {
ReplyDispatchKind,
ReplyDispatcher,
} from "../auto-reply/reply/reply-dispatcher.types.js";
import type { FinalizedMsgContext } from "../auto-reply/templating.js";
import type { ReplyPayload } from "../auto-reply/types.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import type { TtsAutoMode } from "../config/types.tts.js";
import {

View File

@@ -17,8 +17,8 @@ import type { ModelProviderRequestTransportOverrides } from "../agents/provider-
import type { ProviderSystemPromptContribution } from "../agents/system-prompt-contribution.js";
import type { PromptMode } from "../agents/system-prompt.types.js";
import type { AnyAgentTool } from "../agents/tools/common.js";
import type { ReplyPayload } from "../auto-reply/reply-payload.js";
import type { ThinkLevel } from "../auto-reply/thinking.shared.js";
import type { ReplyPayload } from "../auto-reply/types.js";
import type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
import type { ChannelId } from "../channels/plugins/types.public.js";
import type { ModelProviderConfig } from "../config/types.js";