reasonix 0.5.20 → 0.5.21

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/index.d.ts CHANGED
@@ -97,6 +97,21 @@ interface ChatRequestOptions {
97
97
  responseFormat?: {
98
98
  type: "json_object" | "text";
99
99
  };
100
+ /**
101
+ * Explicitly toggle V4 thinking mode. Serialized as
102
+ * `extra_body.thinking.type = enabled|disabled`. Omit to let the
103
+ * server default apply (thinking enabled). Mainly used so the loop
104
+ * can pin the mode per model: `deepseek-chat` → disabled (legacy
105
+ * non-thinking compat), everything else → enabled.
106
+ */
107
+ thinking?: "enabled" | "disabled";
108
+ /**
109
+ * Per-request reasoning-effort cap. Serialized as the top-level
110
+ * `reasoning_effort` field. DeepSeek accepts `high` (standard) or
111
+ * `max` (Agent-class, auto-applied to Claude-Code-style flows per
112
+ * the V4 docs). Reasonix pins `max` because every turn is agent-like.
113
+ */
114
+ reasoningEffort?: "high" | "max";
100
115
  }
101
116
 
102
117
  declare class Usage {
@@ -848,6 +863,11 @@ interface CacheFirstLoopOptions {
848
863
  * since the default selector scores samples by plan-state uncertainty.
849
864
  */
850
865
  branch?: number | BranchOptions;
866
+ /**
867
+ * Reasoning-effort cap. See {@link ReconfigurableOptions} — default
868
+ * `max` for Reasonix (agent-class use per DeepSeek V4 docs).
869
+ */
870
+ reasoningEffort?: "high" | "max";
851
871
  /**
852
872
  * Session name. When set, the loop pre-loads the session's prior messages
853
873
  * into its log on construction, and appends every new log entry to
@@ -884,6 +904,14 @@ interface ReconfigurableOptions {
884
904
  harvest?: boolean | HarvestOptions;
885
905
  branch?: number | BranchOptions;
886
906
  stream?: boolean;
907
+ /**
908
+ * Reasoning-effort cap sent per turn (V4 thinking mode only;
909
+ * deepseek-chat ignores it). Reasonix pins `max` by default because
910
+ * DeepSeek's V4 docs flag Claude-Code-style agent loops as the
911
+ * canonical `max` use case. `/effort high` lets a user step down
912
+ * mid-session for cheaper, faster turns on simple tasks.
913
+ */
914
+ reasoningEffort?: "high" | "max";
887
915
  }
888
916
  declare class CacheFirstLoop {
889
917
  readonly client: DeepSeekClient;
@@ -900,6 +928,8 @@ declare class CacheFirstLoop {
900
928
  harvestOptions: HarvestOptions;
901
929
  branchEnabled: boolean;
902
930
  branchOptions: BranchOptions;
931
+ /** See ReconfigurableOptions — mutable so `/effort` can flip mid-session. */
932
+ reasoningEffort: "high" | "max";
903
933
  sessionName: string | null;
904
934
  /**
905
935
  * Hook list, mutable so `/hooks reload` can swap it without
@@ -1620,7 +1650,7 @@ interface SubagentToolOptions {
1620
1650
  defaultSystem?: string;
1621
1651
  /** Project root for `applyProjectMemory` lookup. Omit in chat mode. */
1622
1652
  projectRoot?: string;
1623
- /** Default model. `deepseek-chat` (V3) by default. */
1653
+ /** Default model. `deepseek-v4-pro` by default. */
1624
1654
  defaultModel?: string;
1625
1655
  /** Iteration ceiling. Lower than the parent (16 by default). */
1626
1656
  maxToolIters?: number;
package/dist/index.js CHANGED
@@ -131,6 +131,12 @@ var DeepSeekClient = class {
131
131
  if (opts.temperature !== void 0) payload.temperature = opts.temperature;
132
132
  if (opts.maxTokens !== void 0) payload.max_tokens = opts.maxTokens;
133
133
  if (opts.responseFormat) payload.response_format = opts.responseFormat;
134
+ if (opts.thinking) {
135
+ payload.extra_body = { thinking: { type: opts.thinking } };
136
+ }
137
+ if (opts.reasoningEffort) {
138
+ payload.reasoning_effort = opts.reasoningEffort;
139
+ }
134
140
  return payload;
135
141
  }
136
142
  /**
@@ -345,6 +351,13 @@ async function harvest(reasoningContent, client, options = {}, signal) {
345
351
  responseFormat: { type: "json_object" },
346
352
  temperature: 0,
347
353
  maxTokens: 600,
354
+ // Pin mode + effort so a future default-model swap (e.g. someone
355
+ // sets `options.model = "deepseek-v4-pro"`) can't accidentally
356
+ // turn this micro-extraction into a multi-thousand-reasoning-
357
+ // token call. DeepSeek ignores these on non-thinking models, so
358
+ // the request stays valid regardless of the chosen model.
359
+ thinking: "disabled",
360
+ reasoningEffort: "high",
348
361
  signal
349
362
  });
350
363
  return parsePlanState(resp.content, maxItems, maxItemLen);
@@ -1704,6 +1717,8 @@ var CacheFirstLoop = class {
1704
1717
  harvestOptions;
1705
1718
  branchEnabled;
1706
1719
  branchOptions;
1720
+ /** See ReconfigurableOptions — mutable so `/effort` can flip mid-session. */
1721
+ reasoningEffort;
1707
1722
  sessionName;
1708
1723
  /**
1709
1724
  * Hook list, mutable so `/hooks reload` can swap it without
@@ -1729,7 +1744,8 @@ var CacheFirstLoop = class {
1729
1744
  this.client = opts.client;
1730
1745
  this.prefix = opts.prefix;
1731
1746
  this.tools = opts.tools ?? new ToolRegistry();
1732
- this.model = opts.model ?? "deepseek-chat";
1747
+ this.model = opts.model ?? "deepseek-v4-pro";
1748
+ this.reasoningEffort = opts.reasoningEffort ?? "max";
1733
1749
  this.maxToolIters = opts.maxToolIters ?? 64;
1734
1750
  this.hooks = opts.hooks ?? [];
1735
1751
  this.hookCwd = opts.hookCwd ?? process.cwd();
@@ -1845,6 +1861,7 @@ var CacheFirstLoop = class {
1845
1861
  configure(opts) {
1846
1862
  if (opts.model !== void 0) this.model = opts.model;
1847
1863
  if (opts.stream !== void 0) this._streamPreference = opts.stream;
1864
+ if (opts.reasoningEffort !== void 0) this.reasoningEffort = opts.reasoningEffort;
1848
1865
  if (opts.branch !== void 0) {
1849
1866
  if (typeof opts.branch === "number") {
1850
1867
  this.branchOptions = { budget: opts.branch };
@@ -2023,7 +2040,9 @@ var CacheFirstLoop = class {
2023
2040
  model: this.model,
2024
2041
  messages,
2025
2042
  tools: toolSpecs.length ? toolSpecs : void 0,
2026
- signal
2043
+ signal,
2044
+ thinking: thinkingModeForModel(this.model),
2045
+ reasoningEffort: this.reasoningEffort
2027
2046
  },
2028
2047
  {
2029
2048
  ...this.branchOptions,
@@ -2075,7 +2094,9 @@ var CacheFirstLoop = class {
2075
2094
  model: this.model,
2076
2095
  messages,
2077
2096
  tools: toolSpecs.length ? toolSpecs : void 0,
2078
- signal
2097
+ signal,
2098
+ thinking: thinkingModeForModel(this.model),
2099
+ reasoningEffort: this.reasoningEffort
2079
2100
  })) {
2080
2101
  if (chunk.contentDelta) {
2081
2102
  assistantContent += chunk.contentDelta;
@@ -2129,7 +2150,9 @@ var CacheFirstLoop = class {
2129
2150
  model: this.model,
2130
2151
  messages,
2131
2152
  tools: toolSpecs.length ? toolSpecs : void 0,
2132
- signal
2153
+ signal,
2154
+ thinking: thinkingModeForModel(this.model),
2155
+ reasoningEffort: this.reasoningEffort
2133
2156
  });
2134
2157
  assistantContent = resp.content;
2135
2158
  reasoningContent = resp.reasoningContent ?? "";
@@ -2322,7 +2345,9 @@ ${reason}`;
2322
2345
  model: this.model,
2323
2346
  messages,
2324
2347
  // no tools → model is forced to answer in text
2325
- signal: this._turnAbort.signal
2348
+ signal: this._turnAbort.signal,
2349
+ thinking: thinkingModeForModel(this.model),
2350
+ reasoningEffort: this.reasoningEffort
2326
2351
  });
2327
2352
  const rawContent = resp.content?.trim() ?? "";
2328
2353
  const cleaned = stripHallucinatedToolMarkup(rawContent);
@@ -2390,6 +2415,12 @@ function isThinkingModeModel(model) {
2390
2415
  if (model === "deepseek-v4-flash" || model === "deepseek-v4-pro") return true;
2391
2416
  return false;
2392
2417
  }
2418
+ function thinkingModeForModel(model) {
2419
+ if (model === "deepseek-chat") return "disabled";
2420
+ if (model.includes("reasoner")) return "enabled";
2421
+ if (model === "deepseek-v4-flash" || model === "deepseek-v4-pro") return "enabled";
2422
+ return void 0;
2423
+ }
2393
2424
  function stripHallucinatedToolMarkup(s) {
2394
2425
  let out = s;
2395
2426
  out = out.replace(/<|DSML|function_calls>[\s\S]*?<\/?|DSML|function_calls>/g, "");
@@ -4003,7 +4034,7 @@ Formatting rules (the parent renders your reply in a TUI with a real markdown re
4003
4034
  - For flow charts and diagrams: use a markdown bullet list with \`\u2192\` or \`\u2193\` between steps. Don't try to draw boxes-and-arrows in ASCII; it never survives word-wrap.`;
4004
4035
  var DEFAULT_MAX_RESULT_CHARS2 = 8e3;
4005
4036
  var DEFAULT_MAX_ITERS = 16;
4006
- var DEFAULT_SUBAGENT_MODEL = "deepseek-chat";
4037
+ var DEFAULT_SUBAGENT_MODEL = "deepseek-v4-pro";
4007
4038
  var SUBAGENT_TOOL_NAME = "spawn_subagent";
4008
4039
  var NEVER_INHERITED_TOOLS = /* @__PURE__ */ new Set([SUBAGENT_TOOL_NAME, "submit_plan"]);
4009
4040
  async function spawnSubagent(opts) {
@@ -4156,7 +4187,7 @@ function registerSubagentTool(parentRegistry, opts) {
4156
4187
  model: {
4157
4188
  type: "string",
4158
4189
  enum: ["deepseek-v4-flash", "deepseek-v4-pro", "deepseek-chat", "deepseek-reasoner"],
4159
- description: "Which DeepSeek model the subagent runs on. 'deepseek-v4-flash' (default; thinking mode) is fast and cheap and is what the legacy 'deepseek-chat' / 'deepseek-reasoner' aliases route to today. Use 'deepseek-v4-pro' only when the subtask needs the strongest model \u2014 roughly 12\xD7 the input cost and 12\xD7 the output cost vs flash."
4190
+ description: "Which DeepSeek model the subagent runs on. Default is 'deepseek-v4-pro' \u2014 the strongest model, best for complex subtasks. Override to 'deepseek-v4-flash' (or the legacy 'deepseek-chat' / 'deepseek-reasoner' aliases, which route to flash non-thinking / thinking modes) when the subtask is simple enough that flash's quality suffices \u2014 flash is roughly 12\xD7 cheaper."
4160
4191
  }
4161
4192
  },
4162
4193
  required: ["task"]