@linxin666/dsh-pet 0.3.4 → 0.3.5
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.i18n.yaml +2 -2
- package/README.md +13 -10
- package/README.zh.md +13 -10
- package/contracts/voice-pack-v1.schema.json +23 -28
- package/lib/client.js +23 -15
- package/lib/client.js.map +1 -1
- package/lib/index.js +344 -461
- package/lib/types/chatter.d.ts +68 -46
- package/lib/types/chatter.d.ts.map +1 -1
- package/lib/types/chatter.js +243 -301
- package/lib/types/client/PetSprite.d.ts.map +1 -1
- package/lib/types/client/PetSprite.js +16 -17
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/index.js +26 -9
- package/lib/types/event-projection.d.ts +9 -4
- package/lib/types/event-projection.d.ts.map +1 -1
- package/lib/types/event-projection.js +46 -14
- package/lib/types/routes.d.ts.map +1 -1
- package/lib/types/routes.js +8 -3
- package/lib/types/service.d.ts +7 -11
- package/lib/types/service.d.ts.map +1 -1
- package/lib/types/service.js +27 -19
- package/lib/types/voice-pack.d.ts +6 -7
- package/lib/types/voice-pack.d.ts.map +1 -1
- package/lib/types/voice-pack.js +44 -47
- package/package.json +1 -1
- package/src/chatter.test.ts +68 -38
- package/src/chatter.ts +269 -316
- package/src/client/PetSprite.test.tsx +32 -15
- package/src/client/PetSprite.tsx +21 -24
- package/src/client/index.test.tsx +10 -1
- package/src/client/index.ts +29 -10
- package/src/event-projection.ts +57 -16
- package/src/routes.ts +9 -4
- package/src/service.ts +32 -29
- package/src/voice-pack.test.ts +48 -25
- package/src/voice-pack.ts +50 -47
|
@@ -360,14 +360,14 @@ export function PetSprite(props) {
|
|
|
360
360
|
const statusBubble = feedback === null && sessionBubbles.length === 0
|
|
361
361
|
? snapshot?.bubble
|
|
362
362
|
: undefined;
|
|
363
|
-
//
|
|
364
|
-
// woken by
|
|
365
|
-
//
|
|
366
|
-
//
|
|
367
|
-
// voices at once. Interaction feedback takes over the
|
|
368
|
-
// while it plays, so whispers yield to it like status
|
|
369
|
-
|
|
370
|
-
const bubblePresent = feedback !== null || sessionBubbles.length > 0 || statusBubble !== undefined
|
|
363
|
+
// Each session's inner whisper (碎碎念) rides its own bubble — short
|
|
364
|
+
// inner-voice copy woken by that session's activity, never the model's or
|
|
365
|
+
// another session's. Instead of a second bubble of its own, a fresh
|
|
366
|
+
// whisper takes over its session's bubble and re-tints it, so the pet
|
|
367
|
+
// never wears two voices at once. Interaction feedback takes over the
|
|
368
|
+
// whole bubble area while it plays, so whispers yield to it like status
|
|
369
|
+
// copy.
|
|
370
|
+
const bubblePresent = feedback !== null || sessionBubbles.length > 0 || statusBubble !== undefined;
|
|
371
371
|
const displayName = snapshot?.name ?? definition.displayName;
|
|
372
372
|
// The host-served status decoration (M5, #567); absent = text-only bubbles.
|
|
373
373
|
const decoration = snapshot?.decoration;
|
|
@@ -447,14 +447,13 @@ export function PetSprite(props) {
|
|
|
447
447
|
}
|
|
448
448
|
}
|
|
449
449
|
props.onPet();
|
|
450
|
-
}, role: "button", "aria-label": definition.displayName, children: props.visual }) }), props.hud, feedback !== null && (_jsx("div", { ref: bubbleRef, className: clsx(styles.bubble, feedback.kind === 'feed' ? styles.bubbleFeed : styles.bubblePet), children: feedback.text }, feedback.at)), feedback === null && (sessionBubbles.length > 0 || statusBubble !== undefined
|
|
451
|
-
//
|
|
452
|
-
//
|
|
453
|
-
//
|
|
454
|
-
//
|
|
455
|
-
|
|
456
|
-
const
|
|
457
|
-
const bubble = (_jsxs("button", { type: "button", className: clsx(styles.bubble, styles.bubbleStatus, styles.bubbleClickable, speaksWhisper && styles.bubbleWhisper), title: props.t('pet.openSessionHint'), onClick: () => { props.onOpenSession(session.sessionId); }, children: [index === 0 && !speaksWhisper && decoration !== undefined && (_jsx(StatusOrnament, { decoration: decoration, phase: phase })), speaksWhisper ? whisper : session.bubble] }, speaksWhisper ? 'whisper:' + whisper : session.sessionId));
|
|
450
|
+
}, role: "button", "aria-label": definition.displayName, children: props.visual }) }), props.hud, feedback !== null && (_jsx("div", { ref: bubbleRef, className: clsx(styles.bubble, feedback.kind === 'feed' ? styles.bubbleFeed : styles.bubblePet), children: feedback.text }, feedback.at)), feedback === null && (sessionBubbles.length > 0 || statusBubble !== undefined) && (_jsxs("div", { ref: bubbleRef, className: styles.bubbleStack, onPointerEnter: () => setStackPeek(true), onPointerLeave: () => setStackPeek(false), children: [visibleSessions.map((session, index) => {
|
|
451
|
+
// A session's whisper rides ITS OWN bubble (the stack lead when
|
|
452
|
+
// the current session has one, any bubble when the stack is
|
|
453
|
+
// expanded). The key swap restarts the entrance animation so the
|
|
454
|
+
// mood change reads as the bubble re-speaking.
|
|
455
|
+
const speaksWhisper = session.whisper !== undefined;
|
|
456
|
+
const bubble = (_jsxs("button", { type: "button", className: clsx(styles.bubble, styles.bubbleStatus, styles.bubbleClickable, speaksWhisper && styles.bubbleWhisper), title: props.t('pet.openSessionHint'), onClick: () => { props.onOpenSession(session.sessionId); }, children: [index === 0 && !speaksWhisper && decoration !== undefined && (_jsx(StatusOrnament, { decoration: decoration, phase: phase })), session.whisper ?? session.bubble] }, speaksWhisper ? 'whisper:' + session.whisper : session.sessionId));
|
|
458
457
|
// The primary bubble carries the '+N' badge while other sessions
|
|
459
458
|
// hide behind it; the badge toggles the pinned (touch) expansion.
|
|
460
459
|
if (index !== 0 || sessionBubbles.length <= 1)
|
|
@@ -467,7 +466,7 @@ export function PetSprite(props) {
|
|
|
467
466
|
e.stopPropagation();
|
|
468
467
|
setStackPinned(open => !open);
|
|
469
468
|
}, children: stackOpen ? '×' : '+' + String(sessionBubbles.length - 1) })] }, "primary"));
|
|
470
|
-
}), sessionBubbles.length === 0 &&
|
|
469
|
+
}), sessionBubbles.length === 0 && statusBubble !== undefined && (_jsxs("div", { className: clsx(styles.bubble, styles.bubbleStatus), role: "status", "aria-live": "polite", children: [decoration !== undefined && (_jsx(StatusOrnament, { decoration: decoration, phase: phase })), statusBubble] }, "status"))] })), hovered && dragRef.current === null && (_jsx("div", { ref: panelRef, className: clsx(styles.panel, panelAbove && styles.panelAbove), "data-placement": panelAbove ? 'above' : 'below', style: panelAbove && panelLift > 0
|
|
471
470
|
? { marginBottom: panelLift }
|
|
472
471
|
: undefined, onPointerEnter: () => {
|
|
473
472
|
// Reaching the panel (or its bridge) must cancel any hide timer
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAwB,aAAa,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAwB,aAAa,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAA;AA4EnI,wEAAwE;AACxE,eAAO,MAAM,MAAM,UAA2E,CAAA;AAE9F,qEAAqE;AACrE,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AACxE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACrD,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC7D,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AACtF,YAAY,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAA;AACpE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAEnD,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf;;;;WAIG;QACH,aAAa,CAAC,EAAE;YAAE,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAA;SAAE,CAAA;KAC1E;CACF;AAED;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAgT9C"}
|
|
@@ -37,7 +37,8 @@ async function petFetch(path, body) {
|
|
|
37
37
|
}
|
|
38
38
|
/** The live host API instance (always defined; failures surface per call). */
|
|
39
39
|
const petApi = {
|
|
40
|
-
state: () => petFetch('/api/pet/state'
|
|
40
|
+
state: (currentSessionId) => petFetch('/api/pet/state'
|
|
41
|
+
+ (currentSessionId === undefined ? '' : '?current=' + encodeURIComponent(currentSessionId))),
|
|
41
42
|
pets: () => petFetch('/api/pet/pets'),
|
|
42
43
|
interact: (kind) => petFetch('/api/pet/interact', { kind }),
|
|
43
44
|
setVisible: (visible) => petFetch('/api/pet/set-visible', { visible }),
|
|
@@ -142,6 +143,19 @@ export function apply(ctx) {
|
|
|
142
143
|
const setPets = petStore.actions.setPets;
|
|
143
144
|
const setState = petStore.actions.setState;
|
|
144
145
|
const setFeedback = petStore.actions.setFeedback;
|
|
146
|
+
// Clicking a session bubble jumps the GUI to that session; the same
|
|
147
|
+
// sessions face reports which session the user is currently on, so the
|
|
148
|
+
// host can lead the bubble stack with it. A bubble can outlive its
|
|
149
|
+
// disposed session by one poll tick, and the sessions service fails
|
|
150
|
+
// loud on unknown ids, so consult the live list first. The pet's type
|
|
151
|
+
// program also loads the host-side dsh-session package through the
|
|
152
|
+
// service types, whose Context merge declares a different 'sessions'
|
|
153
|
+
// face; pin the browser runtime's outward face here.
|
|
154
|
+
const sessions = ctx.sessions;
|
|
155
|
+
const currentSessionId = () => {
|
|
156
|
+
const current = sessions.list.getSnapshot().current;
|
|
157
|
+
return current === undefined ? undefined : String(current);
|
|
158
|
+
};
|
|
145
159
|
// The registry list is fetched lazily with retries baked into the poll
|
|
146
160
|
// cycle: until it lands, the dock entry renders nothing and every 2s
|
|
147
161
|
// tick tries again. After it lands, one list feeds both the sprite and
|
|
@@ -163,7 +177,7 @@ export function apply(ctx) {
|
|
|
163
177
|
}
|
|
164
178
|
const seq = stateSeq + 1;
|
|
165
179
|
stateSeq = seq;
|
|
166
|
-
petApi.state().then((snapshot) => {
|
|
180
|
+
petApi.state(currentSessionId()).then((snapshot) => {
|
|
167
181
|
if (seq !== stateSeq)
|
|
168
182
|
return;
|
|
169
183
|
setSnapshot(snapshot);
|
|
@@ -207,13 +221,16 @@ export function apply(ctx) {
|
|
|
207
221
|
document.removeEventListener('visibilitychange', onVisibility);
|
|
208
222
|
};
|
|
209
223
|
}, 'pet: poll');
|
|
210
|
-
//
|
|
211
|
-
//
|
|
212
|
-
//
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
224
|
+
// A current-session switch should re-order the bubble stack right away,
|
|
225
|
+
// not on the next 2s tick. Poll only while the tab is visible, as the
|
|
226
|
+
// poll loop itself does.
|
|
227
|
+
const disposeSessionWatch = ctx.effect(() => {
|
|
228
|
+
const unsubscribe = sessions.list.subscribe(() => {
|
|
229
|
+
if (document.visibilityState === 'visible')
|
|
230
|
+
pollNow();
|
|
231
|
+
});
|
|
232
|
+
return unsubscribe;
|
|
233
|
+
}, 'pet: current-session watch');
|
|
217
234
|
const openSession = (sessionId) => {
|
|
218
235
|
const list = sessions.list.getSnapshot();
|
|
219
236
|
if (list.byId[sessionId] === undefined)
|
|
@@ -5,8 +5,11 @@
|
|
|
5
5
|
* {@link ProjectionRuntime} per session and feed events in arrival order.
|
|
6
6
|
*
|
|
7
7
|
* Status copy comes from the chatter voice (big rotating pools, per-tool
|
|
8
|
-
* families, real-argument hints), and
|
|
9
|
-
*
|
|
8
|
+
* families, real-argument hints), and the projection feeds the murmur engine
|
|
9
|
+
* (碎碎念) with the SITUATION — thinking/writing during the stream, the
|
|
10
|
+
* running tool family on tool calls, and the STRUCTURED outcome on
|
|
11
|
+
* tool/result and turn/end — so the pet's inner voice always roughly knows
|
|
12
|
+
* what is going on and never mis-fires on output text. The wall clock is
|
|
10
13
|
* injected by the caller, keeping every projection reproducible.
|
|
11
14
|
* @module @linxin666/dsh-pet/event-projection
|
|
12
15
|
*/
|
|
@@ -22,18 +25,20 @@ export interface ActivityStatusEventLike {
|
|
|
22
25
|
/** Per-session facts needed to project the official event stream. */
|
|
23
26
|
export interface ProjectionRuntime {
|
|
24
27
|
activeTools: Set<string>;
|
|
28
|
+
/** callIds whose tool looked like a test run, marked at tool/call (pet M6). */
|
|
29
|
+
testCalls: Set<string>;
|
|
25
30
|
officialEventsSeen: boolean;
|
|
26
31
|
stepHadFailure: boolean;
|
|
27
32
|
/** Round-robin status copy voice (scene-stable, cadence-rotated). */
|
|
28
33
|
voice: StatusVoice;
|
|
29
|
-
/** Inner-whisper engine fed by the
|
|
34
|
+
/** Inner-whisper engine fed by the projection's situation and outcomes. */
|
|
30
35
|
whispers: WhisperEngine;
|
|
31
36
|
}
|
|
32
37
|
/** One official event projection, optionally carrying a completed turn reward. */
|
|
33
38
|
export interface PetActivityTransition {
|
|
34
39
|
input: PetStateInput;
|
|
35
40
|
completedTurn?: number;
|
|
36
|
-
/** A fresh inner whisper woken by this event
|
|
41
|
+
/** A fresh inner whisper woken by this event, when any. */
|
|
37
42
|
whisper?: string;
|
|
38
43
|
}
|
|
39
44
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-projection.d.ts","sourceRoot":"","sources":["../../src/event-projection.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"event-projection.d.ts","sourceRoot":"","sources":["../../src/event-projection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,EACL,WAAW,EAGX,aAAa,EAGb,KAAK,kBAAkB,EACxB,MAAM,cAAc,CAAA;AAErB,2DAA2D;AAC3D,MAAM,WAAW,uBAAuB;IACtC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,qEAAqE;AACrE,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACxB,+EAA+E;IAC/E,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACtB,kBAAkB,EAAE,OAAO,CAAA;IAC3B,cAAc,EAAE,OAAO,CAAA;IACvB,qEAAqE;IACrE,KAAK,EAAE,WAAW,CAAA;IAClB,2EAA2E;IAC3E,QAAQ,EAAE,aAAa,CAAA;CACxB;AAED,kFAAkF;AAClF,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,aAAa,CAAA;IACpB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,CAAC,EAAE,kBAAkB,GAAG,iBAAiB,CASpF;AAQD,wEAAwE;AACxE,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,aAAa,CAAC,OAAO,CAAC,CAE9E;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,iBAAiB,EAC1B,KAAK,GAAE,MAAmB,GACzB,qBAAqB,GAAG,SAAS,CAmHnC"}
|
|
@@ -5,12 +5,15 @@
|
|
|
5
5
|
* {@link ProjectionRuntime} per session and feed events in arrival order.
|
|
6
6
|
*
|
|
7
7
|
* Status copy comes from the chatter voice (big rotating pools, per-tool
|
|
8
|
-
* families, real-argument hints), and
|
|
9
|
-
*
|
|
8
|
+
* families, real-argument hints), and the projection feeds the murmur engine
|
|
9
|
+
* (碎碎念) with the SITUATION — thinking/writing during the stream, the
|
|
10
|
+
* running tool family on tool calls, and the STRUCTURED outcome on
|
|
11
|
+
* tool/result and turn/end — so the pet's inner voice always roughly knows
|
|
12
|
+
* what is going on and never mis-fires on output text. The wall clock is
|
|
10
13
|
* injected by the caller, keeping every projection reproducible.
|
|
11
14
|
* @module @linxin666/dsh-pet/event-projection
|
|
12
15
|
*/
|
|
13
|
-
import { StatusVoice, toolArgHint, WhisperEngine } from "./chatter.js";
|
|
16
|
+
import { StatusVoice, toolArgHint, toolCategory, WhisperEngine, whisperCategoryOf, looksLikeTestTool, } from "./chatter.js";
|
|
14
17
|
/**
|
|
15
18
|
* Fresh projection runtime for a newly seen session. The optional voice-pack
|
|
16
19
|
* provider (pet-center M4, issue #677) hands both chatter engines their
|
|
@@ -20,6 +23,7 @@ import { StatusVoice, toolArgHint, WhisperEngine } from "./chatter.js";
|
|
|
20
23
|
export function emptyProjectionRuntime(pools) {
|
|
21
24
|
return {
|
|
22
25
|
activeTools: new Set(),
|
|
26
|
+
testCalls: new Set(),
|
|
23
27
|
officialEventsSeen: false,
|
|
24
28
|
stepHadFailure: false,
|
|
25
29
|
voice: new StatusVoice(pools),
|
|
@@ -44,6 +48,7 @@ export function projectOfficialEvent(event, runtime, nowMs = Date.now()) {
|
|
|
44
48
|
switch (event.type) {
|
|
45
49
|
case 'turn/start':
|
|
46
50
|
runtime.activeTools.clear();
|
|
51
|
+
runtime.testCalls.clear();
|
|
47
52
|
runtime.stepHadFailure = false;
|
|
48
53
|
return { input: { phase: 'waiting', line: runtime.voice.scene('prepare', nowMs) } };
|
|
49
54
|
case 'step/start':
|
|
@@ -53,14 +58,14 @@ export function projectOfficialEvent(event, runtime, nowMs = Date.now()) {
|
|
|
53
58
|
case 'assistant/chunk': {
|
|
54
59
|
const { chunk } = event.data;
|
|
55
60
|
if (chunk.type === 'reasoning-delta' && chunk.text.length > 0) {
|
|
56
|
-
const whisper = runtime.whispers.feed(
|
|
61
|
+
const whisper = runtime.whispers.feed('thinking', nowMs);
|
|
57
62
|
return {
|
|
58
63
|
input: { phase: 'thinking', line: runtime.voice.scene('thinking', nowMs) },
|
|
59
64
|
...(whisper === undefined ? {} : { whisper }),
|
|
60
65
|
};
|
|
61
66
|
}
|
|
62
67
|
if (chunk.type === 'text-delta' && chunk.text.length > 0) {
|
|
63
|
-
const whisper = runtime.whispers.feed(
|
|
68
|
+
const whisper = runtime.whispers.feed('writing', nowMs);
|
|
64
69
|
return {
|
|
65
70
|
input: { phase: 'review', line: runtime.voice.scene('review', nowMs) },
|
|
66
71
|
...(whisper === undefined ? {} : { whisper }),
|
|
@@ -70,40 +75,67 @@ export function projectOfficialEvent(event, runtime, nowMs = Date.now()) {
|
|
|
70
75
|
}
|
|
71
76
|
case 'assistant/message':
|
|
72
77
|
return { input: { phase: 'review', line: runtime.voice.scene('review', nowMs) } };
|
|
73
|
-
case 'tool/call':
|
|
74
|
-
|
|
78
|
+
case 'tool/call': {
|
|
79
|
+
const callId = String(event.data.callId);
|
|
80
|
+
runtime.activeTools.add(callId);
|
|
81
|
+
// A test-looking call is remembered so its result (the only place the
|
|
82
|
+
// outcome is known) can wake the test-green mood later.
|
|
83
|
+
if (looksLikeTestTool(event.data.name, event.data.arguments))
|
|
84
|
+
runtime.testCalls.add(callId);
|
|
85
|
+
const whisper = runtime.whispers.feed(whisperCategoryOf(toolCategory(event.data.name)), nowMs);
|
|
75
86
|
return {
|
|
76
87
|
input: {
|
|
77
88
|
phase: 'tool',
|
|
78
89
|
line: runtime.voice.tool(event.data.name, displayToolName(event.data.name), toolArgHint(event.data.name, event.data.arguments), nowMs),
|
|
79
90
|
},
|
|
91
|
+
...(whisper === undefined ? {} : { whisper }),
|
|
80
92
|
};
|
|
93
|
+
}
|
|
81
94
|
case 'tool/result': {
|
|
82
95
|
const block = event.data.message.content[0];
|
|
83
|
-
|
|
84
|
-
|
|
96
|
+
const callId = String(event.data.message.source.callId);
|
|
97
|
+
const failed = event.data.error !== undefined || block.isError === true;
|
|
98
|
+
const wasTest = runtime.testCalls.delete(callId);
|
|
99
|
+
runtime.activeTools.delete(callId);
|
|
100
|
+
runtime.stepHadFailure ||= failed;
|
|
101
|
+
const whisper = failed
|
|
102
|
+
? runtime.whispers.result('fail', nowMs)
|
|
103
|
+
: wasTest
|
|
104
|
+
? runtime.whispers.result('pass', nowMs)
|
|
105
|
+
: undefined;
|
|
106
|
+
const whisperSpread = whisper === undefined ? {} : { whisper };
|
|
85
107
|
if (runtime.activeTools.size > 0) {
|
|
86
108
|
return {
|
|
87
109
|
input: {
|
|
88
110
|
phase: 'tool',
|
|
89
111
|
line: runtime.voice.toolRemaining(runtime.activeTools.size, nowMs),
|
|
90
112
|
},
|
|
113
|
+
...whisperSpread,
|
|
91
114
|
};
|
|
92
115
|
}
|
|
93
116
|
return runtime.stepHadFailure
|
|
94
|
-
? { input: { phase: 'failed', line: runtime.voice.scene('toolFailed', nowMs) } }
|
|
95
|
-
: { input: { phase: 'thinking', line: runtime.voice.scene('toolResult', nowMs) } };
|
|
117
|
+
? { input: { phase: 'failed', line: runtime.voice.scene('toolFailed', nowMs) }, ...whisperSpread }
|
|
118
|
+
: { input: { phase: 'thinking', line: runtime.voice.scene('toolResult', nowMs) }, ...whisperSpread };
|
|
96
119
|
}
|
|
97
120
|
case 'turn/end': {
|
|
98
121
|
runtime.activeTools.clear();
|
|
122
|
+
runtime.testCalls.clear();
|
|
99
123
|
switch (event.data.reason.kind) {
|
|
100
|
-
case 'completed':
|
|
124
|
+
case 'completed': {
|
|
125
|
+
const whisper = runtime.whispers.result('done', nowMs);
|
|
101
126
|
return {
|
|
102
127
|
input: { phase: 'done', line: runtime.voice.scene('done', nowMs) },
|
|
103
128
|
completedTurn: event.data.turn,
|
|
129
|
+
...(whisper === undefined ? {} : { whisper }),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
case 'error': {
|
|
133
|
+
const whisper = runtime.whispers.result('fail', nowMs);
|
|
134
|
+
return {
|
|
135
|
+
input: { phase: 'failed', line: runtime.voice.scene('failed', nowMs) },
|
|
136
|
+
...(whisper === undefined ? {} : { whisper }),
|
|
104
137
|
};
|
|
105
|
-
|
|
106
|
-
return { input: { phase: 'failed', line: runtime.voice.scene('failed', nowMs) } };
|
|
138
|
+
}
|
|
107
139
|
case 'max-tokens':
|
|
108
140
|
return { input: { phase: 'failed', line: runtime.voice.scene('maxTokens', nowMs) } };
|
|
109
141
|
case 'interrupted':
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAA;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAO9C,+CAA+C;AAC/C,eAAO,MAAM,cAAc,aAAa,CAAA;AAExC,0EAA0E;AAC1E,eAAO,MAAM,gBAAgB,SAAS,CAAA;AAMtC;;;;GAIG;AACH,eAAO,MAAM,cAAc;IACzB,yBAAyB;;IAEzB,iDAAiD;;IAEjD,8EAA8E;;CAEtE,CAAA;AAEV,6DAA6D;AAC7D,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd;AAWD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAUrF;AAwND,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB,QAA8B,CAAA;AAe7D,4EAA4E;AAC5E,eAAO,MAAM,eAAe,QAAmB,CAAA;AAE/C,6EAA6E;AAC7E,MAAM,WAAW,eAAe;IAC9B,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAwMD,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,UAAU,CAAC;IAAC,GAAG,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,YAAY,CAAA;CAAE,GAAG,eAAe,GAAG,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAA;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAO9C,+CAA+C;AAC/C,eAAO,MAAM,cAAc,aAAa,CAAA;AAExC,0EAA0E;AAC1E,eAAO,MAAM,gBAAgB,SAAS,CAAA;AAMtC;;;;GAIG;AACH,eAAO,MAAM,cAAc;IACzB,yBAAyB;;IAEzB,iDAAiD;;IAEjD,8EAA8E;;CAEtE,CAAA;AAEV,6DAA6D;AAC7D,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd;AAWD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAUrF;AAwND,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB,QAA8B,CAAA;AAe7D,4EAA4E;AAC5E,eAAO,MAAM,eAAe,QAAmB,CAAA;AAE/C,6EAA6E;AAC7E,MAAM,WAAW,eAAe;IAC9B,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAwMD,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,UAAU,CAAC;IAAC,GAAG,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,YAAY,CAAA;CAAE,GAAG,eAAe,GAAG,QAAQ,EAAE,CAgFjI;AAGD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA"}
|
package/lib/types/routes.js
CHANGED
|
@@ -91,7 +91,7 @@ function guard(ctx, req, res) {
|
|
|
91
91
|
writeJson(res, 403, { ok: false, error: 'forbidden: loopback-only' });
|
|
92
92
|
return false;
|
|
93
93
|
}
|
|
94
|
-
/** Wrap one async service call as a GET JSON route. */
|
|
94
|
+
/** Wrap one async service call as a GET JSON route (request passed through for query params). */
|
|
95
95
|
function getRoute(ctx, path, run) {
|
|
96
96
|
return {
|
|
97
97
|
kind: 'exact',
|
|
@@ -101,7 +101,7 @@ function getRoute(ctx, path, run) {
|
|
|
101
101
|
return;
|
|
102
102
|
if (!requireMethod(req, res, 'GET'))
|
|
103
103
|
return;
|
|
104
|
-
run().then((value) => writeJson(res, 200, value), (error) => {
|
|
104
|
+
run(req).then((value) => writeJson(res, 200, value), (error) => {
|
|
105
105
|
writeJson(res, 500, { ok: false, error: error instanceof Error ? error.message : String(error) });
|
|
106
106
|
});
|
|
107
107
|
},
|
|
@@ -506,7 +506,12 @@ function decorationHandler(ctx, registry, caps) {
|
|
|
506
506
|
export function makePetRoutes(deps) {
|
|
507
507
|
const { service, ctx } = deps;
|
|
508
508
|
const apiRoutes = [
|
|
509
|
-
getRoute(ctx, PET_API_PREFIX + '/state', () =>
|
|
509
|
+
getRoute(ctx, PET_API_PREFIX + '/state', (req) => {
|
|
510
|
+
// The browser half reports the GUI's current session id so the bubble
|
|
511
|
+
// stack can lead with the session the user is actually looking at.
|
|
512
|
+
const current = new URL(req.url ?? '/', 'http://pet.local').searchParams.get('current');
|
|
513
|
+
return service.state(current === null || current === '' ? undefined : current);
|
|
514
|
+
}),
|
|
510
515
|
getRoute(ctx, PET_API_PREFIX + '/pets', () => service.pets()),
|
|
511
516
|
getRoute(ctx, PET_API_PREFIX + '/diagnostics', () => service.diagnostics()),
|
|
512
517
|
postRoute(ctx, PET_API_PREFIX + '/interact', (body) => {
|
package/lib/types/service.d.ts
CHANGED
|
@@ -83,6 +83,8 @@ export interface PetSessionView {
|
|
|
83
83
|
bubble: string;
|
|
84
84
|
/** This session's raw activity phase. */
|
|
85
85
|
phase: PetStateSnapshot['phase'];
|
|
86
|
+
/** This session's fresh inner whisper (碎碎念), when one is within its TTL. */
|
|
87
|
+
whisper?: string;
|
|
86
88
|
}
|
|
87
89
|
/** Hard cap on simultaneously displayed session bubbles (most recent first). */
|
|
88
90
|
export declare const MAX_SESSION_BUBBLES = 12;
|
|
@@ -93,10 +95,10 @@ export interface PetStateView {
|
|
|
93
95
|
phase: PetStateSnapshot['phase'];
|
|
94
96
|
sessionActive: boolean;
|
|
95
97
|
/**
|
|
96
|
-
* Per-session bubbles for every concurrently active TOP-LEVEL session
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
* session.
|
|
98
|
+
* Per-session bubbles for every concurrently active TOP-LEVEL session:
|
|
99
|
+
* the GUI's current session first when reported, the rest most recently
|
|
100
|
+
* active first; optional so older hosts without the multi-session view
|
|
101
|
+
* stay consumable. The single 'bubble' above mirrors the display session.
|
|
100
102
|
*/
|
|
101
103
|
sessions?: PetSessionView[];
|
|
102
104
|
/** Affinity ledger snapshot. */
|
|
@@ -121,12 +123,6 @@ export interface PetStateView {
|
|
|
121
123
|
/** Stock cap. */
|
|
122
124
|
max: number;
|
|
123
125
|
};
|
|
124
|
-
/**
|
|
125
|
-
* The display session's fresh inner whisper (碎碎念), when one is within
|
|
126
|
-
* its TTL — short inner-voice copy woken by the model's own output,
|
|
127
|
-
* rendered by the client as a distinct whisper bubble.
|
|
128
|
-
*/
|
|
129
|
-
whisper?: string;
|
|
130
126
|
/**
|
|
131
127
|
* The active status decoration (pet-center M5, #567), when the master
|
|
132
128
|
* switch is on and the default decoration entry exists. Absent means the
|
|
@@ -218,7 +214,7 @@ export declare class PetService extends Service {
|
|
|
218
214
|
/** Whether the pet service consumes session activity while enabled. */
|
|
219
215
|
isEnabled(): boolean;
|
|
220
216
|
/** RPC: current pet state snapshot. */
|
|
221
|
-
state(): Promise<PetStateView>;
|
|
217
|
+
state(currentSessionId?: string): Promise<PetStateView>;
|
|
222
218
|
/** Current persisted display config (read-only view). */
|
|
223
219
|
display(): PetDisplayConfig;
|
|
224
220
|
/** RPC: the registry entries the browser half renders and selects from. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAEtD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AACpF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAQ9C,OAAO,EAAgC,KAAK,uBAAuB,EAAE,MAAM,aAAa,CAAA;AACxF,OAAO,EASL,KAAK,gBAAgB,EACtB,MAAM,cAAc,CAAA;AACrB,OAAO,EAML,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,qBAAqB,EAC3B,MAAM,eAAe,CAAA;AAGtB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AACtE,OAAO,EAGL,KAAK,cAAc,EAEnB,KAAK,gBAAgB,EACtB,MAAM,YAAY,CAAA;AAenB,4BAA4B;AAC5B,MAAM,WAAW,SAAS;IACxB,uBAAuB;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAA;IAClC,4BAA4B;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAA;IAC/B,4BAA4B;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAA;IAC7B,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iEAAiE;IACjE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,6EAA6E;IAC7E,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,WAAW,CAAA;IACtB,oEAAoE;IACpE,IAAI,CAAC,EAAE,SAAS,WAAW,EAAE,CAAA;CAC9B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,qBAAqB;IACrB,OAAO,EAAE,OAAO,CAAA;IAChB,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAA;IACZ,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAA;IACb,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAA;IACd,iEAAiE;IACjE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B;AAED,2HAA2H;AAC3H,eAAO,MAAM,sBAAsB,QAAQ,CAAA;AAE3C;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC7B,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAA;IACjB,uDAAuD;IACvD,SAAS,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAA;IACxC,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAA;IACd,yCAAyC;IACzC,KAAK,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/service.ts"],"names":[],"mappings":"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"}
|
package/lib/types/service.js
CHANGED
|
@@ -114,8 +114,8 @@ export class PetService extends Service {
|
|
|
114
114
|
return this.enabled;
|
|
115
115
|
}
|
|
116
116
|
/** RPC: current pet state snapshot. */
|
|
117
|
-
async state() {
|
|
118
|
-
return this.view();
|
|
117
|
+
async state(currentSessionId) {
|
|
118
|
+
return this.view(currentSessionId);
|
|
119
119
|
}
|
|
120
120
|
/** Current persisted display config (read-only view). */
|
|
121
121
|
display() {
|
|
@@ -547,15 +547,17 @@ export class PetService extends Service {
|
|
|
547
547
|
if (this.ledger.rewardLegacyTurn(Date.now()))
|
|
548
548
|
this.flush();
|
|
549
549
|
}
|
|
550
|
-
view() {
|
|
550
|
+
view(currentSessionId) {
|
|
551
551
|
const snapshot = this.machine.render();
|
|
552
552
|
const entry = this.activeEntry();
|
|
553
|
-
// One bubble per concurrently active TOP-LEVEL session
|
|
554
|
-
//
|
|
555
|
-
//
|
|
556
|
-
//
|
|
557
|
-
//
|
|
558
|
-
//
|
|
553
|
+
// One bubble per concurrently active TOP-LEVEL session. The GUI's current
|
|
554
|
+
// session leads the stack when reported (the browser half passes its
|
|
555
|
+
// session list's 'current'); everything else keeps the most recent
|
|
556
|
+
// meaningful event order. Subagent children render no bubble of their own
|
|
557
|
+
// (their activity already shows through the spawning conversation's
|
|
558
|
+
// bubble/display, and the bubble buttons navigate to GUI sessions, which
|
|
559
|
+
// subagents are not). Sessions whose own machine has settled (no bubble
|
|
560
|
+
// copy) drop out, so a finished turn does not leave a stale bubble behind.
|
|
559
561
|
const sessions = [];
|
|
560
562
|
for (const [session, activity] of [...this.sessionActivity.entries()].reverse()) {
|
|
561
563
|
if (sessions.length >= MAX_SESSION_BUBBLES)
|
|
@@ -565,22 +567,29 @@ export class PetService extends Service {
|
|
|
565
567
|
const perSession = activity.machine.render();
|
|
566
568
|
if (perSession.bubble === undefined)
|
|
567
569
|
continue;
|
|
570
|
+
// Each session's whisper rides its own bubble while fresh; an expired
|
|
571
|
+
// whisper simply stops appearing (the client's 2 s poll drops it).
|
|
572
|
+
const whisper = activity.whisper;
|
|
573
|
+
const freshWhisper = whisper !== undefined && Date.now() - whisper.at < WHISPER_TTL_MS
|
|
574
|
+
? whisper.text
|
|
575
|
+
: undefined;
|
|
568
576
|
sessions.push({
|
|
569
577
|
sessionId: String(session.id),
|
|
570
578
|
animation: perSession.animation,
|
|
571
579
|
bubble: perSession.bubble,
|
|
572
580
|
phase: perSession.phase,
|
|
581
|
+
...(freshWhisper === undefined ? {} : { whisper: freshWhisper }),
|
|
573
582
|
});
|
|
574
583
|
}
|
|
575
|
-
// The
|
|
576
|
-
//
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
+
// The browser half reports the session the user is currently on; that
|
|
585
|
+
// session's bubble leads the stack (its whisper then speaks on the
|
|
586
|
+
// collapsed single bubble). An unreported or absent session keeps the
|
|
587
|
+
// legacy most-recent-first order.
|
|
588
|
+
if (currentSessionId !== undefined) {
|
|
589
|
+
const index = sessions.findIndex(session => session.sessionId === currentSessionId);
|
|
590
|
+
if (index > 0)
|
|
591
|
+
sessions.unshift(sessions.splice(index, 1)[0]);
|
|
592
|
+
}
|
|
584
593
|
const decoration = this.activeDecoration();
|
|
585
594
|
// Gameplay view: a read-only projection. The settle runs on a copy, so
|
|
586
595
|
// polling never writes pet.json (verbs settle and persist).
|
|
@@ -599,7 +608,6 @@ export class PetService extends Service {
|
|
|
599
608
|
phase: snapshot.phase,
|
|
600
609
|
sessionActive: snapshot.sessionActive,
|
|
601
610
|
sessions,
|
|
602
|
-
...(freshWhisper === undefined ? {} : { whisper: freshWhisper }),
|
|
603
611
|
...(decoration === undefined ? {} : { decoration }),
|
|
604
612
|
affinity: this.ledger.affinityView(Date.now()),
|
|
605
613
|
display: { ...this.ledger.snapshot.display },
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* TypeScript mode: keep it erasable-syntax-only.
|
|
28
28
|
* @module @linxin666/dsh-pet/voice-pack
|
|
29
29
|
*/
|
|
30
|
-
import { type VoicePackOverrides, type
|
|
30
|
+
import { type VoicePackOverrides, type WhisperCategory, type WhisperResult } from './chatter.ts';
|
|
31
31
|
/** Schema version this module normalizes (optional field; missing = 1). */
|
|
32
32
|
export declare const VOICE_PACK_V1: 1;
|
|
33
33
|
/** Hover-panel action buttons a pack can show or hide (canonical order). */
|
|
@@ -58,12 +58,9 @@ export interface VoicePack {
|
|
|
58
58
|
/** Hard caps shared by every pool slot (mirrors the remarks discipline). */
|
|
59
59
|
export declare const VOICE_POOL_LINES_MAX = 64;
|
|
60
60
|
export declare const VOICE_LINE_MAX = 160;
|
|
61
|
-
export declare const VOICE_KEYWORDS_PER_RULE_MAX = 16;
|
|
62
|
-
export declare const VOICE_KEYWORD_MAX = 40;
|
|
63
|
-
export declare const VOICE_RULES_MAX = 32;
|
|
64
61
|
export declare const VOICE_LABEL_MAX = 40;
|
|
65
62
|
export declare const VOICE_STAT_MAX = 80;
|
|
66
|
-
type PoolKind = 'status' | 'tools' | 'toolRemaining' | '
|
|
63
|
+
type PoolKind = 'status' | 'tools' | 'toolRemaining' | 'whisperCategory' | 'whisperResult' | 'label' | 'stat';
|
|
67
64
|
/**
|
|
68
65
|
* Normalize one pool slot. Accepts a single line or an array; non-string
|
|
69
66
|
* entries warn and drop, empty lines drop silently, lines over the length
|
|
@@ -73,8 +70,10 @@ type PoolKind = 'status' | 'tools' | 'toolRemaining' | 'whisperGeneric' | 'whisp
|
|
|
73
70
|
* undefined (the slot keeps the built-in pool).
|
|
74
71
|
*/
|
|
75
72
|
export declare function normalizePool(raw: unknown, kind: PoolKind, onWarning?: (message: string) => void): string[] | undefined;
|
|
76
|
-
/** Normalize
|
|
77
|
-
export declare function
|
|
73
|
+
/** Normalize whisper category pools; a key replaces that category's built-in pool (an explicit empty pool mutes it). */
|
|
74
|
+
export declare function normalizeWhisperCategories(raw: unknown, onWarning?: (message: string) => void): Partial<Record<WhisperCategory, readonly string[]>> | undefined;
|
|
75
|
+
/** Normalize whisper outcome pools; a key replaces that outcome's built-in pool (an explicit empty pool mutes it). */
|
|
76
|
+
export declare function normalizeWhisperResults(raw: unknown, onWarning?: (message: string) => void): Partial<Record<WhisperResult, readonly string[]>> | undefined;
|
|
78
77
|
/** Normalize the panel block (labels / stats / actions; warn-and-drop). */
|
|
79
78
|
export declare function normalizePanel(raw: unknown, onWarning?: (message: string) => void): PetPanelView | undefined;
|
|
80
79
|
/** Voice-pack top-level fields ('$schema' mirrors the schema twin; drift-locked in tests). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voice-pack.d.ts","sourceRoot":"","sources":["../../src/voice-pack.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"voice-pack.d.ts","sourceRoot":"","sources":["../../src/voice-pack.ts"],"names":[],"mappings":"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"}
|