@ottocode/ai-sdk 0.1.3 → 0.1.5

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/src/setu.ts CHANGED
@@ -1,5 +1,14 @@
1
- import type { SetuConfig, ProviderId, ProviderApiFormat, FetchFunction, BalanceResponse, WalletUsdcBalance } from './types.ts';
2
- import { createWalletContext, getPublicKeyFromPrivate } from './auth.ts';
1
+ import type {
2
+ SetuConfig,
3
+ ProviderId,
4
+ ProviderApiFormat,
5
+ FetchFunction,
6
+ BalanceResponse,
7
+ WalletUsdcBalance,
8
+ SetuAuth,
9
+ } from './types.ts';
10
+ import { createWalletContext } from './auth.ts';
11
+ import type { WalletContext } from './auth.ts';
3
12
  import { createSetuFetch } from './fetch.ts';
4
13
  import { ProviderRegistry } from './providers/registry.ts';
5
14
  import { createModel } from './providers/factory.ts';
@@ -8,81 +17,121 @@ import { fetchBalance, fetchWalletUsdcBalance } from './balance.ts';
8
17
  const DEFAULT_BASE_URL = 'https://api.setu.ottocode.io';
9
18
 
10
19
  function trimTrailingSlash(url: string) {
11
- return url.endsWith('/') ? url.slice(0, -1) : url;
20
+ return url.endsWith('/') ? url.slice(0, -1) : url;
12
21
  }
13
22
 
14
23
  export interface SetuProvider {
15
- model(modelId: string): ReturnType<typeof createModel>;
24
+ model(modelId: string): ReturnType<typeof createModel>;
16
25
  }
17
26
 
18
27
  export interface SetuInstance {
19
- model(modelId: string): ReturnType<typeof createModel>;
20
- provider(providerId: ProviderId, apiFormat?: ProviderApiFormat): SetuProvider;
21
- fetch(): FetchFunction;
22
- balance(): Promise<BalanceResponse | null>;
23
- walletBalance(network?: 'mainnet' | 'devnet'): Promise<WalletUsdcBalance | null>;
24
- walletAddress: string | null;
25
- registry: ProviderRegistry;
28
+ model(modelId: string): ReturnType<typeof createModel>;
29
+ provider(providerId: ProviderId, apiFormat?: ProviderApiFormat): SetuProvider;
30
+ fetch(): FetchFunction;
31
+ balance(): Promise<BalanceResponse | null>;
32
+ walletBalance(
33
+ network?: 'mainnet' | 'devnet',
34
+ ): Promise<WalletUsdcBalance | null>;
35
+ walletAddress: string | null;
36
+ registry: ProviderRegistry;
37
+ }
38
+
39
+ function resolveAuth(auth: SetuAuth): {
40
+ auth: SetuAuth;
41
+ wallet: WalletContext;
42
+ } {
43
+ if (auth.signer) {
44
+ return { auth, wallet: createWalletContext(auth) };
45
+ }
46
+
47
+ const privateKey = auth.privateKey || process.env.SETU_PRIVATE_KEY;
48
+ if (!privateKey) {
49
+ throw new Error(
50
+ 'Setu: either privateKey (or SETU_PRIVATE_KEY env) or signer is required.',
51
+ );
52
+ }
53
+ const resolvedAuth = { ...auth, privateKey };
54
+ return { auth: resolvedAuth, wallet: createWalletContext(resolvedAuth) };
26
55
  }
27
56
 
