Files
openclaw/extensions/slack/src/authored-text.ts
Peter Steinberger 0e792b6de3 refactor(channels): centralize inbound orchestration and remove internal compat (#109716)
* refactor(channels): centralize inbound turn orchestration

* refactor(runtime): remove stale compatibility paths

* chore(guards): reject internal deprecated API use

* refactor(channels): simplify core turn planning

* chore(guards): keep deprecated checks boundary-focused

* refactor(memory): keep modern config off compat barrel

* fix(msteams): preserve feedback learning

* test(channels): align modern inbound fixtures

* refactor(channels): finish modern inbound migration

* refactor(channels): tighten core inbound kernel

* fix(channels): preserve turn assembly narrowing

* test(sdk): keep runtime mock binding immutable

* test(matrix): isolate read policy runtime

* test(msteams): mock canonical reply factory

* test(slack): mock core inbound turn dispatch

* test(telegram): inject core session recorder

* test(signal): inject core session recorder

* test(googlechat): assert canonical inbound routing

* test(synology-chat): align core turn fixture

* fix(sdk): preserve direct DM runtime compat

* refactor(channels): own inbound envelope compat in core

* refactor(channels): trim inbound dispatch seams

* refactor(channels): remove redundant async wrappers

* test(synology-chat): type canonical dispatcher mock

* refactor(channels): remove remaining dead compat seams

* chore(sdk): refresh API baseline after rebase

* fix(channels): preserve direct DM identity metadata
2026-07-17 00:56:46 -07:00

60 lines
2.1 KiB
TypeScript

// Slack-private authored text placement after block compilation.
import type { LegacyInteractiveReply } from "openclaw/plugin-sdk/interactive-runtime";
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
export type SlackAuthoredTextPlacement = "none" | "blocks" | "outside-blocks";
function normalizeComparableSlackText(text: string): string {
return text.trim().replace(/\s+/g, " ");
}
function isSlackAuthoredTextRepresentedInInteractive(
text: string,
interactive?: LegacyInteractiveReply,
): boolean {
return isSlackAuthoredTextRepresentedInFragments(
text,
interactive?.blocks.flatMap((block) => (block.type === "text" ? [block.text] : [])) ?? [],
);
}
function isSlackAuthoredTextRepresentedInFragments(
text: string,
rawFragments: readonly string[],
): boolean {
const target = normalizeComparableSlackText(text);
const fragments = rawFragments.map(normalizeComparableSlackText).filter(Boolean);
// Legacy inline controls split surrounding text into multiple interactive text blocks.
for (let start = 0; start < fragments.length; start += 1) {
let combined = "";
for (let end = start; end < fragments.length; end += 1) {
combined = normalizeComparableSlackText(`${combined} ${fragments[end]}`);
if (combined === target) {
return true;
}
if (combined.length > target.length) {
break;
}
}
}
return false;
}
/** Resolve placement from producer facts, before accessibility text changes the payload text. */
export function resolveSlackAuthoredTextPlacement(params: {
text?: string;
interactive?: LegacyInteractiveReply;
renderedInBlocks?: boolean;
renderedTextFragments?: readonly string[];
}): SlackAuthoredTextPlacement {
const text = normalizeOptionalString(params.text);
if (!text) {
return "none";
}
const isRepresentedInBlocks =
params.renderedInBlocks ||
isSlackAuthoredTextRepresentedInFragments(text, params.renderedTextFragments ?? []) ||
isSlackAuthoredTextRepresentedInInteractive(text, params.interactive);
return isRepresentedInBlocks ? "blocks" : "outside-blocks";
}