pi-continual-harness 0.16.1 → 0.17.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 +11 -0
- package/package.json +1 -1
- package/src/proposer.ts +39 -5
package/README.md
CHANGED
|
@@ -473,6 +473,17 @@ registerProposer({
|
|
|
473
473
|
Then `"my-proposer"` is selectable via `/refine --proposer my-proposer` or
|
|
474
474
|
`"proposer": "my-proposer"` in the config.
|
|
475
475
|
|
|
476
|
+
**Cross-instance registry (0.17+).** pi's extension loader isolates module
|
|
477
|
+
instances between extensions, so before 0.17.0 a companion's `registerProposer`
|
|
478
|
+
call wrote to a private module copy that `/refine` never read — the
|
|
479
|
+
registration was silently invisible. The registry is now backed by a
|
|
480
|
+
process-wide global (`Symbol.for("pi-continual-harness.proposers")`), so any
|
|
481
|
+
copy's registrations are visible to every copy. Companions that want a
|
|
482
|
+
zero-import startup entry can skip importing this package at runtime entirely
|
|
483
|
+
and push a `DeltaProposer` (typically a lazy delegate that dynamic-imports its
|
|
484
|
+
implementation on first `propose()`) directly into
|
|
485
|
+
`globalThis[Symbol.for("pi-continual-harness.proposers")]`.
|
|
486
|
+
|
|
476
487
|
## Scope and non-goals
|
|
477
488
|
|
|
478
489
|
- **In scope:** unified state store, online `/refine`, structured deltas,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-continual-harness",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "Online self-improvement layer for pi. A unified, in-trajectory harness-state store (prompt notes, memory, skill descriptions, sub-agent specs) with a manual /refine that proposes evidence-backed structured CRUD deltas. Composes with pi-reflect (offline) and pi-mem (storage); owns only the online optimizer layer. Inspired by Continual Harness (arXiv 2605.09998) and ACE (arXiv 2510.04618).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
package/src/proposer.ts
CHANGED
|
@@ -434,21 +434,55 @@ export const dedupeProposer: DeltaProposer = {
|
|
|
434
434
|
|
|
435
435
|
// ---- registry -------------------------------------------------------------
|
|
436
436
|
|
|
437
|
-
|
|
437
|
+
// Cross-instance registry key (0.17.0). pi's extension loader isolates module
|
|
438
|
+
// instances between extensions (a fresh jiti per extension load, module cache
|
|
439
|
+
// off), so a companion package's `import { registerProposer } from
|
|
440
|
+
// "pi-continual-harness"` resolves to a DIFFERENT copy of this module than the
|
|
441
|
+
// one whose /refine reads the registry — a module-level Map made companion
|
|
442
|
+
// registrations silently invisible. Backing the registry with a process-wide
|
|
443
|
+
// global makes registration work no matter which copy each side holds.
|
|
444
|
+
//
|
|
445
|
+
// The string is the public contract: companions that avoid importing this
|
|
446
|
+
// package at all (thin startup entries) can push a DeltaProposer straight into
|
|
447
|
+
// `globalThis[Symbol.for("pi-continual-harness.proposers")]`.
|
|
448
|
+
const REGISTRY_KEY = Symbol.for("pi-continual-harness.proposers");
|
|
449
|
+
type ProposerRegistry = Map<string, DeltaProposer>;
|
|
450
|
+
|
|
451
|
+
function globalRegistry(): ProposerRegistry {
|
|
452
|
+
const g = globalThis as Record<symbol, unknown>;
|
|
453
|
+
let r = g[REGISTRY_KEY] as ProposerRegistry | undefined;
|
|
454
|
+
if (!(r instanceof Map)) {
|
|
455
|
+
r = new Map<string, DeltaProposer>();
|
|
456
|
+
g[REGISTRY_KEY] = r;
|
|
457
|
+
}
|
|
458
|
+
return r;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Built-ins stay module-local: they are pure functions of their input, and
|
|
462
|
+
// keeping them off the shared map means two isolated harness copies never hand
|
|
463
|
+
// each other's closures to /refine. External registrations live ONLY in the
|
|
464
|
+
// shared map, so every copy can see them.
|
|
465
|
+
const builtins = new Map<string, DeltaProposer>([
|
|
438
466
|
["steering", steeringProposer],
|
|
439
467
|
["dedupe", dedupeProposer],
|
|
440
468
|
]);
|
|
441
469
|
|
|
442
|
-
/** Register (or replace) a named proposer. For external extensions.
|
|
470
|
+
/** Register (or replace) a named proposer. For external extensions. Writes to
|
|
471
|
+
* the process-wide registry (Symbol.for("pi-continual-harness.proposers")),
|
|
472
|
+
* so it takes effect across pi's per-extension module isolation. */
|
|
443
473
|
export function registerProposer(p: DeltaProposer): void {
|
|
444
|
-
|
|
474
|
+
globalRegistry().set(p.name, p);
|
|
445
475
|
}
|
|
446
476
|
|
|
447
477
|
/** Look up a proposer by name; falls back to the steering default. */
|
|
448
478
|
export function getProposer(name: string | undefined): DeltaProposer {
|
|
449
|
-
|
|
479
|
+
const key = name ?? "steering";
|
|
480
|
+
const custom = globalRegistry().get(key);
|
|
481
|
+
// Defensive: the shared map can be written by anyone in the process.
|
|
482
|
+
if (custom && typeof custom.propose === "function") return custom;
|
|
483
|
+
return builtins.get(key) ?? steeringProposer;
|
|
450
484
|
}
|
|
451
485
|
|
|
452
486
|
export function listProposers(): string[] {
|
|
453
|
-
return [...
|
|
487
|
+
return [...new Set([...builtins.keys(), ...globalRegistry().keys()])];
|
|
454
488
|
}
|