From d851f9e816e8f20600183d1a40a674b6cb42986d Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 17 Apr 2026 17:04:31 +0100 Subject: [PATCH] perf: narrow Matrix thread binding runtime imports --- .../src/matrix/thread-bindings-shared.ts | 4 +- .../matrix/src/matrix/thread-bindings.ts | 4 +- package.json | 8 +++ scripts/lib/plugin-sdk-entrypoints.json | 2 + src/plugin-sdk/session-key-runtime.ts | 6 +++ .../thread-bindings-session-runtime.ts | 52 +++++++++++++++++++ 6 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 src/plugin-sdk/session-key-runtime.ts create mode 100644 src/plugin-sdk/thread-bindings-session-runtime.ts diff --git a/extensions/matrix/src/matrix/thread-bindings-shared.ts b/extensions/matrix/src/matrix/thread-bindings-shared.ts index 298f7757782..0c6c32b376c 100644 --- a/extensions/matrix/src/matrix/thread-bindings-shared.ts +++ b/extensions/matrix/src/matrix/thread-bindings-shared.ts @@ -1,8 +1,8 @@ import type { BindingTargetKind, SessionBindingRecord, -} from "openclaw/plugin-sdk/thread-bindings-runtime"; -import { resolveThreadBindingLifecycle } from "openclaw/plugin-sdk/thread-bindings-runtime"; +} from "openclaw/plugin-sdk/thread-bindings-session-runtime"; +import { resolveThreadBindingLifecycle } from "openclaw/plugin-sdk/thread-bindings-session-runtime"; export type MatrixThreadBindingTargetKind = "subagent" | "acp"; diff --git a/extensions/matrix/src/matrix/thread-bindings.ts b/extensions/matrix/src/matrix/thread-bindings.ts index e5c87e62b17..edb50da4052 100644 --- a/extensions/matrix/src/matrix/thread-bindings.ts +++ b/extensions/matrix/src/matrix/thread-bindings.ts @@ -1,13 +1,13 @@ import path from "node:path"; import { readJsonFileWithFallback, writeJsonFileAtomically } from "openclaw/plugin-sdk/json-store"; -import { resolveAgentIdFromSessionKey } from "openclaw/plugin-sdk/routing"; +import { resolveAgentIdFromSessionKey } from "openclaw/plugin-sdk/session-key-runtime"; import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime"; import { registerSessionBindingAdapter, resolveThreadBindingFarewellText, type SessionBindingAdapter, unregisterSessionBindingAdapter, -} from "openclaw/plugin-sdk/thread-bindings-runtime"; +} from "openclaw/plugin-sdk/thread-bindings-session-runtime"; import { claimCurrentTokenStorageState, resolveMatrixStateFilePath } from "./client/storage.js"; import type { MatrixAuth } from "./client/types.js"; import type { MatrixClient } from "./sdk.js"; diff --git a/package.json b/package.json index a41cee4fb7f..e65e8d5f938 100644 --- a/package.json +++ b/package.json @@ -284,6 +284,10 @@ "types": "./dist/plugin-sdk/thread-bindings-runtime.d.ts", "default": "./dist/plugin-sdk/thread-bindings-runtime.js" }, + "./plugin-sdk/thread-bindings-session-runtime": { + "types": "./dist/plugin-sdk/thread-bindings-session-runtime.d.ts", + "default": "./dist/plugin-sdk/thread-bindings-session-runtime.js" + }, "./plugin-sdk/text-runtime": { "types": "./dist/plugin-sdk/text-runtime.d.ts", "default": "./dist/plugin-sdk/text-runtime.js" @@ -680,6 +684,10 @@ "types": "./dist/plugin-sdk/session-binding-runtime.d.ts", "default": "./dist/plugin-sdk/session-binding-runtime.js" }, + "./plugin-sdk/session-key-runtime": { + "types": "./dist/plugin-sdk/session-key-runtime.d.ts", + "default": "./dist/plugin-sdk/session-key-runtime.js" + }, "./plugin-sdk/session-store-runtime": { "types": "./dist/plugin-sdk/session-store-runtime.d.ts", "default": "./dist/plugin-sdk/session-store-runtime.js" diff --git a/scripts/lib/plugin-sdk-entrypoints.json b/scripts/lib/plugin-sdk-entrypoints.json index 1a60d63b34b..20b16ae7326 100644 --- a/scripts/lib/plugin-sdk-entrypoints.json +++ b/scripts/lib/plugin-sdk-entrypoints.json @@ -57,6 +57,7 @@ "matrix-runtime-heavy", "matrix-runtime-shared", "thread-bindings-runtime", + "thread-bindings-session-runtime", "text-runtime", "text-chunking", "agent-runtime", @@ -156,6 +157,7 @@ "runtime-fetch", "response-limit-runtime", "session-binding-runtime", + "session-key-runtime", "session-store-runtime", "ssrf-dispatcher", "string-coerce-runtime", diff --git a/src/plugin-sdk/session-key-runtime.ts b/src/plugin-sdk/session-key-runtime.ts new file mode 100644 index 00000000000..84f2ce662fc --- /dev/null +++ b/src/plugin-sdk/session-key-runtime.ts @@ -0,0 +1,6 @@ +// Narrow session-key helpers for channel hot paths that should not import the +// broader routing SDK barrel. +export { + resolveAgentIdFromSessionKey, + type ParsedAgentSessionKey, +} from "../routing/session-key.js"; diff --git a/src/plugin-sdk/thread-bindings-session-runtime.ts b/src/plugin-sdk/thread-bindings-session-runtime.ts new file mode 100644 index 00000000000..ee90a007d77 --- /dev/null +++ b/src/plugin-sdk/thread-bindings-session-runtime.ts @@ -0,0 +1,52 @@ +export { resolveThreadBindingFarewellText } from "../channels/thread-bindings-messages.js"; +export { + registerSessionBindingAdapter, + unregisterSessionBindingAdapter, + type BindingTargetKind, + type SessionBindingAdapter, + type SessionBindingRecord, +} from "../infra/outbound/session-binding-service.js"; + +type ThreadBindingLifecycleRecord = { + boundAt: number; + lastActivityAt: number; + idleTimeoutMs?: number; + maxAgeMs?: number; +}; + +export function resolveThreadBindingLifecycle(params: { + record: ThreadBindingLifecycleRecord; + defaultIdleTimeoutMs: number; + defaultMaxAgeMs: number; +}): { + expiresAt?: number; + reason?: "idle-expired" | "max-age-expired"; +} { + const idleTimeoutMs = + typeof params.record.idleTimeoutMs === "number" + ? Math.max(0, Math.floor(params.record.idleTimeoutMs)) + : params.defaultIdleTimeoutMs; + const maxAgeMs = + typeof params.record.maxAgeMs === "number" + ? Math.max(0, Math.floor(params.record.maxAgeMs)) + : params.defaultMaxAgeMs; + + const inactivityExpiresAt = + idleTimeoutMs > 0 + ? Math.max(params.record.lastActivityAt, params.record.boundAt) + idleTimeoutMs + : undefined; + const maxAgeExpiresAt = maxAgeMs > 0 ? params.record.boundAt + maxAgeMs : undefined; + + if (inactivityExpiresAt != null && maxAgeExpiresAt != null) { + return inactivityExpiresAt <= maxAgeExpiresAt + ? { expiresAt: inactivityExpiresAt, reason: "idle-expired" } + : { expiresAt: maxAgeExpiresAt, reason: "max-age-expired" }; + } + if (inactivityExpiresAt != null) { + return { expiresAt: inactivityExpiresAt, reason: "idle-expired" }; + } + if (maxAgeExpiresAt != null) { + return { expiresAt: maxAgeExpiresAt, reason: "max-age-expired" }; + } + return {}; +}