@markusylisiurunen/tau 0.1.47 → 0.1.49
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 +15 -0
- package/dist/app.js +148 -28
- package/dist/app.js.map +1 -1
- package/dist/cli.js +16 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands.js +21 -5
- package/dist/commands.js.map +1 -1
- package/dist/content_loader.js +67 -6
- package/dist/content_loader.js.map +1 -1
- package/dist/export/engine_history.js +57 -0
- package/dist/export/engine_history.js.map +1 -0
- package/dist/export/html.js +329 -0
- package/dist/export/html.js.map +1 -0
- package/dist/export/index.js +11 -0
- package/dist/export/index.js.map +1 -0
- package/dist/export/types.js +2 -0
- package/dist/export/types.js.map +1 -0
- package/dist/main.js +1 -0
- package/dist/main.js.map +1 -1
- package/dist/personas.js +12 -1
- package/dist/personas.js.map +1 -1
- package/dist/tools/registry.js +2 -2
- package/dist/tools/registry.js.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/ui/bash_execution.js +4 -5
- package/dist/ui/bash_execution.js.map +1 -1
- package/dist/ui/file_execution.js +7 -9
- package/dist/ui/file_execution.js.map +1 -1
- package/dist/ui/restricted_execution.js +20 -31
- package/dist/ui/restricted_execution.js.map +1 -1
- package/dist/ui/slash_autocomplete.js +17 -5
- package/dist/ui/slash_autocomplete.js.map +1 -1
- package/dist/ui/task_execution.js +21 -29
- package/dist/ui/task_execution.js.map +1 -1
- package/dist/ui/theme.js +51 -0
- package/dist/ui/theme.js.map +1 -1
- package/dist/ui/theme_preview.js +154 -0
- package/dist/ui/theme_preview.js.map +1 -0
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -57,6 +57,17 @@ npm run build
|
|
|
57
57
|
npm start
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
+
## theme preview
|
|
61
|
+
|
|
62
|
+
run a model-free UI preview for theme iteration:
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
tau --theme-preview
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
theme preview renders a fixed set of UI fixtures and disables model calls so you can tweak colors and spacing
|
|
69
|
+
without asking the model for visible content.
|
|
70
|
+
|
|
60
71
|
## risk levels
|
|
61
72
|
|
|
62
73
|
tau uses risk levels to control what the model can do. this lets you stay in control while working alongside AI.
|
|
@@ -75,6 +86,8 @@ or change it during a session with `/risk:restricted`, `/risk:read-only`, or `/r
|
|
|
75
86
|
|
|
76
87
|
the default is read-only because it lets the model investigate your code and answer questions without risk of unintended changes. bump it to read-write when you're ready to let the model make edits.
|
|
77
88
|
|
|
89
|
+
custom personas (loaded from disk) only allow `read-only` and `read-write` risk levels. if you try to use `restricted` with a custom persona, tau will keep the risk level at `read-only`.
|
|
90
|
+
|
|
78
91
|
## personas
|
|
79
92
|
|
|
80
93
|
tau comes with several built-in personas across different models:
|
|
@@ -158,6 +171,7 @@ tau supports slash commands for common actions:
|
|
|
158
171
|
| `/new` | clear the session and start fresh |
|
|
159
172
|
| `/copy` | copy the last assistant message |
|
|
160
173
|
| `/copy:code` | copy just the code blocks |
|
|
174
|
+
| `/export:html` | export chat history to html |
|
|
161
175
|
| `/reload` | reload personas, prompts, and skills from disk |
|
|
162
176
|
| `/compact:only-summary` | compress history and continue with a summary |
|
|
163
177
|
| `/compact:with-last-turn` | compress history but keep the last exchange |
|
|
@@ -258,6 +272,7 @@ you can also set model parameters via optional frontmatter fields:
|
|
|
258
272
|
model: claude-haiku-4-5
|
|
259
273
|
reasoning: medium
|
|
260
274
|
```
|
|
275
|
+
- `tools`: list of tool names to enable for this persona. allowed: `bash`, `write`, `edit`, `read`, `list`, `grep`, `task`, `fork`. if omitted, defaults to `bash`, `write`, `edit` (and `task` when subagents are enabled). risk levels still apply.
|
|
261
276
|
|
|
262
277
|
use it with `--persona my-assistant` or `/persona:my-assistant`. if a project persona id conflicts with a user or built-in persona, the project persona wins.
|
|
263
278
|
|
package/dist/app.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mkdtemp, writeFile } from "node:fs/promises";
|
|
2
|
+
import { homedir, tmpdir } from "node:os";
|
|
2
3
|
import { join, resolve } from "node:path";
|
|
3
4
|
import { streamSimple } from "@mariozechner/pi-ai";
|
|
4
5
|
import { Spacer, TUI } from "@mariozechner/pi-tui";
|
|
@@ -7,6 +8,8 @@ import { copyTextToClipboard } from "./clipboard.js";
|
|
|
7
8
|
import { buildHelpText, getRiskLevelDescription, parseCommand } from "./commands.js";
|
|
8
9
|
import { getApiKeyForProvider } from "./config.js";
|
|
9
10
|
import { loadAllContent } from "./content_loader.js";
|
|
11
|
+
import { buildExportEntriesFromHistory } from "./export/engine_history.js";
|
|
12
|
+
import { renderExport } from "./export/index.js";
|
|
10
13
|
import { SessionEngine } from "./session/session_engine.js";
|
|
11
14
|
import { formatSubagentsForPrompt } from "./subagents/registry.js";
|
|
12
15
|
import { createAppTerminal } from "./terminal.js";
|
|
@@ -30,6 +33,7 @@ import { buildGrepBlockedView, buildGrepFinishedView, buildGrepRunningView, buil
|
|
|
30
33
|
import { getFileAutocompleteToken, SlashAutocompleteProvider } from "./ui/slash_autocomplete.js";
|
|
31
34
|
import { buildTaskBlockedView, buildTaskFinishedView, buildTaskRunningView, } from "./ui/task_execution.js";
|
|
32
35
|
import { createUiTheme } from "./ui/theme.js";
|
|
36
|
+
import { buildThemePreviewMessages } from "./ui/theme_preview.js";
|
|
33
37
|
import { buildBaseSystemPrompt, buildEnvironmentTag, buildProjectContextBlock, buildSkillsIndexBlock, findAgentsFilesFromCwdToHome, formatRiskLevelChangeNotice, } from "./utils/context.js";
|
|
34
38
|
import { formatHistoryForCompression } from "./utils/fork.js";
|
|
35
39
|
import { formatAdaptiveNumber, formatCwd, formatTokenWindow } from "./utils/format.js";
|
|
@@ -82,6 +86,7 @@ export class ChatApp {
|
|
|
82
86
|
currentTurnStartedAt;
|
|
83
87
|
lastTurnDurationMs = 0;
|
|
84
88
|
turnTimer;
|
|
89
|
+
themePreview;
|
|
85
90
|
constructor(options) {
|
|
86
91
|
this.personas = options.personas;
|
|
87
92
|
this.prompts = options.prompts ?? [];
|
|
@@ -91,15 +96,11 @@ export class ChatApp {
|
|
|
91
96
|
this.initialUserMessage = options.initialUserMessage;
|
|
92
97
|
this.config = options.config ?? {};
|
|
93
98
|
this.compactToolUi = this.config.toolDisplayMode !== "full";
|
|
94
|
-
|
|
95
|
-
|
|
99
|
+
this.themePreview = options.themePreview ?? false;
|
|
100
|
+
this.showThinking = this.themePreview;
|
|
101
|
+
if (this.themePreview) {
|
|
102
|
+
this.queuedUserMessages.push("Queue: adjust muted contrast and preview again", "Queue: verify tool error colors");
|
|
96
103
|
}
|
|
97
|
-
this.initialRiskLevel = this.riskLevel;
|
|
98
|
-
this.environmentTag = buildEnvironmentTag({
|
|
99
|
-
riskLevel: this.initialRiskLevel,
|
|
100
|
-
cwd: process.cwd(),
|
|
101
|
-
datetime: new Date().toISOString(),
|
|
102
|
-
});
|
|
103
104
|
this.agentsFiles = options.withContext
|
|
104
105
|
? findAgentsFilesFromCwdToHome(process.cwd(), homedir())
|
|
105
106
|
: [];
|
|
@@ -112,6 +113,19 @@ export class ChatApp {
|
|
|
112
113
|
this.personas.find((p) => p.id.toLowerCase() === options.initialPersonaId.toLowerCase())) ||
|
|
113
114
|
this.personas[0];
|
|
114
115
|
this.clampPersonaReasoning(this.currentPersona);
|
|
116
|
+
if (options.initialRiskLevel) {
|
|
117
|
+
this.riskLevel = options.initialRiskLevel;
|
|
118
|
+
}
|
|
119
|
+
const allowedRiskLevels = this.getAllowedRiskLevelsForPersona(this.currentPersona);
|
|
120
|
+
if (!allowedRiskLevels.includes(this.riskLevel)) {
|
|
121
|
+
this.riskLevel = allowedRiskLevels[0] ?? "read-only";
|
|
122
|
+
}
|
|
123
|
+
this.initialRiskLevel = this.riskLevel;
|
|
124
|
+
this.environmentTag = buildEnvironmentTag({
|
|
125
|
+
riskLevel: this.initialRiskLevel,
|
|
126
|
+
cwd: process.cwd(),
|
|
127
|
+
datetime: new Date().toISOString(),
|
|
128
|
+
});
|
|
115
129
|
this.baseSystemPrompt = buildBaseSystemPrompt({
|
|
116
130
|
personaSystemPrompt: this.currentPersona.systemPrompt,
|
|
117
131
|
skillsBlock: this.getSkillsIndexBlockForPersona(this.currentPersona).skillsBlock,
|
|
@@ -139,7 +153,7 @@ export class ChatApp {
|
|
|
139
153
|
});
|
|
140
154
|
this.uiTheme = createUiTheme("ansi");
|
|
141
155
|
this.ui = new TUI(createAppTerminal());
|
|
142
|
-
this.chatContainer = new ChatContainerComponent(this.uiTheme);
|
|
156
|
+
this.chatContainer = new ChatContainerComponent(this.uiTheme, this.showThinking);
|
|
143
157
|
this.chatContainer.setCompactToolUi(this.compactToolUi);
|
|
144
158
|
this.footer = new FooterComponent(this.uiTheme, this.ui);
|
|
145
159
|
this.queuedMessages = new QueuedMessagesComponent(this.uiTheme, this.queuedUserMessages);
|
|
@@ -153,12 +167,20 @@ export class ChatApp {
|
|
|
153
167
|
this.ui.addChild(this.queuedMessages);
|
|
154
168
|
this.ui.addChild(this.editor);
|
|
155
169
|
this.ui.addChild(this.footer);
|
|
156
|
-
this.
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
170
|
+
if (this.themePreview) {
|
|
171
|
+
const messages = buildThemePreviewMessages(this.uiTheme);
|
|
172
|
+
for (const message of messages) {
|
|
173
|
+
this.chatContainer.addMessage(message);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
this.chatContainer.addMessage({
|
|
178
|
+
type: "app_intro",
|
|
179
|
+
appName: "tau",
|
|
180
|
+
version: APP_VERSION,
|
|
181
|
+
helpText: buildHelpText(this.agentsFiles, this.skills, this.getAllowedRiskLevelsForPersona(this.currentPersona)),
|
|
182
|
+
});
|
|
183
|
+
}
|
|
162
184
|
this.ui.setFocus(this.editor);
|
|
163
185
|
this.updateFooter();
|
|
164
186
|
this.updateEditorBorderColor();
|
|
@@ -182,6 +204,9 @@ export class ChatApp {
|
|
|
182
204
|
};
|
|
183
205
|
this.editor.onAltUp = () => this.popQueuedUserMessageIntoEditor();
|
|
184
206
|
this.editor.beforeSubmit = (text) => {
|
|
207
|
+
if (this.themePreview) {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
185
210
|
if (!this.isStreaming)
|
|
186
211
|
return true;
|
|
187
212
|
const trimmed = text.trimStart();
|
|
@@ -206,7 +231,7 @@ export class ChatApp {
|
|
|
206
231
|
this.editor.setAutocompleteProvider(new SlashAutocompleteProvider(() => this.personas.map((p) => ({ id: p.id, label: p.label })), () => this.prompts.map((t) => ({ id: t.id, label: t.label })), () => this.bashCommands.map((b) => ({
|
|
207
232
|
id: b.id,
|
|
208
233
|
description: b.description,
|
|
209
|
-
})), () => this.projectFiles, () => this.skills.map((skill) => skill.name)));
|
|
234
|
+
})), () => this.projectFiles, () => this.skills.map((skill) => skill.name), () => this.getAllowedRiskLevelsForPersona(this.currentPersona)));
|
|
210
235
|
this.editor.onSubmit = (text) => this.handleSubmit(text);
|
|
211
236
|
}
|
|
212
237
|
getEditorTextBeforeCursor() {
|
|
@@ -232,6 +257,9 @@ export class ChatApp {
|
|
|
232
257
|
}
|
|
233
258
|
async start() {
|
|
234
259
|
this.ui.start();
|
|
260
|
+
if (this.themePreview) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
235
263
|
if (this.initialUserMessage) {
|
|
236
264
|
await this.sendInitialUserMessage(this.initialUserMessage);
|
|
237
265
|
}
|
|
@@ -271,6 +299,14 @@ export class ChatApp {
|
|
|
271
299
|
this.ui.requestRender();
|
|
272
300
|
}
|
|
273
301
|
updateEditorHeader(cwd = formatCwd(process.cwd()), personaName = this.currentPersona.label || this.currentPersona.id, reasoningLabel = this.currentPersona.settings.reasoning ?? "none") {
|
|
302
|
+
if (this.themePreview) {
|
|
303
|
+
const labelStyle = this.uiTheme.palette.muted;
|
|
304
|
+
this.editor.setHeader("theme preview", "model disabled", {
|
|
305
|
+
leftStyle: labelStyle,
|
|
306
|
+
rightStyle: labelStyle,
|
|
307
|
+
});
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
274
310
|
if (this.isBashMode) {
|
|
275
311
|
this.editor.setHeader("bash", "", { leftStyle: this.editor.borderColor });
|
|
276
312
|
return;
|
|
@@ -332,7 +368,7 @@ export class ChatApp {
|
|
|
332
368
|
? this.getContextWindowForLastTurn(last)
|
|
333
369
|
: this.currentPersona.model.contextWindow;
|
|
334
370
|
const { input, read, write, output } = this.getSessionTotals();
|
|
335
|
-
const stats = `↑${formatTokenWindow(input)} ↓${formatTokenWindow(output)} cache ${formatTokenWindow(read)}
|
|
371
|
+
const stats = `↑${formatTokenWindow(input)} ↓${formatTokenWindow(output)} (cache r${formatTokenWindow(read)} w${formatTokenWindow(write)})`;
|
|
336
372
|
const promptTokensSent = last
|
|
337
373
|
? (last.usage?.input ?? 0) + (last.usage?.cacheRead ?? 0) + (last.usage?.cacheWrite ?? 0)
|
|
338
374
|
: 0;
|
|
@@ -449,12 +485,20 @@ export class ChatApp {
|
|
|
449
485
|
persona.settings.reasoning = allowed[0];
|
|
450
486
|
}
|
|
451
487
|
}
|
|
488
|
+
isCustomPersona(persona) {
|
|
489
|
+
return persona.source !== "builtin";
|
|
490
|
+
}
|
|
491
|
+
getAllowedRiskLevelsForPersona(persona) {
|
|
492
|
+
return this.isCustomPersona(persona)
|
|
493
|
+
? ["read-only", "read-write"]
|
|
494
|
+
: ["restricted", "read-only", "read-write"];
|
|
495
|
+
}
|
|
452
496
|
// Risk Level Management ---------------------------------------------------------------
|
|
453
497
|
cycleRiskLevel() {
|
|
454
|
-
const levels =
|
|
498
|
+
const levels = this.getAllowedRiskLevelsForPersona(this.currentPersona);
|
|
455
499
|
const previous = this.riskLevel;
|
|
456
500
|
const index = levels.indexOf(this.riskLevel);
|
|
457
|
-
const next = levels[(index + 1) % levels.length];
|
|
501
|
+
const next = levels[(index + 1) % levels.length] ?? levels[0];
|
|
458
502
|
this.riskLevel = next;
|
|
459
503
|
this.engine.setRiskLevel(next);
|
|
460
504
|
this.updateFooter();
|
|
@@ -476,6 +520,13 @@ export class ChatApp {
|
|
|
476
520
|
const next = this.personas[(index + 1) % this.personas.length];
|
|
477
521
|
this.currentPersona = next;
|
|
478
522
|
this.clampPersonaReasoning(this.currentPersona);
|
|
523
|
+
const allowedRiskLevels = this.getAllowedRiskLevelsForPersona(this.currentPersona);
|
|
524
|
+
if (!allowedRiskLevels.includes(this.riskLevel)) {
|
|
525
|
+
this.setRiskLevel(this.riskLevel, {
|
|
526
|
+
force: true,
|
|
527
|
+
reason: "restricted risk level is not available for custom personas.",
|
|
528
|
+
});
|
|
529
|
+
}
|
|
479
530
|
const skillsContext = this.getSkillsIndexBlockForPersona(this.currentPersona);
|
|
480
531
|
this.baseSystemPrompt = buildBaseSystemPrompt({
|
|
481
532
|
personaSystemPrompt: this.currentPersona.systemPrompt,
|
|
@@ -619,6 +670,9 @@ export class ChatApp {
|
|
|
619
670
|
}
|
|
620
671
|
}
|
|
621
672
|
async handleSubmit(text) {
|
|
673
|
+
if (this.themePreview) {
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
622
676
|
const trimmed = text.trim();
|
|
623
677
|
if (!trimmed)
|
|
624
678
|
return;
|
|
@@ -711,6 +765,9 @@ export class ChatApp {
|
|
|
711
765
|
case "copyCode":
|
|
712
766
|
await this.copyLastAssistantCodeBlock();
|
|
713
767
|
break;
|
|
768
|
+
case "export":
|
|
769
|
+
await this.exportSessionHtml();
|
|
770
|
+
break;
|
|
714
771
|
case "new":
|
|
715
772
|
this.clearSession();
|
|
716
773
|
break;
|
|
@@ -741,7 +798,7 @@ export class ChatApp {
|
|
|
741
798
|
}
|
|
742
799
|
}
|
|
743
800
|
showHelp() {
|
|
744
|
-
this.addSystemMessage(buildHelpText(this.agentsFiles, this.skills), "muted");
|
|
801
|
+
this.addSystemMessage(buildHelpText(this.agentsFiles, this.skills, this.getAllowedRiskLevelsForPersona(this.currentPersona)), "muted");
|
|
745
802
|
}
|
|
746
803
|
async copyLastAssistantMessage() {
|
|
747
804
|
const lastAssistant = this.getLastAssistantMessage();
|
|
@@ -782,6 +839,31 @@ export class ChatApp {
|
|
|
782
839
|
this.addSystemMessage(`clipboard copy failed: ${err.message}`, "error");
|
|
783
840
|
}
|
|
784
841
|
}
|
|
842
|
+
async exportSessionHtml() {
|
|
843
|
+
const history = this.engine.history;
|
|
844
|
+
if (history.length === 0) {
|
|
845
|
+
this.addSystemMessage("no conversation to export.", "warn");
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
try {
|
|
849
|
+
const entries = buildExportEntriesFromHistory(history);
|
|
850
|
+
if (entries.length === 0) {
|
|
851
|
+
this.addSystemMessage("no conversation to export.", "warn");
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
854
|
+
const html = renderExport("html", entries, {
|
|
855
|
+
title: "tau chat export",
|
|
856
|
+
generatedAt: Date.now(),
|
|
857
|
+
});
|
|
858
|
+
const dir = await mkdtemp(join(tmpdir(), "tau-export-"));
|
|
859
|
+
const filePath = join(dir, "index.html");
|
|
860
|
+
await writeFile(filePath, html, "utf8");
|
|
861
|
+
this.addSystemMessage(filePath, "muted");
|
|
862
|
+
}
|
|
863
|
+
catch (err) {
|
|
864
|
+
this.addSystemMessage(`export failed: ${err.message}`, "error");
|
|
865
|
+
}
|
|
866
|
+
}
|
|
785
867
|
async stashEditorToClipboard() {
|
|
786
868
|
const text = this.editor.getText();
|
|
787
869
|
if (!text.trim()) {
|
|
@@ -1016,21 +1098,45 @@ Write plain prose, no formatting. Be thorough enough that the reader can resume
|
|
|
1016
1098
|
void this.drainQueuedUserMessages();
|
|
1017
1099
|
}
|
|
1018
1100
|
}
|
|
1019
|
-
setRiskLevel(level) {
|
|
1101
|
+
setRiskLevel(level, options) {
|
|
1102
|
+
const allowed = this.getAllowedRiskLevelsForPersona(this.currentPersona);
|
|
1103
|
+
let target = level;
|
|
1104
|
+
let forced = false;
|
|
1105
|
+
if (!allowed.includes(level)) {
|
|
1106
|
+
if (!options?.force) {
|
|
1107
|
+
if (!options?.silent) {
|
|
1108
|
+
this.addSystemMessage(`risk level '${level}' is not available for the current persona. allowed: ${allowed.join(", ")}.`, "error");
|
|
1109
|
+
}
|
|
1110
|
+
return;
|
|
1111
|
+
}
|
|
1112
|
+
target = allowed[0] ?? "read-only";
|
|
1113
|
+
forced = true;
|
|
1114
|
+
}
|
|
1020
1115
|
const previous = this.riskLevel;
|
|
1021
|
-
this.riskLevel =
|
|
1022
|
-
this.engine.setRiskLevel(
|
|
1116
|
+
this.riskLevel = target;
|
|
1117
|
+
this.engine.setRiskLevel(target);
|
|
1023
1118
|
this.updateFooter();
|
|
1024
|
-
if (previous !==
|
|
1119
|
+
if (previous !== target) {
|
|
1025
1120
|
const from = this.pendingRiskLevelChange?.from ?? previous;
|
|
1026
|
-
if (from ===
|
|
1121
|
+
if (from === target) {
|
|
1027
1122
|
this.pendingRiskLevelChange = undefined;
|
|
1028
1123
|
}
|
|
1029
1124
|
else {
|
|
1030
|
-
this.pendingRiskLevelChange = { from, to:
|
|
1125
|
+
this.pendingRiskLevelChange = { from, to: target };
|
|
1031
1126
|
}
|
|
1032
1127
|
}
|
|
1033
|
-
|
|
1128
|
+
if (options?.silent) {
|
|
1129
|
+
return;
|
|
1130
|
+
}
|
|
1131
|
+
if (forced) {
|
|
1132
|
+
const reason = options?.reason ?? `risk level '${level}' is not available for the current persona.`;
|
|
1133
|
+
const msg = previous === target
|
|
1134
|
+
? `${reason} staying at ${target}.`
|
|
1135
|
+
: `${reason} switched to ${target}.`;
|
|
1136
|
+
this.addSystemMessage(msg, "warn");
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
this.addSystemMessage(this.formatRiskLevelNotice(target), "success");
|
|
1034
1140
|
}
|
|
1035
1141
|
switchPersona(id) {
|
|
1036
1142
|
const persona = this.personas.find((p) => p.id.toLowerCase() === id.toLowerCase());
|
|
@@ -1040,6 +1146,13 @@ Write plain prose, no formatting. Be thorough enough that the reader can resume
|
|
|
1040
1146
|
}
|
|
1041
1147
|
this.currentPersona = persona;
|
|
1042
1148
|
this.clampPersonaReasoning(this.currentPersona);
|
|
1149
|
+
const allowedRiskLevels = this.getAllowedRiskLevelsForPersona(this.currentPersona);
|
|
1150
|
+
if (!allowedRiskLevels.includes(this.riskLevel)) {
|
|
1151
|
+
this.setRiskLevel(this.riskLevel, {
|
|
1152
|
+
force: true,
|
|
1153
|
+
reason: "restricted risk level is not available for custom personas.",
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1043
1156
|
const skillsContext = this.getSkillsIndexBlockForPersona(this.currentPersona);
|
|
1044
1157
|
this.baseSystemPrompt = buildBaseSystemPrompt({
|
|
1045
1158
|
personaSystemPrompt: this.currentPersona.systemPrompt,
|
|
@@ -1102,6 +1215,13 @@ Write plain prose, no formatting. Be thorough enough that the reader can resume
|
|
|
1102
1215
|
this.clampPersonaReasoning(this.currentPersona);
|
|
1103
1216
|
this.addSystemMessage(`previous persona no longer available; switched to ${this.currentPersona.label || this.currentPersona.id}.`, "warn");
|
|
1104
1217
|
}
|
|
1218
|
+
const allowedRiskLevels = this.getAllowedRiskLevelsForPersona(this.currentPersona);
|
|
1219
|
+
if (!allowedRiskLevels.includes(this.riskLevel)) {
|
|
1220
|
+
this.setRiskLevel(this.riskLevel, {
|
|
1221
|
+
force: true,
|
|
1222
|
+
reason: "restricted risk level is not available for custom personas.",
|
|
1223
|
+
});
|
|
1224
|
+
}
|
|
1105
1225
|
// Rebuild system prompt and update the engine
|
|
1106
1226
|
const skillsContext = this.getSkillsIndexBlockForPersona(this.currentPersona);
|
|
1107
1227
|
this.baseSystemPrompt = buildBaseSystemPrompt({
|