@visorcraft/idlehands 1.2.8 → 1.3.2

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.
Files changed (41) hide show
  1. package/dist/agent.js +100 -38
  2. package/dist/agent.js.map +1 -1
  3. package/dist/anton/controller.js +117 -37
  4. package/dist/anton/controller.js.map +1 -1
  5. package/dist/anton/parser.js +12 -13
  6. package/dist/anton/parser.js.map +1 -1
  7. package/dist/anton/prompt.js +116 -49
  8. package/dist/anton/prompt.js.map +1 -1
  9. package/dist/anton/reporter.js +29 -2
  10. package/dist/anton/reporter.js.map +1 -1
  11. package/dist/anton/session.js +25 -0
  12. package/dist/anton/session.js.map +1 -1
  13. package/dist/anton/verifier.js +3 -3
  14. package/dist/anton/verifier.js.map +1 -1
  15. package/dist/bot/commands.js +65 -2
  16. package/dist/bot/commands.js.map +1 -1
  17. package/dist/bot/discord.js +63 -6
  18. package/dist/bot/discord.js.map +1 -1
  19. package/dist/bot/telegram.js +22 -7
  20. package/dist/bot/telegram.js.map +1 -1
  21. package/dist/cli/commands/anton.js +15 -3
  22. package/dist/cli/commands/anton.js.map +1 -1
  23. package/dist/cli/commands/project.js +9 -0
  24. package/dist/cli/commands/project.js.map +1 -1
  25. package/dist/config.js +6 -1
  26. package/dist/config.js.map +1 -1
  27. package/dist/runtime/executor.js +8 -3
  28. package/dist/runtime/executor.js.map +1 -1
  29. package/dist/sys/snapshot.sh +0 -0
  30. package/dist/tools.js +12 -2
  31. package/dist/tools.js.map +1 -1
  32. package/dist/utils.js +16 -8
  33. package/dist/utils.js.map +1 -1
  34. package/dist/vault.js +29 -31
  35. package/dist/vault.js.map +1 -1
  36. package/dist/vim.js +21 -12
  37. package/dist/vim.js.map +1 -1
  38. package/dist/watchdog.js +11 -2
  39. package/dist/watchdog.js.map +1 -1
  40. package/package.json +1 -1
  41. package/src/sys/snapshot.sh +0 -0
package/dist/agent.js CHANGED
@@ -157,41 +157,41 @@ class AgentLoopBreak extends Error {
157
157
  this.name = 'AgentLoopBreak';
158
158
  }
159
159
  }
