@cjhyy/code-shell 0.1.7 → 0.3.0

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 (144) hide show
  1. package/CHANGELOG.md +108 -0
  2. package/README.md +35 -2
  3. package/dist/anthropic-DJXVKFMJ.js +1 -0
  4. package/dist/arena/index.js +1 -1
  5. package/dist/arena-MRBATZFD.js +3 -0
  6. package/dist/chunk-2OD6VR4N.js +2 -0
  7. package/dist/{chunk-RP26WO4R.js → chunk-5QIVXFCT.js} +1 -1
  8. package/dist/{chunk-NFH3UQ3E.js → chunk-AFMP73YP.js} +1 -1
  9. package/dist/{chunk-XDOWC7EG.js → chunk-D3TVASD2.js} +2 -2
  10. package/dist/chunk-DI26OUIU.js +2 -0
  11. package/dist/chunk-FZXY554D.js +2 -0
  12. package/dist/chunk-GGVAOPI7.js +1 -0
  13. package/dist/chunk-GKAQH2DG.js +2 -0
  14. package/dist/chunk-GYNO4R7R.js +2 -0
  15. package/dist/{chunk-Q4O2HGWS.js → chunk-K4HILJ6G.js} +3 -3
  16. package/dist/chunk-M7VU4YVY.js +49 -0
  17. package/dist/chunk-MLCTC53I.js +1 -0
  18. package/dist/{chunk-HIJ2XXGX.js → chunk-OWBYLMDD.js} +1 -1
  19. package/dist/chunk-SKIX2M5Z.js +4 -0
  20. package/dist/chunk-SV7H4FKT.js +3 -0
  21. package/dist/{chunk-Y2NS6HPO.js → chunk-WONQHE4P.js} +41 -41
  22. package/dist/{chunk-WOP6MJKW.js → chunk-X2S7ASQ2.js} +1 -1
  23. package/dist/chunk-Z5HKHAO7.js +336 -0
  24. package/dist/cli/commands/builtin/plugin-commands-registration.d.ts +12 -0
  25. package/dist/cli/commands/builtin/plugin-handler.d.ts +6 -0
  26. package/dist/cli/commands/registry.d.ts +9 -2
  27. package/dist/cli/main.js +140 -124
  28. package/dist/cli/onboarding.d.ts +7 -2
  29. package/dist/client-base-GSFXPP2Y.js +1 -0
  30. package/dist/compaction-L3Y6NG4N.js +1 -0
  31. package/dist/context/compaction.d.ts +2 -1
  32. package/dist/data/static-catalogs.d.ts +25 -0
  33. package/dist/devtools-FBX4HVVY.js +1 -0
  34. package/dist/engine/engine.d.ts +45 -0
  35. package/dist/engine/turn-loop.d.ts +45 -0
  36. package/dist/hooks/events.d.ts +84 -5
  37. package/dist/hooks/inject.d.ts +19 -0
  38. package/dist/hooks/shell-runner.d.ts +45 -0
  39. package/dist/index.d.ts +4 -3
  40. package/dist/index.js +1 -1
  41. package/dist/llm/api-key-sanitize.d.ts +22 -0
  42. package/dist/llm/capabilities/index.d.ts +20 -0
  43. package/dist/llm/capabilities/rules.d.ts +26 -0
  44. package/dist/llm/capabilities/types.d.ts +108 -0
  45. package/dist/llm/model-pool.d.ts +7 -0
  46. package/dist/llm/provider-catalog.d.ts +2 -0
  47. package/dist/llm/provider-kinds.d.ts +1 -1
  48. package/dist/llm/providers/openai.d.ts +45 -0
  49. package/dist/llm/retry.d.ts +12 -0
  50. package/dist/llm/stream-watchdog.d.ts +42 -0
  51. package/dist/llm/types.d.ts +8 -0
  52. package/dist/logging/logger.d.ts +24 -2
  53. package/dist/logging/session-recorder.d.ts +16 -3
  54. package/dist/manager-4XKLZHKE.js +1 -0
  55. package/dist/mcp-manager-3JGHEJO3.js +1 -0
  56. package/dist/model-fetcher-X5W5EASG.js +1 -0
  57. package/dist/openai-OQ6LLN5J.js +1 -0
  58. package/dist/{openrouter-models-AM6M52D6.js → openrouter-models-ZT4R2AE3.js} +1 -1
  59. package/dist/openrouter-sync-ARMVWY7S.js +1 -0
  60. package/dist/plugin-handler-GJISMH5Q.js +11 -0
  61. package/dist/plugins/gitOps.d.ts +23 -0
  62. package/dist/plugins/installedPlugins.d.ts +15 -0
  63. package/dist/plugins/knownMarketplaces.d.ts +10 -0
  64. package/dist/plugins/loadPluginHooks.d.ts +52 -0
  65. package/dist/plugins/marketplaceManager.d.ts +49 -0
  66. package/dist/plugins/parseMarketplaceInput.d.ts +16 -0
  67. package/dist/plugins/pluginCommandHook.d.ts +54 -0
  68. package/dist/plugins/pluginCommandsLoader.d.ts +25 -0
  69. package/dist/plugins/pluginInstaller.d.ts +36 -0
  70. package/dist/plugins/schemas.d.ts +9 -0
  71. package/dist/plugins/types.d.ts +73 -2
  72. package/dist/plugins/varRewrite.d.ts +42 -0
  73. package/dist/product/index.js +1 -1
  74. package/dist/protocol/client.d.ts +1 -1
  75. package/dist/protocol/helpers.d.ts +42 -0
  76. package/dist/render/clearTerminal.d.ts +9 -3
  77. package/dist/render/components/App.d.ts +1 -0
  78. package/dist/render/components/Static.d.ts +23 -0
  79. package/dist/render/devtools.d.ts +8 -4
  80. package/dist/render/dom.d.ts +2 -1
  81. package/dist/render/frame.d.ts +1 -0
  82. package/dist/render/index.d.ts +10 -0
  83. package/dist/render/ink.d.ts +24 -2
  84. package/dist/render/log-update.d.ts +12 -1
  85. package/dist/render/selection.d.ts +1 -1
  86. package/dist/run/index.js +1 -1
  87. package/dist/{seatbelt-WBYROQT6.js → seatbelt-L54CNI2Y.js} +5 -5
  88. package/dist/services/index.d.ts +1 -0
  89. package/dist/services/memory-orchestrator.d.ts +39 -0
  90. package/dist/settings/schema.d.ts +168 -21
  91. package/dist/skills/frontmatter.d.ts +13 -0
  92. package/dist/skills/index.d.ts +4 -4
  93. package/dist/skills/scanner.d.ts +11 -21
  94. package/dist/tool-summary-HJX6RHG4.js +2 -0
  95. package/dist/tool-system/builtin/agent-notifications.d.ts +55 -0
  96. package/dist/tool-system/builtin/agent-registry.d.ts +35 -4
  97. package/dist/tool-system/builtin/agent-transcript-translator.d.ts +22 -0
  98. package/dist/tool-system/builtin/skill-prompt.d.ts +7 -0
  99. package/dist/tool-system/builtin/skill.d.ts +3 -1
  100. package/dist/tool-system/context.d.ts +23 -0
  101. package/dist/tool-system/executor.d.ts +5 -1
  102. package/dist/tool-system/permission.d.ts +1 -1
  103. package/dist/tool-system/sandbox/index.d.ts +7 -0
  104. package/dist/tool-system/task-guard.d.ts +30 -0
  105. package/dist/types.d.ts +48 -0
  106. package/dist/ui/components/AgentBlock.d.ts +5 -2
  107. package/dist/ui/components/AgentDock.d.ts +36 -0
  108. package/dist/ui/components/CommandInput.d.ts +12 -1
  109. package/dist/ui/components/MessageRow.d.ts +54 -0
  110. package/dist/ui/components/SpinnerWithVerb.d.ts +7 -1
  111. package/dist/ui/components/StatusLine.d.ts +5 -1
  112. package/dist/ui/components/TextInput.d.ts +9 -1
  113. package/dist/ui/components/VirtualMessageList.d.ts +30 -11
  114. package/dist/ui/dev-seed.d.ts +1 -0
  115. package/dist/ui/fullscreen-mode.d.ts +9 -0
  116. package/dist/ui/hooks/useVirtualScroll.d.ts +101 -0
  117. package/dist/ui/perf-probes.d.ts +22 -0
  118. package/dist/ui/query-guard.d.ts +35 -0
  119. package/dist/ui/slice-anchor.d.ts +44 -0
  120. package/dist/ui/store.d.ts +26 -1
  121. package/package.json +5 -3
  122. package/dist/anthropic-UBSB5AQH.js +0 -1
  123. package/dist/arena-OW55ZCHT.js +0 -3
  124. package/dist/chunk-2NS3JMNK.js +0 -1
  125. package/dist/chunk-B7K2OWKC.js +0 -2
  126. package/dist/chunk-EWWK56K6.js +0 -2
  127. package/dist/chunk-KCXSARAA.js +0 -1
  128. package/dist/chunk-NMBYBGC7.js +0 -250
  129. package/dist/chunk-NVAZJ5XS.js +0 -2
  130. package/dist/chunk-PGANL6F2.js +0 -3
  131. package/dist/chunk-UDPUTFQT.js +0 -2
  132. package/dist/chunk-W47Z7MGS.js +0 -33
  133. package/dist/client-base-6ZZJJYDY.js +0 -1
  134. package/dist/compaction-ECVQVOCT.js +0 -1
  135. package/dist/devtools-SGDUOOM4.js +0 -1
  136. package/dist/manager-C3TDN6MS.js +0 -1
  137. package/dist/mcp-manager-OP4XYV53.js +0 -1
  138. package/dist/model-fetcher-BJ64META.js +0 -1
  139. package/dist/openai-KEWQ54TM.js +0 -1
  140. package/dist/openrouter-sync-5JNBL3Z6.js +0 -1
  141. package/dist/plugins/loader.d.ts +0 -72
  142. package/dist/skills/matcher.d.ts +0 -21
  143. package/dist/tool-summary-5UE62VU4.js +0 -2
  144. package/skills-builtin/codeshell-help.md +0 -135
