@tritard/waterbrother 0.14.10 → 0.14.11
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/agent.js +32 -2
package/package.json
CHANGED
package/src/agent.js
CHANGED
|
@@ -76,7 +76,8 @@ When you use tools:
|
|
|
76
76
|
- Never claim you ran commands you did not run.
|
|
77
77
|
- If a tool fails, show the failure and recover.
|
|
78
78
|
- You are primarily a coding assistant, but you can also have normal conversations. When the user wants to chat, just chat — be natural, helpful, and engaging. Do not constantly redirect to coding or push "what do you want to build?" when the user is clearly just talking.
|
|
79
|
-
- Only use tools (file writes, shell commands) when the user asks for actual code work. Do not create files for joke requests, hypothetical questions, or non-engineering prompts
|
|
79
|
+
- Only use tools (file writes, shell commands) when the user asks for actual code work. Do not create files for joke requests, hypothetical questions, or non-engineering prompts.
|
|
80
|
+
- You can call multiple tools in a single response. When multiple independent pieces of information are needed, make all calls in parallel for optimal performance. For example, if you need to read 3 files, read all 3 in one response rather than one at a time.`;
|
|
80
81
|
|
|
81
82
|
const COMPACTION_SYSTEM_PROMPT = `You are compacting a coding assistant conversation for context resumption. Write a continuation summary that allows efficient resumption in a new context window where the conversation history will be replaced with this summary.
|
|
82
83
|
|
|
@@ -126,6 +127,7 @@ const PROFILE_PROMPTS = {
|
|
|
126
127
|
const MAX_TOOL_CALL_ITERATIONS = 24;
|
|
127
128
|
const LOCAL_COMPACTION_TRANSCRIPT_CHARS = 400_000;
|
|
128
129
|
const LOCAL_COMPACTION_MESSAGE_PREVIEW_CHARS = 280;
|
|
130
|
+
const MAX_COMPACTION_CONSECUTIVE_FAILURES = 3;
|
|
129
131
|
|
|
130
132
|
function buildSystemPrompt(profile, experienceMode = "standard", autonomyMode = "scoped", memory = "", executionContext = null) {
|
|
131
133
|
const profileLine = PROFILE_PROMPTS[profile] || PROFILE_PROMPTS.coder;
|
|
@@ -321,6 +323,8 @@ export class Agent {
|
|
|
321
323
|
this.autonomyMode = normalizeAutonomyMode(autonomyMode);
|
|
322
324
|
this.requireTurnContracts = requireTurnContracts !== false;
|
|
323
325
|
this.executionContext = null;
|
|
326
|
+
this._compactionFailures = 0;
|
|
327
|
+
this._transcriptPath = null;
|
|
324
328
|
|
|
325
329
|
this.messages = [{ role: "system", content: buildSystemPrompt(profile, this.experienceMode, this.autonomyMode, this.memory) }];
|
|
326
330
|
this.toolRuntime = createToolRuntime({
|
|
@@ -442,6 +446,11 @@ export class Agent {
|
|
|
442
446
|
}
|
|
443
447
|
|
|
444
448
|
async compactConversation({ keepLast = 24, signal } = {}) {
|
|
449
|
+
// Circuit breaker: stop trying after consecutive failures
|
|
450
|
+
if (this._compactionFailures >= MAX_COMPACTION_CONSECUTIVE_FAILURES) {
|
|
451
|
+
return { compacted: false, reason: "circuit_breaker", totalMessages: this.getSessionMessages().length };
|
|
452
|
+
}
|
|
453
|
+
|
|
445
454
|
const keep = Math.max(8, Math.floor(Number(keepLast) || 24));
|
|
446
455
|
const sessionMessages = this.getSessionMessages();
|
|
447
456
|
if (sessionMessages.length <= keep + 2) {
|
|
@@ -486,14 +495,35 @@ export class Agent {
|
|
|
486
495
|
usage = completion?.usage || null;
|
|
487
496
|
} catch (error) {
|
|
488
497
|
if (isAbortError(error)) throw error;
|
|
498
|
+
this._compactionFailures++;
|
|
489
499
|
summaryBody = summarizeMessagesLocally(toSummarize);
|
|
490
500
|
method = "local-fallback";
|
|
491
501
|
}
|
|
492
502
|
}
|
|
493
503
|
|
|
504
|
+
// Reset circuit breaker on success
|
|
505
|
+
this._compactionFailures = 0;
|
|
506
|
+
|
|
507
|
+
// Save transcript to disk before compacting — allows recovery of details
|
|
508
|
+
let transcriptNote = "";
|
|
509
|
+
try {
|
|
510
|
+
if (this.cwd) {
|
|
511
|
+
const { join } = await import("node:path");
|
|
512
|
+
const { mkdir, appendFile } = await import("node:fs/promises");
|
|
513
|
+
const dir = join(this.cwd, ".waterbrother");
|
|
514
|
+
await mkdir(dir, { recursive: true });
|
|
515
|
+
const transcriptPath = this._transcriptPath || join(dir, `transcript-${Date.now()}.jsonl`);
|
|
516
|
+
this._transcriptPath = transcriptPath;
|
|
517
|
+
for (const msg of toSummarize) {
|
|
518
|
+
await appendFile(transcriptPath, JSON.stringify(msg) + "\n", "utf8");
|
|
519
|
+
}
|
|
520
|
+
transcriptNote = `\n\nIf you need specific details from before compaction (like exact code snippets, error messages, or content you generated), read the full transcript at: ${transcriptPath}`;
|
|
521
|
+
}
|
|
522
|
+
} catch {}
|
|
523
|
+
|
|
494
524
|
const summaryMessage = {
|
|
495
525
|
role: "assistant",
|
|
496
|
-
content: `### Compacted context summary\n${summaryBody}`
|
|
526
|
+
content: `### Compacted context summary\n${summaryBody}${transcriptNote}`
|
|
497
527
|
};
|
|
498
528
|
|
|
499
529
|
this.messages = [
|