reasonix 0.52.0 → 0.53.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 (143) hide show
  1. package/README.md +1 -0
  2. package/README.zh-CN.md +1 -0
  3. package/dashboard/dist/app.css +1 -1
  4. package/dashboard/dist/app.js +13 -13
  5. package/dashboard/dist/app.js.map +1 -1
  6. package/dist/cli/{acp-NEUYWGUU.js → acp-ABNDGEYC.js} +63 -30
  7. package/dist/cli/acp-ABNDGEYC.js.map +1 -0
  8. package/dist/cli/chat-377YZV56.js +49 -0
  9. package/dist/cli/{chunk-FY5UERSG.js → chunk-2WZT27GR.js} +9 -9
  10. package/dist/cli/{chunk-B4MOGWHW.js → chunk-4EHRIP5U.js} +7 -7
  11. package/dist/cli/chunk-4EHRIP5U.js.map +1 -0
  12. package/dist/cli/{chunk-RCC73DWQ.js → chunk-4SBXAHR6.js} +4 -4
  13. package/dist/cli/{chunk-5YLEKX2V.js → chunk-4V4TKQMB.js} +4 -4
  14. package/dist/cli/{chunk-5YLEKX2V.js.map → chunk-4V4TKQMB.js.map} +1 -1
  15. package/dist/cli/chunk-7ZO6H6ZK.js +54 -0
  16. package/dist/cli/chunk-7ZO6H6ZK.js.map +1 -0
  17. package/dist/cli/{chunk-3OXD5CBM.js → chunk-A6GSOADP.js} +17870 -16070
  18. package/dist/cli/chunk-A6GSOADP.js.map +1 -0
  19. package/dist/cli/{chunk-Z663GVUB.js → chunk-APOSDBAU.js} +3 -3
  20. package/dist/cli/{chunk-CTRM32BP.js → chunk-B5JISV5I.js} +2 -2
  21. package/dist/cli/{chunk-HNZ4727T.js → chunk-DFHI2MRB.js} +412 -152
  22. package/dist/cli/chunk-DFHI2MRB.js.map +1 -0
  23. package/dist/cli/{chunk-CGVW5W7N.js → chunk-EPIHGOM3.js} +14 -14
  24. package/dist/cli/{chunk-CGVW5W7N.js.map → chunk-EPIHGOM3.js.map} +1 -1
  25. package/dist/cli/{chunk-77JIQ7SL.js → chunk-EQFZIHKJ.js} +8 -8
  26. package/dist/cli/chunk-EQFZIHKJ.js.map +1 -0
  27. package/dist/cli/{chunk-XNMXVL6C.js → chunk-FB27YXPX.js} +2 -2
  28. package/dist/cli/{chunk-ARBGTNHM.js → chunk-FK7NXDRP.js} +2 -2
  29. package/dist/cli/{chunk-AOYUW3HR.js → chunk-GCNBIWK7.js} +22 -2
  30. package/dist/cli/chunk-GCNBIWK7.js.map +1 -0
  31. package/dist/cli/{chunk-XBYHNZ5Z.js → chunk-GMQVINZK.js} +13 -5
  32. package/dist/cli/chunk-GMQVINZK.js.map +1 -0
  33. package/dist/cli/{chunk-MVLPXZAA.js → chunk-GOASYYZ4.js} +43 -11
  34. package/dist/cli/{chunk-MVLPXZAA.js.map → chunk-GOASYYZ4.js.map} +1 -1
  35. package/dist/cli/{chunk-WPY7AFS6.js → chunk-I4SH5Z7S.js} +2 -2
  36. package/dist/cli/{chunk-MW64SQUE.js → chunk-J26XOB2T.js} +2 -2
  37. package/dist/cli/{chunk-DLTE4GBY.js → chunk-J4MYMBJ7.js} +3 -3
  38. package/dist/cli/{chunk-CFJY64UA.js → chunk-LRO63VNK.js} +2 -2
  39. package/dist/cli/{chunk-XUZHBQSM.js → chunk-MQJR7YQ2.js} +2 -2
  40. package/dist/cli/{chunk-CPCUMMSR.js → chunk-NVI4XPOQ.js} +3 -3
  41. package/dist/cli/{chunk-RHQOGG43.js → chunk-OHSVEXFF.js} +3 -3
  42. package/dist/cli/chunk-OHSVEXFF.js.map +1 -0
  43. package/dist/cli/{chunk-AMSK3ZLB.js → chunk-P5SUHDUQ.js} +2 -2
  44. package/dist/cli/{chunk-GFJJEW3Z.js → chunk-QSKDP3OS.js} +55 -5
  45. package/dist/cli/chunk-QSKDP3OS.js.map +1 -0
  46. package/dist/cli/{chunk-D6WRFR6V.js → chunk-R7JMQMLD.js} +6 -5
  47. package/dist/cli/chunk-R7JMQMLD.js.map +1 -0
  48. package/dist/cli/{chunk-VVPV5HU6.js → chunk-RRZIIMAF.js} +2 -2
  49. package/dist/cli/{chunk-GNRKXRRE.js → chunk-S3QII236.js} +369 -359
  50. package/dist/cli/{chunk-GNRKXRRE.js.map → chunk-S3QII236.js.map} +1 -1
  51. package/dist/cli/{chunk-HI6THNAZ.js → chunk-TGP7JGHN.js} +32 -14
  52. package/dist/cli/chunk-TGP7JGHN.js.map +1 -0
  53. package/dist/cli/{chunk-CLHMV6OL.js → chunk-U7G72DHQ.js} +83 -42
  54. package/dist/cli/chunk-U7G72DHQ.js.map +1 -0
  55. package/dist/cli/{chunk-OMNRXZNA.js → chunk-URAI4YRL.js} +2 -2
  56. package/dist/cli/{chunk-6QBUXA73.js → chunk-V4AXMN4X.js} +2 -2
  57. package/dist/cli/{chunk-2W4F3RIZ.js → chunk-XHP6NYOT.js} +3 -2
  58. package/dist/cli/{chunk-2W4F3RIZ.js.map → chunk-XHP6NYOT.js.map} +1 -1
  59. package/dist/cli/{code-WN6D4VZO.js → code-JPFZJYVW.js} +34 -34
  60. package/dist/cli/{commands-DHETOY7O.js → commands-IUL2CLKH.js} +4 -4
  61. package/dist/cli/{commit-BBUYAKZV.js → commit-JT7LYBTL.js} +3 -3
  62. package/dist/cli/{config-KV7VV5LG.js → config-T4RWI5NG.js} +6 -2
  63. package/dist/cli/{desktop-LJVXWXNF.js → desktop-AUBW2SLL.js} +122 -38
  64. package/dist/cli/desktop-AUBW2SLL.js.map +1 -0
  65. package/dist/cli/devtools-O5HOMAGZ.js +3 -0
  66. package/dist/cli/diff-NINZHUJR.js +165 -0
  67. package/dist/cli/diff-NINZHUJR.js.map +1 -0
  68. package/dist/cli/{doctor-GI5LOEZL.js → doctor-OMAYGY4F.js} +10 -10
  69. package/dist/cli/{events-LBKMLFM4.js → events-5IVFJ4H3.js} +5 -5
  70. package/dist/cli/index.js +38 -38
  71. package/dist/cli/{mcp-DKEJK5ND.js → mcp-ECGJACAP.js} +3 -3
  72. package/dist/cli/{mcp-browse-V7KWDY32.js → mcp-browse-NGEOHVJB.js} +15 -15
  73. package/dist/cli/mcp-browse-NGEOHVJB.js.map +1 -0
  74. package/dist/cli/{mcp-inspect-MTABNHVM.js → mcp-inspect-ZIMNRG7G.js} +5 -5
  75. package/dist/cli/{prompt-ATI7DKHF.js → prompt-JCC3A7AA.js} +5 -5
  76. package/dist/cli/{prune-sessions-YQQSZTZS.js → prune-sessions-TE4BJYO2.js} +4 -4
  77. package/dist/cli/{replay-ZJQ4I4CJ.js → replay-2UUTCRTG.js} +29 -29
  78. package/dist/cli/replay-2UUTCRTG.js.map +1 -0
  79. package/dist/cli/{run-HFPRNWJY.js → run-ABQYOPVM.js} +22 -22
  80. package/dist/cli/{server-UHKO2VVM.js → server-MPCXIW2O.js} +27 -25
  81. package/dist/cli/{server-UHKO2VVM.js.map → server-MPCXIW2O.js.map} +1 -1
  82. package/dist/cli/{sessions-IQEWWUH3.js → sessions-YBPRGIAF.js} +16 -16
  83. package/dist/cli/{setup-5BYKCL62.js → setup-A34LF2QE.js} +42 -42
  84. package/dist/cli/setup-A34LF2QE.js.map +1 -0
  85. package/dist/cli/{stats-OFCGOQMZ.js → stats-GKG5JZQX.js} +6 -6
  86. package/dist/cli/stats-GKG5JZQX.js.map +1 -0
  87. package/dist/cli/{version-EODUFAAI.js → version-JD6QSM4X.js} +16 -16
  88. package/dist/index.d.ts +36 -5
  89. package/dist/index.js +443 -73
  90. package/dist/index.js.map +1 -1
  91. package/package.json +7 -2
  92. package/dist/cli/acp-NEUYWGUU.js.map +0 -1
  93. package/dist/cli/chat-QA6IVFJD.js +0 -49
  94. package/dist/cli/chunk-3OXD5CBM.js.map +0 -1
  95. package/dist/cli/chunk-77JIQ7SL.js.map +0 -1
  96. package/dist/cli/chunk-AOYUW3HR.js.map +0 -1
  97. package/dist/cli/chunk-B4MOGWHW.js.map +0 -1
  98. package/dist/cli/chunk-CLHMV6OL.js.map +0 -1
  99. package/dist/cli/chunk-D6WRFR6V.js.map +0 -1
  100. package/dist/cli/chunk-GFJJEW3Z.js.map +0 -1
  101. package/dist/cli/chunk-HI6THNAZ.js.map +0 -1
  102. package/dist/cli/chunk-HNZ4727T.js.map +0 -1
  103. package/dist/cli/chunk-I3NE5S63.js +0 -54
  104. package/dist/cli/chunk-I3NE5S63.js.map +0 -1
  105. package/dist/cli/chunk-RHQOGG43.js.map +0 -1
  106. package/dist/cli/chunk-XBYHNZ5Z.js.map +0 -1
  107. package/dist/cli/desktop-LJVXWXNF.js.map +0 -1
  108. package/dist/cli/diff-2JHMQAHI.js +0 -165
  109. package/dist/cli/diff-2JHMQAHI.js.map +0 -1
  110. package/dist/cli/mcp-browse-V7KWDY32.js.map +0 -1
  111. package/dist/cli/replay-ZJQ4I4CJ.js.map +0 -1
  112. package/dist/cli/setup-5BYKCL62.js.map +0 -1
  113. /package/dist/cli/{chat-QA6IVFJD.js.map → chat-377YZV56.js.map} +0 -0
  114. /package/dist/cli/{chunk-FY5UERSG.js.map → chunk-2WZT27GR.js.map} +0 -0
  115. /package/dist/cli/{chunk-RCC73DWQ.js.map → chunk-4SBXAHR6.js.map} +0 -0
  116. /package/dist/cli/{chunk-Z663GVUB.js.map → chunk-APOSDBAU.js.map} +0 -0
  117. /package/dist/cli/{chunk-CTRM32BP.js.map → chunk-B5JISV5I.js.map} +0 -0
  118. /package/dist/cli/{chunk-XNMXVL6C.js.map → chunk-FB27YXPX.js.map} +0 -0
  119. /package/dist/cli/{chunk-ARBGTNHM.js.map → chunk-FK7NXDRP.js.map} +0 -0
  120. /package/dist/cli/{chunk-WPY7AFS6.js.map → chunk-I4SH5Z7S.js.map} +0 -0
  121. /package/dist/cli/{chunk-MW64SQUE.js.map → chunk-J26XOB2T.js.map} +0 -0
  122. /package/dist/cli/{chunk-DLTE4GBY.js.map → chunk-J4MYMBJ7.js.map} +0 -0
  123. /package/dist/cli/{chunk-CFJY64UA.js.map → chunk-LRO63VNK.js.map} +0 -0
  124. /package/dist/cli/{chunk-XUZHBQSM.js.map → chunk-MQJR7YQ2.js.map} +0 -0
  125. /package/dist/cli/{chunk-CPCUMMSR.js.map → chunk-NVI4XPOQ.js.map} +0 -0
  126. /package/dist/cli/{chunk-AMSK3ZLB.js.map → chunk-P5SUHDUQ.js.map} +0 -0
  127. /package/dist/cli/{chunk-VVPV5HU6.js.map → chunk-RRZIIMAF.js.map} +0 -0
  128. /package/dist/cli/{chunk-OMNRXZNA.js.map → chunk-URAI4YRL.js.map} +0 -0
  129. /package/dist/cli/{chunk-6QBUXA73.js.map → chunk-V4AXMN4X.js.map} +0 -0
  130. /package/dist/cli/{code-WN6D4VZO.js.map → code-JPFZJYVW.js.map} +0 -0
  131. /package/dist/cli/{commands-DHETOY7O.js.map → commands-IUL2CLKH.js.map} +0 -0
  132. /package/dist/cli/{commit-BBUYAKZV.js.map → commit-JT7LYBTL.js.map} +0 -0
  133. /package/dist/cli/{config-KV7VV5LG.js.map → config-T4RWI5NG.js.map} +0 -0
  134. /package/dist/cli/{doctor-GI5LOEZL.js.map → devtools-O5HOMAGZ.js.map} +0 -0
  135. /package/dist/cli/{prompt-ATI7DKHF.js.map → doctor-OMAYGY4F.js.map} +0 -0
  136. /package/dist/cli/{events-LBKMLFM4.js.map → events-5IVFJ4H3.js.map} +0 -0
  137. /package/dist/cli/{mcp-DKEJK5ND.js.map → mcp-ECGJACAP.js.map} +0 -0
  138. /package/dist/cli/{mcp-inspect-MTABNHVM.js.map → mcp-inspect-ZIMNRG7G.js.map} +0 -0
  139. /package/dist/cli/{stats-OFCGOQMZ.js.map → prompt-JCC3A7AA.js.map} +0 -0
  140. /package/dist/cli/{prune-sessions-YQQSZTZS.js.map → prune-sessions-TE4BJYO2.js.map} +0 -0
  141. /package/dist/cli/{run-HFPRNWJY.js.map → run-ABQYOPVM.js.map} +0 -0
  142. /package/dist/cli/{sessions-IQEWWUH3.js.map → sessions-YBPRGIAF.js.map} +0 -0
  143. /package/dist/cli/{version-EODUFAAI.js.map → version-JD6QSM4X.js.map} +0 -0