28
57
  export function createSetu(config: SetuConfig): SetuInstance {
29
- const baseURL = trimTrailingSlash(config.baseURL ?? DEFAULT_BASE_URL);
30
- const wallet = createWalletContext(config.auth);
31
- const registry = new ProviderRegistry(config.providers, config.modelMap);
32
-
33
- const setuFetch = createSetuFetch({
34
- wallet,
35
- baseURL,
36
- rpcURL: config.rpcURL,
37
- callbacks: config.callbacks,
38
- cache: config.cache,
39
- payment: config.payment,
40
- });
41
-
42
- const modelBaseURL = `${baseURL}/v1`;
43
-
44
- return {
45
- model(modelId: string) {
46
- const resolved = registry.resolve(modelId);
47
- if (!resolved) {
48
- throw new Error(
49
- `Setu: unknown model "${modelId}". Register it via providers or modelMap config.`,
50
- );
51
- }
52
- return createModel(
53
- modelId,
54
- resolved.apiFormat,
55
- resolved.providerId,
56
- modelBaseURL,
57
- setuFetch,
58
- config.middleware,
59
- );
60
- },
61
-
62
- provider(providerId: ProviderId, apiFormat?: ProviderApiFormat): SetuProvider {
63
- return {
64
- model(modelId: string) {
65
- const resolved = registry.resolve(modelId);
66
- const format = apiFormat ?? resolved?.apiFormat ?? 'openai-chat';
67
- return createModel(modelId, format, providerId, modelBaseURL, setuFetch, config.middleware);
68
- },
69
- };
70
- },
71
-
72
- fetch(): FetchFunction {
73
- return setuFetch;
74
- },
75
-
76
- async balance() {
77
- return fetchBalance(config.auth, baseURL);
78
- },
79
-
80
- async walletBalance(network?: 'mainnet' | 'devnet') {
81
- return fetchWalletUsdcBalance(config.auth, network);
82
- },
83
-
84
- walletAddress: getPublicKeyFromPrivate(config.auth.privateKey),
85
-
86
- registry,
87
- };
58
+ const baseURL = trimTrailingSlash(config.baseURL ?? DEFAULT_BASE_URL);
59
+ const { auth: resolvedAuth, wallet } = resolveAuth(config.auth);
60
+ const registry = new ProviderRegistry(config.providers, config.modelMap);
61
+
62
+ const setuFetch = createSetuFetch({
63
+ wallet,
64
+ baseURL,
65
+ rpcURL: config.rpcURL,
66
+ callbacks: config.callbacks,
67
+ cache: config.cache,
68
+ payment: config.payment,
69
+ });
70
+
71
+ const modelBaseURL = `${baseURL}/v1`;
72
+
73
+ return {
74
+ model(modelId: string) {
75
+ const resolved = registry.resolve(modelId);
76
+ if (!resolved) {
77
+ throw new Error(
78
+ `Setu: unknown model "${modelId}". Register it via providers or modelMap config.`,
79
+ );
80
+ }
81
+ return createModel(
82
+ modelId,
83
+ resolved.apiFormat,
84
+ resolved.providerId,
85
+ modelBaseURL,
86
+ setuFetch,
87
+ config.middleware,
88
+ );
89
+ },
90
+
91
+ provider(
92
+ providerId: ProviderId,
93
+ apiFormat?: ProviderApiFormat,
94
+ ): SetuProvider {
95
+ return {
96
+ model(modelId: string) {
97
+ const resolved = registry.resolve(modelId);
98
+ const format = apiFormat ?? resolved?.apiFormat ?? 'openai-chat';
99
+ return createModel(
100
+ modelId,
101
+ format,
102
+ providerId,
103
+ modelBaseURL,
104
+ setuFetch,
105
+ config.middleware,
106
+ );
107
+ },
108
+ };
109
+ },
110
+
111
+ fetch(): FetchFunction {
112
+ return setuFetch;
113
+ },
114
+
115
+ async balance() {
116
+ return fetchBalance(wallet, baseURL);
117
+ },
118
+
119
+ async walletBalance(network?: 'mainnet' | 'devnet') {
120
+ const walletAddr = wallet.walletAddress;
121
+ if (!resolvedAuth.privateKey && !walletAddr) {
122
+ return null;
123
+ }
124
+ if (resolvedAuth.privateKey) {
125
+ return fetchWalletUsdcBalance(
126
+ resolvedAuth as Required<Pick<SetuAuth, 'privateKey'>>,
127
+ network,
128
+ );
129
+ }
130
+ return fetchWalletUsdcBalance({ walletAddress: walletAddr }, network);
131
+ },
132
+
133
+ walletAddress: wallet.walletAddress,
134
+
135
+ registry,
136
+ };
88
137
  }
package/src/types.ts CHANGED
@@ -1,50 +1,70 @@
1
1
  import type { LanguageModelV3Middleware } from '@ai-sdk/provider';
2
+ import type { TransactionSigner } from '@solana/kit';
2
3
 
3
4
  export type ProviderId =
4
- | 'openai'
5
- | 'anthropic'
6
- | 'google'
7
- | 'moonshot'
8
- | 'zai'
9
- | 'minimax'
10
- | (string & {});
5
+ | 'openai'
6
+ | 'anthropic'
7
+ | 'google'
8
+ | 'moonshot'
9
+ | 'zai'
10
+ | 'minimax'
11
+ | (string & {});
12
+
13
+ export type ProviderApiFormat =
14
+ | 'openai-responses'
15
+ | 'anthropic-messages'
16
+ | 'openai-chat'
17
+ | 'google-native';
18
+
19
+ export type FetchFunction = (
20
+ input: string | URL | Request,
21
+ init?: RequestInit,
22
+ ) => Promise<Response>;
11
23
 
12
- export type ProviderApiFormat = 'openai-responses' | 'anthropic-messages' | 'openai-chat' | 'google-native';
24
+ export interface ProviderConfig {
25
+ id: ProviderId;
26
+ apiFormat: ProviderApiFormat;
27
+ models?: string[];
28
+ modelPrefix?: string;
29
+ }
13
30
 
