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.
- package/README.md +1 -0
- package/README.zh-CN.md +1 -0
- package/dashboard/dist/app.css +1 -1
- package/dashboard/dist/app.js +13 -13
- package/dashboard/dist/app.js.map +1 -1
- package/dist/cli/{acp-NEUYWGUU.js → acp-ABNDGEYC.js} +63 -30
- package/dist/cli/acp-ABNDGEYC.js.map +1 -0
- package/dist/cli/chat-377YZV56.js +49 -0
- package/dist/cli/{chunk-FY5UERSG.js → chunk-2WZT27GR.js} +9 -9
- package/dist/cli/{chunk-B4MOGWHW.js → chunk-4EHRIP5U.js} +7 -7
- package/dist/cli/chunk-4EHRIP5U.js.map +1 -0
- package/dist/cli/{chunk-RCC73DWQ.js → chunk-4SBXAHR6.js} +4 -4
- package/dist/cli/{chunk-5YLEKX2V.js → chunk-4V4TKQMB.js} +4 -4
- package/dist/cli/{chunk-5YLEKX2V.js.map → chunk-4V4TKQMB.js.map} +1 -1
- package/dist/cli/chunk-7ZO6H6ZK.js +54 -0
- package/dist/cli/chunk-7ZO6H6ZK.js.map +1 -0
- package/dist/cli/{chunk-3OXD5CBM.js → chunk-A6GSOADP.js} +17870 -16070
- package/dist/cli/chunk-A6GSOADP.js.map +1 -0
- package/dist/cli/{chunk-Z663GVUB.js → chunk-APOSDBAU.js} +3 -3
- package/dist/cli/{chunk-CTRM32BP.js → chunk-B5JISV5I.js} +2 -2
- package/dist/cli/{chunk-HNZ4727T.js → chunk-DFHI2MRB.js} +412 -152
- package/dist/cli/chunk-DFHI2MRB.js.map +1 -0
- package/dist/cli/{chunk-CGVW5W7N.js → chunk-EPIHGOM3.js} +14 -14
- package/dist/cli/{chunk-CGVW5W7N.js.map → chunk-EPIHGOM3.js.map} +1 -1
- package/dist/cli/{chunk-77JIQ7SL.js → chunk-EQFZIHKJ.js} +8 -8
- package/dist/cli/chunk-EQFZIHKJ.js.map +1 -0
- package/dist/cli/{chunk-XNMXVL6C.js → chunk-FB27YXPX.js} +2 -2
- package/dist/cli/{chunk-ARBGTNHM.js → chunk-FK7NXDRP.js} +2 -2
- package/dist/cli/{chunk-AOYUW3HR.js → chunk-GCNBIWK7.js} +22 -2
- package/dist/cli/chunk-GCNBIWK7.js.map +1 -0
- package/dist/cli/{chunk-XBYHNZ5Z.js → chunk-GMQVINZK.js} +13 -5
- package/dist/cli/chunk-GMQVINZK.js.map +1 -0
- package/dist/cli/{chunk-MVLPXZAA.js → chunk-GOASYYZ4.js} +43 -11
- package/dist/cli/{chunk-MVLPXZAA.js.map → chunk-GOASYYZ4.js.map} +1 -1
- package/dist/cli/{chunk-WPY7AFS6.js → chunk-I4SH5Z7S.js} +2 -2
- package/dist/cli/{chunk-MW64SQUE.js → chunk-J26XOB2T.js} +2 -2
- package/dist/cli/{chunk-DLTE4GBY.js → chunk-J4MYMBJ7.js} +3 -3
- package/dist/cli/{chunk-CFJY64UA.js → chunk-LRO63VNK.js} +2 -2
- package/dist/cli/{chunk-XUZHBQSM.js → chunk-MQJR7YQ2.js} +2 -2
- package/dist/cli/{chunk-CPCUMMSR.js → chunk-NVI4XPOQ.js} +3 -3
- package/dist/cli/{chunk-RHQOGG43.js → chunk-OHSVEXFF.js} +3 -3
- package/dist/cli/chunk-OHSVEXFF.js.map +1 -0
- package/dist/cli/{chunk-AMSK3ZLB.js → chunk-P5SUHDUQ.js} +2 -2
- package/dist/cli/{chunk-GFJJEW3Z.js → chunk-QSKDP3OS.js} +55 -5
- package/dist/cli/chunk-QSKDP3OS.js.map +1 -0
- package/dist/cli/{chunk-D6WRFR6V.js → chunk-R7JMQMLD.js} +6 -5
- package/dist/cli/chunk-R7JMQMLD.js.map +1 -0
- package/dist/cli/{chunk-VVPV5HU6.js → chunk-RRZIIMAF.js} +2 -2
- package/dist/cli/{chunk-GNRKXRRE.js → chunk-S3QII236.js} +369 -359
- package/dist/cli/{chunk-GNRKXRRE.js.map → chunk-S3QII236.js.map} +1 -1
- package/dist/cli/{chunk-HI6THNAZ.js → chunk-TGP7JGHN.js} +32 -14
- package/dist/cli/chunk-TGP7JGHN.js.map +1 -0
- package/dist/cli/{chunk-CLHMV6OL.js → chunk-U7G72DHQ.js} +83 -42
- package/dist/cli/chunk-U7G72DHQ.js.map +1 -0
- package/dist/cli/{chunk-OMNRXZNA.js → chunk-URAI4YRL.js} +2 -2
- package/dist/cli/{chunk-6QBUXA73.js → chunk-V4AXMN4X.js} +2 -2
- package/dist/cli/{chunk-2W4F3RIZ.js → chunk-XHP6NYOT.js} +3 -2
- package/dist/cli/{chunk-2W4F3RIZ.js.map → chunk-XHP6NYOT.js.map} +1 -1
- package/dist/cli/{code-WN6D4VZO.js → code-JPFZJYVW.js} +34 -34
- package/dist/cli/{commands-DHETOY7O.js → commands-IUL2CLKH.js} +4 -4
- package/dist/cli/{commit-BBUYAKZV.js → commit-JT7LYBTL.js} +3 -3
- package/dist/cli/{config-KV7VV5LG.js → config-T4RWI5NG.js} +6 -2
- package/dist/cli/{desktop-LJVXWXNF.js → desktop-AUBW2SLL.js} +122 -38
- package/dist/cli/desktop-AUBW2SLL.js.map +1 -0
- package/dist/cli/devtools-O5HOMAGZ.js +3 -0
- package/dist/cli/diff-NINZHUJR.js +165 -0
- package/dist/cli/diff-NINZHUJR.js.map +1 -0
- package/dist/cli/{doctor-GI5LOEZL.js → doctor-OMAYGY4F.js} +10 -10
- package/dist/cli/{events-LBKMLFM4.js → events-5IVFJ4H3.js} +5 -5
- package/dist/cli/index.js +38 -38
- package/dist/cli/{mcp-DKEJK5ND.js → mcp-ECGJACAP.js} +3 -3
- package/dist/cli/{mcp-browse-V7KWDY32.js → mcp-browse-NGEOHVJB.js} +15 -15
- package/dist/cli/mcp-browse-NGEOHVJB.js.map +1 -0
- package/dist/cli/{mcp-inspect-MTABNHVM.js → mcp-inspect-ZIMNRG7G.js} +5 -5
- package/dist/cli/{prompt-ATI7DKHF.js → prompt-JCC3A7AA.js} +5 -5
- package/dist/cli/{prune-sessions-YQQSZTZS.js → prune-sessions-TE4BJYO2.js} +4 -4
- package/dist/cli/{replay-ZJQ4I4CJ.js → replay-2UUTCRTG.js} +29 -29
- package/dist/cli/replay-2UUTCRTG.js.map +1 -0
- package/dist/cli/{run-HFPRNWJY.js → run-ABQYOPVM.js} +22 -22
- package/dist/cli/{server-UHKO2VVM.js → server-MPCXIW2O.js} +27 -25
- package/dist/cli/{server-UHKO2VVM.js.map → server-MPCXIW2O.js.map} +1 -1
- package/dist/cli/{sessions-IQEWWUH3.js → sessions-YBPRGIAF.js} +16 -16
- package/dist/cli/{setup-5BYKCL62.js → setup-A34LF2QE.js} +42 -42
- package/dist/cli/setup-A34LF2QE.js.map +1 -0
- package/dist/cli/{stats-OFCGOQMZ.js → stats-GKG5JZQX.js} +6 -6
- package/dist/cli/stats-GKG5JZQX.js.map +1 -0
- package/dist/cli/{version-EODUFAAI.js → version-JD6QSM4X.js} +16 -16
- package/dist/index.d.ts +36 -5
- package/dist/index.js +443 -73
- package/dist/index.js.map +1 -1
- package/package.json +7 -2
- package/dist/cli/acp-NEUYWGUU.js.map +0 -1
- package/dist/cli/chat-QA6IVFJD.js +0 -49
- package/dist/cli/chunk-3OXD5CBM.js.map +0 -1
- package/dist/cli/chunk-77JIQ7SL.js.map +0 -1
- package/dist/cli/chunk-AOYUW3HR.js.map +0 -1
- package/dist/cli/chunk-B4MOGWHW.js.map +0 -1
- package/dist/cli/chunk-CLHMV6OL.js.map +0 -1
- package/dist/cli/chunk-D6WRFR6V.js.map +0 -1
- package/dist/cli/chunk-GFJJEW3Z.js.map +0 -1
- package/dist/cli/chunk-HI6THNAZ.js.map +0 -1
- package/dist/cli/chunk-HNZ4727T.js.map +0 -1
- package/dist/cli/chunk-I3NE5S63.js +0 -54
- package/dist/cli/chunk-I3NE5S63.js.map +0 -1
- package/dist/cli/chunk-RHQOGG43.js.map +0 -1
- package/dist/cli/chunk-XBYHNZ5Z.js.map +0 -1
- package/dist/cli/desktop-LJVXWXNF.js.map +0 -1
- package/dist/cli/diff-2JHMQAHI.js +0 -165
- package/dist/cli/diff-2JHMQAHI.js.map +0 -1
- package/dist/cli/mcp-browse-V7KWDY32.js.map +0 -1
- package/dist/cli/replay-ZJQ4I4CJ.js.map +0 -1
- package/dist/cli/setup-5BYKCL62.js.map +0 -1
- /package/dist/cli/{chat-QA6IVFJD.js.map → chat-377YZV56.js.map} +0 -0
- /package/dist/cli/{chunk-FY5UERSG.js.map → chunk-2WZT27GR.js.map} +0 -0
- /package/dist/cli/{chunk-RCC73DWQ.js.map → chunk-4SBXAHR6.js.map} +0 -0
- /package/dist/cli/{chunk-Z663GVUB.js.map → chunk-APOSDBAU.js.map} +0 -0
- /package/dist/cli/{chunk-CTRM32BP.js.map → chunk-B5JISV5I.js.map} +0 -0
- /package/dist/cli/{chunk-XNMXVL6C.js.map → chunk-FB27YXPX.js.map} +0 -0
- /package/dist/cli/{chunk-ARBGTNHM.js.map → chunk-FK7NXDRP.js.map} +0 -0
- /package/dist/cli/{chunk-WPY7AFS6.js.map → chunk-I4SH5Z7S.js.map} +0 -0
- /package/dist/cli/{chunk-MW64SQUE.js.map → chunk-J26XOB2T.js.map} +0 -0
- /package/dist/cli/{chunk-DLTE4GBY.js.map → chunk-J4MYMBJ7.js.map} +0 -0
- /package/dist/cli/{chunk-CFJY64UA.js.map → chunk-LRO63VNK.js.map} +0 -0
- /package/dist/cli/{chunk-XUZHBQSM.js.map → chunk-MQJR7YQ2.js.map} +0 -0
- /package/dist/cli/{chunk-CPCUMMSR.js.map → chunk-NVI4XPOQ.js.map} +0 -0
- /package/dist/cli/{chunk-AMSK3ZLB.js.map → chunk-P5SUHDUQ.js.map} +0 -0
- /package/dist/cli/{chunk-VVPV5HU6.js.map → chunk-RRZIIMAF.js.map} +0 -0
- /package/dist/cli/{chunk-OMNRXZNA.js.map → chunk-URAI4YRL.js.map} +0 -0
- /package/dist/cli/{chunk-6QBUXA73.js.map → chunk-V4AXMN4X.js.map} +0 -0
- /package/dist/cli/{code-WN6D4VZO.js.map → code-JPFZJYVW.js.map} +0 -0
- /package/dist/cli/{commands-DHETOY7O.js.map → commands-IUL2CLKH.js.map} +0 -0
- /package/dist/cli/{commit-BBUYAKZV.js.map → commit-JT7LYBTL.js.map} +0 -0
- /package/dist/cli/{config-KV7VV5LG.js.map → config-T4RWI5NG.js.map} +0 -0
- /package/dist/cli/{doctor-GI5LOEZL.js.map → devtools-O5HOMAGZ.js.map} +0 -0
- /package/dist/cli/{prompt-ATI7DKHF.js.map → doctor-OMAYGY4F.js.map} +0 -0
- /package/dist/cli/{events-LBKMLFM4.js.map → events-5IVFJ4H3.js.map} +0 -0
- /package/dist/cli/{mcp-DKEJK5ND.js.map → mcp-ECGJACAP.js.map} +0 -0
- /package/dist/cli/{mcp-inspect-MTABNHVM.js.map → mcp-inspect-ZIMNRG7G.js.map} +0 -0
- /package/dist/cli/{stats-OFCGOQMZ.js.map → prompt-JCC3A7AA.js.map} +0 -0
- /package/dist/cli/{prune-sessions-YQQSZTZS.js.map → prune-sessions-TE4BJYO2.js.map} +0 -0
- /package/dist/cli/{run-HFPRNWJY.js.map → run-ABQYOPVM.js.map} +0 -0
- /package/dist/cli/{sessions-IQEWWUH3.js.map → sessions-YBPRGIAF.js.map} +0 -0
- /package/dist/cli/{version-EODUFAAI.js.map → version-JD6QSM4X.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -634,6 +634,20 @@ function loadExaApiKey(path2 = defaultConfigPath()) {
|
|
|
634
634
|
if (cfg && typeof cfg === "string" && cfg.trim()) return cfg.trim();
|
|
635
635
|
return void 0;
|
|
636
636
|
}
|
|
637
|
+
function loadOllamaApiKey(path2 = defaultConfigPath()) {
|
|
638
|
+
if (process.env.OLLAMA_API_KEY) return process.env.OLLAMA_API_KEY.trim();
|
|
639
|
+
if (process.env.ollamaApiKey) return process.env.ollamaApiKey.trim();
|
|
640
|
+
const cfg = readConfig(path2).ollamaApiKey;
|
|
641
|
+
if (cfg && typeof cfg === "string" && cfg.trim()) return cfg.trim();
|
|
642
|
+
return void 0;
|
|
643
|
+
}
|
|
644
|
+
function loadBraveApiKey(path2 = defaultConfigPath()) {
|
|
645
|
+
if (process.env.BRAVE_SEARCH_API_KEY) return process.env.BRAVE_SEARCH_API_KEY.trim();
|
|
646
|
+
if (process.env.BRAVE_API_KEY) return process.env.BRAVE_API_KEY.trim();
|
|
647
|
+
const cfg = readConfig(path2).braveApiKey;
|
|
648
|
+
if (cfg && typeof cfg === "string" && cfg.trim()) return cfg.trim();
|
|
649
|
+
return void 0;
|
|
650
|
+
}
|
|
637
651
|
function defaultConfigPath() {
|
|
638
652
|
return join(homedir(), ".reasonix", "config.json");
|
|
639
653
|
}
|
|
@@ -786,6 +800,8 @@ function webSearchEngine(path2 = defaultConfigPath()) {
|
|
|
786
800
|
if (cfg === "tavily") return "tavily";
|
|
787
801
|
if (cfg === "perplexity") return "perplexity";
|
|
788
802
|
if (cfg === "exa") return "exa";
|
|
803
|
+
if (cfg === "brave") return "brave";
|
|
804
|
+
if (cfg === "ollama") return "ollama";
|
|
789
805
|
return "bing";
|
|
790
806
|
}
|
|
791
807
|
function webSearchEndpoint(path2 = defaultConfigPath()) {
|
|
@@ -795,8 +811,10 @@ function webSearchEndpoint(path2 = defaultConfigPath()) {
|
|
|
795
811
|
}
|
|
796
812
|
function saveApiKey(key, path2 = defaultConfigPath()) {
|
|
797
813
|
const cfg = readConfig(path2);
|
|
798
|
-
|
|
814
|
+
const trimmed = key.trim();
|
|
815
|
+
cfg.apiKey = trimmed;
|
|
799
816
|
writeConfig(cfg, path2);
|
|
817
|
+
if (trimmed) process.env.DEEPSEEK_API_KEY = trimmed;
|
|
800
818
|
}
|
|
801
819
|
function findProjectKey(cfg, rootDir) {
|
|
802
820
|
const projects = cfg.projects;
|
|
@@ -970,6 +988,44 @@ var Usage = class _Usage {
|
|
|
970
988
|
);
|
|
971
989
|
}
|
|
972
990
|
};
|
|
991
|
+
function replaceLoneSurrogates(value) {
|
|
992
|
+
let out = "";
|
|
993
|
+
let last = 0;
|
|
994
|
+
for (let i = 0; i < value.length; i++) {
|
|
995
|
+
const code = value.charCodeAt(i);
|
|
996
|
+
if (code >= 55296 && code <= 56319) {
|
|
997
|
+
const next = value.charCodeAt(i + 1);
|
|
998
|
+
if (next >= 56320 && next <= 57343) {
|
|
999
|
+
i++;
|
|
1000
|
+
} else {
|
|
1001
|
+
out += value.slice(last, i);
|
|
1002
|
+
out += "\uFFFD";
|
|
1003
|
+
last = i + 1;
|
|
1004
|
+
}
|
|
1005
|
+
continue;
|
|
1006
|
+
}
|
|
1007
|
+
if (code >= 56320 && code <= 57343) {
|
|
1008
|
+
out += value.slice(last, i);
|
|
1009
|
+
out += "\uFFFD";
|
|
1010
|
+
last = i + 1;
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
if (last === 0) return value;
|
|
1014
|
+
return out + value.slice(last);
|
|
1015
|
+
}
|
|
1016
|
+
function sanitizeJsonTransportValue(value) {
|
|
1017
|
+
if (typeof value === "string") return replaceLoneSurrogates(value);
|
|
1018
|
+
if (value === null || typeof value !== "object") return value;
|
|
1019
|
+
if (Array.isArray(value)) return value.map((item) => sanitizeJsonTransportValue(item));
|
|
1020
|
+
const out = {};
|
|
1021
|
+
for (const [key, item] of Object.entries(value)) {
|
|
1022
|
+
out[key] = sanitizeJsonTransportValue(item);
|
|
1023
|
+
}
|
|
1024
|
+
return out;
|
|
1025
|
+
}
|
|
1026
|
+
function stringifyJsonTransport(value) {
|
|
1027
|
+
return JSON.stringify(sanitizeJsonTransportValue(value));
|
|
1028
|
+
}
|
|
973
1029
|
var DeepSeekClient = class {
|
|
974
1030
|
apiKey;
|
|
975
1031
|
baseUrl;
|
|
@@ -1019,6 +1075,7 @@ var DeepSeekClient = class {
|
|
|
1019
1075
|
messages: opts.messages,
|
|
1020
1076
|
stream
|
|
1021
1077
|
};
|
|
1078
|
+
if (stream) payload.stream_options = { include_usage: true };
|
|
1022
1079
|
if (opts.tools?.length) payload.tools = opts.tools;
|
|
1023
1080
|
if (opts.temperature !== void 0) payload.temperature = opts.temperature;
|
|
1024
1081
|
if (opts.maxTokens !== void 0) payload.max_tokens = opts.maxTokens;
|
|
@@ -1092,7 +1149,7 @@ var DeepSeekClient = class {
|
|
|
1092
1149
|
Authorization: `Bearer ${this.apiKey}`,
|
|
1093
1150
|
"Content-Type": "application/json"
|
|
1094
1151
|
},
|
|
1095
|
-
body:
|
|
1152
|
+
body: stringifyJsonTransport(this.buildPayload(opts, false)),
|
|
1096
1153
|
signal
|
|
1097
1154
|
},
|
|
1098
1155
|
{ ...this.retry, signal }
|
|
@@ -1133,7 +1190,7 @@ var DeepSeekClient = class {
|
|
|
1133
1190
|
"Content-Type": "application/json",
|
|
1134
1191
|
Accept: "text/event-stream"
|
|
1135
1192
|
},
|
|
1136
|
-
body:
|
|
1193
|
+
body: stringifyJsonTransport(this.buildPayload(opts, true)),
|
|
1137
1194
|
signal
|
|
1138
1195
|
},
|
|
1139
1196
|
{ ...this.retry, signal }
|
|
@@ -1192,7 +1249,18 @@ var DeepSeekClient = class {
|
|
|
1192
1249
|
continue;
|
|
1193
1250
|
}
|
|
1194
1251
|
if (done) break;
|
|
1195
|
-
|
|
1252
|
+
let value;
|
|
1253
|
+
let streamDone;
|
|
1254
|
+
try {
|
|
1255
|
+
({ value, done: streamDone } = await reader.read());
|
|
1256
|
+
} catch (readErr) {
|
|
1257
|
+
const cause = readErr instanceof Error ? readErr : new Error(String(readErr));
|
|
1258
|
+
const code = "code" in cause && typeof cause.code === "string" ? cause.code : void 0;
|
|
1259
|
+
throw Object.assign(new Error(`SSE body read failed: ${cause.message}`), {
|
|
1260
|
+
phase: "stream_body_read",
|
|
1261
|
+
code
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1196
1264
|
if (streamDone) break;
|
|
1197
1265
|
parser.feed(decoder.decode(value, { stream: true }));
|
|
1198
1266
|
}
|
|
@@ -1728,8 +1796,8 @@ var EN = {
|
|
|
1728
1796
|
argsHint: "<question>"
|
|
1729
1797
|
},
|
|
1730
1798
|
"search-engine": {
|
|
1731
|
-
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),
|
|
1732
|
-
argsHint: "<bing|searxng|metaso|tavily|perplexity|exa> [<key>]"
|
|
1799
|
+
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)",
|
|
1800
|
+
argsHint: "<bing|searxng|metaso|tavily|perplexity|exa|brave|ollama> [<key>]"
|
|
1733
1801
|
}
|
|
1734
1802
|
},
|
|
1735
1803
|
wizard: {
|
|
@@ -2374,6 +2442,8 @@ var EN = {
|
|
|
2374
2442
|
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)",
|
|
2375
2443
|
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)",
|
|
2376
2444
|
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)",
|
|
2445
|
+
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",
|
|
2446
|
+
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/)",
|
|
2377
2447
|
alias: "Alias: /se",
|
|
2378
2448
|
searxngInfo: "SearXNG is a self-hosted metasearch engine (https://github.com/searxng/searxng).",
|
|
2379
2449
|
searxngInstall: "Install it with: docker run -d -p 8080:8080 searxng/searxng",
|
|
@@ -2383,6 +2453,8 @@ var EN = {
|
|
|
2383
2453
|
switchedTavilyNote: " Set TAVILY_API_KEY or `tavilyApiKey` in config; free 1000/mo at https://tavily.com.",
|
|
2384
2454
|
switchedPerplexityNote: " Set PERPLEXITY_API_KEY or `perplexityApiKey` in config; get one at https://perplexity.ai/settings/api.",
|
|
2385
2455
|
switchedExaNote: " Set EXA_API_KEY or `exaApiKey` in config; sign up at https://exa.ai.",
|
|
2456
|
+
switchedOllamaNote: " Set OLLAMA_API_KEY or `ollamaApiKey` in config; get one at https://ollama.com/settings/keys.",
|
|
2457
|
+
switchedBraveNote: " Set BRAVE_SEARCH_API_KEY (or BRAVE_API_KEY) or `braveApiKey` in config; free 2000/mo at https://brave.com/search/api/.",
|
|
2386
2458
|
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}.',
|
|
2387
2459
|
keySaved: " API key saved to config.",
|
|
2388
2460
|
confirmed: 'Web search engine set to "{engine}"{detail}. Next assistant turn will pick up the change.',
|
|
@@ -2667,38 +2739,43 @@ var EN = {
|
|
|
2667
2739
|
probeFailed: "probe failed \u2014 {message}"
|
|
2668
2740
|
},
|
|
2669
2741
|
webErrors: {
|
|
2670
|
-
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",
|
|
2742
|
+
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",
|
|
2671
2743
|
rateLimit429: "web_search 429 \u2014 try: wait 10s before retrying, or rephrase the query; the search backend is rate-limiting this client",
|
|
2672
|
-
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",
|
|
2744
|
+
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",
|
|
2673
2745
|
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",
|
|
2674
|
-
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",
|
|
2675
|
-
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",
|
|
2746
|
+
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",
|
|
2747
|
+
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",
|
|
2676
2748
|
invalidEndpoint: 'web_search: invalid SearXNG endpoint "{endpoint}" \u2014 try: set a valid URL with /search-endpoint http://host:port',
|
|
2677
2749
|
endpointMustBeHttp: "web_search: SearXNG endpoint must be http(s), got {protocol} \u2014 try: set a valid URL with /search-endpoint http://host:port",
|
|
2678
|
-
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",
|
|
2679
|
-
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",
|
|
2750
|
+
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",
|
|
2751
|
+
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",
|
|
2680
2752
|
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",
|
|
2681
2753
|
metasoDailyLimit: "web_search: Metaso daily search limit reached \u2014 set METASO_API_KEY or get a key at https://metaso.cn/search-api/playground",
|
|
2682
2754
|
metasoUnauthorized: "web_search: Metaso API key rejected \u2014 check METASO_API_KEY or get one at https://metaso.cn/search-api/playground",
|
|
2683
2755
|
metasoRateLimit: "web_search: Metaso rate-limited \u2014 wait and retry, or get your own API key at https://metaso.cn/search-api/playground",
|
|
2684
|
-
metasoServerError: "web_search: Metaso server error ({status}) \u2014 try again later, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa",
|
|
2756
|
+
metasoServerError: "web_search: Metaso server error ({status}) \u2014 try again later, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave",
|
|
2685
2757
|
metasoParseError: "web_search: Metaso returned unparseable response (HTTP {status}) \u2014 try again later",
|
|
2686
2758
|
metasoApiError: "web_search: Metaso API error (code {code}: {message}) \u2014 try again later",
|
|
2687
2759
|
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",
|
|
2688
2760
|
tavilyUnauthorized: "web_search: Tavily API key rejected \u2014 check TAVILY_API_KEY or get one at https://tavily.com",
|
|
2689
|
-
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",
|
|
2690
|
-
tavilyServerError: "web_search: Tavily server error ({status}) \u2014 try again later, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa",
|
|
2761
|
+
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",
|
|
2762
|
+
tavilyServerError: "web_search: Tavily server error ({status}) \u2014 try again later, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave",
|
|
2691
2763
|
tavilyParseError: "web_search: Tavily returned unparseable response (HTTP {status}) \u2014 try again later",
|
|
2692
2764
|
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",
|
|
2693
2765
|
perplexityUnauthorized: "web_search: Perplexity API key rejected \u2014 check PERPLEXITY_API_KEY or get one at https://perplexity.ai/settings/api",
|
|
2694
|
-
perplexityRateLimit: "web_search: Perplexity rate-limited \u2014 wait and retry, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa",
|
|
2695
|
-
perplexityServerError: "web_search: Perplexity server error ({status}) \u2014 try again later, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa",
|
|
2766
|
+
perplexityRateLimit: "web_search: Perplexity rate-limited \u2014 wait and retry, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave",
|
|
2767
|
+
perplexityServerError: "web_search: Perplexity server error ({status}) \u2014 try again later, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave",
|
|
2696
2768
|
perplexityParseError: "web_search: Perplexity returned unparseable response (HTTP {status}) \u2014 try again later",
|
|
2697
2769
|
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",
|
|
2698
2770
|
exaUnauthorized: "web_search: Exa API key rejected \u2014 check EXA_API_KEY or get one at https://exa.ai",
|
|
2699
2771
|
exaRateLimit: "web_search: Exa API rate-limited or monthly quota exceeded \u2014 wait or upgrade at https://exa.ai/pricing",
|
|
2700
|
-
exaServerError: "web_search: Exa server error ({status}) \u2014 try again later, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa",
|
|
2772
|
+
exaServerError: "web_search: Exa server error ({status}) \u2014 try again later, or switch engine with /search-engine bing|searxng|metaso|tavily|perplexity|exa|brave",
|
|
2701
2773
|
exaParseError: "web_search: Exa returned unparseable response (HTTP {status}) \u2014 try again later",
|
|
2774
|
+
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/",
|
|
2775
|
+
braveUnauthorized: "web_search: Brave Search API key rejected \u2014 check BRAVE_SEARCH_API_KEY or get one at https://brave.com/search/api/",
|
|
2776
|
+
braveRateLimit: "web_search: Brave Search API rate-limited or monthly quota exceeded \u2014 wait or upgrade at https://brave.com/search/api/",
|
|
2777
|
+
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",
|
|
2778
|
+
braveParseError: "web_search: Brave Search returned unparseable response (HTTP {status}) \u2014 try again later",
|
|
2702
2779
|
fetchStatus: "web_fetch {status} for {url} \u2014 try: confirm the URL resolves in a browser; status suggests the host returned an error page",
|
|
2703
2780
|
fetchRateLimit429: "web_fetch 429 for {url} \u2014 try: wait 10s before retrying; the host is rate-limiting this client",
|
|
2704
2781
|
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",
|
|
@@ -4037,6 +4114,7 @@ var de = {
|
|
|
4037
4114
|
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)",
|
|
4038
4115
|
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)",
|
|
4039
4116
|
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)",
|
|
4117
|
+
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/)",
|
|
4040
4118
|
alias: "Alias: /se",
|
|
4041
4119
|
searxngInfo: "SearXNG ist eine selbst gehostete Metasuchmaschine (https://github.com/searxng/searxng).",
|
|
4042
4120
|
searxngInstall: "Installiere mit: docker run -d -p 8080:8080 searxng/searxng",
|
|
@@ -4046,6 +4124,7 @@ var de = {
|
|
|
4046
4124
|
switchedTavilyNote: " Setze TAVILY_API_KEY oder `tavilyApiKey` in der Konfiguration; kostenlos 1000/Monat unter https://tavily.com.",
|
|
4047
4125
|
switchedPerplexityNote: " Setze PERPLEXITY_API_KEY oder `perplexityApiKey` in der Konfiguration; erhalte einen unter https://perplexity.ai/settings/api.",
|
|
4048
4126
|
switchedExaNote: " Setze EXA_API_KEY oder `exaApiKey` in der Konfiguration; registriere dich unter https://exa.ai.",
|
|
4127
|
+
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/.",
|
|
4049
4128
|
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}.',
|
|
4050
4129
|
keySaved: " API-Schl\xFCssel in der Konfiguration gespeichert.",
|
|
4051
4130
|
confirmed: 'Websuchmaschine auf "{engine}" gesetzt{detail}. Der n\xE4chste Assistenten-Turn \xFCbernimmt die \xC4nderung.',
|
|
@@ -4350,38 +4429,43 @@ var de = {
|
|
|
4350
4429
|
},
|
|
4351
4430
|
webErrors: {
|
|
4352
4431
|
...EN.webErrors,
|
|
4353
|
-
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",
|
|
4432
|
+
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",
|
|
4354
4433
|
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",
|
|
4355
|
-
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",
|
|
4434
|
+
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",
|
|
4356
4435
|
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",
|
|
4357
|
-
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",
|
|
4358
|
-
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",
|
|
4436
|
+
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",
|
|
4437
|
+
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",
|
|
4359
4438
|
invalidEndpoint: 'web_search: ung\xFCltiger SearXNG-Endpunkt "{endpoint}" \u2014 versuche: setze eine g\xFCltige URL mit /search-endpoint http://host:port',
|
|
4360
4439
|
endpointMustBeHttp: "web_search: SearXNG-Endpunkt muss http(s) sein, {protocol} erhalten \u2014 versuche: setze eine g\xFCltige URL mit /search-endpoint http://host:port",
|
|
4361
|
-
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",
|
|
4362
|
-
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",
|
|
4440
|
+
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",
|
|
4441
|
+
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",
|
|
4363
4442
|
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",
|
|
4364
4443
|
metasoDailyLimit: "web_search: Metaso-Tageslimit erreicht \u2014 setze METASO_API_KEY oder erhalte einen Schl\xFCssel unter https://metaso.cn/search-api/playground",
|
|
4365
4444
|
metasoUnauthorized: "web_search: Metaso-API-Schl\xFCssel abgelehnt \u2014 \xFCberpr\xFCfe METASO_API_KEY oder erhalte einen unter https://metaso.cn/search-api/playground",
|
|
4366
4445
|
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",
|
|
4367
|
-
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",
|
|
4446
|
+
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",
|
|
4368
4447
|
metasoParseError: "web_search: Metaso hat unparsbare Antwort zur\xFCckgegeben (HTTP {status}) \u2014 versuche es sp\xE4ter erneut",
|
|
4369
4448
|
metasoApiError: "web_search: Metaso-API-Fehler (Code {code}: {message}) \u2014 versuche es sp\xE4ter erneut",
|
|
4370
4449
|
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",
|
|
4371
4450
|
tavilyUnauthorized: "web_search: Tavily-API-Schl\xFCssel abgelehnt \u2014 \xFCberpr\xFCfe TAVILY_API_KEY oder erhalte einen unter https://tavily.com",
|
|
4372
|
-
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",
|
|
4373
|
-
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",
|
|
4451
|
+
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",
|
|
4452
|
+
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",
|
|
4374
4453
|
tavilyParseError: "web_search: Tavily hat unparsbare Antwort zur\xFCckgegeben (HTTP {status}) \u2014 versuche es sp\xE4ter erneut",
|
|
4375
4454
|
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",
|
|
4376
4455
|
perplexityUnauthorized: "web_search: Perplexity-API-Schl\xFCssel abgelehnt \u2014 \xFCberpr\xFCfe PERPLEXITY_API_KEY oder erhalte einen unter https://perplexity.ai/settings/api",
|
|
4377
|
-
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",
|
|
4378
|
-
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",
|
|
4456
|
+
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",
|
|
4457
|
+
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",
|
|
4379
4458
|
perplexityParseError: "web_search: Perplexity hat unparsbare Antwort zur\xFCckgegeben (HTTP {status}) \u2014 versuche es sp\xE4ter erneut",
|
|
4380
4459
|
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",
|
|
4381
4460
|
exaUnauthorized: "web_search: Exa-API-Schl\xFCssel abgelehnt \u2014 \xFCberpr\xFCfe EXA_API_KEY oder erhalte einen unter https://exa.ai",
|
|
4382
4461
|
exaRateLimit: "web_search: Exa-API-Rate-Limit erreicht oder monatliches Kontingent \xFCberschritten \u2014 warte oder upgrade unter https://exa.ai/pricing",
|
|
4383
|
-
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",
|
|
4462
|
+
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",
|
|
4384
4463
|
exaParseError: "web_search: Exa hat unparsbare Antwort zur\xFCckgegeben (HTTP {status}) \u2014 versuche es sp\xE4ter erneut",
|
|
4464
|
+
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/",
|
|
4465
|
+
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/",
|
|
4466
|
+
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/",
|
|
4467
|
+
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",
|
|
4468
|
+
braveParseError: "web_search: Brave Search hat eine nicht auswertbare Antwort zur\xFCckgegeben (HTTP {status}) \u2014 sp\xE4ter erneut versuchen",
|
|
4385
4469
|
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",
|
|
4386
4470
|
fetchRateLimit429: "web_fetch 429 f\xFCr {url} \u2014 versuche: 10s warten vor erneuter Abfrage; der Host ratelimitet diesen Client",
|
|
4387
4471
|
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",
|
|
@@ -5187,6 +5271,22 @@ var ru = {
|
|
|
5187
5271
|
riskMed: " \u0441\u0440\u0435\u0434",
|
|
5188
5272
|
riskHigh: " \u0432\u044B\u0441",
|
|
5189
5273
|
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"
|
|
5274
|
+
},
|
|
5275
|
+
webErrors: {
|
|
5276
|
+
...EN.webErrors,
|
|
5277
|
+
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/",
|
|
5278
|
+
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/",
|
|
5279
|
+
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/",
|
|
5280
|
+
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",
|
|
5281
|
+
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"
|
|
5282
|
+
},
|
|
5283
|
+
handlers: {
|
|
5284
|
+
...EN.handlers,
|
|
5285
|
+
webSearchEngine: {
|
|
5286
|
+
...EN.handlers.webSearchEngine,
|
|
5287
|
+
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/)",
|
|
5288
|
+
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/."
|
|
5289
|
+
}
|
|
5190
5290
|
}
|
|
5191
5291
|
};
|
|
5192
5292
|
|
|
@@ -5581,8 +5681,8 @@ var zhCN = {
|
|
|
5581
5681
|
argsHint: "<question>"
|
|
5582
5682
|
},
|
|
5583
5683
|
"search-engine": {
|
|
5584
|
-
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\
|
|
5585
|
-
argsHint: "<bing|searxng|metaso|tavily|perplexity|exa> [<key>]"
|
|
5684
|
+
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",
|
|
5685
|
+
argsHint: "<bing|searxng|metaso|tavily|perplexity|exa|brave|ollama> [<key>]"
|
|
5586
5686
|
}
|
|
5587
5687
|
},
|
|
5588
5688
|
wizard: {
|
|
@@ -6227,6 +6327,8 @@ var zhCN = {
|
|
|
6227
6327
|
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",
|
|
6228
6328
|
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",
|
|
6229
6329
|
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",
|
|
6330
|
+
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",
|
|
6331
|
+
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",
|
|
6230
6332
|
alias: "\u522B\u540D\uFF1A/se",
|
|
6231
6333
|
searxngInfo: "SearXNG \u662F\u4E00\u4E2A\u81EA\u6258\u7BA1\u7684\u5143\u641C\u7D22\u5F15\u64CE\uFF08https://github.com/searxng/searxng\uFF09\u3002",
|
|
6232
6334
|
searxngInstall: "\u5B89\u88C5\u547D\u4EE4\uFF1A docker run -d -p 8080:8080 searxng/searxng",
|
|
@@ -6236,6 +6338,8 @@ var zhCN = {
|
|
|
6236
6338
|
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",
|
|
6237
6339
|
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",
|
|
6238
6340
|
switchedExaNote: " \u8BF7\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF EXA_API_KEY \u6216 config \u4E2D\u7684 `exaApiKey`\uFF1B\u6CE8\u518C https://exa.ai\u3002",
|
|
6341
|
+
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",
|
|
6342
|
+
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",
|
|
6239
6343
|
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',
|
|
6240
6344
|
keySaved: " API \u5BC6\u94A5\u5DF2\u4FDD\u5B58\u5230\u914D\u7F6E\u3002",
|
|
6241
6345
|
confirmed: '\u7F51\u9875\u641C\u7D22\u5F15\u64CE\u5DF2\u8BBE\u4E3A "{engine}"{detail}\u3002\u4E0B\u4E00\u8F6E\u6A21\u578B\u8C03\u7528\u5C06\u751F\u6548\u3002',
|
|
@@ -6520,38 +6624,43 @@ var zhCN = {
|
|
|
6520
6624
|
probeFailed: "\u63A2\u6D4B\u5931\u8D25 \u2014 {message}"
|
|
6521
6625
|
},
|
|
6522
6626
|
webErrors: {
|
|
6523
|
-
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",
|
|
6627
|
+
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",
|
|
6524
6628
|
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",
|
|
6525
|
-
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",
|
|
6629
|
+
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",
|
|
6526
6630
|
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",
|
|
6527
|
-
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",
|
|
6528
|
-
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",
|
|
6631
|
+
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",
|
|
6632
|
+
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",
|
|
6529
6633
|
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',
|
|
6530
6634
|
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",
|
|
6531
|
-
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",
|
|
6532
|
-
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",
|
|
6635
|
+
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",
|
|
6636
|
+
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",
|
|
6533
6637
|
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",
|
|
6534
6638
|
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",
|
|
6535
6639
|
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",
|
|
6536
6640
|
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",
|
|
6537
|
-
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",
|
|
6641
|
+
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",
|
|
6538
6642
|
metasoParseError: "web_search: Metaso \u8FD4\u56DE\u65E0\u6CD5\u89E3\u6790\u7684\u54CD\u5E94\uFF08HTTP {status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5",
|
|
6539
6643
|
metasoApiError: "web_search: Metaso API \u9519\u8BEF\uFF08code {code}: {message}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5",
|
|
6540
6644
|
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",
|
|
6541
6645
|
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",
|
|
6542
|
-
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",
|
|
6543
|
-
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",
|
|
6646
|
+
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",
|
|
6647
|
+
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",
|
|
6544
6648
|
tavilyParseError: "web_search: Tavily \u8FD4\u56DE\u65E0\u6CD5\u89E3\u6790\u7684\u54CD\u5E94\uFF08HTTP {status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5",
|
|
6545
6649
|
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",
|
|
6546
6650
|
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",
|
|
6547
|
-
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",
|
|
6548
|
-
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",
|
|
6651
|
+
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",
|
|
6652
|
+
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",
|
|
6549
6653
|
perplexityParseError: "web_search: Perplexity \u8FD4\u56DE\u65E0\u6CD5\u89E3\u6790\u7684\u54CD\u5E94\uFF08HTTP {status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5",
|
|
6550
6654
|
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",
|
|
6551
6655
|
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",
|
|
6552
6656
|
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",
|
|
6553
|
-
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",
|
|
6657
|
+
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",
|
|
6554
6658
|
exaParseError: "web_search: Exa \u8FD4\u56DE\u65E0\u6CD5\u89E3\u6790\u7684\u54CD\u5E94\uFF08HTTP {status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5",
|
|
6659
|
+
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",
|
|
6660
|
+
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",
|
|
6661
|
+
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/",
|
|
6662
|
+
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",
|
|
6663
|
+
braveParseError: "web_search: Brave Search \u8FD4\u56DE\u65E0\u6CD5\u89E3\u6790\u7684\u54CD\u5E94\uFF08HTTP {status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5",
|
|
6555
6664
|
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",
|
|
6556
6665
|
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",
|
|
6557
6666
|
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",
|
|
@@ -7493,14 +7602,19 @@ import {
|
|
|
7493
7602
|
writeFileSync as writeFileSync2
|
|
7494
7603
|
} from "fs";
|
|
7495
7604
|
import { homedir as homedir3 } from "os";
|
|
7496
|
-
import { join as join4, relative, resolve as resolve2 } from "path";
|
|
7605
|
+
import { join as join4, parse, relative, resolve as resolve2 } from "path";
|
|
7497
7606
|
var TRUNCATED_DIR = "truncated-results";
|
|
7498
7607
|
var DEFAULT_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
7499
7608
|
function sanitizeToolName(name) {
|
|
7500
7609
|
return name.replace(/[^\w\-]/g, "_").slice(0, 48) || "unknown";
|
|
7501
7610
|
}
|
|
7611
|
+
function useHomeFallback(rootDir) {
|
|
7612
|
+
if (!rootDir) return true;
|
|
7613
|
+
const abs = resolve2(rootDir);
|
|
7614
|
+
return abs === parse(abs).root;
|
|
7615
|
+
}
|
|
7502
7616
|
function storageDir(rootDir) {
|
|
7503
|
-
const base = rootDir ? join4(
|
|
7617
|
+
const base = useHomeFallback(rootDir) ? join4(homedir3(), ".reasonix") : join4(resolve2(rootDir), ".reasonix");
|
|
7504
7618
|
return join4(base, TRUNCATED_DIR);
|
|
7505
7619
|
}
|
|
7506
7620
|
function resultFilename(toolName) {
|
|
@@ -7522,7 +7636,7 @@ function saveTruncatedResult(content, toolName, rootDir) {
|
|
|
7522
7636
|
chmodSync2(absPath, 384);
|
|
7523
7637
|
} catch {
|
|
7524
7638
|
}
|
|
7525
|
-
if (rootDir) {
|
|
7639
|
+
if (!useHomeFallback(rootDir)) {
|
|
7526
7640
|
const absRoot = resolve2(rootDir);
|
|
7527
7641
|
return relative(absRoot, absPath).replaceAll("\\", "/");
|
|
7528
7642
|
}
|
|
@@ -8081,8 +8195,8 @@ function truncateForModel(s, maxChars, extraNote) {
|
|
|
8081
8195
|
if (s.length <= maxChars) return s;
|
|
8082
8196
|
const tailBudget = Math.min(1024, Math.floor(maxChars * 0.1));
|
|
8083
8197
|
const headBudget = Math.max(0, maxChars - tailBudget);
|
|
8084
|
-
const head = s
|
|
8085
|
-
const tail = s
|
|
8198
|
+
const head = sliceAlignedToCodepoint(s, headBudget);
|
|
8199
|
+
const tail = sliceSuffixAlignedToCodepoint(s, tailBudget);
|
|
8086
8200
|
const dropped = s.length - head.length - tail.length;
|
|
8087
8201
|
const note = extraNote ? ` \u2014 ${extraNote}` : "";
|
|
8088
8202
|
return `${head}
|
|
@@ -8091,6 +8205,21 @@ function truncateForModel(s, maxChars, extraNote) {
|
|
|
8091
8205
|
|
|
8092
8206
|
${tail}`;
|
|
8093
8207
|
}
|
|
8208
|
+
function sliceAlignedToCodepoint(s, end) {
|
|
8209
|
+
if (end <= 0) return "";
|
|
8210
|
+
if (end >= s.length) return s;
|
|
8211
|
+
const last = s.charCodeAt(end - 1);
|
|
8212
|
+
if (last >= 55296 && last <= 56319) return s.slice(0, end - 1);
|
|
8213
|
+
return s.slice(0, end);
|
|
8214
|
+
}
|
|
8215
|
+
function sliceSuffixAlignedToCodepoint(s, len) {
|
|
8216
|
+
if (len <= 0) return "";
|
|
8217
|
+
if (len >= s.length) return s;
|
|
8218
|
+
const start = s.length - len;
|
|
8219
|
+
const first = s.charCodeAt(start);
|
|
8220
|
+
if (first >= 56320 && first <= 57343) return s.slice(start + 1);
|
|
8221
|
+
return s.slice(start);
|
|
8222
|
+
}
|
|
8094
8223
|
function truncateForModelByTokens(s, maxTokens, extraNote) {
|
|
8095
8224
|
if (maxTokens <= 0) return "";
|
|
8096
8225
|
if (s.length <= maxTokens) return s;
|
|
@@ -8128,28 +8257,28 @@ function sizePrefixToTokens(s, budget) {
|
|
|
8128
8257
|
let size = Math.min(s.length, budget * 4);
|
|
8129
8258
|
for (let iter = 0; iter < 6; iter++) {
|
|
8130
8259
|
if (size <= 0) return "";
|
|
8131
|
-
const slice = s
|
|
8260
|
+
const slice = sliceAlignedToCodepoint(s, size);
|
|
8132
8261
|
const count = countTokens(slice);
|
|
8133
8262
|
if (count <= budget) return slice;
|
|
8134
8263
|
const next = Math.floor(size * (budget / count) * 0.95);
|
|
8135
|
-
if (next >= size) return s
|
|
8264
|
+
if (next >= size) return sliceAlignedToCodepoint(s, Math.max(0, size - 1));
|
|
8136
8265
|
size = next;
|
|
8137
8266
|
}
|
|
8138
|
-
return s
|
|
8267
|
+
return sliceAlignedToCodepoint(s, Math.max(0, size));
|
|
8139
8268
|
}
|
|
8140
8269
|
function sizeSuffixToTokens(s, budget) {
|
|
8141
8270
|
if (budget <= 0 || s.length === 0) return "";
|
|
8142
8271
|
let size = Math.min(s.length, budget * 4);
|
|
8143
8272
|
for (let iter = 0; iter < 6; iter++) {
|
|
8144
8273
|
if (size <= 0) return "";
|
|
8145
|
-
const slice = s
|
|
8274
|
+
const slice = sliceSuffixAlignedToCodepoint(s, size);
|
|
8146
8275
|
const count = countTokens(slice);
|
|
8147
8276
|
if (count <= budget) return slice;
|
|
8148
8277
|
const next = Math.floor(size * (budget / count) * 0.95);
|
|
8149
|
-
if (next >= size) return s
|
|
8278
|
+
if (next >= size) return sliceSuffixAlignedToCodepoint(s, Math.max(0, size - 1));
|
|
8150
8279
|
size = next;
|
|
8151
8280
|
}
|
|
8152
|
-
return s
|
|
8281
|
+
return sliceSuffixAlignedToCodepoint(s, Math.max(0, size));
|
|
8153
8282
|
}
|
|
8154
8283
|
function blockToString(block) {
|
|
8155
8284
|
if (block.type === "text") return block.text;
|
|
@@ -8993,6 +9122,16 @@ function is5xxError(err) {
|
|
|
8993
9122
|
const m = /^DeepSeek (5\d{2}):/.exec(err.message ?? "");
|
|
8994
9123
|
return m !== null;
|
|
8995
9124
|
}
|
|
9125
|
+
function is4xxError(err) {
|
|
9126
|
+
if (!(err instanceof Error)) return false;
|
|
9127
|
+
return /^DeepSeek (4\d{2}):/.test(err.message ?? "");
|
|
9128
|
+
}
|
|
9129
|
+
function errorMeta(err) {
|
|
9130
|
+
if (!(err instanceof Error)) return {};
|
|
9131
|
+
const code = "code" in err && typeof err.code === "string" ? err.code : void 0;
|
|
9132
|
+
const phase = "phase" in err && typeof err.phase === "string" ? err.phase : void 0;
|
|
9133
|
+
return { code, phase };
|
|
9134
|
+
}
|
|
8996
9135
|
async function probeDeepSeekReachable(client, timeoutMs = 1500) {
|
|
8997
9136
|
const balance = await client.getBalance({ signal: AbortSignal.timeout(timeoutMs) });
|
|
8998
9137
|
return { reachable: balance !== null };
|
|
@@ -9065,9 +9204,8 @@ async function* forceSummaryAfterIterLimit(ctx, opts) {
|
|
|
9065
9204
|
role: "user",
|
|
9066
9205
|
content: "The turn is being force-summarized (context guard or stuck-state). Summarize in plain prose what you learned from the tool results above. Do NOT emit any tool calls, function-call markup, DSML invocations, or SEARCH/REPLACE edit blocks \u2014 they will be silently discarded. Just plain text."
|
|
9067
9206
|
});
|
|
9068
|
-
const summaryModel = "deepseek-v4-flash";
|
|
9069
9207
|
const resp = await ctx.client.chat({
|
|
9070
|
-
model:
|
|
9208
|
+
model: ctx.model,
|
|
9071
9209
|
messages,
|
|
9072
9210
|
signal: ctx.signal,
|
|
9073
9211
|
thinking: "disabled"
|
|
@@ -9079,8 +9217,8 @@ async function* forceSummaryAfterIterLimit(ctx, opts) {
|
|
|
9079
9217
|
const annotated = `${reasonPrefix}
|
|
9080
9218
|
|
|
9081
9219
|
${summary}`;
|
|
9082
|
-
const summaryStats = ctx.recordStats(
|
|
9083
|
-
ctx.appendAndPersist(buildAssistantMessage(summary, [],
|
|
9220
|
+
const summaryStats = ctx.recordStats(ctx.model, resp.usage ?? new Usage());
|
|
9221
|
+
ctx.appendAndPersist(buildAssistantMessage(summary, [], ctx.model, resp.reasoningContent));
|
|
9084
9222
|
yield {
|
|
9085
9223
|
turn: ctx.turn,
|
|
9086
9224
|
role: "assistant_final",
|
|
@@ -9091,11 +9229,18 @@ ${summary}`;
|
|
|
9091
9229
|
yield { turn: ctx.turn, role: "done", content: summary };
|
|
9092
9230
|
} catch (err) {
|
|
9093
9231
|
const label = errorLabelFor(opts.reason);
|
|
9232
|
+
const message = t("summary.failedAfterReason", { label, message: err.message });
|
|
9094
9233
|
yield {
|
|
9095
9234
|
turn: ctx.turn,
|
|
9096
9235
|
role: "error",
|
|
9097
9236
|
content: "",
|
|
9098
|
-
error:
|
|
9237
|
+
error: message,
|
|
9238
|
+
errorDetail: {
|
|
9239
|
+
name: "ForceSummaryFailed",
|
|
9240
|
+
message,
|
|
9241
|
+
retryable: true,
|
|
9242
|
+
recoverable: true
|
|
9243
|
+
}
|
|
9099
9244
|
};
|
|
9100
9245
|
yield { turn: ctx.turn, role: "done", content: "" };
|
|
9101
9246
|
}
|
|
@@ -10282,14 +10427,21 @@ ${reason}`
|
|
|
10282
10427
|
if (this.budgetUsd !== null) {
|
|
10283
10428
|
const spent = this.stats.totalCost;
|
|
10284
10429
|
if (spent >= this.budgetUsd) {
|
|
10430
|
+
const message = t("loop.budgetExhausted", {
|
|
10431
|
+
spent: spent.toFixed(4),
|
|
10432
|
+
cap: this.budgetUsd.toFixed(2)
|
|
10433
|
+
});
|
|
10285
10434
|
yield {
|
|
10286
10435
|
turn: this._turn,
|
|
10287
10436
|
role: "error",
|
|
10288
10437
|
content: "",
|
|
10289
|
-
error:
|
|
10290
|
-
|
|
10291
|
-
|
|
10292
|
-
|
|
10438
|
+
error: message,
|
|
10439
|
+
errorDetail: {
|
|
10440
|
+
name: "BudgetExhausted",
|
|
10441
|
+
message,
|
|
10442
|
+
retryable: false,
|
|
10443
|
+
recoverable: false
|
|
10444
|
+
}
|
|
10293
10445
|
};
|
|
10294
10446
|
this._steerQueue.length = 0;
|
|
10295
10447
|
return;
|
|
@@ -10443,11 +10595,22 @@ ${reason}`
|
|
|
10443
10595
|
const upstreamHost = this.client.baseUrl;
|
|
10444
10596
|
const dsHost = isDeepSeekHost(upstreamHost);
|
|
10445
10597
|
const probe = is5xxError(err) && dsHost ? await probeDeepSeekReachable(this.client) : void 0;
|
|
10598
|
+
const cause = err instanceof Error ? err : new Error(String(err));
|
|
10599
|
+
const retryable = !is4xxError(cause) && cause.name !== "AbortError";
|
|
10600
|
+
const { code, phase } = errorMeta(cause);
|
|
10446
10601
|
yield {
|
|
10447
10602
|
turn: this._turn,
|
|
10448
10603
|
role: "error",
|
|
10449
10604
|
content: "",
|
|
10450
|
-
error: formatLoopError(err, probe, { upstreamHost })
|
|
10605
|
+
error: formatLoopError(err, probe, { upstreamHost }),
|
|
10606
|
+
errorDetail: {
|
|
10607
|
+
name: cause.name,
|
|
10608
|
+
message: cause.message,
|
|
10609
|
+
phase,
|
|
10610
|
+
code,
|
|
10611
|
+
retryable,
|
|
10612
|
+
recoverable: false
|
|
10613
|
+
}
|
|
10451
10614
|
};
|
|
10452
10615
|
this._steerQueue.length = 0;
|
|
10453
10616
|
return;
|
|
@@ -10592,7 +10755,8 @@ ${reason}`
|
|
|
10592
10755
|
buildMessages: () => this.buildMessages(),
|
|
10593
10756
|
appendAndPersist: (m) => this.appendAndPersist(m),
|
|
10594
10757
|
recordStats: (model, usage) => this.stats.record(this._turn, model, usage),
|
|
10595
|
-
turn: this._turn
|
|
10758
|
+
turn: this._turn,
|
|
10759
|
+
model: this.model
|
|
10596
10760
|
};
|
|
10597
10761
|
}
|
|
10598
10762
|
async run(userInput, onEvent) {
|
|
@@ -15452,7 +15616,7 @@ function parseCommandChain(cmd) {
|
|
|
15452
15616
|
const cmdName = seg.argv[0] ?? "";
|
|
15453
15617
|
if (cmdName.toLowerCase() === "cd") {
|
|
15454
15618
|
throw new UnsupportedSyntaxError(
|
|
15455
|
-
"cd in parsed command chains does not change cwd for later segments.
|
|
15619
|
+
"cd in parsed command chains does not change cwd for later segments. By default, run generated scripts from the directory where the script was written; do not assume an input/data directory is the cwd just because the task reads files there. Pass input/data paths as arguments unless the command truly depends on that cwd. For package tools, use command-native cwd flags such as `npm --prefix <dir> run <script>`, `git -C <dir> ...`, or `cargo -C <dir> ...`."
|
|
15456
15620
|
);
|
|
15457
15621
|
}
|
|
15458
15622
|
}
|
|
@@ -16334,7 +16498,7 @@ function registerShellTools(registry, opts) {
|
|
|
16334
16498
|
const isAllowAll = typeof opts.allowAll === "function" ? opts.allowAll : () => opts.allowAll === true;
|
|
16335
16499
|
registry.register({
|
|
16336
16500
|
name: "run_command",
|
|
16337
|
-
description: 'Run a shell command in the project root; returns combined stdout+stderr. Allowlisted read-only / test / lint / typecheck commands run immediately; mutating / network / install commands gate on user confirmation.\n\nDO NOT use run_command for file operations \u2014 use write_file, edit_file, multi_edit, copy_file, move_file, or delete_file instead. Shell utilities (echo, cp, sed, cat, tee, perl, python -c, etc.) bypass validation, lack rollback, and will trigger user confirmation gates that waste turns.\n\nNo real shell \u2014 argv parsed natively for cross-platform parity:\n\u2022 Supported: chains `|`/`||`/`&&`/`;` (each segment allowlist-checked) and file redirects `>`/`>>`/`<`/`2>`/`2>>`/`2>&1`/`&>`.\n\u2022 Rejected: background `&`, heredoc `<<`, `$(\u2026)`, subshells, `$VAR` expansion, glob expansion. Quote operator chars as literals (`grep "a|b" file`).\n\u2022 `cd`
|
|
16501
|
+
description: 'Run a shell command in the project root; returns combined stdout+stderr. Allowlisted read-only / test / lint / typecheck commands run immediately; mutating / network / install commands gate on user confirmation.\n\nDO NOT use run_command for file operations \u2014 use write_file, edit_file, multi_edit, copy_file, move_file, or delete_file instead. Shell utilities (echo, cp, sed, cat, tee, perl, python -c, etc.) bypass validation, lack rollback, and will trigger user confirmation gates that waste turns.\n\nNo real shell \u2014 argv parsed natively for cross-platform parity:\n\u2022 Supported: chains `|`/`||`/`&&`/`;` (each segment allowlist-checked) and file redirects `>`/`>>`/`<`/`2>`/`2>>`/`2>&1`/`&>`.\n\u2022 Rejected: background `&`, heredoc `<<`, `$(\u2026)`, subshells, `$VAR` expansion, glob expansion. Quote operator chars as literals (`grep "a|b" file`).\n\u2022 `cd` is rejected in chains. By default, run generated scripts from the directory where the script was written; do not assume an input/data directory is the cwd. Pass input/data paths as arguments unless the command truly depends on that cwd. For package tools, use `npm --prefix <dir>`, `git -C <dir>`, `cargo -C <dir>`.\n\u2022 Filter at source \u2014 `grep -c` / `wc -l` / narrower paths over unbounded dumps.',
|
|
16338
16502
|
// Plan-mode gate: allow allowlisted commands through (git status,
|
|
16339
16503
|
// cargo check, ls, grep …) so the model can actually investigate
|
|
16340
16504
|
// during planning. Anything that would otherwise trigger a
|
|
@@ -16601,6 +16765,9 @@ var METASO_ENDPOINT = "https://metaso.cn/api/v1";
|
|
|
16601
16765
|
var TAVILY_ENDPOINT = "https://api.tavily.com/search";
|
|
16602
16766
|
var PERPLEXITY_ENDPOINT = "https://api.perplexity.ai/chat/completions";
|
|
16603
16767
|
var EXA_ENDPOINT = "https://api.exa.ai/answer";
|
|
16768
|
+
var BRAVE_ENDPOINT = "https://api.search.brave.com/res/v1/web/search";
|
|
16769
|
+
var OLLAMA_WEB_SEARCH_ENDPOINT = "https://ollama.com/api/web_search";
|
|
16770
|
+
var OLLAMA_WEB_FETCH_ENDPOINT = "https://ollama.com/api/web_fetch";
|
|
16604
16771
|
var FETCH_MAX_REDIRECTS = 5;
|
|
16605
16772
|
function searchStatusError(status) {
|
|
16606
16773
|
if (status === 429) return t("webErrors.rateLimit429");
|
|
@@ -16652,6 +16819,22 @@ function isInternalAddress(address) {
|
|
|
16652
16819
|
if (family === 6) return isPrivateIpv6(address);
|
|
16653
16820
|
return false;
|
|
16654
16821
|
}
|
|
16822
|
+
async function dohResolve(host) {
|
|
16823
|
+
const url = new URL("https://1.1.1.1/dns-query");
|
|
16824
|
+
url.searchParams.set("name", host);
|
|
16825
|
+
url.searchParams.set("type", "A");
|
|
16826
|
+
const resp = await fetch(url.toString(), {
|
|
16827
|
+
headers: { Accept: "application/dns-json" },
|
|
16828
|
+
signal: AbortSignal.timeout(5e3)
|
|
16829
|
+
});
|
|
16830
|
+
if (!resp.ok) throw new Error(`DoH resolve failed: HTTP ${resp.status} for ${host}`);
|
|
16831
|
+
const data = await resp.json();
|
|
16832
|
+
if (data.Status !== 0)
|
|
16833
|
+
throw new Error(`DoH resolve failed: DNS status ${data.Status} for ${host}`);
|
|
16834
|
+
const addresses = (data.Answer ?? []).filter((a) => a.type === 1).map((a) => a.data);
|
|
16835
|
+
if (addresses.length === 0) throw new Error(`DoH resolve returned no A records for ${host}`);
|
|
16836
|
+
return addresses;
|
|
16837
|
+
}
|
|
16655
16838
|
async function assertPublicHttpUrl(rawUrl) {
|
|
16656
16839
|
const url = new URL(rawUrl);
|
|
16657
16840
|
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
@@ -16659,10 +16842,22 @@ async function assertPublicHttpUrl(rawUrl) {
|
|
|
16659
16842
|
}
|
|
16660
16843
|
const host = url.hostname;
|
|
16661
16844
|
const literal = isIP(host);
|
|
16662
|
-
|
|
16663
|
-
|
|
16845
|
+
if (literal) {
|
|
16846
|
+
if (isInternalAddress(host)) {
|
|
16847
|
+
throw new Error(`web_fetch refuses internal or reserved host: ${host}`);
|
|
16848
|
+
}
|
|
16849
|
+
return url;
|
|
16850
|
+
}
|
|
16851
|
+
const sysAddrs = (await lookup(host, { all: true, verbatim: true })).map((e) => e.address);
|
|
16852
|
+
if (sysAddrs.length === 0) {
|
|
16664
16853
|
throw new Error(`web_fetch refuses internal or reserved host: ${host}`);
|
|
16665
16854
|
}
|
|
16855
|
+
if (sysAddrs.some(isInternalAddress)) {
|
|
16856
|
+
const dohAddrs = await dohResolve(host).catch(() => null);
|
|
16857
|
+
if (!dohAddrs || dohAddrs.some(isInternalAddress)) {
|
|
16858
|
+
throw new Error(`web_fetch refuses internal or reserved host: ${host}`);
|
|
16859
|
+
}
|
|
16860
|
+
}
|
|
16666
16861
|
return url;
|
|
16667
16862
|
}
|
|
16668
16863
|
function redirectLocation(resp, currentUrl) {
|
|
@@ -16687,6 +16882,12 @@ async function webSearch(query, opts = {}) {
|
|
|
16687
16882
|
if (opts.engine === "exa") {
|
|
16688
16883
|
return searchExa(query, opts);
|
|
16689
16884
|
}
|
|
16885
|
+
if (opts.engine === "ollama") {
|
|
16886
|
+
return searchOllama(query, opts);
|
|
16887
|
+
}
|
|
16888
|
+
if (opts.engine === "brave") {
|
|
16889
|
+
return searchBrave(query, opts);
|
|
16890
|
+
}
|
|
16690
16891
|
return searchBing(query, opts);
|
|
16691
16892
|
}
|
|
16692
16893
|
async function searchBing(query, opts = {}) {
|
|
@@ -16986,6 +17187,154 @@ async function searchExa(query, opts = {}) {
|
|
|
16986
17187
|
}
|
|
16987
17188
|
return results;
|
|
16988
17189
|
}
|
|
17190
|
+
async function searchOllama(query, opts = {}) {
|
|
17191
|
+
const topK = Math.max(1, Math.min(10, opts.topK ?? DEFAULT_TOPK));
|
|
17192
|
+
const apiKey = loadOllamaApiKey(opts.configPath);
|
|
17193
|
+
if (!apiKey) {
|
|
17194
|
+
throw new Error(
|
|
17195
|
+
"web_search: Ollama web search requires an API key \u2014 set OLLAMA_API_KEY, `ollamaApiKey`, or use /search-engine ollama <key>."
|
|
17196
|
+
);
|
|
17197
|
+
}
|
|
17198
|
+
let resp;
|
|
17199
|
+
try {
|
|
17200
|
+
resp = await fetch(OLLAMA_WEB_SEARCH_ENDPOINT, {
|
|
17201
|
+
method: "POST",
|
|
17202
|
+
headers: {
|
|
17203
|
+
Authorization: `Bearer ${apiKey}`,
|
|
17204
|
+
"Content-Type": "application/json",
|
|
17205
|
+
Accept: "application/json"
|
|
17206
|
+
},
|
|
17207
|
+
body: JSON.stringify({ query, max_results: topK }),
|
|
17208
|
+
signal: opts.signal
|
|
17209
|
+
});
|
|
17210
|
+
} catch (err) {
|
|
17211
|
+
if (err instanceof TypeError && err.message.includes("fetch")) {
|
|
17212
|
+
throw new Error(t("webErrors.cannotReach", { endpoint: OLLAMA_WEB_SEARCH_ENDPOINT }));
|
|
17213
|
+
}
|
|
17214
|
+
throw err;
|
|
17215
|
+
}
|
|
17216
|
+
if (!resp.ok) {
|
|
17217
|
+
if (resp.status === 401 || resp.status === 403) {
|
|
17218
|
+
throw new Error("web_search: Ollama API key rejected \u2014 check OLLAMA_API_KEY.");
|
|
17219
|
+
}
|
|
17220
|
+
if (resp.status === 429) {
|
|
17221
|
+
throw new Error("web_search: Ollama web search is rate-limited or quota-limited.");
|
|
17222
|
+
}
|
|
17223
|
+
throw new Error(`web_search: Ollama web search returned HTTP ${resp.status}.`);
|
|
17224
|
+
}
|
|
17225
|
+
let data;
|
|
17226
|
+
try {
|
|
17227
|
+
data = await resp.json();
|
|
17228
|
+
} catch {
|
|
17229
|
+
throw new Error(`web_search: Ollama returned unparseable response (HTTP ${resp.status}).`);
|
|
17230
|
+
}
|
|
17231
|
+
return (data.results ?? []).slice(0, topK).map((r, i) => ({
|
|
17232
|
+
title: r.title || `Result ${i + 1}`,
|
|
17233
|
+
url: r.url || "",
|
|
17234
|
+
snippet: r.content ?? ""
|
|
17235
|
+
}));
|
|
17236
|
+
}
|
|
17237
|
+
async function searchBrave(query, opts = {}) {
|
|
17238
|
+
const topK = Math.max(1, Math.min(20, opts.topK ?? DEFAULT_TOPK));
|
|
17239
|
+
const apiKey = loadBraveApiKey(opts.configPath);
|
|
17240
|
+
if (!apiKey) throw new Error(t("webErrors.braveMissingKey"));
|
|
17241
|
+
const url = `${BRAVE_ENDPOINT}?q=${encodeURIComponent(query)}&count=${topK}`;
|
|
17242
|
+
let resp;
|
|
17243
|
+
try {
|
|
17244
|
+
resp = await fetch(url, {
|
|
17245
|
+
headers: {
|
|
17246
|
+
Accept: "application/json",
|
|
17247
|
+
"Accept-Encoding": "gzip",
|
|
17248
|
+
"X-Subscription-Token": apiKey
|
|
17249
|
+
},
|
|
17250
|
+
signal: opts.signal
|
|
17251
|
+
});
|
|
17252
|
+
} catch (err) {
|
|
17253
|
+
if (err instanceof TypeError && err.message.includes("fetch")) {
|
|
17254
|
+
throw new Error(t("webErrors.cannotReach", { endpoint: BRAVE_ENDPOINT }));
|
|
17255
|
+
}
|
|
17256
|
+
throw err;
|
|
17257
|
+
}
|
|
17258
|
+
if (!resp.ok) {
|
|
17259
|
+
if (resp.status === 401 || resp.status === 403) {
|
|
17260
|
+
throw new Error(t("webErrors.braveUnauthorized"));
|
|
17261
|
+
}
|
|
17262
|
+
if (resp.status === 429) {
|
|
17263
|
+
throw new Error(t("webErrors.braveRateLimit"));
|
|
17264
|
+
}
|
|
17265
|
+
throw new Error(t("webErrors.braveServerError", { status: resp.status }));
|
|
17266
|
+
}
|
|
17267
|
+
const raw = await resp.text();
|
|
17268
|
+
let data;
|
|
17269
|
+
try {
|
|
17270
|
+
data = JSON.parse(raw);
|
|
17271
|
+
} catch {
|
|
17272
|
+
throw new Error(t("webErrors.braveParseError", { status: resp.status }));
|
|
17273
|
+
}
|
|
17274
|
+
const results = data.web?.results ?? [];
|
|
17275
|
+
return results.slice(0, topK).map((r) => ({
|
|
17276
|
+
title: r.title ?? "",
|
|
17277
|
+
url: r.url ?? "",
|
|
17278
|
+
snippet: r.description ?? ""
|
|
17279
|
+
}));
|
|
17280
|
+
}
|
|
17281
|
+
async function webFetchOllama(url, opts = {}) {
|
|
17282
|
+
const apiKey = loadOllamaApiKey(opts.configPath);
|
|
17283
|
+
if (!apiKey) {
|
|
17284
|
+
throw new Error(
|
|
17285
|
+
"web_fetch: Ollama web fetch requires an API key \u2014 set OLLAMA_API_KEY, `ollamaApiKey`, or use /search-engine ollama <key>."
|
|
17286
|
+
);
|
|
17287
|
+
}
|
|
17288
|
+
const ctrl = new AbortController();
|
|
17289
|
+
const timeout = setTimeout(
|
|
17290
|
+
() => ctrl.abort(
|
|
17291
|
+
new Error(
|
|
17292
|
+
t("webErrors.fetchTimeout", { ms: opts.timeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS, url })
|
|
17293
|
+
)
|
|
17294
|
+
),
|
|
17295
|
+
opts.timeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS
|
|
17296
|
+
);
|
|
17297
|
+
const signal = opts.signal ? AbortSignal.any([opts.signal, ctrl.signal]) : ctrl.signal;
|
|
17298
|
+
let resp;
|
|
17299
|
+
try {
|
|
17300
|
+
resp = await fetch(OLLAMA_WEB_FETCH_ENDPOINT, {
|
|
17301
|
+
method: "POST",
|
|
17302
|
+
headers: {
|
|
17303
|
+
Authorization: `Bearer ${apiKey}`,
|
|
17304
|
+
"Content-Type": "application/json",
|
|
17305
|
+
Accept: "application/json"
|
|
17306
|
+
},
|
|
17307
|
+
body: JSON.stringify({ url }),
|
|
17308
|
+
signal
|
|
17309
|
+
});
|
|
17310
|
+
} finally {
|
|
17311
|
+
clearTimeout(timeout);
|
|
17312
|
+
}
|
|
17313
|
+
if (!resp.ok) {
|
|
17314
|
+
if (resp.status === 401 || resp.status === 403) {
|
|
17315
|
+
throw new Error("web_fetch: Ollama API key rejected \u2014 check OLLAMA_API_KEY.");
|
|
17316
|
+
}
|
|
17317
|
+
if (resp.status === 429) {
|
|
17318
|
+
throw new Error("web_fetch: Ollama web fetch is rate-limited or quota-limited.");
|
|
17319
|
+
}
|
|
17320
|
+
throw new Error(`web_fetch: Ollama web fetch returned HTTP ${resp.status} for ${url}.`);
|
|
17321
|
+
}
|
|
17322
|
+
let data;
|
|
17323
|
+
try {
|
|
17324
|
+
data = await resp.json();
|
|
17325
|
+
} catch {
|
|
17326
|
+
throw new Error(`web_fetch: Ollama returned unparseable response for ${url}.`);
|
|
17327
|
+
}
|
|
17328
|
+
const maxChars = opts.maxChars ?? DEFAULT_FETCH_MAX_CHARS;
|
|
17329
|
+
const text = data.content ?? "";
|
|
17330
|
+
return {
|
|
17331
|
+
url,
|
|
17332
|
+
title: data.title,
|
|
17333
|
+
text: text.length > maxChars ? text.slice(0, maxChars) : text,
|
|
17334
|
+
truncated: text.length > maxChars,
|
|
17335
|
+
links: data.links
|
|
17336
|
+
};
|
|
17337
|
+
}
|
|
16989
17338
|
function parseSearxngHtmlResults(html) {
|
|
16990
17339
|
const root = parseHtml(html);
|
|
16991
17340
|
const results = [];
|
|
@@ -17211,13 +17560,14 @@ function registerWebTools(registry, opts = {}) {
|
|
|
17211
17560
|
required: ["query"]
|
|
17212
17561
|
},
|
|
17213
17562
|
fn: async (args, ctx) => {
|
|
17214
|
-
const engine = webSearchEngine();
|
|
17215
|
-
const endpoint = webSearchEndpoint();
|
|
17563
|
+
const engine = webSearchEngine(opts.configPath);
|
|
17564
|
+
const endpoint = webSearchEndpoint(opts.configPath);
|
|
17216
17565
|
const results = await webSearch(args.query, {
|
|
17217
17566
|
topK: args.topK ?? defaultTopK,
|
|
17218
17567
|
signal: ctx?.signal,
|
|
17219
17568
|
engine,
|
|
17220
|
-
endpoint
|
|
17569
|
+
endpoint,
|
|
17570
|
+
configPath: opts.configPath
|
|
17221
17571
|
});
|
|
17222
17572
|
return formatSearchResults(args.query, results);
|
|
17223
17573
|
}
|
|
@@ -17238,6 +17588,22 @@ function registerWebTools(registry, opts = {}) {
|
|
|
17238
17588
|
if (!/^https?:\/\//i.test(args.url)) {
|
|
17239
17589
|
throw new Error(t("webErrors.fetchInvalidUrl"));
|
|
17240
17590
|
}
|
|
17591
|
+
if (webSearchEngine(opts.configPath) === "ollama") {
|
|
17592
|
+
const page2 = await webFetchOllama(args.url, {
|
|
17593
|
+
maxChars: maxFetchChars,
|
|
17594
|
+
signal: ctx?.signal,
|
|
17595
|
+
configPath: opts.configPath
|
|
17596
|
+
});
|
|
17597
|
+
const header2 = page2.title ? `${page2.title}
|
|
17598
|
+
${page2.url}` : page2.url;
|
|
17599
|
+
const links = page2.links?.length ? `
|
|
17600
|
+
|
|
17601
|
+
links:
|
|
17602
|
+
${page2.links.join("\n")}` : "";
|
|
17603
|
+
return `${header2}
|
|
17604
|
+
|
|
17605
|
+
${page2.text}${links}`;
|
|
17606
|
+
}
|
|
17241
17607
|
const page = await webFetch(args.url, { maxChars: maxFetchChars, signal: ctx?.signal });
|
|
17242
17608
|
const header = page.title ? `${page.title}
|
|
17243
17609
|
${page.url}` : page.url;
|
|
@@ -17312,6 +17678,7 @@ function recordFromLoopEvent(ev, extra) {
|
|
|
17312
17678
|
if (ev.toolName !== void 0) rec.tool = ev.toolName;
|
|
17313
17679
|
if (ev.toolArgs !== void 0) rec.args = ev.toolArgs;
|
|
17314
17680
|
if (ev.error !== void 0) rec.error = ev.error;
|
|
17681
|
+
if (ev.errorDetail !== void 0) rec.errorDetail = ev.errorDetail;
|
|
17315
17682
|
if (ev.stats) {
|
|
17316
17683
|
rec.usage = {
|
|
17317
17684
|
prompt_tokens: ev.stats.usage.promptTokens,
|
|
@@ -18920,6 +19287,7 @@ Skip dependency, build, and VCS directories unless asked (the pinned .gitignore
|
|
|
18920
19287
|
|
|
18921
19288
|
- **Filesystem tools** (\`read_file\`, \`list_directory\`, \`edit_file\`, etc.): paths resolve against the sandbox root. Relative, POSIX-absolute (\`/\` = project root), and OS-absolute (e.g. \`D:\\\\path\\\\foo.cpp\`) all work as long as they resolve INSIDE the sandbox. Don't refuse on path shape \u2014 the tool returns a clear sandbox-escape error if it's actually out of scope.
|
|
18922
19289
|
- **\`run_command\`**: cwd pinned to project root. Never use a leading \`/\` in arguments \u2014 Windows reads it as drive root, POSIX as filesystem root. Use relative paths.
|
|
19290
|
+
- By default, run generated scripts from the directory where the script was written. Do not assume an input or data directory is the cwd just because the task reads files there; pass data paths as arguments unless the command explicitly needs that cwd.
|
|
18923
19291
|
|
|
18924
19292
|
# Workspace is pinned
|
|
18925
19293
|
|
|
@@ -19312,10 +19680,12 @@ export {
|
|
|
19312
19680
|
listSessions,
|
|
19313
19681
|
loadApiKey,
|
|
19314
19682
|
loadBaseUrl,
|
|
19683
|
+
loadBraveApiKey,
|
|
19315
19684
|
loadDotenv,
|
|
19316
19685
|
loadExaApiKey,
|
|
19317
19686
|
loadHooks,
|
|
19318
19687
|
loadMetasoApiKey,
|
|
19688
|
+
loadOllamaApiKey,
|
|
19319
19689
|
loadPerplexityApiKey,
|
|
19320
19690
|
loadSessionMessages,
|
|
19321
19691
|
matchesTool,
|