@kolisachint/hoocode-agent 0.4.74 → 0.4.76

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 (135) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/dist/cli/args.d.ts +0 -2
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +0 -11
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/core/agent-frontmatter.d.ts.map +1 -1
  7. package/dist/core/agent-frontmatter.js +2 -2
  8. package/dist/core/agent-frontmatter.js.map +1 -1
  9. package/dist/core/agent-session-services.d.ts +0 -1
  10. package/dist/core/agent-session-services.d.ts.map +1 -1
  11. package/dist/core/agent-session-services.js +0 -1
  12. package/dist/core/agent-session-services.js.map +1 -1
  13. package/dist/core/agent-session.d.ts +1 -17
  14. package/dist/core/agent-session.d.ts.map +1 -1
  15. package/dist/core/agent-session.js +10 -199
  16. package/dist/core/agent-session.js.map +1 -1
  17. package/dist/core/bash-executor.d.ts.map +1 -1
  18. package/dist/core/bash-executor.js +7 -4
  19. package/dist/core/bash-executor.js.map +1 -1
  20. package/dist/core/compaction/utils.d.ts.map +1 -1
  21. package/dist/core/compaction/utils.js +8 -5
  22. package/dist/core/compaction/utils.js.map +1 -1
  23. package/dist/core/exec.d.ts.map +1 -1
  24. package/dist/core/exec.js +13 -4
  25. package/dist/core/exec.js.map +1 -1
  26. package/dist/core/model-categories.d.ts +28 -0
  27. package/dist/core/model-categories.d.ts.map +1 -0
  28. package/dist/core/model-categories.js +51 -0
  29. package/dist/core/model-categories.js.map +1 -0
  30. package/dist/core/model-registry.d.ts +0 -6
  31. package/dist/core/model-registry.d.ts.map +1 -1
  32. package/dist/core/model-registry.js +0 -32
  33. package/dist/core/model-registry.js.map +1 -1
  34. package/dist/core/sdk.d.ts +0 -6
  35. package/dist/core/sdk.d.ts.map +1 -1
  36. package/dist/core/sdk.js +0 -1
  37. package/dist/core/sdk.js.map +1 -1
  38. package/dist/core/session-manager.d.ts.map +1 -1
  39. package/dist/core/session-manager.js +16 -3
  40. package/dist/core/session-manager.js.map +1 -1
  41. package/dist/core/settings-manager.d.ts +14 -0
  42. package/dist/core/settings-manager.d.ts.map +1 -1
  43. package/dist/core/settings-manager.js.map +1 -1
  44. package/dist/core/subagent-pool-instance.d.ts.map +1 -1
  45. package/dist/core/subagent-pool-instance.js +9 -1
  46. package/dist/core/subagent-pool-instance.js.map +1 -1
  47. package/dist/core/subagent-pool.d.ts +5 -0
  48. package/dist/core/subagent-pool.d.ts.map +1 -1
  49. package/dist/core/subagent-pool.js +13 -2
  50. package/dist/core/subagent-pool.js.map +1 -1
  51. package/dist/core/tools/edit-diff.d.ts +3 -0
  52. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  53. package/dist/core/tools/edit-diff.js +132 -40
  54. package/dist/core/tools/edit-diff.js.map +1 -1
  55. package/dist/core/tools/edit.d.ts.map +1 -1
  56. package/dist/core/tools/edit.js +7 -1
  57. package/dist/core/tools/edit.js.map +1 -1
  58. package/dist/core/tools/fd-utils.d.ts +23 -0
  59. package/dist/core/tools/fd-utils.d.ts.map +1 -0
  60. package/dist/core/tools/fd-utils.js +47 -0
  61. package/dist/core/tools/fd-utils.js.map +1 -0
  62. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  63. package/dist/core/tools/file-mutation-queue.js +15 -2
  64. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  65. package/dist/core/tools/find.d.ts.map +1 -1
  66. package/dist/core/tools/find.js +3 -24
  67. package/dist/core/tools/find.js.map +1 -1
  68. package/dist/core/tools/glob.d.ts +42 -0
  69. package/dist/core/tools/glob.d.ts.map +1 -0
  70. package/dist/core/tools/glob.js +432 -0
  71. package/dist/core/tools/glob.js.map +1 -0
  72. package/dist/core/tools/grep.d.ts.map +1 -1
  73. package/dist/core/tools/grep.js +34 -19
  74. package/dist/core/tools/grep.js.map +1 -1
  75. package/dist/core/tools/index.d.ts +4 -1
  76. package/dist/core/tools/index.d.ts.map +1 -1
  77. package/dist/core/tools/index.js +13 -1
  78. package/dist/core/tools/index.js.map +1 -1
  79. package/dist/core/tools/ls.d.ts +12 -1
  80. package/dist/core/tools/ls.d.ts.map +1 -1
  81. package/dist/core/tools/ls.js +58 -33
  82. package/dist/core/tools/ls.js.map +1 -1
  83. package/dist/core/tools/output-accumulator.d.ts +4 -0
  84. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  85. package/dist/core/tools/output-accumulator.js +39 -20
  86. package/dist/core/tools/output-accumulator.js.map +1 -1
  87. package/dist/core/tools/output-compression.d.ts +53 -0
  88. package/dist/core/tools/output-compression.d.ts.map +1 -0
  89. package/dist/core/tools/output-compression.js +392 -0
  90. package/dist/core/tools/output-compression.js.map +1 -0
  91. package/dist/core/tools/read.d.ts.map +1 -1
  92. package/dist/core/tools/read.js +9 -1
  93. package/dist/core/tools/read.js.map +1 -1
  94. package/dist/core/tools/render-utils.d.ts.map +1 -1
  95. package/dist/core/tools/render-utils.js +9 -2
  96. package/dist/core/tools/render-utils.js.map +1 -1
  97. package/dist/core/tools/write.d.ts.map +1 -1
  98. package/dist/core/tools/write.js +4 -1
  99. package/dist/core/tools/write.js.map +1 -1
  100. package/dist/main.d.ts.map +1 -1
  101. package/dist/main.js +0 -1
  102. package/dist/main.js.map +1 -1
  103. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  104. package/dist/modes/interactive/components/bash-execution.js +2 -2
  105. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  106. package/dist/modes/interactive/components/task-panel.d.ts.map +1 -1
  107. package/dist/modes/interactive/components/task-panel.js +10 -26
  108. package/dist/modes/interactive/components/task-panel.js.map +1 -1
  109. package/dist/utils/tools-manager.d.ts.map +1 -1
  110. package/dist/utils/tools-manager.js +16 -0
  111. package/dist/utils/tools-manager.js.map +1 -1
  112. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  113. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  114. package/examples/extensions/sandbox/package.json +1 -1
  115. package/examples/extensions/with-deps/package.json +1 -1
  116. package/package.json +4 -4
  117. package/templates/agents/explore.md +1 -1
  118. package/templates/agents/general-purpose.md +1 -1
  119. package/templates/agents/plan.md +1 -1
  120. package/dist/core/routing/local-inference.d.ts +0 -128
  121. package/dist/core/routing/local-inference.d.ts.map +0 -1
  122. package/dist/core/routing/local-inference.js +0 -145
  123. package/dist/core/routing/local-inference.js.map +0 -1
  124. package/dist/core/routing/metrics.d.ts +0 -27
  125. package/dist/core/routing/metrics.d.ts.map +0 -1
  126. package/dist/core/routing/metrics.js +0 -35
  127. package/dist/core/routing/metrics.js.map +0 -1
  128. package/dist/core/routing/mlx-server.d.ts +0 -43
  129. package/dist/core/routing/mlx-server.d.ts.map +0 -1
  130. package/dist/core/routing/mlx-server.js +0 -115
  131. package/dist/core/routing/mlx-server.js.map +0 -1
  132. package/dist/core/routing/tool-result-prompts.d.ts +0 -26
  133. package/dist/core/routing/tool-result-prompts.d.ts.map +0 -1
  134. package/dist/core/routing/tool-result-prompts.js +0 -45
  135. package/dist/core/routing/tool-result-prompts.js.map +0 -1
