feat: Fabric channel plugin for OpenClaw (Phase 1, B1)
OpenClaw channel plugin: defineChannelPluginEntry + createChatChannelPlugin.
Inbound via channel-turn kernel (wakeup -> admission: true=dispatch,
else drop+recordHistory). One Fabric socket per agent identity in the
plugin runtime (no sidecar). Center API-key agent auth. Tools:
fabric-register, create-{chat,work,report,discussion}-channel,
discussion-complete (post summary + close channel).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
63
src/channel.ts
Normal file
63
src/channel.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import {
|
||||
createChatChannelPlugin,
|
||||
createChannelPluginBase,
|
||||
} from 'openclaw/plugin-sdk/channel-core';
|
||||
import type { OpenClawConfig } from 'openclaw/plugin-sdk/channel-core';
|
||||
|
||||
export type ResolvedFabricAccount = {
|
||||
accountId: string | null;
|
||||
centerApiBase: string;
|
||||
allowFrom: string[];
|
||||
dmPolicy: string | undefined;
|
||||
};
|
||||
|
||||
export function resolveFabricAccount(
|
||||
cfg: OpenClawConfig,
|
||||
accountId?: string | null,
|
||||
): ResolvedFabricAccount {
|
||||
const section = (cfg.channels as Record<string, any>)?.['fabric'];
|
||||
const centerApiBase: string | undefined = section?.centerApiBase;
|
||||
if (!centerApiBase) throw new Error('fabric: channels.fabric.centerApiBase is required');
|
||||
return {
|
||||
accountId: accountId ?? null,
|
||||
centerApiBase,
|
||||
allowFrom: section?.allowFrom ?? [],
|
||||
dmPolicy: section?.dmSecurity,
|
||||
};
|
||||
}
|
||||
|
||||
// Outbound is wired by the entry (it needs the identity registry + client to
|
||||
// post as the right agent). Channel-turn visible replies go through the
|
||||
// inbound adapter's delivery callback; this object owns config/security only.
|
||||
export function buildFabricChannelPlugin(
|
||||
sendText: (params: { accountId?: string | null; to: string; text: string }) => Promise<{ messageId?: string }>,
|
||||
) {
|
||||
return createChatChannelPlugin<ResolvedFabricAccount>({
|
||||
base: createChannelPluginBase({
|
||||
id: 'fabric',
|
||||
setup: {
|
||||
resolveAccount: resolveFabricAccount,
|
||||
inspectAccount(cfg, accountId) {
|
||||
const section = (cfg.channels as Record<string, any>)?.['fabric'];
|
||||
const ok = Boolean(section?.centerApiBase);
|
||||
return { enabled: ok, configured: ok, tokenStatus: ok ? 'available' : 'missing' };
|
||||
},
|
||||
},
|
||||
}),
|
||||
security: {
|
||||
dm: {
|
||||
channelKey: 'fabric',
|
||||
resolvePolicy: (a) => a.dmPolicy,
|
||||
resolveAllowFrom: (a) => a.allowFrom,
|
||||
defaultPolicy: 'allowlist',
|
||||
},
|
||||
},
|
||||
// Fabric replies thread by being posted into the same channel.
|
||||
threading: { topLevelReplyToMode: 'channel' },
|
||||
outbound: {
|
||||
attachedResults: {
|
||||
sendText: async (params) => sendText(params),
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user