@telosmaylx/dsh-session-notify 0.1.16 → 0.1.17

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/client.js CHANGED
@@ -25,6 +25,7 @@ window.__ModuleLoader__.load({
25
25
  var PLUGIN_TAG = 'dsh-session-notify'
26
26
  var SETTINGS_NS = 'session-complete-notify'
27
27
  var NOTICE_PROJECTION_KEY = 'session-complete-notify' // 宿主投影单元 key(每个会话都带)
28
+ var QUESTION_PROJECTION_KEY = 'session-complete-notify-question' // 提问中投影 key(客户端据此推送提问提醒)
28
29
 
29
30
  /** 语言代码与在原声展示名(所有语言面板统一用各自原声名)。 */
30
31
  var LANG_OPTIONS = [
@@ -44,11 +45,11 @@ window.__ModuleLoader__.load({
44
45
  zh: {
45
46
  title: '会话完成提醒', subtitle: '完成推送的语言与文案模板(保存后刷新生效)',
46
47
  preset: '预设', choosePreset: '选择预设…', language: '语言',
47
- fields: { completed: '完成', error: '出错', aborted: '中止', blocked: '阻塞', 'max-tokens': '上限' },
48
- titlesGroup: '标题', titleLabel: '推送标题', titleHint: '通用推送标题,留空时则使用默认标题,优先级低于下方自定义标题', titleTplLabel: '按原因定制标题(可选)', tplLabel: '内容', ttPlaceholders: { completed: '任务已完成', error: '任务出错', aborted: '任务已中止', blocked: '任务被阻塞', 'max-tokens': '任务达到上限' },
49
- kindLabels: { completed: '会话已完成', error: '会话出错', aborted: '会话已中止', blocked: '会话被阻塞', 'max-tokens': '会话达到上限' },
50
- tokens: { title: '会话标题', label: '完成标签', duration: '用时', usage: '消耗', error: '错误', cache: '缓存命中', tps: '速度 TPS', image: '图片', icon: '图标' },
51
- samples: { title: '示例会话', label: '会话已完成', duration: '12 秒', usage: '1,240 输入 / 3,560 输出', error: '连接超时', cache: '96.5%', tps: '92 tok/s', image: '[图片]', icon: '[图标]' },
48
+ fields: { completed: '完成', error: '出错', aborted: '中止', blocked: '阻塞', 'max-tokens': '上限', question: '提问' },
49
+ titlesGroup: '标题', titleLabel: '推送标题', titleHint: '通用推送标题,留空时则使用默认标题,优先级低于下方自定义标题', titleTplLabel: '按原因定制标题(可选)', tplLabel: '内容', ttPlaceholders: { completed: '任务已完成', error: '任务出错', aborted: '任务已中止', blocked: '任务被阻塞', 'max-tokens': '任务达到上限', question: 'AI 正在向你提问' },
50
+ kindLabels: { completed: '会话已完成', error: '会话出错', aborted: '会话已中止', blocked: '会话被阻塞', 'max-tokens': '会话达到上限', question: '提问' },
51
+ tokens: { title: '会话标题', label: '完成标签', duration: '用时', usage: '消耗', error: '错误', cache: '缓存命中', tps: '速度 TPS', image: '图片', icon: '图标', question: '提问' },
52
+ samples: { title: '示例会话', label: '会话已完成', duration: '12 秒', usage: '1,240 输入 / 3,560 输出', error: '连接超时', cache: '96.5%', tps: '92 tok/s', image: '[图片]', icon: '[图标]', question: '要继续生成报告吗?' },
52
53
  imagePickTitle: '选择本地图片(自动压缩为通知大图)', iconPickTitle: '选择本地图片(自动压缩为通知图标)', imageFailed: '图片读取失败',
53
54
  clearMedia: '清除',
54
55
  mediaNote: '本地上传会自动处理:大图按通知显示比例 16:9 居中裁切(512×288)、图标 1:1 方形裁切(128×128),裁切后即通知中显示的效果',
@@ -68,11 +69,11 @@ window.__ModuleLoader__.load({
68
69
  'zh-tw': {
69
70
  title: '會話完成提醒', subtitle: '完成推送的語言與文案模板(儲存後重新整理生效)',
70
71
  preset: '預設', choosePreset: '選擇預設…', language: '語言',
71
- fields: { completed: '完成', error: '出錯', aborted: '中止', blocked: '阻塞', 'max-tokens': '上限' },
72
- titlesGroup: '標題', titleLabel: '推送標題', titleHint: '通用推送標題,留空時則使用預設標題,優先級低於下方自訂標題', titleTplLabel: '按原因自訂標題(選填)', tplLabel: '內容', ttPlaceholders: { completed: '任務已完成', error: '任務出錯', aborted: '任務已中止', blocked: '任務被阻塞', 'max-tokens': '任務達到上限' },
73
- kindLabels: { completed: '會話已完成', error: '會話出錯', aborted: '會話已中止', blocked: '會話被阻塞', 'max-tokens': '會話達到上限' },
74
- tokens: { title: '會話標題', label: '完成標籤', duration: '用時', usage: '消耗', error: '錯誤', cache: '快取命中', tps: '速度 TPS', image: '圖片', icon: '圖示' },
75
- samples: { title: '範例會話', label: '會話已完成', duration: '12 秒', usage: '1,240 輸入 / 3,560 輸出', error: '連線逾時', cache: '96.5%', tps: '92 tok/s', image: '[圖片]', icon: '[圖示]' },
72
+ fields: { completed: '完成', error: '出錯', aborted: '中止', blocked: '阻塞', 'max-tokens': '上限', question: '提問' },
73
+ titlesGroup: '標題', titleLabel: '推送標題', titleHint: '通用推送標題,留空時則使用預設標題,優先級低於下方自訂標題', titleTplLabel: '按原因自訂標題(選填)', tplLabel: '內容', ttPlaceholders: { completed: '任務已完成', error: '任務出錯', aborted: '任務已中止', blocked: '任務被阻塞', 'max-tokens': '任務達到上限', question: 'AI 正在向你提問' },
74
+ kindLabels: { completed: '會話已完成', error: '會話出錯', aborted: '會話已中止', blocked: '會話被阻塞', 'max-tokens': '會話達到上限', question: '提問' },
75
+ tokens: { title: '會話標題', label: '完成標籤', duration: '用時', usage: '消耗', error: '錯誤', cache: '快取命中', tps: '速度 TPS', image: '圖片', icon: '圖示', question: '提問' },
76
+ samples: { title: '範例會話', label: '會話已完成', duration: '12 秒', usage: '1,240 輸入 / 3,560 輸出', error: '連線逾時', cache: '96.5%', tps: '92 tok/s', image: '[圖片]', icon: '[圖示]', question: '要繼續產生報告嗎?' },
76
77
  imagePickTitle: '選擇本機圖片(自動壓縮為通知大圖)', iconPickTitle: '選擇本機圖片(自動壓縮為通知圖示)', imageFailed: '圖片讀取失敗',
77
78
  clearMedia: '清除',
78
79
  mediaNote: '本機上傳會自動處理:大圖按通知顯示比例 16:9 居中裁切(512×288)、圖示 1:1 方形裁切(128×128),裁切後即通知中顯示的效果',
@@ -92,11 +93,11 @@ window.__ModuleLoader__.load({
92
93
  en: {
93
94
  title: 'Session completion alert', subtitle: 'Language & message templates for completion pushes (refresh after save)',
94
95
  preset: 'Preset', choosePreset: 'Choose preset…', language: 'Language',
95
- fields: { completed: 'Completed', error: 'Error', aborted: 'Aborted', blocked: 'Blocked', 'max-tokens': 'Cap' },
96
- titlesGroup: 'Title', titleLabel: 'Push title', titleHint: 'Generic push title; leave empty to use the default title (per-reason titles below take precedence)', titleTplLabel: 'Per-reason titles (optional)', tplLabel: 'Content', ttPlaceholders: { completed: 'Task completed', error: 'Task failed', aborted: 'Task aborted', blocked: 'Task blocked', 'max-tokens': 'Task hit the cap' },
97
- kindLabels: { completed: 'Session completed', error: 'Session failed', aborted: 'Session aborted', blocked: 'Session blocked', 'max-tokens': 'Session hit the cap' },
98
- tokens: { title: 'Session title', label: 'Label', duration: 'Duration', usage: 'Usage', error: 'Error', cache: 'Cache hit', tps: 'Speed TPS', image: 'Image', icon: 'Icon' },
99
- samples: { title: 'Example session', label: 'Session completed', duration: '12s', usage: '1,240 in / 3,560 out', error: 'connection timeout', cache: '96.5%', tps: '92 tok/s', image: '[image]', icon: '[icon]' },
96
+ fields: { completed: 'Completed', error: 'Error', aborted: 'Aborted', blocked: 'Blocked', 'max-tokens': 'Cap', question: 'Question' },
97
+ titlesGroup: 'Title', titleLabel: 'Push title', titleHint: 'Generic push title; leave empty to use the default title (per-reason titles below take precedence)', titleTplLabel: 'Per-reason titles (optional)', tplLabel: 'Content', ttPlaceholders: { completed: 'Task completed', error: 'Task failed', aborted: 'Task aborted', blocked: 'Task blocked', 'max-tokens': 'Task hit the cap', question: 'AI is asking you a question' },
98
+ kindLabels: { completed: 'Session completed', error: 'Session failed', aborted: 'Session aborted', blocked: 'Session blocked', 'max-tokens': 'Session hit the cap', question: 'Question' },
99
+ tokens: { title: 'Session title', label: 'Label', duration: 'Duration', usage: 'Usage', error: 'Error', cache: 'Cache hit', tps: 'Speed TPS', image: 'Image', icon: 'Icon', question: 'Question' },
100
+ samples: { title: 'Example session', label: 'Session completed', duration: '12s', usage: '1,240 in / 3,560 out', error: 'connection timeout', cache: '96.5%', tps: '92 tok/s', image: '[image]', icon: '[icon]', question: 'Should I continue generating the report?' },
100
101
  imagePickTitle: 'Pick a local image (auto-compressed for the notification)', iconPickTitle: 'Pick a local image (auto-compressed for the notification icon)', imageFailed: 'Failed to read the image',
101
102
  clearMedia: 'Clear',
102
103
  mediaNote: 'Local uploads are processed automatically: large images are center-cropped to the notification ratio 16:9 (512×288) and icons to 1:1 square (128×128) — the cropped result is exactly what shows in the notification',
@@ -116,11 +117,11 @@ window.__ModuleLoader__.load({
116
117
  ja: {
117
118
  title: 'セッション完了通知', subtitle: '完了プッシュの言語とメッセージテンプレート(保存後に再読み込みで反映)',
118
119
  preset: 'プリセット', choosePreset: 'プリセットを選択…', language: '言語',
119
- fields: { completed: '完了', error: 'エラー', aborted: '中止', blocked: 'ブロック', 'max-tokens': '上限' },
120
- titlesGroup: 'タイトル', titleLabel: 'プッシュタイトル', titleHint: '共通のプッシュタイトル。空欄の場合はデフォルトタイトルを使用(下の理由別タイトルが優先)', titleTplLabel: '理由ごとのタイトル(任意)', tplLabel: 'コンテンツ', ttPlaceholders: { completed: 'タスク完了', error: 'タスクエラー', aborted: 'タスク中止', blocked: 'タスクがブロックされました', 'max-tokens': '上限に到達' },
121
- kindLabels: { completed: 'セッション完了', error: 'セッションエラー', aborted: 'セッション中止', blocked: 'セッションがブロックされました', 'max-tokens': '上限に到達' },
122
- tokens: { title: 'セッションタイトル', label: '完了ラベル', duration: '所要時間', usage: '消費', error: 'エラー', cache: 'キャッシュヒット', tps: '速度 TPS', image: '画像', icon: 'アイコン' },
123
- samples: { title: 'サンプルセッション', label: 'セッション完了', duration: '12 秒', usage: '1,240 入力 / 3,560 出力', error: '接続タイムアウト', cache: '96.5%', tps: '92 tok/s', image: '[画像]', icon: '[アイコン]' },
120
+ fields: { completed: '完了', error: 'エラー', aborted: '中止', blocked: 'ブロック', 'max-tokens': '上限', question: '質問' },
121
+ titlesGroup: 'タイトル', titleLabel: 'プッシュタイトル', titleHint: '共通のプッシュタイトル。空欄の場合はデフォルトタイトルを使用(下の理由別タイトルが優先)', titleTplLabel: '理由ごとのタイトル(任意)', tplLabel: 'コンテンツ', ttPlaceholders: { completed: 'タスク完了', error: 'タスクエラー', aborted: 'タスク中止', blocked: 'タスクがブロックされました', 'max-tokens': '上限に到達', question: 'AI からの質問が届きました' },
122
+ kindLabels: { completed: 'セッション完了', error: 'セッションエラー', aborted: 'セッション中止', blocked: 'セッションがブロックされました', 'max-tokens': '上限に到達', question: '質問' },
123
+ tokens: { title: 'セッションタイトル', label: '完了ラベル', duration: '所要時間', usage: '消費', error: 'エラー', cache: 'キャッシュヒット', tps: '速度 TPS', image: '画像', icon: 'アイコン', question: '質問' },
124
+ samples: { title: 'サンプルセッション', label: 'セッション完了', duration: '12 秒', usage: '1,240 入力 / 3,560 出力', error: '接続タイムアウト', cache: '96.5%', tps: '92 tok/s', image: '[画像]', icon: '[アイコン]', question: 'レポートの生成を続けますか?' },
124
125
  imagePickTitle: 'ローカル画像を選択(通知用に自動圧縮)', iconPickTitle: 'ローカル画像を選択(通知アイコン用に自動圧縮)', imageFailed: '画像の読み込みに失敗しました',
125
126
  clearMedia: 'クリア',
126
127
  mediaNote: 'ローカルアップロードは自動処理されます:大きな画像は通知表示比率 16:9(512×288)に中央クロップ、アイコンは 1:1 正方形(128×128)。クロップ後の見た目がそのまま通知に表示されます',
@@ -140,11 +141,11 @@ window.__ModuleLoader__.load({
140
141
  ko: {
141
142
  title: '세션 완료 알림', subtitle: '완료 푸시의 언어 및 메시지 템플릿(저장 후 새로고침 시 적용)',
142
143
  preset: '프리셋', choosePreset: '프리셋 선택…', language: '언어',
143
- fields: { completed: '완료', error: '오류', aborted: '중단', blocked: '차단', 'max-tokens': '한도' },
144
- titlesGroup: '제목', titleLabel: '푸시 제목', titleHint: '공통 푸시 제목. 비우면 기본 제목 사용(아래 사유별 제목이 우선)', titleTplLabel: '이유별 제목 (선택)', tplLabel: '콘텐츠', ttPlaceholders: { completed: '작업 완료', error: '작업 오류', aborted: '작업 중단됨', blocked: '작업 차단됨', 'max-tokens': '한도 도달' },
145
- kindLabels: { completed: '세션 완료', error: '세션 오류', aborted: '세션 중단됨', blocked: '세션 차단됨', 'max-tokens': '한도 도달' },
146
- tokens: { title: '세션 제목', label: '완료 라벨', duration: '소요 시간', usage: '소모', error: '오류', cache: '캐시 히트', tps: '속도 TPS', image: '이미지', icon: '아이콘' },
147
- samples: { title: '예시 세션', label: '세션 완료', duration: '12초', usage: '1,240 입력 / 3,560 출력', error: '연결 시간 초과', cache: '96.5%', tps: '92 tok/s', image: '[이미지]', icon: '[아이콘]' },
144
+ fields: { completed: '완료', error: '오류', aborted: '중단', blocked: '차단', 'max-tokens': '한도', question: '질문' },
145
+ titlesGroup: '제목', titleLabel: '푸시 제목', titleHint: '공통 푸시 제목. 비우면 기본 제목 사용(아래 사유별 제목이 우선)', titleTplLabel: '이유별 제목 (선택)', tplLabel: '콘텐츠', ttPlaceholders: { completed: '작업 완료', error: '작업 오류', aborted: '작업 중단됨', blocked: '작업 차단됨', 'max-tokens': '한도 도달', question: 'AI가 질문했습니다' },
146
+ kindLabels: { completed: '세션 완료', error: '세션 오류', aborted: '세션 중단됨', blocked: '세션 차단됨', 'max-tokens': '한도 도달', question: '질문' },
147
+ tokens: { title: '세션 제목', label: '완료 라벨', duration: '소요 시간', usage: '소모', error: '오류', cache: '캐시 히트', tps: '속도 TPS', image: '이미지', icon: '아이콘', question: '질문' },
148
+ samples: { title: '예시 세션', label: '세션 완료', duration: '12초', usage: '1,240 입력 / 3,560 출력', error: '연결 시간 초과', cache: '96.5%', tps: '92 tok/s', image: '[이미지]', icon: '[아이콘]', question: '보고서 생성을 계속할까요?' },
148
149
  imagePickTitle: '로컬 이미지 선택(알림용으로 자동 압축)', iconPickTitle: '로컬 이미지 선택(알림 아이콘용으로 자동 압축)', imageFailed: '이미지를 읽지 못했습니다',
149
150
  clearMedia: '지우기',
150
151
  mediaNote: '로컬 업로드는 자동 처리됩니다: 큰 이미지는 알림 표시 비율 16:9(512×288) 중앙 크롭, 아이콘은 1:1 정사각(128×128). 크롭 후 모습이 그대로 알림에 표시됩니다',
@@ -176,6 +177,7 @@ window.__ModuleLoader__.load({
176
177
  var notifyScope = null
177
178
  try { notifyScope = ctx.settingsScope.bind({ namespace: SETTINGS_NS }) } catch (e) { /* 无设置作用域时用默认 */ }
178
179
  var prevRunning = new Map() // sessionId -> 上次观测的 running 位
180
+ var pushedQuestions = new Map() // sessionId -> 已推送的提问 callId(避免同一问题重复推送)
179
181
  var primed = false // 首次观测只记录基线(已在 idle 的会话不补发),与官方 sidebar 提醒同策略
180
182
  var retryTimer = null // 完成推送正文轮询定时器(卸载时清除:不在已拆 fiber 上继续弹通知)
181
183
  var debugHook = null // window.__dsch_notify_debug 引用(卸载时按引用删除,防闭包泄漏)
@@ -184,6 +186,14 @@ window.__ModuleLoader__.load({
184
186
  console.log('[' + PLUGIN_TAG + '-client] active, watching session activity for completion pushes')
185
187
  } catch (e) { /* noop */ }
186
188
 
189
+ /** 是否跳过子代理会话:读设置文档 skipSubagents(面板复选框保存的值),缺省/异常按 true 处理。 */
190
+ function subagentSkipped() {
191
+ try {
192
+ var st = notifyScope && typeof notifyScope.get === 'function' ? notifyScope.get() : null
193
+ return !(st && typeof st.skipSubagents === 'boolean') ? true : st.skipSubagents
194
+ } catch (e) { return true }
195
+ }
196
+
187
197
  function onSnapshot() {
188
198
  var snap = list.getSnapshot()
189
199
  if (!snap || typeof snap.byId !== 'object' || snap.byId === null) return
@@ -194,16 +204,43 @@ window.__ModuleLoader__.load({
194
204
  if (!s || typeof s.running !== 'boolean') continue
195
205
  var was = prevRunning.get(id)
196
206
  prevRunning.set(id, s.running)
207
+ // 提问推送不依赖 running 边沿:页面加载时已有 pending 问题也应立即提醒。
208
+ checkQuestion(id, s)
197
209
  if (!primed) continue
198
210
  // 完成事件:running true → false 的边沿
199
211
  if (was === true && s.running === false) {
200
- if (s.origin === 'subagent') continue // 子代理会话由父会话编排
212
+ if (s.origin === 'subagent' && subagentSkipped()) continue // 子代理会话由父会话编排(可取消跳过)
201
213
  pushCompletion(id, s)
202
214
  }
203
215
  }
204
216
  primed = true
205
217
  }
206
218
 
219
+ /**
220
+ * 提问推送:读会话投影里的 pending ask_user_question。
221
+ * 同一 callId 只推一次;问题被 tool/result 或 turn/end 清除后重置记录。
222
+ */
223
+ function checkQuestion(id, s) {
224
+ if (s.origin === 'subagent' && subagentSkipped()) return // 子代理不能直接向人类提问(可取消跳过)
225
+ var pv = null
226
+ try {
227
+ pv = s.projectionValues && s.projectionValues[QUESTION_PROJECTION_KEY]
228
+ } catch (e) { /* 投影缺失时不推送 */ }
229
+ if (!pv || typeof pv !== 'object' || !pv.id || !pv.text) {
230
+ if (pushedQuestions.has(id)) pushedQuestions.delete(id)
231
+ return
232
+ }
233
+ if (pushedQuestions.get(id) === pv.id) return
234
+ pushedQuestions.set(id, pv.id)
235
+ var name = s.displayTitle || s.title || id
236
+ // 标题:宿主按 5 语言默认/自定义模板渲染(titleTemplates.question);老宿主投影无 title 时回落「会话名 想问你」
237
+ var title = (typeof pv.title === 'string' && pv.title.trim() !== '') ? (name ? name + ' · ' : '') + pv.title.trim() : (name ? name + ' 想问你' : '有新的提问')
238
+ // 正文:宿主渲染(templates.question 或语言默认,含问题文本);老宿主投影无 body 时回落原拼接
239
+ var body = (typeof pv.body === 'string' && pv.body.trim() !== '') ? pv.body.trim() : ((name ? '会话「' + name + '」想问你:\n' : '') + pv.text)
240
+ log('question push: ' + id + ' ' + pv.id + ' ' + title)
241
+ notifyUser(title, body, pushModeOf(), mediaOf('question'))
242
+ }
243
+
207
244
  /**
208
245
  * 完成推送:标题 = 哪个会话(displayTitle),正文优先取宿主刚写入的
209
246
  * 系统消息全文(含用时/token/错误详情,来自会话事件窗口的 notice 节点)。
@@ -504,8 +541,8 @@ window.__ModuleLoader__.load({
504
541
 
505
542
  // ============ 设置卡片:官方「设置 → 插件」面板 ============
506
543
 
507
- var REASON_FIELDS = ['completed', 'error', 'aborted', 'blocked', 'max-tokens']
508
- var REASON_LABELS = { completed: '完成', error: '出错', aborted: '中止', blocked: '阻塞', 'max-tokens': '输出上限' }
544
+ var REASON_FIELDS = ['completed', 'error', 'aborted', 'blocked', 'max-tokens', 'question']
545
+ var REASON_LABELS = { completed: '完成', error: '出错', aborted: '中止', blocked: '阻塞', 'max-tokens': '输出上限', question: '提问' }
509
546
 
510
547
  /**
511
548
  * 注册设置卡片:settings.plugin.item(keyed,key = 宿主注册的 settings 命名空间)。
@@ -574,64 +611,75 @@ window.__ModuleLoader__.load({
574
611
 
575
612
  /** 可插入的动态信息 token 名(标签/示例值按语言从 I18N 取)。
576
613
  * 注意:{label} 已从插入菜单移除(旧模板中的 {label} 仍兼容渲染/预览)。 */
577
- var TOKEN_KEYS = ['title', 'duration', 'usage', 'error', 'cache', 'tps']
614
+ var TOKEN_KEYS = ['title', 'duration', 'usage', 'error', 'cache', 'tps', 'question']
615
+
616
+ /** 插入菜单可选 token:提问标签 {question} 仅限「提问」状态(标题行/内容行)可插入,
617
+ * 其他行(全局标题/其他原因)的插入按钮不出现提问标签。field 为 ''/undefined(全局标题)或 REASON_FIELDS 成员。 */
618
+ function insertableKeys(field) {
619
+ return field === 'question' ? TOKEN_KEYS : TOKEN_KEYS.filter(function (k) { return k !== 'question' })
620
+ }
578
621
 
579
622
  /** 系统预设:「默认」为基线 + 4 套风格预设(简体中文文案,颜文字/口癖跨语言不自然,故固定 zh;切换语言仅界面翻译,模板保留)。 */
580
623
  var PRESETS = [
581
- { id: 'default', labelKey: 'default', language: 'zh', titleTemplate: '', titleTemplates: { completed: '', error: '', aborted: '', blocked: '', 'max-tokens': '' }, templates: { completed: '', error: '', aborted: '', blocked: '', 'max-tokens': '' } },
624
+ { id: 'default', labelKey: 'default', language: 'zh', titleTemplate: '', titleTemplates: { completed: '', error: '', aborted: '', blocked: '', 'max-tokens': '', question: '' }, templates: { completed: '', error: '', aborted: '', blocked: '', 'max-tokens': '', question: '' } },
582
625
  // 风格内置预设:i18n[语言] 存放各语言文案(zh 为用户编辑版);language 为 null → 载入不强制切换界面语言,
583
626
  // 载入/切换语言时自动取当前语言的文案(缺语言回退 zh)
584
627
  {
585
628
  id: 'kaomoji', labelKey: 'kaomoji', language: null,
586
629
  i18n: {
587
630
  zh: {
588
- titleTemplates: { completed: '任务完成 (^▽^)', error: '任务出错 (;д;)', aborted: '任务中止 (;ω;)', blocked: '任务被阻塞 (・_・;)', 'max-tokens': '任务到上限 ( ̄▽ ̄)' },
631
+ titleTemplates: { completed: '任务完成 (^▽^)', error: '任务出错 (;д;)', aborted: '任务中止 (;ω;)', blocked: '任务被阻塞 (・_・;)', 'max-tokens': '任务到上限 ( ̄▽ ̄)', question: 'AI 提问 (・ω・)ノ' },
589
632
  templates: {
590
633
  completed: '会话「{title}」已完成 (๑•̀ㅂ•́)و✧,请点击查看~',
591
634
  error: '会话「{title}」出错啦 (。•́︿•̀。),请点击查看。',
592
635
  aborted: '会话「{title}」被中止了 (;ω;),请点击查看。',
593
636
  blocked: '会话「{title}」被阻塞了 (・_・;),请点击查看。',
594
637
  'max-tokens': '会话「{title}」达到上限了 ( ̄▽ ̄)ゞ,建议拆分任务,请点击查看。',
638
+ question: 'AI 向你提问 (・ω・)ノ:{question}',
595
639
  },
596
640
  },
597
641
  'zh-tw': {
598
- titleTemplates: { completed: '任務完成 (^▽^)', error: '任務出錯 (;д;)', aborted: '任務中止 (;ω;)', blocked: '任務被阻塞 (・_・;)', 'max-tokens': '任務到上限 ( ̄▽ ̄)' },
642
+ titleTemplates: { completed: '任務完成 (^▽^)', error: '任務出錯 (;д;)', aborted: '任務中止 (;ω;)', blocked: '任務被阻塞 (・_・;)', 'max-tokens': '任務到上限 ( ̄▽ ̄)', question: 'AI 提問 (・ω・)ノ' },
599
643
  templates: {
600
644
  completed: '會話「{title}」已完成 (๑•̀ㅂ•́)و✧,請點擊查看~',
601
645
  error: '會話「{title}」出錯啦 (。•́︿•̀。),請點擊查看。',
602
646
  aborted: '會話「{title}」被中止了 (;ω;),請點擊查看。',
603
647
  blocked: '會話「{title}」被阻塞了 (・_・;),請點擊查看。',
604
648
  'max-tokens': '會話「{title}」達到上限了 ( ̄▽ ̄)ゞ,建議拆分任務,請點擊查看。',
649
+ question: 'AI 向你提問 (・ω・)ノ:{question}',
605
650
  },
606
651
  },
607
652
  en: {
608
- titleTemplates: { completed: 'Task done (^▽^)', error: 'Task failed (;д;)', aborted: 'Task aborted (;ω;)', blocked: 'Task blocked (・_・;)', 'max-tokens': 'Task hit the cap ( ̄▽ ̄)' },
653
+ titleTemplates: { completed: 'Task done (^▽^)', error: 'Task failed (;д;)', aborted: 'Task aborted (;ω;)', blocked: 'Task blocked (・_・;)', 'max-tokens': 'Task hit the cap ( ̄▽ ̄)', question: 'AI asks (・ω・)ノ' },
609
654
  templates: {
610
655
  completed: 'Session "{title}" completed (๑•̀ㅂ•́)و✧ — click to view~',
611
656
  error: 'Session "{title}" failed (。•́︿•̀。) — click to view.',
612
657
  aborted: 'Session "{title}" was aborted (;ω;) — click to view.',
613
658
  blocked: 'Session "{title}" was blocked (・_・;) — click to view.',
614
659
  'max-tokens': 'Session "{title}" hit the cap ( ̄▽ ̄)ゞ — consider splitting the task. Click to view.',
660
+ question: 'AI is asking you (・ω・)ノ: {question}',
615
661
  },
616
662
  },
617
663
  ja: {
618
- titleTemplates: { completed: 'タスク完了 (^▽^)', error: 'タスクエラー (;д;)', aborted: 'タスク中止 (;ω;)', blocked: 'タスクブロック (・_・;)', 'max-tokens': '上限到達 ( ̄▽ ̄)' },
664
+ titleTemplates: { completed: 'タスク完了 (^▽^)', error: 'タスクエラー (;д;)', aborted: 'タスク中止 (;ω;)', blocked: 'タスクブロック (・_・;)', 'max-tokens': '上限到達 ( ̄▽ ̄)', question: 'AI からの質問 (・ω・)ノ' },
619
665
  templates: {
620
666
  completed: 'セッション「{title}」完了 (๑•̀ㅂ•́)و✧ — クリックして表示~',
621
667
  error: 'セッション「{title}」エラー (。•́︿•̀。) — クリックして表示。',
622
668
  aborted: 'セッション「{title}」が中止されました (;ω;) — クリックして表示。',
623
669
  blocked: 'セッション「{title}」がブロックされました (・_・;) — クリックして表示。',
624
670
  'max-tokens': 'セッション「{title}」が上限に到達 ( ̄▽ ̄)ゞ — タスク分割をおすすめ。クリックして表示。',
671
+ question: 'AI からの質問 (・ω・)ノ:{question}',
625
672
  },
626
673
  },
627
674
  ko: {
628
- titleTemplates: { completed: '작업 완료 (^▽^)', error: '작업 오류 (;д;)', aborted: '작업 중단 (;ω;)', blocked: '작업 차단 (・_・;)', 'max-tokens': '한도 도달 ( ̄▽ ̄)' },
675
+ titleTemplates: { completed: '작업 완료 (^▽^)', error: '작업 오류 (;д;)', aborted: '작업 중단 (;ω;)', blocked: '작업 차단 (・_・;)', 'max-tokens': '한도 도달 ( ̄▽ ̄)', question: 'AI 질문 (・ω・)ノ' },
629
676
  templates: {
630
677
  completed: '세션 "{title}" 완료 (๑•̀ㅂ•́)و✧ — 클릭하여 확인~',
631
678
  error: '세션 "{title}" 오류 (。•́︿•̀。) — 클릭하여 확인.',
632
679
  aborted: '세션 "{title}" 중단됨 (;ω;) — 클릭하여 확인.',
633
680
  blocked: '세션 "{title}" 차단됨 (・_・;) — 클릭하여 확인.',
634
681
  'max-tokens': '세션 "{title}" 한도 도달 ( ̄▽ ̄)ゞ — 작업 분할 권장. 클릭하여 확인.',
682
+ question: 'AI가 질문합니다 (・ω・)ノ: {question}',
635
683
  },
636
684
  },
637
685
  },
@@ -640,53 +688,58 @@ window.__ModuleLoader__.load({
640
688
  id: 'felyne', labelKey: 'felyne', language: null,
641
689
  i18n: {
642
690
  zh: {
643
- titleTemplates: { completed: '喵~任务完成', error: '喵…任务出错', aborted: '喵?任务中止', blocked: '喵…任务被挡住', 'max-tokens': '喵喵 任务到上限' },
691
+ titleTemplates: { completed: '喵~任务完成', error: '喵…任务出错', aborted: '喵?任务中止', blocked: '喵…任务被挡住', 'max-tokens': '喵喵 任务到上限', question: '喵~AI 在问你' },
644
692
  templates: {
645
693
  completed: '喵~任务「{title}」完成啦!老大快去看看吧喵~',
646
694
  error: '喵……任务「{title}」出错了喵,老大快来看看喵。',
647
695
  aborted: '喵?!任务「{title}」中止了喵。',
648
696
  blocked: '喵……任务「{title}」遇到困难了喵。',
649
697
  'max-tokens': '喵喵,会话「{title}」到上限啦喵!拆开任务再试喵~',
698
+ question: '喵~AI 有话想问你:{question}',
650
699
  },
651
700
  },
652
701
  'zh-tw': {
653
- titleTemplates: { completed: '喵~任務完成', error: '喵…任務出錯', aborted: '喵?任務中止', blocked: '喵…任務被擋住', 'max-tokens': '喵喵 任務到上限' },
702
+ titleTemplates: { completed: '喵~任務完成', error: '喵…任務出錯', aborted: '喵?任務中止', blocked: '喵…任務被擋住', 'max-tokens': '喵喵 任務到上限', question: '喵~AI 在問你' },
654
703
  templates: {
655
704
  completed: '喵~任務「{title}」完成啦!老大快去看看吧喵~',
656
705
  error: '喵……任務「{title}」出錯了喵,老大快來看看喵。',
657
706
  aborted: '喵?!任務「{title}」中止了喵。',
658
707
  blocked: '喵……任務「{title}」遇到困難了喵。',
659
708
  'max-tokens': '喵喵,會話「{title}」到上限啦喵!拆開任務再試喵~',
709
+ question: '喵~AI 有話想問你:{question}',
660
710
  },
661
711
  },
662
712
  en: {
663
- titleTemplates: { completed: 'Meow~ Task done', error: 'Meow… Task failed', aborted: 'Meow? Task aborted', blocked: 'Meow… Task stuck', 'max-tokens': 'Meow meow, cap reached' },
713
+ titleTemplates: { completed: 'Meow~ Task done', error: 'Meow… Task failed', aborted: 'Meow? Task aborted', blocked: 'Meow… Task stuck', 'max-tokens': 'Meow meow, cap reached', question: 'Meow~ AI is asking' },
664
714
  templates: {
665
715
  completed: 'Meow~ Task "{title}" done! Boss, go check it out meow~',
666
716
  error: 'Meow…… Task "{title}" failed meow. Boss, come take a look meow.',
667
717
  aborted: 'Meow?! Task "{title}" was aborted meow.',
668
718
  blocked: 'Meow…… Task "{title}" hit a snag meow.',
669
719
  'max-tokens': 'Meow meow, session "{title}" hit the cap meow! Split the task and try again meow~',
720
+ question: 'Meow~ AI wants to ask you: {question}',
670
721
  },
671
722
  },
672
723
  ja: {
673
- titleTemplates: { completed: 'にゃ~タスク完了', error: 'にゃ…タスクエラー', aborted: 'にゃ?タスク中止', blocked: 'にゃ…タスク詰まり', 'max-tokens': 'にゃにゃ 上限到達' },
724
+ titleTemplates: { completed: 'にゃ~タスク完了', error: 'にゃ…タスクエラー', aborted: 'にゃ?タスク中止', blocked: 'にゃ…タスク詰まり', 'max-tokens': 'にゃにゃ 上限到達', question: 'にゃ~AI からの質問' },
674
725
  templates: {
675
726
  completed: 'にゃ~タスク「{title}」完了だよ!ボス、見に行ってにゃ~',
676
727
  error: 'にゃ……タスク「{title}」エラーにゃ。ボス、見に来てにゃ。',
677
728
  aborted: 'にゃ?!タスク「{title}」中止にゃ。',
678
729
  blocked: 'にゃ……タスク「{title}」詰まっちゃったにゃ。',
679
730
  'max-tokens': 'にゃにゃ、セッション「{title}」上限に到達にゃ!タスクを分けて再挑戦にゃ~',
731
+ question: 'にゃ~AI が聞きたいことあるにゃ:{question}',
680
732
  },
681
733
  },
682
734
  ko: {
683
- titleTemplates: { completed: '냐~ 작업 완료', error: '냐… 작업 오류', aborted: '냐? 작업 중단', blocked: '냐… 작업 막힘', 'max-tokens': '냐냐 한도 도달' },
735
+ titleTemplates: { completed: '냐~ 작업 완료', error: '냐… 작업 오류', aborted: '냐? 작업 중단', blocked: '냐… 작업 막힘', 'max-tokens': '냐냐 한도 도달', question: '냐~ AI가 물어봐요' },
684
736
  templates: {
685
737
  completed: '냐~ 작업 "{title}" 완료다옹! 사장님 얼른 보러 가주세요 냐~',
686
738
  error: '냐…… 작업 "{title}" 오류냐옹. 사장님 이리 와서 보세요 냐.',
687
739
  aborted: '냐?! 작업 "{title}" 중단됐다냐옹.',
688
740
  blocked: '냐…… 작업 "{title}" 막혔다냐옹.',
689
741
  'max-tokens': '냐냐, 세션 "{title}" 한도 도달했다냐옹! 작업을 나눠 다시 시도하세요 냐~',
742
+ question: '냐~ AI가 물어볼 게 있어요 냐: {question}',
690
743
  },
691
744
  },
692
745
  },
@@ -695,53 +748,58 @@ window.__ModuleLoader__.load({
695
748
  id: 'neko', labelKey: 'neko', language: null,
696
749
  i18n: {
697
750
  zh: {
698
- titleTemplates: { completed: '主人,任务完成喵~', error: '主人…任务出错喵', aborted: '喵!任务中止', blocked: '主人,任务被挡住喵', 'max-tokens': '主人,任务到上限喵' },
751
+ titleTemplates: { completed: '主人,任务完成喵~', error: '主人…任务出错喵', aborted: '喵!任务中止', blocked: '主人,任务被挡住喵', 'max-tokens': '主人,任务到上限喵', question: '主人,AI 在问你喵~' },
699
752
  templates: {
700
753
  completed: '主人~会话「{title}」已经完成啦喵~,快来看看喵!',
701
754
  error: '主人……会话「{title}」出错了喵呜,人家好担心呢……',
702
755
  aborted: '喵!会话「{title}」被中止了喵。',
703
756
  blocked: '主人,会话「{title}」被挡住了喵呜。',
704
757
  'max-tokens': '主人~会话「{title}」到上限了喵……,要不要拆开任务喵?',
758
+ question: '主人~AI 有件事想问你喵:{question}',
705
759
  },
706
760
  },
707
761
  'zh-tw': {
708
- titleTemplates: { completed: '主人,任務完成喵~', error: '主人…任務出錯喵', aborted: '喵!任務中止', blocked: '主人,任務被擋住喵', 'max-tokens': '主人,任務到上限喵' },
762
+ titleTemplates: { completed: '主人,任務完成喵~', error: '主人…任務出錯喵', aborted: '喵!任務中止', blocked: '主人,任務被擋住喵', 'max-tokens': '主人,任務到上限喵', question: '主人,AI 在問你喵~' },
709
763
  templates: {
710
764
  completed: '主人~會話「{title}」已經完成啦喵~,快來看看喵!',
711
765
  error: '主人……會話「{title}」出錯了喵嗚,人家好擔心呢……',
712
766
  aborted: '喵!會話「{title}」被中止了喵。',
713
767
  blocked: '主人,會話「{title}」被擋住了喵嗚。',
714
768
  'max-tokens': '主人~會話「{title}」到上限了喵……,要不要拆開任務喵?',
769
+ question: '主人~AI 有件事想問你喵:{question}',
715
770
  },
716
771
  },
717
772
  en: {
718
- titleTemplates: { completed: 'Master, task done nya~', error: 'Master… task failed nya', aborted: 'Nya! Task aborted', blocked: 'Master, task stuck nya', 'max-tokens': 'Master, cap reached nya' },
773
+ titleTemplates: { completed: 'Master, task done nya~', error: 'Master… task failed nya', aborted: 'Nya! Task aborted', blocked: 'Master, task stuck nya', 'max-tokens': 'Master, cap reached nya', question: 'Master, AI is asking nya~' },
719
774
  templates: {
720
775
  completed: 'Master~ session "{title}" is done nya~, come check it out nya!',
721
776
  error: 'Master…… session "{title}" failed nya…, I\'m so worried……',
722
777
  aborted: 'Nya! Session "{title}" was aborted nya.',
723
778
  blocked: 'Master, session "{title}" got stuck nya…….',
724
779
  'max-tokens': 'Master~ session "{title}" hit the cap nya……, want to split the task nya?',
780
+ question: 'Master~ AI has something to ask you nya: {question}',
725
781
  },
726
782
  },
727
783
  ja: {
728
- titleTemplates: { completed: 'ご主人様、タスク完了にゃ~', error: 'ご主人様…タスクエラーにゃ', aborted: 'にゃ!タスク中止', blocked: 'ご主人様、タスク詰まりにゃ', 'max-tokens': 'ご主人様、上限にゃ' },
784
+ titleTemplates: { completed: 'ご主人様、タスク完了にゃ~', error: 'ご主人様…タスクエラーにゃ', aborted: 'にゃ!タスク中止', blocked: 'ご主人様、タスク詰まりにゃ', 'max-tokens': 'ご主人様、上限にゃ', question: 'ご主人様、AI からの質問にゃ~' },
729
785
  templates: {
730
786
  completed: 'ご主人様~セッション「{title}」完了にゃ~、見てみてにゃ!',
731
787
  error: 'ご主人様……セッション「{title}」エラーにゃう、心配です……',
732
788
  aborted: 'にゃ!セッション「{title}」中止にゃ。',
733
789
  blocked: 'ご主人様、セッション「{title}」詰まりにゃう……。',
734
790
  'max-tokens': 'ご主人様~セッション「{title}」上限にゃ……、タスク分けるにゃ?',
791
+ question: 'ご主人様~AI から聞きたいことがあるにゃ:{question}',
735
792
  },
736
793
  },
737
794
  ko: {
738
- titleTemplates: { completed: '주인님, 작업 완료냐~', error: '주인님… 작업 오류냐', aborted: '냐! 작업 중단', blocked: '주인님, 작업 막힘냐', 'max-tokens': '주인님, 한도 도달냐' },
795
+ titleTemplates: { completed: '주인님, 작업 완료냐~', error: '주인님… 작업 오류냐', aborted: '냐! 작업 중단', blocked: '주인님, 작업 막힘냐', 'max-tokens': '주인님, 한도 도달냐', question: '주인님, AI가 물어봐요 냐~' },
739
796
  templates: {
740
797
  completed: '주인님~ 세션 "{title}" 완료됐냐~, 얼른 보러 오세요 냐!',
741
798
  error: '주인님…… 세션 "{title}" 오류났냐옹, 걱정돼요……',
742
799
  aborted: '냐! 세션 "{title}" 중단됐냐옹.',
743
800
  blocked: '주인님, 세션 "{title}" 막혔냐옹…….',
744
801
  'max-tokens': '주인님~ 세션 "{title}" 한도 도달냐옹……, 작업 나눠볼까 냐?',
802
+ question: '주인님~ AI가 물어볼 게 있어요 냐: {question}',
745
803
  },
746
804
  },
747
805
  },
@@ -750,53 +808,58 @@ window.__ModuleLoader__.load({
750
808
  id: 'deepseek-chan', labelKey: 'deepseekChan', language: null,
751
809
  i18n: {
752
810
  zh: {
753
- titleTemplates: { completed: '任务完成~', error: '任务出错…', aborted: '任务中止', blocked: '任务阻塞', 'max-tokens': '任务到上限' },
811
+ titleTemplates: { completed: '任务完成~', error: '任务出错…', aborted: '任务中止', blocked: '任务阻塞', 'max-tokens': '任务到上限', question: '深酱提问~' },
754
812
  templates: {
755
813
  completed: '深酱报告!会话「{title}」已完成啦~,请点击查看~',
756
814
  error: '深酱道歉……会话「{title}」出错了呢,非常抱歉!',
757
815
  aborted: '深酱遗憾……会话「{title}」被中止了。',
758
816
  blocked: '深酱呜咽……会话「{title}」被阻塞了。',
759
817
  'max-tokens': '深酱提示!会话「{title}」达到输出上限了~,建议拆分任务哦!',
818
+ question: '深酱呼叫!AI 想请你确认:{question}',
760
819
  },
761
820
  },
762
821
  'zh-tw': {
763
- titleTemplates: { completed: '任務完成~', error: '任務出錯…', aborted: '任務中止', blocked: '任務阻塞', 'max-tokens': '任務到上限' },
822
+ titleTemplates: { completed: '任務完成~', error: '任務出錯…', aborted: '任務中止', blocked: '任務阻塞', 'max-tokens': '任務到上限', question: '深醬提問~' },
764
823
  templates: {
765
824
  completed: '深醬報告!會話「{title}」已完成啦~,請點擊查看~',
766
825
  error: '深醬道歉……會話「{title}」出錯了呢,非常抱歉!',
767
826
  aborted: '深醬遺憾……會話「{title}」被中止了。',
768
827
  blocked: '深醬嗚咽……會話「{title}」被阻塞了。',
769
828
  'max-tokens': '深醬提示!會話「{title}」達到輸出上限了~,建議拆分任務哦!',
829
+ question: '深醬呼叫!AI 想請你確認:{question}',
770
830
  },
771
831
  },
772
832
  en: {
773
- titleTemplates: { completed: 'Task done~', error: 'Task failed…', aborted: 'Task aborted', blocked: 'Task blocked', 'max-tokens': 'Cap reached' },
833
+ titleTemplates: { completed: 'Task done~', error: 'Task failed…', aborted: 'Task aborted', blocked: 'Task blocked', 'max-tokens': 'Cap reached', question: 'Shen-chan asks~' },
774
834
  templates: {
775
835
  completed: 'Shen-chan reporting! Session "{title}" is done~, click to view~',
776
836
  error: 'Shen-chan apologizes…… session "{title}" failed, so sorry!',
777
837
  aborted: 'Shen-chan regrets…… session "{title}" was aborted.',
778
838
  blocked: 'Shen-chan whimpers…… session "{title}" was blocked.',
779
839
  'max-tokens': 'Shen-chan tip! Session "{title}" hit the output cap~, consider splitting the task!',
840
+ question: 'Shen-chan calling! AI wants to confirm with you: {question}',
780
841
  },
781
842
  },
782
843
  ja: {
783
- titleTemplates: { completed: 'タスク完了~', error: 'タスクエラー…', aborted: 'タスク中止', blocked: 'タスクブロック', 'max-tokens': '上限到達' },
844
+ titleTemplates: { completed: 'タスク完了~', error: 'タスクエラー…', aborted: 'タスク中止', blocked: 'タスクブロック', 'max-tokens': '上限到達', question: '深ちゃん質問~' },
784
845
  templates: {
785
846
  completed: '深ちゃん報告!セッション「{title}」完了~、クリックして表示~',
786
847
  error: '深ちゃん謝罪……セッション「{title}」エラー、ごめんなさい!',
787
848
  aborted: '深ちゃん残念……セッション「{title}」中止。',
788
849
  blocked: '深ちゃんしくしく……セッション「{title}」ブロック。',
789
850
  'max-tokens': '深ちゃんお知らせ!セッション「{title}」上限到達~、タスク分割おすすめ!',
851
+ question: '深ちゃん呼び出し!AI からの確認です:{question}',
790
852
  },
791
853
  },
792
854
  ko: {
793
- titleTemplates: { completed: '작업 완료~', error: '작업 오류…', aborted: '작업 중단', blocked: '작업 차단', 'max-tokens': '한도 도달' },
855
+ titleTemplates: { completed: '작업 완료~', error: '작업 오류…', aborted: '작업 중단', blocked: '작업 차단', 'max-tokens': '한도 도달', question: '심짱 질문~' },
794
856
  templates: {
795
857
  completed: '심짱 보고! 세션 "{title}" 완료~, 클릭하여 확인~',
796
858
  error: '심짱 사과…… 세션 "{title}" 오류났어요, 정말 죄송해요!',
797
859
  aborted: '심짱 아쉬움…… 세션 "{title}" 중단됐어요.',
798
860
  blocked: '심짱 훌쩍…… 세션 "{title}" 차단됐어요.',
799
861
  'max-tokens': '심짱 알림! 세션 "{title}" 출력 한도 도달~, 작업 분할 추천!',
862
+ question: '심짱 호출! AI가 확인 요청해요: {question}',
800
863
  },
801
864
  },
802
865
  },
@@ -804,21 +867,22 @@ window.__ModuleLoader__.load({
804
867
  ]
805
868
 
806
869
  /** 重置目标:与宿主 DEFAULT_SETTINGS 一致(设置面板可编辑字段子集;语言保留当前值)。 */
807
- var DEFAULT_IMAGES = { completed: '', error: '', aborted: '', blocked: '', 'max-tokens': '' }
870
+ var DEFAULT_IMAGES = { completed: '', error: '', aborted: '', blocked: '', 'max-tokens': '', question: '' }
808
871
  var DEFAULT_FLAT = {
809
872
  language: 'zh',
810
873
  titleTemplate: '',
811
- titleTemplates: { completed: '', error: '', aborted: '', blocked: '', 'max-tokens': '' },
874
+ titleTemplates: { completed: '', error: '', aborted: '', blocked: '', 'max-tokens': '', question: '' },
812
875
  pushMode: 'dual',
876
+ skipSubagents: true,
813
877
  imageUrl: '',
814
878
  iconUrl: '',
815
879
  imagePreviewUrl: '',
816
880
  iconPreviewUrl: '',
817
- images: { completed: '', error: '', aborted: '', blocked: '', 'max-tokens': '' },
818
- icons: { completed: '', error: '', aborted: '', blocked: '', 'max-tokens': '' },
819
- imagePreviews: { completed: '', error: '', aborted: '', blocked: '', 'max-tokens': '' },
820
- iconPreviews: { completed: '', error: '', aborted: '', blocked: '', 'max-tokens': '' },
821
- templates: { completed: '', error: '', aborted: '', blocked: '', 'max-tokens': '' },
881
+ images: { completed: '', error: '', aborted: '', blocked: '', 'max-tokens': '', question: '' },
882
+ icons: { completed: '', error: '', aborted: '', blocked: '', 'max-tokens': '', question: '' },
883
+ imagePreviews: { completed: '', error: '', aborted: '', blocked: '', 'max-tokens': '', question: '' },
884
+ iconPreviews: { completed: '', error: '', aborted: '', blocked: '', 'max-tokens': '', question: '' },
885
+ templates: { completed: '', error: '', aborted: '', blocked: '', 'max-tokens': '', question: '' },
822
886
  }
823
887
 
824
888
  /** 本地存储的用户自定义预设库。 */
@@ -897,7 +961,7 @@ window.__ModuleLoader__.load({
897
961
  /** 把模板拆成 [text|token] 片段(token = {label|duration|usage|error|cache|tps})。 */
898
962
  function parseTemplate(tpl) {
899
963
  var parts = []
900
- var re = /\{(title|label|duration|usage|error|cache|tps|image|icon)\}/g
964
+ var re = /\{(title|label|duration|usage|error|cache|tps|image|icon|question)\}/g
901
965
  var last = 0
902
966
  var m
903
967
  while ((m = re.exec(tpl)) !== null) {
@@ -954,6 +1018,7 @@ window.__ModuleLoader__.load({
954
1018
  language: LANG_IDS.indexOf(cur.language) >= 0 ? cur.language : 'zh',
955
1019
  titleTemplate: String(cur.titleTemplate ?? ''),
956
1020
  includeDuration: !!cur.includeDuration, includeUsage: !!cur.includeUsage,
1021
+ skipSubagents: cur.skipSubagents !== false,
957
1022
  pushMode: ['dual', 'system', 'toast'].indexOf(cur.pushMode) >= 0 ? cur.pushMode : 'dual',
958
1023
  imageUrl: String(cur.imageUrl ?? ''),
959
1024
  iconUrl: String(cur.iconUrl ?? ''),
@@ -1464,9 +1529,21 @@ window.__ModuleLoader__.load({
1464
1529
  /** 各语言「请点击查看」尾句。 */
1465
1530
  var CLICK_SEE = { zh: ',请点击查看。', 'zh-tw': ',請點擊查看。', en: '. Click to view.', ja: '。クリックして表示。', ko: '. 클릭하여 확인.' }
1466
1531
 
1467
- /** 内置默认内容的提示串(空模板时直接展示真实默认效果:会话「{title}」已{状态},请点击查看)。 */
1532
+ /** 提问行的默认文案(空模板时编辑器显示的 hint,与宿主 DEFAULT_PHRASES.question 逐字对齐;
1533
+ * {question} 是胶囊标签,发送时替换为实际提问文本——所见即所推)。 */
1534
+ var QUESTION_DEFAULT_HINTS = {
1535
+ zh: 'AI 向你提问:{question}',
1536
+ 'zh-tw': 'AI 向你提問:{question}',
1537
+ en: 'AI is asking: {question}',
1538
+ ja: 'AI からの質問:{question}',
1539
+ ko: 'AI가 질문합니다: {question}',
1540
+ }
1541
+
1542
+ /** 内置默认内容的提示串(空模板时直接展示真实默认效果:会话「{title}」已{状态},请点击查看)。
1543
+ * 提问行为专属句式(AI 向你提问:{question}),不走「会话…」拼装。 */
1468
1544
  function defaultHintOf(field, langCode) {
1469
1545
  var lang = LANG_IDS.indexOf(langCode) >= 0 ? langCode : 'zh'
1546
+ if (field === 'question') return QUESTION_DEFAULT_HINTS[lang] || 'AI 向你提问:{question}'
1470
1547
  var tt = tOf(lang)
1471
1548
  var label = (tt.kindLabels && tt.kindLabels[field]) || tt.samples.label
1472
1549
  var prefix = SESSION_PREFIX[lang] || '会话'
@@ -1755,6 +1832,7 @@ window.__ModuleLoader__.load({
1755
1832
  scope.set('titleTemplate', flat.titleTemplate),
1756
1833
  scope.set('titleTemplates', titleTemplates),
1757
1834
  scope.set('pushMode', flat.pushMode),
1835
+ scope.set('skipSubagents', flat.skipSubagents),
1758
1836
  scope.set('imageUrl', flat.imageUrl),
1759
1837
  scope.set('iconUrl', flat.iconUrl),
1760
1838
  scope.set('imagePreviewUrl', flat['preview-imageUrl']),
@@ -2021,6 +2099,7 @@ window.__ModuleLoader__.load({
2021
2099
  .replaceAll('{error}', samples.error)
2022
2100
  .replaceAll('{cache}', samples.cache)
2023
2101
  .replaceAll('{tps}', samples.tps)
2102
+ .replaceAll('{question}', field === 'question' ? samples.question : '')
2024
2103
  .trim() || samples.title
2025
2104
  var tpl = templateOf(cur, field)
2026
2105
  var bodyTpl = tpl !== '' ? tpl : defaultHintOf(field, cur.language)
@@ -2034,6 +2113,7 @@ window.__ModuleLoader__.load({
2034
2113
  .replaceAll('{error}', samples.error)
2035
2114
  .replaceAll('{cache}', samples.cache)
2036
2115
  .replaceAll('{tps}', samples.tps)
2116
+ .replaceAll('{question}', field === 'question' ? samples.question : '')
2037
2117
  notifyUser(title, body, ['dual', 'system', 'toast'].indexOf(cur.pushMode) >= 0 ? cur.pushMode : 'dual', {
2038
2118
  iconUrl: String(cur.iconUrl || ''),
2039
2119
  imageUrl: String(cur.imageUrl || ''),
@@ -2057,6 +2137,7 @@ window.__ModuleLoader__.load({
2057
2137
  scope.set('titleTemplate', def.titleTemplate),
2058
2138
  scope.set('titleTemplates', def.titleTemplates),
2059
2139
  scope.set('pushMode', def.pushMode),
2140
+ scope.set('skipSubagents', def.skipSubagents),
2060
2141
  scope.set('imageUrl', def.imageUrl),
2061
2142
  scope.set('iconUrl', def.iconUrl),
2062
2143
  scope.set('imagePreviewUrl', def.imagePreviewUrl),
@@ -2226,7 +2307,7 @@ window.__ModuleLoader__.load({
2226
2307
  borderRadius: '8px', border: '1px solid var(--dsw-alias-border-l2, rgba(127,127,127,0.35))',
2227
2308
  background: 'var(--dsw-alias-bg-layer-2, rgba(127,127,127,0.10))',
2228
2309
  },
2229
- }, TOKEN_KEYS.map(function (k) {
2310
+ }, insertableKeys('').map(function (k) {
2230
2311
  return h('button', {
2231
2312
  key: k, type: 'button',
2232
2313
  onClick: function () {
@@ -2296,6 +2377,14 @@ window.__ModuleLoader__.load({
2296
2377
  : h('svg', { width: '14', height: '14', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: '2.5', strokeLinecap: 'round', style: { display: 'block' } },
2297
2378
  h('line', { x1: '12', y1: '5', x2: '12', y2: '19' }),
2298
2379
  h('line', { x1: '5', y1: '12', x2: '19', y2: '12' }))),
2380
+ // 发送预览箭头:复用 sendTestNotice(标题优先用本行定制标题 titleTplOf,正文用该原因正文模板)
2381
+ h('button', {
2382
+ type: 'button', title: t.sendTestTitle,
2383
+ onClick: function () { sendTestNotice(field) },
2384
+ style: ICON_BTN,
2385
+ }, h('svg', { width: '15', height: '15', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: '2', strokeLinecap: 'round', strokeLinejoin: 'round', style: { display: 'block' } },
2386
+ h('path', { d: 'M5 12h14' }),
2387
+ h('path', { d: 'm12 5 7 7-7 7' }))),
2299
2388
  ),
2300
2389
  ttMenuFor === field
2301
2390
  ? h('div', {
@@ -2305,7 +2394,7 @@ window.__ModuleLoader__.load({
2305
2394
  borderRadius: '8px', border: '1px solid var(--dsw-alias-border-l2, rgba(127,127,127,0.35))',
2306
2395
  background: 'var(--dsw-alias-bg-layer-2, rgba(127,127,127,0.10))',
2307
2396
  },
2308
- }, TOKEN_KEYS.map(function (k) {
2397
+ }, insertableKeys(field).map(function (k) {
2309
2398
  return h('button', {
2310
2399
  key: k, type: 'button',
2311
2400
  onClick: function () {
@@ -2405,7 +2494,7 @@ window.__ModuleLoader__.load({
2405
2494
  borderRadius: '8px', border: '1px solid var(--dsw-alias-border-l2, rgba(127,127,127,0.35))',
2406
2495
  background: 'var(--dsw-alias-bg-layer-2, rgba(127,127,127,0.10))',
2407
2496
  },
2408
- }, TOKEN_KEYS.map(function (k) {
2497
+ }, insertableKeys(field).map(function (k) {
2409
2498
  return h('button', {
2410
2499
  key: k, type: 'button',
2411
2500
  onClick: function () {
@@ -2460,6 +2549,12 @@ window.__ModuleLoader__.load({
2460
2549
  }
2461
2550
  // 通知权限状态区(footer 之上):授权状态 + 引导(Edge 自动屏蔽等场景一目了然)
2462
2551
  rows.push(notificationPermissionRow(t, requestPermissionNow))
2552
+ // 跳过子代理会话:复选框随保存写入设置文档;host 侧实际跳过判断读取该值(任一为真即跳过)
2553
+ rows.push(h('div', {
2554
+ key: 'skip-subagents',
2555
+ style: { display: 'flex', flexDirection: 'column', gap: '6px', padding: '12px 0', borderTop: DIVIDER },
2556
+ },
2557
+ checkRow(t.skipSubagents, cur.skipSubagents !== false, function (e) { setVal('skipSubagents', e.target.checked) }, 'skip-subagents')))
2463
2558
  rows.push(h('div', {
2464
2559
  key: 'footer',
2465
2560
  style: { borderTop: DIVIDER, display: 'flex', justifyContent: 'flex-end', alignItems: 'center', gap: '8px', padding: '12px 0 4px' },