@p-dsh-market/conversation-knowledge-map 0.1.16 → 0.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/lib/generation-orchestrator.js +70 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ DSH 的“知识视图”插件,把同一工作路径下用户明确选择的
|
|
|
19
19
|
|
|
20
20
|
## 生成失败诊断
|
|
21
21
|
|
|
22
|
-
Host 和生成编排器会输出带 `[conversation-knowledge-map]` 前缀的诊断日志。日志包含路由、Provider / Model、Agent Session、实时事件类型、surface/session 读取次数、提取文本长度、输出形状和错误原因,不记录 Prompt
|
|
22
|
+
Host 和生成编排器会输出带 `[conversation-knowledge-map]` 前缀的诊断日志。日志包含路由、Provider / Model、Agent Session、实时事件类型、surface/session 读取次数、提取文本长度、输出形状和错误原因,不记录 Prompt 或原始对话正文。为诊断结构化输出失败,当前还会记录模型实际返回文本:不超过 32000 字符时完整记录,超过时保留首尾各 16000 字符;该内容可能包含模型整理出的对话信息,排障完成后应按运行环境的日志策略清理。解析失败日志会额外列出 Markdown JSON 围栏、首末大括号位置以及每个候选对象属于未闭合、JSON 语法错误、合法但结构不符或合法目标结构。优先查看 DSH Web Runtime 的终端日志;若 Runtime 提供 logger 服务,则同时写入该 logger。重点关注 `agent output content`、`agent output parse failed`、`agent event`、`agent idle`、`agent turn failure`、`agent surface read` 和 `agent session read`。Runtime 在 `turn/end.reason.kind = error` 时会优先显示其 `code/message`;只有未发现 turn 错误且确实没有助手输出时,才会报告“模型没有返回 JSON 对象”。
|
|
23
23
|
|
|
24
24
|
## 本地验证
|
|
25
25
|
|
|
@@ -128,6 +128,73 @@ function findJsonObject(text, kind = '') {
|
|
|
128
128
|
return null
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
function modelOutputText(value) {
|
|
132
|
+
const text = textFromContent(value)
|
|
133
|
+
if (text) return text
|
|
134
|
+
if (value && typeof value === 'object') {
|
|
135
|
+
try { return JSON.stringify(value) } catch { /* fall through to a printable scalar */ }
|
|
136
|
+
}
|
|
137
|
+
return String(value ?? '')
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function loggableModelOutput(value, max = 32000) {
|
|
141
|
+
const text = modelOutputText(value)
|
|
142
|
+
if (text.length <= max) return { text, loggedText: JSON.stringify(text), truncated: false }
|
|
143
|
+
const half = Math.floor(max / 2)
|
|
144
|
+
const bounded = `${text.slice(0, half)}\n…[中间 ${text.length - max} 个字符因日志长度限制被省略]…\n${text.slice(-half)}`
|
|
145
|
+
return { text, loggedText: JSON.stringify(bounded), truncated: true }
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function jsonParseDiagnostics(value, kind = '') {
|
|
149
|
+
const text = modelOutputText(value).replace(/^\uFEFF/, '').trim()
|
|
150
|
+
const starts = []
|
|
151
|
+
for (let index = 0; index < text.length && starts.length < 12; index += 1) if (text[index] === '{') starts.push(index)
|
|
152
|
+
const candidates = []
|
|
153
|
+
for (const start of starts) {
|
|
154
|
+
let depth = 0
|
|
155
|
+
let inString = false
|
|
156
|
+
let escaped = false
|
|
157
|
+
let end = -1
|
|
158
|
+
for (let index = start; index < text.length; index += 1) {
|
|
159
|
+
const char = text[index]
|
|
160
|
+
if (inString) {
|
|
161
|
+
if (escaped) escaped = false
|
|
162
|
+
else if (char === '\\') escaped = true
|
|
163
|
+
else if (char === '"') inString = false
|
|
164
|
+
continue
|
|
165
|
+
}
|
|
166
|
+
if (char === '"') inString = true
|
|
167
|
+
else if (char === '{') depth += 1
|
|
168
|
+
else if (char === '}' && --depth === 0) { end = index; break }
|
|
169
|
+
}
|
|
170
|
+
if (end < 0) {
|
|
171
|
+
candidates.push({ start, status: 'unclosed-object' })
|
|
172
|
+
continue
|
|
173
|
+
}
|
|
174
|
+
const fragment = text.slice(start, end + 1)
|
|
175
|
+
try {
|
|
176
|
+
const parsed = JSON.parse(fragment)
|
|
177
|
+
candidates.push({
|
|
178
|
+
start,
|
|
179
|
+
end,
|
|
180
|
+
status: expectedObject(parsed, kind) ? 'valid-expected-shape' : 'valid-json-wrong-shape',
|
|
181
|
+
keys: parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? Object.keys(parsed).slice(0, 20) : []
|
|
182
|
+
})
|
|
183
|
+
} catch (error) {
|
|
184
|
+
candidates.push({ start, end, status: 'invalid-json', error: shortText(errorMessage(error), 300) })
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
kind,
|
|
189
|
+
textLength: text.length,
|
|
190
|
+
fencedJson: /```(?:json)?\s*[\s\S]*?```/i.test(text),
|
|
191
|
+
firstBrace: text.indexOf('{'),
|
|
192
|
+
lastBrace: text.lastIndexOf('}'),
|
|
193
|
+
candidateCountInspected: candidates.length,
|
|
194
|
+
candidates
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
131
198
|
export function parseStructuredOutput(value, kind = '') {
|
|
132
199
|
const object = asObject(value)
|
|
133
200
|
if (object && expectedObject(object, kind)) return object
|
|
@@ -976,13 +1043,15 @@ export class KnowledgeGenerationOrchestrator {
|
|
|
976
1043
|
|
|
977
1044
|
async runModel(input) {
|
|
978
1045
|
const parseModelOutput = (value, source, diagnostics = {}) => {
|
|
1046
|
+
const output = loggableModelOutput(value)
|
|
1047
|
+
logMessage(this.logger, 'info', 'agent output content kind=%s source=%s length=%d truncated=%s content=%s', input.kind, source, output.text.length, output.truncated, output.loggedText)
|
|
979
1048
|
try {
|
|
980
1049
|
const result = parseStructuredOutput(value, input.kind)
|
|
981
1050
|
logMessage(this.logger, 'info', 'agent output parsed kind=%s source=%s value=%s result=%s', input.kind, source, diagnosticSummary(value), diagnosticSummary(result))
|
|
982
1051
|
return result
|
|
983
1052
|
} catch (error) {
|
|
984
1053
|
const surfacedError = diagnostics.agentLimit || error
|
|
985
|
-
logMessage(this.logger, 'error', 'agent output parse failed kind=%s source=%s value=%s
|
|
1054
|
+
logMessage(this.logger, 'error', 'agent output parse failed kind=%s source=%s value=%s parseDiagnostics=%s runtimeDiagnostics=%s error=%s', input.kind, source, diagnosticSummary(value), JSON.stringify(jsonParseDiagnostics(value, input.kind)), JSON.stringify(diagnostics), errorMessage(surfacedError))
|
|
986
1055
|
throw surfacedError
|
|
987
1056
|
}
|
|
988
1057
|
}
|