mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
feat: Optimize the code
This commit is contained in:
@@ -4,16 +4,11 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {
|
import type { WebSearchProvider, WebSearchResult } from './types.js';
|
||||||
WebSearchProvider,
|
|
||||||
WebSearchResult,
|
|
||||||
WebSearchResultItem,
|
|
||||||
} from './types.js';
|
|
||||||
import { WebSearchError } from './errors.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base implementation for web search providers.
|
* Base implementation for web search providers.
|
||||||
* Provides common functionality for error handling and result formatting.
|
* Provides common functionality for error handling.
|
||||||
*/
|
*/
|
||||||
export abstract class BaseWebSearchProvider implements WebSearchProvider {
|
export abstract class BaseWebSearchProvider implements WebSearchProvider {
|
||||||
abstract readonly name: string;
|
abstract readonly name: string;
|
||||||
@@ -42,38 +37,22 @@ export abstract class BaseWebSearchProvider implements WebSearchProvider {
|
|||||||
*/
|
*/
|
||||||
async search(query: string, signal: AbortSignal): Promise<WebSearchResult> {
|
async search(query: string, signal: AbortSignal): Promise<WebSearchResult> {
|
||||||
if (!this.isAvailable()) {
|
if (!this.isAvailable()) {
|
||||||
throw new WebSearchError(
|
throw new Error(
|
||||||
this.name,
|
`[${this.name}] Provider is not available. Please check your configuration.`,
|
||||||
'Provider is not available. Please check your configuration.',
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await this.performSearch(query, signal);
|
return await this.performSearch(query, signal);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
if (error instanceof WebSearchError) {
|
if (
|
||||||
|
error instanceof Error &&
|
||||||
|
error.message.startsWith(`[${this.name}]`)
|
||||||
|
) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
throw new WebSearchError(this.name, 'Search failed', error);
|
const message = error instanceof Error ? error.message : String(error);
|
||||||
|
throw new Error(`[${this.name}] Search failed: ${message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Format search results into a consistent format.
|
|
||||||
* @param results Raw results from the provider
|
|
||||||
* @param query The original search query
|
|
||||||
* @param answer Optional answer from the provider
|
|
||||||
* @returns Formatted search results
|
|
||||||
*/
|
|
||||||
protected formatResults(
|
|
||||||
results: WebSearchResultItem[],
|
|
||||||
query: string,
|
|
||||||
answer?: string,
|
|
||||||
): WebSearchResult {
|
|
||||||
return {
|
|
||||||
query,
|
|
||||||
answer,
|
|
||||||
results,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright 2025 Qwen
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom error class for web search operations.
|
|
||||||
*/
|
|
||||||
export class WebSearchError extends Error {
|
|
||||||
constructor(
|
|
||||||
readonly provider: string,
|
|
||||||
message: string,
|
|
||||||
readonly originalError?: unknown,
|
|
||||||
) {
|
|
||||||
super(`[${provider}] ${message}`);
|
|
||||||
this.name = 'WebSearchError';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,7 +5,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { BaseWebSearchProvider } from '../base-provider.js';
|
import { BaseWebSearchProvider } from '../base-provider.js';
|
||||||
import { WebSearchError } from '../errors.js';
|
|
||||||
import type {
|
import type {
|
||||||
WebSearchResult,
|
WebSearchResult,
|
||||||
WebSearchResultItem,
|
WebSearchResultItem,
|
||||||
@@ -104,8 +103,7 @@ export class DashScopeProvider extends BaseWebSearchProvider {
|
|||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const text = await response.text().catch(() => '');
|
const text = await response.text().catch(() => '');
|
||||||
throw new WebSearchError(
|
throw new Error(
|
||||||
this.name,
|
|
||||||
`API error: ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`,
|
`API error: ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -113,10 +111,7 @@ export class DashScopeProvider extends BaseWebSearchProvider {
|
|||||||
const data = (await response.json()) as DashScopeSearchResponse;
|
const data = (await response.json()) as DashScopeSearchResponse;
|
||||||
|
|
||||||
if (data.status !== 0) {
|
if (data.status !== 0) {
|
||||||
throw new WebSearchError(
|
throw new Error(`API error: ${data.message || 'Unknown error'}`);
|
||||||
this.name,
|
|
||||||
`API error: ${data.message || 'Unknown error'}`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const results: WebSearchResultItem[] = (data.data?.docs || []).map(
|
const results: WebSearchResultItem[] = (data.data?.docs || []).map(
|
||||||
@@ -129,6 +124,9 @@ export class DashScopeProvider extends BaseWebSearchProvider {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
return this.formatResults(results, query, undefined);
|
return {
|
||||||
|
query,
|
||||||
|
results,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { BaseWebSearchProvider } from '../base-provider.js';
|
import { BaseWebSearchProvider } from '../base-provider.js';
|
||||||
import { WebSearchError } from '../errors.js';
|
|
||||||
import type {
|
import type {
|
||||||
WebSearchResult,
|
WebSearchResult,
|
||||||
WebSearchResultItem,
|
WebSearchResultItem,
|
||||||
@@ -71,8 +70,7 @@ export class GoogleProvider extends BaseWebSearchProvider {
|
|||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const text = await response.text().catch(() => '');
|
const text = await response.text().catch(() => '');
|
||||||
throw new WebSearchError(
|
throw new Error(
|
||||||
this.name,
|
|
||||||
`API error: ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`,
|
`API error: ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -85,6 +83,9 @@ export class GoogleProvider extends BaseWebSearchProvider {
|
|||||||
content: item.snippet,
|
content: item.snippet,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return this.formatResults(results, query, undefined);
|
return {
|
||||||
|
query,
|
||||||
|
results,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { BaseWebSearchProvider } from '../base-provider.js';
|
import { BaseWebSearchProvider } from '../base-provider.js';
|
||||||
import { WebSearchError } from '../errors.js';
|
|
||||||
import type {
|
import type {
|
||||||
WebSearchResult,
|
WebSearchResult,
|
||||||
WebSearchResultItem,
|
WebSearchResultItem,
|
||||||
@@ -61,8 +60,7 @@ export class TavilyProvider extends BaseWebSearchProvider {
|
|||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const text = await response.text().catch(() => '');
|
const text = await response.text().catch(() => '');
|
||||||
throw new WebSearchError(
|
throw new Error(
|
||||||
this.name,
|
|
||||||
`API error: ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`,
|
`API error: ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -77,6 +75,10 @@ export class TavilyProvider extends BaseWebSearchProvider {
|
|||||||
publishedDate: r.published_date,
|
publishedDate: r.published_date,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return this.formatResults(results, query, data.answer?.trim());
|
return {
|
||||||
|
query,
|
||||||
|
answer: data.answer?.trim(),
|
||||||
|
results,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,19 +8,6 @@
|
|||||||
* Utility functions for web search formatting and processing.
|
* Utility functions for web search formatting and processing.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* Format sources into a numbered list with titles and URLs.
|
|
||||||
* @param sources Array of source objects with title and url
|
|
||||||
* @returns Formatted source list string
|
|
||||||
*/
|
|
||||||
export function formatSources(
|
|
||||||
sources: Array<{ title: string; url: string }>,
|
|
||||||
): string {
|
|
||||||
return sources
|
|
||||||
.map((s, i) => `[${i + 1}] ${s.title || 'Untitled'} (${s.url})`)
|
|
||||||
.join('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build content string with appended sources section.
|
* Build content string with appended sources section.
|
||||||
* @param content Main content text
|
* @param content Main content text
|
||||||
@@ -32,7 +19,10 @@ export function buildContentWithSources(
|
|||||||
sources: Array<{ title: string; url: string }>,
|
sources: Array<{ title: string; url: string }>,
|
||||||
): string {
|
): string {
|
||||||
if (!sources.length) return content;
|
if (!sources.length) return content;
|
||||||
return `${content}\n\nSources:\n${formatSources(sources)}`;
|
const sourceList = sources
|
||||||
|
.map((s, i) => `[${i + 1}] ${s.title || 'Untitled'} (${s.url})`)
|
||||||
|
.join('\n');
|
||||||
|
return `${content}\n\nSources:\n${sourceList}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user