@kolisachint/hoocode-agent 0.4.73 → 0.4.75
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/CHANGELOG.md +32 -0
- package/dist/cli/args.d.ts +0 -2
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +0 -11
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-frontmatter.d.ts.map +1 -1
- package/dist/core/agent-frontmatter.js +2 -2
- package/dist/core/agent-frontmatter.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +0 -1
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +0 -1
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +1 -17
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +3 -198
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +7 -4
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/compaction/utils.d.ts.map +1 -1
- package/dist/core/compaction/utils.js +8 -5
- package/dist/core/compaction/utils.js.map +1 -1
- package/dist/core/model-categories.d.ts +28 -0
- package/dist/core/model-categories.d.ts.map +1 -0
- package/dist/core/model-categories.js +51 -0
- package/dist/core/model-categories.js.map +1 -0
- package/dist/core/model-registry.d.ts +0 -6
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +0 -33
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/sdk.d.ts +0 -6
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +0 -1
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager.d.ts +14 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/subagent-pool-instance.d.ts.map +1 -1
- package/dist/core/subagent-pool-instance.js +36 -1
- package/dist/core/subagent-pool-instance.js.map +1 -1
- package/dist/core/subagent-pool.d.ts +31 -0
- package/dist/core/subagent-pool.d.ts.map +1 -1
- package/dist/core/subagent-pool.js +72 -19
- package/dist/core/subagent-pool.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +4 -0
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/task-store.d.ts +7 -0
- package/dist/core/task-store.d.ts.map +1 -1
- package/dist/core/task-store.js +3 -0
- package/dist/core/task-store.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts +3 -0
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js +35 -3
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +7 -1
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/glob.d.ts +42 -0
- package/dist/core/tools/glob.d.ts.map +1 -0
- package/dist/core/tools/glob.js +448 -0
- package/dist/core/tools/glob.js.map +1 -0
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +4 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +4 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +13 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/output-accumulator.d.ts +3 -0
- package/dist/core/tools/output-accumulator.d.ts.map +1 -1
- package/dist/core/tools/output-accumulator.js +8 -1
- package/dist/core/tools/output-accumulator.js.map +1 -1
- package/dist/core/tools/output-compression.d.ts +53 -0
- package/dist/core/tools/output-compression.d.ts.map +1 -0
- package/dist/core/tools/output-compression.js +392 -0
- package/dist/core/tools/output-compression.js.map +1 -0
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +4 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +0 -1
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +2 -2
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/task-panel.d.ts.map +1 -1
- package/dist/modes/interactive/components/task-panel.js +14 -27
- package/dist/modes/interactive/components/task-panel.js.map +1 -1
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +4 -4
- package/templates/agents/explore.md +1 -1
- package/templates/agents/general-purpose.md +1 -1
- package/templates/agents/plan.md +1 -1
- package/dist/core/routing/local-inference.d.ts +0 -129
- package/dist/core/routing/local-inference.d.ts.map +0 -1
- package/dist/core/routing/local-inference.js +0 -154
- package/dist/core/routing/local-inference.js.map +0 -1
- package/dist/core/routing/metrics.d.ts +0 -27
- package/dist/core/routing/metrics.d.ts.map +0 -1
- package/dist/core/routing/metrics.js +0 -35
- package/dist/core/routing/metrics.js.map +0 -1
- package/dist/core/routing/mlx-server.d.ts +0 -43
- package/dist/core/routing/mlx-server.d.ts.map +0 -1
- package/dist/core/routing/mlx-server.js +0 -115
- package/dist/core/routing/mlx-server.js.map +0 -1
- package/dist/core/routing/tool-result-prompts.d.ts +0 -26
- package/dist/core/routing/tool-result-prompts.d.ts.map +0 -1
- package/dist/core/routing/tool-result-prompts.js +0 -45
- 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,
|
|
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,
|
|
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";
|
|
@@ -113,12 +108,6 @@ export class AgentSession {
|
|
|
113
108
|
_extensionErrorUnsubscriber;
|
|
114
109
|
// Model registry for API key resolution
|
|
115
110
|
_modelRegistry;
|
|
116
|
-
// Local-inference routing (opt-in via enableLocalInference). Lazily built.
|
|
117
|
-
_enableLocalInference;
|
|
118
|
-
_localRouter;
|
|
119
|
-
_localRouterBuilt = false;
|
|
120
|
-
_mlxServer;
|
|
121
|
-
_mlxServerBuilt = false;
|
|
122
111
|
// Tool registry for extension getTools/setTools
|
|
123
112
|
_toolRegistry = new Map();
|
|
124
113
|
_toolDefinitions = new Map();
|
|
@@ -137,7 +126,6 @@ export class AgentSession {
|
|
|
137
126
|
this._customTools = config.customTools ?? [];
|
|
138
127
|
this._cwd = config.cwd;
|
|
139
128
|
this._modelRegistry = config.modelRegistry;
|
|
140
|
-
this._enableLocalInference = config.enableLocalInference ?? false;
|
|
141
129
|
this._extensionRunnerRef = config.extensionRunnerRef;
|
|
142
130
|
this._initialActiveToolNames = config.initialActiveToolNames;
|
|
143
131
|
this._allowedToolNames = config.allowedToolNames ? new Set(config.allowedToolNames) : undefined;
|
|
@@ -160,57 +148,6 @@ export class AgentSession {
|
|
|
160
148
|
get modelRegistry() {
|
|
161
149
|
return this._modelRegistry;
|
|
162
150
|
}
|
|
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
151
|
async _getRequiredRequestAuth(model) {
|
|
215
152
|
const result = await this._modelRegistry.getApiKeyAndHeaders(model);
|
|
216
153
|
if (!result.ok) {
|
|
@@ -284,92 +221,11 @@ export class AgentSession {
|
|
|
284
221
|
changed = true;
|
|
285
222
|
}
|
|
286
223
|
}
|
|
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
224
|
if (!changed)
|
|
298
225
|
return undefined;
|
|
299
226
|
return { content, details, isError: resolvedIsError };
|
|
300
227
|
};
|
|
301
228
|
}
|
|
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
229
|
// =========================================================================
|
|
374
230
|
// Event Subscription
|
|
375
231
|
// =========================================================================
|
|
@@ -680,7 +536,6 @@ export class AgentSession {
|
|
|
680
536
|
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
537
|
this._disconnectFromAgent();
|
|
682
538
|
this._eventListeners = [];
|
|
683
|
-
this._mlxServer?.stop();
|
|
684
539
|
cleanupSessionResources(this.sessionId);
|
|
685
540
|
}
|
|
686
541
|
// =========================================================================
|
|
@@ -1467,7 +1322,7 @@ export class AgentSession {
|
|
|
1467
1322
|
}
|
|
1468
1323
|
}
|
|
1469
1324
|
const generated = extensionCompaction ??
|
|
1470
|
-
(await
|
|
1325
|
+
(await compact(preparation, model, apiKey, headers, customInstructions, signal, this.thinkingLevel));
|
|
1471
1326
|
if (signal.aborted) {
|
|
1472
1327
|
return { status: "cancelled" };
|
|
1473
1328
|
}
|
|
@@ -1488,41 +1343,6 @@ export class AgentSession {
|
|
|
1488
1343
|
result: { summary, firstKeptEntryId, tokensBefore, tokensAfter: tokensAfter ?? tokensBefore, details },
|
|
1489
1344
|
};
|
|
1490
1345
|
}
|
|
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
1346
|
/**
|
|
1527
1347
|
* Manually compact the session context.
|
|
1528
1348
|
* Aborts current agent operation first.
|
|
@@ -2708,19 +2528,4 @@ export class AgentSession {
|
|
|
2708
2528
|
return this._extensionRunner;
|
|
2709
2529
|
}
|
|
2710
2530
|
}
|
|
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
2531
|
//# sourceMappingURL=agent-session.js.map
|