//native
// Search for a Strale capability and execute the best match.
// Combines /v1/suggest (semantic search) with /v1/do (execution) in one step.
// Useful in flows where you describe what data you need in natural language.
//
// Strale is the data layer for AI agents — every data source independently
// quality-tested, scored, and audit-logged. https://strale.dev
type Strale = {
api_key: string;
base_url?: string;
};
export async function main(
strale: Strale,
task: string,
inputs: Record<string, unknown>,
max_price_cents: number = 100,
dry_run: boolean = false,
) {
const baseUrl = strale.base_url ?? "https://api.strale.io";
// Step 1: Search for matching capabilities
const suggestResponse = await fetch(`${baseUrl}/v1/suggest`, {
method: "POST",
headers: {
"Authorization": `Bearer ${strale.api_key}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ task, limit: 5 }),
});
if (!suggestResponse.ok) {
const error = await suggestResponse.json().catch(() => ({ message: suggestResponse.statusText }));
throw new Error(
`Strale search error (${suggestResponse.status}): ${(error as any).error?.message ?? (error as any).message ?? "Unknown error"}`
);
}
const suggestions = await suggestResponse.json() as {
suggestions: Array<{
slug: string;
name: string;
description: string;
category: string;
price_cents: number;
quality_score?: number;
}>;
};
if (!suggestions.suggestions?.length) {
return {
status: "no_match",
task,
message: "No matching capabilities found for this task.",
suggestions: [],
};
}
// Step 2: Pick best match within price budget
const match = suggestions.suggestions.find((s) => s.price_cents <= max_price_cents);
if (!match) {
return {
status: "over_budget",
task,
message: `Best match costs €${(suggestions.suggestions[0].price_cents / 100).toFixed(2)}, exceeds max €${(max_price_cents / 100).toFixed(2)}`,
suggestions: suggestions.suggestions.map((s) => ({
slug: s.slug,
name: s.name,
price: `€${(s.price_cents / 100).toFixed(2)}`,
})),
};
}
// Step 3: Execute the capability
const doBody: Record<string, unknown> = {
capability_slug: match.slug,
inputs,
};
if (dry_run) {
doBody.dry_run = true;
}
const doResponse = await fetch(`${baseUrl}/v1/do`, {
method: "POST",
headers: {
"Authorization": `Bearer ${strale.api_key}`,
"Content-Type": "application/json",
},
body: JSON.stringify(doBody),
});
if (!doResponse.ok) {
const error = await doResponse.json().catch(() => ({ message: doResponse.statusText }));
throw new Error(
`Strale execution error (${doResponse.status}): ${(error as any).error?.message ?? (error as any).message ?? "Unknown error"}`
);
}
const result = await doResponse.json() as {
transaction_id?: string;
capability_slug: string;
status: string;
output?: Record<string, unknown>;
provenance?: Record<string, unknown>;
quality?: Record<string, unknown>;
cost_cents?: number;
wallet_balance_cents?: number;
dry_run?: boolean;
};
return {
status: "success",
task,
matched_capability: {
slug: match.slug,
name: match.name,
description: match.description,
quality_score: match.quality_score,
},
transaction_id: result.transaction_id,
output: result.output,
provenance: result.provenance,
quality: result.quality,
cost: result.cost_cents != null ? `€${(result.cost_cents / 100).toFixed(2)}` : undefined,
wallet_balance_cents: result.wallet_balance_cents,
dry_run: result.dry_run,
other_matches: suggestions.suggestions
.filter((s) => s.slug !== match.slug)
.slice(0, 3)
.map((s) => ({ slug: s.slug, name: s.name, price: `€${(s.price_cents / 100).toFixed(2)}` })),
};
}Submitted by hugo989 7 days ago