@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/README.en.md +66 -32
- package/README.ja.md +66 -32
- package/README.ko.md +66 -32
- package/README.md +66 -32
- package/README.zh-TW.md +66 -32
- package/lib/client.js +157 -62
- package/lib/core.js +44 -5
- package/lib/index.js +96 -8
- package/package.json +1 -1
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
|
-
/**
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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' },
|