micro-models-agent 0.54.1 → 0.55.1

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 (232) hide show
  1. package/README.md +358 -358
  2. package/dist/certification/certifications.json +493 -493
  3. package/dist/main.js +489 -82
  4. package/dist/modules/browser/bridge-server.mjs +202 -202
  5. package/dist/skills/builtin/git.md +36 -36
  6. package/dist/skills/builtin/typescript.md +35 -35
  7. package/package.json +1 -1
  8. package/dist/cli/commands.js +0 -447
  9. package/dist/cli/completer.js +0 -167
  10. package/dist/cli/index.js +0 -2
  11. package/dist/cli/main.js +0 -153
  12. package/dist/cli/plugin-commands.js +0 -36
  13. package/dist/cli/repl-commands.js +0 -761
  14. package/dist/cli/repl.js +0 -702
  15. package/dist/cli/run-result.js +0 -33
  16. package/dist/cli/security-commands.js +0 -164
  17. package/dist/cli/setup.js +0 -237
  18. package/dist/config/config.js +0 -276
  19. package/dist/config/defaults.js +0 -141
  20. package/dist/config/domains.js +0 -179
  21. package/dist/config/experts.js +0 -15
  22. package/dist/config/index.js +0 -4
  23. package/dist/config/security.js +0 -213
  24. package/dist/config/types.js +0 -1
  25. package/dist/core/agent-moe.js +0 -102
  26. package/dist/core/agent.js +0 -1018
  27. package/dist/core/bootstrap.js +0 -481
  28. package/dist/core/crash-handler.js +0 -51
  29. package/dist/core/environment.js +0 -199
  30. package/dist/core/index.js +0 -2
  31. package/dist/core/prompt-builder.js +0 -76
  32. package/dist/core/session-logger.js +0 -251
  33. package/dist/core/types.js +0 -1
  34. package/dist/core/version.js +0 -26
  35. package/dist/core/workspace.js +0 -76
  36. package/dist/i18n/en.json +0 -679
  37. package/dist/i18n/index.js +0 -46
  38. package/dist/i18n/ru.json +0 -679
  39. package/dist/index.js +0 -22
  40. package/dist/llm/image-utils.js +0 -143
  41. package/dist/llm/index.js +0 -4
  42. package/dist/llm/model-loader.js +0 -78
  43. package/dist/llm/openai-compat.js +0 -497
  44. package/dist/llm/orchestrator.js +0 -200
  45. package/dist/llm/provider.js +0 -10
  46. package/dist/llm/response.js +0 -39
  47. package/dist/llm/token-counter.js +0 -39
  48. package/dist/llm/types.js +0 -1
  49. package/dist/logger/app-logger.js +0 -189
  50. package/dist/logger/file-log.js +0 -151
  51. package/dist/logger/index.js +0 -1
  52. package/dist/migration/backup.js +0 -45
  53. package/dist/migration/detect.js +0 -50
  54. package/dist/migration/index.js +0 -2
  55. package/dist/modules/artifacts/store.js +0 -61
  56. package/dist/modules/browser/actions.js +0 -76
  57. package/dist/modules/browser/bridge-client.js +0 -199
  58. package/dist/modules/browser/bridge-path.js +0 -10
  59. package/dist/modules/browser/cookie-store.js +0 -24
  60. package/dist/modules/browser/driver.js +0 -136
  61. package/dist/modules/browser/index.js +0 -7
  62. package/dist/modules/browser/module.js +0 -29
  63. package/dist/modules/browser/session.js +0 -342
  64. package/dist/modules/browser/snapshot.js +0 -148
  65. package/dist/modules/browser/types.js +0 -12
  66. package/dist/modules/certification/cli.js +0 -213
  67. package/dist/modules/certification/fact-checker.js +0 -82
  68. package/dist/modules/certification/loader.js +0 -106
  69. package/dist/modules/certification/manifest.js +0 -58
  70. package/dist/modules/certification/runner.js +0 -245
  71. package/dist/modules/certification/scenarios.js +0 -407
  72. package/dist/modules/certification/types.js +0 -1
  73. package/dist/modules/context/chunk-query.js +0 -100
  74. package/dist/modules/context/fact-extractor.js +0 -168
  75. package/dist/modules/context/history.js +0 -15
  76. package/dist/modules/context/index.js +0 -1
  77. package/dist/modules/context/manager.js +0 -440
  78. package/dist/modules/execution/audit-runners.js +0 -206
  79. package/dist/modules/execution/auditor.js +0 -218
  80. package/dist/modules/execution/execution-plugin.js +0 -431
  81. package/dist/modules/execution/index.js +0 -8
  82. package/dist/modules/execution/module.js +0 -625
  83. package/dist/modules/execution/moe-executor.js +0 -304
  84. package/dist/modules/execution/plan-coverage.js +0 -68
  85. package/dist/modules/execution/plan-persister.js +0 -46
  86. package/dist/modules/execution/plan-store.js +0 -196
  87. package/dist/modules/execution/plan-tool.js +0 -677
  88. package/dist/modules/execution/plan-validator.js +0 -153
  89. package/dist/modules/execution/planner.js +0 -94
  90. package/dist/modules/execution/stuck-detector.js +0 -746
  91. package/dist/modules/execution/tracker.js +0 -69
  92. package/dist/modules/execution/types.js +0 -1
  93. package/dist/modules/execution/verifier.js +0 -235
  94. package/dist/modules/execution/windows-commands.js +0 -41
  95. package/dist/modules/hallucination/confidence.js +0 -66
  96. package/dist/modules/hallucination/consistency.js +0 -26
  97. package/dist/modules/hallucination/detector.js +0 -47
  98. package/dist/modules/hallucination/factual.js +0 -169
  99. package/dist/modules/hallucination/index.js +0 -5
  100. package/dist/modules/hallucination/js-identifiers.js +0 -262
  101. package/dist/modules/hallucination/llm-judge.js +0 -101
  102. package/dist/modules/index.js +0 -5
  103. package/dist/modules/indexer/cache.js +0 -40
  104. package/dist/modules/indexer/index.js +0 -3
  105. package/dist/modules/indexer/module.js +0 -246
  106. package/dist/modules/indexer/project-profile.js +0 -183
  107. package/dist/modules/indexer/walker.js +0 -101
  108. package/dist/modules/lsp/check-tool.js +0 -58
  109. package/dist/modules/lsp/client.js +0 -389
  110. package/dist/modules/lsp/command.js +0 -60
  111. package/dist/modules/lsp/config.js +0 -135
  112. package/dist/modules/lsp/index.js +0 -3
  113. package/dist/modules/lsp/module.js +0 -260
  114. package/dist/modules/lsp/probe.js +0 -86
  115. package/dist/modules/lsp/project-root.js +0 -32
  116. package/dist/modules/lsp/startup-check.js +0 -144
  117. package/dist/modules/lsp/types.js +0 -1
  118. package/dist/modules/mcp/client.js +0 -399
  119. package/dist/modules/mcp/index.js +0 -3
  120. package/dist/modules/mcp/module.js +0 -142
  121. package/dist/modules/mcp/registry.js +0 -15
  122. package/dist/modules/memory/index.js +0 -1
  123. package/dist/modules/memory/module.js +0 -96
  124. package/dist/modules/memory/search.js +0 -42
  125. package/dist/modules/memory/store.js +0 -69
  126. package/dist/modules/pipelines/engine.js +0 -60
  127. package/dist/modules/pipelines/index.js +0 -3
  128. package/dist/modules/pipelines/parser.js +0 -56
  129. package/dist/modules/pipelines/template.js +0 -14
  130. package/dist/modules/plugins/builtin/lint-on-write.js +0 -334
  131. package/dist/modules/plugins/builtin/notify.js +0 -9
  132. package/dist/modules/plugins/index.js +0 -1
  133. package/dist/modules/plugins/loader.js +0 -70
  134. package/dist/modules/plugins/manager.js +0 -261
  135. package/dist/modules/plugins/types.js +0 -1
  136. package/dist/modules/pricing/index.js +0 -61
  137. package/dist/modules/pricing/prices.js +0 -129
  138. package/dist/modules/processes/detect.js +0 -34
  139. package/dist/modules/processes/index.js +0 -2
  140. package/dist/modules/processes/registry.js +0 -327
  141. package/dist/modules/processes/runner.js +0 -23
  142. package/dist/modules/providers/create.js +0 -22
  143. package/dist/modules/providers/fallback.js +0 -79
  144. package/dist/modules/providers/health.js +0 -46
  145. package/dist/modules/providers/index.js +0 -5
  146. package/dist/modules/providers/manager.js +0 -161
  147. package/dist/modules/providers/presets.js +0 -128
  148. package/dist/modules/providers/registry.js +0 -22
  149. package/dist/modules/providers/types.js +0 -1
  150. package/dist/modules/registry.js +0 -48
  151. package/dist/modules/security/audit-log.js +0 -136
  152. package/dist/modules/security/audit-notifier.js +0 -292
  153. package/dist/modules/security/command-validator.js +0 -219
  154. package/dist/modules/security/content-scanner.js +0 -53
  155. package/dist/modules/security/data-sanitizer.js +0 -89
  156. package/dist/modules/security/encryption.js +0 -242
  157. package/dist/modules/security/index.js +0 -14
  158. package/dist/modules/security/network-validator.js +0 -88
  159. package/dist/modules/security/path-validator.js +0 -203
  160. package/dist/modules/security/rate-limiter.js +0 -119
  161. package/dist/modules/security/security-policies.js +0 -531
  162. package/dist/modules/security/session-encryption.js +0 -210
  163. package/dist/modules/security/session-isolation.js +0 -95
  164. package/dist/modules/session/index.js +0 -3
  165. package/dist/modules/session/manager.js +0 -172
  166. package/dist/modules/session/module.js +0 -24
  167. package/dist/modules/session/store.js +0 -222
  168. package/dist/modules/session/types.js +0 -1
  169. package/dist/modules/skills/index.js +0 -2
  170. package/dist/modules/skills/loader.js +0 -72
  171. package/dist/modules/skills/matcher.js +0 -27
  172. package/dist/modules/skills/module.js +0 -129
  173. package/dist/modules/types.js +0 -1
  174. package/dist/modules/updater/checker.js +0 -96
  175. package/dist/modules/updater/index.js +0 -2
  176. package/dist/modules/updater/module.js +0 -116
  177. package/dist/modules/user-profile/compressor.js +0 -16
  178. package/dist/modules/user-profile/index.js +0 -1
  179. package/dist/modules/user-profile/profile.js +0 -68
  180. package/dist/tools/approve.js +0 -33
  181. package/dist/tools/attach-image.js +0 -101
  182. package/dist/tools/bash.js +0 -519
  183. package/dist/tools/browser.js +0 -115
  184. package/dist/tools/chunk-query.js +0 -100
  185. package/dist/tools/create-dir.js +0 -56
  186. package/dist/tools/delete-file.js +0 -63
  187. package/dist/tools/download-file.js +0 -117
  188. package/dist/tools/edit-file.js +0 -80
  189. package/dist/tools/enable-tools.js +0 -59
  190. package/dist/tools/executor.js +0 -154
  191. package/dist/tools/file-info.js +0 -47
  192. package/dist/tools/filter-tools.js +0 -17
  193. package/dist/tools/glob-tool.js +0 -27
  194. package/dist/tools/grep-tool.js +0 -125
  195. package/dist/tools/hidden-tools-block.js +0 -37
  196. package/dist/tools/index.js +0 -78
  197. package/dist/tools/list-dir.js +0 -49
  198. package/dist/tools/load-skill.js +0 -43
  199. package/dist/tools/mcp-call.js +0 -69
  200. package/dist/tools/move-file.js +0 -86
  201. package/dist/tools/path-utils.js +0 -101
  202. package/dist/tools/pipeline-run.js +0 -145
  203. package/dist/tools/preview.js +0 -2
  204. package/dist/tools/process-kill.js +0 -40
  205. package/dist/tools/process-list.js +0 -37
  206. package/dist/tools/process-log.js +0 -54
  207. package/dist/tools/question.js +0 -141
  208. package/dist/tools/read-file.js +0 -179
  209. package/dist/tools/recall.js +0 -118
  210. package/dist/tools/registry.js +0 -47
  211. package/dist/tools/remember.js +0 -68
  212. package/dist/tools/scope-check.js +0 -32
  213. package/dist/tools/search-history.js +0 -85
  214. package/dist/tools/subagent.js +0 -196
  215. package/dist/tools/types.js +0 -1
  216. package/dist/tools/user-input.js +0 -123
  217. package/dist/tools/web-browse.js +0 -87
  218. package/dist/tools/web-fetch.js +0 -119
  219. package/dist/tools/web-search.js +0 -105
  220. package/dist/tools/write-file.js +0 -82
  221. package/dist/ui/box.js +0 -77
  222. package/dist/ui/colors.js +0 -4
  223. package/dist/ui/diff.js +0 -178
  224. package/dist/ui/index.js +0 -6
  225. package/dist/ui/line-editor.js +0 -822
  226. package/dist/ui/line-math.js +0 -73
  227. package/dist/ui/md-formatter.js +0 -212
  228. package/dist/ui/output.js +0 -13
  229. package/dist/ui/plan-view.js +0 -103
  230. package/dist/ui/renderer.js +0 -259
  231. package/dist/ui/spinner.js +0 -70
  232. package/dist/ui/table.js +0 -144
