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
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:
391
extensions/nextcloud-talk/src/inbound.ts
Normal file
391
extensions/nextcloud-talk/src/inbound.ts
Normal file
@@ -0,0 +1,391 @@
|
||||
// Nextcloud Talk plugin module implements inbound behavior.
|
||||
import {
|
||||
channelIngressRoutes,
|
||||
resolveStableChannelMessageIngress,
|
||||
} from "openclaw/plugin-sdk/channel-ingress-runtime";
|
||||
import { resolveInboundRouteEnvelopeBuilderWithRuntime } from "openclaw/plugin-sdk/inbound-envelope";
|
||||
import {
|
||||
normalizeOptionalString,
|
||||
normalizeStringEntries,
|
||||
} from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import {
|
||||
GROUP_POLICY_BLOCKED_LABEL,
|
||||
resolveAllowlistProviderRuntimeGroupPolicy,
|
||||
createChannelPairingController,
|
||||
deliverFormattedTextWithAttachments,
|
||||
logInboundDrop,
|
||||
resolveDefaultGroupPolicy,
|
||||
warnMissingProviderGroupPolicyFallbackOnce,
|
||||
type GroupPolicy,
|
||||
type OpenClawConfig,
|
||||
type OutboundReplyPayload,
|
||||
type RuntimeEnv,
|
||||
} from "../runtime-api.js";
|
||||
import type { ResolvedNextcloudTalkAccount } from "./accounts.js";
|
||||
import {
|
||||
normalizeNextcloudTalkAllowEntry,
|
||||
normalizeNextcloudTalkAllowlist,
|
||||
resolveNextcloudTalkAllowlistMatch,
|
||||
resolveNextcloudTalkRequireMention,
|
||||
resolveNextcloudTalkRoomMatch,
|
||||
} from "./policy.js";
|
||||
import { resolveNextcloudTalkRoomKind } from "./room-info.js";
|
||||
import { getNextcloudTalkRuntime } from "./runtime.js";
|
||||
import { sendMessageNextcloudTalk } from "./send.js";
|
||||
import type { CoreConfig, NextcloudTalkInboundMessage, NextcloudTalkRoomConfig } from "./types.js";
|
||||
|
||||
const CHANNEL_ID = "nextcloud-talk" as const;
|
||||
|
||||
type NextcloudTalkRoomMatch = ReturnType<typeof resolveNextcloudTalkRoomMatch>;
|
||||
|
||||
function hasAllowEntries(entries: string[]): boolean {
|
||||
return normalizeNextcloudTalkAllowlist(entries).length > 0;
|
||||
}
|
||||
|
||||
function roomRoutes(params: {
|
||||
isGroup: boolean;
|
||||
groupPolicy: GroupPolicy;
|
||||
roomMatch: NextcloudTalkRoomMatch;
|
||||
roomConfig?: NextcloudTalkRoomConfig;
|
||||
senderId: string;
|
||||
outerGroupAllowFrom: string[];
|
||||
roomAllowFrom: string[];
|
||||
}) {
|
||||
if (!params.isGroup) {
|
||||
return [];
|
||||
}
|
||||
const roomSenderConfigured =
|
||||
params.groupPolicy === "allowlist" && hasAllowEntries(params.roomAllowFrom);
|
||||
return channelIngressRoutes(
|
||||
params.roomMatch.allowlistConfigured && {
|
||||
id: "nextcloud-talk:room",
|
||||
allowed: params.roomMatch.allowed,
|
||||
precedence: 0,
|
||||
matchId: "nextcloud-talk-room",
|
||||
blockReason: "room_not_allowlisted",
|
||||
},
|
||||
params.roomConfig?.enabled === false && {
|
||||
id: "nextcloud-talk:room-enabled",
|
||||
enabled: false,
|
||||
precedence: 10,
|
||||
blockReason: "room_disabled",
|
||||
},
|
||||
roomSenderConfigured && {
|
||||
id: "nextcloud-talk:room-sender",
|
||||
kind: "nestedAllowlist",
|
||||
precedence: 20,
|
||||
blockReason: "room_sender_not_allowlisted",
|
||||
...(!hasAllowEntries(params.outerGroupAllowFrom)
|
||||
? {
|
||||
senderPolicy: "replace" as const,
|
||||
senderAllowFrom: params.roomAllowFrom,
|
||||
}
|
||||
: {
|
||||
allowed: resolveNextcloudTalkAllowlistMatch({
|
||||
allowFrom: params.roomAllowFrom,
|
||||
senderId: params.senderId,
|
||||
}).allowed,
|
||||
matchId: "nextcloud-talk-room-sender",
|
||||
}),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
async function deliverNextcloudTalkReply(params: {
|
||||
cfg: CoreConfig;
|
||||
payload: OutboundReplyPayload;
|
||||
roomToken: string;
|
||||
accountId: string;
|
||||
statusSink?: (patch: { lastOutboundAt?: number }) => void;
|
||||
}): Promise<void> {
|
||||
const { cfg, payload, roomToken, accountId, statusSink } = params;
|
||||
await deliverFormattedTextWithAttachments({
|
||||
payload,
|
||||
send: async ({ text, replyToId }) => {
|
||||
await sendMessageNextcloudTalk(roomToken, text, {
|
||||
cfg,
|
||||
accountId,
|
||||
replyTo: replyToId,
|
||||
});
|
||||
statusSink?.({ lastOutboundAt: Date.now() });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function handleNextcloudTalkInbound(params: {
|
||||
message: NextcloudTalkInboundMessage;
|
||||
account: ResolvedNextcloudTalkAccount;
|
||||
config: CoreConfig;
|
||||
runtime: RuntimeEnv;
|
||||
statusSink?: (patch: { lastInboundAt?: number; lastOutboundAt?: number }) => void;
|
||||
}): Promise<void> {
|
||||
const { message, account, config, runtime, statusSink } = params;
|
||||
const core = getNextcloudTalkRuntime();
|
||||
const pairing = createChannelPairingController({
|
||||
core,
|
||||
channel: CHANNEL_ID,
|
||||
accountId: account.accountId,
|
||||
});
|
||||
|
||||
const rawBody = message.text?.trim() ?? "";
|
||||
if (!rawBody) {
|
||||
return;
|
||||
}
|
||||
|
||||
const roomKind = await resolveNextcloudTalkRoomKind({
|
||||
account,
|
||||
roomToken: message.roomToken,
|
||||
runtime,
|
||||
});
|
||||
const isGroup = roomKind === "direct" ? false : roomKind === "group" ? true : message.isGroupChat;
|
||||
const senderId = message.senderId;
|
||||
const senderName = message.senderName;
|
||||
const roomToken = message.roomToken;
|
||||
const roomName = message.roomName;
|
||||
|
||||
statusSink?.({ lastInboundAt: message.timestamp });
|
||||
|
||||
const roomMatch = resolveNextcloudTalkRoomMatch({
|
||||
rooms: account.config.rooms,
|
||||
roomToken,
|
||||
});
|
||||
const roomConfig = roomMatch.roomConfig;
|
||||
const allowTextCommands = core.channel.commands.shouldHandleTextCommands({
|
||||
cfg: config as OpenClawConfig,
|
||||
surface: CHANNEL_ID,
|
||||
});
|
||||
const hasControlCommand = core.channel.text.hasControlCommand(rawBody, config as OpenClawConfig);
|
||||
const shouldRequireMention = isGroup
|
||||
? resolveNextcloudTalkRequireMention({
|
||||
roomConfig,
|
||||
wildcardConfig: roomMatch.wildcardConfig,
|
||||
})
|
||||
: false;
|
||||
const { groupPolicy, providerMissingFallbackApplied } =
|
||||
resolveAllowlistProviderRuntimeGroupPolicy({
|
||||
providerConfigPresent:
|
||||
((config.channels as Record<string, unknown> | undefined)?.[CHANNEL_ID] ?? undefined) !==
|
||||
undefined,
|
||||
groupPolicy: account.config.groupPolicy,
|
||||
defaultGroupPolicy: resolveDefaultGroupPolicy(config as OpenClawConfig),
|
||||
});
|
||||
const allowFrom = normalizeStringEntries(account.config.allowFrom);
|
||||
const outerGroupAllowFrom = account.config.groupAllowFrom?.length
|
||||
? normalizeStringEntries(account.config.groupAllowFrom)
|
||||
: allowFrom;
|
||||
const roomAllowFrom = normalizeStringEntries(roomConfig?.allowFrom);
|
||||
const resolveAccess = async (wasMentioned?: boolean) =>
|
||||
await resolveStableChannelMessageIngress({
|
||||
channelId: CHANNEL_ID,
|
||||
accountId: account.accountId,
|
||||
identity: {
|
||||
key: "nextcloud-talk-user-id",
|
||||
normalize: (value) => normalizeNextcloudTalkAllowEntry(value) || null,
|
||||
sensitivity: "pii",
|
||||
entryIdPrefix: "nextcloud-talk-entry",
|
||||
},
|
||||
cfg: config as OpenClawConfig,
|
||||
readStoreAllowFrom: async () =>
|
||||
await pairing.readStoreForDmPolicy(CHANNEL_ID, account.accountId),
|
||||
subject: { stableId: senderId },
|
||||
conversation: {
|
||||
kind: isGroup ? "group" : "direct",
|
||||
id: isGroup ? roomToken : senderId,
|
||||
},
|
||||
route: roomRoutes({
|
||||
isGroup,
|
||||
groupPolicy,
|
||||
roomMatch,
|
||||
roomConfig,
|
||||
senderId,
|
||||
outerGroupAllowFrom,
|
||||
roomAllowFrom,
|
||||
}),
|
||||
dmPolicy: account.config.dmPolicy ?? "pairing",
|
||||
groupPolicy,
|
||||
policy: {
|
||||
groupAllowFromFallbackToAllowFrom: true,
|
||||
activation: {
|
||||
requireMention: isGroup && shouldRequireMention,
|
||||
allowTextCommands,
|
||||
},
|
||||
},
|
||||
mentionFacts:
|
||||
isGroup && wasMentioned !== undefined
|
||||
? {
|
||||
canDetectMention: true,
|
||||
wasMentioned,
|
||||
hasAnyMention: wasMentioned,
|
||||
}
|
||||
: undefined,
|
||||
allowFrom,
|
||||
groupAllowFrom: account.config.groupAllowFrom,
|
||||
command: {
|
||||
allowTextCommands,
|
||||
hasControlCommand,
|
||||
},
|
||||
});
|
||||
let access = await resolveAccess();
|
||||
warnMissingProviderGroupPolicyFallbackOnce({
|
||||
providerMissingFallbackApplied,
|
||||
providerKey: "nextcloud-talk",
|
||||
accountId: account.accountId,
|
||||
blockedLabel: GROUP_POLICY_BLOCKED_LABEL.room,
|
||||
log: (messageValue) => runtime.log?.(messageValue),
|
||||
});
|
||||
const commandAuthorized = access.commandAccess.authorized;
|
||||
const accessReason =
|
||||
access.ingress.reasonCode === "route_blocked"
|
||||
? "route blocked"
|
||||
: access.senderAccess.reasonCode;
|
||||
|
||||
if (isGroup) {
|
||||
if (access.routeAccess.reason === "room_not_allowlisted") {
|
||||
runtime.log?.(`nextcloud-talk: drop room ${roomToken} (not allowlisted)`);
|
||||
return;
|
||||
}
|
||||
if (access.routeAccess.reason === "room_disabled") {
|
||||
runtime.log?.(`nextcloud-talk: drop room ${roomToken} (disabled)`);
|
||||
return;
|
||||
}
|
||||
if (access.routeAccess.reason === "room_sender_not_allowlisted") {
|
||||
runtime.log?.(`nextcloud-talk: drop group sender ${senderId} (policy=${groupPolicy})`);
|
||||
return;
|
||||
}
|
||||
if (access.senderAccess.decision !== "allow") {
|
||||
runtime.log?.(`nextcloud-talk: drop group sender ${senderId} (reason=${accessReason})`);
|
||||
return;
|
||||
}
|
||||
} else if (access.senderAccess.decision !== "allow") {
|
||||
if (access.senderAccess.decision === "pairing") {
|
||||
await pairing.issueChallenge({
|
||||
senderId,
|
||||
senderIdLine: `Your Nextcloud user id: ${senderId}`,
|
||||
meta: { name: senderName || undefined },
|
||||
sendPairingReply: async (text) => {
|
||||
await sendMessageNextcloudTalk(roomToken, text, {
|
||||
cfg: config,
|
||||
accountId: account.accountId,
|
||||
});
|
||||
statusSink?.({ lastOutboundAt: Date.now() });
|
||||
},
|
||||
onReplyError: (err) => {
|
||||
runtime.error?.(`nextcloud-talk: pairing reply failed for ${senderId}: ${String(err)}`);
|
||||
},
|
||||
});
|
||||
}
|
||||
runtime.log?.(`nextcloud-talk: drop DM sender ${senderId} (reason=${accessReason})`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (access.commandAccess.shouldBlockControlCommand) {
|
||||
logInboundDrop({
|
||||
log: (messageLocal) => runtime.log?.(messageLocal),
|
||||
channel: CHANNEL_ID,
|
||||
reason: "control command (unauthorized)",
|
||||
target: senderId,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const mentionRegexes = core.channel.mentions.buildMentionRegexes(config as OpenClawConfig);
|
||||
const wasMentioned = mentionRegexes.length
|
||||
? core.channel.mentions.matchesMentionPatterns(rawBody, mentionRegexes)
|
||||
: false;
|
||||
if (isGroup) {
|
||||
access = await resolveAccess(wasMentioned);
|
||||
}
|
||||
|
||||
if (isGroup && access.activationAccess.shouldSkip) {
|
||||
runtime.log?.(`nextcloud-talk: drop room ${roomToken} (no mention)`);
|
||||
return;
|
||||
}
|
||||
const { route, buildEnvelope } = resolveInboundRouteEnvelopeBuilderWithRuntime({
|
||||
cfg: config as OpenClawConfig,
|
||||
channel: CHANNEL_ID,
|
||||
accountId: account.accountId,
|
||||
peer: {
|
||||
kind: isGroup ? "group" : "direct",
|
||||
id: isGroup ? roomToken : senderId,
|
||||
},
|
||||
runtime: core.channel,
|
||||
sessionStore: (config.session as Record<string, unknown> | undefined)?.store as
|
||||
| string
|
||||
| undefined,
|
||||
});
|
||||
|
||||
const fromLabel = isGroup ? `room:${roomName || roomToken}` : senderName || `user:${senderId}`;
|
||||
const { storePath, body } = buildEnvelope({
|
||||
channel: "Nextcloud Talk",
|
||||
from: fromLabel,
|
||||
timestamp: message.timestamp,
|
||||
body: rawBody,
|
||||
});
|
||||
|
||||
const groupSystemPrompt = normalizeOptionalString(roomConfig?.systemPrompt);
|
||||
|
||||
const ctxPayload = core.channel.reply.finalizeInboundContext({
|
||||
Body: body,
|
||||
BodyForAgent: rawBody,
|
||||
RawBody: rawBody,
|
||||
CommandBody: rawBody,
|
||||
From: isGroup ? `nextcloud-talk:room:${roomToken}` : `nextcloud-talk:${senderId}`,
|
||||
To: `nextcloud-talk:${roomToken}`,
|
||||
SessionKey: route.sessionKey,
|
||||
AccountId: route.accountId,
|
||||
ChatType: isGroup ? "group" : "direct",
|
||||
ConversationLabel: fromLabel,
|
||||
SenderName: senderName || undefined,
|
||||
SenderId: senderId,
|
||||
GroupSubject: isGroup ? roomName || roomToken : undefined,
|
||||
GroupSystemPrompt: isGroup ? groupSystemPrompt : undefined,
|
||||
Provider: CHANNEL_ID,
|
||||
Surface: CHANNEL_ID,
|
||||
WasMentioned: isGroup ? wasMentioned : undefined,
|
||||
MessageSid: message.messageId,
|
||||
Timestamp: message.timestamp,
|
||||
OriginatingChannel: CHANNEL_ID,
|
||||
OriginatingTo: `nextcloud-talk:${roomToken}`,
|
||||
CommandAuthorized: commandAuthorized,
|
||||
});
|
||||
|
||||
await core.channel.inbound.dispatchReply({
|
||||
cfg: config as OpenClawConfig,
|
||||
channel: CHANNEL_ID,
|
||||
accountId: account.accountId,
|
||||
agentId: route.agentId,
|
||||
routeSessionKey: route.sessionKey,
|
||||
storePath,
|
||||
ctxPayload,
|
||||
recordInboundSession: core.channel.session.recordInboundSession,
|
||||
dispatchReplyWithBufferedBlockDispatcher:
|
||||
core.channel.reply.dispatchReplyWithBufferedBlockDispatcher,
|
||||
delivery: {
|
||||
deliver: async (payload) => {
|
||||
await deliverNextcloudTalkReply({
|
||||
cfg: config,
|
||||
payload,
|
||||
roomToken,
|
||||
accountId: account.accountId,
|
||||
statusSink,
|
||||
});
|
||||
},
|
||||
onError: (err, info) => {
|
||||
runtime.error?.(`nextcloud-talk ${info.kind} reply failed: ${String(err)}`);
|
||||
},
|
||||
},
|
||||
replyPipeline: {},
|
||||
replyOptions: {
|
||||
skillFilter: roomConfig?.skills,
|
||||
disableBlockStreaming:
|
||||
typeof account.config.blockStreaming === "boolean"
|
||||
? !account.config.blockStreaming
|
||||
: undefined,
|
||||
},
|
||||
record: {
|
||||
onRecordError: (err) => {
|
||||
runtime.error?.(`nextcloud-talk: failed updating session meta: ${String(err)}`);
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user