@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 CHANGED
@@ -19,7 +19,7 @@ DSH 的“知识视图”插件,把同一工作路径下用户明确选择的
19
19
 
20
20
  ## 生成失败诊断
21
21
 
22
- Host 和生成编排器会输出带 `[conversation-knowledge-map]` 前缀的诊断日志。日志包含路由、Provider / Model、Agent Session、实时事件类型、surface/session 读取次数、提取文本长度、输出形状和错误原因,不记录 Prompt、对话正文或模型返回正文。优先查看 DSH Web Runtime 的终端日志;若 Runtime 提供 logger 服务,则同时写入该 logger。重点关注 `agent event`、`agent idle`、`agent turn failure`、`agent surface read`、`agent session read` 和 `agent output parse failed`。Runtime 在 `turn/end.reason.kind = error` 时会优先显示其 `code/message`;只有未发现 turn 错误且确实没有助手输出时,才会报告“模型没有返回 JSON 对象”。
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 diagnostics=%s error=%s', input.kind, source, diagnosticSummary(value), JSON.stringify(diagnostics), errorMessage(surfacedError))
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@p-dsh-market/conversation-knowledge-map",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "description": "DSH 多对话思维导图与静态知识图谱",
5
5
  "keywords": [
6
6
  "dsh",