openclaw/extensions/slack/src/stream-mode.ts
scoootscooob 8746362f5e
refactor(slack): move Slack channel code to extensions/slack/src/ (#45621)
Move all Slack channel implementation files from src/slack/ to
extensions/slack/src/ and replace originals with shim re-exports.
This follows the extension migration pattern for channel plugins.

- Copy all .ts files to extensions/slack/src/ (preserving directory
  structure: monitor/, http/, monitor/events/, monitor/message-handler/)
- Transform import paths: external src/ imports use relative paths
  back to src/, internal slack imports stay relative within extension
- Replace all src/slack/ files with shim re-exports pointing to
  the extension copies
- Update tsconfig.plugin-sdk.dts.json rootDir from "src" to "." so
  the DTS build can follow shim chains into extensions/
- Update write-plugin-sdk-entry-dts.ts re-export path accordingly
- Preserve extensions/slack/index.ts, package.json, openclaw.plugin.json,
  src/channel.ts, src/runtime.ts, src/channel.test.ts (untouched)
2026-03-14 02:47:04 -07:00

76 lines
2.5 KiB
TypeScript

import {
mapStreamingModeToSlackLegacyDraftStreamMode,
resolveSlackNativeStreaming,
resolveSlackStreamingMode,
type SlackLegacyDraftStreamMode,
type StreamingMode,
} from "../../../src/config/discord-preview-streaming.js";
export type SlackStreamMode = SlackLegacyDraftStreamMode;
export type SlackStreamingMode = StreamingMode;
const DEFAULT_STREAM_MODE: SlackStreamMode = "replace";
export function resolveSlackStreamMode(raw: unknown): SlackStreamMode {
if (typeof raw !== "string") {
return DEFAULT_STREAM_MODE;
}
const normalized = raw.trim().toLowerCase();
if (normalized === "replace" || normalized === "status_final" || normalized === "append") {
return normalized;
}
return DEFAULT_STREAM_MODE;
}
export function resolveSlackStreamingConfig(params: {
streaming?: unknown;
streamMode?: unknown;
nativeStreaming?: unknown;
}): { mode: SlackStreamingMode; nativeStreaming: boolean; draftMode: SlackStreamMode } {
const mode = resolveSlackStreamingMode(params);
const nativeStreaming = resolveSlackNativeStreaming(params);
return {
mode,
nativeStreaming,
draftMode: mapStreamingModeToSlackLegacyDraftStreamMode(mode),
};
}
export function applyAppendOnlyStreamUpdate(params: {
incoming: string;
rendered: string;
source: string;
}): { rendered: string; source: string; changed: boolean } {
const incoming = params.incoming.trimEnd();
if (!incoming) {
return { rendered: params.rendered, source: params.source, changed: false };
}
if (!params.rendered) {
return { rendered: incoming, source: incoming, changed: true };
}
if (incoming === params.source) {
return { rendered: params.rendered, source: params.source, changed: false };
}
// Typical model partials are cumulative prefixes.
if (incoming.startsWith(params.source) || incoming.startsWith(params.rendered)) {
return { rendered: incoming, source: incoming, changed: incoming !== params.rendered };
}
// Ignore regressive shorter variants of the same stream.
if (params.source.startsWith(incoming)) {
return { rendered: params.rendered, source: params.source, changed: false };
}
const separator = params.rendered.endsWith("\n") ? "" : "\n";
return {
rendered: `${params.rendered}${separator}${incoming}`,
source: incoming,
changed: true,
};
}
export function buildStatusFinalPreviewText(updateCount: number): string {
const dots = ".".repeat((Math.max(1, updateCount) % 3) + 1);
return `Status: thinking${dots}`;
}