* fix: WebSearch providers + MCPTool bugs WebSearchTool: - custom.ts: fix buildAuthHeadersForPreset WEB_AUTH_HEADER opt-out - custom.ts: fix WEB_AUTH_SCHEME empty string handling - custom.ts: fix walkJsonPath null safety for jsonPath parsing - duckduckgo.ts: use SafeSearchType enum instead of raw 0 - mojeek.ts: always send Accept: application/json header - README: fix timeout documentation (15s -> 120s to match code) - custom.test.ts: add tests for auth header behavior MCPTool: - MCPTool.ts: fix outputSchema to accept ContentBlockParam[] (not just string) - MCPTool.ts: fix isResultTruncated for array output (iterates text blocks) * fix: address PR #593 review feedback 1. Export buildAuthHeadersForPreset and add direct tests for: - WEB_AUTH_HEADER="" explicit opt-out behavior - WEB_AUTH_SCHEME="" stripping scheme prefix - Preset defaults (authHeader + authScheme) - No WEB_KEY returns empty headers 2. Add duckduckgo.test.ts verifying SafeSearchType.STRICT === 0, confirming the enum change is semantically identical to the previous raw value. Addresses review by @Vasanthdev2004 at pullrequestreview-4093533095 --------- Co-authored-by: FluxLuFFy <flux@openclaude.dev> Co-authored-by: Fix Bot <fix@openclaude.local>
103 lines
2.9 KiB
TypeScript
103 lines
2.9 KiB
TypeScript
import { z } from 'zod/v4'
|
|
import { buildTool, type ToolDef } from '../../Tool.js'
|
|
import { lazySchema } from '../../utils/lazySchema.js'
|
|
import type { PermissionResult } from '../../utils/permissions/PermissionResult.js'
|
|
import { isOutputLineTruncated } from '../../utils/terminal.js'
|
|
import { DESCRIPTION, PROMPT } from './prompt.js'
|
|
import {
|
|
renderToolResultMessage,
|
|
renderToolUseMessage,
|
|
renderToolUseProgressMessage,
|
|
} from './UI.js'
|
|
|
|
// Allow any input object since MCP tools define their own schemas
|
|
export const inputSchema = lazySchema(() => z.object({}).passthrough())
|
|
type InputSchema = ReturnType<typeof inputSchema>
|
|
|
|
// MCP tools can return either a plain string or an array of content blocks
|
|
// (text, images, etc.). The outputSchema must reflect both shapes so the model
|
|
// knows rich content is possible.
|
|
export const outputSchema = lazySchema(() =>
|
|
z.union([
|
|
z.string().describe('MCP tool execution result as text'),
|
|
z
|
|
.array(
|
|
z.object({
|
|
type: z.string(),
|
|
text: z.string().optional(),
|
|
}),
|
|
)
|
|
.describe('MCP tool execution result as content blocks'),
|
|
]),
|
|
)
|
|
type OutputSchema = ReturnType<typeof outputSchema>
|
|
|
|
export type Output = z.infer<OutputSchema>
|
|
|
|
// Re-export MCPProgress from centralized types to break import cycles
|
|
export type { MCPProgress } from '../../types/tools.js'
|
|
|
|
export const MCPTool = buildTool({
|
|
isMcp: true,
|
|
// Overridden in mcpClient.ts with the real MCP tool name + args
|
|
isOpenWorld() {
|
|
return false
|
|
},
|
|
// Overridden in mcpClient.ts
|
|
name: 'mcp',
|
|
maxResultSizeChars: 100_000,
|
|
// Overridden in mcpClient.ts
|
|
async description() {
|
|
return DESCRIPTION
|
|
},
|
|
// Overridden in mcpClient.ts
|
|
async prompt() {
|
|
return PROMPT
|
|
},
|
|
get inputSchema(): InputSchema {
|
|
return inputSchema()
|
|
},
|
|
get outputSchema(): OutputSchema {
|
|
return outputSchema()
|
|
},
|
|
// Overridden in mcpClient.ts
|
|
async call() {
|
|
return {
|
|
data: '',
|
|
}
|
|
},
|
|
async checkPermissions(): Promise<PermissionResult> {
|
|
return {
|
|
behavior: 'passthrough',
|
|
message: 'MCPTool requires permission.',
|
|
}
|
|
},
|
|
renderToolUseMessage,
|
|
// Overridden in mcpClient.ts
|
|
userFacingName: () => 'mcp',
|
|
renderToolUseProgressMessage,
|
|
renderToolResultMessage,
|
|
isResultTruncated(output: Output): boolean {
|
|
if (typeof output === 'string') {
|
|
return isOutputLineTruncated(output)
|
|
}
|
|
// Array of content blocks — check if any text block exceeds the display limit
|
|
if (Array.isArray(output)) {
|
|
return output.some(
|
|
block =>
|
|
block?.type === 'text' &&
|
|
typeof block.text === 'string' &&
|
|
isOutputLineTruncated(block.text),
|
|
)
|
|
}
|
|
return false
|
|
},
|
|
mapToolResultToToolResultBlockParam(content, toolUseID) {
|
|
return {
|
|
tool_use_id: toolUseID,
|
|
type: 'tool_result',
|
|
content,
|
|
}
|
|
},
|
|
} satisfies ToolDef<InputSchema, Output>)
|