@kinqs/brainrouter-cli 0.3.5 → 0.3.6
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/.env.example +55 -48
- package/bin/cli.cjs +71 -0
- package/dist/agent/agent.d.ts +212 -2
- package/dist/agent/agent.js +428 -38
- package/dist/cli/banner.d.ts +60 -0
- package/dist/cli/banner.js +199 -0
- package/dist/cli/cliPrompt.d.ts +69 -0
- package/dist/cli/cliPrompt.js +287 -0
- package/dist/cli/commands/_helpers.js +6 -6
- package/dist/cli/commands/guard.js +75 -10
- package/dist/cli/commands/mcp.d.ts +17 -0
- package/dist/cli/commands/mcp.js +121 -0
- package/dist/cli/commands/memory.js +2 -2
- package/dist/cli/commands/obs.js +22 -22
- package/dist/cli/commands/session.js +13 -5
- package/dist/cli/commands/ui.js +97 -45
- package/dist/cli/commands/workflow.d.ts +18 -0
- package/dist/cli/commands/workflow.js +314 -43
- package/dist/cli/repl.js +219 -132
- package/dist/cli/spinner.d.ts +34 -0
- package/dist/cli/spinner.js +36 -0
- package/dist/cli/statusline.d.ts +67 -0
- package/dist/cli/statusline.js +204 -0
- package/dist/cli/theme.d.ts +79 -0
- package/dist/cli/theme.js +106 -0
- package/dist/cli/whereView.d.ts +81 -0
- package/dist/cli/whereView.js +245 -0
- package/dist/config/config.d.ts +40 -0
- package/dist/config/config.js +45 -73
- package/dist/index.js +80 -13
- package/dist/memory/briefing.d.ts +10 -0
- package/dist/memory/briefing.js +69 -1
- package/dist/prompt/breadthHint.d.ts +5 -0
- package/dist/prompt/breadthHint.js +44 -0
- package/dist/prompt/systemPrompt.d.ts +34 -0
- package/dist/prompt/systemPrompt.js +124 -108
- package/dist/runtime/dangerousCommand.d.ts +53 -0
- package/dist/runtime/dangerousCommand.js +105 -0
- package/dist/runtime/mcpClient.d.ts +38 -1
- package/dist/runtime/mcpClient.js +90 -2
- package/dist/state/goalStore.d.ts +98 -17
- package/dist/state/goalStore.js +132 -42
- package/dist/state/preferencesStore.d.ts +67 -3
- package/dist/state/preferencesStore.js +84 -1
- package/dist/state/workflowArtifacts.d.ts +63 -2
- package/dist/state/workflowArtifacts.js +120 -8
- package/dist/tests/_helpers.d.ts +31 -0
- package/dist/tests/_helpers.js +91 -0
- package/package.json +5 -4
package/.env.example
CHANGED
|
@@ -1,77 +1,81 @@
|
|
|
1
|
-
# BrainRouter CLI agent — environment
|
|
1
|
+
# BrainRouter CLI agent — environment template
|
|
2
2
|
#
|
|
3
|
-
# Copy to brainrouter-cli/.env
|
|
3
|
+
# Copy to `brainrouter-cli/.env`. Loaded by the CLI at startup.
|
|
4
4
|
#
|
|
5
5
|
# This file is for CLI-AGENT concerns only:
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# - workspace override
|
|
6
|
+
# 1. Chat LLM (the model the terminal agent talks to)
|
|
7
|
+
# 2. Tool runtime (loop limit, result clamp, MCP timeout, auto-compact)
|
|
8
|
+
# 3. Sandbox (run_command wrapping)
|
|
9
|
+
# 4. Workspace (root override + shared state root)
|
|
10
|
+
# 5. Web search (custom backend for the web_search tool)
|
|
11
|
+
# 6. Observability (trace log path)
|
|
13
12
|
#
|
|
14
|
-
# MCP-server concerns (cognitive extraction, embeddings, reranker,
|
|
15
|
-
# engine knobs, server auth) live in brainrouter/.env.example
|
|
13
|
+
# MCP-server concerns (cognitive extraction, embeddings, reranker, judge,
|
|
14
|
+
# memory engine knobs, server auth) live in `brainrouter/.env.example`.
|
|
16
15
|
#
|
|
17
16
|
# Why split: the MCP and the CLI are separate processes with different
|
|
18
17
|
# concerns. The CLI's chat LLM can be a smart cloud model while the MCP's
|
|
19
18
|
# cognitive extractor is a cheap local one. Their concurrency caps differ
|
|
20
19
|
# too (CLI default 4, MCP default 2). Keep them independent.
|
|
20
|
+
#
|
|
21
|
+
# All values in this template are blank placeholders. Fill in only what
|
|
22
|
+
# you actually need — most settings have sensible defaults.
|
|
23
|
+
|
|
21
24
|
|
|
22
|
-
#
|
|
23
|
-
# Chat LLM (for the agent's own conversation)
|
|
24
|
-
#
|
|
25
|
+
# =============================================================================
|
|
26
|
+
# 1. Chat LLM (for the agent's own conversation)
|
|
27
|
+
# =============================================================================
|
|
25
28
|
# Same var names as the MCP, but a separate process — set them here for the
|
|
26
29
|
# CLI's chat model. Falls back to OPENAI_API_KEY.
|
|
27
30
|
#
|
|
28
31
|
# If you don't set BRAINROUTER_LLM_API_KEY here, the CLI also reads it from
|
|
29
|
-
# brainrouter/.env as a transitional fallback. Setting it here makes the
|
|
32
|
+
# `brainrouter/.env` as a transitional fallback. Setting it here makes the
|
|
30
33
|
# CLI's choice explicit and lets you use a different chat model than the
|
|
31
34
|
# MCP's extractor (e.g. gpt-4o for chat, gpt-4o-mini for extraction).
|
|
32
|
-
BRAINROUTER_LLM_API_KEY=
|
|
35
|
+
BRAINROUTER_LLM_API_KEY=
|
|
33
36
|
|
|
34
37
|
# OpenAI-compatible chat-completions endpoint.
|
|
35
38
|
# Examples:
|
|
36
|
-
# OpenAI:
|
|
37
|
-
# OpenRouter:
|
|
38
|
-
# Anthropic via OpenRouter: anthropic/claude-sonnet-4
|
|
39
|
-
# LM Studio:
|
|
39
|
+
# OpenAI: https://api.openai.com/v1/chat/completions
|
|
40
|
+
# OpenRouter: https://openrouter.ai/api/v1/chat/completions
|
|
41
|
+
# Anthropic via OpenRouter: model id "anthropic/claude-sonnet-4"
|
|
42
|
+
# LM Studio: http://localhost:1234/v1/chat/completions
|
|
40
43
|
BRAINROUTER_LLM_ENDPOINT=https://api.openai.com/v1/chat/completions
|
|
41
|
-
|
|
42
44
|
BRAINROUTER_LLM_MODEL=gpt-4o-mini
|
|
43
45
|
|
|
44
|
-
# Per-call timeout for the CLI's chat LLM. Default
|
|
46
|
+
# Per-call timeout for the CLI's chat LLM. Default 120000 (2 min).
|
|
45
47
|
# BRAINROUTER_LLM_TIMEOUT_MS=120000
|
|
46
48
|
|
|
47
49
|
# Cap on concurrent in-flight chat LLM calls FROM THE CLI PROCESS.
|
|
48
|
-
# Default
|
|
49
|
-
# local backends;
|
|
50
|
+
# Default 4 (separate from the MCP's own cap). Set to 1 for consumer-grade
|
|
51
|
+
# local backends; raise to 16+ for cloud APIs.
|
|
50
52
|
# BRAINROUTER_LLM_MAX_CONCURRENT=4
|
|
51
53
|
|
|
52
|
-
|
|
53
|
-
#
|
|
54
|
-
#
|
|
55
|
-
#
|
|
54
|
+
|
|
55
|
+
# =============================================================================
|
|
56
|
+
# 2. Tool runtime
|
|
57
|
+
# =============================================================================
|
|
58
|
+
# Per-tool timeout for CLI → MCP requests. Default 60000.
|
|
56
59
|
# BRAINROUTER_MCP_TIMEOUT_MS=60000
|
|
57
60
|
|
|
58
61
|
# LLM-visible clamp on a single tool-result body (full text still recorded
|
|
59
|
-
# in the transcript on disk). Default
|
|
62
|
+
# in the transcript on disk). Default 8000.
|
|
60
63
|
# BRAINROUTER_MAX_TOOL_RESULT_CHARS=8000
|
|
61
64
|
|
|
62
|
-
# Hard ceiling on tool-call iterations per turn. Default
|
|
65
|
+
# Hard ceiling on tool-call iterations per turn. Default 60.
|
|
63
66
|
# BRAINROUTER_MAX_TOOL_LOOPS=60
|
|
64
67
|
|
|
65
|
-
# Estimated history-size trigger for auto-`/compact`. Default
|
|
68
|
+
# Estimated history-size trigger for auto-`/compact`. Default 80000 tokens.
|
|
66
69
|
# BRAINROUTER_AUTO_COMPACT_TOKENS=80000
|
|
67
70
|
|
|
68
|
-
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
+
|
|
72
|
+
# =============================================================================
|
|
73
|
+
# 3. Sandbox (run_command)
|
|
74
|
+
# =============================================================================
|
|
71
75
|
# Wrap shell commands in the platform sandbox:
|
|
72
76
|
# macOS: sandbox-exec
|
|
73
77
|
# Linux: bwrap (preferred) or firejail
|
|
74
|
-
# Set
|
|
78
|
+
# Set `on` to enable. Off by default.
|
|
75
79
|
# BRAINROUTER_SANDBOX=on
|
|
76
80
|
|
|
77
81
|
# Allow outbound network from sandboxed commands. Off by default.
|
|
@@ -81,29 +85,32 @@ BRAINROUTER_LLM_MODEL=gpt-4o-mini
|
|
|
81
85
|
# BRAINROUTER_SANDBOX_READ_PATHS=/usr/local:/opt
|
|
82
86
|
# BRAINROUTER_SANDBOX_WRITE_PATHS=/tmp
|
|
83
87
|
|
|
84
|
-
|
|
85
|
-
#
|
|
86
|
-
#
|
|
87
|
-
#
|
|
88
|
-
#
|
|
88
|
+
|
|
89
|
+
# =============================================================================
|
|
90
|
+
# 4. Workspace
|
|
91
|
+
# =============================================================================
|
|
92
|
+
# Override the workspace root the CLI uses for file tools + session key.
|
|
93
|
+
# Most users let the CLI auto-detect via git / closest package.json.
|
|
89
94
|
# BRAINROUTER_WORKSPACE=/path/to/project
|
|
90
95
|
|
|
91
96
|
# Override per-user state root. Default: ~/.brainrouter.
|
|
92
97
|
# Both the CLI and MCP honor this — set it once and both processes use it.
|
|
93
98
|
# BRAINROUTER_HOME=/path/to/state
|
|
94
99
|
|
|
95
|
-
|
|
96
|
-
#
|
|
97
|
-
#
|
|
100
|
+
|
|
101
|
+
# =============================================================================
|
|
102
|
+
# 5. Web search
|
|
103
|
+
# =============================================================================
|
|
98
104
|
# Custom search backend for the web_search tool. Must accept
|
|
99
|
-
# POST { query, maxResults } → { results: [{ title, url, snippet }] }
|
|
105
|
+
# POST { query, maxResults } → { results: [{ title, url, snippet }] }
|
|
100
106
|
# Falls back to DuckDuckGo's Instant Answer API when unset.
|
|
101
|
-
# Compatible with Brave Search API wrappers, Tavily, SerpAPI proxies.
|
|
107
|
+
# Compatible with Brave Search API wrappers, Tavily, SerpAPI proxies, etc.
|
|
102
108
|
# BRAINROUTER_WEB_SEARCH_ENDPOINT=https://your-search-proxy.example.com/search
|
|
103
109
|
|
|
104
|
-
|
|
105
|
-
#
|
|
106
|
-
#
|
|
110
|
+
|
|
111
|
+
# =============================================================================
|
|
112
|
+
# 6. Observability
|
|
113
|
+
# =============================================================================
|
|
107
114
|
# Path for OTEL-style JSONL turn traces. One line per turn/tool span.
|
|
108
115
|
# Toggle at runtime with /trace on|off.
|
|
109
116
|
# BRAINROUTER_TRACE_LOG=/path/to/trace.jsonl
|
package/bin/cli.cjs
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Thin CommonJS shim that runs BEFORE the real ESM CLI entrypoint.
|
|
5
|
+
*
|
|
6
|
+
* Why CJS for the bin: ESM hoists all `import` statements above any
|
|
7
|
+
* top-level code in the module that owns them. The CLI imports
|
|
8
|
+
* `node:sqlite` transitively via `config/config.ts`, which triggers
|
|
9
|
+
* Node's `ExperimentalWarning` the FIRST time the module is touched —
|
|
10
|
+
* and that happens during import resolution, before any line of code
|
|
11
|
+
* in `src/index.ts` runs. So a warning filter installed inside that
|
|
12
|
+
* file always fires too late.
|
|
13
|
+
*
|
|
14
|
+
* This shim does three things synchronously, with zero ESM imports
|
|
15
|
+
* blocking it, and only then hands off:
|
|
16
|
+
*
|
|
17
|
+
* 1. Remove Node's default "warning" printer.
|
|
18
|
+
* 2. Install a filtered listener that drops `ExperimentalWarning`
|
|
19
|
+
* (sqlite, ESM in older Node) and dotenv self-promotion lines.
|
|
20
|
+
* 3. Override `process.emitWarning` so future direct callers also
|
|
21
|
+
* route through the same filter.
|
|
22
|
+
*
|
|
23
|
+
* Anything BrainRouter itself emits via `process.emitWarning('…',
|
|
24
|
+
* 'BrainRouterWarning')` (or any non-suppressible type) flows through
|
|
25
|
+
* unchanged. NODE_NO_WARNINGS=1 would silence those too, which is why
|
|
26
|
+
* we don't just set that env.
|
|
27
|
+
*
|
|
28
|
+
* The shim then dynamically imports the ESM entry. Dynamic `import()`
|
|
29
|
+
* is the only way to load ESM from CJS; it returns a promise we await
|
|
30
|
+
* so an unhandled rejection during boot still surfaces as an error.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
function isSuppressibleWarning(message, type) {
|
|
34
|
+
const looksExperimental =
|
|
35
|
+
type === 'ExperimentalWarning' ||
|
|
36
|
+
/experimental feature|SQLite is an experimental/i.test(message);
|
|
37
|
+
const looksDotenvNoise = /dotenv@\d|dotenvx|dotenv\.org/i.test(message);
|
|
38
|
+
return looksExperimental || looksDotenvNoise;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
for (const listener of process.listeners('warning')) {
|
|
42
|
+
process.removeListener('warning', listener);
|
|
43
|
+
}
|
|
44
|
+
process.on('warning', (warning) => {
|
|
45
|
+
const message = (warning && warning.message) || '';
|
|
46
|
+
const type = (warning && warning.name) || '';
|
|
47
|
+
if (isSuppressibleWarning(message, type)) return;
|
|
48
|
+
process.stderr.write(`(node:${process.pid}) ${type || 'Warning'}: ${message || warning}\n`);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const originalEmitWarning = process.emitWarning.bind(process);
|
|
52
|
+
process.emitWarning = function emitWarning(warning, ...rest) {
|
|
53
|
+
const message = typeof warning === 'string' ? warning : (warning && warning.message) || '';
|
|
54
|
+
const type =
|
|
55
|
+
typeof rest[0] === 'string' ? rest[0] :
|
|
56
|
+
(rest[0] && typeof rest[0] === 'object' && 'type' in rest[0]) ? rest[0].type :
|
|
57
|
+
(warning && warning.name) || '';
|
|
58
|
+
if (isSuppressibleWarning(message, type)) return;
|
|
59
|
+
return originalEmitWarning(warning, ...rest);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// Path to the compiled ESM entry, resolved relative to this shim.
|
|
63
|
+
const path = require('node:path');
|
|
64
|
+
const url = require('node:url');
|
|
65
|
+
const entry = path.resolve(__dirname, '..', 'dist', 'index.js');
|
|
66
|
+
import(url.pathToFileURL(entry).href).catch((err) => {
|
|
67
|
+
// Surface boot-time errors verbatim — a silent exit would just look like
|
|
68
|
+
// the CLI never started.
|
|
69
|
+
process.stderr.write(`brainrouter: failed to load CLI entrypoint: ${(err && err.stack) || err}\n`);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
});
|
package/dist/agent/agent.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { McpClientWrapper } from '../runtime/mcpClient.js';
|
|
2
2
|
import type { LLMConfig } from '../config/config.js';
|
|
3
3
|
import type { AccessMode } from '../orchestration/roles.js';
|
|
4
|
+
import { type RecalledRecord } from '../memory/briefing.js';
|
|
5
|
+
import { type EffortLevel } from '../state/preferencesStore.js';
|
|
4
6
|
export interface RunTurnCallbacks {
|
|
5
7
|
onStatusUpdate: (status: string) => void;
|
|
6
8
|
onToolStart: (name: string, args: Record<string, any>) => void;
|
|
@@ -77,6 +79,12 @@ export interface ChatCompletionPayload {
|
|
|
77
79
|
};
|
|
78
80
|
}>;
|
|
79
81
|
tool_choice?: 'auto';
|
|
82
|
+
/**
|
|
83
|
+
* OpenAI Chat Completions reasoning slot — accepted by gpt-5 / o-series.
|
|
84
|
+
* Only set when the user has chosen a non-default `/effort` AND the
|
|
85
|
+
* endpoint+model combo accepts the field (see `supportsReasoningEffortField`).
|
|
86
|
+
*/
|
|
87
|
+
reasoning_effort?: EffortLevel;
|
|
80
88
|
}
|
|
81
89
|
export interface AgentOptions {
|
|
82
90
|
workspaceRoot: string;
|
|
@@ -131,6 +139,10 @@ export declare const LOCAL_TOOLS: ({
|
|
|
131
139
|
url?: undefined;
|
|
132
140
|
maxResults?: undefined;
|
|
133
141
|
patch?: undefined;
|
|
142
|
+
question?: undefined;
|
|
143
|
+
header?: undefined;
|
|
144
|
+
options?: undefined;
|
|
145
|
+
multiSelect?: undefined;
|
|
134
146
|
explanation?: undefined;
|
|
135
147
|
plan?: undefined;
|
|
136
148
|
proof?: undefined;
|
|
@@ -163,6 +175,10 @@ export declare const LOCAL_TOOLS: ({
|
|
|
163
175
|
url?: undefined;
|
|
164
176
|
maxResults?: undefined;
|
|
165
177
|
patch?: undefined;
|
|
178
|
+
question?: undefined;
|
|
179
|
+
header?: undefined;
|
|
180
|
+
options?: undefined;
|
|
181
|
+
multiSelect?: undefined;
|
|
166
182
|
explanation?: undefined;
|
|
167
183
|
plan?: undefined;
|
|
168
184
|
proof?: undefined;
|
|
@@ -198,6 +214,10 @@ export declare const LOCAL_TOOLS: ({
|
|
|
198
214
|
url?: undefined;
|
|
199
215
|
maxResults?: undefined;
|
|
200
216
|
patch?: undefined;
|
|
217
|
+
question?: undefined;
|
|
218
|
+
header?: undefined;
|
|
219
|
+
options?: undefined;
|
|
220
|
+
multiSelect?: undefined;
|
|
201
221
|
explanation?: undefined;
|
|
202
222
|
plan?: undefined;
|
|
203
223
|
proof?: undefined;
|
|
@@ -227,6 +247,10 @@ export declare const LOCAL_TOOLS: ({
|
|
|
227
247
|
url?: undefined;
|
|
228
248
|
maxResults?: undefined;
|
|
229
249
|
patch?: undefined;
|
|
250
|
+
question?: undefined;
|
|
251
|
+
header?: undefined;
|
|
252
|
+
options?: undefined;
|
|
253
|
+
multiSelect?: undefined;
|
|
230
254
|
explanation?: undefined;
|
|
231
255
|
plan?: undefined;
|
|
232
256
|
proof?: undefined;
|
|
@@ -259,6 +283,10 @@ export declare const LOCAL_TOOLS: ({
|
|
|
259
283
|
url?: undefined;
|
|
260
284
|
maxResults?: undefined;
|
|
261
285
|
patch?: undefined;
|
|
286
|
+
question?: undefined;
|
|
287
|
+
header?: undefined;
|
|
288
|
+
options?: undefined;
|
|
289
|
+
multiSelect?: undefined;
|
|
262
290
|
explanation?: undefined;
|
|
263
291
|
plan?: undefined;
|
|
264
292
|
proof?: undefined;
|
|
@@ -288,6 +316,10 @@ export declare const LOCAL_TOOLS: ({
|
|
|
288
316
|
url?: undefined;
|
|
289
317
|
maxResults?: undefined;
|
|
290
318
|
patch?: undefined;
|
|
319
|
+
question?: undefined;
|
|
320
|
+
header?: undefined;
|
|
321
|
+
options?: undefined;
|
|
322
|
+
multiSelect?: undefined;
|
|
291
323
|
explanation?: undefined;
|
|
292
324
|
plan?: undefined;
|
|
293
325
|
proof?: undefined;
|
|
@@ -317,6 +349,10 @@ export declare const LOCAL_TOOLS: ({
|
|
|
317
349
|
url?: undefined;
|
|
318
350
|
maxResults?: undefined;
|
|
319
351
|
patch?: undefined;
|
|
352
|
+
question?: undefined;
|
|
353
|
+
header?: undefined;
|
|
354
|
+
options?: undefined;
|
|
355
|
+
multiSelect?: undefined;
|
|
320
356
|
explanation?: undefined;
|
|
321
357
|
plan?: undefined;
|
|
322
358
|
proof?: undefined;
|
|
@@ -346,6 +382,10 @@ export declare const LOCAL_TOOLS: ({
|
|
|
346
382
|
command?: undefined;
|
|
347
383
|
maxResults?: undefined;
|
|
348
384
|
patch?: undefined;
|
|
385
|
+
question?: undefined;
|
|
386
|
+
header?: undefined;
|
|
387
|
+
options?: undefined;
|
|
388
|
+
multiSelect?: undefined;
|
|
349
389
|
explanation?: undefined;
|
|
350
390
|
plan?: undefined;
|
|
351
391
|
proof?: undefined;
|
|
@@ -378,6 +418,10 @@ export declare const LOCAL_TOOLS: ({
|
|
|
378
418
|
command?: undefined;
|
|
379
419
|
url?: undefined;
|
|
380
420
|
patch?: undefined;
|
|
421
|
+
question?: undefined;
|
|
422
|
+
header?: undefined;
|
|
423
|
+
options?: undefined;
|
|
424
|
+
multiSelect?: undefined;
|
|
381
425
|
explanation?: undefined;
|
|
382
426
|
plan?: undefined;
|
|
383
427
|
proof?: undefined;
|
|
@@ -407,6 +451,68 @@ export declare const LOCAL_TOOLS: ({
|
|
|
407
451
|
command?: undefined;
|
|
408
452
|
url?: undefined;
|
|
409
453
|
maxResults?: undefined;
|
|
454
|
+
question?: undefined;
|
|
455
|
+
header?: undefined;
|
|
456
|
+
options?: undefined;
|
|
457
|
+
multiSelect?: undefined;
|
|
458
|
+
explanation?: undefined;
|
|
459
|
+
plan?: undefined;
|
|
460
|
+
proof?: undefined;
|
|
461
|
+
reason?: undefined;
|
|
462
|
+
needed?: undefined;
|
|
463
|
+
};
|
|
464
|
+
required: string[];
|
|
465
|
+
};
|
|
466
|
+
} | {
|
|
467
|
+
name: string;
|
|
468
|
+
description: string;
|
|
469
|
+
inputSchema: {
|
|
470
|
+
type: string;
|
|
471
|
+
properties: {
|
|
472
|
+
question: {
|
|
473
|
+
type: string;
|
|
474
|
+
description: string;
|
|
475
|
+
};
|
|
476
|
+
header: {
|
|
477
|
+
type: string;
|
|
478
|
+
description: string;
|
|
479
|
+
};
|
|
480
|
+
options: {
|
|
481
|
+
type: string;
|
|
482
|
+
description: string;
|
|
483
|
+
minItems: number;
|
|
484
|
+
maxItems: number;
|
|
485
|
+
items: {
|
|
486
|
+
type: string;
|
|
487
|
+
properties: {
|
|
488
|
+
label: {
|
|
489
|
+
type: string;
|
|
490
|
+
description: string;
|
|
491
|
+
};
|
|
492
|
+
description: {
|
|
493
|
+
type: string;
|
|
494
|
+
description: string;
|
|
495
|
+
};
|
|
496
|
+
};
|
|
497
|
+
required: string[];
|
|
498
|
+
};
|
|
499
|
+
};
|
|
500
|
+
multiSelect: {
|
|
501
|
+
type: string;
|
|
502
|
+
description: string;
|
|
503
|
+
};
|
|
504
|
+
path?: undefined;
|
|
505
|
+
startLine?: undefined;
|
|
506
|
+
endLine?: undefined;
|
|
507
|
+
content?: undefined;
|
|
508
|
+
targetContent?: undefined;
|
|
509
|
+
replacementContent?: undefined;
|
|
510
|
+
query?: undefined;
|
|
511
|
+
pattern?: undefined;
|
|
512
|
+
command?: undefined;
|
|
513
|
+
url?: undefined;
|
|
514
|
+
maxResults?: undefined;
|
|
515
|
+
patch?: undefined;
|
|
410
516
|
explanation?: undefined;
|
|
411
517
|
plan?: undefined;
|
|
412
518
|
proof?: undefined;
|
|
@@ -454,6 +560,10 @@ export declare const LOCAL_TOOLS: ({
|
|
|
454
560
|
url?: undefined;
|
|
455
561
|
maxResults?: undefined;
|
|
456
562
|
patch?: undefined;
|
|
563
|
+
question?: undefined;
|
|
564
|
+
header?: undefined;
|
|
565
|
+
options?: undefined;
|
|
566
|
+
multiSelect?: undefined;
|
|
457
567
|
proof?: undefined;
|
|
458
568
|
reason?: undefined;
|
|
459
569
|
needed?: undefined;
|
|
@@ -482,6 +592,10 @@ export declare const LOCAL_TOOLS: ({
|
|
|
482
592
|
url?: undefined;
|
|
483
593
|
maxResults?: undefined;
|
|
484
594
|
patch?: undefined;
|
|
595
|
+
question?: undefined;
|
|
596
|
+
header?: undefined;
|
|
597
|
+
options?: undefined;
|
|
598
|
+
multiSelect?: undefined;
|
|
485
599
|
explanation?: undefined;
|
|
486
600
|
plan?: undefined;
|
|
487
601
|
reason?: undefined;
|
|
@@ -515,6 +629,10 @@ export declare const LOCAL_TOOLS: ({
|
|
|
515
629
|
url?: undefined;
|
|
516
630
|
maxResults?: undefined;
|
|
517
631
|
patch?: undefined;
|
|
632
|
+
question?: undefined;
|
|
633
|
+
header?: undefined;
|
|
634
|
+
options?: undefined;
|
|
635
|
+
multiSelect?: undefined;
|
|
518
636
|
explanation?: undefined;
|
|
519
637
|
plan?: undefined;
|
|
520
638
|
proof?: undefined;
|
|
@@ -575,6 +693,28 @@ export declare class Agent {
|
|
|
575
693
|
private recalledRecordIds;
|
|
576
694
|
private recalledRecords;
|
|
577
695
|
private lastBriefingSources;
|
|
696
|
+
/**
|
|
697
|
+
* 10b: latest MCP tool inventory captured by `listTools()` calls. Used by
|
|
698
|
+
* `createSystemMessage` to decide whether the BrainRouter memory section
|
|
699
|
+
* should render — when `memory_recall` is missing from this list (the
|
|
700
|
+
* cloud brain is offline), the prompt swaps to a brain-offline notice so
|
|
701
|
+
* the model doesn't try to call tools that aren't there. Undefined until
|
|
702
|
+
* the first successful list; treated as "assume online" by the prompt
|
|
703
|
+
* builder until then (back-compat for callers that don't list pre-turn).
|
|
704
|
+
*/
|
|
705
|
+
private lastKnownMcpTools?;
|
|
706
|
+
/**
|
|
707
|
+
* 9b: gated recall state. `recallHasFiredThisSession` flips to true on the
|
|
708
|
+
* first successful briefing injection so subsequent turns can skip the
|
|
709
|
+
* fresh recall pull unless a gated trigger fires. `recallNextTurnIsPost-
|
|
710
|
+
* Compaction` is set by `compactHistory()` to force the next turn through
|
|
711
|
+
* the full briefing path (compaction just dropped the prior briefing as
|
|
712
|
+
* collateral; replay it once so the model isn't blind). Both are
|
|
713
|
+
* cleared on `loadHistory` / `fork` / `bootstrapSession` so a fresh
|
|
714
|
+
* session re-pulls.
|
|
715
|
+
*/
|
|
716
|
+
private recallHasFiredThisSession;
|
|
717
|
+
private recallNextTurnIsPostCompaction;
|
|
578
718
|
private roleOverlay?;
|
|
579
719
|
private accessMode;
|
|
580
720
|
private silent;
|
|
@@ -708,9 +848,30 @@ export declare class Agent {
|
|
|
708
848
|
* Idempotent: calling this with a tag that isn't present is a no-op.
|
|
709
849
|
*/
|
|
710
850
|
removeTaggedSystemMessage(tag: string): void;
|
|
851
|
+
/**
|
|
852
|
+
* Zero the in-process counters that back `/tokens`. Call this on any
|
|
853
|
+
* conceptual session boundary (`/resume`, `fork`) — otherwise the parent
|
|
854
|
+
* row keeps accumulating across the switch and "this session" no longer
|
|
855
|
+
* matches the displayed sessionKey.
|
|
856
|
+
*/
|
|
857
|
+
resetSessionCounters(): void;
|
|
711
858
|
/** Fork the current chat history into a fresh sessionKey. Returns the new key. */
|
|
712
859
|
fork(newSessionKey: string): string;
|
|
713
860
|
private bootstrapSession;
|
|
861
|
+
/**
|
|
862
|
+
* Public, callback-free wrapper around bootstrapSession for slash commands
|
|
863
|
+
* that mutate per-session state (notably `/goal`) BEFORE any runTurn has
|
|
864
|
+
* fired. Without this, the FIRST `/goal` of a session writes goal.json
|
|
865
|
+
* under the deterministic fallback sessionKey ("brainrouter-cli:<path>")
|
|
866
|
+
* because bootstrap hasn't happened yet, but every subsequent runTurn
|
|
867
|
+
* reads from the MCP-resolved UUID sessionKey — split-brain that left
|
|
868
|
+
* the agent reading a stale goal from a different directory.
|
|
869
|
+
*
|
|
870
|
+
* Idempotent: returns immediately if already initialized. Tolerates
|
|
871
|
+
* missing MCP — falls back to the deterministic key the same way
|
|
872
|
+
* bootstrapSession does.
|
|
873
|
+
*/
|
|
874
|
+
ensureInitialized(): Promise<void>;
|
|
714
875
|
private createSystemMessage;
|
|
715
876
|
private injectRecallContext;
|
|
716
877
|
/** Inspectable summary of the most recent memory briefing. Used by the `/briefing` slash command. */
|
|
@@ -718,6 +879,13 @@ export declare class Agent {
|
|
|
718
879
|
sources: string[];
|
|
719
880
|
recordIds: string[];
|
|
720
881
|
};
|
|
882
|
+
/**
|
|
883
|
+
* Snapshot of the records produced by the most recent pre-turn briefing.
|
|
884
|
+
* `/where` surfaces a few of these to give the user a sense of what the
|
|
885
|
+
* agent is leaning on right now. Returns a shallow copy so callers can't
|
|
886
|
+
* mutate the agent's internal state.
|
|
887
|
+
*/
|
|
888
|
+
getRecalledRecords(): RecalledRecord[];
|
|
721
889
|
/** One-line summary of any new contradiction surfaced after the last capture, or undefined if none. */
|
|
722
890
|
private lastContradictionWarning?;
|
|
723
891
|
takeContradictionWarning(): string | undefined;
|
|
@@ -757,8 +925,50 @@ export declare function getToolSummary(name: string, args: Record<string, any>,
|
|
|
757
925
|
* the terminal. Returns undefined when no useful preview is available.
|
|
758
926
|
*/
|
|
759
927
|
export declare function getToolPreview(name: string, args: Record<string, any>, result: string): string | undefined;
|
|
760
|
-
|
|
761
|
-
|
|
928
|
+
/**
|
|
929
|
+
* Heuristic for "does this model accept the OpenAI Chat Completions
|
|
930
|
+
* `reasoning_effort` field?". The signal that actually matters is the
|
|
931
|
+
* **model name**, not the endpoint hostname — modern OpenAI-compatible
|
|
932
|
+
* servers (LM Studio 0.3.29+, Ollama, vLLM, OpenRouter, OpenAI itself)
|
|
933
|
+
* all accept the field on /v1/chat/completions for the reasoning-capable
|
|
934
|
+
* model classes below, and silently ignore it for everything else. So a
|
|
935
|
+
* `gpt-oss-20b` served from localhost via LM Studio gets the same
|
|
936
|
+
* treatment as `gpt-5` on `api.openai.com`.
|
|
937
|
+
*
|
|
938
|
+
* Borrowed shape from openai-node's `ReasoningEffort` enum
|
|
939
|
+
* (openSrc/openai-node/src/resources/shared.ts) — `low|medium|high` map
|
|
940
|
+
* straight through to the provider field across OpenAI, DeepSeek,
|
|
941
|
+
* LM Studio, Ollama, and OpenRouter's pass-through. Anthropic models
|
|
942
|
+
* (`claude-*`) use a different field shape (`thinking: { budget_tokens }`)
|
|
943
|
+
* and a different endpoint (`/v1/messages`), so they're intentionally
|
|
944
|
+
* skipped here — brainrouter would need a separate provider adapter to
|
|
945
|
+
* forward into Anthropic's native API.
|
|
946
|
+
*/
|
|
947
|
+
/**
|
|
948
|
+
* 9b: resolve the recall-gating mode for this process. `BRAINROUTER_RECALL_MODE`
|
|
949
|
+
* env var beats everything; unset defaults to `gated`. Anything outside the
|
|
950
|
+
* three valid values falls back to `gated` (defensive — better to be helpful
|
|
951
|
+
* than crash on a typo). Re-resolved each turn so users can flip with
|
|
952
|
+
* `export BRAINROUTER_RECALL_MODE=always` mid-session via a /run command.
|
|
953
|
+
*/
|
|
954
|
+
export declare function resolveRecallMode(): 'always' | 'gated' | 'off';
|
|
955
|
+
/**
|
|
956
|
+
* 9b: cheap local heuristic for "the user message names something specific
|
|
957
|
+
* memory might have history on." Counts entity-shaped tokens: proper nouns
|
|
958
|
+
* (capitalized words that aren't sentence-starting), file paths (anything
|
|
959
|
+
* with `/` or `\\` or a `.<ext>` suffix), and identifier-shaped tokens (`camelCase`
|
|
960
|
+
* / `snake_case` / `PascalCase` longer than 4 chars). Crude but the bar is
|
|
961
|
+
* "is recall plausibly worth it?" — false positives waste a recall call,
|
|
962
|
+
* false negatives waste an ask. Tunable threshold via the caller.
|
|
963
|
+
*/
|
|
964
|
+
export declare function countEntityTokens(text: string): number;
|
|
965
|
+
export declare function supportsReasoningEffortField(config: LLMConfig): boolean;
|
|
966
|
+
export interface BuildPayloadOptions {
|
|
967
|
+
/** Reasoning-depth preference, when provider supports it. `medium` is a no-op. */
|
|
968
|
+
effort?: EffortLevel;
|
|
969
|
+
}
|
|
970
|
+
export declare function buildChatCompletionPayload(config: LLMConfig, messages: any[], tools: any[], options?: BuildPayloadOptions): ChatCompletionPayload;
|
|
971
|
+
export declare function callOpenAI(config: LLMConfig, messages: any[], tools: any[], options?: BuildPayloadOptions): Promise<{
|
|
762
972
|
content: any;
|
|
763
973
|
toolCalls: any;
|
|
764
974
|
usage: any;
|