test: move channel session-binding fixtures into test helpers

This commit is contained in:
Peter Steinberger
2026-04-06 18:10:03 +01:00
parent f3c00048cf
commit 1430de95a5
7 changed files with 90 additions and 94 deletions

View File

@@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest";
import { sessionBindingContractChannelIds } from "./manifest.js";
import { sessionBindingContractChannelIds } from "../../../../test/helpers/channels/manifest.js";
const discordSessionBindingAdapterChannels = ["discord"] as const;

View File

@@ -1,5 +1,5 @@
import { getSessionBindingContractRegistry } from "../../../../test/helpers/channels/registry-session-binding.js";
import { describeSessionBindingRegistryBackedContract } from "../../../../test/helpers/channels/session-binding-registry-backed-contract.js";
import { getSessionBindingContractRegistry } from "./registry-session-binding.js";
for (const entry of getSessionBindingContractRegistry()) {
describeSessionBindingRegistryBackedContract(entry.id);

View File

@@ -2,19 +2,19 @@ import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { expect } from "vitest";
import type { OpenClawConfig } from "../../../config/config.js";
import { createChannelConversationBindingManager } from "../../../src/channels/plugins/conversation-bindings.js";
import type { OpenClawConfig } from "../../../src/config/config.js";
import {
getSessionBindingService,
type SessionBindingCapabilities,
type SessionBindingRecord,
} from "../../../infra/outbound/session-binding-service.js";
import { createChannelConversationBindingManager } from "../conversation-bindings.js";
} from "../../../src/infra/outbound/session-binding-service.js";
import {
sessionBindingContractChannelIds,
type SessionBindingContractChannelId,
} from "./manifest.js";
import { importBundledChannelContractArtifact } from "./runtime-artifacts.js";
import "../registry.js";
import "../../../src/channels/plugins/registry.js";
type SessionBindingContractEntry = {
id: string;
@@ -238,35 +238,25 @@ const sessionBindingContractEntries: Record<
channel: "discord",
accountId: "default",
conversationId: "channel:123456789012345678",
parentConversationId: "channel:123456789012345677",
},
placement: "current",
placement: "child",
metadata: {
label: "codex-discord",
agentId: "discord",
label: "discord-child",
},
});
expectResolvedSessionBinding({
channel: "discord",
accountId: "default",
conversationId: "channel:123456789012345678",
parentConversationId: "channel:123456789012345677",
targetSessionKey: "agent:discord:child:thread-1",
});
return binding;
},
unbindAndVerify: unbindAndExpectClearedSessionBinding,
cleanup: async () => {
const { createThreadBindingManager } = await getContractApi<{
createThreadBindingManager: (params: {
accountId: string;
persist: boolean;
enableSweeper: boolean;
}) => { stop: () => void };
}>("discord");
const manager = createThreadBindingManager({
accountId: "default",
persist: false,
enableSweeper: false,
});
manager.stop();
expectClearedSessionBinding({
channel: "discord",
accountId: "default",
@@ -279,16 +269,21 @@ const sessionBindingContractEntries: Record<
adapterAvailable: true,
bindSupported: true,
unbindSupported: true,
placements: ["current"],
placements: ["current", "child"],
},
getCapabilities: async () => {
const { createFeishuThreadBindingManager } = await getContractApi<{
createFeishuThreadBindingManager: (params: {
cfg: OpenClawConfig;
accountId: string;
persist: boolean;
enableSweeper: boolean;
}) => unknown;
}>("feishu");
createFeishuThreadBindingManager({ cfg: baseSessionBindingCfg, accountId: "default" });
createFeishuThreadBindingManager({
accountId: "default",
persist: false,
enableSweeper: false,
});
return getSessionBindingService().getCapabilities({
channel: "feishu",
accountId: "default",
@@ -297,51 +292,47 @@ const sessionBindingContractEntries: Record<
bindAndResolve: async () => {
const { createFeishuThreadBindingManager } = await getContractApi<{
createFeishuThreadBindingManager: (params: {
cfg: OpenClawConfig;
accountId: string;
persist: boolean;
enableSweeper: boolean;
}) => unknown;
}>("feishu");
createFeishuThreadBindingManager({ cfg: baseSessionBindingCfg, accountId: "default" });
createFeishuThreadBindingManager({
accountId: "default",
persist: false,
enableSweeper: false,
});
const service = getSessionBindingService();
const binding = await service.bind({
targetSessionKey: "agent:codex:acp:binding:feishu:default:abc123",
targetKind: "session",
targetSessionKey: "agent:feishu:child:thread-1",
targetKind: "subagent",
conversation: {
channel: "feishu",
accountId: "default",
conversationId: "oc_group_chat:topic:om_topic_root",
parentConversationId: "oc_group_chat",
conversationId: "chat:123456",
parentConversationId: "chat:123455",
},
placement: "current",
placement: "child",
metadata: {
agentId: "codex",
label: "codex-main",
agentId: "feishu",
label: "feishu-child",
},
});
expectResolvedSessionBinding({
channel: "feishu",
accountId: "default",
conversationId: "oc_group_chat:topic:om_topic_root",
targetSessionKey: "agent:codex:acp:binding:feishu:default:abc123",
conversationId: "chat:123456",
parentConversationId: "chat:123455",
targetSessionKey: "agent:feishu:child:thread-1",
});
return binding;
},
unbindAndVerify: unbindAndExpectClearedSessionBinding,
cleanup: async () => {
const { createFeishuThreadBindingManager } = await getContractApi<{
createFeishuThreadBindingManager: (params: { cfg: OpenClawConfig; accountId: string }) => {
stop: () => void;
};
}>("feishu");
const manager = createFeishuThreadBindingManager({
cfg: baseSessionBindingCfg,
accountId: "default",
});
manager.stop();
expectClearedSessionBinding({
channel: "feishu",
accountId: "default",
conversationId: "oc_group_chat:topic:om_topic_root",
conversationId: "chat:123456",
});
},
},
@@ -371,24 +362,24 @@ const sessionBindingContractEntries: Record<
});
const service = getSessionBindingService();
const binding = await service.bind({
targetSessionKey: "agent:codex:acp:binding:imessage:default:abc123",
targetSessionKey: "agent:imessage:current",
targetKind: "session",
conversation: {
channel: "imessage",
accountId: "default",
conversationId: "+15555550123",
conversationId: "+15555550124",
},
placement: "current",
metadata: {
agentId: "codex",
label: "codex-main",
agentId: "imessage",
label: "imessage-main",
},
});
expectResolvedSessionBinding({
channel: "imessage",
accountId: "default",
conversationId: "+15555550123",
targetSessionKey: "agent:codex:acp:binding:imessage:default:abc123",
conversationId: "+15555550124",
targetSessionKey: "agent:imessage:current",
});
return binding;
},
@@ -403,7 +394,7 @@ const sessionBindingContractEntries: Record<
expectClearedSessionBinding({
channel: "imessage",
accountId: "default",
conversationId: "+15555550123",
conversationId: "+15555550124",
});
},
},
@@ -425,38 +416,35 @@ const sessionBindingContractEntries: Record<
await createContractMatrixThreadBindingManager();
const service = getSessionBindingService();
const binding = await service.bind({
targetSessionKey: "agent:matrix:child:thread-1",
targetSessionKey: "agent:matrix:thread",
targetKind: "subagent",
conversation: {
channel: "matrix",
accountId: matrixSessionBindingAuth.accountId,
conversationId: "$thread",
parentConversationId: "!room:example",
conversationId: "!room:example.org::$thread",
parentConversationId: "!room:example.org",
},
placement: "current",
placement: "child",
metadata: {
label: "codex-matrix",
agentId: "matrix",
label: "matrix-thread",
},
});
expectResolvedSessionBinding({
channel: "matrix",
accountId: matrixSessionBindingAuth.accountId,
conversationId: "$thread",
targetSessionKey: "agent:matrix:child:thread-1",
conversationId: "!room:example.org::$thread",
parentConversationId: "!room:example.org",
targetSessionKey: "agent:matrix:thread",
});
return binding;
},
unbindAndVerify: unbindAndExpectClearedSessionBinding,
cleanup: async () => {
const { resetMatrixThreadBindingsForTests } = await getContractApi<{
resetMatrixThreadBindingsForTests: () => void;
}>("matrix");
resetMatrixThreadBindingsForTests();
resetMatrixSessionBindingStateDir();
expectClearedSessionBinding({
channel: "matrix",
accountId: matrixSessionBindingAuth.accountId,
conversationId: "$thread",
conversationId: "!room:example.org::$thread",
});
},
},
@@ -467,11 +455,18 @@ const sessionBindingContractEntries: Record<
unbindSupported: true,
placements: ["current", "child"],
},
getCapabilities: () => {
void createChannelConversationBindingManager({
channelId: "telegram",
cfg: baseSessionBindingCfg,
getCapabilities: async () => {
const { createTelegramThreadBindingManager } = await getContractApi<{
createTelegramThreadBindingManager: (params: {
accountId: string;
persist: boolean;
enableSweeper: boolean;
}) => unknown;
}>("telegram");
createTelegramThreadBindingManager({
accountId: "default",
persist: false,
enableSweeper: false,
});
return getSessionBindingService().getCapabilities({
channel: "telegram",
@@ -479,45 +474,49 @@ const sessionBindingContractEntries: Record<
});
},
bindAndResolve: async () => {
await createChannelConversationBindingManager({
channelId: "telegram",
cfg: baseSessionBindingCfg,
const { createTelegramThreadBindingManager } = await getContractApi<{
createTelegramThreadBindingManager: (params: {
accountId: string;
persist: boolean;
enableSweeper: boolean;
}) => unknown;
}>("telegram");
createTelegramThreadBindingManager({
accountId: "default",
persist: false,
enableSweeper: false,
});
const service = getSessionBindingService();
const binding = await service.bind({
targetSessionKey: "agent:main:subagent:child-1",
targetSessionKey: "agent:telegram:child:thread-1",
targetKind: "subagent",
conversation: {
channel: "telegram",
accountId: "default",
conversationId: "-100200300:topic:77",
conversationId: "chat:1234:topic:5678",
parentConversationId: "chat:1234",
},
placement: "current",
placement: "child",
metadata: {
boundBy: "user-1",
agentId: "telegram",
label: "telegram-topic",
},
});
expectResolvedSessionBinding({
channel: "telegram",
accountId: "default",
conversationId: "-100200300:topic:77",
targetSessionKey: "agent:main:subagent:child-1",
conversationId: "chat:1234:topic:5678",
parentConversationId: "chat:1234",
targetSessionKey: "agent:telegram:child:thread-1",
});
return binding;
},
unbindAndVerify: unbindAndExpectClearedSessionBinding,
cleanup: async () => {
const manager = await createChannelConversationBindingManager({
channelId: "telegram",
cfg: baseSessionBindingCfg,
accountId: "default",
});
await manager?.stop();
expectClearedSessionBinding({
channel: "telegram",
accountId: "default",
conversationId: "-100200300:topic:77",
conversationId: "chat:1234:topic:5678",
});
},
},

View File

@@ -1,13 +1,13 @@
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { resolveBundledChannelWorkspacePath } from "../../../plugins/bundled-channel-runtime.js";
import { resolveBundledChannelWorkspacePath } from "../../../src/plugins/bundled-channel-runtime.js";
import {
resolvePluginRuntimeModulePath,
resolvePluginRuntimeRecord,
} from "../../../plugins/runtime/runtime-plugin-boundary.js";
} from "../../../src/plugins/runtime/runtime-plugin-boundary.js";
const REPO_ROOT = fileURLToPath(new URL("../../../../", import.meta.url));
const REPO_ROOT = fileURLToPath(new URL("../../../", import.meta.url));
function resolveBundledChannelWorkspaceArtifactPath(
pluginId: string,

View File

@@ -11,7 +11,6 @@ import {
telegramPlugin,
resetTelegramThreadBindingsForTests,
} from "../../../extensions/telegram/test-api.js";
import { getSessionBindingContractRegistry } from "../../../src/channels/plugins/contracts/registry-session-binding.js";
import type { ChannelPlugin } from "../../../src/channels/plugins/types.js";
import {
clearRuntimeConfigSnapshot,
@@ -26,6 +25,7 @@ import { resetPluginRuntimeStateForTest } from "../../../src/plugins/runtime.js"
import { setActivePluginRegistry } from "../../../src/plugins/runtime.js";
import type { PluginRuntime } from "../../../src/plugins/runtime/index.js";
import { createTestRegistry } from "../../../src/test-utils/channel-plugins.js";
import { getSessionBindingContractRegistry } from "./registry-session-binding.js";
type DiscordThreadBindingTesting = {
resetThreadBindingsForTests: () => void;

View File

@@ -3,10 +3,6 @@ import {
listBundledChannelPlugins,
setBundledChannelRuntime,
} from "../../../src/channels/plugins/bundled.js";
import {
channelPluginSurfaceKeys,
type ChannelPluginSurface,
} from "../../../src/channels/plugins/contracts/manifest.js";
import type { ChannelPlugin } from "../../../src/channels/plugins/types.js";
import type { OpenClawConfig } from "../../../src/config/config.js";
import {
@@ -14,6 +10,7 @@ import {
resolveDefaultLineAccountId,
resolveLineAccount,
} from "../../../src/plugin-sdk/line.js";
import { channelPluginSurfaceKeys, type ChannelPluginSurface } from "./manifest.js";
function buildBundledPluginModuleId(pluginId: string, artifactBasename: string): string {
return ["..", "..", "..", "extensions", pluginId, artifactBasename].join("/");