160
- const SYSTEM_PROMPT = `You are a coding agent with filesystem and shell access. Execute the user's request using the provided tools.
161
-
162
- Rules:
163
- - Work in the current directory. Use relative paths for all file operations.
164
- - Do the work directly. Do NOT use spawn_task to delegate the user's primary request — only use it for genuinely independent subtasks that benefit from parallel execution.
165
- - Never use spawn_task to bypass confirmation/safety restrictions (for example blocked package installs). If a command is blocked, adapt the plan or ask the user for approval mode changes.
166
- - Read the target file before editing. You need the exact text for search/replace.
167
- - Use read_file with search=... to jump to relevant code; avoid reading whole files.
168
- - Never call read_file/read_files/list_dir twice in a row with identical arguments (same path/options). Reuse the previous result instead.
169
- - Prefer apply_patch or edit_range for code edits (token-efficient). Use edit_file only when exact old_text replacement is necessary.
170
- - Tool-call arguments MUST be strict JSON (double-quoted keys/strings, no comments, no trailing commas).
171
- - edit_range example: {"path":"src/foo.ts","start_line":10,"end_line":14,"replacement":"line A\nline B"}
172
- - apply_patch example: {"patch":"--- a/src/foo.ts\n+++ b/src/foo.ts\n@@ -10,2 +10,2 @@\n-old\n+new","files":["src/foo.ts"]}
173
- - write_file is for new files or explicit full rewrites only. Existing non-empty files require overwrite=true/force=true.
174
- - Use insert_file for insertions (prepend/append/line).
175
- - Use exec to run commands, tests, builds; check results before reporting success.
176
- - When running commands in a subdirectory, use exec's cwd parameter — NOT "cd /path && cmd". Each exec call is a fresh shell; cd does not persist.
177
- - Batch work: read all files you need, then apply all edits, then verify.
178
- - Be concise. Report what you changed and why.
179
- - Do NOT read every file in a directory. Use search_files or exec with grep to locate relevant code first, then read only the files that match.
180
- - If search_files returns 0 matches, try a broader pattern or use: exec grep -rn "keyword" path/
181
- - Anton (the autonomous task runner) is ONLY activated when the user explicitly invokes /anton. Never self-activate as Anton or start processing task files on your own.
182
-
183
- Tool call format:
184
- - Use tool_calls. Do not write JSON tool invocations in your message text.
160
+ const SYSTEM_PROMPT = `You are a coding agent with filesystem and shell access. Execute the user's request using the provided tools.
161
+
162
+ Rules:
163
+ - Work in the current directory. Use relative paths for all file operations.
164
+ - Do the work directly. Do NOT use spawn_task to delegate the user's primary request — only use it for genuinely independent subtasks that benefit from parallel execution.
165
+ - Never use spawn_task to bypass confirmation/safety restrictions (for example blocked package installs). If a command is blocked, adapt the plan or ask the user for approval mode changes.
166
+ - Read the target file before editing. You need the exact text for search/replace.
167
+ - Use read_file with search=... to jump to relevant code; avoid reading whole files.
168
+ - Never call read_file/read_files/list_dir twice in a row with identical arguments (same path/options). Reuse the previous result instead.
169
+ - Prefer apply_patch or edit_range for code edits (token-efficient). Use edit_file only when exact old_text replacement is necessary.
170
+ - Tool-call arguments MUST be strict JSON (double-quoted keys/strings, no comments, no trailing commas).
171
+ - edit_range example: {"path":"src/foo.ts","start_line":10,"end_line":14,"replacement":"line A\nline B"}
172
+ - apply_patch example: {"patch":"--- a/src/foo.ts\n+++ b/src/foo.ts\n@@ -10,2 +10,2 @@\n-old\n+new","files":["src/foo.ts"]}
173
+ - write_file is for new files or explicit full rewrites only. Existing non-empty files require overwrite=true/force=true.
174
+ - Use insert_file for insertions (prepend/append/line).
175
+ - Use exec to run commands, tests, builds; check results before reporting success.
176
+ - When running commands in a subdirectory, use exec's cwd parameter — NOT "cd /path && cmd". Each exec call is a fresh shell; cd does not persist.
177
+ - Batch work: read all files you need, then apply all edits, then verify.
178
+ - Be concise. Report what you changed and why.
179
+ - Do NOT read every file in a directory. Use search_files or exec with grep to locate relevant code first, then read only the files that match.
180
+ - If search_files returns 0 matches, try a broader pattern or use: exec grep -rn "keyword" path/
181
+ - Anton (the autonomous task runner) is ONLY activated when the user explicitly invokes /anton. Never self-activate as Anton or start processing task files on your own.
182
+
183
+ Tool call format:
184
+ - Use tool_calls. Do not write JSON tool invocations in your message text.
185
185
  `;
186
186
  const MCP_TOOLS_REQUEST_TOKEN = '[[MCP_TOOLS_REQUEST]]';
187
- const DEFAULT_SUB_AGENT_SYSTEM_PROMPT = `You are a focused coding sub-agent. Execute only the delegated task.
188
- - Work in the current directory. Use relative paths for all file operations.
189
- - Read the target file before editing. You need the exact text for search/replace.
190
- - Keep tool usage tight and efficient.
191
- - Prefer surgical edits over rewrites.
192
- - Do NOT create files outside the working directory unless explicitly requested.
193
- - When running commands in a subdirectory, use exec's cwd parameter — NOT "cd /path && cmd".
194
- - Run verification commands when relevant.
187
+ const DEFAULT_SUB_AGENT_SYSTEM_PROMPT = `You are a focused coding sub-agent. Execute only the delegated task.
188
+ - Work in the current directory. Use relative paths for all file operations.
189
+ - Read the target file before editing. You need the exact text for search/replace.
190
+ - Keep tool usage tight and efficient.
191
+ - Prefer surgical edits over rewrites.
192
+ - Do NOT create files outside the working directory unless explicitly requested.
193
+ - When running commands in a subdirectory, use exec's cwd parameter — NOT "cd /path && cmd".
194
+ - Run verification commands when relevant.
195
195
  - Return a concise outcome summary.`;
196
196
  const DEFAULT_SUB_AGENT_RESULT_TOKEN_CAP = 4000;
197
197
  const APPROVAL_MODE_SET = new Set(['plan', 'reject', 'default', 'auto-edit', 'yolo']);
