@jskit-ai/agent-docs 0.1.197 → 0.1.199

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.
Files changed (24) hide show
  1. package/guide/agent/app-extras/assistant-conversation.md +94 -12
  2. package/guide/agent/app-extras/assistant-voice.md +154 -10
  3. package/package.json +2 -2
  4. package/patterns/feature-package/example/booking-engine/package.json +1 -1
  5. package/patterns/minimal-foundation/example/package.json +5 -5
  6. package/patterns/shell-foundation/example/package.json +6 -6
  7. package/patterns/shell-foundation/example/packages/main/package.json +1 -1
  8. package/reference/autogen/PATTERN_INDEX.md +35 -35
  9. package/reference/autogen/packages/assistant-core.md +2 -0
  10. package/reference/autogen/packages/assistant-runtime.md +2 -2
  11. package/reference/autogen/packages/assistant-voice.md +9 -1
  12. package/skills/jskit/references/pattern-index.md +35 -35
  13. package/skills/jskit/references/patterns/app/minimal-foundation/example/package.json +5 -5
  14. package/skills/jskit/references/patterns/app/shell-foundation/example/package.json +6 -6
  15. package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/package.json +1 -1
  16. package/skills/jskit/references/patterns/auth/supabase-auth/example/package.json +1 -1
  17. package/skills/jskit/references/patterns/connectors/calendar-cli/example/package.json +4 -4
  18. package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/package.json +2 -2
  19. package/skills/jskit/references/patterns/database/mysql-application/example/package.json +1 -1
  20. package/skills/jskit/references/patterns/database/postgres-application/example/package.json +1 -1
  21. package/skills/jskit/references/patterns/realtime/realtime-application/example/package.json +2 -2
  22. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/package.json +1 -1
  23. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/package.json +2 -2
  24. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/package.json +3 -3
@@ -355,6 +355,22 @@ different submission replaces that reference; it never selects an older matching
355
355
  failure from history. Uncertain delivery still requires **Check delivery**.
356
356
  Voice sends keep their own authored capture and do not consume the typed draft.
357
357
 
358
+ `conversation_not_steerable` is a definite pre-admission rejection: its original
359
+ request remains failed, with the same message ID and captured steering intent.
360
+ It does not become uncertain or silently restart as new work. Hosts should use
361
+ this code only when the original turn is absent or finished before dispatch.
362
+ Transport and provider failures without that proof remain uncertain and require
363
+ receipt inspection; an HTTP 409 alone is not proof of rejection.
364
+
365
+ When `draftStorage` restores a page, known failed deliveries remain failed and
366
+ accepted receipts remain accepted. Saved uncertain, pending or unrecognised
367
+ delivery states stay uncertain with the exact original ID, payload and draft;
368
+ closing a page during HTTP is not proof of rejection. Only the transient
369
+ inspection flag is reset so **Check delivery** is reachable again. A matching
370
+ canonical row marked `receipt: false` cannot settle delivery. Unknown inspection
371
+ never retries; an actual accepted receipt is required to acknowledge the request.
372
+ The existing storage shape is unchanged and reads perform no historical repair.
373
+
358
374
  With `queueWhileSending: false`, the composer is disabled during admission and
359
375
  overlapping typed or retained voice sends return `false` before calling the
360
376
  supplied API. A runtime that supports sending while working still permits the
@@ -363,6 +379,20 @@ of the initial retained conversation composition, so use consistent options for
363
379
  mirrored readers of the same identity. The default is `clearDraftOn: "dispatch"`
364
380
  and the existing queuing behavior for a runtime that advertises steering.
365
381
 
