@caupulican/pi-adaptative 0.80.58 → 0.80.59

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.
@@ -2756,7 +2756,12 @@ export class InteractiveMode {
2756
2756
  break;
2757
2757
  }
2758
2758
  case "agent_end":
2759
- if (!this.maybeStartAutoLearn()) {
2759
+ // Native in-process reflection fully replaces the subprocess learning paths
2760
+ // (continuous-learning AND autonomy-review) when enabled; otherwise fall back to legacy.
2761
+ if (this.isNativeReflectionEnabled()) {
2762
+ this.maybeRunNativeReflection(event.messages);
2763
+ }
2764
+ else if (!this.maybeStartAutoLearn()) {
2760
2765
  this.maybeStartAutonomyReview(event.messages);
2761
2766
  }
2762
2767
  if (this.settingsManager.getShowTerminalProgress()) {
@@ -4789,6 +4794,63 @@ export class InteractiveMode {
4789
4794
  }
4790
4795
  return { ...base, shouldRun: false, reason: "reflection thresholds not met" };
4791
4796
  }
4797
+ /**
4798
+ * Native reflection (R2) is the in-process replacement for the buggy `continuous-learning`
4799
+ * subprocess. It runs when auto-learn is enabled and is not killed via `PI_NATIVE_REFLECTION=0`.
4800
+ */
4801
+ isNativeReflectionEnabled() {
4802
+ if (process.env.PI_NATIVE_REFLECTION === "0")
4803
+ return false;
4804
+ if (process.env.PI_AUTO_LEARN_CHILD === "1")
4805
+ return false;
4806
+ return this.getEffectiveAutoLearnSettings().enabled;
4807
+ }
4808
+ /** Heuristic: does the user's turn text read like a correction/steer worth learning from? */
4809
+ hasCorrectionSignal(userText) {
4810
+ return /\b(next time|for future|from now on|remember this|don't|do not|avoid|instead|you should|should have|you forgot|you missed|not what i asked|wrong again)\b/i.test(userText);
4811
+ }
4812
+ /**
4813
+ * End-of-loop native reflection: demand-gate the just-finished turn (zero-I/O) and, when
4814
+ * warranted, run the in-process {@link AgentSession.runReflectionPass} as a fire-and-forget
4815
+ * background microtask. No subprocess, no blocking of the UI.
4816
+ */
4817
+ maybeRunNativeReflection(messages) {
4818
+ if (!this.isNativeReflectionEnabled())
4819
+ return;
4820
+ const settings = this.getEffectiveAutoLearnSettings();
4821
+ const toolCallCount = this.countAgentToolCalls(messages);
4822
+ const contextPercent = this.session.getContextUsage()?.percent ?? 0;
4823
+ const contextHeadroomPct = Math.max(0, 100 - contextPercent);
4824
+ const userText = messages
4825
+ .filter((m) => String(m.role ?? "") === "user")
4826
+ .map((m) => this.getAgentMessagePlainText(m))
4827
+ .join("\n");
4828
+ const hadCorrection = this.hasCorrectionSignal(userText);
4829
+ // A correction is worth learning from even on a short turn; otherwise require a complex turn.
4830
+ const trigger = hadCorrection
4831
+ ? "corrective"
4832
+ : toolCallCount >= Math.max(1, settings.complexTaskToolCalls ?? 12)
4833
+ ? "complex"
4834
+ : "none";
4835
+ if (trigger === "none")
4836
+ return;
4837
+ const recentTurnText = messages
4838
+ .map((m) => `${String(m.role ?? "")}: ${this.getAgentMessagePlainText(m)}`.trim())
4839
+ .filter(Boolean)
4840
+ .join("\n");
4841
+ // Stable per-turn id so a duplicate scheduling/retry can't double-count the reflection cost.
4842
+ const lastId = messages[messages.length - 1]?.id;
4843
+ const reportId = lastId ? `reflection:${lastId}` : undefined;
4844
+ void this.session
4845
+ .runReflectionPass({
4846
+ signals: { trigger, toolCallCount, hadCorrection, contextHeadroomPct, usefulLately: 0 },
4847
+ recentTurnText,
4848
+ reportId,
4849
+ })
4850
+ .catch(() => {
4851
+ // best-effort background learning; never disrupt the session
4852
+ });
4853
+ }
4792
4854
  maybeStartAutoLearn() {
4793
4855
  if (process.env.PI_AUTO_LEARN_CHILD === "1")
4794
4856
  return false;