mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-20 22:40:58 +00:00
Matrix: fix Jiti runtime API boundary
This commit is contained in:
@@ -1,14 +1,4 @@
|
||||
export * from "openclaw/plugin-sdk/matrix";
|
||||
// Keep the external runtime API light so Jiti callers can resolve Matrix config
|
||||
// helpers without traversing the full plugin-sdk/runtime graph.
|
||||
export * from "./src/auth-precedence.js";
|
||||
export {
|
||||
findMatrixAccountEntry,
|
||||
hashMatrixAccessToken,
|
||||
listMatrixEnvAccountIds,
|
||||
resolveConfiguredMatrixAccountIds,
|
||||
resolveMatrixChannelConfig,
|
||||
resolveMatrixCredentialsFilename,
|
||||
resolveMatrixEnvAccountToken,
|
||||
resolveMatrixHomeserverKey,
|
||||
resolveMatrixLegacyFlatStoreRoot,
|
||||
sanitizeMatrixPathSegment,
|
||||
} from "./helper-api.js";
|
||||
export * from "./helper-api.js";
|
||||
|
||||
@@ -17,14 +17,6 @@ import {
|
||||
} from "openclaw/plugin-sdk/channel-runtime";
|
||||
import { buildTrafficStatusSummary } from "openclaw/plugin-sdk/extension-shared";
|
||||
import { createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
|
||||
import {
|
||||
buildChannelConfigSchema,
|
||||
buildProbeChannelStatusSummary,
|
||||
collectStatusIssuesFromLastError,
|
||||
DEFAULT_ACCOUNT_ID,
|
||||
PAIRING_APPROVED_MESSAGE,
|
||||
type ChannelPlugin,
|
||||
} from "../runtime-api.js";
|
||||
import { matrixMessageActions } from "./actions.js";
|
||||
import { MatrixConfigSchema } from "./config-schema.js";
|
||||
import {
|
||||
@@ -44,6 +36,14 @@ import {
|
||||
resolveMatrixDirectUserId,
|
||||
resolveMatrixTargetIdentity,
|
||||
} from "./matrix/target-ids.js";
|
||||
import {
|
||||
buildChannelConfigSchema,
|
||||
buildProbeChannelStatusSummary,
|
||||
collectStatusIssuesFromLastError,
|
||||
DEFAULT_ACCOUNT_ID,
|
||||
PAIRING_APPROVED_MESSAGE,
|
||||
type ChannelPlugin,
|
||||
} from "./runtime-api.js";
|
||||
import { getMatrixRuntime } from "./runtime.js";
|
||||
import { resolveMatrixOutboundSessionRoute } from "./session-route.js";
|
||||
import { matrixSetupAdapter } from "./setup-core.js";
|
||||
|
||||
225
extensions/matrix/src/matrix/thread-bindings-shared.ts
Normal file
225
extensions/matrix/src/matrix/thread-bindings-shared.ts
Normal file
@@ -0,0 +1,225 @@
|
||||
import type {
|
||||
BindingTargetKind,
|
||||
SessionBindingRecord,
|
||||
} from "openclaw/plugin-sdk/conversation-runtime";
|
||||
|
||||
export type MatrixThreadBindingTargetKind = "subagent" | "acp";
|
||||
|
||||
export type MatrixThreadBindingRecord = {
|
||||
accountId: string;
|
||||
conversationId: string;
|
||||
parentConversationId?: string;
|
||||
targetKind: MatrixThreadBindingTargetKind;
|
||||
targetSessionKey: string;
|
||||
agentId?: string;
|
||||
label?: string;
|
||||
boundBy?: string;
|
||||
boundAt: number;
|
||||
lastActivityAt: number;
|
||||
idleTimeoutMs?: number;
|
||||
maxAgeMs?: number;
|
||||
};
|
||||
|
||||
export type MatrixThreadBindingManager = {
|
||||
accountId: string;
|
||||
getIdleTimeoutMs: () => number;
|
||||
getMaxAgeMs: () => number;
|
||||
getByConversation: (params: {
|
||||
conversationId: string;
|
||||
parentConversationId?: string;
|
||||
}) => MatrixThreadBindingRecord | undefined;
|
||||
listBySessionKey: (targetSessionKey: string) => MatrixThreadBindingRecord[];
|
||||
listBindings: () => MatrixThreadBindingRecord[];
|
||||
touchBinding: (bindingId: string, at?: number) => MatrixThreadBindingRecord | null;
|
||||
setIdleTimeoutBySessionKey: (params: {
|
||||
targetSessionKey: string;
|
||||
idleTimeoutMs: number;
|
||||
}) => MatrixThreadBindingRecord[];
|
||||
setMaxAgeBySessionKey: (params: {
|
||||
targetSessionKey: string;
|
||||
maxAgeMs: number;
|
||||
}) => MatrixThreadBindingRecord[];
|
||||
stop: () => void;
|
||||
};
|
||||
|
||||
export type MatrixThreadBindingManagerCacheEntry = {
|
||||
filePath: string;
|
||||
manager: MatrixThreadBindingManager;
|
||||
};
|
||||
|
||||
const MANAGERS_BY_ACCOUNT_ID = new Map<string, MatrixThreadBindingManagerCacheEntry>();
|
||||
const BINDINGS_BY_ACCOUNT_CONVERSATION = new Map<string, MatrixThreadBindingRecord>();
|
||||
|
||||
export function resolveBindingKey(params: {
|
||||
accountId: string;
|
||||
conversationId: string;
|
||||
parentConversationId?: string;
|
||||
}): string {
|
||||
return `${params.accountId}:${params.parentConversationId?.trim() || "-"}:${params.conversationId}`;
|
||||
}
|
||||
|
||||
function toSessionBindingTargetKind(raw: MatrixThreadBindingTargetKind): BindingTargetKind {
|
||||
return raw === "subagent" ? "subagent" : "session";
|
||||
}
|
||||
|
||||
export function toMatrixBindingTargetKind(raw: BindingTargetKind): MatrixThreadBindingTargetKind {
|
||||
return raw === "subagent" ? "subagent" : "acp";
|
||||
}
|
||||
|
||||
export function resolveEffectiveBindingExpiry(params: {
|
||||
record: MatrixThreadBindingRecord;
|
||||
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 {};
|
||||
}
|
||||
|
||||
export function toSessionBindingRecord(
|
||||
record: MatrixThreadBindingRecord,
|
||||
defaults: { idleTimeoutMs: number; maxAgeMs: number },
|
||||
): SessionBindingRecord {
|
||||
const lifecycle = resolveEffectiveBindingExpiry({
|
||||
record,
|
||||
defaultIdleTimeoutMs: defaults.idleTimeoutMs,
|
||||
defaultMaxAgeMs: defaults.maxAgeMs,
|
||||
});
|
||||
const idleTimeoutMs =
|
||||
typeof record.idleTimeoutMs === "number" ? record.idleTimeoutMs : defaults.idleTimeoutMs;
|
||||
const maxAgeMs = typeof record.maxAgeMs === "number" ? record.maxAgeMs : defaults.maxAgeMs;
|
||||
return {
|
||||
bindingId: resolveBindingKey(record),
|
||||
targetSessionKey: record.targetSessionKey,
|
||||
targetKind: toSessionBindingTargetKind(record.targetKind),
|
||||
conversation: {
|
||||
channel: "matrix",
|
||||
accountId: record.accountId,
|
||||
conversationId: record.conversationId,
|
||||
parentConversationId: record.parentConversationId,
|
||||
},
|
||||
status: "active",
|
||||
boundAt: record.boundAt,
|
||||
expiresAt: lifecycle.expiresAt,
|
||||
metadata: {
|
||||
agentId: record.agentId,
|
||||
label: record.label,
|
||||
boundBy: record.boundBy,
|
||||
lastActivityAt: record.lastActivityAt,
|
||||
idleTimeoutMs,
|
||||
maxAgeMs,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function setBindingRecord(record: MatrixThreadBindingRecord): void {
|
||||
BINDINGS_BY_ACCOUNT_CONVERSATION.set(resolveBindingKey(record), record);
|
||||
}
|
||||
|
||||
export function removeBindingRecord(
|
||||
record: MatrixThreadBindingRecord,
|
||||
): MatrixThreadBindingRecord | null {
|
||||
const key = resolveBindingKey(record);
|
||||
const removed = BINDINGS_BY_ACCOUNT_CONVERSATION.get(key) ?? null;
|
||||
if (removed) {
|
||||
BINDINGS_BY_ACCOUNT_CONVERSATION.delete(key);
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
export function listBindingsForAccount(accountId: string): MatrixThreadBindingRecord[] {
|
||||
return [...BINDINGS_BY_ACCOUNT_CONVERSATION.values()].filter(
|
||||
(entry) => entry.accountId === accountId,
|
||||
);
|
||||
}
|
||||
|
||||
export function getMatrixThreadBindingManagerEntry(
|
||||
accountId: string,
|
||||
): MatrixThreadBindingManagerCacheEntry | null {
|
||||
return MANAGERS_BY_ACCOUNT_ID.get(accountId) ?? null;
|
||||
}
|
||||
|
||||
export function setMatrixThreadBindingManagerEntry(
|
||||
accountId: string,
|
||||
entry: MatrixThreadBindingManagerCacheEntry,
|
||||
): void {
|
||||
MANAGERS_BY_ACCOUNT_ID.set(accountId, entry);
|
||||
}
|
||||
|
||||
export function deleteMatrixThreadBindingManagerEntry(accountId: string): void {
|
||||
MANAGERS_BY_ACCOUNT_ID.delete(accountId);
|
||||
}
|
||||
|
||||
export function getMatrixThreadBindingManager(
|
||||
accountId: string,
|
||||
): MatrixThreadBindingManager | null {
|
||||
return MANAGERS_BY_ACCOUNT_ID.get(accountId)?.manager ?? null;
|
||||
}
|
||||
|
||||
export function setMatrixThreadBindingIdleTimeoutBySessionKey(params: {
|
||||
accountId: string;
|
||||
targetSessionKey: string;
|
||||
idleTimeoutMs: number;
|
||||
}): SessionBindingRecord[] {
|
||||
const manager = MANAGERS_BY_ACCOUNT_ID.get(params.accountId)?.manager;
|
||||
if (!manager) {
|
||||
return [];
|
||||
}
|
||||
return manager.setIdleTimeoutBySessionKey(params).map((record) =>
|
||||
toSessionBindingRecord(record, {
|
||||
idleTimeoutMs: manager.getIdleTimeoutMs(),
|
||||
maxAgeMs: manager.getMaxAgeMs(),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export function setMatrixThreadBindingMaxAgeBySessionKey(params: {
|
||||
accountId: string;
|
||||
targetSessionKey: string;
|
||||
maxAgeMs: number;
|
||||
}): SessionBindingRecord[] {
|
||||
const manager = MANAGERS_BY_ACCOUNT_ID.get(params.accountId)?.manager;
|
||||
if (!manager) {
|
||||
return [];
|
||||
}
|
||||
return manager.setMaxAgeBySessionKey(params).map((record) =>
|
||||
toSessionBindingRecord(record, {
|
||||
idleTimeoutMs: manager.getIdleTimeoutMs(),
|
||||
maxAgeMs: manager.getMaxAgeMs(),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export function resetMatrixThreadBindingsForTests(): void {
|
||||
for (const { manager } of MANAGERS_BY_ACCOUNT_ID.values()) {
|
||||
manager.stop();
|
||||
}
|
||||
MANAGERS_BY_ACCOUNT_ID.clear();
|
||||
BINDINGS_BY_ACCOUNT_CONVERSATION.clear();
|
||||
}
|
||||
@@ -6,70 +6,39 @@ import {
|
||||
resolveThreadBindingFarewellText,
|
||||
unregisterSessionBindingAdapter,
|
||||
writeJsonFileAtomically,
|
||||
type BindingTargetKind,
|
||||
type SessionBindingRecord,
|
||||
} from "../runtime-api.js";
|
||||
import { resolveMatrixStoragePaths } from "./client/storage.js";
|
||||
import type { MatrixAuth } from "./client/types.js";
|
||||
import type { MatrixClient } from "./sdk.js";
|
||||
import { sendMessageMatrix } from "./send.js";
|
||||
import {
|
||||
deleteMatrixThreadBindingManagerEntry,
|
||||
getMatrixThreadBindingManager,
|
||||
getMatrixThreadBindingManagerEntry,
|
||||
listBindingsForAccount,
|
||||
removeBindingRecord,
|
||||
resetMatrixThreadBindingsForTests,
|
||||
resolveBindingKey,
|
||||
resolveEffectiveBindingExpiry,
|
||||
setBindingRecord,
|
||||
setMatrixThreadBindingIdleTimeoutBySessionKey,
|
||||
setMatrixThreadBindingManagerEntry,
|
||||
setMatrixThreadBindingMaxAgeBySessionKey,
|
||||
toMatrixBindingTargetKind,
|
||||
toSessionBindingRecord,
|
||||
type MatrixThreadBindingManager,
|
||||
type MatrixThreadBindingRecord,
|
||||
} from "./thread-bindings-shared.js";
|
||||
|
||||
const STORE_VERSION = 1;
|
||||
const THREAD_BINDINGS_SWEEP_INTERVAL_MS = 60_000;
|
||||
const TOUCH_PERSIST_DELAY_MS = 30_000;
|
||||
|
||||
type MatrixThreadBindingTargetKind = "subagent" | "acp";
|
||||
|
||||
type MatrixThreadBindingRecord = {
|
||||
accountId: string;
|
||||
conversationId: string;
|
||||
parentConversationId?: string;
|
||||
targetKind: MatrixThreadBindingTargetKind;
|
||||
targetSessionKey: string;
|
||||
agentId?: string;
|
||||
label?: string;
|
||||
boundBy?: string;
|
||||
boundAt: number;
|
||||
lastActivityAt: number;
|
||||
idleTimeoutMs?: number;
|
||||
maxAgeMs?: number;
|
||||
};
|
||||
|
||||
type StoredMatrixThreadBindingState = {
|
||||
version: number;
|
||||
bindings: MatrixThreadBindingRecord[];
|
||||
};
|
||||
|
||||
export type MatrixThreadBindingManager = {
|
||||
accountId: string;
|
||||
getIdleTimeoutMs: () => number;
|
||||
getMaxAgeMs: () => number;
|
||||
getByConversation: (params: {
|
||||
conversationId: string;
|
||||
parentConversationId?: string;
|
||||
}) => MatrixThreadBindingRecord | undefined;
|
||||
listBySessionKey: (targetSessionKey: string) => MatrixThreadBindingRecord[];
|
||||
listBindings: () => MatrixThreadBindingRecord[];
|
||||
touchBinding: (bindingId: string, at?: number) => MatrixThreadBindingRecord | null;
|
||||
setIdleTimeoutBySessionKey: (params: {
|
||||
targetSessionKey: string;
|
||||
idleTimeoutMs: number;
|
||||
}) => MatrixThreadBindingRecord[];
|
||||
setMaxAgeBySessionKey: (params: {
|
||||
targetSessionKey: string;
|
||||
maxAgeMs: number;
|
||||
}) => MatrixThreadBindingRecord[];
|
||||
stop: () => void;
|
||||
};
|
||||
|
||||
type MatrixThreadBindingManagerCacheEntry = {
|
||||
filePath: string;
|
||||
manager: MatrixThreadBindingManager;
|
||||
};
|
||||
|
||||
const MANAGERS_BY_ACCOUNT_ID = new Map<string, MatrixThreadBindingManagerCacheEntry>();
|
||||
const BINDINGS_BY_ACCOUNT_CONVERSATION = new Map<string, MatrixThreadBindingRecord>();
|
||||
|
||||
function normalizeDurationMs(raw: unknown, fallback: number): number {
|
||||
if (typeof raw !== "number" || !Number.isFinite(raw)) {
|
||||
return fallback;
|
||||
@@ -86,94 +55,6 @@ function normalizeConversationId(raw: unknown): string | undefined {
|
||||
return trimmed || undefined;
|
||||
}
|
||||
|
||||
function resolveBindingKey(params: {
|
||||
accountId: string;
|
||||
conversationId: string;
|
||||
parentConversationId?: string;
|
||||
}): string {
|
||||
return `${params.accountId}:${params.parentConversationId?.trim() || "-"}:${params.conversationId}`;
|
||||
}
|
||||
|
||||
function toSessionBindingTargetKind(raw: MatrixThreadBindingTargetKind): BindingTargetKind {
|
||||
return raw === "subagent" ? "subagent" : "session";
|
||||
}
|
||||
|
||||
function toMatrixBindingTargetKind(raw: BindingTargetKind): MatrixThreadBindingTargetKind {
|
||||
return raw === "subagent" ? "subagent" : "acp";
|
||||
}
|
||||
|
||||
function resolveEffectiveBindingExpiry(params: {
|
||||
record: MatrixThreadBindingRecord;
|
||||
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 {};
|
||||
}
|
||||
|
||||
function toSessionBindingRecord(
|
||||
record: MatrixThreadBindingRecord,
|
||||
defaults: { idleTimeoutMs: number; maxAgeMs: number },
|
||||
): SessionBindingRecord {
|
||||
const lifecycle = resolveEffectiveBindingExpiry({
|
||||
record,
|
||||
defaultIdleTimeoutMs: defaults.idleTimeoutMs,
|
||||
defaultMaxAgeMs: defaults.maxAgeMs,
|
||||
});
|
||||
const idleTimeoutMs =
|
||||
typeof record.idleTimeoutMs === "number" ? record.idleTimeoutMs : defaults.idleTimeoutMs;
|
||||
const maxAgeMs = typeof record.maxAgeMs === "number" ? record.maxAgeMs : defaults.maxAgeMs;
|
||||
return {
|
||||
bindingId: resolveBindingKey(record),
|
||||
targetSessionKey: record.targetSessionKey,
|
||||
targetKind: toSessionBindingTargetKind(record.targetKind),
|
||||
conversation: {
|
||||
channel: "matrix",
|
||||
accountId: record.accountId,
|
||||
conversationId: record.conversationId,
|
||||
parentConversationId: record.parentConversationId,
|
||||
},
|
||||
status: "active",
|
||||
boundAt: record.boundAt,
|
||||
expiresAt: lifecycle.expiresAt,
|
||||
metadata: {
|
||||
agentId: record.agentId,
|
||||
label: record.label,
|
||||
boundBy: record.boundBy,
|
||||
lastActivityAt: record.lastActivityAt,
|
||||
idleTimeoutMs,
|
||||
maxAgeMs,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function resolveBindingsPath(params: {
|
||||
auth: MatrixAuth;
|
||||
accountId: string;
|
||||
@@ -256,25 +137,6 @@ async function persistBindingsSnapshot(
|
||||
await writeJsonFileAtomically(filePath, toStoredBindingsState(bindings));
|
||||
}
|
||||
|
||||
function setBindingRecord(record: MatrixThreadBindingRecord): void {
|
||||
BINDINGS_BY_ACCOUNT_CONVERSATION.set(resolveBindingKey(record), record);
|
||||
}
|
||||
|
||||
function removeBindingRecord(record: MatrixThreadBindingRecord): MatrixThreadBindingRecord | null {
|
||||
const key = resolveBindingKey(record);
|
||||
const removed = BINDINGS_BY_ACCOUNT_CONVERSATION.get(key) ?? null;
|
||||
if (removed) {
|
||||
BINDINGS_BY_ACCOUNT_CONVERSATION.delete(key);
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
function listBindingsForAccount(accountId: string): MatrixThreadBindingRecord[] {
|
||||
return [...BINDINGS_BY_ACCOUNT_CONVERSATION.values()].filter(
|
||||
(entry) => entry.accountId === accountId,
|
||||
);
|
||||
}
|
||||
|
||||
function buildMatrixBindingIntroText(params: {
|
||||
metadata?: Record<string, unknown>;
|
||||
targetSessionKey: string;
|
||||
@@ -365,7 +227,7 @@ export async function createMatrixThreadBindingManager(params: {
|
||||
env: params.env,
|
||||
stateDir: params.stateDir,
|
||||
});
|
||||
const existingEntry = MANAGERS_BY_ACCOUNT_ID.get(params.accountId);
|
||||
const existingEntry = getMatrixThreadBindingManagerEntry(params.accountId);
|
||||
if (existingEntry) {
|
||||
if (existingEntry.filePath === filePath) {
|
||||
return existingEntry.manager;
|
||||
@@ -506,11 +368,11 @@ export async function createMatrixThreadBindingManager(params: {
|
||||
channel: "matrix",
|
||||
accountId: params.accountId,
|
||||
});
|
||||
if (MANAGERS_BY_ACCOUNT_ID.get(params.accountId)?.manager === manager) {
|
||||
MANAGERS_BY_ACCOUNT_ID.delete(params.accountId);
|
||||
if (getMatrixThreadBindingManagerEntry(params.accountId)?.manager === manager) {
|
||||
deleteMatrixThreadBindingManagerEntry(params.accountId);
|
||||
}
|
||||
for (const record of listBindingsForAccount(params.accountId)) {
|
||||
BINDINGS_BY_ACCOUNT_CONVERSATION.delete(resolveBindingKey(record));
|
||||
removeBindingRecord(record);
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -705,57 +567,15 @@ export async function createMatrixThreadBindingManager(params: {
|
||||
sweepTimer.unref?.();
|
||||
}
|
||||
|
||||
MANAGERS_BY_ACCOUNT_ID.set(params.accountId, {
|
||||
setMatrixThreadBindingManagerEntry(params.accountId, {
|
||||
filePath,
|
||||
manager,
|
||||
});
|
||||
return manager;
|
||||
}
|
||||
|
||||
export function getMatrixThreadBindingManager(
|
||||
accountId: string,
|
||||
): MatrixThreadBindingManager | null {
|
||||
return MANAGERS_BY_ACCOUNT_ID.get(accountId)?.manager ?? null;
|
||||
}
|
||||
|
||||
export function setMatrixThreadBindingIdleTimeoutBySessionKey(params: {
|
||||
accountId: string;
|
||||
targetSessionKey: string;
|
||||
idleTimeoutMs: number;
|
||||
}): SessionBindingRecord[] {
|
||||
const manager = MANAGERS_BY_ACCOUNT_ID.get(params.accountId)?.manager;
|
||||
if (!manager) {
|
||||
return [];
|
||||
}
|
||||
return manager.setIdleTimeoutBySessionKey(params).map((record) =>
|
||||
toSessionBindingRecord(record, {
|
||||
idleTimeoutMs: manager.getIdleTimeoutMs(),
|
||||
maxAgeMs: manager.getMaxAgeMs(),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export function setMatrixThreadBindingMaxAgeBySessionKey(params: {
|
||||
accountId: string;
|
||||
targetSessionKey: string;
|
||||
maxAgeMs: number;
|
||||
}): SessionBindingRecord[] {
|
||||
const manager = MANAGERS_BY_ACCOUNT_ID.get(params.accountId)?.manager;
|
||||
if (!manager) {
|
||||
return [];
|
||||
}
|
||||
return manager.setMaxAgeBySessionKey(params).map((record) =>
|
||||
toSessionBindingRecord(record, {
|
||||
idleTimeoutMs: manager.getIdleTimeoutMs(),
|
||||
maxAgeMs: manager.getMaxAgeMs(),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export function resetMatrixThreadBindingsForTests(): void {
|
||||
for (const { manager } of MANAGERS_BY_ACCOUNT_ID.values()) {
|
||||
manager.stop();
|
||||
}
|
||||
MANAGERS_BY_ACCOUNT_ID.clear();
|
||||
BINDINGS_BY_ACCOUNT_CONVERSATION.clear();
|
||||
}
|
||||
export {
|
||||
getMatrixThreadBindingManager,
|
||||
resetMatrixThreadBindingsForTests,
|
||||
setMatrixThreadBindingIdleTimeoutBySessionKey,
|
||||
setMatrixThreadBindingMaxAgeBySessionKey,
|
||||
};
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export * from "openclaw/plugin-sdk/matrix";
|
||||
export * from "../runtime-api.js";
|
||||
|
||||
4
extensions/matrix/thread-bindings-runtime.ts
Normal file
4
extensions/matrix/thread-bindings-runtime.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export {
|
||||
setMatrixThreadBindingIdleTimeoutBySessionKey,
|
||||
setMatrixThreadBindingMaxAgeBySessionKey,
|
||||
} from "./src/matrix/thread-bindings-shared.js";
|
||||
@@ -85,7 +85,7 @@ export {
|
||||
export {
|
||||
setMatrixThreadBindingIdleTimeoutBySessionKey,
|
||||
setMatrixThreadBindingMaxAgeBySessionKey,
|
||||
} from "../../extensions/matrix/src/matrix/thread-bindings.js";
|
||||
} from "../../extensions/matrix/thread-bindings-runtime.js";
|
||||
export { createTypingCallbacks } from "../channels/typing.js";
|
||||
export { createChannelReplyPipeline } from "./channel-reply-pipeline.js";
|
||||
export type { OpenClawConfig } from "../config/config.js";
|
||||
|
||||
@@ -195,8 +195,8 @@ export type PluginRuntimeChannel = {
|
||||
};
|
||||
matrix: {
|
||||
threadBindings: {
|
||||
setIdleTimeoutBySessionKey: typeof import("../../../extensions/matrix/runtime-api.js").setMatrixThreadBindingIdleTimeoutBySessionKey;
|
||||
setMaxAgeBySessionKey: typeof import("../../../extensions/matrix/runtime-api.js").setMatrixThreadBindingMaxAgeBySessionKey;
|
||||
setIdleTimeoutBySessionKey: typeof import("../../plugin-sdk/matrix.js").setMatrixThreadBindingIdleTimeoutBySessionKey;
|
||||
setMaxAgeBySessionKey: typeof import("../../plugin-sdk/matrix.js").setMatrixThreadBindingMaxAgeBySessionKey;
|
||||
};
|
||||
};
|
||||
signal: {
|
||||
|
||||
Reference in New Issue
Block a user