@cydm/pie 1.0.29 → 1.0.31
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 +4 -5
- package/dist/builtin/extensions/ask-user/index.js +1 -1
- package/dist/builtin/extensions/changelog/index.js +65 -65
- package/dist/builtin/extensions/init/index.js +61 -54
- package/dist/builtin/extensions/plan-mode/index.js +1 -1
- package/dist/builtin/extensions/subagent/index.js +2 -2
- package/dist/builtin/extensions/todo/index.js +1 -1
- package/dist/chunks/{chunk-L63BJMTT.js → chunk-BOFCKEV5.js} +478 -34
- package/dist/chunks/{chunk-BDDSZSHX.js → chunk-PLJQYVFC.js} +45 -16
- package/dist/chunks/{test-stream-ZNGAUUVH.js → test-stream-A7JSM2UM.js} +39 -5
- package/dist/cli.js +251 -146
- package/package.json +2 -2
|
@@ -3968,11 +3968,12 @@ var AgentSessionQueue = class {
|
|
|
3968
3968
|
clearEditor: options.clearEditor ?? true,
|
|
3969
3969
|
visibility: options.visibility ?? "user",
|
|
3970
3970
|
deliveredToAgent: false,
|
|
3971
|
+
deliverWhileStreaming: options.deliverWhileStreaming ?? true,
|
|
3971
3972
|
messages: [message],
|
|
3972
3973
|
createdAt: Date.now()
|
|
3973
3974
|
};
|
|
3974
3975
|
this.queuedInputs.push(queuedInput);
|
|
3975
|
-
if (this.getIsStreaming()) {
|
|
3976
|
+
if (this.getIsStreaming() && queuedInput.deliverWhileStreaming) {
|
|
3976
3977
|
this.deliverToAgent(queuedInput);
|
|
3977
3978
|
}
|
|
3978
3979
|
}
|
|
@@ -4004,11 +4005,12 @@ var AgentSessionQueue = class {
|
|
|
4004
4005
|
this.emitQueueChanged();
|
|
4005
4006
|
return;
|
|
4006
4007
|
}
|
|
4007
|
-
const delivered = this.queuedInputs
|
|
4008
|
-
if (delivered) {
|
|
4008
|
+
const delivered = this.queuedInputs[0];
|
|
4009
|
+
if (delivered?.deliveredToAgent) {
|
|
4010
|
+
this.queuedInputs.shift();
|
|
4009
4011
|
this.emit({ type: "queued_turn_dispatched", queuedInput: cloneQueuedInput(delivered) });
|
|
4012
|
+
this.emitQueueChanged();
|
|
4010
4013
|
}
|
|
4011
|
-
this.emitQueueChanged();
|
|
4012
4014
|
}
|
|
4013
4015
|
clear() {
|
|
4014
4016
|
if (this.queuedInputs.length === 0 && !this.agent.hasQueuedMessages()) {
|
|
@@ -4170,6 +4172,9 @@ var AgentSessionQueueDispatcher = class {
|
|
|
4170
4172
|
});
|
|
4171
4173
|
}
|
|
4172
4174
|
resolvePending() {
|
|
4175
|
+
if (this.dispatchTimer !== void 0) {
|
|
4176
|
+
return;
|
|
4177
|
+
}
|
|
4173
4178
|
const resolve3 = this.resolvePendingDispatch;
|
|
4174
4179
|
this.pendingDispatch = void 0;
|
|
4175
4180
|
this.resolvePendingDispatch = void 0;
|
|
@@ -5662,7 +5667,7 @@ function createAskUserCapability() {
|
|
|
5662
5667
|
{
|
|
5663
5668
|
name: "ask_user_multi",
|
|
5664
5669
|
label: "Ask User",
|
|
5665
|
-
description:
|
|
5670
|
+
description: 'Ask the user one or more structured questions with review/back navigation. Invoke it directly when you need user input; do not print example JSON first. For a simple demo, ask one single-choice question with 3-5 options. Prefer the shortest shape: {"question":"Choose a color","options":["Red","Blue","Green"]}. For multiple questions, use `questions`; ids are optional.',
|
|
5666
5671
|
parameters: AskUserMultiParamsSchema,
|
|
5667
5672
|
async execute(toolCallIdOrArgs, maybeArgs) {
|
|
5668
5673
|
try {
|
|
@@ -5805,9 +5810,7 @@ function createAskUserCapability() {
|
|
|
5805
5810
|
requiredInteractions: ["select_one", "confirm", "text_input", "multiline_input"],
|
|
5806
5811
|
systemPromptAdditions: [
|
|
5807
5812
|
"When the user asks you to ask questions, collect choices, or gather structured input, call `ask_user_multi` instead of describing the questions in plain text.",
|
|
5808
|
-
"When demonstrating `ask_user_multi`, call it immediately
|
|
5809
|
-
"When the user asks for a generic ask-tool demo, such as '\u6F14\u793A\u4E00\u4E0B ask \u5DE5\u5177', '\u6F14\u793A\u4E00\u4E0B\u63D0\u95EE\u5DE5\u5177', or 'ask me', ask exactly one simple single-choice question with explicit options so the interaction opens as a selector.",
|
|
5810
|
-
"For a single question, prefer the shortest valid argument shape such as `question` plus optional `options`."
|
|
5813
|
+
"When demonstrating `ask_user_multi`, call it immediately. For a generic demo, ask one simple single-choice question with explicit options."
|
|
5811
5814
|
]
|
|
5812
5815
|
}),
|
|
5813
5816
|
tools
|
|
@@ -6305,6 +6308,13 @@ var BINARY_MAGIC_PREFIX_BYTES = 8 * 1024;
|
|
|
6305
6308
|
var MAX_INLINE_IMAGE_BYTES = 20 * 1024 * 1024;
|
|
6306
6309
|
var MAX_CROSS_HOST_LINE_NUMBER = 2147483647;
|
|
6307
6310
|
var INLINE_IMAGE_MIME_TYPES = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/gif", "image/webp"]);
|
|
6311
|
+
function createReadErrorResult(message, details) {
|
|
6312
|
+
return {
|
|
6313
|
+
content: [{ type: "text", text: `read_file failed: ${message}` }],
|
|
6314
|
+
details,
|
|
6315
|
+
isError: true
|
|
6316
|
+
};
|
|
6317
|
+
}
|
|
6308
6318
|
function createReadTool(cwd, options) {
|
|
6309
6319
|
const fs2 = getFileSystem();
|
|
6310
6320
|
const fileObservationState = options?.fileObservationState ?? createFileObservationState();
|
|
@@ -6325,13 +6335,13 @@ function createReadTool(cwd, options) {
|
|
|
6325
6335
|
execute: async (_toolCallId, params, signal) => {
|
|
6326
6336
|
const { path: path4, root, offset, limit, question } = params;
|
|
6327
6337
|
if (offset !== void 0 && (!Number.isSafeInteger(offset) || offset < 1 || offset > MAX_CROSS_HOST_LINE_NUMBER)) {
|
|
6328
|
-
|
|
6338
|
+
return createReadErrorResult(`Invalid arguments: offset must be a positive safe integer no greater than ${MAX_CROSS_HOST_LINE_NUMBER}.`);
|
|
6329
6339
|
}
|
|
6330
6340
|
if (limit !== void 0 && (!Number.isSafeInteger(limit) || limit < 1 || limit > MAX_CROSS_HOST_LINE_NUMBER)) {
|
|
6331
|
-
|
|
6341
|
+
return createReadErrorResult(`Invalid arguments: limit must be a positive safe integer no greater than ${MAX_CROSS_HOST_LINE_NUMBER}.`);
|
|
6332
6342
|
}
|
|
6333
6343
|
if (offset !== void 0 && limit !== void 0 && offset - 1 + limit > MAX_CROSS_HOST_LINE_NUMBER) {
|
|
6334
|
-
|
|
6344
|
+
return createReadErrorResult(`Invalid arguments: offset and limit exceed the ${MAX_CROSS_HOST_LINE_NUMBER}-line cross-host range.`);
|
|
6335
6345
|
}
|
|
6336
6346
|
let absolutePath;
|
|
6337
6347
|
try {
|
|
@@ -6339,11 +6349,11 @@ function createReadTool(cwd, options) {
|
|
|
6339
6349
|
} catch (error) {
|
|
6340
6350
|
const message = error instanceof Error ? error.message : String(error);
|
|
6341
6351
|
if (/outside sandbox|outside root|escapes sandbox/i.test(message)) {
|
|
6342
|
-
|
|
6352
|
+
return createReadErrorResult(
|
|
6343
6353
|
`${message}. read_file is workspace-scoped; for intentional runtime logs or temporary files outside the workspace, use bash with a bounded command such as head, tail, sed -n, or cat on that path.`
|
|
6344
6354
|
);
|
|
6345
6355
|
}
|
|
6346
|
-
|
|
6356
|
+
return createReadErrorResult(message);
|
|
6347
6357
|
}
|
|
6348
6358
|
return new Promise(
|
|
6349
6359
|
(resolve3, reject) => {
|
|
@@ -6474,6 +6484,24 @@ function createReadTool(cwd, options) {
|
|
|
6474
6484
|
});
|
|
6475
6485
|
return;
|
|
6476
6486
|
}
|
|
6487
|
+
const textBinaryInfo = detectTextOnlyBinary(prefix, absolutePath, stat.size > prefix.length);
|
|
6488
|
+
if (textBinaryInfo) {
|
|
6489
|
+
resolve3({
|
|
6490
|
+
content: [{
|
|
6491
|
+
type: "text",
|
|
6492
|
+
text: `Cannot read binary file ${path4}: ${textBinaryInfo.mimeType}. Use a file-understanding handler for supported media/documents, or inspect metadata with a bounded shell command.`
|
|
6493
|
+
}],
|
|
6494
|
+
details: {
|
|
6495
|
+
understanding: {
|
|
6496
|
+
kind: textBinaryInfo.kind,
|
|
6497
|
+
mimeType: textBinaryInfo.mimeType,
|
|
6498
|
+
fallbackReason: "binary content is not safe to display as text"
|
|
6499
|
+
}
|
|
6500
|
+
},
|
|
6501
|
+
isError: true
|
|
6502
|
+
});
|
|
6503
|
+
return;
|
|
6504
|
+
}
|
|
6477
6505
|
const startLine = offset === void 0 ? 0 : offset - 1;
|
|
6478
6506
|
const startLineDisplay = startLine + 1;
|
|
6479
6507
|
const range2 = await fs2.readTextRange(absolutePath, {
|
|
@@ -6595,7 +6623,12 @@ Base directory: ${nodePath.dirname(absolutePath)}
|
|
|
6595
6623
|
});
|
|
6596
6624
|
} catch (error) {
|
|
6597
6625
|
if (!aborted) {
|
|
6598
|
-
|
|
6626
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6627
|
+
if (/aborted/i.test(message)) {
|
|
6628
|
+
reject(error);
|
|
6629
|
+
return;
|
|
6630
|
+
}
|
|
6631
|
+
resolve3(createReadErrorResult(message, { path: absolutePath }));
|
|
6599
6632
|
}
|
|
6600
6633
|
} finally {
|
|
6601
6634
|
signal?.removeEventListener("abort", onAbort);
|
|
@@ -6725,7 +6758,10 @@ function looksLikeBinaryText(input) {
|
|
|
6725
6758
|
return characters > 0 && suspiciousControls / characters > 0.02;
|
|
6726
6759
|
}
|
|
6727
6760
|
function detectTextOnlyBinary(input, filePath, prefixMayBeTruncated) {
|
|
6728
|
-
|
|
6761
|
+
const magicInfo = detectBinaryMagic(input);
|
|
6762
|
+
if (magicInfo) return magicInfo;
|
|
6763
|
+
if (!looksLikeBinary(input, prefixMayBeTruncated)) return void 0;
|
|
6764
|
+
return detectBinaryKind(filePath) ?? { kind: "document", mimeType: "application/octet-stream" };
|
|
6729
6765
|
}
|
|
6730
6766
|
async function readImageInfo(path4, fs2) {
|
|
6731
6767
|
if (typeof Buffer === "undefined") {
|
|
@@ -7176,6 +7212,25 @@ function createEditErrorResult(params) {
|
|
|
7176
7212
|
isError: true
|
|
7177
7213
|
};
|
|
7178
7214
|
}
|
|
7215
|
+
function createEditThrownErrorResult(message, path4) {
|
|
7216
|
+
return {
|
|
7217
|
+
content: [{ type: "text", text: `edit_file failed: ${message}` }],
|
|
7218
|
+
details: {
|
|
7219
|
+
status: "error",
|
|
7220
|
+
matchKind: "none",
|
|
7221
|
+
changed: false,
|
|
7222
|
+
path: path4,
|
|
7223
|
+
diff: "",
|
|
7224
|
+
oldTextOccurrences: 0,
|
|
7225
|
+
newTextOccurrences: 0,
|
|
7226
|
+
replaceAll: false,
|
|
7227
|
+
replacedOccurrences: 0,
|
|
7228
|
+
errorReason: "old_text_not_found",
|
|
7229
|
+
recoveryHint: "Check the path and read the current file before retrying."
|
|
7230
|
+
},
|
|
7231
|
+
isError: true
|
|
7232
|
+
};
|
|
7233
|
+
}
|
|
7179
7234
|
function createEditTool(cwd, options) {
|
|
7180
7235
|
const fs2 = getFileSystem();
|
|
7181
7236
|
const fileObservationState = options?.fileObservationState ?? createFileObservationState();
|
|
@@ -7201,8 +7256,15 @@ function createEditTool(cwd, options) {
|
|
|
7201
7256
|
parameters: editSchema,
|
|
7202
7257
|
execute: async (_toolCallId, params, signal) => {
|
|
7203
7258
|
const { path: path4, root } = params;
|
|
7204
|
-
|
|
7205
|
-
|
|
7259
|
+
let replacements;
|
|
7260
|
+
let absolutePath;
|
|
7261
|
+
try {
|
|
7262
|
+
replacements = validateEditArgs(params);
|
|
7263
|
+
absolutePath = resolveToCwd(path4, cwd, options, root);
|
|
7264
|
+
} catch (error) {
|
|
7265
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7266
|
+
return createEditThrownErrorResult(message, typeof path4 === "string" ? path4 : void 0);
|
|
7267
|
+
}
|
|
7206
7268
|
return new Promise((resolve3, reject) => {
|
|
7207
7269
|
if (signal?.aborted) {
|
|
7208
7270
|
reject(new Error("Operation aborted"));
|
|
@@ -7225,7 +7287,7 @@ function createEditTool(cwd, options) {
|
|
|
7225
7287
|
await fs2.access(absolutePath);
|
|
7226
7288
|
} catch {
|
|
7227
7289
|
if (signal) signal.removeEventListener("abort", onAbort);
|
|
7228
|
-
|
|
7290
|
+
resolve3(createEditThrownErrorResult(`File not found: ${path4}`, path4));
|
|
7229
7291
|
return;
|
|
7230
7292
|
}
|
|
7231
7293
|
throwIfAborted();
|
|
@@ -7377,7 +7439,12 @@ function createEditTool(cwd, options) {
|
|
|
7377
7439
|
signal.removeEventListener("abort", onAbort);
|
|
7378
7440
|
}
|
|
7379
7441
|
if (!aborted) {
|
|
7380
|
-
|
|
7442
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7443
|
+
if (/aborted/i.test(message)) {
|
|
7444
|
+
reject(error);
|
|
7445
|
+
return;
|
|
7446
|
+
}
|
|
7447
|
+
resolve3(createEditThrownErrorResult(message, path4));
|
|
7381
7448
|
}
|
|
7382
7449
|
}
|
|
7383
7450
|
})();
|
|
@@ -9527,6 +9594,13 @@ var MAX_TEXT_GREP_TOTAL_BYTES = 64 * 1024 * 1024;
|
|
|
9527
9594
|
var MAX_GREP_PATTERN_LENGTH = 512;
|
|
9528
9595
|
var MAX_GREP_CONTEXT_LINES = 20;
|
|
9529
9596
|
var MAX_GREP_RESULT_LIMIT = 1e3;
|
|
9597
|
+
function boundedErrorMessage(prefix, error, hint) {
|
|
9598
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
9599
|
+
const text = `${prefix}: ${message}
|
|
9600
|
+
${hint}`;
|
|
9601
|
+
return text.length > 1e3 ? `${text.slice(0, 1e3)}
|
|
9602
|
+
[error truncated]` : text;
|
|
9603
|
+
}
|
|
9530
9604
|
var SKIP_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", "__pycache__", ".svn", ".hg"]);
|
|
9531
9605
|
var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
9532
9606
|
".png",
|
|
@@ -9873,7 +9947,7 @@ function createGrepTextTool(cwd, options) {
|
|
|
9873
9947
|
return {
|
|
9874
9948
|
name: "grep_text",
|
|
9875
9949
|
label: "grep_text",
|
|
9876
|
-
description: `Search file contents
|
|
9950
|
+
description: `Search file contents with a bounded regex or literal pattern. ${pathResolutionDescription} Use literal=true for plain text or unsafe regexes. outputMode: content (matching lines), files_with_matches, or count. Output is capped at ${DEFAULT_LIMIT2} results or ${DEFAULT_MAX_BYTES / 1024}KB; long lines cap at ${GREP_MAX_LINE_LENGTH} chars.`,
|
|
9877
9951
|
parameters: grepSchema,
|
|
9878
9952
|
execute: async (_toolCallId, params, signal) => {
|
|
9879
9953
|
const {
|
|
@@ -9888,8 +9962,17 @@ function createGrepTextTool(cwd, options) {
|
|
|
9888
9962
|
offset: rawOffset,
|
|
9889
9963
|
limit
|
|
9890
9964
|
} = params;
|
|
9891
|
-
|
|
9892
|
-
|
|
9965
|
+
let fileGlobMatcher;
|
|
9966
|
+
try {
|
|
9967
|
+
assertGrepPatternLength(pattern);
|
|
9968
|
+
fileGlobMatcher = createGrepGlobMatcher(globPattern);
|
|
9969
|
+
} catch (error) {
|
|
9970
|
+
return {
|
|
9971
|
+
content: [{ type: "text", text: boundedErrorMessage("grep_text failed", error, "Use literal=true for plain text, shorten the pattern, or narrow the glob.") }],
|
|
9972
|
+
details: { searchIncomplete: true, safetyLimit: "io_error" },
|
|
9973
|
+
isError: true
|
|
9974
|
+
};
|
|
9975
|
+
}
|
|
9893
9976
|
return new Promise((resolve3, reject) => {
|
|
9894
9977
|
if (signal?.aborted) {
|
|
9895
9978
|
reject(new Error("Operation aborted"));
|
|
@@ -9912,7 +9995,12 @@ function createGrepTextTool(cwd, options) {
|
|
|
9912
9995
|
const stat = await fs2.stat(searchPath);
|
|
9913
9996
|
isDir = stat.isDirectory;
|
|
9914
9997
|
} catch {
|
|
9915
|
-
|
|
9998
|
+
resolve3({
|
|
9999
|
+
content: [{ type: "text", text: `grep_text failed: Path not found: ${searchPath}
|
|
10000
|
+
Check the path or search from the workspace root.` }],
|
|
10001
|
+
details: { searchIncomplete: true, safetyLimit: "io_error" },
|
|
10002
|
+
isError: true
|
|
10003
|
+
});
|
|
9916
10004
|
return;
|
|
9917
10005
|
}
|
|
9918
10006
|
const isGitignored = await loadGitignoreMatcher(searchPath, fs2, {
|
|
@@ -9938,7 +10026,11 @@ function createGrepTextTool(cwd, options) {
|
|
|
9938
10026
|
} else {
|
|
9939
10027
|
}
|
|
9940
10028
|
} catch (e) {
|
|
9941
|
-
|
|
10029
|
+
resolve3({
|
|
10030
|
+
content: [{ type: "text", text: boundedErrorMessage("grep_text failed: invalid regex pattern", e, "Use literal=true for plain text, or simplify the regex.") }],
|
|
10031
|
+
details: { searchIncomplete: true, safetyLimit: "io_error" },
|
|
10032
|
+
isError: true
|
|
10033
|
+
});
|
|
9942
10034
|
return;
|
|
9943
10035
|
}
|
|
9944
10036
|
let outputLines = [];
|
|
@@ -10174,7 +10266,16 @@ function createGrepTextTool(cwd, options) {
|
|
|
10174
10266
|
details: Object.keys(details).length > 0 ? details : void 0
|
|
10175
10267
|
});
|
|
10176
10268
|
} catch (err) {
|
|
10177
|
-
|
|
10269
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
10270
|
+
if (/aborted/i.test(message)) {
|
|
10271
|
+
reject(err);
|
|
10272
|
+
return;
|
|
10273
|
+
}
|
|
10274
|
+
resolve3({
|
|
10275
|
+
content: [{ type: "text", text: boundedErrorMessage("grep_text failed", err, "Check the path/pattern, use literal=true for plain text, or narrow the search.") }],
|
|
10276
|
+
details: { searchIncomplete: true, safetyLimit: "io_error" },
|
|
10277
|
+
isError: true
|
|
10278
|
+
});
|
|
10178
10279
|
} finally {
|
|
10179
10280
|
await regexSession?.dispose();
|
|
10180
10281
|
signal?.removeEventListener("abort", onAbort);
|
|
@@ -10191,6 +10292,13 @@ var MAX_RESULT_LIMIT2 = 1e4;
|
|
|
10191
10292
|
var MAX_SCANNED_DIRECTORIES = 1e4;
|
|
10192
10293
|
var MAX_SCANNED_FILES = 1e4;
|
|
10193
10294
|
var MAX_DIRECTORY_ENTRIES = 1e4;
|
|
10295
|
+
function boundedFindError(error) {
|
|
10296
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
10297
|
+
const text = `find_files failed: ${message}
|
|
10298
|
+
Shorten the pattern, remove unsupported glob syntax, or narrow the search path.`;
|
|
10299
|
+
return text.length > 1e3 ? `${text.slice(0, 1e3)}
|
|
10300
|
+
[error truncated]` : text;
|
|
10301
|
+
}
|
|
10194
10302
|
var SKIP_DIRS2 = /* @__PURE__ */ new Set(["node_modules", ".git", "__pycache__", ".svn", ".hg"]);
|
|
10195
10303
|
function createFindFilesMatcher(pattern) {
|
|
10196
10304
|
assertBoundedGlobPattern(pattern, "find_files pattern");
|
|
@@ -10358,7 +10466,16 @@ function createFindFilesTool(cwd, options) {
|
|
|
10358
10466
|
parameters: findSchema,
|
|
10359
10467
|
execute: async (_toolCallId, params, signal) => {
|
|
10360
10468
|
const { pattern, path: searchDir, root, limit } = params;
|
|
10361
|
-
|
|
10469
|
+
let matchesPattern;
|
|
10470
|
+
try {
|
|
10471
|
+
matchesPattern = createFindFilesMatcher(pattern);
|
|
10472
|
+
} catch (error) {
|
|
10473
|
+
return {
|
|
10474
|
+
content: [{ type: "text", text: boundedFindError(error) }],
|
|
10475
|
+
details: { searchIncomplete: true },
|
|
10476
|
+
isError: true
|
|
10477
|
+
};
|
|
10478
|
+
}
|
|
10362
10479
|
return new Promise((resolve3, reject) => {
|
|
10363
10480
|
if (signal?.aborted) {
|
|
10364
10481
|
reject(new Error("Operation aborted"));
|
|
@@ -10380,7 +10497,12 @@ function createFindFilesTool(cwd, options) {
|
|
|
10380
10497
|
throw new Error(`Invalid find_files arguments: limit must be between 1 and ${MAX_RESULT_LIMIT2}.`);
|
|
10381
10498
|
}
|
|
10382
10499
|
if (!await fs2.exists(searchPath)) {
|
|
10383
|
-
|
|
10500
|
+
resolve3({
|
|
10501
|
+
content: [{ type: "text", text: `find_files failed: Path not found: ${searchPath}
|
|
10502
|
+
Check the path or search from the workspace root.` }],
|
|
10503
|
+
details: { searchIncomplete: true },
|
|
10504
|
+
isError: true
|
|
10505
|
+
});
|
|
10384
10506
|
return;
|
|
10385
10507
|
}
|
|
10386
10508
|
let results;
|
|
@@ -10447,7 +10569,16 @@ function createFindFilesTool(cwd, options) {
|
|
|
10447
10569
|
});
|
|
10448
10570
|
} catch (e) {
|
|
10449
10571
|
signal?.removeEventListener("abort", onAbort);
|
|
10450
|
-
|
|
10572
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
10573
|
+
if (/aborted/i.test(message)) {
|
|
10574
|
+
reject(e);
|
|
10575
|
+
return;
|
|
10576
|
+
}
|
|
10577
|
+
resolve3({
|
|
10578
|
+
content: [{ type: "text", text: boundedFindError(e) }],
|
|
10579
|
+
details: { searchIncomplete: true },
|
|
10580
|
+
isError: true
|
|
10581
|
+
});
|
|
10451
10582
|
}
|
|
10452
10583
|
})();
|
|
10453
10584
|
});
|
|
@@ -12645,10 +12776,19 @@ function createSharedWebFetchTool(deps = {}) {
|
|
|
12645
12776
|
|
|
12646
12777
|
// ../../packages/shared-headless-capabilities/src/web-research.ts
|
|
12647
12778
|
var webResearchSchema = Type.Object({
|
|
12648
|
-
query: Type.String({
|
|
12779
|
+
query: Type.Optional(Type.String({
|
|
12649
12780
|
minLength: 2,
|
|
12650
|
-
description: "
|
|
12651
|
-
}),
|
|
12781
|
+
description: "Research/search query. For url fetch mode, use as an optional extraction prompt."
|
|
12782
|
+
})),
|
|
12783
|
+
url: Type.Optional(Type.String({
|
|
12784
|
+
description: "Specific http(s) URL to fetch and read."
|
|
12785
|
+
})),
|
|
12786
|
+
mode: Type.Optional(Type.Union([
|
|
12787
|
+
Type.Literal("research"),
|
|
12788
|
+
Type.Literal("search")
|
|
12789
|
+
], {
|
|
12790
|
+
description: "Default research searches and fetches cited sources. Use search for low-level provider search results."
|
|
12791
|
+
})),
|
|
12652
12792
|
allowed_domains: Type.Optional(Type.Array(Type.String({
|
|
12653
12793
|
description: "Only include sources from these domains. Use only when the user explicitly asks to limit sources."
|
|
12654
12794
|
}))),
|
|
@@ -12670,12 +12810,70 @@ function isRecord5(value) {
|
|
|
12670
12810
|
function textFromResult(result) {
|
|
12671
12811
|
return result.content.filter((item) => item.type === "text" && typeof item.text === "string").map((item) => item.text).join("\n").trim();
|
|
12672
12812
|
}
|
|
12813
|
+
function makeEmptyResearchDetails(params) {
|
|
12814
|
+
return {
|
|
12815
|
+
query: params.query,
|
|
12816
|
+
actualQueries: params.actualQueries ?? [],
|
|
12817
|
+
sources: params.sources ?? [],
|
|
12818
|
+
fetchedSources: params.fetchedSources ?? [],
|
|
12819
|
+
providerAttempts: params.providerAttempts ?? [],
|
|
12820
|
+
attempts: params.attempts ?? [],
|
|
12821
|
+
qualityScore: params.qualityScore ?? 0,
|
|
12822
|
+
warnings: params.warnings ?? [],
|
|
12823
|
+
browserRequiredSources: params.browserRequiredSources ?? [],
|
|
12824
|
+
routeRankReason: params.routeRankReason,
|
|
12825
|
+
latencyMetrics: {
|
|
12826
|
+
totalDurationMs: Date.now() - params.totalStartedAt,
|
|
12827
|
+
searchDurationMs: params.searchDurationMs ?? 0,
|
|
12828
|
+
fetchDurationMs: params.fetchDurationMs ?? 0,
|
|
12829
|
+
browserDurationMs: params.browserDurationMs ?? 0
|
|
12830
|
+
},
|
|
12831
|
+
costEstimate: {
|
|
12832
|
+
status: "unknown",
|
|
12833
|
+
reason: "Provider usage is not yet normalized across web research search/fetch/browser routes."
|
|
12834
|
+
}
|
|
12835
|
+
};
|
|
12836
|
+
}
|
|
12673
12837
|
function clamp(value, min, max) {
|
|
12674
12838
|
return Math.min(max, Math.max(min, value));
|
|
12675
12839
|
}
|
|
12676
12840
|
function normalizeHost(hostname) {
|
|
12677
12841
|
return hostname.toLowerCase().replace(/^www\./, "");
|
|
12678
12842
|
}
|
|
12843
|
+
function normalizeDomainFilter(value) {
|
|
12844
|
+
let domain = value.trim().toLowerCase();
|
|
12845
|
+
if (!domain) return void 0;
|
|
12846
|
+
domain = domain.replace(/^https?:\/\//i, "");
|
|
12847
|
+
domain = domain.replace(/^[^@/]+@/, "");
|
|
12848
|
+
domain = domain.split(/[/?#]/)[0] || "";
|
|
12849
|
+
if (domain.startsWith("[") && domain.includes("]")) {
|
|
12850
|
+
domain = domain.slice(1, domain.indexOf("]"));
|
|
12851
|
+
} else {
|
|
12852
|
+
domain = domain.split(":")[0] || "";
|
|
12853
|
+
}
|
|
12854
|
+
domain = domain.replace(/^\*\./, "").replace(/^www\./, "").replace(/\.$/, "");
|
|
12855
|
+
return domain || void 0;
|
|
12856
|
+
}
|
|
12857
|
+
function hostMatchesDomainFilter(hostname, filter2) {
|
|
12858
|
+
const host = normalizeHost(hostname);
|
|
12859
|
+
const domain = normalizeDomainFilter(filter2);
|
|
12860
|
+
if (!domain) return false;
|
|
12861
|
+
return host === domain || host.endsWith(`.${domain}`);
|
|
12862
|
+
}
|
|
12863
|
+
function directUrlFilterFailure(url, input) {
|
|
12864
|
+
const allowedDomains = input.allowed_domains?.length ? input.allowed_domains : void 0;
|
|
12865
|
+
const blockedDomains = allowedDomains ? void 0 : input.blocked_domains?.length ? input.blocked_domains : void 0;
|
|
12866
|
+
if (!allowedDomains && !blockedDomains) return void 0;
|
|
12867
|
+
const parsed = parseResearchUrl(url);
|
|
12868
|
+
if (!parsed) return `web_research URL mode only supports http(s) URLs: ${url}`;
|
|
12869
|
+
if (allowedDomains && !allowedDomains.some((domain) => hostMatchesDomainFilter(parsed.hostname, domain))) {
|
|
12870
|
+
return `web_research blocked ${url}: URL host is not in allowed_domains.`;
|
|
12871
|
+
}
|
|
12872
|
+
if (blockedDomains?.some((domain) => hostMatchesDomainFilter(parsed.hostname, domain))) {
|
|
12873
|
+
return `web_research blocked ${url}: URL host matches blocked_domains.`;
|
|
12874
|
+
}
|
|
12875
|
+
return void 0;
|
|
12876
|
+
}
|
|
12679
12877
|
function parseResearchUrl(value) {
|
|
12680
12878
|
const trimmed = value.trim();
|
|
12681
12879
|
const match2 = /^(https?):\/\/([^/?#]+)([^?#]*)?(\?[^#]*)?(#.*)?$/i.exec(trimmed);
|
|
@@ -12967,7 +13165,7 @@ function createSharedWebResearchTool(deps) {
|
|
|
12967
13165
|
return {
|
|
12968
13166
|
name: "web_research",
|
|
12969
13167
|
label: "web_research",
|
|
12970
|
-
description: "
|
|
13168
|
+
description: "Canonical web tool. For normal research, pass query. To read a known page, pass url. For low-level search results only, pass query with mode='search'. Use for current information, official docs, news, releases, issues, and webpage summaries. Do not use bash/curl/Python as a web fallback.",
|
|
12971
13169
|
parameters: webResearchSchema,
|
|
12972
13170
|
capabilityMetadata: {
|
|
12973
13171
|
riskClass: "network",
|
|
@@ -12986,6 +13184,8 @@ function createSharedWebResearchTool(deps) {
|
|
|
12986
13184
|
const rankedCandidates = sortCandidatesByHealth(activeCandidates, currentHealth);
|
|
12987
13185
|
const routeRankReason = describeRouteRanking(rankedCandidates.length ? rankedCandidates : activeCandidates, currentHealth);
|
|
12988
13186
|
const query = String(input.query || "").trim();
|
|
13187
|
+
const directUrl = typeof input.url === "string" ? String(input.url).trim() : "";
|
|
13188
|
+
const mode = input.mode === "search" ? "search" : "research";
|
|
12989
13189
|
const maxSources = clamp(Math.floor(input.max_sources ?? 3), 1, 8);
|
|
12990
13190
|
const searchAttemptTimeoutMs = Math.max(1e3, deps.searchAttemptTimeoutMs ?? deps.timeoutMs ?? DEFAULT_WEB_RESEARCH_SEARCH_ATTEMPT_TIMEOUT_MS);
|
|
12991
13191
|
const fetchAttemptTimeoutMs = Math.max(1e3, deps.fetchAttemptTimeoutMs ?? DEFAULT_WEB_RESEARCH_FETCH_ATTEMPT_TIMEOUT_MS);
|
|
@@ -13003,6 +13203,242 @@ function createSharedWebResearchTool(deps) {
|
|
|
13003
13203
|
let searchDurationMs = 0;
|
|
13004
13204
|
let fetchDurationMs = 0;
|
|
13005
13205
|
let browserDurationMs = 0;
|
|
13206
|
+
if (directUrl) {
|
|
13207
|
+
if (input.allowed_domains?.length && input.blocked_domains?.length) {
|
|
13208
|
+
warnings.push("Both allowed_domains and blocked_domains were provided; web_research used allowed_domains and ignored blocked_domains for provider compatibility.");
|
|
13209
|
+
}
|
|
13210
|
+
const filterFailure = directUrlFilterFailure(directUrl, input);
|
|
13211
|
+
if (filterFailure) {
|
|
13212
|
+
return {
|
|
13213
|
+
content: [{ type: "text", text: filterFailure }],
|
|
13214
|
+
details: makeEmptyResearchDetails({
|
|
13215
|
+
query: query || directUrl,
|
|
13216
|
+
actualQueries: query ? [query] : [],
|
|
13217
|
+
warnings,
|
|
13218
|
+
routeRankReason,
|
|
13219
|
+
totalStartedAt
|
|
13220
|
+
}),
|
|
13221
|
+
isError: true
|
|
13222
|
+
};
|
|
13223
|
+
}
|
|
13224
|
+
onUpdate?.({
|
|
13225
|
+
content: [{ type: "text", text: `Fetching URL: ${directUrl}` }],
|
|
13226
|
+
details: makeEmptyResearchDetails({ query: query || directUrl, attempts, providerAttempts, totalStartedAt, routeRankReason })
|
|
13227
|
+
});
|
|
13228
|
+
const startedAt = Date.now();
|
|
13229
|
+
const fetchResult = await runWithDeadline(
|
|
13230
|
+
(childSignal) => webFetchTool.execute("web_research_fetch_direct", { url: directUrl, prompt: query || void 0 }, childSignal),
|
|
13231
|
+
fetchAttemptTimeoutMs,
|
|
13232
|
+
`web_research fetch attempt timed out after ${Math.ceil(fetchAttemptTimeoutMs / 1e3)} seconds`,
|
|
13233
|
+
signal
|
|
13234
|
+
).catch((error) => ({
|
|
13235
|
+
content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }],
|
|
13236
|
+
details: {
|
|
13237
|
+
url: directUrl,
|
|
13238
|
+
sourceUrl: directUrl,
|
|
13239
|
+
durationMs: Date.now() - startedAt,
|
|
13240
|
+
failureCategory: "timeout"
|
|
13241
|
+
},
|
|
13242
|
+
isError: true
|
|
13243
|
+
}));
|
|
13244
|
+
fetchDurationMs = Date.now() - startedAt;
|
|
13245
|
+
const fetchDetails = contentDetails(fetchResult);
|
|
13246
|
+
const text = textFromResult(fetchResult);
|
|
13247
|
+
const fetchedSource = fetchResult.isError ? void 0 : {
|
|
13248
|
+
url: directUrl,
|
|
13249
|
+
finalUrl: fetchDetails.finalUrl || directUrl,
|
|
13250
|
+
title: fetchDetails.title || directUrl,
|
|
13251
|
+
textExcerpt: excerpt(text),
|
|
13252
|
+
score: 100,
|
|
13253
|
+
scoreReasons: ["direct_url"],
|
|
13254
|
+
extractionMethod: fetchDetails.extractionMethod,
|
|
13255
|
+
citationAnchors: fetchDetails.citationAnchors,
|
|
13256
|
+
requiresBrowser: fetchDetails.requiresBrowser,
|
|
13257
|
+
failureCategory: fetchDetails.failureCategory
|
|
13258
|
+
};
|
|
13259
|
+
const attemptsForFetch = [{
|
|
13260
|
+
phase: "fetch",
|
|
13261
|
+
url: directUrl,
|
|
13262
|
+
status: fetchResult.isError ? "failed" : "completed",
|
|
13263
|
+
failureCategory: fetchDetails.failureCategory,
|
|
13264
|
+
durationMs: fetchDurationMs
|
|
13265
|
+
}];
|
|
13266
|
+
if (fetchDetails.requiresBrowser) {
|
|
13267
|
+
const browserSource = {
|
|
13268
|
+
url: directUrl,
|
|
13269
|
+
finalUrl: typeof fetchDetails.finalUrl === "string" ? fetchDetails.finalUrl : directUrl,
|
|
13270
|
+
title: typeof fetchDetails.title === "string" ? fetchDetails.title : directUrl,
|
|
13271
|
+
score: 100,
|
|
13272
|
+
scoreReasons: ["direct_url"],
|
|
13273
|
+
requiresBrowser: true,
|
|
13274
|
+
failureCategory: fetchDetails.failureCategory
|
|
13275
|
+
};
|
|
13276
|
+
if (deps.renderedPageReader) {
|
|
13277
|
+
const browserStartedAt = Date.now();
|
|
13278
|
+
try {
|
|
13279
|
+
onUpdate?.({
|
|
13280
|
+
content: [{ type: "text", text: `Reading browser-rendered URL: ${fetchDetails.finalUrl || directUrl}` }],
|
|
13281
|
+
details: makeEmptyResearchDetails({
|
|
13282
|
+
query: query || directUrl,
|
|
13283
|
+
actualQueries: query ? [query] : [],
|
|
13284
|
+
sources: [{ title: browserSource.title || directUrl, url: browserSource.finalUrl || directUrl }],
|
|
13285
|
+
attempts: attemptsForFetch,
|
|
13286
|
+
warnings,
|
|
13287
|
+
browserRequiredSources: [browserSource],
|
|
13288
|
+
routeRankReason,
|
|
13289
|
+
totalStartedAt,
|
|
13290
|
+
fetchDurationMs
|
|
13291
|
+
})
|
|
13292
|
+
});
|
|
13293
|
+
const rendered = await runWithDeadline(
|
|
13294
|
+
(childSignal) => deps.renderedPageReader({ url: fetchDetails.finalUrl || directUrl, query }, childSignal),
|
|
13295
|
+
browserAttemptTimeoutMs,
|
|
13296
|
+
`web_research browser reader timed out after ${Math.ceil(browserAttemptTimeoutMs / 1e3)} seconds`,
|
|
13297
|
+
signal
|
|
13298
|
+
);
|
|
13299
|
+
browserDurationMs = Date.now() - browserStartedAt;
|
|
13300
|
+
const renderedSource = {
|
|
13301
|
+
url: directUrl,
|
|
13302
|
+
finalUrl: rendered.finalUrl || rendered.url,
|
|
13303
|
+
title: rendered.title || browserSource.title || directUrl,
|
|
13304
|
+
textExcerpt: excerpt(rendered.text),
|
|
13305
|
+
score: 100,
|
|
13306
|
+
scoreReasons: ["direct_url"],
|
|
13307
|
+
extractionMethod: "browser_rendered",
|
|
13308
|
+
citationAnchors: rendered.citationAnchors,
|
|
13309
|
+
requiresBrowser: false,
|
|
13310
|
+
browserReadSummary: {
|
|
13311
|
+
screenshotPath: rendered.screenshotPath,
|
|
13312
|
+
consoleMessageCount: rendered.consoleMessages?.length,
|
|
13313
|
+
networkRequestCount: rendered.networkRequests?.length
|
|
13314
|
+
}
|
|
13315
|
+
};
|
|
13316
|
+
const attemptsWithBrowser = [
|
|
13317
|
+
...attemptsForFetch,
|
|
13318
|
+
{ phase: "browser", url: rendered.finalUrl || rendered.url, status: "completed", durationMs: browserDurationMs }
|
|
13319
|
+
];
|
|
13320
|
+
return {
|
|
13321
|
+
content: [{ type: "text", text: formatResearchPack(query || directUrl, [renderedSource], warnings, []) }],
|
|
13322
|
+
details: makeEmptyResearchDetails({
|
|
13323
|
+
query: query || directUrl,
|
|
13324
|
+
actualQueries: query ? [query] : [],
|
|
13325
|
+
sources: [{ title: renderedSource.title || directUrl, url: renderedSource.finalUrl || directUrl }],
|
|
13326
|
+
fetchedSources: [renderedSource],
|
|
13327
|
+
attempts: attemptsWithBrowser,
|
|
13328
|
+
warnings,
|
|
13329
|
+
qualityScore: 100,
|
|
13330
|
+
routeRankReason,
|
|
13331
|
+
totalStartedAt,
|
|
13332
|
+
fetchDurationMs,
|
|
13333
|
+
browserDurationMs
|
|
13334
|
+
})
|
|
13335
|
+
};
|
|
13336
|
+
} catch (error) {
|
|
13337
|
+
browserDurationMs = Date.now() - browserStartedAt;
|
|
13338
|
+
attemptsForFetch.push({
|
|
13339
|
+
phase: "browser",
|
|
13340
|
+
url: fetchDetails.finalUrl || directUrl,
|
|
13341
|
+
status: "failed",
|
|
13342
|
+
failureCategory: "requires_browser",
|
|
13343
|
+
warnings: [error instanceof Error ? error.message : String(error)],
|
|
13344
|
+
durationMs: browserDurationMs
|
|
13345
|
+
});
|
|
13346
|
+
warnings.push(`Browser reader failed for ${fetchDetails.finalUrl || directUrl}: ${error instanceof Error ? error.message : String(error)}`);
|
|
13347
|
+
}
|
|
13348
|
+
}
|
|
13349
|
+
return {
|
|
13350
|
+
content: [{ type: "text", text: `web_research could not read ${directUrl}: the page requires browser-rendered reading and no host browser reader completed.` }],
|
|
13351
|
+
details: makeEmptyResearchDetails({
|
|
13352
|
+
query: query || directUrl,
|
|
13353
|
+
actualQueries: query ? [query] : [],
|
|
13354
|
+
sources: [{ title: browserSource.title || directUrl, url: browserSource.finalUrl || directUrl }],
|
|
13355
|
+
attempts: attemptsForFetch,
|
|
13356
|
+
warnings,
|
|
13357
|
+
browserRequiredSources: [browserSource],
|
|
13358
|
+
routeRankReason,
|
|
13359
|
+
totalStartedAt,
|
|
13360
|
+
fetchDurationMs,
|
|
13361
|
+
browserDurationMs
|
|
13362
|
+
}),
|
|
13363
|
+
isError: true
|
|
13364
|
+
};
|
|
13365
|
+
}
|
|
13366
|
+
return {
|
|
13367
|
+
content: fetchResult.content,
|
|
13368
|
+
details: makeEmptyResearchDetails({
|
|
13369
|
+
query: query || directUrl,
|
|
13370
|
+
actualQueries: query ? [query] : [],
|
|
13371
|
+
sources: [{ title: fetchDetails.title || directUrl, url: fetchDetails.finalUrl || directUrl }],
|
|
13372
|
+
fetchedSources: fetchedSource ? [fetchedSource] : [],
|
|
13373
|
+
attempts: attemptsForFetch,
|
|
13374
|
+
warnings,
|
|
13375
|
+
qualityScore: fetchedSource ? 100 : 0,
|
|
13376
|
+
routeRankReason,
|
|
13377
|
+
totalStartedAt,
|
|
13378
|
+
fetchDurationMs
|
|
13379
|
+
}),
|
|
13380
|
+
isError: fetchResult.isError
|
|
13381
|
+
};
|
|
13382
|
+
}
|
|
13383
|
+
if (mode === "search") {
|
|
13384
|
+
if (!query) {
|
|
13385
|
+
return {
|
|
13386
|
+
content: [{ type: "text", text: "web_research search mode requires a non-empty query." }],
|
|
13387
|
+
details: makeEmptyResearchDetails({ query, warnings: ["missing_query"], routeRankReason, totalStartedAt }),
|
|
13388
|
+
isError: true
|
|
13389
|
+
};
|
|
13390
|
+
}
|
|
13391
|
+
const startedAt = Date.now();
|
|
13392
|
+
const allowedDomains = input.allowed_domains?.length ? input.allowed_domains : void 0;
|
|
13393
|
+
const blockedDomains = allowedDomains ? void 0 : input.blocked_domains;
|
|
13394
|
+
const result = await runWithDeadline(
|
|
13395
|
+
(childSignal) => webSearchTool.execute("web_research_search_direct", {
|
|
13396
|
+
query,
|
|
13397
|
+
allowed_domains: allowedDomains,
|
|
13398
|
+
blocked_domains: blockedDomains
|
|
13399
|
+
}, childSignal),
|
|
13400
|
+
searchAttemptTimeoutMs,
|
|
13401
|
+
`web_research search attempt timed out after ${Math.ceil(searchAttemptTimeoutMs / 1e3)} seconds`,
|
|
13402
|
+
signal
|
|
13403
|
+
).catch((error) => ({
|
|
13404
|
+
content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }],
|
|
13405
|
+
details: {
|
|
13406
|
+
query,
|
|
13407
|
+
requestedMode: deps.getMode?.() ?? "auto",
|
|
13408
|
+
providerMode: "unavailable",
|
|
13409
|
+
durationSeconds: (Date.now() - startedAt) / 1e3,
|
|
13410
|
+
sourceCount: 0,
|
|
13411
|
+
sources: [],
|
|
13412
|
+
failureCategory: "timeout"
|
|
13413
|
+
},
|
|
13414
|
+
isError: true
|
|
13415
|
+
}));
|
|
13416
|
+
searchDurationMs = Date.now() - startedAt;
|
|
13417
|
+
const searchDetails = contentDetails(result);
|
|
13418
|
+
return {
|
|
13419
|
+
content: result.content,
|
|
13420
|
+
details: makeEmptyResearchDetails({
|
|
13421
|
+
query,
|
|
13422
|
+
actualQueries: searchDetails.actualQueries ?? [query],
|
|
13423
|
+
sources: searchDetails.sources ?? [],
|
|
13424
|
+
providerAttempts: searchDetails.attempts ?? [],
|
|
13425
|
+
attempts: [{
|
|
13426
|
+
phase: "search",
|
|
13427
|
+
query,
|
|
13428
|
+
status: result.isError ? "failed" : "completed",
|
|
13429
|
+
failureCategory: searchDetails.failureCategory,
|
|
13430
|
+
warnings: searchDetails.qualityWarnings,
|
|
13431
|
+
durationMs: searchDurationMs
|
|
13432
|
+
}],
|
|
13433
|
+
warnings: searchDetails.qualityWarnings ?? [],
|
|
13434
|
+
qualityScore: (searchDetails.sources?.length ?? 0) > 0 ? 50 : 0,
|
|
13435
|
+
routeRankReason,
|
|
13436
|
+
totalStartedAt,
|
|
13437
|
+
searchDurationMs
|
|
13438
|
+
}),
|
|
13439
|
+
isError: result.isError
|
|
13440
|
+
};
|
|
13441
|
+
}
|
|
13006
13442
|
if (!query) {
|
|
13007
13443
|
return {
|
|
13008
13444
|
content: [{ type: "text", text: "web_research requires a non-empty query." }],
|
|
@@ -13586,9 +14022,16 @@ function createCodeIntelTool(options) {
|
|
|
13586
14022
|
isError: result.isError
|
|
13587
14023
|
};
|
|
13588
14024
|
} catch (error) {
|
|
14025
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
13589
14026
|
return {
|
|
13590
|
-
content: [{ type: "text", text: `code_intel failed: ${
|
|
13591
|
-
details: {
|
|
14027
|
+
content: [{ type: "text", text: `code_intel failed: ${message}` }],
|
|
14028
|
+
details: {
|
|
14029
|
+
operation: input.operation,
|
|
14030
|
+
projectRoot,
|
|
14031
|
+
path: input.path,
|
|
14032
|
+
provider: "unavailable",
|
|
14033
|
+
fallbackReason: message
|
|
14034
|
+
},
|
|
13592
14035
|
isError: true
|
|
13593
14036
|
};
|
|
13594
14037
|
}
|
|
@@ -13659,5 +14102,6 @@ export {
|
|
|
13659
14102
|
createSharedWebSearchTool,
|
|
13660
14103
|
createSharedWebFetchTool,
|
|
13661
14104
|
createSharedWebResearchTool,
|
|
14105
|
+
createLightweightCodeIntelProvider,
|
|
13662
14106
|
createCodeIntelTool
|
|
13663
14107
|
};
|