@caupulican/pi-adaptative 0.79.0 → 0.80.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/CHANGELOG.md +17 -0
- package/dist/core/agent-session.d.ts +1 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +34 -2
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/resource-loader.d.ts +1 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +26 -1
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/settings-manager.d.ts +12 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +16 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +2 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +4 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +98 -3
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +1 -0
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +11 -2
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tool-group.d.ts +3 -0
- package/dist/modes/interactive/components/tool-group.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-group.js +13 -0
- package/dist/modes/interactive/components/tool-group.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +13 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +356 -21
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/extensions.md +1 -1
- package/docs/settings.md +30 -6
- package/docs/usage.md +1 -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/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
|
@@ -89,6 +89,7 @@ function isDeadTerminalError(error) {
|
|
|
89
89
|
}
|
|
90
90
|
const ANTHROPIC_SUBSCRIPTION_AUTH_WARNING = "Anthropic subscription auth is active. Third-party harness usage draws from extra usage and is billed per token, not your Claude plan limits. Manage extra usage at https://claude.ai/settings/usage.";
|
|
91
91
|
const AUTO_LEARN_DEFAULTS = {
|
|
92
|
+
enabled: false,
|
|
92
93
|
model: "active",
|
|
93
94
|
longSessionMessages: 32,
|
|
94
95
|
longSessionContextPercent: 70,
|
|
@@ -96,7 +97,53 @@ const AUTO_LEARN_DEFAULTS = {
|
|
|
96
97
|
leaseMinutes: 90,
|
|
97
98
|
maxConcurrentLearners: 2,
|
|
98
99
|
applyHighConfidence: false,
|
|
100
|
+
reflectionReview: true,
|
|
101
|
+
reflectionMinToolCalls: 5,
|
|
102
|
+
reflectionCooldownMinutes: 60,
|
|
99
103
|
};
|
|
104
|
+
const AUTONOMY_AUTO_LEARN_PRESETS = {
|
|
105
|
+
off: { ...AUTO_LEARN_DEFAULTS, enabled: false, reflectionReview: false },
|
|
106
|
+
safe: {
|
|
107
|
+
...AUTO_LEARN_DEFAULTS,
|
|
108
|
+
enabled: true,
|
|
109
|
+
longSessionMessages: 48,
|
|
110
|
+
longSessionContextPercent: 80,
|
|
111
|
+
cooldownMinutes: 180,
|
|
112
|
+
leaseMinutes: 60,
|
|
113
|
+
maxConcurrentLearners: 1,
|
|
114
|
+
applyHighConfidence: false,
|
|
115
|
+
reflectionReview: true,
|
|
116
|
+
reflectionMinToolCalls: 8,
|
|
117
|
+
reflectionCooldownMinutes: 120,
|
|
118
|
+
},
|
|
119
|
+
balanced: {
|
|
120
|
+
...AUTO_LEARN_DEFAULTS,
|
|
121
|
+
enabled: true,
|
|
122
|
+
longSessionMessages: 32,
|
|
123
|
+
longSessionContextPercent: 70,
|
|
124
|
+
cooldownMinutes: 120,
|
|
125
|
+
leaseMinutes: 90,
|
|
126
|
+
maxConcurrentLearners: 2,
|
|
127
|
+
applyHighConfidence: false,
|
|
128
|
+
reflectionReview: true,
|
|
129
|
+
reflectionMinToolCalls: 5,
|
|
130
|
+
reflectionCooldownMinutes: 60,
|
|
131
|
+
},
|
|
132
|
+
full: {
|
|
133
|
+
...AUTO_LEARN_DEFAULTS,
|
|
134
|
+
enabled: true,
|
|
135
|
+
longSessionMessages: 8,
|
|
136
|
+
longSessionContextPercent: 50,
|
|
137
|
+
cooldownMinutes: 15,
|
|
138
|
+
leaseMinutes: 90,
|
|
139
|
+
maxConcurrentLearners: 3,
|
|
140
|
+
applyHighConfidence: true,
|
|
141
|
+
reflectionReview: true,
|
|
142
|
+
reflectionMinToolCalls: 1,
|
|
143
|
+
reflectionCooldownMinutes: 0,
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
const AUTONOMY_MODES = ["off", "safe", "balanced", "full"];
|
|
100
147
|
function isAnthropicSubscriptionAuthKey(apiKey) {
|
|
101
148
|
return typeof apiKey === "string" && apiKey.startsWith("sk-ant-oat");
|
|
102
149
|
}
|
|
@@ -1299,15 +1346,38 @@ export class InteractiveMode {
|
|
|
1299
1346
|
}
|
|
1300
1347
|
this.chatContainer.addChild(component);
|
|
1301
1348
|
}
|
|
1349
|
+
detachToolExecutionComponent(component) {
|
|
1350
|
+
const children = this.chatContainer.children;
|
|
1351
|
+
const directIndex = children.indexOf(component);
|
|
1352
|
+
if (directIndex !== -1) {
|
|
1353
|
+
children.splice(directIndex, 1);
|
|
1354
|
+
return;
|
|
1355
|
+
}
|
|
1356
|
+
for (let i = 0; i < children.length; i++) {
|
|
1357
|
+
const child = children[i];
|
|
1358
|
+
if (!(child instanceof ToolGroupComponent) || !child.removeTool(component))
|
|
1359
|
+
continue;
|
|
1360
|
+
const remaining = child.getToolCount();
|
|
1361
|
+
if (remaining === 0) {
|
|
1362
|
+
children.splice(i, 1);
|
|
1363
|
+
}
|
|
1364
|
+
else if (remaining === 1) {
|
|
1365
|
+
const onlyTool = child.getOnlyTool();
|
|
1366
|
+
if (onlyTool)
|
|
1367
|
+
children[i] = onlyTool;
|
|
1368
|
+
}
|
|
1369
|
+
return;
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1302
1372
|
attachToolExecutionComponent(toolName, toolCallId, args) {
|
|
1303
1373
|
const actionKey = getToolPanelActionKey(this.getToolPanelScope(), toolName, args);
|
|
1304
1374
|
const toolDefinition = this.getRegisteredToolDefinition(toolName);
|
|
1305
1375
|
const existing = this.toolPanels.getReusable(actionKey);
|
|
1306
1376
|
if (existing) {
|
|
1307
|
-
this.
|
|
1377
|
+
this.detachToolExecutionComponent(existing);
|
|
1308
1378
|
existing.resetInvocation(toolName, toolCallId, args, toolDefinition);
|
|
1309
1379
|
existing.setExpanded(this.toolOutputExpanded);
|
|
1310
|
-
this.
|
|
1380
|
+
this.appendToolExecutionComponent(existing, true);
|
|
1311
1381
|
this.toolPanels.register(toolCallId, existing, actionKey);
|
|
1312
1382
|
return existing;
|
|
1313
1383
|
}
|
|
@@ -1316,7 +1386,7 @@ export class InteractiveMode {
|
|
|
1316
1386
|
imageWidthCells: this.settingsManager.getImageWidthCells(),
|
|
1317
1387
|
}, toolDefinition, this.ui, this.sessionManager.getCwd());
|
|
1318
1388
|
component.setExpanded(this.toolOutputExpanded);
|
|
1319
|
-
this.appendToolExecutionComponent(component,
|
|
1389
|
+
this.appendToolExecutionComponent(component, true);
|
|
1320
1390
|
this.toolPanels.register(toolCallId, component, actionKey);
|
|
1321
1391
|
return component;
|
|
1322
1392
|
}
|
|
@@ -2067,6 +2137,11 @@ export class InteractiveMode {
|
|
|
2067
2137
|
this.editor.setText("");
|
|
2068
2138
|
return;
|
|
2069
2139
|
}
|
|
2140
|
+
if (text === "/autonomy" || text.startsWith("/autonomy ")) {
|
|
2141
|
+
this.handleAutonomyCommand(text);
|
|
2142
|
+
this.editor.setText("");
|
|
2143
|
+
return;
|
|
2144
|
+
}
|
|
2070
2145
|
if (text === "/scoped-models") {
|
|
2071
2146
|
this.editor.setText("");
|
|
2072
2147
|
await this.showModelsSelector();
|
|
@@ -2388,7 +2463,9 @@ export class InteractiveMode {
|
|
|
2388
2463
|
break;
|
|
2389
2464
|
}
|
|
2390
2465
|
case "agent_end":
|
|
2391
|
-
this.maybeStartAutoLearn()
|
|
2466
|
+
if (!this.maybeStartAutoLearn()) {
|
|
2467
|
+
this.maybeStartAutonomyReview(event.messages);
|
|
2468
|
+
}
|
|
2392
2469
|
if (this.settingsManager.getShowTerminalProgress()) {
|
|
2393
2470
|
this.ui.terminal.setProgress(false);
|
|
2394
2471
|
}
|
|
@@ -3395,17 +3472,25 @@ export class InteractiveMode {
|
|
|
3395
3472
|
}
|
|
3396
3473
|
return { ...state, runs };
|
|
3397
3474
|
}
|
|
3475
|
+
getAutoLearnPresetForAutonomyMode(mode, current = {}) {
|
|
3476
|
+
const preset = AUTONOMY_AUTO_LEARN_PRESETS[mode] ?? AUTONOMY_AUTO_LEARN_PRESETS.off;
|
|
3477
|
+
return { ...preset, model: current.model?.trim() || preset.model };
|
|
3478
|
+
}
|
|
3398
3479
|
getEffectiveAutoLearnSettings() {
|
|
3399
3480
|
const settings = this.settingsManager.getAutoLearnSettings();
|
|
3481
|
+
const preset = this.getAutoLearnPresetForAutonomyMode(this.settingsManager.getAutonomySettings().mode, settings);
|
|
3400
3482
|
return {
|
|
3401
|
-
enabled: settings.enabled ??
|
|
3402
|
-
model: settings.model?.trim() ||
|
|
3403
|
-
longSessionMessages: settings.longSessionMessages ??
|
|
3404
|
-
longSessionContextPercent: settings.longSessionContextPercent ??
|
|
3405
|
-
cooldownMinutes: settings.cooldownMinutes ??
|
|
3406
|
-
leaseMinutes: settings.leaseMinutes ??
|
|
3407
|
-
maxConcurrentLearners: settings.maxConcurrentLearners ??
|
|
3408
|
-
applyHighConfidence: settings.applyHighConfidence ??
|
|
3483
|
+
enabled: settings.enabled ?? preset.enabled,
|
|
3484
|
+
model: settings.model?.trim() || preset.model,
|
|
3485
|
+
longSessionMessages: settings.longSessionMessages ?? preset.longSessionMessages,
|
|
3486
|
+
longSessionContextPercent: settings.longSessionContextPercent ?? preset.longSessionContextPercent,
|
|
3487
|
+
cooldownMinutes: settings.cooldownMinutes ?? preset.cooldownMinutes,
|
|
3488
|
+
leaseMinutes: settings.leaseMinutes ?? preset.leaseMinutes,
|
|
3489
|
+
maxConcurrentLearners: settings.maxConcurrentLearners ?? preset.maxConcurrentLearners,
|
|
3490
|
+
applyHighConfidence: settings.applyHighConfidence ?? preset.applyHighConfidence,
|
|
3491
|
+
reflectionReview: settings.reflectionReview ?? preset.reflectionReview,
|
|
3492
|
+
reflectionMinToolCalls: settings.reflectionMinToolCalls ?? preset.reflectionMinToolCalls,
|
|
3493
|
+
reflectionCooldownMinutes: settings.reflectionCooldownMinutes ?? preset.reflectionCooldownMinutes,
|
|
3409
3494
|
};
|
|
3410
3495
|
}
|
|
3411
3496
|
getAutoLearnTenantKey() {
|
|
@@ -3542,10 +3627,41 @@ export class InteractiveMode {
|
|
|
3542
3627
|
runningCount,
|
|
3543
3628
|
};
|
|
3544
3629
|
}
|
|
3545
|
-
|
|
3546
|
-
|
|
3630
|
+
buildAutonomyAuthorityPrompt() {
|
|
3631
|
+
const autonomy = this.settingsManager.getAutonomySettings();
|
|
3632
|
+
const selfModification = this.settingsManager.getSelfModificationSettings();
|
|
3633
|
+
if (autonomy.mode !== "full") {
|
|
3634
|
+
return [
|
|
3635
|
+
"Authority mode: proposal-gated.",
|
|
3636
|
+
"- You may autonomously query memory and run bounded learning tools.",
|
|
3637
|
+
"- Durable memory writes require the configured high-confidence policy; skills, extensions, source, settings, publishing, tagging, and releases remain proposals unless the foreground user explicitly asks.",
|
|
3638
|
+
].join("\n");
|
|
3639
|
+
}
|
|
3640
|
+
const sourceAuthority = selfModification.enabled && selfModification.sourcePath?.trim()
|
|
3641
|
+
? `- Pi source: standing authority to edit the authorized selfModification.sourcePath (${selfModification.sourcePath.trim()}) for self-evolution improvements; inspect git status first, preserve unrelated user changes, run focused validation, and leave a clear rollback/test summary.`
|
|
3642
|
+
: "- Pi source: no standing source-edit authority until selfModification.enabled and selfModification.sourcePath are set.";
|
|
3643
|
+
return [
|
|
3644
|
+
"Authority mode: FULL AUTONOMOUS standing grant.",
|
|
3645
|
+
"- Memory: may apply high-confidence durable Automata memory/corrections after duplicate and corroboration checks.",
|
|
3646
|
+
"- Skills: may create or patch user/project-owned procedural skills and support files; prefer updating existing umbrella skills; do not delete skills without making a recoverable archive/backup.",
|
|
3647
|
+
"- User/project extensions and tools: may create or patch small scoped extensions/tools under Pi user/project roots when they address repeated workflow/tooling gaps; validate and keep changes auditable.",
|
|
3648
|
+
"- Settings: may auto-tune autonomy/autoLearn settings to reduce bottlenecks; do not modify credentials, provider auth, package sources, or unrelated user preferences.",
|
|
3649
|
+
sourceAuthority,
|
|
3650
|
+
"- Hard stops without explicit foreground approval: publish, npm release, git push, tag creation, credential changes, destructive user-data deletion, network-exposed services, or authority expansion beyond this policy.",
|
|
3651
|
+
"- Audit: final output must list changed paths/settings, commands/tests run, evidence, residual risks, and rollback guidance. If no safe validation is possible, leave the change as a proposal instead of applying it.",
|
|
3652
|
+
].join("\n");
|
|
3547
3653
|
}
|
|
3548
|
-
|
|
3654
|
+
buildAutoLearnPrompt(reason, settings, options = {}) {
|
|
3655
|
+
const authorityBlock = this.buildAutonomyAuthorityPrompt();
|
|
3656
|
+
const reflectionBlock = options.kind === "reflection" && options.turnDigest
|
|
3657
|
+
? `\n\nLatest completed turn digest (bounded; use only as current-session evidence, not as longitudinal proof):\n<turn_digest>\n${options.turnDigest}\n</turn_digest>`
|
|
3658
|
+
: "";
|
|
3659
|
+
const objective = options.kind === "reflection"
|
|
3660
|
+
? "review the latest completed turn for durable memory, skill, validation, and tooling-improvement cues, then run one bounded continuous-learning pass if the learning tools are available"
|
|
3661
|
+
: "run one bounded continuous-learning pass for this Pi tenant";
|
|
3662
|
+
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.\n2. Run the available Auto Learn tooling, preferably learning_run_auto, with applyHighConfidence=${settings.applyHighConfidence}.\n3. Treat the latest-turn digest as current-session evidence only; do not auto-commit one-off cues unless deterministic tooling corroborates them.\n4. In mode=full, apply safe memory/skill/user-extension/authorized-source improvements under the standing grant above; otherwise keep them proposal-gated.\n5. Never cross hard-stop boundaries from the authority policy.\n6. If the learning tools are unavailable, report BLOCKED with the missing tool names and do not improvise.\n7. Finish with PASS, BLOCKED, or FAIL and concise evidence.${reflectionBlock}`;
|
|
3663
|
+
}
|
|
3664
|
+
launchAutoLearn(reason, force = false, options = {}) {
|
|
3549
3665
|
const settings = this.getEffectiveAutoLearnSettings();
|
|
3550
3666
|
const decision = this.evaluateAutoLearn(force);
|
|
3551
3667
|
if (!decision.shouldRun) {
|
|
@@ -3563,8 +3679,14 @@ export class InteractiveMode {
|
|
|
3563
3679
|
fs.mkdirSync(dir, { recursive: true });
|
|
3564
3680
|
const runId = `${Date.now()}-${crypto.randomUUID().slice(0, 8)}`;
|
|
3565
3681
|
const logPath = path.join(dir, `${runId}.log`);
|
|
3682
|
+
const promptPath = path.join(dir, `${runId}.prompt.md`);
|
|
3566
3683
|
const outFd = fs.openSync(logPath, "a");
|
|
3567
|
-
const
|
|
3684
|
+
const kind = options.promptKind ?? "auto";
|
|
3685
|
+
const prompt = this.buildAutoLearnPrompt(reason, settings, {
|
|
3686
|
+
kind,
|
|
3687
|
+
turnDigest: options.turnDigest,
|
|
3688
|
+
});
|
|
3689
|
+
fs.writeFileSync(promptPath, prompt, "utf-8");
|
|
3568
3690
|
const args = [
|
|
3569
3691
|
...spawnTarget.argsPrefix,
|
|
3570
3692
|
"--print",
|
|
@@ -3584,7 +3706,15 @@ export class InteractiveMode {
|
|
|
3584
3706
|
fs.closeSync(outFd);
|
|
3585
3707
|
const now = Date.now();
|
|
3586
3708
|
const state = this.pruneAutoLearnState(this.readAutoLearnState(), now);
|
|
3587
|
-
|
|
3709
|
+
if (options.cooldownKind === "reflection") {
|
|
3710
|
+
state.lastReflectionByTenant = {
|
|
3711
|
+
...(state.lastReflectionByTenant ?? {}),
|
|
3712
|
+
[this.getAutoLearnTenantKey()]: now,
|
|
3713
|
+
};
|
|
3714
|
+
}
|
|
3715
|
+
else {
|
|
3716
|
+
state.lastLaunchByTenant = { ...(state.lastLaunchByTenant ?? {}), [this.getAutoLearnTenantKey()]: now };
|
|
3717
|
+
}
|
|
3588
3718
|
state.runs = {
|
|
3589
3719
|
...(state.runs ?? {}),
|
|
3590
3720
|
[runId]: {
|
|
@@ -3596,6 +3726,12 @@ export class InteractiveMode {
|
|
|
3596
3726
|
expiresAt: now + settings.leaseMinutes * 60 * 1000,
|
|
3597
3727
|
cwd: this.sessionManager.getCwd(),
|
|
3598
3728
|
logPath,
|
|
3729
|
+
promptPath,
|
|
3730
|
+
kind,
|
|
3731
|
+
autonomyMode: this.settingsManager.getAutonomySettings().mode,
|
|
3732
|
+
authority: this.settingsManager.getAutonomySettings().mode === "full"
|
|
3733
|
+
? "standing-full-autonomous"
|
|
3734
|
+
: "proposal-gated",
|
|
3599
3735
|
},
|
|
3600
3736
|
};
|
|
3601
3737
|
this.writeAutoLearnState(state);
|
|
@@ -3603,17 +3739,159 @@ export class InteractiveMode {
|
|
|
3603
3739
|
this.updateAutoLearnFooter();
|
|
3604
3740
|
return `Auto Learn started (${reason}) with ${modelPattern}. Log: ${logPath}`;
|
|
3605
3741
|
}
|
|
3742
|
+
sanitizeAutoLearnDigestText(text) {
|
|
3743
|
+
return text
|
|
3744
|
+
.replace(/-----BEGIN [A-Z ]*(?:PRIVATE|OPENSSH|RSA|DSA|EC) KEY-----[\s\S]*?-----END [A-Z ]*(?:PRIVATE|OPENSSH|RSA|DSA|EC) KEY-----/g, "[redacted-private-key]")
|
|
3745
|
+
.replace(/\b(?:sk|pk)-(?:proj-)?[A-Za-z0-9_-]{12,}/g, "[redacted-api-key]")
|
|
3746
|
+
.replace(/\bsk-ant-[A-Za-z0-9_-]{12,}/g, "[redacted-api-key]")
|
|
3747
|
+
.replace(/\b(?:ghp|gho|ghu|ghs|github_pat)_[A-Za-z0-9_]{20,}/g, "[redacted-github-token]")
|
|
3748
|
+
.replace(/\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g, "[redacted-aws-access-key]")
|
|
3749
|
+
.replace(/(?:Bearer\s+)[A-Za-z0-9._-]{16,}/gi, "Bearer [redacted]")
|
|
3750
|
+
.replace(/([?&](?:key|token|api_key|access_token|secret|password)=)[^&\s]+/gi, "$1[redacted]")
|
|
3751
|
+
.replace(/((?:access|refresh|token|apiKey|api_key|password|secret|authorization|auth)\s*[:=]\s*)[^\s,'"}]{8,}/gi, "$1[redacted]");
|
|
3752
|
+
}
|
|
3753
|
+
capAutoLearnDigestText(text, maxChars) {
|
|
3754
|
+
const compact = this.sanitizeAutoLearnDigestText(text).replace(/\s+/g, " ").trim();
|
|
3755
|
+
if (compact.length <= maxChars)
|
|
3756
|
+
return compact;
|
|
3757
|
+
return `${compact.slice(0, Math.max(0, maxChars - 20)).trimEnd()} …[truncated]`;
|
|
3758
|
+
}
|
|
3759
|
+
getAgentMessagePlainText(message) {
|
|
3760
|
+
const raw = message;
|
|
3761
|
+
const content = raw.content;
|
|
3762
|
+
if (typeof content === "string")
|
|
3763
|
+
return content;
|
|
3764
|
+
if (!Array.isArray(content))
|
|
3765
|
+
return "";
|
|
3766
|
+
const parts = [];
|
|
3767
|
+
for (const block of content) {
|
|
3768
|
+
if (!block || typeof block !== "object")
|
|
3769
|
+
continue;
|
|
3770
|
+
const item = block;
|
|
3771
|
+
if (item.type === "text" && typeof item.text === "string")
|
|
3772
|
+
parts.push(item.text);
|
|
3773
|
+
if (item.type === "toolCall" && typeof item.name === "string")
|
|
3774
|
+
parts.push(`[tool call: ${item.name}]`);
|
|
3775
|
+
}
|
|
3776
|
+
return parts.join("\n");
|
|
3777
|
+
}
|
|
3778
|
+
countAgentToolCalls(messages) {
|
|
3779
|
+
let toolCalls = 0;
|
|
3780
|
+
let toolResults = 0;
|
|
3781
|
+
for (const message of messages) {
|
|
3782
|
+
const raw = message;
|
|
3783
|
+
const role = String(raw.role ?? "");
|
|
3784
|
+
if (role === "toolResult" || role === "bashExecution")
|
|
3785
|
+
toolResults++;
|
|
3786
|
+
const content = raw.content;
|
|
3787
|
+
if (!Array.isArray(content))
|
|
3788
|
+
continue;
|
|
3789
|
+
for (const block of content) {
|
|
3790
|
+
if (block && typeof block === "object" && block.type === "toolCall") {
|
|
3791
|
+
toolCalls++;
|
|
3792
|
+
}
|
|
3793
|
+
}
|
|
3794
|
+
}
|
|
3795
|
+
return Math.max(toolCalls, toolResults);
|
|
3796
|
+
}
|
|
3797
|
+
buildAutonomyReviewDigest(messages) {
|
|
3798
|
+
const lines = [];
|
|
3799
|
+
for (const message of messages.slice(-18)) {
|
|
3800
|
+
const raw = message;
|
|
3801
|
+
const role = String(raw.role ?? "message");
|
|
3802
|
+
const label = role === "toolResult" && typeof raw.toolName === "string" ? `toolResult:${raw.toolName}` : role;
|
|
3803
|
+
const text = this.capAutoLearnDigestText(this.getAgentMessagePlainText(message), 700);
|
|
3804
|
+
if (text)
|
|
3805
|
+
lines.push(`${label}: ${text}`);
|
|
3806
|
+
}
|
|
3807
|
+
const digest = lines.join("\n---\n");
|
|
3808
|
+
return this.capAutoLearnDigestText(digest || "[No textual turn digest available.]", 6000);
|
|
3809
|
+
}
|
|
3810
|
+
evaluateAutonomyReview(messages) {
|
|
3811
|
+
const settings = this.getEffectiveAutoLearnSettings();
|
|
3812
|
+
const autonomy = this.settingsManager.getAutonomySettings();
|
|
3813
|
+
const state = this.pruneAutoLearnState(this.readAutoLearnState());
|
|
3814
|
+
this.writeAutoLearnState(state);
|
|
3815
|
+
const now = Date.now();
|
|
3816
|
+
const tenant = this.getAutoLearnTenantKey();
|
|
3817
|
+
const runningCount = Object.keys(state.runs ?? {}).length;
|
|
3818
|
+
const lastReflection = state.lastReflectionByTenant?.[tenant] ?? 0;
|
|
3819
|
+
const cooldownMs = settings.reflectionCooldownMinutes * 60 * 1000;
|
|
3820
|
+
const cooldownRemainingMs = Math.max(0, lastReflection + cooldownMs - now);
|
|
3821
|
+
const messageCount = this.getAutoLearnMessageCount();
|
|
3822
|
+
const contextPercent = this.session.getContextUsage()?.percent ?? null;
|
|
3823
|
+
const toolCalls = this.countAgentToolCalls(messages);
|
|
3824
|
+
const userText = messages
|
|
3825
|
+
.filter((message) => String(message.role ?? "") === "user")
|
|
3826
|
+
.map((message) => this.getAgentMessagePlainText(message))
|
|
3827
|
+
.join("\n");
|
|
3828
|
+
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);
|
|
3829
|
+
const base = { messageCount, contextPercent, cooldownRemainingMs, runningCount, toolCalls };
|
|
3830
|
+
if (!settings.enabled)
|
|
3831
|
+
return { ...base, shouldRun: false, reason: "disabled" };
|
|
3832
|
+
if (!settings.reflectionReview)
|
|
3833
|
+
return { ...base, shouldRun: false, reason: "reflection disabled" };
|
|
3834
|
+
if (runningCount >= settings.maxConcurrentLearners) {
|
|
3835
|
+
return {
|
|
3836
|
+
...base,
|
|
3837
|
+
shouldRun: false,
|
|
3838
|
+
reason: `max learners running (${runningCount}/${settings.maxConcurrentLearners})`,
|
|
3839
|
+
};
|
|
3840
|
+
}
|
|
3841
|
+
if (cooldownRemainingMs > 0)
|
|
3842
|
+
return { ...base, shouldRun: false, reason: "reflection cooldown" };
|
|
3843
|
+
if (correctionSignal) {
|
|
3844
|
+
return {
|
|
3845
|
+
...base,
|
|
3846
|
+
shouldRun: true,
|
|
3847
|
+
reason: "reflection correction signal",
|
|
3848
|
+
digest: this.buildAutonomyReviewDigest(messages),
|
|
3849
|
+
};
|
|
3850
|
+
}
|
|
3851
|
+
if (autonomy.mode === "full") {
|
|
3852
|
+
return {
|
|
3853
|
+
...base,
|
|
3854
|
+
shouldRun: true,
|
|
3855
|
+
reason: "full autonomy post-turn review",
|
|
3856
|
+
digest: this.buildAutonomyReviewDigest(messages),
|
|
3857
|
+
};
|
|
3858
|
+
}
|
|
3859
|
+
if (toolCalls >= settings.reflectionMinToolCalls) {
|
|
3860
|
+
return {
|
|
3861
|
+
...base,
|
|
3862
|
+
shouldRun: true,
|
|
3863
|
+
reason: `reflection tool trigger (${toolCalls}/${settings.reflectionMinToolCalls})`,
|
|
3864
|
+
digest: this.buildAutonomyReviewDigest(messages),
|
|
3865
|
+
};
|
|
3866
|
+
}
|
|
3867
|
+
return { ...base, shouldRun: false, reason: "reflection thresholds not met" };
|
|
3868
|
+
}
|
|
3606
3869
|
maybeStartAutoLearn() {
|
|
3607
3870
|
if (process.env.PI_AUTO_LEARN_CHILD === "1")
|
|
3608
|
-
return;
|
|
3871
|
+
return false;
|
|
3609
3872
|
const decision = this.evaluateAutoLearn(false);
|
|
3610
3873
|
if (!decision.shouldRun) {
|
|
3611
3874
|
this.autoLearnLastStatus = decision.reason;
|
|
3612
3875
|
this.updateAutoLearnFooter();
|
|
3613
|
-
return;
|
|
3876
|
+
return false;
|
|
3614
3877
|
}
|
|
3615
3878
|
const message = this.launchAutoLearn(decision.reason, false);
|
|
3616
3879
|
this.showStatus(message);
|
|
3880
|
+
return message.startsWith("Auto Learn started");
|
|
3881
|
+
}
|
|
3882
|
+
maybeStartAutonomyReview(messages) {
|
|
3883
|
+
if (process.env.PI_AUTO_LEARN_CHILD === "1")
|
|
3884
|
+
return false;
|
|
3885
|
+
const decision = this.evaluateAutonomyReview(messages);
|
|
3886
|
+
if (!decision.shouldRun)
|
|
3887
|
+
return false;
|
|
3888
|
+
const message = this.launchAutoLearn(decision.reason, true, {
|
|
3889
|
+
cooldownKind: "reflection",
|
|
3890
|
+
promptKind: "reflection",
|
|
3891
|
+
turnDigest: decision.digest,
|
|
3892
|
+
});
|
|
3893
|
+
this.showStatus(message);
|
|
3894
|
+
return message.startsWith("Auto Learn started");
|
|
3617
3895
|
}
|
|
3618
3896
|
updateAutoLearnFooter() {
|
|
3619
3897
|
const settings = this.getEffectiveAutoLearnSettings();
|
|
@@ -3633,9 +3911,60 @@ export class InteractiveMode {
|
|
|
3633
3911
|
const contextText = decision.contextPercent === null ? "unknown" : `${decision.contextPercent.toFixed(1)}%`;
|
|
3634
3912
|
const cooldownText = decision.cooldownRemainingMs > 0 ? `${Math.ceil(decision.cooldownRemainingMs / 60000)}m remaining` : "ready";
|
|
3635
3913
|
const runLines = runs.length
|
|
3636
|
-
? runs
|
|
3914
|
+
? runs
|
|
3915
|
+
.map(([id, run]) => `- ${id}: ${run.model}, kind=${run.kind ?? "auto"}, authority=${run.authority ?? "unknown"}, pid=${run.pid ?? "?"}, log=${run.logPath}`)
|
|
3916
|
+
.join("\n")
|
|
3637
3917
|
: "- none";
|
|
3638
|
-
|
|
3918
|
+
const reflectionLast = state.lastReflectionByTenant?.[this.getAutoLearnTenantKey()] ?? 0;
|
|
3919
|
+
const reflectionCooldownRemainingMs = Math.max(0, reflectionLast + settings.reflectionCooldownMinutes * 60 * 1000 - Date.now());
|
|
3920
|
+
const reflectionCooldownText = reflectionCooldownRemainingMs > 0 ? `${Math.ceil(reflectionCooldownRemainingMs / 60000)}m remaining` : "ready";
|
|
3921
|
+
return `Auto Learn status\nEnabled: ${settings.enabled}\nModel: ${settings.model}\nNext decision: ${decision.shouldRun ? "ready" : decision.reason}\nMessages: ${decision.messageCount}/${settings.longSessionMessages}\nContext: ${contextText}/${settings.longSessionContextPercent}%\nCooldown: ${cooldownText}\nReflection review: ${settings.reflectionReview ? "enabled" : "disabled"} (tool trigger ${settings.reflectionMinToolCalls}, cooldown ${reflectionCooldownText})\nRunning leases: ${runs.length}/${settings.maxConcurrentLearners}\nRuns:\n${runLines}`;
|
|
3922
|
+
}
|
|
3923
|
+
formatAutonomyStatus() {
|
|
3924
|
+
const autonomy = this.settingsManager.getAutonomySettings();
|
|
3925
|
+
const settings = this.getEffectiveAutoLearnSettings();
|
|
3926
|
+
const autoLearnState = this.pruneAutoLearnState(this.readAutoLearnState());
|
|
3927
|
+
const running = Object.entries(autoLearnState.runs ?? {});
|
|
3928
|
+
const safety = autonomy.mode === "full"
|
|
3929
|
+
? "standing grant for memory, skills, user/project extensions, autonomy/autoLearn tuning, and authorized selfModification.sourcePath edits; hard stops still require explicit foreground approval"
|
|
3930
|
+
: "proposal-gated outside configured high-confidence memory policy";
|
|
3931
|
+
const reflectionLine = autonomy.mode === "full"
|
|
3932
|
+
? `Reflection review: ${settings.reflectionReview ? "enabled" : "disabled"}; post-turn when concurrency allows; cooldown=${settings.reflectionCooldownMinutes}m`
|
|
3933
|
+
: `Reflection review: ${settings.reflectionReview ? "enabled" : "disabled"}; tool trigger=${settings.reflectionMinToolCalls}; cooldown=${settings.reflectionCooldownMinutes}m`;
|
|
3934
|
+
return [
|
|
3935
|
+
"Autonomy status",
|
|
3936
|
+
`Mode: ${autonomy.mode}${autonomy.mode === "full" ? " (standing autonomy)" : ""}`,
|
|
3937
|
+
`Auto Learn: ${settings.enabled ? "enabled" : "disabled"}; model=${settings.model}; applyHighConfidence=${settings.applyHighConfidence}`,
|
|
3938
|
+
`Long-session trigger: ${settings.longSessionMessages} messages or ${settings.longSessionContextPercent}% context; cooldown=${settings.cooldownMinutes}m`,
|
|
3939
|
+
reflectionLine,
|
|
3940
|
+
`Running learners: ${running.length}/${settings.maxConcurrentLearners}`,
|
|
3941
|
+
`Standing authority: ${safety}`,
|
|
3942
|
+
`Audit/log dir: ${this.getAutoLearnDataDir()}`,
|
|
3943
|
+
"Use /autonomy off|safe|balanced|full to switch presets. Advanced overrides remain in /settings → Auto Learn Advanced.",
|
|
3944
|
+
].join("\n");
|
|
3945
|
+
}
|
|
3946
|
+
applyAutonomyMode(mode, scope = "global") {
|
|
3947
|
+
const currentAutoLearn = this.settingsManager.getAutoLearnSettings();
|
|
3948
|
+
const preset = this.getAutoLearnPresetForAutonomyMode(mode, currentAutoLearn);
|
|
3949
|
+
this.settingsManager.setAutonomySettings({ mode }, scope);
|
|
3950
|
+
this.settingsManager.setAutoLearnSettings(preset, scope);
|
|
3951
|
+
this.updateAutoLearnFooter();
|
|
3952
|
+
}
|
|
3953
|
+
handleAutonomyCommand(text) {
|
|
3954
|
+
const action = text.slice("/autonomy".length).trim() || "status";
|
|
3955
|
+
if (AUTONOMY_MODES.includes(action)) {
|
|
3956
|
+
const mode = action;
|
|
3957
|
+
this.applyAutonomyMode(mode);
|
|
3958
|
+
this.showStatus(`Autonomy mode set to ${mode}${mode === "full" ? " (standing autonomy)" : ""}.`);
|
|
3959
|
+
return;
|
|
3960
|
+
}
|
|
3961
|
+
if (action === "status") {
|
|
3962
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
3963
|
+
this.chatContainer.addChild(new Text(this.formatAutonomyStatus(), 1, 0));
|
|
3964
|
+
this.ui.requestRender();
|
|
3965
|
+
return;
|
|
3966
|
+
}
|
|
3967
|
+
this.showStatus("Usage: /autonomy [status|off|safe|balanced|full]");
|
|
3639
3968
|
}
|
|
3640
3969
|
handleAutoLearnCommand(text) {
|
|
3641
3970
|
const action = text.slice("/auto-learn".length).trim() || "status";
|
|
@@ -3683,6 +4012,8 @@ export class InteractiveMode {
|
|
|
3683
4012
|
warnings: this.settingsManager.getWarnings(),
|
|
3684
4013
|
selfModification: this.settingsManager.getSelfModificationSettings(),
|
|
3685
4014
|
selfModificationScope: projectSettings.selfModification ? "project" : "global",
|
|
4015
|
+
autonomy: this.settingsManager.getAutonomySettings(),
|
|
4016
|
+
autonomyScope: projectSettings.autonomy ? "project" : "global",
|
|
3686
4017
|
autoLearn: this.settingsManager.getAutoLearnSettings(),
|
|
3687
4018
|
autoLearnScope: projectSettings.autoLearn ? "project" : "global",
|
|
3688
4019
|
autoLearnModelOptions: this.getAutoLearnModelOptions(),
|
|
@@ -3817,6 +4148,10 @@ export class InteractiveMode {
|
|
|
3817
4148
|
}
|
|
3818
4149
|
this.showStatus(`Self modification settings saved to ${scope}. Start a new session or /reload for system-prompt guardrails to fully refresh.`);
|
|
3819
4150
|
},
|
|
4151
|
+
onAutonomyChange: (settings, scope) => {
|
|
4152
|
+
this.applyAutonomyMode(settings.mode ?? "off", scope);
|
|
4153
|
+
this.showStatus(`Autonomy mode ${settings.mode ?? "off"} saved to ${scope}. Use /autonomy status.`);
|
|
4154
|
+
},
|
|
3820
4155
|
onAutoLearnChange: (settings, scope) => {
|
|
3821
4156
|
this.settingsManager.setAutoLearnSettings(settings, scope);
|
|
3822
4157
|
const validationMessage = this.validateAutoLearnModelValue(settings.model);
|