@p-dsh-market/conversation-knowledge-map 0.1.6 → 0.1.7

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.
@@ -474,8 +474,10 @@ export class KnowledgeGenerationOrchestrator {
474
474
  const sources = await this.sourceReader({ sessionQuery: this.sessionQuery, sessions: this.sessions }, {
475
475
  cwd: request.cwd,
476
476
  sessionIds: request.selectedSessionIds,
477
+ fallbackSessionId: request.anchorSessionId,
477
478
  includeSubagents: request.includeSubagents === true
478
479
  })
480
+ const sourceSessionIds = [...new Set(sources.map((source) => source.sessionId))]
479
481
  this.assertNotCancelled(task)
480
482
  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))
481
483
  this.update(task, 'summarizing', { sourceCount: sources.length })
@@ -488,7 +490,7 @@ export class KnowledgeGenerationOrchestrator {
488
490
  prompt: summaryPrompt(source, chunk, request.strict === true),
489
491
  cwd: request.cwd,
490
492
  strict: request.strict === true,
491
- selectedSessionIds: request.selectedSessionIds,
493
+ selectedSessionIds: sourceSessionIds,
492
494
  model: request.model,
493
495
  signal: task.controller.signal
494
496
  })
@@ -505,11 +507,11 @@ export class KnowledgeGenerationOrchestrator {
505
507
  prompt: outputPrompt('mind-map', summaries, request.prompt, request.strict === true),
506
508
  cwd: request.cwd,
507
509
  strict: request.strict === true,
508
- selectedSessionIds: request.selectedSessionIds,
510
+ selectedSessionIds: sourceSessionIds,
509
511
  model: request.model,
510
512
  signal: task.controller.signal
511
513
  })
512
- mindMap = validateMindMap(value, { selectedSessionIds: request.selectedSessionIds, strict: request.strict === true })
514
+ mindMap = validateMindMap(value, { selectedSessionIds: sourceSessionIds, strict: request.strict === true })
513
515
  }
514
516
  if (request.outputMode === 'knowledge-graph' || request.outputMode === 'both') {
515
517
  this.update(task, 'building-knowledge-graph')
@@ -518,11 +520,11 @@ export class KnowledgeGenerationOrchestrator {
518
520
  prompt: outputPrompt('knowledge-graph', summaries, request.prompt, request.strict === true),
519
521
  cwd: request.cwd,
520
522
  strict: request.strict === true,
521
- selectedSessionIds: request.selectedSessionIds,
523
+ selectedSessionIds: sourceSessionIds,
522
524
  model: request.model,
523
525
  signal: task.controller.signal
524
526
  })
525
- knowledgeGraph = validateKnowledgeGraph(value, { selectedSessionIds: request.selectedSessionIds, strict: request.strict === true })
527
+ knowledgeGraph = validateKnowledgeGraph(value, { selectedSessionIds: sourceSessionIds, strict: request.strict === true })
526
528
  }
527
529
  assertOutputSourceRefs({ mindMap, knowledgeGraph }, sources)
528
530
  this.assertNotCancelled(task)
