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
|
||||
*/
|
||||
|
||||
import type {
|
||||
WebSearchProvider,
|
||||
WebSearchResult,
|
||||
WebSearchResultItem,
|
||||
} from './types.js';
|
||||
import { WebSearchError } from './errors.js';
|
||||
import type { WebSearchProvider, WebSearchResult } from './types.js';
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
abstract readonly name: string;
|
||||
@@ -42,38 +37,22 @@ export abstract class BaseWebSearchProvider implements WebSearchProvider {
|
||||
*/
|
||||
async search(query: string, signal: AbortSignal): Promise<WebSearchResult> {
|
||||
if (!this.isAvailable()) {
|
||||
throw new WebSearchError(
|
||||
this.name,
|
||||
'Provider is not available. Please check your configuration.',
|
||||
throw new Error(
|
||||
`[${this.name}] Provider is not available. Please check your configuration.`,
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
return await this.performSearch(query, signal);
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof WebSearchError) {
|
||||
if (
|
||||
error instanceof Error &&
|
||||
error.message.startsWith(`[${this.name}]`)
|
||||
) {
|
||||
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 { WebSearchError } from '../errors.js';
|
||||
import type {
|
||||
WebSearchResult,
|
||||
WebSearchResultItem,
|
||||
@@ -104,8 +103,7 @@ export class DashScopeProvider extends BaseWebSearchProvider {
|
||||
|
||||
if (!response.ok) {
|
||||
const text = await response.text().catch(() => '');
|
||||
throw new WebSearchError(
|
||||
this.name,
|
||||
throw new Error(
|
||||
`API error: ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`,
|
||||
);
|
||||
}
|
||||
@@ -113,10 +111,7 @@ export class DashScopeProvider extends BaseWebSearchProvider {
|
||||
const data = (await response.json()) as DashScopeSearchResponse;
|
||||
|
||||
if (data.status !== 0) {
|
||||
throw new WebSearchError(
|
||||
this.name,
|
||||
`API error: ${data.message || 'Unknown error'}`,
|
||||
);
|
||||
throw new Error(`API error: ${data.message || 'Unknown error'}`);
|
||||
}
|
||||
|
||||
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 { WebSearchError } from '../errors.js';
|
||||
import type {
|
||||
WebSearchResult,
|
||||
WebSearchResultItem,
|
||||
@@ -71,8 +70,7 @@ export class GoogleProvider extends BaseWebSearchProvider {
|
||||
|
||||
if (!response.ok) {
|
||||
const text = await response.text().catch(() => '');
|
||||
throw new WebSearchError(
|
||||
this.name,
|
||||
throw new Error(
|
||||
`API error: ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`,
|
||||
);
|
||||
}
|
||||
@@ -85,6 +83,9 @@ export class GoogleProvider extends BaseWebSearchProvider {
|
||||
content: item.snippet,
|
||||
}));
|
||||
|
||||
return this.formatResults(results, query, undefined);
|
||||
return {
|
||||
query,
|
||||
results,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
*/
|
||||
|
||||
import { BaseWebSearchProvider } from '../base-provider.js';
|
||||
import { WebSearchError } from '../errors.js';
|
||||
import type {
|
||||
WebSearchResult,
|
||||
WebSearchResultItem,
|
||||
@@ -61,8 +60,7 @@ export class TavilyProvider extends BaseWebSearchProvider {
|
||||
|
||||
if (!response.ok) {
|
||||
const text = await response.text().catch(() => '');
|
||||
throw new WebSearchError(
|
||||
this.name,
|
||||
throw new Error(
|
||||
`API error: ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`,
|
||||
);
|
||||
}
|
||||
@@ -77,6 +75,10 @@ export class TavilyProvider extends BaseWebSearchProvider {
|
||||
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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param content Main content text
|
||||
@@ -32,7 +19,10 @@ export function buildContentWithSources(
|
||||
sources: Array<{ title: string; url: string }>,
|
||||
): string {
|
||||
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