@visorcraft/idlehands 1.3.2 → 1.3.3

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.js CHANGED
@@ -2192,6 +2192,7 @@ export async function createSession(opts) {
2192
2192
  }
2193
2193
  }
2194
2194
  messages = compacted;
2195
+ let summaryUsed = false;
2195
2196
  if (dropped.length) {
2196
2197
  const droppedTokens = estimateTokensFromMessages(dropped);
2197
2198
  if (cfg.compact_summary !== false && droppedTokens > 200) {
@@ -2210,6 +2211,7 @@ export async function createSession(opts) {
2210
2211
  });
2211
2212
  const summary = resp.choices?.[0]?.message?.content ?? '';
2212
2213
  if (summary.trim()) {
2214
+ summaryUsed = true;
2213
2215
  messages.push({
2214
2216
  role: 'system',
2215
2217
  content: `[Compacted ${dropped.length} messages (~${droppedTokens} tokens). Progress summary:]\n${summary.trim()}\n[Continue from where you left off. Do not repeat completed work.]`,
@@ -2230,10 +2232,19 @@ export async function createSession(opts) {
2230
2232
  // Update token count AFTER injections so downstream reads are accurate
2231
2233
  currentContextTokens = estimateTokensFromMessages(messages);
2232
2234
  const afterTokens = estimateTokensFromMessages(compacted);
2235
+ const freedTokens = Math.max(0, beforeTokens - afterTokens);
2236
+ // Emit compaction event for callers (e.g. Anton controller → Discord)
2237
+ if (dropped.length) {
2238
+ try {
2239
+ await hookObj.onCompaction?.({ droppedMessages: dropped.length, freedTokens, summaryUsed });
2240
+ }
2241
+ catch { /* best effort */ }
2242
+ console.error(`[compaction] auto: dropped=${dropped.length} msgs, freed=~${freedTokens} tokens, summary=${summaryUsed}, remaining=${messages.length} msgs (~${currentContextTokens} tokens)`);
2243
+ }
2233
2244
  return {
2234
2245
  beforeMessages: beforeMsgs.length,
2235
2246
  afterMessages: compacted.length,
2236
- freedTokens: Math.max(0, beforeTokens - afterTokens),
2247
+ freedTokens,
2237
2248
  archivedToolMessages: dropped.filter((m) => m.role === 'tool').length,
2238
2249
  droppedMessages: dropped.length,
2239
2250
  dryRun: false,
@@ -2579,6 +2590,8 @@ export async function createSession(opts) {
2579
2590
  const warningKey = `${warning.level}:${warning.detector}:${detected.signature}`;
2580
2591
  if (!toolLoopWarningKeys.has(warningKey)) {
2581
2592
  toolLoopWarningKeys.add(warningKey);
2593
+ const argsSnippet = JSON.stringify(args).slice(0, 300);
2594
+ console.error(`[tool-loop] ${warning.level}: ${warning.toolName} (${warning.detector}, count=${warning.count}) args=${argsSnippet}`);
2582
2595
  await emitToolLoop({
2583
2596
  level: warning.level,
2584
2597
  detector: warning.detector,
@@ -2748,6 +2761,7 @@ export async function createSession(opts) {
2748
2761
  lastTurnSigs = turnSigs;
2749
2762
  if (shouldForceToollessRecovery) {
2750
2763
  if (!toollessRecoveryUsed) {
2764
+ console.error(`[tool-loop] Disabling tools for one recovery turn (turn=${turns})`);
2751
2765
  forceToollessRecoveryTurn = true;
2752
2766
  toollessRecoveryUsed = true;
2753
2767
  messages.push({
@@ -2768,6 +2782,7 @@ export async function createSession(opts) {
2768
2782
  });
2769
2783
  continue;
2770
2784
  }
2785
+ console.error(`[tool-loop] Recovery failed — model resumed looping after tools-disabled turn (turn=${turns})`);
2771
2786
  throw new AgentLoopBreak('critical tool-loop persisted after one tools-disabled recovery turn. Stopping to avoid infinite loop.');
2772
2787
  }
2773
2788
  const runOne = async (tc) => {