From 605cb60586ebb6ffd4f8552fe2f4b70314adf980 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 17 Apr 2026 16:04:02 +0100 Subject: [PATCH] perf: optimize Matrix test boundaries --- extensions/matrix/src/account-selection.ts | 2 +- extensions/matrix/src/actions.ts | 2 +- extensions/matrix/src/approval-native.ts | 2 +- extensions/matrix/src/channel.ts | 4 +- extensions/matrix/src/cli.ts | 19 ++- extensions/matrix/src/directory-live.ts | 2 +- extensions/matrix/src/exec-approvals.ts | 2 +- extensions/matrix/src/matrix/accounts.ts | 2 +- .../matrix/src/matrix/actions/messages.ts | 2 +- .../matrix/src/matrix/actions/verification.ts | 2 +- extensions/matrix/src/matrix/client/config.ts | 9 +- .../matrix/src/matrix/client/create-client.ts | 4 +- .../matrix/src/matrix/client/env-auth.ts | 101 ++++++++++++- .../src/matrix/client/private-network-host.ts | 2 +- extensions/matrix/src/matrix/client/types.ts | 2 +- .../src/matrix/client/url-validation.ts | 76 ++++++++++ extensions/matrix/src/matrix/config-update.ts | 2 +- extensions/matrix/src/matrix/credentials.ts | 2 +- extensions/matrix/src/matrix/deps.ts | 2 +- .../matrix/src/matrix/direct-management.ts | 2 +- .../matrix/src/matrix/draft-stream.test.ts | 137 ++++++++++++++++-- extensions/matrix/src/matrix/errors.ts | 2 +- extensions/matrix/src/matrix/format.ts | 6 +- .../matrix/src/matrix/monitor/ack-config.ts | 3 +- .../matrix/src/matrix/monitor/allowlist.ts | 2 +- .../matrix/src/matrix/monitor/auto-join.ts | 2 +- .../matrix/src/matrix/monitor/events.ts | 2 +- .../monitor/handler.group-history.test.ts | 29 ++++ .../matrix/src/matrix/monitor/handler.ts | 125 +++++++++++----- .../matrix/src/matrix/monitor/location.ts | 2 +- .../matrix/src/matrix/monitor/mentions.ts | 2 +- .../src/matrix/monitor/reaction-events.ts | 2 +- .../matrix/src/matrix/monitor/replies.ts | 2 +- extensions/matrix/src/matrix/monitor/route.ts | 11 +- .../matrix/src/matrix/monitor/runtime-api.ts | 12 +- .../src/matrix/monitor/verification-utils.ts | 2 +- .../src/matrix/outbound-media-runtime.ts | 2 +- extensions/matrix/src/matrix/poll-types.ts | 4 +- extensions/matrix/src/matrix/probe.ts | 2 +- extensions/matrix/src/matrix/profile.ts | 2 +- .../matrix/src/matrix/reaction-common.ts | 2 +- extensions/matrix/src/matrix/sdk.ts | 4 +- .../matrix/src/matrix/sdk/http-client.ts | 2 +- .../src/matrix/sdk/idb-persistence-lock.ts | 2 +- .../sdk/idb-persistence.lock-order.test.ts | 6 +- .../matrix/src/matrix/sdk/idb-persistence.ts | 2 +- .../matrix/sdk/read-response-with-limit.ts | 2 +- .../src/matrix/sdk/transport-runtime-api.ts | 49 +++++++ extensions/matrix/src/matrix/sdk/transport.ts | 12 +- extensions/matrix/src/matrix/send/targets.ts | 2 +- .../matrix/src/matrix/subagent-hooks.ts | 2 +- extensions/matrix/src/matrix/target-ids.ts | 2 +- .../matrix/src/matrix/thread-bindings.ts | 2 +- extensions/matrix/src/migration-config.ts | 2 +- .../matrix/src/migration-snapshot-backup.ts | 3 +- extensions/matrix/src/onboarding.ts | 38 +++-- extensions/matrix/src/plugin-entry.runtime.ts | 2 +- extensions/matrix/src/record-shared.ts | 2 +- extensions/matrix/src/resolve-targets.ts | 2 +- extensions/matrix/src/runtime-api.ts | 8 +- extensions/matrix/src/setup-config.ts | 2 +- extensions/matrix/src/storage-paths.ts | 2 +- extensions/matrix/src/test-runtime.ts | 2 +- extensions/matrix/src/thread-binding-api.ts | 2 +- extensions/matrix/src/tool-actions.ts | 2 +- 65 files changed, 578 insertions(+), 170 deletions(-) create mode 100644 extensions/matrix/src/matrix/client/url-validation.ts create mode 100644 extensions/matrix/src/matrix/sdk/transport-runtime-api.ts diff --git a/extensions/matrix/src/account-selection.ts b/extensions/matrix/src/account-selection.ts index 8f32cadb952..1ef021e1fe2 100644 --- a/extensions/matrix/src/account-selection.ts +++ b/extensions/matrix/src/account-selection.ts @@ -11,7 +11,7 @@ import { } from "openclaw/plugin-sdk/account-id"; import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import { hasConfiguredSecretInput } from "openclaw/plugin-sdk/secret-input"; -import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime"; import { resolveMatrixAccountStringValues, type MatrixResolvedStringField, diff --git a/extensions/matrix/src/actions.ts b/extensions/matrix/src/actions.ts index e25202d3278..aaa0c6e630d 100644 --- a/extensions/matrix/src/actions.ts +++ b/extensions/matrix/src/actions.ts @@ -1,5 +1,5 @@ import { Type } from "@sinclair/typebox"; -import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime"; import { extractToolSend } from "openclaw/plugin-sdk/tool-send"; import { requiresExplicitMatrixDefaultAccount } from "./account-selection.js"; import { resolveDefaultMatrixAccountId, resolveMatrixAccount } from "./matrix/accounts.js"; diff --git a/extensions/matrix/src/approval-native.ts b/extensions/matrix/src/approval-native.ts index 61426d3fce0..7baeee0009c 100644 --- a/extensions/matrix/src/approval-native.ts +++ b/extensions/matrix/src/approval-native.ts @@ -14,7 +14,7 @@ import type { ExecApprovalRequest, PluginApprovalRequest } from "openclaw/plugin import { normalizeLowercaseStringOrEmpty, normalizeOptionalStringifiedId, -} from "openclaw/plugin-sdk/text-runtime"; +} from "openclaw/plugin-sdk/string-coerce-runtime"; import { getMatrixApprovalAuthApprovers, matrixApprovalAuth } from "./approval-auth.js"; import { normalizeMatrixApproverId } from "./approval-ids.js"; import { diff --git a/extensions/matrix/src/channel.ts b/extensions/matrix/src/channel.ts index 060c5ea0e16..f8d6d6fe441 100644 --- a/extensions/matrix/src/channel.ts +++ b/extensions/matrix/src/channel.ts @@ -24,11 +24,11 @@ import { createComputedAccountStatusAdapter, createDefaultChannelRuntimeState, } from "openclaw/plugin-sdk/status-helpers"; -import { chunkTextForOutbound } from "openclaw/plugin-sdk/text-chunking"; import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, -} from "openclaw/plugin-sdk/text-runtime"; +} from "openclaw/plugin-sdk/string-coerce-runtime"; +import { chunkTextForOutbound } from "openclaw/plugin-sdk/text-chunking"; import { matrixMessageActions } from "./actions.js"; import { matrixApprovalCapability } from "./approval-native.js"; import { createMatrixPairingText, createMatrixProbeAccount } from "./channel-account-paths.js"; diff --git a/extensions/matrix/src/cli.ts b/extensions/matrix/src/cli.ts index 784a132d429..aece66537cb 100644 --- a/extensions/matrix/src/cli.ts +++ b/extensions/matrix/src/cli.ts @@ -1,6 +1,8 @@ import type { Command } from "commander"; +import { normalizeAccountId } from "openclaw/plugin-sdk/account-id"; +import { formatZonedTimestamp } from "openclaw/plugin-sdk/matrix-runtime-shared"; +import type { ChannelSetupInput } from "openclaw/plugin-sdk/setup"; import { resolveMatrixAccount, resolveMatrixAccountConfig } from "./matrix/accounts.js"; -import { withResolvedActionClient, withStartedActionClient } from "./matrix/actions/client.js"; import { listMatrixOwnDevices, pruneMatrixStaleGatewayDevices } from "./matrix/actions/devices.js"; import { updateMatrixOwnProfile } from "./matrix/actions/profile.js"; import { @@ -16,14 +18,9 @@ import { resolveMatrixAuthContext } from "./matrix/client.js"; import { setMatrixSdkConsoleLogging, setMatrixSdkLogMode } from "./matrix/client/logging.js"; import { resolveMatrixConfigPath, updateMatrixAccountConfig } from "./matrix/config-update.js"; import { isOpenClawManagedMatrixDevice } from "./matrix/device-health.js"; -import { - inspectMatrixDirectRooms, - repairMatrixDirectRooms, - type MatrixDirectRoomCandidate, -} from "./matrix/direct-management.js"; +import type { MatrixDirectRoomCandidate } from "./matrix/direct-management.js"; import { formatMatrixErrorMessage } from "./matrix/errors.js"; import { applyMatrixProfileUpdate, type MatrixProfileUpdateResult } from "./profile-update.js"; -import { formatZonedTimestamp, normalizeAccountId, type ChannelSetupInput } from "./runtime-api.js"; import { getMatrixRuntime } from "./runtime.js"; import { matrixSetupAdapter } from "./setup-core.js"; import type { CoreConfig } from "./types.js"; @@ -334,6 +331,10 @@ async function inspectMatrixDirectRoom(params: { accountId: string; userId: string; }): Promise { + const [{ withResolvedActionClient }, { inspectMatrixDirectRooms }] = await Promise.all([ + import("./matrix/actions/client.js"), + import("./matrix/direct-management.js"), + ]); return await withResolvedActionClient( { accountId: params.accountId }, async (client) => { @@ -361,6 +362,10 @@ async function repairMatrixDirectRoom(params: { }): Promise { const cfg = getMatrixRuntime().config.loadConfig() as CoreConfig; const account = resolveMatrixAccount({ cfg, accountId: params.accountId }); + const [{ withStartedActionClient }, { repairMatrixDirectRooms }] = await Promise.all([ + import("./matrix/actions/client.js"), + import("./matrix/direct-management.js"), + ]); return await withStartedActionClient({ accountId: params.accountId }, async (client) => { const repaired = await repairMatrixDirectRooms({ client, diff --git a/extensions/matrix/src/directory-live.ts b/extensions/matrix/src/directory-live.ts index 17884837e40..f69019e870a 100644 --- a/extensions/matrix/src/directory-live.ts +++ b/extensions/matrix/src/directory-live.ts @@ -1,7 +1,7 @@ import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, -} from "openclaw/plugin-sdk/text-runtime"; +} from "openclaw/plugin-sdk/string-coerce-runtime"; import { resolveMatrixAuth } from "./matrix/client.js"; import { MatrixAuthedHttpClient } from "./matrix/sdk/http-client.js"; import { isMatrixQualifiedUserId, normalizeMatrixMessagingTarget } from "./matrix/target-ids.js"; diff --git a/extensions/matrix/src/exec-approvals.ts b/extensions/matrix/src/exec-approvals.ts index 731253bf9a3..f12da3d9e56 100644 --- a/extensions/matrix/src/exec-approvals.ts +++ b/extensions/matrix/src/exec-approvals.ts @@ -11,7 +11,7 @@ import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import type { ExecApprovalRequest, PluginApprovalRequest } from "openclaw/plugin-sdk/infra-runtime"; import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; import { normalizeAccountId } from "openclaw/plugin-sdk/routing"; -import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime"; import { getMatrixApprovalAuthApprovers } from "./approval-auth.js"; import { normalizeMatrixApproverId } from "./approval-ids.js"; import { listMatrixAccountIds, resolveMatrixAccount } from "./matrix/accounts.js"; diff --git a/extensions/matrix/src/matrix/accounts.ts b/extensions/matrix/src/matrix/accounts.ts index 48af02ed1d0..ccba883d276 100644 --- a/extensions/matrix/src/matrix/accounts.ts +++ b/extensions/matrix/src/matrix/accounts.ts @@ -1,6 +1,6 @@ import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id"; import { hasConfiguredSecretInput } from "openclaw/plugin-sdk/secret-input"; -import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime"; import { resolveConfiguredMatrixAccountIds, resolveMatrixDefaultOrOnlyAccountId, diff --git a/extensions/matrix/src/matrix/actions/messages.ts b/extensions/matrix/src/matrix/actions/messages.ts index 581e6a7da85..dd51ddf5668 100644 --- a/extensions/matrix/src/matrix/actions/messages.ts +++ b/extensions/matrix/src/matrix/actions/messages.ts @@ -1,4 +1,4 @@ -import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime"; import { fetchMatrixPollMessageSummary, resolveMatrixPollRootEventId } from "../poll-summary.js"; import { isPollEventType } from "../poll-types.js"; import { editMessageMatrix, sendMessageMatrix } from "../send.js"; diff --git a/extensions/matrix/src/matrix/actions/verification.ts b/extensions/matrix/src/matrix/actions/verification.ts index cdb4a8dac07..90bd240223a 100644 --- a/extensions/matrix/src/matrix/actions/verification.ts +++ b/extensions/matrix/src/matrix/actions/verification.ts @@ -1,4 +1,4 @@ -import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime"; import { getMatrixRuntime } from "../../runtime.js"; import type { CoreConfig } from "../../types.js"; import { formatMatrixEncryptionUnavailableError } from "../encryption-guidance.js"; diff --git a/extensions/matrix/src/matrix/client/config.ts b/extensions/matrix/src/matrix/client/config.ts index 7417b1c55cb..66f3abe416a 100644 --- a/extensions/matrix/src/matrix/client/config.ts +++ b/extensions/matrix/src/matrix/client/config.ts @@ -1,7 +1,10 @@ -import { formatErrorMessage, type PinnedDispatcherPolicy } from "openclaw/plugin-sdk/infra-runtime"; -import { coerceSecretRef } from "openclaw/plugin-sdk/provider-auth"; +import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime"; import { retryAsync } from "openclaw/plugin-sdk/retry-runtime"; -import { normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/secret-input"; +import { + coerceSecretRef, + normalizeResolvedSecretInputString, +} from "openclaw/plugin-sdk/secret-input"; +import type { PinnedDispatcherPolicy } from "openclaw/plugin-sdk/ssrf-dispatcher"; import { requiresExplicitMatrixDefaultAccount, resolveMatrixDefaultOrOnlyAccountId, diff --git a/extensions/matrix/src/matrix/client/create-client.ts b/extensions/matrix/src/matrix/client/create-client.ts index 60df22176e6..c543308bd82 100644 --- a/extensions/matrix/src/matrix/client/create-client.ts +++ b/extensions/matrix/src/matrix/client/create-client.ts @@ -1,6 +1,6 @@ import fs from "node:fs"; -import type { PinnedDispatcherPolicy } from "openclaw/plugin-sdk/infra-runtime"; -import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; +import type { PinnedDispatcherPolicy } from "openclaw/plugin-sdk/ssrf-dispatcher"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime"; import type { SsrFPolicy } from "../../runtime-api.js"; import type { MatrixClient } from "../sdk.js"; import { resolveValidatedMatrixHomeserverUrl } from "./config.js"; diff --git a/extensions/matrix/src/matrix/client/env-auth.ts b/extensions/matrix/src/matrix/client/env-auth.ts index f822baf315b..862b57a345f 100644 --- a/extensions/matrix/src/matrix/client/env-auth.ts +++ b/extensions/matrix/src/matrix/client/env-auth.ts @@ -1,6 +1,95 @@ -export { - hasReadyMatrixEnvAuth, - resolveGlobalMatrixEnvConfig, - resolveMatrixEnvAuthReadiness, - resolveScopedMatrixEnvConfig, -} from "./config.js"; +import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id"; +import { getMatrixScopedEnvVarNames } from "../../env-vars.js"; + +type MatrixEnvConfig = { + homeserver: string; + userId: string; + accessToken?: string; + password?: string; + deviceId?: string; + deviceName?: string; +}; + +function cleanEnv(value: unknown): string { + return typeof value === "string" ? value.trim() : ""; +} + +export function resolveGlobalMatrixEnvConfig(env: NodeJS.ProcessEnv): MatrixEnvConfig { + return { + homeserver: cleanEnv(env.MATRIX_HOMESERVER), + userId: cleanEnv(env.MATRIX_USER_ID), + accessToken: cleanEnv(env.MATRIX_ACCESS_TOKEN) || undefined, + password: cleanEnv(env.MATRIX_PASSWORD) || undefined, + deviceId: cleanEnv(env.MATRIX_DEVICE_ID) || undefined, + deviceName: cleanEnv(env.MATRIX_DEVICE_NAME) || undefined, + }; +} + +export function hasReadyMatrixEnvAuth(config: { + homeserver?: string; + userId?: string; + accessToken?: string; + password?: string; +}): boolean { + const homeserver = cleanEnv(config.homeserver); + const userId = cleanEnv(config.userId); + const accessToken = cleanEnv(config.accessToken); + const password = cleanEnv(config.password); + return Boolean(homeserver && (accessToken || (userId && password))); +} + +export function resolveScopedMatrixEnvConfig( + accountId: string, + env: NodeJS.ProcessEnv = process.env, +): MatrixEnvConfig { + const keys = getMatrixScopedEnvVarNames(accountId); + return { + homeserver: cleanEnv(env[keys.homeserver]), + userId: cleanEnv(env[keys.userId]), + accessToken: cleanEnv(env[keys.accessToken]) || undefined, + password: cleanEnv(env[keys.password]) || undefined, + deviceId: cleanEnv(env[keys.deviceId]) || undefined, + deviceName: cleanEnv(env[keys.deviceName]) || undefined, + }; +} + +export function resolveMatrixEnvAuthReadiness( + accountId: string, + env: NodeJS.ProcessEnv = process.env, +): { + ready: boolean; + homeserver?: string; + userId?: string; + sourceHint: string; + missingMessage: string; +} { + const normalizedAccountId = normalizeAccountId(accountId); + const scoped = resolveScopedMatrixEnvConfig(normalizedAccountId, env); + const scopedReady = hasReadyMatrixEnvAuth(scoped); + if (normalizedAccountId !== DEFAULT_ACCOUNT_ID) { + const keys = getMatrixScopedEnvVarNames(normalizedAccountId); + return { + ready: scopedReady, + homeserver: scoped.homeserver || undefined, + userId: scoped.userId || undefined, + sourceHint: `${keys.homeserver} (+ auth vars)`, + missingMessage: `Set per-account env vars for "${normalizedAccountId}" (for example ${keys.homeserver} + ${keys.accessToken} or ${keys.userId} + ${keys.password}).`, + }; + } + + const defaultScoped = resolveScopedMatrixEnvConfig(DEFAULT_ACCOUNT_ID, env); + const global = resolveGlobalMatrixEnvConfig(env); + const defaultScopedReady = hasReadyMatrixEnvAuth(defaultScoped); + const globalReady = hasReadyMatrixEnvAuth(global); + const defaultKeys = getMatrixScopedEnvVarNames(DEFAULT_ACCOUNT_ID); + return { + ready: defaultScopedReady || globalReady, + homeserver: defaultScoped.homeserver || global.homeserver || undefined, + userId: defaultScoped.userId || global.userId || undefined, + sourceHint: "MATRIX_* or MATRIX_DEFAULT_*", + missingMessage: + `Set Matrix env vars for the default account ` + + `(for example MATRIX_HOMESERVER + MATRIX_ACCESS_TOKEN, MATRIX_USER_ID + MATRIX_PASSWORD, ` + + `or ${defaultKeys.homeserver} + ${defaultKeys.accessToken}).`, + }; +} diff --git a/extensions/matrix/src/matrix/client/private-network-host.ts b/extensions/matrix/src/matrix/client/private-network-host.ts index d8d96b1da01..61fc5bf55a1 100644 --- a/extensions/matrix/src/matrix/client/private-network-host.ts +++ b/extensions/matrix/src/matrix/client/private-network-host.ts @@ -1,5 +1,5 @@ import net from "node:net"; -import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime"; function normalizeHost(host: string): string { const normalized = normalizeLowercaseStringOrEmpty(host).replace(/\.+$/, ""); diff --git a/extensions/matrix/src/matrix/client/types.ts b/extensions/matrix/src/matrix/client/types.ts index f2dee1da42d..8bdb234df81 100644 --- a/extensions/matrix/src/matrix/client/types.ts +++ b/extensions/matrix/src/matrix/client/types.ts @@ -1,4 +1,4 @@ -import type { PinnedDispatcherPolicy } from "openclaw/plugin-sdk/infra-runtime"; +import type { PinnedDispatcherPolicy } from "openclaw/plugin-sdk/ssrf-dispatcher"; import type { SsrFPolicy } from "../../runtime-api.js"; export type MatrixResolvedConfig = { diff --git a/extensions/matrix/src/matrix/client/url-validation.ts b/extensions/matrix/src/matrix/client/url-validation.ts new file mode 100644 index 00000000000..975cf415488 --- /dev/null +++ b/extensions/matrix/src/matrix/client/url-validation.ts @@ -0,0 +1,76 @@ +import { + assertHttpUrlTargetsPrivateNetwork, + type LookupFn, +} from "openclaw/plugin-sdk/ssrf-runtime"; +import { isPrivateOrLoopbackHost } from "./private-network-host.js"; + +const MATRIX_HTTP_HOMESERVER_ERROR = + "Matrix homeserver must use https:// unless it targets a private or loopback host"; + +function cleanString(value: unknown, requiredMessage: string): string { + const trimmed = typeof value === "string" ? value.trim() : ""; + if (!trimmed) { + throw new Error(requiredMessage); + } + return trimmed; +} + +export function validateMatrixHomeserverUrl( + homeserver: string, + opts?: { allowPrivateNetwork?: boolean }, +): string { + const trimmed = cleanString(homeserver, "Matrix homeserver is required (matrix.homeserver)"); + + let parsed: URL; + try { + parsed = new URL(trimmed); + } catch { + throw new Error("Matrix homeserver must be a valid http(s) URL"); + } + + if (parsed.protocol !== "https:" && parsed.protocol !== "http:") { + throw new Error("Matrix homeserver must use http:// or https://"); + } + if (!parsed.hostname) { + throw new Error("Matrix homeserver must include a hostname"); + } + if (parsed.username || parsed.password) { + throw new Error("Matrix homeserver URL must not include embedded credentials"); + } + if (parsed.search || parsed.hash) { + throw new Error("Matrix homeserver URL must not include query strings or fragments"); + } + if ( + parsed.protocol === "http:" && + opts?.allowPrivateNetwork !== true && + !isPrivateOrLoopbackHost(parsed.hostname) + ) { + throw new Error(MATRIX_HTTP_HOMESERVER_ERROR); + } + + return trimmed; +} + +export async function resolveValidatedMatrixHomeserverUrl( + homeserver: string, + opts?: { + dangerouslyAllowPrivateNetwork?: boolean; + allowPrivateNetwork?: boolean; + lookupFn?: LookupFn; + }, +): Promise { + const allowPrivateNetwork = + typeof opts?.dangerouslyAllowPrivateNetwork === "boolean" + ? opts.dangerouslyAllowPrivateNetwork + : opts?.allowPrivateNetwork; + const normalized = validateMatrixHomeserverUrl(homeserver, { + allowPrivateNetwork, + }); + await assertHttpUrlTargetsPrivateNetwork(normalized, { + dangerouslyAllowPrivateNetwork: opts?.dangerouslyAllowPrivateNetwork, + allowPrivateNetwork, + lookupFn: opts?.lookupFn, + errorMessage: MATRIX_HTTP_HOMESERVER_ERROR, + }); + return normalized; +} diff --git a/extensions/matrix/src/matrix/config-update.ts b/extensions/matrix/src/matrix/config-update.ts index b089ab4e1b9..5b7280a6698 100644 --- a/extensions/matrix/src/matrix/config-update.ts +++ b/extensions/matrix/src/matrix/config-update.ts @@ -1,5 +1,5 @@ import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id"; -import { coerceSecretRef } from "openclaw/plugin-sdk/config-runtime"; +import { coerceSecretRef } from "openclaw/plugin-sdk/secret-ref-runtime"; import { normalizeSecretInputString } from "openclaw/plugin-sdk/setup"; import type { CoreConfig, MatrixConfig } from "../types.js"; import { findMatrixAccountConfig } from "./account-config.js"; diff --git a/extensions/matrix/src/matrix/credentials.ts b/extensions/matrix/src/matrix/credentials.ts index 11b3a142891..6b8650d3690 100644 --- a/extensions/matrix/src/matrix/credentials.ts +++ b/extensions/matrix/src/matrix/credentials.ts @@ -1,4 +1,4 @@ -import { writeJsonFileAtomically } from "../runtime-api.js"; +import { writeJsonFileAtomically } from "openclaw/plugin-sdk/json-store"; import { createAsyncLock, type AsyncLock } from "./async-lock.js"; import { loadMatrixCredentials, resolveMatrixCredentialsPath } from "./credentials-read.js"; import type { MatrixStoredCredentials } from "./credentials-read.js"; diff --git a/extensions/matrix/src/matrix/deps.ts b/extensions/matrix/src/matrix/deps.ts index 0324c61af00..9bf3216ae7e 100644 --- a/extensions/matrix/src/matrix/deps.ts +++ b/extensions/matrix/src/matrix/deps.ts @@ -4,7 +4,7 @@ import { createRequire } from "node:module"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime"; -import type { RuntimeEnv } from "../runtime-api.js"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime"; const REQUIRED_MATRIX_PACKAGES = [ "matrix-js-sdk", diff --git a/extensions/matrix/src/matrix/direct-management.ts b/extensions/matrix/src/matrix/direct-management.ts index 2174ada0e87..209f63181b5 100644 --- a/extensions/matrix/src/matrix/direct-management.ts +++ b/extensions/matrix/src/matrix/direct-management.ts @@ -1,5 +1,5 @@ import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue"; -import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime"; import { inspectMatrixDirectRoomEvidence } from "./direct-room.js"; import type { MatrixClient } from "./sdk.js"; import { EventType, type MatrixDirectAccountData } from "./send/types.js"; diff --git a/extensions/matrix/src/matrix/draft-stream.test.ts b/extensions/matrix/src/matrix/draft-stream.test.ts index e9239f5a822..559dddacd41 100644 --- a/extensions/matrix/src/matrix/draft-stream.test.ts +++ b/extensions/matrix/src/matrix/draft-stream.test.ts @@ -1,15 +1,134 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import type { PluginRuntime } from "../runtime-api.js"; -const loadConfigMock = vi.fn(() => ({})); -const resolveTextChunkLimitMock = vi.fn< - (cfg: unknown, channel: unknown, accountId?: unknown) => number ->(() => 4000); -const resolveChunkModeMock = vi.fn<(cfg: unknown, channel: unknown, accountId?: unknown) => string>( - () => "length", -); -const chunkMarkdownTextWithModeMock = vi.fn((text: string) => (text ? [text] : [])); -const convertMarkdownTablesMock = vi.fn((text: string) => text); +const sendModuleMocks = vi.hoisted(() => { + const loadConfigMock = vi.fn(() => ({})); + const resolveTextChunkLimitMock = vi.fn< + (cfg: unknown, channel: unknown, accountId?: unknown) => number + >(() => 4000); + const resolveChunkModeMock = vi.fn< + (cfg: unknown, channel: unknown, accountId?: unknown) => string + >(() => "length"); + const chunkMarkdownTextWithModeMock = vi.fn((text: string) => (text ? [text] : [])); + const convertMarkdownTablesMock = vi.fn((text: string) => text); + const prepareMatrixSingleText = vi.fn( + (text: string, opts: { cfg?: unknown; accountId?: string } = {}) => { + const trimmedText = text.trim(); + const convertedText = convertMarkdownTablesMock(trimmedText); + const singleEventLimit = Math.min( + resolveTextChunkLimitMock(opts.cfg ?? {}, "matrix", opts.accountId), + 4000, + ); + return { + trimmedText, + convertedText, + singleEventLimit, + fitsInSingleEvent: convertedText.length <= singleEventLimit, + }; + }, + ); + const sendSingleTextMessageMatrix = vi.fn( + async ( + roomId: string, + text: string, + opts: { + client?: { + sendMessage: (roomId: string, content: Record) => Promise; + }; + cfg?: unknown; + accountId?: string; + msgtype?: string; + includeMentions?: boolean; + live?: boolean; + } = {}, + ) => { + const prepared = prepareMatrixSingleText(text, { + cfg: opts.cfg, + accountId: opts.accountId, + }); + if (!prepared.trimmedText) { + throw new Error("Matrix single-message send requires text"); + } + if (!prepared.fitsInSingleEvent) { + throw new Error("Matrix single-message text exceeds limit"); + } + const content: Record = { + msgtype: opts.msgtype ?? "m.text", + body: prepared.convertedText, + }; + if (opts.live) { + content["org.matrix.msc4357.live"] = {}; + } + const eventId = await opts.client?.sendMessage(roomId, content); + return { + messageId: eventId ?? "unknown", + roomId, + primaryMessageId: eventId ?? "unknown", + messageIds: eventId ? [eventId] : [], + }; + }, + ); + const editMessageMatrix = vi.fn( + async ( + roomId: string, + originalEventId: string, + newText: string, + opts: { + client?: { + sendMessage: (roomId: string, content: Record) => Promise; + }; + msgtype?: string; + live?: boolean; + } = {}, + ) => { + const convertedText = convertMarkdownTablesMock(newText); + const newContent: Record = { + msgtype: opts.msgtype ?? "m.text", + body: convertedText, + }; + if (opts.live) { + newContent["org.matrix.msc4357.live"] = {}; + } + const content: Record = { + ...newContent, + body: `* ${convertedText}`, + "m.new_content": newContent, + "m.relates_to": { + rel_type: "m.replace", + event_id: originalEventId, + }, + }; + if (opts.live) { + content["org.matrix.msc4357.live"] = {}; + } + return (await opts.client?.sendMessage(roomId, content)) ?? ""; + }, + ); + return { + chunkMarkdownTextWithModeMock, + convertMarkdownTablesMock, + editMessageMatrix, + loadConfigMock, + prepareMatrixSingleText, + resolveChunkModeMock, + resolveTextChunkLimitMock, + sendSingleTextMessageMatrix, + }; +}); + +const { + chunkMarkdownTextWithModeMock, + convertMarkdownTablesMock, + loadConfigMock, + resolveChunkModeMock, + resolveTextChunkLimitMock, +} = sendModuleMocks; + +vi.mock("./send.js", () => ({ + editMessageMatrix: sendModuleMocks.editMessageMatrix, + prepareMatrixSingleText: sendModuleMocks.prepareMatrixSingleText, + sendSingleTextMessageMatrix: sendModuleMocks.sendSingleTextMessageMatrix, +})); const runtimeStub = { config: { loadConfig: () => loadConfigMock() }, channel: { diff --git a/extensions/matrix/src/matrix/errors.ts b/extensions/matrix/src/matrix/errors.ts index 1b70d352990..a102d832024 100644 --- a/extensions/matrix/src/matrix/errors.ts +++ b/extensions/matrix/src/matrix/errors.ts @@ -1,5 +1,5 @@ import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime"; -import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime"; export function formatMatrixErrorMessage(err: unknown): string { return formatErrorMessage(err); diff --git a/extensions/matrix/src/matrix/format.ts b/extensions/matrix/src/matrix/format.ts index 33b1c5f498b..f00aa56ecbb 100644 --- a/extensions/matrix/src/matrix/format.ts +++ b/extensions/matrix/src/matrix/format.ts @@ -1,8 +1,6 @@ import MarkdownIt from "markdown-it"; -import { - isAutoLinkedFileRef, - normalizeLowercaseStringOrEmpty, -} from "openclaw/plugin-sdk/text-runtime"; +import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime"; +import { isAutoLinkedFileRef } from "openclaw/plugin-sdk/text-autolink-runtime"; import type { MatrixClient } from "./sdk.js"; import { isMatrixQualifiedUserId } from "./target-ids.js"; diff --git a/extensions/matrix/src/matrix/monitor/ack-config.ts b/extensions/matrix/src/matrix/monitor/ack-config.ts index 55a79c4dc41..0c375aeb516 100644 --- a/extensions/matrix/src/matrix/monitor/ack-config.ts +++ b/extensions/matrix/src/matrix/monitor/ack-config.ts @@ -1,6 +1,7 @@ +import { resolveAckReaction } from "openclaw/plugin-sdk/channel-feedback"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import type { CoreConfig } from "../../types.js"; import { resolveMatrixAccountConfig } from "../account-config.js"; -import { resolveAckReaction, type OpenClawConfig } from "./runtime-api.js"; type MatrixAckReactionScope = "group-mentions" | "group-all" | "direct" | "all" | "none" | "off"; diff --git a/extensions/matrix/src/matrix/monitor/allowlist.ts b/extensions/matrix/src/matrix/monitor/allowlist.ts index b40c142d8b9..e95492bb51d 100644 --- a/extensions/matrix/src/matrix/monitor/allowlist.ts +++ b/extensions/matrix/src/matrix/monitor/allowlist.ts @@ -2,8 +2,8 @@ import { resolveAllowlistMatchByCandidates, type AllowlistMatch, } from "openclaw/plugin-sdk/allow-from"; +import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime"; import { normalizeStringEntries } from "openclaw/plugin-sdk/string-normalization-runtime"; -import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime"; function normalizeAllowList(list?: Array) { return normalizeStringEntries(list); diff --git a/extensions/matrix/src/matrix/monitor/auto-join.ts b/extensions/matrix/src/matrix/monitor/auto-join.ts index 3c48c58a646..6559cde8149 100644 --- a/extensions/matrix/src/matrix/monitor/auto-join.ts +++ b/extensions/matrix/src/matrix/monitor/auto-join.ts @@ -1,4 +1,4 @@ -import { normalizeStringifiedOptionalString } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeStringifiedOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime"; import { getMatrixRuntime } from "../../runtime.js"; import type { MatrixConfig } from "../../types.js"; import type { MatrixClient } from "../sdk.js"; diff --git a/extensions/matrix/src/matrix/monitor/events.ts b/extensions/matrix/src/matrix/monitor/events.ts index 06b21d05e34..64b9b6c8d93 100644 --- a/extensions/matrix/src/matrix/monitor/events.ts +++ b/extensions/matrix/src/matrix/monitor/events.ts @@ -1,4 +1,4 @@ -import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime"; import type { PluginRuntime, RuntimeLogger } from "../../runtime-api.js"; import type { CoreConfig } from "../../types.js"; import type { MatrixAuth } from "../client.js"; diff --git a/extensions/matrix/src/matrix/monitor/handler.group-history.test.ts b/extensions/matrix/src/matrix/monitor/handler.group-history.test.ts index 56da3656294..c3c7f1198e6 100644 --- a/extensions/matrix/src/matrix/monitor/handler.group-history.test.ts +++ b/extensions/matrix/src/matrix/monitor/handler.group-history.test.ts @@ -25,6 +25,35 @@ import { } from "./handler.test-helpers.js"; import { type MatrixRawEvent } from "./types.js"; +const deliverMatrixRepliesMock = vi.hoisted(() => vi.fn(async () => true)); + +vi.mock("./replies.js", () => ({ + deliverMatrixReplies: deliverMatrixRepliesMock, +})); + +vi.mock("./route.js", () => ({ + resolveMatrixInboundRoute: (params: { + resolveAgentRoute: (input: unknown) => unknown; + cfg: unknown; + accountId: string; + roomId: string; + senderId: string; + isDirectMessage: boolean; + }) => ({ + route: params.resolveAgentRoute({ + cfg: params.cfg, + channel: "matrix", + accountId: params.accountId, + peer: { + kind: params.isDirectMessage ? "direct" : "channel", + id: params.isDirectMessage ? params.senderId : params.roomId, + }, + }), + configuredBinding: null, + runtimeBindingId: null, + }), +})); + const DEFAULT_ROOM = "!room:example.org"; function makeRoomTriggerEvent(params: { eventId: string; body: string; ts?: number }) { diff --git a/extensions/matrix/src/matrix/monitor/handler.ts b/extensions/matrix/src/matrix/monitor/handler.ts index f9950169e27..848e6fe0c6e 100644 --- a/extensions/matrix/src/matrix/monitor/handler.ts +++ b/extensions/matrix/src/matrix/monitor/handler.ts @@ -1,19 +1,19 @@ -import { resolveControlCommandGate } from "openclaw/plugin-sdk/command-auth"; +import { resolveControlCommandGate } from "openclaw/plugin-sdk/command-gating"; +import { + evaluateSupplementalContextVisibility, + resolveChannelContextVisibilityMode, +} from "openclaw/plugin-sdk/context-visibility-runtime"; import { loadSessionStore, - resolveChannelContextVisibilityMode, resolveSessionStoreEntry, -} from "openclaw/plugin-sdk/config-runtime"; -import { getSessionBindingService } from "openclaw/plugin-sdk/conversation-runtime"; -import { evaluateSupplementalContextVisibility } from "openclaw/plugin-sdk/security-runtime"; -import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; +} from "openclaw/plugin-sdk/session-store-runtime"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime"; import type { CoreConfig, MatrixRoomConfig, MatrixStreamingMode, ReplyToMode, } from "../../types.js"; -import { createMatrixDraftStream } from "../draft-stream.js"; import { formatMatrixErrorMessage } from "../errors.js"; import { isMatrixMediaSizeLimitError } from "../media-errors.js"; import { @@ -31,13 +31,6 @@ import { parsePollStartContent, } from "../poll-types.js"; import type { LocationMessageEventContent, MatrixClient } from "../sdk.js"; -import { - editMessageMatrix, - reactMatrixMessage, - sendMessageMatrix, - sendReadReceiptMatrix, - sendTypingMatrix, -} from "../send.js"; import { MATRIX_OPENCLAW_FINALIZED_PREVIEW_KEY } from "../send/types.js"; import { resolveMatrixStoredSessionMeta } from "../session-store-metadata.js"; import { resolveMatrixMonitorAccessState } from "./access-state.js"; @@ -47,7 +40,6 @@ import type { MatrixInboundEventDeduper } from "./inbound-dedupe.js"; import { resolveMatrixLocation, type MatrixLocationPayload } from "./location.js"; import { downloadMatrixMedia } from "./media.js"; import { resolveMentions } from "./mentions.js"; -import { handleInboundMatrixReaction } from "./reaction-events.js"; import { deliverMatrixReplies } from "./replies.js"; import { createMatrixReplyContextResolver } from "./reply-context.js"; import { createRoomHistoryTracker } from "./room-history.js"; @@ -57,7 +49,6 @@ import { resolveMatrixInboundRoute } from "./route.js"; import { createReplyPrefixOptions, createTypingCallbacks, - ensureConfiguredAcpBindingReady, formatAllowlistMatchMeta, getAgentScopedMediaLocalRoots, logInboundDrop, @@ -80,9 +71,44 @@ import { isMatrixVerificationRoomMessage } from "./verification-utils.js"; const ALLOW_FROM_STORE_CACHE_TTL_MS = 30_000; const PAIRING_REPLY_COOLDOWN_MS = 5 * 60_000; +let matrixSendModulePromise: Promise | undefined; +let acpBindingRuntimePromise: + | Promise + | undefined; +let sessionBindingRuntimePromise: + | Promise + | undefined; + +function loadMatrixSendModule(): Promise { + matrixSendModulePromise ??= import("../send.js"); + return matrixSendModulePromise; +} + +function loadAcpBindingRuntime(): Promise< + typeof import("openclaw/plugin-sdk/acp-binding-runtime") +> { + acpBindingRuntimePromise ??= import("openclaw/plugin-sdk/acp-binding-runtime"); + return acpBindingRuntimePromise; +} + +function loadSessionBindingRuntime(): Promise< + typeof import("openclaw/plugin-sdk/session-binding-runtime") +> { + sessionBindingRuntimePromise ??= import("openclaw/plugin-sdk/session-binding-runtime"); + return sessionBindingRuntimePromise; +} const MAX_TRACKED_PAIRING_REPLY_SENDERS = 512; const MAX_TRACKED_SHARED_DM_CONTEXT_NOTICES = 512; type MatrixAllowBotsMode = "off" | "mentions" | "all"; +type MatrixDraftStreamHandle = { + update: (text: string) => void; + stop: () => Promise; + eventId: () => string | undefined; + mustDeliverFinalNormally: () => boolean; + matchesPreparedText: (text: string) => boolean; + finalizeLive: () => Promise; + reset: () => void; +}; export class MatrixRetryableInboundError extends Error { constructor(message: string, options?: ErrorOptions) { @@ -426,7 +452,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam return async (roomId: string, event: MatrixRawEvent) => { const eventId = typeof event.event_id === "string" ? event.event_id.trim() : ""; let claimedInboundEvent = false; - let draftStreamRef: ReturnType | undefined; + let draftStreamRef: MatrixDraftStreamHandle | undefined; let draftConsumed = false; try { const eventType = event.type; @@ -645,6 +671,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam : `matrix pairing reminder sender=${senderId} name=${senderName ?? "unknown"} (${allowMatchMeta})`, ); try { + const { sendMessageMatrix } = await loadMatrixSendModule(); await sendMessageMatrix( `room:${roomId}`, created @@ -712,6 +739,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam if (isReactionEvent) { const senderName = await getSenderName(); + const { handleInboundMatrixReaction } = await import("./reaction-events.js"); await handleInboundMatrixReaction({ client, core, @@ -957,6 +985,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam } const senderName = await getSenderName(); if (_configuredBinding) { + const { ensureConfiguredAcpBindingReady } = await loadAcpBindingRuntime(); const ensured = await ensureConfiguredAcpBindingReady({ cfg, configuredBinding: _configuredBinding, @@ -972,6 +1001,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam } } if (_runtimeBindingId) { + const { getSessionBindingService } = await loadSessionBindingRuntime(); getSessionBindingService().touch(_runtimeBindingId, eventTs ?? undefined); } const preparedTrigger = @@ -1270,17 +1300,23 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam }), ); if (shouldAckReaction() && _messageId) { - reactMatrixMessage(roomId, _messageId, ackReaction, client).catch((err) => { - logVerboseMessage(`matrix react failed for room ${roomId}: ${String(err)}`); - }); + loadMatrixSendModule() + .then(({ reactMatrixMessage }) => + reactMatrixMessage(roomId, _messageId, ackReaction, client), + ) + .catch((err) => { + logVerboseMessage(`matrix react failed for room ${roomId}: ${String(err)}`); + }); } if (_messageId) { - sendReadReceiptMatrix(roomId, _messageId, client).catch((err) => { - logVerboseMessage( - `matrix: read receipt failed room=${roomId} id=${_messageId}: ${String(err)}`, - ); - }); + loadMatrixSendModule() + .then(({ sendReadReceiptMatrix }) => sendReadReceiptMatrix(roomId, _messageId, client)) + .catch((err) => { + logVerboseMessage( + `matrix: read receipt failed room=${roomId} id=${_messageId}: ${String(err)}`, + ); + }); } const tableMode = core.channel.text.resolveMarkdownTableMode({ @@ -1299,8 +1335,14 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam accountId: _route.accountId, }); const typingCallbacks = createTypingCallbacks({ - start: () => sendTypingMatrix(roomId, true, undefined, client), - stop: () => sendTypingMatrix(roomId, false, undefined, client), + start: async () => { + const { sendTypingMatrix } = await loadMatrixSendModule(); + await sendTypingMatrix(roomId, true, undefined, client); + }, + stop: async () => { + const { sendTypingMatrix } = await loadMatrixSendModule(); + await sendTypingMatrix(roomId, false, undefined, client); + }, onStartError: (err) => { logTypingFailure({ log: logVerboseMessage, @@ -1323,18 +1365,20 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam const draftStreamingEnabled = streaming !== "off"; const quietDraftStreaming = streaming === "quiet"; const draftReplyToId = replyToMode !== "off" && !threadTarget ? _messageId : undefined; - const draftStream = draftStreamingEnabled - ? createMatrixDraftStream({ - roomId, - client, - cfg, - mode: quietDraftStreaming ? "quiet" : "partial", - threadId: threadTarget, - replyToId: draftReplyToId, - preserveReplyId: replyToMode === "all", - accountId: _route.accountId, - log: logVerboseMessage, - }) + const draftStream: MatrixDraftStreamHandle | undefined = draftStreamingEnabled + ? await import("../draft-stream.js").then(({ createMatrixDraftStream }) => + createMatrixDraftStream({ + roomId, + client, + cfg, + mode: quietDraftStreaming ? "quiet" : "partial", + threadId: threadTarget, + replyToId: draftReplyToId, + preserveReplyId: replyToMode === "all", + accountId: _route.accountId, + log: logVerboseMessage, + }), + ) : undefined; draftStreamRef = draftStream; type PendingDraftBoundary = { @@ -1458,6 +1502,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam const requiresFinalEdit = quietDraftStreaming || !draftStream.matchesPreparedText(payload.text); if (requiresFinalEdit) { + const { editMessageMatrix } = await loadMatrixSendModule(); await editMessageMatrix(roomId, draftEventId, payload.text, { client, cfg, @@ -1500,6 +1545,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam quietDraftStreaming || (typeof payloadText === "string" && !payloadTextMatchesDraft); if (textEditOk && payloadText && requiresFinalTextEdit) { + const { editMessageMatrix } = await loadMatrixSendModule(); textEditOk = await editMessageMatrix(roomId, draftEventId, payloadText, { client, cfg, @@ -1568,6 +1614,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam // Re-assert typing so the user still sees the indicator while // the next block generates. + const { sendTypingMatrix } = await loadMatrixSendModule(); await sendTypingMatrix(roomId, true, undefined, client).catch(() => {}); } } else { diff --git a/extensions/matrix/src/matrix/monitor/location.ts b/extensions/matrix/src/matrix/monitor/location.ts index 46057e8ff98..8317b996e05 100644 --- a/extensions/matrix/src/matrix/monitor/location.ts +++ b/extensions/matrix/src/matrix/monitor/location.ts @@ -1,7 +1,7 @@ import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, -} from "openclaw/plugin-sdk/text-runtime"; +} from "openclaw/plugin-sdk/string-coerce-runtime"; import type { LocationMessageEventContent } from "../sdk.js"; import { formatLocationText, toLocationContext, type NormalizedLocation } from "./runtime-api.js"; import { EventType } from "./types.js"; diff --git a/extensions/matrix/src/matrix/monitor/mentions.ts b/extensions/matrix/src/matrix/monitor/mentions.ts index 201bb7094b9..6b2a1ecd748 100644 --- a/extensions/matrix/src/matrix/monitor/mentions.ts +++ b/extensions/matrix/src/matrix/monitor/mentions.ts @@ -1,4 +1,4 @@ -import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime"; import { getMatrixRuntime } from "../../runtime.js"; import type { RoomMessageEventContent } from "./types.js"; diff --git a/extensions/matrix/src/matrix/monitor/reaction-events.ts b/extensions/matrix/src/matrix/monitor/reaction-events.ts index e280ce1dc52..f6dc4822a02 100644 --- a/extensions/matrix/src/matrix/monitor/reaction-events.ts +++ b/extensions/matrix/src/matrix/monitor/reaction-events.ts @@ -1,4 +1,4 @@ -import { getSessionBindingService } from "openclaw/plugin-sdk/conversation-runtime"; +import { getSessionBindingService } from "openclaw/plugin-sdk/session-binding-runtime"; import { matrixApprovalCapability } from "../../approval-native.js"; import { resolveMatrixApprovalReactionTarget, diff --git a/extensions/matrix/src/matrix/monitor/replies.ts b/extensions/matrix/src/matrix/monitor/replies.ts index 42cdaa47e5a..b66791e0c8e 100644 --- a/extensions/matrix/src/matrix/monitor/replies.ts +++ b/extensions/matrix/src/matrix/monitor/replies.ts @@ -1,4 +1,4 @@ -import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime"; import { getMatrixRuntime } from "../../runtime.js"; import type { MatrixClient } from "../sdk.js"; import { chunkMatrixText, sendMessageMatrix } from "../send.js"; diff --git a/extensions/matrix/src/matrix/monitor/route.ts b/extensions/matrix/src/matrix/monitor/route.ts index 0397b2381ed..9889857bc2c 100644 --- a/extensions/matrix/src/matrix/monitor/route.ts +++ b/extensions/matrix/src/matrix/monitor/route.ts @@ -1,10 +1,11 @@ -import { buildAgentSessionKey, deriveLastRoutePolicy } from "openclaw/plugin-sdk/routing"; +import { resolveConfiguredAcpBindingRecord } from "openclaw/plugin-sdk/acp-binding-resolve-runtime"; +import type { PluginRuntime } from "openclaw/plugin-sdk/plugin-runtime"; import { - getSessionBindingService, + buildAgentSessionKey, + deriveLastRoutePolicy, resolveAgentIdFromSessionKey, - resolveConfiguredAcpBindingRecord, - type PluginRuntime, -} from "../../runtime-api.js"; +} from "openclaw/plugin-sdk/routing"; +import { getSessionBindingService } from "openclaw/plugin-sdk/session-binding-runtime"; import type { CoreConfig } from "../../types.js"; import { resolveMatrixThreadSessionKeys } from "./threads.js"; diff --git a/extensions/matrix/src/matrix/monitor/runtime-api.ts b/extensions/matrix/src/matrix/monitor/runtime-api.ts index 69235b22182..978cdd69b2f 100644 --- a/extensions/matrix/src/matrix/monitor/runtime-api.ts +++ b/extensions/matrix/src/matrix/monitor/runtime-api.ts @@ -2,8 +2,7 @@ // Keep monitor internals off the broad package runtime-api barrel so monitor // tests and shared workers do not pull unrelated Matrix helper surfaces. -export { ensureConfiguredAcpBindingReady } from "openclaw/plugin-sdk/acp-binding-runtime"; -export type { NormalizedLocation } from "openclaw/plugin-sdk/channel-inbound"; +export type { NormalizedLocation } from "openclaw/plugin-sdk/channel-location"; export type { PluginRuntime, RuntimeLogger } from "openclaw/plugin-sdk/plugin-runtime"; export type { BlockReplyContext, ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; export type { MarkdownTableMode, OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; @@ -18,13 +17,10 @@ export { } from "openclaw/plugin-sdk/allow-from"; export { createReplyPrefixOptions } from "openclaw/plugin-sdk/channel-reply-pipeline"; export { createTypingCallbacks } from "openclaw/plugin-sdk/channel-reply-pipeline"; -export { - formatLocationText, - logInboundDrop, - toLocationContext, -} from "openclaw/plugin-sdk/channel-inbound"; +export { formatLocationText, toLocationContext } from "openclaw/plugin-sdk/channel-location"; export { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/agent-media-payload"; -export { logTypingFailure, resolveAckReaction } from "openclaw/plugin-sdk/channel-feedback"; +export { logInboundDrop, logTypingFailure } from "openclaw/plugin-sdk/channel-logging"; +export { resolveAckReaction } from "openclaw/plugin-sdk/channel-feedback"; export { buildChannelKeyCandidates, resolveChannelEntryMatch, diff --git a/extensions/matrix/src/matrix/monitor/verification-utils.ts b/extensions/matrix/src/matrix/monitor/verification-utils.ts index 2044fe259cf..4291cc6d680 100644 --- a/extensions/matrix/src/matrix/monitor/verification-utils.ts +++ b/extensions/matrix/src/matrix/monitor/verification-utils.ts @@ -1,4 +1,4 @@ -import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime"; const VERIFICATION_EVENT_PREFIX = "m.key.verification."; const VERIFICATION_REQUEST_MSGTYPE = "m.key.verification.request"; diff --git a/extensions/matrix/src/matrix/outbound-media-runtime.ts b/extensions/matrix/src/matrix/outbound-media-runtime.ts index b66b1fd2ea6..18cf2066fc8 100644 --- a/extensions/matrix/src/matrix/outbound-media-runtime.ts +++ b/extensions/matrix/src/matrix/outbound-media-runtime.ts @@ -1 +1 @@ -export { loadOutboundMediaFromUrl } from "../runtime-api.js"; +export { loadOutboundMediaFromUrl } from "openclaw/plugin-sdk/outbound-media"; diff --git a/extensions/matrix/src/matrix/poll-types.ts b/extensions/matrix/src/matrix/poll-types.ts index cdf3c172eb8..cec3f73b528 100644 --- a/extensions/matrix/src/matrix/poll-types.ts +++ b/extensions/matrix/src/matrix/poll-types.ts @@ -7,8 +7,8 @@ * - m.poll.end - Closes a poll */ -import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; -import { normalizePollInput, type PollInput } from "../runtime-api.js"; +import { normalizePollInput, type PollInput } from "openclaw/plugin-sdk/poll-runtime"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime"; export const M_POLL_START = "m.poll.start" as const; export const M_POLL_RESPONSE = "m.poll.response" as const; diff --git a/extensions/matrix/src/matrix/probe.ts b/extensions/matrix/src/matrix/probe.ts index 27ab5c04ae3..9cde883a2e4 100644 --- a/extensions/matrix/src/matrix/probe.ts +++ b/extensions/matrix/src/matrix/probe.ts @@ -1,5 +1,5 @@ import { formatErrorMessage, type PinnedDispatcherPolicy } from "openclaw/plugin-sdk/infra-runtime"; -import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime"; import type { SsrFPolicy } from "../runtime-api.js"; import type { BaseProbeResult } from "../runtime-api.js"; import { isBunRuntime } from "./client/runtime.js"; diff --git a/extensions/matrix/src/matrix/profile.ts b/extensions/matrix/src/matrix/profile.ts index bcf2beae7fb..41d41477217 100644 --- a/extensions/matrix/src/matrix/profile.ts +++ b/extensions/matrix/src/matrix/profile.ts @@ -1,7 +1,7 @@ import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, -} from "openclaw/plugin-sdk/text-runtime"; +} from "openclaw/plugin-sdk/string-coerce-runtime"; import type { MatrixClient } from "./sdk.js"; export const MATRIX_PROFILE_AVATAR_MAX_BYTES = 10 * 1024 * 1024; diff --git a/extensions/matrix/src/matrix/reaction-common.ts b/extensions/matrix/src/matrix/reaction-common.ts index e80ab2aef38..9943d62d185 100644 --- a/extensions/matrix/src/matrix/reaction-common.ts +++ b/extensions/matrix/src/matrix/reaction-common.ts @@ -1,4 +1,4 @@ -import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime"; export const MATRIX_ANNOTATION_RELATION_TYPE = "m.annotation"; export const MATRIX_REACTION_EVENT_TYPE = "m.reaction"; diff --git a/extensions/matrix/src/matrix/sdk.ts b/extensions/matrix/src/matrix/sdk.ts index 3259af650a5..dfa102a3f40 100644 --- a/extensions/matrix/src/matrix/sdk.ts +++ b/extensions/matrix/src/matrix/sdk.ts @@ -10,9 +10,9 @@ import { type MatrixEvent, } from "matrix-js-sdk/lib/matrix.js"; import { VerificationMethod } from "matrix-js-sdk/lib/types.js"; -import type { PinnedDispatcherPolicy } from "openclaw/plugin-sdk/infra-runtime"; import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue"; -import { normalizeNullableString } from "openclaw/plugin-sdk/text-runtime"; +import type { PinnedDispatcherPolicy } from "openclaw/plugin-sdk/ssrf-dispatcher"; +import { normalizeNullableString } from "openclaw/plugin-sdk/string-coerce-runtime"; import type { SsrFPolicy } from "../runtime-api.js"; import { resolveMatrixRoomKeyBackupReadinessError } from "./backup-health.js"; import { FileBackedMatrixSyncStore } from "./client/file-sync-store.js"; diff --git a/extensions/matrix/src/matrix/sdk/http-client.ts b/extensions/matrix/src/matrix/sdk/http-client.ts index 5440427439a..a7d7d4a5dea 100644 --- a/extensions/matrix/src/matrix/sdk/http-client.ts +++ b/extensions/matrix/src/matrix/sdk/http-client.ts @@ -1,4 +1,4 @@ -import type { PinnedDispatcherPolicy } from "openclaw/plugin-sdk/infra-runtime"; +import type { PinnedDispatcherPolicy } from "openclaw/plugin-sdk/ssrf-dispatcher"; import type { SsrFPolicy } from "../../runtime-api.js"; import { buildHttpError } from "./event-helpers.js"; import { type HttpMethod, type QueryParams, performMatrixRequest } from "./transport.js"; diff --git a/extensions/matrix/src/matrix/sdk/idb-persistence-lock.ts b/extensions/matrix/src/matrix/sdk/idb-persistence-lock.ts index 37204a912f3..84abb9f093d 100644 --- a/extensions/matrix/src/matrix/sdk/idb-persistence-lock.ts +++ b/extensions/matrix/src/matrix/sdk/idb-persistence-lock.ts @@ -1,4 +1,4 @@ -import type { FileLockOptions } from "openclaw/plugin-sdk/infra-runtime"; +import type { FileLockOptions } from "openclaw/plugin-sdk/file-lock"; export const MATRIX_IDB_PERSIST_INTERVAL_MS = 60_000; diff --git a/extensions/matrix/src/matrix/sdk/idb-persistence.lock-order.test.ts b/extensions/matrix/src/matrix/sdk/idb-persistence.lock-order.test.ts index c8f2e7b45dc..6db30838c36 100644 --- a/extensions/matrix/src/matrix/sdk/idb-persistence.lock-order.test.ts +++ b/extensions/matrix/src/matrix/sdk/idb-persistence.lock-order.test.ts @@ -15,9 +15,9 @@ const { withFileLockMock } = vi.hoisted(() => ({ ), })); -vi.mock("openclaw/plugin-sdk/infra-runtime", async () => { - const actual = await vi.importActual( - "openclaw/plugin-sdk/infra-runtime", +vi.mock("openclaw/plugin-sdk/file-lock", async () => { + const actual = await vi.importActual( + "openclaw/plugin-sdk/file-lock", ); return { ...actual, diff --git a/extensions/matrix/src/matrix/sdk/idb-persistence.ts b/extensions/matrix/src/matrix/sdk/idb-persistence.ts index c9f243ca5f5..5c04a2cd523 100644 --- a/extensions/matrix/src/matrix/sdk/idb-persistence.ts +++ b/extensions/matrix/src/matrix/sdk/idb-persistence.ts @@ -1,7 +1,7 @@ import fs from "node:fs"; import path from "node:path"; import { indexedDB as fakeIndexedDB } from "fake-indexeddb"; -import { withFileLock } from "openclaw/plugin-sdk/infra-runtime"; +import { withFileLock } from "openclaw/plugin-sdk/file-lock"; import { MATRIX_IDB_SNAPSHOT_LOCK_OPTIONS } from "./idb-persistence-lock.js"; import { LogService } from "./logger.js"; diff --git a/extensions/matrix/src/matrix/sdk/read-response-with-limit.ts b/extensions/matrix/src/matrix/sdk/read-response-with-limit.ts index 97abda6e1e8..7730d387070 100644 --- a/extensions/matrix/src/matrix/sdk/read-response-with-limit.ts +++ b/extensions/matrix/src/matrix/sdk/read-response-with-limit.ts @@ -1,4 +1,4 @@ -import { readResponseWithLimit as readSharedResponseWithLimit } from "openclaw/plugin-sdk/media-runtime"; +import { readResponseWithLimit as readSharedResponseWithLimit } from "openclaw/plugin-sdk/response-limit-runtime"; export async function readResponseWithLimit( res: Response, diff --git a/extensions/matrix/src/matrix/sdk/transport-runtime-api.ts b/extensions/matrix/src/matrix/sdk/transport-runtime-api.ts new file mode 100644 index 00000000000..d964cbf6ccf --- /dev/null +++ b/extensions/matrix/src/matrix/sdk/transport-runtime-api.ts @@ -0,0 +1,49 @@ +import { fetchWithRuntimeDispatcher } from "openclaw/plugin-sdk/runtime-fetch"; +import { + closeDispatcher, + createPinnedDispatcher, + resolvePinnedHostnameWithPolicy, + type PinnedDispatcherPolicy, + type SsrFPolicy, +} from "openclaw/plugin-sdk/ssrf-dispatcher"; + +export { + closeDispatcher, + createPinnedDispatcher, + fetchWithRuntimeDispatcher, + resolvePinnedHostnameWithPolicy, + type PinnedDispatcherPolicy, + type SsrFPolicy, +}; + +export function buildTimeoutAbortSignal(params: { timeoutMs?: number; signal?: AbortSignal }): { + signal?: AbortSignal; + cleanup: () => void; +} { + const { timeoutMs, signal } = params; + if (!timeoutMs && !signal) { + return { signal: undefined, cleanup: () => {} }; + } + if (!timeoutMs) { + return { signal, cleanup: () => {} }; + } + + const controller = new AbortController(); + const timeoutId = setTimeout(controller.abort.bind(controller), timeoutMs); + const onAbort = () => controller.abort(); + if (signal) { + if (signal.aborted) { + controller.abort(); + } else { + signal.addEventListener("abort", onAbort, { once: true }); + } + } + + return { + signal: controller.signal, + cleanup: () => { + clearTimeout(timeoutId); + signal?.removeEventListener("abort", onAbort); + }, + }; +} diff --git a/extensions/matrix/src/matrix/sdk/transport.ts b/extensions/matrix/src/matrix/sdk/transport.ts index 228515d5c66..48630c4067e 100644 --- a/extensions/matrix/src/matrix/sdk/transport.ts +++ b/extensions/matrix/src/matrix/sdk/transport.ts @@ -1,16 +1,14 @@ -import { - fetchWithRuntimeDispatcher, - type PinnedDispatcherPolicy, -} from "openclaw/plugin-sdk/infra-runtime"; +import { MatrixMediaSizeLimitError } from "../media-errors.js"; +import { readResponseWithLimit } from "./read-response-with-limit.js"; import { buildTimeoutAbortSignal, closeDispatcher, createPinnedDispatcher, resolvePinnedHostnameWithPolicy, type SsrFPolicy, -} from "../../runtime-api.js"; -import { MatrixMediaSizeLimitError } from "../media-errors.js"; -import { readResponseWithLimit } from "./read-response-with-limit.js"; + fetchWithRuntimeDispatcher, + type PinnedDispatcherPolicy, +} from "./transport-runtime-api.js"; export type HttpMethod = "GET" | "POST" | "PUT" | "DELETE"; diff --git a/extensions/matrix/src/matrix/send/targets.ts b/extensions/matrix/src/matrix/send/targets.ts index af9a650320b..23e50585cde 100644 --- a/extensions/matrix/src/matrix/send/targets.ts +++ b/extensions/matrix/src/matrix/send/targets.ts @@ -1,7 +1,7 @@ import { normalizeLowercaseStringOrEmpty, normalizeOptionalStringifiedId, -} from "openclaw/plugin-sdk/text-runtime"; +} from "openclaw/plugin-sdk/string-coerce-runtime"; import { inspectMatrixDirectRooms, persistMatrixDirectRoomMapping } from "../direct-management.js"; import { isStrictDirectRoom } from "../direct-room.js"; import type { MatrixClient } from "../sdk.js"; diff --git a/extensions/matrix/src/matrix/subagent-hooks.ts b/extensions/matrix/src/matrix/subagent-hooks.ts index 8940b0217af..4f31620ee32 100644 --- a/extensions/matrix/src/matrix/subagent-hooks.ts +++ b/extensions/matrix/src/matrix/subagent-hooks.ts @@ -4,7 +4,7 @@ import { type SessionBindingRecord, } from "openclaw/plugin-sdk/conversation-binding-runtime"; import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core"; -import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime"; import { findMatrixAccountConfig, resolveMatrixBaseConfig } from "./account-config.js"; import { resolveMatrixTargetIdentity } from "./target-ids.js"; import { diff --git a/extensions/matrix/src/matrix/target-ids.ts b/extensions/matrix/src/matrix/target-ids.ts index 3291b45b8ab..413993eecb2 100644 --- a/extensions/matrix/src/matrix/target-ids.ts +++ b/extensions/matrix/src/matrix/target-ids.ts @@ -1,4 +1,4 @@ -import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime"; type MatrixTarget = { kind: "room"; id: string } | { kind: "user"; id: string }; const MATRIX_PREFIX = "matrix:"; diff --git a/extensions/matrix/src/matrix/thread-bindings.ts b/extensions/matrix/src/matrix/thread-bindings.ts index 6544967bdaa..e5c87e62b17 100644 --- a/extensions/matrix/src/matrix/thread-bindings.ts +++ b/extensions/matrix/src/matrix/thread-bindings.ts @@ -1,7 +1,7 @@ import path from "node:path"; import { readJsonFileWithFallback, writeJsonFileAtomically } from "openclaw/plugin-sdk/json-store"; import { resolveAgentIdFromSessionKey } from "openclaw/plugin-sdk/routing"; -import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime"; import { registerSessionBindingAdapter, resolveThreadBindingFarewellText, diff --git a/extensions/matrix/src/migration-config.ts b/extensions/matrix/src/migration-config.ts index 70aae97cd0e..73ef3ee5766 100644 --- a/extensions/matrix/src/migration-config.ts +++ b/extensions/matrix/src/migration-config.ts @@ -3,7 +3,7 @@ import os from "node:os"; import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id"; import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import { resolveStateDir } from "openclaw/plugin-sdk/state-paths"; -import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime"; import { findMatrixAccountEntry, requiresExplicitMatrixDefaultAccount, diff --git a/extensions/matrix/src/migration-snapshot-backup.ts b/extensions/matrix/src/migration-snapshot-backup.ts index e2fde7eeefd..f2918a2c34e 100644 --- a/extensions/matrix/src/migration-snapshot-backup.ts +++ b/extensions/matrix/src/migration-snapshot-backup.ts @@ -2,8 +2,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import { writeJsonFileAtomically } from "openclaw/plugin-sdk/json-store"; -import { resolveRequiredHomeDir } from "openclaw/plugin-sdk/provider-auth"; -import { resolveStateDir } from "openclaw/plugin-sdk/state-paths"; +import { resolveRequiredHomeDir, resolveStateDir } from "openclaw/plugin-sdk/state-paths"; const MATRIX_MIGRATION_SNAPSHOT_DIRNAME = "openclaw-migrations"; diff --git a/extensions/matrix/src/onboarding.ts b/extensions/matrix/src/onboarding.ts index 2876e0e93b7..981ae599118 100644 --- a/extensions/matrix/src/onboarding.ts +++ b/extensions/matrix/src/onboarding.ts @@ -1,44 +1,40 @@ import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id"; +import type { DmPolicy } from "openclaw/plugin-sdk/config-runtime"; +import type { WizardPrompter } from "openclaw/plugin-sdk/matrix-runtime-shared"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime"; import { type ChannelSetupDmPolicy, type ChannelSetupWizardAdapter, + addWildcardAllowFrom, + formatDocsLink, + hasConfiguredSecretInput, + mergeAllowFromEntries, + normalizeAccountId, + promptAccountId, + promptChannelAccessConfig, + splitSetupEntries, } from "openclaw/plugin-sdk/setup"; -import { isPrivateNetworkOptInEnabled } from "openclaw/plugin-sdk/ssrf-runtime"; +import { isPrivateNetworkOptInEnabled } from "openclaw/plugin-sdk/ssrf-policy"; import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeStringifiedOptionalString, -} from "openclaw/plugin-sdk/text-runtime"; +} from "openclaw/plugin-sdk/string-coerce-runtime"; import { requiresExplicitMatrixDefaultAccount } from "./account-selection.js"; -import { listMatrixDirectoryGroupsLive } from "./directory-live.js"; import { listMatrixAccountIds, resolveDefaultMatrixAccountId, resolveMatrixAccount, resolveMatrixAccountConfig, } from "./matrix/accounts.js"; +import { resolveMatrixEnvAuthReadiness } from "./matrix/client/env-auth.js"; +import { isPrivateOrLoopbackHost } from "./matrix/client/private-network-host.js"; import { resolveValidatedMatrixHomeserverUrl, validateMatrixHomeserverUrl, -} from "./matrix/client.js"; -import { resolveMatrixEnvAuthReadiness } from "./matrix/client/env-auth.js"; +} from "./matrix/client/url-validation.js"; import { resolveMatrixConfigFieldPath, updateMatrixAccountConfig } from "./matrix/config-update.js"; import { ensureMatrixSdkInstalled, isMatrixSdkAvailable } from "./matrix/deps.js"; -import { resolveMatrixTargets } from "./resolve-targets.js"; -import type { DmPolicy } from "./runtime-api.js"; -import { - addWildcardAllowFrom, - formatDocsLink, - hasConfiguredSecretInput, - isPrivateOrLoopbackHost, - mergeAllowFromEntries, - normalizeAccountId, - promptAccountId, - promptChannelAccessConfig, - splitSetupEntries, - type RuntimeEnv, - type WizardPrompter, -} from "./runtime-api.js"; import { moveSingleMatrixAccountConfigToNamedAccount } from "./setup-config.js"; import type { CoreConfig, MatrixConfig } from "./types.js"; @@ -161,6 +157,7 @@ async function promptMatrixAllowFrom(params: { } if (pending.length > 0) { + const { resolveMatrixTargets } = await import("./resolve-targets.js"); const results = await resolveMatrixTargets({ cfg, accountId, @@ -362,6 +359,7 @@ async function configureMatrixAccessPrompts(params: { resolvedIds.push(cleaned); continue; } + const { listMatrixDirectoryGroupsLive } = await import("./directory-live.js"); const matches = await listMatrixDirectoryGroupsLive({ cfg: next, accountId: params.accountId, diff --git a/extensions/matrix/src/plugin-entry.runtime.ts b/extensions/matrix/src/plugin-entry.runtime.ts index 2dbf8eae75c..2c62b5949eb 100644 --- a/extensions/matrix/src/plugin-entry.runtime.ts +++ b/extensions/matrix/src/plugin-entry.runtime.ts @@ -1,5 +1,5 @@ import type { GatewayRequestHandlerOptions } from "openclaw/plugin-sdk/gateway-runtime"; -import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime"; import { formatMatrixErrorMessage } from "./matrix/errors.js"; function sendError(respond: (ok: boolean, payload?: unknown) => void, err: unknown) { diff --git a/extensions/matrix/src/record-shared.ts b/extensions/matrix/src/record-shared.ts index b20e3baaa97..32a775a481f 100644 --- a/extensions/matrix/src/record-shared.ts +++ b/extensions/matrix/src/record-shared.ts @@ -1,3 +1,3 @@ -import { isRecord } from "openclaw/plugin-sdk/text-runtime"; +import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; export { isRecord }; diff --git a/extensions/matrix/src/resolve-targets.ts b/extensions/matrix/src/resolve-targets.ts index 4343646915c..c734be5eaca 100644 --- a/extensions/matrix/src/resolve-targets.ts +++ b/extensions/matrix/src/resolve-targets.ts @@ -1,4 +1,4 @@ -import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/string-coerce-runtime"; import { listMatrixDirectoryGroupsLive, listMatrixDirectoryPeersLive } from "./directory-live.js"; import { isMatrixQualifiedUserId, normalizeMatrixMessagingTarget } from "./matrix/target-ids.js"; import type { diff --git a/extensions/matrix/src/runtime-api.ts b/extensions/matrix/src/runtime-api.ts index 60757706f8a..fb2ff5b01f5 100644 --- a/extensions/matrix/src/runtime-api.ts +++ b/extensions/matrix/src/runtime-api.ts @@ -29,11 +29,11 @@ export type { } from "openclaw/plugin-sdk/channel-contract"; export { formatLocationText, - logInboundDrop, toLocationContext, type NormalizedLocation, -} from "openclaw/plugin-sdk/channel-inbound"; -export { resolveAckReaction, logTypingFailure } from "openclaw/plugin-sdk/channel-feedback"; +} from "openclaw/plugin-sdk/channel-location"; +export { logInboundDrop, logTypingFailure } from "openclaw/plugin-sdk/channel-logging"; +export { resolveAckReaction } from "openclaw/plugin-sdk/channel-feedback"; export type { ChannelSetupInput } from "openclaw/plugin-sdk/setup"; export type { OpenClawConfig, @@ -92,7 +92,7 @@ export { resolveAgentIdFromSessionKey } from "openclaw/plugin-sdk/routing"; export { chunkTextForOutbound } from "openclaw/plugin-sdk/text-chunking"; export { createChannelReplyPipeline } from "openclaw/plugin-sdk/channel-reply-pipeline"; export { loadOutboundMediaFromUrl } from "openclaw/plugin-sdk/outbound-media"; -export { normalizePollInput, type PollInput } from "openclaw/plugin-sdk/media-runtime"; +export { normalizePollInput, type PollInput } from "openclaw/plugin-sdk/poll-runtime"; export { writeJsonFileAtomically } from "openclaw/plugin-sdk/json-store"; export { buildChannelKeyCandidates, diff --git a/extensions/matrix/src/setup-config.ts b/extensions/matrix/src/setup-config.ts index feea5d92bf1..f1e1bb4a0bf 100644 --- a/extensions/matrix/src/setup-config.ts +++ b/extensions/matrix/src/setup-config.ts @@ -5,7 +5,7 @@ import { normalizeSecretInputString, type ChannelSetupInput, } from "openclaw/plugin-sdk/setup"; -import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime"; import { resolveMatrixEnvAuthReadiness } from "./matrix/client/env-auth.js"; import { updateMatrixAccountConfig } from "./matrix/config-update.js"; import { isSupportedMatrixAvatarSource } from "./matrix/profile.js"; diff --git a/extensions/matrix/src/storage-paths.ts b/extensions/matrix/src/storage-paths.ts index 1295b527dd9..b8da53ea19a 100644 --- a/extensions/matrix/src/storage-paths.ts +++ b/extensions/matrix/src/storage-paths.ts @@ -1,7 +1,7 @@ import crypto from "node:crypto"; import path from "node:path"; import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id"; -import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime"; export function sanitizeMatrixPathSegment(value: string): string { const cleaned = normalizeLowercaseStringOrEmpty(value) diff --git a/extensions/matrix/src/test-runtime.ts b/extensions/matrix/src/test-runtime.ts index 64972725156..7c57c159ed7 100644 --- a/extensions/matrix/src/test-runtime.ts +++ b/extensions/matrix/src/test-runtime.ts @@ -1,7 +1,7 @@ import { implicitMentionKindWhen, resolveInboundMentionDecision, -} from "openclaw/plugin-sdk/channel-inbound"; +} from "openclaw/plugin-sdk/channel-mention-gating"; import { vi } from "vitest"; import type { PluginRuntime } from "./runtime-api.js"; import { setMatrixRuntime } from "./runtime.js"; diff --git a/extensions/matrix/src/thread-binding-api.ts b/extensions/matrix/src/thread-binding-api.ts index 3fa21d5ba1e..1c4cda8c62e 100644 --- a/extensions/matrix/src/thread-binding-api.ts +++ b/extensions/matrix/src/thread-binding-api.ts @@ -1,4 +1,4 @@ -import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime"; import { resolveMatrixTargetIdentity } from "./matrix/target-ids.js"; export const defaultTopLevelPlacement = "child" as const; diff --git a/extensions/matrix/src/tool-actions.ts b/extensions/matrix/src/tool-actions.ts index 21f513cba20..614adac5c88 100644 --- a/extensions/matrix/src/tool-actions.ts +++ b/extensions/matrix/src/tool-actions.ts @@ -1,5 +1,5 @@ import type { AgentToolResult } from "@mariozechner/pi-agent-core"; -import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/string-coerce-runtime"; import { resolveMatrixAccountConfig } from "./matrix/accounts.js"; import { bootstrapMatrixVerification,