@caupulican/pi-adaptative 0.80.84 → 0.80.86

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/core/agent-session.d.ts +20 -0
  3. package/dist/core/agent-session.d.ts.map +1 -1
  4. package/dist/core/agent-session.js +113 -6
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/cost-guard.d.ts +1 -1
  7. package/dist/core/cost-guard.d.ts.map +1 -1
  8. package/dist/core/cost-guard.js +2 -2
  9. package/dist/core/cost-guard.js.map +1 -1
  10. package/dist/core/profile-registry.d.ts +2 -1
  11. package/dist/core/profile-registry.d.ts.map +1 -1
  12. package/dist/core/profile-registry.js +32 -2
  13. package/dist/core/profile-registry.js.map +1 -1
  14. package/dist/core/resource-loader.d.ts.map +1 -1
  15. package/dist/core/resource-loader.js +3 -1
  16. package/dist/core/resource-loader.js.map +1 -1
  17. package/dist/core/settings-manager.d.ts +2 -0
  18. package/dist/core/settings-manager.d.ts.map +1 -1
  19. package/dist/core/settings-manager.js +33 -3
  20. package/dist/core/settings-manager.js.map +1 -1
  21. package/dist/modes/interactive/components/profile-selector.d.ts.map +1 -1
  22. package/dist/modes/interactive/components/profile-selector.js +2 -0
  23. package/dist/modes/interactive/components/profile-selector.js.map +1 -1
  24. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  25. package/dist/modes/interactive/interactive-mode.js +3 -0
  26. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  27. package/dist/modes/print-mode.d.ts.map +1 -1
  28. package/dist/modes/print-mode.js +3 -0
  29. package/dist/modes/print-mode.js.map +1 -1
  30. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  31. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  32. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  33. package/examples/extensions/sandbox/package-lock.json +2 -2
  34. package/examples/extensions/sandbox/package.json +1 -1
  35. package/examples/extensions/with-deps/package-lock.json +2 -2
  36. package/examples/extensions/with-deps/package.json +1 -1
  37. package/npm-shrinkwrap.json +12 -12
  38. package/package.json +4 -4
