dsh-realtime-audio-ws 0.2.5 → 0.2.7
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/bundle.js +26 -6
- package/lib/client/index.js +26 -6
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +10 -1
- package/lib/index.js.map +1 -1
- package/package.json +3 -3
- package/src/client/index.ts +47 -5
- package/src/index.ts +9 -1
package/lib/client/bundle.js
CHANGED
|
@@ -402,8 +402,14 @@ window.__ModuleLoader__.load({ id: "dsh-realtime-audio-ws",
|
|
|
402
402
|
const lines = [`<p data-dsh-strip-voice>${escapeHtml(summariseVoice(reply, state.audio))}</p>`];
|
|
403
403
|
if (reply !== null)
|
|
404
404
|
lines.push(`<p data-dsh-strip-route>${escapeHtml(summariseRoute(reply))}</p>`);
|
|
405
|
-
if (state.notice !== '')
|
|
406
|
-
|
|
405
|
+
if (state.notice !== '') {
|
|
406
|
+
const link = state.noticeLink ?? '';
|
|
407
|
+
const anchor = link === ''
|
|
408
|
+
? ''
|
|
409
|
+
: ` <a data-dsh-strip-link href="${escapeHtml(link)}" target="_blank"`
|
|
410
|
+
+ ' rel="noreferrer noopener">open ↗</a>';
|
|
411
|
+
lines.push(`<p data-dsh-strip-notice>${escapeHtml(state.notice)}${anchor}</p>`);
|
|
412
|
+
}
|
|
407
413
|
lines.push(`<p data-dsh-strip-buttons>${buttons(state.audio)}</p>`);
|
|
408
414
|
// Restart-bound settings are omitted rather than shown read-only: the gate says no control at all, and a
|
|
409
415
|
// row that cannot be changed is a row a reader will try to change.
|
|
@@ -521,8 +527,10 @@ window.__ModuleLoader__.load({ id: "dsh-realtime-audio-ws",
|
|
|
521
527
|
let reply = null;
|
|
522
528
|
const notes = {};
|
|
523
529
|
let notice = '';
|
|
530
|
+
/** The page the current notice points at, or empty. Set only where a refusal carried one. */
|
|
531
|
+
let noticeLink = '';
|
|
524
532
|
const paint = () => {
|
|
525
|
-
deps.root.innerHTML = renderStrip({ reply, notes, notice, audio: deps.audio() });
|
|
533
|
+
deps.root.innerHTML = renderStrip({ reply, notes, notice, noticeLink, audio: deps.audio() });
|
|
526
534
|
};
|
|
527
535
|
const refresh = async () => {
|
|
528
536
|
try {
|
|
@@ -546,8 +554,19 @@ window.__ModuleLoader__.load({ id: "dsh-realtime-audio-ws",
|
|
|
546
554
|
try {
|
|
547
555
|
const answer = await deps.request(frame);
|
|
548
556
|
// A refusal carries the reason written to be relayed verbatim, so it is relayed rather than
|
|
549
|
-
// translated — including for a field frozen by its class.
|
|
550
|
-
|
|
557
|
+
// translated — including for a field frozen by its class. A **session** refusal nests its own classified
|
|
558
|
+
// code, remedy and page and leaves the control-level `reason` unset, so reading only that answered the
|
|
559
|
+
// failure a user is most likely to meet with "refused: no reason given" — a panel saying nothing at the
|
|
560
|
+
// exact moment it knows what to do.
|
|
561
|
+
const refusal = answer.refusal;
|
|
562
|
+
if (!answer.ok && refusal !== undefined) {
|
|
563
|
+
noticeLink = refusal.link ?? '';
|
|
564
|
+
line = `${refusal.code ?? refusal.class ?? 'refused'}: ${refusal.remedy ?? 'no reason given'}`;
|
|
565
|
+
}
|
|
566
|
+
else {
|
|
567
|
+
noticeLink = '';
|
|
568
|
+
line = answer.ok ? done : `${answer.code ?? 'refused'}: ${answer.reason ?? 'no reason given'}`;
|
|
569
|
+
}
|
|
551
570
|
}
|
|
552
571
|
catch (error) {
|
|
553
572
|
line = error instanceof Error ? error.message : String(error);
|
|
@@ -568,6 +587,7 @@ window.__ModuleLoader__.load({ id: "dsh-realtime-audio-ws",
|
|
|
568
587
|
// Cleared per action: a notice from the last one is about the last one, and leaving it up would make
|
|
569
588
|
// a successful reconnect read as a failed one.
|
|
570
589
|
notice = '';
|
|
590
|
+
noticeLink = '';
|
|
571
591
|
switch (action) {
|
|
572
592
|
case 'refresh':
|
|
573
593
|
await refresh();
|
|
@@ -598,7 +618,7 @@ window.__ModuleLoader__.load({ id: "dsh-realtime-audio-ws",
|
|
|
598
618
|
void act();
|
|
599
619
|
};
|
|
600
620
|
deps.root.addEventListener('click', onClick);
|
|
601
|
-
return { refresh, state: () => ({ reply, notes, notice, audio: deps.audio() }) };
|
|
621
|
+
return { refresh, state: () => ({ reply, notes, notice, noticeLink, audio: deps.audio() }) };
|
|
602
622
|
}
|
|
603
623
|
/**
|
|
604
624
|
* The client plugin. Publishes the client and the strip on a global, and releases them with the plugin.
|
package/lib/client/index.js
CHANGED
|
@@ -398,8 +398,14 @@ function renderStrip(state) {
|
|
|
398
398
|
const lines = [`<p data-dsh-strip-voice>${escapeHtml(summariseVoice(reply, state.audio))}</p>`];
|
|
399
399
|
if (reply !== null)
|
|
400
400
|
lines.push(`<p data-dsh-strip-route>${escapeHtml(summariseRoute(reply))}</p>`);
|
|
401
|
-
if (state.notice !== '')
|
|
402
|
-
|
|
401
|
+
if (state.notice !== '') {
|
|
402
|
+
const link = state.noticeLink ?? '';
|
|
403
|
+
const anchor = link === ''
|
|
404
|
+
? ''
|
|
405
|
+
: ` <a data-dsh-strip-link href="${escapeHtml(link)}" target="_blank"`
|
|
406
|
+
+ ' rel="noreferrer noopener">open ↗</a>';
|
|
407
|
+
lines.push(`<p data-dsh-strip-notice>${escapeHtml(state.notice)}${anchor}</p>`);
|
|
408
|
+
}
|
|
403
409
|
lines.push(`<p data-dsh-strip-buttons>${buttons(state.audio)}</p>`);
|
|
404
410
|
// Restart-bound settings are omitted rather than shown read-only: the gate says no control at all, and a
|
|
405
411
|
// row that cannot be changed is a row a reader will try to change.
|
|
@@ -517,8 +523,10 @@ function mountStrip(deps) {
|
|
|
517
523
|
let reply = null;
|
|
518
524
|
const notes = {};
|
|
519
525
|
let notice = '';
|
|
526
|
+
/** The page the current notice points at, or empty. Set only where a refusal carried one. */
|
|
527
|
+
let noticeLink = '';
|
|
520
528
|
const paint = () => {
|
|
521
|
-
deps.root.innerHTML = renderStrip({ reply, notes, notice, audio: deps.audio() });
|
|
529
|
+
deps.root.innerHTML = renderStrip({ reply, notes, notice, noticeLink, audio: deps.audio() });
|
|
522
530
|
};
|
|
523
531
|
const refresh = async () => {
|
|
524
532
|
try {
|
|
@@ -542,8 +550,19 @@ function mountStrip(deps) {
|
|
|
542
550
|
try {
|
|
543
551
|
const answer = await deps.request(frame);
|
|
544
552
|
// A refusal carries the reason written to be relayed verbatim, so it is relayed rather than
|
|
545
|
-
// translated — including for a field frozen by its class.
|
|
546
|
-
|
|
553
|
+
// translated — including for a field frozen by its class. A **session** refusal nests its own classified
|
|
554
|
+
// code, remedy and page and leaves the control-level `reason` unset, so reading only that answered the
|
|
555
|
+
// failure a user is most likely to meet with "refused: no reason given" — a panel saying nothing at the
|
|
556
|
+
// exact moment it knows what to do.
|
|
557
|
+
const refusal = answer.refusal;
|
|
558
|
+
if (!answer.ok && refusal !== undefined) {
|
|
559
|
+
noticeLink = refusal.link ?? '';
|
|
560
|
+
line = `${refusal.code ?? refusal.class ?? 'refused'}: ${refusal.remedy ?? 'no reason given'}`;
|
|
561
|
+
}
|
|
562
|
+
else {
|
|
563
|
+
noticeLink = '';
|
|
564
|
+
line = answer.ok ? done : `${answer.code ?? 'refused'}: ${answer.reason ?? 'no reason given'}`;
|
|
565
|
+
}
|
|
547
566
|
}
|
|
548
567
|
catch (error) {
|
|
549
568
|
line = error instanceof Error ? error.message : String(error);
|
|
@@ -564,6 +583,7 @@ function mountStrip(deps) {
|
|
|
564
583
|
// Cleared per action: a notice from the last one is about the last one, and leaving it up would make
|
|
565
584
|
// a successful reconnect read as a failed one.
|
|
566
585
|
notice = '';
|
|
586
|
+
noticeLink = '';
|
|
567
587
|
switch (action) {
|
|
568
588
|
case 'refresh':
|
|
569
589
|
await refresh();
|
|
@@ -594,7 +614,7 @@ function mountStrip(deps) {
|
|
|
594
614
|
void act();
|
|
595
615
|
};
|
|
596
616
|
deps.root.addEventListener('click', onClick);
|
|
597
|
-
return { refresh, state: () => ({ reply, notes, notice, audio: deps.audio() }) };
|
|
617
|
+
return { refresh, state: () => ({ reply, notes, notice, noticeLink, audio: deps.audio() }) };
|
|
598
618
|
}
|
|
599
619
|
/**
|
|
600
620
|
* The client plugin. Publishes the client and the strip on a global, and releases them with the plugin.
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAkBlD,OAAO,EAOL,KAAK,qBAAqB,EAC3B,MAAM,YAAY,CAAA;AAEnB,cAAc,YAAY,CAAA;AAC1B;;;;;;GAMG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAC5F,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,WAAW,GACjB,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAA;AACzF,OAAO,EAAE,gBAAgB,EAAE,KAAK,eAAe,EAAE,KAAK,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACzH,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACrF,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAIpE,mBAAmB;AACnB,eAAO,MAAM,IAAI,sBAAsB,CAAA;AAEvC,eAAO,MAAM,MAAM;;;;;;;;;;;;;;aAajB,CAAA;AAqCF,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,qBAAqB,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAkBlD,OAAO,EAOL,KAAK,qBAAqB,EAC3B,MAAM,YAAY,CAAA;AAEnB,cAAc,YAAY,CAAA;AAC1B;;;;;;GAMG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAC5F,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,WAAW,GACjB,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAA;AACzF,OAAO,EAAE,gBAAgB,EAAE,KAAK,eAAe,EAAE,KAAK,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACzH,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACrF,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAIpE,mBAAmB;AACnB,eAAO,MAAM,IAAI,sBAAsB,CAAA;AAEvC,eAAO,MAAM,MAAM;;;;;;;;;;;;;;aAajB,CAAA;AAqCF,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,qBAAqB,GAAG,IAAI,CAyMvE"}
|
package/lib/index.js
CHANGED
|
@@ -85,7 +85,16 @@ export function apply(ctx, config) {
|
|
|
85
85
|
// entries after `record` has redacted them, and that ordering is the reason this is a sink rather than a
|
|
86
86
|
// second writer with its own idea of what a secret looks like.
|
|
87
87
|
if (config.journalPath.length > 0) {
|
|
88
|
-
|
|
88
|
+
const sink = createJournalFileSink(config.journalPath);
|
|
89
|
+
// Everything recorded before this sink existed — every plugin's boot record, in whatever order the
|
|
90
|
+
// plugins happened to load — reaches the file here, or it reaches it never. The file is the record
|
|
91
|
+
// meant to be read without the profile beside it, so an entry that depends on load order is an entry
|
|
92
|
+
// that lies by omission. This plugin's own `config.resolved` is written above this line, which is
|
|
93
|
+
// exactly why the replay is here: the first version of that record never reached the file at all, and
|
|
94
|
+
// the file's silence looked like a plugin that had failed to load.
|
|
95
|
+
for (const entry of journal.snapshot())
|
|
96
|
+
sink(entry);
|
|
97
|
+
journal.onEntry(sink);
|
|
89
98
|
}
|
|
90
99
|
// The injection event is declared by `@deepseek-ai/dsh-host-webserver`, which this package deliberately
|
|
91
100
|
// does not import: importing it would augment `Context` with a second declaration of `webServer` and
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAM7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,UAAU,GAEX,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AACnE,OAAO,EACL,wBAAwB,EACxB,uBAAuB,EACvB,uBAAuB,EACvB,+BAA+B,EAC/B,YAAY,GAGb,MAAM,YAAY,CAAA;AAEnB,cAAc,YAAY,CAAA;AAC1B;;;;;;GAMG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,EAA8B,MAAM,aAAa,CAAA;AAC5F,OAAO,EACL,oBAAoB,EACpB,iBAAiB,GAUlB,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAwB,MAAM,cAAc,CAAA;AACzF,OAAO,EAAE,gBAAgB,EAAwE,MAAM,kBAAkB,CAAA;AACzH,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAGrF,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AAEzD,mBAAmB;AACnB,MAAM,CAAC,MAAM,IAAI,GAAG,mBAAmB,CAAA;AAEvC,MAAM,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC;IAC3C,aAAa,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,uBAAuB,CAAC;IAChE,cAAc,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,uBAAuB,CAAC;IACjE,uGAAuG;IACvG,0GAA0G;IAC1G,uGAAuG;IACvG,oBAAoB,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,+BAA+B,CAAC;IAC/E,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,wBAAwB,CAAC;IAClE,0GAA0G;IAC1G,kGAAkG;IAClG,gCAAgC;IAChC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;CACzC,CAAC,CAAA;AAqCF,MAAM,UAAU,KAAK,CAAC,GAAY,EAAE,MAA6B;IAC/D,GAAG,CAAC,MAAM,CAAC,CAAC,YAAY,EAAE,WAAW,EAAE,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,EAAE;QAC/D,MAAM,QAAQ,GAAG,QAA+E,CAAA;QAChG,MAAM,QAAQ,GAAG,qBAAqB,CAAC,MAAM,CAAC,aAAa,CAAC,CAAA;QAC5D,MAAM,OAAO,GAAG,IAAI,GAAG,EAAe,CAAA;QACtC,MAAM,KAAK,GAAG,gBAAgB,EAAE,CAAA;QAChC,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAA;QACzC,gGAAgG;QAChG,iGAAiG;QACjG,gFAAgF;QAChF,MAAM,IAAI,GAAG,EAAE,oBAAoB,EAAE,MAAM,CAAC,oBAAoB,EAAE,CAAA;QAClE,qGAAqG;QACrG,qGAAqG;QACrG,iGAAiG;QACjG,mDAAmD;QACnD,OAAO,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,CAAA;QAC3B,wGAAwG;QACxG,0GAA0G;QAC1G,0DAA0D;QAC1D,OAAO,CAAC,MAAM,CAAC,iBAAiB,EAAE;YAChC,MAAM,EAAE,uBAAuB;YAC/B,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,oBAAoB,EAAE,MAAM,CAAC,MAAM,CAAC,oBAAoB,CAAC;YACzD,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC;YAC7C,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC;YAC3C,WAAW,EAAE,MAAM,CAAC,WAAW;SAChC,CAAC,CAAA;QACF,wGAAwG;QACxG,kGAAkG;QAClG,yGAAyG;QACzG,+DAA+D;QAC/D,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-realtime-audio-ws",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.7",
|
|
4
4
|
"description": "The host end of the client half's transport: a WebSocket upgrade route that bridges microphone audio in and agent speech out.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -52,8 +52,8 @@
|
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"ws": "^8.22.0",
|
|
55
|
-
"dsh-realtime": "^0.2.
|
|
56
|
-
"dsh-realtime-agent": "^0.2.
|
|
55
|
+
"dsh-realtime": "^0.2.7",
|
|
56
|
+
"dsh-realtime-agent": "^0.2.11"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"@deepseek-ai/cordis": "^4.0.3",
|
package/src/client/index.ts
CHANGED
|
@@ -142,6 +142,19 @@ export interface ControlReplyLike {
|
|
|
142
142
|
readonly verb?: string
|
|
143
143
|
readonly code?: string
|
|
144
144
|
readonly reason?: string
|
|
145
|
+
/**
|
|
146
|
+
* A *session* refusal, nested inside the reply.
|
|
147
|
+
*
|
|
148
|
+
* A control-level refusal sets `code` and `reason`; a session-level one carries its own classified code, the
|
|
149
|
+
* remedy written to be relayed, and the page the remedy is carried out on. Reading only the top level made
|
|
150
|
+
* the panel answer the failure a user is most likely to meet with "refused: no reason given".
|
|
151
|
+
*/
|
|
152
|
+
readonly refusal?: {
|
|
153
|
+
readonly code?: string
|
|
154
|
+
readonly class?: string
|
|
155
|
+
readonly remedy?: string
|
|
156
|
+
readonly link?: string
|
|
157
|
+
}
|
|
145
158
|
readonly key?: string
|
|
146
159
|
readonly value?: unknown
|
|
147
160
|
readonly voice?: { readonly open: boolean; readonly provider?: string; readonly model?: string; readonly sessionId?: string } | null
|
|
@@ -519,6 +532,15 @@ export interface StripState {
|
|
|
519
532
|
readonly notes: Readonly<Record<string, string>>
|
|
520
533
|
/** Anything with no field to belong to — a transport failure, or what a start or stop produced. */
|
|
521
534
|
readonly notice: string
|
|
535
|
+
/**
|
|
536
|
+
* Where a notice points, when it points anywhere.
|
|
537
|
+
*
|
|
538
|
+
* A remedy that says "add credit" without saying where is half an instruction, and the URL lives in the
|
|
539
|
+
* provider's own message — which this design never carries. So it travels as its own field and is rendered
|
|
540
|
+
* as an anchor: the one `href` this panel emits, and it comes from the provider table, never from text a
|
|
541
|
+
* provider sent. Optional, because most notices point nowhere.
|
|
542
|
+
*/
|
|
543
|
+
readonly noticeLink?: string
|
|
522
544
|
/** What the microphone is doing. */
|
|
523
545
|
readonly audio: ClientAudioState
|
|
524
546
|
}
|
|
@@ -587,7 +609,14 @@ export function renderStrip(state: StripState): string {
|
|
|
587
609
|
const reply = state.reply
|
|
588
610
|
const lines = [`<p data-dsh-strip-voice>${escapeHtml(summariseVoice(reply, state.audio))}</p>`]
|
|
589
611
|
if (reply !== null) lines.push(`<p data-dsh-strip-route>${escapeHtml(summariseRoute(reply))}</p>`)
|
|
590
|
-
if (state.notice !== '')
|
|
612
|
+
if (state.notice !== '') {
|
|
613
|
+
const link = state.noticeLink ?? ''
|
|
614
|
+
const anchor = link === ''
|
|
615
|
+
? ''
|
|
616
|
+
: ` <a data-dsh-strip-link href="${escapeHtml(link)}" target="_blank"`
|
|
617
|
+
+ ' rel="noreferrer noopener">open ↗</a>'
|
|
618
|
+
lines.push(`<p data-dsh-strip-notice>${escapeHtml(state.notice)}${anchor}</p>`)
|
|
619
|
+
}
|
|
591
620
|
lines.push(`<p data-dsh-strip-buttons>${buttons(state.audio)}</p>`)
|
|
592
621
|
// Restart-bound settings are omitted rather than shown read-only: the gate says no control at all, and a
|
|
593
622
|
// row that cannot be changed is a row a reader will try to change.
|
|
@@ -711,9 +740,11 @@ export function mountStrip(deps: StripDeps): Strip {
|
|
|
711
740
|
let reply: ControlReplyLike | null = null
|
|
712
741
|
const notes: Record<string, string> = {}
|
|
713
742
|
let notice = ''
|
|
743
|
+
/** The page the current notice points at, or empty. Set only where a refusal carried one. */
|
|
744
|
+
let noticeLink = ''
|
|
714
745
|
|
|
715
746
|
const paint = (): void => {
|
|
716
|
-
deps.root.innerHTML = renderStrip({ reply, notes, notice, audio: deps.audio() })
|
|
747
|
+
deps.root.innerHTML = renderStrip({ reply, notes, notice, noticeLink, audio: deps.audio() })
|
|
717
748
|
}
|
|
718
749
|
|
|
719
750
|
const refresh = async (): Promise<void> => {
|
|
@@ -738,8 +769,18 @@ export function mountStrip(deps: StripDeps): Strip {
|
|
|
738
769
|
try {
|
|
739
770
|
const answer = await deps.request(frame)
|
|
740
771
|
// A refusal carries the reason written to be relayed verbatim, so it is relayed rather than
|
|
741
|
-
// translated — including for a field frozen by its class.
|
|
742
|
-
|
|
772
|
+
// translated — including for a field frozen by its class. A **session** refusal nests its own classified
|
|
773
|
+
// code, remedy and page and leaves the control-level `reason` unset, so reading only that answered the
|
|
774
|
+
// failure a user is most likely to meet with "refused: no reason given" — a panel saying nothing at the
|
|
775
|
+
// exact moment it knows what to do.
|
|
776
|
+
const refusal = answer.refusal
|
|
777
|
+
if (!answer.ok && refusal !== undefined) {
|
|
778
|
+
noticeLink = refusal.link ?? ''
|
|
779
|
+
line = `${refusal.code ?? refusal.class ?? 'refused'}: ${refusal.remedy ?? 'no reason given'}`
|
|
780
|
+
} else {
|
|
781
|
+
noticeLink = ''
|
|
782
|
+
line = answer.ok ? done : `${answer.code ?? 'refused'}: ${answer.reason ?? 'no reason given'}`
|
|
783
|
+
}
|
|
743
784
|
} catch (error) {
|
|
744
785
|
line = error instanceof Error ? error.message : String(error)
|
|
745
786
|
}
|
|
@@ -757,6 +798,7 @@ export function mountStrip(deps: StripDeps): Strip {
|
|
|
757
798
|
// Cleared per action: a notice from the last one is about the last one, and leaving it up would make
|
|
758
799
|
// a successful reconnect read as a failed one.
|
|
759
800
|
notice = ''
|
|
801
|
+
noticeLink = ''
|
|
760
802
|
switch (action) {
|
|
761
803
|
case 'refresh': await refresh(); return
|
|
762
804
|
case 'disconnect': deps.disconnect(); await refresh(); return
|
|
@@ -777,7 +819,7 @@ export function mountStrip(deps: StripDeps): Strip {
|
|
|
777
819
|
|
|
778
820
|
deps.root.addEventListener('click', onClick)
|
|
779
821
|
|
|
780
|
-
return { refresh, state: () => ({ reply, notes, notice, audio: deps.audio() }) }
|
|
822
|
+
return { refresh, state: () => ({ reply, notes, notice, noticeLink, audio: deps.audio() }) }
|
|
781
823
|
}
|
|
782
824
|
|
|
783
825
|
/**
|
package/src/index.ts
CHANGED
|
@@ -159,7 +159,15 @@ export function apply(ctx: Context, config: RealtimeAudioWsConfig): void {
|
|
|
159
159
|
// entries after `record` has redacted them, and that ordering is the reason this is a sink rather than a
|
|
160
160
|
// second writer with its own idea of what a secret looks like.
|
|
161
161
|
if (config.journalPath.length > 0) {
|
|
162
|
-
|
|
162
|
+
const sink = createJournalFileSink(config.journalPath)
|
|
163
|
+
// Everything recorded before this sink existed — every plugin's boot record, in whatever order the
|
|
164
|
+
// plugins happened to load — reaches the file here, or it reaches it never. The file is the record
|
|
165
|
+
// meant to be read without the profile beside it, so an entry that depends on load order is an entry
|
|
166
|
+
// that lies by omission. This plugin's own `config.resolved` is written above this line, which is
|
|
167
|
+
// exactly why the replay is here: the first version of that record never reached the file at all, and
|
|
168
|
+
// the file's silence looked like a plugin that had failed to load.
|
|
169
|
+
for (const entry of journal.snapshot()) sink(entry)
|
|
170
|
+
journal.onEntry(sink)
|
|
163
171
|
}
|
|
164
172
|
// The injection event is declared by `@deepseek-ai/dsh-host-webserver`, which this package deliberately
|
|
165
173
|
// does not import: importing it would augment `Context` with a second declaration of `webServer` and
|