@caupulican/pi-adaptative 0.80.71 → 0.80.72
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 +7 -0
- package/dist/core/agent-session.d.ts +11 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +38 -5
- package/dist/core/agent-session.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
|
@@ -127,6 +127,12 @@ export class AgentSession {
|
|
|
127
127
|
_effectivenessTracker = new EffectivenessTracker();
|
|
128
128
|
/** R8: registry for deployment-supplied gateway channels + schedulers (lifecycle driven by the host runner). */
|
|
129
129
|
_gatewayRegistry = new GatewayRegistry();
|
|
130
|
+
/** Cache for getSpawnedUsage(), keyed by session entry count (Bug #22 — avoid O(N) per render frame). */
|
|
131
|
+
_spawnedUsageCache;
|
|
132
|
+
/** Set on dispose so in-flight background reflection bails instead of writing to a dead session (Bug #21). */
|
|
133
|
+
_disposed = false;
|
|
134
|
+
/** Aborts in-flight background reflection completions on dispose (Bug #21). */
|
|
135
|
+
_reflectionAbort = new AbortController();
|
|
130
136
|
_isChildSession;
|
|
131
137
|
/** Memory providers registered by extensions via pi.registerMemoryProvider, applied on (re)init. */
|
|
132
138
|
_pendingMemoryProviders = [];
|
|
@@ -676,6 +682,15 @@ export class AgentSession {
|
|
|
676
682
|
this.agent.abort();
|
|
677
683
|
// R8: stop any deployment-registered gateway channels / schedulers.
|
|
678
684
|
void this._gatewayRegistry.stop().catch(() => { });
|
|
685
|
+
// Bug #21: abort any in-flight background reflection so it cannot keep spending tokens or
|
|
686
|
+
// write memory/skills against this now-disposed session.
|
|
687
|
+
this._disposed = true;
|
|
688
|
+
this._reflectionAbort.abort();
|
|
689
|
+
// Bug #20: clear the hooks this session installed on the shared agent so their closures stop
|
|
690
|
+
// pinning this (deactivated) session — and all its history/maps — in memory if the agent
|
|
691
|
+
// instance outlives the session.
|
|
692
|
+
this.agent.afterToolCall = undefined;
|
|
693
|
+
this.agent.transformContext = undefined;
|
|
679
694
|
}
|
|
680
695
|
catch {
|
|
681
696
|
// Dispose must succeed even if an abort hook throws.
|
|
@@ -3296,8 +3311,15 @@ export class AgentSession {
|
|
|
3296
3311
|
};
|
|
3297
3312
|
return this.sessionManager.appendCustomEntry(SPAWNED_USAGE_CUSTOM_TYPE, report);
|
|
3298
3313
|
}
|
|
3299
|
-
/**
|
|
3314
|
+
/**
|
|
3315
|
+
* Aggregate all recorded spawned-usage reports (see {@link addSpawnedUsage}). Cached by the session
|
|
3316
|
+
* entry count so the interactive footer (which calls this every render frame) is O(1) between turns
|
|
3317
|
+
* instead of an O(N) scan on every keystroke (Bug #22). Recomputes only when entries change.
|
|
3318
|
+
*/
|
|
3300
3319
|
getSpawnedUsage() {
|
|
3320
|
+
const entryCount = this.sessionManager.getEntryCount?.() ?? this.sessionManager.getEntries().length;
|
|
3321
|
+
if (this._spawnedUsageCache?.entryCount === entryCount)
|
|
3322
|
+
return this._spawnedUsageCache.totals;
|
|
3301
3323
|
let cost = 0;
|
|
3302
3324
|
let reports = 0;
|
|
3303
3325
|
for (const entry of this.sessionManager.getEntries()) {
|
|
@@ -3309,7 +3331,9 @@ export class AgentSession {
|
|
|
3309
3331
|
cost += data.usage.cost.total;
|
|
3310
3332
|
reports += 1;
|
|
3311
3333
|
}
|
|
3312
|
-
|
|
3334
|
+
const totals = { cost, reports };
|
|
3335
|
+
this._spawnedUsageCache = { entryCount, totals };
|
|
3336
|
+
return totals;
|
|
3313
3337
|
}
|
|
3314
3338
|
/**
|
|
3315
3339
|
* Run a one-shot LLM completion fully ISOLATED from the main session — the load-bearing
|
|
@@ -3383,18 +3407,23 @@ export class AgentSession {
|
|
|
3383
3407
|
* is best-effort: a model/parse error yields no writes, never throws into the caller.
|
|
3384
3408
|
*/
|
|
3385
3409
|
async runReflectionPass(input) {
|
|
3386
|
-
if (this._isChildSession)
|
|
3410
|
+
if (this._isChildSession || this._disposed)
|
|
3387
3411
|
return null;
|
|
3388
3412
|
const plan = decideDemand(input.signals);
|
|
3389
3413
|
if (plan.act === "skip")
|
|
3390
3414
|
return null;
|
|
3415
|
+
// Bug #21: tie this background pass to the session lifetime. Disposing the session aborts the
|
|
3416
|
+
// in-flight completion (input.signal can add a more specific abort).
|
|
3417
|
+
const signal = input.signal
|
|
3418
|
+
? AbortSignal.any([input.signal, this._reflectionAbort.signal])
|
|
3419
|
+
: this._reflectionAbort.signal;
|
|
3391
3420
|
const complete = (systemPrompt, userPrompt) => this.runIsolatedCompletion({
|
|
3392
3421
|
systemPrompt,
|
|
3393
3422
|
messages: [{ role: "user", content: [{ type: "text", text: userPrompt }], timestamp: Date.now() }],
|
|
3394
3423
|
model: input.model,
|
|
3395
3424
|
thinkingLevel: input.thinkingLevel ?? "low",
|
|
3396
3425
|
maxTokens: plan.tokenBudget,
|
|
3397
|
-
signal
|
|
3426
|
+
signal,
|
|
3398
3427
|
});
|
|
3399
3428
|
const result = await new ReflectionEngine().reflect({
|
|
3400
3429
|
recentTurnText: input.recentTurnText,
|
|
@@ -3404,8 +3433,12 @@ export class AgentSession {
|
|
|
3404
3433
|
plan,
|
|
3405
3434
|
complete,
|
|
3406
3435
|
});
|
|
3436
|
+
// Bug #21: if the session was disposed while the completion was in flight, do NOT write memory
|
|
3437
|
+
// or skills against the dead session.
|
|
3438
|
+
if (this._disposed)
|
|
3439
|
+
return result;
|
|
3407
3440
|
for (const write of result.writes) {
|
|
3408
|
-
await this._applyReflectionWrite(write,
|
|
3441
|
+
await this._applyReflectionWrite(write, signal);
|
|
3409
3442
|
}
|
|
3410
3443
|
// Account the reflection's spend so it surfaces in the footer roll-up (net-token visibility).
|
|
3411
3444
|
// Idempotent on reportId so a retried/duplicated pass cannot double-count.
|