1 | |
2 |
|
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 |
|
10 | type Strale = { |
11 | api_key: string; |
12 | base_url?: string; |
13 | }; |
14 |
|
15 | export async function main( |
16 | strale: Strale, |
17 | task: string, |
18 | inputs: Record<string, unknown>, |
19 | max_price_cents: number = 100, |
20 | dry_run: boolean = false, |
21 | ) { |
22 | const baseUrl = strale.base_url ?? "https://api.strale.io"; |
23 |
|
24 | |
25 | const suggestResponse = await fetch(`${baseUrl}/v1/suggest`, { |
26 | method: "POST", |
27 | headers: { |
28 | "Authorization": `Bearer ${strale.api_key}`, |
29 | "Content-Type": "application/json", |
30 | }, |
31 | body: JSON.stringify({ task, limit: 5 }), |
32 | }); |
33 |
|
34 | if (!suggestResponse.ok) { |
35 | const error = await suggestResponse.json().catch(() => ({ message: suggestResponse.statusText })); |
36 | throw new Error( |
37 | `Strale search error (${suggestResponse.status}): ${(error as any).error?.message ?? (error as any).message ?? "Unknown error"}` |
38 | ); |
39 | } |
40 |
|
41 | const suggestions = await suggestResponse.json() as { |
42 | suggestions: Array<{ |
43 | slug: string; |
44 | name: string; |
45 | description: string; |
46 | category: string; |
47 | price_cents: number; |
48 | quality_score?: number; |
49 | }>; |
50 | }; |
51 |
|
52 | if (!suggestions.suggestions?.length) { |
53 | return { |
54 | status: "no_match", |
55 | task, |
56 | message: "No matching capabilities found for this task.", |
57 | suggestions: [], |
58 | }; |
59 | } |
60 |
|
61 | |
62 | const match = suggestions.suggestions.find((s) => s.price_cents <= max_price_cents); |
63 | if (!match) { |
64 | return { |
65 | status: "over_budget", |
66 | task, |
67 | message: `Best match costs €${(suggestions.suggestions[0].price_cents / 100).toFixed(2)}, exceeds max €${(max_price_cents / 100).toFixed(2)}`, |
68 | suggestions: suggestions.suggestions.map((s) => ({ |
69 | slug: s.slug, |
70 | name: s.name, |
71 | price: `€${(s.price_cents / 100).toFixed(2)}`, |
72 | })), |
73 | }; |
74 | } |
75 |
|
76 | |
77 | const doBody: Record<string, unknown> = { |
78 | capability_slug: match.slug, |
79 | inputs, |
80 | }; |
81 | if (dry_run) { |
82 | doBody.dry_run = true; |
83 | } |
84 |
|
85 | const doResponse = await fetch(`${baseUrl}/v1/do`, { |
86 | method: "POST", |
87 | headers: { |
88 | "Authorization": `Bearer ${strale.api_key}`, |
89 | "Content-Type": "application/json", |
90 | }, |
91 | body: JSON.stringify(doBody), |
92 | }); |
93 |
|
94 | if (!doResponse.ok) { |
95 | const error = await doResponse.json().catch(() => ({ message: doResponse.statusText })); |
96 | throw new Error( |
97 | `Strale execution error (${doResponse.status}): ${(error as any).error?.message ?? (error as any).message ?? "Unknown error"}` |
98 | ); |
99 | } |
100 |
|
101 | const result = await doResponse.json() as { |
102 | transaction_id?: string; |
103 | capability_slug: string; |
104 | status: string; |
105 | output?: Record<string, unknown>; |
106 | provenance?: Record<string, unknown>; |
107 | quality?: Record<string, unknown>; |
108 | cost_cents?: number; |
109 | wallet_balance_cents?: number; |
110 | dry_run?: boolean; |
111 | }; |
112 |
|
113 | return { |
114 | status: "success", |
115 | task, |
116 | matched_capability: { |
117 | slug: match.slug, |
118 | name: match.name, |
119 | description: match.description, |
120 | quality_score: match.quality_score, |
121 | }, |
122 | transaction_id: result.transaction_id, |
123 | output: result.output, |
124 | provenance: result.provenance, |
125 | quality: result.quality, |
126 | cost: result.cost_cents != null ? `€${(result.cost_cents / 100).toFixed(2)}` : undefined, |
127 | wallet_balance_cents: result.wallet_balance_cents, |
128 | dry_run: result.dry_run, |
129 | other_matches: suggestions.suggestions |
130 | .filter((s) => s.slug !== match.slug) |
131 | .slice(0, 3) |
132 | .map((s) => ({ slug: s.slug, name: s.name, price: `€${(s.price_cents / 100).toFixed(2)}` })), |
133 | }; |
134 | } |