@markusylisiurunen/tau 0.3.72 → 0.3.74

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 (174) hide show
  1. package/dist/core/agent/agent_runtime.js +121 -65
  2. package/dist/core/agent/agent_runtime.js.map +1 -1
  3. package/dist/core/cli.js +1 -0
  4. package/dist/core/cli.js.map +1 -1
  5. package/dist/core/config/builtin_themes.js +31 -0
  6. package/dist/core/config/builtin_themes.js.map +1 -1
  7. package/dist/core/config/schema.js +8 -0
  8. package/dist/core/config/schema.js.map +1 -1
  9. package/dist/core/history/remote_history_client.js +1 -0
  10. package/dist/core/history/remote_history_client.js.map +1 -1
  11. package/dist/core/history/transcript.js +9 -0
  12. package/dist/core/history/transcript.js.map +1 -1
  13. package/dist/core/personas.js +4 -3
  14. package/dist/core/personas.js.map +1 -1
  15. package/dist/core/runtime/chat_runtime.js +3 -0
  16. package/dist/core/runtime/chat_runtime.js.map +1 -1
  17. package/dist/core/runtime/model_sampler.js +4 -1
  18. package/dist/core/runtime/model_sampler.js.map +1 -1
  19. package/dist/core/session/auto_compaction_archive.js +18 -2
  20. package/dist/core/session/auto_compaction_archive.js.map +1 -1
  21. package/dist/core/session/compaction.js +12 -8
  22. package/dist/core/session/compaction.js.map +1 -1
  23. package/dist/core/static/code_mode/history/documentation.md +1 -1
  24. package/dist/core/static/tau_docs/client-tools.md +1 -1
  25. package/dist/core/static/tau_docs/credentials.md +8 -5
  26. package/dist/core/static/tau_docs/history.md +1 -0
  27. package/dist/core/static/tau_docs/image-generation.md +132 -0
  28. package/dist/core/static/tau_docs/index.md +6 -0
  29. package/dist/core/static/tau_docs/manifest.json +3 -0
  30. package/dist/core/static/tau_docs/pdf-unpacking.md +38 -0
  31. package/dist/core/static/tau_docs/personas.md +1 -1
  32. package/dist/core/static/tau_docs/security.md +2 -2
  33. package/dist/core/static/tau_docs/session-protocol-methods.md +3 -3
  34. package/dist/core/static/tau_docs/session-protocol.md +13 -9
  35. package/dist/core/static/tau_docs/sessions.md +9 -1
  36. package/dist/core/static/tau_docs/speech-generation.md +181 -0
  37. package/dist/core/static/tau_docs/telegram.md +6 -12
  38. package/dist/core/static/tau_docs/tools.md +24 -23
  39. package/dist/core/static/tau_docs/tui.md +4 -2
  40. package/dist/core/telegram/adapter.js +138 -302
  41. package/dist/core/telegram/adapter.js.map +1 -1
  42. package/dist/core/telegram/attachments.js +78 -0
  43. package/dist/core/telegram/attachments.js.map +1 -0
  44. package/dist/core/telegram/runtime.js +2 -2
  45. package/dist/core/telegram/runtime.js.map +1 -1
  46. package/dist/core/telegram/{send_image.js → send_file.js} +52 -31
  47. package/dist/core/telegram/send_file.js.map +1 -0
  48. package/dist/core/telegram/session_manager.js +12 -0
  49. package/dist/core/telegram/session_manager.js.map +1 -1
  50. package/dist/core/tool/cli.js +22 -2
  51. package/dist/core/tool/cli.js.map +1 -1
  52. package/dist/core/tool/image_generate.js +320 -0
  53. package/dist/core/tool/image_generate.js.map +1 -0
  54. package/dist/core/tool/media.js +71 -0
  55. package/dist/core/tool/media.js.map +1 -0
  56. package/dist/core/tool/pdf_unpack.js +3 -1
  57. package/dist/core/tool/pdf_unpack.js.map +1 -1
  58. package/dist/core/tool/speech_generate.js +269 -0
  59. package/dist/core/tool/speech_generate.js.map +1 -0
  60. package/dist/core/tools/bash_jobs.js +2 -1
  61. package/dist/core/tools/bash_jobs.js.map +1 -1
  62. package/dist/core/tools/tau_docs.js +25 -8
  63. package/dist/core/tools/tau_docs.js.map +1 -1
  64. package/dist/core/utils/compact.js +8 -0
  65. package/dist/core/utils/compact.js.map +1 -1
  66. package/dist/core/utils/gemini_transcription.js +30 -12
  67. package/dist/core/utils/gemini_transcription.js.map +1 -1
  68. package/dist/core/utils/speech_to_text.js +4 -0
  69. package/dist/core/utils/speech_to_text.js.map +1 -1
  70. package/dist/core/version.js +2 -2
  71. package/dist/diff_tool/app/dist/assets/{angular-html-D8XZ6L1W.js → angular-html-BjHlbeCk.js} +1 -1
  72. package/dist/diff_tool/app/dist/assets/{angular-ts-B2aLLY_Z.js → angular-ts-5J5hsUV-.js} +1 -1
  73. package/dist/diff_tool/app/dist/assets/{apl-CfprQVX4.js → apl-ChIs51_N.js} +1 -1
  74. package/dist/diff_tool/app/dist/assets/{astro-D2f_I3HE.js → astro-RtGdbaIT.js} +1 -1
  75. package/dist/diff_tool/app/dist/assets/{blade-CLtAGpBc.js → blade-Cuc0ZzS1.js} +1 -1
  76. package/dist/diff_tool/app/dist/assets/{c-Qn9tF0wR.js → c-IpjS3QEt.js} +1 -1
  77. package/dist/diff_tool/app/dist/assets/{chapel-DabpXN2c.js → chapel-BvHOmF40.js} +1 -1
  78. package/dist/diff_tool/app/dist/assets/{cobol-BS9rswW2.js → cobol-BWLkapNx.js} +1 -1
  79. package/dist/diff_tool/app/dist/assets/{coffee-DJjZTCkh.js → coffee-lfdf_MuK.js} +1 -1
  80. package/dist/diff_tool/app/dist/assets/{cpp-6G1npUMW.js → cpp-GvMfdutG.js} +1 -1
  81. package/dist/diff_tool/app/dist/assets/{crystal-yGprvv5C.js → crystal--kdmUeXB.js} +1 -1
  82. package/dist/diff_tool/app/dist/assets/{css-BnlmtDZM.js → css-CnlOazId.js} +1 -1
  83. package/dist/diff_tool/app/dist/assets/{edge-DSSWy6df.js → edge-CwnxQiFe.js} +1 -1
  84. package/dist/diff_tool/app/dist/assets/{elixir-Drn1Bw4g.js → elixir-BVO19qQd.js} +1 -1
  85. package/dist/diff_tool/app/dist/assets/{elm-BtjpPFL1.js → elm-BK3istEo.js} +1 -1
  86. package/dist/diff_tool/app/dist/assets/{erb-I91oznQj.js → erb-CO4uKwKD.js} +1 -1
  87. package/dist/diff_tool/app/dist/assets/{git-rebase-B6EXosZ2.js → git-rebase-CDrrgbGV.js} +1 -1
  88. package/dist/diff_tool/app/dist/assets/{glimmer-js-Brv1Xv0-.js → glimmer-js-7CFSyo6c.js} +1 -1
  89. package/dist/diff_tool/app/dist/assets/{glimmer-ts-hSHEQSwK.js → glimmer-ts-Ofllf2Yo.js} +1 -1
  90. package/dist/diff_tool/app/dist/assets/{glsl-Bztv6m8n.js → glsl-K_36bq1K.js} +1 -1
  91. package/dist/diff_tool/app/dist/assets/{graphql-D6eZu1mk.js → graphql-BMZnssUN.js} +1 -1
  92. package/dist/diff_tool/app/dist/assets/{hack-MG8_CyJU.js → hack-MG_t8QNs.js} +1 -1
  93. package/dist/diff_tool/app/dist/assets/{haml-DOpHECVn.js → haml-0hDK-uCt.js} +1 -1
  94. package/dist/diff_tool/app/dist/assets/{handlebars-CXn0JyYm.js → handlebars-D4_MRJPB.js} +1 -1
  95. package/dist/diff_tool/app/dist/assets/{html-yv5WBZF_.js → html-BCi--7qp.js} +1 -1
  96. package/dist/diff_tool/app/dist/assets/{html-derivative-D_UZAUld.js → html-derivative-DYq2AWiD.js} +1 -1
  97. package/dist/diff_tool/app/dist/assets/{http-Cuq8OMRz.js → http-BmLFm2Pm.js} +1 -1
  98. package/dist/diff_tool/app/dist/assets/{hurl-BpL1rvQi.js → hurl-CT71cK69.js} +1 -1
  99. package/dist/diff_tool/app/dist/assets/index-DyaXBald.js +340 -0
  100. package/dist/diff_tool/app/dist/assets/{java-lOL4pIA5.js → java-Bm2FCq-d.js} +1 -1
  101. package/dist/diff_tool/app/dist/assets/{javascript-24hXqooT.js → javascript-C7oEny21.js} +1 -1
  102. package/dist/diff_tool/app/dist/assets/{jinja-CcJm4wgQ.js → jinja-igQBS-SS.js} +1 -1
  103. package/dist/diff_tool/app/dist/assets/{jison-CLWGaM3Z.js → jison-BrOUp4rK.js} +1 -1
  104. package/dist/diff_tool/app/dist/assets/{json-Q4rTF_eD.js → json-DsuR7Nai.js} +1 -1
  105. package/dist/diff_tool/app/dist/assets/{jsx-DgKO46Ra.js → jsx-BdomFXcA.js} +1 -1
  106. package/dist/diff_tool/app/dist/assets/{julia-CcL4q47t.js → julia-DqOG4pbM.js} +1 -1
  107. package/dist/diff_tool/app/dist/assets/{just-CSIuzTSo.js → just-ZrSTuT0n.js} +1 -1
  108. package/dist/diff_tool/app/dist/assets/{latex-Ciy3mJH4.js → latex-DbmtZIwN.js} +1 -1
  109. package/dist/diff_tool/app/dist/assets/{liquid-OONbg0h-.js → liquid-DKnUlRIp.js} +1 -1
  110. package/dist/diff_tool/app/dist/assets/{lua-Btm14Bzf.js → lua-Cyq3f59a.js} +1 -1
  111. package/dist/diff_tool/app/dist/assets/{marko-BmewWoW6.js → marko-hmOsFPHQ.js} +1 -1
  112. package/dist/diff_tool/app/dist/assets/{mdc-sWVstZzQ.js → mdc-BnnQmDC-.js} +1 -1
  113. package/dist/diff_tool/app/dist/assets/{nginx-Dcc3mAzJ.js → nginx-C0zLUSna.js} +1 -1
  114. package/dist/diff_tool/app/dist/assets/{nim-vtS9CCAW.js → nim-Oljl3c5n.js} +1 -1
  115. package/dist/diff_tool/app/dist/assets/{org-B7feKU2q.js → org-Cp4CA-0c.js} +1 -1
  116. package/dist/diff_tool/app/dist/assets/{perl-7rFQ23Cs.js → perl-DstDVYmJ.js} +1 -1
  117. package/dist/diff_tool/app/dist/assets/{php-AmgTWRKZ.js → php-Cc3bNZ7J.js} +1 -1
  118. package/dist/diff_tool/app/dist/assets/{pug-eaJXnOWe.js → pug-B3xDUzl0.js} +1 -1
  119. package/dist/diff_tool/app/dist/assets/{qml-BBoySWOD.js → qml-B9iDahKk.js} +1 -1
  120. package/dist/diff_tool/app/dist/assets/{r-B2GBKjgG.js → r-B7M5ZSBC.js} +1 -1
  121. package/dist/diff_tool/app/dist/assets/{razor-D8emi4Jp.js → razor-BlfV6bjQ.js} +1 -1
  122. package/dist/diff_tool/app/dist/assets/{regexp-CKBgZg4Y.js → regexp-BVT0NBj6.js} +1 -1
  123. package/dist/diff_tool/app/dist/assets/{rst-CVpwV-bV.js → rst-Cq-Mcher.js} +1 -1
  124. package/dist/diff_tool/app/dist/assets/{ruby-DmnwJ-ac.js → ruby-5uCK_s01.js} +1 -1
  125. package/dist/diff_tool/app/dist/assets/{sas-evRrvJrO.js → sas-m4dYluKN.js} +1 -1
  126. package/dist/diff_tool/app/dist/assets/{scss-Do3O6tsR.js → scss-DFiJcBQH.js} +1 -1
  127. package/dist/diff_tool/app/dist/assets/{shellscript-D7jRMvC2.js → shellscript-DCtSkJJQ.js} +1 -1
  128. package/dist/diff_tool/app/dist/assets/{shellsession-BiBPKva9.js → shellsession-_DntbpLM.js} +1 -1
  129. package/dist/diff_tool/app/dist/assets/{soy-CR-Q7WHe.js → soy-Dd1fWsG8.js} +1 -1
  130. package/dist/diff_tool/app/dist/assets/{sql-CoBwCDCB.js → sql-Bygp5F-5.js} +1 -1
  131. package/dist/diff_tool/app/dist/assets/{stata-D6KdJ8PZ.js → stata-CqIA1VQD.js} +1 -1
  132. package/dist/diff_tool/app/dist/assets/{surrealql-Cmqi02II.js → surrealql-C2-2C-z3.js} +1 -1
  133. package/dist/diff_tool/app/dist/assets/{svelte-DdZNRb2C.js → svelte-CrTy7VSb.js} +1 -1
  134. package/dist/diff_tool/app/dist/assets/{templ-CFz1LMKK.js → templ-B_h9AHFJ.js} +1 -1
  135. package/dist/diff_tool/app/dist/assets/{tex-m3WJ8u0a.js → tex-AwlGuBDG.js} +1 -1
  136. package/dist/diff_tool/app/dist/assets/{ts-tags-fLY9Y9r5.js → ts-tags--oqU6stH.js} +1 -1
  137. package/dist/diff_tool/app/dist/assets/{tsx-B6WfBUEX.js → tsx-Cx-oUPFA.js} +1 -1
  138. package/dist/diff_tool/app/dist/assets/{twig-D9vOrthV.js → twig-DMQw3R9O.js} +1 -1
  139. package/dist/diff_tool/app/dist/assets/{typescript-BZTxacEG.js → typescript-BCtu9W7E.js} +1 -1
  140. package/dist/diff_tool/app/dist/assets/{typst-JP3so6Z2.js → typst-jGrqJHSo.js} +1 -1
  141. package/dist/diff_tool/app/dist/assets/{vue-gWDhG9Fb.js → vue-GFZcsvXd.js} +1 -1
  142. package/dist/diff_tool/app/dist/assets/{vue-html-CaRyGpdm.js → vue-html-DTMalvg7.js} +1 -1
  143. package/dist/diff_tool/app/dist/assets/{vue-vine-DJXQ6msH.js → vue-vine-BwDeqLrM.js} +1 -1
  144. package/dist/diff_tool/app/dist/assets/{xml-Cvn8jjwq.js → xml-CoXyuOzf.js} +1 -1
  145. package/dist/diff_tool/app/dist/assets/{xsl-BpNEamvK.js → xsl-BQFm34CN.js} +1 -1
  146. package/dist/diff_tool/app/dist/assets/{yaml-BQh9PoCE.js → yaml-CbO2A_pF.js} +1 -1
  147. package/dist/diff_tool/app/dist/index.html +1 -1
  148. package/dist/history/worker/index.js +5 -5
  149. package/dist/history/worker/index.js.map +1 -1
  150. package/dist/history/worker/viewer.js +8 -8
  151. package/dist/host/local_session_host.js +31 -7
  152. package/dist/host/local_session_host.js.map +1 -1
  153. package/dist/protocol/session_protocol.d.ts +9 -4
  154. package/dist/protocol/session_protocol.js +19 -5
  155. package/dist/protocol/session_protocol.js.map +1 -1
  156. package/dist/protocol/system_message.d.ts +15 -0
  157. package/dist/protocol/system_message.js +30 -0
  158. package/dist/protocol/system_message.js.map +1 -0
  159. package/dist/tui/chat_view.js +3 -0
  160. package/dist/tui/chat_view.js.map +1 -1
  161. package/dist/tui/listen_capture.js +1 -0
  162. package/dist/tui/listen_capture.js.map +1 -1
  163. package/dist/tui/session_chat_controller.js +140 -63
  164. package/dist/tui/session_chat_controller.js.map +1 -1
  165. package/dist/tui/ui/components/editor.js +42 -0
  166. package/dist/tui/ui/components/editor.js.map +1 -1
  167. package/dist/tui/ui/custom_editor.js +50 -14
  168. package/dist/tui/ui/custom_editor.js.map +1 -1
  169. package/dist/tui/ui/theme/palette.js +2 -0
  170. package/dist/tui/ui/theme/palette.js.map +1 -1
  171. package/dist/tui/ui/theme/theme.js.map +1 -1
  172. package/package.json +18 -18
  173. package/dist/core/telegram/send_image.js.map +0 -1
  174. package/dist/diff_tool/app/dist/assets/index-B4p26B5b.js +0 -1559
