@yfwu2020/dsh-selection-explain 0.10.3 → 0.10.5

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 (119) hide show
  1. package/README.md +13 -11
  2. package/cordis.patch.yml +1 -1
  3. package/lib/client.js +10694 -12424
  4. package/lib/client.js.map +7 -0
  5. package/lib/config-values.js +55 -0
  6. package/lib/config-values.js.map +1 -0
  7. package/lib/host/analyze.js +795 -0
  8. package/lib/host/analyze.js.map +1 -0
  9. package/lib/host/config.js +81 -0
  10. package/lib/host/config.js.map +1 -0
  11. package/lib/host/constants.js +25 -0
  12. package/lib/host/constants.js.map +1 -0
  13. package/lib/host/context.js +237 -0
  14. package/lib/host/context.js.map +1 -0
  15. package/lib/host/design-skill.js +42 -0
  16. package/lib/host/design-skill.js.map +1 -0
  17. package/lib/host/effort.js +239 -0
  18. package/lib/host/effort.js.map +1 -0
  19. package/lib/host/filters.js +132 -0
  20. package/lib/host/filters.js.map +1 -0
  21. package/lib/host/history-store.js +404 -0
  22. package/lib/host/history-store.js.map +1 -0
  23. package/lib/host/http.js +46 -0
  24. package/lib/host/http.js.map +1 -0
  25. package/lib/host/messages.js +14 -0
  26. package/lib/host/messages.js.map +1 -0
  27. package/lib/host/mic.js +246 -0
  28. package/lib/host/mic.js.map +1 -0
  29. package/lib/host/models.js +246 -0
  30. package/lib/host/models.js.map +1 -0
  31. package/lib/host/plugin.js +41 -0
  32. package/lib/host/plugin.js.map +1 -0
  33. package/lib/host/promote.js +219 -0
  34. package/lib/host/promote.js.map +1 -0
  35. package/lib/host/routes.js +237 -0
  36. package/lib/host/routes.js.map +1 -0
  37. package/lib/host/sessions.js +181 -0
  38. package/lib/host/sessions.js.map +1 -0
  39. package/lib/host/settings-store.js +140 -0
  40. package/lib/host/settings-store.js.map +1 -0
  41. package/lib/host/speech.js +320 -0
  42. package/lib/host/speech.js.map +1 -0
  43. package/lib/host/tools.js +179 -0
  44. package/lib/host/tools.js.map +1 -0
  45. package/lib/host/types.js +2 -0
  46. package/lib/host/types.js.map +1 -0
  47. package/lib/index.js +10 -3691
  48. package/lib/index.js.map +1 -1
  49. package/lib/prompts.js +1 -1
  50. package/lib/settings.js +17 -27
  51. package/lib/settings.js.map +1 -1
  52. package/lib/types/config-values.d.ts +175 -0
  53. package/lib/types/host/analyze.d.ts +10 -0
  54. package/lib/types/host/config.d.ts +147 -0
  55. package/lib/types/host/constants.d.ts +24 -0
  56. package/lib/types/host/context.d.ts +41 -0
  57. package/lib/types/host/design-skill.d.ts +1 -0
  58. package/lib/types/host/effort.d.ts +61 -0
  59. package/lib/types/host/filters.d.ts +20 -0
  60. package/lib/types/host/history-store.d.ts +13 -0
  61. package/lib/types/host/http.d.ts +8 -0
  62. package/lib/types/host/messages.d.ts +13 -0
  63. package/lib/types/host/mic.d.ts +17 -0
  64. package/lib/types/host/models.d.ts +57 -0
  65. package/lib/types/host/plugin.d.ts +3 -0
  66. package/lib/types/host/promote.d.ts +9 -0
  67. package/lib/types/host/routes.d.ts +14 -0
  68. package/lib/types/host/sessions.d.ts +14 -0
  69. package/lib/types/host/settings-store.d.ts +8 -0
  70. package/lib/types/host/speech.d.ts +23 -0
  71. package/lib/types/host/tools.d.ts +39 -0
  72. package/lib/types/host/types.d.ts +89 -0
  73. package/lib/types/index.d.ts +12 -441
  74. package/lib/types/prompts.d.ts +1 -1
  75. package/lib/types/settings.d.ts +1 -1
  76. package/package.json +31 -21
  77. package/assets/code.png +0 -0
  78. package/assets/detail.png +0 -0
  79. package/assets/quotes.png +0 -0
  80. package/assets/stage1.png +0 -0
  81. package/assets/stage2.png +0 -0
  82. package/assets/translation.png +0 -0
  83. package/assets/voice-card-light.png +0 -0
  84. package/assets/voice-inserted.png +0 -0
  85. package/assets/voice-settings.png +0 -0
  86. package/assets/voice.png +0 -0
  87. package/assets/web.png +0 -0
  88. package/scripts/build-demo-pages.mjs +0 -350
  89. package/scripts/build-vcard-lab.mjs +0 -834
  90. package/scripts/build.sh +0 -147
  91. package/scripts/crop-png.mjs +0 -142
  92. package/scripts/dump-prompt.mjs +0 -143
  93. package/scripts/fixtures/fake-mic-probe.sh +0 -9
  94. package/scripts/gen-star-path.mjs +0 -71
  95. package/scripts/measure-cost.mjs +0 -251
  96. package/scripts/smoke-bridge.mjs +0 -365
  97. package/scripts/smoke-panel.mjs +0 -1903
  98. package/scripts/smoke-voice.mjs +0 -774
  99. package/scripts/test-bridge.mjs +0 -412
  100. package/scripts/test-client.mjs +0 -6175
  101. package/scripts/test-effort-map.mjs +0 -129
  102. package/scripts/test-effort-retry.mjs +0 -109
  103. package/scripts/test-escape-focus.mjs +0 -101
  104. package/scripts/test-filters.mjs +0 -146
  105. package/scripts/test-format.mjs +0 -93
  106. package/scripts/test-guard.mjs +0 -48
  107. package/scripts/test-mic-idle.mjs +0 -158
  108. package/scripts/test-model-follow.mjs +0 -193
  109. package/scripts/test-prompt.mjs +0 -193
  110. package/scripts/test-route-cache.mjs +0 -138
  111. package/scripts/test-settings-behavior.mjs +0 -188
  112. package/scripts/test-settings-host.mjs +0 -48
  113. package/scripts/test-settings.mjs +0 -329
  114. package/scripts/test-speech.mjs +0 -220
  115. package/scripts/test-transcript.mjs +0 -151
  116. package/src/client/index.js +0 -12580
  117. package/src/index.ts +0 -4179
  118. package/src/prompts.ts +0 -144
  119. package/src/settings.ts +0 -313