package/dist/main.js CHANGED
@@ -2356,6 +2356,12 @@ var init_defaults = __esm(() => {
2356
2356
  checkOnStart: true,
2357
2357
  autoInstall: true,
2358
2358
  intervalMs: 0
2359
+ },
2360
+ reasoning: {
2361
+ mode: "auto",
2362
+ min: "low",
2363
+ max: "high",
2364
+ overrideCooldown: 5
2359
2365
  }
2360
2366
  };
2361
2367
  });
@@ -2416,6 +2422,7 @@ The path was joined onto the working directory because it does not exist as give
2416
2422
  "error.llm_stream_idle_toolcall": 'LLM stream stalled after a tool_call started — no data for {timeout}ms. The provider most likely buffers SSE instead of streaming tool-call argument deltas (seen with LM Studio). Raise "retry.noDataTimeoutMs" in ~/.mma/config.json (restart required)',
2417
2423
  "error.llm_truncated": 'Response hit the completion token limit ({tokens}) and was cut off before any content arrived. Split the task into smaller outputs or raise "maxCompletionTokens" in the config',
2418
2424
  "error.llm_truncated_toolcall": 'Response hit the completion token limit ({tokens}) in the middle of a tool_call — its arguments were cut off. Write the file in smaller chunks (several write_file/edit_file calls) or raise "maxCompletionTokens" in the config',
2425
+ "error.llm_provider_stream_error": "Provider returned an error mid-stream: {error}",
2419
2426
  "error.llm_timeout": "LLM request timed out ({timeout}ms)",
2420
2427
  "env.runtime_node": "Running under Node (v{version}) — clipboard image paste, subagent performance and LSP spawn on Windows degrade. Install Bun (https://bun.sh) for full features.",
2421
2428
  "env.runtime_old": "Runtime version {version} is below the required engines {engine}.",
@@ -2708,6 +2715,7 @@ Available commands:`,
2708
2715
  "cli.no_agents_md": "Disable loading AGENTS.md files into system prompt",
2709
2716
  "cli.dir": "Working directory for the agent (defaults to current directory)",
2710
2717
  "cli.exit_on_complete": "Exit immediately when the task is done; interactive tools (question/approve) fail fast instead of blocking on stdin",
2718
+ "cli.reasoning_level": "Set reasoning effort level (auto|none|low|medium|high|max)",
2711
2719
  "cli.json": "Output the result as JSON (single-run mode)",
2712
2720
  "cli.security.description": "Manage security settings",
2713
2721
  "cli.security.status": "Show current security configuration",
@@ -2766,7 +2774,9 @@ Available commands:`,
2766
2774
  "repl.config": "Show current configuration",
2767
2775
  "repl.config_usage": "Usage: /config",
2768
2776
  "repl.reasoning": "Toggle showing model reasoning/thinking",
2769
- "repl.reasoning_usage": "Usage: /reasoning",
2777
+ "repl.reasoning_usage": "Usage: /reasoning [auto|none|low|medium|high|max]",
2778
+ "repl.reasoning_level_set": "Reasoning level set to: {level}",
2779
+ "repl.reasoning_invalid_level": "Invalid level '{level}'. Valid: {valid}",
2770
2780
  "repl.status": "Show agent status",
2771
2781
  "repl.status_usage": "Usage: /status",
2772
2782
  "repl.plugins": "List loaded plugins",
@@ -3067,6 +3077,15 @@ Apply a matching solution from these results. If none is relevant — do NOT rep
3067
3077
  "tools.enable_added": "Enabled tool tags: {tags}. Available tools now: {tools}",
3068
3078
  "tools.hidden_header": "Additional tools (enable on demand via enable_tools or route to subagent tool_tags):",
3069
3079
  "tool.friendly.enable_tools": "Enable tools",
3080
+ "tool.friendly.set_thinking": "Set reasoning level",
3081
+ "tool.thinking_set": "Reasoning level: {level} ({reason})",
3082
+ "tool.thinking_set_clamped": "Reasoning level: {level} (clamped from request, {reason})",
3083
+ "tool.thinking_cooldown": "Reasoning override deferred ({remaining} iterations until available). Current: {current}",
3084
+ "tool.thinking_invalid_level": "Invalid reasoning level: {level}. Use: none, low, high, max",
3085
+ "reasoning.probe_failed": "Reasoning effort mechanism not supported by this backend. Dynamic control disabled.",
3086
+ "reasoning.mode_set": "Reasoning mode: {mode}",
3087
+ "reasoning.current": "Reasoning: {level} ({mode})",
3088
+ "reasoning.invalid_mode": "Invalid reasoning mode: {mode}. Use: auto, default, none, low, medium, high, max",
3070
3089
  "cli.provider_base_hint": "Base URL set to: {baseUrl}",