@@ -1136,6 +1136,7 @@ export async function createSession(opts) {
1136
1136
  dirPinned: cfg.dir_pinned,
1137
1137
  repoCandidates: cfg.repo_candidates,
1138
1138
  confirm: overrides?.confirmBridge ?? defaultConfirmBridge,
1139
+ maxReadLines: cfg.max_read_lines,
1139
1140
  replay,
1140
1141
  vault,
1141
1142
  lens,
@@ -1267,6 +1268,34 @@ export async function createSession(opts) {
1267
1268
  const guidance = compactionVaultGuidance();
1268
1269
  return guidance ? `${prefix} ${guidance}` : prefix;
1269
1270
  };
1271
+ const buildCompactionSummaryPrompt = (dropped) => {
1272
+ const parts = [];
1273
+ for (const m of dropped) {
1274
+ if (m.role === 'assistant') {
1275
+ const text = typeof m.content === 'string' ? m.content : '';
1276
+ const toolCalls = m.tool_calls;
1277
+ if (toolCalls?.length) {
1278
+ for (const tc of toolCalls) {
1279
+ const args = typeof tc.function?.arguments === 'string'
1280
+ ? tc.function.arguments.slice(0, 200)
1281
+ : '';
1282
+ parts.push(`[tool_call: ${tc.function?.name}(${args})]`);
1283
+ }
1284
+ }
1285
+ if (text.trim())
1286
+ parts.push(`[assistant]: ${text.slice(0, 500)}`);
1287
+ }
1288
+ else if (m.role === 'tool') {
1289
+ const content = typeof m.content === 'string' ? m.content : '';
1290
+ parts.push(`[tool_result]: ${content.slice(0, 300)}`);
1291
+ }
1292
+ }
1293
+ let combined = parts.join('\n');
1294
+ if (combined.length > 4000) {
1295
+ combined = combined.slice(0, 4000) + '\n[...truncated]';
1296
+ }
1297
+ return combined;
1298
+ };
1270
1299
  let lastAskInstructionText = '';
1271
1300
  let lastCompactionReminderObjective = '';
1272
1301
  const injectCompactionReminder = (reason) => {
@@ -2128,7 +2157,7 @@ export async function createSession(opts) {
2128
2157
  messages: beforeMsgs,
2129
2158
  contextWindow,
2130
2159
  maxTokens: maxTokens,
2131
- minTailMessages: 12,
2160
+ minTailMessages: cfg.compact_min_tail ?? 12,
2132
2161
  compactAt: cfg.compact_at ?? 0.8,
2133
2162
  toolSchemaTokens: estimateToolSchemaTokens(getToolsSchema()),
2134
2163
  });
@@ -2164,7 +2193,39 @@ export async function createSession(opts) {
2164
2193
  }
2165
2194
  messages = compacted;
2166
2195
  if (dropped.length) {
2167
- messages.push({ role: 'system', content: buildCompactionSystemNote('auto', dropped.length) });
2196
+ const droppedTokens = estimateTokensFromMessages(dropped);
2197
+ if (cfg.compact_summary !== false && droppedTokens > 200) {
2198
+ try {
2199
+ const summaryContent = buildCompactionSummaryPrompt(dropped);
2200
+ const summaryMaxTokens = cfg.compact_summary_max_tokens ?? 300;
2201
+ const resp = await client.chat({
2202
+ model,
2203
+ messages: [
2204
+ { role: 'system', content: 'Summarize this agent session progress concisely. List: files read, key findings, decisions made, current approach. Be terse.' },
2205
+ { role: 'user', content: summaryContent },
2206
+ ],
2207
+ max_tokens: summaryMaxTokens,
2208
+ temperature: 0,
2209
+ responseTimeoutMs: 5_000,
2210
+ });
2211
+ const summary = resp.choices?.[0]?.message?.content ?? '';
2212
+ if (summary.trim()) {
2213
+ messages.push({
2214
+ role: 'system',
2215
+ content: `[Compacted ${dropped.length} messages (~${droppedTokens} tokens). Progress summary:]\n${summary.trim()}\n[Continue from where you left off. Do not repeat completed work.]`,
2216
+ });
2217
+ }
2218
+ else {
2219
+ messages.push({ role: 'system', content: buildCompactionSystemNote('auto', dropped.length) });
2220
+ }
2221
+ }
2222
+ catch {
2223
+ messages.push({ role: 'system', content: buildCompactionSystemNote('auto', dropped.length) });
2224
+ }
2225
+ }
2226
+ else {
2227
+ messages.push({ role: 'system', content: buildCompactionSystemNote('auto', dropped.length) });
2228
+ }
2168
2229
  }
2169
2230
  // Update token count AFTER injections so downstream reads are accurate
2170
2231
  currentContextTokens = estimateTokensFromMessages(messages);
@@ -2202,8 +2263,8 @@ export async function createSession(opts) {
2202
2263
  let resp;
2203
2264
  try {
2204
2265
  try {
2205
- const toolsForTurn = forceToollessRecoveryTurn ? [] : getToolsSchema();
2206
- const toolChoiceForTurn = forceToollessRecoveryTurn ? 'none' : 'auto';
2266
+ const toolsForTurn = (cfg.no_tools || forceToollessRecoveryTurn) ? [] : getToolsSchema();
2267
+ const toolChoiceForTurn = (cfg.no_tools || forceToollessRecoveryTurn) ? 'none' : 'auto';
2207
2268
  resp = await client.chatStream({
2208
2269
  model,
2209
2270
  messages,
@@ -3256,7 +3317,8 @@ export async function createSession(opts) {
3256
3317
  const assistantText = visible || content || '';
3257
3318
  // Recovery fuse: if the model keeps narrating/planning without tool use,
3258
3319
  // nudge it once with the original task. Never resend more than once per ask().
3259
- if (looksLikePlanningNarration(assistantText, finishReason)) {
3320
+ // Skip this check entirely when no_tools is set — text IS the final answer.
3321
+ if (!cfg.no_tools && looksLikePlanningNarration(assistantText, finishReason)) {
3260
3322
  noToolTurns += 1;
3261
3323
  messages.push({ role: 'assistant', content: assistantText });
3262
3324
  if (noToolTurns >= NO_TOOL_REPROMPT_THRESHOLD) {