fix(P1): ticket UUID mapping + sandbox/ticket/search fallback improvements
Deploy LangGraph Server to Azure Web App / build-and-deploy (push) Failing after 21s
Deploy LangGraph UI to Azure Static Web Apps / build-and-deploy (push) Failing after 42s

- Fix ticket_detail UUID resolution: use find() to match ticketNumber instead of tickets[0]
- Add sandbox fallback hint in coder tool-executor catch block
- Add ticket_list empty result friendly hint with suggestions
- Add google_search auto-supplement with Jina when results < 3
- Enhance enterprise tool-executor general catch with fallback_hint

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
gongzhiyong
2026-04-11 21:57:56 +08:00
co-authored by Claude Sonnet 4.6
parent 979e900a17
commit 2430fd2174
4 changed files with 36 additions and 5 deletions
@@ -96,7 +96,10 @@ export async function toolExecutorNode(
return {
role: "tool" as const,
tool_call_id: id,
content: formatToolError(name, e),
content: JSON.stringify({
error: formatToolError(name, e),
fallback_hint: "沙盒暂时不可用。请告知用户:1) 可以直接分析代码逻辑而无需执行;2) 可稍后重试;3) 可以把代码粘贴到本地环境运行。",
}),
};
}
});
@@ -171,6 +171,18 @@ export async function toolExecutorNode(
},
{ message: lastAiMessage },
);
if (tickets.length === 0) {
statusList.push({ tool: name, status: "empty", message: "未查询到工单" });
return {
role: "tool" as const,
tool_call_id: id,
content: JSON.stringify({
total: 0,
tickets: [],
hint: "未查询到工单。请告知用户可以:1) 尝试不同的查询条件;2) 检查权限;3) 确认工单系统是否有数据。",
}),
};
}
statusList.push({ tool: name, status: "ok" });
return {
role: "tool" as const,
@@ -225,7 +237,10 @@ export async function toolExecutorNode(
return {
role: "tool" as const,
tool_call_id: id,
content: formatToolError(name, e),
content: JSON.stringify({
error: formatToolError(name, e),
fallback_hint: "工具执行失败。请用中文向用户解释错误原因,并提供替代建议。",
}),
};
}
});
@@ -59,7 +59,7 @@ export async function ticketDetail(
// If ticketId looks like a ticketNumber (e.g. "TK-2026-296691"), resolve UUID first
let resolvedId = ticketId;
if (ticketId.startsWith("TK-")) {
const searchUrl = `${base}/api/tickets?ticketNumber=${encodeURIComponent(ticketId)}&pageSize=1`;
const searchUrl = `${base}/api/tickets?ticketNumber=${encodeURIComponent(ticketId)}&pageSize=50`;
const searchResp = await fetch(searchUrl, {
headers,
signal: AbortSignal.timeout(15000),
@@ -67,8 +67,9 @@ export async function ticketDetail(
if (searchResp.ok) {
const searchData = await searchResp.json();
const tickets = searchData.tickets ?? [];
if (tickets.length > 0 && tickets[0].id) {
resolvedId = tickets[0].id;
const match = tickets.find((t: Record<string, unknown>) => t.ticketNumber === ticketId);
if (match?.id) {
resolvedId = String(match.id);
}
}
}
@@ -68,6 +68,18 @@ export async function toolExecutorNode(
snippet: r.snippet,
}));
knowledgeGraph = data.knowledgeGraph;
// Auto-supplement with Jina if results < 3
if (results.length < 3) {
try {
const supplementData = await webSearch(parsed.query + " 详细信息");
const supplementResults = supplementData.results.slice(0, 3 - results.length).map((r) => ({
title: r.title ?? "",
url: r.url ?? "",
snippet: (r.description ?? r.content ?? "").slice(0, 200),
}));
results = [...results, ...supplementResults];
} catch { /* supplement search failed silently */ }
}
} catch {
// google_search failed, fallback to web_search_deep (Jina)
console.warn(`[fallback] google_search failed, trying web_search_deep`);