refactor(auto-reply): trim internal export surface (#106409)

* refactor(auto-reply): trim internal export surface

* chore(deadcode): update auto-reply export baseline
This commit is contained in:
Peter Steinberger
2026-07-13 06:17:20 -07:00
committed by GitHub
parent 7cc40d9e46
commit b76a7f453b
28 changed files with 104 additions and 118 deletions

View File

@@ -1254,22 +1254,16 @@ export const KNIP_UNUSED_EXPORT_BASELINE = [
"src/auto-reply/command-detection.runtime-types.ts: IsControlCommandMessage",
"src/auto-reply/command-detection.runtime-types.ts: ShouldComputeCommandAuthorized",
"src/auto-reply/commands-registry.runtime-types.ts: ShouldHandleTextCommands",
"src/auto-reply/reply-payload.ts: buildPairingQrReplyChannelData",
"src/auto-reply/reply/abort.ts: getAbortMemory",
"src/auto-reply/reply/abort.ts: getAbortMemorySizeForTest",
"src/auto-reply/reply/abort.ts: resetAbortMemoryForTest",
"src/auto-reply/reply/abort.ts: testing",
"src/auto-reply/reply/acp-reset-target.ts: testing",
"src/auto-reply/reply/agent-runner-cli-dispatch.ts: ReasoningProgressPayload",
"src/auto-reply/reply/agent-runner-cli-dispatch.ts: ReasoningTextPayload",
"src/auto-reply/reply/agent-runner-execution.ts: AgentRunLoopResult",
"src/auto-reply/reply/agent-runner-execution.ts: buildContextOverflowRecoveryText",
"src/auto-reply/reply/agent-runner-execution.ts: computeContextAwareReserveTokensFloor",
"src/auto-reply/reply/agent-runner-execution.ts: MAX_LIVE_SWITCH_RETRIES",
"src/auto-reply/reply/agent-runner-memory.ts: setAgentRunnerMemoryTestDeps",
"src/auto-reply/reply/agent-runner-session-reset.ts: setAgentRunnerSessionResetTestDeps",
"src/auto-reply/reply/agent-runner-utils.ts: buildEmbeddedRunBaseParams",
"src/auto-reply/reply/agent-runner-utils.ts: resolveProviderScopedAuthProfile",
"src/auto-reply/reply/block-reply-pipeline.ts: createBlockReplyPayloadKey",
"src/auto-reply/reply/commands-diagnostics.ts: createDiagnosticsCommandHandler",
"src/auto-reply/reply/commands-login.ts: testing",
@@ -1277,7 +1271,6 @@ export const KNIP_UNUSED_EXPORT_BASELINE = [
"src/auto-reply/reply/commands-name.ts: parseNameCommand",
"src/auto-reply/reply/commands-setunset.ts: parseSetUnsetCommand",
"src/auto-reply/reply/commands-setunset.ts: parseSetUnsetCommandAction",
"src/auto-reply/reply/commands-subagents/shared.ts: COMMAND",
"src/auto-reply/reply/commands-tasks.ts: buildTasksReply",
"src/auto-reply/reply/completion-delivery-policy.ts: resolveCompletionChatType",
"src/auto-reply/reply/delivery-hints.ts: MESSAGE_TOOL_ONLY_DELIVERY_HINT",
@@ -1286,8 +1279,6 @@ export const KNIP_UNUSED_EXPORT_BASELINE = [
"src/auto-reply/reply/dispatch-from-config.ts: testing",
"src/auto-reply/reply/dispatch-from-config.types.ts: DispatchReplyFromConfig",
"src/auto-reply/reply/dispatcher-registry.ts: clearAllDispatchers",
"src/auto-reply/reply/effective-reply-route.ts: EffectiveReplyRouteContext",
"src/auto-reply/reply/effective-reply-route.ts: EffectiveReplyRouteEntry",
"src/auto-reply/reply/get-reply-directives-apply.ts: formatModelOverrideResetEvent",
"src/auto-reply/reply/get-reply-fast-path.ts: markCompleteReplyConfig",
"src/auto-reply/reply/get-reply-fast-path.ts: withFastReplyConfig",
@@ -1296,23 +1287,15 @@ export const KNIP_UNUSED_EXPORT_BASELINE = [
"src/auto-reply/reply/get-reply-run.ts: resolvePromptSilentReplyConversationType",
"src/auto-reply/reply/history.ts: appendHistoryEntry",
"src/auto-reply/reply/inbound-dedupe.ts: buildInboundDedupeKey",
"src/auto-reply/reply/inbound-dedupe.ts: InboundDedupeClaimResult",
"src/auto-reply/reply/mentions.types.ts: BuildMentionRegexes",
"src/auto-reply/reply/mentions.types.ts: MatchesMentionPatterns",
"src/auto-reply/reply/mentions.types.ts: MatchesMentionWithExplicit",
"src/auto-reply/reply/progress-narrator.ts: createProgressNarrator",
"src/auto-reply/reply/progress-narrator.ts: ProgressNarrationInput",
"src/auto-reply/reply/prompt-prelude.ts: buildReplyPromptBodies",
"src/auto-reply/reply/provider-request-error-classifier.ts: PROVIDER_AUTHENTICATION_ERROR_USER_MESSAGE",
"src/auto-reply/reply/provider-request-error-classifier.ts: PROVIDER_INTERNAL_ERROR_USER_MESSAGE",
"src/auto-reply/reply/provider-request-error-classifier.ts: PROVIDER_MODEL_UNAVAILABLE_USER_MESSAGE",
"src/auto-reply/reply/provider-request-error-classifier.ts: PROVIDER_RATE_LIMIT_OR_QUOTA_ERROR_USER_MESSAGE",
"src/auto-reply/reply/queue.ts: resetRecentQueuedMessageIdDedupe",
"src/auto-reply/reply/queue/cleanup.ts: testing",
"src/auto-reply/reply/queue/drain.ts: resolveFollowupAuthorizationKey",
"src/auto-reply/reply/queue/enqueue.ts: resetRecentQueuedMessageIdDedupe",
"src/auto-reply/reply/reply-dispatcher.runtime-types.ts: CreateReplyDispatcherWithTyping",
"src/auto-reply/reply/reply-operation-run-state.ts: ReplyOptionsWithOperationRunState",
"src/auto-reply/reply/reply-payloads-dedupe.ts: getMatchingMessagingToolReplyTargets",
"src/auto-reply/reply/reply-run-registry.ts: __testing",
"src/auto-reply/reply/reply-run-registry.ts: testing",
@@ -1320,13 +1303,10 @@ export const KNIP_UNUSED_EXPORT_BASELINE = [
"src/auto-reply/reply/reply-threading.ts: resolveConfiguredReplyToMode",
"src/auto-reply/reply/reply-threading.ts: resolveReplyToModeWithThreading",
"src/auto-reply/reply/reply-usage-state.ts: clearReplyUsageStateForTest",
"src/auto-reply/reply/session-fork.ts: ForkSessionEntryFromParentParams",
"src/auto-reply/reply/session-fork.ts: ForkSessionEntryFromParentResult",
"src/auto-reply/reply/session-reset-prompt.ts: buildBareSessionResetPrompt",
"src/auto-reply/reply/stage-sandbox-media.ts: appendScpStderrTail",
"src/auto-reply/reply/stage-sandbox-media.ts: SCP_STDERR_TAIL_CHARS",
"src/auto-reply/reply/stage-sandbox-media.ts: testing",
"src/auto-reply/reply/stranded-reply-recovery.ts: STRANDED_REPLY_RETRY_MARKER",
"src/auto-reply/usage-bar/template.ts: clearUsageBarTemplateCacheForTest",
"src/cli/channel-options.ts: testing",
"src/cli/command-path-policy.ts: resolveCliCatalogCommandPath",

View File

@@ -1,13 +1,15 @@
// Reply payload tests cover internal reply metadata contracts.
import { describe, expect, it } from "vitest";
import { buildPairingQrReplyChannelData, readPairingQrReplyChannelData } from "./reply-payload.js";
import { readPairingQrReplyChannelData } from "./reply-payload.js";
describe("pairing QR reply channel data", () => {
it("builds and reads the private pairing QR payload metadata", () => {
const channelData = buildPairingQrReplyChannelData({
setupCode: "setup-code",
expiresAtMs: 1_800_000_000_000,
});
it("reads the private pairing QR payload metadata", () => {
const channelData = {
openclawPairingQr: {
setupCode: "setup-code",
expiresAtMs: 1_800_000_000_000,
},
};
expect(readPairingQrReplyChannelData({ channelData })).toEqual({
setupCode: "setup-code",

View File

@@ -86,17 +86,6 @@ function normalizePairingQrExpiresAtMs(value: unknown): number | undefined {
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : undefined;
}
export function buildPairingQrReplyChannelData(
params: PairingQrReplyChannelData,
): Record<string, unknown> {
return {
[PAIRING_QR_REPLY_CHANNEL_DATA_KEY]: {
setupCode: params.setupCode,
expiresAtMs: params.expiresAtMs,
},
};
}
export function readPairingQrReplyChannelData(
payload: Pick<ReplyPayload, "channelData">,
): PairingQrReplyChannelData | undefined {

View File

@@ -9,16 +9,20 @@ import {
onAgentEvent,
resetAgentEventsForTest,
} from "../../infra/agent-events.js";
import type {
ReasoningProgressPayload,
ReasoningTextPayload,
} from "./agent-runner-cli-dispatch.js";
import {
createCliToolSummaryTracker,
keepCliSessionBindingOnlyWhenReused,
runCliAgentWithLifecycle,
} from "./agent-runner-cli-dispatch.js";
type RunCliAgentWithLifecycleParams = Parameters<typeof runCliAgentWithLifecycle>[0];
type ReasoningTextPayload = Parameters<
NonNullable<RunCliAgentWithLifecycleParams["onReasoningText"]>
>[0];
type ReasoningProgressPayload = Parameters<
NonNullable<RunCliAgentWithLifecycleParams["onReasoningProgress"]>
>[0];
const cliDispatchState = vi.hoisted(() => ({
runCliAgentMock: vi.fn(),
}));

View File

@@ -147,12 +147,12 @@ function createAssistantTextBridge(params: {
});
}
export type ReasoningTextPayload = {
type ReasoningTextPayload = {
text: string;
isReasoningSnapshot?: boolean;
};
export type ReasoningProgressPayload = {
type ReasoningProgressPayload = {
progressTokens: number;
};

View File

@@ -3,6 +3,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { OAuthRefreshFailureError } from "../../agents/auth-profiles/oauth-refresh-failure.js";
import { testing as cliBackendsTesting } from "../../agents/cli-backends.js";
import { formatBillingErrorMessage } from "../../agents/embedded-agent-helpers.js";
import { AUTH_INVALID_TOKEN_USER_TEXT } from "../../agents/embedded-agent-helpers/errors.js";
import { FailoverError } from "../../agents/failover-error.js";
import { LiveSessionModelSwitchError } from "../../agents/live-model-switch-error.js";
import { MissingProviderAuthError } from "../../agents/model-auth.js";
@@ -35,16 +36,17 @@ import {
resolveRunAfterAutoFallbackPrimaryProbeRecheck,
} from "./agent-runner-execution.js";
import { HEARTBEAT_EXTERNAL_RUN_FAILURE_TEXT } from "./agent-runner-failure-copy.js";
import {
PROVIDER_AUTHENTICATION_ERROR_USER_MESSAGE,
PROVIDER_CONVERSATION_STATE_ERROR_USER_MESSAGE,
PROVIDER_INTERNAL_ERROR_USER_MESSAGE,
PROVIDER_RATE_LIMIT_OR_QUOTA_ERROR_USER_MESSAGE,
} from "./provider-request-error-classifier.js";
import { PROVIDER_CONVERSATION_STATE_ERROR_USER_MESSAGE } from "./provider-request-error-classifier.js";
import type { FollowupRun } from "./queue.js";
import { createReplyOperation, type ReplyOperation } from "./reply-run-registry.js";
import type { TypingSignaler } from "./typing-mode.js";
const PROVIDER_AUTHENTICATION_ERROR_USER_MESSAGE = `⚠️ ${AUTH_INVALID_TOKEN_USER_TEXT}`;
const PROVIDER_RATE_LIMIT_OR_QUOTA_ERROR_USER_MESSAGE =
"⚠️ The model provider returned HTTP 429 before replying. This can mean rate limiting, exhausted quota, or an account balance/billing issue. Check the selected provider/model, API key, and provider billing/quota dashboard, then try again.";
const PROVIDER_INTERNAL_ERROR_USER_MESSAGE =
"⚠️ The model provider returned a temporary internal error before replying. Try again in a moment, or switch to another model if it keeps happening.";
const state = vi.hoisted(() => ({
runEmbeddedAgentMock: vi.fn(),
runCliAgentMock: vi.fn(),

View File

@@ -418,7 +418,7 @@ export type RuntimeFallbackAttempt = {
};
/** Result of running an agent turn through fallback/retry handling. */
export type AgentRunLoopResult =
type AgentRunLoopResult =
| {
kind: "success";
runId: string;

View File

@@ -22,13 +22,20 @@ vi.mock("../../utils/provider-utils.js", () => ({
isReasoningTagProvider: (...args: unknown[]) => hoisted.isReasoningTagProviderMock(...args),
}));
const {
buildThreadingToolContext,
buildEmbeddedRunBaseParams,
buildEmbeddedRunExecutionParams,
resolveModelFallbackOptions,
resolveProviderScopedAuthProfile,
} = await import("./agent-runner-utils.js");
const { buildThreadingToolContext, buildEmbeddedRunExecutionParams, resolveModelFallbackOptions } =
await import("./agent-runner-utils.js");
const { resolveProviderScopedAuthProfile } = await import("./agent-runner-auth-profile.js");
const { buildEmbeddedRunBaseParams: buildEmbeddedRunBaseParamsCore } =
await import("./agent-runner-run-params.js");
function buildEmbeddedRunBaseParams(
params: Omit<Parameters<typeof buildEmbeddedRunBaseParamsCore>[0], "isReasoningTagProvider">,
) {
return buildEmbeddedRunBaseParamsCore({
...params,
isReasoningTagProvider: hoisted.isReasoningTagProviderMock,
});
}
function makeRun(overrides: Partial<FollowupRun["run"]> = {}): FollowupRun["run"] {
return {

View File

@@ -26,11 +26,8 @@ import {
import type { SessionEntry } from "../../config/sessions.js";
import { isReasoningTagProvider } from "../../utils/provider-utils.js";
import type { TemplateContext } from "../templating.js";
import {
resolveProviderScopedAuthProfile,
resolveRunAuthProfile,
} from "./agent-runner-auth-profile.js";
export { resolveProviderScopedAuthProfile, resolveRunAuthProfile };
import { resolveRunAuthProfile } from "./agent-runner-auth-profile.js";
export { resolveRunAuthProfile };
import { buildEmbeddedRunBaseParams as buildEmbeddedRunBaseParamsCore } from "./agent-runner-run-params.js";
export { resolveModelFallbackOptions } from "./agent-runner-run-params.js";
import { hasInboundAudio } from "./inbound-media.js";
@@ -231,9 +228,7 @@ export function resolveRunFastModeForFallbackCandidate(params: {
};
}
/** Builds base embedded run params with auth and provider runtime hints. */
export function buildEmbeddedRunBaseParams(
params: Parameters<typeof buildEmbeddedRunBaseParamsCore>[0],
) {
function buildEmbeddedRunBaseParams(params: Parameters<typeof buildEmbeddedRunBaseParamsCore>[0]) {
return buildEmbeddedRunBaseParamsCore({
...params,
isReasoningTagProvider,

View File

@@ -2,7 +2,6 @@
import path from "node:path";
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { TemplateContext } from "../templating.js";
import type { AgentRunLoopResult } from "./agent-runner-execution.js";
import type { FollowupRun, QueueSettings } from "./queue.js";
import type { ReplyOperation } from "./reply-run-registry.js";
import { createMockFollowupRun, createMockTypingController } from "./test-helpers.js";
@@ -102,6 +101,10 @@ vi.mock("./session-run-accounting.js", () => ({
const { runReplyAgent } = await import("./agent-runner.js");
type AgentRunLoopResult = Awaited<
ReturnType<typeof import("./agent-runner-execution.js").runAgentTurnWithFallback>
>;
function createReplyOperation(): ReplyOperation {
return {
result: undefined,

View File

@@ -28,7 +28,6 @@ import {
import {
REPLY_OPERATION_RUN_STATE,
type ReplyOperationRunState,
type ReplyOptionsWithOperationRunState,
} from "./reply-operation-run-state.js";
import {
createReplyOperation,
@@ -38,6 +37,10 @@ import {
import { consumeReplyUsageState } from "./reply-usage-state.js";
import { createMockTypingController } from "./test-helpers.js";
type ReplyOptionsWithOperationRunState = {
[REPLY_OPERATION_RUN_STATE]?: ReplyOperationRunState;
};
type AgentRunParams = {
sessionId?: string;
sessionFile?: string;

View File

@@ -16,9 +16,10 @@ import {
stopWithText,
} from "./commands-subagents-dispatch.js";
import { handleSubagentsCommand } from "./commands-subagents.js";
import { COMMAND } from "./commands-subagents/shared.js";
import type { HandleCommandsParams } from "./commands-types.js";
const COMMAND = "/subagents";
const listControlledSubagentRunsMock = vi.hoisted(() => vi.fn(() => []));
vi.mock("./commands-subagents-control.runtime.js", () => ({

View File

@@ -28,7 +28,7 @@ import {
export type { ChatMessage } from "../commands-subagents-text.js";
export const COMMAND = "/subagents";
const COMMAND = "/subagents";
const COMMAND_FOCUS = "/focus";
const COMMAND_UNFOCUS = "/unfocus";
const COMMAND_AGENTS = "/agents";

View File

@@ -1,11 +1,10 @@
// Tests effective reply route selection from context, session, and fallback state.
import { describe, expect, it } from "vitest";
import {
isSystemEventProvider,
resolveEffectiveReplyRoute,
type EffectiveReplyRouteContext,
type EffectiveReplyRouteEntry,
} from "./effective-reply-route.js";
import { isSystemEventProvider, resolveEffectiveReplyRoute } from "./effective-reply-route.js";
type EffectiveReplyRouteParams = Parameters<typeof resolveEffectiveReplyRoute>[0];
type EffectiveReplyRouteContext = EffectiveReplyRouteParams["ctx"];
type EffectiveReplyRouteEntry = NonNullable<EffectiveReplyRouteParams["entry"]>;
const ctx = (params: EffectiveReplyRouteContext): EffectiveReplyRouteContext => params;
const entry = (params: EffectiveReplyRouteEntry): EffectiveReplyRouteEntry => params;

View File

@@ -7,7 +7,7 @@ import { INTERNAL_MESSAGE_CHANNEL, normalizeMessageChannel } from "../../utils/m
import type { FinalizedMsgContext } from "../templating.js";
/** Current finalized context fields used for reply route resolution. */
export type EffectiveReplyRouteContext = Pick<
type EffectiveReplyRouteContext = Pick<
FinalizedMsgContext,
| "Provider"
| "Surface"
@@ -19,7 +19,7 @@ export type EffectiveReplyRouteContext = Pick<
>;
/** Persisted session fields used as route fallback/inheritance. */
export type EffectiveReplyRouteEntry = Pick<
type EffectiveReplyRouteEntry = Pick<
SessionEntry,
"deliveryContext" | "lastChannel" | "lastTo" | "lastAccountId" | "route" | "chatType" | "origin"
>;

View File

@@ -2,11 +2,9 @@
import { importFreshModule } from "openclaw/plugin-sdk/test-fixtures";
import { afterEach, describe, expect, it } from "vitest";
import type { MsgContext } from "../templating.js";
import {
buildInboundDedupeKey,
resetInboundDedupe,
type InboundDedupeClaimResult,
} from "./inbound-dedupe.js";
import { buildInboundDedupeKey, resetInboundDedupe } from "./inbound-dedupe.js";
type InboundDedupeClaimResult = ReturnType<typeof import("./inbound-dedupe.js").claimInboundDedupe>;
const sharedInboundContext: MsgContext = {
Provider: "discord",

View File

@@ -29,7 +29,7 @@ const inboundDedupeInFlight = resolveGlobalSingleton(
() => new Set<string>(),
);
export type InboundDedupeClaimResult =
type InboundDedupeClaimResult =
| { status: "invalid" }
| { status: "duplicate"; key: string }
| { status: "inflight"; key: string }

View File

@@ -18,9 +18,12 @@ vi.mock("../../logging/subsystem.js", async (importOriginal) => {
import {
attachProgressNarratorToReplyOptions,
createProgressNarrator,
type ProgressNarrationInput,
} from "./progress-narrator.js";
type ProgressNarrationInput = Parameters<
NonNullable<Parameters<typeof createProgressNarrator>[0]["generate"]>
>[0];
const cfg = {} as OpenClawConfig;
// The narrator runs generations on a detached promise; drain microtasks so

View File

@@ -39,7 +39,7 @@ const NARRATION_SYSTEM_PROMPT = [
"Reply with the status text only.",
].join(" ");
export type ProgressNarrationInput = {
type ProgressNarrationInput = {
userMessage: string;
activityNotes: readonly string[];
previousText: string;

View File

@@ -1,15 +1,20 @@
/** Tests provider request error classification for retry/fallback decisions. */
import { describe, expect, it } from "vitest";
import { AUTH_INVALID_TOKEN_USER_TEXT } from "../../agents/embedded-agent-helpers/errors.js";
import { FailoverError } from "../../agents/failover-error.js";
import {
classifyProviderRequestError,
PROVIDER_AUTHENTICATION_ERROR_USER_MESSAGE,
PROVIDER_CONVERSATION_STATE_ERROR_USER_MESSAGE,
PROVIDER_INTERNAL_ERROR_USER_MESSAGE,
PROVIDER_MODEL_UNAVAILABLE_USER_MESSAGE,
PROVIDER_RATE_LIMIT_OR_QUOTA_ERROR_USER_MESSAGE,
} from "./provider-request-error-classifier.js";
const PROVIDER_AUTHENTICATION_ERROR_USER_MESSAGE = `⚠️ ${AUTH_INVALID_TOKEN_USER_TEXT}`;
const PROVIDER_RATE_LIMIT_OR_QUOTA_ERROR_USER_MESSAGE =
"⚠️ The model provider returned HTTP 429 before replying. This can mean rate limiting, exhausted quota, or an account balance/billing issue. Check the selected provider/model, API key, and provider billing/quota dashboard, then try again.";
const PROVIDER_INTERNAL_ERROR_USER_MESSAGE =
"⚠️ The model provider returned a temporary internal error before replying. Try again in a moment, or switch to another model if it keeps happening.";
const PROVIDER_MODEL_UNAVAILABLE_USER_MESSAGE =
"⚠️ The configured model is unavailable from the provider — it may have been renamed, retired, or is not offered on this account. This needs a config update (agents.defaults.model); retrying or starting a new session won't fix it.";
describe("provider request error classifier", () => {
it("classifies provider HTTP 401 authentication failures", () => {
const message =

View File

@@ -26,20 +26,20 @@ type ProviderRequestErrorClassification = {
export const PROVIDER_CONVERSATION_STATE_ERROR_USER_MESSAGE =
"⚠️ The model provider rejected the conversation state. Please try again, or use /new to start a fresh session.";
export const PROVIDER_RATE_LIMIT_OR_QUOTA_ERROR_USER_MESSAGE =
const PROVIDER_RATE_LIMIT_OR_QUOTA_ERROR_USER_MESSAGE =
"⚠️ The model provider returned HTTP 429 before replying. This can mean rate limiting, exhausted quota, or an account balance/billing issue. Check the selected provider/model, API key, and provider billing/quota dashboard, then try again.";
export const PROVIDER_INTERNAL_ERROR_USER_MESSAGE =
const PROVIDER_INTERNAL_ERROR_USER_MESSAGE =
"⚠️ The model provider returned a temporary internal error before replying. Try again in a moment, or switch to another model if it keeps happening.";
export const PROVIDER_AUTHENTICATION_ERROR_USER_MESSAGE = `⚠️ ${AUTH_INVALID_TOKEN_USER_TEXT}`;
const PROVIDER_AUTHENTICATION_ERROR_USER_MESSAGE = `⚠️ ${AUTH_INVALID_TOKEN_USER_TEXT}`;
/**
* User-facing copy for a configured model the provider no longer serves.
* Distinct from generic failures because retrying or starting a new session
* cannot help: the model id itself must be changed in config.
*/
export const PROVIDER_MODEL_UNAVAILABLE_USER_MESSAGE =
const PROVIDER_MODEL_UNAVAILABLE_USER_MESSAGE =
"⚠️ The configured model is unavailable from the provider — it may have been renamed, retired, or is not offered on this account. This needs a config update (agents.defaults.model); retrying or starting a new session won't fix it.";
/** Classifies provider request failures that are actionable for users. */

View File

@@ -3,11 +3,7 @@
export { clearSessionQueues } from "./queue/cleanup.js";
export type { ClearSessionQueueResult } from "./queue/cleanup.js";
export { scheduleFollowupDrain } from "./queue/drain.js";
export {
enqueueFollowupRun,
getFollowupQueueDepth,
resetRecentQueuedMessageIdDedupe,
} from "./queue/enqueue.js";
export { enqueueFollowupRun, getFollowupQueueDepth } from "./queue/enqueue.js";
export { resolveQueueSettings } from "./queue/settings-runtime.js";
export { refreshQueuedFollowupSession } from "./queue/state.js";
export type { FollowupRun, QueueSettings } from "./queue/types.js";

View File

@@ -10,7 +10,7 @@ export type ReplyOperationRunState = {
// heartbeat cleanup never infers it from whichever operation is active later.
export const REPLY_OPERATION_RUN_STATE = Symbol("openclaw.replyOperationRunState");
export type ReplyOptionsWithOperationRunState = {
type ReplyOptionsWithOperationRunState = {
[REPLY_OPERATION_RUN_STATE]?: ReplyOperationRunState;
};

View File

@@ -47,7 +47,7 @@ type ForkSessionFromParentParams = {
type ForkedParentSessionEntry = ParentForkedSessionTranscript;
export type ForkSessionEntryFromParentResult =
type ForkSessionEntryFromParentResult =
| {
status: "forked";
fork: ForkedParentSessionEntry;
@@ -66,7 +66,7 @@ export type ForkSessionEntryFromParentResult =
| { status: "missing-parent" }
| { status: "failed" };
export type ForkSessionEntryFromParentParams = Omit<ForkSessionFromParentParams, "parentEntry"> & {
type ForkSessionEntryFromParentParams = Omit<ForkSessionFromParentParams, "parentEntry"> & {
parentSessionKey: string;
parentStoreKeys?: readonly string[];
sessionKey: string;

View File

@@ -1,11 +1,10 @@
import { describe, expect, it, vi } from "vitest";
import { completeFollowupRunLifecycle, markFollowupRunEnqueued } from "./queue/types.js";
import {
buildStrandedReplyRetryFollowupRun,
STRANDED_REPLY_RETRY_MARKER,
} from "./stranded-reply-recovery.js";
import { buildStrandedReplyRetryFollowupRun } from "./stranded-reply-recovery.js";
import { createMockFollowupRun } from "./test-helpers.js";
const STRANDED_REPLY_RETRY_MARKER = "stranded-reply-retry";
describe("buildStrandedReplyRetryFollowupRun lifecycle ownership", () => {
it("does not share the client turn's queuedLifecycle with the system retry", () => {
const onComplete = vi.fn();

View File

@@ -3,7 +3,7 @@ import { markReplyPayloadForSourceSuppressionDelivery } from "../reply-payload.j
import type { ReplyPayload } from "../types.js";
import type { FollowupRun } from "./queue/types.js";
export const STRANDED_REPLY_RETRY_MARKER = "stranded-reply-retry";
const STRANDED_REPLY_RETRY_MARKER = "stranded-reply-retry";
const STRANDED_REPLY_DELIVERY_FAILURE_TEXT =
"I generated a reply but could not deliver it to this chat. Please try again.";

View File

@@ -15,10 +15,7 @@ import {
import { ErrorCodes } from "../../../packages/gateway-protocol/src/index.js";
import { CHAT_SEND_SESSION_KEY_MAX_LENGTH } from "../../../packages/gateway-protocol/src/schema.js";
import type { ModelCatalogEntry } from "../../agents/model-catalog.types.js";
import {
buildPairingQrReplyChannelData,
setReplyPayloadMetadata,
} from "../../auto-reply/reply-payload.js";
import { setReplyPayloadMetadata } from "../../auto-reply/reply-payload.js";
import type { MsgContext } from "../../auto-reply/templating.js";
import {
appendTranscriptMessage,
@@ -2651,10 +2648,12 @@ describe("chat directive tag stripping for non-streaming final payloads", () =>
kind: "final",
payload: {
text: "Scan this QR code with the OpenClaw iOS app:",
channelData: buildPairingQrReplyChannelData({
setupCode,
expiresAtMs: Date.now() + 10 * 60_000,
}),
channelData: {
openclawPairingQr: {
setupCode,
expiresAtMs: Date.now() + 10 * 60_000,
},
},
sensitiveMedia: true,
},
},

View File

@@ -1,9 +1,5 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import type { RunEmbeddedAgentParams } from "../agents/embedded-agent-runner/run/params.js";
import type {
ForkSessionEntryFromParentParams,
ForkSessionEntryFromParentResult,
} from "../auto-reply/reply/session-fork.js";
import type { SessionEntry } from "../config/sessions/types.js";
import { MODEL_SELECTION_LOCKED_MESSAGE } from "../sessions/model-overrides.js";
import { runExclusiveSessionLifecycleMutation } from "../sessions/session-lifecycle-admission.js";
@@ -17,6 +13,11 @@ import {
resolveRealtimeVoiceAgentConsultToolsAllow,
} from "./agent-consult-tool.js";
type ForkSessionEntryFromParent =
typeof import("../auto-reply/reply/session-fork.js").forkSessionEntryFromParent;
type ForkSessionEntryFromParentParams = Parameters<ForkSessionEntryFromParent>[0];
type ForkSessionEntryFromParentResult = Awaited<ReturnType<ForkSessionEntryFromParent>>;
function createAgentRuntime(payloads: unknown[] = [{ text: "Speak this." }]) {
const sessionStore: Record<
string,