@@ -532,7 +534,7 @@ export class KnowledgeGenerationOrchestrator {
532
534
  cwd: request.cwd,
533
535
  expectedRevision: request.expectedRevision,
534
536
  generationId: task.id,
535
- sourceSessionIds: request.selectedSessionIds,
537
+ sourceSessionIds,
536
538
  prompt: request.prompt,
537
539
  strict: request.strict,
538
540
  outputMode: request.outputMode,
@@ -112,8 +112,10 @@ function sourceSeqsOf(event) {
112
112
  return Array.isArray(value) ? value.filter((item) => Number.isInteger(item) && item >= 0) : []
113
113
  }
114
114
 
115
- export function surfaceEventView(event) {
115
+ export function surfaceEventView(event, { fullSession = false } = {}) {
116
116
  const role = eventRole(String(event?.type || ''))
117
+ const data = event?.data?.message || event?.data || {}
118
+ if (fullSession && role === 'user' && data?.source?.kind !== 'user') return null
117
119
  const text = shortText(eventMessageText(event), 12000)
118
120
  if (!role || !text) return null
119
121
  return {
@@ -125,42 +127,76 @@ export function surfaceEventView(event) {
125
127
  }
126
128
  }
127
129
 
128
- export async function readSelectedSurfaces({ sessionQuery, sessions }, { cwd, sessionIds, includeSubagents = false }) {
130
+ export async function readSelectedSurfaces({ sessionQuery, sessions }, { cwd, sessionIds, fallbackSessionId = '', includeSubagents = false }) {
129
131
  const selected = [...new Set((sessionIds || []).map((id) => String(id || '').trim()).filter(Boolean))]
130
132
  if (selected.length === 0) throw new Error('至少选择一个对话。')
131
133
  const normalizedCwd = normalizeWorkspacePath(cwd)
132
134
  if (!normalizedCwd) throw new Error('当前工作路径无效。')
135
+ const fallbackId = String(fallbackSessionId || '').trim()
136
+ const resolvedIds = [...new Set([...selected, ...(fallbackId ? [fallbackId] : [])])]
133
137
  const records = []
134
138
  if (typeof sessionQuery?.filterSessions === 'function') {
135
- records.push(...await sessionQuery.filterSessions([{ kind: 'id', values: selected }]))
139
+ records.push(...await sessionQuery.filterSessions([{ kind: 'id', values: resolvedIds }]))
136
140
  } else if (typeof sessionQuery?.listSessions === 'function') {
137
141
  const all = await sessionQuery.listSessions()
138
- records.push(...all.filter((record) => selected.includes(String(headerOf(record)?.id || ''))))
142
+ records.push(...all.filter((record) => resolvedIds.includes(String(headerOf(record)?.id || ''))))
139
143
  }
140
144
  const recordMap = new Map(records.map((record) => [String(headerOf(record)?.id || record?.id || ''), record]))
141
- const sources = []
142
- for (const id of selected) {
145
+ const readSource = async (id) => {
143
146
  const record = recordMap.get(id)
144
147
  const header = headerOf(record) || sessions?.get?.(id)?.header
145
148
  if (!header?.id) throw new Error(`所选对话不存在或已不可读:${id}`)
146
149
  if (!sameWorkspacePath(header.cwd, normalizedCwd)) throw new Error(`所选对话不属于当前工作路径:${id}`)
147
150
  if (!includeSubagents && header.origin === 'subagent') throw new Error(`不能选择子 Agent 对话:${id}`)
148
- if (typeof sessionQuery?.readSurface !== 'function') throw new Error('当前 DSH Runtime 未提供 sessionQuery.readSurface。')
149
- let surface
151
+ if (typeof sessionQuery?.readSurface !== 'function' && typeof sessionQuery?.readSession !== 'function') {
152
+ throw new Error('当前 DSH Runtime 未提供 sessionQuery.readSurface/readSession。')
153
+ }
154
+ let snapshot
155
+ let events = []
156
+ let surfaceError = null
150
157
  try {
151
- surface = await sessionQuery.readSurface(id)
158
+ if (typeof sessionQuery?.readSurface === 'function') {
159
+ snapshot = await sessionQuery.readSurface(id)
160
+ events = (snapshot?.events || []).map((event) => surfaceEventView(event)).filter(Boolean)
161
+ }
152
162
  } catch (error) {
153
- throw new Error(`读取对话“${id}”失败:${errorMessage(error)}`)
163
+ surfaceError = error
154
164
  }
155
- const events = (surface?.events || []).map(surfaceEventView).filter(Boolean)
156
- sources.push({
165
+ if (events.length === 0 && typeof sessionQuery?.readSession === 'function') {
166
+ try {
167
+ const full = await sessionQuery.readSession(id)
168
+ snapshot = full || snapshot
169
+ events = (full?.events || []).map((event) => surfaceEventView(event, { fullSession: true })).filter(Boolean)
170
+ } catch (error) {
171
+ if (surfaceError) throw new Error(`读取对话“${id}”失败:surface=${errorMessage(surfaceError)};session=${errorMessage(error)}`)
172
+ throw new Error(`读取对话“${id}”完整记录失败:${errorMessage(error)}`)
173
+ }
174
+ }
175
+ if (surfaceError && events.length === 0) throw new Error(`读取对话“${id}”失败:${errorMessage(surfaceError)}`)
176
+ return {
157
177
  sessionId: id,
158
178
  title: `对话 ${id.slice(0, 8)}`,
159
- cwd: normalizeWorkspacePath(surface?.session?.cwd || header.cwd),
160
- capturedThroughSeq: Number.isInteger(surface?.capturedThroughSeq) ? surface.capturedThroughSeq : null,
179
+ cwd: normalizeWorkspacePath(snapshot?.session?.cwd || header.cwd),
180
+ capturedThroughSeq: Number.isInteger(snapshot?.capturedThroughSeq) ? snapshot.capturedThroughSeq : null,
161
181
  events,
162
182
  text: events.map((event) => `${event.role === 'user' ? '用户' : '助手'}:${event.text}`).join('\n\n')
163
- })
183
+ }
184
+ }
185
+ const sources = []
186
+ let needsFallback = false
187
+ for (const id of selected) {
188
+ const source = await readSource(id)
189
+ if (source.events.length > 0) sources.push(source)
190
+ else needsFallback = true
191
+ }
192
+ if (needsFallback && fallbackId && !sources.some((source) => source.sessionId === fallbackId)) {
193
+ const fallback = await readSource(fallbackId)
194
+ if (fallback.events.length > 0) sources.push(fallback)
195
+ }
196
+ if (sources.length === 0) {
197
+ throw new Error(fallbackId
198
+ ? `所选对话及当前对话都没有可读取的用户/助手消息:${selected.join(', ')}`
199
+ : `所选对话没有可读取的用户/助手消息:${selected.join(', ')}`)
164
200
  }
165
201
  if (typeof sessionQuery?.readTitleSnapshots === 'function' && sources.length) {
166
202
  const results = await sessionQuery.readTitleSnapshots(sources.map((source) => source.sessionId))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@p-dsh-market/conversation-knowledge-map",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "DSH 多对话思维导图与静态知识图谱",
5
5
  "keywords": [
6
6
  "dsh",