@caupulican/pi-adaptative 0.80.55 → 0.80.58

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 (56) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/cli/args.d.ts +2 -0
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +5 -0
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/core/agent-session.d.ts +70 -1
  7. package/dist/core/agent-session.d.ts.map +1 -1
  8. package/dist/core/agent-session.js +181 -0
  9. package/dist/core/agent-session.js.map +1 -1
  10. package/dist/core/context-gc.d.ts.map +1 -1
  11. package/dist/core/context-gc.js +4 -0
  12. package/dist/core/context-gc.js.map +1 -1
  13. package/dist/core/extensions/loader.d.ts.map +1 -1
  14. package/dist/core/extensions/loader.js +10 -0
  15. package/dist/core/extensions/loader.js.map +1 -1
  16. package/dist/core/extensions/runner.d.ts.map +1 -1
  17. package/dist/core/extensions/runner.js +2 -0
  18. package/dist/core/extensions/runner.js.map +1 -1
  19. package/dist/core/extensions/types.d.ts +23 -1
  20. package/dist/core/extensions/types.d.ts.map +1 -1
  21. package/dist/core/extensions/types.js.map +1 -1
  22. package/dist/core/memory/memory-manager.d.ts +22 -0
  23. package/dist/core/memory/memory-manager.d.ts.map +1 -0
  24. package/dist/core/memory/memory-manager.js +212 -0
  25. package/dist/core/memory/memory-manager.js.map +1 -0
  26. package/dist/core/memory/memory-provider.d.ts +25 -0
  27. package/dist/core/memory/memory-provider.d.ts.map +1 -0
  28. package/dist/core/memory/memory-provider.js +2 -0
  29. package/dist/core/memory/memory-provider.js.map +1 -0
  30. package/dist/core/memory/providers/file-store.d.ts +23 -0
  31. package/dist/core/memory/providers/file-store.d.ts.map +1 -0
  32. package/dist/core/memory/providers/file-store.js +212 -0
  33. package/dist/core/memory/providers/file-store.js.map +1 -0
  34. package/dist/core/sdk.d.ts +2 -0
  35. package/dist/core/sdk.d.ts.map +1 -1
  36. package/dist/core/sdk.js +1 -0
  37. package/dist/core/sdk.js.map +1 -1
  38. package/dist/main.d.ts.map +1 -1
  39. package/dist/main.js +1 -0
  40. package/dist/main.js.map +1 -1
  41. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  42. package/dist/modes/interactive/components/footer.js +11 -3
  43. package/dist/modes/interactive/components/footer.js.map +1 -1
  44. package/dist/modes/print-mode.d.ts +13 -0
  45. package/dist/modes/print-mode.d.ts.map +1 -1
  46. package/dist/modes/print-mode.js +18 -1
  47. package/dist/modes/print-mode.js.map +1 -1
  48. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  49. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  50. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  51. package/examples/extensions/sandbox/package-lock.json +2 -2
  52. package/examples/extensions/sandbox/package.json +1 -1
  53. package/examples/extensions/with-deps/package-lock.json +2 -2
  54. package/examples/extensions/with-deps/package.json +1 -1
  55. package/npm-shrinkwrap.json +12 -12
  56. package/package.json +4 -4
@@ -31,6 +31,8 @@ import { createCoreDiagnosticsToolDefinitions } from "./extensions/builtin.js";
31
31
  import { ExtensionRunner, wrapRegisteredTools, } from "./extensions/index.js";
32
32
  import { disposeExtensionEventSubscriptions } from "./extensions/loader.js";
33
33
  import { emitSessionShutdownEvent } from "./extensions/runner.js";
34
+ import { MemoryManager } from "./memory/memory-manager.js";
35
+ import { FileStoreProvider } from "./memory/providers/file-store.js";
34
36
  import { compactToolResultDetailsForRetention } from "./message-retention.js";
35
37
  import { resolveProfileModelSettings } from "./model-resolver.js";
36
38
  import { expandPromptTemplate } from "./prompt-templates.js";
@@ -57,6 +59,8 @@ export function parseSkillBlock(text) {
57
59
  userMessage: match[4]?.trim() || undefined,
58
60
  };
59
61
  }
62
+ /** customType for spawned-usage roll-up entries (Cost Aggregation, Model A). */
63
+ export const SPAWNED_USAGE_CUSTOM_TYPE = "spawned_usage";
60
64
  // ============================================================================
61
65
  // Constants
62
66
  // ============================================================================
