forked from bai/curriculum-project-hub
fix(hub): 稳定 Feishu trigger 集成测试
This commit is contained in:
@@ -119,6 +119,8 @@ export async function runAgent(req: RunRequest): Promise<RunResult> {
|
||||
let sdkSessionId: string | undefined;
|
||||
let error: string | undefined;
|
||||
try {
|
||||
await persistAgentMessage(req, "user", req.prompt);
|
||||
|
||||
const options: Parameters<typeof query>[0]["options"] = {
|
||||
cwd: req.project.workspaceDir,
|
||||
allowedTools: ["Read", "Write", "Bash", "Glob", "Grep"],
|
||||
@@ -174,14 +176,17 @@ export async function runAgent(req: RunRequest): Promise<RunResult> {
|
||||
const msg = (message as SDKAssistantMessage).message;
|
||||
await heartbeat();
|
||||
numTurns++;
|
||||
let assistantText = "";
|
||||
for (const block of msg.content) {
|
||||
if (block.type === "text" && typeof block.text === "string") {
|
||||
fullText += block.text;
|
||||
assistantText += block.text;
|
||||
}
|
||||
if (block.type === "tool_use") {
|
||||
onStream?.({ type: "tool-end", toolName: block.name });
|
||||
}
|
||||
}
|
||||
await persistAgentMessage(req, "assistant", assistantText);
|
||||
if (msg.usage !== undefined) {
|
||||
usage.inputTokens += msg.usage.input_tokens ?? 0;
|
||||
usage.outputTokens += msg.usage.output_tokens ?? 0;
|
||||
@@ -219,3 +224,20 @@ export async function runAgent(req: RunRequest): Promise<RunResult> {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async function persistAgentMessage(req: RunRequest, role: string, content: string): Promise<void> {
|
||||
if (content === "") return;
|
||||
try {
|
||||
await req.prisma.agentMessage.create({
|
||||
data: {
|
||||
sessionId: req.sessionId,
|
||||
runId: req.runId,
|
||||
role,
|
||||
content,
|
||||
attachments: [],
|
||||
},
|
||||
});
|
||||
} catch {
|
||||
// Best-effort projection: a history write failure must not break the run.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import { z } from "zod";
|
||||
import type { FastifyBaseLogger } from "fastify";
|
||||
import { sendText, sendTextMessage, patchTextMessage, reactToMessage, downloadMessageFile, type FeishuRuntime, type MessageReceiveEvent } from "./client.js";
|
||||
import type { ModelRegistry } from "../agent/models.js";
|
||||
import { runAgent, type ProjectContext } from "../agent/runner.js";
|
||||
import { runAgent as defaultRunAgent, type ProjectContext, type RunRequest, type RunResult } from "../agent/runner.js";
|
||||
import { acquireLock, currentLockRunId, releaseLock } from "../lock.js";
|
||||
import { canTriggerAgent, canTriggerRole } from "../permission.js";
|
||||
import { writeAudit } from "../audit.js";
|
||||
@@ -24,6 +24,7 @@ interface TriggerDeps {
|
||||
readonly prisma: PrismaClient;
|
||||
readonly models: ModelRegistry;
|
||||
readonly logger: FastifyBaseLogger;
|
||||
readonly runAgent?: (req: RunRequest) => Promise<RunResult>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -33,6 +34,7 @@ interface TriggerDeps {
|
||||
*/
|
||||
export function makeTriggerHandler(deps: TriggerDeps) {
|
||||
return async (event: MessageReceiveEvent, rt: FeishuRuntime): Promise<void> => {
|
||||
const runAgent = deps.runAgent ?? defaultRunAgent;
|
||||
const msg = event.message;
|
||||
const sender = event.sender;
|
||||
void sender; // sender→user mapping is OPEN (principal sub-typology)
|
||||
@@ -165,6 +167,7 @@ export function makeTriggerHandler(deps: TriggerDeps) {
|
||||
const existing = await currentLockRunId(deps.prisma, projectId);
|
||||
if (existing !== null) {
|
||||
await reactToMessage(rt, msg.message_id, "OnIt");
|
||||
await sendText(rt, chatId, "项目正在处理中,请稍候。");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -251,6 +254,7 @@ export function makeTriggerHandler(deps: TriggerDeps) {
|
||||
});
|
||||
await writeAudit(deps.prisma, { runId: run.id, projectId, action: "run.lock_race", metadata: {} });
|
||||
await reactToMessage(rt, msg.message_id, "OnIt");
|
||||
await sendText(rt, chatId, "项目正在处理中,请稍候。");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -342,7 +346,11 @@ export function makeTriggerHandler(deps: TriggerDeps) {
|
||||
await writeAudit(deps.prisma, { runId: run.id, projectId, action: "run.failed", metadata: { error: String(e) } });
|
||||
})
|
||||
.finally(async () => {
|
||||
await releaseLock(deps.prisma, run.id);
|
||||
try {
|
||||
await releaseLock(deps.prisma, run.id);
|
||||
} catch (e) {
|
||||
deps.logger.warn({ runId: run.id, err: e instanceof Error ? e.message : String(e) }, "trigger: could not release lock");
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user