@p-dsh-market/conversation-knowledge-map 0.1.9 → 0.1.10

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
@@ -11,6 +11,8 @@ DSH 的“知识视图”插件,把同一工作路径下用户明确选择的
11
11
 
12
12
  配置面板会列出运行时可用的 Provider / Model,并默认带入 DSH 默认模型;本次选择会绑定到确认令牌、Agent 调用和 `manifest.json`,不会因为默认模型变化而被静默替换。提交任务后配置对话框立即关闭,失败原因会显示在知识视图页的任务条中。
13
13
 
14
+ 摘要阶段按对话并行处理,并发上限固定为 3;同一对话的超长分段保持顺序处理,随后先合并为一份对话摘要,再统一生成思维导图或知识图谱。结构化生成关闭推理输出以减少等待和 Token 消耗;知识图谱最多生成 20 个实体、30 条关系。
15
+
14
16
  节点“继续对话”只形成一个可编辑的后续问题。确认导航后,插件使用公开的 Session 导航入口;如果当前 Runtime 没有向该槽位暴露草稿镜像,则提供“打开并复制问题”的安全降级,不自动发送消息。
15
17
 
16
18
  ## 生成失败诊断
@@ -25,4 +27,4 @@ node --check market/conversation-knowledge-map/lib/index.js
25
27
  node --check market/conversation-knowledge-map/lib/client.js
