BREAKING CHANGE(vercel-ai-sdk): migrate to Vercel AI SDK v6 and introduce provider registry (getModel) returning LanguageModelV3
This commit is contained in:
120
ts_research/index.ts
Normal file
120
ts_research/index.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import * as plugins from './plugins.js';
|
||||
|
||||
export interface IResearchOptions {
|
||||
apiKey: string;
|
||||
query: string;
|
||||
searchDepth?: 'basic' | 'advanced' | 'deep';
|
||||
maxSources?: number;
|
||||
allowedDomains?: string[];
|
||||
blockedDomains?: string[];
|
||||
}
|
||||
|
||||
export interface IResearchResponse {
|
||||
answer: string;
|
||||
sources: Array<{ url: string; title: string; snippet: string }>;
|
||||
searchQueries?: string[];
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export async function research(options: IResearchOptions): Promise<IResearchResponse> {
|
||||
const client = new plugins.Anthropic({ apiKey: options.apiKey });
|
||||
|
||||
const systemMessage = `You are a research assistant with web search capabilities.
|
||||
Provide comprehensive, well-researched answers with citations and sources.
|
||||
When searching the web, be thorough and cite your sources accurately.`;
|
||||
|
||||
// Build web search tool config
|
||||
const webSearchTool: any = {
|
||||
type: 'web_search_20250305',
|
||||
name: 'web_search',
|
||||
};
|
||||
|
||||
if (options.maxSources) {
|
||||
webSearchTool.max_uses = options.maxSources;
|
||||
}
|
||||
if (options.allowedDomains?.length) {
|
||||
webSearchTool.allowed_domains = options.allowedDomains;
|
||||
} else if (options.blockedDomains?.length) {
|
||||
webSearchTool.blocked_domains = options.blockedDomains;
|
||||
}
|
||||
|
||||
const result = await client.messages.create({
|
||||
model: 'claude-sonnet-4-5-20250929',
|
||||
system: systemMessage,
|
||||
messages: [
|
||||
{ role: 'user' as const, content: options.query },
|
||||
],
|
||||
max_tokens: 20000,
|
||||
temperature: 0.7,
|
||||
tools: [webSearchTool],
|
||||
});
|
||||
|
||||
// Extract answer, sources, and search queries
|
||||
let answer = '';
|
||||
const sources: Array<{ url: string; title: string; snippet: string }> = [];
|
||||
const searchQueries: string[] = [];
|
||||
|
||||
for (const block of result.content) {
|
||||
const b: any = block;
|
||||
if ('text' in b) {
|
||||
answer += b.text;
|
||||
|
||||
// Extract citations if present
|
||||
if (b.citations && Array.isArray(b.citations)) {
|
||||
for (const citation of b.citations) {
|
||||
if (citation.type === 'web_search_result_location') {
|
||||
sources.push({
|
||||
title: citation.title || '',
|
||||
url: citation.url || '',
|
||||
snippet: citation.cited_text || '',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (b.type === 'server_tool_use') {
|
||||
if (b.name === 'web_search' && b.input?.query) {
|
||||
searchQueries.push(b.input.query);
|
||||
}
|
||||
} else if (b.type === 'web_search_tool_result') {
|
||||
if (Array.isArray(b.content)) {
|
||||
for (const item of b.content) {
|
||||
if (item.type === 'web_search_result') {
|
||||
if (!sources.some(s => s.url === item.url)) {
|
||||
sources.push({
|
||||
title: item.title || '',
|
||||
url: item.url || '',
|
||||
snippet: '',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: parse markdown links if no citations found
|
||||
if (sources.length === 0) {
|
||||
const urlRegex = /\[([^\]]+)\]\(([^)]+)\)/g;
|
||||
let match: RegExpExecArray | null;
|
||||
while ((match = urlRegex.exec(answer)) !== null) {
|
||||
sources.push({
|
||||
title: match[1],
|
||||
url: match[2],
|
||||
snippet: '',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const usage: any = result.usage;
|
||||
return {
|
||||
answer,
|
||||
sources,
|
||||
searchQueries: searchQueries.length > 0 ? searchQueries : undefined,
|
||||
metadata: {
|
||||
model: 'claude-sonnet-4-5-20250929',
|
||||
searchDepth: options.searchDepth || 'basic',
|
||||
tokensUsed: usage?.output_tokens,
|
||||
webSearchesPerformed: usage?.server_tool_use?.web_search_requests ?? 0,
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user