@master0071/dsh-systemone 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/auto.js CHANGED
@@ -42,6 +42,16 @@ const MAX_AUTO_CACHE = 200
42
42
  /** 当前请求注入 state 的最大字符数(历史逐条限 2000,这里限制本轮原文)。 */
43
43
  const MAX_CURRENT_CHARS = 8000
44
44
 
45
+ /** 自动决策数字配置的兜底默认值(与 lib/index.js Config schema 的 default 保持同一份来源)。 */
46
+ export const AUTO_DEFAULTS = {
47
+ autoMaxMessages: 6,
48
+ autoTimeoutMs: 8000,
49
+ autoCacheTtlMs: 60000,
50
+ autoRouteMinConfidence: 0.35,
51
+ autoMinConfidence: 0.6,
52
+ autoMinChars: 4,
53
+ }
54
+
45
55
  /**
46
56
  * 安装自动决策。返回卸载函数。
47
57
  *
@@ -99,7 +109,7 @@ export function installAutoDecide(ctx, deps) {
99
109
  const newText = extractUserText([event?.message])
100
110
  if (!newText) return
101
111
  if (newText.trimStart().startsWith('/')) return
102
- if (isTrivialInput(newText, readNumber(config, 'autoMinChars', 0))) return
112
+ if (isTrivialInput(newText, readNumber(config, 'autoMinChars', AUTO_DEFAULTS.autoMinChars))) return
103
113
  // 返回 promise 便于测试等待;宿主事件总线忽略返回值
104
114
  return computeAndStore(agent, newText)
105
115
  }))
@@ -141,13 +151,14 @@ export function installAutoDecide(ctx, deps) {
141
151
  const newText = extractUserText(claimed)
142
152
  if (!newText) return decision // 工具结果步骤 / 无新用户消息
143
153
  if (newText.trimStart().startsWith('/')) return decision // 斜杠命令
144
- if (isTrivialInput(newText, readNumber(config, 'autoMinChars', 0))) return decision // 寒暄/致谢等无业务含义的输入
154
+ if (isTrivialInput(newText, readNumber(config, 'autoMinChars', AUTO_DEFAULTS.autoMinChars))) return decision // 寒暄/致谢等无业务含义的输入
145
155
 
146
156
  let injected = null
147
157
  try {
148
158
  // 双保险:既给上游传 abort signal,也用 race 兜底,
149
159
  // 即使提供商忽略 signal 也不会让这一步的推理被无限阻塞。
150
- const timeout = combineSignal(payload?.signal, readNumber(config, 'autoTimeoutMs', 8000))
160
+ const timeoutMs = readNumber(config, 'autoTimeoutMs', AUTO_DEFAULTS.autoTimeoutMs)
161
+ const timeout = combineSignal(payload?.signal, timeoutMs)
151
162
  try {
152
163
  injected = await raceTimeout(
153
164
  computeDecision({
@@ -162,7 +173,7 @@ export function installAutoDecide(ctx, deps) {
162
173
  log,
163
174
  warnedScenarios,
164
175
  }),
165
- readNumber(config, 'autoTimeoutMs', 8000),
176
+ timeoutMs,
166
177
  )
167
178
  } finally {
168
179
  timeout.dispose()
@@ -197,7 +208,8 @@ export function installAutoDecide(ctx, deps) {
197
208
  /** 入箱预计算:异步算好并存进 perAgent,供 context 通道渲染。 */
