@caupulican/pi-adaptative 0.80.58 → 0.80.60
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 +18 -0
- package/dist/core/agent-session.d.ts +58 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +155 -5
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extension-metadata.d.ts +20 -0
- package/dist/core/extension-metadata.d.ts.map +1 -0
- package/dist/core/extension-metadata.js +115 -0
- package/dist/core/extension-metadata.js.map +1 -0
- package/dist/core/extensions/runner.d.ts +1 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +3 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/learning/reflection-engine.d.ts +57 -0
- package/dist/core/learning/reflection-engine.d.ts.map +1 -0
- package/dist/core/learning/reflection-engine.js +118 -0
- package/dist/core/learning/reflection-engine.js.map +1 -0
- package/dist/core/memory/memory-manager.d.ts +8 -0
- package/dist/core/memory/memory-manager.d.ts.map +1 -1
- package/dist/core/memory/memory-manager.js +14 -2
- package/dist/core/memory/memory-manager.js.map +1 -1
- package/dist/core/resource-loader.d.ts +26 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +53 -14
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/system-prompt.d.ts +3 -0
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +54 -7
- package/dist/core/system-prompt.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 +6 -2
- package/dist/modes/interactive/components/profile-resource-editor.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +13 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +69 -4
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +1 -1
- package/dist/modes/rpc/rpc-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 +3 -0
- package/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
|
@@ -31,6 +31,7 @@ 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 { decideDemand, ReflectionEngine, } from "./learning/reflection-engine.js";
|
|
34
35
|
import { MemoryManager } from "./memory/memory-manager.js";
|
|
35
36
|
import { FileStoreProvider } from "./memory/providers/file-store.js";
|
|
36
37
|
import { compactToolResultDetailsForRetention } from "./message-retention.js";
|
|
@@ -776,7 +777,7 @@ export class AgentSession {
|
|
|
776
777
|
}
|
|
777
778
|
/** File-based prompt templates */
|
|
778
779
|
get promptTemplates() {
|
|
779
|
-
return this._resourceLoader.
|
|
780
|
+
return this._resourceLoader.getActivePrompts();
|
|
780
781
|
}
|
|
781
782
|
_normalizePromptSnippet(text) {
|
|
782
783
|
if (!text)
|
|
@@ -885,7 +886,9 @@ export class AgentSession {
|
|
|
885
886
|
...loaderAppendSystemPrompt,
|
|
886
887
|
].filter((part) => Boolean(part));
|
|
887
888
|
const appendSystemPrompt = appendSystemPromptParts.length > 0 ? appendSystemPromptParts.join("\n\n") : undefined;
|
|
888
|
-
|
|
889
|
+
// Only surface skills the active profile permits — the agent must not be told about (or able
|
|
890
|
+
// to invoke) a skill its profile blocks.
|
|
891
|
+
const loadedSkills = this._resourceLoader.getActiveSkills();
|
|
889
892
|
const loadedContextFiles = this._resourceLoader.getAgentsFiles().agentsFiles;
|
|
890
893
|
this._baseSystemPromptOptions = {
|
|
891
894
|
cwd: this._cwd,
|
|
@@ -896,6 +899,7 @@ export class AgentSession {
|
|
|
896
899
|
selectedTools: validToolNames,
|
|
897
900
|
toolSnippets,
|
|
898
901
|
promptGuidelines,
|
|
902
|
+
extensions: [...this._extensionRunner.activeExtensions],
|
|
899
903
|
};
|
|
900
904
|
return buildSystemPrompt(this._baseSystemPromptOptions);
|
|
901
905
|
}
|
|
@@ -1132,9 +1136,11 @@ export class AgentSession {
|
|
|
1132
1136
|
const spaceIndex = text.indexOf(" ");
|
|
1133
1137
|
const skillName = spaceIndex === -1 ? text.slice(7) : text.slice(7, spaceIndex);
|
|
1134
1138
|
const args = spaceIndex === -1 ? "" : text.slice(spaceIndex + 1).trim();
|
|
1135
|
-
|
|
1139
|
+
// Resolve only against profile-active skills so a `/skill:` the active profile blocks cannot be
|
|
1140
|
+
// expanded/invoked — by the user OR the agent — even if it loaded before a runtime profile switch.
|
|
1141
|
+
const skill = this.resourceLoader.getActiveSkills().find((s) => s.name === skillName);
|
|
1136
1142
|
if (!skill)
|
|
1137
|
-
return text; // Unknown skill, pass through
|
|
1143
|
+
return text; // Unknown or profile-blocked skill, pass through unchanged
|
|
1138
1144
|
try {
|
|
1139
1145
|
const content = readFileSync(skill.filePath, "utf-8");
|
|
1140
1146
|
const body = stripResourceProfileBlocks(stripFrontmatter(content)).trim();
|
|
@@ -2030,7 +2036,7 @@ export class AgentSession {
|
|
|
2030
2036
|
source: "prompt",
|
|
2031
2037
|
sourceInfo: template.sourceInfo,
|
|
2032
2038
|
}));
|
|
2033
|
-
const skills = this._resourceLoader.
|
|
2039
|
+
const skills = this._resourceLoader.getActiveSkills().map((skill) => ({
|
|
2034
2040
|
name: `skill:${skill.name}`,
|
|
2035
2041
|
description: skill.description,
|
|
2036
2042
|
source: "skill",
|
|
@@ -3204,6 +3210,150 @@ export class AgentSession {
|
|
|
3204
3210
|
}
|
|
3205
3211
|
return { cost, reports };
|
|
3206
3212
|
}
|
|
3213
|
+
/**
|
|
3214
|
+
* Run a one-shot LLM completion fully ISOLATED from the main session — the load-bearing
|
|
3215
|
+
* primitive for the native reflection engine (adaptive-agent design §6c/§7).
|
|
3216
|
+
*
|
|
3217
|
+
* Isolation invariants (audited by codex): builds a fresh {@link Context} (no main history), runs
|
|
3218
|
+
* with `tools: []`, sets `cacheRetention: "none"`, and passes **no `sessionId`** — so it cannot
|
|
3219
|
+
* mutate `agent.state.messages`, cannot append session entries, cannot touch the tool registry,
|
|
3220
|
+
* and cannot churn the main session's prompt cache. Mirrors `generateSummary()`'s mechanics.
|
|
3221
|
+
*
|
|
3222
|
+
* Returns the result even on an error/aborted stop reason (callers — e.g. a background reflection
|
|
3223
|
+
* microtask — decide whether to act); it does not throw on a model-level error.
|
|
3224
|
+
*/
|
|
3225
|
+
async runIsolatedCompletion(opts) {
|
|
3226
|
+
const model = opts.model ?? this.model;
|
|
3227
|
+
if (!model) {
|
|
3228
|
+
throw new Error("runIsolatedCompletion: no model available");
|
|
3229
|
+
}
|
|
3230
|
+
const thinkingLevel = opts.thinkingLevel ?? "off";
|
|
3231
|
+
// Fresh, isolated context: explicit messages, no tools, nothing from the main session.
|
|
3232
|
+
const context = {
|
|
3233
|
+
systemPrompt: opts.systemPrompt,
|
|
3234
|
+
messages: opts.messages,
|
|
3235
|
+
tools: [],
|
|
3236
|
+
};
|
|
3237
|
+
// Isolate the prompt cache and DELIBERATELY omit sessionId so no session-aware caching/routing
|
|
3238
|
+
// can entangle this call with the main session.
|
|
3239
|
+
const options = {
|
|
3240
|
+
maxTokens: opts.maxTokens,
|
|
3241
|
+
signal: opts.signal,
|
|
3242
|
+
cacheRetention: "none",
|
|
3243
|
+
};
|
|
3244
|
+
// pi-ai's `reasoning` option does not include "off" (that's the provider default already).
|
|
3245
|
+
if (thinkingLevel !== "off") {
|
|
3246
|
+
options.reasoning = thinkingLevel;
|
|
3247
|
+
}
|
|
3248
|
+
// When streamFn is the raw streamSimple (e.g. in tests), auth must be injected explicitly.
|
|
3249
|
+
// Throw only when auth genuinely fails — providers that authenticate without an API key
|
|
3250
|
+
// (OAuth, local no-key) legitimately return ok with an undefined apiKey.
|
|
3251
|
+
if (this.agent.streamFn === streamSimple) {
|
|
3252
|
+
const auth = await this._modelRegistry.getApiKeyAndHeaders(model);
|
|
3253
|
+
if (!auth.ok) {
|
|
3254
|
+
throw new Error(auth.error);
|
|
3255
|
+
}
|
|
3256
|
+
options.apiKey = auth.apiKey;
|
|
3257
|
+
options.headers = auth.headers;
|
|
3258
|
+
}
|
|
3259
|
+
const stream = await this.agent.streamFn(model, context, options);
|
|
3260
|
+
const result = await stream.result();
|
|
3261
|
+
const text = result.content
|
|
3262
|
+
.filter((c) => c.type === "text")
|
|
3263
|
+
.map((c) => c.text)
|
|
3264
|
+
.join("");
|
|
3265
|
+
const usage = result.usage ?? {
|
|
3266
|
+
input: 0,
|
|
3267
|
+
output: 0,
|
|
3268
|
+
cacheRead: 0,
|
|
3269
|
+
cacheWrite: 0,
|
|
3270
|
+
totalTokens: 0,
|
|
3271
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
3272
|
+
};
|
|
3273
|
+
return { text, usage, stopReason: result.stopReason };
|
|
3274
|
+
}
|
|
3275
|
+
/**
|
|
3276
|
+
* Native end-of-loop reflection pass (R2). Demand-gates (zero-I/O), and when warranted runs the
|
|
3277
|
+
* {@link ReflectionEngine} via an isolated completion ({@link runIsolatedCompletion}), applies the
|
|
3278
|
+
* resulting memory writes through the bundled `memory` tool, and accounts the reflection's token
|
|
3279
|
+
* cost via the cost-aggregation surface so it stays visible and net-negative-auditable.
|
|
3280
|
+
*
|
|
3281
|
+
* Returns `null` when the gate skips (or in a child session, which must not learn). The whole pass
|
|
3282
|
+
* is best-effort: a model/parse error yields no writes, never throws into the caller.
|
|
3283
|
+
*/
|
|
3284
|
+
async runReflectionPass(input) {
|
|
3285
|
+
if (this._isChildSession)
|
|
3286
|
+
return null;
|
|
3287
|
+
const plan = decideDemand(input.signals);
|
|
3288
|
+
if (plan.act === "skip")
|
|
3289
|
+
return null;
|
|
3290
|
+
const complete = (systemPrompt, userPrompt) => this.runIsolatedCompletion({
|
|
3291
|
+
systemPrompt,
|
|
3292
|
+
messages: [{ role: "user", content: [{ type: "text", text: userPrompt }], timestamp: Date.now() }],
|
|
3293
|
+
model: input.model,
|
|
3294
|
+
thinkingLevel: input.thinkingLevel ?? "low",
|
|
3295
|
+
maxTokens: plan.tokenBudget,
|
|
3296
|
+
signal: input.signal,
|
|
3297
|
+
});
|
|
3298
|
+
const result = await new ReflectionEngine().reflect({
|
|
3299
|
+
recentTurnText: input.recentTurnText,
|
|
3300
|
+
// Read memory FRESH (not the prefix-cache-frozen system-prompt block) so confront-before-write
|
|
3301
|
+
// sees writes made earlier this session.
|
|
3302
|
+
existingMemory: this._memoryManager.buildSystemPromptBlockFresh() || "",
|
|
3303
|
+
plan,
|
|
3304
|
+
complete,
|
|
3305
|
+
});
|
|
3306
|
+
for (const write of result.writes) {
|
|
3307
|
+
await this._applyReflectionWrite(write, input.signal);
|
|
3308
|
+
}
|
|
3309
|
+
// Account the reflection's spend so it surfaces in the footer roll-up (net-token visibility).
|
|
3310
|
+
// Idempotent on reportId so a retried/duplicated pass cannot double-count.
|
|
3311
|
+
if (result.usage.cost.total > 0 || result.usage.totalTokens > 0) {
|
|
3312
|
+
this.addSpawnedUsage(result.usage, { label: "reflection", reportId: input.reportId });
|
|
3313
|
+
}
|
|
3314
|
+
return result;
|
|
3315
|
+
}
|
|
3316
|
+
/**
|
|
3317
|
+
* Apply one reflection write through the bundled `memory` tool. `memory_replace`/`memory_remove`
|
|
3318
|
+
* don't carry a target file, so we try MEMORY.md first and fall back to USER.md when the substring
|
|
3319
|
+
* isn't found there. Best-effort: failures are swallowed (reflection must never break a turn).
|
|
3320
|
+
*/
|
|
3321
|
+
async _applyReflectionWrite(write, signal) {
|
|
3322
|
+
const memTool = this._memoryManager.getToolDefinitions().find((t) => t.name === "memory");
|
|
3323
|
+
const exec = memTool?.execute;
|
|
3324
|
+
if (!exec)
|
|
3325
|
+
return;
|
|
3326
|
+
const run = (params) => exec("reflection", params, signal, undefined, undefined);
|
|
3327
|
+
if (write.kind === "memory_add") {
|
|
3328
|
+
try {
|
|
3329
|
+
await run({ action: "add", target: write.section === "USER" ? "user" : "memory", content: write.text });
|
|
3330
|
+
}
|
|
3331
|
+
catch {
|
|
3332
|
+
// best-effort; reflection writes must never throw into the turn loop
|
|
3333
|
+
}
|
|
3334
|
+
return;
|
|
3335
|
+
}
|
|
3336
|
+
// replace / remove carry no target file — try MEMORY.md, then USER.md. The memory tool reports
|
|
3337
|
+
// outcomes via `details.success` (it catches its own errors rather than throwing). Only a
|
|
3338
|
+
// genuine "not found in the file" justifies trying the other file; a real failure for a file
|
|
3339
|
+
// (budget exceeded / drift) must NOT fall through and mutate the wrong target.
|
|
3340
|
+
for (const target of ["memory", "user"]) {
|
|
3341
|
+
try {
|
|
3342
|
+
const params = write.kind === "memory_replace"
|
|
3343
|
+
? { action: "replace", target, oldContent: write.target, content: write.text }
|
|
3344
|
+
: { action: "remove", target, oldContent: write.target };
|
|
3345
|
+
const res = await run(params);
|
|
3346
|
+
if (res?.details?.success === true)
|
|
3347
|
+
return; // applied
|
|
3348
|
+
if (!/not found/i.test(String(res?.details?.error ?? "")))
|
|
3349
|
+
return; // real failure — don't misapply
|
|
3350
|
+
// substring simply absent from this file — try the next target
|
|
3351
|
+
}
|
|
3352
|
+
catch {
|
|
3353
|
+
// defensive: if the tool ever does throw, try the next target
|
|
3354
|
+
}
|
|
3355
|
+
}
|
|
3356
|
+
}
|
|
3207
3357
|
getContextUsage() {
|
|
3208
3358
|
const model = this.model;
|
|
3209
3359
|
if (!model)
|