pi-web-providers 3.0.0 → 3.1.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 +29 -24
- package/dist/index.js +1164 -300
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { mkdir as mkdir2, writeFile as writeFile2 } from "node:fs/promises";
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
5
|
-
import { dirname as dirname2, join as join2, relative } from "node:path";
|
|
5
|
+
import { basename, dirname as dirname2, join as join2, relative } from "node:path";
|
|
6
6
|
import {
|
|
7
7
|
DEFAULT_MAX_BYTES,
|
|
8
8
|
DEFAULT_MAX_LINES,
|
|
9
|
-
formatSize,
|
|
9
|
+
formatSize as formatSize2,
|
|
10
10
|
getMarkdownTheme,
|
|
11
11
|
truncateHead
|
|
12
|
-
} from "@
|
|
12
|
+
} from "@earendil-works/pi-coding-agent";
|
|
13
13
|
import {
|
|
14
14
|
Box,
|
|
15
15
|
Editor,
|
|
@@ -21,13 +21,13 @@ import {
|
|
|
21
21
|
truncateToWidth,
|
|
22
22
|
visibleWidth,
|
|
23
23
|
wrapTextWithAnsi
|
|
24
|
-
} from "@
|
|
24
|
+
} from "@earendil-works/pi-tui";
|
|
25
25
|
import { Type as Type16 } from "typebox";
|
|
26
26
|
|
|
27
27
|
// src/config.ts
|
|
28
28
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
29
29
|
import { dirname, join } from "node:path";
|
|
30
|
-
import { getAgentDir } from "@
|
|
30
|
+
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
31
31
|
|
|
32
32
|
// src/config-values.ts
|
|
33
33
|
import { execSync } from "node:child_process";
|
|
@@ -117,7 +117,13 @@ function asJsonObject(value) {
|
|
|
117
117
|
function formatJson(value) {
|
|
118
118
|
return JSON.stringify(value, null, 2);
|
|
119
119
|
}
|
|
120
|
-
function getApiKeyStatus(apiKeyReference) {
|
|
120
|
+
function getApiKeyStatus(apiKeyReference, options = {}) {
|
|
121
|
+
if (!apiKeyReference) {
|
|
122
|
+
return { state: "missing_api_key" };
|
|
123
|
+
}
|
|
124
|
+
if (options.resolveSecrets === false && isSecretReference(apiKeyReference)) {
|
|
125
|
+
return { state: "deferred_secret" };
|
|
126
|
+
}
|
|
121
127
|
try {
|
|
122
128
|
return resolveConfigValue(apiKeyReference) ? { state: "ready" } : { state: "missing_api_key" };
|
|
123
129
|
} catch (error) {
|
|
@@ -127,6 +133,9 @@ function getApiKeyStatus(apiKeyReference) {
|
|
|
127
133
|
};
|
|
128
134
|
}
|
|
129
135
|
}
|
|
136
|
+
function isSecretReference(reference) {
|
|
137
|
+
return reference.startsWith("!") || /^[A-Z][A-Z0-9_]*$/.test(reference);
|
|
138
|
+
}
|
|
130
139
|
function formatConfigValueError(error) {
|
|
131
140
|
const message = error instanceof Error ? error.message : String(error);
|
|
132
141
|
return message.replace(/\s+/g, " ").trim() || "Failed to resolve config value";
|
|
@@ -385,8 +394,14 @@ var braveSearchPromptGuidelines = [
|
|
|
385
394
|
];
|
|
386
395
|
var braveAnswerOptionsSchema = Type.Object(
|
|
387
396
|
{
|
|
397
|
+
model: Type.Optional(
|
|
398
|
+
Type.Enum({ brave: "brave", bravePro: "brave-pro" }, {
|
|
399
|
+
description: "Brave Answers model. Defaults to 'brave'."
|
|
400
|
+
})
|
|
401
|
+
),
|
|
388
402
|
country: Type.Optional(Type.String()),
|
|
389
403
|
language: Type.Optional(Type.String()),
|
|
404
|
+
safesearch: safesearchOption,
|
|
390
405
|
enable_citations: Type.Optional(Type.Boolean()),
|
|
391
406
|
enable_entities: Type.Optional(Type.Boolean()),
|
|
392
407
|
max_completion_tokens: Type.Optional(Type.Integer({ minimum: 1 }))
|
|
@@ -395,8 +410,14 @@ var braveAnswerOptionsSchema = Type.Object(
|
|
|
395
410
|
);
|
|
396
411
|
var braveResearchOptionsSchema = Type.Object(
|
|
397
412
|
{
|
|
413
|
+
model: Type.Optional(
|
|
414
|
+
Type.Enum({ brave: "brave", bravePro: "brave-pro" }, {
|
|
415
|
+
description: "Brave Answers model. Defaults to 'brave'."
|
|
416
|
+
})
|
|
417
|
+
),
|
|
398
418
|
country: Type.Optional(Type.String()),
|
|
399
419
|
language: Type.Optional(Type.String()),
|
|
420
|
+
safesearch: safesearchOption,
|
|
400
421
|
enable_entities: Type.Optional(Type.Boolean()),
|
|
401
422
|
enable_citations: Type.Optional(
|
|
402
423
|
Type.Boolean({
|
|
@@ -448,19 +469,19 @@ var braveImplementation = {
|
|
|
448
469
|
options: {}
|
|
449
470
|
};
|
|
450
471
|
},
|
|
451
|
-
getCapabilityStatus(config, _cwd, tool) {
|
|
472
|
+
getCapabilityStatus(config, _cwd, tool, options) {
|
|
452
473
|
const key = tool === "answer" || tool === "research" ? config?.credentials?.answers : config?.credentials?.search;
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
}
|
|
474
|
+
if (tool) {
|
|
475
|
+
return getApiKeyStatus(key, options);
|
|
476
|
+
}
|
|
477
|
+
const statuses = [
|
|
478
|
+
config?.credentials?.search,
|
|
479
|
+
config?.credentials?.answers,
|
|
480
|
+
config?.credentials?.autosuggest
|
|
481
|
+
].map((value) => getApiKeyStatus(value, options));
|
|
482
|
+
return statuses.find((status) => status.state === "ready") ?? statuses.find((status) => status.state === "deferred_secret") ?? statuses.find((status) => status.state === "invalid_config") ?? {
|
|
483
|
+
state: "missing_api_key"
|
|
484
|
+
};
|
|
464
485
|
},
|
|
465
486
|
async search(query2, maxResults, config, context, options) {
|
|
466
487
|
const apiKey = requireKey(config.credentials?.search, "Brave search");
|
|
@@ -945,25 +966,25 @@ function placeRating(place, details) {
|
|
|
945
966
|
return rating === void 0 ? void 0 : `Rating: ${rating}`;
|
|
946
967
|
}
|
|
947
968
|
function buildAnswerRequest(raw) {
|
|
948
|
-
const
|
|
969
|
+
const webSearchOptions = pick(raw, [
|
|
949
970
|
"country",
|
|
950
971
|
"language",
|
|
951
972
|
"safesearch",
|
|
952
973
|
"enable_entities",
|
|
953
974
|
"enable_citations"
|
|
954
975
|
]);
|
|
955
|
-
if (
|
|
956
|
-
|
|
976
|
+
if (webSearchOptions.enable_citations === void 0) {
|
|
977
|
+
webSearchOptions.enable_citations = true;
|
|
957
978
|
}
|
|
958
|
-
const stream =
|
|
979
|
+
const stream = webSearchOptions.enable_citations === true || webSearchOptions.enable_entities === true;
|
|
959
980
|
return {
|
|
960
981
|
stream,
|
|
961
|
-
...pick(raw, ["max_completion_tokens", "metadata", "seed"]),
|
|
962
|
-
|
|
982
|
+
...pick(raw, ["model", "max_completion_tokens", "metadata", "seed"]),
|
|
983
|
+
web_search_options: webSearchOptions
|
|
963
984
|
};
|
|
964
985
|
}
|
|
965
986
|
function buildResearchRequest(raw) {
|
|
966
|
-
const
|
|
987
|
+
const webSearchOptions = pick(raw, [
|
|
967
988
|
"country",
|
|
968
989
|
"language",
|
|
969
990
|
"safesearch",
|
|
@@ -975,12 +996,12 @@ function buildResearchRequest(raw) {
|
|
|
975
996
|
"research_maximum_number_of_seconds",
|
|
976
997
|
"research_maximum_number_of_results_per_query"
|
|
977
998
|
]);
|
|
999
|
+
webSearchOptions.enable_research = true;
|
|
1000
|
+
webSearchOptions.enable_citations = false;
|
|
978
1001
|
return {
|
|
979
1002
|
stream: true,
|
|
980
|
-
...pick(raw, ["max_completion_tokens", "metadata", "seed"]),
|
|
981
|
-
|
|
982
|
-
enable_research: true,
|
|
983
|
-
enable_citations: false
|
|
1003
|
+
...pick(raw, ["model", "max_completion_tokens", "metadata", "seed"]),
|
|
1004
|
+
web_search_options: webSearchOptions
|
|
984
1005
|
};
|
|
985
1006
|
}
|
|
986
1007
|
async function completion(input, config, context, request) {
|
|
@@ -1197,10 +1218,11 @@ var braveProvider = defineProvider({
|
|
|
1197
1218
|
},
|
|
1198
1219
|
optionCapabilities: ["search", "answer", "research"]
|
|
1199
1220
|
},
|
|
1200
|
-
getCapabilityStatus: (config, cwd, tool) => braveImplementation.getCapabilityStatus(
|
|
1221
|
+
getCapabilityStatus: (config, cwd, tool, options) => braveImplementation.getCapabilityStatus(
|
|
1201
1222
|
config,
|
|
1202
1223
|
cwd,
|
|
1203
|
-
tool
|
|
1224
|
+
tool,
|
|
1225
|
+
options
|
|
1204
1226
|
),
|
|
1205
1227
|
capabilities: {
|
|
1206
1228
|
search: defineCapability({
|
|
@@ -1666,10 +1688,12 @@ var cloudflareImplementation = {
|
|
|
1666
1688
|
}
|
|
1667
1689
|
};
|
|
1668
1690
|
},
|
|
1669
|
-
getCapabilityStatus(config) {
|
|
1670
|
-
const apiTokenStatus = getApiKeyStatus(config?.credentials?.api);
|
|
1691
|
+
getCapabilityStatus(config, _cwd, _tool, options) {
|
|
1692
|
+
const apiTokenStatus = getApiKeyStatus(config?.credentials?.api, options);
|
|
1671
1693
|
if (apiTokenStatus.state !== "ready") {
|
|
1672
|
-
|
|
1694
|
+
if (apiTokenStatus.state !== "deferred_secret") {
|
|
1695
|
+
return apiTokenStatus;
|
|
1696
|
+
}
|
|
1673
1697
|
}
|
|
1674
1698
|
try {
|
|
1675
1699
|
if (!resolveConfigValue(config?.accountId)) {
|
|
@@ -1681,7 +1705,7 @@ var cloudflareImplementation = {
|
|
|
1681
1705
|
detail: formatConfigValueError(error)
|
|
1682
1706
|
};
|
|
1683
1707
|
}
|
|
1684
|
-
return { state: "ready" };
|
|
1708
|
+
return apiTokenStatus.state === "deferred_secret" ? apiTokenStatus : { state: "ready" };
|
|
1685
1709
|
},
|
|
1686
1710
|
async contents(urls, config, context, options) {
|
|
1687
1711
|
const client = createClient(config);
|
|
@@ -1740,10 +1764,11 @@ var cloudflareProvider = defineProvider({
|
|
|
1740
1764
|
createTemplate: () => cloudflareImplementation.createTemplate(),
|
|
1741
1765
|
fields: ["credentials", "accountId", "options", "settings"]
|
|
1742
1766
|
},
|
|
1743
|
-
getCapabilityStatus: (config, cwd, tool) => cloudflareImplementation.getCapabilityStatus(
|
|
1767
|
+
getCapabilityStatus: (config, cwd, tool, options) => cloudflareImplementation.getCapabilityStatus(
|
|
1744
1768
|
config,
|
|
1745
1769
|
cwd,
|
|
1746
|
-
tool
|
|
1770
|
+
tool,
|
|
1771
|
+
options
|
|
1747
1772
|
),
|
|
1748
1773
|
capabilities: {
|
|
1749
1774
|
contents: defineCapability({
|
|
@@ -2876,8 +2901,8 @@ var exaImplementation = {
|
|
|
2876
2901
|
}
|
|
2877
2902
|
};
|
|
2878
2903
|
},
|
|
2879
|
-
getCapabilityStatus(config) {
|
|
2880
|
-
return getApiKeyStatus(config?.credentials?.api);
|
|
2904
|
+
getCapabilityStatus(config, _cwd, _tool, options) {
|
|
2905
|
+
return getApiKeyStatus(config?.credentials?.api, options);
|
|
2881
2906
|
},
|
|
2882
2907
|
async search(query2, maxResults, config, _context, searchOptions) {
|
|
2883
2908
|
const client = createClient2(config);
|
|
@@ -3012,10 +3037,11 @@ var exaProvider = defineProvider({
|
|
|
3012
3037
|
fields: ["credentials", "baseUrl", "options", "settings"],
|
|
3013
3038
|
optionCapabilities: ["search"]
|
|
3014
3039
|
},
|
|
3015
|
-
getCapabilityStatus: (config, cwd, tool) => exaImplementation.getCapabilityStatus(
|
|
3040
|
+
getCapabilityStatus: (config, cwd, tool, options) => exaImplementation.getCapabilityStatus(
|
|
3016
3041
|
config,
|
|
3017
3042
|
cwd,
|
|
3018
|
-
tool
|
|
3043
|
+
tool,
|
|
3044
|
+
options
|
|
3019
3045
|
),
|
|
3020
3046
|
capabilities: {
|
|
3021
3047
|
search: defineCapability({
|
|
@@ -3070,6 +3096,7 @@ var exaProvider = defineProvider({
|
|
|
3070
3096
|
// src/providers/firecrawl.ts
|
|
3071
3097
|
import FirecrawlClient from "@mendable/firecrawl-js";
|
|
3072
3098
|
import { Type as Type7 } from "typebox";
|
|
3099
|
+
var FIRECRAWL_CLOUD_HOST = "api.firecrawl.dev";
|
|
3073
3100
|
var firecrawlSearchOptionsSchema = Type7.Object(
|
|
3074
3101
|
{
|
|
3075
3102
|
lang: Type7.Optional(
|
|
@@ -3201,8 +3228,8 @@ var firecrawlImplementation = {
|
|
|
3201
3228
|
}
|
|
3202
3229
|
};
|
|
3203
3230
|
},
|
|
3204
|
-
getCapabilityStatus(config) {
|
|
3205
|
-
return
|
|
3231
|
+
getCapabilityStatus(config, _cwd, _tool, options) {
|
|
3232
|
+
return getFirecrawlCapabilityStatus(config, options);
|
|
3206
3233
|
},
|
|
3207
3234
|
async search(query2, maxResults, config, _context, options) {
|
|
3208
3235
|
const client = createClient3(config);
|
|
@@ -3255,15 +3282,26 @@ var firecrawlImplementation = {
|
|
|
3255
3282
|
}
|
|
3256
3283
|
};
|
|
3257
3284
|
function createClient3(config) {
|
|
3285
|
+
const apiUrl = resolveConfigValue(config.baseUrl);
|
|
3258
3286
|
const apiKey = resolveConfigValue(config.credentials?.api);
|
|
3259
|
-
if (!apiKey) {
|
|
3287
|
+
if (isFirecrawlCloudApiUrl(apiUrl) && !apiKey) {
|
|
3260
3288
|
throw new Error("is missing an API key");
|
|
3261
3289
|
}
|
|
3262
3290
|
return new FirecrawlClient({
|
|
3263
3291
|
apiKey,
|
|
3264
|
-
apiUrl
|
|
3292
|
+
apiUrl
|
|
3265
3293
|
});
|
|
3266
3294
|
}
|
|
3295
|
+
function getFirecrawlCapabilityStatus(config, options) {
|
|
3296
|
+
if (!config?.baseUrl || isFirecrawlCloudApiUrl(config.baseUrl)) {
|
|
3297
|
+
return getApiKeyStatus(config?.credentials?.api, options);
|
|
3298
|
+
}
|
|
3299
|
+
const apiKeyStatus = getApiKeyStatus(config.credentials?.api, options);
|
|
3300
|
+
return apiKeyStatus.state === "missing_api_key" ? { state: "ready" } : apiKeyStatus;
|
|
3301
|
+
}
|
|
3302
|
+
function isFirecrawlCloudApiUrl(apiUrl) {
|
|
3303
|
+
return !apiUrl || apiUrl.includes(FIRECRAWL_CLOUD_HOST);
|
|
3304
|
+
}
|
|
3267
3305
|
function flattenSearchResults(response) {
|
|
3268
3306
|
return ["web", "news", "images"].flatMap(
|
|
3269
3307
|
(source) => (response[source] ?? []).map((entry) => toSearchResult(source, entry)).filter((entry) => entry !== null)
|
|
@@ -3321,10 +3359,11 @@ var firecrawlProvider = defineProvider({
|
|
|
3321
3359
|
createTemplate: () => firecrawlImplementation.createTemplate(),
|
|
3322
3360
|
fields: ["credentials", "baseUrl", "options", "settings"]
|
|
3323
3361
|
},
|
|
3324
|
-
getCapabilityStatus: (config, cwd, tool) => firecrawlImplementation.getCapabilityStatus(
|
|
3362
|
+
getCapabilityStatus: (config, cwd, tool, options) => firecrawlImplementation.getCapabilityStatus(
|
|
3325
3363
|
config,
|
|
3326
3364
|
cwd,
|
|
3327
|
-
tool
|
|
3365
|
+
tool,
|
|
3366
|
+
options
|
|
3328
3367
|
),
|
|
3329
3368
|
capabilities: {
|
|
3330
3369
|
search: defineCapability({
|
|
@@ -3479,8 +3518,8 @@ var geminiImplementation = {
|
|
|
3479
3518
|
}
|
|
3480
3519
|
};
|
|
3481
3520
|
},
|
|
3482
|
-
getCapabilityStatus(config) {
|
|
3483
|
-
return getApiKeyStatus(config?.credentials?.api);
|
|
3521
|
+
getCapabilityStatus(config, _cwd, _tool, options) {
|
|
3522
|
+
return getApiKeyStatus(config?.credentials?.api, options);
|
|
3484
3523
|
},
|
|
3485
3524
|
async search(query2, maxResults, config, context, options) {
|
|
3486
3525
|
const ai = this.createClient(config);
|
|
@@ -4109,10 +4148,11 @@ var geminiProvider = defineProvider({
|
|
|
4109
4148
|
createTemplate: () => geminiImplementation.createTemplate(),
|
|
4110
4149
|
fields: ["credentials", "options", "settings"]
|
|
4111
4150
|
},
|
|
4112
|
-
getCapabilityStatus: (config, cwd, tool) => geminiImplementation.getCapabilityStatus(
|
|
4151
|
+
getCapabilityStatus: (config, cwd, tool, options) => geminiImplementation.getCapabilityStatus(
|
|
4113
4152
|
config,
|
|
4114
4153
|
cwd,
|
|
4115
|
-
tool
|
|
4154
|
+
tool,
|
|
4155
|
+
options
|
|
4116
4156
|
),
|
|
4117
4157
|
capabilities: {
|
|
4118
4158
|
search: defineCapability({
|
|
@@ -4220,8 +4260,8 @@ var linkupImplementation = {
|
|
|
4220
4260
|
credentials: { api: "LINKUP_API_KEY" }
|
|
4221
4261
|
};
|
|
4222
4262
|
},
|
|
4223
|
-
getCapabilityStatus(config) {
|
|
4224
|
-
return getApiKeyStatus(config?.credentials?.api);
|
|
4263
|
+
getCapabilityStatus(config, _cwd, _tool, options) {
|
|
4264
|
+
return getApiKeyStatus(config?.credentials?.api, options);
|
|
4225
4265
|
},
|
|
4226
4266
|
async search(query2, maxResults, config, _context, options) {
|
|
4227
4267
|
const client = createClient4(config);
|
|
@@ -4365,10 +4405,11 @@ var linkupProvider = defineProvider({
|
|
|
4365
4405
|
createTemplate: () => linkupImplementation.createTemplate(),
|
|
4366
4406
|
fields: ["credentials", "baseUrl", "options", "settings"]
|
|
4367
4407
|
},
|
|
4368
|
-
getCapabilityStatus: (config, cwd, tool) => linkupImplementation.getCapabilityStatus(
|
|
4408
|
+
getCapabilityStatus: (config, cwd, tool, options) => linkupImplementation.getCapabilityStatus(
|
|
4369
4409
|
config,
|
|
4370
4410
|
cwd,
|
|
4371
|
-
tool
|
|
4411
|
+
tool,
|
|
4412
|
+
options
|
|
4372
4413
|
),
|
|
4373
4414
|
capabilities: {
|
|
4374
4415
|
search: defineCapability({
|
|
@@ -4414,8 +4455,8 @@ var ollamaProvider = defineProvider({
|
|
|
4414
4455
|
},
|
|
4415
4456
|
fields: ["credentials", "baseUrl", "settings"]
|
|
4416
4457
|
},
|
|
4417
|
-
getCapabilityStatus(config) {
|
|
4418
|
-
return getApiKeyStatus(config?.credentials?.api);
|
|
4458
|
+
getCapabilityStatus(config, _cwd, _tool, options) {
|
|
4459
|
+
return getApiKeyStatus(config?.credentials?.api, options);
|
|
4419
4460
|
},
|
|
4420
4461
|
capabilities: {
|
|
4421
4462
|
search: defineCapability({
|
|
@@ -4679,8 +4720,8 @@ var openaiImplementation = {
|
|
|
4679
4720
|
}
|
|
4680
4721
|
};
|
|
4681
4722
|
},
|
|
4682
|
-
getCapabilityStatus(config) {
|
|
4683
|
-
return getApiKeyStatus(config?.credentials?.api);
|
|
4723
|
+
getCapabilityStatus(config, _cwd, _tool, options) {
|
|
4724
|
+
return getApiKeyStatus(config?.credentials?.api, options);
|
|
4684
4725
|
},
|
|
4685
4726
|
async search(query2, maxResults, config, context, options) {
|
|
4686
4727
|
const client = createClient5(config);
|
|
@@ -5036,10 +5077,11 @@ var openaiProvider = defineProvider({
|
|
|
5036
5077
|
fields: ["credentials", "baseUrl", "options", "settings"],
|
|
5037
5078
|
optionCapabilities: ["search", "answer", "research"]
|
|
5038
5079
|
},
|
|
5039
|
-
getCapabilityStatus: (config, cwd, tool) => openaiImplementation.getCapabilityStatus(
|
|
5080
|
+
getCapabilityStatus: (config, cwd, tool, options) => openaiImplementation.getCapabilityStatus(
|
|
5040
5081
|
config,
|
|
5041
5082
|
cwd,
|
|
5042
|
-
tool
|
|
5083
|
+
tool,
|
|
5084
|
+
options
|
|
5043
5085
|
),
|
|
5044
5086
|
capabilities: {
|
|
5045
5087
|
search: defineCapability({
|
|
@@ -5134,8 +5176,8 @@ var parallelImplementation = {
|
|
|
5134
5176
|
}
|
|
5135
5177
|
};
|
|
5136
5178
|
},
|
|
5137
|
-
getCapabilityStatus(config) {
|
|
5138
|
-
return getApiKeyStatus(config?.credentials?.api);
|
|
5179
|
+
getCapabilityStatus(config, _cwd, _tool, options) {
|
|
5180
|
+
return getApiKeyStatus(config?.credentials?.api, options);
|
|
5139
5181
|
},
|
|
5140
5182
|
async search(query2, maxResults, config, context, options) {
|
|
5141
5183
|
const client = createClient6(config);
|
|
@@ -5219,10 +5261,11 @@ var parallelProvider = defineProvider({
|
|
|
5219
5261
|
createTemplate: () => parallelImplementation.createTemplate(),
|
|
5220
5262
|
fields: ["credentials", "baseUrl", "options", "settings"]
|
|
5221
5263
|
},
|
|
5222
|
-
getCapabilityStatus: (config, cwd, tool) => parallelImplementation.getCapabilityStatus(
|
|
5264
|
+
getCapabilityStatus: (config, cwd, tool, options) => parallelImplementation.getCapabilityStatus(
|
|
5223
5265
|
config,
|
|
5224
5266
|
cwd,
|
|
5225
|
-
tool
|
|
5267
|
+
tool,
|
|
5268
|
+
options
|
|
5226
5269
|
),
|
|
5227
5270
|
capabilities: {
|
|
5228
5271
|
search: defineCapability({
|
|
@@ -5327,8 +5370,8 @@ var perplexityImplementation = {
|
|
|
5327
5370
|
}
|
|
5328
5371
|
};
|
|
5329
5372
|
},
|
|
5330
|
-
getCapabilityStatus(config) {
|
|
5331
|
-
return getApiKeyStatus(config?.credentials?.api);
|
|
5373
|
+
getCapabilityStatus(config, _cwd, _tool, options) {
|
|
5374
|
+
return getApiKeyStatus(config?.credentials?.api, options);
|
|
5332
5375
|
},
|
|
5333
5376
|
async search(query2, maxResults, config, context, options) {
|
|
5334
5377
|
const client = createClient7(config);
|
|
@@ -5538,10 +5581,11 @@ var perplexityProvider = defineProvider({
|
|
|
5538
5581
|
createTemplate: () => perplexityImplementation.createTemplate(),
|
|
5539
5582
|
fields: ["credentials", "baseUrl", "options", "settings"]
|
|
5540
5583
|
},
|
|
5541
|
-
getCapabilityStatus: (config, cwd, tool) => perplexityImplementation.getCapabilityStatus(
|
|
5584
|
+
getCapabilityStatus: (config, cwd, tool, options) => perplexityImplementation.getCapabilityStatus(
|
|
5542
5585
|
config,
|
|
5543
5586
|
cwd,
|
|
5544
|
-
tool
|
|
5587
|
+
tool,
|
|
5588
|
+
options
|
|
5545
5589
|
),
|
|
5546
5590
|
capabilities: {
|
|
5547
5591
|
search: defineCapability({
|
|
@@ -5584,9 +5628,103 @@ var perplexityProvider = defineProvider({
|
|
|
5584
5628
|
|
|
5585
5629
|
// src/providers/serper.ts
|
|
5586
5630
|
import { Type as Type13 } from "typebox";
|
|
5631
|
+
|
|
5632
|
+
// src/types.ts
|
|
5633
|
+
var TOOLS = ["search", "contents", "answer", "research"];
|
|
5634
|
+
var SERPER_SEARCH_MODE_VALUES = {
|
|
5635
|
+
search: "search",
|
|
5636
|
+
images: "images",
|
|
5637
|
+
videos: "videos",
|
|
5638
|
+
places: "places",
|
|
5639
|
+
maps: "maps",
|
|
5640
|
+
reviews: "reviews",
|
|
5641
|
+
news: "news",
|
|
5642
|
+
shopping: "shopping",
|
|
5643
|
+
productReviews: "product-reviews",
|
|
5644
|
+
lens: "lens",
|
|
5645
|
+
scholar: "scholar",
|
|
5646
|
+
patents: "patents",
|
|
5647
|
+
autocomplete: "autocomplete",
|
|
5648
|
+
webpage: "webpage"
|
|
5649
|
+
};
|
|
5650
|
+
|
|
5651
|
+
// src/providers/serper.ts
|
|
5587
5652
|
var DEFAULT_BASE_URL3 = "https://google.serper.dev";
|
|
5653
|
+
var DEFAULT_SCRAPE_URL = "https://scrape.serper.dev";
|
|
5654
|
+
var SERPER_SEARCH_MODES = Object.values(SERPER_SEARCH_MODE_VALUES);
|
|
5655
|
+
var SERPER_SEARCH_MODE_SET = new Set(SERPER_SEARCH_MODES);
|
|
5656
|
+
var RESERVED_REQUEST_OPTION_KEYS = [
|
|
5657
|
+
"q",
|
|
5658
|
+
"num",
|
|
5659
|
+
"mode",
|
|
5660
|
+
"url",
|
|
5661
|
+
"productId",
|
|
5662
|
+
"nextPageToken",
|
|
5663
|
+
"ll",
|
|
5664
|
+
"placeId",
|
|
5665
|
+
"cid",
|
|
5666
|
+
"fid",
|
|
5667
|
+
"sortBy",
|
|
5668
|
+
"topicId",
|
|
5669
|
+
"includeMarkdown",
|
|
5670
|
+
"includeImages",
|
|
5671
|
+
"includeLinks",
|
|
5672
|
+
"includeVideos",
|
|
5673
|
+
"location",
|
|
5674
|
+
"gl",
|
|
5675
|
+
"hl",
|
|
5676
|
+
"tbs",
|
|
5677
|
+
"page",
|
|
5678
|
+
"autocorrect"
|
|
5679
|
+
];
|
|
5680
|
+
var PRIMARY_RESULT_FIELDS_BY_MODE = {
|
|
5681
|
+
search: ["organic"],
|
|
5682
|
+
images: ["images"],
|
|
5683
|
+
videos: ["videos"],
|
|
5684
|
+
places: ["places"],
|
|
5685
|
+
maps: ["maps", "places"],
|
|
5686
|
+
reviews: ["reviews"],
|
|
5687
|
+
news: ["news"],
|
|
5688
|
+
shopping: ["shopping"],
|
|
5689
|
+
"product-reviews": ["reviews", "productReviews"],
|
|
5690
|
+
lens: ["visualMatches", "organic", "images"],
|
|
5691
|
+
scholar: ["organic"],
|
|
5692
|
+
patents: ["organic"],
|
|
5693
|
+
autocomplete: ["suggestions"],
|
|
5694
|
+
webpage: []
|
|
5695
|
+
};
|
|
5696
|
+
var CONTEXT_ARRAY_FIELDS = [
|
|
5697
|
+
"peopleAlsoAsk",
|
|
5698
|
+
"relatedSearches",
|
|
5699
|
+
"topStories",
|
|
5700
|
+
"news",
|
|
5701
|
+
"images",
|
|
5702
|
+
"videos",
|
|
5703
|
+
"places",
|
|
5704
|
+
"maps",
|
|
5705
|
+
"shopping",
|
|
5706
|
+
"reviews",
|
|
5707
|
+
"productReviews",
|
|
5708
|
+
"visualMatches",
|
|
5709
|
+
"suggestions"
|
|
5710
|
+
];
|
|
5711
|
+
var serperSearchPromptGuidelines = [
|
|
5712
|
+
"Use Serper news mode for recent journalism, current events, announcements, or time-sensitive reporting.",
|
|
5713
|
+
"Use Serper images or videos mode when the user asks for visual references, screenshots, diagrams, clips, tutorials, or media results.",
|
|
5714
|
+
"Use Serper places or maps mode for local businesses, venues, addresses, ratings, phone numbers, opening details, or nearby/in-location searches.",
|
|
5715
|
+
"Use Serper reviews mode when the task needs Google business reviews. Prefer cid, fid, or placeId from a maps or places result when available; otherwise use the search query as the place identifier.",
|
|
5716
|
+
"Use Serper shopping mode for product listings, prices, merchants, offers, or purchase comparisons, and use product-reviews mode when the task needs reviews for a known product ID.",
|
|
5717
|
+
"Use Serper scholar mode for academic papers and patents mode for patent searches.",
|
|
5718
|
+
"Use Serper autocomplete mode when the task is to discover search suggestions or query completions rather than source pages.",
|
|
5719
|
+
"Use Serper lens mode for reverse image search with an image URL, and use webpage mode to scrape a specific URL. Webpage mode includes Markdown by default."
|
|
5720
|
+
];
|
|
5588
5721
|
var serperSearchOptionsSchema = Type13.Object(
|
|
5589
5722
|
{
|
|
5723
|
+
mode: Type13.Optional(
|
|
5724
|
+
Type13.Enum(SERPER_SEARCH_MODE_VALUES, {
|
|
5725
|
+
description: "Serper search type. Use 'search' for web results, 'news' for recent journalism/current events, 'images' for visual references, 'videos' for clips/tutorials, 'places' or 'maps' for local businesses/venues, 'reviews' for Google business reviews by place ID/CID/FID or query, 'shopping' for products, 'product-reviews' for product reviews, 'lens' for reverse image search, 'scholar' for scholarly articles, 'patents' for patents, 'autocomplete' for suggestions, and 'webpage' to scrape a URL."
|
|
5726
|
+
})
|
|
5727
|
+
),
|
|
5590
5728
|
gl: Type13.Optional(
|
|
5591
5729
|
Type13.String({
|
|
5592
5730
|
description: "Country code hint for Google results (for example 'us')."
|
|
@@ -5608,10 +5746,63 @@ var serperSearchOptionsSchema = Type13.Object(
|
|
|
5608
5746
|
description: "1-based results page to request from Serper."
|
|
5609
5747
|
})
|
|
5610
5748
|
),
|
|
5749
|
+
tbs: Type13.Optional(
|
|
5750
|
+
Type13.String({
|
|
5751
|
+
description: "Google time/date or vertical-specific filter string passed through to Serper, for example 'qdr:d' for past day."
|
|
5752
|
+
})
|
|
5753
|
+
),
|
|
5611
5754
|
autocorrect: Type13.Optional(
|
|
5612
5755
|
Type13.Boolean({
|
|
5613
5756
|
description: "Enable or disable Serper query autocorrection."
|
|
5614
5757
|
})
|
|
5758
|
+
),
|
|
5759
|
+
url: Type13.Optional(
|
|
5760
|
+
Type13.String({
|
|
5761
|
+
description: "URL for modes that need one: image URL for 'lens', or page URL for 'webpage'. Defaults to the query string when omitted."
|
|
5762
|
+
})
|
|
5763
|
+
),
|
|
5764
|
+
ll: Type13.Optional(
|
|
5765
|
+
Type13.String({
|
|
5766
|
+
description: "Google Maps latitude/longitude/zoom hint, for example '@40.6973709,-74.1444871,11z'."
|
|
5767
|
+
})
|
|
5768
|
+
),
|
|
5769
|
+
placeId: Type13.Optional(
|
|
5770
|
+
Type13.String({ description: "Google place ID for maps or reviews." })
|
|
5771
|
+
),
|
|
5772
|
+
cid: Type13.Optional(
|
|
5773
|
+
Type13.String({ description: "Google CID for maps or reviews." })
|
|
5774
|
+
),
|
|
5775
|
+
fid: Type13.Optional(Type13.String({ description: "Google FID for reviews." })),
|
|
5776
|
+
sortBy: Type13.Optional(
|
|
5777
|
+
Type13.String({ description: "Review sort order for reviews mode." })
|
|
5778
|
+
),
|
|
5779
|
+
topicId: Type13.Optional(
|
|
5780
|
+
Type13.String({ description: "Review topic ID for reviews mode." })
|
|
5781
|
+
),
|
|
5782
|
+
productId: Type13.Optional(
|
|
5783
|
+
Type13.String({
|
|
5784
|
+
description: "Google product ID for product-reviews mode. Defaults to the query string when omitted."
|
|
5785
|
+
})
|
|
5786
|
+
),
|
|
5787
|
+
nextPageToken: Type13.Optional(
|
|
5788
|
+
Type13.String({
|
|
5789
|
+
description: "Pagination token for reviews or product-reviews modes."
|
|
5790
|
+
})
|
|
5791
|
+
),
|
|
5792
|
+
includeMarkdown: Type13.Optional(
|
|
5793
|
+
Type13.Boolean({
|
|
5794
|
+
default: true,
|
|
5795
|
+
description: "Include Markdown content in webpage mode. Defaults to true."
|
|
5796
|
+
})
|
|
5797
|
+
),
|
|
5798
|
+
includeImages: Type13.Optional(
|
|
5799
|
+
Type13.Boolean({ description: "Include image metadata in webpage mode." })
|
|
5800
|
+
),
|
|
5801
|
+
includeLinks: Type13.Optional(
|
|
5802
|
+
Type13.Boolean({ description: "Include link metadata in webpage mode." })
|
|
5803
|
+
),
|
|
5804
|
+
includeVideos: Type13.Optional(
|
|
5805
|
+
Type13.Boolean({ description: "Include video metadata in webpage mode." })
|
|
5615
5806
|
)
|
|
5616
5807
|
},
|
|
5617
5808
|
{ description: "Serper search options." }
|
|
@@ -5631,58 +5822,218 @@ var serperImplementation = {
|
|
|
5631
5822
|
createTemplate() {
|
|
5632
5823
|
return {
|
|
5633
5824
|
credentials: { api: "SERPER_API_KEY" },
|
|
5634
|
-
options: {
|
|
5825
|
+
options: {
|
|
5826
|
+
search: {
|
|
5827
|
+
includeMarkdown: true
|
|
5828
|
+
}
|
|
5829
|
+
}
|
|
5635
5830
|
};
|
|
5636
5831
|
},
|
|
5637
|
-
getCapabilityStatus(config) {
|
|
5638
|
-
return getApiKeyStatus(config?.credentials?.api);
|
|
5832
|
+
getCapabilityStatus(config, _cwd, _tool, options) {
|
|
5833
|
+
return getApiKeyStatus(config?.credentials?.api, options);
|
|
5639
5834
|
},
|
|
5640
5835
|
async search(query2, maxResults, config, context, options) {
|
|
5641
5836
|
const apiKey = resolveConfigValue(config.credentials?.api);
|
|
5642
5837
|
if (!apiKey) {
|
|
5643
5838
|
throw new Error("is missing an API key");
|
|
5644
5839
|
}
|
|
5645
|
-
const defaults = asJsonObject(config.options?.search)
|
|
5840
|
+
const defaults = asJsonObject(config.options?.search);
|
|
5646
5841
|
const callOptions = asJsonObject(options);
|
|
5647
|
-
const {
|
|
5648
|
-
q: _ignoredQuery,
|
|
5649
|
-
num: _ignoredNum,
|
|
5650
|
-
...providerOptions
|
|
5651
|
-
} = {
|
|
5842
|
+
const requestOptions = readRequestOptions({
|
|
5652
5843
|
...defaults,
|
|
5653
|
-
...callOptions
|
|
5654
|
-
};
|
|
5655
|
-
const response = await fetch(joinUrl(resolveConfigValue(config.baseUrl)), {
|
|
5656
|
-
method: "POST",
|
|
5657
|
-
headers: {
|
|
5658
|
-
"content-type": "application/json",
|
|
5659
|
-
"x-api-key": apiKey
|
|
5660
|
-
},
|
|
5661
|
-
body: JSON.stringify({
|
|
5662
|
-
q: query2,
|
|
5663
|
-
num: clampMaxResults2(maxResults),
|
|
5664
|
-
...providerOptions
|
|
5665
|
-
}),
|
|
5666
|
-
signal: context.signal
|
|
5844
|
+
...callOptions
|
|
5667
5845
|
});
|
|
5846
|
+
const requestBody = buildRequestBody(
|
|
5847
|
+
query2,
|
|
5848
|
+
clampMaxResults2(maxResults),
|
|
5849
|
+
requestOptions
|
|
5850
|
+
);
|
|
5851
|
+
const response = await fetch(
|
|
5852
|
+
joinUrl(resolveConfigValue(config.baseUrl), requestOptions.mode),
|
|
5853
|
+
{
|
|
5854
|
+
method: "POST",
|
|
5855
|
+
headers: {
|
|
5856
|
+
"content-type": "application/json",
|
|
5857
|
+
"x-api-key": apiKey
|
|
5858
|
+
},
|
|
5859
|
+
body: JSON.stringify(requestBody),
|
|
5860
|
+
signal: context.signal
|
|
5861
|
+
}
|
|
5862
|
+
);
|
|
5668
5863
|
if (!response.ok) {
|
|
5669
5864
|
throw new Error(await buildHttpError2(response));
|
|
5670
5865
|
}
|
|
5671
5866
|
const payload = await response.json();
|
|
5672
|
-
const responseRecord =
|
|
5673
|
-
|
|
5674
|
-
|
|
5867
|
+
const responseRecord = enrichResponseRecord(
|
|
5868
|
+
asRecord3(payload) ?? {},
|
|
5869
|
+
requestOptions.mode,
|
|
5870
|
+
requestBody
|
|
5871
|
+
);
|
|
5872
|
+
const results = readPrimaryResults(responseRecord, requestOptions.mode);
|
|
5873
|
+
const searchContext = buildSearchContext(
|
|
5874
|
+
responseRecord,
|
|
5875
|
+
requestOptions.mode
|
|
5876
|
+
);
|
|
5675
5877
|
return {
|
|
5676
5878
|
provider: serperImplementation.id,
|
|
5677
|
-
results:
|
|
5879
|
+
results: results.map(
|
|
5880
|
+
(entry) => toSearchResult3(entry, searchContext, requestOptions.mode)
|
|
5881
|
+
).filter(
|
|
5678
5882
|
(result) => result !== null
|
|
5679
5883
|
).slice(0, clampMaxResults2(maxResults))
|
|
5680
5884
|
};
|
|
5681
5885
|
}
|
|
5682
5886
|
};
|
|
5683
|
-
function joinUrl(baseUrl) {
|
|
5887
|
+
function joinUrl(baseUrl, mode = "search") {
|
|
5684
5888
|
const base2 = (baseUrl ?? DEFAULT_BASE_URL3).replace(/\/+$/, "");
|
|
5685
|
-
|
|
5889
|
+
if (mode === "webpage" && base2 === DEFAULT_BASE_URL3) {
|
|
5890
|
+
return DEFAULT_SCRAPE_URL;
|
|
5891
|
+
}
|
|
5892
|
+
return `${base2}/${mode}`;
|
|
5893
|
+
}
|
|
5894
|
+
function readRequestOptions(options) {
|
|
5895
|
+
const result = {
|
|
5896
|
+
mode: readSearchMode(options.mode),
|
|
5897
|
+
extra: extractExtraMetadata(options, RESERVED_REQUEST_OPTION_KEYS)
|
|
5898
|
+
};
|
|
5899
|
+
copyStringOption(result, "gl", options.gl);
|
|
5900
|
+
copyStringOption(result, "hl", options.hl);
|
|
5901
|
+
copyStringOption(result, "location", options.location);
|
|
5902
|
+
copyStringOption(result, "tbs", options.tbs);
|
|
5903
|
+
copyStringOption(result, "url", options.url);
|
|
5904
|
+
copyStringOption(result, "ll", options.ll);
|
|
5905
|
+
copyStringOption(result, "placeId", options.placeId);
|
|
5906
|
+
copyStringOption(result, "cid", options.cid);
|
|
5907
|
+
copyStringOption(result, "fid", options.fid);
|
|
5908
|
+
copyStringOption(result, "sortBy", options.sortBy);
|
|
5909
|
+
copyStringOption(result, "topicId", options.topicId);
|
|
5910
|
+
copyStringOption(result, "productId", options.productId);
|
|
5911
|
+
copyStringOption(result, "nextPageToken", options.nextPageToken);
|
|
5912
|
+
copyBooleanOption(result, "autocorrect", options.autocorrect);
|
|
5913
|
+
copyBooleanOption(result, "includeMarkdown", options.includeMarkdown);
|
|
5914
|
+
copyBooleanOption(result, "includeImages", options.includeImages);
|
|
5915
|
+
copyBooleanOption(result, "includeLinks", options.includeLinks);
|
|
5916
|
+
copyBooleanOption(result, "includeVideos", options.includeVideos);
|
|
5917
|
+
const page = readInteger2(options.page);
|
|
5918
|
+
if (page !== void 0) {
|
|
5919
|
+
result.page = Math.max(1, page);
|
|
5920
|
+
}
|
|
5921
|
+
return result;
|
|
5922
|
+
}
|
|
5923
|
+
function buildRequestBody(query2, maxResults, options) {
|
|
5924
|
+
const common = omitUndefined({
|
|
5925
|
+
location: options.location,
|
|
5926
|
+
gl: options.gl,
|
|
5927
|
+
hl: options.hl
|
|
5928
|
+
});
|
|
5929
|
+
const withExtra = (body) => ({
|
|
5930
|
+
...body,
|
|
5931
|
+
...options.extra
|
|
5932
|
+
});
|
|
5933
|
+
switch (options.mode) {
|
|
5934
|
+
case "webpage":
|
|
5935
|
+
return withExtra(
|
|
5936
|
+
omitUndefined({
|
|
5937
|
+
url: options.url ?? query2,
|
|
5938
|
+
includeMarkdown: options.includeMarkdown ?? true,
|
|
5939
|
+
includeImages: options.includeImages,
|
|
5940
|
+
includeLinks: options.includeLinks,
|
|
5941
|
+
includeVideos: options.includeVideos
|
|
5942
|
+
})
|
|
5943
|
+
);
|
|
5944
|
+
case "product-reviews":
|
|
5945
|
+
return withExtra(
|
|
5946
|
+
omitUndefined({
|
|
5947
|
+
productId: options.productId ?? query2,
|
|
5948
|
+
nextPageToken: options.nextPageToken,
|
|
5949
|
+
...common,
|
|
5950
|
+
num: maxResults
|
|
5951
|
+
})
|
|
5952
|
+
);
|
|
5953
|
+
case "autocomplete":
|
|
5954
|
+
return withExtra({ q: query2, ...common });
|
|
5955
|
+
case "maps":
|
|
5956
|
+
return withExtra(
|
|
5957
|
+
omitUndefined({
|
|
5958
|
+
q: query2,
|
|
5959
|
+
num: maxResults,
|
|
5960
|
+
...common,
|
|
5961
|
+
ll: options.ll,
|
|
5962
|
+
placeId: options.placeId,
|
|
5963
|
+
cid: options.cid,
|
|
5964
|
+
page: options.page
|
|
5965
|
+
})
|
|
5966
|
+
);
|
|
5967
|
+
case "reviews": {
|
|
5968
|
+
const hasExplicitPlaceIdentifier = firstNonEmptyString(options.cid, options.fid, options.placeId) !== void 0;
|
|
5969
|
+
return withExtra(
|
|
5970
|
+
omitUndefined({
|
|
5971
|
+
q: hasExplicitPlaceIdentifier ? void 0 : query2,
|
|
5972
|
+
cid: options.cid,
|
|
5973
|
+
fid: options.fid,
|
|
5974
|
+
placeId: options.placeId,
|
|
5975
|
+
gl: options.gl,
|
|
5976
|
+
hl: options.hl,
|
|
5977
|
+
sortBy: options.sortBy,
|
|
5978
|
+
topicId: options.topicId,
|
|
5979
|
+
nextPageToken: options.nextPageToken
|
|
5980
|
+
})
|
|
5981
|
+
);
|
|
5982
|
+
}
|
|
5983
|
+
case "lens":
|
|
5984
|
+
return withExtra(
|
|
5985
|
+
omitUndefined({
|
|
5986
|
+
url: options.url ?? query2,
|
|
5987
|
+
...common,
|
|
5988
|
+
tbs: options.tbs
|
|
5989
|
+
})
|
|
5990
|
+
);
|
|
5991
|
+
case "scholar":
|
|
5992
|
+
return withExtra(
|
|
5993
|
+
omitUndefined({
|
|
5994
|
+
q: query2,
|
|
5995
|
+
...common,
|
|
5996
|
+
autocorrect: options.autocorrect,
|
|
5997
|
+
tbs: options.tbs,
|
|
5998
|
+
page: options.page
|
|
5999
|
+
})
|
|
6000
|
+
);
|
|
6001
|
+
default:
|
|
6002
|
+
return withExtra(
|
|
6003
|
+
omitUndefined({
|
|
6004
|
+
q: query2,
|
|
6005
|
+
num: maxResults,
|
|
6006
|
+
...common,
|
|
6007
|
+
autocorrect: options.autocorrect,
|
|
6008
|
+
tbs: options.tbs,
|
|
6009
|
+
page: options.page
|
|
6010
|
+
})
|
|
6011
|
+
);
|
|
6012
|
+
}
|
|
6013
|
+
}
|
|
6014
|
+
function enrichResponseRecord(response, mode, requestBody) {
|
|
6015
|
+
if (mode !== "webpage") {
|
|
6016
|
+
return response;
|
|
6017
|
+
}
|
|
6018
|
+
return omitUndefined({
|
|
6019
|
+
...response,
|
|
6020
|
+
url: readString4(response.url) ?? readString4(requestBody.url)
|
|
6021
|
+
});
|
|
6022
|
+
}
|
|
6023
|
+
function readSearchMode(value) {
|
|
6024
|
+
return typeof value === "string" && SERPER_SEARCH_MODE_SET.has(value) ? value : "search";
|
|
6025
|
+
}
|
|
6026
|
+
function readPrimaryResults(response, mode) {
|
|
6027
|
+
if (mode === "webpage") {
|
|
6028
|
+
return [response];
|
|
6029
|
+
}
|
|
6030
|
+
for (const field of PRIMARY_RESULT_FIELDS_BY_MODE[mode]) {
|
|
6031
|
+
const values = asArray(response[field]);
|
|
6032
|
+
if (values) {
|
|
6033
|
+
return values;
|
|
6034
|
+
}
|
|
6035
|
+
}
|
|
6036
|
+
return [];
|
|
5686
6037
|
}
|
|
5687
6038
|
function clampMaxResults2(value) {
|
|
5688
6039
|
return Math.max(1, Math.min(20, Math.trunc(value || 0)));
|
|
@@ -5709,18 +6060,52 @@ async function readErrorDetail2(response) {
|
|
|
5709
6060
|
return text;
|
|
5710
6061
|
}
|
|
5711
6062
|
}
|
|
5712
|
-
function toSearchResult3(entry, searchContext) {
|
|
6063
|
+
function toSearchResult3(entry, searchContext, mode) {
|
|
6064
|
+
if (typeof entry === "string") {
|
|
6065
|
+
return {
|
|
6066
|
+
title: entry,
|
|
6067
|
+
url: mode === "autocomplete" ? toGoogleSearchUrl(entry) : "",
|
|
6068
|
+
snippet: entry,
|
|
6069
|
+
metadata: {
|
|
6070
|
+
source: mode,
|
|
6071
|
+
...searchContext ? { searchContext } : {}
|
|
6072
|
+
}
|
|
6073
|
+
};
|
|
6074
|
+
}
|
|
5713
6075
|
const record = asRecord3(entry);
|
|
5714
6076
|
if (!record) {
|
|
5715
6077
|
return null;
|
|
5716
6078
|
}
|
|
5717
|
-
const
|
|
5718
|
-
const
|
|
6079
|
+
const responseMetadata = asRecord3(record.metadata);
|
|
6080
|
+
const user = asRecord3(record.user);
|
|
6081
|
+
const resultUrl = firstString(record.link, record.website, record.url, record.imageUrl) ?? "";
|
|
6082
|
+
const title = firstNonEmptyString(
|
|
6083
|
+
record.title,
|
|
6084
|
+
responseMetadata?.title,
|
|
6085
|
+
record.name,
|
|
6086
|
+
record.query,
|
|
6087
|
+
record.value,
|
|
6088
|
+
user?.name,
|
|
6089
|
+
formatReviewTitle(record, user),
|
|
6090
|
+
resultUrl
|
|
6091
|
+
) ?? "Untitled";
|
|
6092
|
+
const url2 = resultUrl || (mode === "autocomplete" ? toGoogleSearchUrl(title) : "");
|
|
5719
6093
|
const snippet = trimSnippet(
|
|
5720
|
-
|
|
6094
|
+
firstNonEmptyString(
|
|
6095
|
+
record.snippet,
|
|
6096
|
+
record.richSnippet,
|
|
6097
|
+
record.markdown,
|
|
6098
|
+
record.text,
|
|
6099
|
+
record.address,
|
|
6100
|
+
record.price,
|
|
6101
|
+
record.date,
|
|
6102
|
+
record.name,
|
|
6103
|
+
record.value,
|
|
6104
|
+
record.url
|
|
6105
|
+
) ?? ""
|
|
5721
6106
|
);
|
|
5722
6107
|
const metadata = omitUndefined({
|
|
5723
|
-
source: "organic",
|
|
6108
|
+
source: readString4(record.source) ?? (mode === "search" ? "organic" : mode),
|
|
5724
6109
|
position: readNumber(record.position),
|
|
5725
6110
|
date: readString4(record.date),
|
|
5726
6111
|
attributes: asRecord3(record.attributes),
|
|
@@ -5728,7 +6113,16 @@ function toSearchResult3(entry, searchContext) {
|
|
|
5728
6113
|
rating: readNumber(record.rating),
|
|
5729
6114
|
ratingCount: readNumber(record.ratingCount),
|
|
5730
6115
|
cid: readString4(record.cid),
|
|
5731
|
-
...extractExtraMetadata(record, [
|
|
6116
|
+
...extractExtraMetadata(record, [
|
|
6117
|
+
"title",
|
|
6118
|
+
"name",
|
|
6119
|
+
"query",
|
|
6120
|
+
"value",
|
|
6121
|
+
"link",
|
|
6122
|
+
"website",
|
|
6123
|
+
"url",
|
|
6124
|
+
"snippet"
|
|
6125
|
+
]),
|
|
5732
6126
|
...searchContext ? { searchContext } : {}
|
|
5733
6127
|
});
|
|
5734
6128
|
return {
|
|
@@ -5738,23 +6132,72 @@ function toSearchResult3(entry, searchContext) {
|
|
|
5738
6132
|
...Object.keys(metadata).length > 0 ? { metadata } : {}
|
|
5739
6133
|
};
|
|
5740
6134
|
}
|
|
5741
|
-
function buildSearchContext(response) {
|
|
6135
|
+
function buildSearchContext(response, mode) {
|
|
5742
6136
|
const context = omitUndefined({
|
|
5743
6137
|
searchParameters: asRecord3(response.searchParameters),
|
|
5744
6138
|
searchInformation: asRecord3(response.searchInformation),
|
|
5745
6139
|
credits: readNumber(response.credits),
|
|
5746
6140
|
answerBox: asRecord3(response.answerBox),
|
|
5747
|
-
knowledgeGraph: asRecord3(response.knowledgeGraph)
|
|
5748
|
-
peopleAlsoAsk: asArray(response.peopleAlsoAsk),
|
|
5749
|
-
relatedSearches: asArray(response.relatedSearches),
|
|
5750
|
-
topStories: asArray(response.topStories),
|
|
5751
|
-
news: asArray(response.news),
|
|
5752
|
-
images: asArray(response.images),
|
|
5753
|
-
videos: asArray(response.videos),
|
|
5754
|
-
places: asArray(response.places)
|
|
6141
|
+
knowledgeGraph: asRecord3(response.knowledgeGraph)
|
|
5755
6142
|
});
|
|
6143
|
+
const primaryResultFields = new Set(
|
|
6144
|
+
PRIMARY_RESULT_FIELDS_BY_MODE[mode]
|
|
6145
|
+
);
|
|
6146
|
+
for (const field of CONTEXT_ARRAY_FIELDS) {
|
|
6147
|
+
if (primaryResultFields.has(field)) {
|
|
6148
|
+
continue;
|
|
6149
|
+
}
|
|
6150
|
+
const value = asArray(response[field]);
|
|
6151
|
+
if (value) {
|
|
6152
|
+
context[field] = value;
|
|
6153
|
+
}
|
|
6154
|
+
}
|
|
5756
6155
|
return Object.keys(context).length > 0 ? context : void 0;
|
|
5757
6156
|
}
|
|
6157
|
+
function copyStringOption(target, key, value) {
|
|
6158
|
+
const text = readString4(value);
|
|
6159
|
+
if (text !== void 0) {
|
|
6160
|
+
target[key] = text;
|
|
6161
|
+
}
|
|
6162
|
+
}
|
|
6163
|
+
function copyBooleanOption(target, key, value) {
|
|
6164
|
+
const flag = readBoolean(value);
|
|
6165
|
+
if (flag !== void 0) {
|
|
6166
|
+
target[key] = flag;
|
|
6167
|
+
}
|
|
6168
|
+
}
|
|
6169
|
+
function firstString(...values) {
|
|
6170
|
+
return values.find((value) => typeof value === "string");
|
|
6171
|
+
}
|
|
6172
|
+
function toGoogleSearchUrl(query2) {
|
|
6173
|
+
return `https://www.google.com/search?q=${encodeURIComponent(query2)}`;
|
|
6174
|
+
}
|
|
6175
|
+
function formatReviewTitle(record, user) {
|
|
6176
|
+
const userName = readString4(user?.name);
|
|
6177
|
+
const rating = readNumber(record.rating);
|
|
6178
|
+
const date = readString4(record.date) ?? readString4(record.isoDate);
|
|
6179
|
+
if (userName && rating !== void 0) {
|
|
6180
|
+
return `${userName} (${rating}-star review)`;
|
|
6181
|
+
}
|
|
6182
|
+
if (userName) {
|
|
6183
|
+
return `${userName}'s review`;
|
|
6184
|
+
}
|
|
6185
|
+
if (rating !== void 0 && date) {
|
|
6186
|
+
return `${rating}-star review from ${date}`;
|
|
6187
|
+
}
|
|
6188
|
+
if (rating !== void 0) {
|
|
6189
|
+
return `${rating}-star review`;
|
|
6190
|
+
}
|
|
6191
|
+
if (date) {
|
|
6192
|
+
return `Review from ${date}`;
|
|
6193
|
+
}
|
|
6194
|
+
return void 0;
|
|
6195
|
+
}
|
|
6196
|
+
function firstNonEmptyString(...values) {
|
|
6197
|
+
return values.find(
|
|
6198
|
+
(value) => typeof value === "string" && value.length > 0
|
|
6199
|
+
);
|
|
6200
|
+
}
|
|
5758
6201
|
function extractExtraMetadata(record, ignoredKeys) {
|
|
5759
6202
|
return Object.fromEntries(
|
|
5760
6203
|
Object.entries(record).filter(
|
|
@@ -5779,6 +6222,12 @@ function readString4(value) {
|
|
|
5779
6222
|
function readNumber(value) {
|
|
5780
6223
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
5781
6224
|
}
|
|
6225
|
+
function readInteger2(value) {
|
|
6226
|
+
return typeof value === "number" && Number.isInteger(value) ? value : void 0;
|
|
6227
|
+
}
|
|
6228
|
+
function readBoolean(value) {
|
|
6229
|
+
return typeof value === "boolean" ? value : void 0;
|
|
6230
|
+
}
|
|
5782
6231
|
var serperProvider = defineProvider({
|
|
5783
6232
|
id: "serper",
|
|
5784
6233
|
label: serperImplementation.label,
|
|
@@ -5788,14 +6237,16 @@ var serperProvider = defineProvider({
|
|
|
5788
6237
|
fields: ["credentials", "baseUrl", "options", "settings"],
|
|
5789
6238
|
optionCapabilities: ["search"]
|
|
5790
6239
|
},
|
|
5791
|
-
getCapabilityStatus: (config, cwd, tool) => serperImplementation.getCapabilityStatus(
|
|
6240
|
+
getCapabilityStatus: (config, cwd, tool, options) => serperImplementation.getCapabilityStatus(
|
|
5792
6241
|
config,
|
|
5793
6242
|
cwd,
|
|
5794
|
-
tool
|
|
6243
|
+
tool,
|
|
6244
|
+
options
|
|
5795
6245
|
),
|
|
5796
6246
|
capabilities: {
|
|
5797
6247
|
search: defineCapability({
|
|
5798
6248
|
options: serperImplementation.getToolOptionsSchema?.("search"),
|
|
6249
|
+
promptGuidelines: serperSearchPromptGuidelines,
|
|
5799
6250
|
async execute(input, ctx) {
|
|
5800
6251
|
const { query: query2, maxResults, options } = input;
|
|
5801
6252
|
return await serperImplementation.search(
|
|
@@ -5920,8 +6371,8 @@ var tavilyImplementation = {
|
|
|
5920
6371
|
}
|
|
5921
6372
|
};
|
|
5922
6373
|
},
|
|
5923
|
-
getCapabilityStatus(config) {
|
|
5924
|
-
return getApiKeyStatus(config?.credentials?.api);
|
|
6374
|
+
getCapabilityStatus(config, _cwd, _tool, options) {
|
|
6375
|
+
return getApiKeyStatus(config?.credentials?.api, options);
|
|
5925
6376
|
},
|
|
5926
6377
|
async search(query2, maxResults, config, _context, options) {
|
|
5927
6378
|
const client = createClient8(config);
|
|
@@ -6019,10 +6470,11 @@ var tavilyProvider = defineProvider({
|
|
|
6019
6470
|
createTemplate: () => tavilyImplementation.createTemplate(),
|
|
6020
6471
|
fields: ["credentials", "baseUrl", "options", "settings"]
|
|
6021
6472
|
},
|
|
6022
|
-
getCapabilityStatus: (config, cwd, tool) => tavilyImplementation.getCapabilityStatus(
|
|
6473
|
+
getCapabilityStatus: (config, cwd, tool, options) => tavilyImplementation.getCapabilityStatus(
|
|
6023
6474
|
config,
|
|
6024
6475
|
cwd,
|
|
6025
|
-
tool
|
|
6476
|
+
tool,
|
|
6477
|
+
options
|
|
6026
6478
|
),
|
|
6027
6479
|
capabilities: {
|
|
6028
6480
|
search: defineCapability({
|
|
@@ -6126,8 +6578,8 @@ var valyuImplementation = {
|
|
|
6126
6578
|
}
|
|
6127
6579
|
};
|
|
6128
6580
|
},
|
|
6129
|
-
getCapabilityStatus(config) {
|
|
6130
|
-
return getApiKeyStatus(config?.credentials?.api);
|
|
6581
|
+
getCapabilityStatus(config, _cwd, _tool, options) {
|
|
6582
|
+
return getApiKeyStatus(config?.credentials?.api, options);
|
|
6131
6583
|
},
|
|
6132
6584
|
async search(query2, maxResults, config, _context, searchOptions) {
|
|
6133
6585
|
const client = createClient9(config);
|
|
@@ -6302,10 +6754,11 @@ var valyuProvider = defineProvider({
|
|
|
6302
6754
|
fields: ["credentials", "baseUrl", "options", "settings"],
|
|
6303
6755
|
optionCapabilities: ["search", "answer", "research"]
|
|
6304
6756
|
},
|
|
6305
|
-
getCapabilityStatus: (config, cwd, tool) => valyuImplementation.getCapabilityStatus(
|
|
6757
|
+
getCapabilityStatus: (config, cwd, tool, options) => valyuImplementation.getCapabilityStatus(
|
|
6306
6758
|
config,
|
|
6307
6759
|
cwd,
|
|
6308
|
-
tool
|
|
6760
|
+
tool,
|
|
6761
|
+
options
|
|
6309
6762
|
),
|
|
6310
6763
|
capabilities: {
|
|
6311
6764
|
search: defineCapability({
|
|
@@ -6380,9 +6833,6 @@ var PROVIDERS_BY_ID = PROVIDERS;
|
|
|
6380
6833
|
var PROVIDER_LIST = Object.values(PROVIDERS);
|
|
6381
6834
|
var PROVIDER_IDS = Object.keys(PROVIDERS);
|
|
6382
6835
|
|
|
6383
|
-
// src/types.ts
|
|
6384
|
-
var TOOLS = ["search", "contents", "answer", "research"];
|
|
6385
|
-
|
|
6386
6836
|
// src/provider-tools.ts
|
|
6387
6837
|
var TOOL_INFO = {
|
|
6388
6838
|
search: {
|
|
@@ -7138,17 +7588,21 @@ function isPlainObject4(value) {
|
|
|
7138
7588
|
function getMappedProviderIdForTool(config, tool) {
|
|
7139
7589
|
return getMappedProviderForTool(config, tool);
|
|
7140
7590
|
}
|
|
7141
|
-
function getProviderCapabilityStatus(config, cwd, providerId, tool) {
|
|
7591
|
+
function getProviderCapabilityStatus(config, cwd, providerId, tool, options) {
|
|
7142
7592
|
const provider = PROVIDERS[providerId];
|
|
7143
7593
|
return provider.getCapabilityStatus(
|
|
7144
7594
|
getEffectiveProviderConfig(config, providerId),
|
|
7145
7595
|
cwd,
|
|
7146
|
-
tool
|
|
7596
|
+
tool,
|
|
7597
|
+
options
|
|
7147
7598
|
);
|
|
7148
7599
|
}
|
|
7149
7600
|
function isProviderCapabilityReady(status) {
|
|
7150
7601
|
return status.state === "ready";
|
|
7151
7602
|
}
|
|
7603
|
+
function isProviderCapabilityExposable(status) {
|
|
7604
|
+
return status.state === "ready" || status.state === "deferred_secret";
|
|
7605
|
+
}
|
|
7152
7606
|
function getProviderSetupState(config, providerId) {
|
|
7153
7607
|
if (providerId === "claude" || providerId === "codex") {
|
|
7154
7608
|
return "builtin";
|
|
@@ -7163,12 +7617,17 @@ function getProviderSetupState(config, providerId) {
|
|
|
7163
7617
|
if (providerId === "cloudflare") {
|
|
7164
7618
|
return providerConfig.credentials !== void 0 || providerConfig.accountId !== void 0 ? "configured" : "none";
|
|
7165
7619
|
}
|
|
7620
|
+
if (providerId === "firecrawl") {
|
|
7621
|
+
return providerConfig.credentials !== void 0 || providerConfig.baseUrl !== void 0 ? "configured" : "none";
|
|
7622
|
+
}
|
|
7166
7623
|
return providerConfig.credentials !== void 0 ? "configured" : "none";
|
|
7167
7624
|
}
|
|
7168
7625
|
function formatProviderCapabilityStatus(status, providerId, tool) {
|
|
7169
7626
|
switch (status.state) {
|
|
7170
7627
|
case "ready":
|
|
7171
7628
|
return "Ready";
|
|
7629
|
+
case "deferred_secret":
|
|
7630
|
+
return "Secret resolved on first use";
|
|
7172
7631
|
case "missing_api_key":
|
|
7173
7632
|
return "Missing API key";
|
|
7174
7633
|
case "missing_executable":
|
|
@@ -8812,6 +9271,158 @@ function cleanupCapabilityOptions(config, keys) {
|
|
|
8812
9271
|
cleanupEmpty(config, "options");
|
|
8813
9272
|
}
|
|
8814
9273
|
|
|
9274
|
+
// src/tool-display.ts
|
|
9275
|
+
import { formatSize } from "@earendil-works/pi-coding-agent";
|
|
9276
|
+
var ANSWER_EXCERPT_MAX_LENGTH = 100;
|
|
9277
|
+
function buildSearchToolDisplay(details) {
|
|
9278
|
+
return buildToolDisplay(details.provider, buildSearchSummaryParts(details));
|
|
9279
|
+
}
|
|
9280
|
+
function buildProgressDisplay(providerId, action) {
|
|
9281
|
+
return {
|
|
9282
|
+
provider: getProviderDisplay(providerId),
|
|
9283
|
+
progress: { action }
|
|
9284
|
+
};
|
|
9285
|
+
}
|
|
9286
|
+
function buildProviderToolDisplay({
|
|
9287
|
+
capability,
|
|
9288
|
+
providerId,
|
|
9289
|
+
details,
|
|
9290
|
+
text,
|
|
9291
|
+
outputBytes,
|
|
9292
|
+
outputTruncated,
|
|
9293
|
+
failedItemCount
|
|
9294
|
+
}) {
|
|
9295
|
+
const summary = capability === "contents" && details.tool === "web_contents" ? buildContentsDisplaySummary(details, text, {
|
|
9296
|
+
outputBytes,
|
|
9297
|
+
outputTruncated,
|
|
9298
|
+
failedItemCount
|
|
9299
|
+
}) : capability === "research" && text ? { success: text } : buildCollapsedProviderToolSummaryParts(details, text);
|
|
9300
|
+
return buildToolDisplay(providerId, summary);
|
|
9301
|
+
}
|
|
9302
|
+
function buildCollapsedProviderToolSummary(details, text) {
|
|
9303
|
+
const summary = buildCollapsedProviderToolSummaryParts(details, text);
|
|
9304
|
+
return summary.failure ? `${summary.success}, ${summary.failure}` : summary.success;
|
|
9305
|
+
}
|
|
9306
|
+
function buildCollapsedProviderToolSummaryParts(details, text) {
|
|
9307
|
+
if (details?.tool === "web_answer") {
|
|
9308
|
+
return buildAnswerCollapsedSummary(details, text);
|
|
9309
|
+
}
|
|
9310
|
+
if (details?.tool === "web_contents") {
|
|
9311
|
+
return buildContentsSummary(details, text);
|
|
9312
|
+
}
|
|
9313
|
+
const baseSummary = getCompactProviderToolSummary(details) ?? getFirstLine(text) ?? `${details?.tool ?? "tool"} output available`;
|
|
9314
|
+
return { success: baseSummary };
|
|
9315
|
+
}
|
|
9316
|
+
function buildSearchSummaryParts({
|
|
9317
|
+
queryCount,
|
|
9318
|
+
resultCount,
|
|
9319
|
+
failedQueryCount
|
|
9320
|
+
}) {
|
|
9321
|
+
const success = typeof resultCount === "number" ? `${resultCount} result${resultCount === 1 ? "" : "s"}` : "Search output available";
|
|
9322
|
+
if (failedQueryCount && failedQueryCount > 0 && queryCount) {
|
|
9323
|
+
return {
|
|
9324
|
+
success,
|
|
9325
|
+
failure: `${failedQueryCount} of ${queryCount} ${queryCount === 1 ? "query" : "queries"} failed`
|
|
9326
|
+
};
|
|
9327
|
+
}
|
|
9328
|
+
return { success };
|
|
9329
|
+
}
|
|
9330
|
+
function buildToolDisplay(providerId, outcome) {
|
|
9331
|
+
return {
|
|
9332
|
+
provider: getProviderDisplay(providerId),
|
|
9333
|
+
outcome
|
|
9334
|
+
};
|
|
9335
|
+
}
|
|
9336
|
+
function getProviderDisplay(providerId) {
|
|
9337
|
+
const provider = PROVIDERS_BY_ID[providerId];
|
|
9338
|
+
return { id: providerId, label: provider?.label ?? providerId };
|
|
9339
|
+
}
|
|
9340
|
+
function buildContentsDisplaySummary(details, text, metadata) {
|
|
9341
|
+
const totalCount = details.itemCount ?? inferContentsPageCount(text);
|
|
9342
|
+
const failedCount = metadata.failedItemCount ?? inferContentsFailureCount(text);
|
|
9343
|
+
const successCount = totalCount === void 0 ? void 0 : Math.max(0, totalCount - (failedCount ?? 0));
|
|
9344
|
+
const sizeSummary = typeof metadata.outputBytes === "number" ? `${formatSize(metadata.outputBytes)}${metadata.outputTruncated ? " (truncated)" : ""}` : void 0;
|
|
9345
|
+
const success = successCount === void 0 ? sizeSummary ?? "Contents output available" : successCount === 1 && sizeSummary ? sizeSummary : `${successCount} page${successCount === 1 ? "" : "s"}${sizeSummary ? `, ${sizeSummary}` : ""}`;
|
|
9346
|
+
if (failedCount && failedCount > 0 && totalCount) {
|
|
9347
|
+
return {
|
|
9348
|
+
success,
|
|
9349
|
+
failure: `${failedCount} of ${totalCount} ${totalCount === 1 ? "page" : "pages"} failed`
|
|
9350
|
+
};
|
|
9351
|
+
}
|
|
9352
|
+
return { success };
|
|
9353
|
+
}
|
|
9354
|
+
function buildAnswerCollapsedSummary(details, text) {
|
|
9355
|
+
if (typeof details.queryCount === "number" && (details.queryCount > 1 || (details.failedQueryCount ?? 0) > 0)) {
|
|
9356
|
+
return buildAnswerSummary(details);
|
|
9357
|
+
}
|
|
9358
|
+
return { success: buildAnswerExcerpt(text) ?? "Answer output available" };
|
|
9359
|
+
}
|
|
9360
|
+
function buildAnswerSummary(details) {
|
|
9361
|
+
const queryCount = details.queryCount ?? 0;
|
|
9362
|
+
const failedQueryCount = details.failedQueryCount ?? 0;
|
|
9363
|
+
const answerCount = Math.max(0, queryCount - failedQueryCount);
|
|
9364
|
+
const success = `${answerCount} answer${answerCount === 1 ? "" : "s"}`;
|
|
9365
|
+
if (failedQueryCount > 0) {
|
|
9366
|
+
return {
|
|
9367
|
+
success,
|
|
9368
|
+
failure: `${failedQueryCount} of ${queryCount} ${queryCount === 1 ? "question" : "questions"} failed`
|
|
9369
|
+
};
|
|
9370
|
+
}
|
|
9371
|
+
return { success };
|
|
9372
|
+
}
|
|
9373
|
+
function buildAnswerExcerpt(text) {
|
|
9374
|
+
const excerpt = getFirstLine(text);
|
|
9375
|
+
if (!excerpt) {
|
|
9376
|
+
return void 0;
|
|
9377
|
+
}
|
|
9378
|
+
if (excerpt.length <= ANSWER_EXCERPT_MAX_LENGTH) {
|
|
9379
|
+
return excerpt;
|
|
9380
|
+
}
|
|
9381
|
+
return `${excerpt.slice(0, ANSWER_EXCERPT_MAX_LENGTH - 1).trimEnd()}\u2026`;
|
|
9382
|
+
}
|
|
9383
|
+
function buildContentsSummary(details, text) {
|
|
9384
|
+
const totalCount = details.itemCount ?? inferContentsPageCount(text);
|
|
9385
|
+
const failedCount = inferContentsFailureCount(text);
|
|
9386
|
+
const successCount = totalCount === void 0 ? void 0 : Math.max(0, totalCount - (failedCount ?? 0));
|
|
9387
|
+
const success = successCount === void 0 ? "Contents output available" : `${successCount} page${successCount === 1 ? "" : "s"}`;
|
|
9388
|
+
if (failedCount && failedCount > 0 && totalCount) {
|
|
9389
|
+
return {
|
|
9390
|
+
success,
|
|
9391
|
+
failure: `${failedCount} of ${totalCount} ${totalCount === 1 ? "page" : "pages"} failed`
|
|
9392
|
+
};
|
|
9393
|
+
}
|
|
9394
|
+
return { success };
|
|
9395
|
+
}
|
|
9396
|
+
function getCompactProviderToolSummary(details) {
|
|
9397
|
+
if (!details) {
|
|
9398
|
+
return void 0;
|
|
9399
|
+
}
|
|
9400
|
+
if (details.tool === "web_contents" && typeof details.itemCount === "number") {
|
|
9401
|
+
return `${details.itemCount} page${details.itemCount === 1 ? "" : "s"}`;
|
|
9402
|
+
}
|
|
9403
|
+
if (details.tool === "web_research") {
|
|
9404
|
+
return "Research";
|
|
9405
|
+
}
|
|
9406
|
+
return void 0;
|
|
9407
|
+
}
|
|
9408
|
+
function inferContentsPageCount(text) {
|
|
9409
|
+
if (!text) {
|
|
9410
|
+
return void 0;
|
|
9411
|
+
}
|
|
9412
|
+
const pageMatches = text.match(/^##\s+/gm);
|
|
9413
|
+
return pageMatches?.length;
|
|
9414
|
+
}
|
|
9415
|
+
function inferContentsFailureCount(text) {
|
|
9416
|
+
if (!text) {
|
|
9417
|
+
return void 0;
|
|
9418
|
+
}
|
|
9419
|
+
const failureMatches = text.match(/^##\s+(?:\d+\.\s+)?Error:/gm);
|
|
9420
|
+
return failureMatches?.length;
|
|
9421
|
+
}
|
|
9422
|
+
function getFirstLine(text) {
|
|
9423
|
+
return text?.split("\n").map((line) => line.trim()).find((line) => line.length > 0);
|
|
9424
|
+
}
|
|
9425
|
+
|
|
8815
9426
|
// src/index.ts
|
|
8816
9427
|
var DEFAULT_MAX_RESULTS = 5;
|
|
8817
9428
|
var MAX_ALLOWED_RESULTS = 20;
|
|
@@ -8828,6 +9439,10 @@ var CAPABILITY_TOOL_NAMES = {
|
|
|
8828
9439
|
research: "web_research"
|
|
8829
9440
|
};
|
|
8830
9441
|
var MANAGED_TOOL_NAMES = Object.values(CAPABILITY_TOOL_NAMES);
|
|
9442
|
+
var DEFAULT_SUMMARY_SYMBOLS = {
|
|
9443
|
+
success: "\u2714",
|
|
9444
|
+
failure: "\u2718"
|
|
9445
|
+
};
|
|
8831
9446
|
function webProvidersExtension(pi) {
|
|
8832
9447
|
const activeWebResearchRequests = /* @__PURE__ */ new Map();
|
|
8833
9448
|
let latestWidgetContext;
|
|
@@ -8873,7 +9488,7 @@ function webProvidersExtension(pi) {
|
|
|
8873
9488
|
if ("registerMessageRenderer" in pi) {
|
|
8874
9489
|
pi.registerMessageRenderer(
|
|
8875
9490
|
WEB_RESEARCH_RESULT_MESSAGE_TYPE,
|
|
8876
|
-
renderWebResearchResultMessage
|
|
9491
|
+
(message, state, theme) => renderWebResearchResultMessage(message, state, theme)
|
|
8877
9492
|
);
|
|
8878
9493
|
}
|
|
8879
9494
|
pi.registerCommand("web-providers", {
|
|
@@ -8934,7 +9549,7 @@ function registerWebSearchTool(pi, providerIds) {
|
|
|
8934
9549
|
pi.registerTool({
|
|
8935
9550
|
name: "web_search",
|
|
8936
9551
|
label: "Web Search",
|
|
8937
|
-
description: `Find likely sources on the public web for up to ${MAX_SEARCH_QUERIES} queries in a single call and return titles, URLs, and snippets grouped by query. Output is truncated to ${DEFAULT_MAX_LINES} lines or ${
|
|
9552
|
+
description: `Find likely sources on the public web for up to ${MAX_SEARCH_QUERIES} queries in a single call and return titles, URLs, and snippets grouped by query. Output is truncated to ${DEFAULT_MAX_LINES} lines or ${formatSize2(DEFAULT_MAX_BYTES)} when needed.`,
|
|
8938
9553
|
promptGuidelines: buildPromptGuidelines("search", selectedProviderId, [
|
|
8939
9554
|
"Batch related searches when grouped comparison matters; use separate sibling web_search calls when independent results should surface as soon as they are ready."
|
|
8940
9555
|
]),
|
|
@@ -9179,12 +9794,20 @@ function getAvailableProviderIdsForCapability(config, cwd, capability) {
|
|
|
9179
9794
|
if (!providerId) {
|
|
9180
9795
|
return [];
|
|
9181
9796
|
}
|
|
9182
|
-
|
|
9183
|
-
|
|
9184
|
-
return [providerId];
|
|
9185
|
-
} catch {
|
|
9797
|
+
const provider = PROVIDERS_BY_ID[providerId];
|
|
9798
|
+
if (!supportsTool2(provider, capability)) {
|
|
9186
9799
|
return [];
|
|
9187
9800
|
}
|
|
9801
|
+
const status = getProviderCapabilityStatus(
|
|
9802
|
+
config,
|
|
9803
|
+
cwd,
|
|
9804
|
+
providerId,
|
|
9805
|
+
capability,
|
|
9806
|
+
{
|
|
9807
|
+
resolveSecrets: false
|
|
9808
|
+
}
|
|
9809
|
+
);
|
|
9810
|
+
return isProviderCapabilityExposable(status) ? [providerId] : [];
|
|
9188
9811
|
}
|
|
9189
9812
|
function getProviderStatusForTool(config, cwd, providerId, capability) {
|
|
9190
9813
|
return getProviderCapabilityStatus(config, cwd, providerId, capability);
|
|
@@ -9324,6 +9947,7 @@ async function executeSearchToolInternal({
|
|
|
9324
9947
|
);
|
|
9325
9948
|
const batchProgress = searchQueries.length > 1 ? createBatchCompletionReporter(
|
|
9326
9949
|
"Searching",
|
|
9950
|
+
provider.id,
|
|
9327
9951
|
provider.label,
|
|
9328
9952
|
searchQueries.length,
|
|
9329
9953
|
progressReporter.report
|
|
@@ -9372,7 +9996,7 @@ async function executeSearchToolInternal({
|
|
|
9372
9996
|
progressReporter.stop();
|
|
9373
9997
|
}
|
|
9374
9998
|
if (outcomes.every((outcome) => outcome.error !== void 0)) {
|
|
9375
|
-
throw buildSearchBatchError(outcomes);
|
|
9999
|
+
throw buildSearchBatchError(outcomes, provider.label);
|
|
9376
10000
|
}
|
|
9377
10001
|
const prefetch = prefetchOptions !== void 0 && executionOverrides === void 0 ? await startContentsPrefetch({
|
|
9378
10002
|
config,
|
|
@@ -9384,9 +10008,11 @@ async function executeSearchToolInternal({
|
|
|
9384
10008
|
formatSearchResponses(outcomes, prefetch),
|
|
9385
10009
|
"web-search"
|
|
9386
10010
|
);
|
|
10011
|
+
const details = buildWebSearchDetails(provider.id, outcomes);
|
|
9387
10012
|
return {
|
|
9388
10013
|
content: [{ type: "text", text: rendered }],
|
|
9389
|
-
details
|
|
10014
|
+
details,
|
|
10015
|
+
display: buildSearchToolDisplay2(details)
|
|
9390
10016
|
};
|
|
9391
10017
|
}
|
|
9392
10018
|
async function executeRawProviderRequest({
|
|
@@ -9461,16 +10087,22 @@ async function executeRawProviderRequest({
|
|
|
9461
10087
|
input
|
|
9462
10088
|
});
|
|
9463
10089
|
}
|
|
9464
|
-
function buildSearchBatchError(outcomes) {
|
|
10090
|
+
function buildSearchBatchError(outcomes, providerLabel) {
|
|
9465
10091
|
const failed = outcomes.filter((outcome) => outcome.error !== void 0);
|
|
9466
10092
|
if (failed.length === 1) {
|
|
9467
|
-
return new Error(
|
|
10093
|
+
return new Error(
|
|
10094
|
+
formatProviderCapabilityFailure(
|
|
10095
|
+
providerLabel,
|
|
10096
|
+
"search",
|
|
10097
|
+
failed[0]?.error ?? ""
|
|
10098
|
+
)
|
|
10099
|
+
);
|
|
9468
10100
|
}
|
|
9469
10101
|
const summary = failed.map(
|
|
9470
10102
|
(outcome, index) => `${index + 1}. ${formatQuotedPreview(outcome.query, 40)} \u2014 ${outcome.error}`
|
|
9471
10103
|
).join("; ");
|
|
9472
10104
|
return new Error(
|
|
9473
|
-
|
|
10105
|
+
`${providerLabel} search failed for ${failed.length} queries: ${summary}`
|
|
9474
10106
|
);
|
|
9475
10107
|
}
|
|
9476
10108
|
async function executeSingleSearchQuery({
|
|
@@ -9546,6 +10178,7 @@ async function executeAnswerToolInternal({
|
|
|
9546
10178
|
);
|
|
9547
10179
|
const batchProgress = answerQueries.length > 1 ? createBatchCompletionReporter(
|
|
9548
10180
|
"Answering",
|
|
10181
|
+
provider.id,
|
|
9549
10182
|
provider.label,
|
|
9550
10183
|
answerQueries.length,
|
|
9551
10184
|
progressReporter.report
|
|
@@ -9588,7 +10221,7 @@ async function executeAnswerToolInternal({
|
|
|
9588
10221
|
progressReporter.stop();
|
|
9589
10222
|
}
|
|
9590
10223
|
if (outcomes.every((outcome) => outcome.error !== void 0)) {
|
|
9591
|
-
throw buildAnswerBatchError(outcomes);
|
|
10224
|
+
throw buildAnswerBatchError(outcomes, provider.label);
|
|
9592
10225
|
}
|
|
9593
10226
|
const text = await truncateAndSave(
|
|
9594
10227
|
formatAnswerResponses(outcomes),
|
|
@@ -9597,19 +10230,31 @@ async function executeAnswerToolInternal({
|
|
|
9597
10230
|
const details = buildWebAnswerDetails(provider.id, outcomes);
|
|
9598
10231
|
return {
|
|
9599
10232
|
content: [{ type: "text", text }],
|
|
9600
|
-
details
|
|
10233
|
+
details,
|
|
10234
|
+
display: buildProviderToolDisplay2({
|
|
10235
|
+
capability: "answer",
|
|
10236
|
+
providerId: provider.id,
|
|
10237
|
+
details,
|
|
10238
|
+
text
|
|
10239
|
+
})
|
|
9601
10240
|
};
|
|
9602
10241
|
}
|
|
9603
|
-
function buildAnswerBatchError(outcomes) {
|
|
10242
|
+
function buildAnswerBatchError(outcomes, providerLabel) {
|
|
9604
10243
|
const failed = outcomes.filter((outcome) => outcome.error !== void 0);
|
|
9605
10244
|
if (failed.length === 1) {
|
|
9606
|
-
return new Error(
|
|
10245
|
+
return new Error(
|
|
10246
|
+
formatProviderCapabilityFailure(
|
|
10247
|
+
providerLabel,
|
|
10248
|
+
"answer",
|
|
10249
|
+
failed[0]?.error ?? ""
|
|
10250
|
+
)
|
|
10251
|
+
);
|
|
9607
10252
|
}
|
|
9608
10253
|
const summary = failed.map(
|
|
9609
10254
|
(outcome, index) => `${index + 1}. ${formatQuotedPreview(outcome.query, 40)} \u2014 ${outcome.error}`
|
|
9610
10255
|
).join("; ");
|
|
9611
10256
|
return new Error(
|
|
9612
|
-
|
|
10257
|
+
`${providerLabel} answer failed for ${failed.length} questions: ${summary}`
|
|
9613
10258
|
);
|
|
9614
10259
|
}
|
|
9615
10260
|
function formatAnswerResponses(outcomes) {
|
|
@@ -9671,13 +10316,24 @@ async function executeProviderOperation({
|
|
|
9671
10316
|
});
|
|
9672
10317
|
}
|
|
9673
10318
|
if (capability === "contents") {
|
|
10319
|
+
const urlCount = (urls ?? []).length;
|
|
9674
10320
|
onProgress?.(
|
|
9675
|
-
`Fetching contents via ${provider.label} for ${
|
|
10321
|
+
`Fetching contents via ${provider.label} for ${urlCount} URL(s)`,
|
|
10322
|
+
buildProgressDisplay2(
|
|
10323
|
+
provider.id,
|
|
10324
|
+
urlCount === 1 ? "Fetching page" : `Fetching ${urlCount} pages`
|
|
10325
|
+
)
|
|
9676
10326
|
);
|
|
9677
10327
|
} else if (capability === "answer") {
|
|
9678
|
-
onProgress?.(
|
|
10328
|
+
onProgress?.(
|
|
10329
|
+
`Answering via ${provider.label}`,
|
|
10330
|
+
buildProgressDisplay2(provider.id, "Answering")
|
|
10331
|
+
);
|
|
9679
10332
|
} else if (capability === "research") {
|
|
9680
|
-
onProgress?.(
|
|
10333
|
+
onProgress?.(
|
|
10334
|
+
`Researching via ${provider.label}`,
|
|
10335
|
+
buildProgressDisplay2(provider.id, "Researching")
|
|
10336
|
+
);
|
|
9681
10337
|
}
|
|
9682
10338
|
const result = executionOverride ? await executeProviderExecution(executionOverride, {
|
|
9683
10339
|
cwd: ctx.cwd,
|
|
@@ -9782,18 +10438,36 @@ async function executeProviderToolInternal({
|
|
|
9782
10438
|
} finally {
|
|
9783
10439
|
progressReporter.stop();
|
|
9784
10440
|
}
|
|
9785
|
-
const
|
|
9786
|
-
tool: `web_${capability}`,
|
|
9787
|
-
provider: response.provider,
|
|
9788
|
-
itemCount: isContentsResponse2(response) ? response.answers.length : response.itemCount
|
|
9789
|
-
};
|
|
9790
|
-
const text = await truncateAndSave(
|
|
10441
|
+
const rendered = await truncateAndSaveWithMetadata(
|
|
9791
10442
|
isContentsResponse2(response) ? formatContentsResponse(response) : response.text,
|
|
9792
10443
|
capability
|
|
9793
10444
|
);
|
|
10445
|
+
const details = isContentsResponse2(response) ? {
|
|
10446
|
+
tool: "web_contents",
|
|
10447
|
+
provider: response.provider,
|
|
10448
|
+
itemCount: response.answers.length
|
|
10449
|
+
} : capability === "answer" ? {
|
|
10450
|
+
tool: "web_answer",
|
|
10451
|
+
provider: response.provider,
|
|
10452
|
+
itemCount: response.itemCount,
|
|
10453
|
+
queryCount: 1,
|
|
10454
|
+
failedQueryCount: 0
|
|
10455
|
+
} : {
|
|
10456
|
+
tool: "web_research",
|
|
10457
|
+
provider: response.provider
|
|
10458
|
+
};
|
|
9794
10459
|
return {
|
|
9795
|
-
content: [{ type: "text", text }],
|
|
9796
|
-
details
|
|
10460
|
+
content: [{ type: "text", text: rendered.text }],
|
|
10461
|
+
details,
|
|
10462
|
+
display: buildProviderToolDisplay2({
|
|
10463
|
+
capability,
|
|
10464
|
+
providerId: response.provider,
|
|
10465
|
+
details,
|
|
10466
|
+
text: rendered.text,
|
|
10467
|
+
outputBytes: capability === "contents" ? rendered.totalBytes : void 0,
|
|
10468
|
+
outputTruncated: capability === "contents" ? rendered.truncated : void 0,
|
|
10469
|
+
failedItemCount: isContentsResponse2(response) ? response.answers.filter((answer) => answer.error !== void 0).length : void 0
|
|
10470
|
+
})
|
|
9797
10471
|
};
|
|
9798
10472
|
}
|
|
9799
10473
|
async function dispatchWebResearch({
|
|
@@ -9857,7 +10531,13 @@ async function dispatchWebResearchInternal({
|
|
|
9857
10531
|
text: `Started web research via ${provider.label}.`
|
|
9858
10532
|
}
|
|
9859
10533
|
],
|
|
9860
|
-
details: request
|
|
10534
|
+
details: request,
|
|
10535
|
+
display: buildProviderToolDisplay2({
|
|
10536
|
+
capability: "research",
|
|
10537
|
+
providerId: provider.id,
|
|
10538
|
+
details: { tool: "web_research", provider: provider.id },
|
|
10539
|
+
text: "started"
|
|
10540
|
+
})
|
|
9861
10541
|
};
|
|
9862
10542
|
}
|
|
9863
10543
|
async function runDispatchedWebResearch({
|
|
@@ -10089,6 +10769,7 @@ async function executeBatchedContentsTool({
|
|
|
10089
10769
|
}
|
|
10090
10770
|
const batchProgress = createBatchCompletionReporter(
|
|
10091
10771
|
"Fetching contents",
|
|
10772
|
+
provider.id,
|
|
10092
10773
|
provider.label,
|
|
10093
10774
|
urls.length,
|
|
10094
10775
|
progressReport
|
|
@@ -10140,7 +10821,11 @@ async function executeBatchedContentsTool({
|
|
|
10140
10821
|
);
|
|
10141
10822
|
if (successful.length === 0 && failures.length > 0) {
|
|
10142
10823
|
throw new Error(
|
|
10143
|
-
failures.length === 1 ?
|
|
10824
|
+
failures.length === 1 ? formatProviderCapabilityFailure(
|
|
10825
|
+
provider.label,
|
|
10826
|
+
"contents",
|
|
10827
|
+
failures[0]?.error ?? ""
|
|
10828
|
+
) : `${provider.label} fetch failed for ${failures.length} pages: ${failures.map(
|
|
10144
10829
|
(failure, index) => `${index + 1}. ${failure.url} \u2014 ${failure.error}`
|
|
10145
10830
|
).join("; ")}`
|
|
10146
10831
|
);
|
|
@@ -10205,10 +10890,11 @@ function createProgressEmitter(onUpdate) {
|
|
|
10205
10890
|
if (!onUpdate) {
|
|
10206
10891
|
return void 0;
|
|
10207
10892
|
}
|
|
10208
|
-
return (message) => {
|
|
10893
|
+
return (message, display) => {
|
|
10209
10894
|
onUpdate({
|
|
10210
10895
|
content: [{ type: "text", text: message }],
|
|
10211
|
-
details: {}
|
|
10896
|
+
details: {},
|
|
10897
|
+
display
|
|
10212
10898
|
});
|
|
10213
10899
|
};
|
|
10214
10900
|
}
|
|
@@ -10217,7 +10903,7 @@ function createToolProgressReporter(capability, providerId, progress) {
|
|
|
10217
10903
|
return { report: void 0, stop: () => {
|
|
10218
10904
|
} };
|
|
10219
10905
|
}
|
|
10220
|
-
const emit = (message) => progress(message);
|
|
10906
|
+
const emit = (message, display) => progress(message, display);
|
|
10221
10907
|
const startedAt = Date.now();
|
|
10222
10908
|
let lastUpdateAt = startedAt;
|
|
10223
10909
|
let timer;
|
|
@@ -10228,14 +10914,17 @@ function createToolProgressReporter(capability, providerId, progress) {
|
|
|
10228
10914
|
}
|
|
10229
10915
|
const providerLabel = PROVIDERS_BY_ID[providerId]?.label ?? providerId;
|
|
10230
10916
|
const elapsed = formatElapsed(Date.now() - startedAt);
|
|
10231
|
-
emit(
|
|
10917
|
+
emit(
|
|
10918
|
+
`Researching via ${providerLabel} (${elapsed} elapsed)`,
|
|
10919
|
+
buildProgressDisplay2(providerId, `Researching ${elapsed}`)
|
|
10920
|
+
);
|
|
10232
10921
|
lastUpdateAt = Date.now();
|
|
10233
10922
|
}, RESEARCH_HEARTBEAT_MS);
|
|
10234
10923
|
}
|
|
10235
10924
|
return {
|
|
10236
|
-
report: (message) => {
|
|
10925
|
+
report: (message, display) => {
|
|
10237
10926
|
lastUpdateAt = Date.now();
|
|
10238
|
-
emit(message);
|
|
10927
|
+
emit(message, display);
|
|
10239
10928
|
},
|
|
10240
10929
|
stop: () => {
|
|
10241
10930
|
if (timer) {
|
|
@@ -10306,77 +10995,125 @@ function renderQuestionCallHeader(params, theme) {
|
|
|
10306
10995
|
);
|
|
10307
10996
|
}
|
|
10308
10997
|
function renderResearchCallHeader(params, theme) {
|
|
10309
|
-
return renderListCallHeader(
|
|
10998
|
+
return renderListCallHeader(
|
|
10999
|
+
"web_research",
|
|
11000
|
+
[params.input],
|
|
11001
|
+
theme,
|
|
11002
|
+
void 0,
|
|
11003
|
+
{ quoteSingleItem: true }
|
|
11004
|
+
);
|
|
10310
11005
|
}
|
|
10311
|
-
function
|
|
11006
|
+
function renderWebToolResult(result, state, theme, config, symbols = DEFAULT_SUMMARY_SYMBOLS) {
|
|
10312
11007
|
const text = extractTextContent(result.content);
|
|
10313
|
-
|
|
10314
|
-
|
|
10315
|
-
return renderSimpleText(text ?? "Working\u2026", theme, "warning");
|
|
11008
|
+
if (state.isPartial) {
|
|
11009
|
+
return renderToolProgress(result.display, text, theme);
|
|
10316
11010
|
}
|
|
10317
|
-
if (isError) {
|
|
10318
|
-
return
|
|
11011
|
+
if (result.isError) {
|
|
11012
|
+
return renderFailureText(
|
|
11013
|
+
buildFailureSummary({
|
|
11014
|
+
text,
|
|
11015
|
+
details: result.details,
|
|
11016
|
+
capability: config.capability,
|
|
11017
|
+
fallback: config.failureText
|
|
11018
|
+
}),
|
|
11019
|
+
theme,
|
|
11020
|
+
symbols
|
|
11021
|
+
);
|
|
10319
11022
|
}
|
|
10320
|
-
const details = result.details;
|
|
10321
|
-
if (
|
|
10322
|
-
return
|
|
11023
|
+
const details = config.getDetails(result.details);
|
|
11024
|
+
if (state.expanded) {
|
|
11025
|
+
return config.renderExpanded(details, text);
|
|
10323
11026
|
}
|
|
10324
|
-
|
|
11027
|
+
const summary = config.preferDisplaySummary === false ? config.getCollapsedSummary(details, text) : getDisplaySummaryParts(result.display) ?? config.getCollapsedSummary(details, text);
|
|
11028
|
+
return renderCollapsedSummary(summary, theme, symbols);
|
|
10325
11029
|
}
|
|
10326
|
-
function
|
|
10327
|
-
|
|
10328
|
-
|
|
10329
|
-
|
|
10330
|
-
|
|
10331
|
-
|
|
10332
|
-
"",
|
|
10333
|
-
"
|
|
10334
|
-
|
|
10335
|
-
details
|
|
10336
|
-
""
|
|
10337
|
-
|
|
10338
|
-
|
|
10339
|
-
|
|
10340
|
-
].join("\n") : text;
|
|
10341
|
-
return renderMarkdownBlock(expandedText);
|
|
10342
|
-
}
|
|
10343
|
-
const summary = details ? `Started web research via ${PROVIDERS_BY_ID[details.provider]?.label ?? details.provider}` : text;
|
|
10344
|
-
let summaryText = theme.fg("success", summary);
|
|
10345
|
-
summaryText += theme.fg("muted", ` (${getExpandHint()})`);
|
|
10346
|
-
return new Text(summaryText, 0, 0);
|
|
11030
|
+
function renderSearchToolResult(result, expanded, isPartial, theme, symbols = DEFAULT_SUMMARY_SYMBOLS) {
|
|
11031
|
+
return renderWebToolResult(
|
|
11032
|
+
result,
|
|
11033
|
+
{ expanded, isPartial },
|
|
11034
|
+
theme,
|
|
11035
|
+
{
|
|
11036
|
+
capability: "search",
|
|
11037
|
+
failureText: "web_search failed",
|
|
11038
|
+
getDetails: (details) => details,
|
|
11039
|
+
getCollapsedSummary: (details, text) => details ? buildSearchSummaryParts2(details) : { success: getFirstLine2(text) ?? "web_search output available" },
|
|
11040
|
+
renderExpanded: (_details, text) => renderMarkdownBlock(text ?? "")
|
|
11041
|
+
},
|
|
11042
|
+
symbols
|
|
11043
|
+
);
|
|
10347
11044
|
}
|
|
10348
|
-
function
|
|
11045
|
+
function renderWebResearchDispatchResult(result, expanded, theme, symbols = DEFAULT_SUMMARY_SYMBOLS) {
|
|
11046
|
+
return renderWebToolResult(
|
|
11047
|
+
result,
|
|
11048
|
+
{ expanded },
|
|
11049
|
+
theme,
|
|
11050
|
+
{
|
|
11051
|
+
capability: "research",
|
|
11052
|
+
failureText: "web_research failed",
|
|
11053
|
+
getDetails: (details) => isWebResearchRequest(details) ? details : void 0,
|
|
11054
|
+
getCollapsedSummary: () => ({ success: "started" }),
|
|
11055
|
+
renderExpanded: (details, text) => renderMarkdownBlock(
|
|
11056
|
+
details ? renderWebResearchRequestMarkdown(details) : text ?? "Started web research."
|
|
11057
|
+
),
|
|
11058
|
+
preferDisplaySummary: false
|
|
11059
|
+
},
|
|
11060
|
+
symbols
|
|
11061
|
+
);
|
|
11062
|
+
}
|
|
11063
|
+
function renderWebResearchResultMessage(message, { expanded }, theme, symbols = DEFAULT_SUMMARY_SYMBOLS) {
|
|
10349
11064
|
const text = typeof message.content === "string" ? message.content : extractTextContent(message.content);
|
|
10350
11065
|
const details = isWebResearchResult(message.details) ? message.details : void 0;
|
|
10351
11066
|
const isSuccess = details?.status === "completed";
|
|
10352
11067
|
const accent = isSuccess ? "success" : "error";
|
|
10353
11068
|
const box = new Box(1, 1, (value) => theme.bg("customMessageBg", value));
|
|
10354
11069
|
if (!expanded) {
|
|
10355
|
-
const
|
|
10356
|
-
|
|
10357
|
-
|
|
11070
|
+
const summary = details ? buildWebResearchResultSummaryLine(details, theme, symbols) : theme.fg(accent, "Web research update");
|
|
11071
|
+
box.addChild(
|
|
11072
|
+
new Text(`${summary}${theme.fg("muted", ` (${getExpandHint()})`)}`, 0, 0)
|
|
11073
|
+
);
|
|
10358
11074
|
return box;
|
|
10359
11075
|
}
|
|
10360
11076
|
box.addChild(
|
|
10361
|
-
isSuccess ? renderMarkdownBlock(text ?? "") : renderBlockText(text ?? "", theme, "error")
|
|
11077
|
+
details ? renderMarkdownBlock(renderWebResearchResultMarkdown(details)) : isSuccess ? renderMarkdownBlock(text ?? "") : renderBlockText(text ?? "", theme, "error")
|
|
10362
11078
|
);
|
|
10363
11079
|
return box;
|
|
10364
11080
|
}
|
|
10365
|
-
function
|
|
11081
|
+
function renderWebResearchRequestMarkdown(request) {
|
|
11082
|
+
return [
|
|
11083
|
+
"### Web research",
|
|
11084
|
+
"",
|
|
11085
|
+
`**Brief:** ${request.input}`,
|
|
11086
|
+
"",
|
|
11087
|
+
"**Status:** running ",
|
|
11088
|
+
`**Elapsed:** ${formatSummaryElapsed(Date.now() - Date.parse(request.startedAt))} `,
|
|
11089
|
+
`**Artifact:** \`${request.outputPath}\``
|
|
11090
|
+
].join("\n");
|
|
11091
|
+
}
|
|
11092
|
+
function renderWebResearchResultMarkdown(result) {
|
|
11093
|
+
const status = result.status === "completed" ? "completed" : result.status;
|
|
11094
|
+
return [
|
|
11095
|
+
"### Web research",
|
|
11096
|
+
"",
|
|
11097
|
+
`**Brief:** ${result.input}`,
|
|
11098
|
+
"",
|
|
11099
|
+
`**Status:** ${status} `,
|
|
11100
|
+
`**Duration:** ${formatSummaryElapsed(result.elapsedMs)} `,
|
|
11101
|
+
`**Artifact:** \`${result.outputPath}\``,
|
|
11102
|
+
...result.error ? ["", `**Error:** ${result.error}`] : []
|
|
11103
|
+
].join("\n");
|
|
11104
|
+
}
|
|
11105
|
+
function buildWebResearchResultSummaryLine(result, theme, symbols) {
|
|
10366
11106
|
const providerLabel = PROVIDERS_BY_ID[result.provider]?.label ?? result.provider;
|
|
10367
|
-
|
|
10368
|
-
|
|
10369
|
-
|
|
10370
|
-
|
|
10371
|
-
|
|
10372
|
-
|
|
10373
|
-
theme.fg("muted", `\u25F4 duration: ${formatElapsed(result.elapsedMs)}`),
|
|
10374
|
-
theme.fg("muted", `\u21B3 file: ${result.outputPath}`)
|
|
10375
|
-
);
|
|
10376
|
-
if (result.error) {
|
|
10377
|
-
lines.push(theme.fg("muted", `\u2715 error: ${result.error}`));
|
|
11107
|
+
if (result.status === "completed") {
|
|
11108
|
+
return renderSuccessSummary(
|
|
11109
|
+
`${formatSummaryElapsed(result.elapsedMs)} \xB7 ${basename(result.outputPath)}`,
|
|
11110
|
+
theme,
|
|
11111
|
+
symbols
|
|
11112
|
+
);
|
|
10378
11113
|
}
|
|
10379
|
-
|
|
11114
|
+
const statusText = result.status === "cancelled" ? `${providerLabel} research canceled after ${formatSummaryElapsed(result.elapsedMs)}` : `${providerLabel} research failed after ${formatSummaryElapsed(result.elapsedMs)}`;
|
|
11115
|
+
const errorSuffix = result.error ? `: ${normalizeProviderFailureDetail(providerLabel, result.error)}` : "";
|
|
11116
|
+
return renderFailureSummary(`${statusText}${errorSuffix}`, theme, symbols);
|
|
10380
11117
|
}
|
|
10381
11118
|
function isWebResearchRequest(details) {
|
|
10382
11119
|
return typeof details === "object" && details !== null && "tool" in details && details.tool === "web_research" && "startedAt" in details && "outputPath" in details && !("status" in details);
|
|
@@ -10385,48 +11122,58 @@ function isWebResearchResult(details) {
|
|
|
10385
11122
|
return typeof details === "object" && details !== null && "tool" in details && details.tool === "web_research" && "status" in details && "completedAt" in details;
|
|
10386
11123
|
}
|
|
10387
11124
|
function renderProviderToolResult(result, expanded, isPartial, failureText, theme, options = {}) {
|
|
10388
|
-
|
|
10389
|
-
|
|
10390
|
-
|
|
10391
|
-
|
|
10392
|
-
|
|
10393
|
-
|
|
10394
|
-
|
|
10395
|
-
|
|
10396
|
-
|
|
10397
|
-
|
|
10398
|
-
|
|
10399
|
-
|
|
10400
|
-
|
|
10401
|
-
summaryText += theme.fg("muted", ` (${getExpandHint()})`);
|
|
10402
|
-
return new Text(summaryText, 0, 0);
|
|
11125
|
+
return renderWebToolResult(
|
|
11126
|
+
result,
|
|
11127
|
+
{ expanded, isPartial },
|
|
11128
|
+
theme,
|
|
11129
|
+
{
|
|
11130
|
+
capability: toolFromFailureText(failureText),
|
|
11131
|
+
failureText,
|
|
11132
|
+
getDetails: (details) => details,
|
|
11133
|
+
getCollapsedSummary: buildCollapsedProviderToolSummary2,
|
|
11134
|
+
renderExpanded: (_details, text) => options.markdownWhenExpanded ? renderMarkdownBlock(text ?? "") : renderBlockText(text ?? "", theme, "toolOutput")
|
|
11135
|
+
},
|
|
11136
|
+
options.symbols
|
|
11137
|
+
);
|
|
10403
11138
|
}
|
|
10404
11139
|
function renderCollapsedProviderToolSummary(details, text) {
|
|
10405
|
-
|
|
10406
|
-
const providerLabel = PROVIDERS_BY_ID[details.provider]?.label ?? details.provider;
|
|
10407
|
-
const failureSuffix = details.failedQueryCount && details.failedQueryCount > 0 ? `, ${details.failedQueryCount} failed` : "";
|
|
10408
|
-
return `${details.queryCount} questions via ${providerLabel}${failureSuffix}`;
|
|
10409
|
-
}
|
|
10410
|
-
const baseSummary = getCompactProviderToolSummary(details) ?? getFirstLine(text) ?? `${details?.tool ?? "tool"} output available`;
|
|
10411
|
-
if (!details?.provider) {
|
|
10412
|
-
return baseSummary;
|
|
10413
|
-
}
|
|
10414
|
-
return appendProviderSummary(baseSummary, details.provider);
|
|
11140
|
+
return buildCollapsedProviderToolSummary(details, text);
|
|
10415
11141
|
}
|
|
10416
|
-
function
|
|
10417
|
-
|
|
10418
|
-
|
|
10419
|
-
|
|
10420
|
-
|
|
10421
|
-
|
|
10422
|
-
|
|
10423
|
-
|
|
10424
|
-
|
|
10425
|
-
|
|
10426
|
-
|
|
10427
|
-
|
|
10428
|
-
|
|
10429
|
-
|
|
11142
|
+
function buildCollapsedProviderToolSummary2(details, text) {
|
|
11143
|
+
return buildCollapsedProviderToolSummaryParts(details, text);
|
|
11144
|
+
}
|
|
11145
|
+
function renderCollapsedSummary(summary, theme, symbols = DEFAULT_SUMMARY_SYMBOLS) {
|
|
11146
|
+
let rendered = renderSummary(summary, theme, symbols);
|
|
11147
|
+
rendered += theme.fg("muted", ` (${getExpandHint()})`);
|
|
11148
|
+
return new Text(rendered, 0, 0);
|
|
11149
|
+
}
|
|
11150
|
+
function getDisplaySummaryParts(display) {
|
|
11151
|
+
return display?.outcome;
|
|
11152
|
+
}
|
|
11153
|
+
function buildSearchToolDisplay2(details) {
|
|
11154
|
+
return buildSearchToolDisplay(details);
|
|
11155
|
+
}
|
|
11156
|
+
function buildProgressDisplay2(providerId, action) {
|
|
11157
|
+
return buildProgressDisplay(providerId, action);
|
|
11158
|
+
}
|
|
11159
|
+
function buildProviderToolDisplay2({
|
|
11160
|
+
capability,
|
|
11161
|
+
providerId,
|
|
11162
|
+
details,
|
|
11163
|
+
text,
|
|
11164
|
+
outputBytes,
|
|
11165
|
+
outputTruncated,
|
|
11166
|
+
failedItemCount
|
|
11167
|
+
}) {
|
|
11168
|
+
return buildProviderToolDisplay({
|
|
11169
|
+
capability,
|
|
11170
|
+
providerId,
|
|
11171
|
+
details,
|
|
11172
|
+
text,
|
|
11173
|
+
outputBytes,
|
|
11174
|
+
outputTruncated,
|
|
11175
|
+
failedItemCount
|
|
11176
|
+
});
|
|
10430
11177
|
}
|
|
10431
11178
|
function getProviderSettings(providerId) {
|
|
10432
11179
|
return getProviderConfigManifest(providerId).settings;
|
|
@@ -10486,12 +11233,19 @@ function resolveProviderSelectionValue(providerIds, value) {
|
|
|
10486
11233
|
);
|
|
10487
11234
|
}
|
|
10488
11235
|
function getReadyCompatibleProvidersForTool(config, cwd, toolId) {
|
|
11236
|
+
const mappedProviderId = getMappedProviderIdForTool(config, toolId);
|
|
10489
11237
|
return sortProviderIdsForSettings(
|
|
10490
|
-
getCompatibleProviders(toolId).filter(
|
|
10491
|
-
(providerId)
|
|
10492
|
-
|
|
10493
|
-
|
|
10494
|
-
|
|
11238
|
+
getCompatibleProviders(toolId).filter((providerId) => {
|
|
11239
|
+
const setupState = getProviderSetupState(config, providerId);
|
|
11240
|
+
if (setupState === "none" && providerId !== mappedProviderId) {
|
|
11241
|
+
return false;
|
|
11242
|
+
}
|
|
11243
|
+
return isProviderCapabilityExposable(
|
|
11244
|
+
getProviderCapabilityStatus(config, cwd, providerId, toolId, {
|
|
11245
|
+
resolveSecrets: false
|
|
11246
|
+
})
|
|
11247
|
+
);
|
|
11248
|
+
})
|
|
10495
11249
|
);
|
|
10496
11250
|
}
|
|
10497
11251
|
function sortProviderIdsForSettings(providerIds) {
|
|
@@ -10571,6 +11325,9 @@ function ensureSettings(config) {
|
|
|
10571
11325
|
return config.settings;
|
|
10572
11326
|
}
|
|
10573
11327
|
function cleanupSettings(config) {
|
|
11328
|
+
if (config.settings?.search && Object.keys(config.settings.search).length === 0) {
|
|
11329
|
+
delete config.settings.search;
|
|
11330
|
+
}
|
|
10574
11331
|
if (config.settings && Object.keys(config.settings).length === 0) {
|
|
10575
11332
|
delete config.settings;
|
|
10576
11333
|
}
|
|
@@ -10718,19 +11475,21 @@ var WebProvidersSettingsView = class {
|
|
|
10718
11475
|
id: `tool:${toolId}`,
|
|
10719
11476
|
label: TOOL_INFO[toolId].label,
|
|
10720
11477
|
currentValue,
|
|
10721
|
-
description: `Press Enter to configure web_${toolId}. ${TOOL_INFO[toolId].help} Route web_${toolId} to one compatible provider or turn it off.` + (compatibleLabels.length > 0 ? `
|
|
11478
|
+
description: `Press Enter to configure web_${toolId}. ${TOOL_INFO[toolId].help} Route web_${toolId} to one compatible provider or turn it off.` + (compatibleLabels.length > 0 ? ` Compatible providers: ${compatibleLabels.join(", ")}.` : ""),
|
|
10722
11479
|
kind: "action"
|
|
10723
11480
|
};
|
|
10724
11481
|
});
|
|
10725
11482
|
}
|
|
10726
11483
|
buildSettingsSectionItems() {
|
|
10727
|
-
return
|
|
10728
|
-
id
|
|
10729
|
-
|
|
10730
|
-
|
|
10731
|
-
|
|
10732
|
-
|
|
10733
|
-
|
|
11484
|
+
return [
|
|
11485
|
+
...SETTING_IDS.map((id) => ({
|
|
11486
|
+
id: `settings:${id}`,
|
|
11487
|
+
label: SETTING_META[id].label,
|
|
11488
|
+
currentValue: getSharedSettingDisplayValue(this.config, id),
|
|
11489
|
+
description: SETTING_META[id].help,
|
|
11490
|
+
kind: "text"
|
|
11491
|
+
}))
|
|
11492
|
+
];
|
|
10734
11493
|
}
|
|
10735
11494
|
getSectionEntries(section) {
|
|
10736
11495
|
if (section === "provider") return this.buildProviderSectionItems();
|
|
@@ -11040,7 +11799,7 @@ var ToolSettingsSubmenu = class {
|
|
|
11040
11799
|
id: "provider",
|
|
11041
11800
|
label: "Provider",
|
|
11042
11801
|
currentValue: currentProviderValue,
|
|
11043
|
-
description: `Route web_${this.toolId} to one compatible
|
|
11802
|
+
description: `Route web_${this.toolId} to one compatible provider or turn it off.`,
|
|
11044
11803
|
kind: "cycle",
|
|
11045
11804
|
values: providerValues
|
|
11046
11805
|
}
|
|
@@ -11452,17 +12211,24 @@ function formatProviderSetupState(state) {
|
|
|
11452
12211
|
function getProviderReadinessSummary(config, cwd, providerId) {
|
|
11453
12212
|
const tools = getProviderTools(providerId);
|
|
11454
12213
|
const statuses = tools.map(
|
|
11455
|
-
(tool) => getProviderCapabilityStatus(config, cwd, providerId, tool
|
|
12214
|
+
(tool) => getProviderCapabilityStatus(config, cwd, providerId, tool, {
|
|
12215
|
+
resolveSecrets: false
|
|
12216
|
+
})
|
|
11456
12217
|
);
|
|
11457
12218
|
if (statuses.some((status) => status.state === "ready")) {
|
|
11458
12219
|
return "Ready";
|
|
11459
12220
|
}
|
|
12221
|
+
if (statuses.some((status) => status.state === "deferred_secret")) {
|
|
12222
|
+
return "Secrets resolved on first use";
|
|
12223
|
+
}
|
|
11460
12224
|
return formatProviderCapabilityStatus(statuses[0], providerId, tools[0]);
|
|
11461
12225
|
}
|
|
11462
12226
|
function getProviderReadinessSummaryForProviderConfig(providerId, providerConfig) {
|
|
11463
12227
|
const status = PROVIDERS_BY_ID[providerId].getCapabilityStatus(
|
|
11464
12228
|
providerConfig ?? PROVIDERS_BY_ID[providerId].config.createTemplate(),
|
|
11465
|
-
""
|
|
12229
|
+
"",
|
|
12230
|
+
void 0,
|
|
12231
|
+
{ resolveSecrets: false }
|
|
11466
12232
|
);
|
|
11467
12233
|
return formatProviderCapabilityStatus(status, providerId);
|
|
11468
12234
|
}
|
|
@@ -11511,7 +12277,7 @@ function getSearchQueriesForDisplay(queries) {
|
|
|
11511
12277
|
function getAnswerQueriesForDisplay(queries) {
|
|
11512
12278
|
return getSearchQueriesForDisplay(queries);
|
|
11513
12279
|
}
|
|
11514
|
-
function createBatchCompletionReporter(verb, providerLabel, total, report) {
|
|
12280
|
+
function createBatchCompletionReporter(verb, providerId, providerLabel, total, report) {
|
|
11515
12281
|
if (!report) {
|
|
11516
12282
|
return {
|
|
11517
12283
|
start: () => {
|
|
@@ -11529,7 +12295,8 @@ function createBatchCompletionReporter(verb, providerLabel, total, report) {
|
|
|
11529
12295
|
if (failedCount > 0) {
|
|
11530
12296
|
message += `, ${failedCount} failed`;
|
|
11531
12297
|
}
|
|
11532
|
-
|
|
12298
|
+
const action = verb === "Fetching contents" ? `Fetching ${completedCount}/${total} pages` : `${verb} ${completedCount}/${total}`;
|
|
12299
|
+
report(message, buildProgressDisplay2(providerId, action));
|
|
11533
12300
|
};
|
|
11534
12301
|
return {
|
|
11535
12302
|
start: emit,
|
|
@@ -11590,34 +12357,52 @@ ${rendered}`, 0, 0);
|
|
|
11590
12357
|
function renderSimpleText(text, theme, color) {
|
|
11591
12358
|
return new Text(theme.fg(color, text), 0, 0);
|
|
11592
12359
|
}
|
|
11593
|
-
function
|
|
12360
|
+
function renderSummary(summary, theme, symbols) {
|
|
12361
|
+
let rendered = renderSuccessSummary(summary.success, theme, symbols);
|
|
12362
|
+
if (summary.failure) {
|
|
12363
|
+
rendered += `, ${renderFailureSummary(summary.failure, theme, symbols)}`;
|
|
12364
|
+
}
|
|
12365
|
+
return rendered;
|
|
12366
|
+
}
|
|
12367
|
+
function renderSuccessSummary(text, theme, symbols) {
|
|
12368
|
+
return theme.fg("success", prefixWithSymbol(text, symbols.success));
|
|
12369
|
+
}
|
|
12370
|
+
function renderFailureSummary(text, theme, symbols) {
|
|
12371
|
+
return theme.fg("error", prefixWithSymbol(text, symbols.failure));
|
|
12372
|
+
}
|
|
12373
|
+
function renderFailureText(text, theme, symbols) {
|
|
12374
|
+
return new Text(renderFailureSummary(text, theme, symbols), 0, 0);
|
|
12375
|
+
}
|
|
12376
|
+
function prefixWithSymbol(text, symbol) {
|
|
12377
|
+
return symbol ? `${symbol} ${text}` : text;
|
|
12378
|
+
}
|
|
12379
|
+
function renderToolProgress(display, fallbackText, theme) {
|
|
12380
|
+
const progress = display?.progress;
|
|
12381
|
+
const providerLabel = display?.provider?.label;
|
|
12382
|
+
if (!progress || !providerLabel) {
|
|
12383
|
+
return renderSimpleText(fallbackText ?? "Working\u2026", theme, "warning");
|
|
12384
|
+
}
|
|
12385
|
+
return new Text(
|
|
12386
|
+
`${theme.fg("warning", progress.action)} ${theme.fg("muted", `via ${providerLabel}`)}`,
|
|
12387
|
+
0,
|
|
12388
|
+
0
|
|
12389
|
+
);
|
|
12390
|
+
}
|
|
12391
|
+
function renderCollapsedSearchSummary(details, text, theme, symbols = DEFAULT_SUMMARY_SYMBOLS) {
|
|
11594
12392
|
const queryCount = typeof details?.queryCount === "number" ? details.queryCount : inferSearchQueryCount(text);
|
|
11595
12393
|
const resultCount = typeof details?.resultCount === "number" ? details.resultCount : inferSearchResultCount(text);
|
|
11596
12394
|
const failedQueryCount = typeof details?.failedQueryCount === "number" ? details.failedQueryCount : inferSearchFailureCount(text);
|
|
11597
|
-
const
|
|
11598
|
-
let base2 = buildSearchSummaryText({
|
|
12395
|
+
const summary = buildSearchSummaryParts2({
|
|
11599
12396
|
queryCount,
|
|
11600
|
-
resultCount
|
|
12397
|
+
resultCount,
|
|
12398
|
+
failedQueryCount
|
|
11601
12399
|
});
|
|
11602
|
-
|
|
11603
|
-
|
|
11604
|
-
|
|
11605
|
-
if (failedQueryCount && failedQueryCount > 0) {
|
|
11606
|
-
base2 += `, ${failedQueryCount} failed`;
|
|
11607
|
-
}
|
|
11608
|
-
let summary = theme.fg("success", base2);
|
|
11609
|
-
summary += theme.fg("muted", ` (${getExpandHint()})`);
|
|
11610
|
-
return new Text(summary, 0, 0);
|
|
12400
|
+
let rendered = renderSummary(summary, theme, symbols);
|
|
12401
|
+
rendered += theme.fg("muted", ` (${getExpandHint()})`);
|
|
12402
|
+
return new Text(rendered, 0, 0);
|
|
11611
12403
|
}
|
|
11612
|
-
function
|
|
11613
|
-
|
|
11614
|
-
resultCount
|
|
11615
|
-
}) {
|
|
11616
|
-
const countSummary = typeof resultCount === "number" ? `${resultCount} result${resultCount === 1 ? "" : "s"}` : "Search output available";
|
|
11617
|
-
if (queryCount && queryCount > 1) {
|
|
11618
|
-
return `${queryCount} queries, ${countSummary}`;
|
|
11619
|
-
}
|
|
11620
|
-
return countSummary;
|
|
12404
|
+
function buildSearchSummaryParts2(options) {
|
|
12405
|
+
return buildSearchSummaryParts(options);
|
|
11621
12406
|
}
|
|
11622
12407
|
function inferSearchQueryCount(text) {
|
|
11623
12408
|
if (!text) {
|
|
@@ -11643,12 +12428,77 @@ function inferSearchFailureCount(text) {
|
|
|
11643
12428
|
const failureMatches = text.match(/^Search failed:/gm);
|
|
11644
12429
|
return failureMatches?.length;
|
|
11645
12430
|
}
|
|
11646
|
-
function
|
|
11647
|
-
|
|
11648
|
-
|
|
11649
|
-
|
|
12431
|
+
function buildFailureSummary({
|
|
12432
|
+
text,
|
|
12433
|
+
details,
|
|
12434
|
+
capability,
|
|
12435
|
+
fallback
|
|
12436
|
+
}) {
|
|
12437
|
+
const detail = stripTrailingSentencePunctuation(getFirstLine2(text) ?? "");
|
|
12438
|
+
const providerLabel = details?.provider !== void 0 ? PROVIDERS_BY_ID[details.provider]?.label ?? details.provider : void 0;
|
|
12439
|
+
if (!providerLabel) {
|
|
12440
|
+
return detail || fallback;
|
|
12441
|
+
}
|
|
12442
|
+
return formatProviderCapabilityFailure(providerLabel, capability, detail);
|
|
11650
12443
|
}
|
|
11651
|
-
function
|
|
12444
|
+
function formatProviderCapabilityFailure(providerLabel, capability, detail) {
|
|
12445
|
+
const action = getFailureAction(capability);
|
|
12446
|
+
const base2 = `${providerLabel} ${action} failed`;
|
|
12447
|
+
if (!detail || detail === base2) {
|
|
12448
|
+
return base2;
|
|
12449
|
+
}
|
|
12450
|
+
if (detail.toLowerCase().startsWith(base2.toLowerCase())) {
|
|
12451
|
+
return detail;
|
|
12452
|
+
}
|
|
12453
|
+
const normalizedDetail = normalizeProviderFailureDetail(
|
|
12454
|
+
providerLabel,
|
|
12455
|
+
detail
|
|
12456
|
+
);
|
|
12457
|
+
return `${base2}: ${normalizedDetail}`;
|
|
12458
|
+
}
|
|
12459
|
+
function normalizeProviderFailureDetail(providerLabel, detail) {
|
|
12460
|
+
const normalized = stripTrailingSentencePunctuation(detail);
|
|
12461
|
+
const providerPrefix = `${providerLabel}:`;
|
|
12462
|
+
return normalized.toLowerCase().startsWith(providerPrefix.toLowerCase()) ? normalized.slice(providerPrefix.length).trim() : normalized;
|
|
12463
|
+
}
|
|
12464
|
+
function getFailureAction(capability) {
|
|
12465
|
+
switch (capability) {
|
|
12466
|
+
case "contents":
|
|
12467
|
+
return "fetch";
|
|
12468
|
+
case "search":
|
|
12469
|
+
case "answer":
|
|
12470
|
+
case "research":
|
|
12471
|
+
return capability;
|
|
12472
|
+
}
|
|
12473
|
+
}
|
|
12474
|
+
function toolFromFailureText(text) {
|
|
12475
|
+
if (text.startsWith("web_contents")) {
|
|
12476
|
+
return "contents";
|
|
12477
|
+
}
|
|
12478
|
+
if (text.startsWith("web_answer")) {
|
|
12479
|
+
return "answer";
|
|
12480
|
+
}
|
|
12481
|
+
if (text.startsWith("web_research")) {
|
|
12482
|
+
return "research";
|
|
12483
|
+
}
|
|
12484
|
+
return "search";
|
|
12485
|
+
}
|
|
12486
|
+
function stripTrailingSentencePunctuation(text) {
|
|
12487
|
+
return text.trim().replace(/[.\s]+$/u, "");
|
|
12488
|
+
}
|
|
12489
|
+
function formatSummaryElapsed(ms) {
|
|
12490
|
+
const totalSeconds = Math.max(0, Math.floor(ms / 1e3));
|
|
12491
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
12492
|
+
const seconds = totalSeconds % 60;
|
|
12493
|
+
if (minutes > 0 && seconds === 0) {
|
|
12494
|
+
return `${minutes}m`;
|
|
12495
|
+
}
|
|
12496
|
+
if (minutes > 0) {
|
|
12497
|
+
return `${minutes}m ${seconds}s`;
|
|
12498
|
+
}
|
|
12499
|
+
return `${seconds}s`;
|
|
12500
|
+
}
|
|
12501
|
+
function getFirstLine2(text) {
|
|
11652
12502
|
if (!text) {
|
|
11653
12503
|
return void 0;
|
|
11654
12504
|
}
|
|
@@ -11729,18 +12579,32 @@ function escapeMarkdownText(text) {
|
|
|
11729
12579
|
return text.replaceAll("\\", "\\\\").replaceAll("*", "\\*").replaceAll("_", "\\_").replaceAll("`", "\\`").replaceAll("#", "\\#").replaceAll("[", "\\[").replaceAll("]", "\\]");
|
|
11730
12580
|
}
|
|
11731
12581
|
async function truncateAndSave(text, prefix) {
|
|
12582
|
+
return (await truncateAndSaveWithMetadata(text, prefix)).text;
|
|
12583
|
+
}
|
|
12584
|
+
async function truncateAndSaveWithMetadata(text, prefix) {
|
|
12585
|
+
const totalBytes = Buffer.byteLength(text, "utf-8");
|
|
11732
12586
|
const truncation = truncateHead(text, {
|
|
11733
12587
|
maxLines: DEFAULT_MAX_LINES,
|
|
11734
12588
|
maxBytes: DEFAULT_MAX_BYTES
|
|
11735
12589
|
});
|
|
11736
|
-
if (!truncation.truncated)
|
|
12590
|
+
if (!truncation.truncated) {
|
|
12591
|
+
return {
|
|
12592
|
+
text: truncation.content,
|
|
12593
|
+
totalBytes,
|
|
12594
|
+
truncated: false
|
|
12595
|
+
};
|
|
12596
|
+
}
|
|
11737
12597
|
const dir = join2(tmpdir(), `pi-web-providers-${prefix}-${Date.now()}`);
|
|
11738
12598
|
await mkdir2(dir, { recursive: true });
|
|
11739
12599
|
const fullPath = join2(dir, "output.txt");
|
|
11740
12600
|
await writeFile2(fullPath, text, "utf-8");
|
|
11741
|
-
return
|
|
12601
|
+
return {
|
|
12602
|
+
text: truncation.content + `
|
|
11742
12603
|
|
|
11743
|
-
[Output truncated: ${truncation.outputLines} of ${truncation.totalLines} lines (${
|
|
12604
|
+
[Output truncated: ${truncation.outputLines} of ${truncation.totalLines} lines (${formatSize2(truncation.outputBytes)} of ${formatSize2(truncation.totalBytes)}). Full output saved to: ${fullPath}]`,
|
|
12605
|
+
totalBytes,
|
|
12606
|
+
truncated: true
|
|
12607
|
+
};
|
|
11744
12608
|
}
|
|
11745
12609
|
function truncateInline(text, maxLength) {
|
|
11746
12610
|
if (text.length <= maxLength) return text;
|