@caupulican/pi-adaptative 0.81.16 → 0.81.18

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 (42) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/bundled-resources/skills/tool-call-repair/references/repair-catalogue.md +18 -0
  3. package/dist/core/agent-session.d.ts +6 -0
  4. package/dist/core/agent-session.d.ts.map +1 -1
  5. package/dist/core/agent-session.js +109 -9
  6. package/dist/core/agent-session.js.map +1 -1
  7. package/dist/core/models/adaptation-store.d.ts +3 -0
  8. package/dist/core/models/adaptation-store.d.ts.map +1 -1
  9. package/dist/core/models/adaptation-store.js +12 -0
  10. package/dist/core/models/adaptation-store.js.map +1 -1
  11. package/dist/core/models/context-sizing.d.ts +30 -0
  12. package/dist/core/models/context-sizing.d.ts.map +1 -0
  13. package/dist/core/models/context-sizing.js +90 -0
  14. package/dist/core/models/context-sizing.js.map +1 -0
  15. package/dist/core/models/default-model-suggestions.d.ts.map +1 -1
  16. package/dist/core/models/default-model-suggestions.js +9 -0
  17. package/dist/core/models/default-model-suggestions.js.map +1 -1
  18. package/dist/core/models/local-runtime.d.ts +19 -0
  19. package/dist/core/models/local-runtime.d.ts.map +1 -1
  20. package/dist/core/models/local-runtime.js +43 -0
  21. package/dist/core/models/local-runtime.js.map +1 -1
  22. package/dist/core/models/perf-profile.d.ts +36 -0
  23. package/dist/core/models/perf-profile.d.ts.map +1 -0
  24. package/dist/core/models/perf-profile.js +163 -0
  25. package/dist/core/models/perf-profile.js.map +1 -0
  26. package/dist/core/models/runtime-arbiter.d.ts +57 -0
  27. package/dist/core/models/runtime-arbiter.d.ts.map +1 -0
  28. package/dist/core/models/runtime-arbiter.js +49 -0
  29. package/dist/core/models/runtime-arbiter.js.map +1 -0
  30. package/dist/modes/interactive/local-model-commands.d.ts.map +1 -1
  31. package/dist/modes/interactive/local-model-commands.js +30 -3
  32. package/dist/modes/interactive/local-model-commands.js.map +1 -1
  33. package/docs/models.md +1 -0
  34. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  35. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  36. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  37. package/examples/extensions/sandbox/package-lock.json +2 -2
  38. package/examples/extensions/sandbox/package.json +1 -1
  39. package/examples/extensions/with-deps/package-lock.json +2 -2
  40. package/examples/extensions/with-deps/package.json +1 -1
  41. package/npm-shrinkwrap.json +12 -12
  42. package/package.json +34 -4
@@ -1,7 +1,7 @@
1
1
  import { readFileSync, rmSync, writeFileSync } from "node:fs";
2
2
  import { tmpdir } from "node:os";
3
3
  import { basename, dirname, join } from "node:path";
4
- import { classifyFailure, compactToolResultDetailsForRetention, computeRetryDelayMs, createCustomMessage, DEFAULT_RETRY_POLICY, RetryController, sleepAbortable, withStreamIdleWatchdog, } from "@caupulican/pi-agent-core";
4
+ import { classifyFailure, compactToolResultDetailsForRetention, computeRetryDelayMs, createCustomMessage, DEFAULT_RETRY_POLICY, DEFAULT_STREAM_IDLE, RetryController, sleepAbortable, withStreamIdleWatchdog, } from "@caupulican/pi-agent-core";
5
5
  import { calculateContextTokens, compact, createDeterministicCompaction, estimateContextTokens, getLatestCompactionEntry, prepareCompaction, runCompactionLoop, shouldCompact, } from "@caupulican/pi-agent-core/node";
6
6
  import { cleanupSessionResources, formatToolRepairStandingRule, generateTextToolProtocolPrimer, isContextOverflow, parseTextToolCalls, streamSimple, } from "@caupulican/pi-ai";
7
7
  import { Type } from "typebox";
@@ -31,6 +31,7 @@ import { deriveModelCapabilityProfile, filterToolNamesForCapability, } from "./m
31
31
  import { formatModelRouterModel, ModelRouterController } from "./model-router-controller.js";
32
32
  import { ModelSelectionController } from "./model-selection-controller.js";
33
33
  import { ModelAdaptationStore } from "./models/adaptation-store.js";
34
+ import { DEFAULT_ADAPTIVE_STREAM_IDLE_CEILING_MS, estimateContextPromptTokens, resolveAdaptiveStreamIdleOptions, withModelPerfProfile, } from "./models/perf-profile.js";
34
35
  import { ProfileFilterController } from "./profile-filter-controller.js";
