pi-ultracode 0.4.0 → 0.6.0
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 +26 -10
- package/README.zh-CN.md +26 -10
- package/extensions/ultracode.ts +18 -85
- package/package.json +2 -2
- package/src/commands.ts +26 -24
- package/src/depth.ts +37 -0
- package/src/index.ts +8 -0
- package/src/mode.ts +81 -407
- package/src/prompts.ts +65 -31
- package/src/thinking.ts +2 -2
- package/src/workflow/runtime.ts +3 -3
- package/src/workflow/tool.ts +6 -7
package/src/mode.ts
CHANGED
|
@@ -1,45 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Ultracode mode controller.
|
|
3
3
|
*
|
|
4
|
-
* Ultracode is a session-scoped
|
|
5
|
-
* -
|
|
4
|
+
* Ultracode is a session-scoped semantic analysis-depth mode. While active, it:
|
|
5
|
+
* - leaves the parent session's thinking level under user control,
|
|
6
6
|
* - keeps the `workflow` tool active,
|
|
7
|
-
* - injects
|
|
8
|
-
*
|
|
9
|
-
* - persists its on/off state in session custom entries so it survives
|
|
10
|
-
* reload, resume, fork, and compaction.
|
|
7
|
+
* - injects the configured auto/focused/standard/deep policy on every turn,
|
|
8
|
+
* - persists branch-local mode state across reload, resume, fork, and compaction.
|
|
11
9
|
*/
|
|
12
10
|
|
|
13
11
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
14
|
-
import { ULTRACODE_ACTIVE_REMINDER, ULTRACODE_TAGLINE, ultracodeSystemBlock } from "./prompts.ts";
|
|
15
12
|
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
} from "./
|
|
13
|
+
isActiveUltracodeMode,
|
|
14
|
+
type ActiveUltracodeMode,
|
|
15
|
+
type UltracodeModeName,
|
|
16
|
+
} from "./depth.ts";
|
|
17
|
+
import { ULTRACODE_ACTIVE_REMINDER, ULTRACODE_TAGLINE, ultracodeSystemBlock } from "./prompts.ts";
|
|
18
|
+
import type { ThinkingLevel } from "./thinking.ts";
|
|
21
19
|
|
|
22
20
|
export type { ThinkingLevel } from "./thinking.ts";
|
|
23
21
|
|
|
24
22
|
export const MODE_ENTRY_TYPE = "ultracode-mode";
|
|
25
23
|
|
|
26
24
|
interface PersistedModeState {
|
|
27
|
-
|
|
28
|
-
previousThinking?: ThinkingLevel;
|
|
29
|
-
/** `null` records that the setting was originally absent (Pi defaults to medium). */
|
|
30
|
-
previousDefaultThinking?: ThinkingLevel | null;
|
|
31
|
-
/** Deferred when the selected model cannot represent the pre-mode level. */
|
|
32
|
-
pendingPreviousThinking?: ThinkingLevel;
|
|
25
|
+
mode: UltracodeModeName;
|
|
33
26
|
}
|
|
34
27
|
|
|
28
|
+
/** @deprecated Ultracode no longer reads or writes the parent's effort preference. */
|
|
35
29
|
export interface ThinkingPreferenceSnapshot {
|
|
36
|
-
/** Raw global value; undefined means Pi's implicit medium default. */
|
|
37
30
|
global: ThinkingLevel | undefined;
|
|
38
|
-
/** Global + project merged value used by Pi for model switches. */
|
|
39
31
|
effective: ThinkingLevel | undefined;
|
|
40
32
|
}
|
|
41
33
|
|
|
42
|
-
/**
|
|
34
|
+
/** @deprecated Ultracode no longer reads or writes the parent's effort preference. */
|
|
43
35
|
export interface ThinkingPreferenceStore {
|
|
44
36
|
getThinkingPreference(): ThinkingPreferenceSnapshot;
|
|
45
37
|
setDefaultThinkingLevel(level: ThinkingLevel | undefined): void | Promise<void>;
|
|
@@ -47,149 +39,95 @@ export interface ThinkingPreferenceStore {
|
|
|
47
39
|
}
|
|
48
40
|
|
|
49
41
|
export class UltracodeMode {
|
|
50
|
-
private
|
|
42
|
+
private mode: UltracodeModeName = "off";
|
|
51
43
|
private suspended = false;
|
|
52
|
-
private previousThinking: ThinkingLevel | undefined;
|
|
53
|
-
private previousDefaultThinking: ThinkingLevel | null | undefined;
|
|
54
|
-
/** Restore a level later if the current non-reasoning model clamps it to off. */
|
|
55
|
-
private pendingPreviousThinking: ThinkingLevel | undefined;
|
|
56
|
-
/** The level Pi actually applied after clamping the maximum request. */
|
|
57
|
-
private appliedThinking: ThinkingLevel | undefined;
|
|
58
|
-
/** Prevent mode-owned thinking changes from being mistaken for manual overrides. */
|
|
59
|
-
private applyingThinking = false;
|
|
60
|
-
private thinkingPreferenceStore: ThinkingPreferenceStore | undefined;
|
|
61
|
-
private preferenceWriteQueue: Promise<void> = Promise.resolve();
|
|
62
|
-
private preferenceWriteGeneration = 0;
|
|
63
|
-
private legacyDefaultMigrationPending = false;
|
|
64
|
-
private pendingClearGeneration = 0;
|
|
65
|
-
private currentModelSupportsThinking: boolean | undefined;
|
|
66
|
-
private runtimeSupportsMaxThinking = true;
|
|
67
44
|
private readonly workflowToolName: string;
|
|
68
45
|
|
|
69
46
|
constructor(workflowToolName: string) {
|
|
70
47
|
this.workflowToolName = workflowToolName;
|
|
71
48
|
}
|
|
72
49
|
|
|
73
|
-
/**
|
|
74
|
-
bindThinkingPreferenceStore(
|
|
75
|
-
this.preferenceWriteGeneration++;
|
|
76
|
-
this.thinkingPreferenceStore = store;
|
|
77
|
-
}
|
|
50
|
+
/** @deprecated Parent effort is user-owned; retained as a compatibility no-op. */
|
|
51
|
+
bindThinkingPreferenceStore(_store: ThinkingPreferenceStore | undefined): void {}
|
|
78
52
|
|
|
79
|
-
/**
|
|
80
|
-
setCurrentModelSupportsThinking(
|
|
81
|
-
this.currentModelSupportsThinking = supportsThinking;
|
|
82
|
-
}
|
|
53
|
+
/** @deprecated Parent effort is user-owned; retained as a compatibility no-op. */
|
|
54
|
+
setCurrentModelSupportsThinking(_supportsThinking: boolean | undefined): void {}
|
|
83
55
|
|
|
84
|
-
/**
|
|
85
|
-
setRuntimeSupportsMaxThinking(
|
|
86
|
-
this.runtimeSupportsMaxThinking = supportsMaxThinking;
|
|
87
|
-
}
|
|
56
|
+
/** @deprecated Parent effort is user-owned; retained as a compatibility no-op. */
|
|
57
|
+
setRuntimeSupportsMaxThinking(_supportsMaxThinking: boolean): void {}
|
|
88
58
|
|
|
89
|
-
/**
|
|
90
|
-
async flushThinkingPreference(): Promise<void> {
|
|
91
|
-
try {
|
|
92
|
-
await this.preferenceWriteQueue;
|
|
93
|
-
} catch {
|
|
94
|
-
// Pi owns settings error reporting; effort enforcement must remain usable.
|
|
95
|
-
}
|
|
96
|
-
}
|
|
59
|
+
/** @deprecated Parent effort is user-owned; retained as a compatibility no-op. */
|
|
60
|
+
async flushThinkingPreference(): Promise<void> {}
|
|
97
61
|
|
|
98
|
-
/** Enable if off, disable
|
|
62
|
+
/** Enable auto if off, otherwise disable. Returns the new enabled state. */
|
|
99
63
|
toggle(pi: ExtensionAPI): boolean {
|
|
100
|
-
if (this.
|
|
64
|
+
if (this.isEnabled()) {
|
|
101
65
|
this.disable(pi);
|
|
102
66
|
return false;
|
|
103
67
|
}
|
|
104
|
-
this.enable(pi);
|
|
68
|
+
this.enable(pi, "auto");
|
|
105
69
|
return true;
|
|
106
70
|
}
|
|
107
71
|
|
|
108
|
-
|
|
72
|
+
getMode(): UltracodeModeName {
|
|
73
|
+
return this.mode;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** @deprecated Ultracode no longer applies a parent thinking level. */
|
|
109
77
|
getAppliedThinking(): ThinkingLevel | undefined {
|
|
110
|
-
return
|
|
78
|
+
return undefined;
|
|
111
79
|
}
|
|
112
80
|
|
|
113
81
|
/**
|
|
114
|
-
*
|
|
115
|
-
*
|
|
82
|
+
* @deprecated Workflow agents now select effort per call. An omitted suffix
|
|
83
|
+
* falls back to the child Pi session's normal user/model configuration rather
|
|
84
|
+
* than a mode-owned default.
|
|
116
85
|
*/
|
|
117
86
|
getSubagentThinkingLevel(): ThinkingLevel | undefined {
|
|
118
|
-
return
|
|
87
|
+
return undefined;
|
|
119
88
|
}
|
|
120
89
|
|
|
121
|
-
/**
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
this.applyUltracodeThinking(pi);
|
|
125
|
-
return true;
|
|
90
|
+
/** @deprecated Parent effort is user-owned; retained as a compatibility no-op. */
|
|
91
|
+
reapplyConfiguredThinking(_pi: ExtensionAPI): boolean {
|
|
92
|
+
return false;
|
|
126
93
|
}
|
|
127
94
|
|
|
128
|
-
/**
|
|
129
|
-
|
|
130
|
-
* Returns true when Ultracode remains active and the UI should be refreshed.
|
|
131
|
-
*/
|
|
132
|
-
handleModelSelect(pi: ExtensionAPI): boolean {
|
|
133
|
-
if (this.suspended) return false;
|
|
134
|
-
this.pendingClearGeneration++;
|
|
135
|
-
if (this.enabled) {
|
|
136
|
-
this.applyUltracodeThinking(pi);
|
|
137
|
-
return true;
|
|
138
|
-
}
|
|
139
|
-
if (this.pendingPreviousThinking) {
|
|
140
|
-
const pending = this.pendingPreviousThinking;
|
|
141
|
-
this.applyCompatibleThinking(pi, pending);
|
|
142
|
-
if (this.pendingRestoreSucceeded(pending)) this.pendingPreviousThinking = undefined;
|
|
143
|
-
this.persist(pi);
|
|
144
|
-
}
|
|
95
|
+
/** @deprecated Parent effort is user-owned; retained as a compatibility no-op. */
|
|
96
|
+
reapplyMaximumThinking(_pi: ExtensionAPI): boolean {
|
|
145
97
|
return false;
|
|
146
98
|
}
|
|
147
99
|
|
|
148
|
-
/**
|
|
149
|
-
|
|
150
|
-
|
|
100
|
+
/** @deprecated Model changes do not alter Ultracode mode or parent effort. */
|
|
101
|
+
handleModelSelect(_pi: ExtensionAPI): boolean {
|
|
102
|
+
return false;
|
|
151
103
|
}
|
|
152
104
|
|
|
153
|
-
/**
|
|
105
|
+
/** @deprecated Parent effort is never restored because Ultracode never changes it. */
|
|
106
|
+
restorePreviousThinking(_pi: ExtensionAPI): void {}
|
|
107
|
+
|
|
108
|
+
/** Quiesce tool and prompt enforcement before session teardown. */
|
|
154
109
|
suspend(pi: ExtensionAPI): void {
|
|
155
110
|
if (this.suspended) {
|
|
156
111
|
this.syncWorkflowTool(pi);
|
|
157
112
|
return;
|
|
158
113
|
}
|
|
159
114
|
this.suspended = true;
|
|
160
|
-
this.restorePreviousThinking(pi);
|
|
161
115
|
this.syncWorkflowTool(pi);
|
|
162
116
|
}
|
|
163
117
|
|
|
164
|
-
/**
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
* Returns true when a manual selection was overridden.
|
|
168
|
-
*/
|
|
169
|
-
handleThinkingLevelSelect(pi: ExtensionAPI, level: ThinkingLevel): boolean {
|
|
170
|
-
if (this.suspended || this.applyingThinking) return false;
|
|
171
|
-
const current = safeGetThinking(pi);
|
|
172
|
-
if (!current || current !== level) return false;
|
|
173
|
-
if (!this.enabled) {
|
|
174
|
-
// Pi emits the same event for a user selection and an automatic model
|
|
175
|
-
// re-clamp. Defer clearing until model_select has had a chance to consume it.
|
|
176
|
-
if (this.pendingPreviousThinking) this.deferPendingClear(pi, level);
|
|
177
|
-
return false;
|
|
178
|
-
}
|
|
179
|
-
if (current === this.appliedThinking) return false;
|
|
180
|
-
this.applyUltracodeThinking(pi);
|
|
181
|
-
return true;
|
|
118
|
+
/** @deprecated User-selected parent effort is accepted without interception. */
|
|
119
|
+
handleThinkingLevelSelect(_pi: ExtensionAPI, _level: ThinkingLevel): boolean {
|
|
120
|
+
return false;
|
|
182
121
|
}
|
|
183
122
|
|
|
184
123
|
isEnabled(): boolean {
|
|
185
|
-
return this.
|
|
124
|
+
return this.mode !== "off";
|
|
186
125
|
}
|
|
187
126
|
|
|
188
127
|
isSuspended(): boolean {
|
|
189
128
|
return this.suspended;
|
|
190
129
|
}
|
|
191
130
|
|
|
192
|
-
|
|
193
131
|
/** Keep tool availability aligned with the current mode state. */
|
|
194
132
|
syncWorkflowTool(pi: ExtensionAPI): void {
|
|
195
133
|
if (this.isEnforcing()) this.activateWorkflowTool(pi);
|
|
@@ -200,55 +138,31 @@ export class UltracodeMode {
|
|
|
200
138
|
return ULTRACODE_TAGLINE;
|
|
201
139
|
}
|
|
202
140
|
|
|
203
|
-
/**
|
|
204
|
-
|
|
141
|
+
/**
|
|
142
|
+
* Enable or switch modes. The no-argument form retains the pre-0.5
|
|
143
|
+
* programmatic deep behavior; user commands pass an explicit mode and bare
|
|
144
|
+
* `/ultracode` uses toggle() to enter auto.
|
|
145
|
+
*/
|
|
146
|
+
enable(pi: ExtensionAPI, mode: ActiveUltracodeMode = "deep"): void {
|
|
205
147
|
this.suspended = false;
|
|
206
|
-
this.
|
|
207
|
-
this.pendingClearGeneration++;
|
|
208
|
-
if (!this.enabled) {
|
|
209
|
-
const current = safeGetThinking(pi);
|
|
210
|
-
const preference = this.captureThinkingPreference();
|
|
211
|
-
const effectivePreference = this.runtimeCompatibleThinking(preference.effective) as
|
|
212
|
-
| ThinkingLevel
|
|
213
|
-
| undefined;
|
|
214
|
-
const maxIsUnknownToRuntime = !this.runtimeSupportsMaxThinking
|
|
215
|
-
&& preference.effective === ULTRACODE_THINKING_LEVEL;
|
|
216
|
-
// A non-reasoning model exposes only `off`; preserve the merged default
|
|
217
|
-
// that Pi would use when the user later selects a reasoning model. A
|
|
218
|
-
// pre-max Pi also reports a persisted max preference as off.
|
|
219
|
-
this.previousThinking = current === "off"
|
|
220
|
-
&& (this.currentModelSupportsThinking !== true || maxIsUnknownToRuntime)
|
|
221
|
-
? effectivePreference ?? current
|
|
222
|
-
: current;
|
|
223
|
-
this.previousDefaultThinking = this.runtimeCompatibleThinking(preference.global);
|
|
224
|
-
this.legacyDefaultMigrationPending = false;
|
|
225
|
-
this.enabled = true;
|
|
226
|
-
}
|
|
227
|
-
this.applyUltracodeThinking(pi);
|
|
148
|
+
this.mode = mode;
|
|
228
149
|
this.syncWorkflowTool(pi);
|
|
229
150
|
this.persist(pi);
|
|
230
151
|
}
|
|
231
152
|
|
|
232
|
-
/** Turn
|
|
153
|
+
/** Turn Ultracode off without changing the parent thinking level. */
|
|
233
154
|
disable(pi: ExtensionAPI): void {
|
|
234
|
-
if (!this.
|
|
155
|
+
if (!this.isEnabled()) {
|
|
235
156
|
this.syncWorkflowTool(pi);
|
|
236
157
|
return;
|
|
237
158
|
}
|
|
238
|
-
|
|
239
|
-
this.restorePreviousThinking(pi);
|
|
240
|
-
this.pendingPreviousThinking = previous && !this.pendingRestoreSucceeded(previous)
|
|
241
|
-
? previous
|
|
242
|
-
: undefined;
|
|
243
|
-
this.pendingClearGeneration++;
|
|
244
|
-
this.enabled = false;
|
|
159
|
+
this.mode = "off";
|
|
245
160
|
this.suspended = false;
|
|
246
161
|
this.syncWorkflowTool(pi);
|
|
247
162
|
this.persist(pi);
|
|
248
163
|
}
|
|
249
164
|
|
|
250
|
-
|
|
251
|
-
/** Restore mode state from the active session branch. */
|
|
165
|
+
/** Restore mode state from the active session branch without touching effort. */
|
|
252
166
|
restore(
|
|
253
167
|
pi: ExtensionAPI,
|
|
254
168
|
entries: Array<{
|
|
@@ -258,250 +172,31 @@ export class UltracodeMode {
|
|
|
258
172
|
thinkingLevel?: unknown;
|
|
259
173
|
}>,
|
|
260
174
|
): void {
|
|
261
|
-
const wasEnforcing = this.isEnforcing();
|
|
262
|
-
this.pendingClearGeneration++;
|
|
263
175
|
let latestData: unknown;
|
|
264
|
-
let branchThinking: ThinkingLevel | undefined;
|
|
265
|
-
let thinkingAfterLatestMode: ThinkingLevel | undefined;
|
|
266
176
|
for (const entry of entries) {
|
|
267
177
|
if (entry.type === "custom" && entry.customType === MODE_ENTRY_TYPE && entry.data) {
|
|
268
178
|
latestData = entry.data;
|
|
269
|
-
thinkingAfterLatestMode = undefined;
|
|
270
|
-
} else if (entry.type === "thinking_level_change" && isThinkingLevel(entry.thinkingLevel)) {
|
|
271
|
-
branchThinking = entry.thinkingLevel;
|
|
272
|
-
if (latestData !== undefined) thinkingAfterLatestMode = entry.thinkingLevel;
|
|
273
179
|
}
|
|
274
180
|
}
|
|
275
181
|
|
|
276
|
-
|
|
277
|
-
const preference = this.captureThinkingPreference();
|
|
278
|
-
const effectivePreference = this.runtimeCompatibleThinking(preference.effective) as
|
|
279
|
-
| ThinkingLevel
|
|
280
|
-
| undefined;
|
|
281
|
-
const globalPreference = this.runtimeCompatibleThinking(preference.global);
|
|
282
|
-
const latest = parsePersistedModeState(latestData);
|
|
283
|
-
if (!latest) {
|
|
284
|
-
const target = this.runtimeCompatibleThinking(
|
|
285
|
-
branchThinking
|
|
286
|
-
?? (wasEnforcing ? this.previousThinking : undefined)
|
|
287
|
-
?? effectivePreference,
|
|
288
|
-
) as ThinkingLevel | undefined;
|
|
289
|
-
this.enabled = false;
|
|
290
|
-
this.suspended = false;
|
|
291
|
-
this.pendingPreviousThinking = undefined;
|
|
292
|
-
this.previousThinking = target;
|
|
293
|
-
this.previousDefaultThinking = globalPreference;
|
|
294
|
-
this.legacyDefaultMigrationPending = false;
|
|
295
|
-
this.appliedThinking = current;
|
|
296
|
-
this.syncWorkflowTool(pi);
|
|
297
|
-
if (target && current !== target) this.applyCompatibleThinking(pi, target);
|
|
298
|
-
if (target && !this.pendingRestoreSucceeded(target)) {
|
|
299
|
-
this.pendingPreviousThinking = target;
|
|
300
|
-
this.persist(pi);
|
|
301
|
-
} else {
|
|
302
|
-
this.previousThinking = undefined;
|
|
303
|
-
this.previousDefaultThinking = undefined;
|
|
304
|
-
}
|
|
305
|
-
return;
|
|
306
|
-
}
|
|
307
|
-
|
|
182
|
+
this.mode = parsePersistedModeState(latestData)?.mode ?? "off";
|
|
308
183
|
this.suspended = false;
|
|
309
|
-
this.enabled = latest.enabled;
|
|
310
184
|
this.syncWorkflowTool(pi);
|
|
311
|
-
const maxIsUnknownToRuntime = !this.runtimeSupportsMaxThinking
|
|
312
|
-
&& preference.effective === ULTRACODE_THINKING_LEVEL;
|
|
313
|
-
this.previousThinking = latest.previousThinking
|
|
314
|
-
?? (current === "off"
|
|
315
|
-
&& (this.currentModelSupportsThinking !== true || maxIsUnknownToRuntime)
|
|
316
|
-
? effectivePreference ?? current
|
|
317
|
-
: current);
|
|
318
|
-
|
|
319
|
-
// Pre-preference-store releases persisted only previousThinking while their
|
|
320
|
-
// active xhigh request polluted Pi's global default. Recover that baseline
|
|
321
|
-
// once instead of treating the known Ultracode value as a user preference.
|
|
322
|
-
const migratesLegacyDefault = latest.enabled
|
|
323
|
-
&& latest.previousDefaultThinking === undefined
|
|
324
|
-
&& latest.previousThinking !== undefined
|
|
325
|
-
&& (preference.global === LEGACY_ULTRACODE_THINKING_LEVEL
|
|
326
|
-
|| preference.global === ULTRACODE_THINKING_LEVEL);
|
|
327
|
-
this.previousDefaultThinking = migratesLegacyDefault
|
|
328
|
-
? this.runtimeCompatibleThinking(latest.previousThinking)
|
|
329
|
-
: preference.global !== undefined
|
|
330
|
-
? globalPreference
|
|
331
|
-
: this.runtimeCompatibleThinking(latest.previousDefaultThinking);
|
|
332
|
-
this.legacyDefaultMigrationPending = migratesLegacyDefault;
|
|
333
|
-
|
|
334
|
-
this.pendingPreviousThinking = this.enabled ? undefined : latest.pendingPreviousThinking;
|
|
335
|
-
if (this.enabled) {
|
|
336
|
-
this.applyUltracodeThinking(pi);
|
|
337
|
-
if (migratesLegacyDefault) {
|
|
338
|
-
this.queueDefaultThinkingRestore(() => {
|
|
339
|
-
this.legacyDefaultMigrationPending = false;
|
|
340
|
-
this.persist(pi);
|
|
341
|
-
});
|
|
342
|
-
}
|
|
343
|
-
return;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
if (this.pendingPreviousThinking) {
|
|
347
|
-
if (thinkingAfterLatestMode !== undefined) {
|
|
348
|
-
// A thinking entry after the disabled mode snapshot is an explicit user
|
|
349
|
-
// choice and supersedes the older deferred restoration.
|
|
350
|
-
const target = this.runtimeCompatibleThinking(thinkingAfterLatestMode) as ThinkingLevel;
|
|
351
|
-
this.pendingPreviousThinking = undefined;
|
|
352
|
-
this.previousThinking = target;
|
|
353
|
-
this.appliedThinking = current;
|
|
354
|
-
if (current !== target) this.applyCompatibleThinking(pi, target);
|
|
355
|
-
if (!this.pendingRestoreSucceeded(target)) this.pendingPreviousThinking = target;
|
|
356
|
-
this.persist(pi);
|
|
357
|
-
} else if (this.currentModelSupportsThinking === true) {
|
|
358
|
-
const pending = this.pendingPreviousThinking;
|
|
359
|
-
this.applyCompatibleThinking(pi, pending);
|
|
360
|
-
if (this.pendingRestoreSucceeded(pending)) this.pendingPreviousThinking = undefined;
|
|
361
|
-
this.persist(pi);
|
|
362
|
-
}
|
|
363
|
-
return;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
const target = this.runtimeCompatibleThinking(branchThinking ?? latest.previousThinking) as
|
|
367
|
-
| ThinkingLevel
|
|
368
|
-
| undefined;
|
|
369
|
-
this.appliedThinking = current;
|
|
370
|
-
if (target && current !== target) this.applyCompatibleThinking(pi, target);
|
|
371
|
-
if (target && !this.pendingRestoreSucceeded(target)) {
|
|
372
|
-
this.pendingPreviousThinking = target;
|
|
373
|
-
this.persist(pi);
|
|
374
|
-
}
|
|
375
185
|
}
|
|
376
186
|
|
|
377
|
-
/**
|
|
378
|
-
* Build the before_agent_start result: appends the ultracode system block to the
|
|
379
|
-
* turn's system prompt when enabled.
|
|
380
|
-
*/
|
|
187
|
+
/** Append the configured semantic-depth policy to the turn's system prompt. */
|
|
381
188
|
beforeAgentStart(event: { systemPrompt: string }): { systemPrompt: string } | undefined {
|
|
382
|
-
if (!this.isEnforcing()) return undefined;
|
|
383
|
-
const block = ultracodeSystemBlock();
|
|
189
|
+
if (!this.isEnforcing() || !isActiveUltracodeMode(this.mode)) return undefined;
|
|
190
|
+
const block = ultracodeSystemBlock(this.mode);
|
|
384
191
|
return { systemPrompt: `${event.systemPrompt}\n\n${block}\n\n${ULTRACODE_ACTIVE_REMINDER}` };
|
|
385
192
|
}
|
|
386
193
|
|
|
387
|
-
statusLine(): string {
|
|
388
|
-
|
|
389
|
-
const parts = ["ultracode: on"];
|
|
390
|
-
// Show the level that actually applied, including compatibility/model fallback.
|
|
391
|
-
if (this.appliedThinking) parts.push(this.appliedThinking);
|
|
392
|
-
return parts.join(" · ");
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
private applyUltracodeThinking(pi: ExtensionAPI): void {
|
|
396
|
-
const writeGeneration = this.preferenceWriteGeneration;
|
|
397
|
-
this.applyCompatibleThinking(pi, ULTRACODE_THINKING_LEVEL);
|
|
398
|
-
// Pi normally skips persistence when the effective level is unchanged, but
|
|
399
|
-
// the extension API does not promise that. Defensively restore the raw
|
|
400
|
-
// baseline even after a stable max -> max request.
|
|
401
|
-
if (writeGeneration === this.preferenceWriteGeneration) {
|
|
402
|
-
this.queueDefaultThinkingRestore();
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
/** Apply max compatibly and return the concrete level accepted as success. */
|
|
407
|
-
private applyCompatibleThinking(pi: ExtensionAPI, level: ThinkingLevel): ThinkingLevel {
|
|
408
|
-
this.applyThinking(pi, level);
|
|
409
|
-
if (level === ULTRACODE_THINKING_LEVEL && this.appliedThinking !== level) {
|
|
410
|
-
// Modern Pi clamps max per model. Pre-max Pi may treat it as unknown, so
|
|
411
|
-
// retry xhigh for both activation and restoration of persisted max state.
|
|
412
|
-
this.applyThinking(pi, LEGACY_ULTRACODE_THINKING_LEVEL);
|
|
413
|
-
return LEGACY_ULTRACODE_THINKING_LEVEL;
|
|
414
|
-
}
|
|
415
|
-
return level;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
private applyThinking(pi: ExtensionAPI, level: ThinkingLevel): void {
|
|
419
|
-
const wasApplying = this.applyingThinking;
|
|
420
|
-
const before = safeGetThinking(pi);
|
|
421
|
-
this.applyingThinking = true;
|
|
422
|
-
try {
|
|
423
|
-
// Pi clamps the request and persists the effective level. Preference
|
|
424
|
-
// restoration is queued after Pi's own SettingsManager chain drains.
|
|
425
|
-
pi.setThinkingLevel(level as any);
|
|
426
|
-
this.appliedThinking = safeGetThinking(pi) ?? level;
|
|
427
|
-
} catch {
|
|
428
|
-
this.appliedThinking = safeGetThinking(pi);
|
|
429
|
-
} finally {
|
|
430
|
-
if (this.appliedThinking !== before) this.queueDefaultThinkingRestore();
|
|
431
|
-
this.applyingThinking = wasApplying;
|
|
432
|
-
}
|
|
194
|
+
statusLine(styleLabel: (label: string) => string = (label) => label): string {
|
|
195
|
+
return [styleLabel("ultracode"), this.mode].join(" · ");
|
|
433
196
|
}
|
|
434
197
|
|
|
435
198
|
isEnforcing(): boolean {
|
|
436
|
-
return this.
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
private pendingRestoreSucceeded(pending: ThinkingLevel): boolean {
|
|
440
|
-
if (this.appliedThinking === pending) return true;
|
|
441
|
-
return pending === ULTRACODE_THINKING_LEVEL
|
|
442
|
-
&& !this.runtimeSupportsMaxThinking
|
|
443
|
-
&& this.appliedThinking !== undefined
|
|
444
|
-
&& this.appliedThinking !== "off";
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
private runtimeCompatibleThinking(
|
|
448
|
-
level: ThinkingLevel | null | undefined,
|
|
449
|
-
): ThinkingLevel | null | undefined {
|
|
450
|
-
return level === ULTRACODE_THINKING_LEVEL && !this.runtimeSupportsMaxThinking
|
|
451
|
-
? LEGACY_ULTRACODE_THINKING_LEVEL
|
|
452
|
-
: level;
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
private captureThinkingPreference(): {
|
|
456
|
-
global: ThinkingLevel | null | undefined;
|
|
457
|
-
effective: ThinkingLevel | undefined;
|
|
458
|
-
} {
|
|
459
|
-
if (!this.thinkingPreferenceStore) return { global: undefined, effective: undefined };
|
|
460
|
-
try {
|
|
461
|
-
const preference = this.thinkingPreferenceStore.getThinkingPreference();
|
|
462
|
-
return {
|
|
463
|
-
global: isThinkingLevel(preference.global) ? preference.global : null,
|
|
464
|
-
effective: isThinkingLevel(preference.effective) ? preference.effective : undefined,
|
|
465
|
-
};
|
|
466
|
-
} catch {
|
|
467
|
-
return { global: undefined, effective: undefined };
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
private queueDefaultThinkingRestore(onSuccess?: () => void): void {
|
|
472
|
-
const store = this.thinkingPreferenceStore;
|
|
473
|
-
const baseline = this.runtimeCompatibleThinking(this.previousDefaultThinking);
|
|
474
|
-
if (!store || baseline === undefined) return;
|
|
475
|
-
const generation = ++this.preferenceWriteGeneration;
|
|
476
|
-
this.preferenceWriteQueue = this.preferenceWriteQueue
|
|
477
|
-
.catch(() => {})
|
|
478
|
-
.then(waitForSettingsWrites)
|
|
479
|
-
.then(async () => {
|
|
480
|
-
if (generation !== this.preferenceWriteGeneration) return;
|
|
481
|
-
const currentGlobal = this.captureThinkingPreference().global;
|
|
482
|
-
if (currentGlobal !== baseline) {
|
|
483
|
-
await store.setDefaultThinkingLevel(baseline ?? undefined);
|
|
484
|
-
await store.flush?.();
|
|
485
|
-
}
|
|
486
|
-
if (generation === this.preferenceWriteGeneration) onSuccess?.();
|
|
487
|
-
})
|
|
488
|
-
.catch(() => {
|
|
489
|
-
// Keep the session usable even when settings cannot be restored.
|
|
490
|
-
});
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
private deferPendingClear(pi: ExtensionAPI, level: ThinkingLevel): void {
|
|
494
|
-
const generation = ++this.pendingClearGeneration;
|
|
495
|
-
setImmediate(() => {
|
|
496
|
-
if (
|
|
497
|
-
generation !== this.pendingClearGeneration
|
|
498
|
-
|| this.enabled
|
|
499
|
-
|| this.suspended
|
|
500
|
-
|| safeGetThinking(pi) !== level
|
|
501
|
-
) return;
|
|
502
|
-
this.pendingPreviousThinking = undefined;
|
|
503
|
-
this.persist(pi);
|
|
504
|
-
});
|
|
199
|
+
return this.isEnabled() && !this.suspended;
|
|
505
200
|
}
|
|
506
201
|
|
|
507
202
|
private activateWorkflowTool(pi: ExtensionAPI): void {
|
|
@@ -511,7 +206,7 @@ export class UltracodeMode {
|
|
|
511
206
|
pi.setActiveTools([...active, this.workflowToolName]);
|
|
512
207
|
}
|
|
513
208
|
} catch {
|
|
514
|
-
//
|
|
209
|
+
// Prompt policy remains usable when tool selection is unavailable.
|
|
515
210
|
}
|
|
516
211
|
}
|
|
517
212
|
|
|
@@ -527,14 +222,7 @@ export class UltracodeMode {
|
|
|
527
222
|
}
|
|
528
223
|
|
|
529
224
|
private persist(pi: ExtensionAPI): void {
|
|
530
|
-
const state: PersistedModeState = {
|
|
531
|
-
enabled: this.enabled,
|
|
532
|
-
previousThinking: this.previousThinking,
|
|
533
|
-
previousDefaultThinking: this.legacyDefaultMigrationPending
|
|
534
|
-
? undefined
|
|
535
|
-
: this.previousDefaultThinking,
|
|
536
|
-
pendingPreviousThinking: this.pendingPreviousThinking,
|
|
537
|
-
};
|
|
225
|
+
const state: PersistedModeState = { mode: this.mode };
|
|
538
226
|
try {
|
|
539
227
|
pi.appendEntry(MODE_ENTRY_TYPE, state);
|
|
540
228
|
} catch {
|
|
@@ -546,28 +234,14 @@ export class UltracodeMode {
|
|
|
546
234
|
function parsePersistedModeState(data: unknown): PersistedModeState | undefined {
|
|
547
235
|
if (!data || typeof data !== "object") return undefined;
|
|
548
236
|
const value = data as Record<string, unknown>;
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
?
|
|
555
|
-
:
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
};
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
function waitForSettingsWrites(): Promise<void> {
|
|
563
|
-
return new Promise((resolve) => setImmediate(resolve));
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
function safeGetThinking(pi: ExtensionAPI): ThinkingLevel | undefined {
|
|
567
|
-
try {
|
|
568
|
-
const level = pi.getThinkingLevel();
|
|
569
|
-
return isThinkingLevel(level) ? level : undefined;
|
|
570
|
-
} catch {
|
|
571
|
-
return undefined;
|
|
572
|
-
}
|
|
237
|
+
// Sessions written before semantic-depth modes stored only enabled:boolean.
|
|
238
|
+
// Preserve their behavior by migrating enabled:true to the old deep mode.
|
|
239
|
+
const mode: UltracodeModeName = isActiveUltracodeMode(value.mode)
|
|
240
|
+
? value.mode
|
|
241
|
+
: value.mode === "off"
|
|
242
|
+
? "off"
|
|
243
|
+
: value.enabled === true
|
|
244
|
+
? "deep"
|
|
245
|
+
: "off";
|
|
246
|
+
return { mode };
|
|
573
247
|
}
|