@@ -112,6 +116,11 @@ export class AgentSession {
112
116
  _toolProfileFilter;
113
117
  _isExplicitModel;
114
118
  _isExplicitThinking;
119
+ /** Plug-and-play memory subsystem. Recreated on each (re)initialize so reload is safe. */
120
+ _memoryManager = new MemoryManager();
121
+ _isChildSession;
122
+ /** Memory providers registered by extensions via pi.registerMemoryProvider, applied on (re)init. */
123
+ _pendingMemoryProviders = [];
115
124
  _baseToolsOverride;
116
125
  _sessionStartEvent;
117
126
  _extensionUIContext;
@@ -150,6 +159,7 @@ export class AgentSession {
150
159
  : undefined;
151
160
  this._isExplicitModel = config.isExplicitModel ?? false;
152
161
  this._isExplicitThinking = config.isExplicitThinking ?? false;
162
+ this._isChildSession = config.isChildSession ?? process.env.PI_CHILD_SESSION === "1";
153
163
  this._baseToolsOverride = config.baseToolsOverride;
154
164
  this._sessionStartEvent = config.sessionStartEvent ?? { type: "session_start", reason: "startup" };
155
165
  // Always subscribe to agent events for internal handling
@@ -651,6 +661,9 @@ export class AgentSession {
651
661
  this._extensionRunner.invalidate("This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().");
652
662
  this._disconnectFromAgent();
653
663
  this._eventListeners = [];
664
+ // Best-effort memory cleanup (release locks/handles). Write-side onSessionEnd is wired on a
665
+ // true session-end hook (P3); file-store shutdown is a no-op.
666
+ void this._memoryManager.shutdownAll().catch(() => { });
654
667
  cleanupSessionResources(this.sessionId);
655
668
  }
656
669
  // =========================================================================
@@ -867,6 +880,8 @@ export class AgentSession {
867
880
  const appendSystemPromptParts = [
868
881
  this._buildSelfModificationPrompt(),
869
882
  this._buildAutonomyPrompt(),
883
+ // Memory subsystem: static, frozen-per-session block (e.g. file-store MEMORY.md/USER.md).
884
+ this._memoryManager.buildSystemPromptBlock() || undefined,
870
885
  ...loaderAppendSystemPrompt,
871
886
  ].filter((part) => Boolean(part));
872
887
  const appendSystemPrompt = appendSystemPromptParts.length > 0 ? appendSystemPromptParts.join("\n\n") : undefined;
@@ -1938,6 +1953,8 @@ export class AgentSession {
1938
1953
  this._applyExtensionBindings(this._extensionRunner);
1939
1954
  await this._extensionRunner.emit(this._sessionStartEvent);
1940
1955
  await this.extendResourcesFromExtensions(this._sessionStartEvent.reason === "reload" ? "reload" : "startup");
1956
+ // Initialize the memory subsystem after extensions have had a chance to register providers.
1957
+ await this._initializeMemory();
1941
1958
  }
1942
1959
  async extendResourcesFromExtensions(reason) {
1943
1960
  if (!this._extensionRunner.hasHandlers("resources_discover")) {
@@ -2066,6 +2083,10 @@ export class AgentSession {
2066
2083
  getThinkingLevel: () => this.thinkingLevel,
2067
2084
  setThinkingLevel: (level) => this.setThinkingLevel(level),
2068
2085
  getExternalResourceRoots: () => this.settingsManager.getEffectiveExternalResourceRoots(),
2086
+ registerMemoryProvider: (provider) => this.registerMemoryProvider(provider),
2087
+ reportSpawnedUsage: (usage, opts) => {
2088
+ this.addSpawnedUsage(usage, opts);
2089
+ },
2069
2090
  }, {
2070
2091
  getModel: () => this.model,
2071
2092
  isIdle: () => !this.isStreaming,
@@ -2163,6 +2184,47 @@ export class AgentSession {
2163
2184
  this.setThinkingLevel(profileSettings.thinkingLevel);
2164
2185
  }
2165
2186
  }
2187
+ /**
2188
+ * (Re)build the memory subsystem: a fresh MemoryManager (reload-safe), register the bundled
2189
+ * file-store + any extension-contributed providers, initialize, then surface the memory tools and
2190
+ * the frozen system-prompt block. Best-effort: never throws into the session lifecycle.
2191
+ */
2192
+ async _initializeMemory() {
2193
+ try {
2194
+ // Release the previous generation's providers (locks/handles) before recreating, so a
2195
+ // reload does not orphan the old MemoryManager. No-op on first init / for file-store.
2196
+ await this._memoryManager.shutdownAll().catch(() => { });
2197
+ const manager = new MemoryManager();
2198
+ manager.registerProvider(new FileStoreProvider());
2199
+ for (const provider of this._pendingMemoryProviders) {
2200
+ try {
2201
+ manager.registerProvider(provider);
2202
+ }
2203
+ catch {
2204
+ // Duplicate name or reserved-tool collision — skip this provider, keep the rest.
2205
+ }
2206
+ }
2207
+ this._memoryManager = manager;
2208
+ await manager.initializeAll(this.sessionManager.getSessionId(), {
2209
+ agentDir: this._agentDir,
2210
+ cwd: this._cwd,
2211
+ isChildSession: this._isChildSession,
2212
+ });
2213
+ // Surface memory tools + the frozen memory block now that providers are initialized.
2214
+ // _refreshToolRegistry() ends in setActiveToolsByName(), which rebuilds AND assigns the
2215
+ // system prompt (including the memory block), so no explicit _rebuildSystemPrompt is needed.
2216
+ this._refreshToolRegistry();
2217
+ }
2218
+ catch (error) {
2219
+ console.error("Memory subsystem init failed:", error instanceof Error ? error.message : String(error));
2220
+ }
2221
+ }
2222
+ /** Register a memory provider contributed by an extension; applied on the next memory (re)init. */
2223
+ registerMemoryProvider(provider) {
2224
+ if (!this._pendingMemoryProviders.some((p) => p.name === provider.name)) {
2225
+ this._pendingMemoryProviders.push(provider);
2226
+ }
2227
+ }
2166
2228
  _refreshToolRegistry(options) {
2167
2229
  const previousRegistryNames = new Set(this._toolRegistry.keys());
2168
2230
  const previousActiveToolNames = this.getActiveToolNames();
@@ -2190,6 +2252,11 @@ export class AgentSession {
2190
2252
  definition,
2191
2253
  sourceInfo: createSyntheticSourceInfo(`<sdk:${definition.name}>`, { source: "sdk" }),
2192
2254
  })),
2255
+ // Memory subsystem provider tools (e.g. file-store's `memory` tool).
2256
+ ...this._memoryManager.getToolDefinitions().map((definition) => ({
2257
+ definition,
2258
+ sourceInfo: createSyntheticSourceInfo(`<memory:${definition.name}>`, { source: "sdk" }),
2259
+ })),
2193
2260
  ].filter((tool) => isAllowedTool(tool.definition.name));
2194
2261
  const definitionRegistry = new Map(Array.from(this._baseToolDefinitions.entries())
2195
2262
  .filter(([name]) => isAllowedTool(name))
@@ -2381,6 +2448,8 @@ export class AgentSession {
2381
2448
  });
2382
2449
  try {
2383
2450
  this._doctorReloadRuntime();
2451
+ // Reload starts memory providers fresh; loaded extensions re-register below.
2452
+ this._pendingMemoryProviders = [];
2384
2453
  const hasBindings = this._extensionUIContext ||
2385
2454
  this._extensionCommandContextActions ||
2386
2455
  this._extensionShutdownHandler ||
@@ -2400,6 +2469,8 @@ export class AgentSession {
2400
2469
  await emitSessionShutdownEvent(previousRunner, { type: "session_shutdown", reason: "reload" });
2401
2470
  previousRunner.invalidate();
2402
2471
  this._resourceLoader.commitReload?.();
2472
+ // Re-derive the memory subsystem from the reloaded settings/providers.
2473
+ await this._initializeMemory();
2403
2474
  }
2404
2475
  catch (error) {
2405
2476
  if (newRunner && newRunner !== previousRunner) {
@@ -3023,6 +3094,116 @@ export class AgentSession {
3023
3094
  contextUsage: this.getContextUsage(),
3024
3095
  };
3025
3096
  }
3097
+ /**
3098
+ * Cumulative usage (full breakdown) for this session's entire spawn subtree: its own
3099
+ * assistant messages PLUS every `spawned_usage` report it has rolled up. Single source of
3100
+ * truth for "how much did this session and everything it spawned spend" — used by print-mode
3101
+ * to emit a child's total so a spawner can roll it up via {@link addSpawnedUsage}.
3102
+ *
3103
+ * Including the `spawned_usage` reports is what keeps the single-hop invariant intact: a child
3104
+ * that itself spawned grandchildren must report own + sub-usage in one number, or the parent
3105
+ * silently under-counts the grandchildren.
3106
+ */
3107
+ getCumulativeUsage() {
3108
+ let input = 0;
3109
+ let output = 0;
3110
+ let cacheRead = 0;
3111
+ let cacheWrite = 0;
3112
+ let totalTokens = 0;
3113
+ let costInput = 0;
3114
+ let costOutput = 0;
3115
+ let costCacheRead = 0;
3116
+ let costCacheWrite = 0;
3117
+ let costTotal = 0;
3118
+ const add = (usage) => {
3119
+ input += usage.input;
3120
+ output += usage.output;
3121
+ cacheRead += usage.cacheRead;
3122
+ cacheWrite += usage.cacheWrite;
3123
+ totalTokens += usage.totalTokens;
3124
+ costInput += usage.cost.input;
3125
+ costOutput += usage.cost.output;
3126
+ costCacheRead += usage.cost.cacheRead;
3127
+ costCacheWrite += usage.cost.cacheWrite;
3128
+ costTotal += usage.cost.total;
3129
+ };
3130
+ for (const message of this.state.messages) {
3131
+ if (message.role !== "assistant")
3132
+ continue;
3133
+ const usage = message.usage;
3134
+ if (!usage)
3135
+ continue;
3136
+ add(usage);
3137
+ }
3138
+ // Roll up usage this session attributed to its own spawned children (single-hop).
3139
+ for (const entry of this.sessionManager.getEntries()) {
3140
+ if (entry.type !== "custom" || entry.customType !== SPAWNED_USAGE_CUSTOM_TYPE)
3141
+ continue;
3142
+ const data = entry.data;
3143
+ if (data?.usage)
3144
+ add(data.usage);
3145
+ }
3146
+ return {
3147
+ input,
3148
+ output,
3149
+ cacheRead,
3150
+ cacheWrite,
3151
+ totalTokens,
3152
+ cost: {
3153
+ input: costInput,
3154
+ output: costOutput,
3155
+ cacheRead: costCacheRead,
3156
+ cacheWrite: costCacheWrite,
3157
+ total: costTotal,
3158
+ },
3159
+ };
3160
+ }
3161
+ /**
3162
+ * Record usage spent by a spawned/subagent session so the footer can roll it into the
3163
+ * displayed cost. Persisted as a `CustomEntry` (`customType: "spawned_usage"`, Model A) so
3164
+ * it survives reload and is reconstructed exactly like main usage; a new/forked session
3165
+ * starts fresh because it owns a new log file.
3166
+ *
3167
+ * Idempotent on `opts.reportId`: a re-report (retry, duplicate `agent_end`) with a
3168
+ * previously-seen id is ignored, so cost cannot be double-counted. Honors the single-hop
3169
+ * invariant documented on {@link SpawnedUsageReport}.
3170
+ *
3171
+ * @returns the id of the appended entry, or `undefined` if the report was a duplicate.
3172
+ */
3173
+ addSpawnedUsage(usage, opts) {
3174
+ const reportId = opts?.reportId;
3175
+ if (reportId) {
3176
+ for (const entry of this.sessionManager.getEntries()) {
3177
+ if (entry.type === "custom" &&
3178
+ entry.customType === SPAWNED_USAGE_CUSTOM_TYPE &&
3179
+ entry.data?.reportId === reportId) {
3180
+ return undefined;
3181
+ }
3182
+ }
3183
+ }
3184
+ const report = {
3185
+ usage,
3186
+ label: opts?.label,
3187
+ sourceSessionId: opts?.sourceSessionId,
3188
+ reportId,
3189
+ };
3190
+ return this.sessionManager.appendCustomEntry(SPAWNED_USAGE_CUSTOM_TYPE, report);
3191
+ }
3192
+ /** Aggregate all recorded spawned-usage reports (see {@link addSpawnedUsage}). */
3193
+ getSpawnedUsage() {
3194
+ let cost = 0;
3195
+ let reports = 0;
3196
+ for (const entry of this.sessionManager.getEntries()) {
3197
+ if (entry.type !== "custom" || entry.customType !== SPAWNED_USAGE_CUSTOM_TYPE)
3198
+ continue;
3199
+ const data = entry.data;
3200
+ if (!data?.usage)
3201
+ continue;
3202
+ cost += data.usage.cost.total;
3203
+ reports += 1;
3204
+ }
3205
+ return { cost, reports };
3206
+ }
3026
3207
  getContextUsage() {
3027
3208
  const model = this.model;
3028
3209
  if (!model)