@yadsh/dsh-qa-surface 0.3.0 → 0.4.0

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.
Files changed (245) hide show
  1. package/README.md +153 -12
  2. package/lib/account-remotes.js +100 -0
  3. package/lib/account-remotes.js.map +1 -0
  4. package/lib/accounts/credentials.js +27 -0
  5. package/lib/accounts/credentials.js.map +1 -0
  6. package/lib/accounts/errors.js +9 -0
  7. package/lib/accounts/errors.js.map +1 -0
  8. package/lib/accounts/file.js +101 -0
  9. package/lib/accounts/file.js.map +1 -0
  10. package/lib/accounts/store.js +144 -161
  11. package/lib/accounts/store.js.map +1 -1
  12. package/lib/accounts/token.js +61 -0
  13. package/lib/accounts/token.js.map +1 -0
  14. package/lib/attachment-rules.js +111 -0
  15. package/lib/attachment-rules.js.map +1 -0
  16. package/lib/cli.js +122 -9
  17. package/lib/cli.js.map +1 -1
  18. package/lib/client/QaAccountsController.js +32 -2
  19. package/lib/client/QaAccountsController.js.map +1 -1
  20. package/lib/client/QaSessionController.js +47 -65
  21. package/lib/client/QaSessionController.js.map +1 -1
  22. package/lib/client/QaSurface.js +121 -107
  23. package/lib/client/QaSurface.js.map +1 -1
  24. package/lib/client/QaTranscriptAdapter.js +71 -6
  25. package/lib/client/QaTranscriptAdapter.js.map +1 -1
  26. package/lib/client/attachments.js +150 -0
  27. package/lib/client/attachments.js.map +1 -0
  28. package/lib/client/attestation.js +1 -1
  29. package/lib/client/attestation.js.map +1 -1
  30. package/lib/client/base64.js +16 -0
  31. package/lib/client/base64.js.map +1 -0
  32. package/lib/client/chat-files.js +48 -0
  33. package/lib/client/chat-files.js.map +1 -0
  34. package/lib/client/components/Markdown.js +1 -1
  35. package/lib/client/components/Markdown.js.map +1 -1
  36. package/lib/client/components/QaChangelog.js +38 -19
  37. package/lib/client/components/QaChangelog.js.map +1 -1
  38. package/lib/client/components/QaComposer.js +56 -74
  39. package/lib/client/components/QaComposer.js.map +1 -1
  40. package/lib/client/components/QaFileAttachment.js +19 -0
  41. package/lib/client/components/QaFileAttachment.js.map +1 -0
  42. package/lib/client/components/QaFilesPanel.js +45 -0
  43. package/lib/client/components/QaFilesPanel.js.map +1 -0
  44. package/lib/client/components/QaHeader.js +34 -0
  45. package/lib/client/components/QaHeader.js.map +1 -0
  46. package/lib/client/components/QaMessage.js +17 -4
  47. package/lib/client/components/QaMessage.js.map +1 -1
  48. package/lib/client/components/QaModal.js +31 -0
  49. package/lib/client/components/QaModal.js.map +1 -0
  50. package/lib/client/components/QaProfile.js +64 -0
  51. package/lib/client/components/QaProfile.js.map +1 -0
  52. package/lib/client/components/QaRightRail.js +15 -0
  53. package/lib/client/components/QaRightRail.js.map +1 -0
  54. package/lib/client/components/QaSidebar.js +6 -1
  55. package/lib/client/components/QaSidebar.js.map +1 -1
  56. package/lib/client/components/{QaSourcesDrawer.js → QaSourcesPanel.js} +3 -3
  57. package/lib/client/components/QaSourcesPanel.js.map +1 -0
  58. package/lib/client/components/QaTurnRail.js +15 -0
  59. package/lib/client/components/QaTurnRail.js.map +1 -1
  60. package/lib/client/components/QaWidthHandle.js +25 -20
  61. package/lib/client/components/QaWidthHandle.js.map +1 -1
  62. package/lib/client/components/QaWorkGroup.js +19 -20
  63. package/lib/client/components/QaWorkGroup.js.map +1 -1
  64. package/lib/client/components/surface-utils.js +28 -0
  65. package/lib/client/components/surface-utils.js.map +1 -0
  66. package/lib/client/components/thinking-phrases.js +24 -0
  67. package/lib/client/components/thinking-phrases.js.map +1 -0
  68. package/lib/client/create-session.js +7 -32
  69. package/lib/client/create-session.js.map +1 -1
  70. package/lib/client/failure-copy.js +63 -0
  71. package/lib/client/failure-copy.js.map +1 -0
  72. package/lib/client/index.js +38 -7
  73. package/lib/client/index.js.map +1 -1
  74. package/lib/client/prompt-content.js +54 -0
  75. package/lib/client/prompt-content.js.map +1 -0
  76. package/lib/client/settings/card.js +143 -0
  77. package/lib/client/settings/card.js.map +1 -0
  78. package/lib/client/settings/fields.js +145 -0
  79. package/lib/client/settings/fields.js.map +1 -0
  80. package/lib/client/settings/format.js +255 -0
  81. package/lib/client/settings/format.js.map +1 -0
  82. package/lib/client/settings/sections/access.js +25 -0
  83. package/lib/client/settings/sections/access.js.map +1 -0
  84. package/lib/client/settings/sections/accounts.js +47 -0
  85. package/lib/client/settings/sections/accounts.js.map +1 -0
  86. package/lib/client/settings/sections/attachments.js +46 -0
  87. package/lib/client/settings/sections/attachments.js.map +1 -0
  88. package/lib/client/settings/sections/branding.js +28 -0
  89. package/lib/client/settings/sections/branding.js.map +1 -0
  90. package/lib/client/settings/sections/common.js +20 -0
  91. package/lib/client/settings/sections/common.js.map +1 -0
  92. package/lib/client/settings/sections/embedding.js +19 -0
  93. package/lib/client/settings/sections/embedding.js.map +1 -0
  94. package/lib/client/settings/sections/interface.js +60 -0
  95. package/lib/client/settings/sections/interface.js.map +1 -0
  96. package/lib/client/settings/sections/lockdown.js +82 -0
  97. package/lib/client/settings/sections/lockdown.js.map +1 -0
  98. package/lib/client/settings/sections/session.js +53 -0
  99. package/lib/client/settings/sections/session.js.map +1 -0
  100. package/lib/client/settings/sections/sources.js +72 -0
  101. package/lib/client/settings/sections/sources.js.map +1 -0
  102. package/lib/client/settings/sections/status.js +37 -0
  103. package/lib/client/settings/sections/status.js.map +1 -0
  104. package/lib/client/settings/sections.js +23 -0
  105. package/lib/client/settings/sections.js.map +1 -0
  106. package/lib/client/settings/styles.js +57 -0
  107. package/lib/client/settings/styles.js.map +1 -0
  108. package/lib/client/stream-publisher.js +47 -0
  109. package/lib/client/stream-publisher.js.map +1 -0
  110. package/lib/client/styles.js +85 -19
  111. package/lib/client/styles.js.map +1 -1
  112. package/lib/client/types.js.map +1 -1
  113. package/lib/client/use-right-rail.js +96 -0
  114. package/lib/client/use-right-rail.js.map +1 -0
  115. package/lib/client/use-session-ui-state.js +26 -19
  116. package/lib/client/use-session-ui-state.js.map +1 -1
  117. package/lib/client.js +4788 -869
  118. package/lib/client.js.map +1 -1
  119. package/lib/config-resolvers/accounts.js +60 -0
  120. package/lib/config-resolvers/accounts.js.map +1 -0
  121. package/lib/config-resolvers/attachments.js +28 -0
  122. package/lib/config-resolvers/attachments.js.map +1 -0
  123. package/lib/config-resolvers/basics.js +59 -0
  124. package/lib/config-resolvers/basics.js.map +1 -0
  125. package/lib/config-resolvers/defaults.js +132 -0
  126. package/lib/config-resolvers/defaults.js.map +1 -0
  127. package/lib/config-resolvers/lockdown.js +79 -0
  128. package/lib/config-resolvers/lockdown.js.map +1 -0
  129. package/lib/config-resolvers/session.js +42 -0
  130. package/lib/config-resolvers/session.js.map +1 -0
  131. package/lib/config-resolvers/shared.js +42 -0
  132. package/lib/config-resolvers/shared.js.map +1 -0
  133. package/lib/config-resolvers/sources.js +81 -0
  134. package/lib/config-resolvers/sources.js.map +1 -0
  135. package/lib/config-resolvers/ui.js +20 -0
  136. package/lib/config-resolvers/ui.js.map +1 -0
  137. package/lib/config.js +65 -4
  138. package/lib/config.js.map +1 -1
  139. package/lib/entry-redirect.js +2 -1
  140. package/lib/entry-redirect.js.map +1 -1
  141. package/lib/index.js +123 -74
  142. package/lib/index.js.map +1 -1
  143. package/lib/profile.js +214 -0
  144. package/lib/profile.js.map +1 -0
  145. package/lib/prompt-notes.js +231 -0
  146. package/lib/prompt-notes.js.map +1 -0
  147. package/lib/resolve-config.js +35 -410
  148. package/lib/resolve-config.js.map +1 -1
  149. package/lib/secure-session.js +82 -16
  150. package/lib/secure-session.js.map +1 -1
  151. package/lib/shared/session-key.js +18 -0
  152. package/lib/shared/session-key.js.map +1 -0
  153. package/lib/shared/settings.js +10 -0
  154. package/lib/shared/settings.js.map +1 -0
  155. package/lib/thinking-phrases.js +68 -0
  156. package/lib/thinking-phrases.js.map +1 -0
  157. package/lib/typert.host.js +162 -17
  158. package/lib/typert.remote-client.d.ts +5 -1
  159. package/lib/typert.remote-client.js +132 -13
  160. package/lib/types/account-remotes.d.ts +42 -0
  161. package/lib/types/accounts/credentials.d.ts +14 -0
  162. package/lib/types/accounts/errors.d.ts +11 -0
  163. package/lib/types/accounts/file.d.ts +82 -0
  164. package/lib/types/accounts/store.d.ts +66 -43
  165. package/lib/types/accounts/token.d.ts +31 -0
  166. package/lib/types/attachment-rules.d.ts +44 -0
  167. package/lib/types/cli.d.ts +2 -2
  168. package/lib/types/client/QaAccountsController.d.ts +8 -1
  169. package/lib/types/client/QaSessionController.d.ts +16 -16
  170. package/lib/types/client/QaSurface.d.ts +7 -1
  171. package/lib/types/client/attachments.d.ts +54 -0
  172. package/lib/types/client/base64.d.ts +10 -0
  173. package/lib/types/client/chat-files.d.ts +30 -0
  174. package/lib/types/client/components/QaChangelog.d.ts +1 -1
  175. package/lib/types/client/components/QaComposer.d.ts +8 -4
  176. package/lib/types/client/components/QaFileAttachment.d.ts +14 -0
  177. package/lib/types/client/components/QaFilesPanel.d.ts +15 -0
  178. package/lib/types/client/components/QaHeader.d.ts +41 -0
  179. package/lib/types/client/components/QaMessage.d.ts +3 -1
  180. package/lib/types/client/components/QaModal.d.ts +26 -0
  181. package/lib/types/client/components/QaProfile.d.ts +25 -0
  182. package/lib/types/client/components/QaRightRail.d.ts +23 -0
  183. package/lib/types/client/components/QaSidebar.d.ts +14 -0
  184. package/lib/types/client/components/{QaSourcesDrawer.d.ts → QaSourcesPanel.d.ts} +7 -4
  185. package/lib/types/client/components/QaTurnRail.d.ts +6 -0
  186. package/lib/types/client/components/QaWidthHandle.d.ts +14 -7
  187. package/lib/types/client/components/QaWorkGroup.d.ts +5 -3
  188. package/lib/types/client/components/surface-utils.d.ts +11 -0
  189. package/lib/types/client/components/thinking-phrases.d.ts +9 -0
  190. package/lib/types/client/create-session.d.ts +6 -9
  191. package/lib/types/client/failure-copy.d.ts +19 -0
  192. package/lib/types/client/prompt-content.d.ts +30 -0
  193. package/lib/types/client/settings/card.d.ts +23 -0
  194. package/lib/types/client/settings/fields.d.ts +139 -0
  195. package/lib/types/client/settings/format.d.ts +108 -0
  196. package/lib/types/client/settings/sections/access.d.ts +9 -0
  197. package/lib/types/client/settings/sections/accounts.d.ts +9 -0
  198. package/lib/types/client/settings/sections/attachments.d.ts +15 -0
  199. package/lib/types/client/settings/sections/branding.d.ts +8 -0
  200. package/lib/types/client/settings/sections/common.d.ts +28 -0
  201. package/lib/types/client/settings/sections/embedding.d.ts +8 -0
  202. package/lib/types/client/settings/sections/interface.d.ts +9 -0
  203. package/lib/types/client/settings/sections/lockdown.d.ts +9 -0
  204. package/lib/types/client/settings/sections/session.d.ts +9 -0
  205. package/lib/types/client/settings/sections/sources.d.ts +9 -0
  206. package/lib/types/client/settings/sections/status.d.ts +22 -0
  207. package/lib/types/client/settings/sections.d.ts +25 -0
  208. package/lib/types/client/settings/styles.d.ts +8 -0
  209. package/lib/types/client/stream-publisher.d.ts +28 -0
  210. package/lib/types/client/types.d.ts +29 -1
  211. package/lib/types/client/use-right-rail.d.ts +56 -0
  212. package/lib/types/client/use-session-ui-state.d.ts +13 -7
  213. package/lib/types/config-resolvers/accounts.d.ts +15 -0
  214. package/lib/types/config-resolvers/attachments.d.ts +6 -0
  215. package/lib/types/config-resolvers/basics.d.ts +8 -0
  216. package/lib/types/config-resolvers/defaults.d.ts +4 -0
  217. package/lib/types/config-resolvers/lockdown.d.ts +10 -0
  218. package/lib/types/config-resolvers/session.d.ts +6 -0
  219. package/lib/types/config-resolvers/shared.d.ts +16 -0
  220. package/lib/types/config-resolvers/sources.d.ts +6 -0
  221. package/lib/types/config-resolvers/ui.d.ts +6 -0
  222. package/lib/types/index.d.ts +20 -13
  223. package/lib/types/profile.d.ts +76 -0
  224. package/lib/types/prompt-notes.d.ts +110 -0
  225. package/lib/types/resolve-config.d.ts +8 -3
  226. package/lib/types/secure-session.d.ts +26 -1
  227. package/lib/types/shared/session-key.d.ts +23 -0
  228. package/lib/types/shared/settings.d.ts +10 -0
  229. package/lib/types/thinking-phrases.d.ts +17 -0
  230. package/lib/types/types.d.ts +123 -5
  231. package/lib/types/user-workspace.d.ts +38 -0
  232. package/lib/user-workspace.js +231 -0
  233. package/lib/user-workspace.js.map +1 -0
  234. package/package.json +14 -7
  235. package/CHANGELOG.md +0 -176
  236. package/SPEC-dsh-qa-surface.md +0 -2425
  237. package/docs/ARCHITECTURE.md +0 -66
  238. package/docs/COMPATIBILITY.md +0 -14
  239. package/docs/CONFIGURATION.md +0 -199
  240. package/docs/EMBEDDING.md +0 -13
  241. package/docs/SOURCES-MIGRATION.md +0 -28
  242. package/docs/SOURCES-PROVENANCE-AUDIT.md +0 -88
  243. package/docs/SPEC-dsh-qa-surface-accounts.md +0 -219
  244. package/docs/SPEC-dsh-qa-surface-sources-provenance.md +0 -1692
  245. package/lib/client/components/QaSourcesDrawer.js.map +0 -1
