@matthewfl/pi-contemplator 0.1.16 → 0.1.17
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/agents/observer/agent.ts +13 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@matthewfl/pi-contemplator",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.17",
|
|
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",
|
|
@@ -74,6 +74,8 @@ const RecordObservationsSchema = Type.Object({
|
|
|
74
74
|
|
|
75
75
|
type RecordObservationsArgs = Static<typeof RecordObservationsSchema>;
|
|
76
76
|
|
|
77
|
+
export const OBSERVER_MAX_LENGTH_ATTEMPTS = 4;
|
|
78
|
+
|
|
77
79
|
/** A terminal provider/agent-loop failure that must not advance observation coverage. */
|
|
78
80
|
export class ObserverStreamError extends Error {
|
|
79
81
|
readonly stopReason: string;
|
|
@@ -218,7 +220,7 @@ IMPORTANT: Now call record_observations to record the useful new observations fr
|
|
|
218
220
|
const loop = args.agentLoop ?? agentLoop;
|
|
219
221
|
const history: AgentMessage[] = [];
|
|
220
222
|
let terminalFailure: { stopReason: string; errorMessage?: string } | undefined;
|
|
221
|
-
let
|
|
223
|
+
let lengthAttempts = 0;
|
|
222
224
|
const runInvocation = async (prompt: Message, afterLength = false): Promise<void> => {
|
|
223
225
|
const context: AgentContext = {
|
|
224
226
|
systemPrompt: OBSERVER_SYSTEM,
|
|
@@ -265,8 +267,8 @@ IMPORTANT: Now call record_observations to record the useful new observations fr
|
|
|
265
267
|
};
|
|
266
268
|
|
|
267
269
|
await runInvocation(initialPrompt);
|
|
268
|
-
if (
|
|
269
|
-
|
|
270
|
+
if (terminalFailure?.stopReason === "length") lengthAttempts = 1;
|
|
271
|
+
while (accumulated.size === 0 && terminalFailure?.stopReason === "length" && lengthAttempts < OBSERVER_MAX_LENGTH_ATTEMPTS) {
|
|
270
272
|
// A provider can impose a lower output ceiling than the advertised model
|
|
271
273
|
// maximum. agentLoop stops on `length` when no tool call was completed; it
|
|
272
274
|
// does not automatically send a continuation request. Preserve the partial
|
|
@@ -275,7 +277,8 @@ IMPORTANT: Now call record_observations to record the useful new observations fr
|
|
|
275
277
|
// assistant text at the LLM boundary because some provider templates strip
|
|
276
278
|
// historical reasoning; encrypted thinking retains its opaque structure.
|
|
277
279
|
// Then append a short tool-focused instruction and reduce reasoning to
|
|
278
|
-
// minimal.
|
|
280
|
+
// minimal. The bounded attempt limit prevents pathological chunks from
|
|
281
|
+
// consuming background tokens forever.
|
|
279
282
|
terminalFailure = undefined;
|
|
280
283
|
const retryPrompt: Message = {
|
|
281
284
|
role: "user",
|
|
@@ -283,6 +286,10 @@ IMPORTANT: Now call record_observations to record the useful new observations fr
|
|
|
283
286
|
timestamp: Date.now(),
|
|
284
287
|
};
|
|
285
288
|
await runInvocation(retryPrompt, true);
|
|
289
|
+
// runInvocation mutates this through its async stream callbacks; TypeScript
|
|
290
|
+
// cannot infer that mutation after the explicit reset above.
|
|
291
|
+
const retryFailure = terminalFailure as { stopReason: string; errorMessage?: string } | undefined;
|
|
292
|
+
if (retryFailure?.stopReason === "length") lengthAttempts++;
|
|
286
293
|
}
|
|
287
294
|
if (accumulated.size === 0 && !doneCalled && !terminalFailure && rejectedTotal === 0) {
|
|
288
295
|
const reminder: Message = {
|
|
@@ -298,8 +305,8 @@ IMPORTANT: Now call record_observations to record the useful new observations fr
|
|
|
298
305
|
// zero-observation stop is also a valid empty result after the reminder;
|
|
299
306
|
// actual stream failures, truncation, and malformed records still throw.
|
|
300
307
|
if (accumulated.size === 0 && terminalFailure) {
|
|
301
|
-
const detail = terminalFailure.stopReason === "length" &&
|
|
302
|
-
? `provider reached the output limit
|
|
308
|
+
const detail = terminalFailure.stopReason === "length" && lengthAttempts > 0
|
|
309
|
+
? `provider reached the output limit ${lengthAttempts} times without recording an observation (effective max output request: ${baseConfig.maxTokens} tokens)`
|
|
303
310
|
: terminalFailure.errorMessage;
|
|
304
311
|
throw new ObserverStreamError(terminalFailure.stopReason, detail);
|
|
305
312
|
}
|