@markusylisiurunen/tau 0.3.98 → 0.3.99

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 (46) hide show
  1. package/dist/core/config/schema.js.map +1 -1
  2. package/dist/core/persona_selection.js +38 -0
  3. package/dist/core/persona_selection.js.map +1 -0
  4. package/dist/core/runtime/chat_runtime.js +0 -5
  5. package/dist/core/runtime/chat_runtime.js.map +1 -1
  6. package/dist/core/session/auto_compaction_threshold.js.map +1 -1
  7. package/dist/core/static/code_mode/history/documentation.md +1 -1
  8. package/dist/core/static/tau_docs/configuration.md +1 -1
  9. package/dist/core/static/tau_docs/history.md +6 -3
  10. package/dist/core/static/tau_docs/node-sdk.md +5 -5
  11. package/dist/core/static/tau_docs/ownership-and-scope.md +1 -1
  12. package/dist/core/static/tau_docs/personas.md +4 -4
  13. package/dist/core/static/tau_docs/remote-sessions.md +1 -1
  14. package/dist/core/static/tau_docs/session-protocol-methods.md +14 -5
  15. package/dist/core/static/tau_docs/session-protocol.md +1 -1
  16. package/dist/core/static/tau_docs/sessions.md +7 -3
  17. package/dist/core/static/tau_docs/telegram-projects.md +4 -7
  18. package/dist/core/static/tau_docs/telegram.md +51 -35
  19. package/dist/core/static/tau_docs/troubleshooting.md +2 -0
  20. package/dist/core/static/tau_docs/tui.md +1 -1
  21. package/dist/core/telegram/adapter.js +24 -39
  22. package/dist/core/telegram/adapter.js.map +1 -1
  23. package/dist/core/telegram/config.js +41 -58
  24. package/dist/core/telegram/config.js.map +1 -1
  25. package/dist/core/telegram/local_session_client.js +1 -1
  26. package/dist/core/telegram/local_session_client.js.map +1 -1
  27. package/dist/core/telegram/runtime.js +9 -4
  28. package/dist/core/telegram/runtime.js.map +1 -1
  29. package/dist/core/telegram/session_manager.js +6 -7
  30. package/dist/core/telegram/session_manager.js.map +1 -1
  31. package/dist/core/version.js +1 -1
  32. package/dist/host/local_session_host.js +48 -13
  33. package/dist/host/local_session_host.js.map +1 -1
  34. package/dist/host/session_host.js.map +1 -1
  35. package/dist/host/session_protocol_handler.js +9 -1
  36. package/dist/host/session_protocol_handler.js.map +1 -1
  37. package/dist/protocol/session_protocol.d.ts +7 -2
  38. package/dist/protocol/session_protocol.js +21 -8
  39. package/dist/protocol/session_protocol.js.map +1 -1
  40. package/dist/sdk/local_client.d.ts +4 -0
  41. package/dist/sdk/local_client.js +13 -6
  42. package/dist/sdk/local_client.js.map +1 -1
  43. package/dist/sdk/session.js +4 -3
  44. package/dist/sdk/session.js.map +1 -1
  45. package/dist/sdk/types.d.ts +2 -2
  46. package/package.json +4 -4
@@ -14,7 +14,7 @@ tau telegram --config-file /etc/tau/telegram.json
14
14
 
15
15
  The process stays in the foreground until `SIGINT` or `SIGTERM`. Relative `--config-file` paths resolve from the process working directory. Paths inside that file resolve as described below, usually from the config file's directory.
16
16
 
17
- The Telegram file is **not** one of Tau's `config.json` levels. It configures the runner: bot tokens, projects, workspace roots, and routing. Tau still loads normal configuration from the runner's startup directory and from each session's workspace. See [configuration](configuration.md) and [ownership and scope](ownership-and-scope.md).
17
+ The Telegram file is **not** one of Tau's `config.json` levels. It configures the runner: bot tokens, startup settings, presets, projects, workspace roots, and routing. Tau still loads normal configuration from the runner's startup directory and from each session's workspace. See [configuration](configuration.md) and [ownership and scope](ownership-and-scope.md).
18
18
 
