forked from EduCraft/curriculum-project-hub
fix: reply to Feishu trigger messages
This commit is contained in:
@@ -25,6 +25,7 @@ import {
|
||||
type CardActionEvent,
|
||||
type FeishuRuntime,
|
||||
type MessageReceiveEvent,
|
||||
type SendMessageOptions,
|
||||
} from "./client.js";
|
||||
import { runAgent as defaultRunAgent, type ProjectContext, type RunRequest, type RunResult } from "../agent/runner.js";
|
||||
import type { RuntimeSettings } from "../settings/runtime.js";
|
||||
@@ -124,6 +125,7 @@ export function makeTriggerHandler(deps: TriggerDeps): TriggerHandler {
|
||||
options: { readonly queueIfLocked?: boolean } = {},
|
||||
): Promise<StartAgentRunOutcome> {
|
||||
const { msg, rt, chatId, projectId, senderOpenId, actor } = context;
|
||||
const sendOptions = sendOptionsForTriggerMessage(msg);
|
||||
const queueIfLocked = options.queueIfLocked ?? true;
|
||||
|
||||
// ADR-0002: if locked by another run, enqueue the trigger for this project.
|
||||
@@ -169,7 +171,7 @@ export function makeTriggerHandler(deps: TriggerDeps): TriggerHandler {
|
||||
sender: await senderAuditMetadata(rt, senderOpenId),
|
||||
},
|
||||
});
|
||||
await sendText(rt, chatId, `无权限使用角色 ${roleId}。`);
|
||||
await sendText(rt, chatId, `无权限使用角色 ${roleId}。`, sendOptions);
|
||||
return "skipped";
|
||||
}
|
||||
const role = models.role(roleId);
|
||||
@@ -279,7 +281,14 @@ export function makeTriggerHandler(deps: TriggerDeps): TriggerHandler {
|
||||
// Streaming agent card: single interactive card through the full run
|
||||
// lifecycle (thinking → tool calls → streaming text → complete).
|
||||
// Shows tool-use trace panel + reasoning panel + answer text.
|
||||
const card = new StreamingAgentCard({ runId: run.id, rt, chatId, patchIntervalMs: undefined, maxMessageLength: undefined });
|
||||
const card = new StreamingAgentCard({
|
||||
runId: run.id,
|
||||
rt,
|
||||
chatId,
|
||||
sendOptions,
|
||||
patchIntervalMs: undefined,
|
||||
maxMessageLength: undefined,
|
||||
});
|
||||
const deliveredFiles: string[] = [];
|
||||
const fileDeliveryMcpServer = createFileDeliveryMcpServer({
|
||||
rt,
|
||||
@@ -287,6 +296,7 @@ export function makeTriggerHandler(deps: TriggerDeps): TriggerHandler {
|
||||
projectId,
|
||||
runId: run.id,
|
||||
workspaceDir: project.workspaceDir,
|
||||
sendOptions,
|
||||
approvalManager,
|
||||
onDelivered: (path) => {
|
||||
deliveredFiles.push(path);
|
||||
@@ -422,11 +432,16 @@ export function makeTriggerHandler(deps: TriggerDeps): TriggerHandler {
|
||||
});
|
||||
if (position === 0) {
|
||||
await reactToMessage(context.rt, context.msg.message_id, "OnIt");
|
||||
await sendText(context.rt, context.chatId, "队列已满,请稍后再试");
|
||||
await sendText(context.rt, context.chatId, "队列已满,请稍后再试", sendOptionsForTriggerMessage(context.msg));
|
||||
return "rejected";
|
||||
}
|
||||
|
||||
await sendText(context.rt, context.chatId, `已加入队列(第${position}位),当前处理完成后将自动开始`);
|
||||
await sendText(
|
||||
context.rt,
|
||||
context.chatId,
|
||||
`已加入队列(第${position}位),当前处理完成后将自动开始`,
|
||||
sendOptionsForTriggerMessage(context.msg),
|
||||
);
|
||||
return "queued";
|
||||
}
|
||||
|
||||
@@ -614,7 +629,7 @@ export function makeTriggerHandler(deps: TriggerDeps): TriggerHandler {
|
||||
if (senderOpenId === "") {
|
||||
deps.logger.warn({ projectId, chatId }, "feishu trigger: sender has no open_id, denying");
|
||||
await writeAudit(deps.prisma, { projectId, action: "trigger.denied", metadata: { reason: "missing open_id" } });
|
||||
await sendText(rt, chatId, "无法识别发送者,拒绝触发。");
|
||||
await sendText(rt, chatId, "无法识别发送者,拒绝触发。", sendOptionsForTriggerMessage(msg));
|
||||
return;
|
||||
}
|
||||
const actor = { feishuOpenId: senderOpenId, chatId };
|
||||
@@ -634,7 +649,7 @@ export function makeTriggerHandler(deps: TriggerDeps): TriggerHandler {
|
||||
sender: await senderAuditMetadata(rt, senderOpenId),
|
||||
},
|
||||
});
|
||||
await sendText(rt, chatId, "无权限触发。");
|
||||
await sendText(rt, chatId, "无权限触发。", sendOptionsForTriggerMessage(msg));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -689,14 +704,14 @@ export function makeTriggerHandler(deps: TriggerDeps): TriggerHandler {
|
||||
if (helpSubcommandTarget !== null) {
|
||||
// Help is generated on demand because role/tool configuration is runtime data.
|
||||
const models = await deps.settings.modelRegistry({ projectId });
|
||||
await sendText(rt, chatId, formatSlashHelpTarget(helpSubcommandTarget, models, slashCommands));
|
||||
await sendText(rt, chatId, formatSlashHelpTarget(helpSubcommandTarget, models, slashCommands), sendOptionsForTriggerMessage(msg));
|
||||
return;
|
||||
}
|
||||
|
||||
if (invocation !== null) {
|
||||
const slashCommand = slashCommands.get(invocation.name);
|
||||
if (slashCommand !== undefined) {
|
||||
await slashCommand.run({ invocation, projectId, chatId, rt });
|
||||
await slashCommand.run({ invocation, projectId, chatId, rt, sendOptions: sendOptionsForTriggerMessage(msg) });
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -772,6 +787,10 @@ function nonEmpty(value: string | undefined): string | undefined {
|
||||
return value === undefined || value === "" ? undefined : value;
|
||||
}
|
||||
|
||||
function sendOptionsForTriggerMessage(msg: MessageReceiveEvent["message"]): SendMessageOptions {
|
||||
return { replyToMessageId: msg.message_id };
|
||||
}
|
||||
|
||||
function approvalActionFromValue(value: unknown): string | null {
|
||||
if (typeof value === "string") {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user