Vendor OpenClaw source as Adolf fork baseline
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled

Adolf is a fork/vendored clone of github.com/openclaw/openclaw (v2026.6.11),
free to diverge. Tree copied sans upstream .git; upstream remote added for
future syncs. Node pinned to 24 (.nvmrc); engines already require >=22.19.
Preserves docs/ARCHITECTURE.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
This commit is contained in:
2026-07-05 09:36:54 +00:00
parent 3216769225
commit bedb527145
21108 changed files with 6010766 additions and 0 deletions

View File

@@ -0,0 +1,414 @@
// Qa Channel plugin module implements inbound behavior.
import { resolveStableChannelMessageIngress } from "openclaw/plugin-sdk/channel-ingress-runtime";
import { resolveNativeCommandSessionTargets } from "openclaw/plugin-sdk/command-auth-native";
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
import { resolveInboundRouteEnvelopeBuilderWithRuntime } from "openclaw/plugin-sdk/inbound-envelope";
import {
buildAgentMediaPayload,
saveMediaBuffer,
saveMediaSource,
} from "openclaw/plugin-sdk/media-runtime";
import {
sanitizeQaBusToolCallArguments,
type QaBusToolCall,
} from "openclaw/plugin-sdk/qa-channel-protocol";
import {
buildQaTarget,
deleteQaBusMessage,
editQaBusMessage,
sendQaBusMessage,
type QaBusMessage,
} from "./bus-client.js";
import { getQaChannelRuntime } from "./runtime.js";
import type { CoreConfig, ResolvedQaChannelAccount } from "./types.js";
export function isHttpMediaUrl(value: string): boolean {
try {
const parsed = new URL(value);
return parsed.protocol === "http:" || parsed.protocol === "https:";
} catch {
return false;
}
}
function normalizeBase64ForCompare(value: string): string {
return value.replace(/=+$/u, "").replace(/-/gu, "+").replace(/_/gu, "/");
}
function decodeAttachmentBase64(value: string): Buffer | null {
const buffer = Buffer.from(value, "base64");
if (normalizeBase64ForCompare(buffer.toString("base64")) !== normalizeBase64ForCompare(value)) {
return null;
}
return buffer;
}
async function resolveQaInboundMediaPayload(attachments: QaBusMessage["attachments"]) {
if (!Array.isArray(attachments) || attachments.length === 0) {
return {};
}
const mediaList: Array<{ path: string; contentType?: string | null }> = [];
for (const attachment of attachments) {
if (!attachment?.mimeType) {
continue;
}
if (typeof attachment.contentBase64 === "string" && attachment.contentBase64.trim()) {
const buffer = decodeAttachmentBase64(attachment.contentBase64);
if (!buffer) {
console.warn("[qa-channel] inbound attachment contentBase64 rejected (invalid base64)");
continue;
}
const saved = await saveMediaBuffer(
buffer,
attachment.mimeType,
"inbound",
undefined,
attachment.fileName,
);
mediaList.push({
path: saved.path,
contentType: saved.contentType,
});
continue;
}
if (typeof attachment.url === "string" && attachment.url.trim()) {
if (!isHttpMediaUrl(attachment.url)) {
console.warn(
`[qa-channel] inbound attachment URL rejected (non-http scheme): ${attachment.url}`,
);
continue;
}
const saved = await saveMediaSource(attachment.url, undefined, "inbound");
mediaList.push({
path: saved.path,
contentType: saved.contentType,
});
}
}
return mediaList.length > 0 ? buildAgentMediaPayload(mediaList) : {};
}
function resolveQaGroupConfig(params: {
account: ResolvedQaChannelAccount;
conversationId: string;
target: string;
}) {
const groups = params.account.config.groups;
return groups?.[params.conversationId] ?? groups?.[params.target] ?? groups?.["*"];
}
function formatQaErrorForLog(error: unknown): string {
let escaped = "";
const message = formatErrorMessage(error) || Object.prototype.toString.call(error);
for (const character of message) {
const codePoint = character.codePointAt(0) ?? 0;
const isControl = codePoint <= 0x1f || (codePoint >= 0x7f && codePoint <= 0x9f);
const isLineSeparator = codePoint === 0x2028 || codePoint === 0x2029;
escaped +=
isControl || isLineSeparator ? `\\u${codePoint.toString(16).padStart(4, "0")}` : character;
}
return escaped;
}
function createQaReplyPreview(params: {
account: ResolvedQaChannelAccount;
inbound: QaBusMessage;
target: string;
toolCalls: QaBusToolCall[];
}) {
let messageId: string | null = null;
let currentText = "";
let pending = Promise.resolve();
const write = (text: string) => {
if (!text.trim() || text === currentText) {
return pending;
}
pending = pending.then(async () => {
if (messageId) {
await editQaBusMessage({
baseUrl: params.account.baseUrl,
accountId: params.account.accountId,
messageId,
text,
});
} else {
const response = await sendQaBusMessage({
baseUrl: params.account.baseUrl,
accountId: params.account.accountId,
to: params.target,
text,
senderId: params.account.botUserId,
senderName: params.account.botDisplayName,
threadId: params.inbound.threadId,
replyToId: params.inbound.id,
toolCalls: params.toolCalls,
});
messageId = response.message.id;
}
currentText = text;
});
return pending;
};
const clear = async () => {
await pending.catch(() => undefined);
if (!messageId) {
return;
}
await deleteQaBusMessage({
baseUrl: params.account.baseUrl,
accountId: params.account.accountId,
messageId,
});
messageId = null;
currentText = "";
};
const sendDurable = async (text: string) => {
if (!text.trim()) {
return;
}
await sendQaBusMessage({
baseUrl: params.account.baseUrl,
accountId: params.account.accountId,
to: params.target,
text,
senderId: params.account.botUserId,
senderName: params.account.botDisplayName,
threadId: params.inbound.threadId,
replyToId: params.inbound.id,
toolCalls: params.toolCalls,
});
};
return {
clear,
async deliver(text: string, kind: string) {
await pending;
if (kind === "final" && messageId && params.toolCalls.length === 0) {
await write(text);
return;
}
await clear();
await sendDurable(text);
},
update: write,
};
}
export async function handleQaInbound(params: {
channelId: string;
channelLabel: string;
account: ResolvedQaChannelAccount;
config: CoreConfig;
message: QaBusMessage;
}) {
const runtime = getQaChannelRuntime();
const inbound = params.message;
const target = buildQaTarget({
chatType: inbound.conversation.kind,
conversationId: inbound.conversation.id,
threadId: inbound.threadId,
});
const toolCalls: QaBusToolCall[] = [];
const preview = createQaReplyPreview({
account: params.account,
inbound,
target,
toolCalls,
});
const { route, buildEnvelope } = resolveInboundRouteEnvelopeBuilderWithRuntime({
cfg: params.config as OpenClawConfig,
channel: params.channelId,
accountId: params.account.accountId,
peer: {
kind:
inbound.conversation.kind === "direct"
? "direct"
: inbound.conversation.kind === "group"
? "group"
: "channel",
id: target,
},
runtime: runtime.channel,
sessionStore: params.config.session?.store,
});
const isGroup = inbound.conversation.kind !== "direct";
const wasMentioned = isGroup
? runtime.channel.mentions.matchesMentionPatterns(
inbound.text,
runtime.channel.mentions.buildMentionRegexes(
params.config as OpenClawConfig,
route.agentId,
),
)
: undefined;
const groupConfig = isGroup
? resolveQaGroupConfig({
account: params.account,
conversationId: inbound.conversation.id,
target,
})
: undefined;
const access = await resolveStableChannelMessageIngress({
channelId: params.channelId,
accountId: params.account.accountId,
identity: { key: "sender", entryIdPrefix: "qa-entry" },
groupAllowFromFallbackToAllowFrom: true,
subject: { stableId: inbound.senderId },
conversation: {
kind: inbound.conversation.kind,
id: inbound.conversation.id,
threadId: inbound.threadId,
title: inbound.conversation.title,
},
mentionFacts: isGroup
? {
canDetectMention: true,
wasMentioned: wasMentioned ?? false,
}
: undefined,
dmPolicy: "open",
groupPolicy: params.account.config.groupPolicy ?? "open",
policy: {
activation: isGroup
? {
requireMention: groupConfig?.requireMention ?? false,
allowTextCommands: true,
}
: undefined,
},
allowFrom: params.account.config.allowFrom,
groupAllowFrom: params.account.config.groupAllowFrom,
});
if (access.ingress.admission !== "dispatch") {
return;
}
const { storePath, body } = buildEnvelope({
channel: params.channelLabel,
from: inbound.senderName || inbound.senderId,
timestamp: inbound.timestamp,
body: inbound.text,
});
const mediaPayload = await resolveQaInboundMediaPayload(inbound.attachments);
const nativeCommand = inbound.nativeCommand;
const commandTargets = nativeCommand
? resolveNativeCommandSessionTargets({
agentId: route.agentId,
sessionPrefix: "qa-channel:slash",
userId: inbound.senderId,
targetSessionKey: route.sessionKey,
})
: undefined;
const commandBody = nativeCommand ? `/${nativeCommand.name}` : inbound.text;
const ctxPayload = runtime.channel.reply.finalizeInboundContext({
Body: body,
BodyForAgent: inbound.text,
RawBody: inbound.text,
CommandBody: commandBody,
From: target,
To: target,
SessionKey: commandTargets?.sessionKey ?? route.sessionKey,
CommandTargetSessionKey: commandTargets?.commandTargetSessionKey,
AccountId: route.accountId ?? params.account.accountId,
ChatType: inbound.conversation.kind === "direct" ? "direct" : "group",
WasMentioned: wasMentioned,
ConversationLabel:
inbound.threadTitle ||
inbound.conversation.title ||
inbound.senderName ||
inbound.conversation.id,
GroupSubject: isGroup
? inbound.threadTitle || inbound.conversation.title || inbound.conversation.id
: undefined,
GroupChannel: inbound.conversation.kind === "channel" ? inbound.conversation.id : undefined,
NativeChannelId: inbound.conversation.id,
MessageThreadId: inbound.threadId,
ThreadLabel: inbound.threadTitle,
ThreadParentId: inbound.threadId ? inbound.conversation.id : undefined,
SenderName: inbound.senderName,
SenderId: inbound.senderId,
Provider: params.channelId,
Surface: params.channelId,
MessageSid: inbound.id,
MessageSidFull: inbound.id,
ReplyToId: inbound.replyToId,
Timestamp: inbound.timestamp,
OriginatingChannel: params.channelId,
OriginatingTo: target,
CommandAuthorized: true,
CommandSource: nativeCommand ? "native" : undefined,
CommandTurn: nativeCommand
? {
kind: "native",
source: "native",
authorized: true,
body: commandBody,
}
: undefined,
...mediaPayload,
});
await runtime.channel.inbound.dispatchReply({
cfg: params.config as OpenClawConfig,
channel: params.channelId,
accountId: params.account.accountId,
agentId: route.agentId,
routeSessionKey: route.sessionKey,
storePath,
ctxPayload,
recordInboundSession: runtime.channel.session.recordInboundSession,
dispatchReplyWithBufferedBlockDispatcher:
runtime.channel.reply.dispatchReplyWithBufferedBlockDispatcher,
delivery: {
deliver: async (payload, info) => {
const text =
payload && typeof payload === "object" && "text" in payload
? ((payload as { text?: string }).text ?? "")
: "";
if (!text.trim()) {
return;
}
await preview.deliver(text, info?.kind ?? "final");
},
onError: (error) => {
void preview.clear().catch((clearError: unknown) => {
console.warn(
`[qa-channel] failed to clear reply preview after dispatch error: ${formatQaErrorForLog(clearError)}`,
);
});
console.warn(`[qa-channel] reply dispatch failed: ${formatQaErrorForLog(error)}`);
},
},
replyOptions: {
onPartialReply: async (payload) => {
await preview.update(payload.text ?? "");
},
onToolStart: (payload) => {
if (payload.phase && payload.phase !== "start") {
return;
}
const name = payload.name?.trim();
if (!name) {
return;
}
const args = sanitizeQaBusToolCallArguments(payload.args);
toolCalls.push({
name,
...(args && Object.keys(args).length > 0 ? { arguments: args } : {}),
});
},
},
replyPipeline: {},
record: {
onRecordError: (error) => {
throw error instanceof Error
? error
: new Error(`qa-channel session record failed: ${String(error)}`);
},
},
});
}