@matthewfl/pi-contemplator 0.0.6 → 0.0.7
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@matthewfl/pi-contemplator",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"description": "A Pi extension that keeps long-running agentic sessions on track with background memory, contemplation, and structural review.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,13 +30,22 @@ function isCurrentWatch(runtime: Runtime, generation: number): boolean {
|
|
|
30
30
|
return runtime.compactionResumePending && runtime.compactionResumeGeneration === generation;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
function
|
|
33
|
+
function continuationMessage(afterFailure: boolean, shortContinuationPrompt?: string): string {
|
|
34
|
+
if (shortContinuationPrompt) {
|
|
35
|
+
return afterFailure
|
|
36
|
+
? `Context compaction failed. Continue with these instructions:\n\n${shortContinuationPrompt}`
|
|
37
|
+
: shortContinuationPrompt;
|
|
38
|
+
}
|
|
39
|
+
return afterFailure
|
|
40
|
+
? "Context compaction failed. Continue the current task without waiting for another user message."
|
|
41
|
+
: "Continue the current task from the compacted context without waiting for another user message.";
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function sendResumeMessage(pi: ExtensionAPI, ctx: ResumeCtx, afterFailure: boolean, shortContinuationPrompt?: string): void {
|
|
34
45
|
try {
|
|
35
46
|
pi.sendMessage({
|
|
36
47
|
customType: "om.compaction.resume",
|
|
37
|
-
content: afterFailure
|
|
38
|
-
? "Context compaction failed. Continue the current task without waiting for another user message."
|
|
39
|
-
: "Continue the current task from the compacted context without waiting for another user message.",
|
|
48
|
+
content: continuationMessage(afterFailure, shortContinuationPrompt),
|
|
40
49
|
display: false,
|
|
41
50
|
}, {
|
|
42
51
|
deliverAs: "followUp",
|
|
@@ -54,6 +63,7 @@ function scheduleResumeRetries(
|
|
|
54
63
|
ctx: ResumeCtx,
|
|
55
64
|
generation: number,
|
|
56
65
|
afterFailure: boolean,
|
|
66
|
+
shortContinuationPrompt: string | undefined,
|
|
57
67
|
retryIndex = 0,
|
|
58
68
|
): void {
|
|
59
69
|
if (!isCurrentWatch(runtime, generation)) return;
|
|
@@ -75,8 +85,8 @@ function scheduleResumeRetries(
|
|
|
75
85
|
`Observational memory: continuation did not start; retrying (${retryIndex + 1}/${RESUME_RETRY_DELAYS_MS.length})`,
|
|
76
86
|
"warning",
|
|
77
87
|
);
|
|
78
|
-
sendResumeMessage(pi, ctx, afterFailure);
|
|
79
|
-
scheduleResumeRetries(pi, runtime, ctx, generation, afterFailure, retryIndex + 1);
|
|
88
|
+
sendResumeMessage(pi, ctx, afterFailure, shortContinuationPrompt);
|
|
89
|
+
scheduleResumeRetries(pi, runtime, ctx, generation, afterFailure, shortContinuationPrompt, retryIndex + 1);
|
|
80
90
|
}, RESUME_RETRY_DELAYS_MS[retryIndex]);
|
|
81
91
|
}
|
|
82
92
|
|
|
@@ -86,10 +96,11 @@ export function resumeAfterCompaction(
|
|
|
86
96
|
runtime: Runtime,
|
|
87
97
|
ctx: ResumeCtx,
|
|
88
98
|
afterFailure = false,
|
|
99
|
+
shortContinuationPrompt?: string,
|
|
89
100
|
): void {
|
|
90
101
|
const generation = beginResumeWatch(runtime);
|
|
91
|
-
sendResumeMessage(pi, ctx, afterFailure);
|
|
92
|
-
scheduleResumeRetries(pi, runtime, ctx, generation, afterFailure);
|
|
102
|
+
sendResumeMessage(pi, ctx, afterFailure, shortContinuationPrompt);
|
|
103
|
+
scheduleResumeRetries(pi, runtime, ctx, generation, afterFailure, shortContinuationPrompt);
|
|
93
104
|
}
|
|
94
105
|
|
|
95
106
|
/**
|
|
@@ -111,7 +122,7 @@ export function watchForNativeCompactionResume(
|
|
|
111
122
|
"warning",
|
|
112
123
|
);
|
|
113
124
|
sendResumeMessage(pi, ctx, false);
|
|
114
|
-
scheduleResumeRetries(pi, runtime, ctx, generation, false);
|
|
125
|
+
scheduleResumeRetries(pi, runtime, ctx, generation, false, undefined);
|
|
115
126
|
}, NATIVE_RESUME_GRACE_MS);
|
|
116
127
|
}
|
|
117
128
|
|
|
@@ -17,6 +17,7 @@ export function registerCompactionTrigger(pi: ExtensionAPI, runtime: Runtime): v
|
|
|
17
17
|
if (runtime.compactInFlight) return;
|
|
18
18
|
|
|
19
19
|
const agentRequested = runtime.compactRequested;
|
|
20
|
+
const shortContinuationPrompt = agentRequested ? runtime.compactContinuationPrompt : undefined;
|
|
20
21
|
if (agentRequested) runtime.compactRequested = false;
|
|
21
22
|
else if (runtime.config.passive === true) return;
|
|
22
23
|
|
|
@@ -88,6 +89,7 @@ export function registerCompactionTrigger(pi: ExtensionAPI, runtime: Runtime): v
|
|
|
88
89
|
"info",
|
|
89
90
|
);
|
|
90
91
|
}
|
|
92
|
+
if (agentRequested) runtime.compactContinuationPrompt = undefined;
|
|
91
93
|
ctx.compact({
|
|
92
94
|
onComplete: () => {
|
|
93
95
|
runtime.compactInFlight = false;
|
|
@@ -95,7 +97,7 @@ export function registerCompactionTrigger(pi: ExtensionAPI, runtime: Runtime): v
|
|
|
95
97
|
// Both explicit and proactive OM compactions are manual from Pi's
|
|
96
98
|
// perspective (willRetry=false), so Pi will not continue either one.
|
|
97
99
|
// Always enqueue a hidden continuation after OM finishes compacting.
|
|
98
|
-
resumeAfterCompaction(pi, runtime, { hasUI, ui });
|
|
100
|
+
resumeAfterCompaction(pi, runtime, { hasUI, ui }, false, shortContinuationPrompt);
|
|
99
101
|
},
|
|
100
102
|
onError: (error: { message: string }) => {
|
|
101
103
|
runtime.compactInFlight = false;
|
|
@@ -104,18 +106,19 @@ export function registerCompactionTrigger(pi: ExtensionAPI, runtime: Runtime): v
|
|
|
104
106
|
if (error.message !== "Compaction cancelled" && hasUI) {
|
|
105
107
|
ui?.notify(`Observational memory: ${error.message}`, "error");
|
|
106
108
|
}
|
|
107
|
-
resumeAfterCompaction(pi, runtime, { hasUI, ui }, true);
|
|
109
|
+
resumeAfterCompaction(pi, runtime, { hasUI, ui }, true, shortContinuationPrompt);
|
|
108
110
|
},
|
|
109
111
|
});
|
|
110
112
|
} catch (error) {
|
|
111
113
|
runtime.compactInFlight = false;
|
|
114
|
+
if (agentRequested) runtime.compactContinuationPrompt = undefined;
|
|
112
115
|
runtime.compactOrigin = undefined;
|
|
113
116
|
const msg = error instanceof Error ? error.message : String(error);
|
|
114
117
|
if (hasUI) {
|
|
115
118
|
ui?.setStatus?.(COMPACTION_STATUS_KEY, undefined);
|
|
116
119
|
ui?.notify(`Observational memory: compact threw: ${msg}`, "error");
|
|
117
120
|
}
|
|
118
|
-
resumeAfterCompaction(pi, runtime, { hasUI, ui }, true);
|
|
121
|
+
resumeAfterCompaction(pi, runtime, { hasUI, ui }, true, shortContinuationPrompt);
|
|
119
122
|
}
|
|
120
123
|
}, 0);
|
|
121
124
|
});
|
package/src/runtime.ts
CHANGED
|
@@ -145,6 +145,8 @@ export class Runtime {
|
|
|
145
145
|
consolidationPhase: ConsolidationPhase | undefined;
|
|
146
146
|
compactInFlight = false;
|
|
147
147
|
compactRequested = false;
|
|
148
|
+
/** Agent-authored instructions to deliver after an explicit compact_context request. */
|
|
149
|
+
compactContinuationPrompt: string | undefined;
|
|
148
150
|
compactOrigin: "proactive" | "agent-requested" | undefined;
|
|
149
151
|
compactHookInFlight = false;
|
|
150
152
|
compactionResumePending = false;
|
|
@@ -212,6 +214,7 @@ export class Runtime {
|
|
|
212
214
|
// never-cleared compactInFlight bricking all future compactions).
|
|
213
215
|
this.compactInFlight = false;
|
|
214
216
|
this.compactRequested = false;
|
|
217
|
+
this.compactContinuationPrompt = undefined;
|
|
215
218
|
this.compactOrigin = undefined;
|
|
216
219
|
this.compactionResumePending = false;
|
|
217
220
|
this.compactionResumeGeneration += 1;
|
|
@@ -4,7 +4,7 @@ import type { Runtime } from "../runtime.js";
|
|
|
4
4
|
|
|
5
5
|
export const COMPACT_CONTEXT_TOOL_NAME = "compact_context";
|
|
6
6
|
export const COMPACT_CONTEXT_DESCRIPTION =
|
|
7
|
-
"Force manual compaction. Use sparingly when substantial work remains but the remaining context is insufficient, or when accumulated context has become noisy or stale enough to impair focus and reliable reasoning.";
|
|
7
|
+
"Force manual compaction and resume with agent-authored next-step instructions. Use sparingly when substantial work remains but the remaining context is insufficient, or when accumulated context has become noisy or stale enough to impair focus and reliable reasoning.";
|
|
8
8
|
|
|
9
9
|
export type CompactContextDetails = {
|
|
10
10
|
status: "scheduled" | "already_pending" | "in_progress";
|
|
@@ -20,10 +20,17 @@ export function createCompactContextTool(runtime: Runtime) {
|
|
|
20
20
|
promptGuidelines: [
|
|
21
21
|
"Use compact_context sparingly when either substantial additional work remains and there is not enough context left to complete it, or accumulated past context has become noisy, stale, or distracting enough that you are struggling to focus on the current task or reason about it reliably.",
|
|
22
22
|
"Do not use compact_context routinely, for short tasks, or merely because the conversation is long; use it for genuine context-capacity pressure or context degradation that is interfering with the work.",
|
|
23
|
-
"Call compact_context by itself and stop the current turn; observational memory will compact the context and automatically resume
|
|
23
|
+
"Call compact_context by itself, provide short_continuation_prompt with concrete instructions for the next agent step, and stop the current turn; observational memory will compact the context and automatically resume with those instructions.",
|
|
24
24
|
],
|
|
25
|
-
parameters: Type.Object({
|
|
26
|
-
|
|
25
|
+
parameters: Type.Object({
|
|
26
|
+
short_continuation_prompt: Type.String({
|
|
27
|
+
minLength: 1,
|
|
28
|
+
maxLength: 1_000,
|
|
29
|
+
pattern: "\\S",
|
|
30
|
+
description: "Short, concrete instructions to your post-compaction self describing the next action and any critical immediate constraint. Do not summarize the whole conversation.",
|
|
31
|
+
}),
|
|
32
|
+
}),
|
|
33
|
+
async execute(_toolCallId, params) {
|
|
27
34
|
if (runtime.compactInFlight) {
|
|
28
35
|
return {
|
|
29
36
|
content: [{ type: "text" as const, text: "Context compaction is already in progress. Stop this turn and wait for automatic resume." }],
|
|
@@ -40,6 +47,7 @@ export function createCompactContextTool(runtime: Runtime) {
|
|
|
40
47
|
}
|
|
41
48
|
|
|
42
49
|
runtime.compactRequested = true;
|
|
50
|
+
runtime.compactContinuationPrompt = params.short_continuation_prompt.trim();
|
|
43
51
|
return {
|
|
44
52
|
content: [{ type: "text" as const, text: "Context compaction scheduled. Stop this turn; the task will resume automatically after compaction." }],
|
|
45
53
|
details: { status: "scheduled" } as CompactContextDetails,
|