@@ -1,1692 +0,0 @@
1
- # SPEC: Structured Sources / Provenance for `dsh-qa-surface`
2
-
3
- Status: Draft / implementation plan
4
- Target: `plugins/dsh-qa-surface`
5
- Scope: source collection, source inheritance from subagents, unified source UI, source preview, Markdown rendering for local `.md` files
6
-
7
- ---
8
-
9
- ## 1. Goal
10
-
11
- Доработать `dsh-qa-surface` так, чтобы источники ответа перестали быть свободно оформленным текстом, который LLM вручную дописывает в конец ответа, и стали **структурированными данными, собираемыми плагином автоматически**.
12
-
13
- После доработки:
14
-
15
- - главный агент не обязан вручную формировать раздел `Источники`;
16
- - источники собираются из фактических tool calls/results текущего turn;
17
- - источники субагентов автоматически наследуются родительским turn;
18
- - один и тот же структурированный набор источников используется:
19
- - в правой панели Sources;
20
- - в компактном footer под ответом;
21
- - при необходимости — для inline citations;
22
- - одинаковые источники дедуплицируются;
23
- - web search discovery не раздувает список до десятков/сотен малоценных ссылок;
24
- - локальные файловые источники можно открыть прямо из QA UI;
25
- - `.md` / `.markdown` файлы по умолчанию открываются как отформатированный Markdown, а не как plain text;
26
- - у Markdown preview есть переключение `Rendered / Raw`;
27
- - источник сохраняет происхождение: parent agent / subagent / конкретный tool call / turn.
28
-
29
- Главный принцип:
30
-
31
- > **LLM отвечает за содержание ответа. Плагин отвечает за provenance и отображение источников.**
32
-
33
- Не использовать natural-language блок `Источники` в assistant message как canonical source of truth.
34
-
35
- ---
36
-
37
- ## 2. Current problems
38
-
39
- По текущему UX наблюдаются несколько проблем.
40
-
41
- ### 2.1. Источники в ответе нестабильны
42
-
43
- LLM может оформить их как:
44
-
45
- ```md
46
- ## Источники
47
-
48
- 1. Документация ...
49
- 2. Jira ...
50
- 3. Confluence ...
51
- 4. Код ...
52
- ```
53
-
54
- или в другом порядке/формате, объединить несколько ссылок в одну строку, забыть часть источников, добавить текст без URL, поменять названия секций и т.п.
55
-
56
- Это делает формат зависимым от модели и prompt adherence.
57
-
58
- ### 2.2. Ответ и Sources sidebar расходятся
59
-
60
- Источник может присутствовать в тексте ответа, но отсутствовать в боковом списке, или наоборот.
61
-
62
- Причина архитектурная: две поверхности получают данные разными путями.
63
-
64
- ### 2.3. Список Sources слишком шумный
65
-
66
- Текущий Activity/Sources может показывать десятки web результатов (`Web · 72`, `Sources · 100`). Для QA-пользователя это практически не отличается от лога поискового движка.
67
-
68
- Особенно плохо считать каждый результат `web_search` полноценным использованным источником, если агент реально открыл/прочитал только несколько страниц.
69
-
70
- ### 2.4. Источники субагентов теряются
71
-
72
- Parent agent видит финальный ответ child/subagent, но provenance внутренних tool calls ребёнка может не попадать в итоговый source list родительского turn.
73
-
74
- ### 2.5. File preview слишком сырой
75
-
76
- Markdown-файлы сейчас могут открываться как raw/plain text. Для документации это заметно хуже стандартного rendered Markdown.
77
-
78
- ---
79
-
80
- ## 3. Non-goals
81
-
82
- В рамках этой доработки не требуется:
83
-
84
- - строить полноценную citation-verification систему, доказывающую, что каждая фраза ответа логически подтверждается источником;
85
- - автоматически генерировать библиографию в академическом стиле;
86
- - делать editable file viewer;
87
- - выполнять JavaScript/HTML из Markdown;
88
- - давать QA-пользователю filesystem navigation;
89
- - открывать произвольные файлы, которые агент не использовал как source;
90
- - превращать каждый grep/glob/search hit в пользовательский источник;
91
- - менять read-only/security policy `/qa`;
92
- - форкать DSH core ради source tracking.
93
-
94
- ---
95
-
96
- ## 4. Design principles
97
-
98
- ### 4.1. Structured first
99
-
100
- Canonical representation источника — typed object, а не строка Markdown.
101
-
102
- ### 4.2. Observe actual tool usage
103
-
104
- Плагин должен в первую очередь собирать provenance из tool presentation/result metadata и session events.
105
-
106
- Не просить LLM повторно пересказывать то, что runtime уже знает.
107
-
108
- ### 4.3. Evidence != discovery
109
-
110
- Нужно различать:
111
-
112
- - **evidence / consumed source** — документ реально был прочитан/получен агентом;
113
- - **discovery candidate** — ссылка/файл только встретился в поисковой выдаче;
114
- - **navigation artifact** — glob/list/grep entry, использованный только для навигации.
115
-
116
- Основной Sources UI показывает evidence sources.
117
-
118
- Discovery candidates могут быть доступны в debug/activity view, но не должны автоматически раздувать пользовательский список Sources.
119
-
120
- ### 4.4. Same data for every presentation
121
-
122
- Sources sidebar, footer и inline citation resolver должны получать один `QaTurnSources` snapshot.
123
-
124
- ### 4.5. Fail soft, not silently wrong
125
-
126
- Если provenance конкретного внешнего subagent provider недоступен, UI должен уметь показать:
127
-
128
- ```text
129
- Sources may be incomplete for 1 delegated run
130
- ```
131
-
132
- в debug mode, а не притворяться, что список гарантированно полный.
133
-
134
- ### 4.6. Reuse DSH structured presentation metadata
135
-
136
- DSH уже имеет structured tool presentation types, включая:
137
-
138
- - file read result (`ReadResultView` с `path`, `offset`, numbered `lines`, `totalLines`, `lang`);
139
- - file search result (`SearchResultView`);
140
- - web search result (`WebSearchResultView.sources`);
141
- - web fetch result (`WebFetchResultView.url`);
142
- - generic call locations (`FileLocation`).
143
-
144
- Где эти данные доступны, extractor обязан использовать их вместо regex parsing model-facing text.
145
-
146
- ---
147
-
148
- ## 5. High-level architecture
149
-
150
- ```text
151
- Parent Agent
152
- │
153
- tool calls / tool results
154
- │
155
- ▼
156
- ┌──────────────────┐
157
- │ Source Collector │◄─────────────┐
158
- └────────┬─────────┘ │
159
- │ │
160
- normalize / classify / dedupe │
161
- │ │
162
- │ Child/Subagent tools
163
- │ │
164
- │ ┌─────────┴─────────┐
165
- │ │ Subagent lineage │
166
- │ │ + child collector │
167
- │ └─────────┬─────────┘
168
- │ │
169
- └────────────┬───────────┘
170
- │
171
- turn/end
172
- │
173
- ▼
174
- ┌─────────────────────┐
175
- │ qa/sources event │
176
- │ QaTurnSources │
177
- └──────────┬──────────┘
178
- │
179
- ┌───────────────┼────────────────┐
180
- │ │ │
181
- ▼ ▼ ▼
182
- Sources sidebar Answer footer Inline citation
183
- resolver
184
- │
185
- ▼
186
- Source preview
187
- │
188
- ┌────────────┴────────────┐
189
- │ │
190
- Web/Jira/... Local file
191
- │
192
- ┌──────────┴──────────┐
193
- │ Markdown | Raw text │
194
- └─────────────────────┘
195
- ```
196
-
197
- ---
198
-
199
- ## 6. Canonical data model
200
-
201
- Suggested types:
202
-
203
- ```ts
204
- export type QaSourceKind =
205
- "file" | "code" | "web" | "jira" | "confluence" | "knowledge" | "other";
206
-
207
- export type QaSourceEvidence =
208
- "read" | "fetched" | "queried" | "reported" | "inherited" | "discovered";
209
-
210
- export interface QaSourceLocation {
211
- path?: string;
212
- lineStart?: number;
213
- lineEnd?: number;
214
- anchor?: string;
215
-
216
- jiraKey?: string;
217
- confluencePageId?: string;
218
- }
219
-
220
- export interface QaSourceOrigin {
221
- sessionId: string;
222
- turn: number;
223
- step?: number;
224
- toolCallId?: string;
225
- toolName?: string;
226
-
227
- agentId?: string;
228
- role: "parent" | "subagent";
229
-
230
- subagentRunId?: string;
231
- subagentSessionId?: string;
232
- }
233
-
234
- export interface QaSourceReference {
235
- /** Stable canonical identity after normalization. */
236
- id: string;
237
-
238
- kind: QaSourceKind;
239
- title: string;
240
-
241
- /** Click target for remote sources. */
242
- uri?: string;
243
-
244
- /** Canonical path for workspace/local sources. */
245
- path?: string;
246
-
247
- /** Optional human-facing description/snippet. */
248
- snippet?: string;
249
-
250
- /** All useful ranges/anchors retained after dedupe. */
251
- locations: QaSourceLocation[];
252
-
253
- /** Why this object is considered a source. */
254
- evidence: QaSourceEvidence;
255
-
256
- /** All parent/subagent/tool origins merged by dedupe. */
257
- origins: QaSourceOrigin[];
258
-
259
- /** Higher means more suitable for main Sources UI. */
260
- score: number;
261
-
262
- metadata?: Record<string, unknown>;
263
- }
264
-
265
- export interface QaTurnSources {
266
- version: 1;
267
- sessionId: string;
268
- turn: number;
269
-
270
- sources: QaSourceReference[];
271
-
272
- /** Optional low-value candidates hidden from the default source list. */
273
- discovered?: QaSourceReference[];
274
-
275
- complete: boolean;
276
-
277
- incompleteOrigins?: Array<{
278
- subagentRunId?: string;
279
- provider?: string;
280
- reason: string;
281
- }>;
282
- }
283
- ```
284
-
285
- ### 6.1. Why keep `origins[]`
286
-
287
- Если один и тот же документ:
288
-
289
- - прочитал parent;
290
- - затем прочитал subagent A;
291
- - затем открыл subagent B;
292
-
293
- в UI должен оставаться один source card, но debug details могут показать `Used by 3 agent runs`.
294
-
295
- ### 6.2. Stable ID rules
296
-
297
- Recommended canonical IDs:
298
-
299
- ```text
300
- file:<workspace-relative-canonical-path>
301
- web:<canonical-url>
302
- jira:<issue-key>
303
- confluence:<space-or-page-id>
304
- knowledge:<backend>:<document-id>
305
- ```
306
-
307
- Line ranges **не включать** в primary source ID.
308
-
309
- Несколько ranges одного файла должны merge'иться в `locations[]`.
310
-
311
- ---
312
-
313
- ## 7. Source collection
314
-
315
- ### 7.1. Preferred integration point
316
-
317
- Primary collection path:
318
-
319
- 1. observe completed tool results;
320
- 2. resolve structured presentation/result metadata;
321
- 3. pass the final typed result through an extractor;
322
- 4. add normalized references to the active turn collector.
323
-
324
- Implementation should prefer DSH's final tool-result observation seam / durable `tool/result` event rather than parsing call text before execution.
325
-
326
- Why:
327
-
328
- - result already knows whether the call succeeded;
329
- - final redirect URL can be known for web fetch;
330
- - read presentation contains structured path/lines;
331
- - web search presentation contains structured source objects;
332
- - session replay can reproduce persisted result metadata.
333
-
334
- ### 7.2. Extractor registry
335
-
336
- Do not write one large `switch(toolName)`.
337
-
338
- Suggested registry:
339
-
340
- ```ts
341
- interface SourceExtractorContext {
342
- toolName: string;
343
- args: unknown;
344
- result: unknown;
345
- presentation?: unknown;
346
- origin: QaSourceOrigin;
347
- }
348
-
349
- interface SourceExtractor {
350
- matches(ctx: SourceExtractorContext): boolean;
351
- extract(ctx: SourceExtractorContext): QaSourceReference[];
352
- }
353
-
354
- class SourceExtractorRegistry {
355
- register(extractor: SourceExtractor): Disposable;
356
- extract(ctx: SourceExtractorContext): QaSourceReference[];
357
- }
358
- ```
359
-
360
- Possible modules:
361
-
362
- ```text
363
- provenance/extractors/
364
- read-file.ts
365
- file-search.ts
366
- web-search.ts
367
- web-fetch.ts
368
- jira.ts
369
- confluence.ts
370
- knowledge.ts
371
- generic-presented-location.ts
372
- reported-source.ts
373
- ```
374
-
375
- ### 7.3. Built-in DSH file read
376
-
377
- For a successful `ReadResultView`:
378
-
379
- ```ts
380
- {
381
- card: ("read", path, offset, lines, totalLines, lang);
382
- }
383
- ```
384
-
385
- create one evidence source:
386
-
387
- ```text
388
- kind = file/code
389
- path = path
390
- evidence = read
391
- lineStart = first returned line
392
- lineEnd = last returned line
393
- score = high
394
- ```
395
-
396
- Classification:
397
-
398
- - documentation-like extension (`.md`, `.markdown`, `.rst`, `.adoc`, `.txt`) → `file`;
399
- - source-code extension → `code`;
400
- - unknown textual → `file`.
401
-
402
- ### 7.4. grep/content search
403
-
404
- `grep` results are useful, but every matched file should not automatically become a high-confidence source.
405
-
406
- Recommended behavior:
407
-
408
- - file only appears in grep result and is never opened/read → `evidence='discovered'`;
409
- - later `read` on the same file promotes/merges it into evidence source;
410
- - optional config may include grep-only files if the grep snippets themselves materially formed the answer.
411
-
412
- Default: keep them in `discovered`, not main Sources.
413
-
414
- ### 7.5. glob/path search/listing
415
-
416
- Treat as navigation only.
417
-
418
- Do not show paths from glob/list results in main Sources unless they are subsequently read.
419
-
420
- ### 7.6. `web_search`
421
-
422
- DSH already exposes a structured `WebSearchResultView.sources` list.
423
-
424
- Important: these are search results, not necessarily pages meaningfully consumed by the agent.
425
-
426
- Therefore:
427
-
428
- - initially add each search result as `evidence='discovered'` with low score;
429
- - if the same URL is later fetched/opened, promote to `evidence='fetched'`;
430
- - if the provider's search result itself is the only retrieval mechanism and returns substantive snippets used by the model, allow a bounded number of top search sources to be promoted by policy.
431
-
432
- Default policy proposal:
433
-
434
- ```yaml
435
- sources:
436
- webSearch:
437
- showDiscovered: false
438
- promoteSearchResultsWithoutFetch: true
439
- maxPromotedPerSearch: 5
440
- ```
441
-
442
- This avoids current situations like `Web · 72` unless those 72 sources were actually meaningful.
443
-
444
- ### 7.7. `web_fetch`
445
-
446
- Successful fetch = strong evidence source.
447
-
448
- Use final redirected URL if DSH supplies it.
449
-
450
- ```text
451
- kind = web
452
- evidence = fetched
453
- score = very high
454
- ```
455
-
456
- Canonicalize URL before dedupe:
457
-
458
- - lowercase host;
459
- - strip known tracking query params (`utm_*`, etc.);
460
- - normalize default port;
461
- - preserve business-relevant query params;
462
- - remove fragment for primary identity unless fragment identifies a distinct documentation section worth keeping as a location/anchor.
463
-
464
- Do not aggressively remove arbitrary query params.
465
-
466
- ### 7.8. Jira
467
-
468
- Support explicit Jira extractors for actual Jira/MCP tool names used in the deployment.
469
-
470
- Canonical identity:
471
-
472
- ```text
473
- jira:MDC-24929
474
- ```
475
-
476
- Data:
477
-
478
- ```ts
479
- {
480
- kind: 'jira',
481
- title: 'MDC-24929 — Вибродоктор. Добавить метод GET /history',
482
- uri: '<actual issue URL>',
483
- locations: [{ jiraKey: 'MDC-24929' }],
484
- evidence: 'queried'
485
- }
486
- ```
487
-
488
- Only issue read/search-result objects actually returned to the model should count.
489
-
490
- Avoid treating login pages, Jira search UI URL, board URLs, etc. as separate sources when a concrete issue is known.
491
-
492
- ### 7.9. Confluence
493
-
494
- Canonical identity should prefer stable page ID over title URL.
495
-
496
- ```text
497
- confluence:<page-id>
498
- ```
499
-
500
- Keep:
501
-
502
- - page title;
503
- - canonical page URL;
504
- - page id;
505
- - optional space key;
506
- - optional anchor/section.
507
-
508
- ### 7.10. Custom knowledge tools
509
-
510
- Provide a small adapter API so internal KB tools can register their own source extractor without modifying core collector code.
511
-
512
- Example:
513
-
514
- ```ts
515
- ctx.qaSources.registerExtractor({
516
- id: 'company-kb',
517
- matches: ({ toolName }) => toolName === 'kb_search' || toolName === 'kb_get',
518
- extract: ...,
519
- })
520
- ```
521
-
522
- If exposing a cross-plugin service is too expensive for first version, keep registry internal but design its types so it can be promoted later.
523
-
524
- ---
525
-
526
- ## 8. Subagent provenance
527
-
528
- This is a required part of the feature, not a later enhancement.
529
-
530
- ### 8.1. Lineage registry
531
-
532
- Observe DSH subagent lifecycle:
533
-
534
- ```text
535
- subagent/start
536
- subagent/end
537
- ```
538
-
539
- Maintain a runtime mapping:
540
-
541
- ```ts
542
- interface SubagentLineage {
543
- runId: string;
544
- parentSessionId: string;
545
- parentTurn: number;
546
- childAgentId?: string;
547
- childSessionId?: string;
548
- provider?: string;
549
- parentRunId?: string;
550
- }
551
- ```
552
-
553
- Nested children must be supported recursively.
554
-
555
- ### 8.2. In-process / observable child agents
556
-
557
- When a child session/agent is observable by the current Host:
558
-
559
- - collect its tool sources exactly as for the parent;
560
- - mark origin `role='subagent'`;
561
- - associate the child source with the parent turn that initiated the delegation;
562
- - on `subagent/end`, merge collected child evidence into parent `QaTurnSources`;
563
- - retain `subagentRunId` in `origins[]`.
564
-
565
- ### 8.3. Nested subagents
566
-
567
- If child A starts child B:
568
-
569
- ```text
570
- Parent turn
571
- └─ A
572
- └─ B
573
- ```
574
-
575
- sources from B should bubble to the original parent turn while retaining full origin lineage.
576
-
577
- No duplicates should be created when A also reports B's source in its final answer.
578
-
579
- ### 8.4. Opaque/external child providers
580
-
581
- Some providers may not expose internal tool-result traffic to the Host.
582
-
583
- For these, automatic observation cannot guarantee complete provenance.
584
-
585
- Add a fallback model-facing tool usable by subagents:
586
-
587
- ```text
588
- qa_report_sources
589
- ```
590
-
591
- Suggested schema:
592
-
593
- ```ts
594
- {
595
- sources: Array<{
596
- kind: "file" | "web" | "jira" | "confluence" | "knowledge" | "other";
597
- title: string;
598
- uri?: string;
599
- path?: string;
600
- lineStart?: number;
601
- lineEnd?: number;
602
- externalId?: string;
603
- }>;
604
- }
605
- ```
606
-
607
- Properties:
608
-
609
- - read-only;
610
- - no external side effects;
611
- - only appends provenance to current child run collector;
612
- - can be called multiple times;
613
- - duplicate-safe;
614
- - never mutates workspace;
615
- - preferably hidden/unavailable to ordinary `/qa` parent unless needed.
616
-
617
- ### 8.5. Companion skill / prompt guidance
618
-
619
- Add a short internal instruction for delegated research:
620
-
621
- ```text
622
- When you use sources that may not be observable by the parent harness,
623
- report them with qa_report_sources before returning your result.
624
- Do not manually format a "Sources" section unless explicitly requested.
625
- ```
626
-
627
- Important: this skill/tool path is **fallback**, not primary architecture.
628
-
629
- The parent agent should not be asked to reconstruct child sources from prose.
630
-
631
- ### 8.6. Completeness flag
632
-
633
- If a child provider is opaque and no `qa_report_sources` calls were received:
634
-
635
- ```ts
636
- complete = false;
637
- incompleteOrigins.push({
638
- subagentRunId,
639
- provider,
640
- reason:
641
- "Child tool provenance is not observable and no structured source report was received.",
642
- });
643
- ```
644
-
645
- In normal QA mode this warning may stay hidden unless the source drawer is expanded into details/debug.
646
-
647
- ---
648
-
649
- ## 9. Turn finalization and persistence
650
-
651
- ### 9.1. Do not add an extra LLM step by default
652
-
653
- At the end of the turn the plugin should finalize sources itself.
654
-
655
- Desired lifecycle:
656
-
657
- ```text
658
- turn/start
659
- collector.open(parent session, turn)
660
-
661
- ...tool results...
662
- ...subagent starts/results/ends...
663
-
664
- turn/end
665
- collector.finalize()
666
- append durable qa/sources event
667
- ```
668
-
669
- ### 9.2. Custom session event
670
-
671
- Use a plugin-owned durable session event if current DSH plugin API allows SessionEventMap declaration merging.
672
-
673
- Suggested event:
674
-
675
- ```ts
676
- declare module "@deepseek-ai/dsh-session" {
677
- interface SessionEventMap {
678
- "qa/sources": QaTurnSources;
679
- }
680
- }
681
- ```
682
-
683
- The event should be log-only / non-message-producing.
684
-
685
- It must not enter model conversation history.
686
-
687
- ### 9.3. Why persist it
688
-
689
- Persistence is required so:
690
-
691
- - session reload produces the same source list;
692
- - UI does not have to re-run extraction over old raw tool text;
693
- - source dedupe/order stays stable;
694
- - source panel works for historical turns;
695
- - future migrations can version the source payload.
696
-
697
- ### 9.4. Replay / migration
698
-
699
- For old sessions without `qa/sources`:
700
-
701
- Preferred fallback:
702
-
703
- 1. reconstruct from historical structured `tool/result` metadata where possible;
704
- 2. do not parse arbitrary final `## Источники` prose by default;
705
- 3. optionally allow one-time legacy parser behind config.
706
-
707
- ```yaml
708
- sources:
709
- legacy:
710
- parseAssistantSourcesBlock: false
711
- ```
712
-
713
- Reason: natural-language parsing would reintroduce the very ambiguity this feature is intended to remove.
714
-
715
- ---
716
-
717
- ## 10. Dedupe and ranking
718
-
719
- ### 10.1. Dedupe
720
-
721
- Merge same canonical source across:
722
-
723
- - repeated reads;
724
- - parent + child;
725
- - multiple subagents;
726
- - web search + web fetch;
727
- - multiple line ranges;
728
- - repeated Jira/Confluence fetches.
729
-
730
- Merge rules:
731
-
732
- ```text
733
- title -> prefer explicit resource title over filename/domain fallback
734
- uri -> prefer canonical/final URL
735
- locations -> union + compact overlapping line ranges
736
- origins -> union
737
- snippet -> keep best non-empty snippet
738
- score -> max / recompute from strongest evidence
739
- ```
740
-
741
- ### 10.2. Evidence promotion
742
-
743
- Example:
744
-
745
- ```text
746
- web_search result -> discovered, score 20
747
- web_fetch same URL -> fetched, score 100
748
- ```
749
-
750
- Final source becomes one object with `evidence='fetched'`.
751
-
752
- ### 10.3. Suggested scoring
753
-
754
- Initial policy, configurable later:
755
-
756
- | Event | Score |
757
- | ------------------------------- | ----: |
758
- | explicit file read | 100 |
759
- | web fetch | 100 |
760
- | Jira issue read | 100 |
761
- | Confluence page read | 100 |
762
- | knowledge document get | 100 |
763
- | structured subagent report | 90 |
764
- | web search source without fetch | 55 |
765
- | grep matched file without read | 30 |
766
- | glob/path discovery | 10 |
767
-
768
- ### 10.4. Default display threshold
769
-
770
- Main Sources UI should show `score >= 50` by default.
771
-
772
- Lower-score objects remain available in diagnostics if retained.
773
-
774
- ---
775
-
776
- ## 11. Source count semantics
777
-
778
- Current `Sources · 100` style count is not useful if it includes every discovery result.
779
-
780
- Change semantics:
781
-
782
- ```text
783
- Sources · N
784
- ```
785
-
786
- where `N` = unique evidence sources shown by default after dedupe/promotion/filtering.
787
-
788
- Optional debug row:
789
-
790
- ```text
791
- Discovered · 73
792
- ```
793
-
794
- should be collapsed/hidden unless explicitly enabled.
795
-
796
- This makes the count understandable to a QA user.
797
-
798
- ---
799
-
800
- ## 12. Sources UI redesign
801
-
802
- The UI should look like a product source browser, not raw tool activity.
803
-
804
- ### 12.1. Main drawer
805
-
806
- Suggested layout:
807
-
808
- ```text
809
- ┌──────────────────────────────────────────┐
810
- │ Sources ✕ │
811
- │ 12 sources │
812
- ├──────────────────────────────────────────┤
813
- │ Documentation · 4 │
814
- │ │
815
- │ [MD] technicalDiagnosis.md │
816
- │ EAM / technicalDiagnosis │
817
- │ lines 197–218 Used by agent │
818
- │ │
819
- │ [MD] products_eam.md │
820
- │ AIS_Dispatcher / products │
821
- │ │
822
- │ Jira · 3 │
823
- │ │
824
- │ [J] MDC-24929 │
825
- │ Вибродоктор. GET /history │
826
- │ │
827
- │ Confluence · 2 │
828
- │ ... │
829
- │ │
830
- │ Web · 3 │
831
- │ ... │
832
- └──────────────────────────────────────────┘
833
- ```
834
-
835
- ### 12.2. Grouping
836
-
837
- Default group order:
838
-
839
- 1. Documentation / Files
840
- 2. Code
841
- 3. Jira
842
- 4. Confluence
843
- 5. Knowledge
844
- 6. Web
845
- 7. Other
846
-
847
- Do not sort alphabetically across categories.
848
-
849
- Within group sort by:
850
-
851
- 1. score descending;
852
- 2. first use/order in turn;
853
- 3. title.
854
-
855
- ### 12.3. Card content
856
-
857
- Each card may show:
858
-
859
- - source icon / type badge;
860
- - short title;
861
- - path/domain/space;
862
- - line range or issue key;
863
- - optional favicon/service icon;
864
- - optional `Subagent` indicator;
865
- - optional `Used by N agents` only in details/tooltip;
866
- - external-link icon for remote resources.
867
-
868
- Avoid showing long raw URLs if title exists.
869
-
870
- ### 12.4. Source details
871
-
872
- On hover/secondary details:
873
-
874
- ```text
875
- Used by:
876
- - Parent · read · turn 4
877
- - Subagent "Search Jira" · jira_get
878
-
879
- Locations:
880
- - lines 197–218
881
- - lines 355–371
882
- ```
883
-
884
- This is useful for debugging but should not clutter the default card.
885
-
886
- ### 12.5. Footer under answer
887
-
888
- Replace free-form model-written `## Источники` with a deterministic UI footer.
889
-
890
- Example compact state:
891
-
892
- ```text
893
- Sources 12 [Documentation 4] [Jira 3] [Confluence 2] [Web 3] ›
894
- ```
895
-
896
- Expanded:
897
-
898
- ```text
899
- Sources
900
-
901
- Documentation
902
- • technicalDiagnosis.md · 197–218
903
- • products_eam.md
904
-
905
- Jira
906
- • MDC-24929 — Вибродоктор. GET /history
907
- ...
908
- ```
909
-
910
- Both footer and drawer must render from the same `QaTurnSources` object.
911
-
912
- ### 12.6. Avoid duplicated textual Sources block
913
-
914
- Add system-prompt guidance:
915
-
916
- ```text
917
- The QA surface renders collected sources automatically.
918
- Do not append a manual Sources/Источники section unless the user explicitly asks for a textual bibliography.
919
- ```
920
-
921
- Do not depend on this for data correctness; it is only to avoid duplicate visual output.
922
-
923
- ---
924
-
925
- ## 13. File source preview
926
-
927
- ### 13.1. Click behavior
928
-
929
- Clicking a local file source opens a source preview surface (existing drawer/modal/dock area is acceptable).
930
-
931
- Header example:
932
-
933
- ```text
934
- Library / docs / User_Guide / EAM / ... / technicalDiagnosis.md
935
- Raw/Rendered Download ✕
936
- ```
937
-
938
- ### 13.2. Markdown default
939
-
940
- For extensions:
941
-
942
- ```text
943
- .md
944
- .markdown
945
- ```
946
-
947
- open in `Rendered` mode by default.
948
-
949
- For ordinary source code/text:
950
-
951
- - use existing line-numbered/syntax-highlighted text/code preview;
952
- - default to raw/code presentation.
953
-
954
- ### 13.3. Rendered / Raw toggle
955
-
956
- For Markdown provide:
957
-
958
- ```text
959
- [Rendered] [Raw]
960
- ```
961
-
962
- State can be local to the preview component.
963
-
964
- Optional: remember preference per extension for current browser session.
965
-
966
- ### 13.4. Reuse DSH `MarkdownText`
967
-
968
- Preferred implementation: use the existing DSH `MarkdownText` primitive from `@deepseek-ai/dsh-client-ui-primitives` if accessible through the plugin's supported dependency/injection model.
969
-
970
- Reasons:
971
-
972
- - already supports GFM-style Markdown;
973
- - already handles untrusted assistant Markdown safely;
974
- - raw HTML is not executed;
975
- - links are constrained/sanitized;
976
- - style matches the rest of DSH Web.
977
-
978
- Do not introduce a second unrelated Markdown renderer unless the existing primitive cannot be cleanly consumed from an out-of-tree plugin.
979
-
980
- If direct cross-package value import violates the current DSH client-plugin boundary in the exact target version, either:
981
-
982
- 1. use the officially allowed package dependency if the package is a public primitive library;
983
- 2. expose an internal qa-surface renderer adapter;
984
- 3. as fallback, use a minimal Markdown renderer with equivalent sanitization behavior.
985
-
986
- Do not render Markdown with `dangerouslySetInnerHTML` from unsanitized source.
987
-
988
- ### 13.5. Markdown features
989
-
990
- Required:
991
-
992
- - headings;
993
- - paragraphs;
994
- - lists;
995
- - blockquotes;
996
- - inline/fenced code;
997
- - tables;
998
- - links;
999
- - emphasis/strong;
1000
- - horizontal rules.
1001
-
1002
- Nice-to-have:
1003
-
1004
- - task lists;
1005
- - KaTeX if already inherited from DSH renderer;
1006
- - anchor navigation;
1007
- - syntax highlighting inside fenced blocks.
1008
-
1009
- ### 13.6. Relative links inside Markdown
1010
-
1011
- A Markdown document may contain:
1012
-
1013
- ```md
1014
- [See architecture](../architecture.md)
1015
- ```
1016
-
1017
- Phase 1:
1018
-
1019
- - do not navigate browser to arbitrary relative URL;
1020
- - render it as a safe file-source link only if target can be resolved inside allowed QA workspace root;
1021
- - otherwise show as non-clickable or raw link text.
1022
-
1023
- Phase 2 may allow opening linked local Markdown documents in the same previewer, but only through Host-side canonical path validation.
1024
-
1025
- ### 13.7. Line highlighting
1026
-
1027
- If source has a line range:
1028
-
1029
- ```text
1030
- technicalDiagnosis.md · lines 197–218
1031
- ```
1032
-
1033
- Raw mode should scroll to and visually highlight that range.
1034
-
1035
- Rendered Markdown cannot reliably map every original source line to exact DOM nodes after Markdown parsing.
1036
-
1037
- Therefore:
1038
-
1039
- - best effort: scroll to nearest heading/section if an anchor is available;
1040
- - provide a visible `Referenced lines: 197–218` chip;
1041
- - `View raw at lines 197–218` jumps to exact raw line range.
1042
-
1043
- Do not fake exact rendered-line highlighting.
1044
-
1045
- ### 13.8. Large files
1046
-
1047
- Avoid loading/rendering unlimited files in browser.
1048
-
1049
- Suggested defaults:
1050
-
1051
- ```yaml
1052
- sources:
1053
- filePreview:
1054
- maxBytes: 2_000_000
1055
- maxMarkdownRenderBytes: 1_000_000
1056
- ```
1057
-
1058
- If too large:
1059
-
1060
- ```text
1061
- This file is too large for rendered preview.
1062
- [Open raw excerpt] [Download]
1063
- ```
1064
-
1065
- Use existing Host/file read service where possible rather than exposing a new unrestricted arbitrary-file HTTP endpoint.
1066
-
1067
- ---
1068
-
1069
- ## 14. Remote source behavior
1070
-
1071
- ### Web
1072
-
1073
- Click opens canonical URL in new tab with safe `noopener/noreferrer` behavior.
1074
-
1075
- Optional future enhancement: cached fetched-text preview, but not required now.
1076
-
1077
- ### Jira / Confluence
1078
-
1079
- Default:
1080
-
1081
- - open canonical application URL in new tab;
1082
- - if a structured content payload was already returned by the connector/tool, optionally show an in-QA preview before external navigation.
1083
-
1084
- Do not store credentials in the browser for source rendering.
1085
-
1086
- ---
1087
-
1088
- ## 15. Inline citations (optional phase)
1089
-
1090
- This is not required for MVP, but the data model should allow it.
1091
-
1092
- Possible model guidance:
1093
-
1094
- ```text
1095
- When useful, cite collected sources by stable id:
1096
- [[source:file:docs/foo.md]]
1097
- [[source:jira:MDC-24929]]
1098
- ```
1099
-
1100
- UI converts them into compact citation chips such as `[1]`.
1101
-
1102
- However do not make `QaTurnSources` dependent on inline citations.
1103
-
1104
- Sources must still be collected even if the model emits zero citation markers.
1105
-
1106
- No extra turn-stopping LLM rewrite by default.
1107
-
1108
- ---
1109
-
1110
- ## 16. Proposed configuration
1111
-
1112
- ```yaml
1113
- sources:
1114
- enabled: true
1115
-
1116
- collect:
1117
- parentAgent: true
1118
- subagents: true
1119
- persistTurnEvent: true
1120
-
1121
- display:
1122
- sidebar: true
1123
- footer: true
1124
- groupByKind: true
1125
- showDiscovered: false
1126
- showOriginBadges: false
1127
- maxInitiallyVisiblePerGroup: 8
1128
-
1129
- webSearch:
1130
- promoteSearchResultsWithoutFetch: true
1131
- maxPromotedPerSearch: 5
1132
-
1133
- dedupe:
1134
- normalizeUrls: true
1135
- stripTrackingParams: true
1136
- mergeFileRanges: true
1137
-
1138
- filePreview:
1139
- enabled: true
1140
- markdownRenderedByDefault: true
1141
- allowRawToggle: true
1142
- maxBytes: 2000000
1143
- maxMarkdownRenderBytes: 1000000
1144
-
1145
- subagents:
1146
- inheritSources: true
1147
- enableReportToolFallback: true
1148
- markIncompleteOpaqueRuns: true
1149
-
1150
- legacy:
1151
- parseAssistantSourcesBlock: false
1152
- ```
1153
-
1154
- All defaults should remain compatible with `/qa` read-only mode.
1155
-
1156
- ---
1157
-
1158
- ## 17. Suggested code structure
1159
-
1160
- Adapt to the actual current plugin layout after repository audit.
1161
-
1162
- ```text
1163
- plugins/dsh-qa-surface/
1164
- src/
1165
- host/
1166
- provenance/
1167
- types.ts
1168
- collector.ts
1169
- turn-store.ts
1170
- normalize.ts
1171
- dedupe.ts
1172
- scoring.ts
1173
- lineage.ts
1174
- event.ts
1175
-
1176
- extractors/
1177
- registry.ts
1178
- read-file.ts
1179
- file-search.ts
1180
- web-search.ts
1181
- web-fetch.ts
1182
- jira.ts
1183
- confluence.ts
1184
- knowledge.ts
1185
- generic-location.ts
1186
- reported.ts
1187
-
1188
- tools/
1189
- report-sources.ts
1190
-
1191
- prompt/
1192
- source-guidance.ts
1193
-
1194
- remotes/
1195
- sources.ts
1196
- file-preview.ts
1197
-
1198
- client/
1199
- sources/
1200
- SourcesPanel.tsx
1201
- SourcesGroup.tsx
1202
- SourceCard.tsx
1203
- SourceFooter.tsx
1204
- SourceIcon.tsx
1205
- SourceDetails.tsx
1206
- source-store.ts
1207
-
1208
- preview/
1209
- SourcePreview.tsx
1210
- FilePreview.tsx
1211
- MarkdownPreview.tsx
1212
- RawFilePreview.tsx
1213
- PreviewHeader.tsx
1214
-
1215
- styles/
1216
- sources.module.css
1217
- preview.module.css
1218
- ```
1219
-
1220
- If the plugin already has host/client folders with different naming, preserve existing conventions instead of mechanically applying this tree.
1221
-
1222
- ---
1223
-
1224
- ## 18. Host/client contract
1225
-
1226
- The browser should not infer sources from rendered chat nodes.
1227
-
1228
- Preferred flow:
1229
-
1230
- ```text
1231
- Host persisted qa/sources event
1232
- ↓
1233
- existing session transport / remote projection
1234
- ↓
1235
- client source store keyed by sessionId + turn
1236
- ↓
1237
- SourcesPanel / SourceFooter
1238
- ```
1239
-
1240
- For file preview, use an explicit read-only Host capability with workspace-root validation if the existing DSH workspace-file read service cannot be reused.
1241
-
1242
- Example narrow contract:
1243
-
1244
- ```ts
1245
- interface QaSourcePreviewApi {
1246
- readFile(input: {
1247
- sessionId: string;
1248
- path: string;
1249
- maxBytes?: number;
1250
- }): Promise<{
1251
- path: string;
1252
- content: string;
1253
- size: number;
1254
- truncated: boolean;
1255
- mime?: string;
1256
- }>;
1257
- }
1258
- ```
1259
-
1260
- Security requirements:
1261
-
1262
- - canonicalize path on Host;
1263
- - ensure path is inside allowed workspace/root;
1264
- - reject symlink escape according to the deployment's existing file security semantics;
1265
- - no arbitrary absolute-path browser API;
1266
- - no write endpoint;
1267
- - source preview request does not relax QA sandbox/tool policy.
1268
-
1269
- ---
1270
-
1271
- ## 19. Source presentation mapping
1272
-
1273
- Suggested source labels/icons:
1274
-
1275
- | Kind | Label | Example |
1276
- | ------------ | -------------------- | ---------------------------- |
1277
- | `file` | Documentation / File | `technicalDiagnosis.md` |
1278
- | `code` | Code | `ActivitySectionTypeEnum.cs` |
1279
- | `jira` | Jira | `MDC-24929` |
1280
- | `confluence` | Confluence | `Вибродиагностика MM3` |
1281
- | `knowledge` | Knowledge | KB document |
1282
- | `web` | Web | GitHub / docs site |
1283
- | `other` | Other | connector-specific source |
1284
-
1285
- Web source title fallback order:
1286
-
1287
- 1. tool/provider supplied title;
1288
- 2. page title cached by fetch;
1289
- 3. hostname + shortened path;
1290
- 4. raw URL only as last resort.
1291
-
1292
- File title:
1293
-
1294
- - primary: basename;
1295
- - secondary: shortened directory path;
1296
- - never show huge absolute host filesystem path to QA user if workspace-relative path is available.
1297
-
1298
- ---
1299
-
1300
- ## 20. UI states
1301
-
1302
- ### No sources
1303
-
1304
- Do not render an empty `Sources` footer.
1305
-
1306
- Sidebar source action may be hidden/disabled.
1307
-
1308
- ### Loading / active turn
1309
-
1310
- Sources may appear incrementally while the turn is running, but mark them as provisional.
1311
-
1312
- At `turn/end`, replace with finalized snapshot.
1313
-
1314
- ### Error
1315
-
1316
- Source preview failure:
1317
-
1318
- ```text
1319
- Could not open this source.
1320
- The source may have moved or is no longer accessible.
1321
- ```
1322
-
1323
- Do not expose raw Host stack traces.
1324
-
1325
- ### Truncated source
1326
-
1327
- Show a small `Partial` badge if file/web result was truncated.
1328
-
1329
- ### Incomplete subagent provenance
1330
-
1331
- Only show in debug/details by default:
1332
-
1333
- ```text
1334
- Some delegated-source provenance is unavailable.
1335
- ```
1336
-
1337
- ---
1338
-
1339
- ## 21. Testing plan
1340
-
1341
- ### 21.1. Unit: normalization
1342
-
1343
- Test:
1344
-
1345
- - URL canonicalization;
1346
- - tracking parameter removal;
1347
- - Jira key canonicalization;
1348
- - Confluence page-id identity;
1349
- - workspace path normalization;
1350
- - line-range compaction.
1351
-
1352
- ### 21.2. Unit: dedupe
1353
-
1354
- Cases:
1355
-
1356
- - same URL from search + fetch;
1357
- - same file read twice at overlapping ranges;
1358
- - same Jira issue by parent + child;
1359
- - same source from nested subagents;
1360
- - stronger evidence promotes weaker evidence.
1361
-
1362
- ### 21.3. Unit: extractors
1363
-
1364
- Fixtures for:
1365
-
1366
- - DSH `ReadResultView`;
1367
- - DSH `SearchResultView`;
1368
- - DSH `WebSearchResultView`;
1369
- - DSH `WebFetchResultView`;
1370
- - Jira connector payload;
1371
- - Confluence connector payload;
1372
- - structured `qa_report_sources` input.
1373
-
1374
- ### 21.4. Integration: turn lifecycle
1375
-
1376
- Scenario:
1377
-
1378
- ```text
1379
- user prompt
1380
- → parent reads docs/a.md
1381
- → parent web_search returns 10 results
1382
- → parent fetches 2 results
1383
- → turn ends
1384
- ```
1385
-
1386
- Expected:
1387
-
1388
- - `docs/a.md` included;
1389
- - 2 fetched web pages included;
1390
- - at most configured number of search-only results included;
1391
- - no duplicates;
1392
- - persisted `qa/sources` event exists.
1393
-
1394
- ### 21.5. Integration: subagent inheritance
1395
-
1396
- Scenario:
1397
-
1398
- ```text
1399
- parent
1400
- → starts child A
1401
- → reads docs/a.md
1402
- → reads Jira MDC-1
1403
- → child ends
1404
- → parent reads docs/a.md
1405
- → parent ends
1406
- ```
1407
-
1408
- Expected:
1409
-
1410
- - one `docs/a.md` card with parent + child origins;
1411
- - one Jira card;
1412
- - parent turn source bundle owns both.
1413
-
1414
- ### 21.6. Integration: nested subagent
1415
-
1416
- Parent → A → B, B reads source.
1417
-
1418
- Expected source appears in parent turn with nested origin chain preserved.
1419
-
1420
- ### 21.7. Integration: opaque provider fallback
1421
-
1422
- Opaque child calls `qa_report_sources`.
1423
-
1424
- Expected reported source merged into parent bundle.
1425
-
1426
- Opaque child does not report.
1427
-
1428
- Expected `complete=false` and incomplete origin metadata.
1429
-
1430
- ### 21.8. UI: source panel
1431
-
1432
- Test:
1433
-
1434
- - grouping;
1435
- - counts;
1436
- - dedupe;
1437
- - collapsed/expanded groups;
1438
- - long titles;
1439
- - source click;
1440
- - external-link behavior;
1441
- - subagent badge/details;
1442
- - zero-state.
1443
-
1444
- ### 21.9. UI: Markdown preview
1445
-
1446
- Test `.md` file with:
1447
-
1448
- - headings;
1449
- - lists;
1450
- - table;
1451
- - fenced code;
1452
- - links;
1453
- - HTML/script attempt;
1454
- - large document;
1455
- - rendered/raw switch;
1456
- - referenced line range.
1457
-
1458
- Unsafe HTML/script must not execute.
1459
-
1460
- ### 21.10. Reload/replay
1461
-
1462
- Reload browser/session.
1463
-
1464
- Expected source order and counts remain identical without re-running tools.
1465
-
1466
- ---
1467
-
1468
- ## 22. Acceptance criteria
1469
-
1470
- Feature is complete when all of the following hold:
1471
-
1472
- 1. Final assistant response no longer needs to manually produce a Sources section.
1473
- 2. A turn that reads/fetches known resources produces a structured `QaTurnSources` bundle automatically.
1474
- 3. Sources panel and answer footer use the same bundle.
1475
- 4. Repeated sources are deduplicated.
1476
- 5. Parent and observable subagent sources are merged into one turn-level source set.
1477
- 6. Nested subagent sources are inherited.
1478
- 7. Opaque subagents have `qa_report_sources` fallback and completeness tracking.
1479
- 8. Web search results do not automatically flood the main source list with every candidate.
1480
- 9. `Sources · N` reflects unique visible evidence sources, not raw tool-result count.
1481
- 10. File source cards open a safe file preview.
1482
- 11. `.md` and `.markdown` open rendered by default.
1483
- 12. Markdown preview offers `Rendered / Raw` toggle.
1484
- 13. Raw mode can jump to referenced line range.
1485
- 14. Markdown rendering does not execute raw HTML/JS.
1486
- 15. Session reload restores the same source bundle from persisted state.
1487
- 16. Source collection does not require an extra LLM call at end of every turn.
1488
- 17. `/qa` remains read-only; source preview introduces no write/control capability.
1489
- 18. Existing non-QA DSH UI remains unaffected unless explicitly wired to the new source service.
1490
-
1491
- ---
1492
-
1493
- ## 23. Implementation phases
1494
-
1495
- ### Phase 0 — audit current `dsh-qa-surface`
1496
-
1497
- Before coding:
1498
-
1499
- - identify current source-panel implementation;
1500
- - identify how current DSH Sources/Activity data reaches QA UI;
1501
- - identify available tool presentation metadata in the pinned DSH version;
1502
- - identify exact subagent lifecycle payloads;
1503
- - identify existing file preview/read remote that can be reused;
1504
- - identify whether `MarkdownText` is safely consumable by the out-of-tree client plugin.
1505
-
1506
- Do not duplicate an existing DSH service if current version already exposes equivalent structured source/file-preview capabilities.
1507
-
1508
- ### Phase 1 — structured parent sources
1509
-
1510
- Implement:
1511
-
1512
- - canonical types;
1513
- - extractor registry;
1514
- - read/web extractors;
1515
- - dedupe/ranking;
1516
- - turn collector;
1517
- - persisted `qa/sources`;
1518
- - simple source panel bound to structured bundle.
1519
-
1520
- No subagents yet only if needed to keep the first PR reviewable, but types must already support origins.
1521
-
1522
- ### Phase 2 — subagents
1523
-
1524
- Implement:
1525
-
1526
- - `subagent/start/end` lineage;
1527
- - child collection;
1528
- - nested inheritance;
1529
- - `qa_report_sources` fallback;
1530
- - completeness metadata.
1531
-
1532
- ### Phase 3 — polished Sources UX
1533
-
1534
- Implement:
1535
-
1536
- - grouped cards;
1537
- - compact footer;
1538
- - source details;
1539
- - useful count semantics;
1540
- - hide discovery noise;
1541
- - icons/badges.
1542
-
1543
- ### Phase 4 — file preview + Markdown
1544
-
1545
- Implement:
1546
-
1547
- - click-to-preview;
1548
- - secure Host file read/reuse existing service;
1549
- - `Rendered / Raw`;
1550
- - DSH `MarkdownText` reuse;
1551
- - line-range jump in raw mode;
1552
- - size limits.
1553
-
1554
- ### Phase 5 — optional inline citations
1555
-
1556
- Only after structured source data is stable.
1557
-
1558
- Do not block MVP on inline citation generation.
1559
-
1560
- ---
1561
-
1562
- ## 24. Migration from current textual Sources behavior
1563
-
1564
- During transition:
1565
-
1566
- 1. keep current source panel available behind feature flag if needed;
1567
- 2. enable structured collector;
1568
- 3. compare structured source bundle to current UI during development;
1569
- 4. switch Sources panel to structured bundle;
1570
- 5. add system guidance suppressing manual `Источники` block;
1571
- 6. remove any code that parses assistant prose into Sources;
1572
- 7. retain optional legacy parser only for historical sessions if genuinely needed.
1573
-
1574
- Feature flags example:
1575
-
1576
- ```yaml
1577
- sources:
1578
- implementation: structured # structured | legacy
1579
- ```
1580
-
1581
- Remove `legacy` after migration period if no longer required.
1582
-
1583
- ---
1584
-
1585
- ## 25. Important implementation constraints
1586
-
1587
- ### Do
1588
-
1589
- - treat session/tool metadata as authority;
1590
- - preserve provenance across replay;
1591
- - reuse DSH presentation metadata;
1592
- - keep Host-side path validation;
1593
- - keep source UI deterministic;
1594
- - store source origin information even if default UI hides it;
1595
- - make source extractors independently testable;
1596
- - preserve current plugin's out-of-tree installability.
1597
-
1598
- ### Do not
1599
-
1600
- - regex-parse arbitrary final assistant text as the main source mechanism;
1601
- - require the parent LLM to copy child sources into its final answer;
1602
- - show every `web_search` result as an equal source;
1603
- - expose an arbitrary file-read endpoint to the browser;
1604
- - use unsanitized `dangerouslySetInnerHTML` for Markdown;
1605
- - make source collection depend on a second completion after `turn/end`;
1606
- - fork DSH core for logic that can live in the plugin.
1607
-
1608
- ---
1609
-
1610
- ## 26. Notes for coding agent
1611
-
1612
- 1. Start by reading the current `plugins/dsh-qa-surface` source. This SPEC describes target behavior, not assumed current file names.
1613
- 2. Verify APIs against the exact DSH version pinned by the monorepo before coding; upstream DSH is moving quickly.
1614
- 3. Prefer typed DSH tool presentation metadata over tool-name-specific text parsing.
1615
- 4. Keep extraction adapters narrow; Jira/Confluence payloads may vary by MCP/provider.
1616
- 5. If the current DSH Sources panel already exposes a structured source model that covers part of this design, reuse/adapt it instead of building a parallel source universe.
1617
- 6. Add tests with representative real payload fixtures from the currently configured Jira/Confluence/web tools.
1618
- 7. Keep all source-preview capabilities read-only and compatible with the existing `/qa` lockdown policy.
1619
- 8. If implementation discovers a required upstream gap, document the gap before introducing a runtime patch.
1620
-
1621
- ---
1622
-
1623
- ## 27. Relevant upstream DSH references
1624
-
1625
- These are architecture references for implementation; verify against the exact pinned commit/version during development.
1626
-
1627
- - DSH tool subsystem / execution pipeline:
1628
- `https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/tools.md`
1629
-
1630
- - Structured tool presentation types (`ReadResultView`, `WebSearchResultView`, `WebFetchResultView`, file/search views):
1631
- `https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/tools/src/presentation.ts`
1632
-
1633
- - Session event model / extensible `SessionEventMap`:
1634
- `https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/session.md`
1635
-
1636
- - Subagent lifecycle (`subagent/start`, `subagent/end`):
1637
- `https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/subagent.md`
1638
-
1639
- - Web client architecture:
1640
- `https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/web-client.md`
1641
-
1642
- - DSH Markdown primitive / UI primitives documentation:
1643
- `https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/client/ui-primitives`
1644
-
1645
- ---
1646
-
1647
- ## 28. Desired end-state example
1648
-
1649
- User asks a QA question.
1650
-
1651
- Internally:
1652
-
1653
- ```text
1654
- parent
1655
- ├─ read docs/User_Guide/EAM/.../technicalDiagnosis.md:197-218
1656
- ├─ subagent "Jira research"
1657
- │ ├─ Jira MDC-24929
1658
- │ ├─ Jira MDC-23617
1659
- │ └─ Confluence page 12345
1660
- ├─ web_search -> 10 candidates
1661
- └─ web_fetch -> 2 actual pages
1662
- ```
1663
-
1664
- Assistant only writes the answer.
1665
-
1666
- No manually generated bibliography is required.
1667
-
1668
- QA UI renders:
1669
-
1670
- ```text
1671
- Ответ ...
1672
-
1673
- ────────────────────────────────────────
1674
- Sources · 7
1675
- Documentation 1 · Jira 2 · Confluence 1 · Web 2 · ...
1676
- ```
1677
-
1678
- Opening `technicalDiagnosis.md` shows:
1679
-
1680
- ```text
1681
- [Rendered] [Raw]
1682
-
1683
- # Technical Diagnosis
1684
-
1685
- ...proper formatted Markdown...
1686
- ```
1687
-
1688
- `Raw` jumps to lines `197–218`.
1689
-
1690
- The Sources sidebar shows the exact same seven canonical source objects, grouped and deduplicated, including sources obtained by the subagent.
1691
-
1692
- That is the target behavior.