@astrosheep/pi-context 0.2.0 → 0.3.0

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/README.md CHANGED
@@ -20,7 +20,8 @@ The extension composes Pi's public `session_before_compact` / `session_compact`
20
20
 
21
21
  - **`new_context` tool** — the model requests a fresh context window. The extension waits for the current tool turn to end, compacts with a short deterministic reset message (old conversation is excluded from the new provider context but stays in the session), then sends exactly one hidden continuation turn.
22
22
  - **`<context_window>` hint** — every model request carries a Codex-equivalent fragment with the agent name, first/current/previous window IDs, and the 5 most recently updated notes. The model gets recovery entry points, not a bare "go search" message.
23
- - **Low-budget guidance** — when remaining context drops to 16,000 tokens or below, a `<context_window_guidance>` reminder is injected exactly once per window (re-armed after each reset), matching Codex's `token_budget` reminder semantics: it tells the model to persist state with `notes_write_file` and call `new_context` before the window closes.
23
+ - **Low-budget guidance** — when remaining context drops to 16,000 tokens or below, a `<context_window_guidance>` reminder is injected exactly once per window (re-armed after each reset), matching Codex's `token_budget` reminder semantics: it tells the model to persist state with `notes_write_file` and call `new_context` before the window closes. Note: Pi's built-in auto-compaction fires when remaining context falls below `reserveTokens` (default 16,384), so raise the reminder threshold above your `reserveTokens` or the reminder never precedes compaction.
24
+ - **Runtime toggle** — `/pi-context off` disables hint injection, guidance, and reset-style compaction (Pi's default compaction, including `keepRecentTokens`, applies again). `/pi-context on` re-enables; a bare `/pi-context` reports the current state.
24
25
  - **History tools** — the model searches pre-reset conversation with case-sensitive literal substring search, exactly like Codex's `history.*` namespace.
25
26
  - **Notes tools** — persistent, session-scoped virtual files that survive window resets.
26
27
 
@@ -55,7 +56,7 @@ Two extra controls compose Pi public APIs:
55
56
 
56
57
  On `session_before_compact`, the extension appends a persistent custom reset marker through public `pi.appendEntry`, reads that real marker ID from the readonly session manager, and returns it as `firstKeptEntryId`. Pi's `buildContextEntries()` then keeps the compaction envelope plus that custom marker; custom markers are excluded from LLM context. Thus the subsequent provider context contains the short reset result and hidden continuation, not old conversation messages. The old entries remain only in the session tree for `history_*`.
57
58
 
58
- The same handler is used for native automatic compaction. When Pi marks an overflow compaction `willRetry`, Pi core performs its single retry itself and this extension deliberately sends no second continuation.
59
+ The same handler is used for native automatic compaction. When Pi marks an overflow compaction `willRetry`, Pi core performs its single retry itself and this extension deliberately sends no second continuation. While the extension is enabled, its custom reset keeps nothing after the boundary marker, so Pi's `keepRecentTokens` setting has no effect; with `/pi-context off`, Pi's default compaction (and `keepRecentTokens`) applies again.
59
60
 
60
61
  This is a composition of public `session_before_compact`, `session_compact`, `pi.appendEntry`, `ctx.compact`, and `pi.sendMessage`; it is not a Pi-core `newSession` call. A manual Pi compaction is only eligible when Pi's own `prepareCompaction()` accepts the session. Therefore a `new_context` request in a too-small/uncompactable session fails cleanly without default-summary fallback or continuation. A core change would be needed only to guarantee a force-reset at arbitrary small context sizes or to atomically interrupt a mixed parallel tool batch.
61
62
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrosheep/pi-context",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "description": "Codex-style context windows for Pi: reset-style compaction, durable session history tools, and persistent notes.",
6
6
  "license": "MIT",
package/src/index.ts CHANGED
@@ -265,12 +265,29 @@ const role = Type.Union([Type.Literal("user"), Type.Literal("assistant"), Type.L
265
265
  export default function piContext(pi: ExtensionAPI) {
266
266
  let rollover: "idle" | "requested" | "compacting" | "continued" = "idle";
267
267
  let reminderClaimedInWindow: string | undefined;
268
+ let enabled = true;
268
269
  const saveNote = (op: NoteOperation) => {
269
270
  // pi.appendEntry writes a custom SessionManager entry. Custom entries are persistent but excluded from LLM context.
270
271
  // ExtensionContext deliberately exposes only a readonly SessionManager, so this is the public extension write path.
271
272
  pi.appendEntry(NOTE_TYPE, op);
272
273
  };
273
274
 
275
+ pi.registerCommand("pi-context", {
276
+ description: "Toggle pi-context: context_window hint, low-budget guidance, and reset-style compaction",
277
+ getArgumentCompletions: (prefix) =>
278
+ ["on", "off"].filter((a) => a.startsWith(prefix)).map((a) => ({ value: a, label: a })),
279
+ handler: async (args, cmdCtx) => {
280
+ const arg = args.trim().toLowerCase();
281
+ if (arg === "on") enabled = true;
282
+ else if (arg === "off") enabled = false;
283
+ else if (arg !== "") {
284
+ cmdCtx.ui.notify("Usage: /pi-context [on|off]", "error");
285
+ return;
286
+ }
287
+ cmdCtx.ui.notify(`pi-context: ${enabled ? "on" : "off"}`, "info");
288
+ },
289
+ });
290
+
274
291
  pi.registerTool(defineTool({
275
292
  name: "history_list_windows",
276
293
  label: "History list windows",
@@ -391,6 +408,7 @@ export default function piContext(pi: ExtensionAPI) {
391
408
  }
392
409
 
393
410
  pi.on("context", (event, ctx) => {
411
+ if (!enabled) return undefined;
394
412
  // Rebuilt per request, so no state diffing is needed; identical to Codex's
395
413
  // context_window developer fragment rendered into each model call.
396
414
  const userText = (text: string) => ({
@@ -432,18 +450,24 @@ export default function piContext(pi: ExtensionAPI) {
432
450
  description: "Request a reset-style context rollover after this tool result is safely recorded. Call alone in a tool batch.",
433
451
  parameters: Type.Object({}, { additionalProperties: false }),
434
452
  async execute() {
453
+ if (!enabled) return output({ error: "pi-context is off (/pi-context on to enable)" });
435
454
  if (rollover === "idle") rollover = "requested";
436
455
  return output({ status: rollover === "requested" ? "rollover_requested" : "rollover_already_pending" }, undefined, true);
437
456
  },
438
457
  }));
439
458
 
440
459
  pi.on("agent_end", (_event, ctx) => {
460
+ if (!enabled) {
461
+ if (rollover === "requested") rollover = "idle";
462
+ return;
463
+ }
441
464
  if (rollover !== "requested") return;
442
465
  rollover = "compacting";
443
466
  ctx.compact({ onError: () => { if (rollover === "compacting") rollover = "idle"; } });
444
467
  });
445
468
 
446
469
  pi.on("session_before_compact", async (event, ctx) => {
470
+ if (!enabled) return undefined; // Default Pi compaction applies; keepRecentTokens is honored again.
447
471
  // Never let an aborted or failed custom reset fall through to Pi's default summary.
448
472
  if (event.signal.aborted) return { cancel: true };
449
473
  try {
@@ -457,6 +481,7 @@ export default function piContext(pi: ExtensionAPI) {
457
481
  });
458
482
 
459
483
  pi.on("session_compact", (event) => {
484
+ if (!enabled) return;
460
485
  // Overflow retry is already continued once by Pi core. Sending another turn would duplicate it.
461
486
  if (event.willRetry) return;
462
487
  if (rollover !== "compacting") return;