198
209
  async function computeAndStore(agent, newText) {
199
210
  try {
200
- const timeout = combineSignal(undefined, readNumber(config, 'autoTimeoutMs', 8000))
211
+ const timeoutMs = readNumber(config, 'autoTimeoutMs', AUTO_DEFAULTS.autoTimeoutMs)
212
+ const timeout = combineSignal(undefined, timeoutMs)
201
213
  try {
202
214
  const injected = await raceTimeout(
203
215
  computeDecision({
@@ -212,7 +224,7 @@ export function installAutoDecide(ctx, deps) {
212
224
  log,
213
225
  warnedScenarios,
214
226
  }),
215
- readNumber(config, 'autoTimeoutMs', 8000),
227
+ timeoutMs,
216
228
  )
217
229
  if (injected) perAgent.set(agent?.id ?? 'unknown', injected)
218
230
  } finally {
@@ -244,7 +256,7 @@ export function installAutoDecide(ctx, deps) {
244
256
  * 计算决策(带并发去重)。相同 state 只发一次上游请求。
245
257
  */
246
258
  async function computeDecision({ agent, newText, provider, config, scenarios, cache, inFlight, signal, log, warnedScenarios }) {
247
- const state = captureState(agent, newText, readNumber(config, 'autoMaxMessages', 6))
259
+ const state = captureState(agent, newText, readNumber(config, 'autoMaxMessages', AUTO_DEFAULTS.autoMaxMessages))
248
260
  const key = hashString(state)
249
261
  const existing = inFlight.get(key)
250
262
  if (existing) return existing
@@ -268,7 +280,7 @@ async function computeDecision({ agent, newText, provider, config, scenarios, ca
268
280
  }
269
281
 
270
282
  async function decide({ agent, newText, state, key, provider, config, scenarios, cache, signal, log, warnedScenarios }) {
271
- const ttl = readNumber(config, 'autoCacheTtlMs', 0) || 0
283
+ const ttl = readNumber(config, 'autoCacheTtlMs', AUTO_DEFAULTS.autoCacheTtlMs) || 0
272
284
  if (ttl > 0) {
273
285
  const hit = cache.get(key)
274
286
  if (hit && Date.now() - hit.at < ttl) return hit.result
@@ -279,7 +291,7 @@ async function decide({ agent, newText, state, key, provider, config, scenarios,
279
291
  if (!routed) return null
280
292
 
281
293
  // 路由置信度不足:宁可不注入,也不要塞一个瞎猜的结论
282
- const floor = readNumber(config, 'autoRouteMinConfidence', 0)
294
+ const floor = readNumber(config, 'autoRouteMinConfidence', AUTO_DEFAULTS.autoRouteMinConfidence)
283
295
  if (Number.isFinite(floor) && floor > 0
284
296
  && Number.isFinite(routed.confidence) && routed.confidence < floor) {
285
297
  log?.('info', `路由置信度 ${(routed.confidence * 100).toFixed(1)}% 低于阈值 ${(floor * 100).toFixed(0)}%,跳过注入`)
@@ -294,7 +306,7 @@ async function decide({ agent, newText, state, key, provider, config, scenarios,
294
306
  scenario: routed.scenario.id,
295
307
  state,
296
308
  exec: { signal },
297
- minConfidence: readNumber(config, 'autoMinConfidence', 0.6),
309
+ minConfidence: readNumber(config, 'autoMinConfidence', AUTO_DEFAULTS.autoMinConfidence),
298
310
  })
299
311
  if (!result?.ok) {
300
312
  log?.('warn', `场景 ${routed.scenario.id} 执行失败,已放行:${result?.error || '未知错误'}`)
package/lib/client.js CHANGED
@@ -352,7 +352,7 @@ window.__ModuleLoader__.load({
352
352
  : null
353
353
  if (keys === null) issues.push(`问题 ${qid}(choice)需要 criteria 对象`)
354
354
  else if (keys.length < 2) issues.push(`问题 ${qid}(choice)至少 2 个选项`)
355
- else if (keys.length > 26) issues.push(`问题 ${qid}(choice)选项建议 ≤26(当前 ${keys.length})`)
355
+ else if (keys.length > 26) issues.push(`问题 ${qid}(choice)选项不能超过 26 个(当前 ${keys.length})`)
356
356
  }
357
357
  if (q.type === 'score'
358
358
  && (!Array.isArray(q.criteria) || q.criteria.length < 2)) {
@@ -495,7 +495,7 @@ window.__ModuleLoader__.load({
495
495
  control = h('input', {
496
496
  id: controlId,
497
497
  style: inputStyle,
498
- type: field.kind === 'password' ? 'password' : field.kind === 'number' ? 'text' : 'text',
498
+ type: field.kind === 'password' ? 'password' : 'text',
499
499
  inputMode: field.kind === 'number' ? 'decimal' : undefined,
500
500
  value,
501
501
  disabled,
@@ -679,6 +679,18 @@ window.__ModuleLoader__.load({
679
679
  ],
680
680
  })
681
681
 
682
+ // 三张卡片共用同一套 footer:save(可选 revert / 额外状态)+ 状态行
683
+ const renderFooter = ({ showRevert, extra }) => hs('div', {
684
+ key: 'footer',
685
+ style: footerStyle,
686
+ children: [
687
+ h('button', { key: 'save', type: 'button', style: { ...primaryButton, opacity: canSave ? 1 : 0.5 }, disabled: !canSave, onClick: onSave, children: busy ? t('saving') : t('save') }),
688
+ ...(showRevert ? [h('button', { key: 'revert', type: 'button', style: ghostButton, disabled: !dirty || busy, onClick: () => { setDraft(null); setNotice(null) }, children: t('revert') })] : []),
689
+ ...(extra ? [extra] : []),
690
+ statusLine,
691
+ ],
692
+ })
693
+
682
694
  return hs('ul', {
683
695
  style: listStyle,
684
696
  children: [
@@ -692,32 +704,7 @@ window.__ModuleLoader__.load({
692
704
  children: hs(Fragment, {
693
705
  children: [
694
706
  ...renderFields(SERVICE_FIELDS, numberExtras),
695
- hs('div', {
696
- key: 'footer',
697
- style: footerStyle,
698
- children: [
699
- h('button', {
700
- key: 'save',
701
- type: 'button',
702
- style: { ...primaryButton, opacity: canSave ? 1 : 0.5 },
703
- disabled: !canSave,
704
- onClick: onSave,
705
- children: busy ? t('saving') : t('save'),
706
- }),
707
- h('button', {
708
- key: 'revert',
709
- type: 'button',
710
- style: ghostButton,
711
- disabled: !dirty || busy,
712
- onClick: () => {
713
- setDraft(null)
714
- setNotice(null)
715
- },
716
- children: t('revert'),
717
- }),
718
- statusLine,
719
- ],
720
- }),
707
+ renderFooter({ showRevert: true }),
721
708
  ],
722
709
  }),
723
710
  }),
@@ -779,40 +766,17 @@ window.__ModuleLoader__.load({
779
766
  }),
780
767
  },
781
768
  }),
782
- hs('div', {
783
- key: 'footer',
784
- style: footerStyle,
785
- children: [
786
- h('button', {
787
- key: 'save',
788
- type: 'button',
789
- style: { ...primaryButton, opacity: canSave ? 1 : 0.5 },
790
- disabled: !canSave,
791
- onClick: onSave,
792
- children: busy ? t('saving') : t('save'),
793
- }),
794
- h('button', {
795
- key: 'revert',
796
- type: 'button',
797
- style: ghostButton,
798
- disabled: !dirty || busy,
799
- onClick: () => {
800
- setDraft(null)
801
- setNotice(null)
802
- },
803
- children: t('revert'),
804
- }),
805
- customCheck.ok
806
- ? h('span', {
807
- key: 'ok',
808
- style: statusStyle,
809
- children: customCheck.count === 0
810
- ? t('jsonEmpty')
811
- : `${t('jsonOk', { count: customCheck.count })} ${t('customIdsUsed')}`,
812
- })
813
- : null,
814
- statusLine,
815
- ],
769
+ renderFooter({
770
+ showRevert: true,
771
+ extra: customCheck.ok
772
+ ? h('span', {
773
+ key: 'ok',
774
+ style: statusStyle,
775
+ children: customCheck.count === 0
776
+ ? t('jsonEmpty')
777
+ : `${t('jsonOk', { count: customCheck.count })} ${t('customIdsUsed')}`,
778
+ })
779
+ : null,
816
780
  }),
817
781
  ],
818
782
  }),
@@ -826,21 +790,7 @@ window.__ModuleLoader__.load({
826
790
  children: hs(Fragment, {
827
791
  children: [
828
792
  ...renderFields(AUTO_FIELDS, numberExtras),
829
- hs('div', {
830
- key: 'footer',
831
- style: footerStyle,
832
- children: [
833
- h('button', {
834
- key: 'save',
835
- type: 'button',
836
- style: { ...primaryButton, opacity: canSave ? 1 : 0.5 },
837
- disabled: !canSave,
838
- onClick: onSave,
839
- children: busy ? t('saving') : t('save'),
840
- }),
841
- statusLine,
842
- ],
843
- }),
793
+ renderFooter({ showRevert: false }),
844
794
  ],
845
795
  }),
846
796
  }),
package/lib/index.js CHANGED
@@ -16,7 +16,7 @@ import z from '@deepseek-ai/schemastery'
16
16
  import { createProvider } from './provider.js'
17
17
  import { createTools } from './tools.js'
18
18
  import { resolveScenarios } from './scenarios.js'
19
- import { installAutoDecide } from './auto.js'
19
+ import { installAutoDecide, AUTO_DEFAULTS } from './auto.js'
20
20
  import { readBoolean, readString, unwrap } from './volatile.js'
21
21
 
22
22
  /** 合法的提供商类型;其他值会按 unisound 处理并告警一次。 */
@@ -82,17 +82,17 @@ const Config = z.object({
82
82
  /** 注入通道:message=本步生效(pre-step 注入);context=官方动态上下文(晚一步生效) */
83
83
  autoInject: z.string().default('message').volatile(),
84
84
  /** 自动决策超时(毫秒),超时即放行,绝不阻塞会话 */
85
- autoTimeoutMs: z.number().min(500).default(8000).volatile(),
85
+ autoTimeoutMs: z.number().min(500).default(AUTO_DEFAULTS.autoTimeoutMs).volatile(),
86
86
  /** 捕获的历史消息条数(不含本轮新消息) */
87
- autoMaxMessages: z.number().min(1).max(50).default(6).volatile(),
87
+ autoMaxMessages: z.number().min(1).max(50).default(AUTO_DEFAULTS.autoMaxMessages).volatile(),
88
88
  /** 相同内容的结果缓存时长(毫秒),0 表示不缓存 */
89
- autoCacheTtlMs: z.number().min(0).default(60000).volatile(),
89
+ autoCacheTtlMs: z.number().min(0).default(AUTO_DEFAULTS.autoCacheTtlMs).volatile(),
90
90
  /** 自动决策使用的置信度阈值 */
91
- autoMinConfidence: z.number().min(0).max(1).default(0.6).volatile(),
91
+ autoMinConfidence: z.number().min(0).max(1).default(AUTO_DEFAULTS.autoMinConfidence).volatile(),
92
92
  /** 自动路由的置信度门槛:低于该值宁可不注入,避免塞入瞎猜的结论 */
93
- autoRouteMinConfidence: z.number().min(0).max(1).default(0.35).volatile(),
93
+ autoRouteMinConfidence: z.number().min(0).max(1).default(AUTO_DEFAULTS.autoRouteMinConfidence).volatile(),
94
94
  /** 触发自动决策的最小输入长度(字符);低于该长度且整体是寒暄才跳过 */
95
- autoMinChars: z.number().min(0).default(4).volatile(),
95
+ autoMinChars: z.number().min(0).default(AUTO_DEFAULTS.autoMinChars).volatile(),
96
96
  })
97
97
 
98
98
  export default class SystemOneService extends Service {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@master0071/dsh-systemone",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "DeepSeek Harness 插件:将 SystemOne 决策模型(默认云知声 u2-decision,可切换提供商)接入软件开发、客服、内容审核、路由、销售线索、风控、招聘、数据治理、教育、需求变更等 10 大业务场景,为 Agent 返回带概率分布的决策与处置建议。",
5
5
  "license": "MIT",
6
6
  "type": "module",