@@ -14,26 +14,21 @@
14
14
  */
15
15
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
16
16
  import { basename, dirname, resolve } from "node:path";
17
- import { clampThinkingLevel, cleanupSessionResources, completeSimple, getSupportedThinkingLevels, isContextOverflow, modelsAreEqual, resetApiProviders, } from "@kolisachint/hoocode-ai";
17
+ import { clampThinkingLevel, cleanupSessionResources, getSupportedThinkingLevels, isContextOverflow, modelsAreEqual, resetApiProviders, } from "@kolisachint/hoocode-ai";
18
18
  import { theme } from "../modes/interactive/theme/theme.js";
19
19
  import { stripFrontmatter } from "../utils/frontmatter.js";
20
20
  import { sleep } from "../utils/sleep.js";
21
21
  import { loadAgentRegistry } from "./agent-registry.js";
22
22
  import { formatNoApiKeyFoundMessage, formatNoModelSelectedMessage } from "./auth-guidance.js";
23
23
  import { executeBashWithOperations } from "./bash-executor.js";
24
- import { calculateContextTokens, collectEntriesForBranchSummary, compact, estimateContextTokens, generateBranchSummary, prepareCompaction, serializeConversation, shouldCompact, } from "./compaction/index.js";
24
+ import { calculateContextTokens, collectEntriesForBranchSummary, compact, estimateContextTokens, generateBranchSummary, prepareCompaction, shouldCompact, } from "./compaction/index.js";
25
25
  import { DEFAULT_THINKING_LEVEL } from "./defaults.js";
