@pencil-agent/nano-pencil 1.14.2 → 1.14.4

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 (104) hide show
  1. package/dist/build-meta.json +3 -3
  2. package/dist/builtin-extensions.d.ts +4 -0
  3. package/dist/builtin-extensions.js +16 -16
  4. package/dist/core/config/settings-manager.d.ts +8 -1
  5. package/dist/core/config/settings-manager.js +9 -0
  6. package/dist/core/extensions/runner.d.ts +70 -4
  7. package/dist/core/extensions/runner.js +188 -8
  8. package/dist/core/extensions/types.d.ts +8 -1
  9. package/dist/core/i18n/slash-commands.d.ts +12 -0
  10. package/dist/core/i18n/slash-commands.js +16 -4
  11. package/dist/core/i18n/slash-commands.zh.d.ts +12 -0
  12. package/dist/core/i18n/slash-commands.zh.js +16 -4
  13. package/dist/core/runtime/agent-session.d.ts +5 -0
  14. package/dist/core/runtime/agent-session.js +85 -27
  15. package/dist/core/runtime/extension-core-bindings.d.ts +3 -3
  16. package/dist/core/runtime/extension-core-bindings.js +73 -20
  17. package/dist/core/runtime/retry-coordinator.d.ts +10 -1
  18. package/dist/core/runtime/retry-coordinator.js +20 -4
  19. package/dist/core/runtime/sdk.js +2 -1
  20. package/dist/core/runtime/slash-command-catalog.d.ts +2 -1
  21. package/dist/core/runtime/slash-command-catalog.js +9 -1
  22. package/dist/core/slash-commands.d.ts +12 -1
  23. package/dist/core/slash-commands.js +81 -32
  24. package/dist/core/telemetry/batching-dispatcher.d.ts +41 -0
  25. package/dist/core/telemetry/batching-dispatcher.js +89 -0
  26. package/dist/core/telemetry/build-meta.d.ts +12 -0
  27. package/dist/core/telemetry/build-meta.js +57 -0
  28. package/dist/core/telemetry/caller-context.d.ts +32 -0
  29. package/dist/core/telemetry/caller-context.js +19 -0
  30. package/dist/core/telemetry/credentials.d.ts +27 -0
  31. package/dist/core/telemetry/credentials.js +87 -0
  32. package/dist/core/telemetry/ext-events.d.ts +89 -0
  33. package/dist/core/telemetry/ext-events.js +189 -0
  34. package/dist/core/telemetry/index.d.ts +13 -0
  35. package/dist/core/telemetry/index.js +6 -0
  36. package/dist/core/telemetry/insforge-base.d.ts +37 -0
  37. package/dist/core/telemetry/insforge-base.js +160 -0
  38. package/dist/core/telemetry/types.d.ts +33 -0
  39. package/dist/core/telemetry/types.js +7 -0
  40. package/dist/extensions/defaults/browser/index.js +14 -6
  41. package/dist/extensions/defaults/btw/index.js +2 -2
  42. package/dist/extensions/defaults/debug/index.js +38 -3
  43. package/dist/extensions/defaults/diagnostics/index.js +12 -0
  44. package/dist/extensions/defaults/grub/grub-parser.d.ts +15 -1
  45. package/dist/extensions/defaults/grub/grub-parser.js +31 -1
  46. package/dist/extensions/defaults/grub/index.d.ts +1 -1
  47. package/dist/extensions/defaults/grub/index.js +4 -3
  48. package/dist/extensions/defaults/interview/index.js +2 -2
  49. package/dist/extensions/defaults/link-world/index.js +14 -6
  50. package/dist/extensions/defaults/loop/cron/cron-scheduler.js +19 -0
  51. package/dist/extensions/defaults/loop/index.js +35 -0
  52. package/dist/extensions/defaults/mcp/index.js +18 -0
  53. package/dist/extensions/defaults/plan/index.js +29 -11
  54. package/dist/extensions/defaults/presence/index.d.ts +12 -2
  55. package/dist/extensions/defaults/presence/index.js +77 -23
  56. package/dist/extensions/defaults/presence/presence-memory.d.ts +2 -1
  57. package/dist/extensions/defaults/presence/presence-memory.js +37 -1
  58. package/dist/extensions/defaults/recap/index.js +12 -0
  59. package/dist/extensions/defaults/sal/eval/insforge-sink.d.ts +6 -17
  60. package/dist/extensions/defaults/sal/eval/insforge-sink.js +40 -183
  61. package/dist/extensions/defaults/sal/index.js +31 -8
  62. package/dist/extensions/defaults/sal/sal-config.d.ts +5 -0
  63. package/dist/extensions/defaults/sal/sal-config.js +15 -82
  64. package/dist/extensions/defaults/security-audit/index.js +141 -83
  65. package/dist/extensions/defaults/subagent/index.js +29 -5
  66. package/dist/extensions/defaults/team/index.js +10 -9
  67. package/dist/extensions/defaults/team/team-parser.d.ts +18 -0
  68. package/dist/extensions/defaults/team/team-parser.js +91 -3
  69. package/dist/extensions/defaults/team/team-ui.js +4 -14
  70. package/dist/extensions/defaults/token-save/index.js +14 -1
  71. package/dist/extensions/optional/export-html/index.js +19 -5
  72. package/dist/extensions/optional/simplify/index.js +11 -5
  73. package/dist/modes/interactive/interactive-mode.d.ts +2 -1
  74. package/dist/modes/interactive/interactive-mode.js +68 -19
  75. package/dist/modes/interactive/slash-command-arguments.d.ts +16 -0
  76. package/dist/modes/interactive/slash-command-arguments.js +97 -0
  77. package/dist/modes/rpc/rpc-mode.d.ts +3 -0
  78. package/dist/modes/rpc/rpc-mode.js +40 -31
  79. package/dist/modes/rpc/rpc-types.d.ts +3 -0
  80. package/dist/node_modules/@pencil-agent/agent-core/agent.d.ts +15 -1
  81. package/dist/node_modules/@pencil-agent/agent-core/agent.js +13 -1
  82. package/dist/node_modules/@pencil-agent/agent-core/index.d.ts +2 -1
  83. package/dist/node_modules/@pencil-agent/agent-core/index.js +2 -1
  84. package/dist/node_modules/@pencil-agent/agent-core/structured-adaptive-agent-loop.d.ts +1 -1
  85. package/dist/node_modules/@pencil-agent/agent-core/structured-adaptive-agent-loop.js +293 -20
  86. package/dist/node_modules/@pencil-agent/agent-core/structured-adaptive-streaming-tool-executor.d.ts +33 -0
  87. package/dist/node_modules/@pencil-agent/agent-core/structured-adaptive-streaming-tool-executor.js +189 -0
  88. package/dist/node_modules/@pencil-agent/agent-core/structured-adaptive-tool-orchestration.d.ts +9 -0
  89. package/dist/node_modules/@pencil-agent/agent-core/structured-adaptive-tool-orchestration.js +30 -5
  90. package/dist/node_modules/@pencil-agent/agent-core/types.d.ts +90 -3
  91. package/dist/node_modules/@pencil-agent/agent-core/types.js +1 -1
  92. package/dist/node_modules/@pencil-agent/ai/models.generated.d.ts +0 -17
  93. package/dist/node_modules/@pencil-agent/ai/models.generated.js +29 -46
  94. package/dist/node_modules/@pencil-agent/tui/autocomplete.d.ts +8 -1
  95. package/dist/node_modules/@pencil-agent/tui/autocomplete.js +18 -2
  96. package/dist/node_modules/@pencil-agent/tui/index.d.ts +1 -1
  97. package/dist/node_modules/@pencil-agent/tui/tui.d.ts +8 -3
  98. package/dist/node_modules/@pencil-agent/tui/tui.js +68 -33
  99. package/dist/packages/mem-core/extension.js +154 -83
  100. package/dist/packages/mem-core/full-insights-sections.d.ts +48 -0
  101. package/dist/packages/mem-core/full-insights-sections.js +231 -0
  102. package/dist/packages/mem-core/full-insights.d.ts +1 -1
  103. package/dist/packages/mem-core/full-insights.js +102 -42
  104. package/package.json +2 -2
