pi-voicekit 0.2.1 → 0.2.2

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.md CHANGED
@@ -399,6 +399,9 @@ Every dictation also writes one `voice-polish` entry into the session file: the
399
399
  transcript, what reached the editor and why the pass decided that. The model never sees
400
400
  these entries — they are not part of the conversation context — so they are there for
401
401
  analysis, and they do keep the raw text on disk for as long as the session file exists.
402
+ Each entry also records how the pass was configured: the transcript length on its own
403
+ (separate from any text already in the editor), whether thinking was turned off for it,
404
+ and the output-token cap it carried.
402
405
 
403
406
  | Setting | Scope | Default | Notes |
404
407
  | ------------------------- | ------------------ | ----------- | ------------------------------------------------------- |
@@ -69,7 +69,10 @@ If nothing in <TRANSCRIPT> can be cleaned, return it unchanged.
69
69
  */
70
70
  export function polishMaxTokens(rawChars: number): number {
71
71
  const bounded = Number.isFinite(rawChars) ? Math.max(1, Math.floor(rawChars)) : 1;
72
- return Math.min(4096, Math.max(1024, Math.ceil(bounded * 2) + 512));
72
+ // The floor is 2048 because thinking is not bounded by the input length: a 76-character
73
+ // dictation spent about 1,200 reasoning tokens, so the earlier 1024 floor truncated it and
74
+ // dropped the pass back to the raw transcript after a 7.6 s wait.
75
+ return Math.min(4096, Math.max(2048, Math.ceil(bounded * 2) + 512));
73
76
  }
74
77
 
75
78
  function renderContext(context: AssembledContext): string {
@@ -240,6 +240,14 @@ export interface PolishAudit {
240
240
  latencyMs?: number;
241
241
  contextChars?: number;
242
242
  truncated?: boolean;
243
+ /** Characters of the dictation itself, excluding text already in the editor. */
244
+ transcriptChars?: number;
245
+ /** Characters of the editor prefix, which is not part of the transcript. */
246
+ editorPrefixChars?: number;
247
+ /** True when the pass asked the model not to think. */
248
+ thinkingOff?: boolean;
249
+ /** The output-token cap the request carried, a cap and not a spend. */
250
+ maxTokens?: number;
243
251
  }
244
252
 
245
253
  export function buildPolishAudit(input: {
@@ -248,6 +256,10 @@ export function buildPolishAudit(input: {
248
256
  status?: string;
249
257
  disposition?: string;
250
258
  reason?: string;
259
+ transcriptChars?: number;
260
+ editorPrefixChars?: number;
261
+ thinkingOff?: boolean;
262
+ maxTokens?: number;
251
263
  telemetry?: {
252
264
  model?: string;
253
265
  configured?: string;
@@ -266,6 +278,10 @@ export function buildPolishAudit(input: {
266
278
  if (input.status !== undefined) audit.status = input.status;
267
279
  if (input.disposition !== undefined) audit.disposition = input.disposition;
268
280
  if (input.reason !== undefined) audit.reason = input.reason;
281
+ if (input.transcriptChars !== undefined) audit.transcriptChars = input.transcriptChars;
282
+ if (input.editorPrefixChars !== undefined) audit.editorPrefixChars = input.editorPrefixChars;
283
+ if (input.thinkingOff !== undefined) audit.thinkingOff = input.thinkingOff;
284
+ if (input.maxTokens !== undefined) audit.maxTokens = input.maxTokens;
269
285
  const telemetry = input.telemetry;
270
286
  if (telemetry) {
271
287
  if (telemetry.model !== undefined) audit.model = telemetry.model;
@@ -114,6 +114,7 @@ import {
114
114
  resolveModelChoice,
115
115
  } from "./voice/post-process";
116
116
  import { DEFAULT_CONTEXT_LIMITS } from "./voice/post-process-context";
117
+ import { polishMaxTokens } from "./voice/post-process-prompt";
117
118
 
118
119
  /** Adapter for the real event loop — lets GapTimer run under the real setTimeout. */
119
120
  const realTimerPort: TimerPort = {
@@ -883,6 +884,9 @@ export default function (pi: ExtensionAPI) {
883
884
  ms: number;
884
885
  contextChars?: number;
885
886
  truncated?: boolean;
887
+ /** Recorded so a slow or truncated pass can be diagnosed without reading code. */
888
+ thinkingOff?: boolean;
889
+ maxTokens?: number;
886
890
  reason?: string;
887
891
  error?: string;
888
892
  };
@@ -987,6 +991,10 @@ export default function (pi: ExtensionAPI) {
987
991
  const telemetry = {
988
992
  model: polishModelLabel(choice),
989
993
  configured: choice.ref,
994
+ // Pure and cheap, so computing it twice (here and in the call options) is fine, and it
995
+ // keeps the audit entry honest about what the pass decided.
996
+ thinkingOff: Boolean(polishSamplingOptions(model as { reasoning?: boolean }, raw.length).samplingParams),
997
+ maxTokens: polishMaxTokens(raw.length),
990
998
  status: result.status,
991
999
  ms: Date.now() - started,
992
1000
  contextChars: result.contextChars,
@@ -1818,6 +1826,10 @@ export default function (pi: ExtensionAPI) {
1818
1826
  "voice-polish",
1819
1827
  buildPolishAudit({
1820
1828
  raw: prefix + fullText,
1829
+ transcriptChars: fullText.length,
1830
+ editorPrefixChars: prefix.length,
1831
+ thinkingOff: polishTelemetry?.thinkingOff,
1832
+ maxTokens: polishTelemetry?.maxTokens,
1821
1833
  written: wroteEditor ? finalText : undefined,
1822
1834
  status: final.status,
1823
1835
  disposition: final.disposition,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-voicekit",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Voice in + voice out for Pi CLI — hold-to-talk STT (Deepgram streaming or 21 offline models) plus TTS (Kitten Nano, Piper, Kokoro, or Deepgram Aura)",
5
5
  "type": "module",
6
6
  "keywords": [