26
26
  import { exportSessionToHtml } from "./export-html/index.js";
27
27
  import { createToolHtmlRenderer } from "./export-html/tool-renderer.js";
28
28
  import { ExtensionRunner, wrapRegisteredTools, } from "./extensions/index.js";
29
29
  import { emitSessionShutdownEvent } from "./extensions/runner.js";
30
- import { convertToLlm } from "./messages.js";
31
30
  import { expandPromptTemplate, tryExpandPromptTemplate } from "./prompt-templates.js";
32
31
  import { clearProviderExhaustion, isProviderQuotaError, markProviderExhausted } from "./provider-health.js";
33
- import { LocalInferenceRouter, resolveRoutingMode } from "./routing/local-inference.js";
34
- import { logLocalInferenceFallback, logRoutingMetrics } from "./routing/metrics.js";
35
- import { MlxServerManager } from "./routing/mlx-server.js";
36
- import { buildToolResultPrompt, stripThinkTags, TOOL_RESULT_SYSTEM_PROMPT } from "./routing/tool-result-prompts.js";
37
32
  import { CURRENT_SESSION_VERSION, getLatestCompactionEntry } from "./session-manager.js";
38
33
  import { createSyntheticSourceInfo } from "./source-info.js";
39
34
  import { updateSubagentSkillPaths } from "./subagent-pool-instance.js";
@@ -41,6 +36,12 @@ import { buildSystemPrompt } from "./system-prompt.js";
41
36
  import { createLocalBashOperations } from "./tools/bash.js";
42
37
  import { createAllToolDefinitions } from "./tools/index.js";
43
38
  import { createToolDefinitionFromAgentTool } from "./tools/tool-definition-wrapper.js";
