| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- /**
- * Visit 链辅助工具(DAG / AGENTIC 模式统一)。
- *
- * <p>WorkflowEditor / RunHistory 两处共用:实时运行 + 历史回放均渲染同一组 Visit 卡片,
- * 字段解析逻辑(outputJson / variablesJson / decisionJson / logsJson 反序列化、未知节点类型兜底)
- * 抽到此工具,避免两份实现漂移。</p>
- *
- * <p>对应设计文档 {@code docs/plans/agentic-workflow-plan.md} §3 数据结构。</p>
- */
- import { unwrapNodeOutput } from '../composables/useWorkflowRunner'
- import {
- extractStreamingThinking,
- extractToolHistory,
- extractLatestTodos,
- extractNonThinkingLogs
- } from './runResultReplay'
- /**
- * 未知节点类型的兜底配置(灰色),避免 nodeTypeInfo 查不到时模板渲染崩。
- * 各页面在 nodeTypeInfo 上层做 lookup 时使用。
- */
- export const UNKNOWN_NODE_TYPE_INFO = Object.freeze({
- color: '#6b7280',
- typeLabel: '未知',
- icon: null
- })
- /**
- * Visit.outputJson 是节点输出 envelope 序列化后的 JSON 字符串;
- * unwrapNodeOutput 期望对象,故先 parse 再 unwrap。
- *
- * @param {string|object|null} jsonStr
- * @returns {object|null} unwrap 后的 data 字段;解析失败或为空返回 null
- */
- export function parseVisitOutput(jsonStr) {
- if (!jsonStr) return null
- try {
- const obj = typeof jsonStr === 'string' ? JSON.parse(jsonStr) : jsonStr
- return unwrapNodeOutput(obj)
- } catch { return null }
- }
- /**
- * Visit.variablesJson 是工作区变量快照(含初始输入 + 此前所有访问节点输出,
- * 按 nodeId__varName 形式存放)。
- *
- * @param {string|object|null} jsonStr
- * @returns {Record<string, any>} 解析失败或非对象返回空对象
- */
- export function parseVisitVariables(jsonStr) {
- if (!jsonStr) return {}
- try {
- const obj = typeof jsonStr === 'string' ? JSON.parse(jsonStr) : jsonStr
- return obj && typeof obj === 'object' ? obj : {}
- } catch { return {} }
- }
- /**
- * Visit.decisionJson 是跳转元数据。当前仅记录"非画布跳转"标志:
- * - null / 空 → 按画布连线跳转(与 DAG 一致,前端不展示"来自 X"徽章)
- * - {"offCanvas":true} → AGENTIC 自由跳转(前端展示"来自 X"徽章)
- *
- * <p>兼容字段:未来若同时记录 Planner 决策(nextNodeId / reason),扩展本函数即可。</p>
- *
- * @param {string|object|null} jsonStr
- * @returns {{offCanvas: boolean, nextNodeId: string|null, reason: string}|null}
- */
- export function parseVisitDecision(jsonStr) {
- if (!jsonStr) return null
- try {
- const obj = typeof jsonStr === 'string' ? JSON.parse(jsonStr) : jsonStr
- if (!obj || typeof obj !== 'object') return null
- return {
- offCanvas: obj.offCanvas === true,
- nextNodeId: obj.nextNodeId || obj.next || null,
- reason: obj.reason || ''
- }
- } catch { return null }
- }
- /**
- * 把后端 WorkflowRunVisit 还原为前端 Visit 卡片格式(含 streamingThinking / toolHistory / todos / logs)。
- *
- * <p>用于 RunHistory 页面回放,与 WorkflowEditor 实时态 Visit 字段一致:
- * - 元数据:visitUuid / nodeId / nodeType / nodeLabel / iterSeq / fromVisitUuid / fromNodeId / sortOrder
- * - 结果:status / output / logs / contextSnapshot / variablesJson / outputJson / errorMsg
- * - 流式回放:从 logsJson 还原 streamingThinking / toolHistory / todos
- * - 已完成态:currentStatus / currentTool 留空</p>
- *
- * @param {Object} visit 后端 WorkflowRunVisit(含 outputJson / variablesJson / logsJson / decisionJson)
- * @param {{color:string,typeLabel:string,icon?:any}} info 节点类型信息(由调用方查 nodeTypeInfo 后传入)
- * @returns {Object} 前端 Visit 卡片格式
- */
- export function buildReplayVisit(visit, info) {
- const v = visit || {}
- const logsJson = v.logsJson || ''
- const decision = parseVisitDecision(v.decisionJson)
- return {
- visitUuid: v.visitUuid || null,
- nodeId: v.nodeId,
- nodeType: v.nodeType,
- nodeLabel: v.nodeLabel || v.nodeId || '节点',
- iterSeq: v.iterSeq || 1,
- fromVisitUuid: v.fromVisitUuid || null,
- fromNodeId: v.fromNodeId || null,
- // offCanvas:仅当 decisionJson 显式标记为 true 才为 true(按画布走或起始节点均为 false)
- offCanvas: decision?.offCanvas === true,
- sortOrder: v.sortOrder ?? 0,
- status: (v.status || '').toLowerCase(),
- errorMsg: v.errorMsg || null,
- // output:保留 envelope(envelope 在 useWorkflowRunner.unwrapNodeOutput 中解封)
- output: v.outputJson ? safeParse(v.outputJson) : null,
- variablesJson: v.variablesJson || '{}',
- outputJson: v.outputJson || null,
- contextSnapshot: null, // Visit 不存 contextSnapshot;上下文展示回退到 variablesJson
- // 流式回放:从 logsJson 还原
- streamingThinking: extractStreamingThinking(logsJson),
- toolHistory: extractToolHistory(logsJson),
- todos: extractLatestTodos(logsJson),
- logs: extractNonThinkingLogs(logsJson),
- // 已完成态无实时
- currentStatus: '',
- currentTool: null,
- // 视觉信息(由调用方注入)
- color: info?.color || '#6b7280',
- typeLabel: info?.typeLabel || '未知'
- }
- }
- function safeParse(str) {
- try { return JSON.parse(str) } catch { return null }
- }
|