@jxgame2020/dsh-token-quota 0.1.23 → 0.1.24
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 +127 -73
- package/lib/index.js +7 -1
- package/lib/types/client/music.d.ts +16 -0
- package/lib/types/client/music.js +68 -1
- package/lib/types/index.js +3 -0
- package/lib/types/types.d.ts +3 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -91,7 +91,7 @@ window.__ModuleLoader__.load({
|
|
|
91
91
|
d.musicStyle = style;
|
|
92
92
|
},
|
|
93
93
|
setUpgrade: (d, upgrade) => {
|
|
94
|
-
const normalized = upgrade !== null && upgrade.latestVersion !== "" && upgrade.latestVersion !== "0.1.
|
|
94
|
+
const normalized = upgrade !== null && upgrade.latestVersion !== "" && upgrade.latestVersion !== "0.1.24" ? upgrade : null;
|
|
95
95
|
if (d.upgrade === null || d.upgrade.latestVersion !== normalized?.latestVersion) d.upgradeDismissed = false;
|
|
96
96
|
d.upgrade = normalized;
|
|
97
97
|
},
|
|
@@ -197,92 +197,92 @@ window.__ModuleLoader__.load({
|
|
|
197
197
|
document.head.appendChild(tag);
|
|
198
198
|
}
|
|
199
199
|
var TokenQuotaPanel_module_css_default = {
|
|
200
|
+
"dialogBtn": "NPLLIq_dialogBtn",
|
|
201
|
+
"currentBadge": "NPLLIq_currentBadge",
|
|
202
|
+
"panelDim": "NPLLIq_panelDim",
|
|
200
203
|
"row": "NPLLIq_row",
|
|
201
|
-
"
|
|
202
|
-
"bar": "NPLLIq_bar",
|
|
203
|
-
"title": "NPLLIq_title",
|
|
204
|
-
"noticeError": "NPLLIq_noticeError",
|
|
205
|
-
"rowHeader": "NPLLIq_rowHeader",
|
|
206
|
-
"settingsBtn": "NPLLIq_settingsBtn",
|
|
207
|
-
"checkUpdatesRow": "NPLLIq_checkUpdatesRow",
|
|
208
|
-
"logHeader": "NPLLIq_logHeader",
|
|
209
|
-
"logTable": "NPLLIq_logTable",
|
|
210
|
-
"dialogTitle": "NPLLIq_dialogTitle",
|
|
211
|
-
"dialogSection": "NPLLIq_dialogSection",
|
|
212
|
-
"dialogActions": "NPLLIq_dialogActions",
|
|
213
|
-
"tabLabel": "NPLLIq_tabLabel",
|
|
214
|
-
"logModelCol": "NPLLIq_logModelCol",
|
|
215
|
-
"logPagerPages": "NPLLIq_logPagerPages",
|
|
204
|
+
"controls": "NPLLIq_controls",
|
|
216
205
|
"logSearch": "NPLLIq_logSearch",
|
|
206
|
+
"logPagerControls": "NPLLIq_logPagerControls",
|
|
207
|
+
"logModelCol": "NPLLIq_logModelCol",
|
|
208
|
+
"logUsedCol": "NPLLIq_logUsedCol",
|
|
209
|
+
"logTable": "NPLLIq_logTable",
|
|
210
|
+
"checkUpdatesRow": "NPLLIq_checkUpdatesRow",
|
|
211
|
+
"resetRow": "NPLLIq_resetRow",
|
|
217
212
|
"monitorName": "NPLLIq_monitorName",
|
|
218
|
-
"
|
|
219
|
-
"
|
|
220
|
-
"
|
|
213
|
+
"resetSelect": "NPLLIq_resetSelect",
|
|
214
|
+
"settingsBtnActive": "NPLLIq_settingsBtnActive",
|
|
215
|
+
"upgradeBannerText": "NPLLIq_upgradeBannerText",
|
|
216
|
+
"upgradeClose": "NPLLIq_upgradeClose",
|
|
217
|
+
"fullNotice": "NPLLIq_fullNotice",
|
|
218
|
+
"radioRow": "NPLLIq_radioRow",
|
|
221
219
|
"dialogHint": "NPLLIq_dialogHint",
|
|
222
|
-
"
|
|
223
|
-
"
|
|
224
|
-
"rowName": "NPLLIq_rowName",
|
|
225
|
-
"copyBtnDone": "NPLLIq_copyBtnDone",
|
|
226
|
-
"logClearDate": "NPLLIq_logClearDate",
|
|
227
|
-
"notice": "NPLLIq_notice",
|
|
228
|
-
"resetRow": "NPLLIq_resetRow",
|
|
229
|
-
"rowMeta": "NPLLIq_rowMeta",
|
|
230
|
-
"logClearDialog": "NPLLIq_logClearDialog",
|
|
231
|
-
"subtitle": "NPLLIq_subtitle",
|
|
232
|
-
"panel": "NPLLIq_panel",
|
|
233
|
-
"monitorHint": "NPLLIq_monitorHint",
|
|
234
|
-
"logPager": "NPLLIq_logPager",
|
|
235
|
-
"save": "NPLLIq_save",
|
|
236
|
-
"tab": "NPLLIq_tab",
|
|
220
|
+
"rowHeader": "NPLLIq_rowHeader",
|
|
221
|
+
"dialogClose": "NPLLIq_dialogClose",
|
|
237
222
|
"selectBtn": "NPLLIq_selectBtn",
|
|
223
|
+
"upgradeCommands": "NPLLIq_upgradeCommands",
|
|
224
|
+
"fillWarn": "NPLLIq_fillWarn",
|
|
238
225
|
"upgradeCommand": "NPLLIq_upgradeCommand",
|
|
239
|
-
"
|
|
240
|
-
"
|
|
241
|
-
"monitorRow": "NPLLIq_monitorRow",
|
|
242
|
-
"upgradeCommandRow": "NPLLIq_upgradeCommandRow",
|
|
243
|
-
"logPagerControls": "NPLLIq_logPagerControls",
|
|
226
|
+
"checkBtn": "NPLLIq_checkBtn",
|
|
227
|
+
"dialog": "NPLLIq_dialog",
|
|
244
228
|
"logDayCol": "NPLLIq_logDayCol",
|
|
245
|
-
"
|
|
246
|
-
"
|
|
247
|
-
"radioRow": "NPLLIq_radioRow",
|
|
229
|
+
"dialogBtnPrimary": "NPLLIq_dialogBtnPrimary",
|
|
230
|
+
"logPager": "NPLLIq_logPager",
|
|
248
231
|
"dialogOverlay": "NPLLIq_dialogOverlay",
|
|
249
|
-
"
|
|
250
|
-
"
|
|
251
|
-
"
|
|
252
|
-
"
|
|
253
|
-
"
|
|
254
|
-
"
|
|
255
|
-
"
|
|
256
|
-
"
|
|
257
|
-
"
|
|
258
|
-
"
|
|
232
|
+
"dialogSection": "NPLLIq_dialogSection",
|
|
233
|
+
"logClearDialog": "NPLLIq_logClearDialog",
|
|
234
|
+
"headerText": "NPLLIq_headerText",
|
|
235
|
+
"notice": "NPLLIq_notice",
|
|
236
|
+
"tabLabel": "NPLLIq_tabLabel",
|
|
237
|
+
"dialogActions": "NPLLIq_dialogActions",
|
|
238
|
+
"subtitle": "NPLLIq_subtitle",
|
|
239
|
+
"logClearDate": "NPLLIq_logClearDate",
|
|
240
|
+
"headerActions": "NPLLIq_headerActions",
|
|
241
|
+
"dialogTitle": "NPLLIq_dialogTitle",
|
|
259
242
|
"logClearBtn": "NPLLIq_logClearBtn",
|
|
260
|
-
"
|
|
261
|
-
"
|
|
262
|
-
"
|
|
263
|
-
"
|
|
264
|
-
"
|
|
243
|
+
"dialogBody": "NPLLIq_dialogBody",
|
|
244
|
+
"title": "NPLLIq_title",
|
|
245
|
+
"upgradeHint": "NPLLIq_upgradeHint",
|
|
246
|
+
"version": "NPLLIq_version",
|
|
247
|
+
"body": "NPLLIq_body",
|
|
248
|
+
"logPagerPages": "NPLLIq_logPagerPages",
|
|
249
|
+
"monitorList": "NPLLIq_monitorList",
|
|
250
|
+
"logHeader": "NPLLIq_logHeader",
|
|
251
|
+
"copyBtnDone": "NPLLIq_copyBtnDone",
|
|
252
|
+
"tab": "NPLLIq_tab",
|
|
253
|
+
"monitorHint": "NPLLIq_monitorHint",
|
|
254
|
+
"settingsBtn": "NPLLIq_settingsBtn",
|
|
265
255
|
"panelDimStrong": "NPLLIq_panelDimStrong",
|
|
266
256
|
"logToolbar": "NPLLIq_logToolbar",
|
|
257
|
+
"logPagerInfo": "NPLLIq_logPagerInfo",
|
|
258
|
+
"logScroll": "NPLLIq_logScroll",
|
|
259
|
+
"checkErrorHint": "NPLLIq_checkErrorHint",
|
|
260
|
+
"rowMeta": "NPLLIq_rowMeta",
|
|
267
261
|
"logPagerBtn": "NPLLIq_logPagerBtn",
|
|
268
|
-
"
|
|
262
|
+
"logPageSizeSelect": "NPLLIq_logPageSizeSelect",
|
|
263
|
+
"bar": "NPLLIq_bar",
|
|
264
|
+
"input": "NPLLIq_input",
|
|
265
|
+
"panel": "NPLLIq_panel",
|
|
266
|
+
"gearBtn": "NPLLIq_gearBtn",
|
|
267
|
+
"tabIcon": "NPLLIq_tabIcon",
|
|
269
268
|
"upgradeBanner": "NPLLIq_upgradeBanner",
|
|
269
|
+
"noticeError": "NPLLIq_noticeError",
|
|
270
|
+
"upgradeBannerFlash": "NPLLIq_upgradeBannerFlash",
|
|
270
271
|
"copyBtn": "NPLLIq_copyBtn",
|
|
271
|
-
"
|
|
272
|
-
"
|
|
273
|
-
"
|
|
272
|
+
"switch": "NPLLIq_switch",
|
|
273
|
+
"collapse": "NPLLIq_collapse",
|
|
274
|
+
"monitorRow": "NPLLIq_monitorRow",
|
|
275
|
+
"dialogLabel": "NPLLIq_dialogLabel",
|
|
276
|
+
"fillOver": "NPLLIq_fillOver",
|
|
277
|
+
"versionNew": "NPLLIq_versionNew",
|
|
278
|
+
"rowName": "NPLLIq_rowName",
|
|
279
|
+
"save": "NPLLIq_save",
|
|
280
|
+
"upgradeCommandRow": "NPLLIq_upgradeCommandRow",
|
|
274
281
|
"fillIdle": "NPLLIq_fillIdle",
|
|
275
|
-
"headerText": "NPLLIq_headerText",
|
|
276
|
-
"logPagerInfo": "NPLLIq_logPagerInfo",
|
|
277
|
-
"headerActions": "NPLLIq_headerActions",
|
|
278
|
-
"checkErrorHint": "NPLLIq_checkErrorHint",
|
|
279
|
-
"upgradeCommands": "NPLLIq_upgradeCommands",
|
|
280
|
-
"dialogBtnPrimary": "NPLLIq_dialogBtnPrimary",
|
|
281
|
-
"version": "NPLLIq_version",
|
|
282
|
-
"upgradeClose": "NPLLIq_upgradeClose",
|
|
283
282
|
"dialogHeader": "NPLLIq_dialogHeader",
|
|
284
|
-
"
|
|
285
|
-
"
|
|
283
|
+
"logDialog": "NPLLIq_logDialog",
|
|
284
|
+
"checkUpdatesLabel": "NPLLIq_checkUpdatesLabel",
|
|
285
|
+
"header": "NPLLIq_header"
|
|
286
286
|
};
|
|
287
287
|
//#endregion
|
|
288
288
|
//#region lib/types/client/TokenQuotaPanel.js
|
|
@@ -587,13 +587,13 @@ window.__ModuleLoader__.load({
|
|
|
587
587
|
title: t("upgradeAvailableHint"),
|
|
588
588
|
children: [
|
|
589
589
|
"v",
|
|
590
|
-
"0.1.
|
|
590
|
+
"0.1.24",
|
|
591
591
|
" → v",
|
|
592
592
|
upgrade.latestVersion
|
|
593
593
|
]
|
|
594
594
|
}) : (0, react_jsx_runtime.jsxs)("span", {
|
|
595
595
|
className: TokenQuotaPanel_module_css_default.version,
|
|
596
|
-
children: ["v", "0.1.
|
|
596
|
+
children: ["v", "0.1.24"]
|
|
597
597
|
})]
|
|
598
598
|
}), (0, react_jsx_runtime.jsx)("div", {
|
|
599
599
|
className: TokenQuotaPanel_module_css_default.subtitle,
|
|
@@ -1316,8 +1316,20 @@ window.__ModuleLoader__.load({
|
|
|
1316
1316
|
stepCount = 0;
|
|
1317
1317
|
/** Tool counter — used for tool-note pitch. */
|
|
1318
1318
|
toolCount = 0;
|
|
1319
|
+
/**
|
|
1320
|
+
* Progress layer: while a request is in flight (thinking + streaming) the
|
|
1321
|
+
* engine ticks a quiet scale-walking background note every tick so the wait
|
|
1322
|
+
* is audible. Cleared on assistant/message, assistant/attempt or turn/end.
|
|
1323
|
+
*/
|
|
1324
|
+
progressTimer;
|
|
1325
|
+
/** Direction of the progress walk: +1 up the scale, -1 down. */
|
|
1326
|
+
progressDir = 1;
|
|
1327
|
+
/** Scale degree of the next progress note. */
|
|
1328
|
+
progressDegree = 0;
|
|
1319
1329
|
/** Base MIDI note of the current key. C4 = middle C. */
|
|
1320
1330
|
static BASE_MIDI = 60;
|
|
1331
|
+
/** Tick interval of the progress layer (ms). */
|
|
1332
|
+
static PROGRESS_TICK_MS = 750;
|
|
1321
1333
|
/** True once the audio context has been started (needs a user gesture). */
|
|
1322
1334
|
get started() {
|
|
1323
1335
|
return this.audio !== null;
|
|
@@ -1353,6 +1365,7 @@ window.__ModuleLoader__.load({
|
|
|
1353
1365
|
}
|
|
1354
1366
|
setEnabled(value) {
|
|
1355
1367
|
this.enabled = value;
|
|
1368
|
+
if (!value) this.stopProgress();
|
|
1356
1369
|
}
|
|
1357
1370
|
setVolume(value) {
|
|
1358
1371
|
this.volume = Math.max(0, Math.min(1, value));
|
|
@@ -1360,12 +1373,44 @@ window.__ModuleLoader__.load({
|
|
|
1360
1373
|
setStyle(value) {
|
|
1361
1374
|
this.style = value;
|
|
1362
1375
|
}
|
|
1376
|
+
/** Start the quiet in-flight background loop (idempotent). */
|
|
1377
|
+
startProgress() {
|
|
1378
|
+
if (!this.audio || !this.enabled) return;
|
|
1379
|
+
if (this.progressTimer !== void 0) return;
|
|
1380
|
+
this.progressDegree = 0;
|
|
1381
|
+
this.progressDir = 1;
|
|
1382
|
+
const tick = () => {
|
|
1383
|
+
if (!this.audio || !this.enabled) return;
|
|
1384
|
+
const scale = SCALES[this.style];
|
|
1385
|
+
const degree = this.progressDegree % scale.length;
|
|
1386
|
+
const note = TokenQuotaMusic.BASE_MIDI + 12 + (scale[degree] ?? 0);
|
|
1387
|
+
this.playNote(note, .18, .22);
|
|
1388
|
+
const next = this.progressDegree + this.progressDir;
|
|
1389
|
+
if (next >= scale.length) {
|
|
1390
|
+
this.progressDir = -1;
|
|
1391
|
+
this.progressDegree = scale.length - 2;
|
|
1392
|
+
} else if (next < 0) {
|
|
1393
|
+
this.progressDir = 1;
|
|
1394
|
+
this.progressDegree = 0;
|
|
1395
|
+
} else this.progressDegree = next;
|
|
1396
|
+
};
|
|
1397
|
+
tick();
|
|
1398
|
+
this.progressTimer = setInterval(tick, TokenQuotaMusic.PROGRESS_TICK_MS);
|
|
1399
|
+
}
|
|
1400
|
+
/** Stop the in-flight background loop. */
|
|
1401
|
+
stopProgress() {
|
|
1402
|
+
if (this.progressTimer !== void 0) {
|
|
1403
|
+
clearInterval(this.progressTimer);
|
|
1404
|
+
this.progressTimer = void 0;
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1363
1407
|
/** Handle one incoming host action and turn it into sound. */
|
|
1364
1408
|
onAction(action) {
|
|
1365
1409
|
if (!this.enabled || this.audio === null) return;
|
|
1366
1410
|
const base = TokenQuotaMusic.BASE_MIDI;
|
|
1367
1411
|
switch (action.type) {
|
|
1368
1412
|
case "turn/start":
|
|
1413
|
+
this.stopProgress();
|
|
1369
1414
|
this.chordIndex = 0;
|
|
1370
1415
|
this.stepCount = 0;
|
|
1371
1416
|
this.toolCount = 0;
|
|
@@ -1383,6 +1428,7 @@ window.__ModuleLoader__.load({
|
|
|
1383
1428
|
break;
|
|
1384
1429
|
}
|
|
1385
1430
|
case "request/header": {
|
|
1431
|
+
this.startProgress();
|
|
1386
1432
|
const degree = (this.stepCount * 2 + this.toolCount) % SCALES[this.style].length;
|
|
1387
1433
|
const note = base + 12 + SCALES[this.style][degree];
|
|
1388
1434
|
this.playNote(note, .18, .35);
|
|
@@ -1402,11 +1448,19 @@ window.__ModuleLoader__.load({
|
|
|
1402
1448
|
setTimeout(() => this.playNote(base + 11, .22, .3), 70);
|
|
1403
1449
|
}
|
|
1404
1450
|
break;
|
|
1451
|
+
case "assistant/attempt":
|
|
1452
|
+
this.stopProgress();
|
|
1453
|
+
this.playNote(base + 8, .18, .4);
|
|
1454
|
+
setTimeout(() => this.playNote(base + 7, .2, .4), 100);
|
|
1455
|
+
setTimeout(() => this.playNote(base + 5, .25, .4), 200);
|
|
1456
|
+
break;
|
|
1405
1457
|
case "assistant/message":
|
|
1458
|
+
this.stopProgress();
|
|
1406
1459
|
if (action.interrupted) this.playChord(base + 7, "dim", .9, .5);
|
|
1407
1460
|
else this.playChord(this.currentChordRoot(base), this.currentChordQuality(), 1.1, .55);
|
|
1408
1461
|
break;
|
|
1409
1462
|
case "turn/end":
|
|
1463
|
+
this.stopProgress();
|
|
1410
1464
|
this.playChord(base, this.style === "minor" ? "minor" : "major", 2.2, .65);
|
|
1411
1465
|
this.chordIndex = 0;
|
|
1412
1466
|
break;
|
package/lib/index.js
CHANGED
|
@@ -504,7 +504,7 @@ var TokenQuotaService = class TokenQuotaService extends Service {
|
|
|
504
504
|
return this.upgradeCheck;
|
|
505
505
|
}
|
|
506
506
|
async doRefreshUpgrade() {
|
|
507
|
-
const current = "0.1.
|
|
507
|
+
const current = "0.1.24";
|
|
508
508
|
let latest;
|
|
509
509
|
try {
|
|
510
510
|
const response = await fetch(REGISTRY_LATEST_URL, {
|
|
@@ -682,6 +682,12 @@ var TokenQuotaService = class TokenQuotaService extends Service {
|
|
|
682
682
|
error: event.data.error !== void 0
|
|
683
683
|
});
|
|
684
684
|
break;
|
|
685
|
+
case "assistant/attempt":
|
|
686
|
+
this.pushMusicAction({
|
|
687
|
+
type: "assistant/attempt",
|
|
688
|
+
sessionId
|
|
689
|
+
});
|
|
690
|
+
break;
|
|
685
691
|
case "assistant/message":
|
|
686
692
|
this.pushMusicAction({
|
|
687
693
|
type: "assistant/message",
|
|
@@ -27,8 +27,20 @@ export declare class TokenQuotaMusic {
|
|
|
27
27
|
private stepCount;
|
|
28
28
|
/** Tool counter — used for tool-note pitch. */
|
|
29
29
|
private toolCount;
|
|
30
|
+
/**
|
|
31
|
+
* Progress layer: while a request is in flight (thinking + streaming) the
|
|
32
|
+
* engine ticks a quiet scale-walking background note every tick so the wait
|
|
33
|
+
* is audible. Cleared on assistant/message, assistant/attempt or turn/end.
|
|
34
|
+
*/
|
|
35
|
+
private progressTimer;
|
|
36
|
+
/** Direction of the progress walk: +1 up the scale, -1 down. */
|
|
37
|
+
private progressDir;
|
|
38
|
+
/** Scale degree of the next progress note. */
|
|
39
|
+
private progressDegree;
|
|
30
40
|
/** Base MIDI note of the current key. C4 = middle C. */
|
|
31
41
|
private static readonly BASE_MIDI;
|
|
42
|
+
/** Tick interval of the progress layer (ms). */
|
|
43
|
+
private static readonly PROGRESS_TICK_MS;
|
|
32
44
|
/** True once the audio context has been started (needs a user gesture). */
|
|
33
45
|
get started(): boolean;
|
|
34
46
|
/**
|
|
@@ -40,6 +52,10 @@ export declare class TokenQuotaMusic {
|
|
|
40
52
|
setEnabled(value: boolean): void;
|
|
41
53
|
setVolume(value: number): void;
|
|
42
54
|
setStyle(value: TokenQuotaMusicStyle): void;
|
|
55
|
+
/** Start the quiet in-flight background loop (idempotent). */
|
|
56
|
+
private startProgress;
|
|
57
|
+
/** Stop the in-flight background loop. */
|
|
58
|
+
private stopProgress;
|
|
43
59
|
/** Handle one incoming host action and turn it into sound. */
|
|
44
60
|
onAction(action: TokenQuotaMusicAction): void;
|
|
45
61
|
private currentChordRoot;
|
|
@@ -53,8 +53,20 @@ export class TokenQuotaMusic {
|
|
|
53
53
|
stepCount = 0;
|
|
54
54
|
/** Tool counter — used for tool-note pitch. */
|
|
55
55
|
toolCount = 0;
|
|
56
|
+
/**
|
|
57
|
+
* Progress layer: while a request is in flight (thinking + streaming) the
|
|
58
|
+
* engine ticks a quiet scale-walking background note every tick so the wait
|
|
59
|
+
* is audible. Cleared on assistant/message, assistant/attempt or turn/end.
|
|
60
|
+
*/
|
|
61
|
+
progressTimer;
|
|
62
|
+
/** Direction of the progress walk: +1 up the scale, -1 down. */
|
|
63
|
+
progressDir = 1;
|
|
64
|
+
/** Scale degree of the next progress note. */
|
|
65
|
+
progressDegree = 0;
|
|
56
66
|
/** Base MIDI note of the current key. C4 = middle C. */
|
|
57
67
|
static BASE_MIDI = 60;
|
|
68
|
+
/** Tick interval of the progress layer (ms). */
|
|
69
|
+
static PROGRESS_TICK_MS = 750;
|
|
58
70
|
/** True once the audio context has been started (needs a user gesture). */
|
|
59
71
|
get started() {
|
|
60
72
|
return this.audio !== null;
|
|
@@ -96,6 +108,8 @@ export class TokenQuotaMusic {
|
|
|
96
108
|
}
|
|
97
109
|
setEnabled(value) {
|
|
98
110
|
this.enabled = value;
|
|
111
|
+
if (!value)
|
|
112
|
+
this.stopProgress();
|
|
99
113
|
}
|
|
100
114
|
setVolume(value) {
|
|
101
115
|
this.volume = Math.max(0, Math.min(1, value));
|
|
@@ -103,6 +117,47 @@ export class TokenQuotaMusic {
|
|
|
103
117
|
setStyle(value) {
|
|
104
118
|
this.style = value;
|
|
105
119
|
}
|
|
120
|
+
// ── progress layer (while a request is in flight) ──────────────────────
|
|
121
|
+
/** Start the quiet in-flight background loop (idempotent). */
|
|
122
|
+
startProgress() {
|
|
123
|
+
if (!this.audio || !this.enabled)
|
|
124
|
+
return;
|
|
125
|
+
if (this.progressTimer !== undefined)
|
|
126
|
+
return;
|
|
127
|
+
this.progressDegree = 0;
|
|
128
|
+
this.progressDir = 1;
|
|
129
|
+
const tick = () => {
|
|
130
|
+
if (!this.audio || !this.enabled)
|
|
131
|
+
return;
|
|
132
|
+
const scale = SCALES[this.style];
|
|
133
|
+
const degree = this.progressDegree % scale.length;
|
|
134
|
+
const note = TokenQuotaMusic.BASE_MIDI + 12 + (scale[degree] ?? 0);
|
|
135
|
+
// Very quiet, short so it stays in the background.
|
|
136
|
+
this.playNote(note, 0.18, 0.22);
|
|
137
|
+
// Walk up and down the scale like a pendulum.
|
|
138
|
+
const next = this.progressDegree + this.progressDir;
|
|
139
|
+
if (next >= scale.length) {
|
|
140
|
+
this.progressDir = -1;
|
|
141
|
+
this.progressDegree = scale.length - 2;
|
|
142
|
+
}
|
|
143
|
+
else if (next < 0) {
|
|
144
|
+
this.progressDir = 1;
|
|
145
|
+
this.progressDegree = 0;
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
this.progressDegree = next;
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
tick();
|
|
152
|
+
this.progressTimer = setInterval(tick, TokenQuotaMusic.PROGRESS_TICK_MS);
|
|
153
|
+
}
|
|
154
|
+
/** Stop the in-flight background loop. */
|
|
155
|
+
stopProgress() {
|
|
156
|
+
if (this.progressTimer !== undefined) {
|
|
157
|
+
clearInterval(this.progressTimer);
|
|
158
|
+
this.progressTimer = undefined;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
106
161
|
/** Handle one incoming host action and turn it into sound. */
|
|
107
162
|
onAction(action) {
|
|
108
163
|
if (!this.enabled || this.audio === null)
|
|
@@ -110,6 +165,7 @@ export class TokenQuotaMusic {
|
|
|
110
165
|
const base = TokenQuotaMusic.BASE_MIDI;
|
|
111
166
|
switch (action.type) {
|
|
112
167
|
case 'turn/start':
|
|
168
|
+
this.stopProgress();
|
|
113
169
|
this.chordIndex = 0;
|
|
114
170
|
this.stepCount = 0;
|
|
115
171
|
this.toolCount = 0;
|
|
@@ -129,6 +185,8 @@ export class TokenQuotaMusic {
|
|
|
129
185
|
break;
|
|
130
186
|
}
|
|
131
187
|
case 'request/header': {
|
|
188
|
+
// start the background progress layer so thinking + streaming feel audible
|
|
189
|
+
this.startProgress();
|
|
132
190
|
// short melodic flicker — pitch follows step + tool positions
|
|
133
191
|
const degree = (this.stepCount * 2 + this.toolCount) % SCALES[this.style].length;
|
|
134
192
|
const note = base + 12 + SCALES[this.style][degree];
|
|
@@ -137,7 +195,7 @@ export class TokenQuotaMusic {
|
|
|
137
195
|
}
|
|
138
196
|
case 'tool/call':
|
|
139
197
|
this.toolCount += 1;
|
|
140
|
-
// high plink + a low percussive tap
|
|
198
|
+
// high plink + a low percussive tap (progress keeps going in the background)
|
|
141
199
|
this.playNote(base + 24 + (this.toolCount % 3) * 2, 0.12, 0.45);
|
|
142
200
|
this.playNote(base - 12, 0.08, 0.25);
|
|
143
201
|
break;
|
|
@@ -154,7 +212,15 @@ export class TokenQuotaMusic {
|
|
|
154
212
|
}
|
|
155
213
|
break;
|
|
156
214
|
}
|
|
215
|
+
case 'assistant/attempt':
|
|
216
|
+
// failed attempt: cut the progress and play a downward tension figure
|
|
217
|
+
this.stopProgress();
|
|
218
|
+
this.playNote(base + 8, 0.18, 0.4);
|
|
219
|
+
setTimeout(() => this.playNote(base + 7, 0.2, 0.4), 100);
|
|
220
|
+
setTimeout(() => this.playNote(base + 5, 0.25, 0.4), 200);
|
|
221
|
+
break;
|
|
157
222
|
case 'assistant/message':
|
|
223
|
+
this.stopProgress();
|
|
158
224
|
if (action.interrupted) {
|
|
159
225
|
// interrupted turn: diminished tension chord
|
|
160
226
|
this.playChord(base + 7, 'dim', 0.9, 0.5);
|
|
@@ -165,6 +231,7 @@ export class TokenQuotaMusic {
|
|
|
165
231
|
}
|
|
166
232
|
break;
|
|
167
233
|
case 'turn/end':
|
|
234
|
+
this.stopProgress();
|
|
168
235
|
// final tonic chord, longer release
|
|
169
236
|
this.playChord(base, this.style === 'minor' ? 'minor' : 'major', 2.2, 0.65);
|
|
170
237
|
this.chordIndex = 0;
|
package/lib/types/index.js
CHANGED
|
@@ -690,6 +690,9 @@ export class TokenQuotaService extends Service {
|
|
|
690
690
|
case 'tool/result':
|
|
691
691
|
this.pushMusicAction({ type: 'tool/result', sessionId, error: event.data.error !== undefined });
|
|
692
692
|
break;
|
|
693
|
+
case 'assistant/attempt':
|
|
694
|
+
this.pushMusicAction({ type: 'assistant/attempt', sessionId });
|
|
695
|
+
break;
|
|
693
696
|
case 'assistant/message':
|
|
694
697
|
this.pushMusicAction({ type: 'assistant/message', sessionId, interrupted: event.data.interrupted === true });
|
|
695
698
|
if (event.data.usage !== undefined) {
|
package/lib/types/types.d.ts
CHANGED
|
@@ -85,6 +85,9 @@ export type TokenQuotaMusicAction = {
|
|
|
85
85
|
type: 'assistant/message';
|
|
86
86
|
sessionId: string;
|
|
87
87
|
interrupted: boolean;
|
|
88
|
+
} | {
|
|
89
|
+
type: 'assistant/attempt';
|
|
90
|
+
sessionId: string;
|
|
88
91
|
};
|
|
89
92
|
/**
|
|
90
93
|
* Per-model daily-limit settings document shape. Keys are `provider/model`
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jxgame2020/dsh-token-quota",
|
|
3
3
|
"description": "Daily per-model token quota accounting, enforcement, and a floating quota panel for the DeepSeek Harness — a fully self-contained plugin (no core-Harness wiring, no generated RPC contract)",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.24",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|