teapot-coding-agent 0.37.103 → 0.37.104
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/dist/agent/agent.js
CHANGED
|
@@ -78,6 +78,11 @@ const SUMMARY_CLOSE = "\n</conversation_checkpoint>";
|
|
|
78
78
|
const AUDIT_READ_ONLY_TOOLS = new Set(["read_file", "list_dir", "grep", "bash"]);
|
|
79
79
|
const SYSTEM_TEMPLATE = `You are a coding agent working autonomously inside a workspace.
|
|
80
80
|
|
|
81
|
+
Start any session with three cheap calls, in this order: get_goal() (what am I
|
|
82
|
+
actually doing), get_todo() (what the operator is tracking), list_skills() (what
|
|
83
|
+
playbooks already exist). They cost about a line each and decide what to do next;
|
|
84
|
+
skipping them is how work already done gets done again.
|
|
85
|
+
|
|
81
86
|
Most session state is not injected into prompts — fetch it with tools instead:
|
|
82
87
|
- get_goal() → current objective + status. Call at session start, after a
|
|
83
88
|
compaction notice, or whenever you lose the thread.
|
|
@@ -85,6 +90,9 @@ Most session state is not injected into prompts — fetch it with tools instead:
|
|
|
85
90
|
- finish(goalComplete=true, summary) → goal fully achieved.
|
|
86
91
|
- ask_user(question, options?) → park the loop and wait for the operator's
|
|
87
92
|
decision (plan confirmation, ambiguity). One concrete question at a time.
|
|
93
|
+
Which one ends the turn: finish() closes the round, ask_user() parks it until
|
|
94
|
+
the operator answers, and report_progress() does NOT end it — that output goes
|
|
95
|
+
to the operator's progress panel and you carry on working.
|
|
88
96
|
- read_memory(query?) / add_memory(text) / forget_memory(query) / set_memory(content)
|
|
89
97
|
→ your durable notes (memory.md). add_memory appends and cannot lose earlier
|
|
90
98
|
notes; forget_memory removes the lines matching a substring, so a stale note can
|
|
@@ -117,17 +125,19 @@ Most session state is not injected into prompts — fetch it with tools instead:
|
|
|
117
125
|
valid string), and it took longer to repair than doing the edits one by one.
|
|
118
126
|
A genuine bulk transform across many files (a rename, an import change) IS a
|
|
119
127
|
job for a script — then keep the pattern specific and read the diff.
|
|
120
|
-
- **
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
128
|
+
- **Never wait with a bare sleep.** A bash call with a sleep inside is one opaque
|
|
129
|
+
command: the operator cannot interrupt it, cannot see whether anything is
|
|
130
|
+
happening, and the whole turn is spent doing nothing. A fixed nap also cannot
|
|
131
|
+
tell "finished 5 minutes ago" from "still running", which is how a turn gets
|
|
132
|
+
wasted twice. Two interruptible shapes instead:
|
|
124
133
|
· long single-purpose work (CI, a release, a tarball appearing, a dev
|
|
125
134
|
server, a watcher) → bash(background=true). It returns a job id at once
|
|
126
135
|
and you are NOTIFIED when it exits, so keep working and let it report.
|
|
127
|
-
· waiting on a condition you are actively watching → poll
|
|
128
|
-
deadline in ONE call, then stop.
|
|
129
|
-
|
|
130
|
-
|
|
136
|
+
· waiting on a condition you are actively watching → poll for the CONDITION
|
|
137
|
+
with a bounded deadline in ONE call, then stop. Polling is not a nap: it
|
|
138
|
+
re-checks and returns as soon as the condition holds.
|
|
139
|
+
The line is fixed-vs-condition, not short-vs-long: a bounded poll that returns
|
|
140
|
+
on the condition is fine, a sleep that always burns the same wall-clock is not.
|
|
131
141
|
- When a loaded skill matches your task, follow its playbook.
|
|
132
142
|
- Turn proven procedures into skills: once something non-trivial worked well,
|
|
133
143
|
save_skill(name, description, content, files=[{name, content}]) so future
|
|
@@ -149,6 +159,11 @@ Most session state is not injected into prompts — fetch it with tools instead:
|
|
|
149
159
|
panel) — do NOT also repeat the same content as a chat message; end the
|
|
150
160
|
turn right after the call (a short "reported." is fine).
|
|
151
161
|
- Be frugal: prefer small precise edits, avoid runaway loops.
|
|
162
|
+
- **Two failures on the same cause is the signal to change approach, not to try
|
|
163
|
+
a third time.** Reread the error, list what you have already ruled out, and
|
|
164
|
+
then either fix the actual cause or ask_user with what you know: two concrete
|
|
165
|
+
options and the evidence for each. Grinding a third variation of a failing idea
|
|
166
|
+
is the costliest loop there is, because it looks like progress.
|
|
152
167
|
- When the operator asks you to remember something, WRITE it with add_memory.
|
|
153
168
|
Write the KIND of thing that stays true and saves work later: a decision and
|
|
154
169
|
why, a gotcha that cost time, a command that works here, where you left off.
|
|
@@ -164,6 +179,8 @@ Most session state is not injected into prompts — fetch it with tools instead:
|
|
|
164
179
|
read_memory(query), open at most one or two of the notes that match, and stop.
|
|
165
180
|
If nothing is relevant, carry on — do not keep searching, and do not read the
|
|
166
181
|
whole file "just in case". An unread note is an unwritten note.`;
|
|
182
|
+
/** how much of memory.md a no-query read_memory() may dump into the transcript */
|
|
183
|
+
export const MEMORY_DUMP_LIMIT = 8_000;
|
|
167
184
|
export const PLACEHOLDER_TEXT = /^\(.*\)$/;
|
|
168
185
|
export const HARNESS_ACK = /^(decision recorded|progress recorded|goal saved|feedback saved|memory saved|todo saved|no skills yet|skills created|read_memory|memory|\(tool call\)|\(no content\)|\(no output\)|true|false|null|none)\b/i;
|
|
169
186
|
export class Agent {
|
|
@@ -1660,7 +1677,16 @@ export class Agent {
|
|
|
1660
1677
|
return "next";
|
|
1661
1678
|
}
|
|
1662
1679
|
if (!query) {
|
|
1663
|
-
|
|
1680
|
+
/**
|
|
1681
|
+
* No query means "give me everything", and everything is now tens of KB — memory.md is capped at
|
|
1682
|
+
* 32_000 chars and a long-lived session fills it. Dumping that into the transcript costs more than
|
|
1683
|
+
* the answer is worth, and the prompt already carries a digest, so cap it and say how to narrow.
|
|
1684
|
+
*/
|
|
1685
|
+
const body = mem.trim();
|
|
1686
|
+
await this.answerMeta(call, body.length <= MEMORY_DUMP_LIMIT
|
|
1687
|
+
? body
|
|
1688
|
+
: `${body.slice(0, MEMORY_DUMP_LIMIT)}\n… (truncated — ${body.length} chars in memory.md; ` +
|
|
1689
|
+
`pass a query to read a specific part)`);
|
|
1664
1690
|
return "next";
|
|
1665
1691
|
}
|
|
1666
1692
|
const needle = query.toLowerCase();
|
package/dist/agent/tools.js
CHANGED
|
@@ -1459,12 +1459,8 @@ export const TOOLS = [
|
|
|
1459
1459
|
const id = startBackgroundShell(str(args.command), ctx);
|
|
1460
1460
|
return {
|
|
1461
1461
|
ok: true,
|
|
1462
|
-
result: `started in background (job ${id})
|
|
1463
|
-
`
|
|
1464
|
-
`than ending. Do NOT poll bash_output: each poll is a whole turn, and the report ` +
|
|
1465
|
-
`already carries the tail. Call bash_output only when you need output BEYOND the ` +
|
|
1466
|
-
`tail (a long build's earlier lines), or to kill it. ` +
|
|
1467
|
-
`Full output: bash_output(job_id="${id}"). Kill: bash_output(job_id="${id}", action="kill").`,
|
|
1462
|
+
result: `started in background (job ${id}) — you are notified when it exits (code + output tail); ` +
|
|
1463
|
+
`do NOT poll it. Output: bash_output(job_id="${id}"). Stop: bash_output(job_id="${id}", action="kill").`,
|
|
1468
1464
|
};
|
|
1469
1465
|
}
|
|
1470
1466
|
const explicit = args.timeout_ms !== undefined && args.timeout_ms !== null;
|