@p-dsh-market/conversation-knowledge-map 0.1.8 → 0.1.9
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/lib/generation-orchestrator.js +34 -15
- package/package.json +1 -1
|
@@ -68,7 +68,16 @@ function textFromContent(value) {
|
|
|
68
68
|
return ''
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
function
|
|
71
|
+
function expectedObject(value, kind = '') {
|
|
72
|
+
if (!kind) return true
|
|
73
|
+
if (kind === 'summary') return typeof value?.summary === 'string' || typeof value?.narrative === 'string' || typeof value?.text === 'string'
|
|
74
|
+
if (kind === 'mind-map') return Array.isArray(value?.nodes)
|
|
75
|
+
if (kind === 'knowledge-graph') return Array.isArray(value?.entities) && Array.isArray(value?.relations)
|
|
76
|
+
if (kind === 'follow-up') return typeof value?.question === 'string'
|
|
77
|
+
return true
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function findJsonObject(text, kind = '') {
|
|
72
81
|
const candidates = []
|
|
73
82
|
const fenced = String(text || '').match(/```(?:json)?\s*([\s\S]*?)```/i)
|
|
74
83
|
if (fenced) candidates.push(fenced[1])
|
|
@@ -98,7 +107,7 @@ function findJsonObject(text) {
|
|
|
98
107
|
const fragment = candidate.slice(start, index + 1)
|
|
99
108
|
try {
|
|
100
109
|
const parsed = JSON.parse(fragment)
|
|
101
|
-
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) return parsed
|
|
110
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed) && expectedObject(parsed, kind)) return parsed
|
|
102
111
|
} catch {
|
|
103
112
|
// Try the next opening brace in case prose contained an example.
|
|
104
113
|
}
|
|
@@ -111,11 +120,11 @@ function findJsonObject(text) {
|
|
|
111
120
|
return null
|
|
112
121
|
}
|
|
113
122
|
|
|
114
|
-
export function parseStructuredOutput(value) {
|
|
123
|
+
export function parseStructuredOutput(value, kind = '') {
|
|
115
124
|
const object = asObject(value)
|
|
116
|
-
if (object) return object
|
|
125
|
+
if (object && expectedObject(object, kind)) return object
|
|
117
126
|
const text = textFromContent(value).replace(/^\uFEFF/, '').trim()
|
|
118
|
-
const parsed = findJsonObject(text)
|
|
127
|
+
const parsed = findJsonObject(text, kind)
|
|
119
128
|
if (parsed) return parsed
|
|
120
129
|
if (!text) throw new Error('模型没有返回 JSON 对象。')
|
|
121
130
|
throw new Error('模型返回了文本,但其中没有可解析的 JSON 对象。')
|
|
@@ -198,6 +207,7 @@ function summaryPrompt(source, chunk, strict) {
|
|
|
198
207
|
return [
|
|
199
208
|
'请把一段 DSH 对话整理成带来源的结构化摘要。不要复述完整聊天,不要添加对话中没有的事实。',
|
|
200
209
|
'只输出 JSON:{"summary":"完整阶段性说明","keyPoints":["..."],"sourceRefs":[{"sessionId":"...","eventSeqs":[1]}]}。',
|
|
210
|
+
'summary 控制在 1200 字以内;keyPoints 最多 8 条,每条不超过 160 字。不要增加其他字段。字符串中的双引号必须正确转义,确保整个输出可以被 JSON.parse 直接解析。',
|
|
201
211
|
strict ? '严格模式:每个关键点都要能回指给定事件。' : '允许标记尚未确认的冲突,但不能编造事件序号。',
|
|
202
212
|
`Session:${source.sessionId}`,
|
|
203
213
|
`标题:${source.title}`,
|
|
@@ -493,16 +503,25 @@ export class KnowledgeGenerationOrchestrator {
|
|
|
493
503
|
})
|
|
494
504
|
for (const chunk of chunkSourceText(source)) {
|
|
495
505
|
this.assertNotCancelled(task)
|
|
496
|
-
const
|
|
497
|
-
|
|
498
|
-
prompt:
|
|
499
|
-
|
|
500
|
-
strict: request.strict === true,
|
|
501
|
-
selectedSessionIds: sourceSessionIds,
|
|
502
|
-
model: request.model,
|
|
503
|
-
signal: task.controller.signal
|
|
506
|
+
const prompt = summaryPrompt(source, chunk, request.strict === true)
|
|
507
|
+
const generateSummary = async (summaryInput) => this.runModel({
|
|
508
|
+
kind: 'summary', prompt: summaryInput, cwd: request.cwd, strict: request.strict === true,
|
|
509
|
+
selectedSessionIds: sourceSessionIds, model: request.model, signal: task.controller.signal
|
|
504
510
|
})
|
|
505
|
-
|
|
511
|
+
try {
|
|
512
|
+
const value = await generateSummary(prompt)
|
|
513
|
+
summaries.push(normalizeSummary(value, source, chunk))
|
|
514
|
+
} catch (error) {
|
|
515
|
+
this.assertNotCancelled(task)
|
|
516
|
+
logMessage(this.logger, 'warn', 'summary first attempt invalid id=%s session=%s error=%s', logId(task.id), logId(source.sessionId), errorMessage(error))
|
|
517
|
+
this.update(task, 'summarizing', {
|
|
518
|
+
message: `对话 ${sourceIndex + 1}/${sources.length} 摘要结构无效,正在自动修复…`,
|
|
519
|
+
progress: { percent: 10 + Math.floor(60 * sourceIndex / sources.length), current: sourceIndex, total: sources.length, label: `自动修复:${source.title}` }
|
|
520
|
+
})
|
|
521
|
+
const retryPrompt = `${prompt}\n\n上一次输出未通过校验:${shortText(errorMessage(error), 500)}。请从头重新整理,缩短内容,只输出严格合法的顶层摘要 JSON。`
|
|
522
|
+
const retryValue = await generateSummary(retryPrompt)
|
|
523
|
+
summaries.push(normalizeSummary(retryValue, source, chunk))
|
|
524
|
+
}
|
|
506
525
|
}
|
|
507
526
|
this.update(task, 'summarizing', {
|
|
508
527
|
sourceCount: sources.length,
|
|
@@ -581,7 +600,7 @@ export class KnowledgeGenerationOrchestrator {
|
|
|
581
600
|
async runModel(input) {
|
|
582
601
|
const parseModelOutput = (value, source, diagnostics = {}) => {
|
|
583
602
|
try {
|
|
584
|
-
const result = parseStructuredOutput(value)
|
|
603
|
+
const result = parseStructuredOutput(value, input.kind)
|
|
585
604
|
logMessage(this.logger, 'info', 'agent output parsed kind=%s source=%s value=%s result=%s', input.kind, source, diagnosticSummary(value), diagnosticSummary(result))
|
|
586
605
|
return result
|
|
587
606
|
} catch (error) {
|