@@ -2,10 +2,10 @@
2
2
  import { createRequire as __cr } from 'node:module'; if (typeof globalThis.require === 'undefined') { globalThis.require = __cr(import.meta.url); }
3
3
  import {
4
4
  checkOllamaStatus
5
- } from "./chunk-VVPV5HU6.js";
5
+ } from "./chunk-RRZIIMAF.js";
6
6
  import {
7
7
  indexExists
8
- } from "./chunk-WPY7AFS6.js";
8
+ } from "./chunk-I4SH5Z7S.js";
9
9
  import {
10
10
  detectProxyUrl,
11
11
  matchesNoProxy,
@@ -14,32 +14,32 @@ import {
14
14
  import {
15
15
  resolveDataPath
16
16
  } from "./chunk-BOWSNGQC.js";
17
+ import {
18
+ DeepSeekClient,
19
+ pickPrimaryBalance
20
+ } from "./chunk-QSKDP3OS.js";
17
21
  import {
18
22
  loadHooks
19
- } from "./chunk-CPCUMMSR.js";
23
+ } from "./chunk-NVI4XPOQ.js";
20
24
  import {
21
25
  listSessions
22
- } from "./chunk-AMSK3ZLB.js";
26
+ } from "./chunk-P5SUHDUQ.js";
23
27
  import {
24
28
  VERSION
25
29
  } from "./chunk-XXC2BYTV.js";
26
- import {
27
- DeepSeekClient,
28
- pickPrimaryBalance
29
- } from "./chunk-GFJJEW3Z.js";
30
30
  import {
31
31
  loadDotenv
32
32
  } from "./chunk-2UQP6H6T.js";
33
33
  import {
34
34
  t
35
- } from "./chunk-CLHMV6OL.js";
35
+ } from "./chunk-U7G72DHQ.js";
36
36
  import {
37
37
  defaultConfigPath,
38
38
  loadEndpoint,
39
39
  loadProxyConfig,
40
40
  readConfig,
41
41
  resolveSemanticEmbeddingConfig
42
- } from "./chunk-AOYUW3HR.js";
42
+ } from "./chunk-GCNBIWK7.js";
43
43
 
44
44
  // src/cli/commands/doctor.ts
45
45
  import { existsSync, readFileSync, statSync } from "fs";
@@ -199,7 +199,8 @@ async function checkConfig() {
199
199
  }
200
200
  }
