import { getClient, extractCursor, extractIdFromUrn, formatPaginatedResponse, formatPaginatedMarkdown, formatEntityMarkdown } from '../client.js';
import { formatError } from '../utils/errors.js';
import { SearchCompaniesInput, SearchTypeaheadInput, FindSimilarCompaniesInput } from '../schemas/inputs.js';
// ============================================================================
// Response Types
// ============================================================================
interface SearchAgentResult {
urn: string;
cursor?: string;
}
interface SearchAgentResponse {
count: number;
page_info?: {
next?: string;
has_next?: boolean;
};
results: SearchAgentResult[];
query_interpretation?: {
semantic?: string;
faceted?: Array<{
field_name: string;
operator: string;
filter_value: unknown;
}>;
};
}
interface TypeaheadResult {
entity_urn: string;
type: string;
text: string;
ranking_score: number;
}
interface TypeaheadResponse {
count: number;
results: TypeaheadResult[];
}
interface SimilarCompaniesResponse {
count: number;
page_info?: {
next?: string;
has_next?: boolean;
};
results: string[];
}
// ============================================================================
// Formatters
// ============================================================================
function formatSearchResultMarkdown(result: SearchAgentResult & { id?: string }, index: number): string {
const id = result.id || extractIdFromUrn(result.urn);
return `${index + 1}. **${result.urn}** (ID: ${id})`;
}
function formatTypeaheadResultMarkdown(result: TypeaheadResult, index: number): string {
const id = extractIdFromUrn(result.entity_urn);
return `${index + 1}. **${result.text}** (ID: ${id}, Score: ${result.ranking_score.toFixed(2)})`;
}
function formatSimilarCompanyMarkdown(urn: string, index: number): string {
const id = extractIdFromUrn(urn);
return `${index + 1}. **${urn}** (ID: ${id})`;
}
// ============================================================================
// Executors
// ============================================================================
/**
* Execute search companies tool
*
* @see GET /search/search_agent
*/
export async function executeSearchCompanies(input: SearchCompaniesInput): Promise<string> {
try {
const client = getClient();
const params: Record<string, string | number | undefined> = {
query: input.query
};
if (input.size !== undefined) {
params.size = input.size;
}
if (input.similarity_threshold !== undefined) {
params.similarity_threshold = input.similarity_threshold;
}
if (input.cursor) {
params.cursor = input.cursor;
}
const response = await client.get<SearchAgentResponse>('/search/search_agent', params);
const nextCursor = extractCursor(response);
// Enrich results with extracted IDs for convenience
const enrichedResults = response.results.map(r => ({
...r,
id: extractIdFromUrn(r.urn)
}));
if (input.response_format === 'markdown') {
const lines: string[] = [];
lines.push(`# Company Search Results`);
lines.push('');
lines.push(`**Query:** "${input.query}"`);
lines.push(`**Total matches:** ${response.count}`);
lines.push('');
if (response.query_interpretation) {
lines.push('## Query Interpretation');
if (response.query_interpretation.semantic) {
lines.push(`**Semantic:** ${response.query_interpretation.semantic}`);
}
if (response.query_interpretation.faceted && response.query_interpretation.faceted.length > 0) {
lines.push('**Filters applied:**');
for (const filter of response.query_interpretation.faceted) {
lines.push(`- ${filter.field_name}: ${JSON.stringify(filter.filter_value)}`);
}
}
lines.push('');
}
lines.push('## Results');
lines.push('');
for (let i = 0; i < enrichedResults.length; i++) {
lines.push(formatSearchResultMarkdown(enrichedResults[i], i));
}
if (nextCursor) {
lines.push('');
lines.push('---');
lines.push(`*More results available. Use cursor: \`${nextCursor}\`*`);
}
return lines.join('\n');
}
const result = {
...formatPaginatedResponse(enrichedResults, nextCursor, response.count, 'companies'),
queryInterpretation: response.query_interpretation
};
return JSON.stringify(result, null, 2);
} catch (error) {
return formatError(error);
}
}
/**
* Execute search typeahead tool
*
* @see GET /search/typeahead
*/
export async function executeSearchTypeahead(input: SearchTypeaheadInput): Promise<string> {
try {
const client = getClient();
const params = {
query: input.query,
search_type: 'COMPANY'
};
const response = await client.get<TypeaheadResponse>('/search/typeahead', params);
// Enrich results with extracted IDs
const enrichedResults = response.results.map(r => ({
...r,
id: extractIdFromUrn(r.entity_urn)
}));
if (input.response_format === 'markdown') {
const lines: string[] = [];
lines.push(`# Typeahead Results: "${input.query}"`);
lines.push('');
lines.push(`**Total matches:** ${response.count}`);
lines.push('');
if (enrichedResults.length === 0) {
lines.push('No companies found matching your query.');
} else {
for (let i = 0; i < enrichedResults.length; i++) {
lines.push(formatTypeaheadResultMarkdown(enrichedResults[i], i));
}
}
return lines.join('\n');
}
return JSON.stringify({
data: enrichedResults,
count: enrichedResults.length,
totalAvailable: response.count,
summary: `Found ${enrichedResults.length} companies matching "${input.query}"`
}, null, 2);
} catch (error) {
return formatError(error);
}
}
/**
* Execute find similar companies tool
*
* @see GET /search/similar_companies/{id}
*/
export async function executeFindSimilarCompanies(input: FindSimilarCompaniesInput): Promise<string> {
try {
const client = getClient();
const companyId = extractIdFromUrn(input.company_id);
const params: Record<string, number | undefined> = {};
if (input.size !== undefined) {
params.size = input.size;
}
const response = await client.get<SimilarCompaniesResponse>(`/search/similar_companies/${companyId}`, params);
// Enrich results with extracted IDs
const enrichedResults = response.results.map(urn => ({
urn,
id: extractIdFromUrn(urn)
}));
if (input.response_format === 'markdown') {
const lines: string[] = [];
lines.push(`# Similar Companies`);
lines.push('');
lines.push(`**Source company ID:** ${companyId}`);
lines.push(`**Found:** ${response.count} similar companies`);
lines.push('');
if (enrichedResults.length === 0) {
lines.push('No similar companies found.');
} else {
for (let i = 0; i < enrichedResults.length; i++) {
lines.push(formatSimilarCompanyMarkdown(enrichedResults[i].urn, i));
}
}
lines.push('');
lines.push('---');
lines.push('*Use harmonic_get_company with the ID to get full company details.*');
return lines.join('\n');
}
return JSON.stringify({
data: enrichedResults,
count: enrichedResults.length,
sourceCompanyId: companyId,
summary: `Found ${enrichedResults.length} companies similar to company ${companyId}`
}, null, 2);
} catch (error) {
return formatError(error);
}
}