@caupulican/pi-adaptative 0.80.42 → 0.80.44
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/CHANGELOG.md +17 -0
- package/dist/bundled-resources/prompts/extensionify.md +20 -0
- package/dist/bundled-resources/prompts/learn.md +27 -0
- package/dist/bundled-resources/prompts/skillify.md +21 -0
- package/dist/bundled-resources/skills/pi-harness-learning/SKILL.md +217 -0
- package/dist/bundled-resources/skills/skill-architect/SKILL.md +162 -0
- package/dist/config.d.ts +17 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +30 -0
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +37 -2
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +215 -9
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/context-gc.d.ts.map +1 -1
- package/dist/core/context-gc.js +27 -5
- package/dist/core/context-gc.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +10 -3
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +38 -7
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +6 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +53 -6
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +16 -2
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/profile-registry.d.ts +39 -0
- package/dist/core/profile-registry.d.ts.map +1 -0
- package/dist/core/profile-registry.js +230 -0
- package/dist/core/profile-registry.js.map +1 -0
- package/dist/core/profile-resource-selection.d.ts +19 -0
- package/dist/core/profile-resource-selection.d.ts.map +1 -0
- package/dist/core/profile-resource-selection.js +84 -0
- package/dist/core/profile-resource-selection.js.map +1 -0
- package/dist/core/resource-loader.d.ts +33 -3
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +68 -11
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/settings-manager.d.ts +44 -2
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +557 -27
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts +5 -0
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +2 -2
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +5 -17
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/extensionify.d.ts +33 -0
- package/dist/core/tools/extensionify.d.ts.map +1 -0
- package/dist/core/tools/extensionify.js +146 -0
- package/dist/core/tools/extensionify.js.map +1 -0
- package/dist/core/tools/index.d.ts +10 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +36 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/skill-audit.d.ts +63 -0
- package/dist/core/tools/skill-audit.d.ts.map +1 -0
- package/dist/core/tools/skill-audit.js +175 -0
- package/dist/core/tools/skill-audit.js.map +1 -0
- package/dist/core/tools/skillify.d.ts +30 -0
- package/dist/core/tools/skillify.d.ts.map +1 -0
- package/dist/core/tools/skillify.js +91 -0
- package/dist/core/tools/skillify.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/profile-resource-editor.d.ts +50 -0
- package/dist/modes/interactive/components/profile-resource-editor.d.ts.map +1 -0
- package/dist/modes/interactive/components/profile-resource-editor.js +232 -0
- package/dist/modes/interactive/components/profile-resource-editor.js.map +1 -0
- package/dist/modes/interactive/components/profile-selector.d.ts +8 -0
- package/dist/modes/interactive/components/profile-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/profile-selector.js +77 -0
- package/dist/modes/interactive/components/profile-selector.js.map +1 -0
- package/dist/modes/interactive/components/settings-selector.d.ts +7 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +62 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +12 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +362 -24
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/settings.md +20 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/12-full-control.ts +4 -0
- package/npm-shrinkwrap.json +12 -12
- package/package.json +6 -6
|
@@ -18,7 +18,7 @@ import { FooterDataProvider } from "../../core/footer-data-provider.js";
|
|
|
18
18
|
import { configureHttpDispatcher, formatHttpIdleTimeoutMs } from "../../core/http-dispatcher.js";
|
|
19
19
|
import { KeybindingsManager } from "../../core/keybindings.js";
|
|
20
20
|
import { createCompactionSummaryMessage } from "../../core/messages.js";
|
|
21
|
-
import { cliProviderAliases, defaultModelPerProvider, findExactModelReferenceMatch, resolveModelScope, } from "../../core/model-resolver.js";
|
|
21
|
+
import { cliProviderAliases, defaultModelPerProvider, findExactModelReferenceMatch, resolveCliModel, resolveModelScope, } from "../../core/model-resolver.js";
|
|
22
22
|
import { DefaultPackageManager } from "../../core/package-manager.js";
|
|
23
23
|
import { BUILT_IN_PROVIDER_DISPLAY_NAMES } from "../../core/provider-display-names.js";
|
|
24
24
|
import { getPendingReloadBlockers } from "../../core/reload-blockers.js";
|
|
@@ -26,6 +26,7 @@ import { formatMissingSessionCwdPrompt, MissingSessionCwdError } from "../../cor
|
|
|
26
26
|
import { isAutoLearnSessionId, SessionManager } from "../../core/session-manager.js";
|
|
27
27
|
import { BUILTIN_SLASH_COMMANDS } from "../../core/slash-commands.js";
|
|
28
28
|
import { isInstallTelemetryEnabled } from "../../core/telemetry.js";
|
|
29
|
+
import { allToolNames } from "../../core/tools/index.js";
|
|
29
30
|
import { hasProjectTrustInputs, ProjectTrustStore } from "../../core/trust-manager.js";
|
|
30
31
|
import { getChangelogPath, getNewEntries, parseChangelog } from "../../utils/changelog.js";
|
|
31
32
|
import { copyToClipboard } from "../../utils/clipboard.js";
|
|
@@ -56,6 +57,8 @@ import { formatKeyText, keyDisplayText, keyHint, keyText, rawKeyHint } from "./c
|
|
|
56
57
|
import { LoginDialogComponent } from "./components/login-dialog.js";
|
|
57
58
|
import { ModelSelectorComponent } from "./components/model-selector.js";
|
|
58
59
|
import { OAuthSelectorComponent } from "./components/oauth-selector.js";
|
|
60
|
+
import { ProfileResourceEditorComponent, } from "./components/profile-resource-editor.js";
|
|
61
|
+
import { ProfileSelectorComponent } from "./components/profile-selector.js";
|
|
59
62
|
import { ScopedModelsSelectorComponent } from "./components/scoped-models-selector.js";
|
|
60
63
|
import { SessionSelectorComponent } from "./components/session-selector.js";
|
|
61
64
|
import { SettingsSelectorComponent } from "./components/settings-selector.js";
|
|
@@ -101,6 +104,7 @@ const ANTHROPIC_SUBSCRIPTION_AUTH_WARNING = "Anthropic subscription auth is acti
|
|
|
101
104
|
const AUTO_LEARN_DEFAULTS = {
|
|
102
105
|
enabled: false,
|
|
103
106
|
model: "active",
|
|
107
|
+
thinkingLevel: "low",
|
|
104
108
|
longSessionMessages: 32,
|
|
105
109
|
longSessionContextPercent: 70,
|
|
106
110
|
cooldownMinutes: 24 * 60,
|
|
@@ -108,36 +112,39 @@ const AUTO_LEARN_DEFAULTS = {
|
|
|
108
112
|
maxConcurrentLearners: 1,
|
|
109
113
|
applyHighConfidence: false,
|
|
110
114
|
reflectionReview: true,
|
|
111
|
-
reflectionMinToolCalls:
|
|
115
|
+
reflectionMinToolCalls: 12,
|
|
112
116
|
reflectionCooldownMinutes: 24 * 60,
|
|
117
|
+
complexTaskToolCalls: 12,
|
|
113
118
|
};
|
|
114
119
|
const AUTONOMY_AUTO_LEARN_PRESETS = {
|
|
115
120
|
off: { ...AUTO_LEARN_DEFAULTS, enabled: false, reflectionReview: false },
|
|
116
121
|
safe: {
|
|
117
122
|
...AUTO_LEARN_DEFAULTS,
|
|
118
|
-
enabled:
|
|
123
|
+
enabled: false,
|
|
119
124
|
longSessionMessages: 64,
|
|
120
125
|
longSessionContextPercent: 85,
|
|
121
126
|
cooldownMinutes: 24 * 60,
|
|
122
127
|
leaseMinutes: 60,
|
|
123
128
|
maxConcurrentLearners: 1,
|
|
124
129
|
applyHighConfidence: false,
|
|
125
|
-
reflectionReview:
|
|
126
|
-
reflectionMinToolCalls:
|
|
130
|
+
reflectionReview: false,
|
|
131
|
+
reflectionMinToolCalls: 12,
|
|
127
132
|
reflectionCooldownMinutes: 24 * 60,
|
|
133
|
+
complexTaskToolCalls: 12,
|
|
128
134
|
},
|
|
129
135
|
balanced: {
|
|
130
136
|
...AUTO_LEARN_DEFAULTS,
|
|
131
|
-
enabled:
|
|
137
|
+
enabled: false,
|
|
132
138
|
longSessionMessages: 64,
|
|
133
139
|
longSessionContextPercent: 85,
|
|
134
140
|
cooldownMinutes: 24 * 60,
|
|
135
141
|
leaseMinutes: 90,
|
|
136
142
|
maxConcurrentLearners: 1,
|
|
137
143
|
applyHighConfidence: false,
|
|
138
|
-
reflectionReview:
|
|
139
|
-
reflectionMinToolCalls:
|
|
144
|
+
reflectionReview: false,
|
|
145
|
+
reflectionMinToolCalls: 12,
|
|
140
146
|
reflectionCooldownMinutes: 24 * 60,
|
|
147
|
+
complexTaskToolCalls: 12,
|
|
141
148
|
},
|
|
142
149
|
full: {
|
|
143
150
|
...AUTO_LEARN_DEFAULTS,
|
|
@@ -149,14 +156,13 @@ const AUTONOMY_AUTO_LEARN_PRESETS = {
|
|
|
149
156
|
maxConcurrentLearners: 1,
|
|
150
157
|
applyHighConfidence: true,
|
|
151
158
|
reflectionReview: true,
|
|
152
|
-
reflectionMinToolCalls:
|
|
159
|
+
reflectionMinToolCalls: 12,
|
|
153
160
|
reflectionCooldownMinutes: 24 * 60,
|
|
161
|
+
complexTaskToolCalls: 12,
|
|
154
162
|
},
|
|
155
163
|
};
|
|
156
164
|
const AUTONOMY_MODES = ["off", "safe", "balanced", "full"];
|
|
157
165
|
const AUTO_LEARN_RESERVATION_MS = 2 * 60 * 1000;
|
|
158
|
-
const AUTO_LEARN_THINKING_LEVEL = "xhigh";
|
|
159
|
-
const AUTO_LEARN_COMPLEX_TASK_TOOL_CALLS = 5;
|
|
160
166
|
export const AUTO_LEARN_HISTORY_RETENTION_MS = 7 * 24 * 60 * 60 * 1000;
|
|
161
167
|
function definedStringSet(values) {
|
|
162
168
|
const set = new Set();
|
|
@@ -434,6 +440,7 @@ export class InteractiveMode {
|
|
|
434
440
|
skillCommands = new Map();
|
|
435
441
|
// Agent subscription unsubscribe function
|
|
436
442
|
unsubscribe;
|
|
443
|
+
unsubscribeExtensionsChanged;
|
|
437
444
|
signalCleanupHandlers = [];
|
|
438
445
|
// Track if editor is in bash mode (text starts with !)
|
|
439
446
|
isBashMode = false;
|
|
@@ -750,6 +757,10 @@ export class InteractiveMode {
|
|
|
750
757
|
this.isInitialized = true;
|
|
751
758
|
// Initialize extensions first so resources are shown before messages
|
|
752
759
|
await this.rebindCurrentSession();
|
|
760
|
+
// Register extensions-changed listener for live reload UI refresh
|
|
761
|
+
this.unsubscribeExtensionsChanged = this.session.onExtensionsChanged(() => {
|
|
762
|
+
this.refreshUIAfterExtensionsChanged();
|
|
763
|
+
});
|
|
753
764
|
// Render initial messages AFTER showing loaded resources
|
|
754
765
|
await this.renderInitialMessages();
|
|
755
766
|
this.renderProjectTrustWarningIfNeeded();
|
|
@@ -2437,6 +2448,12 @@ export class InteractiveMode {
|
|
|
2437
2448
|
await this.handleModelCommand(searchTerm);
|
|
2438
2449
|
return;
|
|
2439
2450
|
}
|
|
2451
|
+
if (text === "/profiles" || text.startsWith("/profiles ")) {
|
|
2452
|
+
const rawProfileName = text.startsWith("/profiles ") ? text.slice(10).trim() : undefined;
|
|
2453
|
+
this.editor.setText("");
|
|
2454
|
+
await this.handleProfilesCommand(rawProfileName?.length ? rawProfileName : undefined);
|
|
2455
|
+
return;
|
|
2456
|
+
}
|
|
2440
2457
|
if (text === "/export" || text.startsWith("/export ")) {
|
|
2441
2458
|
await this.handleExportCommand(text);
|
|
2442
2459
|
this.editor.setText("");
|
|
@@ -4134,6 +4151,8 @@ export class InteractiveMode {
|
|
|
4134
4151
|
reflectionReview: settings.reflectionReview ?? preset.reflectionReview,
|
|
4135
4152
|
reflectionMinToolCalls: settings.reflectionMinToolCalls ?? preset.reflectionMinToolCalls,
|
|
4136
4153
|
reflectionCooldownMinutes: settings.reflectionCooldownMinutes ?? preset.reflectionCooldownMinutes,
|
|
4154
|
+
complexTaskToolCalls: settings.complexTaskToolCalls ?? preset.complexTaskToolCalls,
|
|
4155
|
+
thinkingLevel: settings.thinkingLevel ?? preset.thinkingLevel,
|
|
4137
4156
|
};
|
|
4138
4157
|
}
|
|
4139
4158
|
getAutoLearnTenantKey() {
|
|
@@ -4338,7 +4357,7 @@ export class InteractiveMode {
|
|
|
4338
4357
|
const objective = options.kind === "reflection"
|
|
4339
4358
|
? "review the latest completed turn for durable memory, skill, validation, tooling, and code-baked self-improvement cues, then run one bounded continuous-learning pass if the learning tools are available"
|
|
4340
4359
|
: "run one bounded continuous-learning pass for this Pi tenant";
|
|
4341
|
-
return `You are Pi Auto Learn running as a background learner.\n\nObjective: ${objective}.\nTrigger: ${reason}.\n\n${authorityBlock}\n\nRequired workflow:\n1. Query existing durable memory/rules first when tools allow it. Memory confrontation is mandatory before accepting, merging, upgrading, or rejecting learning candidates.\n2. Run the available Auto Learn tooling, preferably learning_run_auto, with applyHighConfidence=${settings.applyHighConfidence}. Process candidate validation in vectorized chunks/batches; avoid scalar per-candidate memory queries except for final selected writes.\n3. Apply the learning validation tree to each candidate chunk: (a) Why is this good for the user? (b) Is it unique, or similar to existing memory/skills/agents so it should merge or upgrade existing knowledge? (c) Will this make Pi a better agent? Candidates that cannot answer all three are noise.\n4. Hermes-style learning cycle: after a complex task (${
|
|
4360
|
+
return `You are Pi Auto Learn running as a background learner.\n\nObjective: ${objective}.\nTrigger: ${reason}.\n\n${authorityBlock}\n\nRequired workflow:\n1. Query existing durable memory/rules first when tools allow it. Memory confrontation is mandatory before accepting, merging, upgrading, or rejecting learning candidates.\n2. Run the available Auto Learn tooling, preferably learning_run_auto, with applyHighConfidence=${settings.applyHighConfidence}. Process candidate validation in vectorized chunks/batches; avoid scalar per-candidate memory queries except for final selected writes.\n3. Apply the learning validation tree to each candidate chunk: (a) Why is this good for the user? (b) Is it unique, or similar to existing memory/skills/agents so it should merge or upgrade existing knowledge? (c) Will this make Pi a better agent? Candidates that cannot answer all three are noise.\n4. Hermes-style learning cycle: after a complex task (${settings.complexTaskToolCalls}+ tool calls), user correction, repeated steering pattern, non-trivial fix/workaround/debugging path, loaded-skill defect, trigger gap, tool gap, or harness workflow defect, actively create or update durable learning artifacts. Memory stores compact facts/preferences/state; skills/prompts/agents/extensions/source store procedural behavior. When a lesson changes how Pi should act on a future class of task, memory alone is not completion.\n5. Skill update preference order: (1) patch the currently loaded or consulted skill that governed the task; (2) patch an existing class-level umbrella skill/agent/prompt; (3) add a support file under references/, templates/, or scripts/ and add a SKILL.md pointer; (4) create a new class-level umbrella skill only when no existing artifact fits. Never create one-off PR/error/codename/session skills.\n6. Behavioral self-improvement is code-baked by default: prefer the lowest durable executable layer that fixes the behavior — patch an existing skill/prompt/agent/extension/tool, tune an approved setting, or edit the authorized Pi source when source authority is available. Use Automata only for concise facts/evidence pointers that support the baked change.\n7. Do not harden transient or environment-dependent failures into durable behavior: missing binaries, fresh-install package gaps, credentials not configured, path mismatches, one-off task narratives, or negative tool-broken claims should become setup/troubleshooting fixes only when the fix itself is reusable.\n8. Treat the latest-turn digest as current-session evidence only; do not auto-commit one-off cues unless deterministic tooling and memory confrontation corroborate them.\n9. In mode=full, apply safe memory/skill/user-extension/authorized-source improvements under the standing grant above; otherwise keep them proposal-gated.\n10. Never cross hard-stop boundaries from the authority policy.\n11. If the learning tools are unavailable, report BLOCKED with the missing tool names and do not improvise.\n12. Finish with PASS, BLOCKED, or FAIL and concise evidence, including chunk counts, merge/upgrade/code-bake decisions, changed paths/settings, validation, and cleanup/purge status.${reflectionBlock}`;
|
|
4342
4361
|
}
|
|
4343
4362
|
reserveAutoLearnRun(params) {
|
|
4344
4363
|
return this.withAutoLearnStateLock((current) => {
|
|
@@ -4468,7 +4487,7 @@ export class InteractiveMode {
|
|
|
4468
4487
|
const args = buildAutoLearnSpawnArgs(spawnTarget, {
|
|
4469
4488
|
name: `Auto Learn ${runId}`,
|
|
4470
4489
|
modelPattern,
|
|
4471
|
-
thinkingLevel:
|
|
4490
|
+
thinkingLevel: settings.thinkingLevel ?? "low",
|
|
4472
4491
|
sessionDir,
|
|
4473
4492
|
sessionId,
|
|
4474
4493
|
promptPath,
|
|
@@ -4630,7 +4649,6 @@ export class InteractiveMode {
|
|
|
4630
4649
|
}
|
|
4631
4650
|
evaluateAutonomyReview(messages) {
|
|
4632
4651
|
const settings = this.getEffectiveAutoLearnSettings();
|
|
4633
|
-
const autonomy = this.settingsManager.getAutonomySettings();
|
|
4634
4652
|
const state = this.withAutoLearnStateLock((current) => {
|
|
4635
4653
|
const pruned = this.pruneAutoLearnHistoryFromState(current);
|
|
4636
4654
|
return { result: pruned, next: pruned };
|
|
@@ -4651,7 +4669,8 @@ export class InteractiveMode {
|
|
|
4651
4669
|
const correctionSignal = /\b(next time|for future|from now on|remember this|don't|do not|avoid|instead|you should|should have|you forgot|you missed|not what i asked|wrong again)\b/i.test(userText);
|
|
4652
4670
|
const behavioralSelfImprovementSignal = /\b(harness|pi|agent|autonomy|autonomous|self[- ]?improv(?:e|ement|ing)?|steer(?:ing)?|trigger(?:s)?|skill(?:s)?|code[- ]?bak(?:e|ed)|bake(?:d)? into code|not (?:automata|memory)|reference agent|hermes)\b/i.test(userText) &&
|
|
4653
4671
|
/\b(improve|automatic(?:ally)?|autonomous|trigger|fire|skill|steer|self[- ]?improv(?:e|ement|ing)?|code[- ]?bak(?:e|ed)|bake(?:d)?|too much|less)\b/i.test(userText);
|
|
4654
|
-
const
|
|
4672
|
+
const complexTaskThreshold = Math.max(1, settings.complexTaskToolCalls ?? 12);
|
|
4673
|
+
const complexTaskSignal = toolCalls >= complexTaskThreshold;
|
|
4655
4674
|
const bypassCooldown = correctionSignal || behavioralSelfImprovementSignal || complexTaskSignal;
|
|
4656
4675
|
const base = { messageCount, contextPercent, cooldownRemainingMs, runningCount, toolCalls };
|
|
4657
4676
|
if (!settings.enabled)
|
|
@@ -4690,19 +4709,12 @@ export class InteractiveMode {
|
|
|
4690
4709
|
return {
|
|
4691
4710
|
...base,
|
|
4692
4711
|
shouldRun: true,
|
|
4693
|
-
reason: `reflection complex task learning signal (${toolCalls}/${
|
|
4712
|
+
reason: `reflection complex task learning signal (${toolCalls}/${complexTaskThreshold} tool calls)`,
|
|
4694
4713
|
digest: this.buildAutonomyReviewDigest(messages),
|
|
4695
4714
|
bypassCooldown: true,
|
|
4696
4715
|
};
|
|
4697
4716
|
}
|
|
4698
|
-
|
|
4699
|
-
return {
|
|
4700
|
-
...base,
|
|
4701
|
-
shouldRun: true,
|
|
4702
|
-
reason: "full autonomy post-turn review",
|
|
4703
|
-
digest: this.buildAutonomyReviewDigest(messages),
|
|
4704
|
-
};
|
|
4705
|
-
}
|
|
4717
|
+
// Full autonomy expands allowed action scope for triggered reviews; it does not make every turn a review trigger.
|
|
4706
4718
|
if (toolCalls >= settings.reflectionMinToolCalls) {
|
|
4707
4719
|
return {
|
|
4708
4720
|
...base,
|
|
@@ -4859,6 +4871,21 @@ export class InteractiveMode {
|
|
|
4859
4871
|
showSettingsSelector() {
|
|
4860
4872
|
this.showSelector((done) => {
|
|
4861
4873
|
const projectSettings = this.settingsManager.getProjectSettings();
|
|
4874
|
+
const profileOptions = [
|
|
4875
|
+
{
|
|
4876
|
+
value: "(none)",
|
|
4877
|
+
label: "(none)",
|
|
4878
|
+
description: "Use configured profile selection (session default)",
|
|
4879
|
+
},
|
|
4880
|
+
...this.settingsManager
|
|
4881
|
+
.getProfileRegistry()
|
|
4882
|
+
.listProfiles()
|
|
4883
|
+
.map((profile) => ({
|
|
4884
|
+
value: profile.name,
|
|
4885
|
+
label: profile.name,
|
|
4886
|
+
description: profile.description ?? profile.source,
|
|
4887
|
+
})),
|
|
4888
|
+
];
|
|
4862
4889
|
const selector = new SettingsSelectorComponent({
|
|
4863
4890
|
autoCompact: this.session.autoCompactionEnabled,
|
|
4864
4891
|
showImages: this.settingsManager.getShowImages(),
|
|
@@ -4896,6 +4923,8 @@ export class InteractiveMode {
|
|
|
4896
4923
|
currentModelPattern: this.session.model
|
|
4897
4924
|
? `${this.session.model.provider}/${this.session.model.id}`
|
|
4898
4925
|
: undefined,
|
|
4926
|
+
activeProfileName: this.settingsManager.getActiveResourceProfileNames()[0],
|
|
4927
|
+
profileOptions,
|
|
4899
4928
|
}, {
|
|
4900
4929
|
onAutoCompactChange: (enabled) => {
|
|
4901
4930
|
this.session.setAutoCompactionEnabled(enabled);
|
|
@@ -5038,6 +5067,22 @@ export class InteractiveMode {
|
|
|
5038
5067
|
this.updateAutoLearnFooter();
|
|
5039
5068
|
this.showStatus(`Auto Learn settings saved to ${scope}. Use /auto-learn status or /auto-learn run.`);
|
|
5040
5069
|
},
|
|
5070
|
+
onProfileChange: (profile) => {
|
|
5071
|
+
done();
|
|
5072
|
+
void this.applyProfile(profile);
|
|
5073
|
+
},
|
|
5074
|
+
onProfileEdit: (profileName) => {
|
|
5075
|
+
done();
|
|
5076
|
+
void this.openProfileResourceEditor(profileName);
|
|
5077
|
+
},
|
|
5078
|
+
onProfilePersistActive: (scope) => {
|
|
5079
|
+
done();
|
|
5080
|
+
this.persistActiveProfile(scope);
|
|
5081
|
+
},
|
|
5082
|
+
onProfileDelete: (profileName) => {
|
|
5083
|
+
done();
|
|
5084
|
+
this.deleteProfileFromSource(profileName);
|
|
5085
|
+
},
|
|
5041
5086
|
onCancel: () => {
|
|
5042
5087
|
done();
|
|
5043
5088
|
this.ui.requestRender();
|
|
@@ -5046,6 +5091,231 @@ export class InteractiveMode {
|
|
|
5046
5091
|
return { component: selector, focus: selector.getSettingsList() };
|
|
5047
5092
|
});
|
|
5048
5093
|
}
|
|
5094
|
+
async handleProfilesCommand(profileName) {
|
|
5095
|
+
if (profileName) {
|
|
5096
|
+
await this.applyProfile(profileName);
|
|
5097
|
+
return;
|
|
5098
|
+
}
|
|
5099
|
+
const registry = this.settingsManager.getProfileRegistry();
|
|
5100
|
+
const profiles = registry.listProfiles();
|
|
5101
|
+
if (profiles.length === 0) {
|
|
5102
|
+
this.showWarning("No profiles found. Add resourceProfiles to settings or JSON files under ~/.pi/agent/profiles/.");
|
|
5103
|
+
return;
|
|
5104
|
+
}
|
|
5105
|
+
this.showSelector((done) => {
|
|
5106
|
+
const selector = new ProfileSelectorComponent(profiles, this.settingsManager.getActiveResourceProfileNames(), (profile) => {
|
|
5107
|
+
done();
|
|
5108
|
+
void this.applyProfile(profile);
|
|
5109
|
+
}, () => {
|
|
5110
|
+
done();
|
|
5111
|
+
this.ui.requestRender();
|
|
5112
|
+
});
|
|
5113
|
+
return { component: selector, focus: selector.getSelectList() };
|
|
5114
|
+
});
|
|
5115
|
+
}
|
|
5116
|
+
async applyProfile(profileName) {
|
|
5117
|
+
const normalizedName = profileName.trim();
|
|
5118
|
+
const normalizedLower = normalizedName.toLowerCase();
|
|
5119
|
+
if (normalizedName.length === 0 || normalizedLower === "none" || normalizedLower === "(none)") {
|
|
5120
|
+
try {
|
|
5121
|
+
this.settingsManager.setRuntimeResourceProfiles([]);
|
|
5122
|
+
this.session.sessionManager.appendCustomEntry("pi.activeResourceProfiles", {
|
|
5123
|
+
profiles: [],
|
|
5124
|
+
});
|
|
5125
|
+
await this.handleReloadCommand();
|
|
5126
|
+
const activeProfileName = this.settingsManager.getActiveResourceProfileNames()[0] ?? "(none)";
|
|
5127
|
+
this.footerDataProvider.setExtensionStatus("profile", activeProfileName);
|
|
5128
|
+
this.footer.invalidate();
|
|
5129
|
+
this.updateEditorBorderColor();
|
|
5130
|
+
this.showStatus(`Profile: ${activeProfileName}`);
|
|
5131
|
+
}
|
|
5132
|
+
catch (error) {
|
|
5133
|
+
this.showError(error instanceof Error ? error.message : String(error));
|
|
5134
|
+
}
|
|
5135
|
+
return;
|
|
5136
|
+
}
|
|
5137
|
+
const registry = this.settingsManager.getProfileRegistry();
|
|
5138
|
+
const profile = normalizedName.startsWith("./") || normalizedName.startsWith("../")
|
|
5139
|
+
? registry.resolveProfileRef(normalizedName, this.sessionManager.getCwd())
|
|
5140
|
+
: registry.getProfile(normalizedName);
|
|
5141
|
+
if (!profile) {
|
|
5142
|
+
this.showError(`Profile not found: ${profileName}`);
|
|
5143
|
+
return;
|
|
5144
|
+
}
|
|
5145
|
+
try {
|
|
5146
|
+
let appliedModel;
|
|
5147
|
+
if (profile.model) {
|
|
5148
|
+
this.session.modelRegistry.refresh();
|
|
5149
|
+
const resolved = resolveCliModel({ cliModel: profile.model, modelRegistry: this.session.modelRegistry });
|
|
5150
|
+
if (resolved.error) {
|
|
5151
|
+
this.showError(resolved.error);
|
|
5152
|
+
return;
|
|
5153
|
+
}
|
|
5154
|
+
if (resolved.warning) {
|
|
5155
|
+
this.showWarning(resolved.warning);
|
|
5156
|
+
}
|
|
5157
|
+
if (resolved.model) {
|
|
5158
|
+
await this.session.setModel(resolved.model, { persistSettings: false });
|
|
5159
|
+
appliedModel = resolved.model;
|
|
5160
|
+
}
|
|
5161
|
+
if (resolved.thinkingLevel && !profile.thinking) {
|
|
5162
|
+
this.session.setThinkingLevel(resolved.thinkingLevel, { persistSettings: false });
|
|
5163
|
+
}
|
|
5164
|
+
}
|
|
5165
|
+
if (profile.thinking) {
|
|
5166
|
+
this.session.setThinkingLevel(profile.thinking, { persistSettings: false });
|
|
5167
|
+
}
|
|
5168
|
+
this.settingsManager.setRuntimeResourceProfiles([profile.name]);
|
|
5169
|
+
this.session.sessionManager.appendCustomEntry("pi.activeResourceProfiles", {
|
|
5170
|
+
profiles: [profile.name],
|
|
5171
|
+
});
|
|
5172
|
+
await this.handleReloadCommand();
|
|
5173
|
+
this.footerDataProvider.setExtensionStatus("profile", profile.name);
|
|
5174
|
+
this.footer.invalidate();
|
|
5175
|
+
this.updateEditorBorderColor();
|
|
5176
|
+
this.showStatus(`Profile: ${profile.name}`);
|
|
5177
|
+
if (appliedModel) {
|
|
5178
|
+
void this.maybeWarnAboutAnthropicSubscriptionAuth(appliedModel);
|
|
5179
|
+
this.checkDaxnutsEasterEgg(appliedModel);
|
|
5180
|
+
}
|
|
5181
|
+
}
|
|
5182
|
+
catch (error) {
|
|
5183
|
+
this.showError(error instanceof Error ? error.message : String(error));
|
|
5184
|
+
}
|
|
5185
|
+
}
|
|
5186
|
+
async getProfileResourceKinds() {
|
|
5187
|
+
const loader = this.session.resourceLoader;
|
|
5188
|
+
const base = (p) => p.split(/[\\/]/).pop() ?? p;
|
|
5189
|
+
// Get all discoverable extension paths (enabled and disabled) for profile filtering
|
|
5190
|
+
const allDiscoverableExtensions = await loader.getDiscoverableExtensionPaths();
|
|
5191
|
+
return [
|
|
5192
|
+
{ kind: "tools", label: "Tools", allIds: [...allToolNames] },
|
|
5193
|
+
{ kind: "skills", label: "Skills", allIds: loader.getSkills().skills.map((s) => s.name) },
|
|
5194
|
+
{
|
|
5195
|
+
kind: "extensions",
|
|
5196
|
+
label: "Extensions",
|
|
5197
|
+
allIds: allDiscoverableExtensions.map((e) => base(e)),
|
|
5198
|
+
},
|
|
5199
|
+
{ kind: "agents", label: "Agents", allIds: loader.getAgentsFiles().agentsFiles.map((f) => base(f.path)) },
|
|
5200
|
+
{ kind: "prompts", label: "Prompts", allIds: loader.getPrompts().prompts.map((p) => p.name) },
|
|
5201
|
+
{ kind: "themes", label: "Themes", allIds: getAvailableThemes() },
|
|
5202
|
+
];
|
|
5203
|
+
}
|
|
5204
|
+
/** Map where a profile currently lives to the scope we should write it back to. */
|
|
5205
|
+
scopeForProfileSource(source) {
|
|
5206
|
+
switch (source) {
|
|
5207
|
+
case "profile-file":
|
|
5208
|
+
return "reusable-file";
|
|
5209
|
+
case "directory-overlay":
|
|
5210
|
+
case "embedded":
|
|
5211
|
+
return "directory";
|
|
5212
|
+
case "inline":
|
|
5213
|
+
return "session";
|
|
5214
|
+
default:
|
|
5215
|
+
return "global"; // "settings"
|
|
5216
|
+
}
|
|
5217
|
+
}
|
|
5218
|
+
async refreshAfterProfileMutation(profileName) {
|
|
5219
|
+
if (this.settingsManager.getActiveResourceProfileNames().includes(profileName)) {
|
|
5220
|
+
await this.handleReloadCommand();
|
|
5221
|
+
const active = this.settingsManager.getActiveResourceProfileNames()[0] ?? "(none)";
|
|
5222
|
+
this.footerDataProvider.setExtensionStatus("profile", active);
|
|
5223
|
+
this.footer.invalidate();
|
|
5224
|
+
this.updateEditorBorderColor();
|
|
5225
|
+
}
|
|
5226
|
+
}
|
|
5227
|
+
async openProfileResourceEditor(profileName) {
|
|
5228
|
+
const profile = this.settingsManager.getProfileRegistry().getProfile(profileName);
|
|
5229
|
+
if (!profile) {
|
|
5230
|
+
this.showError(`Profile not found: ${profileName}`);
|
|
5231
|
+
return;
|
|
5232
|
+
}
|
|
5233
|
+
const scope = this.scopeForProfileSource(profile.source);
|
|
5234
|
+
const kinds = await this.getProfileResourceKinds();
|
|
5235
|
+
const isActiveProfile = this.settingsManager.getActiveResourceProfileNames().includes(profile.name);
|
|
5236
|
+
const originalResources = profile.resources;
|
|
5237
|
+
this.showSelector((done) => {
|
|
5238
|
+
const editor = new ProfileResourceEditorComponent({
|
|
5239
|
+
profileName: profile.name,
|
|
5240
|
+
initialResources: profile.resources,
|
|
5241
|
+
kinds,
|
|
5242
|
+
onSave: (resources) => {
|
|
5243
|
+
done();
|
|
5244
|
+
try {
|
|
5245
|
+
this.settingsManager.setProfileDefinition(profile.name, {
|
|
5246
|
+
name: profile.name,
|
|
5247
|
+
description: profile.description,
|
|
5248
|
+
model: profile.model,
|
|
5249
|
+
thinking: profile.thinking,
|
|
5250
|
+
resources,
|
|
5251
|
+
}, scope);
|
|
5252
|
+
this.showStatus(`Saved profile "${profile.name}" to ${scope}.`);
|
|
5253
|
+
// For active profiles, detect if only extensions changed to avoid full reload
|
|
5254
|
+
if (isActiveProfile) {
|
|
5255
|
+
const extensionsChanged = originalResources.extensions !== resources.extensions;
|
|
5256
|
+
const otherResourcesChanged = originalResources.tools !== resources.tools ||
|
|
5257
|
+
originalResources.skills !== resources.skills ||
|
|
5258
|
+
originalResources.agents !== resources.agents ||
|
|
5259
|
+
originalResources.prompts !== resources.prompts ||
|
|
5260
|
+
originalResources.themes !== resources.themes;
|
|
5261
|
+
if (extensionsChanged && !otherResourcesChanged) {
|
|
5262
|
+
// Only extensions changed: use live reconciliation
|
|
5263
|
+
void this.reconcileExtensionsAndRefreshUI(profile.name);
|
|
5264
|
+
}
|
|
5265
|
+
else {
|
|
5266
|
+
// Other resources changed or mixed: use full reload
|
|
5267
|
+
void this.refreshAfterProfileMutation(profile.name);
|
|
5268
|
+
}
|
|
5269
|
+
}
|
|
5270
|
+
// Non-active profiles don't need refresh
|
|
5271
|
+
}
|
|
5272
|
+
catch (error) {
|
|
5273
|
+
this.showError(error instanceof Error ? error.message : String(error));
|
|
5274
|
+
}
|
|
5275
|
+
},
|
|
5276
|
+
onCancel: () => {
|
|
5277
|
+
done();
|
|
5278
|
+
this.ui.requestRender();
|
|
5279
|
+
},
|
|
5280
|
+
});
|
|
5281
|
+
return { component: editor, focus: editor };
|
|
5282
|
+
});
|
|
5283
|
+
}
|
|
5284
|
+
persistActiveProfile(scope) {
|
|
5285
|
+
const active = this.settingsManager.getActiveResourceProfileNames()[0];
|
|
5286
|
+
if (!active) {
|
|
5287
|
+
this.showError("No active profile to persist. Select one with /profiles first.");
|
|
5288
|
+
return;
|
|
5289
|
+
}
|
|
5290
|
+
try {
|
|
5291
|
+
if (scope === "session") {
|
|
5292
|
+
this.settingsManager.setRuntimeResourceProfiles([active]);
|
|
5293
|
+
}
|
|
5294
|
+
else {
|
|
5295
|
+
this.settingsManager.setActiveProfile(active, scope);
|
|
5296
|
+
}
|
|
5297
|
+
this.showStatus(`Active profile "${active}" persisted to ${scope}.`);
|
|
5298
|
+
}
|
|
5299
|
+
catch (error) {
|
|
5300
|
+
this.showError(error instanceof Error ? error.message : String(error));
|
|
5301
|
+
}
|
|
5302
|
+
}
|
|
5303
|
+
deleteProfileFromSource(profileName) {
|
|
5304
|
+
const profile = this.settingsManager.getProfileRegistry().getProfile(profileName);
|
|
5305
|
+
if (!profile) {
|
|
5306
|
+
this.showError(`Profile not found: ${profileName}`);
|
|
5307
|
+
return;
|
|
5308
|
+
}
|
|
5309
|
+
const scope = this.scopeForProfileSource(profile.source);
|
|
5310
|
+
try {
|
|
5311
|
+
this.settingsManager.deleteProfile(profileName, scope);
|
|
5312
|
+
this.showStatus(`Deleted profile "${profileName}" from ${scope}.`);
|
|
5313
|
+
void this.refreshAfterProfileMutation(profileName);
|
|
5314
|
+
}
|
|
5315
|
+
catch (error) {
|
|
5316
|
+
this.showError(error instanceof Error ? error.message : String(error));
|
|
5317
|
+
}
|
|
5318
|
+
}
|
|
5049
5319
|
async handleModelCommand(searchTerm) {
|
|
5050
5320
|
if (!searchTerm) {
|
|
5051
5321
|
await this.showModelSelector();
|
|
@@ -5916,6 +6186,71 @@ export class InteractiveMode {
|
|
|
5916
6186
|
this.showError(`Reload failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
5917
6187
|
}
|
|
5918
6188
|
}
|
|
6189
|
+
/**
|
|
6190
|
+
* Refresh UI after extensions are loaded/unloaded live.
|
|
6191
|
+
* Performs the same refresh calls as handleReloadCommand but without the full reload.
|
|
6192
|
+
*/
|
|
6193
|
+
async refreshUIAfterExtensionsChanged() {
|
|
6194
|
+
try {
|
|
6195
|
+
// Refresh keybindings and autocomplete
|
|
6196
|
+
this.keybindings.reload();
|
|
6197
|
+
this.setupAutocompleteProvider();
|
|
6198
|
+
// Refresh themes
|
|
6199
|
+
const activeHeader = this.customHeader ?? this.builtInHeader;
|
|
6200
|
+
if (isExpandable(activeHeader)) {
|
|
6201
|
+
activeHeader.setExpanded(this.toolOutputExpanded);
|
|
6202
|
+
}
|
|
6203
|
+
setRegisteredThemes(this.session.resourceLoader.getThemes().themes);
|
|
6204
|
+
this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
|
|
6205
|
+
const themeName = this.settingsManager.getTheme();
|
|
6206
|
+
const themeResult = themeName ? setTheme(themeName, true) : { success: true };
|
|
6207
|
+
if (!themeResult.success) {
|
|
6208
|
+
this.showError(`Failed to load theme "${themeName}": ${themeResult.error}\nFell back to dark theme.`);
|
|
6209
|
+
}
|
|
6210
|
+
// Refresh editor settings
|
|
6211
|
+
const editorPaddingX = this.settingsManager.getEditorPaddingX();
|
|
6212
|
+
const autocompleteMaxVisible = this.settingsManager.getAutocompleteMaxVisible();
|
|
6213
|
+
this.defaultEditor.setPaddingX(editorPaddingX);
|
|
6214
|
+
this.defaultEditor.setAutocompleteMaxVisible(autocompleteMaxVisible);
|
|
6215
|
+
if (this.editor !== this.defaultEditor) {
|
|
6216
|
+
this.editor.setPaddingX?.(editorPaddingX);
|
|
6217
|
+
this.editor.setAutocompleteMaxVisible?.(autocompleteMaxVisible);
|
|
6218
|
+
}
|
|
6219
|
+
// Refresh extension shortcuts
|
|
6220
|
+
const runner = this.session.extensionRunner;
|
|
6221
|
+
this.setupExtensionShortcuts(runner);
|
|
6222
|
+
// Refresh chat and UI
|
|
6223
|
+
await this.rebuildChatFromMessages();
|
|
6224
|
+
this.footer.invalidate();
|
|
6225
|
+
this.ui.requestRender();
|
|
6226
|
+
}
|
|
6227
|
+
catch (error) {
|
|
6228
|
+
this.showError(`Extension refresh failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
6229
|
+
}
|
|
6230
|
+
}
|
|
6231
|
+
/**
|
|
6232
|
+
* Reconcile extensions for the active profile and refresh UI.
|
|
6233
|
+
* Used when only extensions change in the active profile to avoid full reload.
|
|
6234
|
+
*/
|
|
6235
|
+
async reconcileExtensionsAndRefreshUI(profileName) {
|
|
6236
|
+
try {
|
|
6237
|
+
await this.session.reconcileLoadedExtensions();
|
|
6238
|
+
const active = this.settingsManager.getActiveResourceProfileNames()[0] ?? "(none)";
|
|
6239
|
+
this.footerDataProvider.setExtensionStatus("profile", active);
|
|
6240
|
+
this.footer.invalidate();
|
|
6241
|
+
this.updateEditorBorderColor();
|
|
6242
|
+
}
|
|
6243
|
+
catch (error) {
|
|
6244
|
+
// On error, fall back to full reload
|
|
6245
|
+
try {
|
|
6246
|
+
await this.refreshAfterProfileMutation(profileName);
|
|
6247
|
+
}
|
|
6248
|
+
catch {
|
|
6249
|
+
// If full reload also fails, show error
|
|
6250
|
+
this.showError(`Failed to reconcile extensions: ${error instanceof Error ? error.message : String(error)}`);
|
|
6251
|
+
}
|
|
6252
|
+
}
|
|
6253
|
+
}
|
|
5919
6254
|
async handleExportCommand(text) {
|
|
5920
6255
|
const outputPath = this.getPathCommandArgument(text, "/export");
|
|
5921
6256
|
try {
|
|
@@ -6466,6 +6801,9 @@ export class InteractiveMode {
|
|
|
6466
6801
|
if (this.unsubscribe) {
|
|
6467
6802
|
this.unsubscribe();
|
|
6468
6803
|
}
|
|
6804
|
+
if (this.unsubscribeExtensionsChanged) {
|
|
6805
|
+
this.unsubscribeExtensionsChanged();
|
|
6806
|
+
}
|
|
6469
6807
|
if (this.isInitialized) {
|
|
6470
6808
|
this.ui.stop();
|
|
6471
6809
|
this.isInitialized = false;
|