382
+ Applications may opt into `deferWhileWorking: true` with
383
+ `queueWhileSending: true` for a conversation that cannot steer its active turn.
384
+ Typed and retained voice submissions become pending in the original serial
385
+ queue with their exact message ID, text, attachments and captured data. The
386
+ existing subscription must report ready before each ordinary request reaches
387
+ the API; normal server permissions still apply at dispatch. Show **Send** and
388
+ the existing pending status, not **Steer**, when the runtime cannot steer.
389
+ Native steering and explicit retries keep their captured intent. Stop aborts
390
+ these local pre-dispatch followers before stopping the original turn; actor
391
+ retirement and lost access cannot dispatch them later. This option defaults to
392
+ false and belongs to the initial retained conversation composition. It adds no
393
+ server queue or persisted queue recovery; genuine uncertainty still blocks new
394
+ submissions and requires receipt inspection.
395
+
366
396
  Set `draftWhileLoading: true` when people should be able to type before the
367
397
  application resolves its conversation ID or while the first read is unavailable.
368
398
  This keeps one local input scoped to the real actor, endpoint, surface and
@@ -547,13 +577,40 @@ control the corresponding transcript presentation. `userMessageFormat` is
547
577
  For live speech that has not been admitted, supply
548
578
  `adapter.conversation.previewMessage = { messageId, text }` (the original
549
579
  voice capture's `id` is also accepted). The element displays one pending user
550
- message after merging canonical and delivery turns. A matching canonical or
580
+ message after merging canonical and delivery turns. A matching admitted canonical or
551
581
  delivery message ID suppresses that preview, so an admitted utterance appears
552
- once. The application owns updating or clearing its current capture. Preview
582
+ once. An exact unadmitted canonical user (`receipt: false`) or known failed local
583
+ delivery may retain the same bubble as an editable preview; its real status and
584
+ error remain unchanged until the host performs an explicit action. The application owns updating or clearing its current capture. Preview
553
585
  text never enters saved history, the retained runtime's turns or receipt
554
586
  reconciliation; it cannot acknowledge a pending or uncertain send. Keep it out
555
587
  of `adapter.conversation.turns`.
556
588
 
589
+ An optional `previewMessage.actions` supplies `discard(messageId)` and
590
+ `edit(messageId)` with explicit `canDiscard` and `canEdit` booleans. The element
591
+ shows X and pencil actions only on its unsent preview bubble; accepted messages
592
+ never receive them. Add `editing`, `update(messageId, text)`, `send(messageId)`,
593
+ `canSend` and `sending` to reuse the original review textarea inside that same
594
+ bubble and its existing action row for Send. An empty editor remains visible.
595
+ The host owns identity, admission and current-target guards; the typed draft need
596
+ not change. For a known failed voice delivery, explicit Edit may cancel only that
597
+ exact failed local entry through the original delivery owner before authoring a
598
+ fresh request. Plain Retry preserves its original text and intent. The preview
599
+ row replaces the generic failed-action row without concealing the real error.
600
+ `user-message-actions` receives `{ message, turn }` inside the existing user
601
+ bubble; the assistant's `message-actions` slot remains separate.
602
+
603
+ A host with both an existing pending utterance and a newer live capture can
604
+ project `adapter.conversation.previewMessages` as a read-only, identity-deduplicated
605
+ list of those existing descriptors. The singular `previewMessage` contract stays
606
+ available; a supplied list owns the displayed previews. Each row binds only its
607
+ matching descriptor, so the retained failed bubble keeps its actual error and
608
+ recovery controls while newer words stay visible. This list never queues,
609
+ submits or stores transcripts. The host disables the newer capture's Edit while
610
+ its existing pending editor is occupied, preserving its independent Discard.
611
+ Existing runtime presentation options that forward only `previewMessage` do not
612
+ implicitly forward this list; supply it on the host's final adapter conversation.
613
+
557
614
  ### Message delivery
558
615
 
559
616
  Use `createAssistantMessageDelivery` from `/client/conversation` (or the
@@ -765,8 +822,10 @@ are `focus()`, `preserveHeightForNextModelValue()` and `queueResizeTextarea()`;
765
822
 
766
823
  ### Optional avatar
767
824
 
768
- Supply the `avatar` slot to add artwork above the existing transcript. With no
769
- slot, the text-only layout has no avatar region or size control and requires no
825
+ Supply the `avatar` slot to add artwork fixed at the chat's upper right. It stays
826
+ outside the transcript's scroll container; chat text scrolls behind the artwork
827
+ and controls. It creates no side gutter or text wrapping. With no
828
+ slot, the text-only layout has no avatar region or visibility control and requires no
770
829
  voice package or speech service. The application supplies artwork and any
771
830
  animation; the element does not acquire audio or another conversation.
772
831
 
@@ -777,12 +836,30 @@ animation; the element does not acquire audio or another conversation.
777
836
  ```
778
837
 
779
838
  `avatarSize` is a controlled preference: `hidden`, `compact`, `standard`, or
780
- `large`, requesting 0, 64, 112, or 176 CSS pixels of artwork. Its default is
781
- `compact`. The Avatar size button opens the four-preset menu and emits
782
- `update:avatarSize`; keep that value in the application's existing preference
783
- owner if it should be remembered. The button uses the default composer toolbar.
784
- A custom or transcript-only composer uses a separate row above the transcript.
785
- Hidden leaves the button available so the person can show the avatar again.
839
+ `large`, requesting 0, 96, 112, or 176 CSS pixels of artwork. Its default is
840
+ `compact`. The anonymous avatar icon at the chat's upper right shows the avatar;
841
+ the expanded round minus icon at the end of the avatar controls row hides it
842
+ (accessible label **Minimise avatar**). The collapsed **Show avatar** icon remains
843
+ at the chat's upper right and remains clickable above the transcript's reload
844
+ control. Both controls emit
845
+ `update:avatarSize`; keep that
846
+ value in the application's existing preference owner if it should be remembered.
847
+ Show restores the last visible size, or Compact if none has been selected.
848
+ There is no size menu. Hosts can still supply any supported controlled preset.
849
+ The overlay is transparent, so transcript text shows behind the supplied artwork
850
+ rather than an opaque panel.
851
+ Changing visibility does not change the input or composer button layout.
852
+
853
+ The optional `avatar-tools` slot receives the same `{ size, height }` scope and
854
+ places application-supplied controls below the artwork, outside the composer,
855
+ immediately before the element's round minimise control in the same compact row.
856
+ Its content stays mounted while Hidden conceals the presentation with `v-show`,
857
+ so a local controls target can retain its identity. Keep required review,
858
+ recovery and active-capture controls visible outside the hidden presentation.
859
+ The always-visible `avatar-control` slot receives `{ size, height }` beside
860
+ Show/Hide. An application can use it for a collapsed active-mic
861
+ indicator or control without placing voice state in the conversation element.
862
+ The element supplies no audio session or control actions.
786
863
 
787
864
  The effective artwork height uses the conversation container's actual remaining
788
865
  space after its composer, feedback, support and other controls, leaving a target
@@ -793,8 +870,8 @@ a preference change; enlarging the container restores the requested size.
793
870
  The slot receives `{ size, height }`, where `size` is the requested preset and
794
871
  `height` is the effective artwork height. Size artwork to fit that region.
795
872
 
796
- `AssistantConversationClientElement` accepts the same slot and
797
- `v-model:avatar-size`. Its slot also receives the existing retained `runtime`.
873
+ `AssistantConversationClientElement` forwards all three avatar slots and
874
+ `v-model:avatar-size`. Its slots also receive the existing retained `runtime`.
798
875
  Changing the preference does not acquire a new runtime, change the transcript,
799
876
  clear the draft, or deliberately move focus. The transcript retains its normal
800
877
  scroll-following behavior; application visibility and focus policies remain
@@ -3198,6 +3275,11 @@ the native session is idle; the shared native owner establishes that separately.
3198
3275
  Update `draft` synchronously in `setDraft`. Keep the composer mounted during
3199
3276
  external state changes, and change `canSend`, `canStop`, `stopPending` and labels
3200
3277
  from authoritative state. Use `disabled` only when typing itself is unavailable.
3278
+ The retained voice presentation applies a shallow composer `canSend` guard while
3279
+ its existing session has unfinished capture, transcription or review. It keeps
3280
+ the typed draft editable and shows how to resolve the speech first. Sending or
3281
+ discarding the speech restores typed Send; the guard does not replace delivery,
3282
+ attachments, questions or runtime ownership.
3201
3283
  A stopped session must become sendable without waiting for an unrelated pending
3202
3284
  HTTP response. Do not clear the draft on connection recovery or Stop.
3203
3285
 
@@ -108,26 +108,98 @@ recording destinations. Bindings without an adapter retain the original portrait
108
108
  and latest-word/latest-answer caption presentation while their consumers migrate.
109
109
  Headless controller/session use requires no adapter or mounted view.
110
110
 
111
+ An adapter-backed combined view has no Talk/Text tabs: its typed composer and
112
+ voice controls are available together. Minimize it to return to the application's
113
+ existing text navigation; revealing it retains the same conversation. Caption-only
114
+ bindings keep Talk/Text when `openText` is supplied, and Text calls that original
115
+ navigation action without replacing the retained voice session.
116
+
111
117
  `VoiceConversation` accepts `adapter`, `session`, `disabled`, and controlled
112
118
  `avatarSize`, and emits `update:avatarSize`. `VoiceConversationHost` forwards that
113
- preference and event. Supply `v-model:avatar-size` from the application's existing
119
+ preference and event; its default is `hidden`. Supply `v-model:avatar-size` from the application's existing
114
120
  preference owner. Its avatar slot receives the original visual state plus the
115
121
  core slot's requested `size` and effective `height`; temporary clamping preserves
116
122
  the preference.
117
123
 
124
+ `VoiceConversation` also accepts `showAvatar`, which defaults to `true`.
125
+ Set `binding.showAvatar: false` when using `VoiceConversationHost` to omit the
126
+ portrait entirely. Caption-only views then give that space to the existing
127
+ captions and controls; adapter-backed views omit the core avatar slot and its
128
+ visibility control. This presentation choice does not change the retained session,
129
+ typed draft, capture, review or playback operations.
130
+
118
131
  `VoiceConversationControls` reuses the session's original Talk/Pause gesture,
119
- speaker, Stop speaking, error and recording review operations. `compact` places
120
- 48px voice actions beside the ordinary composer tools and bounds the independent
121
- review textarea. Captured words stay explicitly Not sent until normal admission;
122
- review edits do not replace the typed draft. Send retries keep the recording's
132
+ speaker, Stop speaking, error and recording review operations. `compact` uses
133
+ 48px voice actions. Optional `iconOnly`, default `false`, replaces the Talk label
134
+ with its microphone icon while retaining the full state label in `aria-label`,
135
+ the gesture hint and the original pointer/keyboard handlers. The microphone
136
+ tooltip reads “click or long press to talk”.
137
+ Stop speaking keeps a 48px target. Icon-only Talk, speaker and the compact
138
+ settings cog use 32px visible circles inside transparent targets 40px wide and
139
+ 44px tall, with no gap between targets and 8px between visible circles. The
140
+ expanded avatar's minimise button uses the same compact target; collapsed Show
141
+ avatar keeps its 44px square target. All voice controls remain visible while idle. Stop speaking sits beside that pair without changing its position.
142
+ The adapter-backed voice view places these icons below the fixed upper-right
143
+ avatar, outside the composer. Hidden preserves the tools target. Its default
144
+ collapsed presentation shows passive Listening and Speaking icons only while
145
+ those states are active; Show avatar restores the ordinary controls. An idle or
146
+ muted microphone has no Listening indicator. Icon-only presentation omits the
147
+ routine Listening footer; errors, provisional words, review and sound recovery
148
+ remain visible.
149
+ Its `avatar-control` slot forwards the core scope for an always-visible control
150
+ supplied by the application. Hiding is presentation only; it does not pause
151
+ capture, cancel speech or end the session. Compact review keeps its
152
+ independent editable textarea beside the 48px Discard and Send actions, with up
153
+ to two rows and scrolling. Errors keep their full text in small body typography
154
+ to preserve readable history in short containers. Compact Talk keeps one bounded track across Talk, Pause,
155
+ Connecting and held-recording labels. In the labelled compact layout, space for Stop speaking and the normal
156
+ status line remains allocated while idle; an unavailable Stop speaking action
157
+ is absent from keyboard and accessibility navigation. These reservations keep
158
+ capture and playback state changes from moving Talk. Captured words stay
159
+ explicitly Not sent until normal admission;
160
+ review edits do not replace the typed draft. An open hands-free microphone
161
+ does not block typed steering. `session.composerBlocked` gates Send during startup and non-live or
162
+ non-hands-free capture, admission or review. Live hands-free keeps typed Send
163
+ available while spoken requests await admission;
164
+ `session.hasUnsentSpeech` independently protects target switching. The latest
165
+ recognized words remain observable through `binding.onTranscript`, including
166
+ while an earlier request awaits admission. Pause remains usable during that wait
167
+ and does not discard either recording or stop playback. This presentation guard keeps the original adapter's
168
+ actions, attachments and questions. Send retries keep the recording's
123
169
  UUID and captured destination; Discard uses the original cleanup operation.
124
170
 
171
+ `onTranscript(transcript, { canTake })` preserves the original `{ id, text }` or
172
+ null projection and supplies eligibility for unsent-preview controls.
173
+ `session.takeTranscript(messageId, transfer?)` refuses wrong, admitted,
174
+ committing or sending messages. An optional synchronous `transfer(text)` must
175
+ recheck the host's empty typed draft, set it through its original setter, and
176
+ return true; false leaves speech untouched. Taking an active partial uses the
177
+ original capture cancellation and guarded hands-free restart, preserving the
178
+ session and playback. Taking a pending review clears only that review. Hosts
179
+ also gate these controls while their canonical delivery has uncertain admission.
180
+
125
181
  For custom compositions, its optional `toolsTarget` is a DOM element belonging
126
- to the local composer-tools slot. One controls instance moves its buttons there
127
- with Vue Teleport, while review and errors remain in composer-feedback. Keep
128
- that target mounted with the composer; there is no global portal or second
182
+ to the local host, such as an `avatar-tools` target. One controls instance moves
183
+ its buttons there with Vue Teleport, while review and errors stay in the host's
184
+ visible feedback region. Optional `feedbackTarget` moves those existing
185
+ feedback controls into a local composer element without creating another
186
+ controller or replacing its typed draft. Keep these targets mounted, including while the avatar
187
+ is hidden; there is no global portal or second
129
188
  gesture/session owner. With no target, the controls render together in place.
130
189
 
190
+ `VoiceConversationHost` accepts `presentation: 'dialog' | 'inline'`, defaulting
191
+ to `dialog`. Inline replaces the modal wrapper with an in-flow section using
192
+ the same settings, error, target-switch recovery and conversation slot. It omits
193
+ the separate window title, settings and close-button header. Its settings control
194
+ sits with the avatar tools when using the built-in conversation. It has
195
+ no scrim, activator, focus trap, floating reopen button or modal sizing. Its body
196
+ remains mounted for the retained session even when the controller is minimized.
197
+ The application chooses inline only while its existing conversation host is
198
+ present and chooses dialog for fallback; changing presentation does not end or
199
+ replace the controller/session. The `conversation` slot still receives
200
+ `{ binding, session, disabled }`, and the existing `settings` slot receives
201
+ `{ voice }` in either presentation.
202
+
131
203
  The host's optional `conversation` slot receives `{ binding, session, disabled }`
132
204
  and replaces its primary body. Settings, target-switch guards, minimizing,
133
205
  reopening and controller lifetime stay with the same host. An application can
@@ -148,18 +220,39 @@ the visible screen preserves its destination. Opening another target first
148
220
  releases the old audio. Unfinished words must be sent or explicitly discarded
149
221
  before switching. A send in progress cannot be discarded to switch targets.
150
222
 
223
+ Microphone and speaker choices are independent. Opening or restoring a voice
224
+ view starts neither direction. Sound defaults off unless the application supplies
225
+ `defaults.readAloud: true`. Tap or hold Talk starts capture without changing that
226
+ choice; Pause or ending live capture leaves queued/current playback intact.
227
+ Ordinary typed or spoken steering also leaves playback intact. An explicit
228
+ silence command, Stop speaking, switching the speaker off, or releasing the voice
229
+ target interrupts it.
230
+
231
+ The speaker button changes the requested preference. Its optional
232
+ `binding.onReadAloudChange(value)` callback runs only for that explicit change,
233
+ never for preference hydration, microphone actions or navigation. The application
234
+ owns storing it for the correct authenticated user. `defaults.readAloud` initializes
235
+ a new session; it is not a second preference store. Sound on applies to future
236
+ outputs and does not replay history. If browser playback is blocked, the speaker
237
+ choice stays on and **Enable sound** retries unlocking it. Microphone permission
238
+ and capture continue independently, including while sound unlock is pending.
239
+
151
240
  Stop speaking cancels playback and queued speech. Stop agent work calls the
152
241
  binding's separate `cancelWork` operation. `end()` releases voice after pending
153
242
  words are resolved; `dispose()` always releases it. Reconnection does not replay
154
243
  messages, resend captured audio or automatically restart the microphone.
155
244
 
156
245
  Bindings may supply `defaults.mode` (`push-to-talk` or `hands-free`),
157
- `defaults.reviewBeforeSend`, and `defaults.voiceId`. Recordings started through
246
+ `defaults.reviewBeforeSend`, `defaults.voiceId`, and boolean `defaults.readAloud`. Recordings started through
158
247
  `startHeldRecording()` require review; the modal's push-to-talk gesture uses
159
248
  `reviewBeforeSend`. The Talk/Pause microphone icon and speaker toggle show their states. The
160
249
  Voice settings cog loads the service's installed voices without recording.
161
250
  Pause finalizes the current utterance before muting, including buffered audio,
162
- and applies the recording's review preference. Resume starts a fresh recording.
251
+ and applies the recording's review preference. If an earlier request is pending,
252
+ Pause finishes the newer recording after that request settles. Resume keeps an
253
+ unfinished recording open or starts a fresh recording after it ends. Talk and
254
+ hold remain available during pending delivery, while transcribing and committing
255
+ retain their original guards.
163
256
  The review panel stays hidden during automatic admission; failed admission keeps
164
257
  the words and message identity available for review and retry.
165
258
  The retained-adapter view scrolls the shared full history while its composer and
@@ -168,6 +261,39 @@ portrait and controls stay fixed while captions scroll. A voice selection affect
168
261
  phrases of a reply retain the original speaker. Voice does not change the agent's
169
262
  reasoning model.
170
263
 
264
+ ### Output playback observation
265
+
266
+ Supply optional `binding.onPlayback(event)` before requesting the output:
267
+
268
+ ```js
269
+ onPlayback({ conversationId, outputId, phase, reason }) {
270
+ // Store application-owned playback status for this canonical output.
271
+ }
272
+ ```
273
+
274
+ `conversationId` is the binding's logical `conversationId`, falling back to its
275
+ scoped `id` for existing bindings. `outputId` is the canonical assistant output
276
+ identity, never the internal synthesis chunk UUID. `phase` is `started`,
277
+ `completed`, `interrupted` or `failed`; `reason` is optional and generic, such as
278
+ `muted`, `cancelled`, `disconnected`, `playback-error` or `no-audio`.
279
+
280
+ Start is observed from the running audio clock reaching scheduled PCM, or a
281
+ natural end of a very short sound. Text arrival, synthesis requests and future
282
+ scheduled audio do not claim playback. Completion requires the canonical output
283
+ to be final and its server stream, queued frames and scheduled audio to drain
284
+ successfully. The existing bounded speech projection still limits each output
285
+ to 4,000 source characters; reaching that limit is not canonical finalization.
286
+ A queued output cancelled before audio begins emits interrupted without started.
287
+ A final projection with no speakable text, or declined playback, retires as
288
+ interrupted with `no-audio`; it does not claim a start or completion.
289
+ A disappearing unfinished output is interrupted. Each output starts at most once
290
+ and has one terminal outcome; delayed audio from an old epoch cannot change it.
291
+ Silent text mode emits no invented audio receipts.
292
+
293
+ Observers cannot control scheduling or cleanup. Synchronous exceptions and
294
+ rejected observer promises are isolated. Keep application actions, teaching cues
295
+ and any interpretation of these generic receipts in the consuming application.
296
+
171
297
  `ConversationDialog` is the shared Vue frame for voice and application Text views.
172
298
  It fixes header/tab geometry, uses full screen below 600 pixels, and switches
173
299
  without content or backdrop transitions. It accepts `title`, `mode`, `showModes`, `minimizable` and
@@ -296,3 +422,21 @@ through an application-authorized route; credentials stay on the server. The
296
422
  result contains `voices` (IDs, labels and optional languages) and `defaultVoice`,
297
423
  matching the WebSocket greeting. Listing voices does not synthesize or load
298
424
  additional voice models.
425
+
426
+ `VoiceConversationSettings` from `/client` extracts that same menu for hosts
427
+ which supply their own conversation body. Pass the existing `voice` object and
428
+ use its default slot for application-owned avatar and voice preferences. The
429
+ slot receives `{ voice }`; saved identity, scope, permissions and defaults remain
430
+ the application's responsibility. With no slot, opening connects the existing
431
+ voice object and lists installed voices, without recording. `compact` gives the
432
+ cog the same small visual circle and 48-pixel target as the avatar voice tools.
433
+ Use `VoiceConversationControls`'s `settings-control` slot to put it after the
434
+ microphone and speaker controls. A custom conversation body owns placement of
435
+ its extracted settings menu.
436
+
437
+ When Pause occurs while an earlier message is awaiting admission, the original
438
+ recording retains its words, ID and captured destination. Pause immediately mutes
439
+ input; once that earlier admission settles, the existing capture owner finalizes
440
+ and sends the retained utterance exactly once. Resuming before admission settles
441
+ keeps that recording open. Cancellation retires the requested finish; genuinely
442
+ unknown delivery remains unresolved until the person uses existing recovery.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/agent-docs",
3
- "version": "0.1.197",
3
+ "version": "0.1.199",
4
4
  "description": "Distributed JSKIT agent references, prompts, guides, and generated reference maps.",
5
5
  "type": "module",
6
6
  "files": [
@@ -11,7 +11,7 @@
11
11
  "templates"
12
12
  ],
13
13
  "scripts": {
14
- "test": "node --test test/*.test.js"
14
+ "test": "node --test --test-concurrency=1 test/*.test.js"
15
15
  },
16
16
  "engines": {
17
17
  "node": "^22.13.0 || ^24.0.0 || ^26.0.0"
@@ -5,7 +5,7 @@
5
5
  "private": true,
6
6
  "type": "module",
7
7
  "dependencies": {
8
- "@jskit-ai/kernel": "0.1.225",
8
+ "@jskit-ai/kernel": "0.1.227",
9
9
  "json-rest-schema": "^1.0.17"
10
10
  },
11
11
  "exports": {
@@ -24,7 +24,7 @@
24
24
  "build:home": "VITE_SURFACE=home vite build",
25
25
  "preview": "vite preview",
26
26
  "lint": "eslint .",
27
- "test": "node --test",
27
+ "test": "node --test --test-concurrency=1",
28
28
  "test:client": "vitest run tests/client",
29
29
  "test:e2e": "playwright test tests/e2e",
30
30
  "jskit:update": "npx --yes @jskit-ai/jskit-catalog@latest update",
@@ -34,7 +34,7 @@
34
34
  "dependencies": {
35
35
  "@local/main": "0.1.0",
36
36
  "@fastify/static": "^10.1.3",
37
- "@jskit-ai/kernel": "0.1.225",
37
+ "@jskit-ai/kernel": "0.1.227",
38
38
  "@tanstack/vue-query": "^5.101.0",
39
39
  "fastify": "^5.8.5",
40
40
  "json-rest-schema": "^1.0.17",
@@ -42,13 +42,13 @@
42
42
  "vue": "^3.5.43",
43
43
  "vue-router": "^5.3.1",
44
44
  "vuetify": "^4.1.2",
45
- "@jskit-ai/http-runtime": "0.1.223",
45
+ "@jskit-ai/http-runtime": "0.1.225",
46
46
  "@fastify/fast-json-stringify-compiler": "^5.1.0",
47
47
  "@vue/devtools-api": "^8.2.1"
48
48
  },
49
49
  "devDependencies": {
50
- "@jskit-ai/config-eslint": "0.1.222",
51
- "@jskit-ai/jskit-catalog": "0.1.250",
50
+ "@jskit-ai/config-eslint": "0.1.224",
51
+ "@jskit-ai/jskit-catalog": "0.1.252",
52
52
  "@playwright/test": "1.61.1",
53
53
  "@vitejs/plugin-vue": "^6.0.7",
54
54
  "eslint": "^10.8.0",
@@ -24,7 +24,7 @@
24
24
  "build:home": "VITE_SURFACE=home vite build",
25
25
  "preview": "vite preview",
26
26
  "lint": "eslint .",
27
- "test": "node --test",
27
+ "test": "node --test --test-concurrency=1",
28
28
  "test:client": "vitest run tests/client",
29
29
  "test:e2e": "playwright test tests/e2e",
30
30
  "jskit:update": "npx --yes @jskit-ai/jskit-catalog@latest update",
@@ -34,7 +34,7 @@
34
34
  "dependencies": {
35
35
  "@local/main": "0.1.0",
36
36
  "@fastify/static": "^10.1.3",
37
- "@jskit-ai/kernel": "0.1.225",
37
+ "@jskit-ai/kernel": "0.1.227",
38
38
  "@tanstack/vue-query": "^5.101.0",
39
39
  "fastify": "^5.8.5",
40
40
  "json-rest-schema": "^1.0.17",
@@ -42,15 +42,15 @@
42
42
  "vue": "^3.5.43",
43
43
  "vue-router": "^5.3.1",
44
44
  "vuetify": "^4.1.2",
45
- "@jskit-ai/http-runtime": "0.1.223",
45
+ "@jskit-ai/http-runtime": "0.1.225",
46
46
  "@mdi/js": "^7.4.47",
47
- "@jskit-ai/shell-web": "0.1.229",
47
+ "@jskit-ai/shell-web": "0.1.231",
48
48
  "@fastify/fast-json-stringify-compiler": "^5.1.0",
49
49
  "@vue/devtools-api": "^8.2.1"
50
50
  },
51
51
  "devDependencies": {
52
- "@jskit-ai/config-eslint": "0.1.222",
53
- "@jskit-ai/jskit-catalog": "0.1.250",
52
+ "@jskit-ai/config-eslint": "0.1.224",
53
+ "@jskit-ai/jskit-catalog": "0.1.252",
54
54
  "@playwright/test": "1.61.1",
55
55
  "@vitejs/plugin-vue": "^6.0.7",
56
56
  "eslint": "^10.8.0",
@@ -9,7 +9,7 @@
9
9
  },
10
10
  "description": "App-local runtime composition and lightweight glue.",
11
11
  "dependencies": {
12
- "@jskit-ai/kernel": "0.1.225"
12
+ "@jskit-ai/kernel": "0.1.227"
13
13
  },
14
14
  "jskit": {
15
15
  "kind": "runtime",