@caupulican/pi-adaptative 0.80.91 → 0.80.94
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 +29 -0
- package/dist/core/agent-session.d.ts +18 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +134 -36
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +2 -2
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +15 -5
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/context/brain-curator.d.ts +21 -0
- package/dist/core/context/brain-curator.d.ts.map +1 -1
- package/dist/core/context/brain-curator.js +66 -0
- package/dist/core/context/brain-curator.js.map +1 -1
- package/dist/core/settings-manager.d.ts +8 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +25 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +17 -10
- package/dist/modes/interactive/interactive-mode.js.map +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
|
@@ -28,7 +28,7 @@ import { composeSubagentSystemPrompt } from "./autonomy/subagent-prompt.js";
|
|
|
28
28
|
import { executeBashWithOperations } from "./bash-executor.js";
|
|
29
29
|
import { calculateContextTokens, collectEntriesForBranchSummary, compact, estimateContextTokens, generateBranchSummary, prepareCompaction, shouldCompact, } from "./compaction/index.js";
|
|
30
30
|
// (module-scope helper for curation goal extraction defined below the imports)
|
|
31
|
-
import { BrainCurator } from "./context/brain-curator.js";
|
|
31
|
+
import { BrainCurator, preDigestConversationText } from "./context/brain-curator.js";
|
|
32
32
|
import { createFileArtifactStore } from "./context/context-artifacts.js";
|
|
33
33
|
import { runContextAudit } from "./context/context-audit.js";
|
|
34
34
|
import { buildContextCompositionReport, formatContextCompositionDashboard, } from "./context/context-composition.js";
|
|
@@ -228,6 +228,9 @@ export class AgentSession {
|
|
|
228
228
|
* contextPolicy.curation setting is enabled AND the model passes the digest fitness gate. */
|
|
229
229
|
_brainCurator = new BrainCurator();
|
|
230
230
|
_lastCurationSkipReason = undefined;
|
|
231
|
+
_inertExtensionWarnings = [];
|
|
232
|
+
_lastPreDigestSkipReason = undefined;
|
|
233
|
+
_unboundToolGrantWarnings = [];
|
|
231
234
|
_toolArtifactStore = undefined;
|
|
232
235
|
_latestContextAuditReport = undefined;
|
|
233
236
|
_latestPromptPolicyReport = undefined;
|
|
@@ -772,48 +775,113 @@ export class AgentSession {
|
|
|
772
775
|
* fitness probe on THIS host (design: unfit or unprobed models are refused with a visible
|
|
773
776
|
* reason, never silently degraded). Fire-and-forget; never throws into a turn.
|
|
774
777
|
*/
|
|
778
|
+
/**
|
|
779
|
+
* Resolve the curation model IFF every gate passes: setting enabled, model configured,
|
|
780
|
+
* resolvable+authed, and digest-fitness-proven on THIS host (canonical "provider/id" ref —
|
|
781
|
+
* runModelFitness stores reports under it, while settings.model may be a bare id or pattern).
|
|
782
|
+
* Sets _lastCurationSkipReason on refusal; never throws.
|
|
783
|
+
*/
|
|
784
|
+
_resolveCurationModelIfFit() {
|
|
785
|
+
const settings = this.settingsManager.getContextCurationSettings();
|
|
786
|
+
if (!settings.enabled) {
|
|
787
|
+
// Never surface a stale refusal reason for a feature the user has since disabled.
|
|
788
|
+
this._lastCurationSkipReason = undefined;
|
|
789
|
+
return undefined;
|
|
790
|
+
}
|
|
791
|
+
if (!settings.model) {
|
|
792
|
+
this._lastCurationSkipReason = "curation_model_unset";
|
|
793
|
+
return undefined;
|
|
794
|
+
}
|
|
795
|
+
const resolved = resolveCliModel({ cliModel: settings.model, modelRegistry: this._modelRegistry });
|
|
796
|
+
if (!resolved.model || !this._modelRegistry.hasConfiguredAuth(resolved.model)) {
|
|
797
|
+
this._lastCurationSkipReason = "curation_model_unresolved";
|
|
798
|
+
return undefined;
|
|
799
|
+
}
|
|
800
|
+
const canonicalRef = `${resolved.model.provider}/${resolved.model.id}`;
|
|
801
|
+
const fitness = FitnessStore.forAgentDir(this._agentDir)
|
|
802
|
+
.getForHost()
|
|
803
|
+
.find((entry) => entry.model === canonicalRef);
|
|
804
|
+
const digestScore = fitness?.report.digest;
|
|
805
|
+
if (!digestScore) {
|
|
806
|
+
this._lastCurationSkipReason = "curation_model_unprobed";
|
|
807
|
+
return undefined;
|
|
808
|
+
}
|
|
809
|
+
if (digestScore.succeeded < Math.ceil(digestScore.total * (2 / 3))) {
|
|
810
|
+
this._lastCurationSkipReason = "curation_model_digest_unfit";
|
|
811
|
+
return undefined;
|
|
812
|
+
}
|
|
813
|
+
this._lastCurationSkipReason = undefined;
|
|
814
|
+
return resolved.model;
|
|
815
|
+
}
|
|
775
816
|
_maybeDrainBrainCuration() {
|
|
776
817
|
try {
|
|
777
|
-
const settings = this.settingsManager.getContextCurationSettings();
|
|
778
|
-
if (!settings.enabled) {
|
|
779
|
-
// Never surface a stale refusal reason for a feature the user has since disabled.
|
|
780
|
-
this._lastCurationSkipReason = undefined;
|
|
781
|
-
return;
|
|
782
|
-
}
|
|
783
818
|
if (!this._brainCurator.hasWork() || this._brainCurator.isDraining)
|
|
784
819
|
return;
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
return;
|
|
788
|
-
}
|
|
789
|
-
const resolved = resolveCliModel({ cliModel: settings.model, modelRegistry: this._modelRegistry });
|
|
790
|
-
if (!resolved.model || !this._modelRegistry.hasConfiguredAuth(resolved.model)) {
|
|
791
|
-
this._lastCurationSkipReason = "curation_model_unresolved";
|
|
792
|
-
return;
|
|
793
|
-
}
|
|
794
|
-
// Match on the CANONICAL "provider/id" ref — runModelFitness stores reports under it,
|
|
795
|
-
// while settings.model may be a bare id or pattern; comparing raw strings would refuse
|
|
796
|
-
// forever with curation_model_unprobed even after a successful probe.
|
|
797
|
-
const canonicalRef = `${resolved.model.provider}/${resolved.model.id}`;
|
|
798
|
-
const fitness = FitnessStore.forAgentDir(this._agentDir)
|
|
799
|
-
.getForHost()
|
|
800
|
-
.find((entry) => entry.model === canonicalRef);
|
|
801
|
-
const digestScore = fitness?.report.digest;
|
|
802
|
-
if (!digestScore) {
|
|
803
|
-
this._lastCurationSkipReason = "curation_model_unprobed";
|
|
804
|
-
return;
|
|
805
|
-
}
|
|
806
|
-
if (digestScore.succeeded < Math.ceil(digestScore.total * (2 / 3))) {
|
|
807
|
-
this._lastCurationSkipReason = "curation_model_digest_unfit";
|
|
820
|
+
const model = this._resolveCurationModelIfFit();
|
|
821
|
+
if (!model)
|
|
808
822
|
return;
|
|
809
|
-
|
|
810
|
-
this.
|
|
811
|
-
void this._drainBrainCuration(resolved.model, settings.maxJobsPerTurn);
|
|
823
|
+
const settings = this.settingsManager.getContextCurationSettings();
|
|
824
|
+
void this._drainBrainCuration(model, settings.maxJobsPerTurn);
|
|
812
825
|
}
|
|
813
826
|
catch {
|
|
814
827
|
// curation is a sidecar; it must never disrupt a turn
|
|
815
828
|
}
|
|
816
829
|
}
|
|
830
|
+
/**
|
|
831
|
+
* Compaction pre-digest gate (design surface 3): everything the drain gate requires PLUS a
|
|
832
|
+
* RUNTIME reliability proof — the curator must have run >=5 jobs on this session with a parse
|
|
833
|
+
* failure rate <=5% before it is trusted to pre-digest compaction input. Returns undefined
|
|
834
|
+
* (verbatim compaction, byte-for-byte today's behavior) whenever any gate refuses.
|
|
835
|
+
*/
|
|
836
|
+
_buildCompactionPreDigest() {
|
|
837
|
+
try {
|
|
838
|
+
const model = this._resolveCurationModelIfFit();
|
|
839
|
+
if (!model)
|
|
840
|
+
return undefined;
|
|
841
|
+
const telemetry = this._brainCurator.telemetry();
|
|
842
|
+
if (telemetry.jobsRun < 5 || telemetry.parseFailures / telemetry.jobsRun > 0.05) {
|
|
843
|
+
this._lastPreDigestSkipReason = "curation_predigest_reliability_unproven";
|
|
844
|
+
return undefined;
|
|
845
|
+
}
|
|
846
|
+
this._lastPreDigestSkipReason = undefined;
|
|
847
|
+
return async (text, signal) => {
|
|
848
|
+
const result = await preDigestConversationText({
|
|
849
|
+
text,
|
|
850
|
+
signal,
|
|
851
|
+
complete: async ({ systemPrompt, userPrompt, signal: chunkSignal }) => {
|
|
852
|
+
const completion = await this.runIsolatedCompletion({
|
|
853
|
+
systemPrompt,
|
|
854
|
+
messages: [{ role: "user", content: [{ type: "text", text: userPrompt }], timestamp: Date.now() }],
|
|
855
|
+
model,
|
|
856
|
+
thinkingLevel: "off",
|
|
857
|
+
maxTokens: 512,
|
|
858
|
+
signal: chunkSignal,
|
|
859
|
+
cacheRetention: "short",
|
|
860
|
+
});
|
|
861
|
+
return {
|
|
862
|
+
text: completion.text,
|
|
863
|
+
costUsd: completion.usage.cost.total,
|
|
864
|
+
stopReason: String(completion.stopReason),
|
|
865
|
+
};
|
|
866
|
+
},
|
|
867
|
+
});
|
|
868
|
+
if (!this._disposed && result.totalChunks > 0) {
|
|
869
|
+
this.sessionManager.appendCustomEntry("brain-curation-predigest", {
|
|
870
|
+
version: 1,
|
|
871
|
+
totalChunks: result.totalChunks,
|
|
872
|
+
digested: result.digested,
|
|
873
|
+
failed: result.failed,
|
|
874
|
+
charsBefore: text.length,
|
|
875
|
+
charsAfter: result.text.length,
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
return result.text;
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
catch {
|
|
882
|
+
return undefined;
|
|
883
|
+
}
|
|
884
|
+
}
|
|
817
885
|
async _drainBrainCuration(model, maxJobs) {
|
|
818
886
|
try {
|
|
819
887
|
// ACCUMULATE across all drained jobs (the drain runs the completer once PER job) —
|
|
@@ -932,7 +1000,15 @@ export class AgentSession {
|
|
|
932
1000
|
},
|
|
933
1001
|
spawned: { cost: spawned.cost, reports: spawned.reports },
|
|
934
1002
|
adjustments: { memoryEvidenceTokens, enforcementSavedTokens },
|
|
935
|
-
extraObservations:
|
|
1003
|
+
extraObservations: [
|
|
1004
|
+
...this._resourceLoader.getAgentsDiagnostics().map((diagnostic) => diagnostic.message),
|
|
1005
|
+
...this._inertExtensionWarnings,
|
|
1006
|
+
...this._unboundToolGrantWarnings,
|
|
1007
|
+
// G14 (ratified): a user disable always beats a profile grant — surface the conflict.
|
|
1008
|
+
...["tools", "skills", "prompts", "extensions"].flatMap((kind) => this.settingsManager
|
|
1009
|
+
.getProfileGrantsOverriddenByUserDisable(kind)
|
|
1010
|
+
.map((entry) => `profile grants ${kind} "${entry}" but your disable list overrides it (user disable wins; re-enable to use)`)),
|
|
1011
|
+
],
|
|
936
1012
|
});
|
|
937
1013
|
}
|
|
938
1014
|
/** Bounded plain-text rendering of {@link getContextCompositionReport} for the /context command. */
|
|
@@ -947,6 +1023,7 @@ export class AgentSession {
|
|
|
947
1023
|
model: settings.model,
|
|
948
1024
|
telemetry: this._brainCurator.telemetry(),
|
|
949
1025
|
lastSkipReason: this._lastCurationSkipReason,
|
|
1026
|
+
lastPreDigestSkipReason: this._lastPreDigestSkipReason,
|
|
950
1027
|
};
|
|
951
1028
|
}
|
|
952
1029
|
/** Read-only inspection of the latest prompt-enforcement report, for tests/debugging. */
|
|
@@ -3037,7 +3114,7 @@ export class AgentSession {
|
|
|
3037
3114
|
}
|
|
3038
3115
|
else {
|
|
3039
3116
|
// Generate compaction result
|
|
3040
|
-
const result = await compact(preparation, compactionModel, apiKey, headers, customInstructions, this._compactionAbortController.signal, this.thinkingLevel, this.agent.streamFn);
|
|
3117
|
+
const result = await compact(preparation, compactionModel, apiKey, headers, customInstructions, this._compactionAbortController.signal, this.thinkingLevel, this.agent.streamFn, this._buildCompactionPreDigest());
|
|
3041
3118
|
summary = result.summary;
|
|
3042
3119
|
firstKeptEntryId = result.firstKeptEntryId;
|
|
3043
3120
|
tokensBefore = result.tokensBefore;
|
|
@@ -3336,7 +3413,7 @@ export class AgentSession {
|
|
|
3336
3413
|
}
|
|
3337
3414
|
else {
|
|
3338
3415
|
// Generate compaction result
|
|
3339
|
-
const compactResult = await compact(preparation, compactionModel, apiKey, headers, undefined, this._autoCompactionAbortController.signal, this.thinkingLevel, this.agent.streamFn);
|
|
3416
|
+
const compactResult = await compact(preparation, compactionModel, apiKey, headers, undefined, this._autoCompactionAbortController.signal, this.thinkingLevel, this.agent.streamFn, this._buildCompactionPreDigest());
|
|
3340
3417
|
summary = compactResult.summary;
|
|
3341
3418
|
firstKeptEntryId = compactResult.firstKeptEntryId;
|
|
3342
3419
|
tokensBefore = compactResult.tokensBefore;
|
|
@@ -3651,6 +3728,7 @@ export class AgentSession {
|
|
|
3651
3728
|
(this._toolProfileFilter.allow.length > 0 || this._toolProfileFilter.block.length > 0)));
|
|
3652
3729
|
}
|
|
3653
3730
|
_filterExtensionsForRuntime(extensions) {
|
|
3731
|
+
this._inertExtensionWarnings = [];
|
|
3654
3732
|
if (this.settingsManager.getActiveResourceProfileNames().length === 0) {
|
|
3655
3733
|
return this.settingsManager.hasExplicitActiveResourceProfileSelection()
|
|
3656
3734
|
? []
|
|
@@ -3664,6 +3742,13 @@ export class AgentSession {
|
|
|
3664
3742
|
return extension;
|
|
3665
3743
|
const tools = new Map(Array.from(extension.tools.entries()).filter(([name]) => this._isToolOrCommandAllowedByProfile(name)));
|
|
3666
3744
|
const commands = new Map(Array.from(extension.commands.entries()).filter(([name]) => this._isToolOrCommandAllowedByProfile(name)));
|
|
3745
|
+
// G12: an extension the profile ALLOWS whose every tool and command the tools filter
|
|
3746
|
+
// then denies loads and runs lifecycle hooks but is completely uninvocable — surface
|
|
3747
|
+
// it instead of presenting a "loaded" extension that silently does nothing.
|
|
3748
|
+
if (extension.tools.size + extension.commands.size > 0 && tools.size + commands.size === 0) {
|
|
3749
|
+
const name = extension.path.split(/[\\/]/).pop() ?? extension.path;
|
|
3750
|
+
this._inertExtensionWarnings.push(`extension "${name}" is loaded but fully inert: the active profile's tools filter denies all ${extension.tools.size} tool(s) and ${extension.commands.size} command(s) it contributes`);
|
|
3751
|
+
}
|
|
3667
3752
|
return { ...extension, tools, commands };
|
|
3668
3753
|
});
|
|
3669
3754
|
}
|
|
@@ -3868,14 +3953,27 @@ export class AgentSession {
|
|
|
3868
3953
|
// stays grant-only: activation then still derives from the request/defaults above.
|
|
3869
3954
|
const explicitAllowPatterns = toolProfileFilter?.allow.filter((pattern) => pattern !== "*") ?? [];
|
|
3870
3955
|
if (explicitAllowPatterns.length > 0) {
|
|
3956
|
+
const boundPatterns = new Set();
|
|
3871
3957
|
for (const toolName of this._toolRegistry.keys()) {
|
|
3872
3958
|
if (!isAllowedTool(toolName))
|
|
3873
3959
|
continue;
|
|
3960
|
+
for (const pattern of explicitAllowPatterns) {
|
|
3961
|
+
if (matchesResourceProfilePattern(toolName, [pattern]))
|
|
3962
|
+
boundPatterns.add(pattern);
|
|
3963
|
+
}
|
|
3874
3964
|
if (matchesResourceProfilePattern(toolName, explicitAllowPatterns)) {
|
|
3875
3965
|
nextActiveToolNames.push(toolName);
|
|
3876
3966
|
autoActivated.push(toolName);
|
|
3877
3967
|
}
|
|
3878
3968
|
}
|
|
3969
|
+
// G13: an explicit grant that binds to NO registered tool is a silent no-op — typo'd
|
|
3970
|
+
// name, or the owning extension is not granted/loaded. Surface it.
|
|
3971
|
+
this._unboundToolGrantWarnings = explicitAllowPatterns
|
|
3972
|
+
.filter((pattern) => !boundPatterns.has(pattern))
|
|
3973
|
+
.map((pattern) => `profile tool grant "${pattern}" binds to no registered tool (typo, or the owning extension is not granted/loaded)`);
|
|
3974
|
+
}
|
|
3975
|
+
else {
|
|
3976
|
+
this._unboundToolGrantWarnings = [];
|
|
3879
3977
|
}
|
|
3880
3978
|
// artifact_retrieve companion auto-activation is enforced inside
|
|
3881
3979
|
// setActiveToolsByName() itself (not duplicated here), so every activation path --
|