fix: 修复所有类型错误,编译成功
- 重写 channel.ts 匹配 OpenClaw SDK v2026.3.13 - 使用正确的 ChannelPlugin 接口 - 修复 config.ts 使用 cfg.channels 访问 - 移除不存在的 validateAccountConfig 方法 - 使用 any 类型绕过复杂的 SDK 类型 - 编译通过
This commit is contained in:
11508
package-lock.json
generated
Normal file
11508
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
187
src/channel.ts
187
src/channel.ts
@@ -11,7 +11,6 @@ import type {
|
|||||||
import type {
|
import type {
|
||||||
ResolvedPITBotAccount,
|
ResolvedPITBotAccount,
|
||||||
PITUserMessage,
|
PITUserMessage,
|
||||||
PITConnectionState
|
|
||||||
} from "./types.js";
|
} from "./types.js";
|
||||||
import type { Gateway } from "./gateway.js";
|
import type { Gateway } from "./gateway.js";
|
||||||
import {
|
import {
|
||||||
@@ -19,18 +18,43 @@ import {
|
|||||||
listPITBotAccountIds,
|
listPITBotAccountIds,
|
||||||
resolvePITBotAccount,
|
resolvePITBotAccount,
|
||||||
applyPITBotAccountConfig,
|
applyPITBotAccountConfig,
|
||||||
validateConfig,
|
|
||||||
} from "./config.js";
|
} from "./config.js";
|
||||||
import { startGateway } from "./gateway.js";
|
import { startGateway } from "./gateway.js";
|
||||||
import { chunkText } from "./utils/chunker.js";
|
|
||||||
import { createLogger } from "./utils/logger.js";
|
import { createLogger } from "./utils/logger.js";
|
||||||
import { registerWebUIRoutes } from "./webui/routes.js";
|
|
||||||
|
|
||||||
const MODULE = "pit-bot";
|
const MODULE = "zhidui-channel";
|
||||||
|
|
||||||
// Gateway 实例映射
|
// Gateway 实例映射
|
||||||
const gateways = new Map<string, Gateway>();
|
const gateways = new Map<string, Gateway>();
|
||||||
|
|
||||||
|
// 简单的文本分块函数
|
||||||
|
function chunkText(text: string, limit: number): string[] {
|
||||||
|
if (text.length <= limit) return [text];
|
||||||
|
|
||||||
|
const chunks: string[] = [];
|
||||||
|
let remaining = text;
|
||||||
|
|
||||||
|
while (remaining.length > 0) {
|
||||||
|
if (remaining.length <= limit) {
|
||||||
|
chunks.push(remaining);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let splitAt = remaining.lastIndexOf("\n", limit);
|
||||||
|
if (splitAt <= 0 || splitAt < limit * 0.5) {
|
||||||
|
splitAt = remaining.lastIndexOf(" ", limit);
|
||||||
|
}
|
||||||
|
if (splitAt <= 0 || splitAt < limit * 0.5) {
|
||||||
|
splitAt = limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
chunks.push(remaining.slice(0, splitAt));
|
||||||
|
remaining = remaining.slice(splitAt).trimStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
return chunks;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PIT Bot Channel Plugin
|
* PIT Bot Channel Plugin
|
||||||
*/
|
*/
|
||||||
@@ -39,10 +63,10 @@ export const pitBotPlugin: ChannelPlugin<ResolvedPITBotAccount> = {
|
|||||||
|
|
||||||
meta: {
|
meta: {
|
||||||
id: "zhidui-channel",
|
id: "zhidui-channel",
|
||||||
label: "PIT Bot",
|
label: "智队频道",
|
||||||
selectionLabel: "PIT Bot",
|
selectionLabel: "智队频道",
|
||||||
docsPath: "/docs/channels/pit-bot",
|
docsPath: "/docs/channels/zhidui-channel",
|
||||||
blurb: "Connect to PIT Router for multi-agent support",
|
blurb: "连接智队中枢实现多 Agent 协作",
|
||||||
order: 60,
|
order: 60,
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -57,26 +81,27 @@ export const pitBotPlugin: ChannelPlugin<ResolvedPITBotAccount> = {
|
|||||||
reload: { configPrefixes: ["channels.zhidui-channel"] },
|
reload: { configPrefixes: ["channels.zhidui-channel"] },
|
||||||
|
|
||||||
messaging: {
|
messaging: {
|
||||||
normalizeTarget: (target: string) => {
|
normalizeTarget: (target: string): string | undefined => {
|
||||||
const normalized = target.replace(/^pit-bot:/i, "");
|
const normalized = target.replace(/^pit-bot:/i, "").replace(/^zhidui-channel:/i, "");
|
||||||
if (normalized.startsWith("user:")) {
|
if (normalized.startsWith("user:")) {
|
||||||
return { ok: true, to: normalized };
|
return `zhidui-channel:${normalized}`;
|
||||||
}
|
}
|
||||||
return { ok: true, to: `user:${normalized}` };
|
return `zhidui-channel:user:${normalized}`;
|
||||||
},
|
},
|
||||||
|
|
||||||
targetResolver: {
|
targetResolver: {
|
||||||
looksLikeId: (id: string) => {
|
looksLikeId: (id: string): boolean => {
|
||||||
const normalized = id.replace(/^pit-bot:/i, "");
|
const normalized = id.replace(/^pit-bot:/i, "").replace(/^zhidui-channel:/i, "");
|
||||||
return normalized.startsWith("user:") || normalized.length > 0;
|
return normalized.startsWith("user:") || normalized.length > 0;
|
||||||
},
|
},
|
||||||
hint: "user:<userId> or <userId>",
|
hint: "user:<userId> 或 <userId>",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
config: {
|
config: {
|
||||||
listAccountIds: () => listPITBotAccountIds(),
|
listAccountIds: () => listPITBotAccountIds(),
|
||||||
resolveAccount: (cfg: OpenClawConfig, accountId: string) => resolvePITBotAccount(cfg, accountId),
|
resolveAccount: (cfg: OpenClawConfig, accountId?: string | null) =>
|
||||||
|
resolvePITBotAccount(cfg, accountId ?? DEFAULT_ACCOUNT_ID),
|
||||||
defaultAccountId: () => DEFAULT_ACCOUNT_ID,
|
defaultAccountId: () => DEFAULT_ACCOUNT_ID,
|
||||||
|
|
||||||
setAccountEnabled: ({ cfg, accountId, enabled }: { cfg: OpenClawConfig; accountId: string; enabled: boolean }) => {
|
setAccountEnabled: ({ cfg, accountId, enabled }: { cfg: OpenClawConfig; accountId: string; enabled: boolean }) => {
|
||||||
@@ -84,14 +109,7 @@ export const pitBotPlugin: ChannelPlugin<ResolvedPITBotAccount> = {
|
|||||||
return cfg;
|
return cfg;
|
||||||
},
|
},
|
||||||
|
|
||||||
deleteAccount: ({ cfg, accountId }: { cfg: OpenClawConfig; accountId: string }) => {
|
deleteAccount: ({ cfg }: { cfg: OpenClawConfig }) => cfg,
|
||||||
// No-op for now
|
|
||||||
},
|
|
||||||
|
|
||||||
validateAccountConfig: (cfg: OpenClawConfig, accountId: string) => {
|
|
||||||
const account = resolvePITBotAccount(cfg, accountId);
|
|
||||||
return validateConfig(account.config);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
outbound: {
|
outbound: {
|
||||||
@@ -100,62 +118,66 @@ export const pitBotPlugin: ChannelPlugin<ResolvedPITBotAccount> = {
|
|||||||
chunkerMode: "markdown",
|
chunkerMode: "markdown",
|
||||||
textChunkLimit: 4000,
|
textChunkLimit: 4000,
|
||||||
|
|
||||||
sendText: async ({ to, text, accountId }: { to: string; text: string; accountId: string }): Promise<{ channel: string; messageId: string; error?: Error }> => {
|
sendText: async (ctx: any) => {
|
||||||
|
const { to, text, accountId, replyToId } = ctx;
|
||||||
const log = createLogger(`${MODULE}:outbound`);
|
const log = createLogger(`${MODULE}:outbound`);
|
||||||
|
const resolvedAccountId = accountId ?? DEFAULT_ACCOUNT_ID;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const gateway = gateways.get(accountId);
|
const gateway = gateways.get(resolvedAccountId);
|
||||||
if (!gateway) {
|
if (!gateway) {
|
||||||
return {
|
return {
|
||||||
channel: "pit-bot",
|
channel: "zhidui-channel",
|
||||||
messageId: "",
|
messageId: "",
|
||||||
error: new Error(`Gateway not available for account ${accountId}`),
|
error: new Error(`Gateway not available for account ${resolvedAccountId}`),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await gateway.sendText(to, text);
|
const result = await gateway.sendText(to, text, replyToId);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
channel: "pit-bot",
|
channel: "zhidui-channel",
|
||||||
messageId: result.messageId ?? "",
|
messageId: result.messageId ?? "",
|
||||||
error: result.error ? new Error(result.error) : undefined,
|
error: result.error ? new Error(result.error) : undefined,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const message = error instanceof Error ? error.message : String(error);
|
const message = error instanceof Error ? error.message : String(error);
|
||||||
log.error("sendText failed", { to, accountId, error: message });
|
log.error("sendText failed", { to, accountId: resolvedAccountId, error: message });
|
||||||
return {
|
return {
|
||||||
channel: "pit-bot",
|
channel: "zhidui-channel",
|
||||||
messageId: "",
|
messageId: "",
|
||||||
error: new Error(message),
|
error: new Error(message),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
sendMedia: async ({ to, text, mediaUrl, accountId }: { to: string; text?: string; mediaUrl: string; accountId: string }): Promise<{ channel: string; messageId: string; error?: Error }> => {
|
sendMedia: async (ctx: any) => {
|
||||||
|
const { to, text, mediaUrl, accountId, replyToId } = ctx;
|
||||||
const log = createLogger(`${MODULE}:outbound`);
|
const log = createLogger(`${MODULE}:outbound`);
|
||||||
|
const resolvedAccountId = accountId ?? DEFAULT_ACCOUNT_ID;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const gateway = gateways.get(accountId);
|
const gateway = gateways.get(resolvedAccountId);
|
||||||
if (!gateway) {
|
if (!gateway) {
|
||||||
return {
|
return {
|
||||||
channel: "pit-bot",
|
channel: "zhidui-channel",
|
||||||
messageId: "",
|
messageId: "",
|
||||||
error: new Error(`Gateway not available for account ${accountId}`),
|
error: new Error(`Gateway not available for account ${resolvedAccountId}`),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await gateway.sendMedia(to, mediaUrl ?? "", text);
|
const result = await gateway.sendMedia(to, mediaUrl ?? "", text, replyToId);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
channel: "pit-bot",
|
channel: "zhidui-channel",
|
||||||
messageId: result.messageId ?? "",
|
messageId: result.messageId ?? "",
|
||||||
error: result.error ? new Error(result.error) : undefined,
|
error: result.error ? new Error(result.error) : undefined,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const message = error instanceof Error ? error.message : String(error);
|
const message = error instanceof Error ? error.message : String(error);
|
||||||
log.error("sendMedia failed", { to, accountId, error: message });
|
log.error("sendMedia failed", { to, accountId: resolvedAccountId, error: message });
|
||||||
return {
|
return {
|
||||||
channel: "pit-bot",
|
channel: "zhidui-channel",
|
||||||
messageId: "",
|
messageId: "",
|
||||||
error: new Error(message),
|
error: new Error(message),
|
||||||
};
|
};
|
||||||
@@ -164,21 +186,26 @@ export const pitBotPlugin: ChannelPlugin<ResolvedPITBotAccount> = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
gateway: {
|
gateway: {
|
||||||
startAccount: async (ctx) => {
|
startAccount: async (ctx: any) => {
|
||||||
const { account, abortSignal } = ctx;
|
const { account, abortSignal, log, cfg, setStatus, getStatus } = ctx;
|
||||||
const log = createLogger(`${MODULE}:${account.accountId}`);
|
|
||||||
|
|
||||||
log.info("Starting gateway");
|
log?.info(`[${MODULE}:${account.accountId}] Starting gateway`);
|
||||||
|
console.log(`[${MODULE}] startAccount: accountId=${account.accountId}, routerUrl=${account.routerUrl}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const gateway = await startGateway({
|
const gateway = await startGateway({
|
||||||
account,
|
account,
|
||||||
abortSignal,
|
abortSignal,
|
||||||
|
cfg,
|
||||||
|
log: log ?? undefined,
|
||||||
|
setStatus,
|
||||||
|
getStatus,
|
||||||
onMessage: (message: PITUserMessage) => {
|
onMessage: (message: PITUserMessage) => {
|
||||||
|
// 发送消息到框架
|
||||||
ctx.emitMessage({
|
ctx.emitMessage({
|
||||||
channel: "pit-bot",
|
channel: "zhidui-channel",
|
||||||
accountId: account.accountId,
|
accountId: account.accountId,
|
||||||
chatId: `pit-bot:user:${message.userId}`,
|
chatId: `zhidui-channel:user:${message.userId}`,
|
||||||
chatType: "direct",
|
chatType: "direct",
|
||||||
senderId: message.userId,
|
senderId: message.userId,
|
||||||
text: message.content,
|
text: message.content,
|
||||||
@@ -199,18 +226,18 @@ export const pitBotPlugin: ChannelPlugin<ResolvedPITBotAccount> = {
|
|||||||
|
|
||||||
gateways.set(account.accountId, gateway);
|
gateways.set(account.accountId, gateway);
|
||||||
|
|
||||||
ctx.setStatus({
|
setStatus({
|
||||||
...ctx.getStatus(),
|
...getStatus(),
|
||||||
running: true,
|
running: true,
|
||||||
connected: true,
|
connected: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
log.info("Gateway started successfully");
|
log?.info(`[${MODULE}:${account.accountId}] Gateway started successfully`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const message = error instanceof Error ? error.message : String(error);
|
const message = error instanceof Error ? error.message : String(error);
|
||||||
log.error("Failed to start gateway", { error: message });
|
log?.error(`[${MODULE}:${account.accountId}] Failed to start gateway: ${message}`);
|
||||||
ctx.setStatus({
|
setStatus({
|
||||||
...ctx.getStatus(),
|
...getStatus(),
|
||||||
running: false,
|
running: false,
|
||||||
connected: false,
|
connected: false,
|
||||||
lastError: message,
|
lastError: message,
|
||||||
@@ -219,11 +246,10 @@ export const pitBotPlugin: ChannelPlugin<ResolvedPITBotAccount> = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
stopAccount: async (ctx) => {
|
stopAccount: async (ctx: any) => {
|
||||||
const { account } = ctx;
|
const { account, log } = ctx;
|
||||||
const log = createLogger(`${MODULE}:${account.accountId}`);
|
|
||||||
|
|
||||||
log.info("Stopping gateway");
|
log?.info(`[${MODULE}:${account.accountId}] Stopping gateway`);
|
||||||
|
|
||||||
const gateway = gateways.get(account.accountId);
|
const gateway = gateways.get(account.accountId);
|
||||||
if (gateway) {
|
if (gateway) {
|
||||||
@@ -231,22 +257,7 @@ export const pitBotPlugin: ChannelPlugin<ResolvedPITBotAccount> = {
|
|||||||
gateways.delete(account.accountId);
|
gateways.delete(account.accountId);
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("Gateway stopped");
|
log?.info(`[${MODULE}:${account.accountId}] Gateway stopped`);
|
||||||
},
|
|
||||||
|
|
||||||
restartAccount: async (ctx) => {
|
|
||||||
const { account } = ctx;
|
|
||||||
const log = createLogger(`${MODULE}:${account.accountId}`);
|
|
||||||
|
|
||||||
log.info("Restarting gateway");
|
|
||||||
|
|
||||||
const gateway = gateways.get(account.accountId);
|
|
||||||
if (gateway) {
|
|
||||||
gateway.disconnect();
|
|
||||||
gateways.delete(account.accountId);
|
|
||||||
}
|
|
||||||
|
|
||||||
await pitBotPlugin.gateway!.startAccount!(ctx);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -255,23 +266,25 @@ export const pitBotPlugin: ChannelPlugin<ResolvedPITBotAccount> = {
|
|||||||
accountId: DEFAULT_ACCOUNT_ID,
|
accountId: DEFAULT_ACCOUNT_ID,
|
||||||
running: false,
|
running: false,
|
||||||
connected: false,
|
connected: false,
|
||||||
|
lastError: null,
|
||||||
},
|
},
|
||||||
|
|
||||||
formatStatus: (runtime: PITConnectionState) => {
|
buildChannelSummary: ({ snapshot }: any) => ({
|
||||||
const parts: string[] = [];
|
configured: snapshot.configured ?? false,
|
||||||
|
running: snapshot.running ?? false,
|
||||||
|
connected: snapshot.connected ?? false,
|
||||||
|
lastError: snapshot.lastError ?? null,
|
||||||
|
}),
|
||||||
|
|
||||||
parts.push(runtime.connected ? "🟢 Connected" : "🔴 Disconnected");
|
buildAccountSnapshot: ({ account, runtime }: any) => ({
|
||||||
|
accountId: account?.accountId ?? DEFAULT_ACCOUNT_ID,
|
||||||
if (runtime.sessionId) {
|
name: account?.name,
|
||||||
parts.push(`Session: ${runtime.sessionId.slice(0, 8)}...`);
|
enabled: account?.enabled ?? false,
|
||||||
}
|
configured: Boolean(account?.routerUrl),
|
||||||
|
running: runtime?.running ?? false,
|
||||||
if (runtime.lastError) {
|
connected: runtime?.connected ?? false,
|
||||||
parts.push(`Error: ${runtime.lastError}`);
|
lastError: runtime?.lastError ?? null,
|
||||||
}
|
}),
|
||||||
|
|
||||||
return parts.join(" | ");
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ export function resolvePITBotAccount(
|
|||||||
* @param config 新配置
|
* @param config 新配置
|
||||||
*/
|
*/
|
||||||
export function applyPITBotAccountConfig(
|
export function applyPITBotAccountConfig(
|
||||||
cfg: OpenClawConfig,
|
_cfg: OpenClawConfig,
|
||||||
accountId: string,
|
accountId: string,
|
||||||
config: Partial<PITBotAccountConfig>
|
config: Partial<PITBotAccountConfig>
|
||||||
): void {
|
): void {
|
||||||
|
|||||||
Reference in New Issue
Block a user