26
28
  ```
27
29
 
28
- 本地实现未执行 `npm pack`、发布或真实 Profile 安装;真实 DSH Web 视觉回放仍需在插件安装后验证。
30
+ 仓库测试通过后可同步到 DSH Web Profile;真实 DSH Web 视觉回放仍需重启 Runtime 后验证。
@@ -8,6 +8,7 @@ import { chunkSourceText, readSelectedSurfaces } from './session-source.js'
8
8
  const MAX_SUMMARY_CHARS = 2400
9
9
  const SUMMARY_MAX_TOKENS = 8000
10
10
  const VIEW_MAX_TOKENS = 12000
11
+ const SUMMARY_CONCURRENCY = 3
11
12
 
12
13
  function modelLabel(selection) {
13
14
  const provider = String(selection?.provider || '').trim()
@@ -164,6 +165,39 @@ function normalizeSummary(value, source, chunk) {
164
165
  }
165
166
  }
166
167
 
168
+ function mergeSourceSummaries(source, chunkSummaries) {
169
+ if (chunkSummaries.length === 1) return chunkSummaries[0]
170
+ const summary = shortText(chunkSummaries.map((item) => item.summary).filter(Boolean).join('\n'), MAX_SUMMARY_CHARS)
171
+ const keyPoints = [...new Set(chunkSummaries.flatMap((item) => item.keyPoints || []).map((item) => shortText(item, 500)).filter(Boolean))].slice(0, 12)
172
+ const eventSeqs = [...new Set(chunkSummaries.flatMap((item) => item.sourceRefs || [])
173
+ .filter((ref) => ref.sessionId === source.sessionId)
174
+ .flatMap((ref) => ref.eventSeqs || []))].slice(0, 24)
175
+ const sourceRefs = eventSeqs.length ? [{ sessionId: source.sessionId, eventSeqs }] : []
176
+ return { sessionId: source.sessionId, title: source.title, summary, keyPoints, sourceRefs }
177
+ }
178
+
179
+ async function mapWithConcurrency(items, limit, mapper) {
180
+ const results = new Array(items.length)
181
+ let nextIndex = 0
182
+ let failure = null
183
+ const worker = async () => {
184
+ while (!failure) {
185
+ const index = nextIndex
186
+ nextIndex += 1
187
+ if (index >= items.length) return
188
+ try {
189
+ results[index] = await mapper(items[index], index)
190
+ } catch (error) {
191
+ failure ||= error
192
+ }
193
+ }
194
+ }
195
+ const workerCount = Math.min(Math.max(1, limit), items.length)
196
+ await Promise.all(Array.from({ length: workerCount }, () => worker()))
197
+ if (failure) throw failure
198
+ return results
199
+ }
200
+
167
201
  function assertOutputSourceRefs(value, sources) {
168
202
  const allowed = new Map(sources.map((source) => [source.sessionId, new Set((source.events || []).flatMap((event) => [event.seq, ...(event.sourceEventSeqs || [])]))]))
169
203
  const check = (ref, label) => {
@@ -196,6 +230,7 @@ function outputPrompt(kind, summaries, prompt, strict) {
196
230
  }
197
231
  return [
198
232
  '请根据以下多个对话摘要生成静态知识图谱。抽取实体、概念、模块、接口、决策、风险和外部系统,并只建立有依据的关系。',
233
+ '最多生成 20 个实体、30 条关系;实体 summary 控制在 220 字以内。不要输出 schema 之外的字段。确保最终内容是可被 JSON.parse 直接解析的完整 JSON。',
199
234
  'JSON 形状:{"entities":[{"id":"...","type":"...","name":"...","summary":"...","confidence":"confirmed|inferred|conflicted","sourceRefs":[{"sessionId":"...","eventSeqs":[1]}]}],"relations":[{"id":"...","from":"...","to":"...","type":"depends_on|calls|supports|constrains|belongs_to|derived_from","confidence":"confirmed|inferred|conflicted","evidence":[{"sessionId":"...","eventSeqs":[1]}]}]}。',
200
235
  ...rules,
201
236
  `额外要求:${shortText(prompt, 2000) || '没有额外要求。'}`,
@@ -494,13 +529,14 @@ export class KnowledgeGenerationOrchestrator {
494
529
  this.assertNotCancelled(task)
495
530
  logMessage(this.logger, 'info', 'generation sources loaded id=%s sources=%d events=%d', logId(task.id), sources.length, sources.reduce((total, source) => total + (Array.isArray(source.events) ? source.events.length : 0), 0))
496
531
  this.update(task, 'summarizing', { sourceCount: sources.length, progress: { percent: 10, current: 0, total: sources.length, label: '准备整理对话' } })
497
- const summaries = []
498
- for (let sourceIndex = 0; sourceIndex < sources.length; sourceIndex += 1) {
499
- const source = sources[sourceIndex]
532
+ let completedSources = 0
533
+ logMessage(this.logger, 'info', 'summary batch start id=%s sources=%d concurrency=%d', logId(task.id), sources.length, Math.min(SUMMARY_CONCURRENCY, sources.length))
534
+ const summaries = await mapWithConcurrency(sources, SUMMARY_CONCURRENCY, async (source, sourceIndex) => {
500
535
  this.update(task, 'summarizing', {
501
536
  sourceCount: sources.length,
502
- progress: { percent: 10 + Math.floor(60 * sourceIndex / sources.length), current: sourceIndex, total: sources.length, label: source.title }
537
+ progress: { percent: 10 + Math.floor(60 * completedSources / sources.length), current: completedSources, total: sources.length, label: `并行整理:${source.title}` }
503
538
  })
539
+ const chunkSummaries = []
504
540
  for (const chunk of chunkSourceText(source)) {
505
541
  this.assertNotCancelled(task)
506
542
  const prompt = summaryPrompt(source, chunk, request.strict === true)
@@ -510,7 +546,7 @@ export class KnowledgeGenerationOrchestrator {
510
546
  })
511
547
  try {
512
548
  const value = await generateSummary(prompt)
513
- summaries.push(normalizeSummary(value, source, chunk))
549
+ chunkSummaries.push(normalizeSummary(value, source, chunk))
514
550
  } catch (error) {
515
551
  this.assertNotCancelled(task)
516
552
  logMessage(this.logger, 'warn', 'summary first attempt invalid id=%s session=%s error=%s', logId(task.id), logId(source.sessionId), errorMessage(error))
@@ -520,14 +556,16 @@ export class KnowledgeGenerationOrchestrator {
520
556
  })
521
557
  const retryPrompt = `${prompt}\n\n上一次输出未通过校验:${shortText(errorMessage(error), 500)}。请从头重新整理,缩短内容,只输出严格合法的顶层摘要 JSON。`
522
558
  const retryValue = await generateSummary(retryPrompt)
523
- summaries.push(normalizeSummary(retryValue, source, chunk))
559
+ chunkSummaries.push(normalizeSummary(retryValue, source, chunk))
524
560
  }
525
561
  }
562
+ completedSources += 1
526
563
  this.update(task, 'summarizing', {
527
564
  sourceCount: sources.length,
528
- progress: { percent: 10 + Math.floor(60 * (sourceIndex + 1) / sources.length), current: sourceIndex + 1, total: sources.length, label: source.title }
565
+ progress: { percent: 10 + Math.floor(60 * completedSources / sources.length), current: completedSources, total: sources.length, label: source.title }
529
566
  })
530
- }
567
+ return mergeSourceSummaries(source, chunkSummaries)
568
+ })
531
569
  this.assertNotCancelled(task)
532
570
  let mindMap = null
533
571
  let knowledgeGraph = null
@@ -685,7 +723,7 @@ export class KnowledgeGenerationOrchestrator {
685
723
  handle = await this.agents.create({
686
724
  sessionId,
687
725
  meta: { cwd: input.cwd, origin: 'subagent' },
688
- agentOptions: { provider, model, maxTokens: input.kind === 'summary' ? SUMMARY_MAX_TOKENS : VIEW_MAX_TOKENS },
726
+ agentOptions: { provider, model, reasoningEffort: 'off', maxTokens: input.kind === 'summary' ? SUMMARY_MAX_TOKENS : VIEW_MAX_TOKENS },
689
727
  signal: input.signal,
690
728
  setup: async (agentCtx) => {
691
729
  agentCtx?.systemPrompt?.section?.({
@@ -206,7 +206,7 @@ export async function readSelectedSurfaces({ sessionQuery, sessions }, { cwd, se
206
206
  return sources
207
207
  }
208
208
 
209
- export function chunkSourceText(source, maxChars = 9000) {
209
+ export function chunkSourceText(source, maxChars = 16000) {
210
210
  const text = String(source?.text || '')
211
211
  if (!text) return [{ text: '', sourceRefs: [] }]
212
212
  const chunks = []
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@p-dsh-market/conversation-knowledge-map",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "DSH 多对话思维导图与静态知识图谱",
5
5
  "keywords": [
6
6
  "dsh",