35
36
  import { expandPromptTemplate } from "./prompt-templates.js";
36
37
  import { ReflectionController } from "./reflection-controller.js";
@@ -159,6 +160,8 @@ export class AgentSession {
159
160
  _collectWorkspaceSources;
160
161
  _localRuntimeController;
161
162
  _modelAdaptationStore;
163
+ _prefixWarmer;
164
+ _completedPrefixWarms = new Set();
162
165
  _repairModeSessionCounts = new Map();
163
166
  _textProtocolParseFailures = new Map();
164
167
  _textProtocolParseObservedThisTurn = false;
@@ -240,14 +243,35 @@ export class AgentSession {
240
243
  // withStreamIdleWatchdog's contract), so no extra drain is added at this wiring site.
241
244
  // Wrapping also breaks the `streamFn === streamSimple` identity the auth-injection checks
242
245
  // use, so the wrapper carries a rawness marker that _isRawStreamSimple reads.
246
+ const agentDir = config.agentDir ?? getAgentDir();
247
+ const modelAdaptationStore = ModelAdaptationStore.forAgentDir(agentDir);
243
248
  const baseStreamFn = this.agent.streamFn;
249
+ const profiledStreamFn = withModelPerfProfile(baseStreamFn, {
250
+ modelKey: (model) => formatModelRouterModel(model),
251
+ recordSample: (modelKey, sample) => {
252
+ modelAdaptationStore.recordPerfSample(modelKey, sample);
253
+ },
254
+ });
244
255
  // `this.settingsManager` is assigned below; the resolver closes over the config reference
245
256
  // because the wrapper must be installed before that assignment runs.
246
257
  const stallSettingsSource = config.settingsManager;
247
- this.agent.streamFn = tagRawness(withStreamIdleWatchdog(baseStreamFn, () => ({
248
- ...stallSettingsSource.getStreamStallSettings(),
249
- ...streamIdleOptionsOverride,
250
- })), baseStreamFn === streamSimple);
258
+ this.agent.streamFn = tagRawness(withStreamIdleWatchdog(profiledStreamFn, (model, context) => {
259
+ const configured = {
260
+ ...stallSettingsSource.getStreamStallSettings(),
261
+ ...streamIdleOptionsOverride,
262
+ };
263
+ const httpIdleTimeoutMs = stallSettingsSource.getHttpIdleTimeoutMs();
264
+ const profile = modelAdaptationStore.get(formatModelRouterModel(model)).perf;
265
+ const adaptive = resolveAdaptiveStreamIdleOptions({
266
+ base: { ...DEFAULT_STREAM_IDLE, ...configured },
267
+ profile,
268
+ promptTokens: estimateContextPromptTokens(context),
269
+ ceilingMs: httpIdleTimeoutMs === 0
270
+ ? DEFAULT_ADAPTIVE_STREAM_IDLE_CEILING_MS
271
+ : Math.max(DEFAULT_STREAM_IDLE.quietIdleMs, httpIdleTimeoutMs - 60_000),
272
+ });
273
+ return { ...configured, ...adaptive };
274
+ }), baseStreamFn === streamSimple);
251
275
  this.sessionManager = config.sessionManager;
252
276
  this.settingsManager = config.settingsManager;
253
277
  // Auto-retry rides the reliability kernel: the controller owns the attempt counter and the
@@ -271,8 +295,8 @@ export class AgentSession {
271
295
  this._resourceLoader = config.resourceLoader;
272
296
  this._customTools = config.customTools ?? [];
273
297
  this._cwd = config.cwd;
274
- this._agentDir = config.agentDir ?? getAgentDir();
275
- this._modelAdaptationStore = ModelAdaptationStore.forAgentDir(this._agentDir);
298
+ this._agentDir = agentDir;
299
+ this._modelAdaptationStore = modelAdaptationStore;
276
300
  this.agent.onTextToolProtocolParse = (event) => this._handleTextToolProtocolParse(event);
277
301
  this._applyToolRepairLayerSettings();
278
302
  this._collectWorkspaceSources = config.collectWorkspaceSources ?? collectWorkspaceSources;
@@ -589,11 +613,82 @@ export class AgentSession {
589
613
  activeToolNames: this._initialActiveToolNames,
590
614
  includeAllExtensionTools: true,
591
615
  });
616
+ this._scheduleLocalPrefixWarm(this.agent.state.model, "session-start");
592
617
  }
593
618
  /** Model registry for API key resolution and model discovery */
594
619
  get modelRegistry() {
595
620
  return this._modelRegistry;
596
621
  }
622
+ _scheduleLocalPrefixWarm(model, _reason) {
623
+ if (!model || !this._isWarmableLocalModel(model))
624
+ return;
625
+ const modelKey = formatModelRouterModel(model);
626
+ if (this._completedPrefixWarms.has(modelKey) || this._prefixWarmer?.modelKey === modelKey)
627
+ return;
628
+ this._cancelPrefixWarm();
629
+ const controller = new AbortController();
630
+ const timer = setTimeout(() => {
631
+ const warmer = this._prefixWarmer;
632
+ if (!warmer || warmer.controller !== controller || controller.signal.aborted)
633
+ return;
634
+ warmer.timer = undefined;
635
+ void this._runLocalPrefixWarm(model, modelKey, controller);
636
+ }, 0);
637
+ timer.unref?.();
638
+ this._prefixWarmer = { modelKey, controller, timer };
639
+ }
640
+ _cancelPrefixWarm() {
641
+ const warmer = this._prefixWarmer;
642
+ if (!warmer)
643
+ return;
644
+ if (warmer.timer)
645
+ clearTimeout(warmer.timer);
646
+ warmer.controller.abort(new Error("prefix warmer preempted"));
647
+ this._prefixWarmer = undefined;
648
+ }
649
+ async _runLocalPrefixWarm(model, modelKey, controller) {
650
+ try {
651
+ const options = {
652
+ maxTokens: 1,
653
+ signal: controller.signal,
654
+ onPayload: this.agent.onPayload,
655
+ onResponse: this.agent.onResponse,
656
+ };
657
+ if (this._isRawStreamSimple(this.agent.streamFn)) {
658
+ const auth = await this._getRequiredRequestAuth(model);
659
+ options.apiKey = auth.apiKey;
660
+ options.headers = auth.headers;
661
+ }
662
+ if (controller.signal.aborted)
663
+ return;
664
+ const stream = await this.agent.streamFn(model, {
665
+ systemPrompt: this._baseSystemPrompt,
666
+ tools: this.agent.state.tools,
667
+ messages: [],
668
+ }, options);
669
+ await stream.result();
670
+ if (!controller.signal.aborted)
671
+ this._completedPrefixWarms.add(modelKey);
672
+ }
673
+ catch {
674
+ // Best-effort cache warm only; a miss must never affect the real turn.
675
+ }
676
+ finally {
677
+ if (this._prefixWarmer?.controller === controller)
678
+ this._prefixWarmer = undefined;
679
+ }
680
+ }
681
+ _isWarmableLocalModel(model) {
682
+ if (model.api !== "openai-completions")
683
+ return false;
684
+ try {
685
+ const hostname = new URL(model.baseUrl).hostname.toLowerCase();
686
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname === "[::1]";
687
+ }
688
+ catch {
689
+ return false;
690
+ }
691
+ }
597
692
  /**
598
693
  * True when the session's stream fn is the raw `streamSimple` provider entry (directly, or as the
599
694
  * base wrapped by the idle watchdog at construction). Callers use this to decide whether request
@@ -1760,6 +1855,7 @@ export class AgentSession {
1760
1855
  this.abortCompaction();
1761
1856
  this.abortBranchSummary();
1762
1857
  this.abortBash();
1858
+ this._cancelPrefixWarm();
1763
1859
  this.agent.abort();
1764
1860
  // R8: stop any deployment-registered gateway channels / schedulers.
1765
1861
  void this._gatewayRegistry.stop().catch(() => { });
@@ -2086,6 +2182,7 @@ export class AgentSession {
2086
2182
  }
2087
2183
  async _promptUnserialized(text, options) {
2088
2184
  this._applyToolRepairLayerSettings();
2185
+ this._cancelPrefixWarm();
2089
2186
  const expandPromptTemplates = options?.expandPromptTemplates ?? true;
2090
2187
  const processSlashCommands = options?.processSlashCommands ?? expandPromptTemplates;
2091
2188
  const preflightResult = options?.preflightResult;
@@ -2597,10 +2694,13 @@ export class AgentSession {
2597
2694
  // Model Management
2598
2695
  // =========================================================================
2599
2696
  async setModel(model, options = {}) {
2600
- return this._modelSelection.setModel(model, options);
2697
+ await this._modelSelection.setModel(model, options);
2698
+ this._scheduleLocalPrefixWarm(this.agent.state.model, "selection");
2601
2699
  }
2602
2700
  async cycleModel(direction = "forward") {
2603
- return this._modelSelection.cycleModel(direction);
2701
+ const result = await this._modelSelection.cycleModel(direction);
2702
+ this._scheduleLocalPrefixWarm(result?.model, "selection");
2703
+ return result;
2604
2704
  }
2605
2705
  // =========================================================================
2606
2706
  // Thinking Level Management