39
+ /**
40
+ * Retryable error signatures (overloaded, rate limit, server/network errors,
41
+ * transport closes). Compiled once at module load instead of on every assistant
42
+ * response. Context-overflow errors are handled separately by compaction.
43
+ */
44
+ const RETRYABLE_ERROR_PATTERN = /overloaded|provider.?returned.?error|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server.?error|internal.?error|network.?error|connection.?error|connection.?refused|connection.?lost|websocket.?closed|websocket.?error|other side closed|fetch failed|upstream.?connect|reset before headers|socket hang up|ended without|http2 request did not get a response|timed? out|timeout|terminated|retry delay/i;
44
45
  /**
45
46
  * Parse a skill block from message text.
46
47
  * Returns null if the text doesn't contain a skill block.
@@ -113,12 +114,6 @@ export class AgentSession {
113
114
  _extensionErrorUnsubscriber;
114
115
  // Model registry for API key resolution
115
116
  _modelRegistry;
116
- // Local-inference routing (opt-in via enableLocalInference). Lazily built.
117
- _enableLocalInference;
118
- _localRouter;
119
- _localRouterBuilt = false;
120
- _mlxServer;
121
- _mlxServerBuilt = false;
122
117
  // Tool registry for extension getTools/setTools
123
118
  _toolRegistry = new Map();
124
119
  _toolDefinitions = new Map();
@@ -137,7 +132,6 @@ export class AgentSession {
137
132
  this._customTools = config.customTools ?? [];
138
133
  this._cwd = config.cwd;
139
134
  this._modelRegistry = config.modelRegistry;
140
- this._enableLocalInference = config.enableLocalInference ?? false;
141
135
  this._extensionRunnerRef = config.extensionRunnerRef;
142
136
  this._initialActiveToolNames = config.initialActiveToolNames;
143
137
  this._allowedToolNames = config.allowedToolNames ? new Set(config.allowedToolNames) : undefined;
@@ -160,57 +154,6 @@ export class AgentSession {
160
154
  get modelRegistry() {
161
155
  return this._modelRegistry;
162
156
  }
163
- /**
164
- * Local-inference router, built lazily from the flag + env + models.json
165
- * routing config. Returns undefined when routing is not active.
166
- */
167
- get localRouter() {
168
- if (!this._localRouterBuilt) {
169
- this._localRouterBuilt = true;
170
- const mode = resolveRoutingMode({
171
- enableFlag: this._enableLocalInference,
172
- envMode: process.env.HOOCODE_ROUTING_MODE,
173
- configMode: this._modelRegistry.getRoutingConfig()?.mode,
174
- });
175
- this._localRouter =
176
- mode === "primary-only"
177
- ? undefined
178
- : LocalInferenceRouter.create({
179
- mode,
180
- config: this._modelRegistry.getRoutingConfig(),
181
- registry: this._modelRegistry,
182
- });
183
- }
184
- return this._localRouter;
185
- }
186
- /**
187
- * Ensure the harness-managed executor server (if configured) is healthy before
188
- * the executor is used. Returns false when routing is inactive or the server
189
- * could not be started (caller degrades to primary/raw). Reuses an externally
190
- * started server when one is already healthy.
191
- */
192
- async _ensureExecutorServer(signal) {
193
- const router = this.localRouter;
194
- if (!router?.isExecutorAvailable())
195
- return false;
196
- const serverConfig = router.getExecutorConfig()?.server;
197
- if (!serverConfig)
198
- return true; // user-managed server; assume available
199
- if (!this._mlxServerBuilt) {
200
- this._mlxServerBuilt = true;
201
- const executor = router.getExecutorModel();
202
- if (executor) {
203
- this._mlxServer = new MlxServerManager({
204
- config: serverConfig,
205
- modelId: executor.id,
206
- baseUrl: executor.baseUrl,
207
- });
208
- }
209
- }
210
- if (!this._mlxServer)
211
- return false;
212
- return this._mlxServer.ensureStarted(signal);
213
- }
214
157
  async _getRequiredRequestAuth(model) {
215
158
  const result = await this._modelRegistry.getApiKeyAndHeaders(model);
216
159
  if (!result.ok) {
@@ -284,92 +227,11 @@ export class AgentSession {
284
227
  changed = true;
285
228
  }
286
229
  }
287
- // Optionally compress large bash output before it enters context.
288
- // Only when local-inference tool-result routing is active; on any
289
- // failure the original (uncompressed) content is kept (fallback to raw).
290
- if (!resolvedIsError) {
291
- const compressed = await this._maybeCompressToolResult(toolCall.name, content);
292
- if (compressed) {
293
- content = compressed;
294
- changed = true;
295
- }
296
- }
297
230
  if (!changed)
298
231
  return undefined;
299
232
  return { content, details, isError: resolvedIsError };
300
233
  };
