mirror of
https://github.com/basketikun/infinite-canvas.git
synced 2026-08-04 16:14:22 +08:00
fix(agent): handle task failure by displaying user-friendly error messages in conversation flow
This commit is contained in:
@@ -327,7 +327,7 @@ function normalizeCodexNotification(method: string, params: JsonRecord): AgentEv
|
||||
const scope = codexEventScope(params);
|
||||
if (method === "thread/started") return { type: "thread.started", ...scope };
|
||||
if (method === "turn/started") return { type: "turn.started", ...scope };
|
||||
if (method === "turn/completed") return { type: "turn.completed", status: field(field(params, "turn"), "status"), usage: null, duration_ms: field(field(params, "turn"), "durationMs"), ...scope };
|
||||
if (method === "turn/completed") return { type: "turn.completed", status: field(field(params, "turn"), "status"), error: field(field(params, "turn"), "error"), usage: null, duration_ms: field(field(params, "turn"), "durationMs"), ...scope };
|
||||
if (method === "turn/plan/updated") return { type: "plan.updated", explanation: field(params, "explanation"), plan: field(params, "plan"), ...scope };
|
||||
if (method === "item/started") return { type: "item.started", item: normalizeItem(field(params, "item")), ...scope };
|
||||
if (method === "item/completed") return { type: "item.completed", item: normalizeItem(field(params, "item")), ...scope };
|
||||
|
||||
@@ -26,6 +26,7 @@ export function threadMessages(thread: unknown, planUpdates: CodexPlanUpdate[] =
|
||||
const messages: AgentHistoryMessage[] = [];
|
||||
turns.forEach((turn, turnIndex) => {
|
||||
const turnId = String(field(turn, "id") || turnIndex);
|
||||
const turnError = String(field(field(turn, "error"), "message") || "").trim();
|
||||
const planMessage = structuredPlanMessage(plansByTurn.get(turnId) || { threadId: "", turnId, explanation: stringOrNull(field(turn, "explanation")), plan: arrayValue(field(turn, "plan")) as CodexPlanUpdate["plan"], turnStatus: String(field(turn, "status") || "") });
|
||||
let planAdded = false;
|
||||
arrayValue(field(turn, "items")).forEach((item, itemIndex) => {
|
||||
@@ -72,6 +73,10 @@ export function threadMessages(thread: unknown, planUpdates: CodexPlanUpdate[] =
|
||||
if (type === "collabToolCall") messages.push({ id, role: "tool", title: "协作处理", text: "已完成协作任务", detail: { kind: "tool", status: field(item, "status") } });
|
||||
});
|
||||
if (planMessage && !planAdded) messages.push(planMessage);
|
||||
if (turnError) {
|
||||
const error = userFacingCodexError(turnError);
|
||||
messages.push({ id: `error-${turnId}`, role: "error", title: error.title, text: error.text });
|
||||
}
|
||||
});
|
||||
return messages.filter((item) => item.text).slice(-120);
|
||||
}
|
||||
@@ -101,6 +106,12 @@ function planStatus(tasks: Array<{ status: string }>, turnStatus?: string) {
|
||||
return turnStatus === "completed" ? "finished" : "inProgress";
|
||||
}
|
||||
|
||||
/** 将常见 Codex 错误转换为普通用户可理解的提示。 */
|
||||
function userFacingCodexError(message: string) {
|
||||
if (/selected model is at capacity/i.test(message)) return { title: "模型暂时繁忙", text: "当前选择的模型请求量过大,暂时无法处理。请稍后重试,或切换其他模型后再试。" };
|
||||
return { title: "任务失败", text: message || "Codex 未能完成本次任务,请稍后重试。" };
|
||||
}
|
||||
|
||||
/** 提取用户输入条目中的文本与附件占位信息。 */
|
||||
function userInputText(content: unknown) {
|
||||
return arrayValue(content)
|
||||
|
||||
@@ -145,7 +145,7 @@ export function startHttpServer() {
|
||||
/** 将当前 turn 事件固定广播到实际线程。 */
|
||||
const turnEmit = (type: string, payload: unknown) => {
|
||||
const data = payload && typeof payload === "object" && !Array.isArray(payload) ? payload as Record<string, unknown> : { value: payload };
|
||||
session.emitThread(type, threadId, data);
|
||||
session.emitThread(type, threadId, { ...data, ...(turnId ? { turn_id: turnId } : {}) });
|
||||
};
|
||||
void runCodexTurn(withAttachmentContext(prompt, attachmentRefs), turnEmit, attachments, {
|
||||
threadId,
|
||||
|
||||
Reference in New Issue
Block a user