@@ -1,151 +0,0 @@
1
- /**
2
- * 会话背景窗口的离线测试(不依赖运行中的 host)。
3
- *
4
- * 覆盖:
5
- * · 窗口锚定「选中文字所在的消息」,向上最多 maxMessages 条(含锚点),其后的对话不进去
6
- * · 默认不做任何字数截断(长消息整条保留)
7
- * · 工具结果 / 系统提示 / harness 注入的 user 消息全部剔除
8
- * · 定位不到选中位置时退回最近 maxMessages 条
9
- *
10
- * 用法:node scripts/test-transcript.mjs (先 npm run build)
11
- */
12
- import { quoteContextOf, transcriptOf } from '../lib/index.js'
13
-
14
- let failed = 0
15
- const assert = (label, ok, extra) => {
16
- console.log(`${ok ? 'PASS' : 'FAIL'} ${label}${extra ? ' — ' + extra : ''}`)
17
- if (!ok) failed += 1
18
- }
19
-
20
- const userEvent = (text, kind = 'user') => ({
21
- type: 'user/message',
22
- data: { role: 'user', source: { kind }, content: [{ type: 'text', text }] },
23
- })
24
- const assistantEvent = (text) => ({ type: 'assistant/message', data: { message: { content: [{ type: 'text', text }] } } })
25
- const toolEvent = () => ({ type: 'tool/result', data: { message: { content: [{ type: 'tool-result', toolCallId: 't' }] } } })
26
- const systemEvent = (text) => ({ type: 'system/message', data: { message: { content: [{ type: 'text', text }] } } })
27
-
28
- const LONG = '很长的助手答复'.repeat(300) // 2100 字,用于验证「不截断」
29
-
30
- // 30 轮对话:用户 U01..U30 / 助手 A01..A30(零填充避免子串误命中),夹杂工具与系统消息
31
- const events = [systemEvent('系统提示词'.repeat(500)), userEvent('被 harness 注入的上下文', 'plugin')]
32
- for (let i = 1; i <= 30; i += 1) {
33
- events.push(userEvent(`U${String(i).padStart(2, '0')}`))
34
- events.push(toolEvent())
35
- events.push(assistantEvent(i === 25 ? `${LONG} A25` : `A${String(i).padStart(2, '0')}`))
36
- events.push(toolEvent())
37
- }
38
-
39
- // ── 1) 命中 U25:窗口 = 从 U25 向上数 24 条(A13..U25),其后的对话不进背景
40
- const hit = transcriptOf(events, { maxMessages: 24, maxChars: 0, marker: 'U25' })
41
- const lines = hit.transcript.split('\n').filter((line) => /^\s*(▶\s*)?(用户|助手):/.test(line))
42
- assert('窗口条数 = 24(含锚点)', lines.length === 24, `实际 ${lines.length}`)
43
- assert('首条是 A13(自锚点向上满 24 条)', lines[0].includes('助手:A13'), lines[0])
44
- assert('末条是选中所在的 U25,且带 ▶', lines[lines.length - 1].includes('▶') && lines[lines.length - 1].includes('用户:U25'), lines[lines.length - 1].slice(0, 30))
45
- assert('锚点命中标记正确', hit.marked === true)
46
- assert('锚点之后的对话不进背景', hit.transcript.indexOf('A26') < 0 && hit.transcript.indexOf('U26') < 0 && hit.transcript.indexOf('U30') < 0)
47
- assert('提示行说明前面还有更早消息', hit.transcript.includes('未包含'))
48
-
49
- // ── 1b) 锚点稍后(U26)时,锚点之前的长消息整条保留(默认不截断)
50
- const later = transcriptOf(events, { maxMessages: 24, maxChars: 0, marker: 'U26' })
51
- assert('长消息未被截断', later.transcript.includes(LONG), `背景共 ${later.transcript.length} 字`)
52
-
53
- // ── 2) 剔除噪音:工具/系统/注入消息不出现
54
- assert('工具结果被剔除', hit.transcript.indexOf('工具:') < 0)
55
- assert('系统提示词被剔除', hit.transcript.indexOf('系统提示') < 0)
56
- assert('harness 注入的上下文被剔除', hit.transcript.indexOf('被 harness 注入') < 0)
57
-
58
- // ── 3) 定位不到:退回最近 24 条,且不带锚点
59
- const miss = transcriptOf(events, { maxMessages: 24, maxChars: 0, marker: '这段文字不在任何消息里' })
60
- const missLines = miss.transcript.split('\n').filter((line) => /^\s*(▶\s*)?(用户|助手):/.test(line))
61
- assert('未命中时退回最近 24 条', missLines.length === 24 && missLines[missLines.length - 1].includes('A30'), `末条=${missLines[missLines.length - 1]}`)
62
- assert('未命中时不标锚点', miss.marked === false)
63
-
64
- // ── 4) 早期消息:锚点靠近开头时窗口自然变短
65
- const early = transcriptOf(events, { maxMessages: 24, maxChars: 0, marker: 'U02' })
66
- const earlyLines = early.transcript.split('\n').filter((line) => /^\s*(▶\s*)?(用户|助手):/.test(line))
67
- assert(
68
- '锚点靠开头时窗口自然缩短(U01 / A01 / U02)',
69
- earlyLines.length === 3 && earlyLines[0].includes('U01'),
70
- `实际 ${earlyLines.length} 条`,
71
- )
72
-
73
- // ── 5) 显式设了总量上限时才裁剪
74
- const capped = transcriptOf(events, { maxMessages: 24, maxChars: 200, marker: 'U25' })
75
- assert('显式上限生效(配置 >0 时)', capped.transcript.length < 2000, `${capped.transcript.length} 字`)
76
-
77
- // ───────────────────────── 引用上下文(quoteContextOf)─────────────────────────
78
- // 与解读用的会话背景不同:窗口是**锚点两侧**、按"轮"取整(上下各至少一整组)。
79
- {
80
- const lines = (text) => text.split('\n').filter((line) => /^(用户|助手|提示):/.test(line))
81
- const quoted = quoteContextOf(events, 'U10', {})
82
- const picked = lines(quoted.transcript)
83
- assert('引用上下文:命中并报出组数', quoted.matched === true && quoted.rounds === 3, JSON.stringify({ matched: quoted.matched, rounds: quoted.rounds }))
84
- assert(
85
- '引用上下文:锚点所在那一组 + 上下各一组(U09/A09 · U10/A10 · U11/A11)',
86
- picked.length === 6 &&
87
- picked[0].includes('用户:U09') &&
88
- picked[1].includes('助手:A09') &&
89
- picked[2].includes('用户:【U10】') &&
90
- picked[3].includes('助手:A10') &&
91
- picked[4].includes('用户:U11') &&
92
- picked[5].includes('助手:A11'),
93
- picked.map((line) => line.slice(0, 14)).join(' | '),
94
- )
95
- assert('引用上下文:被引用的部分用【】标出', quoted.transcript.includes('用户:【U10】'), quoted.transcript.split('\n')[2])
96
-
97
- // 引用落在助手回复里(常见:引用 AI 的某句话)→ 同样带上下各一组
98
- const inAnswer = quoteContextOf(events, 'A10', {})
99
- const answerLines = lines(inAnswer.transcript)
100
- assert(
101
- '引用在助手回复里:一样是上下一整组',
102
- inAnswer.matched === true && answerLines.length === 6 && inAnswer.transcript.includes('助手:【A10】'),
103
- answerLines.map((line) => line.slice(0, 14)).join(' | '),
104
- )
105
-
106
- // 引用跨行/空白不一致(选中文字与消息原文差在换行、缩进)也要标得出来
107
- const wrapped = [
108
- userEvent('第一句\n第二句 在这里\n第三句'),
109
- assistantEvent('A1'),
110
- userEvent('U2'),
111
- assistantEvent('A2'),
112
- ]
113
- const spread = quoteContextOf(wrapped, '第一句 第二句 在这里', {})
114
- assert('引用跨行时按"空白等价"标记', spread.matched === true && spread.transcript.includes('【第一句\n第二句 在这里】'), spread.transcript.replace(/\n/g, '⏎').slice(0, 60))
115
-
116
- // 定位不到:不猜、返回空(客户端会退回自己的局部上下文)
117
- const nowhere = quoteContextOf(events, '这段文字不在会话里', {})
118
- assert('引用定位不到时返回 matched:false 且不带上下文', nowhere.matched === false && nowhere.transcript === '', JSON.stringify(nowhere))
119
-
120
- // 长消息:**围绕引用**截断,引用本身不能被裁掉
121
- const longTurn = [userEvent(`${'前'.repeat(3000)}引用的这句${'后'.repeat(3000)}`), assistantEvent('A1')]
122
- const clamped = quoteContextOf(longTurn, '引用的这句', { maxCharsPerTurn: 400, maxChars: 6000 })
123
- assert(
124
- '长消息围绕引用截断(引用仍在,前后留边)',
125
- clamped.transcript.includes('【引用的这句】') && clamped.transcript.length < 700 && clamped.transcript.includes('…'),
126
- `${clamped.transcript.length} 字`,
127
- )
128
-
129
- // 总上限:超了丢最早的那几组,引用所在那条一定留下
130
- const many = []
131
- for (let i = 1; i <= 9; i += 1) {
132
- many.push(userEvent(`Q${i} ${'x'.repeat(400)}`))
133
- many.push(assistantEvent(`R${i} ${'y'.repeat(400)}`))
134
- }
135
- const budget = quoteContextOf(many, 'Q5', { roundsAround: 3, maxChars: 1200 })
136
- assert(
137
- '总上限生效:引用所在那条保留,更早的被丢掉并留提示',
138
- budget.transcript.includes('【Q5】') && budget.transcript.includes('未包含') && budget.transcript.length < 2200,
139
- `${budget.transcript.length} 字`,
140
- )
141
-
142
- // 噪音过滤与解读背景一致
143
- assert(
144
- '引用上下文同样剔除工具/系统/harness 注入',
145
- quoted.transcript.indexOf('工具') < 0 && quoted.transcript.indexOf('系统提示') < 0 && quoted.transcript.indexOf('被 harness 注入') < 0,
146
- '',
147
- )
148
- }
149
-
150
- console.log(`\n${failed === 0 ? '全部通过' : failed + ' 项失败'}`)
151
- process.exit(failed === 0 ? 0 : 1)