@charzhu/openjaw-agent 0.2.3 → 0.2.5

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/main.js CHANGED
@@ -125,6 +125,7 @@ function loadAgentConfig() {
125
125
  use_responses_api: parsedLlm?.use_responses_api ?? DEFAULT_CONFIG.llm.use_responses_api,
126
126
  openai_tool_mode: parsedLlm?.openai_tool_mode ?? DEFAULT_CONFIG.llm.openai_tool_mode,
127
127
  openai_max_tools: parsedLlm?.openai_max_tools ?? DEFAULT_CONFIG.llm.openai_max_tools,
128
+ openai_mcp_max_tools: parsedLlm?.openai_mcp_max_tools,
128
129
  copilot_enterprise_url: parsedLlm?.copilot_enterprise_url,
129
130
  copilot_oauth_client_id: parsedLlm?.copilot_oauth_client_id ?? DEFAULT_CONFIG.llm.copilot_oauth_client_id,
130
131
  context_compression: parsedLlm?.context_compression,
@@ -214,7 +215,7 @@ var init_config = __esm({
214
215
  computer_use: true,
215
216
  // Enable computer use by default (auto-disabled for proxy)
216
217
  openai_tool_mode: "auto",
217
- openai_max_tools: 32,
218
+ openai_max_tools: 64,
218
219
  copilot_oauth_client_id: DEFAULT_COPILOT_OAUTH_CLIENT_ID
219
220
  }
220
221
  };
@@ -2432,9 +2433,9 @@ function systemPromptSection(name, compute) {
2432
2433
  function DANGEROUS_uncachedSection(name, compute, _reason) {
2433
2434
  return { name, compute, cacheBreak: true };
2434
2435
  }
2435
- async function resolveSystemPromptSections(sections2) {
2436
+ async function resolveSystemPromptSections(sections) {
2436
2437
  const results = [];
2437
- for (const section of sections2) {
2438
+ for (const section of sections) {
2438
2439
  if (!section.cacheBreak && sectionCache.has(section.name)) {
2439
2440
  results.push(sectionCache.get(section.name));
2440
2441
  continue;
@@ -2781,9 +2782,9 @@ var init_cache_monitor = __esm({
2781
2782
  /**
2782
2783
  * Take a snapshot of the current prompt state BEFORE an API call.
2783
2784
  */
2784
- snapshot(sections2, toolNames) {
2785
+ snapshot(sections, toolNames) {
2785
2786
  const sectionHashes = /* @__PURE__ */ new Map();
2786
- sections2.forEach((s, i) => {
2787
+ sections.forEach((s, i) => {
2787
2788
  sectionHashes.set(`section_${i}`, hash(s));
2788
2789
  });
2789
2790
  const toolsHash = hash(toolNames.sort().join("|"));
@@ -2793,14 +2794,14 @@ var init_cache_monitor = __esm({
2793
2794
  * Check for cache break AFTER an API call by comparing current state to previous snapshot.
2794
2795
  * Also uses cache_read_tokens from the API response to detect breaks.
2795
2796
  */
2796
- check(sections2, toolNames, cacheReadTokens, previousCacheReadTokens) {
2797
+ check(sections, toolNames, cacheReadTokens, previousCacheReadTokens) {
2797
2798
  this.totalTurns++;
2798
2799
  if (!this.lastSnapshot) {
2799
- this.snapshot(sections2, toolNames);
2800
+ this.snapshot(sections, toolNames);
2800
2801
  return null;
2801
2802
  }
2802
2803
  const changedSections = [];
2803
- sections2.forEach((s, i) => {
2804
+ sections.forEach((s, i) => {
2804
2805
  const key = `section_${i}`;
2805
2806
  const oldHash = this.lastSnapshot.sectionHashes.get(key);
2806
2807
  const newHash = hash(s);
@@ -2814,7 +2815,7 @@ var init_cache_monitor = __esm({
2814
2815
  }
2815
2816
  const tokenDrop = previousCacheReadTokens - cacheReadTokens;
2816
2817
  const hasTokenDrop = previousCacheReadTokens > 0 && tokenDrop > 1e3;
2817
- this.snapshot(sections2, toolNames);
2818
+ this.snapshot(sections, toolNames);
2818
2819
  if (changedSections.length > 0 || hasTokenDrop) {
2819
2820
  const event = {
2820
2821
  timestamp: Date.now(),
@@ -3394,6 +3395,13 @@ function resolveOpenAIMaxTools(config) {
3394
3395
  }
3395
3396
  return DEFAULT_OPENAI_MAX_TOOLS;
3396
3397
  }
3398
+ function resolveMcpMaxTools(config) {
3399
+ const configured = config.llm.openai_mcp_max_tools;
3400
+ if (typeof configured === "number" && Number.isFinite(configured) && configured >= 0) {
3401
+ return Math.floor(configured);
3402
+ }
3403
+ return null;
3404
+ }
3397
3405
  function rememberLoadedToolExposure(state, input, allTools) {
3398
3406
  const names = /* @__PURE__ */ new Set();
3399
3407
  const byName2 = new Map(allTools.map((tool) => [tool.name, tool]));
@@ -3425,36 +3433,54 @@ function rememberLoadedToolExposure(state, input, allTools) {
3425
3433
  }
3426
3434
  function selectToolsForRequest(params) {
3427
3435
  const { config, allTools, userMessage, state } = params;
3428
- const maxTools = resolveOpenAIMaxTools(config);
3436
+ const configuredMax = resolveOpenAIMaxTools(config);
3429
3437
  const compact = shouldCompactOpenAITools(config);
3438
+ const mcpTools = allTools.filter((tool) => categoryForTool(tool.name) === "mcp");
3430
3439
  if (!compact) {
3431
3440
  return {
3432
3441
  tools: allTools,
3433
3442
  mode: "full",
3434
3443
  reason: "full-mode",
3435
- maxTools,
3444
+ maxTools: configuredMax,
3436
3445
  fullToolCount: allTools.length,
3437
- exposedToolNames: allTools.map((tool) => tool.name)
3446
+ exposedToolNames: allTools.map((tool) => tool.name),
3447
+ mcpToolCount: mcpTools.length
3438
3448
  };
3439
3449
  }
3450
+ const mcpCap = resolveMcpMaxTools(config);
3451
+ const includedMcpTools = mcpCap !== null && mcpTools.length > mcpCap ? mcpTools.slice(0, mcpCap) : mcpTools;
3452
+ const maxTools = Math.min(
3453
+ MCP_AUTO_GROW_HARD_CAP,
3454
+ Math.max(configuredMax, FOUNDATION_TOOL_NAMES.length + includedMcpTools.length + BUILTIN_HEADROOM)
3455
+ );
3440
3456
  const selected = /* @__PURE__ */ new Map();
3441
3457
  const addByName = /* @__PURE__ */ __name((name) => {
3442
3458
  const tool = allTools.find((candidate) => candidate.name === name);
3443
3459
  if (tool) selected.set(tool.name, tool);
3444
3460
  }, "addByName");
3445
3461
  for (const name of FOUNDATION_TOOL_NAMES) addByName(name);
3446
- for (const name of state.exposedToolNames) addByName(name);
3462
+ for (const tool of includedMcpTools) {
3463
+ if (selected.size >= maxTools) break;
3464
+ selected.set(tool.name, tool);
3465
+ }
3466
+ for (const name of state.exposedToolNames) {
3467
+ if (selected.size >= maxTools) break;
3468
+ addByName(name);
3469
+ }
3447
3470
  const relevantCategories = categoriesForMessage(userMessage);
3448
3471
  for (const tool of allTools) {
3449
3472
  if (selected.size >= maxTools) break;
3450
- if (relevantCategories.has(categoryForTool(tool.name))) {
3473
+ const cat = categoryForTool(tool.name);
3474
+ if (cat === "mcp") continue;
3475
+ if (relevantCategories.has(cat)) {
3451
3476
  selected.set(tool.name, tool);
3452
3477
  }
3453
3478
  }
3454
3479
  if (selected.size < maxTools && relevantCategories.size === 0) {
3455
3480
  for (const tool of allTools) {
3456
3481
  if (selected.size >= maxTools) break;
3457
- if (categoryForTool(tool.name) === "memory" || categoryForTool(tool.name) === "system") {
3482
+ const cat = categoryForTool(tool.name);
3483
+ if (cat === "memory" || cat === "system") {
3458
3484
  selected.set(tool.name, tool);
3459
3485
  }
3460
3486
  }
@@ -3466,7 +3492,8 @@ function selectToolsForRequest(params) {
3466
3492
  reason: config.llm.provider === "github-copilot" ? "github-copilot" : isOpenAIProxyConfig(config) ? "openai-proxy" : "configured-compact",
3467
3493
  maxTools,
3468
3494
  fullToolCount: allTools.length,
3469
- exposedToolNames: tools.map((tool) => tool.name)
3495
+ exposedToolNames: tools.map((tool) => tool.name),
3496
+ mcpToolCount: includedMcpTools.length
3470
3497
  };
3471
3498
  }
3472
3499
  function categoriesForMessage(message) {
@@ -3498,11 +3525,13 @@ function categoryForTool(toolName) {
3498
3525
  if (toolName.startsWith("system_") || toolName.startsWith("clipboard_") || ["code_execute", "web_fetch", "web_search", "notify", "sleep", "ask_user", "config"].includes(toolName)) return "system";
3499
3526
  return "mcp";
3500
3527
  }
3501
- var DEFAULT_OPENAI_MAX_TOOLS, FOUNDATION_TOOL_NAMES, PROFILE_CATEGORIES, CATEGORY_KEYWORDS;
3528
+ var DEFAULT_OPENAI_MAX_TOOLS, MCP_AUTO_GROW_HARD_CAP, BUILTIN_HEADROOM, FOUNDATION_TOOL_NAMES, PROFILE_CATEGORIES, CATEGORY_KEYWORDS;
3502
3529
  var init_tool_exposure = __esm({
3503
3530
  "src/tool-exposure.ts"() {
3504
3531
  "use strict";
3505
- DEFAULT_OPENAI_MAX_TOOLS = 32;
3532
+ DEFAULT_OPENAI_MAX_TOOLS = 64;
3533
+ MCP_AUTO_GROW_HARD_CAP = 100;
3534
+ BUILTIN_HEADROOM = 8;
3506
3535
  FOUNDATION_TOOL_NAMES = [
3507
3536
  "openjaw_load_tools",
3508
3537
  "invoke_skill",
@@ -3530,6 +3559,7 @@ var init_tool_exposure = __esm({
3530
3559
  __name(isOpenAIProxyConfig, "isOpenAIProxyConfig");
3531
3560
  __name(shouldCompactOpenAITools, "shouldCompactOpenAITools");
3532
3561
  __name(resolveOpenAIMaxTools, "resolveOpenAIMaxTools");
3562
+ __name(resolveMcpMaxTools, "resolveMcpMaxTools");
3533
3563
  __name(rememberLoadedToolExposure, "rememberLoadedToolExposure");
3534
3564
  __name(selectToolsForRequest, "selectToolsForRequest");
3535
3565
  __name(categoriesForMessage, "categoriesForMessage");
@@ -19456,7 +19486,8 @@ var init_user = __esm({
19456
19486
  var memory_exports = {};
19457
19487
  __export(memory_exports, {
19458
19488
  getMemorySection: () => getMemorySection,
19459
- setMemoryPrefetchQuery: () => setMemoryPrefetchQuery
19489
+ setMemoryPrefetchQuery: () => setMemoryPrefetchQuery,
19490
+ shouldSkipPrefetch: () => shouldSkipPrefetch
19460
19491
  });
19461
19492
  import { join as join21 } from "node:path";
19462
19493
  import { homedir as homedir11 } from "node:os";
@@ -19466,8 +19497,48 @@ function setMemoryPrefetchQuery(query) {
19466
19497
  function escapeLike2(token) {
19467
19498
  return `%${token.replace(/[\\%_]/g, "\\$&")}%`;
19468
19499
  }
19500
+ function shouldSkipPrefetch(query) {
19501
+ const trimmed = query.trim();
19502
+ if (trimmed.length === 0) return true;
19503
+ if (/^[\d\s+\-*/().%^=]+$/.test(trimmed)) return true;
19504
+ if (/^[a-z][a-z0-9_-]*( +-{0,2}[a-z0-9_./-]+){0,3}$/.test(trimmed) && trimmed.length <= 32 && !/\s+(my|i|me|the|a|an|alice|bob|carol|dave)\b/i.test(trimmed)) {
19505
+ return true;
19506
+ }
19507
+ const codeMarkers = [
19508
+ /\bfunction\s+\w+\s*\(/,
19509
+ // function foo(
19510
+ /=>/,
19511
+ // arrow fn
19512
+ /\bimport\s+[\w*{]/,
19513
+ // import x
19514
+ /\bfrom\s+['"][\w./-]+['"]/,
19515
+ // from "x"
19516
+ /\bclass\s+\w+/,
19517
+ // class Foo
19518
+ /\bdef\s+\w+\s*\(/,
19519
+ // def foo(
19520
+ /\bconst\s+\w+\s*=/,
19521
+ // const x =
19522
+ /\blet\s+\w+\s*=/,
19523
+ // let x =
19524
+ /\bvar\s+\w+\s*=/,
19525
+ // var x =
19526
+ /\binterface\s+\w+/,
19527
+ // interface Foo
19528
+ /\btype\s+\w+\s*=/
19529
+ // type Foo =
19530
+ ];
19531
+ if (codeMarkers.some((re) => re.test(trimmed))) return true;
19532
+ const hasFileExt = /\b[\w.-]+\.(ts|tsx|js|jsx|mjs|cjs|py|rb|go|rs|java|c|cpp|h|md|json|yaml|yml|toml|sh|ps1|css|scss|html|xml|sql)\b/i.test(trimmed);
19533
+ if (hasFileExt) {
19534
+ const personalSignal = /\b(my|wife|husband|manager|boss|team|alice|bob|carol|dave|remember|usual|standard|default|reply|template|email|outlook|teams|workiq|msvacation|icm|servicenow)\b/i.test(trimmed);
19535
+ if (!personalSignal) return true;
19536
+ }
19537
+ return false;
19538
+ }
19469
19539
  function getMemorySection() {
19470
19540
  if (!currentQuery) return null;
19541
+ if (shouldSkipPrefetch(currentQuery)) return null;
19471
19542
  try {
19472
19543
  const { DatabaseSync: DatabaseSync2 } = __require("node:sqlite");
19473
19544
  const dbPath = join21(homedir11(), ".openjaw", "memory.db");
@@ -19530,8 +19601,8 @@ var MAX_PREFETCH_RESULTS, MAX_PREFETCH_CHARS, MAX_LIKE_TERMS2, STOPWORDS2, curre
19530
19601
  var init_memory2 = __esm({
19531
19602
  "src/prompts/memory.ts"() {
19532
19603
  "use strict";
19533
- MAX_PREFETCH_RESULTS = 10;
19534
- MAX_PREFETCH_CHARS = 4e3;
19604
+ MAX_PREFETCH_RESULTS = 5;
19605
+ MAX_PREFETCH_CHARS = 2e3;
19535
19606
  MAX_LIKE_TERMS2 = 16;
19536
19607
  STOPWORDS2 = /* @__PURE__ */ new Set([
19537
19608
  "a",
@@ -19596,6 +19667,7 @@ var init_memory2 = __esm({
19596
19667
  currentQuery = null;
19597
19668
  __name(setMemoryPrefetchQuery, "setMemoryPrefetchQuery");
19598
19669
  __name(escapeLike2, "escapeLike");
19670
+ __name(shouldSkipPrefetch, "shouldSkipPrefetch");
19599
19671
  __name(getMemorySection, "getMemorySection");
19600
19672
  }
19601
19673
  });
@@ -19925,6 +19997,54 @@ var init_context = __esm({
19925
19997
  }
19926
19998
  });
19927
19999
 
20000
+ // src/prompts/mcp.ts
20001
+ function getMcpSection(mcpManager) {
20002
+ if (!mcpManager) return null;
20003
+ const servers = mcpManager.getConnectedServers();
20004
+ if (servers.length === 0) return null;
20005
+ const lines = [
20006
+ "# Connected MCP Servers",
20007
+ "",
20008
+ "The following Model Context Protocol (MCP) servers are connected.",
20009
+ "Their tools are ALREADY registered and visible in your tool list \u2014",
20010
+ "you do NOT need to call `openjaw_load_tools` to use them.",
20011
+ ""
20012
+ ];
20013
+ const allTools = mcpManager.getTools();
20014
+ for (const server of servers) {
20015
+ const prefix = normalizeServerName(server);
20016
+ const toolsForServer = allTools.filter((t) => t.name.startsWith(`mcp__${prefix}__`));
20017
+ lines.push(`- **${server}** (${toolsForServer.length} tools) \u2014 tools start with \`mcp__${prefix}__\``);
20018
+ }
20019
+ lines.push(
20020
+ "",
20021
+ "## Tool Selection Rule",
20022
+ "",
20023
+ "When a user request maps to a domain covered by a connected MCP server,",
20024
+ "**call the `mcp__*` tool directly**. Do NOT call `openjaw_load_tools`",
20025
+ "first to load equivalent built-in openjaw tools. Only fall back to",
20026
+ "`openjaw_load_tools` and built-in `outlook_*` / `teams_*` / `office_*`",
20027
+ "tools when no connected MCP tool covers the task.",
20028
+ "",
20029
+ "Examples:",
20030
+ "- Work items, work-related Teams chats, project/task tracking \u2192 if a",
20031
+ " workiq-style MCP server is listed above, use its `mcp__*` tools.",
20032
+ "- Generic web search / file ops / shell \u2014 use the openjaw built-ins",
20033
+ " when no MCP server provides equivalent functionality."
20034
+ );
20035
+ return lines.join("\n");
20036
+ }
20037
+ function normalizeServerName(name) {
20038
+ return name.replace(/[^a-zA-Z0-9_-]/g, "_");
20039
+ }
20040
+ var init_mcp = __esm({
20041
+ "src/prompts/mcp.ts"() {
20042
+ "use strict";
20043
+ __name(getMcpSection, "getMcpSection");
20044
+ __name(normalizeServerName, "normalizeServerName");
20045
+ }
20046
+ });
20047
+
19928
20048
  // src/prompts/index.ts
19929
20049
  var prompts_exports = {};
19930
20050
  __export(prompts_exports, {
@@ -19932,14 +20052,14 @@ __export(prompts_exports, {
19932
20052
  clearPromptCache: () => clearPromptCache,
19933
20053
  getSystemPrompt: () => getSystemPrompt
19934
20054
  });
19935
- async function getSystemPrompt() {
19936
- const resolved = await resolveSystemPromptSections(sections);
20055
+ async function getSystemPrompt(opts = {}) {
20056
+ const resolved = await resolveSystemPromptSections(buildSections(opts));
19937
20057
  return resolved.filter((s) => s != null && s.length > 0);
19938
20058
  }
19939
20059
  function clearPromptCache() {
19940
20060
  clearSectionCache();
19941
20061
  }
19942
- var sections;
20062
+ var buildSections;
19943
20063
  var init_prompts = __esm({
19944
20064
  "src/prompts/index.ts"() {
19945
20065
  "use strict";
@@ -19952,8 +20072,9 @@ var init_prompts = __esm({
19952
20072
  init_memory2();
19953
20073
  init_skills();
19954
20074
  init_context();
20075
+ init_mcp();
19955
20076
  init_sections();
19956
- sections = [
20077
+ buildSections = /* @__PURE__ */ __name((opts = {}) => [
19957
20078
  // Static sections (cached across calls)
19958
20079
  systemPromptSection("identity", () => getIdentitySection()),
19959
20080
  systemPromptSection("reasoning", () => getReasoningSection()),
@@ -19965,8 +20086,9 @@ var init_prompts = __esm({
19965
20086
  DANGEROUS_uncachedSection("user", () => getUserSection(), "user prompt may be edited between calls"),
19966
20087
  DANGEROUS_uncachedSection("memory", () => getMemorySection(), "memory prefetch changes per query"),
19967
20088
  DANGEROUS_uncachedSection("skills", () => getSkillsSection(), "skill files may be added/edited between calls"),
20089
+ DANGEROUS_uncachedSection("mcp", () => getMcpSection(opts.mcpManager ?? null), "MCP servers can connect/disconnect mid-session via /mcp"),
19968
20090
  DANGEROUS_uncachedSection("context", () => getContextSection(), "time and cwd change between calls")
19969
- ];
20091
+ ], "buildSections");
19970
20092
  __name(getSystemPrompt, "getSystemPrompt");
19971
20093
  __name(clearPromptCache, "clearPromptCache");
19972
20094
  }
@@ -20221,8 +20343,8 @@ var init_telegram = __esm({
20221
20343
  }, "updateStatus");
20222
20344
  const { setMemoryPrefetchQuery: setMemoryPrefetchQuery2 } = await Promise.resolve().then(() => (init_memory2(), memory_exports));
20223
20345
  setMemoryPrefetchQuery2(text);
20224
- const sections2 = await this.systemPromptFn();
20225
- const systemPrompt = sections2.filter(Boolean).join("\n\n");
20346
+ const sections = await this.systemPromptFn();
20347
+ const systemPrompt = sections.filter(Boolean).join("\n\n");
20226
20348
  let answer = "";
20227
20349
  let toolCalls = [];
20228
20350
  const typingInterval = setInterval(() => {
@@ -20364,8 +20486,8 @@ Options: ${chunk.choices.join(" | ")}` : "";
20364
20486
  await this.bot.sendMessage(chatId, `\u{1F4F7} Processing image...`);
20365
20487
  const { setMemoryPrefetchQuery: setMemoryPrefetchQuery2 } = await Promise.resolve().then(() => (init_memory2(), memory_exports));
20366
20488
  setMemoryPrefetchQuery2(text);
20367
- const sections2 = await this.systemPromptFn();
20368
- const systemPrompt = sections2.filter(Boolean).join("\n\n");
20489
+ const sections = await this.systemPromptFn();
20490
+ const systemPrompt = sections.filter(Boolean).join("\n\n");
20369
20491
  const typingInterval = setInterval(() => {
20370
20492
  this.bot.sendChatAction(chatId, "typing").catch(() => {
20371
20493
  });
@@ -20501,7 +20623,7 @@ __export(meta_exports, {
20501
20623
  function createMetaTool(registry) {
20502
20624
  return {
20503
20625
  name: "openjaw_load_tools",
20504
- description: 'Dynamically load additional tools. PREFERRED: Load individual tools by name: tools: ["word_focus", "word_insert_text", "word_save"]. Only load specific tools you need for the task \u2014 avoid loading entire categories. Alternative: Load full category if many tools needed: categories: ["office"]. Available categories: ' + ALL_CATEGORIES.join(", ") + ".",
20626
+ description: 'Dynamically load additional openjaw built-in tools (file, browser, office, etc.). NOTE: MCP server tools (any tool whose name starts with `mcp__`) are ALWAYS loaded automatically \u2014 never call this tool to load them, and never assume you need it before invoking an `mcp__*` tool. Load individual openjaw built-in tools by name: tools: ["word_focus", "word_insert_text", "word_save"]. Only load specific tools you need for the task \u2014 avoid loading entire categories. Alternative: Load full category if many tools needed: categories: ["office"]. Available categories: ' + ALL_CATEGORIES.join(", ") + ".",
20505
20627
  parameters: {
20506
20628
  type: "object",
20507
20629
  properties: {
@@ -25304,8 +25426,8 @@ Type /resume <id> to resume.` });
25304
25426
  const { spawnFork: spawnFork2 } = await Promise.resolve().then(() => (init_fork(), fork_exports));
25305
25427
  const { loadAgentConfig: loadAgentConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
25306
25428
  const forkConfig = loadAgentConfig2();
25307
- const sections2 = await systemPromptFn();
25308
- const sysPrompt = sections2.filter(Boolean).join("\n\n");
25429
+ const sections = await systemPromptFn();
25430
+ const sysPrompt = sections.filter(Boolean).join("\n\n");
25309
25431
  const task = spawnFork2(
25310
25432
  forkPrompt,
25311
25433
  forkConfig,
@@ -25347,8 +25469,8 @@ ${list}` });
25347
25469
  addMessage({ type: "system", content: "Not enough history to compact (need >12 messages)." });
25348
25470
  return;
25349
25471
  }
25350
- const sections2 = await systemPromptFn();
25351
- const systemPrompt = sections2.filter(Boolean).join("\n\n");
25472
+ const sections = await systemPromptFn();
25473
+ const systemPrompt = sections.filter(Boolean).join("\n\n");
25352
25474
  const result = await agentLoop.compact(systemPrompt);
25353
25475
  if (result) {
25354
25476
  const afterTokens = contextManager.getEstimatedTokens();
@@ -25370,8 +25492,8 @@ ${list}` });
25370
25492
  addMessage({ type: "system", content: "Not enough history to compress (need >6 messages)." });
25371
25493
  return;
25372
25494
  }
25373
- const sections2 = await systemPromptFn();
25374
- const systemPrompt = sections2.filter(Boolean).join("\n\n");
25495
+ const sections = await systemPromptFn();
25496
+ const systemPrompt = sections.filter(Boolean).join("\n\n");
25375
25497
  const compressor = agentLoop.contextCompressor;
25376
25498
  if (compressor.isThrottled) {
25377
25499
  addMessage({ type: "system", content: "\u26A0 Compression throttled \u2014 recent attempts saved <10%. Try /compact or /clear instead." });
@@ -25670,8 +25792,8 @@ ${voices.length > 20 ? `... and ${voices.length - 20} more` : ""}` });
25670
25792
  try {
25671
25793
  const { setMemoryPrefetchQuery: setMemoryPrefetchQuery2 } = await Promise.resolve().then(() => (init_memory2(), memory_exports));
25672
25794
  setMemoryPrefetchQuery2(input);
25673
- const sections2 = await systemPromptFn();
25674
- const systemPrompt = sections2.filter(Boolean).join("\n\n");
25795
+ const sections = await systemPromptFn();
25796
+ const systemPrompt = sections.filter(Boolean).join("\n\n");
25675
25797
  let userMessage = image ? `${input}
25676
25798
 
25677
25799
  [User has attached a screenshot image (${image.width}\xD7${image.height}). Analyze the image carefully.]` : input;
@@ -26532,8 +26654,8 @@ var init_teams = __esm({
26532
26654
  }, "updateStatus");
26533
26655
  const { setMemoryPrefetchQuery: setMemoryPrefetchQuery2 } = await Promise.resolve().then(() => (init_memory2(), memory_exports));
26534
26656
  setMemoryPrefetchQuery2(text);
26535
- const sections2 = await this.systemPromptFn();
26536
- const systemPrompt = sections2.filter(Boolean).join("\n\n");
26657
+ const sections = await this.systemPromptFn();
26658
+ const systemPrompt = sections.filter(Boolean).join("\n\n");
26537
26659
  let answer = "";
26538
26660
  let thinkingBuffer = "";
26539
26661
  let toolCalls = [];
@@ -26811,8 +26933,8 @@ var init_feishu = __esm({
26811
26933
  }, "updateStatus");
26812
26934
  const { setMemoryPrefetchQuery: setMemoryPrefetchQuery2 } = await Promise.resolve().then(() => (init_memory2(), memory_exports));
26813
26935
  setMemoryPrefetchQuery2(text);
26814
- const sections2 = await this.systemPromptFn();
26815
- const systemPrompt = sections2.filter(Boolean).join("\n\n");
26936
+ const sections = await this.systemPromptFn();
26937
+ const systemPrompt = sections.filter(Boolean).join("\n\n");
26816
26938
  let answer = "";
26817
26939
  let thinkingBuffer = "";
26818
26940
  let toolCalls = [];
@@ -27589,8 +27711,8 @@ Scan URL manually: ${qrUrl}` });
27589
27711
  });
27590
27712
  const { setMemoryPrefetchQuery: setMemoryPrefetchQuery2 } = await Promise.resolve().then(() => (init_memory2(), memory_exports));
27591
27713
  setMemoryPrefetchQuery2(text);
27592
- const sections2 = await this.systemPromptFn();
27593
- const systemPrompt = sections2.filter(Boolean).join("\n\n");
27714
+ const sections = await this.systemPromptFn();
27715
+ const systemPrompt = sections.filter(Boolean).join("\n\n");
27594
27716
  let answer = "";
27595
27717
  let thinkingBuffer = "";
27596
27718
  let lastThinkingSegment = "";
@@ -28129,7 +28251,7 @@ async function startInkUI(resumeSessionId, bridges = []) {
28129
28251
  join36(homedir22(), ".openjaw", "memory", "MEMORY.md")
28130
28252
  ];
28131
28253
  const memoryStatus = existsSync28(memoryDbPath) ? "loaded" : memoryLegacyPaths.some((p) => existsSync28(p)) ? "legacy" : "empty";
28132
- const systemPromptFn = /* @__PURE__ */ __name(() => getSystemPrompt(), "systemPromptFn");
28254
+ const systemPromptFn = /* @__PURE__ */ __name(() => getSystemPrompt({ mcpManager }), "systemPromptFn");
28133
28255
  const { createSkillTool: createSkillTool2 } = await Promise.resolve().then(() => (init_skill_tool(), skill_tool_exports));
28134
28256
  toolRegistry.registerTool(createSkillTool2(agentConfig, toolRegistry, systemPromptFn));
28135
28257
  const totalToolCount = toolRegistry.listTools().length;
@@ -28916,7 +29038,7 @@ async function bootstrapAgent(opts = {}) {
28916
29038
  join38(homedir24(), ".openjaw", "memory", "MEMORY.md")
28917
29039
  ];
28918
29040
  const memoryStatus = existsSync30(memoryDbPath) ? "loaded" : memoryLegacyPaths.some((p) => existsSync30(p)) ? "legacy" : "empty";
28919
- const systemPromptFn = /* @__PURE__ */ __name(() => getSystemPrompt(), "systemPromptFn");
29041
+ const systemPromptFn = /* @__PURE__ */ __name(() => getSystemPrompt({ mcpManager }), "systemPromptFn");
28920
29042
  const { createSkillTool: createSkillTool2 } = await Promise.resolve().then(() => (init_skill_tool(), skill_tool_exports));
28921
29043
  toolRegistry.registerTool(createSkillTool2(agentConfig, toolRegistry, systemPromptFn));
28922
29044
  const totalToolCount = toolRegistry.listTools().length;
@@ -44239,7 +44361,7 @@ var init_details = __esm({
44239
44361
  resolveSections = /* @__PURE__ */ __name((raw) => raw && typeof raw === "object" && !Array.isArray(raw) ? Object.fromEntries(
44240
44362
  Object.entries(raw).map(([k, v]) => [k, parseDetailsMode(v)]).filter(([k, m]) => !!m && isSectionName(k))
44241
44363
  ) : {}, "resolveSections");
44242
- sectionMode = /* @__PURE__ */ __name((name, global, sections2, commandOverride = false) => sections2?.[name] ?? (commandOverride ? global : SECTION_DEFAULTS[name] ?? global), "sectionMode");
44364
+ sectionMode = /* @__PURE__ */ __name((name, global, sections, commandOverride = false) => sections?.[name] ?? (commandOverride ? global : SECTION_DEFAULTS[name] ?? global), "sectionMode");
44243
44365
  nextDetailsMode = /* @__PURE__ */ __name((m) => MODES[(MODES.indexOf(m) + 1) % MODES.length], "nextDetailsMode");
44244
44366
  }
44245
44367
  });
@@ -44813,14 +44935,14 @@ var init_core = __esm({
44813
44935
  help: "list commands + hotkeys",
44814
44936
  name: "help",
44815
44937
  run: /* @__PURE__ */ __name((_arg, ctx) => {
44816
- const sections2 = (ctx.local.catalog?.categories ?? []).map((cat) => ({
44938
+ const sections = (ctx.local.catalog?.categories ?? []).map((cat) => ({
44817
44939
  rows: cat.pairs,
44818
44940
  title: cat.name
44819
44941
  }));
44820
44942
  if (ctx.local.catalog?.skillCount) {
44821
- sections2.push({ text: `${ctx.local.catalog.skillCount} skill commands available \u2014 /skills to browse` });
44943
+ sections.push({ text: `${ctx.local.catalog.skillCount} skill commands available \u2014 /skills to browse` });
44822
44944
  }
44823
- sections2.push(
44945
+ sections.push(
44824
44946
  {
44825
44947
  rows: [
44826
44948
  ["/details [hidden|collapsed|expanded|cycle]", "set global agent detail visibility mode"],
@@ -44834,7 +44956,7 @@ var init_core = __esm({
44834
44956
  },
44835
44957
  { rows: HOTKEYS, title: "Hotkeys" }
44836
44958
  );
44837
- ctx.transcript.panel(ctx.ui.theme.brand.helpHeader, sections2);
44959
+ ctx.transcript.panel(ctx.ui.theme.brand.helpHeader, sections);
44838
44960
  }, "run")
44839
44961
  },
44840
44962
  {
@@ -44995,8 +45117,8 @@ var init_core = __esm({
44995
45117
  if (!next) {
44996
45118
  return transcript.sys(DETAILS_USAGE);
44997
45119
  }
44998
- const sections2 = Object.fromEntries(SECTION_NAMES.map((section) => [section, next]));
44999
- patchUiState({ detailsMode: next, detailsModeCommandOverride: true, sections: sections2 });
45120
+ const sections = Object.fromEntries(SECTION_NAMES.map((section) => [section, next]));
45121
+ patchUiState({ detailsMode: next, detailsModeCommandOverride: true, sections });
45000
45122
  gateway.rpc("config.set", { key: "details_mode", value: next }).catch(() => {
45001
45123
  });
45002
45124
  transcript.sys(`details: ${next}`);
@@ -45831,7 +45953,7 @@ var init_openjaw = __esm({
45831
45953
  run: /* @__PURE__ */ __name((_arg, ctx) => {
45832
45954
  ctx.gateway.rpc("session.stats", { session_id: ctx.sid }).then(
45833
45955
  ctx.guarded((r) => {
45834
- const sections2 = [
45956
+ const sections = [
45835
45957
  {
45836
45958
  rows: [
45837
45959
  ["Session", r.session_id ?? ctx.sid ?? "(none)"],
@@ -45844,7 +45966,7 @@ var init_openjaw = __esm({
45844
45966
  ]
45845
45967
  }
45846
45968
  ];
45847
- ctx.transcript.panel("Session stats", sections2);
45969
+ ctx.transcript.panel("Session stats", sections);
45848
45970
  })
45849
45971
  ).catch(ctx.guardedErr);
45850
45972
  }, "run")
@@ -46345,11 +46467,11 @@ ${body}` : body;
46345
46467
  ["Category", String(info.category ?? "")],
46346
46468
  ["Path", String(info.path ?? "")]
46347
46469
  ];
46348
- const sections2 = [{ rows }];
46470
+ const sections = [{ rows }];
46349
46471
  if (info.description) {
46350
- sections2.push({ text: String(info.description) });
46472
+ sections.push({ text: String(info.description) });
46351
46473
  }
46352
- panel("Skill", sections2);
46474
+ panel("Skill", sections);
46353
46475
  })
46354
46476
  ).catch(ctx.guardedErr);
46355
46477
  return;
@@ -47104,14 +47226,14 @@ var init_session2 = __esm({
47104
47226
  if (cost) {
47105
47227
  rows.push(["Cost", cost]);
47106
47228
  }
47107
- const sections2 = [{ rows }];
47229
+ const sections = [{ rows }];
47108
47230
  if (r.context_max) {
47109
- sections2.push({ text: `Context: ${f(r.context_used)} / ${f(r.context_max)} (${r.context_percent}%)` });
47231
+ sections.push({ text: `Context: ${f(r.context_used)} / ${f(r.context_max)} (${r.context_percent}%)` });
47110
47232
  }
47111
47233
  if (r.compressions) {
47112
- sections2.push({ text: `Compressions: ${r.compressions}` });
47234
+ sections.push({ text: `Compressions: ${r.compressions}` });
47113
47235
  }
47114
- ctx.transcript.panel("Usage", sections2);
47236
+ ctx.transcript.panel("Usage", sections);
47115
47237
  });
47116
47238
  }, "run")
47117
47239
  }
@@ -48126,8 +48248,8 @@ ${helpMessage}` : field.label;
48126
48248
  if (!prompt) {
48127
48249
  return { id: 0, status: "error" };
48128
48250
  }
48129
- const sections2 = await systemPromptFn();
48130
- const systemPrompt = sections2.filter(Boolean).join("\n\n");
48251
+ const sections = await systemPromptFn();
48252
+ const systemPrompt = sections.filter(Boolean).join("\n\n");
48131
48253
  const task = spawnFork(prompt, loadAgentConfig(), toolRegistry, systemPrompt, (completed) => {
48132
48254
  const success = completed.status === "done";
48133
48255
  const text = `${success ? "\u2705" : "\u274C"} Fork #${completed.id} completed: ${completed.result || "(no result)"}`;
@@ -48334,8 +48456,8 @@ ${helpMessage}` : field.label;
48334
48456
  };
48335
48457
  }
48336
48458
  const before = agentLoop.history.length;
48337
- const sections2 = await systemPromptFn();
48338
- const systemPrompt = sections2.filter(Boolean).join("\n\n");
48459
+ const sections = await systemPromptFn();
48460
+ const systemPrompt = sections.filter(Boolean).join("\n\n");
48339
48461
  let ok = false;
48340
48462
  try {
48341
48463
  ok = await agentLoop.compact(systemPrompt);
@@ -48392,8 +48514,8 @@ ${helpMessage}` : field.label;
48392
48514
  bus.registerRpc("prompt.background", async (params) => {
48393
48515
  const text = String(params.text ?? "").trim();
48394
48516
  if (!text) return { task_id: "" };
48395
- const sections2 = await systemPromptFn();
48396
- const systemPrompt = sections2.filter(Boolean).join("\n\n");
48517
+ const sections = await systemPromptFn();
48518
+ const systemPrompt = sections.filter(Boolean).join("\n\n");
48397
48519
  const task = spawnFork(text, loadAgentConfig(), toolRegistry, systemPrompt, (completed) => {
48398
48520
  const success = completed.status === "done";
48399
48521
  const taskText = `${success ? "\u2705" : "\u274C"} bg ${completed.id} done: ${completed.result || "(no result)"}`;
@@ -53533,7 +53655,7 @@ function useMainApp(gw) {
53533
53655
  []
53534
53656
  );
53535
53657
  const panel = useCallback10(
53536
- (title, sections2) => appendMessage({ kind: "panel", panelData: { sections: sections2, title }, role: "system", text: "" }),
53658
+ (title, sections) => appendMessage({ kind: "panel", panelData: { sections, title }, role: "system", text: "" }),
53537
53659
  [appendMessage]
53538
53660
  );
53539
53661
  const maybeWarn = useCallback10(
@@ -57961,10 +58083,10 @@ function SessionPanel({ info, sid, t }) {
57961
58083
  ] })
57962
58084
  ] });
57963
58085
  }
57964
- function Panel({ sections: sections2, t, title }) {
58086
+ function Panel({ sections, t, title }) {
57965
58087
  return /* @__PURE__ */ jsxs18(Box_default, { borderColor: t.color.border, borderStyle: "round", flexDirection: "column", paddingX: 2, paddingY: 1, children: [
57966
58088
  /* @__PURE__ */ jsx30(Box_default, { justifyContent: "center", marginBottom: 1, children: /* @__PURE__ */ jsx30(Text9, { bold: true, color: t.color.primary, children: title }) }),
57967
- sections2.map((sec, si) => /* @__PURE__ */ jsxs18(Box_default, { flexDirection: "column", marginTop: si > 0 ? 1 : 0, children: [
58089
+ sections.map((sec, si) => /* @__PURE__ */ jsxs18(Box_default, { flexDirection: "column", marginTop: si > 0 ? 1 : 0, children: [
57968
58090
  sec.title && /* @__PURE__ */ jsx30(Text9, { bold: true, color: t.color.accent, children: sec.title }),
57969
58091
  sec.rows?.map(([k, v], ri) => /* @__PURE__ */ jsxs18(Text9, { wrap: "truncate", children: [
57970
58092
  /* @__PURE__ */ jsx30(Text9, { color: t.color.muted, children: k.padEnd(20) }),
@@ -60126,9 +60248,9 @@ function SubagentAccordion({
60126
60248
  const noteRows = [...summary ? [summary] : [], ...item.notes];
60127
60249
  const hasNotes = noteRows.length > 0;
60128
60250
  const noteColor = statusTone === "error" ? t.color.error : statusTone === "warn" ? t.color.warn : t.color.muted;
60129
- const sections2 = [];
60251
+ const sections = [];
60130
60252
  if (hasThinking) {
60131
- sections2.push({
60253
+ sections.push({
60132
60254
  header: /* @__PURE__ */ jsx36(
60133
60255
  Chevron,
60134
60256
  {
@@ -60162,7 +60284,7 @@ function SubagentAccordion({
60162
60284
  });
60163
60285
  }
60164
60286
  if (hasTools) {
60165
- sections2.push({
60287
+ sections.push({
60166
60288
  header: /* @__PURE__ */ jsx36(
60167
60289
  Chevron,
60168
60290
  {
@@ -60198,7 +60320,7 @@ function SubagentAccordion({
60198
60320
  });
60199
60321
  }
60200
60322
  if (hasNotes) {
60201
- sections2.push({
60323
+ sections.push({
60202
60324
  header: /* @__PURE__ */ jsx36(
60203
60325
  Chevron,
60204
60326
  {
@@ -60233,7 +60355,7 @@ function SubagentAccordion({
60233
60355
  });
60234
60356
  }
60235
60357
  if (children.length > 0) {
60236
- sections2.push({
60358
+ sections.push({
60237
60359
  header: /* @__PURE__ */ jsx36(
60238
60360
  Chevron,
60239
60361
  {
@@ -60299,10 +60421,10 @@ function SubagentAccordion({
60299
60421
  stemColor: stem,
60300
60422
  stemDim: stem == null,
60301
60423
  t,
60302
- children: (childRails) => /* @__PURE__ */ jsx36(Box_default, { flexDirection: "column", children: sections2.map((section, index) => /* @__PURE__ */ jsx36(
60424
+ children: (childRails) => /* @__PURE__ */ jsx36(Box_default, { flexDirection: "column", children: sections.map((section, index) => /* @__PURE__ */ jsx36(
60303
60425
  TreeNode,
60304
60426
  {
60305
- branch: index === sections2.length - 1 ? "last" : "mid",
60427
+ branch: index === sections.length - 1 ? "last" : "mid",
60306
60428
  header: section.header,
60307
60429
  open: section.open,
60308
60430
  rails: childRails,
@@ -60374,7 +60496,7 @@ var init_thinking = __esm({
60374
60496
  reasoning = "",
60375
60497
  reasoningTokens,
60376
60498
  reasoningStreaming = false,
60377
- sections: sections2,
60499
+ sections,
60378
60500
  subagents = [],
60379
60501
  t,
60380
60502
  tools = [],
@@ -60384,12 +60506,12 @@ var init_thinking = __esm({
60384
60506
  }) {
60385
60507
  const visible = useMemo15(
60386
60508
  () => ({
60387
- thinking: sectionMode("thinking", detailsMode, sections2, commandOverride),
60388
- tools: sectionMode("tools", detailsMode, sections2, commandOverride),
60389
- subagents: sectionMode("subagents", detailsMode, sections2, commandOverride),
60390
- activity: sectionMode("activity", detailsMode, sections2, commandOverride)
60509
+ thinking: sectionMode("thinking", detailsMode, sections, commandOverride),
60510
+ tools: sectionMode("tools", detailsMode, sections, commandOverride),
60511
+ subagents: sectionMode("subagents", detailsMode, sections, commandOverride),
60512
+ activity: sectionMode("activity", detailsMode, sections, commandOverride)
60391
60513
  }),
60392
- [commandOverride, detailsMode, sections2]
60514
+ [commandOverride, detailsMode, sections]
60393
60515
  );
60394
60516
  const [now2, setNow] = useState26(() => Date.now());
60395
60517
  const [openThinking, setOpenThinking] = useState26(visible.thinking === "expanded");
@@ -60848,13 +60970,13 @@ var init_messageLine = __esm({
60848
60970
  isStreaming = false,
60849
60971
  limitHistoryRender = false,
60850
60972
  msg,
60851
- sections: sections2,
60973
+ sections,
60852
60974
  t,
60853
60975
  tools = []
60854
60976
  }) {
60855
- const thinkingMode = sectionMode("thinking", detailsMode, sections2, detailsModeCommandOverride);
60856
- const toolsMode = sectionMode("tools", detailsMode, sections2, detailsModeCommandOverride);
60857
- const activityMode = sectionMode("activity", detailsMode, sections2, detailsModeCommandOverride);
60977
+ const thinkingMode = sectionMode("thinking", detailsMode, sections, detailsModeCommandOverride);
60978
+ const toolsMode = sectionMode("tools", detailsMode, sections, detailsModeCommandOverride);
60979
+ const activityMode = sectionMode("activity", detailsMode, sections, detailsModeCommandOverride);
60858
60980
  const thinking = msg.thinking?.trim() ?? "";
60859
60981
  const systemHasBoxArt = msg.role === "system" && (msg.text.match(/[\u2500-\u259F]/g)?.length ?? 0) >= 3;
60860
60982
  const systemIsLong = msg.role === "system" && msg.text.length > SYSTEM_COLLAPSE_CHARS && !systemHasBoxArt;
@@ -60878,7 +61000,7 @@ var init_messageLine = __esm({
60878
61000
  detailsMode,
60879
61001
  reasoning: thinking,
60880
61002
  reasoningTokens: msg.thinkingTokens,
60881
- sections: sections2,
61003
+ sections,
60882
61004
  t,
60883
61005
  tools,
60884
61006
  toolTokens: msg.toolTokens,
@@ -60950,7 +61072,7 @@ var init_messageLine = __esm({
60950
61072
  detailsMode,
60951
61073
  reasoning: thinking,
60952
61074
  reasoningTokens: msg.thinkingTokens,
60953
- sections: sections2,
61075
+ sections,
60954
61076
  t,
60955
61077
  toolTokens: msg.toolTokens,
60956
61078
  trail: msg.tools
@@ -61039,7 +61161,7 @@ var init_streamingAssistant = __esm({
61039
61161
  detailsMode,
61040
61162
  detailsModeCommandOverride,
61041
61163
  progress,
61042
- sections: sections2
61164
+ sections
61043
61165
  }) {
61044
61166
  const ui = useStore8($uiState);
61045
61167
  const streamSegments = useTurnSelector((state) => state.streamSegments);
@@ -61059,7 +61181,7 @@ var init_streamingAssistant = __esm({
61059
61181
  detailsMode,
61060
61182
  detailsModeCommandOverride,
61061
61183
  msg,
61062
- sections: sections2,
61184
+ sections,
61063
61185
  t: ui.theme
61064
61186
  },
61065
61187
  `seg:${i}`
@@ -61072,7 +61194,7 @@ var init_streamingAssistant = __esm({
61072
61194
  detailsMode,
61073
61195
  detailsModeCommandOverride,
61074
61196
  msg: { kind: "trail", role: "system", text: "" },
61075
- sections: sections2,
61197
+ sections,
61076
61198
  t: ui.theme,
61077
61199
  tools: activeTools
61078
61200
  }
@@ -61090,7 +61212,7 @@ var init_streamingAssistant = __esm({
61090
61212
  text: streaming,
61091
61213
  ...streamPendingTools.length && { tools: streamPendingTools }
61092
61214
  },
61093
- sections: sections2,
61215
+ sections,
61094
61216
  t: ui.theme
61095
61217
  }
61096
61218
  ),
@@ -61102,7 +61224,7 @@ var init_streamingAssistant = __esm({
61102
61224
  detailsMode,
61103
61225
  detailsModeCommandOverride,
61104
61226
  msg: { kind: "trail", role: "system", text: "", tools: streamPendingTools },
61105
- sections: sections2,
61227
+ sections,
61106
61228
  t: ui.theme
61107
61229
  }
61108
61230
  )
@@ -61698,7 +61820,7 @@ Memory: ~/.openjaw/memory/ (shared with MCP mode)
61698
61820
  token: agentConfig.telegram.token,
61699
61821
  allowedUsers: agentConfig.telegram.allowed_users,
61700
61822
  agentLoop,
61701
- systemPromptFn: /* @__PURE__ */ __name(() => getSystemPrompt2(), "systemPromptFn")
61823
+ systemPromptFn: /* @__PURE__ */ __name(() => getSystemPrompt2({ mcpManager }), "systemPromptFn")
61702
61824
  });
61703
61825
  try {
61704
61826
  await bridge.validate();