201
201
  async function checkApiReach() {
202
- const key = process.env.DEEPSEEK_API_KEY ?? readConfig().apiKey;
202
+ const endpoint = loadEndpoint();
203
+ const key = endpoint.apiKey;
203
204
  if (!key) {
204
205
  return {
205
206
  id: "api-reach",
@@ -209,11 +210,21 @@ async function checkApiReach() {
209
210
  };
210
211
  }
211
212
  try {
212
- const client = new DeepSeekClient({ apiKey: key, baseUrl: loadEndpoint().baseUrl });
213
+ const client = new DeepSeekClient({ apiKey: key, baseUrl: endpoint.baseUrl });
213
214
  const ctl = new AbortController();
214
215
  const timer = setTimeout(() => ctl.abort(), 8e3);
216
+ let models;
215
217
  let balance;
216
218
  try {
219
+ models = await client.listModels({ signal: ctl.signal });
220
+ if (models) {
221
+ return {
222
+ id: "api-reach",
223
+ label: "api reach ",
224
+ level: "ok",
225
+ detail: `/models ok \u2014 ${summarizeModels(models.data)}`
226
+ };
227
+ }
217
228
  balance = await client.getBalance({ signal: ctl.signal });
218
229
  } finally {
219
230
  clearTimeout(timer);
@@ -223,7 +234,7 @@ async function checkApiReach() {
223
234
  id: "api-reach",
224
235
  label: "api reach ",
225
236
  level: "fail",
226
- detail: "/user/balance returned null \u2014 auth failed or network blocked"
237
+ detail: "/models and /user/balance returned null \u2014 auth failed or network blocked"
227
238
  };
228
239
  }
229
240
  const summary = summarizeBalances(balance.balance_infos);
@@ -250,6 +261,13 @@ async function checkApiReach() {
250
261
  };
251
262
  }
252
263
  }
264
+ function summarizeModels(models) {
265
+ if (models.length === 0) return "0 models";
266
+ const ids = models.map((m) => m.id).filter(Boolean);
267
+ const preview = ids.slice(0, 3).join(", ");
268
+ const suffix = ids.length > 3 ? ", ..." : "";
269
+ return `${models.length} model${models.length === 1 ? "" : "s"}${preview ? ` (${preview}${suffix})` : ""}`;
270
+ }
253
271
  function summarizeBalances(infos) {
254
272
  if (infos.length === 0) return "";
255
273
  const primary = pickPrimaryBalance(infos);
@@ -487,4 +505,4 @@ export {
487
505
  formatDoctorJson,
488
506
  doctorCommand
489
507
  };
490
- //# sourceMappingURL=chunk-HI6THNAZ.js.map
508
+ //# sourceMappingURL=chunk-TGP7JGHN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/commands/doctor.ts"],"sourcesContent":["/** Plain-text (not Ink) — must work when everything else is broken. fail → exit 1; warn → exit 0. */\n\nimport { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\nimport { DeepSeekClient, pickPrimaryBalance } from \"../../client.js\";\nimport {\n defaultConfigPath,\n loadEndpoint,\n loadProxyConfig,\n readConfig,\n resolveSemanticEmbeddingConfig,\n} from \"../../config.js\";\nimport { loadDotenv } from \"../../env.js\";\nimport { loadHooks } from \"../../hooks.js\";\nimport { t } from \"../../i18n/index.js\";\nimport { indexExists } from \"../../index/semantic/builder.js\";\nimport { checkOllamaStatus } from \"../../index/semantic/ollama-launcher.js\";\nimport { listSessions } from \"../../memory/session.js\";\nimport { detectProxyUrl, matchesNoProxy, resolveNoProxy } from \"../../net/proxy.js\";\nimport { resolveDataPath } from \"../../tokenizer.js\";\nimport { VERSION } from \"../../version.js\";\n\nexport type DoctorLevel = \"ok\" | \"warn\" | \"fail\";\n\nexport interface DoctorCheck {\n id: string;\n label: string;\n level: DoctorLevel;\n detail: string;\n}\n\nexport interface DoctorOptions {\n json?: boolean;\n}\n\ntype Level = DoctorLevel;\ntype Check = DoctorCheck;\n\nexport async function runDoctorChecks(projectRoot: string): Promise<DoctorCheck[]> {\n // No descriptive names for the destructured slots — CodeQL's clear-text-logging\n // heuristic taints any variable name matching `*key*`/`*auth*`/`*cred*`/etc and\n // would trip on `apiKeyCheck`. The slots map 1:1 to the Promise.all array below.\n const r = await Promise.all([\n checkApiKey(),\n checkConfig(),\n checkApiReach(),\n checkTokenizer(),\n checkSessions(),\n checkHooks(projectRoot),\n checkOllama(projectRoot),\n checkProject(projectRoot),\n ]);\n return [r[0], r[1], ...checkProxy(), r[2], r[3], r[4], r[5], r[6], r[7]];\n}\n\n/** Probe hosts used to show users what's going through the proxy vs. direct. Cheap (no I/O), purely a routing simulation against the same NO_PROXY patterns the dispatcher uses. */\nconst PROXY_PROBE_HOSTS = [\"api.deepseek.com\", \"github.com\", \"api.github.com\"] as const;\n\nfunction checkProxy(): Check[] {\n const cfg = loadProxyConfig();\n const envUrl = detectProxyUrl();\n const url = cfg.url ?? envUrl;\n if (!url) {\n return [\n {\n id: \"proxy\",\n label: \"http proxy \",\n level: \"ok\",\n detail:\n \"no proxy configured (cfg.proxy.url / HTTPS_PROXY / HTTP_PROXY / ALL_PROXY unset) — direct connection\",\n },\n ];\n }\n let redacted = url;\n try {\n const u = new URL(url);\n if (u.username || u.password) {\n u.username = \"***\";\n u.password = \"\";\n redacted = u.toString();\n }\n } catch {\n /* not a URL — leave raw */\n }\n const urlSource = cfg.url ? \"cfg.proxy.url\" : \"HTTPS_PROXY\";\n if (cfg.disabled) {\n return [\n {\n id: \"proxy\",\n label: \"http proxy \",\n level: \"ok\",\n detail: `${urlSource}=${redacted} is set but cfg.proxy.disabled — Reasonix routes direct`,\n },\n ];\n }\n const resolved = resolveNoProxy(process.env, {\n extraNoProxy: cfg.noProxy,\n bypassDeepSeekDirect: cfg.bypassDeepSeekDirect,\n });\n const total = resolved.all.length;\n const sourceSummary = [\n `defaults ${resolved.defaults.length}`,\n resolved.envSystem.length > 0 ? `env ${resolved.envSystem.length}` : null,\n resolved.envReasonix.length > 0 ? `REASONIX ${resolved.envReasonix.length}` : null,\n resolved.extra.length > 0 ? `config ${resolved.extra.length}` : null,\n ]\n .filter(Boolean)\n .join(\" + \");\n const proxyCheck: Check = {\n id: \"proxy\",\n label: \"http proxy \",\n level: \"ok\",\n detail: `routing fetch through ${redacted} via ${urlSource} (NO_PROXY: ${total} pattern${total === 1 ? \"\" : \"s\"} — ${sourceSummary})`,\n };\n const probes = PROXY_PROBE_HOSTS.map(\n (h) => `${h} → ${matchesNoProxy(h, resolved.all) ? \"direct\" : \"via proxy\"}`,\n );\n const routingCheck: Check = {\n id: \"proxy-routing\",\n label: \"proxy routing\",\n level: \"ok\",\n detail: probes.join(\", \"),\n };\n return [proxyCheck, routingCheck];\n}\n\nconst TTY = process.stdout.isTTY && process.env.TERM !== \"dumb\";\n\nfunction color(text: string, code: string): string {\n if (!TTY) return text;\n return `\\x1b[${code}m${text}\\x1b[0m`;\n}\n\nfunction badge(level: Level): string {\n if (level === \"ok\") return color(\"✓\", \"32\");\n if (level === \"warn\") return color(\"⚠\", \"33\");\n return color(\"✗\", \"31\");\n}\n\nfunction fmtBytes(n: number): string {\n if (n < 1024) return `${n} B`;\n if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;\n return `${(n / 1024 / 1024).toFixed(1)} MB`;\n}\n\nasync function checkApiKey(): Promise<Check> {\n const fromEnv = process.env.DEEPSEEK_API_KEY;\n if (fromEnv) {\n return {\n id: \"api-key\",\n label: \"api key \",\n level: \"ok\",\n detail: \"set via env DEEPSEEK_API_KEY\",\n };\n }\n try {\n const cfg = readConfig();\n if (cfg.apiKey) {\n return {\n id: \"api-key\",\n label: \"api key \",\n level: \"ok\",\n detail: `from ${defaultConfigPath()}`,\n };\n }\n } catch {\n /* fall through */\n }\n return {\n id: \"api-key\",\n label: \"api key \",\n level: \"fail\",\n detail:\n \"not set — `reasonix setup` to save one, or export DEEPSEEK_API_KEY. Get a key at https://platform.deepseek.com/api_keys\",\n };\n}\n\nasync function checkConfig(): Promise<Check> {\n const path = defaultConfigPath();\n if (!existsSync(path)) {\n return {\n id: \"config\",\n label: \"config \",\n level: \"warn\",\n detail: \"missing — running with library defaults. `reasonix setup` writes one.\",\n };\n }\n try {\n const cfg = readConfig(path);\n const parts: string[] = [];\n if (cfg.model) parts.push(`model=${cfg.model}`);\n if (cfg.reasoningEffort) parts.push(`effort=${cfg.reasoningEffort}`);\n if (cfg.editMode) parts.push(`editMode=${cfg.editMode}`);\n if (cfg.mcp && cfg.mcp.length > 0) parts.push(`mcp=${cfg.mcp.length}`);\n return {\n id: \"config\",\n label: \"config \",\n level: \"ok\",\n detail: `${path}${parts.length ? ` (${parts.join(\", \")})` : \"\"}`,\n };\n } catch (err) {\n return {\n id: \"config\",\n label: \"config \",\n level: \"fail\",\n detail: t(\"doctorErrors.unreadable\", { path, message: (err as Error).message }),\n };\n }\n}\n\nasync function checkApiReach(): Promise<Check> {\n const endpoint = loadEndpoint();\n const key = endpoint.apiKey;\n if (!key) {\n return {\n id: \"api-reach\",\n label: \"api reach \",\n level: \"warn\",\n detail: \"skipped — no api key to test with\",\n };\n }\n try {\n const client = new DeepSeekClient({ apiKey: key, baseUrl: endpoint.baseUrl });\n const ctl = new AbortController();\n const timer = setTimeout(() => ctl.abort(), 8_000);\n let models: Awaited<ReturnType<DeepSeekClient[\"listModels\"]>>;\n let balance: Awaited<ReturnType<DeepSeekClient[\"getBalance\"]>>;\n try {\n models = await client.listModels({ signal: ctl.signal });\n if (models) {\n return {\n id: \"api-reach\",\n label: \"api reach \",\n level: \"ok\",\n detail: `/models ok — ${summarizeModels(models.data)}`,\n };\n }\n balance = await client.getBalance({ signal: ctl.signal });\n } finally {\n clearTimeout(timer);\n }\n if (!balance) {\n return {\n id: \"api-reach\",\n label: \"api reach \",\n level: \"fail\",\n detail: \"/models and /user/balance returned null — auth failed or network blocked\",\n };\n }\n const summary = summarizeBalances(balance.balance_infos);\n if (!balance.is_available) {\n return {\n id: \"api-reach\",\n label: \"api reach \",\n level: \"warn\",\n detail: `account flagged not-available${summary ? ` (${summary})` : \"\"} — top up or check your dashboard`,\n };\n }\n return {\n id: \"api-reach\",\n label: \"api reach \",\n level: \"ok\",\n detail: summary ? `/user/balance ok — ${summary}` : \"/user/balance ok\",\n };\n } catch (err) {\n return {\n id: \"api-reach\",\n label: \"api reach \",\n level: \"fail\",\n detail: `${(err as Error).message}`,\n };\n }\n}\n\nfunction summarizeModels(models: ReadonlyArray<{ id: string }>): string {\n if (models.length === 0) return \"0 models\";\n const ids = models.map((m) => m.id).filter(Boolean);\n const preview = ids.slice(0, 3).join(\", \");\n const suffix = ids.length > 3 ? \", ...\" : \"\";\n return `${models.length} model${models.length === 1 ? \"\" : \"s\"}${preview ? ` (${preview}${suffix})` : \"\"}`;\n}\n\nfunction summarizeBalances(\n infos: ReadonlyArray<{ currency: string; total_balance: string }>,\n): string {\n if (infos.length === 0) return \"\";\n const primary = pickPrimaryBalance(infos);\n if (infos.length === 1 || !primary)\n return primary ? `${primary.total_balance} ${primary.currency}` : \"\";\n const rest = infos.filter((i) => i !== primary).map((i) => `${i.total_balance} ${i.currency}`);\n return `${primary.total_balance} ${primary.currency} + ${rest.join(\" + \")}`;\n}\n\nasync function checkTokenizer(): Promise<Check> {\n // Reuse the runtime's resolver so the doctor never disagrees with what\n // the tokenizer actually loads — three candidates including a global\n // npm install probe via createRequire.\n const path = resolveDataPath();\n if (existsSync(path)) {\n try {\n const stat = statSync(path);\n return {\n id: \"tokenizer\",\n label: \"tokenizer \",\n level: \"ok\",\n detail: `${path} (${fmtBytes(stat.size)})`,\n };\n } catch {\n /* fall through to warn */\n }\n }\n return {\n id: \"tokenizer\",\n label: \"tokenizer \",\n level: \"warn\",\n detail:\n \"data/deepseek-tokenizer.json.gz not found — token counts will fall back to char heuristics\",\n };\n}\n\nasync function checkSessions(): Promise<Check> {\n try {\n const list = listSessions();\n if (list.length === 0) {\n return {\n id: \"sessions\",\n label: \"sessions \",\n level: \"ok\",\n detail: \"0 saved\",\n };\n }\n const totalBytes = list.reduce((s, e) => s + e.size, 0);\n const oldest = list[list.length - 1]!;\n const ageDays = Math.floor((Date.now() - oldest.mtime.getTime()) / (24 * 60 * 60 * 1000));\n const stale = list.filter(\n (e) => Date.now() - e.mtime.getTime() >= 90 * 24 * 60 * 60 * 1000,\n ).length;\n const detail = `${list.length} saved · ${fmtBytes(totalBytes)} · oldest ${ageDays}d`;\n if (stale > 0) {\n return {\n id: \"sessions\",\n label: \"sessions \",\n level: \"warn\",\n detail: `${detail} · ${stale} idle ≥90d (run \\`reasonix prune-sessions\\`)`,\n };\n }\n return { id: \"sessions\", label: \"sessions \", level: \"ok\", detail };\n } catch (err) {\n return {\n id: \"sessions\",\n label: \"sessions \",\n level: \"warn\",\n detail: t(\"doctorErrors.cannotList\", { message: (err as Error).message }),\n };\n }\n}\n\nasync function checkHooks(projectRoot: string): Promise<Check> {\n try {\n const all = loadHooks({ projectRoot });\n const global = all.filter((h) => h.scope === \"global\").length;\n const project = all.filter((h) => h.scope === \"project\").length;\n return {\n id: \"hooks\",\n label: \"hooks \",\n level: \"ok\",\n detail: `${global} global, ${project} project`,\n };\n } catch (err) {\n return {\n id: \"hooks\",\n label: \"hooks \",\n level: \"warn\",\n detail: t(\"doctorErrors.parseFailed\", { message: (err as Error).message }),\n };\n }\n}\n\nasync function checkOllama(projectRoot: string): Promise<Check> {\n let exists = false;\n try {\n exists = await indexExists(projectRoot);\n } catch {\n /* treat as no index */\n }\n if (!exists) {\n return {\n id: \"semantic\",\n label: \"semantic \",\n level: \"ok\",\n detail: \"not in use (no semantic index built; `reasonix index` to enable)\",\n };\n }\n const meta = readSemanticMeta(projectRoot);\n if (meta?.provider === \"openai-compat\") {\n const resolved = resolveSemanticEmbeddingConfig();\n if (resolved.provider !== \"openai-compat\") {\n return {\n id: \"semantic\",\n label: \"semantic \",\n level: \"warn\",\n detail: `index uses openai-compat/${meta.model} but current config resolves to ${resolved.provider}/${resolved.model} — rebuild before searching`,\n };\n }\n return {\n id: \"semantic\",\n label: \"semantic \",\n level: \"ok\",\n detail: `openai-compat · ${resolved.baseUrl} · model ${resolved.model} · api key configured`,\n };\n }\n try {\n const model = meta?.model || process.env.REASONIX_EMBED_MODEL || \"nomic-embed-text\";\n const status = await checkOllamaStatus(model);\n if (!status.binaryFound) {\n return {\n id: \"semantic\",\n label: \"semantic \",\n level: \"warn\",\n detail:\n \"ollama binary not on PATH — semantic_search will fail; install from https://ollama.com\",\n };\n }\n if (!status.daemonRunning) {\n return {\n id: \"semantic\",\n label: \"semantic \",\n level: \"warn\",\n detail:\n \"ollama daemon not running — `ollama serve` (or call /semantic in TUI to auto-start)\",\n };\n }\n if (!status.modelPulled) {\n return {\n id: \"semantic\",\n label: \"semantic \",\n level: \"warn\",\n detail: `model ${status.modelName} not pulled — \\`ollama pull ${status.modelName}\\``,\n };\n }\n return {\n id: \"semantic\",\n label: \"semantic \",\n level: \"ok\",\n detail: `ollama daemon up · model ${status.modelName} ready`,\n };\n } catch (err) {\n return {\n id: \"semantic\",\n label: \"semantic \",\n level: \"warn\",\n detail: t(\"doctorErrors.probeFailed\", { message: (err as Error).message }),\n };\n }\n}\n\nfunction readSemanticMeta(\n projectRoot: string,\n): { provider: \"ollama\" | \"openai-compat\"; model: string } | null {\n try {\n const raw = readFileSync(join(projectRoot, \".reasonix\", \"semantic\", \"index.meta.json\"), \"utf8\");\n const parsed = JSON.parse(raw) as { provider?: string; model?: string };\n return {\n provider: parsed.provider === \"openai-compat\" ? \"openai-compat\" : \"ollama\",\n model: typeof parsed.model === \"string\" ? parsed.model : \"\",\n };\n } catch {\n return null;\n }\n}\n\nasync function checkProject(projectRoot: string): Promise<Check> {\n // Heuristic: a \"real\" project has either .git, REASONIX.md, or\n // package.json. Lacking all three, `reasonix code` still works but\n // @-mentions and the project-memory pin won't surface much.\n const markers = [\".git\", \"REASONIX.md\", \"package.json\", \"pyproject.toml\", \"Cargo.toml\", \"go.mod\"];\n const found = markers.filter((m) => existsSync(join(projectRoot, m)));\n if (found.length === 0) {\n return {\n id: \"project\",\n label: \"project \",\n level: \"warn\",\n detail: `${projectRoot} has none of: ${markers.slice(0, 3).join(\", \")} … — \\`reasonix code\\` will still run, but @-mentions and project memory have nothing to anchor`,\n };\n }\n return {\n id: \"project\",\n label: \"project \",\n level: \"ok\",\n detail: `${projectRoot} (${found.join(\", \")})`,\n };\n}\n\nexport function formatDoctorJson(checks: DoctorCheck[], version: string): string {\n const ok = checks.filter((c) => c.level === \"ok\").length;\n const warn = checks.filter((c) => c.level === \"warn\").length;\n const fail = checks.filter((c) => c.level === \"fail\").length;\n return JSON.stringify({\n version,\n summary: { ok, warn, fail },\n checks: checks.map((c) => ({ id: c.id, status: c.level, message: c.detail })),\n });\n}\n\nexport async function doctorCommand(opts: DoctorOptions = {}): Promise<void> {\n loadDotenv();\n\n const projectRoot = resolve(process.cwd());\n const json = !!opts.json;\n\n if (!json) {\n console.log(`${color(`reasonix ${VERSION} · doctor`, \"1\")} (cwd: ${projectRoot})`);\n console.log(` home: ${homedir()}`);\n console.log(\"\");\n }\n\n // Run independent checks in parallel — saves ~5s when api-reach has\n // to time out. Each handler swallows its own throws into a `fail`\n // result so a thrown promise can't kill the whole report.\n const checks = await runDoctorChecks(projectRoot);\n\n const ok = checks.filter((c) => c.level === \"ok\").length;\n const warn = checks.filter((c) => c.level === \"warn\").length;\n const fail = checks.filter((c) => c.level === \"fail\").length;\n\n if (json) {\n console.log(formatDoctorJson(checks, VERSION));\n if (fail > 0) process.exit(1);\n return;\n }\n\n for (const c of checks) {\n console.log(` ${badge(c.level)} ${c.label} ${c.detail}`);\n }\n\n console.log(\"\");\n const summary = `${ok} ok · ${warn} warn · ${fail} fail`;\n if (fail > 0) {\n console.log(color(summary, \"31\"));\n process.exit(1);\n } else if (warn > 0) {\n console.log(color(summary, \"33\"));\n } else {\n console.log(color(summary, \"32\"));\n }\n}\n"],"mappings":"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","names":[]}
@@ -3,7 +3,7 @@ import { createRequire as __cr } from 'node:module'; if (typeof globalThis.requi
3
3
  import {
4
4
  loadLanguage,
5
5
  saveLanguage
6
- } from "./chunk-AOYUW3HR.js";
6
+ } from "./chunk-GCNBIWK7.js";
7
7
 
8
8
  // src/i18n/EN.ts
9
9
  var EN = {
@@ -399,8 +399,8 @@ var EN = {
399
399
  argsHint: "<question>"
400
400
  },
401
401
  "search-engine": {
402
- description: "switch web search backend \u2014 bing (default, works from CN without proxy), searxng (self-hosted), metaso (free 100/d), tavily (free 1000/mo), perplexity (AI-native), or exa (AI-native)",
403
- argsHint: "<bing|searxng|metaso|tavily|perplexity|exa> [<key>]"
402
+ description: "switch web search backend \u2014 bing (default, works from CN without proxy), searxng (self-hosted), metaso (free 100/d), tavily (free 1000/mo), perplexity (AI-native), exa (AI-native), or ollama (Ollama cloud web search)",
403
+ argsHint: "<bing|searxng|metaso|tavily|perplexity|exa|brave|ollama> [<key>]"
404
404
  }
405
405
  },
406
406
  wizard: {
@@ -1045,6 +1045,8 @@ var EN = {
1045
1045
  usageTavily: " /search-engine tavily use Tavily API (LLM-friendly, free 1000/mo \u2014 set TAVILY_API_KEY or tavilyApiKey in config; get one at https://tavily.com)",
1046
1046
  usagePerplexity: " /search-engine perplexity use Perplexity AI (AI-native answer + citations \u2014 set PERPLEXITY_API_KEY or perplexityApiKey in config; get one at https://perplexity.ai/settings/api)",
1047
1047
  usageExa: " /search-engine exa use Exa API (AI-native answer + citations, free 1000/mo \u2014 set EXA_API_KEY or exaApiKey in config; sign up at https://exa.ai)",
1048
+ usageOllama: " /search-engine ollama use Ollama cloud web search \u2014 set OLLAMA_API_KEY or ollamaApiKey in config; get one at https://ollama.com/settings/keys",
1049
+ usageBrave: " /search-engine brave use Brave Search API (independent index, free 2000/mo \u2014 set BRAVE_SEARCH_API_KEY or braveApiKey in config; get one at https://brave.com/search/api/)",
1048
1050
  alias: "Alias: /se",
1049
1051
  searxngInfo: "SearXNG is a self-hosted metasearch engine (https://github.com/searxng/searxng).",
1050
1052
  searxngInstall: "Install it with: docker run -d -p 8080:8080 searxng/searxng",
@@ -1054,6 +1056,8 @@ var EN = {
1054
1056
  switchedTavilyNote: " Set TAVILY_API_KEY or `tavilyApiKey` in config; free 1000/mo at https://tavily.com.",
1055
1057
  switchedPerplexityNote: " Set PERPLEXITY_API_KEY or `perplexityApiKey` in config; get one at https://perplexity.ai/settings/api.",
1056
1058
  switchedExaNote: " Set EXA_API_KEY or `exaApiKey` in config; sign up at https://exa.ai.",
1059
+ switchedOllamaNote: " Set OLLAMA_API_KEY or `ollamaApiKey` in config; get one at https://ollama.com/settings/keys.",
1060
+ switchedBraveNote: " Set BRAVE_SEARCH_API_KEY (or BRAVE_API_KEY) or `braveApiKey` in config; free 2000/mo at https://brave.com/search/api/.",
1057
1061
  keyNeeded: 'No API key configured for "{engine}".\n\n 1. Set the {envVar} environment variable\n 2. Or provide one inline: /search-engine {engine} <your-key>\n 3. Or add "{engine}ApiKey" to ~/.reasonix/config.json\n\nThen retry /search-engine {engine}.',
1058
1062
  keySaved: " API key saved to config.",
1059
1063
  confirmed: 'Web search engine set to "{engine}"{detail}. Next assistant turn will pick up the change.',
@@ -1338,38 +1342,43 @@ var EN = {
1338
1342
  probeFailed: "probe failed \u2014 {message}"
1339
1343
  },
1340
1344
  webErrors: {
1341
- status: "web_search {status} \u2014 try: the search backend returned an error; rephrase the query, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa",
1345
+ status: "web_search {status} \u2014 try: the search backend returned an error; rephrase the query, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave",
1342
1346
  rateLimit429: "web_search 429 \u2014 try: wait 10s before retrying, or rephrase the query; the search backend is rate-limiting this client",
1343
- forbidden403: "web_search 403 \u2014 try: the search backend is blocking this client; switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa, or wait and retry later",
1347
+ forbidden403: "web_search 403 \u2014 try: the search backend is blocking this client; switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave, or wait and retry later",
1344
1348
  serverError5xx: "web_search {status} \u2014 try: open the search URL in a browser; if it loads this is transient and a retry in 30s may help",
1345
- bingBlocked: "web_search: Bing anti-bot page \u2014 rate-limited or blocked \u2014 try: wait 30s and retry, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa",
1346
- bingNoResults: "web_search: 0 results but response doesn't look like a real empty page ({chars} chars, first 120: {preview}) \u2014 try: rephrase the query with simpler terms, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa",
1349
+ bingBlocked: "web_search: Bing anti-bot page \u2014 rate-limited or blocked \u2014 try: wait 30s and retry, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave",
1350
+ bingNoResults: "web_search: 0 results but response doesn't look like a real empty page ({chars} chars, first 120: {preview}) \u2014 try: rephrase the query with simpler terms, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave",
1347
1351
  invalidEndpoint: 'web_search: invalid SearXNG endpoint "{endpoint}" \u2014 try: set a valid URL with /search-endpoint http://host:port',
1348
1352
  endpointMustBeHttp: "web_search: SearXNG endpoint must be http(s), got {protocol} \u2014 try: set a valid URL with /search-endpoint http://host:port",
1349
- cannotReach: "web_search: Cannot reach SearXNG server at {endpoint} \u2014 try: install and start SearXNG (https://github.com/searxng/searxng, e.g. `docker run -d -p 8080:8080 searxng/searxng`), or switch to another engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa",
1350
- searxngNoResults: "web_search: 0 results but SearXNG response doesn't look like an empty results page ({chars} chars) \u2014 try: rephrase the query with simpler terms, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa",
1353
+ cannotReach: "web_search: Cannot reach SearXNG server at {endpoint} \u2014 try: install and start SearXNG (https://github.com/searxng/searxng, e.g. `docker run -d -p 8080:8080 searxng/searxng`), or switch to another engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave",
1354
+ searxngNoResults: "web_search: 0 results but SearXNG response doesn't look like an empty results page ({chars} chars) \u2014 try: rephrase the query with simpler terms, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave",
1351
1355
  metasoMissingKey: "web_search: Metaso requires an API key \u2014 set METASO_API_KEY or configure one with /search-engine metaso <key>. Get one at https://metaso.cn/search-api/playground",
1352
1356
  metasoDailyLimit: "web_search: Metaso daily search limit reached \u2014 set METASO_API_KEY or get a key at https://metaso.cn/search-api/playground",
1353
1357
  metasoUnauthorized: "web_search: Metaso API key rejected \u2014 check METASO_API_KEY or get one at https://metaso.cn/search-api/playground",
1354
1358
  metasoRateLimit: "web_search: Metaso rate-limited \u2014 wait and retry, or get your own API key at https://metaso.cn/search-api/playground",
1355
- metasoServerError: "web_search: Metaso server error ({status}) \u2014 try again later, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa",
1359
+ metasoServerError: "web_search: Metaso server error ({status}) \u2014 try again later, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave",
1356
1360
  metasoParseError: "web_search: Metaso returned unparseable response (HTTP {status}) \u2014 try again later",
1357
1361
  metasoApiError: "web_search: Metaso API error (code {code}: {message}) \u2014 try again later",
1358
1362
  tavilyMissingKey: "web_search: Tavily backend requires an API key \u2014 set TAVILY_API_KEY env var or `tavilyApiKey` in ~/.reasonix/config.json; free 1000/mo signup at https://tavily.com",
1359
1363
  tavilyUnauthorized: "web_search: Tavily API key rejected \u2014 check TAVILY_API_KEY or get one at https://tavily.com",
1360
- tavilyRateLimit: "web_search: Tavily rate-limited or monthly quota exceeded \u2014 wait, switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa, or upgrade your Tavily plan",
1361
- tavilyServerError: "web_search: Tavily server error ({status}) \u2014 try again later, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa",
1364
+ tavilyRateLimit: "web_search: Tavily rate-limited or monthly quota exceeded \u2014 wait, switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave, or upgrade your Tavily plan",
1365
+ tavilyServerError: "web_search: Tavily server error ({status}) \u2014 try again later, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave",
1362
1366
  tavilyParseError: "web_search: Tavily returned unparseable response (HTTP {status}) \u2014 try again later",
1363
1367
  perplexityMissingKey: "web_search: Perplexity backend requires an API key \u2014 set PERPLEXITY_API_KEY env var or `perplexityApiKey` in ~/.reasonix/config.json; get one at https://perplexity.ai/settings/api",
1364
1368
  perplexityUnauthorized: "web_search: Perplexity API key rejected \u2014 check PERPLEXITY_API_KEY or get one at https://perplexity.ai/settings/api",
1365
- perplexityRateLimit: "web_search: Perplexity rate-limited \u2014 wait and retry, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa",
1366
- perplexityServerError: "web_search: Perplexity server error ({status}) \u2014 try again later, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa",
1369
+ perplexityRateLimit: "web_search: Perplexity rate-limited \u2014 wait and retry, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave",
1370
+ perplexityServerError: "web_search: Perplexity server error ({status}) \u2014 try again later, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave",
1367
1371
  perplexityParseError: "web_search: Perplexity returned unparseable response (HTTP {status}) \u2014 try again later",
1368
1372
  exaMissingKey: "web_search: Exa backend requires an API key \u2014 set EXA_API_KEY env var or `exaApiKey` in ~/.reasonix/config.json; free 1000/mo signup at https://exa.ai",
1369
1373
  exaUnauthorized: "web_search: Exa API key rejected \u2014 check EXA_API_KEY or get one at https://exa.ai",
1370
1374
  exaRateLimit: "web_search: Exa API rate-limited or monthly quota exceeded \u2014 wait or upgrade at https://exa.ai/pricing",
1371
- exaServerError: "web_search: Exa server error ({status}) \u2014 try again later, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa",
1375
+ exaServerError: "web_search: Exa server error ({status}) \u2014 try again later, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave",
1372
1376
  exaParseError: "web_search: Exa returned unparseable response (HTTP {status}) \u2014 try again later",
1377
+ braveMissingKey: "web_search: Brave Search requires an API key \u2014 set BRAVE_SEARCH_API_KEY (or BRAVE_API_KEY) env var or `braveApiKey` in ~/.reasonix/config.json; free 2000/mo signup at https://brave.com/search/api/",
1378
+ braveUnauthorized: "web_search: Brave Search API key rejected \u2014 check BRAVE_SEARCH_API_KEY or get one at https://brave.com/search/api/",
1379
+ braveRateLimit: "web_search: Brave Search API rate-limited or monthly quota exceeded \u2014 wait or upgrade at https://brave.com/search/api/",
1380
+ braveServerError: "web_search: Brave Search server error ({status}) \u2014 try again later, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave",
1381
+ braveParseError: "web_search: Brave Search returned unparseable response (HTTP {status}) \u2014 try again later",
1373
1382
  fetchStatus: "web_fetch {status} for {url} \u2014 try: confirm the URL resolves in a browser; status suggests the host returned an error page",
1374
1383
  fetchRateLimit429: "web_fetch 429 for {url} \u2014 try: wait 10s before retrying; the host is rate-limiting this client",
1375
1384
  fetchForbidden403: "web_fetch 403 for {url} \u2014 try: the host is blocking this client; the page may require login or block bots \u2014 use web_search snippets instead",
@@ -2708,6 +2717,7 @@ var de = {
2708
2717
  usageTavily: " /search-engine tavily Tavily-API verwenden (LLM-freundlich, kostenlos 1000/Monat \u2014 setze TAVILY_API_KEY oder tavilyApiKey in der Konfiguration; erhalte einen unter https://tavily.com)",
2709
2718
  usagePerplexity: " /search-engine perplexity Perplexity AI verwenden (AI-native Antwort + Quellenangaben \u2014 setze PERPLEXITY_API_KEY oder perplexityApiKey in der Konfiguration; erhalte einen unter https://perplexity.ai/settings/api)",
2710
2719
  usageExa: " /search-engine exa Exa-API verwenden (AI-native Antwort + Quellenangaben, kostenlos 1000/Monat \u2014 setze EXA_API_KEY oder exaApiKey in der Konfiguration; registriere dich unter https://exa.ai)",
2720
+ usageBrave: " /search-engine brave Brave Search API nutzen (unabh\xE4ngiger Index, kostenlos 2000/Monat \u2014 setze BRAVE_SEARCH_API_KEY oder braveApiKey in der Konfiguration; Schl\xFCssel unter https://brave.com/search/api/)",
2711
2721
  alias: "Alias: /se",
2712
2722
  searxngInfo: "SearXNG ist eine selbst gehostete Metasuchmaschine (https://github.com/searxng/searxng).",
2713
2723
  searxngInstall: "Installiere mit: docker run -d -p 8080:8080 searxng/searxng",
@@ -2717,6 +2727,7 @@ var de = {
2717
2727
  switchedTavilyNote: " Setze TAVILY_API_KEY oder `tavilyApiKey` in der Konfiguration; kostenlos 1000/Monat unter https://tavily.com.",
2718
2728
  switchedPerplexityNote: " Setze PERPLEXITY_API_KEY oder `perplexityApiKey` in der Konfiguration; erhalte einen unter https://perplexity.ai/settings/api.",
2719
2729
  switchedExaNote: " Setze EXA_API_KEY oder `exaApiKey` in der Konfiguration; registriere dich unter https://exa.ai.",
2730
+ switchedBraveNote: " Setze BRAVE_SEARCH_API_KEY (oder BRAVE_API_KEY) oder `braveApiKey` in der Konfiguration; 2000 kostenlose Zugriffe pro Monat unter https://brave.com/search/api/.",
2720
2731
  keyNeeded: 'Kein API-Schl\xFCssel f\xFCr "{engine}" konfiguriert.\n\n 1. Setze die {envVar}-Umgebungsvariable\n 2. Oder gib ihn inline an: /search-engine {engine} <dein-schl\xFCssel>\n 3. Oder f\xFCge "{engine}ApiKey" zu ~/.reasonix/config.json hinzu\n\nWiederhole dann /search-engine {engine}.',
2721
2732
  keySaved: " API-Schl\xFCssel in der Konfiguration gespeichert.",
2722
2733
  confirmed: 'Websuchmaschine auf "{engine}" gesetzt{detail}. Der n\xE4chste Assistenten-Turn \xFCbernimmt die \xC4nderung.',
@@ -3021,38 +3032,43 @@ var de = {
3021
3032
  },
3022
3033
  webErrors: {
3023
3034
  ...EN.webErrors,
3024
- status: "web_search {status} \u2014 versuche: Das Such-Backend hat einen Fehler zur\xFCckgegeben; formuliere die Abfrage um oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa",
3035
+ status: "web_search {status} \u2014 versuche: Das Such-Backend hat einen Fehler zur\xFCckgegeben; formuliere die Abfrage um oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave|ollama",
3025
3036
  rateLimit429: "web_search 429 \u2014 versuche: 10s warten vor erneuter Abfrage oder Abfrage umformulieren; das Such-Backend hat das Rate-Limit f\xFCr diesen Client erreicht",
3026
- forbidden403: "web_search 403 \u2014 versuche: Das Such-Backend blockiert diesen Client; wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa oder warte und versuche es sp\xE4ter erneut",
3037
+ forbidden403: "web_search 403 \u2014 versuche: Das Such-Backend blockiert diesen Client; wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave|ollama oder warte und versuche es sp\xE4ter erneut",
3027
3038
  serverError5xx: "web_search {status} \u2014 versuche: \xD6ffne die Such-URL in einem Browser; falls sie l\xE4dt, ist dies vor\xFCbergehend und ein erneuter Versuch in 30s kann helfen",
3028
- bingBlocked: "web_search: Bing-Anti-Bot-Seite \u2014 Rate-Limit erreicht oder blockiert \u2014 versuche: 30s warten und erneut versuchen, oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa",
3029
- bingNoResults: "web_search: 0 Ergebnisse, aber die Antwort sieht nicht wie eine echte leere Seite aus ({chars} Zeichen, erste 120: {preview}) \u2014 versuche: formuliere die Abfrage mit einfacheren Begriffen um oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa",
3039
+ bingBlocked: "web_search: Bing-Anti-Bot-Seite \u2014 Rate-Limit erreicht oder blockiert \u2014 versuche: 30s warten und erneut versuchen, oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave|ollama",
3040
+ bingNoResults: "web_search: 0 Ergebnisse, aber die Antwort sieht nicht wie eine echte leere Seite aus ({chars} Zeichen, erste 120: {preview}) \u2014 versuche: formuliere die Abfrage mit einfacheren Begriffen um oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave|ollama",
3030
3041
  invalidEndpoint: 'web_search: ung\xFCltiger SearXNG-Endpunkt "{endpoint}" \u2014 versuche: setze eine g\xFCltige URL mit /search-endpoint http://host:port',
3031
3042
  endpointMustBeHttp: "web_search: SearXNG-Endpunkt muss http(s) sein, {protocol} erhalten \u2014 versuche: setze eine g\xFCltige URL mit /search-endpoint http://host:port",
3032
- cannotReach: "web_search: SearXNG-Server unter {endpoint} nicht erreichbar \u2014 versuche: SearXNG installieren und starten (https://github.com/searxng/searxng, z.B. `docker run -d -p 8080:8080 searxng/searxng`), oder wechsle zu einer anderen Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa",
3033
- searxngNoResults: "web_search: 0 Ergebnisse, aber SearXNG-Antwort sieht nicht wie eine leere Ergebnisseite aus ({chars} Zeichen) \u2014 versuche: formuliere die Abfrage mit einfacheren Begriffen um oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa",
3043
+ cannotReach: "web_search: SearXNG-Server unter {endpoint} nicht erreichbar \u2014 versuche: SearXNG installieren und starten (https://github.com/searxng/searxng, z.B. `docker run -d -p 8080:8080 searxng/searxng`), oder wechsle zu einer anderen Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave|ollama",
3044
+ searxngNoResults: "web_search: 0 Ergebnisse, aber SearXNG-Antwort sieht nicht wie eine leere Ergebnisseite aus ({chars} Zeichen) \u2014 versuche: formuliere die Abfrage mit einfacheren Begriffen um oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave|ollama",
3034
3045
  metasoMissingKey: "web_search: Metaso ben\xF6tigt einen API-Schl\xFCssel \u2014 setze METASO_API_KEY oder konfiguriere einen mit /search-engine metaso <schl\xFCssel>. Erhalte einen unter https://metaso.cn/search-api/playground",
3035
3046
  metasoDailyLimit: "web_search: Metaso-Tageslimit erreicht \u2014 setze METASO_API_KEY oder erhalte einen Schl\xFCssel unter https://metaso.cn/search-api/playground",
3036
3047
  metasoUnauthorized: "web_search: Metaso-API-Schl\xFCssel abgelehnt \u2014 \xFCberpr\xFCfe METASO_API_KEY oder erhalte einen unter https://metaso.cn/search-api/playground",
3037
3048
  metasoRateLimit: "web_search: Metaso-Rate-Limit erreicht \u2014 warte und versuche es erneut, oder erhalte einen eigenen API-Schl\xFCssel unter https://metaso.cn/search-api/playground",
3038
- metasoServerError: "web_search: Metaso-Serverfehler ({status}) \u2014 versuche es sp\xE4ter erneut oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa",
3049
+ metasoServerError: "web_search: Metaso-Serverfehler ({status}) \u2014 versuche es sp\xE4ter erneut oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave|ollama",
3039
3050
  metasoParseError: "web_search: Metaso hat unparsbare Antwort zur\xFCckgegeben (HTTP {status}) \u2014 versuche es sp\xE4ter erneut",
3040
3051
  metasoApiError: "web_search: Metaso-API-Fehler (Code {code}: {message}) \u2014 versuche es sp\xE4ter erneut",
3041
3052
  tavilyMissingKey: "web_search: Tavily-Backend ben\xF6tigt einen API-Schl\xFCssel \u2014 setze TAVILY_API_KEY-Umgebungsvariable oder `tavilyApiKey` in ~/.reasonix/config.json; kostenlose 1000/Monat-Registrierung unter https://tavily.com",
3042
3053
  tavilyUnauthorized: "web_search: Tavily-API-Schl\xFCssel abgelehnt \u2014 \xFCberpr\xFCfe TAVILY_API_KEY oder erhalte einen unter https://tavily.com",
3043
- tavilyRateLimit: "web_search: Tavily-Rate-Limit erreicht oder monatliches Kontingent \xFCberschritten \u2014 warte, wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa oder upgrade deinen Tavily-Plan",
3044
- tavilyServerError: "web_search: Tavily-Serverfehler ({status}) \u2014 versuche es sp\xE4ter erneut oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa",
3054
+ tavilyRateLimit: "web_search: Tavily-Rate-Limit erreicht oder monatliches Kontingent \xFCberschritten \u2014 warte, wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave|ollama oder upgrade deinen Tavily-Plan",
3055
+ tavilyServerError: "web_search: Tavily-Serverfehler ({status}) \u2014 versuche es sp\xE4ter erneut oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave|ollama",
3045
3056
  tavilyParseError: "web_search: Tavily hat unparsbare Antwort zur\xFCckgegeben (HTTP {status}) \u2014 versuche es sp\xE4ter erneut",
3046
3057
  perplexityMissingKey: "web_search: Perplexity-Backend ben\xF6tigt einen API-Schl\xFCssel \u2014 setze PERPLEXITY_API_KEY-Umgebungsvariable oder `perplexityApiKey` in ~/.reasonix/config.json; erhalte einen unter https://perplexity.ai/settings/api",
3047
3058
  perplexityUnauthorized: "web_search: Perplexity-API-Schl\xFCssel abgelehnt \u2014 \xFCberpr\xFCfe PERPLEXITY_API_KEY oder erhalte einen unter https://perplexity.ai/settings/api",
3048
- perplexityRateLimit: "web_search: Perplexity-Rate-Limit erreicht \u2014 warte und versuche es erneut, oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa",
3049
- perplexityServerError: "web_search: Perplexity-Serverfehler ({status}) \u2014 versuche es sp\xE4ter erneut oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa",
3059
+ perplexityRateLimit: "web_search: Perplexity-Rate-Limit erreicht \u2014 warte und versuche es erneut, oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave|ollama",
3060
+ perplexityServerError: "web_search: Perplexity-Serverfehler ({status}) \u2014 versuche es sp\xE4ter erneut oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave|ollama",
3050
3061
  perplexityParseError: "web_search: Perplexity hat unparsbare Antwort zur\xFCckgegeben (HTTP {status}) \u2014 versuche es sp\xE4ter erneut",
3051
3062
  exaMissingKey: "web_search: Exa-Backend ben\xF6tigt einen API-Schl\xFCssel \u2014 setze EXA_API_KEY-Umgebungsvariable oder `exaApiKey` in ~/.reasonix/config.json; kostenlose 1000/Monat-Registrierung unter https://exa.ai",
3052
3063
  exaUnauthorized: "web_search: Exa-API-Schl\xFCssel abgelehnt \u2014 \xFCberpr\xFCfe EXA_API_KEY oder erhalte einen unter https://exa.ai",
3053
3064
  exaRateLimit: "web_search: Exa-API-Rate-Limit erreicht oder monatliches Kontingent \xFCberschritten \u2014 warte oder upgrade unter https://exa.ai/pricing",
3054
- exaServerError: "web_search: Exa-Serverfehler ({status}) \u2014 versuche es sp\xE4ter erneut oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa",
3065
+ exaServerError: "web_search: Exa-Serverfehler ({status}) \u2014 versuche es sp\xE4ter erneut oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave|ollama",
3055
3066
  exaParseError: "web_search: Exa hat unparsbare Antwort zur\xFCckgegeben (HTTP {status}) \u2014 versuche es sp\xE4ter erneut",
3067
+ braveMissingKey: "web_search: F\xFCr Brave Search ist ein API-Schl\xFCssel erforderlich \u2014 setze die Umgebungsvariable BRAVE_SEARCH_API_KEY (oder BRAVE_API_KEY) oder `braveApiKey` in ~/.reasonix/config.json; kostenlose Anmeldung mit 2000 Einheiten pro Monat unter https://brave.com/search/api/",
3068
+ braveUnauthorized: "web_search: Brave-Such-API-Schl\xFCssel abgelehnt \u2014 \xFCberpr\xFCfe BRAVE_SEARCH_API_KEY oder beantrage einen unter https://brave.com/search/api/",
3069
+ braveRateLimit: "web_search: Die Brave Search API unterliegt einer Ratenbegrenzung oder das monatliche Kontingent wurde \xFCberschritten \u2014 warten oder ein Upgrade durchf\xFChren unter https://brave.com/search/api/",
3070
+ braveServerError: "web_search: Fehler beim Brave-Suchserver ({status}) \u2014 sp\xE4ter erneut versuchen oder die Engine wechseln mit /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave|ollama",
3071
+ braveParseError: "web_search: Brave Search hat eine nicht auswertbare Antwort zur\xFCckgegeben (HTTP {status}) \u2014 sp\xE4ter erneut versuchen",
3056
3072
  fetchStatus: "web_fetch {status} f\xFCr {url} \u2014 versuche: Best\xE4tige, dass die URL im Browser aufgel\xF6st wird; der Status deutet darauf hin, dass der Host eine Fehlerseite zur\xFCckgegeben hat",
3057
3073
  fetchRateLimit429: "web_fetch 429 f\xFCr {url} \u2014 versuche: 10s warten vor erneuter Abfrage; der Host ratelimitet diesen Client",
3058
3074
  fetchForbidden403: "web_fetch 403 f\xFCr {url} \u2014 versuche: Der Host blockiert diesen Client; die Seite erfordert m\xF6glicherweise eine Anmeldung oder blockiert Bots \u2014 verwende stattdessen web_search-Ausz\xFCge",
@@ -3858,6 +3874,22 @@ var ru = {
3858
3874
  riskMed: " \u0441\u0440\u0435\u0434",
3859
3875
  riskHigh: " \u0432\u044B\u0441",
3860
3876
  completeMsg: "\u25B8 \u043F\u043B\u0430\u043D \u0432\u044B\u043F\u043E\u043B\u043D\u0435\u043D \u2014 \u0432\u0441\u0435 {total} \u0448\u0430\u0433(\u043E\u0432) \u0441\u0434\u0435\u043B\u0430\u043D\u044B \xB7 \u0430\u0440\u0445\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u043D"
3877
+ },
3878
+ webErrors: {
3879
+ ...EN.webErrors,
3880
+ braveMissingKey: "web_search: \u0414\u043B\u044F \u0440\u0430\u0431\u043E\u0442\u044B Brave Search \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044F \u043A\u043B\u044E\u0447 API \u2014 \u0437\u0430\u0434\u0430\u0439\u0442\u0435 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u0443\u044E \u0441\u0440\u0435\u0434\u044B BRAVE_SEARCH_API_KEY (\u0438\u043B\u0438 BRAVE_API_KEY) \u0438\u043B\u0438 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 `braveApiKey` \u0432 \u0444\u0430\u0439\u043B\u0435 ~/.reasonix/config.json; \u0431\u0435\u0441\u043F\u043B\u0430\u0442\u043D\u0430\u044F \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044F \u0441 \u043B\u0438\u043C\u0438\u0442\u043E\u043C 2000 \u0437\u0430\u043F\u0440\u043E\u0441\u043E\u0432 \u0432 \u043C\u0435\u0441\u044F\u0446 \u043D\u0430 \u0441\u0430\u0439\u0442\u0435 https://brave.com/search/api/",
3881
+ braveUnauthorized: "web_search: \u041A\u043B\u044E\u0447 API Brave Search \u043E\u0442\u043A\u043B\u043E\u043D\u0435\u043D \u2014 \u043F\u0440\u043E\u0432\u0435\u0440\u044C\u0442\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 BRAVE_SEARCH_API_KEY \u0438\u043B\u0438 \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u0435 \u043D\u043E\u0432\u044B\u0439 \u043A\u043B\u044E\u0447 \u043D\u0430 \u0441\u0430\u0439\u0442\u0435 https://brave.com/search/api/",
3882
+ braveRateLimit: "web_search: \u041F\u0440\u0435\u0432\u044B\u0448\u0435\u043D \u043B\u0438\u043C\u0438\u0442 \u0437\u0430\u043F\u0440\u043E\u0441\u043E\u0432 \u0438\u043B\u0438 \u043C\u0435\u0441\u044F\u0447\u043D\u0430\u044F \u043A\u0432\u043E\u0442\u0430 \u0434\u043B\u044F Brave Search API \u2014 \u043F\u043E\u0434\u043E\u0436\u0434\u0438\u0442\u0435 \u0438\u043B\u0438 \u043F\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043D\u0430 \u043F\u043B\u0430\u0442\u043D\u0443\u044E \u0432\u0435\u0440\u0441\u0438\u044E \u043D\u0430 \u0441\u0430\u0439\u0442\u0435 https://brave.com/search/api/",
3883
+ braveServerError: "web_search: \u041E\u0448\u0438\u0431\u043A\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 Brave Search ({status}) \u2014 \u043F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u043F\u043E\u0437\u0436\u0435 \u0438\u043B\u0438 \u0432\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0434\u0440\u0443\u0433\u043E\u0439 \u043F\u043E\u0438\u0441\u043A\u043E\u0432\u0438\u043A \u0441 \u043F\u043E\u043C\u043E\u0449\u044C\u044E /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave",
3884
+ braveParseError: "web_search: Brave Search \u0432\u0435\u0440\u043D\u0443\u043B \u043D\u0435\u0440\u0430\u0437\u0431\u043E\u0440\u0447\u0438\u0432\u044B\u0439 \u043E\u0442\u0432\u0435\u0442 (HTTP {status}) \u2014 \u043F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u043F\u043E\u0437\u0436\u0435"
3885
+ },
3886
+ handlers: {
3887
+ ...EN.handlers,
3888
+ webSearchEngine: {
3889
+ ...EN.handlers.webSearchEngine,
3890
+ usageBrave: " /search-engine brave \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442 Brave Search API (\u043D\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043C\u044B\u0439 \u0438\u043D\u0434\u0435\u043A\u0441, \u0431\u0435\u0441\u043F\u043B\u0430\u0442\u043D\u043E 2000 \u0437\u0430\u043F\u0440\u043E\u0441\u043E\u0432 \u0432 \u043C\u0435\u0441\u044F\u0446 \u2014 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u0435 BRAVE_SEARCH_API_KEY \u0438\u043B\u0438 braveApiKey \u0432 \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438; \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C \u043A\u043B\u044E\u0447 \u043C\u043E\u0436\u043D\u043E \u043D\u0430 \u0441\u0430\u0439\u0442\u0435 https://brave.com/search/api/)",
3891
+ switchedBraveNote: " \u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 BRAVE_SEARCH_API_KEY (\u0438\u043B\u0438 BRAVE_API_KEY) \u0438\u043B\u0438 `braveApiKey` \u0432 \u0444\u0430\u0439\u043B\u0435 \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438; 2000 \u0431\u0435\u0441\u043F\u043B\u0430\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0440\u043E\u0441\u043E\u0432 \u0432 \u043C\u0435\u0441\u044F\u0446 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B \u043F\u043E \u0430\u0434\u0440\u0435\u0441\u0443 https://brave.com/search/api/."
3892
+ }
3861
3893
  }
3862
3894
  };
3863
3895
 
@@ -4252,8 +4284,8 @@ var zhCN = {
4252
4284
  argsHint: "<question>"
4253
4285
  },
4254
4286
  "search-engine": {
4255
- description: "\u5207\u6362\u7F51\u7EDC\u641C\u7D22\u540E\u7AEF \u2014 bing\uFF08\u9ED8\u8BA4\uFF0C\u56FD\u5185\u88F8 IP \u76F4\u8FDE\uFF09\u3001searxng\uFF08\u81EA\u6258\u7BA1\uFF09\u3001metaso\uFF08\u6BCF\u65E5 100 \u6B21\uFF09\u3001tavily\uFF08\u6BCF\u6708 1000 \u6B21\u514D\u8D39\uFF09\u3001perplexity\uFF08AI \u76F4\u63A5\u56DE\u7B54\uFF09\u6216 exa\uFF08AI \u76F4\u63A5\u56DE\u7B54\uFF09",
4256
- argsHint: "<bing|searxng|metaso|tavily|perplexity|exa> [<key>]"
4287
+ description: "\u5207\u6362\u7F51\u7EDC\u641C\u7D22\u540E\u7AEF \u2014 bing\uFF08\u9ED8\u8BA4\uFF0C\u56FD\u5185\u88F8 IP \u76F4\u8FDE\uFF09\u3001searxng\uFF08\u81EA\u6258\u7BA1\uFF09\u3001metaso\uFF08\u6BCF\u65E5 100 \u6B21\uFF09\u3001tavily\uFF08\u6BCF\u6708 1000 \u6B21\u514D\u8D39\uFF09\u3001perplexity\uFF08AI \u76F4\u63A5\u56DE\u7B54\uFF09\u3001exa\uFF08AI \u76F4\u63A5\u56DE\u7B54\uFF09\u6216 ollama\uFF08Ollama \u4E91\u7AEF\u641C\u7D22\uFF09",
4288
+ argsHint: "<bing|searxng|metaso|tavily|perplexity|exa|brave|ollama> [<key>]"
4257
4289
  }
4258
4290
  },
4259
4291
  wizard: {
@@ -4898,6 +4930,8 @@ var zhCN = {
4898
4930
  usageTavily: " /search-engine tavily \u4F7F\u7528 Tavily API\uFF08LLM \u53CB\u597D\uFF0C\u6BCF\u6708 1000 \u6B21\u514D\u8D39 \u2014 \u8BBE\u7F6E TAVILY_API_KEY \u6216 config \u7684 tavilyApiKey\uFF1B\u6CE8\u518C https://tavily.com\uFF09",
4899
4931
  usagePerplexity: " /search-engine perplexity \u4F7F\u7528 Perplexity AI\uFF08AI \u76F4\u63A5\u56DE\u7B54 + \u5F15\u7528 \u2014 \u8BBE\u7F6E PERPLEXITY_API_KEY \u6216 config \u7684 perplexityApiKey\uFF1B\u5728 https://perplexity.ai/settings/api \u83B7\u53D6\u5BC6\u94A5\uFF09",
4900
4932
  usageExa: " /search-engine exa \u4F7F\u7528 Exa API\uFF08AI \u76F4\u63A5\u56DE\u7B54 + \u5F15\u7528\uFF0C\u6BCF\u6708 1000 \u6B21\u514D\u8D39 \u2014 \u8BBE\u7F6E EXA_API_KEY \u6216 config \u7684 exaApiKey\uFF1B\u6CE8\u518C https://exa.ai\uFF09",
4933
+ usageOllama: " /search-engine ollama \u4F7F\u7528 Ollama \u4E91\u7AEF\u7F51\u9875\u641C\u7D22 \u2014 \u8BBE\u7F6E OLLAMA_API_KEY \u6216 config \u7684 ollamaApiKey\uFF1B\u5728 https://ollama.com/settings/keys \u83B7\u53D6\u5BC6\u94A5",
4934
+ usageBrave: " /search-engine brave \u4F7F\u7528 Brave Search API\uFF08\u72EC\u7ACB\u7D22\u5F15\uFF0C\u6BCF\u6708 2000 \u6B21\u514D\u8D39 \u2014 \u8BBE\u7F6E BRAVE_SEARCH_API_KEY \u6216 config \u7684 braveApiKey\uFF1B\u5728 https://brave.com/search/api/ \u83B7\u53D6\u5BC6\u94A5\uFF09",
4901
4935
  alias: "\u522B\u540D\uFF1A/se",
4902
4936
  searxngInfo: "SearXNG \u662F\u4E00\u4E2A\u81EA\u6258\u7BA1\u7684\u5143\u641C\u7D22\u5F15\u64CE\uFF08https://github.com/searxng/searxng\uFF09\u3002",
4903
4937
  searxngInstall: "\u5B89\u88C5\u547D\u4EE4\uFF1A docker run -d -p 8080:8080 searxng/searxng",
@@ -4907,6 +4941,8 @@ var zhCN = {
4907
4941
  switchedTavilyNote: " \u8BF7\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF TAVILY_API_KEY \u6216 config \u4E2D\u7684 `tavilyApiKey`\uFF1Bhttps://tavily.com \u6BCF\u6708 1000 \u6B21\u514D\u8D39\u3002",
4908
4942
  switchedPerplexityNote: " \u8BF7\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF PERPLEXITY_API_KEY \u6216 config \u4E2D\u7684 `perplexityApiKey`\uFF1B\u5728 https://perplexity.ai/settings/api \u83B7\u53D6\u5BC6\u94A5\u3002",
4909
4943
  switchedExaNote: " \u8BF7\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF EXA_API_KEY \u6216 config \u4E2D\u7684 `exaApiKey`\uFF1B\u6CE8\u518C https://exa.ai\u3002",
4944
+ switchedOllamaNote: " \u8BF7\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF OLLAMA_API_KEY \u6216 config \u4E2D\u7684 `ollamaApiKey`\uFF1B\u5728 https://ollama.com/settings/keys \u83B7\u53D6\u5BC6\u94A5\u3002",
4945
+ switchedBraveNote: " \u8BF7\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF BRAVE_SEARCH_API_KEY \u6216 config \u4E2D\u7684 `braveApiKey`\uFF1Bhttps://brave.com/search/api/ \u6BCF\u6708 2000 \u6B21\u514D\u8D39\u3002",
4910
4946
  keyNeeded: '\u672A\u914D\u7F6E "{engine}" \u7684 API \u5BC6\u94A5\u3002\n\n 1. \u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF {envVar}\n 2. \u6216\u5185\u8054\u63D0\u4F9B\uFF1A/search-engine {engine} <your-key>\n 3. \u6216\u5728 ~/.reasonix/config.json \u4E2D\u6DFB\u52A0 "{engine}ApiKey"\n\n\u5B8C\u6210\u540E\u91CD\u65B0\u6267\u884C /search-engine {engine}\u3002',
4911
4947
  keySaved: " API \u5BC6\u94A5\u5DF2\u4FDD\u5B58\u5230\u914D\u7F6E\u3002",
4912
4948
  confirmed: '\u7F51\u9875\u641C\u7D22\u5F15\u64CE\u5DF2\u8BBE\u4E3A "{engine}"{detail}\u3002\u4E0B\u4E00\u8F6E\u6A21\u578B\u8C03\u7528\u5C06\u751F\u6548\u3002',
@@ -5191,38 +5227,43 @@ var zhCN = {
5191
5227
  probeFailed: "\u63A2\u6D4B\u5931\u8D25 \u2014 {message}"
5192
5228
  },
5193
5229
  webErrors: {
5194
- status: "web_search {status} \u2014 try: \u641C\u7D22\u540E\u7AEF\u8FD4\u56DE\u9519\u8BEF\uFF1B\u8BF7\u6539\u5199\u67E5\u8BE2\uFF0C\u6216\u4F7F\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa \u5207\u6362\u5F15\u64CE",
5230
+ status: "web_search {status} \u2014 try: \u641C\u7D22\u540E\u7AEF\u8FD4\u56DE\u9519\u8BEF\uFF1B\u8BF7\u6539\u5199\u67E5\u8BE2\uFF0C\u6216\u4F7F\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave \u5207\u6362\u5F15\u64CE",
5195
5231
  rateLimit429: "web_search 429 \u2014 try: \u7B49\u5F85 10 \u79D2\u540E\u91CD\u8BD5\uFF0C\u6216\u6539\u5199\u67E5\u8BE2\uFF1B\u641C\u7D22\u540E\u7AEF\u6B63\u5728\u5BF9\u8BE5\u5BA2\u6237\u7AEF\u8FDB\u884C\u9650\u6D41",
5196
- forbidden403: "web_search 403 \u2014 try: \u641C\u7D22\u540E\u7AEF\u62D2\u7EDD\u8BE5\u5BA2\u6237\u7AEF\u8BBF\u95EE\uFF1B\u4F7F\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa \u5207\u6362\u5F15\u64CE\uFF0C\u6216\u7A0D\u540E\u91CD\u8BD5",
5232
+ forbidden403: "web_search 403 \u2014 try: \u641C\u7D22\u540E\u7AEF\u62D2\u7EDD\u8BE5\u5BA2\u6237\u7AEF\u8BBF\u95EE\uFF1B\u4F7F\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave \u5207\u6362\u5F15\u64CE\uFF0C\u6216\u7A0D\u540E\u91CD\u8BD5",
5197
5233
  serverError5xx: "web_search {status} \u2014 try: \u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00\u641C\u7D22 URL\uFF1B\u82E5\u80FD\u52A0\u8F7D\u5219\u5C5E\u4E34\u65F6\u6545\u969C\uFF0C\u7B49 30 \u79D2\u91CD\u8BD5\u5373\u53EF",
5198
- bingBlocked: "web_search: Bing \u53CD\u722C\u9875\u9762 \u2014 \u9891\u7387\u9650\u5236\u6216\u88AB\u5C4F\u853D \u2014 try: \u7B49\u5F85 30 \u79D2\u540E\u91CD\u8BD5\uFF0C\u6216\u4F7F\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa \u5207\u6362\u5F15\u64CE",
5199
- bingNoResults: "web_search: \u8FD4\u56DE 0 \u6761\u7ED3\u679C\u4F46\u54CD\u5E94\u770B\u8D77\u6765\u4E0D\u662F\u6B63\u5E38\u7A7A\u7ED3\u679C\u9875\uFF08{chars} \u5B57\u7B26\uFF0C\u524D 120 \u5B57\u7B26\uFF1A{preview}\uFF09\u2014 try: \u4F7F\u7528\u66F4\u7B80\u5355\u7684\u5173\u952E\u8BCD\u6539\u5199\u67E5\u8BE2\uFF0C\u6216\u4F7F\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa \u5207\u6362\u5F15\u64CE",
5234
+ bingBlocked: "web_search: Bing \u53CD\u722C\u9875\u9762 \u2014 \u9891\u7387\u9650\u5236\u6216\u88AB\u5C4F\u853D \u2014 try: \u7B49\u5F85 30 \u79D2\u540E\u91CD\u8BD5\uFF0C\u6216\u4F7F\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave \u5207\u6362\u5F15\u64CE",
5235
+ bingNoResults: "web_search: \u8FD4\u56DE 0 \u6761\u7ED3\u679C\u4F46\u54CD\u5E94\u770B\u8D77\u6765\u4E0D\u662F\u6B63\u5E38\u7A7A\u7ED3\u679C\u9875\uFF08{chars} \u5B57\u7B26\uFF0C\u524D 120 \u5B57\u7B26\uFF1A{preview}\uFF09\u2014 try: \u4F7F\u7528\u66F4\u7B80\u5355\u7684\u5173\u952E\u8BCD\u6539\u5199\u67E5\u8BE2\uFF0C\u6216\u4F7F\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave \u5207\u6362\u5F15\u64CE",
5200
5236
  invalidEndpoint: 'web_search: \u65E0\u6548\u7684 SearXNG \u7AEF\u70B9 "{endpoint}" \u2014 try: \u4F7F\u7528 /search-endpoint http://host:port \u8BBE\u7F6E\u6709\u6548\u7684 URL',
5201
5237
  endpointMustBeHttp: "web_search: SearXNG \u7AEF\u70B9\u5FC5\u987B\u662F http(s) \u534F\u8BAE\uFF0C\u5F53\u524D\u4E3A {protocol} \u2014 try: \u4F7F\u7528 /search-endpoint http://host:port \u8BBE\u7F6E\u6709\u6548\u7684 URL",
5202
- cannotReach: "web_search: \u65E0\u6CD5\u8BBF\u95EE SearXNG \u670D\u52A1\u5668 {endpoint} \u2014 try: \u5B89\u88C5\u5E76\u542F\u52A8 SearXNG\uFF08https://github.com/searxng/searxng\uFF0C\u4F8B\u5982 `docker run -d -p 8080:8080 searxng/searxng`\uFF09\uFF0C\u6216\u4F7F\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa \u5207\u6362\u5F15\u64CE",
5203
- searxngNoResults: "web_search: \u8FD4\u56DE 0 \u6761\u7ED3\u679C\u4F46 SearXNG \u54CD\u5E94\u770B\u8D77\u6765\u4E0D\u662F\u6B63\u5E38\u7A7A\u7ED3\u679C\u9875\uFF08{chars} \u5B57\u7B26\uFF09\u2014 try: \u4F7F\u7528\u66F4\u7B80\u5355\u7684\u5173\u952E\u8BCD\u6539\u5199\u67E5\u8BE2\uFF0C\u6216\u4F7F\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa \u5207\u6362\u5F15\u64CE",
5238
+ cannotReach: "web_search: \u65E0\u6CD5\u8BBF\u95EE SearXNG \u670D\u52A1\u5668 {endpoint} \u2014 try: \u5B89\u88C5\u5E76\u542F\u52A8 SearXNG\uFF08https://github.com/searxng/searxng\uFF0C\u4F8B\u5982 `docker run -d -p 8080:8080 searxng/searxng`\uFF09\uFF0C\u6216\u4F7F\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave \u5207\u6362\u5F15\u64CE",
5239
+ searxngNoResults: "web_search: \u8FD4\u56DE 0 \u6761\u7ED3\u679C\u4F46 SearXNG \u54CD\u5E94\u770B\u8D77\u6765\u4E0D\u662F\u6B63\u5E38\u7A7A\u7ED3\u679C\u9875\uFF08{chars} \u5B57\u7B26\uFF09\u2014 try: \u4F7F\u7528\u66F4\u7B80\u5355\u7684\u5173\u952E\u8BCD\u6539\u5199\u67E5\u8BE2\uFF0C\u6216\u4F7F\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave \u5207\u6362\u5F15\u64CE",
5204
5240
  metasoMissingKey: "web_search: Metaso \u9700\u8981 API \u5BC6\u94A5 \u2014 \u8BBE\u7F6E METASO_API_KEY\uFF0C\u6216\u4F7F\u7528 /search-engine metaso <key> \u914D\u7F6E\uFF1B\u53EF\u5728 https://metaso.cn/search-api/playground \u83B7\u53D6\u5BC6\u94A5",
5205
5241
  metasoDailyLimit: "web_search: Metaso \u6BCF\u65E5\u641C\u7D22\u6B21\u6570\u5DF2\u8FBE\u4E0A\u9650 \u2014 \u8BBE\u7F6E METASO_API_KEY\uFF0C\u6216\u5728 https://metaso.cn/search-api/playground \u83B7\u53D6\u5BC6\u94A5",
5206
5242
  metasoUnauthorized: "web_search: Metaso API \u5BC6\u94A5\u88AB\u62D2\u7EDD \u2014 \u68C0\u67E5 METASO_API_KEY\uFF0C\u6216\u5728 https://metaso.cn/search-api/playground \u83B7\u53D6\u5BC6\u94A5",
5207
5243
  metasoRateLimit: "web_search: Metaso \u8BF7\u6C42\u9891\u7387\u9650\u5236 \u2014 \u7B49\u5F85\u540E\u91CD\u8BD5\uFF0C\u6216\u5728 https://metaso.cn/search-api/playground \u83B7\u53D6\u81EA\u5DF1\u7684\u5BC6\u94A5",
5208
- metasoServerError: "web_search: Metaso \u670D\u52A1\u5668\u9519\u8BEF\uFF08{status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5\uFF0C\u6216\u4F7F\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa \u5207\u6362\u5F15\u64CE",
5244
+ metasoServerError: "web_search: Metaso \u670D\u52A1\u5668\u9519\u8BEF\uFF08{status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5\uFF0C\u6216\u4F7F\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave \u5207\u6362\u5F15\u64CE",
5209
5245
  metasoParseError: "web_search: Metaso \u8FD4\u56DE\u65E0\u6CD5\u89E3\u6790\u7684\u54CD\u5E94\uFF08HTTP {status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5",
5210
5246
  metasoApiError: "web_search: Metaso API \u9519\u8BEF\uFF08code {code}: {message}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5",
5211
5247
  tavilyMissingKey: "web_search: Tavily \u540E\u7AEF\u9700\u8981 API \u5BC6\u94A5 \u2014 \u8BBE\u7F6E TAVILY_API_KEY \u73AF\u5883\u53D8\u91CF\uFF0C\u6216\u5728 ~/.reasonix/config.json \u4E2D\u914D\u7F6E `tavilyApiKey`\uFF1Bhttps://tavily.com \u6BCF\u6708 1000 \u6B21\u514D\u8D39",
5212
5248
  tavilyUnauthorized: "web_search: Tavily API \u5BC6\u94A5\u88AB\u62D2\u7EDD \u2014 \u68C0\u67E5 TAVILY_API_KEY\uFF0C\u6216\u5728 https://tavily.com \u83B7\u53D6\u5BC6\u94A5",
5213
- tavilyRateLimit: "web_search: Tavily \u8BF7\u6C42\u9891\u7387\u9650\u5236\u6216\u6708\u5EA6\u914D\u989D\u7528\u5C3D \u2014 \u7B49\u5F85\u3001\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa \u5207\u6362\u5F15\u64CE\uFF0C\u6216\u5347\u7EA7 Tavily \u8BA1\u5212",
5214
- tavilyServerError: "web_search: Tavily \u670D\u52A1\u5668\u9519\u8BEF\uFF08{status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5\uFF0C\u6216\u4F7F\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa \u5207\u6362\u5F15\u64CE",
5249
+ tavilyRateLimit: "web_search: Tavily \u8BF7\u6C42\u9891\u7387\u9650\u5236\u6216\u6708\u5EA6\u914D\u989D\u7528\u5C3D \u2014 \u7B49\u5F85\u3001\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave \u5207\u6362\u5F15\u64CE\uFF0C\u6216\u5347\u7EA7 Tavily \u8BA1\u5212",
5250
+ tavilyServerError: "web_search: Tavily \u670D\u52A1\u5668\u9519\u8BEF\uFF08{status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5\uFF0C\u6216\u4F7F\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave \u5207\u6362\u5F15\u64CE",
5215
5251
  tavilyParseError: "web_search: Tavily \u8FD4\u56DE\u65E0\u6CD5\u89E3\u6790\u7684\u54CD\u5E94\uFF08HTTP {status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5",
5216
5252
  perplexityMissingKey: "web_search: Perplexity \u540E\u7AEF\u9700\u8981 API \u5BC6\u94A5 \u2014 \u8BBE\u7F6E PERPLEXITY_API_KEY \u73AF\u5883\u53D8\u91CF\uFF0C\u6216\u5728 ~/.reasonix/config.json \u4E2D\u914D\u7F6E `perplexityApiKey`\uFF1B\u5728 https://perplexity.ai/settings/api \u83B7\u53D6\u5BC6\u94A5",
5217
5253
  perplexityUnauthorized: "web_search: Perplexity API \u5BC6\u94A5\u88AB\u62D2\u7EDD \u2014 \u68C0\u67E5 PERPLEXITY_API_KEY\uFF0C\u6216\u5728 https://perplexity.ai/settings/api \u83B7\u53D6\u5BC6\u94A5",
5218
- perplexityRateLimit: "web_search: Perplexity \u8BF7\u6C42\u9891\u7387\u9650\u5236 \u2014 \u7B49\u5F85\u540E\u91CD\u8BD5\uFF0C\u6216\u4F7F\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa \u5207\u6362\u5F15\u64CE",
5219
- perplexityServerError: "web_search: Perplexity \u670D\u52A1\u5668\u9519\u8BEF\uFF08{status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5\uFF0C\u6216\u4F7F\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa \u5207\u6362\u5F15\u64CE",
5254
+ perplexityRateLimit: "web_search: Perplexity \u8BF7\u6C42\u9891\u7387\u9650\u5236 \u2014 \u7B49\u5F85\u540E\u91CD\u8BD5\uFF0C\u6216\u4F7F\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave \u5207\u6362\u5F15\u64CE",
5255
+ perplexityServerError: "web_search: Perplexity \u670D\u52A1\u5668\u9519\u8BEF\uFF08{status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5\uFF0C\u6216\u4F7F\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave \u5207\u6362\u5F15\u64CE",
5220
5256
  perplexityParseError: "web_search: Perplexity \u8FD4\u56DE\u65E0\u6CD5\u89E3\u6790\u7684\u54CD\u5E94\uFF08HTTP {status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5",
5221
5257
  exaMissingKey: "web_search: Exa \u540E\u7AEF\u9700\u8981 API \u5BC6\u94A5 \u2014 \u8BBE\u7F6E EXA_API_KEY \u73AF\u5883\u53D8\u91CF\uFF0C\u6216\u5728 ~/.reasonix/config.json \u4E2D\u914D\u7F6E `exaApiKey`\uFF1Bhttps://exa.ai \u6BCF\u6708 1000 \u6B21\u514D\u8D39",
5222
5258
  exaUnauthorized: "web_search: Exa API \u5BC6\u94A5\u88AB\u62D2\u7EDD \u2014 \u68C0\u67E5 EXA_API_KEY\uFF0C\u6216\u5728 https://exa.ai \u83B7\u53D6\u5BC6\u94A5",
5223
5259
  exaRateLimit: "web_search: Exa \u8BF7\u6C42\u9891\u7387\u9650\u5236\u6216\u6708\u5EA6\u914D\u989D\u7528\u5C3D \u2014 \u7B49\u5F85\u5347\u7EA7\uFF0C\u6216\u5728 https://exa.ai/pricing \u67E5\u770B\u8BA1\u5212",
5224
- exaServerError: "web_search: Exa \u670D\u52A1\u5668\u9519\u8BEF\uFF08{status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5\uFF0C\u6216\u4F7F\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa \u5207\u6362\u5F15\u64CE",
5260
+ exaServerError: "web_search: Exa \u670D\u52A1\u5668\u9519\u8BEF\uFF08{status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5\uFF0C\u6216\u4F7F\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave \u5207\u6362\u5F15\u64CE",
5225
5261
  exaParseError: "web_search: Exa \u8FD4\u56DE\u65E0\u6CD5\u89E3\u6790\u7684\u54CD\u5E94\uFF08HTTP {status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5",
5262
+ braveMissingKey: "web_search: Brave Search \u9700\u8981 API \u5BC6\u94A5 \u2014 \u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF BRAVE_SEARCH_API_KEY\uFF08\u6216 BRAVE_API_KEY\uFF09\u6216 config \u7684 `braveApiKey`\uFF1Bhttps://brave.com/search/api/ \u6BCF\u6708 2000 \u6B21\u514D\u8D39",
5263
+ braveUnauthorized: "web_search: Brave Search API \u5BC6\u94A5\u88AB\u62D2\u7EDD \u2014 \u68C0\u67E5 BRAVE_SEARCH_API_KEY \u6216\u5728 https://brave.com/search/api/ \u83B7\u53D6\u5BC6\u94A5",
5264
+ braveRateLimit: "web_search: Brave Search API \u8FBE\u5230\u901F\u7387\u9650\u5236\u6216\u6708\u5EA6\u914D\u989D\u7528\u5C3D \u2014 \u7B49\u5F85\u6216\u5347\u7EA7 https://brave.com/search/api/",
5265
+ braveServerError: "web_search: Brave Search \u670D\u52A1\u5668\u9519\u8BEF\uFF08{status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5\uFF0C\u6216\u4F7F\u7528 /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave \u5207\u6362\u5F15\u64CE",
5266
+ braveParseError: "web_search: Brave Search \u8FD4\u56DE\u65E0\u6CD5\u89E3\u6790\u7684\u54CD\u5E94\uFF08HTTP {status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5",
5226
5267
  fetchStatus: "web_fetch {status} for {url} \u2014 try: \u5728\u6D4F\u89C8\u5668\u4E2D\u786E\u8BA4\u8BE5 URL \u80FD\u5426\u8BBF\u95EE\uFF1B\u8BE5\u72B6\u6001\u7801\u8868\u660E\u76EE\u6807\u4E3B\u673A\u8FD4\u56DE\u4E86\u9519\u8BEF\u9875\u9762",
5227
5268
  fetchRateLimit429: "web_fetch 429 for {url} \u2014 try: \u7B49\u5F85 10 \u79D2\u540E\u91CD\u8BD5\uFF1B\u76EE\u6807\u4E3B\u673A\u6B63\u5728\u5BF9\u8BE5\u5BA2\u6237\u7AEF\u8FDB\u884C\u9650\u6D41",
5228
5269
  fetchForbidden403: "web_fetch 403 for {url} \u2014 try: \u76EE\u6807\u4E3B\u673A\u62D2\u7EDD\u8BE5\u5BA2\u6237\u7AEF\u8BBF\u95EE\uFF1B\u8BE5\u9875\u9762\u53EF\u80FD\u9700\u8981\u767B\u5F55\u6216\u5C4F\u853D\u722C\u866B \u2014 \u6539\u7528 web_search \u6458\u8981",
@@ -5606,4 +5647,4 @@ export {
5606
5647
  tObj,
5607
5648
  t
5608
5649
  };
5609
- //# sourceMappingURL=chunk-CLHMV6OL.js.map
5650
+ //# sourceMappingURL=chunk-U7G72DHQ.js.map