@@ -153,6 +153,7 @@ export class AgentSession {
153
153
  _activeModelRouterIntent;
154
154
  _modelRouterSessionBuffer;
155
155
  _modelRouterEscalationRequested = false;
156
+ _isModelRouterRetry = false;
156
157
  _lastModelRouterDecision;
157
158
  _lastModelRouterSkipReason;
158
159
  _lastModelRouterIntent;
@@ -295,7 +296,7 @@ export class AgentSession {
295
296
  const authoritativeMessages = this.agent.state.messages.length > 0 ? this.agent.state.messages : transformed;
296
297
  let currentMessages = authoritativeMessages;
297
298
  try {
298
- const settings = this.settingsManager.getCompactionSettings();
299
+ const settings = this._getAdaptedCompactionSettings();
299
300
  const contextWindow = this.model?.contextWindow ?? 0;
300
301
  if (settings.enabled && contextWindow > 0 && !this.isCompacting) {
301
302
  const contextTokens = this._estimateCurrentContextTokens(authoritativeMessages);
@@ -584,8 +585,13 @@ export class AgentSession {
584
585
  }
585
586
  // Emit to extensions first
586
587
  await this._emitExtensionEvent(event);
588
+ const suppressRetryPromptEvent = this._isModelRouterRetry &&
589
+ (event.type === "message_start" || event.type === "message_end") &&
590
+ (event.message.role === "user" || event.message.role === "custom");
587
591
  // Notify all listeners
588
- this._emit(event.type === "agent_end" ? { ...event, willRetry: this._willRetryAfterAgentEnd(event) } : event);
592
+ if (!suppressRetryPromptEvent) {
593
+ this._emit(event.type === "agent_end" ? { ...event, willRetry: this._willRetryAfterAgentEnd(event) } : event);
594
+ }
589
595
  // Handle session/context retention. Tool result details are UI/log metadata,
590
596
  // not provider-visible content, and large graph/search payloads can otherwise
591
597
  // accumulate until the interactive Node process hits the V8 heap limit.
@@ -926,6 +932,7 @@ export class AgentSession {
926
932
  // Rebuild base system prompt with new tool set
927
933
  this._baseSystemPrompt = this._rebuildSystemPrompt(validToolNames);
928
934
  this.agent.state.systemPrompt = this._baseSystemPrompt;
935
+ this._checkContextWindowUsageWarning();
929
936
  }
930
937
  /** Whether compaction or branch summarization is currently running */
931
938
  get isCompacting() {
@@ -1243,8 +1250,11 @@ export class AgentSession {
1243
1250
  this._modelRouterEscalationRequested = previousModelRouterEscalationRequested;
1244
1251
  }
1245
1252
  if (retryModel && !thrownError) {
1253
+ const previousIsModelRouterRetry = this._isModelRouterRetry;
1246
1254
  try {
1255
+ this._isModelRouterRetry = true;
1247
1256
  await this._runAgentPromptWithModelRouter(messages, retryModel, "modify", false);
1257
+ this._lastModelRouterDecision = completedDecision;
1248
1258
  }
1249
1259
  catch (error) {
1250
1260
  thrownError = error;
@@ -1253,6 +1263,9 @@ export class AgentSession {
1253
1263
  this._lastModelRouterDecision = completedDecision;
1254
1264
  }
1255
1265
  }
1266
+ finally {
1267
+ this._isModelRouterRetry = previousIsModelRouterRetry;
1268
+ }
1256
1269
  }
1257
1270
  if (persistDecision && completedDecision) {
1258
1271
  persistModelRouterDecision(this.sessionManager, completedDecision);
@@ -1404,6 +1417,7 @@ export class AgentSession {
1404
1417
  }
1405
1418
  throw new Error(formatNoApiKeyFoundMessage(requestModel.provider));
1406
1419
  }
1420
+ this._checkContextWindowUsageWarning();
1407
1421
  // Check if we need to compact before sending (catches aborted responses).
1408
1422
  // Do not call agent.continue() here: the next model turn must include the
1409
1423
  // user's pending prompt, not an empty continuation after compaction.
@@ -1814,6 +1828,7 @@ export class AgentSession {
1814
1828
  // Re-clamp thinking level for new model's capabilities
1815
1829
  this.setThinkingLevel(thinkingLevel, { persistSettings });
1816
1830
  await this._emitModelSelect(model, previousModel, "set");
1831
+ this._checkContextWindowUsageWarning();
1817
1832
  }
1818
1833
  /**
1819
1834
  * Cycle to next/previous model.
@@ -1849,6 +1864,7 @@ export class AgentSession {
1849
1864
  // setThinkingLevel clamps to model capabilities.
1850
1865
  this.setThinkingLevel(thinkingLevel);
1851
1866
  await this._emitModelSelect(next.model, currentModel, "cycle");
1867
+ this._checkContextWindowUsageWarning();
1852
1868
  return { model: next.model, thinkingLevel: this.thinkingLevel, isScoped: true };
1853
1869
  }
1854
1870
  async _cycleAvailableModel(direction) {
@@ -1869,6 +1885,7 @@ export class AgentSession {
1869
1885
  // Re-clamp thinking level for new model's capabilities
1870
1886
  this.setThinkingLevel(thinkingLevel);
1871
1887
  await this._emitModelSelect(nextModel, currentModel, "cycle");
1888
+ this._checkContextWindowUsageWarning();
1872
1889
  return { model: nextModel, thinkingLevel: this.thinkingLevel, isScoped: false };
1873
1890
  }
1874
1891
  // =========================================================================
@@ -1980,7 +1997,7 @@ export class AgentSession {
1980
1997
  const compactionModel = this._resolveCompactionModel(this.model);
1981
1998
  const { apiKey, headers } = await this._getCompactionRequestAuth(compactionModel);
1982
1999
  const pathEntries = this.sessionManager.getBranch();
1983
- const settings = this.settingsManager.getCompactionSettings();
2000
+ const settings = this._getAdaptedCompactionSettings();
1984
2001
  const preparation = prepareCompaction(pathEntries, settings);
1985
2002
  if (!preparation) {
1986
2003
  // Check why we can't compact
@@ -2100,8 +2117,57 @@ export class AgentSession {
2100
2117
  * @param assistantMessage The assistant message to check
2101
2118
  * @param skipAbortedCheck If false, include aborted messages (for pre-prompt check). Default: true
2102
2119
  */
2103
- async _checkCompaction(assistantMessage, skipAbortedCheck = true) {
2120
+ _getAdaptedCompactionSettings() {
2104
2121
  const settings = this.settingsManager.getCompactionSettings();
2122
+ if (!this.model)
2123
+ return settings;
2124
+ const contextWindow = this.model.contextWindow ?? 0;
2125
+ if (contextWindow <= 0)
2126
+ return settings;
2127
+ // Adapt reserveTokens: at most 25% of context window
2128
+ const maxReserve = Math.floor(contextWindow * 0.25);
2129
+ const reserveTokens = Math.min(settings.reserveTokens, maxReserve);
2130
+ // Adapt keepRecentTokens: at most 50% of context window
2131
+ const maxKeepRecent = Math.floor(contextWindow * 0.5);
2132
+ const keepRecentTokens = Math.min(settings.keepRecentTokens, maxKeepRecent);
2133
+ return {
2134
+ ...settings,
2135
+ reserveTokens,
2136
+ keepRecentTokens,
2137
+ };
2138
+ }
2139
+ _checkContextWindowUsageWarning() {
2140
+ if (!this.model)
2141
+ return;
2142
+ const contextWindow = this.model.contextWindow ?? 0;
2143
+ if (contextWindow <= 0)
2144
+ return;
2145
+ const systemPromptTokens = Math.ceil((this.agent.state.systemPrompt ?? "").length / 4);
2146
+ let toolsChars = 0;
2147
+ for (const tool of this.agent.state.tools || []) {
2148
+ toolsChars += tool.name.length;
2149
+ toolsChars += tool.description?.length ?? 0;
2150
+ if (tool.parameters) {
2151
+ toolsChars += JSON.stringify(tool.parameters).length;
2152
+ }
2153
+ }
2154
+ const toolsTokens = Math.ceil(toolsChars / 4);
2155
+ const baseTokens = systemPromptTokens + toolsTokens;
2156
+ if (baseTokens >= contextWindow) {
2157
+ this._emit({
2158
+ type: "warning",
2159
+ message: `Base configuration (system prompt and active tools) consumes ${baseTokens} tokens, which exceeds the model's context window of ${contextWindow} tokens. The model cannot process any prompts in this state.`,
2160
+ });
2161
+ }
2162
+ else if (baseTokens >= contextWindow * 0.7) {
2163
+ this._emit({
2164
+ type: "warning",
2165
+ message: `Base configuration (system prompt and active tools) consumes ${baseTokens} tokens (${Math.round((baseTokens / contextWindow) * 100)}% of the ${contextWindow} context window). This leaves very little room for conversation history and may cause immediate compaction or context overflow.`,
2166
+ });
2167
+ }
2168
+ }
2169
+ async _checkCompaction(assistantMessage, skipAbortedCheck = true) {
2170
+ const settings = this._getAdaptedCompactionSettings();
2105
2171
  if (!settings.enabled)
2106
2172
  return false;
2107
2173
  // Skip if message was aborted (user cancelled) - unless skipAbortedCheck is false
@@ -2185,7 +2251,7 @@ export class AgentSession {
2185
2251
  * Internal: Run auto-compaction with events.
2186
2252
  */
2187
2253
  async _runAutoCompaction(reason, willRetry) {
2188
- const settings = this.settingsManager.getCompactionSettings();
2254
+ const settings = this._getAdaptedCompactionSettings();
2189
2255
  this._emit({ type: "compaction_start", reason });
2190
2256
  this._autoCompactionAbortController = new AbortController();
2191
2257
  try {
@@ -2565,6 +2631,43 @@ export class AgentSession {
2565
2631
  const filter = this.settingsManager.getResourceProfileFilter("tools");
2566
2632
  return { allow: filter.allow ?? [], block: filter.block ?? [] };
2567
2633
  }
2634
+ _isToolOrCommandAllowedByProfile(name) {
2635
+ if (this._allowedToolNames && !this._allowedToolNames.has(name))
2636
+ return false;
2637
+ if (this._excludedToolNames?.has(name))
2638
+ return false;
2639
+ const filter = this._toolProfileFilter;
2640
+ if (!filter)
2641
+ return true;
2642
+ if (filter.allow.length > 0 && !matchesResourceProfilePattern(name, filter.allow))
2643
+ return false;
2644
+ if (matchesResourceProfilePattern(name, filter.block))
2645
+ return false;
2646
+ return true;
2647
+ }
2648
+ _hasToolOrCommandProfileGate() {
2649
+ return Boolean(this._allowedToolNames ||
2650
+ this._excludedToolNames ||
2651
+ (this._toolProfileFilter &&
2652
+ (this._toolProfileFilter.allow.length > 0 || this._toolProfileFilter.block.length > 0)));
2653
+ }
2654
+ _filterExtensionsForRuntime(extensions) {
2655
+ if (this.settingsManager.getActiveResourceProfileNames().length === 0) {
2656
+ return this.settingsManager.hasExplicitActiveResourceProfileSelection()
2657
+ ? []
2658
+ : extensions.filter((extension) => extension.sourceInfo.source === "inline");
2659
+ }
2660
+ const hasToolOrCommandGate = this._hasToolOrCommandProfileGate();
2661
+ return extensions
2662
+ .filter((extension) => this.settingsManager.isResourceAllowedByProfile("extensions", extension.path, extension.sourceInfo.baseDir))
2663
+ .map((extension) => {
2664
+ if (!hasToolOrCommandGate)
2665
+ return extension;
2666
+ const tools = new Map(Array.from(extension.tools.entries()).filter(([name]) => this._isToolOrCommandAllowedByProfile(name)));
2667
+ const commands = new Map(Array.from(extension.commands.entries()).filter(([name]) => this._isToolOrCommandAllowedByProfile(name)));
2668
+ return { ...extension, tools, commands };
2669
+ });
2670
+ }
2568
2671
  /**
2569
2672
  * Re-resolve the active resource profile's model/thinking from current settings and apply it.
2570
2673
  * Only acts when the profile actually binds model/thinking AND that field was not set by an
@@ -2826,7 +2929,11 @@ export class AgentSession {
2826
2929
  extensionsResult.runtime.flagValues.set(name, value);
2827
2930
  }
2828
2931
  }
2829
- this._extensionRunner = new ExtensionRunner(extensionsResult.extensions, extensionsResult.runtime, this._cwd, this.sessionManager, this._modelRegistry);
2932
+ const extensions = this._filterExtensionsForRuntime(extensionsResult.extensions);
2933
+ const runtimeExtensionPaths = new Set(extensions.map((extension) => extension.path));
2934
+ extensionsResult.runtime.pendingProviderRegistrations =
2935
+ extensionsResult.runtime.pendingProviderRegistrations.filter((registration) => runtimeExtensionPaths.has(registration.extensionPath));
2936
+ this._extensionRunner = new ExtensionRunner(extensions, extensionsResult.runtime, this._cwd, this.sessionManager, this._modelRegistry);
2830
2937
  if (this._extensionRunnerRef) {
2831
2938
  this._extensionRunnerRef.current = this._extensionRunner;
2832
2939
  }