@caupulican/pi-adaptative 0.80.90 → 0.80.93
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 +33 -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 -35
- 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/context/context-composition.d.ts +2 -0
- package/dist/core/context/context-composition.d.ts.map +1 -1
- package/dist/core/context/context-composition.js +1 -1
- package/dist/core/context/context-composition.js.map +1 -1
- package/dist/core/profile-resource-selection.d.ts.map +1 -1
- package/dist/core/profile-resource-selection.js +19 -6
- package/dist/core/profile-resource-selection.js.map +1 -1
- package/dist/core/resource-loader.d.ts +22 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +54 -0
- package/dist/core/resource-loader.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/components/profile-resource-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/profile-resource-editor.js +11 -4
- package/dist/modes/interactive/components/profile-resource-editor.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +65 -14
- 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/examples/sdk/12-full-control.ts +4 -0
- 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,6 +1000,15 @@ export class AgentSession {
|
|
|
932
1000
|
},
|
|
933
1001
|
spawned: { cost: spawned.cost, reports: spawned.reports },
|
|
934
1002
|
adjustments: { memoryEvidenceTokens, enforcementSavedTokens },
|
|
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
|
+
],
|
|
935
1012
|
});
|
|
936
1013
|
}
|
|
937
1014
|
/** Bounded plain-text rendering of {@link getContextCompositionReport} for the /context command. */
|
|
@@ -946,6 +1023,7 @@ export class AgentSession {
|
|
|
946
1023
|
model: settings.model,
|
|
947
1024
|
telemetry: this._brainCurator.telemetry(),
|
|
948
1025
|
lastSkipReason: this._lastCurationSkipReason,
|
|
1026
|
+
lastPreDigestSkipReason: this._lastPreDigestSkipReason,
|
|
949
1027
|
};
|
|
950
1028
|
}
|
|
951
1029
|
/** Read-only inspection of the latest prompt-enforcement report, for tests/debugging. */
|
|
@@ -3036,7 +3114,7 @@ export class AgentSession {
|
|
|
3036
3114
|
}
|
|
3037
3115
|
else {
|
|
3038
3116
|
// Generate compaction result
|
|
3039
|
-
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());
|
|
3040
3118
|
summary = result.summary;
|
|
3041
3119
|
firstKeptEntryId = result.firstKeptEntryId;
|
|
3042
3120
|
tokensBefore = result.tokensBefore;
|
|
@@ -3335,7 +3413,7 @@ export class AgentSession {
|
|
|
3335
3413
|
}
|
|
3336
3414
|
else {
|
|
3337
3415
|
// Generate compaction result
|
|
3338
|
-
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());
|
|
3339
3417
|
summary = compactResult.summary;
|
|
3340
3418
|
firstKeptEntryId = compactResult.firstKeptEntryId;
|
|
3341
3419
|
tokensBefore = compactResult.tokensBefore;
|
|
@@ -3650,6 +3728,7 @@ export class AgentSession {
|
|
|
3650
3728
|
(this._toolProfileFilter.allow.length > 0 || this._toolProfileFilter.block.length > 0)));
|
|
3651
3729
|
}
|
|
3652
3730
|
_filterExtensionsForRuntime(extensions) {
|
|
3731
|
+
this._inertExtensionWarnings = [];
|
|
3653
3732
|
if (this.settingsManager.getActiveResourceProfileNames().length === 0) {
|
|
3654
3733
|
return this.settingsManager.hasExplicitActiveResourceProfileSelection()
|
|
3655
3734
|
? []
|
|
@@ -3663,6 +3742,13 @@ export class AgentSession {
|
|
|
3663
3742
|
return extension;
|
|
3664
3743
|
const tools = new Map(Array.from(extension.tools.entries()).filter(([name]) => this._isToolOrCommandAllowedByProfile(name)));
|
|
3665
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
|
+
}
|
|
3666
3752
|
return { ...extension, tools, commands };
|
|
3667
3753
|
});
|
|
3668
3754
|
}
|
|
@@ -3867,14 +3953,27 @@ export class AgentSession {
|
|
|
3867
3953
|
// stays grant-only: activation then still derives from the request/defaults above.
|
|
3868
3954
|
const explicitAllowPatterns = toolProfileFilter?.allow.filter((pattern) => pattern !== "*") ?? [];
|
|
3869
3955
|
if (explicitAllowPatterns.length > 0) {
|
|
3956
|
+
const boundPatterns = new Set();
|
|
3870
3957
|
for (const toolName of this._toolRegistry.keys()) {
|
|
3871
3958
|
if (!isAllowedTool(toolName))
|
|
3872
3959
|
continue;
|
|
3960
|
+
for (const pattern of explicitAllowPatterns) {
|
|
3961
|
+
if (matchesResourceProfilePattern(toolName, [pattern]))
|
|
3962
|
+
boundPatterns.add(pattern);
|
|
3963
|
+
}
|
|
3873
3964
|
if (matchesResourceProfilePattern(toolName, explicitAllowPatterns)) {
|
|
3874
3965
|
nextActiveToolNames.push(toolName);
|
|
3875
3966
|
autoActivated.push(toolName);
|
|
3876
3967
|
}
|
|
3877
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 = [];
|
|
3878
3977
|
}
|
|
3879
3978
|
// artifact_retrieve companion auto-activation is enforced inside
|
|
3880
3979
|
// setActiveToolsByName() itself (not duplicated here), so every activation path --
|