mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-27 09:21:35 +07:00
test: dedupe matrix setup seams
This commit is contained in:
@@ -19,12 +19,108 @@ describe("matrix setup post-write bootstrap", () => {
|
||||
const exit = vi.fn((code: number): never => {
|
||||
throw new Error(`exit ${code}`);
|
||||
});
|
||||
const encryptedDefaultCfg = {
|
||||
channels: {
|
||||
matrix: {
|
||||
encryption: true,
|
||||
},
|
||||
},
|
||||
} as CoreConfig;
|
||||
const defaultPasswordInput = {
|
||||
homeserver: "https://matrix.example.org",
|
||||
userId: "@flurry:example.org",
|
||||
password: "secret", // pragma: allowlist secret
|
||||
} as const;
|
||||
const runtime: RuntimeEnv = {
|
||||
log,
|
||||
error,
|
||||
exit,
|
||||
};
|
||||
|
||||
function applyAccountConfig(params: {
|
||||
previousCfg: CoreConfig;
|
||||
accountId: string;
|
||||
input: Record<string, unknown>;
|
||||
}) {
|
||||
return {
|
||||
previousCfg: params.previousCfg,
|
||||
accountId: params.accountId,
|
||||
input: params.input,
|
||||
nextCfg: matrixPlugin.setup!.applyAccountConfig({
|
||||
cfg: params.previousCfg,
|
||||
accountId: params.accountId,
|
||||
input: params.input,
|
||||
}) as CoreConfig,
|
||||
};
|
||||
}
|
||||
|
||||
function applyDefaultAccountConfig(input: Record<string, unknown> = defaultPasswordInput) {
|
||||
return applyAccountConfig({
|
||||
previousCfg: encryptedDefaultCfg,
|
||||
accountId: "default",
|
||||
input,
|
||||
});
|
||||
}
|
||||
|
||||
function mockBootstrapResult(params: {
|
||||
success: boolean;
|
||||
backupVersion?: string | null;
|
||||
error?: string;
|
||||
}) {
|
||||
verificationMocks.bootstrapMatrixVerification.mockResolvedValue({
|
||||
success: params.success,
|
||||
...(params.error ? { error: params.error } : {}),
|
||||
verification: {
|
||||
backupVersion: params.backupVersion ?? null,
|
||||
},
|
||||
crossSigning: {},
|
||||
pendingVerifications: 0,
|
||||
cryptoBootstrap: null,
|
||||
});
|
||||
}
|
||||
|
||||
async function runAfterAccountConfigWritten(params: {
|
||||
previousCfg: CoreConfig;
|
||||
nextCfg: CoreConfig;
|
||||
accountId: string;
|
||||
input: Record<string, unknown>;
|
||||
}) {
|
||||
await matrixPlugin.setup!.afterAccountConfigWritten?.({
|
||||
previousCfg: params.previousCfg,
|
||||
cfg: params.nextCfg,
|
||||
accountId: params.accountId,
|
||||
input: params.input,
|
||||
runtime,
|
||||
});
|
||||
}
|
||||
|
||||
async function withSavedEnv<T>(
|
||||
values: Record<string, string | undefined>,
|
||||
run: () => Promise<T> | T,
|
||||
) {
|
||||
const previousEnv = Object.fromEntries(
|
||||
Object.keys(values).map((key) => [key, process.env[key]]),
|
||||
) as Record<string, string | undefined>;
|
||||
for (const [key, value] of Object.entries(values)) {
|
||||
if (value === undefined) {
|
||||
delete process.env[key];
|
||||
} else {
|
||||
process.env[key] = value;
|
||||
}
|
||||
}
|
||||
try {
|
||||
return await run();
|
||||
} finally {
|
||||
for (const [key, value] of Object.entries(previousEnv)) {
|
||||
if (value === undefined) {
|
||||
delete process.env[key];
|
||||
} else {
|
||||
process.env[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
verificationMocks.bootstrapMatrixVerification.mockReset();
|
||||
log.mockClear();
|
||||
@@ -34,40 +130,10 @@ describe("matrix setup post-write bootstrap", () => {
|
||||
});
|
||||
|
||||
it("bootstraps verification for newly added encrypted accounts", async () => {
|
||||
const previousCfg = {
|
||||
channels: {
|
||||
matrix: {
|
||||
encryption: true,
|
||||
},
|
||||
},
|
||||
} as CoreConfig;
|
||||
const input = {
|
||||
homeserver: "https://matrix.example.org",
|
||||
userId: "@flurry:example.org",
|
||||
password: "secret", // pragma: allowlist secret
|
||||
};
|
||||
const nextCfg = matrixPlugin.setup!.applyAccountConfig({
|
||||
cfg: previousCfg,
|
||||
accountId: "default",
|
||||
input,
|
||||
}) as CoreConfig;
|
||||
verificationMocks.bootstrapMatrixVerification.mockResolvedValue({
|
||||
success: true,
|
||||
verification: {
|
||||
backupVersion: "7",
|
||||
},
|
||||
crossSigning: {},
|
||||
pendingVerifications: 0,
|
||||
cryptoBootstrap: null,
|
||||
});
|
||||
const { previousCfg, nextCfg, accountId, input } = applyDefaultAccountConfig();
|
||||
mockBootstrapResult({ success: true, backupVersion: "7" });
|
||||
|
||||
await matrixPlugin.setup!.afterAccountConfigWritten?.({
|
||||
previousCfg,
|
||||
cfg: nextCfg,
|
||||
accountId: "default",
|
||||
input,
|
||||
runtime,
|
||||
});
|
||||
await runAfterAccountConfigWritten({ previousCfg, nextCfg, accountId, input });
|
||||
|
||||
expect(verificationMocks.bootstrapMatrixVerification).toHaveBeenCalledWith({
|
||||
accountId: "default",
|
||||
@@ -97,61 +163,27 @@ describe("matrix setup post-write bootstrap", () => {
|
||||
userId: "@flurry:example.org",
|
||||
accessToken: "new-token",
|
||||
};
|
||||
const nextCfg = matrixPlugin.setup!.applyAccountConfig({
|
||||
cfg: previousCfg,
|
||||
accountId: "flurry",
|
||||
input,
|
||||
}) as CoreConfig;
|
||||
|
||||
await matrixPlugin.setup!.afterAccountConfigWritten?.({
|
||||
const { nextCfg, accountId } = applyAccountConfig({
|
||||
previousCfg,
|
||||
cfg: nextCfg,
|
||||
accountId: "flurry",
|
||||
input,
|
||||
runtime,
|
||||
});
|
||||
|
||||
await runAfterAccountConfigWritten({ previousCfg, nextCfg, accountId, input });
|
||||
|
||||
expect(verificationMocks.bootstrapMatrixVerification).not.toHaveBeenCalled();
|
||||
expect(log).not.toHaveBeenCalled();
|
||||
expect(error).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("logs a warning when verification bootstrap fails", async () => {
|
||||
const previousCfg = {
|
||||
channels: {
|
||||
matrix: {
|
||||
encryption: true,
|
||||
},
|
||||
},
|
||||
} as CoreConfig;
|
||||
const input = {
|
||||
homeserver: "https://matrix.example.org",
|
||||
userId: "@flurry:example.org",
|
||||
password: "secret", // pragma: allowlist secret
|
||||
};
|
||||
const nextCfg = matrixPlugin.setup!.applyAccountConfig({
|
||||
cfg: previousCfg,
|
||||
accountId: "default",
|
||||
input,
|
||||
}) as CoreConfig;
|
||||
verificationMocks.bootstrapMatrixVerification.mockResolvedValue({
|
||||
const { previousCfg, nextCfg, accountId, input } = applyDefaultAccountConfig();
|
||||
mockBootstrapResult({
|
||||
success: false,
|
||||
error: "no room-key backup exists on the homeserver",
|
||||
verification: {
|
||||
backupVersion: null,
|
||||
},
|
||||
crossSigning: {},
|
||||
pendingVerifications: 0,
|
||||
cryptoBootstrap: null,
|
||||
});
|
||||
|
||||
await matrixPlugin.setup!.afterAccountConfigWritten?.({
|
||||
previousCfg,
|
||||
cfg: nextCfg,
|
||||
accountId: "default",
|
||||
input,
|
||||
runtime,
|
||||
});
|
||||
await runAfterAccountConfigWritten({ previousCfg, nextCfg, accountId, input });
|
||||
|
||||
expect(error).toHaveBeenCalledWith(
|
||||
'Matrix verification bootstrap warning for "default": no room-key backup exists on the homeserver',
|
||||
@@ -159,76 +191,40 @@ describe("matrix setup post-write bootstrap", () => {
|
||||
});
|
||||
|
||||
it("bootstraps a newly added env-backed default account when encryption is already enabled", async () => {
|
||||
const previousEnv = {
|
||||
MATRIX_HOMESERVER: process.env.MATRIX_HOMESERVER,
|
||||
MATRIX_ACCESS_TOKEN: process.env.MATRIX_ACCESS_TOKEN,
|
||||
};
|
||||
process.env.MATRIX_HOMESERVER = "https://matrix.example.org";
|
||||
process.env.MATRIX_ACCESS_TOKEN = "env-token";
|
||||
try {
|
||||
const previousCfg = {
|
||||
channels: {
|
||||
matrix: {
|
||||
encryption: true,
|
||||
await withSavedEnv(
|
||||
{
|
||||
MATRIX_HOMESERVER: "https://matrix.example.org",
|
||||
MATRIX_ACCESS_TOKEN: "env-token",
|
||||
},
|
||||
},
|
||||
} as CoreConfig;
|
||||
const input = {
|
||||
async () => {
|
||||
const { previousCfg, nextCfg, accountId, input } = applyDefaultAccountConfig({
|
||||
useEnv: true,
|
||||
};
|
||||
const nextCfg = matrixPlugin.setup!.applyAccountConfig({
|
||||
cfg: previousCfg,
|
||||
accountId: "default",
|
||||
input,
|
||||
}) as CoreConfig;
|
||||
verificationMocks.bootstrapMatrixVerification.mockResolvedValue({
|
||||
success: true,
|
||||
verification: {
|
||||
backupVersion: "9",
|
||||
},
|
||||
crossSigning: {},
|
||||
pendingVerifications: 0,
|
||||
cryptoBootstrap: null,
|
||||
});
|
||||
mockBootstrapResult({ success: true, backupVersion: "9" });
|
||||
|
||||
await matrixPlugin.setup!.afterAccountConfigWritten?.({
|
||||
previousCfg,
|
||||
cfg: nextCfg,
|
||||
accountId: "default",
|
||||
input,
|
||||
runtime,
|
||||
});
|
||||
await runAfterAccountConfigWritten({ previousCfg, nextCfg, accountId, input });
|
||||
|
||||
expect(verificationMocks.bootstrapMatrixVerification).toHaveBeenCalledWith({
|
||||
accountId: "default",
|
||||
});
|
||||
expect(log).toHaveBeenCalledWith('Matrix verification bootstrap: complete for "default".');
|
||||
} finally {
|
||||
for (const [key, value] of Object.entries(previousEnv)) {
|
||||
if (value === undefined) {
|
||||
delete process.env[key];
|
||||
} else {
|
||||
process.env[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects default useEnv setup when no Matrix auth env vars are available", () => {
|
||||
const previousEnv = {
|
||||
MATRIX_HOMESERVER: process.env.MATRIX_HOMESERVER,
|
||||
MATRIX_USER_ID: process.env.MATRIX_USER_ID,
|
||||
MATRIX_ACCESS_TOKEN: process.env.MATRIX_ACCESS_TOKEN,
|
||||
MATRIX_PASSWORD: process.env.MATRIX_PASSWORD,
|
||||
MATRIX_DEFAULT_HOMESERVER: process.env.MATRIX_DEFAULT_HOMESERVER,
|
||||
MATRIX_DEFAULT_USER_ID: process.env.MATRIX_DEFAULT_USER_ID,
|
||||
MATRIX_DEFAULT_ACCESS_TOKEN: process.env.MATRIX_DEFAULT_ACCESS_TOKEN,
|
||||
MATRIX_DEFAULT_PASSWORD: process.env.MATRIX_DEFAULT_PASSWORD,
|
||||
};
|
||||
for (const key of Object.keys(previousEnv)) {
|
||||
delete process.env[key];
|
||||
}
|
||||
try {
|
||||
return withSavedEnv(
|
||||
{
|
||||
MATRIX_HOMESERVER: undefined,
|
||||
MATRIX_USER_ID: undefined,
|
||||
MATRIX_ACCESS_TOKEN: undefined,
|
||||
MATRIX_PASSWORD: undefined,
|
||||
MATRIX_DEFAULT_HOMESERVER: undefined,
|
||||
MATRIX_DEFAULT_USER_ID: undefined,
|
||||
MATRIX_DEFAULT_ACCESS_TOKEN: undefined,
|
||||
MATRIX_DEFAULT_PASSWORD: undefined,
|
||||
},
|
||||
() => {
|
||||
expect(
|
||||
matrixPlugin.setup!.validateInput?.({
|
||||
cfg: {} as CoreConfig,
|
||||
@@ -236,15 +232,8 @@ describe("matrix setup post-write bootstrap", () => {
|
||||
input: { useEnv: true },
|
||||
}),
|
||||
).toContain("Set Matrix env vars for the default account");
|
||||
} finally {
|
||||
for (const [key, value] of Object.entries(previousEnv)) {
|
||||
if (value === undefined) {
|
||||
delete process.env[key];
|
||||
} else {
|
||||
process.env[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("clears allowPrivateNetwork when deleting the default Matrix account config", () => {
|
||||
|
||||
@@ -2,6 +2,40 @@ import { describe, expect, it, vi } from "vitest";
|
||||
import type { MatrixClient } from "../sdk.js";
|
||||
import { readMatrixMessages } from "./messages.js";
|
||||
|
||||
function createPollResponseEvent(): Record<string, unknown> {
|
||||
return {
|
||||
event_id: "$vote",
|
||||
sender: "@bob:example.org",
|
||||
type: "m.poll.response",
|
||||
origin_server_ts: 20,
|
||||
content: {
|
||||
"m.poll.response": { answers: ["a1"] },
|
||||
"m.relates_to": { rel_type: "m.reference", event_id: "$poll" },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function createPollStartEvent(params?: {
|
||||
answers?: Array<Record<string, unknown>>;
|
||||
includeDisclosedKind?: boolean;
|
||||
maxSelections?: number;
|
||||
}): Record<string, unknown> {
|
||||
return {
|
||||
event_id: "$poll",
|
||||
sender: "@alice:example.org",
|
||||
type: "m.poll.start",
|
||||
origin_server_ts: 1,
|
||||
content: {
|
||||
"m.poll.start": {
|
||||
question: { "m.text": "Favorite fruit?" },
|
||||
...(params?.includeDisclosedKind ? { kind: "m.poll.disclosed" } : {}),
|
||||
...(params?.maxSelections !== undefined ? { max_selections: params.maxSelections } : {}),
|
||||
answers: params?.answers ?? [{ id: "a1", "m.text": "Apple" }],
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function createMessagesClient(params: {
|
||||
chunk: Array<Record<string, unknown>>;
|
||||
hydratedChunk?: Array<Record<string, unknown>>;
|
||||
@@ -43,16 +77,7 @@ describe("matrix message actions", () => {
|
||||
it("includes poll snapshots when reading message history", async () => {
|
||||
const { client, doRequest, getEvent, getRelations } = createMessagesClient({
|
||||
chunk: [
|
||||
{
|
||||
event_id: "$vote",
|
||||
sender: "@bob:example.org",
|
||||
type: "m.poll.response",
|
||||
origin_server_ts: 20,
|
||||
content: {
|
||||
"m.poll.response": { answers: ["a1"] },
|
||||
"m.relates_to": { rel_type: "m.reference", event_id: "$poll" },
|
||||
},
|
||||
},
|
||||
createPollResponseEvent(),
|
||||
{
|
||||
event_id: "$msg",
|
||||
sender: "@alice:example.org",
|
||||
@@ -64,35 +89,15 @@ describe("matrix message actions", () => {
|
||||
},
|
||||
},
|
||||
],
|
||||
pollRoot: {
|
||||
event_id: "$poll",
|
||||
sender: "@alice:example.org",
|
||||
type: "m.poll.start",
|
||||
origin_server_ts: 1,
|
||||
content: {
|
||||
"m.poll.start": {
|
||||
question: { "m.text": "Favorite fruit?" },
|
||||
kind: "m.poll.disclosed",
|
||||
max_selections: 1,
|
||||
pollRoot: createPollStartEvent({
|
||||
includeDisclosedKind: true,
|
||||
maxSelections: 1,
|
||||
answers: [
|
||||
{ id: "a1", "m.text": "Apple" },
|
||||
{ id: "a2", "m.text": "Strawberry" },
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
pollRelations: [
|
||||
{
|
||||
event_id: "$vote",
|
||||
sender: "@bob:example.org",
|
||||
type: "m.poll.response",
|
||||
origin_server_ts: 20,
|
||||
content: {
|
||||
"m.poll.response": { answers: ["a1"] },
|
||||
"m.relates_to": { rel_type: "m.reference", event_id: "$poll" },
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
pollRelations: [createPollResponseEvent()],
|
||||
});
|
||||
|
||||
const result = await readMatrixMessages("room:!room:example.org", { client, limit: 2.9 });
|
||||
@@ -127,42 +132,8 @@ describe("matrix message actions", () => {
|
||||
|
||||
it("dedupes multiple poll events for the same poll within one read page", async () => {
|
||||
const { client, getEvent } = createMessagesClient({
|
||||
chunk: [
|
||||
{
|
||||
event_id: "$vote",
|
||||
sender: "@bob:example.org",
|
||||
type: "m.poll.response",
|
||||
origin_server_ts: 20,
|
||||
content: {
|
||||
"m.poll.response": { answers: ["a1"] },
|
||||
"m.relates_to": { rel_type: "m.reference", event_id: "$poll" },
|
||||
},
|
||||
},
|
||||
{
|
||||
event_id: "$poll",
|
||||
sender: "@alice:example.org",
|
||||
type: "m.poll.start",
|
||||
origin_server_ts: 1,
|
||||
content: {
|
||||
"m.poll.start": {
|
||||
question: { "m.text": "Favorite fruit?" },
|
||||
answers: [{ id: "a1", "m.text": "Apple" }],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
pollRoot: {
|
||||
event_id: "$poll",
|
||||
sender: "@alice:example.org",
|
||||
type: "m.poll.start",
|
||||
origin_server_ts: 1,
|
||||
content: {
|
||||
"m.poll.start": {
|
||||
question: { "m.text": "Favorite fruit?" },
|
||||
answers: [{ id: "a1", "m.text": "Apple" }],
|
||||
},
|
||||
},
|
||||
},
|
||||
chunk: [createPollResponseEvent(), createPollStartEvent()],
|
||||
pollRoot: createPollStartEvent(),
|
||||
pollRelations: [],
|
||||
});
|
||||
|
||||
@@ -189,30 +160,8 @@ describe("matrix message actions", () => {
|
||||
content: {},
|
||||
},
|
||||
],
|
||||
hydratedChunk: [
|
||||
{
|
||||
event_id: "$vote",
|
||||
sender: "@bob:example.org",
|
||||
type: "m.poll.response",
|
||||
origin_server_ts: 20,
|
||||
content: {
|
||||
"m.poll.response": { answers: ["a1"] },
|
||||
"m.relates_to": { rel_type: "m.reference", event_id: "$poll" },
|
||||
},
|
||||
},
|
||||
],
|
||||
pollRoot: {
|
||||
event_id: "$poll",
|
||||
sender: "@alice:example.org",
|
||||
type: "m.poll.start",
|
||||
origin_server_ts: 1,
|
||||
content: {
|
||||
"m.poll.start": {
|
||||
question: { "m.text": "Favorite fruit?" },
|
||||
answers: [{ id: "a1", "m.text": "Apple" }],
|
||||
},
|
||||
},
|
||||
},
|
||||
hydratedChunk: [createPollResponseEvent()],
|
||||
pollRoot: createPollStartEvent(),
|
||||
pollRelations: [],
|
||||
});
|
||||
|
||||
|
||||
@@ -41,6 +41,50 @@ describe("matrix thread bindings", () => {
|
||||
userId: "@bot:example.org",
|
||||
accessToken: "token",
|
||||
} as const;
|
||||
const accountId = "ops";
|
||||
const idleTimeoutMs = 24 * 60 * 60 * 1000;
|
||||
const matrixClient = {} as never;
|
||||
|
||||
function currentThreadConversation(params?: {
|
||||
conversationId?: string;
|
||||
parentConversationId?: string;
|
||||
}) {
|
||||
return {
|
||||
channel: "matrix" as const,
|
||||
accountId,
|
||||
conversationId: params?.conversationId ?? "$thread",
|
||||
parentConversationId: params?.parentConversationId ?? "!room:example",
|
||||
};
|
||||
}
|
||||
|
||||
async function createStaticThreadBindingManager() {
|
||||
return createMatrixThreadBindingManager({
|
||||
accountId,
|
||||
auth,
|
||||
client: matrixClient,
|
||||
idleTimeoutMs,
|
||||
maxAgeMs: 0,
|
||||
enableSweeper: false,
|
||||
});
|
||||
}
|
||||
|
||||
async function bindCurrentThread(params?: {
|
||||
targetSessionKey?: string;
|
||||
conversationId?: string;
|
||||
parentConversationId?: string;
|
||||
metadata?: { introText?: string };
|
||||
}) {
|
||||
return getSessionBindingService().bind({
|
||||
targetSessionKey: params?.targetSessionKey ?? "agent:ops:subagent:child",
|
||||
targetKind: "subagent",
|
||||
conversation: currentThreadConversation({
|
||||
conversationId: params?.conversationId,
|
||||
parentConversationId: params?.parentConversationId,
|
||||
}),
|
||||
placement: "current",
|
||||
...(params?.metadata ? { metadata: params.metadata } : {}),
|
||||
});
|
||||
}
|
||||
|
||||
function resolveBindingsFilePath(customStateDir?: string) {
|
||||
return path.join(
|
||||
@@ -77,10 +121,10 @@ describe("matrix thread bindings", () => {
|
||||
|
||||
it("creates child Matrix thread bindings from a top-level room context", async () => {
|
||||
await createMatrixThreadBindingManager({
|
||||
accountId: "ops",
|
||||
accountId,
|
||||
auth,
|
||||
client: {} as never,
|
||||
idleTimeoutMs: 24 * 60 * 60 * 1000,
|
||||
client: matrixClient,
|
||||
idleTimeoutMs,
|
||||
maxAgeMs: 0,
|
||||
enableSweeper: false,
|
||||
});
|
||||
@@ -112,25 +156,9 @@ describe("matrix thread bindings", () => {
|
||||
});
|
||||
|
||||
it("posts intro messages inside existing Matrix threads for current placement", async () => {
|
||||
await createMatrixThreadBindingManager({
|
||||
accountId: "ops",
|
||||
auth,
|
||||
client: {} as never,
|
||||
idleTimeoutMs: 24 * 60 * 60 * 1000,
|
||||
maxAgeMs: 0,
|
||||
enableSweeper: false,
|
||||
});
|
||||
await createStaticThreadBindingManager();
|
||||
|
||||
const binding = await getSessionBindingService().bind({
|
||||
targetSessionKey: "agent:ops:subagent:child",
|
||||
targetKind: "subagent",
|
||||
conversation: {
|
||||
channel: "matrix",
|
||||
accountId: "ops",
|
||||
conversationId: "$thread",
|
||||
parentConversationId: "!room:example",
|
||||
},
|
||||
placement: "current",
|
||||
const binding = await bindCurrentThread({
|
||||
metadata: {
|
||||
introText: "intro thread",
|
||||
},
|
||||
@@ -574,25 +602,8 @@ describe("matrix thread bindings", () => {
|
||||
vi.useFakeTimers();
|
||||
vi.setSystemTime(new Date("2026-03-06T10:00:00.000Z"));
|
||||
try {
|
||||
await createMatrixThreadBindingManager({
|
||||
accountId: "ops",
|
||||
auth,
|
||||
client: {} as never,
|
||||
idleTimeoutMs: 24 * 60 * 60 * 1000,
|
||||
maxAgeMs: 0,
|
||||
enableSweeper: false,
|
||||
});
|
||||
const binding = await getSessionBindingService().bind({
|
||||
targetSessionKey: "agent:ops:subagent:child",
|
||||
targetKind: "subagent",
|
||||
conversation: {
|
||||
channel: "matrix",
|
||||
accountId: "ops",
|
||||
conversationId: "$thread",
|
||||
parentConversationId: "!room:example",
|
||||
},
|
||||
placement: "current",
|
||||
});
|
||||
await createStaticThreadBindingManager();
|
||||
const binding = await bindCurrentThread();
|
||||
|
||||
const bindingsPath = resolveBindingsFilePath();
|
||||
const originalLastActivityAt = await readPersistedLastActivityAt(bindingsPath);
|
||||
@@ -618,25 +629,8 @@ describe("matrix thread bindings", () => {
|
||||
vi.useFakeTimers();
|
||||
vi.setSystemTime(new Date("2026-03-06T10:00:00.000Z"));
|
||||
try {
|
||||
const manager = await createMatrixThreadBindingManager({
|
||||
accountId: "ops",
|
||||
auth,
|
||||
client: {} as never,
|
||||
idleTimeoutMs: 24 * 60 * 60 * 1000,
|
||||
maxAgeMs: 0,
|
||||
enableSweeper: false,
|
||||
});
|
||||
const binding = await getSessionBindingService().bind({
|
||||
targetSessionKey: "agent:ops:subagent:child",
|
||||
targetKind: "subagent",
|
||||
conversation: {
|
||||
channel: "matrix",
|
||||
accountId: "ops",
|
||||
conversationId: "$thread",
|
||||
parentConversationId: "!room:example",
|
||||
},
|
||||
placement: "current",
|
||||
});
|
||||
const manager = await createStaticThreadBindingManager();
|
||||
const binding = await bindCurrentThread();
|
||||
const touchedAt = Date.parse("2026-03-06T12:00:00.000Z");
|
||||
getSessionBindingService().touch(binding.bindingId, touchedAt);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user