@@ -306,6 +306,7 @@ export declare class InteractiveMode {
306
306
  private promptAfterRender;
307
307
  private updateEditorBorderColor;
308
308
  private cycleThinkingLevel;
309
+ private handleThinkingCommand;
309
310
  private handleAgentLoopCommand;
310
311
  private cycleModel;
311
312
  private toggleToolOutputExpansion;
@@ -398,7 +399,7 @@ export declare class InteractiveMode {
398
399
  private getEditorKeyDisplay;
399
400
  private handleHotkeysCommand;
400
401
  private handleClearCommand;
401
- private handleDebugCommand;
402
+ private handleRenderDebugCommand;
402
403
  private handleArminSaysHi;
403
404
  private handleShowResourcesCommand;
404
405
  private handleDaxnuts;
@@ -13,7 +13,7 @@ import { createCompactionSummaryMessage } from "../../core/messages.js";
13
13
  import { listMCPServers, setMCPServerEnabled } from "../../core/mcp/mcp-config.js";
14
14
  import { resolveModelScope } from "../../core/model-resolver.js";
15
15
  import { SessionManager, } from "../../core/session/session-manager.js";
16
- import { getLocalizedCommands } from "../../core/slash-commands.js";
16
+ import { getExtensionBackedBuiltinCommandNames, formatSlashCommandDescription, getLocalizedCommands, inferSlashCommandCategory, } from "../../core/slash-commands.js";
17
17
  import { t } from "../../core/i18n/index.js";
18
18
  import { getActivePersonaId, getPersonaDir, getPersonaMcpConfigPath, getPersonaMemoryDir, getPersonaSoulDir, listPersonas, setActivePersonaId, toAbsolutePath, } from "../../core/persona/persona-manager.js";
19
19
  import { NANOPENCIL_ALI_TOKEN_PLAN_ANTHROPIC_PROVIDER, NANOPENCIL_ALI_TOKEN_PLAN_OPENAI_PROVIDER, NANOPENCIL_WHATS_NEW, } from "../../nanopencil-defaults.js";
@@ -58,6 +58,7 @@ import { UserMessageComponent } from "./components/user-message.js";
58
58
  import { UserMessageSelectorComponent } from "./components/user-message-selector.js";
59
59
  import { RawText } from "./components/raw-text.js";
60
60
  import { getAvailableThemes, getAvailableThemesWithPaths, getEditorTheme, getMarkdownTheme, getThemeByName, initTheme, onThemeChange, setRegisteredThemes, setTheme, setThemeInstance, Theme, theme, } from "./theme/theme.js";
61
+ import { getAgentLoopArgumentCompletions, getLanguageArgumentCompletions, getMcpArgumentCompletions, getPersonaArgumentCompletions, getThinkingArgumentCompletions, } from "./slash-command-arguments.js";
61
62
  function isExpandable(obj) {
62
63
  return (typeof obj === "object" &&
63
64
  obj !== null &&
@@ -230,7 +231,7 @@ export class InteractiveMode {
230
231
  const localizedCommands = getLocalizedCommands(t);
231
232
  const slashCommands = localizedCommands.map((command) => ({
232
233
  name: command.name,
233
- description: command.description,
234
+ description: formatSlashCommandDescription(command.description, command.category, t),
234
235
  }));
235
236
  const modelCommand = slashCommands.find((command) => command.name === "model");
236
237
  if (modelCommand) {
@@ -258,16 +259,53 @@ export class InteractiveMode {
258
259
  }));
259
260
  };
260
261
  }
262
+ const thinkingCommand = slashCommands.find((command) => command.name === "thinking");
263
+ if (thinkingCommand) {
264
+ thinkingCommand.getArgumentCompletions = (prefix, context) => getThinkingArgumentCompletions(prefix, context, this.session.getAvailableThinkingLevels());
265
+ }
266
+ const agentLoopCommand = slashCommands.find((command) => command.name === "agent-loop");
267
+ if (agentLoopCommand) {
268
+ agentLoopCommand.getArgumentCompletions = getAgentLoopArgumentCompletions;
269
+ }
270
+ const mcpCommand = slashCommands.find((command) => command.name === "mcp");
271
+ if (mcpCommand) {
272
+ mcpCommand.getArgumentCompletions = (prefix, context) => getMcpArgumentCompletions(prefix, context, listMCPServers());
273
+ }
274
+ const languageCommand = slashCommands.find((command) => command.name === "language");
275
+ if (languageCommand) {
276
+ languageCommand.getArgumentCompletions = getLanguageArgumentCompletions;
277
+ }
278
+ const personaCommand = slashCommands.find((command) => command.name === "persona");
279
+ if (personaCommand) {
280
+ personaCommand.getArgumentCompletions = (prefix, context) => getPersonaArgumentCompletions(prefix, context, listPersonas(), getActivePersonaId());
281
+ }
261
282
  // Convert prompt templates to SlashCommand format for autocomplete
262
283
  const templateCommands = this.session.promptTemplates.map((cmd) => ({
263
284
  name: cmd.name,
264
- description: cmd.description,
285
+ description: formatSlashCommandDescription(cmd.description, inferSlashCommandCategory(cmd.name, "prompt"), t),
265
286
  }));
266
- // Convert extension commands to SlashCommand format
287
+ // Convert extension commands to SlashCommand format. Some discoverable
288
+ // built-ins are implemented by default extensions; merge their argument
289
+ // completions into the built-in entry instead of showing duplicates.
267
290
  const builtinCommandNames = new Set(slashCommands.map((c) => c.name));
268
- const extensionCommands = (this.session.extensionRunner?.getRegisteredCommands(builtinCommandNames) ?? []).map((cmd) => ({
291
+ const extensionBackedBuiltinNames = getExtensionBackedBuiltinCommandNames();
292
+ const reservedCommandNames = new Set([...builtinCommandNames].filter((name) => !extensionBackedBuiltinNames.has(name)));
293
+ const registeredExtensionCommands = this.session.extensionRunner?.getRegisteredCommands(reservedCommandNames) ?? [];
294
+ const extensionCommandByName = new Map(registeredExtensionCommands.map((command) => [command.name, command]));
295
+ for (const command of slashCommands) {
296
+ if (!extensionBackedBuiltinNames.has(command.name))
297
+ continue;
298
+ const extensionCommand = extensionCommandByName.get(command.name);
299
+ if (extensionCommand?.getArgumentCompletions) {
300
+ command.getArgumentCompletions =
301
+ extensionCommand.getArgumentCompletions;
302
+ }
303
+ }
304
+ const extensionCommands = registeredExtensionCommands
305
+ .filter((cmd) => !builtinCommandNames.has(cmd.name))
306
+ .map((cmd) => ({
269
307
  name: cmd.name,
270
- description: cmd.description ?? "(extension command)",
308
+ description: formatSlashCommandDescription(cmd.description ?? "(extension command)", inferSlashCommandCategory(cmd.name, "extension"), t),
271
309
  getArgumentCompletions: cmd.getArgumentCompletions,
272
310
  }));
273
311
  // Build skill commands from session.skills (if enabled)
@@ -279,7 +317,7 @@ export class InteractiveMode {
279
317
  this.skillCommands.set(commandName, skill.filePath);
280
318
  skillCommandList.push({
281
319
  name: commandName,
282
- description: skill.description,
320
+ description: formatSlashCommandDescription(skill.description, inferSlashCommandCategory(skill.name, "skill"), t),
283
321
  });
284
322
  }
285
323
  }
@@ -1691,7 +1729,7 @@ export class InteractiveMode {
1691
1729
  this.defaultEditor.onAction("cycleModelForward", () => this.cycleModel("forward"));
1692
1730
  this.defaultEditor.onAction("cycleModelBackward", () => this.cycleModel("backward"));
1693
1731
  // Global debug handler on TUI (works regardless of focus)
1694
- this.ui.onDebug = () => this.handleDebugCommand();
1732
+ this.ui.onDebug = () => this.handleRenderDebugCommand();
1695
1733
  this.defaultEditor.onAction("selectModel", () => this.showProviderThenModelSelector());
1696
1734
  this.defaultEditor.onAction("selectProviderThenModel", () => this.showProviderThenModelSelector());
1697
1735
  this.defaultEditor.onAction("expandTools", () => this.toggleToolOutputExpansion());
@@ -1984,11 +2022,6 @@ export class InteractiveMode {
1984
2022
  this.editor.setText("");
1985
2023
  return;
1986
2024
  }
1987
- if (text === "/debug") {
1988
- this.handleDebugCommand();
1989
- this.editor.setText("");
1990
- return;
1991
- }
1992
2025
  if (text === "/arminsayshi") {
1993
2026
  this.handleArminSaysHi();
1994
2027
  this.editor.setText("");
@@ -2209,6 +2242,11 @@ export class InteractiveMode {
2209
2242
  await this.handleModelCommand(searchTerm);
2210
2243
  return true;
2211
2244
  }
2245
+ if (text === "/thinking" || text.startsWith("/thinking ")) {
2246
+ this.handleThinkingCommand(text);
2247
+ clear();
2248
+ return true;
2249
+ }
2212
2250
  if (text === "/agent-loop" || text.startsWith("/agent-loop ")) {
2213
2251
  this.handleAgentLoopCommand(text);
2214
2252
  clear();
@@ -2337,11 +2375,6 @@ export class InteractiveMode {
2337
2375
  clear();
2338
2376
  return true;
2339
2377
  }
2340
- if (text === "/debug") {
2341
- this.handleDebugCommand();
2342
- clear();
2343
- return true;
2344
- }
2345
2378
  if (text === "/arminsayshi") {
2346
2379
  this.handleArminSaysHi();
2347
2380
  clear();
@@ -3165,6 +3198,22 @@ export class InteractiveMode {
3165
3198
  this.showStatus(`Thinking level: ${newLevel}`);
3166
3199
  }
3167
3200
  }
3201
+ handleThinkingCommand(text) {
3202
+ const arg = text.slice("/thinking".length).trim().toLowerCase();
3203
+ const levels = this.session.getAvailableThinkingLevels();
3204
+ if (!arg) {
3205
+ this.showStatus(`Thinking level: ${this.session.thinkingLevel} (available: ${levels.join(", ")})`);
3206
+ return;
3207
+ }
3208
+ if (!levels.includes(arg)) {
3209
+ this.showStatus(`Unknown thinking level: ${arg} (available: ${levels.join(", ")})`);
3210
+ return;
3211
+ }
3212
+ this.session.setThinkingLevel(arg);
3213
+ this.footer.invalidate();
3214
+ this.updateEditorBorderColor();
3215
+ this.showStatus(`Thinking level: ${this.session.thinkingLevel}`);
3216
+ }
3168
3217
  handleAgentLoopCommand(text) {
3169
3218
  const arg = text.slice("/agent-loop".length).trim().toLowerCase();
3170
3219
  const choices = ["standard", "weak-model-compatible"];
@@ -5129,7 +5178,7 @@ export class InteractiveMode {
5129
5178
  this.chatContainer.addChild(new Text(`${theme.fg("accent", "✓ New session started")}`, 1, 1));
5130
5179
  this.ui.requestRender();
5131
5180
  }
5132
- handleDebugCommand() {
5181
+ handleRenderDebugCommand() {
5133
5182
  const width = this.ui.terminal.columns;
5134
5183
  const height = this.ui.terminal.rows;
5135
5184
  const allLines = this.ui.render(width);
@@ -0,0 +1,16 @@
1
+ /**
2
+ * [WHO]: getAgentLoopArgumentCompletions(), getThinkingArgumentCompletions(), getMcpArgumentCompletions(), getLanguageArgumentCompletions(), getPersonaArgumentCompletions()
3
+ * [FROM]: Depends on @pencil-agent/agent-core, @pencil-agent/tui, core/i18n, core/mcp/mcp-client
4
+ * [TO]: Consumed by modes/interactive/interactive-mode.ts
5
+ * [HERE]: modes/interactive/slash-command-arguments.ts - pure argument completion helpers for built-in TUI slash commands
6
+ */
7
+ import type { ThinkingLevel } from "@pencil-agent/agent-core";
8
+ import type { ArgumentCompletionContext, AutocompleteItem } from "@pencil-agent/tui";
9
+ import type { MCPServerConfig } from "../../core/mcp/mcp-client.js";
10
+ type McpCompletionServer = Pick<MCPServerConfig, "id" | "name" | "enabled">;
11
+ export declare function getThinkingArgumentCompletions(argumentPrefix: string, context: Pick<ArgumentCompletionContext, "tokenIndex"> | undefined, levels: readonly ThinkingLevel[]): AutocompleteItem[] | null;
12
+ export declare function getAgentLoopArgumentCompletions(argumentPrefix: string, context?: Pick<ArgumentCompletionContext, "tokenIndex">): AutocompleteItem[] | null;
13
+ export declare function getMcpArgumentCompletions(argumentPrefix: string, context?: Pick<ArgumentCompletionContext, "tokenIndex" | "previousTokens">, servers?: readonly McpCompletionServer[]): AutocompleteItem[] | null;
14
+ export declare function getLanguageArgumentCompletions(argumentPrefix: string, context?: Pick<ArgumentCompletionContext, "tokenIndex">): AutocompleteItem[] | null;
15
+ export declare function getPersonaArgumentCompletions(argumentPrefix: string, context?: Pick<ArgumentCompletionContext, "tokenIndex" | "previousTokens">, personas?: readonly string[], activePersonaId?: string): AutocompleteItem[] | null;
16
+ export {};
@@ -0,0 +1,97 @@
1
+ /**
2
+ * [WHO]: getAgentLoopArgumentCompletions(), getThinkingArgumentCompletions(), getMcpArgumentCompletions(), getLanguageArgumentCompletions(), getPersonaArgumentCompletions()
3
+ * [FROM]: Depends on @pencil-agent/agent-core, @pencil-agent/tui, core/i18n, core/mcp/mcp-client
4
+ * [TO]: Consumed by modes/interactive/interactive-mode.ts
5
+ * [HERE]: modes/interactive/slash-command-arguments.ts - pure argument completion helpers for built-in TUI slash commands
6
+ */
7
+ import { AVAILABLE_LOCALES, LOCALE_NAMES } from "../../core/i18n/index.js";
8
+ const THINKING_COMPLETIONS = {
9
+ off: "Skip extra reasoning",
10
+ minimal: "Very small reasoning budget",
11
+ low: "Light reasoning for simple tasks",
12
+ medium: "Balanced reasoning for everyday coding",
13
+ high: "Deeper reasoning for complex work",
14
+ xhigh: "Maximum reasoning when the model supports it",
15
+ };
16
+ const AGENT_LOOP_COMPLETIONS = [
17
+ {
18
+ value: "standard",
19
+ label: "standard",
20
+ description: "Use the normal agent loop",
21
+ },
22
+ {
23
+ value: "weak-model-compatible",
24
+ label: "weak-model-compatible",
25
+ description: "Keep working with simpler models",
26
+ },
27
+ ];
28
+ const MCP_ACTION_COMPLETIONS = [
29
+ { value: "list", label: "list", description: "Show configured MCP servers" },
30
+ { value: "status", label: "status", description: "Show loaded MCP tools and runtime status" },
31
+ { value: "tools", label: "tools", description: "Show loaded MCP tools and runtime status" },
32
+ { value: "enable", label: "enable", description: "Turn on an MCP server" },
33
+ { value: "disable", label: "disable", description: "Turn off an MCP server" },
34
+ ];
35
+ const PERSONA_ACTION_COMPLETIONS = [
36
+ { value: "list", label: "list", description: "Show available personas" },
37
+ { value: "use", label: "use", description: "Switch to a persona" },
38
+ ];
39
+ function matchCompletions(items, prefix) {
40
+ const lowerPrefix = prefix.trim().toLowerCase();
41
+ const matches = items.filter((item) => item.value.toLowerCase().startsWith(lowerPrefix));
42
+ return matches.length > 0 ? matches.map((item) => ({ ...item })) : null;
43
+ }
44
+ function isFirstToken(context) {
45
+ return !context || context.tokenIndex === 0;
46
+ }
47
+ export function getThinkingArgumentCompletions(argumentPrefix, context, levels) {
48
+ if (!isFirstToken(context))
49
+ return null;
50
+ return matchCompletions(levels.map((level) => ({
51
+ value: level,
52
+ label: level,
53
+ description: THINKING_COMPLETIONS[level],
54
+ })), argumentPrefix);
55
+ }
56
+ export function getAgentLoopArgumentCompletions(argumentPrefix, context) {
57
+ if (!isFirstToken(context))
58
+ return null;
59
+ return matchCompletions(AGENT_LOOP_COMPLETIONS, argumentPrefix);
60
+ }
61
+ export function getMcpArgumentCompletions(argumentPrefix, context, servers = []) {
62
+ if (isFirstToken(context))
63
+ return matchCompletions(MCP_ACTION_COMPLETIONS, argumentPrefix);
64
+ if (context?.tokenIndex !== 1)
65
+ return null;
66
+ const action = context.previousTokens[0]?.toLowerCase();
67
+ if (action !== "enable" && action !== "disable")
68
+ return null;
69
+ const targetEnabledState = action === "disable";
70
+ return matchCompletions(servers
71
+ .filter((server) => (server.enabled !== false) === targetEnabledState)
72
+ .map((server) => ({
73
+ value: server.id,
74
+ label: server.id,
75
+ description: `${server.name} (${server.enabled === false ? "disabled" : "enabled"})`,
76
+ })), argumentPrefix);
77
+ }
78
+ export function getLanguageArgumentCompletions(argumentPrefix, context) {
79
+ if (!isFirstToken(context))
80
+ return null;
81
+ return matchCompletions(AVAILABLE_LOCALES.map((locale) => ({
82
+ value: locale,
83
+ label: locale,
84
+ description: LOCALE_NAMES[locale],
85
+ })), argumentPrefix);
86
+ }
87
+ export function getPersonaArgumentCompletions(argumentPrefix, context, personas = [], activePersonaId) {
88
+ if (isFirstToken(context))
89
+ return matchCompletions(PERSONA_ACTION_COMPLETIONS, argumentPrefix);
90
+ if (context?.tokenIndex !== 1 || context.previousTokens[0]?.toLowerCase() !== "use")
91
+ return null;
92
+ return matchCompletions(personas.map((personaId) => ({
93
+ value: personaId,
94
+ label: personaId,
95
+ description: personaId === activePersonaId ? "Current persona" : `Switch to ${personaId}`,
96
+ })), argumentPrefix);
97
+ }
@@ -1,5 +1,8 @@
1
1
  import type { AgentSession } from "../../core/runtime/agent-session.js";
2
+ import type { RpcSlashCommand } from "./rpc-types.js";
2
3
  export type { RpcCommand, RpcExtensionUIRequest, RpcExtensionUIResponse, RpcResponse, RpcSessionState, } from "./rpc-types.js";
4
+ type RpcSlashCommandCatalogSession = Pick<AgentSession, "extensionRunner" | "promptTemplates" | "resourceLoader">;
5
+ export declare function buildRpcSlashCommands(session: RpcSlashCommandCatalogSession): RpcSlashCommand[];
3
6
  /**
4
7
  * Run in RPC mode.
5
8
  * Listens for JSON commands on stdin, outputs events and responses on stdout.
@@ -6,7 +6,46 @@
6
6
  */
7
7
  import * as crypto from "node:crypto";
8
8
  import * as readline from "readline";
9
+ import { buildExtensionSlashCommands } from "../../core/runtime/slash-command-catalog.js";
10
+ import { inferSlashCommandCategory } from "../../core/slash-commands.js";
9
11
  import { theme } from "../interactive/theme/theme.js";
12
+ function toRpcSlashCommand(command) {
13
+ return {
14
+ name: command.name,
15
+ description: command.description,
16
+ source: command.source,
17
+ category: command.category,
18
+ location: command.location,
19
+ path: command.path,
20
+ };
21
+ }
22
+ export function buildRpcSlashCommands(session) {
23
+ if (session.extensionRunner) {
24
+ return buildExtensionSlashCommands({
25
+ promptTemplates: session.promptTemplates,
26
+ resourceLoader: session.resourceLoader,
27
+ extensionRunner: session.extensionRunner,
28
+ }).map(toRpcSlashCommand);
29
+ }
30
+ return [
31
+ ...session.promptTemplates.map((template) => ({
32
+ name: template.name,
33
+ description: template.description,
34
+ source: "prompt",
35
+ category: inferSlashCommandCategory(template.name, "prompt"),
36
+ location: template.source,
37
+ path: template.filePath,
38
+ })),
39
+ ...session.resourceLoader.getSkills().skills.map((skill) => ({
40
+ name: `skill:${skill.name}`,
41
+ description: skill.description,
42
+ source: "skill",
43
+ category: inferSlashCommandCategory(skill.name, "skill"),
44
+ location: skill.source,
45
+ path: skill.filePath,
46
+ })),
47
+ ];
48
+ }
10
49
  /**
11
50
  * Run in RPC mode.
12
51
  * Listens for JSON commands on stdin, outputs events and responses on stdout.
@@ -436,37 +475,7 @@ export async function runRpcMode(session) {
436
475
  // Commands (available for invocation via prompt)
437
476
  // =================================================================
438
477
  case "get_commands": {
439
- const commands = [];
440
- // Extension commands
441
- for (const { command, extensionPath } of session.extensionRunner?.getRegisteredCommandsWithPaths() ?? []) {
442
- commands.push({
443
- name: command.name,
444
- description: command.description,
445
- source: "extension",
446
- path: extensionPath,
447
- });
448
- }
449
- // Prompt templates (source is always "user" | "project" | "path" in coding-agent)
450
- for (const template of session.promptTemplates) {
451
- commands.push({
452
- name: template.name,
453
- description: template.description,
454
- source: "prompt",
455
- location: template.source,
456
- path: template.filePath,
457
- });
458
- }
459
- // Skills (source is always "user" | "project" | "path" in coding-agent)
460
- for (const skill of session.resourceLoader.getSkills().skills) {
461
- commands.push({
462
- name: `skill:${skill.name}`,
463
- description: skill.description,
464
- source: "skill",
465
- location: skill.source,
466
- path: skill.filePath,
467
- });
468
- }
469
- return success(id, "get_commands", { commands });
478
+ return success(id, "get_commands", { commands: buildRpcSlashCommands(session) });
470
479
  }
471
480
  default: {
472
481
  const unknownCommand = command;
@@ -9,6 +9,7 @@ import type { ImageContent, Model } from "@pencil-agent/ai";
9
9
  import type { SessionStats } from "../../core/runtime/agent-session.js";
10
10
  import type { BashResult } from "../../core/bash-executor.js";
11
11
  import type { CompactionResult } from "../../core/session/compaction/index.js";
12
+ import type { SlashCommandCategory } from "../../core/slash-commands.js";
12
13
  type AgentLoopFrameworkInput = AgentLoopFramework | "high-intelligence" | "low-intelligence" | "structured-adaptive";
13
14
  export type RpcCommand = {
14
15
  id?: string;
@@ -128,6 +129,8 @@ export interface RpcSlashCommand {
128
129
  description?: string;
129
130
  /** What kind of command this is */
130
131
  source: "extension" | "prompt" | "skill";
132
+ /** Human-facing command category for grouping and filtering */
133
+ category?: SlashCommandCategory;
131
134
  /** Where the command was loaded from (undefined for extensions) */
132
135
  location?: "user" | "project" | "path";
133
136
  /** File path to the command source */
@@ -3,7 +3,7 @@
3
3
  * No transport abstraction - calls streamSimple via the loop.
4
4
  */
5
5
  /**
6
- * [WHO]: AgentOptions, Agent
6
+ * [WHO]: AgentOptions, Agent, in-loop model error recovery and loop budget option plumbing
7
7
  * [FROM]: Depends on ./agent-loop.js and ./structured-adaptive-agent-loop.js
8
8
  * [TO]: Consumed by packages/agent-core/src/index.ts
9
9
  * [HERE]: packages/agent-core/src/agent.ts -
@@ -68,6 +68,16 @@ export interface AgentOptions {
68
68
  * Optional tool permission gate used by weak-model-compatible loop execution.
69
69
  */
70
70
  canUseTool?: AgentLoopConfig["canUseTool"];
71
+ /**
72
+ * Optional aggregate tool-result batch budget used by weak-model-compatible loop execution.
73
+ */
74
+ maxToolResultBatchSizeChars?: AgentLoopConfig["maxToolResultBatchSizeChars"];
75
+ /**
76
+ * Optional in-loop model error recovery hook used by weak-model-compatible loop execution.
77
+ */
78
+ recoverModelError?: AgentLoopConfig["recoverModelError"];
79
+ /** Maximum in-loop model error recoveries per prompt. */
80
+ maxModelErrorRecoveryAttempts?: number;
71
81
  }
72
82
  export declare class Agent {
73
83
  private _state;
@@ -89,6 +99,9 @@ export declare class Agent {
89
99
  private _maxRetryDelayMs?;
90
100
  private _agentLoopFramework?;
91
101
  private canUseTool?;
102
+ private maxToolResultBatchSizeChars?;
103
+ private recoverModelError?;
104
+ private maxModelErrorRecoveryAttempts?;
92
105
  constructor(opts?: AgentOptions);
93
106
  /**
94
107
  * Get the current session ID used for provider caching.
@@ -136,6 +149,7 @@ export declare class Agent {
136
149
  setFollowUpMode(mode: "all" | "one-at-a-time"): void;
137
150
  getFollowUpMode(): "all" | "one-at-a-time";
138
151
  setTools(t: AgentTool<any>[]): void;
152
+ setModelErrorRecovery(recoverModelError: AgentLoopConfig["recoverModelError"] | undefined): void;
139
153
  replaceMessages(ms: AgentMessage[]): void;
140
154
  appendMessage(m: AgentMessage): void;
141
155
  /**
@@ -3,7 +3,7 @@
3
3
  * No transport abstraction - calls streamSimple via the loop.
4
4
  */
5
5
  /**
6
- * [WHO]: AgentOptions, Agent
6
+ * [WHO]: AgentOptions, Agent, in-loop model error recovery and loop budget option plumbing
7
7
  * [FROM]: Depends on ./agent-loop.js and ./structured-adaptive-agent-loop.js
8
8
  * [TO]: Consumed by packages/agent-core/src/index.ts
9
9
  * [HERE]: packages/agent-core/src/agent.ts -
@@ -48,6 +48,9 @@ export class Agent {
48
48
  _maxRetryDelayMs;
49
49
  _agentLoopFramework;
50
50
  canUseTool;
51
+ maxToolResultBatchSizeChars;
52
+ recoverModelError;
53
+ maxModelErrorRecoveryAttempts;
51
54
  constructor(opts = {}) {
52
55
  this._state = { ...this._state, ...opts.initialState };
53
56
  this.convertToLlm = opts.convertToLlm || defaultConvertToLlm;
@@ -62,6 +65,9 @@ export class Agent {
62
65
  this._maxRetryDelayMs = opts.maxRetryDelayMs;
63
66
  this._agentLoopFramework = normalizeAgentLoopFramework(opts.agentLoopFramework);
64
67
  this.canUseTool = opts.canUseTool;
68
+ this.maxToolResultBatchSizeChars = opts.maxToolResultBatchSizeChars;
69
+ this.recoverModelError = opts.recoverModelError;
70
+ this.maxModelErrorRecoveryAttempts = opts.maxModelErrorRecoveryAttempts;
65
71
  }
66
72
  /**
67
73
  * Get the current session ID used for provider caching.
@@ -151,6 +157,9 @@ export class Agent {
151
157
  setTools(t) {
152
158
  this._state.tools = t;
153
159
  }
160
+ setModelErrorRecovery(recoverModelError) {
161
+ this.recoverModelError = recoverModelError;
162
+ }
154
163
  replaceMessages(ms) {
155
164
  this._state.messages = ms.slice();
156
165
  }
@@ -318,6 +327,9 @@ export class Agent {
318
327
  transformContext: this.transformContext,
319
328
  getApiKey: this.getApiKey,
320
329
  canUseTool: this.canUseTool,
330
+ maxToolResultBatchSizeChars: this.maxToolResultBatchSizeChars,
331
+ recoverModelError: this.recoverModelError,
332
+ maxModelErrorRecoveryAttempts: this.maxModelErrorRecoveryAttempts,
321
333
  getSteeringMessages: async () => {
322
334
  if (skipInitialSteeringPoll) {
323
335
  skipInitialSteeringPoll = false;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * [WHO]: agent-core barrel exports
3
- * [FROM]: Depends on agent.js, agent-loop.js, structured-adaptive-agent-loop.js, structured-adaptive-tool-orchestration.js, proxy.js, types.js
3
+ * [FROM]: Depends on agent.js, agent-loop.js, structured-adaptive-agent-loop.js, structured-adaptive-tool-orchestration.js, structured-adaptive-streaming-tool-executor.js, proxy.js, types.js
4
4
  * [TO]: Consumed by @pencil-agent/agent-core package consumers
5
5
  * [HERE]: packages/agent-core/src/index.ts - agent-core entry point
6
6
  */
@@ -8,6 +8,7 @@ export * from "./agent.js";
8
8
  export * from "./agent-loop.js";
9
9
  export * from "./structured-adaptive-agent-loop.js";
10
10
  export * from "./structured-adaptive-tool-orchestration.js";
11
+ export * from "./structured-adaptive-streaming-tool-executor.js";
11
12
  export * from "./proxy.js";
12
13
  export * from "./types.js";
13
14
  export * from "./errors.js";
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * [WHO]: agent-core barrel exports
3
- * [FROM]: Depends on agent.js, agent-loop.js, structured-adaptive-agent-loop.js, structured-adaptive-tool-orchestration.js, proxy.js, types.js
3
+ * [FROM]: Depends on agent.js, agent-loop.js, structured-adaptive-agent-loop.js, structured-adaptive-tool-orchestration.js, structured-adaptive-streaming-tool-executor.js, proxy.js, types.js
4
4
  * [TO]: Consumed by @pencil-agent/agent-core package consumers
5
5
  * [HERE]: packages/agent-core/src/index.ts - agent-core entry point
6
6
  */
@@ -10,6 +10,7 @@ export * from "./agent.js";
10
10
  export * from "./agent-loop.js";
11
11
  export * from "./structured-adaptive-agent-loop.js";
12
12
  export * from "./structured-adaptive-tool-orchestration.js";
13
+ export * from "./structured-adaptive-streaming-tool-executor.js";
13
14
  // Proxy utilities
14
15
  export * from "./proxy.js";
15
16
  // Types
@@ -5,7 +5,7 @@
5
5
  */
6
6
  /**
7
7
  * [WHO]: structuredAdaptiveAgentLoop, structuredAdaptiveAgentLoopContinue
8
- * [FROM]: Depends on @pencil-agent/ai, ./types, ./errors, ./structured-adaptive-tool-orchestration
8
+ * [FROM]: Depends on @pencil-agent/ai, ./types, ./errors, ./structured-adaptive-tool-orchestration, ./structured-adaptive-streaming-tool-executor
9
9
  * [TO]: Consumed by packages/agent-core/src/agent.ts and index.ts
10
10
  * [HERE]: packages/agent-core/src/structured-adaptive-agent-loop.ts - selectable structured-adaptive query loop framework
11
11
  */