'use strict'; // 轻量 trace 明细:LLM/工具步骤写入 agent_trace_steps(瀑布图数据源)。 // TRACE_ENABLED=false 时不写,零开销。 function createTraceWriter(pool, enabled = false) { let ready = null; function ensureTable() { if (!pool) return Promise.resolve(); if (!ready) { ready = pool.query(` CREATE TABLE IF NOT EXISTS agent_trace_steps ( id BIGSERIAL PRIMARY KEY, trace_id TEXT, conv_id TEXT, step_type TEXT, phase TEXT, turn INTEGER, model TEXT, tool_name TEXT, prompt_tokens INTEGER, completion_tokens INTEGER, duration_ms INTEGER, finish_reason TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ) `).catch((e) => console.error('[trace_writer] table init error:', e.message.slice(0, 120))); } return ready; } async function writeSteps(steps, traceId, convId) { if (!enabled || !pool || !steps || !steps.length) return; await ensureTable(); const values = []; const params = []; let i = 1; for (const s of steps) { values.push(`($${i++},$${i++},$${i++},$${i++},$${i++},$${i++},$${i++},$${i++},$${i++},$${i++},$${i++})`); params.push(traceId || null, convId || null, s.step_type || null, s.phase || null, s.turn ?? null, s.model || null, s.tool_name || null, s.prompt_tokens ?? null, s.completion_tokens ?? null, s.duration_ms ?? null, s.finish_reason || null); } try { await pool.query(`INSERT INTO agent_trace_steps (trace_id,conv_id,step_type,phase,turn,model,tool_name,prompt_tokens,completion_tokens,duration_ms,finish_reason) VALUES ${values.join(',')}`, params); } catch (err) { console.error('[trace_writer] insert error:', err.message.slice(0, 120)); } } return { writeSteps, enabled }; } module.exports = { createTraceWriter };