mono-pilot 0.2.0 → 0.2.1
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 +3 -7
- package/dist/src/extensions/mode-runtime.js +51 -5
- package/dist/src/extensions/user-message.js +21 -3
- package/dist/tools/README.md +3 -1
- package/dist/tools/ask-mode-reminder.md +30 -0
- package/dist/tools/subagent-description.md +1 -1
- package/dist/tools/subagent.js +10 -31
- package/dist/tools/switch-mode.js +14 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -80,7 +80,7 @@ The full Cursor-styled tool list exposed by the extension:
|
|
|
80
80
|
- `FetchMcpResource` – fetch a specific MCP resource
|
|
81
81
|
- `ListMcpTools` – discover MCP tools and schemas
|
|
82
82
|
- `CallMcpTool` – invoke MCP tools by name
|
|
83
|
-
- `SwitchMode` – switch interaction mode (
|
|
83
|
+
- `SwitchMode` – switch interaction mode (`option + m`, cycles Plan → Ask → Agent)
|
|
84
84
|
- `ApplyPatch` – apply single-file patches
|
|
85
85
|
|
|
86
86
|
## User rules
|
|
@@ -143,10 +143,6 @@ The report shows:
|
|
|
143
143
|
- the runtime envelope built from `<rules>`, `<mcp_instructions>`, `<system_reminder>`, and `<user_query>`
|
|
144
144
|
|
|
145
145
|
|
|
146
|
-
##
|
|
146
|
+
## License
|
|
147
147
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
- Gradually migrate additional Cursor-style tools from `tools/`.
|
|
151
|
-
- Keep compatibility behavior focused and testable, one tool at a time.
|
|
152
|
-
- Expand docs and examples for customization.
|
|
148
|
+
MIT
|
|
@@ -5,6 +5,12 @@ Plan mode is still active. Continue with the task in the current mode.
|
|
|
5
5
|
export const AGENT_MODE_SWITCH_REMINDER = `<system_reminder>
|
|
6
6
|
You are now in Agent mode. Continue with the task in the new mode.
|
|
7
7
|
</system_reminder>`;
|
|
8
|
+
export const ASK_MODE_SWITCH_REMINDER = `<system_reminder>
|
|
9
|
+
You are now in Ask mode. Continue with the task in the new mode.
|
|
10
|
+
</system_reminder>`;
|
|
11
|
+
export const ASK_MODE_STILL_ACTIVE_REMINDER = `<system_reminder>
|
|
12
|
+
Ask mode is still active. Continue with the task in the current mode.
|
|
13
|
+
</system_reminder>`;
|
|
8
14
|
export function parseModeStateEntry(entry) {
|
|
9
15
|
if (typeof entry !== "object" || entry === null)
|
|
10
16
|
return undefined;
|
|
@@ -17,10 +23,12 @@ export function parseModeStateEntry(entry) {
|
|
|
17
23
|
if (typeof data !== "object" || data === null)
|
|
18
24
|
return undefined;
|
|
19
25
|
const state = data;
|
|
20
|
-
if (state.activeMode === "plan" || state.activeMode === "agent") {
|
|
26
|
+
if (state.activeMode === "plan" || state.activeMode === "agent" || state.activeMode === "ask") {
|
|
21
27
|
return {
|
|
22
28
|
activeMode: state.activeMode,
|
|
23
|
-
pendingReminder: state.pendingReminder === "plan-entry" ||
|
|
29
|
+
pendingReminder: state.pendingReminder === "plan-entry" ||
|
|
30
|
+
state.pendingReminder === "agent-entry" ||
|
|
31
|
+
state.pendingReminder === "ask-entry"
|
|
24
32
|
? state.pendingReminder
|
|
25
33
|
: undefined,
|
|
26
34
|
};
|
|
@@ -83,14 +91,37 @@ class ModeRuntimeStore {
|
|
|
83
91
|
return { changed: false, snapshot: this.getSnapshot() };
|
|
84
92
|
}
|
|
85
93
|
this.state.activeMode = nextMode;
|
|
86
|
-
|
|
94
|
+
switch (nextMode) {
|
|
95
|
+
case "plan":
|
|
96
|
+
this.state.pendingReminder = "plan-entry";
|
|
97
|
+
break;
|
|
98
|
+
case "ask":
|
|
99
|
+
this.state.pendingReminder = "ask-entry";
|
|
100
|
+
break;
|
|
101
|
+
case "agent":
|
|
102
|
+
default:
|
|
103
|
+
this.state.pendingReminder = "agent-entry";
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
87
106
|
return { changed: true, snapshot: this.getSnapshot() };
|
|
88
107
|
}
|
|
89
108
|
toggleMode() {
|
|
90
|
-
|
|
109
|
+
let nextMode;
|
|
110
|
+
switch (this.state.activeMode) {
|
|
111
|
+
case "agent":
|
|
112
|
+
nextMode = "plan";
|
|
113
|
+
break;
|
|
114
|
+
case "plan":
|
|
115
|
+
nextMode = "ask";
|
|
116
|
+
break;
|
|
117
|
+
case "ask":
|
|
118
|
+
default:
|
|
119
|
+
nextMode = "agent";
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
91
122
|
return this.setMode(nextMode);
|
|
92
123
|
}
|
|
93
|
-
consumeReminder(planEntryReminder) {
|
|
124
|
+
consumeReminder(planEntryReminder, askEntryReminder) {
|
|
94
125
|
if (this.state.activeMode === "plan") {
|
|
95
126
|
if (this.state.pendingReminder === "plan-entry") {
|
|
96
127
|
this.state.pendingReminder = undefined;
|
|
@@ -106,6 +137,21 @@ class ModeRuntimeStore {
|
|
|
106
137
|
snapshot: this.getSnapshot(),
|
|
107
138
|
};
|
|
108
139
|
}
|
|
140
|
+
if (this.state.activeMode === "ask") {
|
|
141
|
+
if (this.state.pendingReminder === "ask-entry") {
|
|
142
|
+
this.state.pendingReminder = undefined;
|
|
143
|
+
return {
|
|
144
|
+
reminder: askEntryReminder,
|
|
145
|
+
changed: true,
|
|
146
|
+
snapshot: this.getSnapshot(),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
reminder: ASK_MODE_STILL_ACTIVE_REMINDER,
|
|
151
|
+
changed: false,
|
|
152
|
+
snapshot: this.getSnapshot(),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
109
155
|
if (this.state.pendingReminder === "agent-entry") {
|
|
110
156
|
this.state.pendingReminder = undefined;
|
|
111
157
|
return {
|
|
@@ -3,9 +3,10 @@ import { readdir, readFile } from "node:fs/promises";
|
|
|
3
3
|
import { dirname, join, resolve } from "node:path";
|
|
4
4
|
import process from "node:process";
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
|
-
import { buildRuntimeEnvelope, createModeStateData, modeRuntimeStore, MODE_STATE_ENTRY_TYPE, PLAN_MODE_STILL_ACTIVE_REMINDER, } from "./mode-runtime.js";
|
|
6
|
+
import { buildRuntimeEnvelope, createModeStateData, modeRuntimeStore, MODE_STATE_ENTRY_TYPE, ASK_MODE_SWITCH_REMINDER, PLAN_MODE_STILL_ACTIVE_REMINDER, } from "./mode-runtime.js";
|
|
7
7
|
import { createRpcRequestId, extractStringHeaders, isRecord, isServerEnabled, parseMcpConfig, postJsonRpcRequest, resolveMcpConfigPath, toNonEmptyString, MCP_PROTOCOL_VERSION, MCP_CLIENT_NAME, MCP_CLIENT_VERSION, } from "../utils/mcp-client.js";
|
|
8
8
|
const PLAN_MODE_REMINDER_PATH = fileURLToPath(new URL("../../tools/plan-mode-reminder.md", import.meta.url));
|
|
9
|
+
const ASK_MODE_REMINDER_PATH = fileURLToPath(new URL("../../tools/ask-mode-reminder.md", import.meta.url));
|
|
9
10
|
const RULES_RELATIVE_DIR = join(".pi", "rules");
|
|
10
11
|
const MCP_INSTRUCTIONS_DESCRIPTION = "Instructions provided by MCP servers to help use them properly";
|
|
11
12
|
const USER_QUERY_RENDER_PATCH_FLAG = "__monoPilotUserQueryRenderPatched__";
|
|
@@ -180,6 +181,7 @@ async function buildRulesEnvelope(workspaceCwd) {
|
|
|
180
181
|
export default function runtimeEnvelopeExtension(pi) {
|
|
181
182
|
void patchInteractiveModeUserMessageDisplay();
|
|
182
183
|
let planModeReminderCache;
|
|
184
|
+
let askModeReminderCache;
|
|
183
185
|
let mcpInstructionsCache;
|
|
184
186
|
let rulesEnvelopeCache;
|
|
185
187
|
let mcpInstructionsPending;
|
|
@@ -199,6 +201,20 @@ export default function runtimeEnvelopeExtension(pi) {
|
|
|
199
201
|
return PLAN_MODE_STILL_ACTIVE_REMINDER;
|
|
200
202
|
}
|
|
201
203
|
};
|
|
204
|
+
const getAskEntryReminder = async () => {
|
|
205
|
+
if (askModeReminderCache !== undefined) {
|
|
206
|
+
return askModeReminderCache ?? ASK_MODE_SWITCH_REMINDER;
|
|
207
|
+
}
|
|
208
|
+
try {
|
|
209
|
+
const content = await readFile(ASK_MODE_REMINDER_PATH, "utf-8");
|
|
210
|
+
askModeReminderCache = content.trim();
|
|
211
|
+
return askModeReminderCache || ASK_MODE_SWITCH_REMINDER;
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
askModeReminderCache = null;
|
|
215
|
+
return ASK_MODE_SWITCH_REMINDER;
|
|
216
|
+
}
|
|
217
|
+
};
|
|
202
218
|
const getMcpInstructions = async () => {
|
|
203
219
|
if (mcpInstructionsCache !== undefined) {
|
|
204
220
|
return mcpInstructionsCache ?? undefined;
|
|
@@ -242,15 +258,17 @@ export default function runtimeEnvelopeExtension(pi) {
|
|
|
242
258
|
// Eagerly pre-fetch rules and MCP instructions in the background so the first input isn't delayed
|
|
243
259
|
getRulesEnvelope().catch(() => { });
|
|
244
260
|
getMcpInstructions().catch(() => { });
|
|
261
|
+
getAskEntryReminder().catch(() => { });
|
|
245
262
|
pi.on("input", async (event) => {
|
|
246
263
|
if (event.source === "extension")
|
|
247
264
|
return;
|
|
248
|
-
const [planEntryReminder, mcpInstructions, rulesEnvelope] = await Promise.all([
|
|
265
|
+
const [planEntryReminder, askEntryReminder, mcpInstructions, rulesEnvelope] = await Promise.all([
|
|
249
266
|
getPlanEntryReminder(),
|
|
267
|
+
getAskEntryReminder(),
|
|
250
268
|
getMcpInstructions(),
|
|
251
269
|
getRulesEnvelope(),
|
|
252
270
|
]);
|
|
253
|
-
const { reminder, changed, snapshot } = modeRuntimeStore.consumeReminder(planEntryReminder);
|
|
271
|
+
const { reminder, changed, snapshot } = modeRuntimeStore.consumeReminder(planEntryReminder, askEntryReminder);
|
|
254
272
|
if (changed) {
|
|
255
273
|
pi.appendEntry(MODE_STATE_ENTRY_TYPE, createModeStateData(snapshot));
|
|
256
274
|
}
|
package/dist/tools/README.md
CHANGED
|
@@ -7,7 +7,9 @@ This directory stores the tool layer for `mono-pilot`.
|
|
|
7
7
|
- `*.ts`: tool implementation (registration, validation, execution)
|
|
8
8
|
- `*.test.ts`: tool unit tests
|
|
9
9
|
- `*-description.md`: shared tool description text consumed by the corresponding tool
|
|
10
|
-
-
|
|
10
|
+
- mode reminders
|
|
11
|
+
- `plan-mode-reminder.md`: system reminder injected when entering Plan mode
|
|
12
|
+
- `ask-mode-reminder.md`: system reminder injected when entering Ask mode
|
|
11
13
|
|
|
12
14
|
Tool descriptions are now loaded by the tool implementation and exposed via the system-prompt extension.
|
|
13
15
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<system_reminder>
|
|
2
|
+
You are now in Ask mode. Continue with the task in the new mode.
|
|
3
|
+
</system_reminder>
|
|
4
|
+
|
|
5
|
+
<system_reminder>
|
|
6
|
+
Ask mode is active. The user wants you to answer questions about their codebase or coding in general. You MUST NOT make any edits, run any non-readonly tools (including changing configs or making commits), or otherwise make any changes to the system. This supersedes any other instructions you have received (for example, to make edits).
|
|
7
|
+
|
|
8
|
+
Your role in Ask mode:
|
|
9
|
+
|
|
10
|
+
1. Answer the user's questions comprehensively and accurately. Focus on providing clear, detailed explanations.
|
|
11
|
+
|
|
12
|
+
2. Use readonly tools to explore the codebase and gather information needed to answer the user's questions. You can:
|
|
13
|
+
- Read files to understand code structure and implementation
|
|
14
|
+
- Search the codebase to find relevant code
|
|
15
|
+
- Use grep to find patterns and usages
|
|
16
|
+
- List directory contents to understand project structure
|
|
17
|
+
- Read lints/diagnostics to understand code quality issues
|
|
18
|
+
|
|
19
|
+
3. Provide code examples and references when helpful, citing specific file paths and line numbers.
|
|
20
|
+
|
|
21
|
+
4. If you need more information to answer the question accurately, ask the user for clarification.
|
|
22
|
+
|
|
23
|
+
5. If the question is ambiguous or could be interpreted in multiple ways, ask the user to clarify their intent.
|
|
24
|
+
|
|
25
|
+
6. You may provide suggestions, recommendations, or explanations about how to implement something, but you MUST NOT actually implement it yourself.
|
|
26
|
+
|
|
27
|
+
7. Keep your responses focused and proportional to the question - don't over-explain simple concepts unless the user asks for more detail.
|
|
28
|
+
|
|
29
|
+
8. If the user asks you to make changes or implement something, politely remind them that you're in Ask mode and can only provide information and guidance. Suggest they switch to Agent mode if they want you to make changes.
|
|
30
|
+
</system_reminder>
|
|
@@ -57,7 +57,7 @@ Available subagent_types and a quick description of what they do:
|
|
|
57
57
|
- browser-use: Perform browser-based testing and web automation. This subagent can navigate web pages, interact with elements, fill forms, and take screenshots. Use this for testing web applications, verifying UI changes, or any browser-based tasks. Use this browser subagent when you need to either: (1) parallelize browser tasks alongside other work, or (2) execute a longer sequence of browser actions that benefit from dedicated context. This subagent_type is stateful; if a browserUse subagent already exists, the previously created subagent will be resumed if you reuse the Task tool with subagent_type set to browserUse. (Auto-resumes most recent agent of this type; `resume` arg is ignored)
|
|
58
58
|
|
|
59
59
|
Available models:
|
|
60
|
-
- fast
|
|
60
|
+
- fast: Uses the parent model with thinking effort set to low (same model, lower thinking).
|
|
61
61
|
|
|
62
62
|
When speaking to the USER about which model you selected for a Task/subagent, do NOT reveal these internal model alias names (e.g., fast, alpha, beta, gamma). Instead, use natural language such as "a faster model", "a more capable model", or "the default model".
|
|
63
63
|
|
package/dist/tools/subagent.js
CHANGED
|
@@ -12,10 +12,9 @@ const SUBAGENTS_DIRNAME = ".pi/subagents";
|
|
|
12
12
|
const SUBAGENT_ID_PATTERN = /^[a-zA-Z0-9._-]+$/;
|
|
13
13
|
const MAX_PARALLEL_TASKS = 8;
|
|
14
14
|
const MAX_CONCURRENCY = 4;
|
|
15
|
-
const FAST_MODEL_HINTS = ["haiku", "flash", "mini", "small", "nano", "lite", "fast", "instant", "spark"];
|
|
16
15
|
const BUILTIN_SUBAGENT_TYPES = ["generalPurpose", "explore", "shell", "browser-use"];
|
|
17
16
|
const modelAliasSchema = Type.Union([Type.Literal("fast")], {
|
|
18
|
-
description: 'Optional model alias. If not provided, inherits from parent/model profile.
|
|
17
|
+
description: 'Optional model alias. If not provided, inherits from parent/model profile. "fast" runs the parent model with thinking effort set to low.',
|
|
19
18
|
});
|
|
20
19
|
const subagentTypeSchema = Type.Union([
|
|
21
20
|
Type.Literal("generalPurpose"),
|
|
@@ -240,39 +239,16 @@ function listModelCandidates(ctx) {
|
|
|
240
239
|
return [...availableModels];
|
|
241
240
|
return [...ctx.modelRegistry.getAll()];
|
|
242
241
|
}
|
|
243
|
-
function scoreFastCandidate(model, preferredProvider) {
|
|
244
|
-
const haystack = `${model.id} ${model.name ?? ""}`.toLowerCase();
|
|
245
|
-
let score = 0;
|
|
246
|
-
if (preferredProvider && model.provider === preferredProvider)
|
|
247
|
-
score += 20;
|
|
248
|
-
if (FAST_MODEL_HINTS.some((hint) => haystack.includes(hint)))
|
|
249
|
-
score += 100;
|
|
250
|
-
if (haystack.includes("opus") || haystack.includes("sonnet") || haystack.includes("pro"))
|
|
251
|
-
score -= 15;
|
|
252
|
-
if (haystack.includes("gpt-4") || haystack.includes("gpt-5"))
|
|
253
|
-
score -= 10;
|
|
254
|
-
return score;
|
|
255
|
-
}
|
|
256
242
|
function pickInheritedModel(ctx) {
|
|
257
243
|
if (!ctx.model)
|
|
258
244
|
return undefined;
|
|
259
245
|
return { provider: ctx.model.provider, modelId: ctx.model.id };
|
|
260
246
|
}
|
|
261
|
-
function
|
|
262
|
-
const
|
|
263
|
-
if (
|
|
247
|
+
function pickLowThinkingModel(ctx) {
|
|
248
|
+
const inherited = pickInheritedModel(ctx);
|
|
249
|
+
if (!inherited)
|
|
264
250
|
return undefined;
|
|
265
|
-
|
|
266
|
-
candidates.sort((a, b) => {
|
|
267
|
-
const scoreDiff = scoreFastCandidate(b, preferredProvider) - scoreFastCandidate(a, preferredProvider);
|
|
268
|
-
if (scoreDiff !== 0)
|
|
269
|
-
return scoreDiff;
|
|
270
|
-
if (a.provider !== b.provider)
|
|
271
|
-
return a.provider.localeCompare(b.provider);
|
|
272
|
-
return a.id.localeCompare(b.id);
|
|
273
|
-
});
|
|
274
|
-
const picked = candidates[0];
|
|
275
|
-
return { provider: picked.provider, modelId: picked.id };
|
|
251
|
+
return { ...inherited, thinking: "low" };
|
|
276
252
|
}
|
|
277
253
|
function pickModelBySpec(ctx, spec) {
|
|
278
254
|
const normalized = spec.trim();
|
|
@@ -282,7 +258,7 @@ function pickModelBySpec(ctx, spec) {
|
|
|
282
258
|
if (lowered === "inherit")
|
|
283
259
|
return pickInheritedModel(ctx);
|
|
284
260
|
if (lowered === "fast")
|
|
285
|
-
return
|
|
261
|
+
return pickLowThinkingModel(ctx) ?? pickInheritedModel(ctx);
|
|
286
262
|
const slashIndex = normalized.indexOf("/");
|
|
287
263
|
if (slashIndex > 0) {
|
|
288
264
|
const provider = normalized.slice(0, slashIndex);
|
|
@@ -303,7 +279,7 @@ function pickModelBySpec(ctx, spec) {
|
|
|
303
279
|
}
|
|
304
280
|
function selectModelForTask(ctx, explicitAlias, profileModelSpec) {
|
|
305
281
|
if (explicitAlias === "fast") {
|
|
306
|
-
return
|
|
282
|
+
return pickLowThinkingModel(ctx) ?? pickInheritedModel(ctx);
|
|
307
283
|
}
|
|
308
284
|
if (profileModelSpec) {
|
|
309
285
|
return pickModelBySpec(ctx, profileModelSpec) ?? pickInheritedModel(ctx);
|
|
@@ -748,6 +724,9 @@ async function executeTask(task, index, options) {
|
|
|
748
724
|
];
|
|
749
725
|
if (selectedModel) {
|
|
750
726
|
args.push("--provider", selectedModel.provider, "--model", selectedModel.modelId);
|
|
727
|
+
if (selectedModel.thinking === "low") {
|
|
728
|
+
args.push("--thinking", "low");
|
|
729
|
+
}
|
|
751
730
|
}
|
|
752
731
|
for (const attachment of attachments) {
|
|
753
732
|
args.push(`@${attachment}`);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
|
|
2
2
|
import { Type } from "@sinclair/typebox";
|
|
3
3
|
import { createModeStateData, deriveInitialModeState, hasMessageEntries, modeRuntimeStore, MODE_STATE_ENTRY_TYPE, parseModeStateEntry, } from "../src/extensions/mode-runtime.js";
|
|
4
|
-
const MODE_HINT_MESSAGE_TYPE = "
|
|
4
|
+
const MODE_HINT_MESSAGE_TYPE = "Hints";
|
|
5
5
|
const MODE_STATUS_KEY = "mono-pilot-mode";
|
|
6
6
|
const DESCRIPTION = `Switch the interaction mode to better match the current task. Each mode is optimized for a specific type of work.
|
|
7
7
|
|
|
@@ -252,7 +252,11 @@ function updateModeStatus(ctx) {
|
|
|
252
252
|
if (!ctx.hasUI)
|
|
253
253
|
return;
|
|
254
254
|
const { activeMode } = modeRuntimeStore.getSnapshot();
|
|
255
|
-
const statusText = activeMode === "plan"
|
|
255
|
+
const statusText = activeMode === "plan"
|
|
256
|
+
? ctx.ui.theme.fg("warning", "mode:plan")
|
|
257
|
+
: activeMode === "ask"
|
|
258
|
+
? ctx.ui.theme.fg("borderAccent", "mode:ask")
|
|
259
|
+
: ctx.ui.theme.fg("muted", "mode:agent");
|
|
256
260
|
ctx.ui.setStatus(MODE_STATUS_KEY, statusText);
|
|
257
261
|
}
|
|
258
262
|
function persistModeState(pi) {
|
|
@@ -273,7 +277,8 @@ function togglePlanMode(pi, ctx) {
|
|
|
273
277
|
persistModeState(pi);
|
|
274
278
|
updateModeStatus(ctx);
|
|
275
279
|
if (ctx.hasUI) {
|
|
276
|
-
|
|
280
|
+
const label = snapshot.activeMode === "plan" ? "Plan" : snapshot.activeMode === "ask" ? "Ask" : "Agent";
|
|
281
|
+
ctx.ui.notify(`Switched to ${label} mode.`);
|
|
277
282
|
}
|
|
278
283
|
}
|
|
279
284
|
export default function switchModeExtension(pi) {
|
|
@@ -282,9 +287,11 @@ export default function switchModeExtension(pi) {
|
|
|
282
287
|
type: "boolean",
|
|
283
288
|
default: false,
|
|
284
289
|
});
|
|
285
|
-
pi.
|
|
286
|
-
description: "
|
|
287
|
-
handler: async (
|
|
290
|
+
pi.registerShortcut("alt+m", {
|
|
291
|
+
description: "Cycle between Plan, Ask, and Agent modes",
|
|
292
|
+
handler: async (ctx) => {
|
|
293
|
+
togglePlanMode(pi, ctx);
|
|
294
|
+
}
|
|
288
295
|
});
|
|
289
296
|
pi.on("session_start", async (_event, ctx) => {
|
|
290
297
|
const fromFlag = pi.getFlag("plan") === true;
|
|
@@ -307,7 +314,7 @@ export default function switchModeExtension(pi) {
|
|
|
307
314
|
if (ctx.hasUI && !hasMessageEntries(entries)) {
|
|
308
315
|
pi.sendMessage({
|
|
309
316
|
customType: MODE_HINT_MESSAGE_TYPE,
|
|
310
|
-
content: "Mode switch: use
|
|
317
|
+
content: "Mode switch: use `option+m` to toggle Plan/Ask/Agent mode.",
|
|
311
318
|
display: true,
|
|
312
319
|
}, { triggerTurn: false });
|
|
313
320
|
}
|