@ottocode/sdk 0.1.198 → 0.1.200
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -30,6 +30,12 @@ const isAllowedGoogleModel = (id: string): boolean => {
|
|
|
30
30
|
return false;
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
+
const isAllowedZaiModel = (id: string): boolean => {
|
|
34
|
+
if (id.startsWith('glm-4.7')) return true;
|
|
35
|
+
if (id.startsWith('glm-5')) return true;
|
|
36
|
+
return false;
|
|
37
|
+
};
|
|
38
|
+
|
|
33
39
|
const SETU_SOURCES: Array<{
|
|
34
40
|
id: ProviderId;
|
|
35
41
|
npm: string;
|
|
@@ -55,6 +61,11 @@ const SETU_SOURCES: Array<{
|
|
|
55
61
|
npm: '@ai-sdk/google',
|
|
56
62
|
family: 'google',
|
|
57
63
|
},
|
|
64
|
+
{
|
|
65
|
+
id: 'zai',
|
|
66
|
+
npm: '@ai-sdk/openai-compatible',
|
|
67
|
+
family: 'openai-compatible',
|
|
68
|
+
},
|
|
58
69
|
];
|
|
59
70
|
|
|
60
71
|
function cloneModel(model: ModelInfo): ModelInfo {
|
|
@@ -83,6 +94,7 @@ function buildSetuEntry(base: CatalogMap): ProviderCatalogEntry | null {
|
|
|
83
94
|
if (id === 'openai') return isAllowedOpenAIModel(model.id);
|
|
84
95
|
if (id === 'anthropic') return isAllowedAnthropicModel(model.id);
|
|
85
96
|
if (id === 'google') return isAllowedGoogleModel(model.id);
|
|
97
|
+
if (id === 'zai') return isAllowedZaiModel(model.id);
|
|
86
98
|
return true;
|
|
87
99
|
});
|
|
88
100
|
return sourceModels.map((model) => {
|
|
@@ -44,6 +44,13 @@ const DEFAULT_RPC_URL = 'https://api.mainnet-beta.solana.com';
|
|
|
44
44
|
const DEFAULT_MAX_ATTEMPTS = 3;
|
|
45
45
|
const DEFAULT_MAX_PAYMENT_ATTEMPTS = 20;
|
|
46
46
|
|
|
47
|
+
export type SetuBalanceUpdate = {
|
|
48
|
+
costUsd: number;
|
|
49
|
+
balanceRemaining: number;
|
|
50
|
+
inputTokens?: number;
|
|
51
|
+
outputTokens?: number;
|
|
52
|
+
};
|
|
53
|
+
|
|
47
54
|
export type SetuPaymentCallbacks = {
|
|
48
55
|
onPaymentRequired?: (amountUsd: number, currentBalance?: number) => void;
|
|
49
56
|
onPaymentSigning?: () => void;
|
|
@@ -57,6 +64,7 @@ export type SetuPaymentCallbacks = {
|
|
|
57
64
|
amountUsd: number;
|
|
58
65
|
currentBalance: number;
|
|
59
66
|
}) => Promise<'crypto' | 'fiat' | 'cancel'>;
|
|
67
|
+
onBalanceUpdate?: (update: SetuBalanceUpdate) => void;
|
|
60
68
|
};
|
|
61
69
|
|
|
62
70
|
export type SetuProviderOptions = {
|
|
@@ -197,7 +205,7 @@ export function createSetuFetch(
|
|
|
197
205
|
const response = await baseFetch(input, { ...init, body, headers });
|
|
198
206
|
|
|
199
207
|
if (response.status !== 402) {
|
|
200
|
-
return response;
|
|
208
|
+
return wrapResponseWithBalanceSniffing(response, callbacks);
|
|
201
209
|
}
|
|
202
210
|
|
|
203
211
|
const payload = await response.json().catch(() => ({}));
|
|
@@ -266,6 +274,70 @@ export function createSetuFetch(
|
|
|
266
274
|
};
|
|
267
275
|
}
|
|
268
276
|
|
|
277
|
+
function tryParseSetuComment(
|
|
278
|
+
line: string,
|
|
279
|
+
onBalanceUpdate: (update: SetuBalanceUpdate) => void,
|
|
280
|
+
) {
|
|
281
|
+
const trimmed = line.replace(/\r$/, '');
|
|
282
|
+
if (!trimmed.startsWith(': setu ')) return;
|
|
283
|
+
try {
|
|
284
|
+
const data = JSON.parse(trimmed.slice(7));
|
|
285
|
+
onBalanceUpdate({
|
|
286
|
+
costUsd: parseFloat(data.cost_usd ?? '0'),
|
|
287
|
+
balanceRemaining: parseFloat(data.balance_remaining ?? '0'),
|
|
288
|
+
inputTokens: data.input_tokens ? Number(data.input_tokens) : undefined,
|
|
289
|
+
outputTokens: data.output_tokens ? Number(data.output_tokens) : undefined,
|
|
290
|
+
});
|
|
291
|
+
} catch {}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function wrapResponseWithBalanceSniffing(
|
|
295
|
+
response: Response,
|
|
296
|
+
callbacks: SetuPaymentCallbacks,
|
|
297
|
+
): Response {
|
|
298
|
+
if (!callbacks.onBalanceUpdate) return response;
|
|
299
|
+
|
|
300
|
+
const balanceHeader = response.headers.get('x-balance-remaining');
|
|
301
|
+
const costHeader = response.headers.get('x-cost-usd');
|
|
302
|
+
if (balanceHeader && costHeader) {
|
|
303
|
+
callbacks.onBalanceUpdate({
|
|
304
|
+
costUsd: parseFloat(costHeader),
|
|
305
|
+
balanceRemaining: parseFloat(balanceHeader),
|
|
306
|
+
});
|
|
307
|
+
return response;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (!response.body) return response;
|
|
311
|
+
|
|
312
|
+
const onBalanceUpdate = callbacks.onBalanceUpdate;
|
|
313
|
+
let partial = '';
|
|
314
|
+
const decoder = new TextDecoder();
|
|
315
|
+
const transform = new TransformStream<Uint8Array, Uint8Array>({
|
|
316
|
+
transform(chunk, controller) {
|
|
317
|
+
controller.enqueue(chunk);
|
|
318
|
+
partial += decoder.decode(chunk, { stream: true });
|
|
319
|
+
let nlIndex = partial.indexOf('\n');
|
|
320
|
+
while (nlIndex !== -1) {
|
|
321
|
+
const line = partial.slice(0, nlIndex);
|
|
322
|
+
partial = partial.slice(nlIndex + 1);
|
|
323
|
+
tryParseSetuComment(line, onBalanceUpdate);
|
|
324
|
+
nlIndex = partial.indexOf('\n');
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
flush() {
|
|
328
|
+
if (partial.trim()) {
|
|
329
|
+
tryParseSetuComment(partial, onBalanceUpdate);
|
|
330
|
+
}
|
|
331
|
+
},
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
return new Response(response.body.pipeThrough(transform), {
|
|
335
|
+
status: response.status,
|
|
336
|
+
statusText: response.statusText,
|
|
337
|
+
headers: response.headers,
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
|
|
269
341
|
/**
|
|
270
342
|
* Create a Setu-backed AI model.
|
|
271
343
|
*
|