diff --git a/docs/plugins/sdk-subpaths.md b/docs/plugins/sdk-subpaths.md index 818776fc01e..51d86db060d 100644 --- a/docs/plugins/sdk-subpaths.md +++ b/docs/plugins/sdk-subpaths.md @@ -67,7 +67,8 @@ For the plugin authoring guide, see [Plugin SDK overview](/plugins/sdk-overview) | `plugin-sdk/interactive-runtime` | Semantic message presentation, delivery, and legacy interactive reply helpers. See [Message Presentation](/plugins/message-presentation) | | `plugin-sdk/channel-inbound` | Compatibility barrel for inbound debounce, mention matching, mention-policy helpers, and envelope helpers | | `plugin-sdk/channel-inbound-debounce` | Narrow inbound debounce helpers | - | `plugin-sdk/channel-mention-gating` | Narrow mention-policy helpers without the broader inbound runtime surface | + | `plugin-sdk/channel-mention-gating` | Narrow mention-policy and mention text helpers without the broader inbound runtime surface | + | `plugin-sdk/channel-envelope` | Narrow inbound envelope formatting helpers | | `plugin-sdk/channel-location` | Channel location context and formatting helpers | | `plugin-sdk/channel-logging` | Channel logging helpers for inbound drops and typing/ack failures | | `plugin-sdk/channel-send-result` | Reply result types | @@ -105,6 +106,7 @@ For the plugin authoring guide, see [Plugin SDK overview](/plugins/sdk-overview) | `plugin-sdk/provider-transport-runtime` | Native provider transport helpers such as guarded fetch, transport message transforms, and writable transport event streams | | `plugin-sdk/provider-onboard` | Onboarding config patch helpers | | `plugin-sdk/global-singleton` | Process-local singleton/map/cache helpers | + | `plugin-sdk/group-activation` | Narrow group activation mode and command parsing helpers | @@ -120,6 +122,7 @@ For the plugin authoring guide, see [Plugin SDK overview](/plugins/sdk-overview) | `plugin-sdk/approval-handler-runtime` | Broader approval handler runtime helpers; prefer the narrower adapter/gateway seams when they are enough | | `plugin-sdk/approval-native-runtime` | Native approval target + account-binding helpers | | `plugin-sdk/approval-reply-runtime` | Exec/plugin approval reply payload helpers | + | `plugin-sdk/reply-dedupe` | Narrow inbound reply dedupe reset helpers | | `plugin-sdk/channel-contract-testing` | Narrow channel contract test helpers without the broad testing barrel | | `plugin-sdk/command-auth-native` | Native command auth + native session-target helpers | | `plugin-sdk/command-detection` | Shared command detection helpers | @@ -172,7 +175,7 @@ For the plugin authoring guide, see [Plugin SDK overview](/plugins/sdk-overview) | `plugin-sdk/tool-send` | Extract canonical send target fields from tool args | | `plugin-sdk/temp-path` | Shared temp-download path helpers | | `plugin-sdk/logging-core` | Subsystem logger and redaction helpers | - | `plugin-sdk/markdown-table-runtime` | Markdown table mode helpers | + | `plugin-sdk/markdown-table-runtime` | Markdown table mode and conversion helpers | | `plugin-sdk/json-store` | Small JSON state read/write helpers | | `plugin-sdk/file-lock` | Re-entrant file-lock helpers | | `plugin-sdk/persistent-dedupe` | Disk-backed dedupe cache helpers | @@ -210,6 +213,7 @@ For the plugin authoring guide, see [Plugin SDK overview](/plugins/sdk-overview) | Subpath | Key exports | | --- | --- | | `plugin-sdk/media-runtime` | Shared media fetch/transform/store helpers plus media payload builders | + | `plugin-sdk/media-store` | Narrow media store helpers such as `saveMediaBuffer` | | `plugin-sdk/media-generation-runtime` | Shared media-generation failover helpers, candidate selection, and missing-model messaging | | `plugin-sdk/media-understanding` | Media understanding provider types plus provider-facing image/audio helper exports | | `plugin-sdk/text-runtime` | Shared text/markdown/logging helpers such as assistant-visible-text stripping, markdown render/chunking/table helpers, redaction helpers, directive-tag helpers, and safe-text utilities | diff --git a/extensions/whatsapp/src/auto-reply.test-harness.ts b/extensions/whatsapp/src/auto-reply.test-harness.ts index b1aa4ad83f5..3dd8b9c646a 100644 --- a/extensions/whatsapp/src/auto-reply.test-harness.ts +++ b/extensions/whatsapp/src/auto-reply.test-harness.ts @@ -2,7 +2,7 @@ import "./test-helpers.js"; import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; -import { resetInboundDedupe } from "openclaw/plugin-sdk/reply-runtime"; +import { resetInboundDedupe } from "openclaw/plugin-sdk/reply-dedupe"; import { resetLogger, setLoggerOverride } from "openclaw/plugin-sdk/runtime-env"; import { mockPinnedHostnameResolution } from "openclaw/plugin-sdk/testing"; import { afterAll, afterEach, beforeAll, beforeEach, vi, type Mock } from "vitest"; diff --git a/extensions/whatsapp/src/auto-reply/mentions.ts b/extensions/whatsapp/src/auto-reply/mentions.ts index b9967a77961..864643f18ac 100644 --- a/extensions/whatsapp/src/auto-reply/mentions.ts +++ b/extensions/whatsapp/src/auto-reply/mentions.ts @@ -1,4 +1,7 @@ -import { buildMentionRegexes, normalizeMentionText } from "openclaw/plugin-sdk/channel-inbound"; +import { + buildMentionRegexes, + normalizeMentionText, +} from "openclaw/plugin-sdk/channel-mention-gating"; import type { loadConfig } from "openclaw/plugin-sdk/config-runtime"; import { getComparableIdentityValues, diff --git a/extensions/whatsapp/src/auto-reply/monitor/group-activation.runtime.ts b/extensions/whatsapp/src/auto-reply/monitor/group-activation.runtime.ts index 326105287a8..fc739e666ed 100644 --- a/extensions/whatsapp/src/auto-reply/monitor/group-activation.runtime.ts +++ b/extensions/whatsapp/src/auto-reply/monitor/group-activation.runtime.ts @@ -1 +1 @@ -export { normalizeGroupActivation } from "openclaw/plugin-sdk/reply-runtime"; +export { normalizeGroupActivation } from "openclaw/plugin-sdk/group-activation"; diff --git a/extensions/whatsapp/src/auto-reply/monitor/group-gating.runtime.ts b/extensions/whatsapp/src/auto-reply/monitor/group-gating.runtime.ts index c0da26fd7ad..07497919942 100644 --- a/extensions/whatsapp/src/auto-reply/monitor/group-gating.runtime.ts +++ b/extensions/whatsapp/src/auto-reply/monitor/group-gating.runtime.ts @@ -1,8 +1,8 @@ export { implicitMentionKindWhen, resolveInboundMentionDecision, -} from "openclaw/plugin-sdk/channel-inbound"; +} from "openclaw/plugin-sdk/channel-mention-gating"; export { hasControlCommand } from "openclaw/plugin-sdk/command-detection"; export { recordPendingHistoryEntryIfEnabled } from "openclaw/plugin-sdk/reply-history"; -export { parseActivationCommand } from "openclaw/plugin-sdk/reply-runtime"; +export { parseActivationCommand } from "openclaw/plugin-sdk/group-activation"; export { normalizeE164 } from "../../text-runtime.js"; diff --git a/extensions/whatsapp/src/auto-reply/monitor/message-line.runtime.ts b/extensions/whatsapp/src/auto-reply/monitor/message-line.runtime.ts index 4ef7c15c834..5d468eedbad 100644 --- a/extensions/whatsapp/src/auto-reply/monitor/message-line.runtime.ts +++ b/extensions/whatsapp/src/auto-reply/monitor/message-line.runtime.ts @@ -2,4 +2,4 @@ export { resolveMessagePrefix } from "openclaw/plugin-sdk/agent-runtime"; export { formatInboundEnvelope, type EnvelopeFormatOptions, -} from "openclaw/plugin-sdk/channel-inbound"; +} from "openclaw/plugin-sdk/channel-envelope"; diff --git a/extensions/whatsapp/src/auto-reply/monitor/runtime-api.ts b/extensions/whatsapp/src/auto-reply/monitor/runtime-api.ts index dbc78cf9c83..d73498d205f 100644 --- a/extensions/whatsapp/src/auto-reply/monitor/runtime-api.ts +++ b/extensions/whatsapp/src/auto-reply/monitor/runtime-api.ts @@ -1,9 +1,10 @@ export { resolveIdentityNamePrefix } from "openclaw/plugin-sdk/agent-runtime"; export { formatInboundEnvelope, - resolveInboundSessionEnvelopeContext, - toLocationContext, -} from "openclaw/plugin-sdk/channel-inbound"; + resolveEnvelopeFormatOptions, +} from "openclaw/plugin-sdk/channel-envelope"; +export { resolveInboundSessionEnvelopeContext } from "openclaw/plugin-sdk/channel-inbound"; +export { toLocationContext } from "openclaw/plugin-sdk/channel-location"; export { createChannelReplyPipeline } from "openclaw/plugin-sdk/channel-reply-pipeline"; export { shouldComputeCommandAuthorized } from "openclaw/plugin-sdk/command-detection"; export { diff --git a/extensions/whatsapp/src/inbound.media.test.ts b/extensions/whatsapp/src/inbound.media.test.ts index 1407fe7e564..c7f4a72281e 100644 --- a/extensions/whatsapp/src/inbound.media.test.ts +++ b/extensions/whatsapp/src/inbound.media.test.ts @@ -60,9 +60,9 @@ vi.mock("../../../src/pairing/pairing-store.js", () => { }; }); -vi.mock("openclaw/plugin-sdk/media-runtime", async () => { - const actual = await vi.importActual( - "openclaw/plugin-sdk/media-runtime", +vi.mock("openclaw/plugin-sdk/media-store", async () => { + const actual = await vi.importActual( + "openclaw/plugin-sdk/media-store", ); return { ...actual, diff --git a/extensions/whatsapp/src/inbound/save-media.runtime.ts b/extensions/whatsapp/src/inbound/save-media.runtime.ts index 3c82f2be877..cace8a847a2 100644 --- a/extensions/whatsapp/src/inbound/save-media.runtime.ts +++ b/extensions/whatsapp/src/inbound/save-media.runtime.ts @@ -1 +1 @@ -export { saveMediaBuffer } from "openclaw/plugin-sdk/media-runtime"; +export { saveMediaBuffer } from "openclaw/plugin-sdk/media-store"; diff --git a/extensions/whatsapp/src/inbound/types.ts b/extensions/whatsapp/src/inbound/types.ts index 45cebb371c1..0890dc65231 100644 --- a/extensions/whatsapp/src/inbound/types.ts +++ b/extensions/whatsapp/src/inbound/types.ts @@ -1,6 +1,6 @@ import type { AnyMessageContent, MiscMessageGenerationOptions } from "@whiskeysockets/baileys"; import type { NormalizedLocation } from "openclaw/plugin-sdk/channel-inbound"; -import type { PollInput } from "openclaw/plugin-sdk/media-runtime"; +import type { PollInput } from "openclaw/plugin-sdk/poll-runtime"; import type { WhatsAppIdentity, WhatsAppReplyContext, WhatsAppSelfIdentity } from "../identity.js"; export type WebListenerCloseReason = { diff --git a/extensions/whatsapp/src/media.test.ts b/extensions/whatsapp/src/media.test.ts index b7f89c288aa..0e301f7f2b3 100644 --- a/extensions/whatsapp/src/media.test.ts +++ b/extensions/whatsapp/src/media.test.ts @@ -1,11 +1,11 @@ import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; -import { optimizeImageToPng } from "openclaw/plugin-sdk/media-runtime"; import { resolveStateDir } from "openclaw/plugin-sdk/state-paths"; import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/temp-path"; import { captureEnv } from "openclaw/plugin-sdk/testing"; import { mockPinnedHostnameResolution } from "openclaw/plugin-sdk/testing"; +import { optimizeImageToPng } from "openclaw/plugin-sdk/web-media"; import sharp from "sharp"; import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from "vitest"; import { sendVoiceMessageDiscord } from "../../discord/src/send.js"; diff --git a/extensions/whatsapp/src/outbound-adapter.ts b/extensions/whatsapp/src/outbound-adapter.ts index 7d0993936e9..df56baf527b 100644 --- a/extensions/whatsapp/src/outbound-adapter.ts +++ b/extensions/whatsapp/src/outbound-adapter.ts @@ -1,5 +1,5 @@ import { type ChannelOutboundAdapter } from "openclaw/plugin-sdk/channel-send-result"; -import { chunkText } from "openclaw/plugin-sdk/reply-runtime"; +import { chunkText } from "openclaw/plugin-sdk/reply-chunking"; import { shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env"; import { createWhatsAppOutboundBase } from "./outbound-base.js"; import { resolveWhatsAppOutboundTarget } from "./resolve-outbound-target.js"; diff --git a/extensions/whatsapp/src/outbound-base.ts b/extensions/whatsapp/src/outbound-base.ts index 74742dfce92..5bcb0f3986c 100644 --- a/extensions/whatsapp/src/outbound-base.ts +++ b/extensions/whatsapp/src/outbound-base.ts @@ -9,7 +9,7 @@ import { type ChannelOutboundAdapter, } from "openclaw/plugin-sdk/channel-send-result"; import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; -import { resolveOutboundSendDep, sanitizeForPlainText } from "openclaw/plugin-sdk/infra-runtime"; +import { resolveOutboundSendDep, sanitizeForPlainText } from "openclaw/plugin-sdk/outbound-runtime"; import { sendTextMediaPayload } from "openclaw/plugin-sdk/reply-payload"; import { normalizeWhatsAppOutboundPayload, diff --git a/extensions/whatsapp/src/send.ts b/extensions/whatsapp/src/send.ts index 12da0318adc..1cb5100621a 100644 --- a/extensions/whatsapp/src/send.ts +++ b/extensions/whatsapp/src/send.ts @@ -1,12 +1,13 @@ import { formatCliCommand } from "openclaw/plugin-sdk/cli-runtime"; import { requireRuntimeConfig, type OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; -import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime"; import { generateSecureUuid } from "openclaw/plugin-sdk/core"; -import { normalizePollInput, type PollInput } from "openclaw/plugin-sdk/media-runtime"; -import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env"; -import { getChildLogger } from "openclaw/plugin-sdk/text-runtime"; -import { redactIdentifier } from "openclaw/plugin-sdk/text-runtime"; -import { convertMarkdownTables } from "openclaw/plugin-sdk/text-runtime"; +import { redactIdentifier } from "openclaw/plugin-sdk/logging-core"; +import { + convertMarkdownTables, + resolveMarkdownTableMode, +} from "openclaw/plugin-sdk/markdown-table-runtime"; +import { normalizePollInput, type PollInput } from "openclaw/plugin-sdk/poll-runtime"; +import { createSubsystemLogger, getChildLogger } from "openclaw/plugin-sdk/runtime-env"; import { resolveDefaultWhatsAppAccountId, resolveWhatsAppAccount, diff --git a/package.json b/package.json index 06596d5f2d6..b9ee57cc4ba 100644 --- a/package.json +++ b/package.json @@ -185,6 +185,10 @@ "types": "./dist/plugin-sdk/reply-runtime.d.ts", "default": "./dist/plugin-sdk/reply-runtime.js" }, + "./plugin-sdk/reply-dedupe": { + "types": "./dist/plugin-sdk/reply-dedupe.d.ts", + "default": "./dist/plugin-sdk/reply-dedupe.js" + }, "./plugin-sdk/reply-dispatch-runtime": { "types": "./dist/plugin-sdk/reply-dispatch-runtime.d.ts", "default": "./dist/plugin-sdk/reply-dispatch-runtime.js" @@ -265,6 +269,10 @@ "types": "./dist/plugin-sdk/media-runtime.d.ts", "default": "./dist/plugin-sdk/media-runtime.js" }, + "./plugin-sdk/media-store": { + "types": "./dist/plugin-sdk/media-store.d.ts", + "default": "./dist/plugin-sdk/media-store.js" + }, "./plugin-sdk/media-mime": { "types": "./dist/plugin-sdk/media-mime.d.ts", "default": "./dist/plugin-sdk/media-mime.js" @@ -629,6 +637,10 @@ "types": "./dist/plugin-sdk/channel-contract.d.ts", "default": "./dist/plugin-sdk/channel-contract.js" }, + "./plugin-sdk/channel-envelope": { + "types": "./dist/plugin-sdk/channel-envelope.d.ts", + "default": "./dist/plugin-sdk/channel-envelope.js" + }, "./plugin-sdk/channel-feedback": { "types": "./dist/plugin-sdk/channel-feedback.d.ts", "default": "./dist/plugin-sdk/channel-feedback.js" @@ -733,6 +745,10 @@ "types": "./dist/plugin-sdk/string-coerce-runtime.d.ts", "default": "./dist/plugin-sdk/string-coerce-runtime.js" }, + "./plugin-sdk/group-activation": { + "types": "./dist/plugin-sdk/group-activation.d.ts", + "default": "./dist/plugin-sdk/group-activation.js" + }, "./plugin-sdk/group-access": { "types": "./dist/plugin-sdk/group-access.d.ts", "default": "./dist/plugin-sdk/group-access.js" diff --git a/scripts/lib/plugin-sdk-entrypoints.json b/scripts/lib/plugin-sdk-entrypoints.json index 9d48b1d07df..0485b3ee376 100644 --- a/scripts/lib/plugin-sdk-entrypoints.json +++ b/scripts/lib/plugin-sdk-entrypoints.json @@ -32,6 +32,7 @@ "config-runtime", "config-schema", "reply-runtime", + "reply-dedupe", "reply-dispatch-runtime", "reply-reference", "reply-chunking", @@ -52,6 +53,7 @@ "ssrf-policy", "ssrf-runtime", "media-runtime", + "media-store", "media-mime", "media-generation-runtime", "conversation-binding-runtime", @@ -143,6 +145,7 @@ "channel-core", "channel-entry-contract", "channel-contract", + "channel-envelope", "channel-feedback", "channel-inbound", "channel-inbound-debounce", @@ -169,6 +172,7 @@ "session-store-runtime", "ssrf-dispatcher", "string-coerce-runtime", + "group-activation", "group-access", "global-singleton", "directory-config-runtime", diff --git a/src/plugin-sdk/channel-envelope.ts b/src/plugin-sdk/channel-envelope.ts new file mode 100644 index 00000000000..1cdc71d563f --- /dev/null +++ b/src/plugin-sdk/channel-envelope.ts @@ -0,0 +1,7 @@ +// Narrow inbound envelope helpers for hot channel message-formatting paths. + +export { + formatInboundEnvelope, + resolveEnvelopeFormatOptions, + type EnvelopeFormatOptions, +} from "../auto-reply/envelope.js"; diff --git a/src/plugin-sdk/channel-mention-gating.ts b/src/plugin-sdk/channel-mention-gating.ts index 077854be96e..dff01d0d421 100644 --- a/src/plugin-sdk/channel-mention-gating.ts +++ b/src/plugin-sdk/channel-mention-gating.ts @@ -19,3 +19,4 @@ export { // @deprecated Prefer `resolveInboundMentionDecision({ facts, policy })`. resolveMentionGatingWithBypass, } from "../channels/mention-gating.js"; +export { buildMentionRegexes, normalizeMentionText } from "../auto-reply/reply/mentions.js"; diff --git a/src/plugin-sdk/group-activation.ts b/src/plugin-sdk/group-activation.ts new file mode 100644 index 00000000000..876b10cc7a5 --- /dev/null +++ b/src/plugin-sdk/group-activation.ts @@ -0,0 +1,7 @@ +// Narrow group activation helpers for channel mention-gating paths. + +export { + normalizeGroupActivation, + parseActivationCommand, + type GroupActivationMode, +} from "../auto-reply/group-activation.js"; diff --git a/src/plugin-sdk/markdown-table-runtime.ts b/src/plugin-sdk/markdown-table-runtime.ts index 62e2848512f..0efe2807915 100644 --- a/src/plugin-sdk/markdown-table-runtime.ts +++ b/src/plugin-sdk/markdown-table-runtime.ts @@ -1,2 +1,3 @@ export { resolveMarkdownTableMode } from "../config/markdown-tables.js"; +export { convertMarkdownTables } from "../markdown/tables.js"; export type { MarkdownTableMode } from "../config/types.base.js"; diff --git a/src/plugin-sdk/media-store.ts b/src/plugin-sdk/media-store.ts new file mode 100644 index 00000000000..4814d9ca5d8 --- /dev/null +++ b/src/plugin-sdk/media-store.ts @@ -0,0 +1,3 @@ +// Narrow media store helpers for channel runtimes that do not need the full media runtime. + +export { saveMediaBuffer } from "../media/store.js"; diff --git a/src/plugin-sdk/reply-dedupe.ts b/src/plugin-sdk/reply-dedupe.ts new file mode 100644 index 00000000000..134872008b4 --- /dev/null +++ b/src/plugin-sdk/reply-dedupe.ts @@ -0,0 +1,3 @@ +// Narrow reply dedupe helpers for tests and channel runtimes that do not need the full reply runtime. + +export { resetInboundDedupe } from "../auto-reply/reply/inbound-dedupe.js";