fix(ai写作): 技能检索稳定接收数据(复用参考文献提取+截断抢救+上限早停)

- 复用主智能体「参考文献」模式的提取逻辑(deerflow.runtime.references)解析技能JSON,字段并集兼容
- bash输出中间截断时逐条抢救完整记录对象,不再因大JSON解析失败而全丢
- 所有退出路径(超时/递归上限/异常)都从tool输出收割,不依赖模型最终汇总
- 达到max_materials上限即停止驱动模型,修复步骤条爆100+条/素材超额
- 步骤条实时显示每次检索获得多少条数据
- 内网兜底:与技能并行预跑、响应解析兼容两套接口字段、0结果换简单检索词重试、超时放宽到10分钟

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
fengxiangdebaoziandClaude Opus 4.8 committed 2026-06-25 17:05:09 +08:00
1 parent 893f1e6933
commit 854de9b43c
7 files changed
+340 -162

No files matched your search

+18 -8
View File
@@ -20,7 +20,7 @@ import {
readCopTaskDetail,
resolveTaskDeeplinkTarget,
} from "@/core/auth/task-deeplink";
import { readUserInfo } from "@/strategy-components/lib/light-app";
import { readUserInfo, resolveRouteParamValue } from "@/strategy-components/lib/light-app";
/** 「大屏绘制」独立页应用内路由(深链「上一步」默认指向它,跳转追加 ?taskId=)。 */
export const DASHBOARD_AGENT_ROUTE = "/page/strategy/dashboard-agent";
@@ -106,17 +106,20 @@ export interface TaskButton {
sortOrder: number;
}
/** 运行时解析单个登录参数的值(``other`` 取字面值,否则从 ``userInfo`` 取 ``source`` 字段)。 */
/**
* 运行时解析单个登录参数的值——**与「应用管理」完全一致**:直接复用 light-app 的
* ``resolveRouteParamValue``(把本按钮的登录参数适配成 ``login`` 类型的路由参数),
* 保证取值来源/逻辑跟轻应用一模一样(``other`` 取字面 ``customValue``,否则从
* ``userInfo`` 取 ``source`` 字段)。
*/
function resolveLoginParamValue(
p: TaskButtonLoginParam,
userInfo: Record<string, unknown>,
): string {
if (p.source === "other") return p.customValue ?? "";
if (p.source) {
const value = userInfo[p.source];
return value == null ? "" : String(value);
}
return "";
return resolveRouteParamValue(
{ key: p.key, paramType: "login", source: p.source, customValue: p.customValue },
userInfo,
);
}
/** 内部切换可选的目标业务(``business`` 类型按钮的下拉项)。 */
@@ -311,13 +314,20 @@ export async function runTaskButton(btn: TaskButton, ctx: RunTaskButtonCtx): Pro
if (base.startsWith("/") && !base.startsWith("//")) {
if (btn.openMode === "blank") {
const full = `${window.location.origin}${window.location.pathname}#${url}`;
// 打印实际打开地址,便于排查登录参数/拼接问题。
console.info(`[task-button] 「${btn.label}」内部路由(新标签) → ${full}`);
window.open(full, "_blank", "noopener,noreferrer");
} else {
console.info(`[task-button] 「${btn.label}」内部路由(同窗) → ${url}`);
ctx.navigate(url);
}
return;
}
// 外链:self=当前窗口(嵌入态即当前 iframe);否则 blank=新窗口(默认)。
// 打印最终跳转地址(含追加的 id / 登录参数),便于排查问题。
console.info(
`[task-button] 「${btn.label}」外链(${btn.openMode === "self" ? "当前窗口" : "新窗口"}) → ${url}`,
);
if (btn.openMode === "self") {
window.location.assign(url);
} else {
@@ -2265,6 +2265,7 @@ export default function RoundtablePlanningPage() {
<TaskJumpBar
business={BUSINESS_CODE_TO_TASK_BUSINESS[prefillRef.current.businessCode]}
taskId={prefillRef.current.taskId}
actionId={prefillRef.current.actionId}
roundtable
/>
)}
@@ -44,10 +44,19 @@ import { TaskPurposeDialog } from "@/strategy-components/components/task-compone
export function TaskJumpBar({
business,
taskId,
actionId,
roundtable,
}: {
business: TaskBusiness;
taskId: string;
/**
* xdfx 深链原始「行动id」(URL ?taskId= 传入值,与解析后的任务id 不同)。
* 单智能体问答(``TaskFxWorkspace``)由 ``persistTaskContext`` 写进 ``TaskContext``,
* 故省略时回退 ``readTaskContext()?.actionId``;多智能体会商(``RoundtablePlanningPage``)
* 不写 ``TaskContext``(只在 ``roundtablePrefill`` 里),必须**显式**把 ``prefill.actionId``
* 传进来,否则「追加行动id」的按钮会拿不到行动id 而回退任务id。
*/
actionId?: string;
/** 多智能体会商深链模式:不展示「编辑」与「弹框查看」(purpose)按钮。 */
roundtable?: boolean;
}) {
@@ -73,10 +82,13 @@ export function TaskJumpBar({
// 目的树弹框(purpose 类型按钮)由组件层打开。
const [purposeOpen, setPurposeOpen] = useState(false);
// xdfx:深链原始「行动id」(与解析后的任务id 不同才算真行动id),弹框据此换回任务id 再查目的。
const ctxActionId = readTaskContext()?.actionId;
// xdfx 深链原始「行动id」:会商模式由 prop 显式传入;单智能体回退 TaskContext。
const effectiveActionId = actionId ?? readTaskContext()?.actionId;
// 与解析后的任务id 不同才算真行动id,弹框据此换回任务id 再查目的。
const purposeActionId =
business === "xdfx" && ctxActionId && ctxActionId !== taskId ? ctxActionId : undefined;
business === "xdfx" && effectiveActionId && effectiveActionId !== taskId
? effectiveActionId
: undefined;
if (jumpButtons.length === 0) return null;
// 深链 `hideJump=1`(外部 iframe 套用时):整条跳转栏隐藏——底部「下一步」等按钮 +
@@ -90,7 +102,7 @@ export function TaskJumpBar({
}
void runTaskButton(btn, {
taskId,
actionId: readTaskContext()?.actionId,
actionId: effectiveActionId,
navigate,
onError: (m) => toast.error(m),
});