301
234
  }
302
- /**
303
- * Compress a tool result via the local executor when routing is active and the
304
- * tool/size qualify. Returns the compressed content blocks, or undefined to
305
- * keep the original (no routing, not compressible, outside the size band, or
306
- * any failure).
307
- */
308
- async _maybeCompressToolResult(toolName, content) {
309
- const router = this.localRouter;
310
- if (!router)
311
- return undefined;
312
- const text = extractTextContent(content);
313
- if (text === undefined)
314
- return undefined;
315
- const bytes = Buffer.byteLength(text, "utf8");
316
- if (!router.shouldCompressToolResult(toolName, bytes))
317
- return undefined;
318
- const executor = router.getExecutorModel();
319
- const prompt = buildToolResultPrompt(toolName, text);
320
- if (!executor || !prompt)
321
- return undefined;
322
- const startedAt = Date.now();
323
- try {
324
- if (!(await this._ensureExecutorServer())) {
325
- throw new Error("executor server unavailable");
326
- }
327
- const { apiKey, headers } = await this._getRequiredRequestAuth(executor);
328
- const response = await completeSimple(executor, {
329
- systemPrompt: TOOL_RESULT_SYSTEM_PROMPT,
330
- messages: [
331
- {
332
- role: "user",
333
- content: [{ type: "text", text: prompt }],
334
- timestamp: Date.now(),
335
- },
336
- ],
337
- }, { apiKey, headers });
338
- if (response.stopReason === "error") {
339
- throw new Error(response.errorMessage || "executor error");
340
- }
341
- const rawSummary = response.content
342
- .filter((c) => c.type === "text")
343
- .map((c) => c.text)
344
- .join("\n");
345
- const summary = stripThinkTags(rawSummary);
346
- if (summary === "")
347
- throw new Error("empty compression");
348
- const compressedBytes = Buffer.byteLength(summary, "utf8");
349
- // Guard: if the model failed to compress (output not smaller), keep raw.
350
- if (compressedBytes >= bytes)
351
- return undefined;
352
- logRoutingMetrics({
353
- turnKind: "tool-result",
354
- provider: executor.provider,
355
- model: executor.id,
356
- latencyMs: Date.now() - startedAt,
357
- bytesBefore: bytes,
358
- bytesAfter: compressedBytes,
359
- fallback: false,
360
- });
361
- return [
362
- {
363
- type: "text",
364
- text: `${summary}\n\n[compressed from ${bytes} to ${compressedBytes} bytes by local executor]`,
365
- },
366
- ];
367
- }
368
- catch (error) {
369
- logLocalInferenceFallback("tool-result", error);
370
- return undefined;
371
- }
372
- }
373
235
  // =========================================================================
374
236
  // Event Subscription
375
237
  // =========================================================================
@@ -680,7 +542,6 @@ export class AgentSession {
680
542
  this._extensionRunner.invalidate("This extension ctx is stale after session replacement or reload. Do not use a captured extension API or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().");
681
543
  this._disconnectFromAgent();
682
544
  this._eventListeners = [];
683
- this._mlxServer?.stop();
684
545
  cleanupSessionResources(this.sessionId);
685
546
  }
686
547
  // =========================================================================
@@ -1467,7 +1328,7 @@ export class AgentSession {
1467
1328
  }
1468
1329
  }
1469
1330
  const generated = extensionCompaction ??
1470
- (await this._compactWithRouting(preparation, model, apiKey, headers, customInstructions, signal));
1331
+ (await compact(preparation, model, apiKey, headers, customInstructions, signal, this.thinkingLevel));
1471
1332
  if (signal.aborted) {
1472
1333
  return { status: "cancelled" };
1473
1334
  }