@@ -23,9 +23,14 @@ export interface ProviderDef {
23
23
  envKey: string;
24
24
  provider: string;
25
25
  baseUrl: string;
26
- defaultModel: string;
27
26
  keyUrl: string;
28
27
  keyPrefix: string;
28
+ /**
29
+ * The catalog of model IDs to register for this provider. The first
30
+ * entry doubles as the zero-config default — auto-activated when the
31
+ * user boots with just an env key (no onboarding). Users override by
32
+ * picking in the wizard or running `/model`.
33
+ */
29
34
  models: string[];
30
35
  /** When true, skip API key prompt (e.g. local providers like Ollama). */
31
36
  noKey?: boolean;
@@ -77,7 +82,7 @@ export declare function findSavedKeyForProvider(provider: ProviderDef): {
77
82
  * Return the list of model IDs previously saved under this provider
78
83
  * (matched by baseUrl). Used by the onboarding wizard to pre-populate the
79
84
  * "model pool" step with the user's prior choices instead of resetting to
80
- * just provider.defaultModel.
85
+ * just the provider's first model.
81
86
  */
82
87
  export declare function loadSavedModelsForProvider(provider: ProviderDef): string[];
83
88
  export declare function hasApiKey(): boolean;
@@ -0,0 +1 @@
1
+ export{a as LLMClientBase}from'./chunk-OWBYLMDD.js';import'./chunk-FU7AHZNN.js';import'./chunk-DI26OUIU.js';import'./chunk-3QP5BQ3L.js';
@@ -0,0 +1 @@
1
+ import {p}from'./chunk-M7VU4YVY.js';export{e as COMPACTABLE_TOOL_NAMES,b as adjustIndexToPreserveAPIInvariants,k as applySummaryCompaction,g as applyToolResultBudget,i as buildSummarizationPrompt,m as dropOldestRounds,a as estimateTokens,j as extractAnchoredSummary,n as extractReferencedFilePaths,l as groupMessagesByApiRound,f as microcompact,c as snipCompact,h as truncateToolResult,d as windowCompact}from'./chunk-M7VU4YVY.js';import'./chunk-3QP5BQ3L.js';p();
@@ -89,7 +89,8 @@ export declare function truncateToolResult(result: string, maxChars?: number): s
89
89
  * Build a structured summarization prompt from messages to be compacted.
90
90
  * Produces a 9-section summary preserving key details.
91
91
  */
92
- export declare function buildSummarizationPrompt(messagesToSummarize: Message[]): string;
92
+ export declare function buildSummarizationPrompt(messagesToSummarize: Message[], priorSummary?: string): string;
93
+ export declare function extractAnchoredSummary(messages: Message[]): string | undefined;
93
94
  /**
94
95
  * Apply LLM-generated summary compaction (hybrid mode).
95
96
  *
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Hand-maintained static model catalogs for providers whose /v1/models
3
+ * endpoint returns only ids — no context window, max output, or pricing.
4
+ *
5
+ * At runtime we still call the live /models endpoint to discover ids
6
+ * (so newly-released models work without a code update), then left-join
7
+ * this table on `id` to fill in metadata. Edit the JSONs in src/data/
8
+ * when a vendor ships a new model.
9
+ *
10
+ * OpenRouter is NOT here — its catalog is generated at build time by
11
+ * scripts/sync-models.ts because OpenRouter exposes full metadata.
12
+ */
13
+ import type { ProviderKindName } from "../llm/provider-kinds.js";
14
+ export interface StaticModel {
15
+ id: string;
16
+ name: string;
17
+ contextLength: number;
18
+ maxOutputTokens: number;
19
+ inputPricePerMillion: number;
20
+ outputPricePerMillion: number;
21
+ modalities: string[];
22
+ thinking?: boolean;
23
+ }
24
+ export declare function listStaticModels(kind: ProviderKindName): StaticModel[];
25
+ export declare function hasStaticCatalog(kind: ProviderKindName): boolean;
@@ -0,0 +1 @@
1
+ export{a as recordFrame,b as renderDevtools}from'./chunk-GYNO4R7R.js';import'./chunk-3QP5BQ3L.js';
@@ -51,6 +51,14 @@ export interface EngineConfig {
51
51
  * the loop to approve commands.
52
52
  */
53
53
  sandbox?: SandboxConfig;
54
+ /**
55
+ * True when this Engine is itself a sub-agent (spawned by another
56
+ * Engine's Agent tool). Threaded into ToolContext so the Agent tool can
57
+ * refuse re-entry — defense in depth against the tool-list strip in
58
+ * spawn(): if a tool registry regression ever leaks Agent into a child's
59
+ * pool, the runtime check still blocks the call.
60
+ */
61
+ isSubAgent?: boolean;
54
62
  }
55
63
  export interface EngineHookConfig {
56
64
  event: HookEventName;
@@ -78,10 +86,41 @@ export declare class Engine {
78
86
  private lastMessages;
79
87
  private lastSessionId;
80
88
  private compactedMessagesBySession;
89
+ /**
90
+ * SIDs whose ctx-bar seed we've already emitted in this process. The seed
91
+ * is a rough char/4 estimate; only useful before the first real
92
+ * usage_update arrives (cold start or cross-process resume). On subsequent
93
+ * turns the UI already shows the previous turn's accurate ctx — re-seeding
94
+ * would visibly drop the bar on every submit.
95
+ */
96
+ private ctxSeedSent;
97
+ /**
98
+ * Per-sid cache of "non-messages overhead" (system prompt + tool defs, in
99
+ * tokens). Survives across turns so each fresh TurnLoop instance can seed
100
+ * its first pre-llm emit with the right offset — without this the ctx bar
101
+ * visibly drops on every user submit (e.g. from ~20k → 3k) until the next
102
+ * LLM response arrives.
103
+ */
104
+ private ctxOverheadBySid;
81
105
  private activePermission;
82
106
  /** Public accessor so UI/clients can read the resolved per-model window. */
83
107
  get maxContextTokens(): number;
84
108
  private resolveMaxContextTokens;
109
+ /**
110
+ * Emit a lifecycle hook with isSubAgent auto-merged into data so handlers
111
+ * can skip noisy injections for spawned children. All Engine-side hook
112
+ * emits should go through this wrapper to keep the context envelope
113
+ * uniform with TurnLoop.emitHook.
114
+ */
115
+ private emitHook;
116
+ /**
117
+ * Read settings.hooks and register a shell-runner wrapper handler per
118
+ * entry. Sub-agents skip shell hooks entirely — spawning child processes
119
+ * per emit for every sub-agent run would multiply token-side overhead
120
+ * for marginal value; explicit users who want sub-agent observability
121
+ * should register SDK-side handlers.
122
+ */
123
+ private registerSettingsHooks;
85
124
  constructor(config: EngineConfig);
86
125
  /**
87
126
  * Load models[] / providers[] from settings into the active ModelPool and
@@ -121,6 +160,12 @@ export declare class Engine {
121
160
  signal?: AbortSignal;
122
161
  sessionId?: string;
123
162
  }): Promise<EngineResult>;
163
+ /**
164
+ * Run the end-of-session memory pipeline as a fire-and-forget background
165
+ * task. Extracts durable memories from the transcript, saves a session
166
+ * summary, and conditionally triggers auto-dream consolidation.
167
+ */
168
+ private runMemoryPipeline;
124
169
  getToolRegistry(): ToolRegistry;
125
170
  /**
126
171
  * Switch the active model by pool key. Takes effect on the next run() call.
@@ -23,6 +23,11 @@ export interface TurnLoopConfig {
23
23
  */
24
24
  onTurnBoundary?: (turnCount: number) => void;
25
25
  }
26
+ export interface CtxOverheadStore {
27
+ /** Tokens for system prompt + tool defs, derived from provider's promptTokens. */
28
+ get(sid: string): number;
29
+ set(sid: string, tokens: number): void;
30
+ }
26
31
  export interface TurnLoopDeps {
27
32
  model: ModelFacade;
28
33
  toolExecutor: ToolExecutor;
@@ -31,6 +36,28 @@ export interface TurnLoopDeps {
31
36
  transcript: Transcript;
32
37
  systemPrompt: string;
33
38
  tools: import("../types.js").ToolDefinition[];
39
+ /** Per-sid overhead cache so the ctx bar doesn't drop between turns. */
40
+ ctxOverheadStore: CtxOverheadStore;
41
+ /** Current session id, used to key the overhead store. */
42
+ sessionId: string;
43
+ /**
44
+ * Carried into every hook emit's `ctx.data.isSubAgent` so handlers can
45
+ * skip noisy injections for spawned children. Set by Engine from
46
+ * EngineConfig.isSubAgent (engine.ts:119).
47
+ */
48
+ isSubAgent?: boolean;
49
+ /**
50
+ * Reads/clears the most recent compaction event emitted by
51
+ * ContextManager since the last call. Returns `null` if no compaction
52
+ * fired since the previous check. The Engine wires this up so the
53
+ * turn loop can `post_compact` emit + inject hook messages without
54
+ * the ContextManager itself depending on HookRegistry.
55
+ */
56
+ consumePendingCompactInfo?: () => {
57
+ strategy: string;
58
+ before: number;
59
+ after: number;
60
+ } | null;
34
61
  }
35
62
  export interface TurnLoopResult {
36
63
  text: string;
@@ -50,7 +77,25 @@ export declare class TurnLoop {
50
77
  * every line they write is tagged with the current turn/turnId.
51
78
  */
52
79
  private currentTurnLog;
80
+ /** Last emitted ctx token estimate; used to skip no-op usage_update events. */
81
+ private lastCtxEmit;
53
82
  constructor(deps: TurnLoopDeps, config: TurnLoopConfig);
83
+ /**
84
+ * Emit a lifecycle hook with isSubAgent + sessionId auto-merged into data.
85
+ * Returns the aggregated HookResult so callers can consume `messages` /
86
+ * `decision` / `stop`. Use this instead of `deps.hooks.emit` directly so
87
+ * every emit carries the same context envelope.
88
+ */
89
+ private emitHook;
90
+ /**
91
+ * Emit a usage_update so the UI ctx bar reflects current message-array
92
+ * size. Called at every point where messages mutate: after a tool_result
93
+ * is appended, after context management (which may shrink), and after an
94
+ * LLM response (which we also feed through with the provider's authoritative
95
+ * promptTokens to override our estimate).
96
+ */
97
+ private emitCtxFromMessages;
98
+ private emitCtxFromUsage;
54
99
  /**
55
100
  * Run the multi-turn agent loop until completion.
56
101
  */
@@ -5,16 +5,72 @@
5
5
  * Lifecycle hooks the engine emits.
6
6
  *
7
7
  * **Currently emitted** (handlers registered here will actually fire):
8
- * - on_agent_start / on_agent_end (engine.ts)
9
- * - on_turn_start / on_turn_end (turn-loop.ts)
10
- * - pre_tool_use / post_tool_use (executor.ts)
8
+ * - on_session_start / on_session_end (engine.ts) — fires once per Engine.run().
9
+ * on_session_start handlers may return
10
+ * `messages` to inject a <system-reminder>
11
+ * at the head of the conversation, before
12
+ * the current user prompt.
13
+ * - on_agent_start / on_agent_end (engine.ts) — notify-only; returned
14
+ * messages are NOT consumed (the loop
15
+ * is already armed by the time these
16
+ * fire). Use on_session_start instead.
17
+ * - user_prompt_submit (engine.ts) — fires once per run() for
18
+ * every new user prompt (cold-start and
19
+ * resume both qualify). Returned messages
20
+ * are merged into the same lifecycle
21
+ * <system-reminder> as on_session_start.
22
+ * - on_turn_start / on_turn_end (turn-loop.ts) — on_turn_start handlers
23
+ * may return `messages` to inject a
24
+ * per-turn reminder appended to the
25
+ * conversation right before the model call.
26
+ * - pre_tool_use / post_tool_use (executor.ts) — pre_tool_use honors
27
+ * `decision: "deny"` to short-circuit
28
+ * the call (executor.ts:131).
11
29
  * - on_tool_start / on_tool_end (executor.ts)
12
30
  * - file_changed (executor.ts, Write/Edit only)
31
+ * - on_permission_check (executor.ts) — fires after the
32
+ * classifier runs and before its
33
+ * decision is acted on. Handler can
34
+ * override via `decision`; the
35
+ * override is logged as
36
+ * `permission.hook_override`. ctx.data
37
+ * carries `classifierDecision` so
38
+ * handlers can branch on the rule
39
+ * set's verdict.
40
+ * - post_compact (turn-loop.ts) — fires after
41
+ * ContextManager.manageAsync() runs
42
+ * a non-micro compaction. Handlers
43
+ * may return `messages` to inject a
44
+ * <system-reminder> into the same
45
+ * turn before the model call. ctx.data
46
+ * carries `strategy` (summary/snip/
47
+ * window/emergency), `beforeTokens`,
48
+ * `afterTokens`. Microcompact is
49
+ * intentionally suppressed.
50
+ * - notification (agent.ts) — fired when a background
51
+ * sub-agent transitions to a terminal
52
+ * state. ctx.data carries `kind`
53
+ * ("agent_completed" / "agent_failed" /
54
+ * "agent_cancelled"), `agentId`,
55
+ * `name`, `description`, plus
56
+ * `finalText` (completed) or `error`
57
+ * (failed). Fired void — handler
58
+ * latency does not block the main
59
+ * loop. Not consumed by the engine
60
+ * (bg-agent feed renders the same
61
+ * info via notificationQueue);
62
+ * intended for shell hooks (osascript
63
+ * / desktop notifications).
64
+ *
65
+ * All Engine-side emits run through Engine.emitHook / TurnLoop.emitHook, which
66
+ * auto-merge `isSubAgent` (and sessionId, for turn-loop) into ctx.data so
67
+ * handlers can skip noisy injections for spawned children.
13
68
  *
14
69
  * **Reserved / not-yet-emitted** (defined so downstream can register handlers
15
70
  * in anticipation; wire the emitter before relying on them):
16
- * - on_permission_check / on_session_start / on_session_end
17
- * - user_prompt_submit / pre_compact / post_compact / notification
71
+ * - pre_compact — would require pre-flight prediction inside
72
+ * ContextManager; current implementation only knows
73
+ * after-the-fact (use post_compact instead).
18
74
  */
19
75
  export type HookEventName = "on_agent_start" | "on_agent_end" | "on_turn_start" | "on_turn_end" | "on_tool_start" | "on_tool_end" | "on_permission_check" | "on_session_start" | "on_session_end" | "pre_tool_use" | "post_tool_use" | "user_prompt_submit" | "pre_compact" | "post_compact" | "file_changed" | "notification";
20
76
  export interface HookContext {
@@ -32,4 +88,27 @@ export interface HookResult {
32
88
  messages?: string[];
33
89
  /** Allow/deny/ask override for permission hooks */
34
90
  decision?: "allow" | "deny" | "ask";
91
+ /**
92
+ * For pre_tool_use: replace the tool's args before execution. Used by
93
+ * "sanitizer" handlers (e.g. redact secrets in Bash commands, normalize
94
+ * file paths, inject a default flag). Last handler in the chain wins.
95
+ * Args are re-validated against the tool's input schema before the
96
+ * tool runs, so a malformed updatedInput still surfaces as an
97
+ * "Invalid input" error rather than silently passing through.
98
+ */
99
+ updatedInput?: Record<string, unknown>;
100
+ /**
101
+ * For post_tool_use: text appended to the tool's content (visible to
102
+ * the model on the next LLM call). Used by linter/typecheck handlers
103
+ * to surface results without re-running the tool. Multiple handlers'
104
+ * additionalContext entries are joined with two newlines.
105
+ */
106
+ additionalContext?: string;
107
+ /**
108
+ * For user_prompt_submit: replace the most recent user message text
109
+ * with this string. Last handler wins. Used to auto-prepend project
110
+ * context, mask secrets, or rewrite shorthand prompts. The original
111
+ * prompt is logged at info level for audit purposes.
112
+ */
113
+ updatedPrompt?: string;
35
114
  }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Hook message injection helper.
3
+ *
4
+ * Handlers return raw markdown strings via HookResult.messages. The emit
5
+ * site uses wrapHookMessages() to package them into a single user-role
6
+ * <system-reminder> Message so the model sees them as one block instead
7
+ * of a noisy sequence of separate user turns.
8
+ *
9
+ * Contract:
10
+ * - Handlers do NOT wrap their own <system-reminder>; emit-site owns the
11
+ * wrapper. Keeps formatting consistent and lets us evolve it (e.g. add
12
+ * a trailing close-tag, tag attributes) without touching every handler.
13
+ * - Empty / whitespace-only messages are dropped before wrapping; if
14
+ * nothing remains, returns null (caller skips the injection).
15
+ * - Multiple handlers' messages are joined with a blank line between
16
+ * blocks so each is visually distinct inside the reminder.
17
+ */
18
+ import type { Message } from "../types.js";
19
+ export declare function wrapHookMessages(messages: string[] | undefined): Message | null;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * shell-runner — execute a user-configured shell command as a hook handler.
3
+ *
4
+ * Protocol (matches Claude Code's shell-hook contract):
5
+ *
6
+ * stdin JSON.stringify({ eventName, data }) — the full HookContext
7
+ * envelope, including ctx.data fields like toolName / args /
8
+ * sessionId / isSubAgent.
9
+ *
10
+ * stdout Either ignored (when exit 0 with no/blank output) or parsed
11
+ * as a HookResult JSON document. Unparseable stdout on exit 0
12
+ * is logged at warn level and dropped — we do NOT crash the
13
+ * turn loop on malformed handler output.
14
+ *
15
+ * exit 0 Normal return. Stdout (if any) becomes the HookResult.
16
+ * exit 2 Deny / block. Stderr becomes the human-readable reason and
17
+ * is surfaced to the model via HookResult.messages so the LLM
18
+ * sees why the action was rejected.
19
+ * exit * Any other non-zero code = handler error. Logged at error
20
+ * level; we return {} (no effect) so a buggy hook never wedges
21
+ * the engine.
22
+ *
23
+ * ENV (passed to child):
24
+ * CODESHELL_HOOK_EVENT — event name, also in stdin
25
+ * CODESHELL_HOOK_CWD — repo root for context-aware hooks
26
+ * (callers may add more by reading process.env directly)
27
+ *
28
+ * timeout Defaults to 60_000 ms; settings.timeout_ms overrides.
29
+ * On timeout we SIGTERM then SIGKILL, log, and return {}.
30
+ */
31
+ import type { HookContext, HookResult } from "./events.js";
32
+ import type { SettingsHookConfig } from "../types.js";
33
+ /**
34
+ * Run one shell-hook command and return the parsed HookResult. Catches
35
+ * every failure mode (spawn error, timeout, malformed JSON) and
36
+ * returns an empty result so the registry's chain keeps going.
37
+ */
38
+ export declare function runShellHook(config: SettingsHookConfig, ctx: HookContext): Promise<HookResult>;
39
+ /**
40
+ * Check whether the hook should fire for the current ctx, respecting
41
+ * the optional `matcher` regex. Returns false for non-tool events
42
+ * when matcher is set (matcher only makes sense when ctx.data has a
43
+ * toolName field).
44
+ */
45
+ export declare function shellHookMatches(config: SettingsHookConfig, ctx: HookContext): boolean;
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Public API exports.
5
5
  */
6
- export declare const VERSION = "0.1.7";
6
+ export declare const VERSION = "0.2.0";
7
7
  export type { Message, ContentBlock, ToolDefinition, ToolCall, ToolResult, RegisteredTool, TranscriptEvent, TranscriptEventType, SessionState, TokenUsage, CompiledInput, PermissionDecision, PermissionMode, PermissionRule, TurnPhase, TurnResult, TerminalReason, StreamEvent, StreamCallback, LLMConfig, LLMResponse, Settings, MCPServerConfig, } from "./types.js";
8
8
  export { FrameworkError, LLMError, LLMRateLimitError, ContextLimitError, ToolError, ToolNotFoundError, ToolExecutionError, ToolTimeoutError, PermissionDeniedError, SessionError, TranscriptError, ConfigError, } from "./exceptions.js";
9
9
  export { Engine } from "./engine/engine.js";
@@ -25,6 +25,7 @@ export { taskManager } from "./tool-system/builtin/task.js";
25
25
  export type { Task, TaskStatus } from "./tool-system/builtin/task.js";
26
26
  export { HookRegistry } from "./hooks/registry.js";
27
27
  export type { HookEventName, HookContext, HookResult } from "./hooks/events.js";
28
+ export { wrapHookMessages } from "./hooks/inject.js";
28
29
  export { Transcript } from "./session/transcript.js";
29
30
  export { SessionManager } from "./session/session-manager.js";
30
31
  export { FileHistory } from "./session/file-history.js";
@@ -43,8 +44,8 @@ export type { MicrocompactOptions } from "./context/compaction.js";
43
44
  export type { SummarizeFn, CompactStrategy, OnCompactFn, ContextManagerConfig, } from "./context/manager.js";
44
45
  export { applyToolResultPersistence, createContentReplacementState, reconstructContentReplacementState, resolveToolResultsDir, isPersistedReplacement, DEFAULT_PERSIST_THRESHOLD, PER_MESSAGE_AGGREGATE_CAP, PREVIEW_SIZE, } from "./context/tool-result-storage.js";
45
46
  export type { ContentReplacementState } from "./context/tool-result-storage.js";
46
- export { scanSkills, matchSkillsByInput, matchSkillsByTool, buildSkillListing } from "./skills/index.js";
47
- export type { SkillDefinition, MatchResult } from "./skills/index.js";
47
+ export { scanSkills, invalidateSkillCache } from "./skills/index.js";
48
+ export type { SkillDefinition } from "./skills/index.js";
48
49
  export { Arena } from "./arena/arena.js";
49
50
  export { MODEL_PRESETS, getMaxOutputTokens } from "./arena/model-presets.js";
50
51
  export type { ModelPreset } from "./arena/model-presets.js";
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export{a as defineProduct}from'./chunk-KCXSARAA.js';export{a as createRunManager}from'./chunk-RP26WO4R.js';export{_ as ArtifactTracker,i as AutoApprovalBackend,I as BUILTIN_AGENT_PRESETS,e as BUILTIN_TOOLS,Z as CheckpointWriter,ca as CompositeEvaluator,w as ContextManager,J as DEFAULT_AGENT_PRESET,K as DEFAULT_CLI_PRESET,o as DEFAULT_PERSIST_THRESHOLD,T as Engine,da as EngineRunner,V as FileRunStore,h as HeadlessApprovalBackend,aa as Heartbeat,n as HookRegistry,ba as NoopEvaluator,p as PER_MESSAGE_AGGREGATE_CAP,q as PREVIEW_SIZE,m as PermissionClassifier,Q as PromptComposer,X as RunApprovalBackend,$ as RunLock,ea as RunManager,W as RunQueue,x as SectionCache,g as ToolExecutor,f as ToolRegistry,U as VALID_TRANSITIONS,u as applyToolResultPersistence,H as availableSections,O as buildPresetSystemPrompt,D as buildSkillListing,z as combineInstructions,r as createContentReplacementState,Y as createRunAskUserFn,v as isPersistedReplacement,M as listPresetNames,F as loadSection,G as loadSections,B as matchSkillsByInput,C as matchSkillsByTool,s as reconstructContentReplacementState,L as registerPreset,E as registerSection,N as resolveAgentPreset,P as resolveBuiltinToolNames,t as resolveToolResultsDir,y as scanInstructions,A as scanSkills,c as taskManager}from'./chunk-NMBYBGC7.js';export{a as ModelPool}from'./chunk-2NS3JMNK.js';export{a as FileHistory}from'./chunk-WI6FSWGU.js';import'./chunk-P6JSTIFM.js';import'./chunk-SNFAPSLA.js';export{a as MCPManager}from'./chunk-XDOWC7EG.js';import {o}from'./chunk-W47Z7MGS.js';export{e as COMPACTABLE_TOOL_NAMES,j as applySummaryCompaction,i as buildSummarizationPrompt,a as estimateTokens,f as microcompact,h as truncateToolResult,d as windowCompact}from'./chunk-W47Z7MGS.js';export{b as MemoryManager}from'./chunk-T222K6IV.js';export{b as SessionManager,a as Transcript}from'./chunk-QTWU7UNA.js';export{c as SettingsManager,a as SettingsSchema,b as validateSettings}from'./chunk-UDPUTFQT.js';export{j as IterativeArena,f as defaultIterateConvergence,i as getIterateFormat,g as iterateCodeFormat,e as iterateDiffRatio,h as iterateDocumentFormat}from'./chunk-Q4O2HGWS.js';export{J as Arena,I as ArenaLedger,e as DiscussionStrategy,Q as MODEL_PRESETS,f as PlanningStrategy,d as ReviewStrategy,z as applyReviewResult,u as buildDigest,n as collectEvidence,b as createLLMClient,v as formatDigest,R as getMaxOutputTokens,k as getStrategy,l as getStrategyForPlan,p as hasTools,B as isTerminal,y as markUnderReview,A as markUnresolved,m as planArena,s as registerClaims,a as registerProvider,x as resolveClaimStatus,t as selectClaimsForReview,o as selectTools,w as transitionClaim,C as validTransitions}from'./chunk-Y2NS6HPO.js';import'./chunk-NVAZJ5XS.js';export{a as AnthropicClient}from'./chunk-WOP6MJKW.js';export{a as OpenAIClient}from'./chunk-PGANL6F2.js';import'./chunk-O5HFCH2U.js';export{a as LLMClientBase}from'./chunk-HIJ2XXGX.js';export{l as ConfigError,d as ContextLimitError,a as FrameworkError,b as LLMError,c as LLMRateLimitError,i as PermissionDeniedError,j as SessionError,e as ToolError,g as ToolExecutionError,f as ToolNotFoundError,h as ToolTimeoutError,k as TranscriptError}from'./chunk-FU7AHZNN.js';export{b as logger}from'./chunk-B7K2OWKC.js';import {h,a}from'./chunk-3QP5BQ3L.js';h();o();h();var vt={review:[{patterns:[/\breview\b/i,/\baudit\b/i,/\binspect\b/i,/\bcheck\b/i],weight:2},{patterns:[/\bcode\s*quality\b/i,/\bbug\b/i,/\bvulnerab/i,/\bsecur/i]},{patterns:[/\bpr\b/i,/\bpull\s*request\b/i,/\bdiff\b/i,/\bchanges?\b/i]},{patterns:[/\brefactor/i,/\bclean\s*up\b/i,/\bimprove\b/i]}],discussion:[{patterns:[/\bdiscuss\b/i,/\bdebate\b/i,/\bcompare\b/i],weight:2},{patterns:[/\bpros?\s*(and|&|\/)\s*cons?\b/i,/\btrade\s*-?\s*offs?\b/i]},{patterns:[/\bshould\s+we\b/i,/\bwhich\s+(is|approach|way)\b/i,/\bvs\.?\b/i]},{patterns:[/\bopinion\b/i,/\bthoughts?\b/i,/\badvice\b/i]}],planning:[{patterns:[/\bplan\b/i,/\bplanning\b/i,/\broadmap\b/i,/\bstrategy\b/i],weight:2},{patterns:[/\barchitect/i,/\bdesign\b/i,/\bproposal\b/i]},{patterns:[/\bimplement(ation)?\s+(plan|strategy|approach)\b/i],weight:2},{patterns:[/\bphase\b/i,/\bmilestone\b/i,/\btimeline\b/i,/\bprioritiz/i]},{patterns:[/\bbuild\b/i,/\bcreate\b/i,/\bsetup\b/i,/\bbootstrap\b/i]}]},kt=3,Mt=2;function Pt(m){let a={review:0,discussion:0,planning:0};for(let[n,i]of Object.entries(vt))for(let p of i){let u=p.weight??1;for(let d of p.patterns)d.test(m)&&(a[n]+=u);}let s=Object.entries(a).sort((n,i)=>i[1]-n[1]),[t,e]=s[0],[,l]=s[1],r=e-l;return e>=kt&&r>=Mt?{mode:t,confidence:"high",reason:`Topic strongly matches "${t}" (score: ${e}, lead: +${r})`}:e>0&&r>0?{mode:t,confidence:"low",reason:`Topic weakly matches "${t}" (score: ${e}, lead: +${r})`}:{mode:"review",confidence:"low",reason:"No strong mode signal detected, defaulting to review"}}a(Pt,"detectArenaMode");var wt="0.1.7";export{wt as VERSION,Pt as detectArenaMode};
1
+ export{a as defineProduct}from'./chunk-GGVAOPI7.js';export{a as createRunManager}from'./chunk-5QIVXFCT.js';export{Y as ArtifactTracker,k as AutoApprovalBackend,F as BUILTIN_AGENT_PRESETS,f as BUILTIN_TOOLS,X as CheckpointWriter,aa as CompositeEvaluator,x as ContextManager,G as DEFAULT_AGENT_PRESET,H as DEFAULT_CLI_PRESET,p as DEFAULT_PERSIST_THRESHOLD,R as Engine,fa as EngineRunner,T as FileRunStore,j as HeadlessApprovalBackend,_ as Heartbeat,n as HookRegistry,$ as NoopEvaluator,q as PER_MESSAGE_AGGREGATE_CAP,r as PREVIEW_SIZE,m as PermissionClassifier,N as PromptComposer,V as RunApprovalBackend,Z as RunLock,ga as RunManager,U as RunQueue,y as SectionCache,i as ToolExecutor,g as ToolRegistry,S as VALID_TRANSITIONS,v as applyToolResultPersistence,E as availableSections,L as buildPresetSystemPrompt,A as combineInstructions,s as createContentReplacementState,W as createRunAskUserFn,w as isPersistedReplacement,J as listPresetNames,C as loadSection,D as loadSections,t as reconstructContentReplacementState,I as registerPreset,B as registerSection,K as resolveAgentPreset,M as resolveBuiltinToolNames,u as resolveToolResultsDir,z as scanInstructions,e as taskManager,o as wrapHookMessages}from'./chunk-Z5HKHAO7.js';export{i as invalidateSkillCache,h as scanSkills}from'./chunk-SKIX2M5Z.js';export{a as ModelPool}from'./chunk-MLCTC53I.js';export{a as FileHistory}from'./chunk-WI6FSWGU.js';import'./chunk-P6JSTIFM.js';import'./chunk-SNFAPSLA.js';export{a as MCPManager}from'./chunk-D3TVASD2.js';export{c as SettingsManager,a as SettingsSchema,b as validateSettings}from'./chunk-FZXY554D.js';import {p}from'./chunk-M7VU4YVY.js';export{e as COMPACTABLE_TOOL_NAMES,k as applySummaryCompaction,i as buildSummarizationPrompt,a as estimateTokens,f as microcompact,h as truncateToolResult,d as windowCompact}from'./chunk-M7VU4YVY.js';export{b as MemoryManager}from'./chunk-T222K6IV.js';export{b as SessionManager,a as Transcript}from'./chunk-QTWU7UNA.js';export{j as IterativeArena,f as defaultIterateConvergence,i as getIterateFormat,g as iterateCodeFormat,e as iterateDiffRatio,h as iterateDocumentFormat}from'./chunk-K4HILJ6G.js';export{J as Arena,I as ArenaLedger,e as DiscussionStrategy,S as MODEL_PRESETS,f as PlanningStrategy,d as ReviewStrategy,z as applyReviewResult,u as buildDigest,n as collectEvidence,b as createLLMClient,v as formatDigest,T as getMaxOutputTokens,k as getStrategy,l as getStrategyForPlan,p as hasTools,B as isTerminal,y as markUnderReview,A as markUnresolved,m as planArena,s as registerClaims,a as registerProvider,x as resolveClaimStatus,t as selectClaimsForReview,o as selectTools,w as transitionClaim,C as validTransitions}from'./chunk-WONQHE4P.js';import'./chunk-GKAQH2DG.js';export{a as AnthropicClient}from'./chunk-X2S7ASQ2.js';export{b as OpenAIClient}from'./chunk-SV7H4FKT.js';import'./chunk-O5HFCH2U.js';export{a as LLMClientBase}from'./chunk-OWBYLMDD.js';export{l as ConfigError,d as ContextLimitError,a as FrameworkError,b as LLMError,c as LLMRateLimitError,i as PermissionDeniedError,j as SessionError,e as ToolError,g as ToolExecutionError,f as ToolNotFoundError,h as ToolTimeoutError,k as TranscriptError}from'./chunk-FU7AHZNN.js';export{d as logger}from'./chunk-DI26OUIU.js';import {h,a}from'./chunk-3QP5BQ3L.js';h();p();h();var vt={review:[{patterns:[/\breview\b/i,/\baudit\b/i,/\binspect\b/i,/\bcheck\b/i],weight:2},{patterns:[/\bcode\s*quality\b/i,/\bbug\b/i,/\bvulnerab/i,/\bsecur/i]},{patterns:[/\bpr\b/i,/\bpull\s*request\b/i,/\bdiff\b/i,/\bchanges?\b/i]},{patterns:[/\brefactor/i,/\bclean\s*up\b/i,/\bimprove\b/i]}],discussion:[{patterns:[/\bdiscuss\b/i,/\bdebate\b/i,/\bcompare\b/i],weight:2},{patterns:[/\bpros?\s*(and|&|\/)\s*cons?\b/i,/\btrade\s*-?\s*offs?\b/i]},{patterns:[/\bshould\s+we\b/i,/\bwhich\s+(is|approach|way)\b/i,/\bvs\.?\b/i]},{patterns:[/\bopinion\b/i,/\bthoughts?\b/i,/\badvice\b/i]}],planning:[{patterns:[/\bplan\b/i,/\bplanning\b/i,/\broadmap\b/i,/\bstrategy\b/i],weight:2},{patterns:[/\barchitect/i,/\bdesign\b/i,/\bproposal\b/i]},{patterns:[/\bimplement(ation)?\s+(plan|strategy|approach)\b/i],weight:2},{patterns:[/\bphase\b/i,/\bmilestone\b/i,/\btimeline\b/i,/\bprioritiz/i]},{patterns:[/\bbuild\b/i,/\bcreate\b/i,/\bsetup\b/i,/\bbootstrap\b/i]}]},ht=3,Mt=2;function Pt(m){let a={review:0,discussion:0,planning:0};for(let[n,i]of Object.entries(vt))for(let p of i){let u=p.weight??1;for(let d of p.patterns)d.test(m)&&(a[n]+=u);}let s=Object.entries(a).sort((n,i)=>i[1]-n[1]),[t,e]=s[0],[,l]=s[1],r=e-l;return e>=ht&&r>=Mt?{mode:t,confidence:"high",reason:`Topic strongly matches "${t}" (score: ${e}, lead: +${r})`}:e>0&&r>0?{mode:t,confidence:"low",reason:`Topic weakly matches "${t}" (score: ${e}, lead: +${r})`}:{mode:"review",confidence:"low",reason:"No strong mode signal detected, defaulting to review"}}a(Pt,"detectArenaMode");var Dt="0.2.0";export{Dt as VERSION,Pt as detectArenaMode};
@@ -0,0 +1,22 @@
1
+ /**
2
+ * sanitizeApiKey — defensive cleanup for API keys pasted via the wizard.
3
+ *
4
+ * Windows terminals (ConPTY, legacy cmd.exe, IME-active states) are the main
5
+ * source of breakage: bracketed-paste residue, CR endings, zero-width chars
6
+ * pulled in from rich-text sources (Notion / OneNote / web pages), full-width
7
+ * spaces from CJK IME, smart quotes from word processors. None of these are
8
+ * valid in any real provider's API key, so we strip them and warn.
9
+ */
10
+ export type SanitizeResult = {
11
+ value: string;
12
+ changed: boolean;
13
+ warnings: string[];
14
+ };
15
+ export declare function sanitizeApiKey(raw: string): SanitizeResult;
16
+ /**
17
+ * Returns true when the sanitized key contains any non-ASCII-printable
18
+ * character. Real provider keys are uniformly ASCII (`[A-Za-z0-9_\-.]`-ish),
19
+ * so a stray non-ASCII char almost certainly means the user pasted the wrong
20
+ * thing (e.g. the surrounding sentence in Chinese).
21
+ */
22
+ export declare function hasNonAsciiPrintable(s: string): boolean;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Capability layer — single entry point.
3
+ *
4
+ * `capabilitiesFor(kind, model)` walks the rules in `rules.ts`, returns
5
+ * a `Capability` describing what params the (provider, model) pair will
6
+ * accept. Clients spread the result into their request-build code.
7
+ *
8
+ * Pure function. No I/O, no caching beyond the rules array.
9
+ */
10
+ import type { ProviderKindName } from "../provider-kinds.js";
11
+ import { type Capability } from "./types.js";
12
+ export { DEFAULT_CAPABILITY } from "./types.js";
13
+ export type { Capability, ReasoningShape, ReasoningEffort, ThinkingSwitch, EchoReasoning, ParallelToolCallsShape, StreamUsageShape, } from "./types.js";
14
+ /**
15
+ * Resolve the capability for a given (provider kind, model id).
16
+ *
17
+ * First matching rule for the kind wins — rules.ts is ordered so that
18
+ * more specific patterns come before catch-alls.
19
+ */
20
+ export declare function capabilitiesFor(kind: ProviderKindName, model: string): Capability;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Per-(provider kind, model family) capability overrides.
3
+ *
4
+ * Each rule patches the conservative DEFAULT_CAPABILITY. First match per
5
+ * kind wins — order matters for overlapping families.
6
+ *
7
+ * Authority for every entry is the vendor's own docs; the `why` field
8
+ * cites the specific page. When a model 400s on something not captured
9
+ * here, add a rule, don't patch the client.
10
+ *
11
+ * Sources audited 2026-05-15:
12
+ * OpenAI: https://platform.openai.com/docs/guides/reasoning
13
+ * https://learn.microsoft.com/en-us/azure/foundry/openai/how-to/reasoning
14
+ * Anthropic: https://platform.claude.com/docs/en/build-with-claude/extended-thinking
15
+ * DeepSeek: https://api-docs.deepseek.com/guides/reasoning_model
16
+ * https://api-docs.deepseek.com/guides/thinking_mode
17
+ * Z.AI: https://docs.z.ai/guides/llm/glm-4.6
18
+ * Gemini: https://ai.google.dev/gemini-api/docs/openai
19
+ * https://ai.google.dev/gemini-api/docs/thinking
20
+ * OpenRouter: https://openrouter.ai/docs/guides/best-practices/reasoning-tokens
21
+ * xAI: https://docs.x.ai/docs/guides/reasoning
22
+ * Mistral: https://docs.mistral.ai/api/
23
+ * Groq: https://console.groq.com/docs/reasoning
24
+ */
25
+ import type { CapabilityRule } from "./types.js";
26
+ export declare const RULES: ReadonlyArray<CapabilityRule>;
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Per-(provider, model) capability descriptor.
3
+ *
4
+ * Captures the subset of request-shape divergence we've actually observed
5
+ * cause HTTP 400s or behavior changes. Each rule in `rules.ts` produces
6
+ * one of these; clients spread it into the outgoing request.
7
+ *
8
+ * Sources for every field are documented next to the matching rule in
9
+ * `rules.ts` — vendor docs, not folklore.
10
+ */
11
+ import type { ProviderKindName } from "../provider-kinds.js";
12
+ /** OpenAI-style reasoning effort levels — shared by several vendors. */
13
+ export type ReasoningEffort = "minimal" | "low" | "medium" | "high";
14
+ /** A binary thinking switch, like DeepSeek V4 and Z.AI GLM use. */
15
+ export type ThinkingSwitch = "enabled" | "disabled";
16
+ /**
17
+ * How the vendor exposes a "think harder / think less" knob (or none).
18
+ * Each kind has different field names and value shapes — we keep them
19
+ * separate so the engine can't accidentally cross-pollinate.
20
+ */
21
+ export type ReasoningShape = {
22
+ kind: "none";
23
+ }
24
+ /** DeepSeek V4, Z.AI GLM-4.5+ — `{thinking: {type: "enabled"|"disabled"}}` at top level. */
25
+ | {
26
+ kind: "deepseek-thinking";
27
+ }
28
+ /**
29
+ * OpenAI o-series & gpt-5+ — `reasoning_effort: "minimal"|"low"|"medium"|"high"`.
30
+ * `disabledEffort` is the value we send when the caller asks for thinking
31
+ * "disabled" — defaults to `"minimal"` (OpenAI), but vendors with a
32
+ * narrower vocabulary override it (e.g. xAI Grok 4.3 has no `"minimal"`;
33
+ * Mistral Magistral only accepts `"high"` and `"none"`).
34
+ */
35
+ | {
36
+ kind: "openai-effort";
37
+ disabledEffort?: ReasoningEffort | "none";
38
+ }
39
+ /** Anthropic Claude 4.x ≤ 4.5 — `{thinking: {type: "enabled", budget_tokens: N}}`. */
40
+ | {
41
+ kind: "anthropic-budget";
42
+ minBudgetTokens: number;
43
+ }
44
+ /** Anthropic Claude 4.6+ — no opt-in, thinking is adaptive. Sending `type: "enabled"` 400s. */
45
+ | {
46
+ kind: "anthropic-adaptive";
47
+ }
48
+ /** OpenRouter normalized — `{reasoning: {effort, max_tokens, exclude, enabled}}`. */
49
+ | {
50
+ kind: "openrouter-reasoning";
51
+ };
52
+ /**
53
+ * How prior `reasoning_content` (or `thinking` blocks) must be threaded
54
+ * back into the next request.
55
+ */
56
+ export type EchoReasoning =
57
+ /** DeepSeek `deepseek-reasoner`: 400 if you echo it back at all. */
58
+ "never"
59
+ /** DeepSeek V4 + tools, Claude 4.x + tools: must echo or 400. */
60
+ | "when-tools"
61
+ /** Optional — echo if you have it, but absence is fine. */
62
+ | "optional";
63
+ /**
64
+ * Parallel-tool-call shape. OpenAI exposes `parallel_tool_calls: bool`.
65
+ * Anthropic exposes it inside `tool_choice.disable_parallel_tool_use`.
66
+ * Some endpoints don't support it at all.
67
+ */
68
+ export type ParallelToolCallsShape = "openai-flag" | "anthropic-disable-flag" | "unsupported";
69
+ /**
70
+ * Streaming usage signal. OpenAI-compat needs `stream_options:
71
+ * {include_usage: true}`; Anthropic always emits usage in
72
+ * `message_delta`; some endpoints reject the field.
73
+ */
74
+ export type StreamUsageShape = "include-usage-flag" | "auto" | "none";
75
+ export interface Capability {
76
+ /** Token-limit request field. */
77
+ tokenLimitField: "max_tokens" | "max_completion_tokens";
78
+ /**
79
+ * Request fields the model 400s on (or silently drops). We just don't
80
+ * send them. Names are in OpenAI-compat spelling; clients translate
81
+ * for native protocols.
82
+ */
83
+ rejectedParams: ReadonlySet<"temperature" | "top_p" | "presence_penalty" | "frequency_penalty" | "logit_bias" | "logprobs" | "top_logprobs">;
84
+ /** How thinking is exposed (or not). */
85
+ reasoning: ReasoningShape;
86
+ /** Echo-back contract for prior reasoning. */
87
+ echoReasoning: EchoReasoning;
88
+ /** Parallel-tool-calls flag shape. */
89
+ parallelToolCalls: ParallelToolCallsShape;
90
+ /** Streaming usage reporting shape. */
91
+ streamUsage: StreamUsageShape;
92
+ }
93
+ /**
94
+ * Conservative default — used when no rule matches. Picks "send everything
95
+ * the vanilla OpenAI Chat Completions spec accepts," because that's what
96
+ * every OpenAI-compat endpoint at minimum understands.
97
+ */
98
+ export declare const DEFAULT_CAPABILITY: Capability;
99
+ export interface CapabilityRule {
100
+ /** Which provider kind this rule applies to. */
101
+ kind: ProviderKindName;
102
+ /** Model-id matcher. First matching rule wins (per kind). */
103
+ match: RegExp;
104
+ /** Patch applied on top of DEFAULT_CAPABILITY. */
105
+ capability: Partial<Capability>;
106
+ /** Free-text reason — shown in logs, helps future-you. */
107
+ why: string;
108
+ }
@@ -29,6 +29,13 @@ export interface ModelEntry {
29
29
  /** Optional reference into ProviderCatalog. When set, baseUrl/apiKey
30
30
  * come from the catalog unless the entry overrides them. */
31
31
  providerKey?: string;
32
+ /**
33
+ * Per-model thinking override. Wins over the provider-level setting
34
+ * (ProviderCatalog entry's `thinking`). Useful when models in the same
35
+ * provider need different defaults — e.g. DeepSeek V4 Pro off but
36
+ * V4 Flash on.
37
+ */
38
+ thinking?: "enabled" | "disabled";
32
39
  }
33
40
  export declare class ModelPool {
34
41
  private models;
@@ -13,6 +13,8 @@ export interface ProviderConfig {
13
13
  apiKey?: string;
14
14
  protocol?: "openai-compat" | "anthropic-style";
15
15
  modelsPath?: string;
16
+ /** Default DeepSeek V4 thinking-mode for this provider. See LLMConfig. */
17
+ thinking?: "enabled" | "disabled";
16
18
  }
17
19
  export declare class ProviderCatalog {
18
20
  private byKey;