pi-continual-harness 0.15.0 → 0.15.1
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/package.json +1 -1
- package/src/index.ts +5 -0
- package/src/outcome.ts +4 -4
- package/src/refine.ts +15 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-continual-harness",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.1",
|
|
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/index.ts
CHANGED
|
@@ -190,6 +190,11 @@ export {
|
|
|
190
190
|
type ProjectedLike,
|
|
191
191
|
} from "./auto-refine.js";
|
|
192
192
|
|
|
193
|
+
// Message-content flattening (0.15.1): pi message content is a plain string OR
|
|
194
|
+
// a block array; every trajectory reader must go through this instead of
|
|
195
|
+
// assuming blocks. Re-exported for tests and companion packages.
|
|
196
|
+
export { messageText } from "./refine.js";
|
|
197
|
+
|
|
193
198
|
// Setup wizard (issue #22): presets as pure data + expandPreset, and the one
|
|
194
199
|
// reviewed write path for harness.json (backup + atomic write + reload).
|
|
195
200
|
// Re-exported so tests and companion packages never reach into internal
|
package/src/outcome.ts
CHANGED
|
@@ -26,13 +26,15 @@ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
|
26
26
|
import { DEFAULT_REF_BUMP, type HarnessConfig, loadConfig } from "./config.js";
|
|
27
27
|
import { turnEndedBadly } from "./auto-refine.js";
|
|
28
28
|
import { bumpImportance, getState, modelKey } from "./store.js";
|
|
29
|
+
import { messageText } from "./refine.js";
|
|
29
30
|
|
|
30
31
|
// Minimal entry shape; kept loose to avoid coupling to pi's internal types.
|
|
32
|
+
// Message content is a plain string OR a block array depending on the source.
|
|
31
33
|
type AnyEntry = {
|
|
32
34
|
type?: string;
|
|
33
35
|
message?: {
|
|
34
36
|
role?: string;
|
|
35
|
-
content?: Array<{ type?: string; text?: string }>;
|
|
37
|
+
content?: string | Array<{ type?: string; text?: string }>;
|
|
36
38
|
};
|
|
37
39
|
};
|
|
38
40
|
|
|
@@ -88,9 +90,7 @@ export function registerOutcome(pi: ExtensionAPI): void {
|
|
|
88
90
|
const fresh = asst.slice(scannedMessages);
|
|
89
91
|
scannedMessages = asst.length;
|
|
90
92
|
|
|
91
|
-
const text = fresh
|
|
92
|
-
.map((e) => (e.message?.content ?? []).map((c) => c.text ?? "").join(" "))
|
|
93
|
-
.join("\n");
|
|
93
|
+
const text = fresh.map((e) => messageText(e.message?.content)).join("\n");
|
|
94
94
|
if (!text.trim()) return;
|
|
95
95
|
|
|
96
96
|
// Only the active model's items are injected, so only those can be cited.
|
package/src/refine.ts
CHANGED
|
@@ -31,16 +31,28 @@ const DEFAULT_EVIDENCE_BYTES = 16000;
|
|
|
31
31
|
export const DEFAULT_LOOKBACK_TURNS = 25;
|
|
32
32
|
|
|
33
33
|
// Minimal entry shape for trajectory walking; kept loose to avoid coupling to
|
|
34
|
-
// pi's internal session entry types.
|
|
34
|
+
// pi's internal session entry types. NOTE: message content is a plain string
|
|
35
|
+
// OR a block array depending on the message source — never assume either.
|
|
35
36
|
type AnyEntry = {
|
|
36
37
|
type?: string;
|
|
37
38
|
customType?: string;
|
|
38
39
|
message?: {
|
|
39
40
|
role?: string;
|
|
40
|
-
content?: Array<{ type?: string; text?: string }>;
|
|
41
|
+
content?: string | Array<{ type?: string; text?: string }>;
|
|
41
42
|
};
|
|
42
43
|
};
|
|
43
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Flatten a pi message content to plain text. Pi messages carry content as a
|
|
47
|
+
* plain string or as an array of content blocks (text blocks carry `.text`);
|
|
48
|
+
* anything else degrades to "" instead of throwing. Pure.
|
|
49
|
+
*/
|
|
50
|
+
export function messageText(content: string | Array<{ type?: string; text?: string }> | undefined): string {
|
|
51
|
+
if (typeof content === "string") return content;
|
|
52
|
+
if (!Array.isArray(content)) return "";
|
|
53
|
+
return content.map((c) => c?.text ?? "").join(" ");
|
|
54
|
+
}
|
|
55
|
+
|
|
44
56
|
export function registerRefine(pi: ExtensionAPI): void {
|
|
45
57
|
pi.registerCommand("refine", {
|
|
46
58
|
description:
|
|
@@ -268,9 +280,7 @@ export function gatherEvidence(ctx: ExtensionContext, lookback: number): string
|
|
|
268
280
|
let bytes = 0;
|
|
269
281
|
for (const e of recent) {
|
|
270
282
|
const role = e.message?.role ?? "?";
|
|
271
|
-
const text = (e.message?.content
|
|
272
|
-
.map((c) => c.text ?? "")
|
|
273
|
-
.join(" ")
|
|
283
|
+
const text = messageText(e.message?.content)
|
|
274
284
|
.replace(/\s+/g, " ")
|
|
275
285
|
.trim();
|
|
276
286
|
if (!text) continue;
|