19
19
  Run at most one runner per configuration and workspace root. Two runners would compete for Telegram updates, runner state, and workspace cleanup.
20
20
 
@@ -28,6 +28,7 @@ A useful configuration defines at least one bot and one project:
28
28
  "bots": {
29
29
  "engineering": {
30
30
  "botToken": "<telegram-bot-token>",
31
+ "startup": { "source": "workspace" },
31
32
  "allowedProjectIds": ["ledger"],
32
33
  "allowedUserIds": [18422031],
33
34
  "allowedChatIds": [18422031],
@@ -37,8 +38,7 @@ A useful configuration defines at least one bot and one project:
37
38
  "projects": {
38
39
  "ledger": {
39
40
  "repo": "acme/ledger",
40
- "ref": "main",
41
- "persona": "gpt-6.1-sol-coder:high"
41
+ "ref": "main"
42
42
  }
43
43
  }
44
44
  }
@@ -46,7 +46,7 @@ A useful configuration defines at least one bot and one project:
46
46
 
47
47
  The bot token must be written in the file; it cannot come from an environment variable. Protect the file, never commit it, and rotate an exposed token through BotFather. Never print the config into a session or shared log.
48
48
 
49
- Unknown fields are removed, so a misspelled field silently has no effect. The exception is a `personaMenu` entry, where an unknown field makes the config invalid.
49
+ The runner refuses to start if the file contains an unknown field, and the error names that field.
50
50
 
51
51
  ## Top-level fields
52
52
 
@@ -70,7 +70,8 @@ Each `bots.<id>` object supports:
70
70
  | `botToken` | Yes | Telegram Bot API token. |
71
71
  | `allowedProjectIds` | No | Non-empty unique subset of configured project IDs; omission exposes all projects. |
72
72
  | `autoCompactThresholdTokens` | No | Default automatic-compaction threshold for this bot's sessions. See [compaction thresholds](#compaction-thresholds). |
73
- | `personaMenu` | No | Ordered list of personas offered by `/persona`; omission offers every persona. See [persona menu](#persona-menu). |
73
+ | `startup` | Yes | `{ "source": "workspace" }` or `{ "source": "preset", "preset": "<key>" }`. See [startup and presets](#startup-and-presets). |
74
+ | `presets` | No | Named choices that `/persona` offers. Omission offers all workspace personas, and `{}` offers none. |
74
75
  | `allowedUserIds` | No | Integer user IDs allowed to trigger turns, commands, and callbacks. |
75
76
  | `allowedChatIds` | No | Integer chat IDs allowed to interact with the bot; also opts groups in. |
76
77
  | `defaultProjectId` | No | Initial project preference, and must be allowed for this bot. |
@@ -84,7 +85,7 @@ Use both lists for a private bot. `allowedUserIds` decides who can start work, b
84
85
 
85
86
  A bot sees only its `allowedProjectIds`, or every project if the field is missing. If only one project is allowed, it is selected automatically and the command palette omits `/use_<project>` commands. The command still works when typed directly. Otherwise the palette includes project-switch commands, and a chat needs `defaultProjectId` or a `/use_<project>` choice before `/new`. Each startup replaces the palette, removing switch commands if the bot now has only one available project.
86
87
 
87
- Telegram allows 100 commands per bot: twelve built-ins and up to 88 `/use_<projectId>` commands.
88
+ Telegram allows 100 commands per bot: thirteen built-ins and up to 87 `/use_<projectId>` commands. With `presets: {}`, `/persona` is hidden, which leaves room for one more project command.
88
89
 
89
90
  ## Projects
90
91
 
@@ -102,7 +103,7 @@ Project IDs become `/use_<projectId>` commands, so they may contain only lowerca
102
103
 
103
104
  After preparation, Tau creates an ordinary local session in the workspace. It reads `~/.config/tau` and the `.tau` directories above the workspace as usual, so personas, prompts, skills, project context, host tools, and other settings work as in the TUI.
104
105
 
105
- A project's `persona` replaces the default for its sessions. Composite sessions use the generated root files and their required persona.
106
+ The bot's `startup` selects a new session's settings, as described in [startup and presets](#startup-and-presets).
106
107
 
107
108
  Every Telegram turn starts with a hidden `<system>` block saying the message comes from Telegram and the reply goes there. It asks for direct answers to simple questions, and for short acknowledgements or useful progress updates during longer work, because users cannot see tool activity.
108
109
 
@@ -125,7 +126,7 @@ The runner loads its speech credentials and `speech.voiceId` at startup, from it
125
126
  | `/use_<projectId>` | Selects the project for future `/new` sessions. |
126
127
  | `/new` | Replaces the active session using the preferred project. |
127
128
  | `/status` | Reports session state, project, model, reasoning, context usage, and cost. |
128
- | `/persona` | Switches persona while idle without losing history or starting a turn. |
129
+ | `/persona` | Applies a persona or preset from a menu while idle, without losing history or starting a turn. |
129
130
  | `/effort_low` | Selects low reasoning for future turns. |
130
131
  | `/effort_medium` | Selects medium reasoning for future turns. |
131
132
  | `/effort_high` | Selects high reasoning for future turns. |
@@ -137,9 +138,9 @@ The runner loads its speech credentials and `speech.voiceId` at startup, from it
137
138
  | `/tts_on` | Sends a voice note after each final assistant response. |
138
139
  | `/tts_off` | Disables voice responses. |
139
140
 
140
- Changes to the auto-compaction threshold apply from the next turn and survive session recovery. Switching to a different persona removes the override. `/status` shows context usage as a percentage of the full model window. When a session override is set, or the default threshold is below the model-based threshold, it also shows the effective threshold in parentheses. See [compaction thresholds](#compaction-thresholds) for bot defaults and [automatic compaction](sessions.md#automatic-compaction) for limits and costs.
141
+ Changes to the auto-compaction threshold apply from the next turn and survive session recovery. `/status` shows context usage as a percentage of the full model window. When a session override is set, or the default threshold is below the model-based threshold, it also shows the effective threshold in parentheses. See [compaction thresholds](#compaction-thresholds) for bot defaults and [automatic compaction](sessions.md#automatic-compaction) for limits and costs.
141
142
 
142
- A [persona](personas.md) choice applies to the current session only; `/new` uses the project's default.
143
+ A [persona](personas.md) or preset choice applies to the current session only. `/new` starts from the bot's `startup`.
143
144
 
144
145
  Preferences are saved per bot and chat, and survive restarts and new sessions. A project change applies at the next `/new`, not to the current session.
145
146
 
@@ -153,43 +154,58 @@ In groups, commands must explicitly mention the bot. Accepted forms include:
153
154
 
154
155
  Commands addressed to other bots are ignored.
155
156
 
156
- ### Persona menu
157
+ ## Startup and presets
157
158
 
158
- By default, `/persona` offers every persona in the session. A bot's `personaMenu` replaces that list with the personas you name, in the order you list them, and can give each one a shorter label:
159
+ `startup` decides how a bot's new sessions start, and `presets` decides what `/persona` offers. `startup` does not add a menu entry.
160
+
161
+ `startup` is required. `{ "source": "workspace" }` uses the workspace's `defaultPersona`, found through the same configuration layers as the TUI, including any effort suffix. To start with a named preset instead:
159
162
 
160
163
  ```json
161
- "personaMenu": [
162
- { "id": "gpt-6.1-sol-coder", "label": "sol" },
163
- { "id": "sonnet-5.5-coder", "autoCompactThresholdTokens": 150000 }
164
- ]
164
+ "startup": { "source": "preset", "preset": "astra" },
165
+ "presets": {
166
+ "workspace": { "source": "workspace", "label": "Workspace default" },
167
+ "astra": {
168
+ "source": "persona",
169
+ "label": "Astra",
170
+ "persona": "gpt-6-astra-chat",
171
+ "reasoning": "low",
172
+ "autoCompactThresholdTokens": 120000
173
+ }
174
+ }
165
175
  ```
166
176
 
167
- Each entry has a required `id`, the exact persona ID, an optional `label`, and an optional `autoCompactThresholdTokens` (see [compaction thresholds](#compaction-thresholds)). The ID and label must be non-empty after surrounding whitespace is trimmed, IDs must be unique, and no other fields are allowed. Without a label, the picker shows the persona's own label, or its ID if it has none. The label appears in the picker and in the switch confirmation. It changes nothing else, so the persona keeps its ID, prompt, model, tools, and reasoning settings, and the TUI still shows its normal name.
177
+ `startup.preset` must name a key in `presets`. There are two kinds of preset:
168
178
 
169
- The menu is matched against each session's personas when `/persona` runs, because different projects can define different personas. Listed personas that the session lacks are named in the picker message, and the rest of the menu still works. An empty list, `[]`, offers no personas.
179
+ - A `workspace` preset resolves the workspace's `defaultPersona` each time it is applied.
180
+ - A `persona` preset names a persona ID without an effort suffix. Its optional `reasoning` is one of `none`, `minimal`, `low`, `medium`, `high`, `xhigh`, or `max`, and defaults to the persona's own setting. Its optional `autoCompactThresholdTokens` is [described below](#compaction-thresholds).
170
181
 
171
- Apart from compaction thresholds, the menu only changes what the picker offers. It does not restrict which personas a session may use, and it does not change default personas. A project's `persona` still applies to new sessions even if the menu omits it. When the session's current persona is not in the menu, the picker message names it, but it is not added as a choice.
182
+ Every preset needs a non-empty `label`. Keys must be non-empty, without surrounding whitespace.
172
183
 
173
- ### Compaction thresholds
184
+ The `/persona` menu depends on `presets`:
174
185
 
175
- A bot can set default [automatic-compaction](sessions.md#automatic-compaction) thresholds for its sessions. Both fields take a safe integer of at least 50,000 tokens:
186
+ - Omitted: all personas available in the session's workspace, with their own labels and default settings.
187
+ - `{}`: nothing, and `/persona` is hidden from the command palette. Typing it replies that no presets are configured.
188
+ - With entries: exactly those entries, in the object's order. Integer-like keys sort first, so use non-numeric keys to keep the order you wrote.
176
189
 
177
- ```json
178
- "engineering": {
179
- "botToken": "<telegram-bot-token>",
180
- "autoCompactThresholdTokens": 200000,
181
- "personaMenu": [
182
- { "id": "gpt-6.1-sol-coder", "autoCompactThresholdTokens": 120000 },
183
- { "id": "sonnet-5.5-coder" }
184
- ]
185
- }
186
- ```
190
+ Buttons show only labels, because a session does not record which preset was applied. `/status` reports the session's actual settings.
191
+
192
+ Applying a preset changes the prompt, model, tools, reasoning, and other persona settings together, and keeps the conversation. It applies them once, so effort commands then change only reasoning, and applying the preset again restores its settings.
193
+
194
+ An unavailable persona stays in the menu. Applying it, or a `reasoning` value the persona does not support, reports an error and changes no settings. The value must be in the persona's `allowedReasoningLevels` when that list is non-empty, and a model without reasoning accepts only `none`. A failing preset at `startup` fails the new session.
195
+
196
+ A workspace selection works as in the TUI: an unavailable `defaultPersona` falls back to the first available persona, and its effort suffix skips these checks.
197
+
198
+ Restart the runner after editing `startup` or `presets`. Recovery keeps a session's saved settings and does not reapply them. Reload keeps the session's settings if its persona still exists.
199
+
200
+ ## Compaction thresholds
201
+
202
+ A bot's optional `autoCompactThresholdTokens` sets a default for its sessions. A persona preset's optional field of the same name sets a saved session override when the preset is applied, including at startup. Both take a safe integer of at least 50,000 tokens.
187
203
 
188
- A session uses the first threshold that is set: its `/auto_compact` override, the `personaMenu` entry whose `id` exactly matches the current persona, the bot's `autoCompactThresholdTokens`, the persona's own `autoCompactThresholdTokens`, and finally the model's context window minus 16,384 tokens. Every threshold is capped at that model-based limit. In this example, a session using `gpt-6.1-sol-coder` compacts at 120,000 tokens, and a session using any other persona compacts at 200,000 tokens. A menu entry's threshold applies whenever the session uses that persona, including through the project's default `persona`.
204
+ A session uses its saved override first, then the bot default, the persona default, and finally the model's context window minus 16,384 tokens. The effective threshold is capped at that model-based limit. `/auto_compact` changes the saved override. Applying a persona or preset clears the previous override unless the preset sets a threshold, even when the persona stays the same.
189
205
 
190
- These defaults are not saved with the session. The runner reads them at startup, so restart the runner after changing them. Recovered sessions then use the new defaults, and keep any `/auto_compact` override they had.
206
+ The runner reads the bot default at startup and does not save it with the session. Recovered sessions use the current bot default and keep their saved override.
191
207
 
192
- Native subagents launched without a model use the session's effective threshold, as described in [subagents](subagents.md#automatic-compaction). Ephemeral threads use the persona's own default and ignore the bot's thresholds.
208
+ Native subagents launched without a model use the session's effective threshold, as described in [subagents](subagents.md#automatic-compaction). Ephemeral threads use the persona's own default and ignore both the bot default and the session override.
193
209
 
194
210
  ## DMs, groups, and active work
195
211
 
@@ -250,7 +266,7 @@ Do not verify bot tokens, provider keys, Access secrets, transcript contents, or
250
266
 
251
267
  ## Troubleshooting
252
268
 
253
- **The runner rejects its config.** Startup errors name every invalid bot or project field. Check the required `bots` and `projects` objects, exact project IDs, positive numbers, allowed project IDs, persona suffixes, `personaMenu` entries, and that each project defines exactly one of `repo`, `directory`, or `projectIds`. Check the JSON syntax without printing the file, which contains bot tokens, and restart the runner after fixing it. Relative paths in the file resolve from its directory.
269
+ **The runner rejects its config.** Startup errors name every invalid bot or project field. Check the required `bots` and `projects` objects, exact project IDs, positive numbers, allowed project IDs, startup sources, preset references, and that each project defines exactly one of `repo`, `directory`, or `projectIds`. Check the JSON syntax without printing the file, which contains bot tokens, and restart the runner after fixing it. Relative paths in the file resolve from its directory.
254
270
 
255
271
  **The bot ignores a DM.** If `allowedChatIds` is set, the DM's chat ID must be listed. If `allowedUserIds` is set, the sender's user ID must be listed too.
256
272
 
@@ -200,6 +200,8 @@ If attachment reports an unsupported protocol version or an invalid message, upg
200
200
 
201
201
  For `tau attach --new`, `--cwd` must be an absolute path inside the chosen execution environment. With the default local kind, it is a path on the host, not on the attaching machine. Tau does not create the directory, clone a repository, or detect repository attributes.
202
202
 
203
+ Creating a session also fails if Tau cannot read the hostname from the execution environment, for example because `node` is missing there or the target does not respond in time. The error gives the reason and any output from the failed command. Over the session protocol, these details are in the error's `data.cause`.
204
+
203
205
  For a Fly Sprite session, check on the host that:
204
206
 
205
207
  - `flySprites` is set in the host's startup configuration;
@@ -106,7 +106,7 @@ Then use Shift+Tab to choose a reasoning level. A newly added persona appears on
106
106
 
107
107
  Run commands that change the context, such as persona changes, compaction, rewind, and reload, while idle. `/auto-compact` can inspect or change the next-turn threshold during a running turn. `/auto-speak`, `/listen`, `/prompt:<id>`, and `/exit` do little during a running turn. Other commands wait until Tau is idle.
108
108
 
109
- The footer shows context usage as a percentage of the full model window, such as `20%/272k`. When a session override is set, or the default threshold is below the model-based threshold, the effective compaction threshold appears in parentheses: `20%/272k (50k)`. This threshold cannot exceed the model's context window minus 16,384 tokens. Without an override or a lower default, the footer shows no threshold. Switching to a different persona removes the session override.
109
+ The footer shows context usage as a percentage of the full model window, such as `20%/272k`. When a session override is set, or the default threshold is below the model-based threshold, the effective compaction threshold appears in parentheses: `20%/272k (50k)`. This threshold cannot exceed the model's context window minus 16,384 tokens. Without an override or a lower default, the footer shows no threshold. Applying a persona removes the session override, even when reapplying the current persona.
110
110
 
111
111
  While subagents are running, a panel above the editor shows the selected subagent's title, recent activity, and a usage line such as `openai-codex/gpt-6-astra:medium · ↑12k ↓2k (r8k w0) · 14%/200k · $0.04`. The line starts with the subagent's provider, model, and reasoning effort, including settings inherited from the persona. Text that does not fit the terminal width is cut off on the right.
112
112
 
@@ -774,7 +774,7 @@ class TelegramAdapterImpl {
774
774
  projects;
775
775
  defaultProjectId;
776
776
  systemMessage;
777
- personaMenu;
777
+ presets;
778
778
  allowedUserIds;
779
779
  allowedChatIds;
780
780
  botUsername;
@@ -825,7 +825,7 @@ class TelegramAdapterImpl {
825
825
  this.projects = options.projects;
826
826
  this.defaultProjectId = options.defaultProjectId;
827
827
  this.systemMessage = options.systemMessage?.trim() || undefined;
828
- this.personaMenu = options.personaMenu;
828
+ this.presets = options.presets;
829
829
  this.allowedUserIds =
830
830
  options.allowedUserIds && options.allowedUserIds.length > 0
831
831
  ? new Set(options.allowedUserIds)
@@ -919,7 +919,8 @@ class TelegramAdapterImpl {
919
919
  },
920
920
  {
921
921
  command: "/persona",
922
- description: "switch the active session persona",
922
+ description: "choose a persona or preset",
923
+ hiddenFromMenu: this.presets !== undefined && Object.keys(this.presets).length === 0,
923
924
  handler: async (chatId, args) => this.handlePersona(chatId, args),
924
925
  },
925
926
  {
@@ -1556,6 +1557,10 @@ class TelegramAdapterImpl {
1556
1557
  await this.reply(chatId, "use /persona to choose a persona.");
1557
1558
  return;
1558
1559
  }
1560
+ if (this.presets !== undefined && Object.keys(this.presets).length === 0) {
1561
+ await this.reply(chatId, "this bot has no presets configured.");
1562
+ return;
1563
+ }
1559
1564
  const session = await this.requireActiveSession(chatId);
1560
1565
  if (!session)
1561
1566
  return;
@@ -1566,47 +1571,27 @@ class TelegramAdapterImpl {
1566
1571
  return;
1567
1572
  }
1568
1573
  const catalog = snapshot.catalog.personas;
1569
- const currentPersonaId = snapshot.settings.personaId;
1570
- const menu = this.personaMenu ?? catalog.map((persona) => ({ id: persona.id }));
1571
- const personas = [];
1572
- const missingIds = [];
1573
- for (const entry of menu) {
1574
- const persona = catalog.find((candidate) => candidate.id === entry.id);
1575
- if (persona)
1576
- personas.push({ id: persona.id, label: entry.label ?? persona.label ?? persona.id });
1577
- else
1578
- missingIds.push(entry.id);
1579
- }
1580
- const currentLabel = catalog.find((persona) => persona.id === currentPersonaId)?.label ?? currentPersonaId;
1581
- const missingText = missingIds.length > 0
1582
- ? `these personas from this bot's menu aren't available in this session: ${missingIds.join(", ")}.`
1583
- : undefined;
1574
+ const personas = this.presets === undefined
1575
+ ? catalog.map((persona) => ({ id: persona.id, label: persona.label || persona.id }))
1576
+ : Object.values(this.presets).map((preset) => preset.source === "workspace"
1577
+ ? { id: null, label: preset.label }
1578
+ : {
1579
+ id: preset.persona,
1580
+ label: preset.label,
1581
+ overrides: {
1582
+ reasoning: preset.reasoning,
1583
+ autoCompactThresholdTokens: preset.autoCompactThresholdTokens,
1584
+ },
1585
+ });
1584
1586
  if (personas.length === 0) {
1585
- if (!this.personaMenu) {
1586
- await this.reply(chatId, "this session has no personas.");
1587
- return;
1588
- }
1589
- const emptyText = this.personaMenu.length === 0
1590
- ? "this bot's persona menu is empty, so there are no personas to switch to."
1591
- : "none of the personas in this bot's menu are available in this session, so there are no personas to switch to.";
1592
- const lines = [emptyText, missingText, `this session is using ${currentLabel}.`];
1593
- await this.reply(chatId, lines.filter(Boolean).join("\n\n"));
1587
+ await this.reply(chatId, "this bot has no presets configured.");
1594
1588
  return;
1595
1589
  }
1596
- const currentOutsideText = this.personaMenu && !personas.some((persona) => persona.id === currentPersonaId)
1597
- ? `this session is using ${currentLabel}, which isn't in this menu.`
1598
- : undefined;
1599
- const lines = [
1600
- "choose a persona for this session. switching is available only while Tau is idle.",
1601
- currentOutsideText,
1602
- missingText,
1603
- ];
1604
1590
  this.personaPickers.set(chatId, {
1605
1591
  token: randomUUID(),
1606
1592
  sessionId: session.id,
1607
1593
  personas,
1608
- currentPersonaId,
1609
- text: lines.filter(Boolean).join("\n\n"),
1594
+ text: "choose a persona or preset for this session. this works only while Tau is idle.",
1610
1595
  });
1611
1596
  await this.showPersonaPage(chatId, 0);
1612
1597
  }
@@ -1621,7 +1606,7 @@ class TelegramAdapterImpl {
1621
1606
  const start = page * 20;
1622
1607
  const keyboard = picker.personas.slice(start, start + 20).map((persona, index) => [
1623
1608
  {
1624
- text: `${persona.label}${persona.id === picker.currentPersonaId ? " (current)" : ""}`,
1609
+ text: persona.label,
1625
1610
  callback_data: `persona:${picker.token}:select:${start + index}`,
1626
1611
  },
1627
1612
  ]);
@@ -1666,7 +1651,7 @@ class TelegramAdapterImpl {
1666
1651
  return;
1667
1652
  let snapshot;
1668
1653
  try {
1669
- snapshot = await this.getSessionManagerForChat(chatId).setPersona(picker.sessionId, persona.id);
1654
+ snapshot = await this.getSessionManagerForChat(chatId).setPersona(picker.sessionId, persona.id, persona.overrides);
1670
1655
  }
1671
1656
  catch (error) {
1672
1657
  await this.reply(chatId, this.formatManagerError(error));