@@ -1,6 +1,6 @@
1
1
  # Session protocol method reference
2
2
 
3
- This page defines every request method in protocol version 13. It is the compact wire reference for clients that already understand connection, observation, and delta application from the [session protocol](session-protocol.md).
3
+ This page defines every request method in protocol version 14. It is the compact wire reference for clients that already understand connection, observation, and delta application from the [session protocol](session-protocol.md).
4
4
 
5
5
  Every request uses `{ version, type: "request", id, method, params }`. Every successful response uses `{ version, type: "response", id, ok: true, result }`. `params` is required even when empty, and unknown object fields are stripped.
6
6
 
@@ -47,7 +47,7 @@ params: {
47
47
  }
48
48
 
49
49
  result: {
50
- protocolVersion: 13;
50
+ protocolVersion: 14;
51
51
  methods: string[];
52
52
  alreadyInitialized: boolean;
53
53
  }
@@ -306,7 +306,7 @@ params: {
306
306
  result: { message: AssistantMessage }
307
307
  ```
308
308
 
309
- `context.messages` and the returned message use Tau's provider-neutral model message shape. Returned tool calls are data only. Samples can run concurrently and are cancelled by `session.interrupt`, transport shutdown, or host shutdown.
309
+ `context.messages` and the returned message use Tau's provider-neutral model message shape. Intermediate system messages use the plain-text, versioned metadata shape described in the [session protocol](session-protocol.md); metadata is not sent to the provider. Unsupported sections and tool mutations are rejected. Returned tool calls are data only. Samples can run concurrently and are cancelled by `session.interrupt`, transport shutdown, or host shutdown.
310
310
 
311
311
  ## Read and change session state
312
312
 
@@ -18,7 +18,7 @@ The server sends `ready` as its first message:
18
18
 
19
19
  ```json
20
20
  {
21
- "version": 13,
21
+ "version": 14,
22
22
  "type": "ready",
23
23
  "methods": ["initialize", "session.create", "session.list"]
24
24
  }
@@ -30,7 +30,7 @@ After `ready`, send `initialize` with non-empty client metadata:
30
30
 
31
31
  ```json
32
32
  {
33
- "version": 13,
33
+ "version": 14,
34
34
  "type": "request",
35
35
  "id": "init-1",
36
36
  "method": "initialize",
@@ -50,7 +50,7 @@ Every request has the same envelope:
50
50
 
51
51
  ```json
52
52
  {
53
- "version": 13,
53
+ "version": 14,
54
54
  "type": "request",
55
55
  "id": "req-42",
56
56
  "method": "session.snapshot",
@@ -58,13 +58,13 @@ Every request has the same envelope:
58
58
  }
59
59
  ```
60
60
 
61
- `id` is a non-empty client-chosen string and must identify the outstanding request on that connection. `params` is always required, including `{}` for `session.list`. The host validates required fields, field types, discriminators, method names, and the exact protocol version. Unknown object fields are accepted and stripped.
61
+ `id` is a non-empty client-chosen string and must identify the outstanding request on that connection. `params` is always required, including `{}` for `session.list`. The host validates required fields, field types, discriminators, method names, and the exact protocol version. Unknown object fields are accepted and stripped, except system messages and their metadata, which reject unsupported fields.
62
62
 
63
63
  Successful responses echo the request id:
64
64
 
65
65
  ```json
66
66
  {
67
- "version": 13,
67
+ "version": 14,
68
68
  "type": "response",
69
69
  "id": "req-42",
70
70
  "ok": true,
@@ -114,6 +114,10 @@ The timeline has an `epoch`, a per-epoch sequence high-water mark, and ordered i
114
114
 
115
115
  User message text is raw recoverable session text. User-facing renderers should remove Tau metadata and leading exact `<system>...</system>\n` blocks. The Node SDK exports projection helpers for this purpose. Do not apply user-text projection to assistant, tool-result, or protocol system messages.
116
116
 
117
+ The initial system message is the separate persona/base prompt. Intermediate system messages are ordered history records with plain-text `content`, a `timestamp`, and required structured `metadata`: `{ type: "instruction" | "auto-compaction-continuation", version: 1 }`. They remain model-visible and recoverable. The normal TUI hides them, while searchable conversation history includes them as system entries. Tau metadata is removed before provider dispatch. Text-block arrays, named sections, and tool additions or removals are not supported in system messages.
118
+
119
+ Intermediate instructions are committed without a user turn receipt. Their durable append uses the `system-message` delta cause and does not require a timeline item. The initial prompt has no intermediate-message metadata; recovery restores subsequent instructions without duplicating that base prompt. There is no public insertion method or automatic conversion of user-authored `<system>` text.
120
+
117
121
  Turn requests return a terminal outcome, and accepted user turns are also keyed by `userHistoryEntryId` in `snapshot.turns`. Use that ledger to distinguish an unknown request from accepted running work and settled work. Do not infer request outcomes from notice titles, message counts, or timing.
118
122
 
119
123
  User-facing behavior such as goals, retry, compaction, rewind, and recovery is described in [sessions](sessions.md).
@@ -124,7 +128,7 @@ Observed snapshot changes arrive as `session.delta`:
124
128
 
125
129
  ```json
126
130
  {
127
- "version": 13,
131
+ "version": 14,
128
132
  "type": "session.delta",
129
133
  "sessionId": "0195d6e4-4cf9-7f44-a2d8-f8f7f49ee9d3",
130
134
  "fromRevision": 8,
@@ -162,7 +166,7 @@ Not all observed state belongs in the recoverable snapshot. Each live channel ha
162
166
 
163
167
  ```json
164
168
  {
165
- "version": 13,
169
+ "version": 14,
166
170
  "type": "session.pendingUserMessages",
167
171
  "sessionId": "...",
168
172
  "state": {
@@ -199,7 +203,7 @@ An initialized client that advertised a tool can receive:
199
203
 
200
204
  ```json
201
205
  {
202
- "version": 13,
206
+ "version": 14,
203
207
  "type": "session.clientTool.call",
204
208
  "sessionId": "...",
205
209
  "agentId": "main",
@@ -223,7 +227,7 @@ Error responses use `ok: false`:
223
227
 
224
228
  ```json
225
229
  {
226
- "version": 13,
230
+ "version": 14,
227
231
  "type": "response",
228
232
  "id": "req-42",
229
233
  "ok": false,
@@ -131,6 +131,14 @@ Configure the policy in [configuration](configuration.md):
131
131
  }
132
132
  ```
133
133
 
134
+ ### Intermediate system instructions
135
+
136
+ Tau supports plain-text system instructions in conversation history separately from the persona/base prompt. These records are hidden in the TUI, persisted for recovery, recorded as system entries in searchable transcript history, and sent to the model in conversation order. The initial persona/base prompt is not recorded in transcript history. Providers that cannot represent intermediate system messages may fold their instructions into the leading prompt through the model adapter.
137
+
138
+ Compaction treats ordinary intermediate instructions as historical context: their relevant consequences can enter the summary, while instructions in the retained recent tail remain unchanged. The persona/base prompt is supplied separately and is not replaced by the summary. Structured continuation metadata identifies obsolete compaction guidance, which is excluded from both summarization and retained context. Instructions needing exact long-lived preservation must be regenerated or retained by their owning feature rather than relying on system-role authority alone. Rewind removes intermediate instructions after the selected boundary.
139
+
140
+ Existing hidden `<system>` blocks and instruction producers are unchanged. Native system-message support does not promote user-authored tags into privileged instructions.
141
+
134
142
  ### Manual compaction
135
143
 
136
144
  Manual compaction requires idle state and summarizes the whole active model history rather than retaining an automatic recent tail.
@@ -164,7 +172,7 @@ Protocol clients can request mutations directly, but should still wait for idle
164
172
  Tau keeps two durable views for different jobs:
165
173
 
166
174
  - The session snapshot is the recoverable source of truth for continuing one conversation. It contains the current active model context and user-visible session state.
167
- - Transcript history is a flat sequence of committed user entries, assistant text, and completed tools used for cross-session search and reading. It is stored separately in the host’s history database and may also replicate to a configured history service.
175
+ - Transcript history is a flat sequence of committed user entries, intermediate system instructions, assistant text, and completed tools used for cross-session search and reading. It is stored separately in the host’s history database and may also replicate to a configured history service.
168
176
 
169
177
  Compaction changes the session snapshot’s active context but leaves transcript history intact. Rewind truncates both from the removed boundary. Transcript history cannot reconstruct all session runtime state and is not used to recover a session. See [history](history.md) for storage, replication, and the history tool.
170
178
 
@@ -0,0 +1,181 @@
1
+ # Speech generation
2
+
3
+ `tau tool speech-generate` turns a caller-chunked script into one WAV using ElevenLabs Eleven v4 Turbo (`eleven_v4_turbo`) or Eleven v4 (`eleven_v4`). It supports single-speaker narration and multi-speaker dialogue.
4
+
5
+ ```bash
6
+ tau tool speech-generate --help
7
+ ```
8
+
9
+ ## Credentials and requirements
10
+
11
+ Requires an ElevenLabs API key. See [feature-specific credentials](credentials.md#feature-specific-keys) for setup.
12
+
13
+ ```bash
14
+ tau tool speech-generate --list-voices
15
+ ```
16
+
17
+ Voice listing prints one JSON object per voice, containing `voice_id` and `name`. Use those IDs in the script.
18
+
19
+ ## Models
20
+
21
+ `--model` is required; the CLI has no implicit default. Use `eleven_v4_turbo` for lower-latency speech, as shown in the examples. Use `eleven_v4` when maximum quality matters more than latency. Both support narration and multi-speaker dialogue.
22
+
23
+ ## Input and examples
24
+
25
+ Supply a UTF-8 JSON document with exactly `voices` and `chunks`. `voices` maps speaker names to voice IDs; `chunks` is an ordered, nonempty array of nonempty arrays of speaker turns. Each turn contains exactly `speaker` and nonblank `text`.
26
+
27
+ ```json
28
+ {
29
+ "voices": {
30
+ "host": "VOICE_ID_A",
31
+ "guest": "VOICE_ID_B"
32
+ },
33
+ "chunks": [
34
+ [
35
+ {
36
+ "speaker": "host",
37
+ "text": "[calm] Welcome. What are we exploring today?"
38
+ },
39
+ {
40
+ "speaker": "guest",
41
+ "text": "How a forest changes through the seasons."
42
+ }
43
+ ],
44
+ [
45
+ { "speaker": "host", "text": "Let's begin with spring." },
46
+ {
47
+ "speaker": "guest",
48
+ "text": "The first changes happen before the leaves appear."
49
+ }
50
+ ]
51
+ ]
52
+ }
53
+ ```
54
+
55
+ Save as `dialogue.json`, replacing the placeholder voice IDs:
56
+
57
+ ```bash
58
+ tau tool speech-generate --model eleven_v4_turbo \
59
+ --input ./dialogue.json --output ./dialogue.wav
60
+
61
+ # Alternatively, use Eleven v4 for maximum quality.
62
+ tau tool speech-generate --model eleven_v4 \
63
+ --input ./dialogue.json --output ./dialogue-v4.wav
64
+ ```
65
+
66
+ Single-speaker narration uses the same shape with one voice. All chunks are validated before generation:
67
+
68
+ - Each chunk contains at most 2,000 Unicode code points across its text, including whitespace and delivery tags.
69
+ - Every speaker must resolve to a voice. At most 10 distinct voices may be used.
70
+
71
+ Tau packs consecutive whole chunks into requests of at most 2,000 characters, following the [dialogue endpoint's reliability recommendation](https://elevenlabs.io/docs/api-reference/text-to-dialogue/convert). The caller chooses chunk boundaries; text and turn order are preserved.
72
+
73
+ ## Conversational assistant replies
74
+
75
+ For conversational assistant replies with Eleven v4 Turbo or Eleven v4, use `[Brisk but relaxed, speaking naturally to a colleague]` as a starting point. Put the tag at the beginning of the turn's `text`, followed by the words to speak. Tags guide delivery; they are not intended to be spoken aloud.
76
+
77
+ Choose a delivery that fits the content:
78
+
79
+ | Use case | Suggested tag |
80
+ | --- | --- |
81
+ | Everyday assistant reply | `[Brisk but relaxed, speaking naturally to a colleague]` |
82
+ | Faster update | `[Brisk but relaxed, slightly faster, brief natural pauses]` |
83
+ | Step-by-step explanation | `[Calm and clear, measured pace, brief pauses between steps]` |
84
+ | Story narration | `[Warm, expressive storytelling, unhurried pace]` |
85
+ | Quiet aside in dialogue | `[whispering]` |
86
+
87
+ These are custom prompting suggestions, not official named presets or guaranteed speed controls. Each speaker turn can use a different tag; place a tag before a phrase when the delivery should change within a turn.
88
+
89
+ ElevenLabs documents open-ended audio tags in its [v4 prompting guide](https://elevenlabs.io/docs/overview/capabilities/text-to-speech/best-practices#prompting-eleven-v4), also available as [plain Markdown](https://elevenlabs.io/docs/overview/capabilities/text-to-speech/best-practices.md#prompting-eleven-v4). Its [documentation index](https://elevenlabs.io/docs/llms.txt) lists other guides in an agent-friendly format.
90
+
91
+ Documented tags include `[curious]`, `[excited]`, `[sarcastic]`, `[whispering]`, `[laughs]`, `[sighs]`, and `[short pause]`. For example, a turn's `text` can contain:
92
+
93
+ ```text
94
+ [curious] What happens if we try the other route?
95
+
96
+ [excited] That worked! [short pause] Here's what changed.
97
+
98
+ [Warm, conversational tone, faint amusement] You always did choose the longest way home.
99
+ ```
100
+
101
+ Tags describe audible delivery or vocal actions, not visual actions such as smiling or standing. Clear descriptions reduce ambiguity between a delivery instruction and a sound effect. Results vary by voice and language; neither Eleven v4 Turbo nor Eleven v4 treats tags as deterministic controls.
102
+
103
+ Save this as `assistant-reply.json`, replacing `VOICE_ID` with an ID from `--list-voices`:
104
+
105
+ ```json
106
+ {
107
+ "voices": { "assistant": "VOICE_ID" },
108
+ "chunks": [
109
+ [
110
+ {
111
+ "speaker": "assistant",
112
+ "text": "[Brisk but relaxed, speaking naturally to a colleague] I found the issue. The app was using an old setting, so your changes never reached the server. I've fixed that and checked the result. You don't need to reinstall anything. Try saving once more. If the warning comes back, send me the exact message and I'll trace it from there."
113
+ }
114
+ ]
115
+ ]
116
+ }
117
+ ```
118
+
119
+ ```bash
120
+ tau tool speech-generate --model eleven_v4_turbo \
121
+ --input ./assistant-reply.json --output ./assistant-reply.wav
122
+
123
+ # Alternatively, use Eleven v4 for maximum quality.
124
+ tau tool speech-generate --model eleven_v4 \
125
+ --input ./assistant-reply.json --output ./assistant-reply-v4.wav
126
+ ```
127
+
128
+ For a Finnish reply, replace the turn's `text` with:
129
+
130
+ ```text
131
+ [Brisk but relaxed, speaking naturally to a colleague] Löysin ongelman. Sovellus käytti vanhaa asetusta, joten muutoksesi eivät päätyneet palvelimelle. Korjasin asetuksen ja tarkistin, että tallennus toimii. Sinun ei tarvitse asentaa mitään uudelleen. Kokeile tallentaa vielä kerran. Jos varoitus palaa, lähetä minulle sen tarkka teksti, niin selvitän syyn.
132
+ ```
133
+
134
+ To compare pacing, replace the leading tag with `[Brisk but relaxed, slightly faster, brief natural pauses]` and generate to a fresh output path, keeping the voice and spoken text fixed.
135
+
136
+ [Eleven v4 Turbo and Eleven v4](https://elevenlabs.io/docs/overview/capabilities/text-to-speech/eleven-v4) control delivery through audio tags rather than a numeric speed setting. Results vary by voice and language.
137
+
138
+ ## Long recordings and assembly
139
+
140
+ Responses are streamed to disk as mono 24 kHz, signed 16-bit little-endian PCM. Batches are concatenated in order into one WAV. Approximately 30 minutes occupies 86.4 MB of PCM. Each batch is capped at 128 MiB and the assembled file must fit standard RIFF/WAV's roughly 4 GiB limit. Provider requests have a ten-minute deadline.
141
+
142
+ Each request receives up to three previous completed request IDs for ElevenLabs request stitching. A missing ID stops subsequent generation. Stitching uses normal ElevenLabs request logging.
143
+
144
+ ## Outputs and recovery
145
+
146
+ The output parent directory must exist. Neither the requested WAV nor `<output>.parts` may exist. The `.parts` directory contains:
147
+
148
+ - `manifest.json`: model, PCM format, output path, request plan, text and voice IDs, one-based chunk indices, completion flags, and byte counts. `requestId` and `characterCost` retain the provider's `request-id` and `character-cost` headers, including when a subsequent audio download fails.
149
+ - `batch-0001.pcm`, etc.: completed raw PCM batches in request order.
150
+ - `.partial` files: interrupted downloads.
151
+ - `assembled.wav`: the assembled output.
152
+
153
+ Stdout on success is one JSON object with absolute `output`, `artifacts`, and the number of `batches`. The manifest contains the script text; keep artifacts private for sensitive scripts.
154
+
155
+ Failures exit nonzero and report the retained directory. Requests are not automatically retried because a failed request may already have incurred a charge.
156
+
157
+ To recover after a later batch fails, inspect the manifest's `completed` flags and chunk mapping. Generate only the unfinished chunks to a fresh output path, then assemble the completed PCM files from both runs in script order. Request stitching does not carry over between invocations.
158
+
159
+ For example, with FFmpeg installed:
160
+
161
+ ```bash
162
+ cat ./first.wav.parts/batch-0001.pcm \
163
+ ./first.wav.parts/batch-0002.pcm \
164
+ ./remaining.wav.parts/batch-0001.pcm > ./complete.pcm
165
+ ffmpeg -n -f s16le -ar 24000 -ac 1 -i ./complete.pcm -c:a pcm_s16le ./complete.wav
166
+ ```
167
+
168
+ Use only completed `.pcm` batches, not `.partial` files.
169
+
170
+ ## Approximate cost
171
+
172
+ Standard rates from the [ElevenLabs API pricing page](https://elevenlabs.io/pricing/api):
173
+
174
+ | Model | Per 1,000 characters | 2,000 characters | 27,000 characters (roughly 30 minutes) |
175
+ | --- | --- | --- | --- |
176
+ | `eleven_v4_turbo` | $0.04 | $0.08 | $1.08 |
177
+ | `eleven_v4` | $0.08 | $0.16 | $2.16 |
178
+
179
+ Check current API pricing for plan and voice-specific rates. The manifest's `characterCost` preserves the provider's billing header verbatim.
180
+
181
+ See [command-line tools](tools.md) for command discovery and execution ownership.
@@ -269,32 +269,26 @@ Tau keeps tool and lifecycle chatter quiet. It sends committed assistant text, i
269
269
 
270
270
  ## Attachments and audio
271
271
 
272
- Telegram accepts photos and documents identified as images, PDF, `.txt`, `.md`, `.json`, `.csv`, `.yaml`, or `.yml`. It downloads supported attachments immediately to a runner temporary directory and gives the agent the local path, MIME type, byte size, and caption.
272
+ Telegram accepts arbitrary documents, photos, videos, animations, video notes, audio files, and voice notes. The agent receives execution-environment paths, sanitized filenames, MIME types, byte sizes, and captions. Receipt never executes files.
273
273
 
274
- Limits are:
274
+ Limits are 32 attachments per turn, 20 MiB per file, and 100 MiB per turn. Downloads are bounded even without size metadata. Oversized or failed transfers are skipped with a warning.
275
275
 
276
- - at most 32 attachments per turn
277
- - at most 20 MiB per file
278
- - at most 100 MiB total per turn
276
+ Uploads only queue files; captions are metadata. The next text or voice transcript submits or steers with one hidden `<system>` block per attachment. Only voice notes are automatically transcribed, up to 20 minutes. Audio-player files and audio documents arrive without transcription. Voice originals remain available even if transcription fails. DM and bot-triggering group transcripts are echoed before submission.
279
277
 
280
- An attachment-only DM queues files for the next text or voice/audio turn; it does not run the agent by itself. Unsupported, oversized, or failed downloads are skipped with a warning. Treat every attachment as untrusted input even though its path is local.
281
-
282
- The local execution environment can access these runner temporary paths. Pending attachments and group context are not snapshot data. Shutdown clears their queues, and startup removes stale `tau-telegram-attachments-*` directories.
283
-
284
- Telegram `voice` and `audio` messages up to 20 minutes long are downloaded and transcribed. Direct DM turns and bot-triggering group turns echo the transcript to the chat before submission so the sender can verify it.
278
+ Files use native temporary directories in the execution environment; OS cleanup can invalidate their paths. Pending queues and group context clear on shutdown. File contents and metadata are untrusted.
285
279
 
286
280
  OpenAI is the default. Select Gemini with `speechToText.provider`. Runner credentials are:
287
281
 
288
282
  - Gemini: `GEMINI_API_KEY`, then `apiKeys.google`
289
283
  - OpenAI: `OPENAI_API_KEY`, then `apiKeys.openai`
290
284
 
291
- Gemini extracts spelling hints from recent conversation with Gemini 3.8 Flash, uploads downloaded audio for `gemini-3.5-transcribe` smart transcription, and attempts to delete the remote file afterward. OpenAI normalizes downloaded audio with runner-side `ffmpeg` and uploads it to `gpt-transcribe`. Missing keys reject the audio. See [credentials](credentials.md).
285
+ Gemini extracts spelling hints with Gemini 3.8 Flash and transcribes uploaded audio verbatim with `gemini-3.5-transcribe`, using English (`en-US`) and Finnish (`fi-FI`) hints. It attempts remote file deletion afterward. OpenAI normalizes downloaded audio with runner-side `ffmpeg` and uploads it to `gpt-transcribe`. Missing keys prevent transcription, not file delivery. See [credentials](credentials.md).
292
286
 
293
287
  `/tts_on` uses `gemini-3.8-flash`, `gemini-3.1-flash-tts-preview`, Despina, the Google key, and runner `ffmpeg` with Opus. Source and rewritten text each allow 10,000 Unicode characters; audio allows 32 MiB. Rewrite and job timeouts are one and five minutes. Jobs are ephemeral. Failure sends `voice response failed. please try again.` without affecting text; details stay in logs.
294
288
 
295
289
  ## Command client tools
296
290
 
297
- Telegram provides [`send_image`](tools.md#sending-images-to-telegram) for original PNG/JPEG delivery, plus workspace-selected command tools. Global `clientTools` definitions provide executables; the workspace's nearest `enabledClientTools` selects an exact subset. An empty list disables configured tools, not `send_image`.
291
+ Telegram provides [photo, video, audio, and document delivery tools](tools.md#sending-files-to-telegram), plus workspace-selected command tools. Global `clientTools` definitions provide executables; the workspace's nearest `enabledClientTools` selects an exact subset. An empty list disables configured tools, not built-in delivery tools.
298
292
 
299
293
  These command processes run on the Telegram runner machine with the runner process environment. They can reach the session workspace only through their explicit execution-environment facade, despite physical co-location. Telegram does not advertise TUI-only `diff_review` or `prefill_input` tools.
300
294
 
@@ -69,7 +69,7 @@ The tool accepts one exact flat Markdown path. It has no search or list operatio
69
69
  index.md
70
70
  ```
71
71
 
72
- Then follow paths linked by that page. Unknown paths are rejected. The corpus describes supported Tau contracts, not the current effective configuration of a particular session, so use configuration inspection or debug output when the answer depends on local state.
72
+ Then follow paths linked by that page. The tool description also advertises built-in command-line tools with capability summaries and dedicated documentation paths. Agents may read those pages directly when a tool is relevant, without first loading the index. Use of these utilities is optional and depends on the execution environment's prerequisites. Unknown paths are rejected. The corpus describes supported Tau contracts, not the current effective configuration of a particular session, so use configuration inspection or debug output when the answer depends on local state.
73
73
 
74
74
  ## Main-session goal tools
75
75
 
@@ -133,27 +133,17 @@ Neither tool provides a general read operation. Use a scoped non-interactive Bas
133
133
 
134
134
  The supported formats are JPEG, PNG, and WebP. Source reads are capped at 50 MiB. Images larger than 2,000 pixels in either dimension or 2.5 MiB of model payload are resized or re-encoded while preserving aspect ratio. If Tau cannot reduce a valid image below the model payload limit, the call fails. Relative paths resolve from the execution-environment working directory.
135
135
 
136
- ## Unpack a PDF from the command line
136
+ ## Command-line tools
137
137
 
138
- `tau tool pdf-unpack` is a standalone utility for turning a PDF into OCR Markdown and page-image patches. It is not an agent-callable host tool. Run it from the machine that owns the input file:
138
+ `tau tool` provides standalone utilities for people and agents, usable from a shell inside or outside Tau. Files, configuration, credentials, and required executables must be available on the machine running the command. Agents can invoke these commands through Bash.
139
139
 
140
- ```bash
141
- tau tool pdf-unpack ./docs/architecture.pdf
142
- ```
143
-
144
- The path is resolved from the command's current working directory and must name a readable file. The command requires `pdftoppm` from Poppler on `PATH`. On macOS, install it with `brew install poppler`; Debian-based Linux distributions provide it through `apt install poppler-utils`.
145
-
146
- PDF OCR requires `MISTRAL_API_KEY` or `apiKeys.mistral`, with the environment variable taking precedence. Tau loads configuration for the command's current working directory. The credential and local executable therefore belong to the process running `tau tool`, not to an attached TUI, remote host, or session execution environment unless that is where the command itself runs. See [credentials](credentials.md) for credential ownership.
147
-
148
- On success, Tau prints the persistent temporary output directory and a complete artifact list. The directory contains:
149
-
150
- - `document.md`, the complete OCR document with recognized tables inlined;
151
- - `pages/page-0001.md` and later numbered files, one Markdown file per PDF page; and
152
- - `images/page-0001/patch-0001.png` and later numbered patches for visual verification.
140
+ | Command | Purpose | Guide |
141
+ | --- | --- | --- |
142
+ | `tau tool pdf-unpack` | Extract OCR Markdown and page-image patches from a PDF using Mistral. | [PDF unpacking](pdf-unpacking.md) |
143
+ | `tau tool image-generate` | Generate or edit an image using Google or OpenAI. | [Image generation](image-generation.md) |
144
+ | `tau tool speech-generate` | Generate narration or dialogue using ElevenLabs and assemble a WAV. | [Speech generation](speech-generation.md) |
153
145
 
154
- OCR text can contain recognition mistakes. Embedded visuals that are not represented in Markdown are marked with placeholders pointing to the corresponding page patches. Read `document.md` for the whole document, use `pages/` for page-level work, and inspect `images/` before trusting or correcting uncertain OCR.
155
-
156
- The command uploads the PDF to Mistral and attempts to delete the remote upload after OCR. A deletion failure is reported in the command output. Successful local artifacts remain on disk for follow-up use; delete them when they are no longer needed. If processing fails, Tau attempts to remove the partial local output directory. Do not use the command for a sensitive document unless sending it to Mistral and retaining derived local artifacts are both permitted.
146
+ Each guide covers setup, input, examples, outputs, and failure behavior. Use `tau tool --help` to list commands or `tau tool <command> --help` for command-specific help. The same guides are packaged for `tau_docs` and linked from its `index.md`.
157
147
 
158
148
  ## Code-mode service tools
159
149
 
@@ -207,13 +197,24 @@ The TUI advertises `diff_review` and `prefill_input` unless client tools are dis
207
197
 
208
198
  Configured command client tools are also client-owned. They can run local client processes and use a bounded execution-environment facade when work belongs on the session machine. Remote attachment makes this distinction visible: the TUI process and its tools may be on a laptop while the host and execution environment are elsewhere. See [client tools](client-tools.md) for configuration, protocol helpers, and limits, and [TUI](tui.md) for diff-tool configuration.
209
199
 
210
- ### Sending images to Telegram
200
+ ### Sending files to Telegram
201
+
202
+ Telegram provides four client tools, each accepting `{ path, caption? }` and delivering to the current chat:
203
+
204
+ | Tool | Delivery | Supported files | Maximum size |
205
+ | --- | --- | --- | --- |
206
+ | `send_photo_to_telegram` | In-chat photo | JPEG/PNG; width plus height at most 10,000 pixels, aspect ratio at most 20 | 10,000,000 bytes |
207
+ | `send_video_to_telegram` | Playable video | MPEG4 | 50,000,000 bytes |
208
+ | `send_audio_to_telegram` | Audio player | MP3/M4A | 50,000,000 bytes |
209
+ | `send_document_to_telegram` | Original file attachment | Any type, including PDF, CSV, ZIP, WAV, and original-quality images | 50,000,000 bytes |
210
+
211
+ Paths may be absolute or relative to the session working directory. Captions are plain text, limited to 1,024 UTF-16 code units. Document delivery preserves original bytes and filenames; photo delivery uses Telegram's native photo processing. File bytes do not enter model context or session history.
211
212
 
212
- The Telegram-only `send_image({ path, caption? })` client tool delivers a PNG or JPEG from the session execution environment to the current chat as a Telegram document. It preserves the original bytes and filename without resizing or recompression. Paths may be absolute or relative to the session working directory; captions are plain text, limited to 1,024 UTF-16 code units.
213
+ Transfers read at most 8,000,000 bytes per execution-environment request and reject non-regular, empty, oversized, or changing files. Tools do not inspect codecs, convert files, or fall back to another delivery method. Telegram validates media compatibility, including photo dimensions. Unsupported media can be explicitly converted before sending or delivered as a document instead.
213
214
 
214
- Images may be up to 50,000,000 bytes. Transfers read at most 8,000,000 bytes per execution-environment request and reject non-regular, empty, oversized, or changing files. Format is detected from file content rather than the extension. Image bytes do not enter model context or session history. Reading, validation, cancellation, and Telegram delivery failures fail the tool call. Calls allow five minutes and are not automatically retried, since an interrupted upload may already have reached Telegram.
215
+ Reading, cancellation, and Telegram delivery failures fail the tool call. Calls allow five minutes and are not automatically retried, since an interrupted upload may already have reached Telegram.
215
216
 
216
- The runner owns upload credentials and binds the recipient to the session's bot and chat; the agent cannot select a recipient. This built-in tool is independent of configured command-tool selection and does not appear in TUI sessions or subagents. Inspecting an image with `view_image` does not send it to Telegram.
217
+ The runner owns upload credentials and binds the recipient to the session's bot and chat; the agent cannot select a recipient. These built-in tools are independent of configured command-tool selection and do not appear in TUI sessions or subagents. Inspecting an image with `view_image` does not send it to Telegram. Automatic voice responses through `/tts_on` are separate from these tools.
217
218
 
218
219
  ## When a tool is missing or fails
219
220
 
@@ -197,9 +197,11 @@ The TUI also advertises diff review as a client tool unless `--no-client-tools`
197
197
 
198
198
  ## Use speech
199
199
 
200
- `/listen` and Ctrl+Y are currently macOS-only. Recording uses local `ffmpeg` with the AVFoundation audio input and stops when Ctrl+Y is pressed again, when Escape is pressed, or after 20 minutes. Startup fails if the microphone produces no audio within 15 seconds. Stopping manually or reaching the 20-minute limit finishes transcription and inserts the transcript at the cursor for review without submitting it.
200
+ `/listen` and Ctrl+Y are currently macOS-only. Recording uses local `ffmpeg` with the AVFoundation audio input and stops when Ctrl+Y is pressed again, when Escape is pressed, or at the provider recording limit: 9 minutes for Gemini and 20 minutes for OpenAI. The Gemini limit leaves time for setup and finalization within its 10-minute live session. Startup fails if the microphone produces no audio within 15 seconds. Stopping manually or reaching the recording limit finishes transcription and inserts the transcript at the cursor for review without submitting it.
201
201
 
202
- If transcription fails, Tau retains the local WAV and reports its path. Run `/listen retry` to transcribe the same audio again with the current provider and conversation context, or `/listen discard` to delete it. Retained recordings longer than 20 minutes are rejected rather than sent to the provider. A replacement recording deletes the retained file only after the new capture starts producing audio. Tau keeps at most one failed recording, and exiting leaves that file at the reported path for manual recovery. For live transcription, both providers extract spelling hints from recent conversation while recording begins, buffer audio until the transcription session is ready, and then stream subsequent audio. Gemini uses Gemini 3.8 Flash for hint extraction and `gemini-3.5-transcribe-live` in smart mode; OpenAI uses GPT-6 Luna and `gpt-live-transcribe`. Hint extraction failure does not fail transcription. On retry, Gemini uploads the retained recording for `gemini-3.5-transcribe` smart transcription and attempts to delete the remote file afterward; OpenAI uploads it to `gpt-transcribe` with recent context.
202
+ Gemini displays a replaceable live preview in muted italic text at the original cursor position. Finalized dictation uses normal text once transcription settles. Its final transcript replaces the preview without duplication. Editing stays disabled from recording startup through finalization, and failure restores the original draft. OpenAI inserts its transcript after finalization. Recording and retries cannot start while another editor update is pending.
203
+
204
+ If transcription fails, Tau retains the local WAV and reports its path. Run `/listen retry` to transcribe the same audio again with the current provider and conversation context, or `/listen discard` to delete it. Retained recordings longer than 20 minutes are rejected rather than sent to the provider. A replacement recording deletes the retained file only after the new capture starts producing audio. Tau keeps at most one failed recording, and exiting leaves that file at the reported path for manual recovery. For live transcription, both providers extract spelling hints from recent conversation while recording begins, buffer audio until the transcription session is ready, and then stream subsequent audio. Gemini uses Gemini 3.8 Flash for hint extraction and `gemini-3.5-transcribe-live` in verbatim mode with English (`en-US`) and Finnish (`fi-FI`) language hints; OpenAI uses GPT-6 Luna and `gpt-live-transcribe`. Hint extraction failure does not fail transcription. On retry, Gemini uploads the retained recording for `gemini-3.5-transcribe` verbatim transcription with the same language hints and attempts to delete the remote file afterward; OpenAI uploads it to `gpt-transcribe` with recent context.
203
205
 
204
206
  Install `ffmpeg` and configure a speech-to-text provider:
205
207