3071
3090
  "cli.add_provider": "Add a provider to the config",
3072
3091
  "cli.provider_no_url": 'No base URL for provider "{name}". Pass --url.',
@@ -3148,6 +3167,7 @@ var init_ru = __esm(() => {
3148
3167
  "error.llm_stream_idle_toolcall": 'Поток LLM завис после начала tool_call — нет данных {timeout}мс. Скорее всего провайдер буферизирует SSE вместо потоковой передачи аргументов tool_call (наблюдается в LM Studio). Увеличьте "retry.noDataTimeoutMs" в ~/.mma/config.json (нужен рестарт)',
3149
3168
  "error.llm_truncated": 'Ответ упёрся в лимит токенов генерации ({tokens}) и был обрезан до какого-либо содержимого. Разбейте задачу на меньшие порции вывода или увеличьте "maxCompletionTokens" в конфиге',
3150
3169
  "error.llm_truncated_toolcall": 'Ответ упёрся в лимит токенов генерации ({tokens}) посреди tool_call — его аргументы обрезаны. Пишите файл частями (несколько вызовов write_file/edit_file) или увеличьте "maxCompletionTokens" в конфиге',
3170
+ "error.llm_provider_stream_error": "Провайдер вернул ошибку посреди стрима: {error}",
3151
3171
  "error.llm_timeout": "Время запроса LLM истекло ({timeout}мс)",
3152
3172
  "env.runtime_node": "Запущено под Node (v{version}) — вставка изображений из буфера и LSP на Windows работают урезанно. Установите Bun (https://bun.sh) для полного функционала.",
3153
3173
  "env.runtime_old": "Версия рантайма {version} ниже требуемой engines {engine}.",
@@ -3435,6 +3455,7 @@ var init_ru = __esm(() => {
3435
3455
  "cli.no_agents_md": "Отключить загрузку AGENTS.md в системный промпт",
3436
3456
  "cli.dir": "Рабочая директория агента (по умолчанию — текущая)",
3437
3457
  "cli.exit_on_complete": "Завершить сразу после выполнения задачи; интерактивные тулзы (question/approve) не блокируют stdin, а возвращают ошибку",
3458
+ "cli.reasoning_level": "Установить уровень рассуждений (auto|none|low|medium|high|max)",
3438
3459
  "cli.json": "Вывести результат в формате JSON (режим однократного запуска)",
3439
3460
  "cli.security.description": "Управление настройками безопасности",
3440
3461
  "cli.security.status": "Показать текущую конфигурацию безопасности",
@@ -3493,7 +3514,9 @@ var init_ru = __esm(() => {
3493
3514
  "repl.config": "Показать текущую конфигурацию",
3494
3515
  "repl.config_usage": "Использование: /config",
3495
3516
  "repl.reasoning": "Переключить показ рассуждений модели",
3496
- "repl.reasoning_usage": "Использование: /reasoning",
3517
+ "repl.reasoning_usage": "Использование: /reasoning [auto|none|low|medium|high|max]",
3518
+ "repl.reasoning_level_set": "Уровень рассуждений установлен: {level}",
3519
+ "repl.reasoning_invalid_level": "Неверный уровень '{level}'. Допустимые: {valid}",
3497
3520
  "repl.status": "Показать статус агента",
3498
3521
  "repl.status_usage": "Использование: /status",
3499
3522
  "repl.plugins": "Список загруженных плагинов",
@@ -3801,6 +3824,15 @@ var init_ru = __esm(() => {
3801
3824
  "tools.enable_added": "Включены теги тулов: {tags}. Теперь доступны тулы: {tools}",
3802
3825
  "tools.hidden_header": "Дополнительные тулы (включите по требованию через enable_tools или маршрутизируйте через subagent tool_tags):",
3803
3826
  "tool.friendly.enable_tools": "Включить тулы",
3827
+ "tool.friendly.set_thinking": "Уровень рассуждений",
3828
+ "tool.thinking_set": "Уровень рассуждений: {level} ({reason})",
3829
+ "tool.thinking_set_clamped": "Уровень рассуждений: {level} (ограничен конфигом, {reason})",
3830
+ "tool.thinking_cooldown": "Override отложен ({remaining} итераций до доступа). Текущий: {current}",
3831
+ "tool.thinking_invalid_level": "Неверный уровень рассуждений: {level}. Допустимые: none, low, high, max",
3832
+ "reasoning.probe_failed": "Бэкенд не поддерживает управление reasoning effort. Динамическое управление отключено.",
3833
+ "reasoning.mode_set": "Режим рассуждений: {mode}",
3834
+ "reasoning.current": "Рассуждения: {level} ({mode})",
3835
+ "reasoning.invalid_mode": "Неверный режим рассуждений: {mode}. Допустимые: auto, default, none, low, medium, high, max",
3804
3836
  "cli.provider_base_hint": "Базовый URL установлен: {baseUrl}",
3805
3837
  "cli.add_provider": "Добавить провайдера в конфиг",
3806
3838
  "cli.provider_no_url": 'Нет базового URL для провайдера "{name}". Укажите --url.',
@@ -4293,7 +4325,8 @@ var init_domains = __esm(() => {
4293
4325
  "autoPlan",
4294
4326
  "showReasoning",
4295
4327
  "logLevel",
4296
- "locale"
4328
+ "locale",
4329
+ "reasoning"
4297
4330
  ],
4298
4331
  provider: ["provider", "orchestrator", "retry", "pricing"],
4299
4332
  moe: ["moe", "experts"],
@@ -5507,8 +5540,14 @@ function buildRequestBody(opts) {
5507
5540
  };
5508
5541
  if (opts.maxTokens !== undefined)
5509
5542
  body.max_tokens = opts.maxTokens;
5510
- if (opts.reasoningEffort) {
5511
- body.reasoning_effort = opts.reasoningEffort;
5543
+ const strategy = opts.reasoningStrategy ?? "openai-effort";
5544
+ const level = opts.reasoningEffort;
5545
+ if (strategy === "openai-effort" && level && level !== "default") {
5546
+ body.reasoning_effort = level;
5547
+ } else if (strategy === "template-kwarg") {
5548
+ body.chat_template_kwargs = { enable_thinking: level !== "none" };
5549
+ } else if (strategy === "prompt-tag" && level && level !== "default") {
5550
+ body.reasoning_effort = level;
5512
5551
  }
5513
5552
  if (opts.tools && opts.tools.length > 0) {
5514
5553
  body.tools = opts.tools.map((t2) => ({
@@ -5531,6 +5570,7 @@ class OpenAICompatProvider {
5531
5570
  tokenCounter;
5532
5571
  retryConfig;
5533
5572
  rateLimiter;
5573
+ debug;
5534
5574
  constructor(config) {
5535
5575
  this.config = config;
5536
5576
  this.model = config.model;
@@ -5544,13 +5584,18 @@ class OpenAICompatProvider {
5544
5584
  noDataTimeoutMs: 180000
5545
5585
  };
5546
5586
  this.rateLimiter = createRateLimiter(config.rateLimits);
5587
+ this.debug = config.logger ? config.logger.debug.bind(config.logger) : null;
5547
5588
  }
5548
5589
  async* chat(messages, tools, signal, options) {
5549
5590
  if (!this.rateLimiter.canMakeRequest()) {
5550
5591
  throw new Error(`Rate limit exceeded: ${this.rateLimiter.getConfig().maxRequestsPerMinute} requests per minute`);
5551
5592
  }
5552
5593
  this.rateLimiter.recordRequest();
5553
- const streamResult = this.doStream(messages, tools, signal, options);
5594
+ let effectiveMessages = messages;
5595
+ if (options?.reasoningStrategy === "prompt-tag" && options?.reasoningEffort === "none") {
5596
+ effectiveMessages = this.applyPromptTag(messages, "/no_think");
5597
+ }
5598
+ const streamResult = this.doStream(effectiveMessages, tools, signal, options);
5554
5599
  let hasToolCall = false;
5555
5600
  let hasText = false;
5556
5601
  for await (const chunk of streamResult) {
@@ -5561,12 +5606,31 @@ class OpenAICompatProvider {
5561
5606
  yield chunk;
5562
5607
  }
5563
5608
  if (!hasToolCall && !hasText) {
5564
- const fallback = await this.doNonStreaming(messages, tools, signal, options);
5609
+ this.debug?.("LLM streaming produced no text/tool_call falling back to non-streaming");
5610
+ const fallback = await this.doNonStreaming(effectiveMessages, tools, signal, options);
5611
+ this.debug?.("LLM non-streaming fallback result", { chunks: fallback.length });
5565
5612
  for (const chunk of fallback) {
5566
5613
  yield chunk;
5567
5614
  }
5568
5615
  }
5569
5616
  }
5617
+ applyPromptTag(messages, tag) {
5618
+ const copy = [...messages];
5619
+ for (let i = copy.length - 1;i >= 0; i--) {
5620
+ if (copy[i].role === "user") {
5621
+ const msg = { ...copy[i] };
5622
+ if (typeof msg.content === "string") {
5623
+ msg.content = msg.content + `
5624
+ ` + tag;
5625
+ } else {
5626
+ msg.content = [...msg.content, { type: "text", text: tag }];
5627
+ }
5628
+ copy[i] = msg;
5629
+ break;
5630
+ }
5631
+ }
5632
+ return copy;
5633
+ }
5570
5634
  async* doStream(messages, tools, signal, options) {
5571
5635
  const { baseDelay, maxDelay, maxStreamRetries, noDataTimeoutMs } = this.retryConfig;
5572
5636
  const streamRetries = maxStreamRetries ?? 2;
@@ -5601,7 +5665,18 @@ class OpenAICompatProvider {
5601
5665
  tools,
5602
5666
  stream: true,
5603
5667
  maxTokens,
5604
- reasoningEffort: options?.reasoningEffort
5668
+ reasoningEffort: options?.reasoningEffort,
5669
+ reasoningStrategy: options?.reasoningStrategy
5670
+ });
5671
+ this.debug?.("LLM stream request", {
5672
+ baseUrl: this.config.baseUrl,
5673
+ model: this.model,
5674
+ stream: true,
5675
+ maxTokens,
5676
+ toolsCount: tools?.length ?? 0,
5677
+ reasoningEffort: options?.reasoningEffort,
5678
+ reasoningStrategy: options?.reasoningStrategy,
5679
+ messagesCount: messages.length
5605
5680
  });
5606
5681
  const { headers, abortSignal, cleanup, isTimeout, flagTimeout, controller } = this.buildRequestSetup(signal);
5607
5682
  let response;
@@ -5630,6 +5705,11 @@ class OpenAICompatProvider {
5630
5705
  err.llmTerminal = true;
5631
5706
  throw err;
5632
5707
  }
5708
+ const contentType = response.headers?.get?.("content-type") ?? "";
5709
+ this.debug?.("LLM stream response headers", {
5710
+ status: response.status,
5711
+ contentType
5712
+ });
5633
5713
  const reader = response.body?.getReader();
5634
5714
  if (!reader) {
5635
5715
  cleanup();
@@ -5639,6 +5719,10 @@ class OpenAICompatProvider {
5639
5719
  let buffer = "";
5640
5720
  const toolCallAccs = new Map;
5641
5721
  let sawToolCallStart = false;
5722
+ let nonDataLines = 0;
5723
+ const nonDataSamples = [];
5724
+ let parsedChunks = 0;
5725
+ let midStreamError = null;
5642
5726
  let usage;
5643
5727
  let sawDone = false;
5644
5728
  let lastFinishReason;
@@ -5673,15 +5757,24 @@ class OpenAICompatProvider {
5673
5757
  buffer = lines.pop() || "";
5674
5758
  for (const line of lines) {
5675
5759
  const trimmed = line.trim();
5676
- if (!trimmed || !trimmed.startsWith("data: "))
5677
- continue;
5678
- const data = trimmed.slice(6);
5679
- if (data === "[DONE]") {
5680
- sawDone = true;
5760
+ if (!trimmed)
5681
5761
  continue;
5762
+ let data;
5763
+ if (trimmed.startsWith("data: ")) {
5764
+ data = trimmed.slice(6);
5765
+ if (data === "[DONE]") {
5766
+ sawDone = true;
5767
+ continue;
5768
+ }
5769
+ } else {
5770
+ nonDataLines++;
5771
+ if (nonDataSamples.length < 5)
5772
+ nonDataSamples.push(trimmed.slice(0, 200));
5773
+ data = trimmed;
5682
5774
  }
5683
5775
  try {
5684
5776
  const parsed = JSON.parse(data);
5777
+ parsedChunks++;
5685
5778
  const choice = parsed.choices?.[0];
5686
5779
  if (!choice) {
5687
5780
  if (parsed.usage) {
@@ -5690,56 +5783,71 @@ class OpenAICompatProvider {
5690
5783
  completionTokens: parsed.usage.completion_tokens ?? 0,
5691
5784
  totalTokens: parsed.usage.total_tokens ?? 0
5692
5785
  };
5786
+ this.debug?.("LLM stream usage", { ...usage });
5787
+ } else if (parsed.error) {
5788
+ midStreamError = String(parsed.error);
5693
5789
  }
5694
- continue;
5695
- }
5696
- const delta = choice.delta || {};
5697
- const finishReason = choice.finish_reason;
5698
- if (finishReason)
5699
- lastFinishReason = finishReason;
5700
- if (delta.reasoning_content) {
5701
- onEmit();
5702
- yield { type: "reasoning", content: delta.reasoning_content };
5703
- }
5704
- if (delta.tool_calls) {
5705
- sawToolCallStart = true;
5706
- for (const tc of delta.tool_calls) {
5707
- const idx = tc.index ?? 0;
5708
- if (!toolCallAccs.has(idx)) {
5709
- toolCallAccs.set(idx, { id: "", name: "", arguments: "" });
5710
- }
5711
- const acc = toolCallAccs.get(idx);
5712
- if (tc.id)
5713
- acc.id = tc.id;
5714
- if (tc.function?.name)
5715
- acc.name = tc.function.name;
5716
- if (tc.function?.arguments) {
5717
- acc.arguments += tc.function.arguments;
5790
+ } else {
5791
+ if (parsedChunks <= 3 || parsedChunks % 50 === 0) {
5792
+ const d = choice.delta ?? {};
5793
+ this.debug?.("LLM stream chunk", {
5794
+ n: parsedChunks,
5795
+ finishReason: choice.finish_reason ?? null,
5796
+ deltaKeys: Object.keys(d)
5797
+ });
5798
+ }
5799
+ const delta = choice.delta || {};
5800
+ const finishReason = choice.finish_reason;
5801
+ if (finishReason)
5802
+ lastFinishReason = finishReason;
5803
+ const reasoningDelta = delta.reasoning_content ?? delta.reasoning;
5804
+ if (reasoningDelta) {
5805
+ onEmit();
5806
+ yield { type: "reasoning", content: reasoningDelta };
5807
+ }
5808
+ if (delta.tool_calls) {
5809
+ sawToolCallStart = true;
5810
+ for (const tc of delta.tool_calls) {
5811
+ const idx = tc.index ?? 0;
5812
+ if (!toolCallAccs.has(idx)) {
5813
+ toolCallAccs.set(idx, { id: "", name: "", arguments: "" });
5814
+ }
5815
+ const acc = toolCallAccs.get(idx);
5816
+ if (tc.id)
5817
+ acc.id = tc.id;
5818
+ if (tc.function?.name)
5819
+ acc.name = tc.function.name;
5820
+ if (tc.function?.arguments) {
5821
+ acc.arguments += tc.function.arguments;
5822
+ }
5718
5823
  }
5719
5824
  }
5720
- }
5721
- if (delta.content) {
5722
- onEmit();
5723
- sawText = true;
5724
- yield { type: "text", content: delta.content };
5725
- }
5726
- if (finishReason === "tool_calls" && toolCallAccs.size > 0) {
5727
- for (const [, acc] of toolCallAccs) {
5728
- if (acc.name) {
5729
- onEmit();
5730
- yield {
5731
- type: "tool_call",
5732
- toolCall: {
5733
- id: acc.id,
5734
- name: acc.name,
5735
- arguments: acc.arguments || "{}"
5736
- }
5737
- };
5825
+ if (delta.content) {
5826
+ onEmit();
5827
+ sawText = true;
5828
+ yield { type: "text", content: delta.content };
5829
+ }
5830
+ if (finishReason === "tool_calls" && toolCallAccs.size > 0) {
5831
+ for (const [, acc] of toolCallAccs) {
5832
+ if (acc.name) {
5833
+ onEmit();
5834
+ yield {
5835
+ type: "tool_call",
5836
+ toolCall: {
5837
+ id: acc.id,
5838
+ name: acc.name,
5839
+ arguments: acc.arguments || "{}"
5840
+ }
5841
+ };
5842
+ }
5738
5843
  }
5844
+ toolCallAccs.clear();
5739
5845
  }
5740
- toolCallAccs.clear();
5741
5846
  }
5742
5847
  } catch {}
5848
+ if (midStreamError) {
5849
+ throw new Error(t("error.llm_provider_stream_error", { error: midStreamError.slice(0, 300) }));
5850
+ }
5743
5851
  }
5744
5852
  }
5745
5853
  if (usage) {
@@ -5760,6 +5868,15 @@ class OpenAICompatProvider {
5760
5868
  } finally {
5761
5869
  cleanup();
5762
5870
  reader.releaseLock();
5871
+ this.debug?.("LLM stream finished", {
5872
+ sawDone,
5873
+ lastFinishReason: lastFinishReason ?? null,
5874
+ sawText,
5875
+ sawToolCallStart,
5876
+ parsedChunks,
5877
+ nonDataLines,
5878
+ nonDataSamples: nonDataLines > 0 ? nonDataSamples : undefined
5879
+ });
5763
5880
  }
5764
5881
  return sawDone;
5765
5882
  }
@@ -5806,7 +5923,8 @@ class OpenAICompatProvider {
5806
5923
  tools,
5807
5924
  stream: false,
5808
5925
  maxTokens: options?.maxTokens ?? this.config.maxCompletionTokens ?? 4096,
5809
- reasoningEffort: options?.reasoningEffort
5926
+ reasoningEffort: options?.reasoningEffort,
5927
+ reasoningStrategy: options?.reasoningStrategy
5810
5928
  });
5811
5929
  const { headers, abortSignal, cleanup, isTimeout } = this.buildRequestSetup(signal);
5812
5930
  try {
@@ -5825,14 +5943,18 @@ class OpenAICompatProvider {
5825
5943
  }));
5826
5944
  }
5827
5945
  const data = await response.json();
5946
+ if (data.error && !data.choices) {
5947
+ throw new Error(t("error.llm_provider_stream_error", { error: String(data.error).slice(0, 300) }));
5948
+ }
5828
5949
  const choice = data.choices?.[0];
5829
5950
  if (!choice) {
5830
5951
  return [];
5831
5952
  }
5832
5953
  const msg = choice.message || {};
5833
5954
  const chunks = [];
5834
- if (msg.reasoning_content) {
5835
- chunks.push({ type: "reasoning", content: msg.reasoning_content });
5955
+ const reasoning = msg.reasoning_content ?? msg.reasoning;
5956
+ if (reasoning) {
5957
+ chunks.push({ type: "reasoning", content: reasoning });
5836
5958
  }
5837
5959
  if (msg.content) {
5838
5960
  chunks.push({ type: "text", content: msg.content });
@@ -5976,7 +6098,8 @@ function openaiCompat(opts) {
5976
6098
  contextWindow: opts.contextWindow,
5977
6099
  retry,
5978
6100
  rateLimits,
5979
- maxCompletionTokens: opts.maxCompletionTokens
6101
+ maxCompletionTokens: opts.maxCompletionTokens,
6102
+ logger: opts.logger
5980
6103
  });
5981
6104
  }
5982
6105
  var OPENAI_COMPAT, OPENROUTER, OPENAI, ANTHROPIC, OPENCODE_ZEN, OPENCODE_GO, BUILTIN_PROVIDERS, HOSTED_BASE_URLS;
@@ -5990,7 +6113,7 @@ var init_presets = __esm(() => {
5990
6113
  streaming: true,
5991
6114
  tools: true,
5992
6115
  vision: false,
5993
- reasoningEffort: false,
6116
+ reasoningStrategy: "prompt-tag",
5994
6117
  listModels: true,
5995
6118
  requiresKey: false,
5996
6119
  auth: "bearer"
@@ -6005,7 +6128,7 @@ var init_presets = __esm(() => {
6005
6128
  streaming: true,
6006
6129
  tools: true,
6007
6130
  vision: true,
6008
- reasoningEffort: false,
6131
+ reasoningStrategy: "openai-effort",
6009
6132
  listModels: true,
6010
6133
  requiresKey: true,
6011
6134
  auth: "bearer"
@@ -6020,7 +6143,7 @@ var init_presets = __esm(() => {
6020
6143
  streaming: true,
6021
6144
  tools: true,
6022
6145
  vision: true,
6023
- reasoningEffort: true,
6146
+ reasoningStrategy: "openai-effort",
6024
6147
  listModels: true,
6025
6148
  requiresKey: true,
6026
6149
  auth: "bearer"
@@ -6035,7 +6158,7 @@ var init_presets = __esm(() => {
6035
6158
  streaming: false,
6036
6159
  tools: false,
6037
6160
  vision: true,
6038
- reasoningEffort: false,
6161
+ reasoningStrategy: "none",
6039
6162
  listModels: false,
6040
6163
  requiresKey: true,
6041
6164
  auth: "header"
@@ -6050,7 +6173,7 @@ var init_presets = __esm(() => {
6050
6173
  streaming: true,
6051
6174
  tools: true,
6052
6175
  vision: false,
6053
- reasoningEffort: false,
6176
+ reasoningStrategy: "openai-effort",
6054
6177
  listModels: true,
6055
6178
  requiresKey: false,
6056
6179
  auth: "bearer"
@@ -6065,7 +6188,7 @@ var init_presets = __esm(() => {
6065
6188
  streaming: true,
6066
6189
  tools: true,
6067
6190
  vision: false,
6068
- reasoningEffort: false,
6191
+ reasoningStrategy: "openai-effort",
6069
6192
  listModels: true,
6070
6193
  requiresKey: false,
6071
6194
  auth: "bearer"
@@ -6230,7 +6353,8 @@ class ProviderManager {
6230
6353
  contextWindow: entry.contextWindow ?? this.opts.contextWindow,
6231
6354
  retry: entry.retry ?? this.opts.retry,
6232
6355
  rateLimits: entry.rateLimits ?? this.opts.rateLimits,
6233
- maxCompletionTokens: entry.maxCompletionTokens
6356
+ maxCompletionTokens: entry.maxCompletionTokens,
6357
+ logger: this.opts.logger
6234
6358
  }, this.registry);
6235
6359
  this.cache.set(key, provider);
6236
6360
  return provider;
@@ -6562,6 +6686,8 @@ class ToolExecutor {
6562
6686
  const timeoutPromise = new Promise((_, reject) => {
6563
6687
  setTimeout(() => {
6564
6688
  killByCallId(call.id);
6689
+ this.ctx.cleanup?.();
6690
+ this.ctx.cleanup = undefined;
6565
6691
  reject(new Error(t("tool.timeout", {
6566
6692
  name: call.name,
6567
6693
  seconds: Math.round(timeoutMs / 1000)
@@ -6576,6 +6702,8 @@ class ToolExecutor {
6576
6702
  const abortPromise = new Promise((_, reject) => {
6577
6703
  const onAbort = () => {
6578
6704
  killByCallId(call.id);
6705
+ this.ctx.cleanup?.();
6706
+ this.ctx.cleanup = undefined;
6579
6707
  reject(new Error(t("tool.aborted", { name: call.name })));
6580
6708
  };
6581
6709
  if (signal.aborted) {
@@ -9544,6 +9672,18 @@ class SessionLogger {
9544
9672
  skills: data.skills
9545
9673
  });
9546
9674
  }
9675
+ logReasoningControl(data) {
9676
+ this.session?.appendLog({
9677
+ ts: new Date().toISOString(),
9678
+ type: "reasoning_control",
9679
+ content: `reasoning level: ${data.level} (source: ${data.source ?? "policy"})`,
9680
+ iteration: data.iteration,
9681
+ level: data.level,
9682
+ strategy: data.strategy,
9683
+ probePassed: data.probePassed,
9684
+ source: data.source
9685
+ });
9686
+ }
9547
9687
  }
9548
9688
  var init_session_logger = __esm(() => {
9549
9689
  init_audit_log();
@@ -12651,6 +12791,42 @@ var init_pricing = __esm(() => {
12651
12791
  init_prices();
12652
12792
  });
12653
12793
 
12794
+ // src/modules/reasoning/policy.ts
12795
+ function createPolicyState() {
12796
+ return { iterationsSinceRaise: 0, boostRemaining: 0 };
12797
+ }
12798
+ function evaluateReasoningPolicy(input, state) {
12799
+ if (input.hallucinationRetry || input.auditRejection || input.recoverableLlmError) {
12800
+ state.iterationsSinceRaise = 0;
12801
+ return { level: "high", reason: input.hallucinationRetry ? "policy:hallucination-retry" : input.auditRejection ? "policy:audit-rejection" : "policy:recoverable-llm-error" };
12802
+ }
12803
+ if (input.planCreated) {
12804
+ state.boostRemaining = 3;
12805
+ state.iterationsSinceRaise = 0;
12806
+ return { level: "high", reason: "policy:plan-created" };
12807
+ }
12808
+ if (state.boostRemaining > 0) {
12809
+ state.boostRemaining--;
12810
+ state.iterationsSinceRaise = 0;
12811
+ return { level: "high", reason: "policy:plan-boost" };
12812
+ }
12813
+ if (input.consecutiveSuccesses >= 2) {
12814
+ state.iterationsSinceRaise++;
12815
+ return { level: "low", reason: "policy:routine-write" };
12816
+ }
12817
+ if (input.isRepetitive) {
12818
+ state.iterationsSinceRaise++;
12819
+ return { level: "low", reason: "policy:repetitive-tools" };
12820
+ }
12821
+ if (state.iterationsSinceRaise >= DECAY_THRESHOLD) {
12822
+ state.iterationsSinceRaise = 0;
12823
+ return { level: input.baseline, reason: "policy:decay" };
12824
+ }
12825
+ state.iterationsSinceRaise++;
12826
+ return { level: input.baseline, reason: "policy:default" };
12827
+ }
12828
+ var DECAY_THRESHOLD = 5;
12829
+
12654
12830
  // src/core/agent.ts
12655
12831
  function isToolCallJson(text) {
12656
12832
  const trimmed = text.trim();
@@ -12678,13 +12854,28 @@ class Agent {
12678
12854
  abortController = null;
12679
12855
  lastCompactionShown = 0;
12680
12856
  costTracker;
12857
+ policyState;
12858
+ reasoningState;
12859
+ _currentIteration = 0;
12681
12860
  constructor(deps) {
12682
12861
  this.deps = deps;
12683
12862
  this.costTracker = new CostTracker(deps.config.model, deps.config.pricing);
12863
+ this.policyState = createPolicyState();
12864
+ const initialLevel = (deps.config.reasoning?.mode !== "auto" ? deps.config.reasoning?.mode : undefined) ?? "medium";
12865
+ this.reasoningState = { level: initialLevel, overrideIteration: -100 };
12684
12866
  }
12685
12867
  get contextManager() {
12686
12868
  return this.deps.contextManager;
12687
12869
  }
12870
+ get reasoningLevel() {
12871
+ return this.reasoningState.level;
12872
+ }
12873
+ setReasoningLevel(level) {
12874
+ this.reasoningState.level = level;
12875
+ }
12876
+ get currentIteration() {
12877
+ return this._currentIteration;
12878
+ }
12688
12879
  callerProvenance() {
12689
12880
  return {
12690
12881
  provider: this.deps.config.provider?.type || "unknown",
@@ -12912,13 +13103,22 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
12912
13103
  let repeatedToolCount = 0;
12913
13104
  const MAX_REPEATED_TOOL_CALLS = 2;
12914
13105
  let llmErrorRetries = 0;
13106
+ let iterHallucinationRetry = false;
13107
+ let iterAuditRejection = false;
13108
+ let iterRecoverableLlmError = false;
13109
+ let iterPlanCreated = false;
12915
13110
  let allToolsForBudget = toolExecutor.getToolDefinitions(this.deps.toolTags);
12916
13111
  let boundedToolNames = new Set(allToolsForBudget.filter((t2) => t2.boundedOutput).map((t2) => t2.name));
12917
13112
  let toolTokenEstimate = allToolsForBudget.reduce((sum, t2) => sum + Math.ceil((t2.description.length + JSON.stringify(t2.parameters).length) / 4), 0);
12918
13113
  contextManager.setToolTokens(toolTokenEstimate);
12919
13114
  while (iteration < config.maxToolIterations && !this.shutdownRequested) {
12920
13115
  iteration++;
13116
+ this._currentIteration = iteration;
12921
13117
  contextManager.noteIteration();
13118
+ iterHallucinationRetry = false;
13119
+ iterAuditRejection = false;
13120
+ iterRecoverableLlmError = false;
13121
+ iterPlanCreated = false;
12922
13122
  allToolsForBudget = toolExecutor.getToolDefinitions(this.deps.toolTags);
12923
13123
  boundedToolNames = new Set(allToolsForBudget.filter((t2) => t2.boundedOutput).map((t2) => t2.name));
12924
13124
  toolTokenEstimate = allToolsForBudget.reduce((sum, t2) => sum + Math.ceil((t2.description.length + JSON.stringify(t2.parameters).length) / 4), 0);
@@ -12989,8 +13189,35 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
12989
13189
  const promptBefore = apiPromptTokens;
12990
13190
  const completionBefore = apiCompletionTokens;
12991
13191
  logger.logLLMRequest(config.model, history.length, input, "agent");
13192
+ const reasoningConfig = config.reasoning;
13193
+ let effectiveReasoningLevel;
13194
+ let reasoningStrategy = this.deps.reasoningStrategy;
13195
+ if (reasoningConfig && reasoningConfig.mode === "auto" && this.deps.reasoningProbePassed) {
13196
+ const policyResult = evaluateReasoningPolicy({
13197
+ hallucinationRetry: iterHallucinationRetry,
13198
+ auditRejection: iterAuditRejection,
13199
+ recoverableLlmError: iterRecoverableLlmError,
13200
+ planCreated: iterPlanCreated,
13201
+ consecutiveSuccesses: 0,
13202
+ isRepetitive: false,
13203
+ baseline: "medium"
13204
+ }, this.policyState);
13205
+ effectiveReasoningLevel = policyResult.level;
13206
+ } else if (reasoningConfig && reasoningConfig.mode !== "auto") {
13207
+ effectiveReasoningLevel = reasoningConfig.mode;
13208
+ }
13209
+ if (effectiveReasoningLevel) {
13210
+ slog.logReasoningControl({
13211
+ iteration,
13212
+ level: effectiveReasoningLevel,
13213
+ strategy: reasoningStrategy,
13214
+ probePassed: this.deps.reasoningProbePassed,
13215
+ source: this.reasoningState.overrideIteration === iteration ? "agent_override" : "policy"
13216
+ });
13217
+ contextManager.thinkingLevel = effectiveReasoningLevel;
13218
+ }
12992
13219
  try {
12993
- for await (const chunk of llmProvider.chat(history, allToolsForBudget, this.abortController?.signal)) {
13220
+ for await (const chunk of llmProvider.chat(history, allToolsForBudget, this.abortController?.signal, effectiveReasoningLevel ? { reasoningEffort: effectiveReasoningLevel, reasoningStrategy } : undefined)) {
12994
13221
  if (this.shutdownRequested)
12995
13222
  break;
12996
13223
  if (chunk.type === "text" && chunk.content) {
@@ -13037,6 +13264,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
13037
13264
  break;
13038
13265
  }
13039
13266
  if (err?.recoverableLlm && llmErrorRetries < MAX_LLM_ERROR_RETRIES) {
13267
+ iterRecoverableLlmError = true;
13040
13268
  llmErrorRetries++;
13041
13269
  logger.warn(`Recoverable LLM error, feeding back (${llmErrorRetries}/${MAX_LLM_ERROR_RETRIES}): ${err.message}`);
13042
13270
  slog.logError(err.message);
@@ -13313,6 +13541,7 @@ ${warnLine}
13313
13541
  }
13314
13542
  }
13315
13543
  if (hallucinationResult.status === "retry") {
13544
+ iterHallucinationRetry = true;
13316
13545
  if (this.deps.exitOnComplete && textContent?.trim() && !this.deps.finalAudit) {
13317
13546
  logger.debug("Exit-on-complete: stopping on first response");
13318
13547
  lastText = textContent;
@@ -13391,6 +13620,7 @@ ${warnLine}
13391
13620
  if (this.deps.finalAudit) {
13392
13621
  const audit = await this.deps.finalAudit();
13393
13622
  if (audit && !audit.passed) {
13623
+ iterAuditRejection = true;
13394
13624
  logger.warn(`Final audit incomplete: ${audit.summary}`);
13395
13625
  const steps = audit.pendingSteps.slice(0, 5).join("; ") || "—";
13396
13626
  contextManager.addMessage({
@@ -13478,7 +13708,8 @@ ${warnLine}
13478
13708
  const manager = new ProviderManager(this.deps.config.provider, {
13479
13709
  contextWindow: this.deps.config.contextWindow,
13480
13710
  retry: this.deps.config.retry,
13481
- rateLimits: this.deps.config.security?.rateLimits
13711
+ rateLimits: this.deps.config.security?.rateLimits,
13712
+ logger: this.deps.logger
13482
13713
  });
13483
13714
  manager.switch(name, model);
13484
13715
  const providerCfg = manager.toConfig();
@@ -13504,7 +13735,8 @@ ${warnLine}
13504
13735
  const manager = new ProviderManager(this.deps.config.provider, {
13505
13736
  contextWindow: this.deps.config.contextWindow,
13506
13737
  retry: this.deps.config.retry,
13507
- rateLimits: this.deps.config.security?.rateLimits
13738
+ rateLimits: this.deps.config.security?.rateLimits,
13739
+ logger: this.deps.logger
13508
13740
  });
13509
13741
  manager.setModel(this.deps.config.model);
13510
13742
  manager.switch(name);
@@ -13746,6 +13978,7 @@ class ContextManager {
13746
13978
  tokenCounter;
13747
13979
  pendingImageParts = [];
13748
13980
  toolTokens = 0;
13981
+ thinkingLevel = null;
13749
13982
  onCompact = null;
13750
13983
  planSummaryProvider = null;
13751
13984
  constructor(contextWindow, contextBudget, tokenCounter) {
@@ -13939,6 +14172,8 @@ class ContextManager {
13939
14172
  const errorsLine = this.facts.errorsLine();
13940
14173
  if (errorsLine)
13941
14174
  parts.push(errorsLine);
14175
+ if (this.thinkingLevel)
14176
+ parts.push(`[Thinking: ${this.thinkingLevel}]`);
13942
14177
  const triedAndFailed = extractTriedAndFailed(oldTurns);
13943
14178
  if (triedAndFailed.length > 0) {
13944
14179
  const lines = triedAndFailed.map((t2) => `- ${t2.tool}(${t2.args}): ${t2.error} (failed ${t2.count}x)`);
@@ -14759,6 +14994,7 @@ var init_subagent = __esm(() => {
14759
14994
  icon: "\uD83E\uDD16",
14760
14995
  description: "Spawn an isolated sub-agent to work on a task independently. The sub-agent has its own context and executes autonomously. Use for parallel work or complex sub-tasks.",
14761
14996
  tags: ["code"],
14997
+ timeoutMs: 180000,
14762
14998
  parameters: {
14763
14999
  type: "object",
14764
15000
  properties: {
@@ -14851,6 +15087,7 @@ var init_subagent = __esm(() => {
14851
15087
  const hallucinationDetector = new HallucinationDetector(ctx.baseDir, ctx.llmProvider);
14852
15088
  const parentScope = ctx.scope;
14853
15089
  ctx.toolExecutor.setScope(scope || { allowed_files: [], read_only_files: [] });
15090
+ ctx.cleanup = () => ctx.toolExecutor?.setScope(parentScope);
14854
15091
  const systemPrompt = {
14855
15092
  content: buildSubagentSystemPrompt(context, ctx.config.subagent?.stableSystemPrompt !== false),
14856
15093
  priority: "critical",
@@ -14912,6 +15149,7 @@ Iterations: ${result.iterationCount}`
14912
15149
  };
14913
15150
  } finally {
14914
15151
  ctx.toolExecutor.setScope(parentScope);
15152
+ ctx.cleanup = undefined;
14915
15153
  }
14916
15154
  } catch (e) {
14917
15155
  return { success: false, output: `Sub-agent error: ${e.message}` };
@@ -15091,7 +15329,7 @@ var init_chunk_query = __esm(() => {
15091
15329
  },
15092
15330
  reasoning_effort: {
15093
15331
  type: "string",
15094
- enum: ["none", "low", "medium", "high"],
15332
+ enum: ["none", "low", "medium", "high", "max"],
15095
15333
  description: 'Reasoning effort for chunk/synthesis calls (default "none"). "none" prevents long thinking chains from eating the token budget on reasoning models.'
15096
15334
  },
15097
15335
  synthesize: {
@@ -15131,7 +15369,7 @@ var init_chunk_query = __esm(() => {
15131
15369
  synthesize: typeof args.synthesize === "boolean" ? args.synthesize : undefined,
15132
15370
  maxChunkTokens: typeof args.max_chunk_tokens === "number" ? args.max_chunk_tokens : undefined,
15133
15371
  maxSynthesisTokens: typeof args.max_synthesis_tokens === "number" ? args.max_synthesis_tokens : undefined,
15134
- reasoningEffort: ["none", "low", "medium", "high"].includes(args.reasoning_effort) ? args.reasoning_effort : undefined,
15372
+ reasoningEffort: ["none", "low", "medium", "high", "max"].includes(args.reasoning_effort) ? args.reasoning_effort : undefined,
15135
15373
  logger: ctx.logger
15136
15374
  });
15137
15375
  ctx.logger.debug(`chunk_query: ${res.chunks} chunk(s), ${res.totalChars} chars, max parallel ${res.maxParallelObserved}`);
@@ -23341,6 +23579,126 @@ function syncGlobalManifest(override, bundledPathOverride) {
23341
23579
  var certKey = (e) => `${e.model}::${e.providerUrl}`;
23342
23580
  var init_manifest = () => {};
23343
23581
 
23582
+ // src/modules/reasoning/probe.ts
23583
+ var exports_probe = {};
23584
+ __export(exports_probe, {
23585
+ setCachedProbeResult: () => setCachedProbeResult,
23586
+ resetProbeCache: () => resetProbeCache,
23587
+ probeReasoningSupport: () => probeReasoningSupport,
23588
+ getCachedProbeResult: () => getCachedProbeResult,
23589
+ cacheKey: () => cacheKey
23590
+ });
23591
+ async function probeReasoningSupport(provider, strategy, signal) {
23592
+ if (strategy === "none")
23593
+ return false;
23594
+ try {
23595
+ let hasReasoning = false;
23596
+ for await (const chunk of provider.chat(PROBE_MESSAGES, undefined, signal, {
23597
+ maxTokens: 32,
23598
+ reasoningEffort: "none",
23599
+ reasoningStrategy: strategy
23600
+ })) {
23601
+ if (chunk.type === "reasoning")
23602
+ hasReasoning = true;
23603
+ }
23604
+ return !hasReasoning;
23605
+ } catch {
23606
+ return false;
23607
+ }
23608
+ }
23609
+ function cacheKey(baseUrl, model) {
23610
+ return `${baseUrl}|${model}`;
23611
+ }
23612
+ function getCachedProbeResult(key) {
23613
+ return probeCache.get(key);
23614
+ }
23615
+ function setCachedProbeResult(key, result) {
23616
+ probeCache.set(key, result);
23617
+ }
23618
+ function resetProbeCache() {
23619
+ probeCache.clear();
23620
+ }
23621
+ var PROBE_MESSAGES, probeCache;
23622
+ var init_probe = __esm(() => {
23623
+ PROBE_MESSAGES = [
23624
+ { role: "user", content: "Reply with exactly: ok" }
23625
+ ];
23626
+ probeCache = new Map;
23627
+ });
23628
+
23629
+ // src/tools/set-thinking.ts
23630
+ var exports_set_thinking = {};
23631
+ __export(exports_set_thinking, {
23632
+ createSetThinkingTool: () => createSetThinkingTool
23633
+ });
23634
+ function createSetThinkingTool(state, config, getCurrentIteration) {
23635
+ return {
23636
+ name: "set_thinking",
23637
+ description: "Set reasoning effort level for the next LLM call. Normally managed automatically by the harness. Use only to force deeper thinking for genuinely hard subproblems or shallower for mechanical batches.",
23638
+ icon: "\uD83E\uDDE0",
23639
+ tags: [],
23640
+ alwaysOn: true,
23641
+ parameters: {
23642
+ type: "object",
23643
+ properties: {
23644
+ level: {
23645
+ type: "string",
23646
+ enum: ["none", "low", "high", "max"],
23647
+ description: "Reasoning effort level to set"
23648
+ },
23649
+ reason: {
23650
+ type: "string",
23651
+ description: "Why changing the level"
23652
+ }
23653
+ },
23654
+ required: ["level"]
23655
+ },
23656
+ handler: async (_ctx, args) => {
23657
+ const requested = args.level;
23658
+ const reason = args.reason || "agent override";
23659
+ if (!VALID_LEVELS.includes(requested) && requested !== "auto") {
23660
+ return {
23661
+ success: false,
23662
+ output: t("tool.thinking_invalid_level", { level: requested })
23663
+ };
23664
+ }
23665
+ const currentIter = getCurrentIteration();
23666
+ const elapsed = currentIter - state.overrideIteration;
23667
+ if (elapsed > 0 && elapsed < config.overrideCooldown) {
23668
+ return {
23669
+ success: true,
23670
+ output: t("tool.thinking_cooldown", {
23671
+ remaining: config.overrideCooldown - elapsed,
23672
+ current: state.level
23673
+ })
23674
+ };
23675
+ }
23676
+ let level = requested;
23677
+ const levelOrder = ["none", "low", "medium", "high", "max"];
23678
+ const minIdx = levelOrder.indexOf(config.min);
23679
+ const maxIdx = levelOrder.indexOf(config.max);
23680
+ const reqIdx = levelOrder.indexOf(level);
23681
+ let clamped = false;
23682
+ if (reqIdx >= 0 && reqIdx < minIdx) {
23683
+ level = config.min;
23684
+ clamped = true;
23685
+ } else if (reqIdx > maxIdx) {
23686
+ level = config.max;
23687
+ clamped = true;
23688
+ }
23689
+ state.level = level;
23690
+ state.overrideIteration = currentIter;
23691
+ const msg = clamped ? t("tool.thinking_set_clamped", { level, reason }) : t("tool.thinking_set", { level, reason });
23692
+ return { success: true, output: msg };
23693
+ }
23694
+ };
23695
+ }
23696
+ var VALID_LEVELS;
23697
+ var init_set_thinking = __esm(() => {
23698
+ init_i18n();
23699
+ VALID_LEVELS = ["default", "none", "low", "medium", "high", "max"];
23700
+ });
23701
+
23344
23702
  // src/core/bootstrap.ts
23345
23703
  var exports_bootstrap = {};
23346
23704
  __export(exports_bootstrap, {
@@ -23401,11 +23759,17 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
23401
23759
  return lines.join(`
23402
23760
  `);
23403
23761
  }
23404
- async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
23762
+ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reasoningLevel) {
23405
23763
  const dir = configDir || process.env.MMA_CONFIG_DIR || join41(homedir14(), ".mma");
23406
23764
  const projectConfigPath = projectDir ? join41(projectDir, ".mmrc") : join41(process.cwd(), ".mmrc");
23407
23765
  const { config, legacyDetected } = loadConfig({ configDir: dir, projectConfigPath });
23408
23766
  setLocale(config.locale);
23767
+ if (reasoningLevel && reasoningLevel !== "auto") {
23768
+ if (!config.reasoning)
23769
+ config.reasoning = { mode: reasoningLevel, min: "low", max: "high", overrideCooldown: 3 };
23770
+ else
23771
+ config.reasoning.mode = reasoningLevel;
23772
+ }
23409
23773
  try {
23410
23774
  const { globalAuditNotifier: globalAuditNotifier2 } = await Promise.resolve().then(() => (init_audit_notifier(), exports_audit_notifier));
23411
23775
  if (config.security?.auditNotifier) {
@@ -23448,7 +23812,8 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
23448
23812
  const providerManager = new ProviderManager(config.provider, {
23449
23813
  contextWindow: config.contextWindow,
23450
23814
  retry: config.retry,
23451
- rateLimits: config.security?.rateLimits
23815
+ rateLimits: config.security?.rateLimits,
23816
+ logger
23452
23817
  });
23453
23818
  providerManager.setModel(config.model);
23454
23819
  let llmProvider = providerManager.active;
@@ -23457,6 +23822,29 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
23457
23822
  logger.warn(`provider failover: ${from} -> ${to} (${error.message.slice(0, 120)})`);
23458
23823
  });
23459
23824
  }
23825
+ const providerSpec = BUILTIN_PROVIDERS.find((p) => p.type === config.provider.type);
23826
+ const reasoningStrategy = providerSpec?.capabilities.reasoningStrategy ?? "none";
23827
+ let reasoningProbePassed = false;
23828
+ if (config.reasoning && config.reasoning.mode !== "none" && reasoningStrategy !== "none") {
23829
+ try {
23830
+ const { probeReasoningSupport: probeReasoningSupport2, getCachedProbeResult: getCachedProbeResult2, setCachedProbeResult: setCachedProbeResult2 } = await Promise.resolve().then(() => (init_probe(), exports_probe));
23831
+ const cacheK = `${config.provider.baseUrl ?? ""}|${config.model}`;
23832
+ const cached = getCachedProbeResult2(cacheK);
23833
+ if (cached !== undefined) {
23834
+ reasoningProbePassed = cached;
23835
+ } else {
23836
+ reasoningProbePassed = await probeReasoningSupport2(llmProvider, reasoningStrategy);
23837
+ setCachedProbeResult2(cacheK, reasoningProbePassed);
23838
+ }
23839
+ if (reasoningProbePassed) {
23840
+ logger.info(`Reasoning probe: strategy=${reasoningStrategy} → mechanism respected`);
23841
+ } else {
23842
+ logger.info(`Reasoning probe: strategy=${reasoningStrategy} → mechanism IGNORED`);
23843
+ }
23844
+ } catch {
23845
+ reasoningProbePassed = false;
23846
+ }
23847
+ }
23460
23848
  const baseDir = projectDir ? resolve23(projectDir) : process.cwd();
23461
23849
  const envReport = collectEnvironment({
23462
23850
  configDir: dir,
@@ -23723,9 +24111,16 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
23723
24111
  sessionManager,
23724
24112
  memoryStore,
23725
24113
  moduleRegistry,
23726
- exitOnComplete
24114
+ exitOnComplete,
24115
+ reasoningProbePassed,
24116
+ reasoningStrategy
23727
24117
  };
23728
24118
  const agent = new Agent(agentDeps);
24119
+ if (config.reasoning) {
24120
+ const { createSetThinkingTool: createSetThinkingTool2 } = await Promise.resolve().then(() => (init_set_thinking(), exports_set_thinking));
24121
+ const setThinkingTool = createSetThinkingTool2(agent.reasoningState, config.reasoning, () => agent.currentIteration);
24122
+ toolRegistry.register(setThinkingTool);
24123
+ }
23729
24124
  return {
23730
24125
  agent,
23731
24126
  config,
@@ -23746,6 +24141,7 @@ var init_bootstrap = __esm(() => {
23746
24141
  init_config2();
23747
24142
  init_app_logger();
23748
24143
  init_providers();
24144
+ init_presets();
23749
24145
  init_tools();
23750
24146
  init_hidden_tools_block();
23751
24147
  init_executor();
@@ -31528,7 +31924,8 @@ var init_scenarios = __esm(() => {
31528
31924
  }
31529
31925
  };
31530
31926
  PROVIDER_BASE = {
31531
- provider: { maxCompletionTokens: 16384 }
31927
+ provider: { maxCompletionTokens: 16384 },
31928
+ reasoning: { mode: "none", min: "low", max: "high", overrideCooldown: 3 }
31532
31929
  };
31533
31930
  SCENARIO_DEFS = [
31534
31931
  {
@@ -32856,10 +33253,19 @@ function registerMmaCommands(ctx) {
32856
33253
  name: "reasoning",
32857
33254
  description: t("repl.reasoning"),
32858
33255
  usage: t("repl.reasoning_usage"),
32859
- action: () => {
32860
- ctx.config.showReasoning = !ctx.config.showReasoning;
32861
- const status = ctx.config.showReasoning ? pc2.green(t("repl.show")) : pc2.dim(t("repl.hide"));
32862
- console.log(t("repl.reasoning_status", { status }));
33256
+ action: (args) => {
33257
+ const level = args[0]?.trim().toLowerCase();
33258
+ const VALID_LEVELS2 = ["auto", "none", "low", "medium", "high", "max"];
33259
+ if (!level) {
33260
+ ctx.config.showReasoning = !ctx.config.showReasoning;
33261
+ const status = ctx.config.showReasoning ? pc2.green(t("repl.show")) : pc2.dim(t("repl.hide"));
33262
+ console.log(t("repl.reasoning_status", { status }));
33263
+ } else if (VALID_LEVELS2.includes(level)) {
33264
+ ctx.agent.setReasoningLevel(level);
33265
+ console.log(pc2.green(t("repl.reasoning_level_set", { level })));
33266
+ } else {
33267
+ console.log(pc2.yellow(t("repl.reasoning_invalid_level", { level, valid: VALID_LEVELS2.join(", ") })));
33268
+ }
32863
33269
  }
32864
33270
  });
32865
33271
  ctx.registerCommand({
@@ -34101,7 +34507,7 @@ init_presets();
34101
34507
  init_version();
34102
34508
  var version = readMmaVersion();
34103
34509
  function createProgram() {
34104
- const program2 = new Command().name("mma").description(t("cli.description")).version(version).option("--no-agents-md", t("cli.no_agents_md")).option("-d, --dir <path>", t("cli.dir")).option("-e, --exit-on-complete", t("cli.exit_on_complete")).option("-j, --json", t("cli.json"));
34510
+ const program2 = new Command().name("mma").description(t("cli.description")).version(version).option("--no-agents-md", t("cli.no_agents_md")).option("-d, --dir <path>", t("cli.dir")).option("-e, --exit-on-complete", t("cli.exit_on_complete")).option("-j, --json", t("cli.json")).option("--reasoning <level>", t("cli.reasoning_level"), "auto");
34105
34511
  program2.command("init").description(t("cli.init")).action(async () => {
34106
34512
  const answers = await runSetup();
34107
34513
  const configPath = join47(homedir16(), ".mma", "config.json");
@@ -36832,13 +37238,14 @@ async function main() {
36832
37238
  const projectDir = opts.dir;
36833
37239
  const exitOnComplete = opts.exitOnComplete === true;
36834
37240
  const jsonMode = opts.json === true;
37241
+ const reasoningLevel = opts.reasoning;
36835
37242
  const isSubcommand = program2.args.length > 0 && cmdNames.has(program2.args[0]);
36836
37243
  if (isSubcommand) {
36837
37244
  return;
36838
37245
  }
36839
37246
  if (program2.args.length > 0) {
36840
37247
  const prompt = program2.args.join(" ");
36841
- const { agent, config, baseDir, legacyDetected } = await bootstrap(undefined, projectDir, noAgentsMd, exitOnComplete);
37248
+ const { agent, config, baseDir, legacyDetected } = await bootstrap(undefined, projectDir, noAgentsMd, exitOnComplete, reasoningLevel);
36842
37249
  if (legacyDetected) {
36843
37250
  console.error(pc2.yellow(` ${t("config.legacy_hint")}`));
36844
37251
  }