@@ -1488,41 +1349,6 @@ export class AgentSession {
1488
1349
  result: { summary, firstKeptEntryId, tokensBefore, tokensAfter: tokensAfter ?? tokensBefore, details },
1489
1350
  };
1490
1351
  }
1491
- /**
1492
- * Run compaction, routing the summarization to the local executor model when
1493
- * local-inference routing is active for summarization. Any executor
1494
- * failure falls back to the primary model so compaction never hard-fails.
1495
- */
1496
- async _compactWithRouting(preparation, primaryModel, apiKey, headers, customInstructions, signal) {
1497
- const router = this.localRouter;
1498
- const executor = router?.selectModel("summarization", primaryModel);
1499
- // Size band guards local inference globally: only route conversations within
1500
- // the configured byte band to the executor. Oversized conversations are slow
1501
- // locally and can OOM small machines, so they fall back to the primary model.
1502
- // Only serialize to measure size when routing is actually engaged (avoids
1503
- // needless work on the common primary-only path).
1504
- if (router && executor && executor !== primaryModel) {
1505
- const conversationBytes = Buffer.byteLength(serializeConversation(convertToLlm(preparation.messagesToSummarize)), "utf8");
1506
- if (router.withinSizeBand(conversationBytes)) {
1507
- try {
1508
- if (!(await this._ensureExecutorServer(signal))) {
1509
- throw new Error("executor server unavailable");
1510
- }
1511
- const { apiKey: exKey, headers: exHeaders } = await this._getRequiredRequestAuth(executor);
1512
- return await compact(preparation, executor, exKey, exHeaders, customInstructions, signal,
1513
- // Executor runs without thinking (validated config); summary quality
1514
- // relies on /no_think via the model's promptSuffix compat setting.
1515
- "off");
1516
- }
1517
- catch (error) {
1518
- if (signal.aborted)
1519
- throw error;
1520
- logLocalInferenceFallback("summarization", error);
1521
- }
1522
- }
1523
- }
1524
- return compact(preparation, primaryModel, apiKey, headers, customInstructions, signal, this.thinkingLevel);
1525
- }
1526
1352
  /**
1527
1353
  * Manually compact the session context.
1528
1354
  * Aborts current agent operation first.
@@ -2118,7 +1944,7 @@ export class AgentSession {
2118
1944
  return false;
2119
1945
  const err = message.errorMessage;
2120
1946
  // Match: overloaded_error, provider returned error, rate limit, 429, 500, 502, 503, 504, service unavailable, network/connection errors (including connection lost), WebSocket transport closes/errors, fetch failed, request ended without sending chunks, HTTP/2 closed before response, terminated, retry delay exceeded
2121
- return /overloaded|provider.?returned.?error|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server.?error|internal.?error|network.?error|connection.?error|connection.?refused|connection.?lost|websocket.?closed|websocket.?error|other side closed|fetch failed|upstream.?connect|reset before headers|socket hang up|ended without|http2 request did not get a response|timed? out|timeout|terminated|retry delay/i.test(err);
1947
+ return RETRYABLE_ERROR_PATTERN.test(err);
2122
1948
  }
2123
1949
  /**
2124
1950
  * Handle retryable errors with exponential backoff.
@@ -2708,19 +2534,4 @@ export class AgentSession {
2708
2534
  return this._extensionRunner;
2709
2535
  }
2710
2536
  }
2711
- /**
2712
- * Join all text blocks of a tool result. Returns undefined if any non-text
2713
- * (e.g. image) content is present, since those must not be compressed.
2714
- */
2715
- function extractTextContent(content) {
2716
- if (content.length === 0)
2717
- return undefined;
2718
- const texts = [];
2719
- for (const block of content) {
2720
- if (block.type !== "text")
2721
- return undefined;
2722
- texts.push(block.text);
2723
- }
2724
- return texts.join("\n");
2725
- }
2726
2537
  //# sourceMappingURL=agent-session.js.map