14
- export type FetchFunction = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
31
+ export interface LegacySigner {
32
+ publicKey: { toBase58(): string };
33
+ secretKey: Uint8Array;
34
+ }
15
35
 
16
- export interface ProviderConfig {
17
- id: ProviderId;
18
- apiFormat: ProviderApiFormat;
19
- models?: string[];
20
- modelPrefix?: string;
36
+ export interface ExternalSigner {
37
+ walletAddress: string;
38
+ signNonce: (nonce: string) => Promise<string> | string;
39
+ signTransaction?: TransactionSigner | LegacySigner;
21
40
  }
22
41
 
23
42
  export interface SetuAuth {
24
- privateKey: string;
43
+ privateKey?: string;
44
+ signer?: ExternalSigner;
25
45
  }
26
46
 
27
47
  export interface BalanceUpdate {
28
- costUsd: number;
29
- balanceRemaining: number;
30
- inputTokens?: number;
31
- outputTokens?: number;
48
+ costUsd: number;
49
+ balanceRemaining: number;
50
+ inputTokens?: number;
51
+ outputTokens?: number;
32
52
  }
33
53
 
34
54
  export interface PaymentCallbacks {
35
- onPaymentRequired?: (amountUsd: number, currentBalance?: number) => void;
36
- onPaymentSigning?: () => void;
37
- onPaymentComplete?: (data: {
38
- amountUsd: number;
39
- newBalance: number;
40
- transactionId?: string;
41
- }) => void;
42
- onPaymentError?: (error: string) => void;
43
- onPaymentApproval?: (info: {
44
- amountUsd: number;
45
- currentBalance: number;
46
- }) => Promise<'crypto' | 'fiat' | 'cancel'>;
47
- onBalanceUpdate?: (update: BalanceUpdate) => void;
55
+ onPaymentRequired?: (amountUsd: number, currentBalance?: number) => void;
56
+ onPaymentSigning?: () => void;
57
+ onPaymentComplete?: (data: {
58
+ amountUsd: number;
59
+ newBalance: number;
60
+ transactionId?: string;
61
+ }) => void;
62
+ onPaymentError?: (error: string) => void;
63
+ onPaymentApproval?: (info: {
64
+ amountUsd: number;
65
+ currentBalance: number;
66
+ }) => Promise<'crypto' | 'fiat' | 'cancel'>;
67
+ onBalanceUpdate?: (update: BalanceUpdate) => void;
48
68
  }
49
69
 
50
70
  export type AnthropicCacheStrategy = 'auto' | 'manual' | 'custom' | false;
@@ -52,71 +72,71 @@ export type AnthropicCacheStrategy = 'auto' | 'manual' | 'custom' | false;
52
72
  export type AnthropicCachePlacement = 'first' | 'last' | 'all';
53
73
 
54
74
  export interface AnthropicCacheConfig {
55
- strategy?: AnthropicCacheStrategy;
56
- systemBreakpoints?: number;
57
- messageBreakpoints?: number;
58
- systemPlacement?: AnthropicCachePlacement;
59
- messagePlacement?: AnthropicCachePlacement;
60
- cacheType?: 'ephemeral';
61
- transform?: (body: Record<string, unknown>) => Record<string, unknown>;
75
+ strategy?: AnthropicCacheStrategy;
76
+ systemBreakpoints?: number;
77
+ messageBreakpoints?: number;
78
+ systemPlacement?: AnthropicCachePlacement;
79
+ messagePlacement?: AnthropicCachePlacement;
80
+ cacheType?: 'ephemeral';
81
+ transform?: (body: Record<string, unknown>) => Record<string, unknown>;
62
82
  }
63
83
 
64
84
  export interface CacheOptions {
65
- promptCacheKey?: string;
66
- promptCacheRetention?: 'in_memory' | '24h';
67
- anthropicCaching?: boolean | AnthropicCacheConfig;
85
+ promptCacheKey?: string;
86
+ promptCacheRetention?: 'in_memory' | '24h';
87
+ anthropicCaching?: boolean | AnthropicCacheConfig;
68
88
  }
69
89
 
70
90
  export interface PaymentOptions {
71
- topupApprovalMode?: 'auto' | 'approval';
72
- autoPayThresholdUsd?: number;
73
- maxRequestAttempts?: number;
74
- maxPaymentAttempts?: number;
91
+ topupApprovalMode?: 'auto' | 'approval';
92
+ autoPayThresholdUsd?: number;
93
+ maxRequestAttempts?: number;
94
+ maxPaymentAttempts?: number;
75
95
  }
76
96
 
77
97
  export interface SetuConfig {
78
- auth: SetuAuth;
79
- baseURL?: string;
80
- rpcURL?: string;
81
- providers?: ProviderConfig[];
82
- modelMap?: Record<string, ProviderId>;
83
- callbacks?: PaymentCallbacks;
84
- cache?: CacheOptions;
85
- payment?: PaymentOptions;
86
- middleware?: LanguageModelV3Middleware | LanguageModelV3Middleware[];
98
+ auth: SetuAuth;
99
+ baseURL?: string;
100
+ rpcURL?: string;
101
+ providers?: ProviderConfig[];
102
+ modelMap?: Record<string, ProviderId>;
103
+ callbacks?: PaymentCallbacks;
104
+ cache?: CacheOptions;
105
+ payment?: PaymentOptions;
106
+ middleware?: LanguageModelV3Middleware | LanguageModelV3Middleware[];
87
107
  }
88
108
 
89
109
  export interface ExactPaymentRequirement {
90
- scheme: 'exact';
91
- network: string;
92
- maxAmountRequired: string;
93
- asset: string;
94
- payTo: string;
95
- description?: string;
96
- resource?: string;
97
- extra?: Record<string, unknown>;
98
- maxTimeoutSeconds?: number;
110
+ scheme: 'exact';
111
+ network: string;
112
+ maxAmountRequired: string;
113
+ asset: string;
114
+ payTo: string;
115
+ description?: string;
116
+ resource?: string;
117
+ extra?: Record<string, unknown>;
118
+ maxTimeoutSeconds?: number;
99
119
  }
100
120
 
101
121
  export interface PaymentPayload {
102
- x402Version: 1;
103
- scheme: 'exact';
104
- network: string;
105
- payload: { transaction: string };
122
+ x402Version: 1;
123
+ scheme: 'exact';
124
+ network: string;
125
+ payload: { transaction: string };
106
126
  }
107
127
 
108
128
  export interface BalanceResponse {
109
- walletAddress: string;
110
- balance: number;
111
- totalSpent: number;
112
- totalTopups: number;
113
- requestCount: number;
114
- createdAt?: string;
115
- lastRequest?: string;
129
+ walletAddress: string;
130
+ balance: number;
131
+ totalSpent: number;
132
+ totalTopups: number;
133
+ requestCount: number;
134
+ createdAt?: string;
135
+ lastRequest?: string;
116
136
  }
117
137
 
118
138
  export interface WalletUsdcBalance {
119
- walletAddress: string;
120
- usdcBalance: number;
121
- network: 'mainnet' | 'devnet';
139
+ walletAddress: string;
140
+ usdcBalance: number;
141
+ network: 'mainnet' | 'devnet';
122
142
  }
package/src/wallet.ts CHANGED
@@ -2,33 +2,33 @@ import { Keypair } from '@solana/web3.js';
2
2
  import bs58 from 'bs58';
3
3
 
4
4
  export interface WalletInfo {
5
- publicKey: string;
6
- privateKey: string;
5
+ publicKey: string;
6
+ privateKey: string;
7
7
  }
8
8
 
9
9
  export function generateWallet(): WalletInfo {
10
- const keypair = Keypair.generate();
11
- return {
12
- privateKey: bs58.encode(keypair.secretKey),
13
- publicKey: keypair.publicKey.toBase58(),
14
- };
10
+ const keypair = Keypair.generate();
11
+ return {
12
+ privateKey: bs58.encode(keypair.secretKey),
13
+ publicKey: keypair.publicKey.toBase58(),
14
+ };
15
15
  }
16
16
 
17
17
  export function importWallet(privateKey: string): WalletInfo {
18
- const privateKeyBytes = bs58.decode(privateKey);
19
- const keypair = Keypair.fromSecretKey(privateKeyBytes);
20
- return {
21
- privateKey,
22
- publicKey: keypair.publicKey.toBase58(),
23
- };
18
+ const privateKeyBytes = bs58.decode(privateKey);
19
+ const keypair = Keypair.fromSecretKey(privateKeyBytes);
20
+ return {
21
+ privateKey,
22
+ publicKey: keypair.publicKey.toBase58(),
23
+ };
24
24
  }
25
25
 
26
26
  export function isValidPrivateKey(privateKey: string): boolean {
27
- try {
28
- const bytes = bs58.decode(privateKey);
29
- Keypair.fromSecretKey(bytes);
30
- return true;
31
- } catch {
32
- return false;
33
- }
27
+ try {
28
+ const bytes = bs58.decode(privateKey);
29
+ Keypair.fromSecretKey(bytes);
30
+ return true;
31
+ } catch {
32
+ return false;
33
+ }
34
34
  }