refactor: dedupe reply gateway helpers

This commit is contained in:
Peter Steinberger
2026-04-07 10:06:02 +01:00
parent cb29ecc100
commit f1bdfca1ed
5 changed files with 26 additions and 73 deletions

View File

@@ -72,14 +72,6 @@ function redactObservationText(text: string | undefined): string | undefined {
});
}
function extractRequestId(text: string | undefined): string | undefined {
if (!text) {
return undefined;
}
const match = text.match(REQUEST_ID_RE);
return normalizeOptionalString(match?.[1]);
}
function buildObservationFingerprint(params: {
raw: string;
requestId?: string;
@@ -123,7 +115,8 @@ export function buildApiErrorObservationFields(rawError?: string): {
}
try {
const parsed = parseApiErrorInfo(trimmed);
const requestId = parsed?.requestId ?? extractRequestId(trimmed);
const requestId =
parsed?.requestId ?? normalizeOptionalString(trimmed.match(REQUEST_ID_RE)?.[1]);
const requestIdHash = requestId ? redactIdentifier(requestId, { len: 12 }) : undefined;
const rawFingerprint = buildObservationFingerprint({
raw: trimmed,

View File

@@ -24,7 +24,7 @@ import { formatErrorMessage } from "../../infra/errors.js";
import { parseAgentSessionKey } from "../../routing/session-key.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import { resolveCommandAuthorization } from "../command-auth.js";
import type { FinalizedMsgContext, MsgContext } from "../templating.js";
import type { FinalizedMsgContext } from "../templating.js";
import {
applyAbortCutoffToSessionEntry,
resolveAbortCutoffFromContext,
@@ -118,14 +118,6 @@ export function resolveSessionEntryForKey(
return {};
}
function resolveAbortTargetKey(ctx: MsgContext): string | undefined {
const target = normalizeOptionalString(ctx.CommandTargetSessionKey);
if (target) {
return target;
}
return normalizeOptionalString(ctx.SessionKey);
}
function normalizeRequesterSessionKey(
cfg: OpenClawConfig,
key: string | undefined,
@@ -232,7 +224,8 @@ export async function tryFastAbortFromMessage(params: {
cfg: OpenClawConfig;
}): Promise<{ handled: boolean; aborted: boolean; stoppedSubagents?: number }> {
const { ctx, cfg } = params;
const targetKey = resolveAbortTargetKey(ctx);
const targetKey =
normalizeOptionalString(ctx.CommandTargetSessionKey) ?? normalizeOptionalString(ctx.SessionKey);
// Use RawBody/CommandBody for abort detection (clean message without structural context).
const raw = stripStructuralPrefixes(ctx.CommandBody ?? ctx.RawBody ?? ctx.Body ?? "");
const isGroup = normalizeOptionalString(ctx.ChatType)?.toLowerCase() === "group";

View File

@@ -58,26 +58,6 @@ function normalizeDeliveryChannel(value: string | undefined): string | undefined
return normalized || undefined;
}
function resolveDeliveryAccountId(params: {
cfg: OpenClawConfig;
channel: string | undefined;
accountId: string | undefined;
}): string | undefined {
const explicit = normalizeOptionalString(params.accountId);
if (explicit) {
return explicit;
}
const channelId = normalizeDeliveryChannel(params.channel);
if (!channelId) {
return undefined;
}
const channelCfg = (
params.cfg.channels as Record<string, { defaultAccount?: unknown } | undefined> | undefined
)?.[channelId];
const configuredDefault = channelCfg?.defaultAccount;
return normalizeOptionalString(configuredDefault);
}
async function shouldTreatDeliveredTextAsVisible(params: {
channel: string | undefined;
kind: ReplyDispatchKind;
@@ -207,11 +187,14 @@ export function createAcpDispatchDeliveryCoordinator(params: {
};
const directChannel = normalizeDeliveryChannel(params.ctx.Provider ?? params.ctx.Surface);
const routedChannel = normalizeDeliveryChannel(params.originatingChannel);
const resolvedAccountId = resolveDeliveryAccountId({
cfg: params.cfg,
channel: routedChannel ?? directChannel,
accountId: params.ctx.AccountId,
});
const explicitAccountId = normalizeOptionalString(params.ctx.AccountId);
const resolvedAccountId =
explicitAccountId ??
normalizeOptionalString(
(
params.cfg.channels as Record<string, { defaultAccount?: unknown } | undefined> | undefined
)?.[routedChannel ?? directChannel ?? ""]?.defaultAccount,
);
const settleDirectVisibleText = async () => {
if (state.settledDirectVisibleText || state.queuedDirectVisibleTextDeliveries === 0) {

View File

@@ -139,24 +139,6 @@ async function hasBoundConversationForSession(params: {
});
}
function resolveDispatchAccountId(params: {
cfg: OpenClawConfig;
channelRaw: string | undefined;
accountIdRaw: string | undefined;
}): string | undefined {
const channel = normalizeOptionalString(params.channelRaw)?.toLowerCase() ?? "";
if (!channel) {
return normalizeOptionalString(params.accountIdRaw);
}
const explicit = normalizeOptionalString(params.accountIdRaw);
if (explicit) {
return explicit;
}
const channels = params.cfg.channels as Record<string, { defaultAccount?: unknown } | undefined>;
const configuredDefaultAccountId = channels?.[channel]?.defaultAccount;
return normalizeOptionalString(configuredDefaultAccountId);
}
export type AcpDispatchAttemptResult = {
queuedFinal: boolean;
counts: Record<ReplyDispatchKind, number>;
@@ -357,11 +339,18 @@ export async function tryDispatchAcpReply(params: {
normalizeOptionalString(params.cfg.acp?.defaultAgent) ??
resolveAgentIdFromSessionKey(canonicalSessionKey))
: resolveAgentIdFromSessionKey(canonicalSessionKey);
const effectiveDispatchAccountId = resolveDispatchAccountId({
cfg: params.cfg,
channelRaw: params.ctx.OriginatingChannel ?? params.ctx.Surface ?? params.ctx.Provider,
accountIdRaw: params.ctx.AccountId,
});
const normalizedDispatchChannel =
normalizeOptionalString(
params.ctx.OriginatingChannel ?? params.ctx.Surface ?? params.ctx.Provider,
)?.toLowerCase() ?? "";
const explicitDispatchAccountId = normalizeOptionalString(params.ctx.AccountId);
const effectiveDispatchAccountId =
explicitDispatchAccountId ??
normalizeOptionalString(
(
params.cfg.channels as Record<string, { defaultAccount?: unknown } | undefined> | undefined
)?.[normalizedDispatchChannel]?.defaultAccount,
);
const projector = createAcpReplyProjector({
cfg: params.cfg,
shouldSendToolSummaries: params.shouldSendToolSummaries,

View File

@@ -64,11 +64,6 @@ function resolveLimit(req: IncomingMessage): number | undefined {
return Math.min(MAX_SESSION_HISTORY_LIMIT, Math.max(1, value));
}
function resolveCursor(req: IncomingMessage): string | undefined {
const raw = getRequestUrl(req).searchParams.get("cursor");
return normalizeOptionalString(raw);
}
function canonicalizePath(value: string | undefined): string | undefined {
const trimmed = normalizeOptionalString(value);
if (!trimmed) {
@@ -152,7 +147,7 @@ export async function handleSessionHistoryHttpRequest(
return true;
}
const limit = resolveLimit(req);
const cursor = resolveCursor(req);
const cursor = normalizeOptionalString(getRequestUrl(req).searchParams.get("cursor"));
const effectiveMaxChars =
typeof cfg.gateway?.webchat?.chatHistoryMaxChars === "number"
? cfg.gateway.webchat.chatHistoryMaxChars