mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-06 06:41:08 +00:00
refactor(feishu): lazy-load subagent hooks
This commit is contained in:
@@ -6,7 +6,6 @@ import { registerFeishuDocTools } from "./src/docx.js";
|
||||
import { registerFeishuDriveTools } from "./src/drive.js";
|
||||
import { registerFeishuPermTools } from "./src/perm.js";
|
||||
import { setFeishuRuntime } from "./src/runtime.js";
|
||||
import { registerFeishuSubagentHooks } from "./src/subagent-hooks.js";
|
||||
import { registerFeishuWikiTools } from "./src/wiki.js";
|
||||
|
||||
export { feishuPlugin } from "./src/channel.js";
|
||||
@@ -46,14 +45,21 @@ export {
|
||||
} from "./src/mention.js";
|
||||
|
||||
type MonitorFeishuProvider = typeof import("./src/monitor.js").monitorFeishuProvider;
|
||||
type FeishuSubagentHooksModule = typeof import("./src/subagent-hooks.js");
|
||||
|
||||
let feishuMonitorPromise: Promise<typeof import("./src/monitor.js")> | null = null;
|
||||
let feishuSubagentHooksPromise: Promise<FeishuSubagentHooksModule> | null = null;
|
||||
|
||||
function loadFeishuMonitorModule() {
|
||||
feishuMonitorPromise ??= import("./src/monitor.js");
|
||||
return feishuMonitorPromise;
|
||||
}
|
||||
|
||||
function loadFeishuSubagentHooksModule() {
|
||||
feishuSubagentHooksPromise ??= import("./src/subagent-hooks.js");
|
||||
return feishuSubagentHooksPromise;
|
||||
}
|
||||
|
||||
export async function monitorFeishuProvider(
|
||||
...args: Parameters<MonitorFeishuProvider>
|
||||
): ReturnType<MonitorFeishuProvider> {
|
||||
@@ -68,7 +74,18 @@ export default defineChannelPluginEntry({
|
||||
plugin: feishuPlugin,
|
||||
setRuntime: setFeishuRuntime,
|
||||
registerFull(api) {
|
||||
registerFeishuSubagentHooks(api);
|
||||
api.on("subagent_spawning", async (event, ctx) => {
|
||||
const { handleFeishuSubagentSpawning } = await loadFeishuSubagentHooksModule();
|
||||
return await handleFeishuSubagentSpawning(event, ctx);
|
||||
});
|
||||
api.on("subagent_delivery_target", async (event) => {
|
||||
const { handleFeishuSubagentDeliveryTarget } = await loadFeishuSubagentHooksModule();
|
||||
return await handleFeishuSubagentDeliveryTarget(event);
|
||||
});
|
||||
api.on("subagent_ended", async (event) => {
|
||||
const { handleFeishuSubagentEnded } = await loadFeishuSubagentHooksModule();
|
||||
await handleFeishuSubagentEnded(event);
|
||||
});
|
||||
registerFeishuDocTools(api);
|
||||
registerFeishuChatTools(api);
|
||||
registerFeishuWikiTools(api);
|
||||
|
||||
@@ -232,110 +232,151 @@ function resolveMatchingChildBinding(params: {
|
||||
return childBindings.length === 1 ? childBindings[0] : null;
|
||||
}
|
||||
|
||||
export function registerFeishuSubagentHooks(api: OpenClawPluginApi) {
|
||||
api.on("subagent_spawning", async (event, ctx) => {
|
||||
if (!event.threadRequested) {
|
||||
return;
|
||||
}
|
||||
const requesterChannel = event.requester?.channel?.trim().toLowerCase();
|
||||
if (requesterChannel !== "feishu") {
|
||||
return;
|
||||
}
|
||||
type FeishuSubagentContext = {
|
||||
requesterSessionKey?: string;
|
||||
};
|
||||
|
||||
const manager = getFeishuThreadBindingManager(event.requester?.accountId);
|
||||
if (!manager) {
|
||||
return {
|
||||
status: "error" as const,
|
||||
error:
|
||||
"Feishu current-conversation binding is unavailable because the Feishu account monitor is not active.",
|
||||
};
|
||||
}
|
||||
type FeishuSubagentSpawningEvent = {
|
||||
threadRequested?: boolean;
|
||||
requester?: {
|
||||
channel?: string;
|
||||
accountId?: string;
|
||||
to?: string;
|
||||
threadId?: string | number;
|
||||
};
|
||||
childSessionKey: string;
|
||||
agentId?: string;
|
||||
label?: string;
|
||||
};
|
||||
|
||||
const conversation = resolveFeishuRequesterConversation({
|
||||
accountId: event.requester?.accountId,
|
||||
to: event.requester?.to,
|
||||
threadId: event.requester?.threadId,
|
||||
requesterSessionKey: ctx.requesterSessionKey,
|
||||
});
|
||||
if (!conversation) {
|
||||
return {
|
||||
status: "error" as const,
|
||||
error:
|
||||
"Feishu current-conversation binding is only available in direct messages or topic conversations.",
|
||||
};
|
||||
}
|
||||
type FeishuSubagentDeliveryTargetEvent = {
|
||||
expectsCompletionMessage?: boolean;
|
||||
requesterOrigin?: {
|
||||
channel?: string;
|
||||
accountId?: string;
|
||||
to?: string;
|
||||
threadId?: string | number;
|
||||
};
|
||||
childSessionKey: string;
|
||||
requesterSessionKey?: string;
|
||||
};
|
||||
|
||||
try {
|
||||
const binding = manager.bindConversation({
|
||||
conversationId: conversation.conversationId,
|
||||
parentConversationId: conversation.parentConversationId,
|
||||
targetKind: "subagent",
|
||||
targetSessionKey: event.childSessionKey,
|
||||
metadata: {
|
||||
agentId: event.agentId,
|
||||
label: event.label,
|
||||
boundBy: "system",
|
||||
deliveryTo: event.requester?.to,
|
||||
deliveryThreadId:
|
||||
event.requester?.threadId != null && event.requester.threadId !== ""
|
||||
? String(event.requester.threadId)
|
||||
: undefined,
|
||||
},
|
||||
});
|
||||
if (!binding) {
|
||||
return {
|
||||
status: "error" as const,
|
||||
error:
|
||||
"Unable to bind this Feishu conversation to the spawned subagent session. Session mode is unavailable for this target.",
|
||||
};
|
||||
}
|
||||
return {
|
||||
status: "ok" as const,
|
||||
threadBindingReady: true,
|
||||
};
|
||||
} catch (err) {
|
||||
return {
|
||||
status: "error" as const,
|
||||
error: `Feishu conversation bind failed: ${summarizeError(err)}`,
|
||||
};
|
||||
}
|
||||
type FeishuSubagentEndedEvent = {
|
||||
accountId?: string;
|
||||
targetSessionKey: string;
|
||||
};
|
||||
|
||||
export async function handleFeishuSubagentSpawning(
|
||||
event: FeishuSubagentSpawningEvent,
|
||||
ctx: FeishuSubagentContext,
|
||||
) {
|
||||
if (!event.threadRequested) {
|
||||
return;
|
||||
}
|
||||
const requesterChannel = event.requester?.channel?.trim().toLowerCase();
|
||||
if (requesterChannel !== "feishu") {
|
||||
return;
|
||||
}
|
||||
|
||||
const manager = getFeishuThreadBindingManager(event.requester?.accountId);
|
||||
if (!manager) {
|
||||
return {
|
||||
status: "error" as const,
|
||||
error:
|
||||
"Feishu current-conversation binding is unavailable because the Feishu account monitor is not active.",
|
||||
};
|
||||
}
|
||||
|
||||
const conversation = resolveFeishuRequesterConversation({
|
||||
accountId: event.requester?.accountId,
|
||||
to: event.requester?.to,
|
||||
threadId: event.requester?.threadId,
|
||||
requesterSessionKey: ctx.requesterSessionKey,
|
||||
});
|
||||
if (!conversation) {
|
||||
return {
|
||||
status: "error" as const,
|
||||
error:
|
||||
"Feishu current-conversation binding is only available in direct messages or topic conversations.",
|
||||
};
|
||||
}
|
||||
|
||||
api.on("subagent_delivery_target", (event) => {
|
||||
if (!event.expectsCompletionMessage) {
|
||||
return;
|
||||
}
|
||||
const requesterChannel = event.requesterOrigin?.channel?.trim().toLowerCase();
|
||||
if (requesterChannel !== "feishu") {
|
||||
return;
|
||||
}
|
||||
|
||||
const binding = resolveMatchingChildBinding({
|
||||
accountId: event.requesterOrigin?.accountId,
|
||||
childSessionKey: event.childSessionKey,
|
||||
requesterSessionKey: event.requesterSessionKey,
|
||||
requesterOrigin: {
|
||||
to: event.requesterOrigin?.to,
|
||||
threadId: event.requesterOrigin?.threadId,
|
||||
try {
|
||||
const binding = manager.bindConversation({
|
||||
conversationId: conversation.conversationId,
|
||||
parentConversationId: conversation.parentConversationId,
|
||||
targetKind: "subagent",
|
||||
targetSessionKey: event.childSessionKey,
|
||||
metadata: {
|
||||
agentId: event.agentId,
|
||||
label: event.label,
|
||||
boundBy: "system",
|
||||
deliveryTo: event.requester?.to,
|
||||
deliveryThreadId:
|
||||
event.requester?.threadId != null && event.requester.threadId !== ""
|
||||
? String(event.requester.threadId)
|
||||
: undefined,
|
||||
},
|
||||
});
|
||||
if (!binding) {
|
||||
return;
|
||||
return {
|
||||
status: "error" as const,
|
||||
error:
|
||||
"Unable to bind this Feishu conversation to the spawned subagent session. Session mode is unavailable for this target.",
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
origin: resolveFeishuDeliveryOrigin({
|
||||
conversationId: binding.conversationId,
|
||||
parentConversationId: binding.parentConversationId,
|
||||
accountId: binding.accountId,
|
||||
deliveryTo: binding.deliveryTo,
|
||||
deliveryThreadId: binding.deliveryThreadId,
|
||||
}),
|
||||
status: "ok" as const,
|
||||
threadBindingReady: true,
|
||||
};
|
||||
});
|
||||
|
||||
api.on("subagent_ended", (event) => {
|
||||
const manager = getFeishuThreadBindingManager(event.accountId);
|
||||
manager?.unbindBySessionKey(event.targetSessionKey);
|
||||
});
|
||||
} catch (err) {
|
||||
return {
|
||||
status: "error" as const,
|
||||
error: `Feishu conversation bind failed: ${summarizeError(err)}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function handleFeishuSubagentDeliveryTarget(event: FeishuSubagentDeliveryTargetEvent) {
|
||||
if (!event.expectsCompletionMessage) {
|
||||
return;
|
||||
}
|
||||
const requesterChannel = event.requesterOrigin?.channel?.trim().toLowerCase();
|
||||
if (requesterChannel !== "feishu") {
|
||||
return;
|
||||
}
|
||||
|
||||
const binding = resolveMatchingChildBinding({
|
||||
accountId: event.requesterOrigin?.accountId,
|
||||
childSessionKey: event.childSessionKey,
|
||||
requesterSessionKey: event.requesterSessionKey,
|
||||
requesterOrigin: {
|
||||
to: event.requesterOrigin?.to,
|
||||
threadId: event.requesterOrigin?.threadId,
|
||||
},
|
||||
});
|
||||
if (!binding) {
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
origin: resolveFeishuDeliveryOrigin({
|
||||
conversationId: binding.conversationId,
|
||||
parentConversationId: binding.parentConversationId,
|
||||
accountId: binding.accountId,
|
||||
deliveryTo: binding.deliveryTo,
|
||||
deliveryThreadId: binding.deliveryThreadId,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
export function handleFeishuSubagentEnded(event: FeishuSubagentEndedEvent) {
|
||||
const manager = getFeishuThreadBindingManager(event.accountId);
|
||||
manager?.unbindBySessionKey(event.targetSessionKey);
|
||||
}
|
||||
|
||||
export function registerFeishuSubagentHooks(api: OpenClawPluginApi) {
|
||||
api.on("subagent_spawning", (event, ctx) => handleFeishuSubagentSpawning(event, ctx));
|
||||
api.on("subagent_delivery_target", (event) => handleFeishuSubagentDeliveryTarget(event));
|
||||
api.on("subagent_ended", (event) => handleFeishuSubagentEnded(event));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user