@ottocode/ai-sdk 0.1.4 → 0.1.6
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 +2 -2
- package/src/auth.ts +62 -27
- package/src/balance.ts +104 -90
- package/src/cache.ts +154 -132
- package/src/catalog.ts +1242 -1487
- package/src/fetch.ts +275 -254
- package/src/index.ts +18 -17
- package/src/payment.ts +199 -136
- package/src/providers/factory.ts +53 -53
- package/src/providers/registry.ts +59 -94
- package/src/setu.ts +119 -75
- package/src/types.ts +93 -79
- package/src/wallet.ts +20 -20
package/src/payment.ts
CHANGED
|
@@ -1,171 +1,234 @@
|
|
|
1
|
-
import { Buffer } from 'node:buffer';
|
|
2
1
|
import bs58 from 'bs58';
|
|
3
2
|
import { createPaymentHeader } from 'x402/client';
|
|
4
3
|
import { svm } from 'x402/shared';
|
|
5
4
|
import type { PaymentRequirements } from 'x402/types';
|
|
6
5
|
import type { WalletContext } from './auth.ts';
|
|
7
6
|
import type {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
ExactPaymentRequirement,
|
|
8
|
+
PaymentPayload,
|
|
9
|
+
PaymentCallbacks,
|
|
11
10
|
} from './types.ts';
|
|
12
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
address,
|
|
13
|
+
getTransactionEncoder,
|
|
14
|
+
getTransactionDecoder,
|
|
15
|
+
type Transaction,
|
|
16
|
+
type TransactionWithLifetime,
|
|
17
|
+
type TransactionWithinSizeLimit,
|
|
18
|
+
} from '@solana/kit';
|
|
13
19
|
|
|
14
20
|
function simplifyPaymentError(errMsg: string): string {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
21
|
+
const lower = errMsg.toLowerCase();
|
|
22
|
+
if (
|
|
23
|
+
lower.includes('insufficient') ||
|
|
24
|
+
lower.includes('not enough') ||
|
|
25
|
+
lower.includes('balance')
|
|
26
|
+
)
|
|
27
|
+
return 'Insufficient USDC balance';
|
|
28
|
+
if (lower.includes('simulation') || lower.includes('compute unit'))
|
|
29
|
+
return 'Transaction simulation failed';
|
|
30
|
+
if (lower.includes('blockhash') || lower.includes('expired'))
|
|
31
|
+
return 'Transaction expired, please retry';
|
|
32
|
+
if (lower.includes('timeout') || lower.includes('timed out'))
|
|
33
|
+
return 'Transaction timed out';
|
|
34
|
+
if (lower.includes('rejected') || lower.includes('cancelled'))
|
|
35
|
+
return 'Transaction rejected';
|
|
36
|
+
if (lower.includes('network') || lower.includes('connection'))
|
|
37
|
+
return 'Network error';
|
|
38
|
+
const short = (errMsg.split('.')[0] ?? errMsg).slice(0, 80);
|
|
39
|
+
return short.length < errMsg.length ? `${short}...` : errMsg;
|
|
30
40
|
}
|
|
31
41
|
|
|
32
42
|
export function pickPaymentRequirement(
|
|
33
|
-
|
|
43
|
+
payload: unknown,
|
|
34
44
|
): ExactPaymentRequirement | null {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
const acceptsValue =
|
|
46
|
+
typeof payload === 'object' && payload !== null
|
|
47
|
+
? (payload as { accepts?: unknown }).accepts
|
|
48
|
+
: undefined;
|
|
49
|
+
const accepts = Array.isArray(acceptsValue)
|
|
50
|
+
? (acceptsValue as ExactPaymentRequirement[])
|
|
51
|
+
: [];
|
|
52
|
+
return accepts.find((opt) => opt && opt.scheme === 'exact') ?? null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function wrapCallbackAsSigner(
|
|
56
|
+
walletAddress: string,
|
|
57
|
+
callback: (transaction: Uint8Array) => Promise<Uint8Array>,
|
|
58
|
+
) {
|
|
59
|
+
const encoder = getTransactionEncoder();
|
|
60
|
+
const decoder = getTransactionDecoder();
|
|
61
|
+
return {
|
|
62
|
+
address: address(walletAddress),
|
|
63
|
+
modifyAndSignTransactions: async (
|
|
64
|
+
transactions: readonly (
|
|
65
|
+
| Transaction
|
|
66
|
+
| (Transaction & TransactionWithLifetime)
|
|
67
|
+
)[],
|
|
68
|
+
): Promise<
|
|
69
|
+
readonly (Transaction &
|
|
70
|
+
TransactionWithinSizeLimit &
|
|
71
|
+
TransactionWithLifetime)[]
|
|
72
|
+
> => {
|
|
73
|
+
const results = [];
|
|
74
|
+
for (const tx of transactions) {
|
|
75
|
+
const bytes = new Uint8Array(encoder.encode(tx));
|
|
76
|
+
const signedBytes = await callback(bytes);
|
|
77
|
+
const signed = decoder.decode(signedBytes);
|
|
78
|
+
results.push(
|
|
79
|
+
signed as Transaction &
|
|
80
|
+
TransactionWithinSizeLimit &
|
|
81
|
+
TransactionWithLifetime,
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
return results;
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function resolvePaymentSigner(wallet: WalletContext) {
|
|
90
|
+
if (wallet.signTransaction) {
|
|
91
|
+
return wrapCallbackAsSigner(wallet.walletAddress, wallet.signTransaction);
|
|
92
|
+
}
|
|
93
|
+
if (wallet.keypair) {
|
|
94
|
+
const privateKeyBase58 = bs58.encode(wallet.keypair.secretKey);
|
|
95
|
+
return svm.createSignerFromBase58(privateKeyBase58);
|
|
96
|
+
}
|
|
97
|
+
throw new Error(
|
|
98
|
+
'Setu: payments require either a privateKey or signer.signTransaction.',
|
|
99
|
+
);
|
|
43
100
|
}
|
|
44
101
|
|
|
45
102
|
export async function createPaymentPayload(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
103
|
+
requirement: ExactPaymentRequirement,
|
|
104
|
+
wallet: WalletContext,
|
|
105
|
+
rpcURL: string,
|
|
49
106
|
): Promise<PaymentPayload> {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
) as { payload: { transaction: string } };
|
|
107
|
+
const signer = await resolvePaymentSigner(wallet);
|
|
108
|
+
const header = await createPaymentHeader(
|
|
109
|
+
signer,
|
|
110
|
+
1,
|
|
111
|
+
requirement as PaymentRequirements,
|
|
112
|
+
{ svmConfig: { rpcUrl: rpcURL } },
|
|
113
|
+
);
|
|
114
|
+
const decoded = JSON.parse(atob(header)) as {
|
|
115
|
+
payload: { transaction: string };
|
|
116
|
+
};
|
|
61
117
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
118
|
+
return {
|
|
119
|
+
x402Version: 1,
|
|
120
|
+
scheme: 'exact',
|
|
121
|
+
network: requirement.network,
|
|
122
|
+
payload: { transaction: decoded.payload.transaction },
|
|
123
|
+
};
|
|
68
124
|
}
|
|
69
125
|
|
|
70
126
|
interface PaymentResponse {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
127
|
+
amount_usd?: number | string;
|
|
128
|
+
new_balance?: number | string;
|
|
129
|
+
amount?: number;
|
|
130
|
+
balance?: number;
|
|
131
|
+
transaction?: string;
|
|
76
132
|
}
|
|
77
133
|
|
|
78
134
|
export async function processSinglePayment(args: {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
135
|
+
requirement: ExactPaymentRequirement;
|
|
136
|
+
wallet: WalletContext;
|
|
137
|
+
rpcURL: string;
|
|
138
|
+
baseURL: string;
|
|
139
|
+
baseFetch: typeof fetch;
|
|
140
|
+
callbacks: PaymentCallbacks;
|
|
85
141
|
}): Promise<{ attempts: number; balance?: number | string }> {
|
|
86
|
-
|
|
142
|
+
args.callbacks.onPaymentSigning?.();
|
|
87
143
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
144
|
+
let paymentPayload: PaymentPayload;
|
|
145
|
+
try {
|
|
146
|
+
paymentPayload = await createPaymentPayload(
|
|
147
|
+
args.requirement,
|
|
148
|
+
args.wallet,
|
|
149
|
+
args.rpcURL,
|
|
150
|
+
);
|
|
151
|
+
} catch (err) {
|
|
152
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
153
|
+
const userMsg = `Payment failed: ${simplifyPaymentError(errMsg)}`;
|
|
154
|
+
args.callbacks.onPaymentError?.(userMsg);
|
|
155
|
+
throw new Error(`Setu: ${userMsg}`);
|
|
156
|
+
}
|
|
101
157
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
158
|
+
const walletHeaders = await args.wallet.buildHeaders();
|
|
159
|
+
const response = await args.baseFetch(`${args.baseURL}/v1/topup`, {
|
|
160
|
+
method: 'POST',
|
|
161
|
+
headers: { 'Content-Type': 'application/json', ...walletHeaders },
|
|
162
|
+
body: JSON.stringify({
|
|
163
|
+
paymentPayload,
|
|
164
|
+
paymentRequirement: args.requirement,
|
|
165
|
+
}),
|
|
166
|
+
});
|
|
111
167
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
168
|
+
const rawBody = await response.text().catch(() => '');
|
|
169
|
+
if (!response.ok) {
|
|
170
|
+
if (
|
|
171
|
+
response.status === 400 &&
|
|
172
|
+
rawBody.toLowerCase().includes('already processed')
|
|
173
|
+
) {
|
|
174
|
+
return { attempts: 1 };
|
|
175
|
+
}
|
|
176
|
+
args.callbacks.onPaymentError?.(`Topup failed: ${response.status}`);
|
|
177
|
+
throw new Error(`Setu topup failed (${response.status}): ${rawBody}`);
|
|
178
|
+
}
|
|
120
179
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
180
|
+
let parsed: PaymentResponse | undefined;
|
|
181
|
+
try {
|
|
182
|
+
parsed = rawBody ? (JSON.parse(rawBody) as PaymentResponse) : undefined;
|
|
183
|
+
} catch {
|
|
184
|
+
parsed = undefined;
|
|
185
|
+
}
|
|
127
186
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
187
|
+
if (parsed) {
|
|
188
|
+
const amountUsd =
|
|
189
|
+
typeof parsed.amount_usd === 'string'
|
|
190
|
+
? parseFloat(parsed.amount_usd)
|
|
191
|
+
: (parsed.amount_usd ?? parsed.amount ?? 0);
|
|
192
|
+
const newBalance =
|
|
193
|
+
typeof parsed.new_balance === 'string'
|
|
194
|
+
? parseFloat(parsed.new_balance)
|
|
195
|
+
: (parsed.new_balance ?? parsed.balance ?? 0);
|
|
196
|
+
args.callbacks.onPaymentComplete?.({
|
|
197
|
+
amountUsd,
|
|
198
|
+
newBalance,
|
|
199
|
+
transactionId: parsed.transaction,
|
|
200
|
+
});
|
|
201
|
+
return { attempts: 1, balance: newBalance };
|
|
202
|
+
}
|
|
203
|
+
return { attempts: 1 };
|
|
145
204
|
}
|
|
146
205
|
|
|
147
206
|
export async function handlePayment(args: {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
207
|
+
requirement: ExactPaymentRequirement;
|
|
208
|
+
wallet: WalletContext;
|
|
209
|
+
rpcURL: string;
|
|
210
|
+
baseURL: string;
|
|
211
|
+
baseFetch: typeof fetch;
|
|
212
|
+
maxAttempts: number;
|
|
213
|
+
callbacks: PaymentCallbacks;
|
|
155
214
|
}): Promise<{ attemptsUsed: number }> {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
215
|
+
let attempts = 0;
|
|
216
|
+
while (attempts < args.maxAttempts) {
|
|
217
|
+
const result = await processSinglePayment(args);
|
|
218
|
+
attempts += result.attempts;
|
|
219
|
+
const balanceValue =
|
|
220
|
+
typeof result.balance === 'number'
|
|
221
|
+
? result.balance
|
|
222
|
+
: result.balance != null
|
|
223
|
+
? Number(result.balance)
|
|
224
|
+
: undefined;
|
|
225
|
+
if (
|
|
226
|
+
balanceValue == null ||
|
|
227
|
+
Number.isNaN(balanceValue) ||
|
|
228
|
+
balanceValue >= 0
|
|
229
|
+
) {
|
|
230
|
+
return { attemptsUsed: attempts };
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
throw new Error(`Setu: payment failed after ${attempts} additional top-ups.`);
|
|
171
234
|
}
|
package/src/providers/factory.ts
CHANGED
|
@@ -7,64 +7,64 @@ import type { LanguageModelV3Middleware } from '@ai-sdk/provider';
|
|
|
7
7
|
import type { ProviderApiFormat, ProviderId, FetchFunction } from '../types.ts';
|
|
8
8
|
|
|
9
9
|
export function createModel(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
modelId: string,
|
|
11
|
+
apiFormat: ProviderApiFormat,
|
|
12
|
+
providerId: ProviderId,
|
|
13
|
+
baseURL: string,
|
|
14
|
+
customFetch: FetchFunction,
|
|
15
|
+
middleware?: LanguageModelV3Middleware | LanguageModelV3Middleware[],
|
|
16
16
|
) {
|
|
17
|
-
|
|
17
|
+
const fetchFn = customFetch as unknown as typeof globalThis.fetch;
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
let model:
|
|
20
|
+
| ReturnType<ReturnType<typeof createOpenAI>['responses']>
|
|
21
|
+
| ReturnType<ReturnType<typeof createAnthropic>>;
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
switch (apiFormat) {
|
|
24
|
+
case 'anthropic-messages': {
|
|
25
|
+
const provider = createAnthropic({
|
|
26
|
+
baseURL,
|
|
27
|
+
apiKey: 'setu-wallet-auth',
|
|
28
|
+
fetch: fetchFn,
|
|
29
|
+
});
|
|
30
|
+
model = provider(modelId);
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
case 'google-native': {
|
|
35
|
+
const provider = createGoogleGenerativeAI({
|
|
36
|
+
baseURL,
|
|
37
|
+
apiKey: 'setu-wallet-auth',
|
|
38
|
+
fetch: fetchFn,
|
|
39
|
+
});
|
|
40
|
+
model = provider(modelId);
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
44
|
+
case 'openai-chat': {
|
|
45
|
+
const provider = createOpenAICompatible({
|
|
46
|
+
name: `setu-${providerId}`,
|
|
47
|
+
baseURL,
|
|
48
|
+
headers: { Authorization: 'Bearer setu-wallet-auth' },
|
|
49
|
+
fetch: fetchFn,
|
|
50
|
+
});
|
|
51
|
+
model = provider(modelId);
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
default: {
|
|
55
|
+
const provider = createOpenAI({
|
|
56
|
+
baseURL,
|
|
57
|
+
apiKey: 'setu-wallet-auth',
|
|
58
|
+
fetch: fetchFn,
|
|
59
|
+
});
|
|
60
|
+
model = provider.responses(modelId);
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
52
64
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
baseURL,
|
|
57
|
-
apiKey: 'setu-wallet-auth',
|
|
58
|
-
fetch: fetchFn,
|
|
59
|
-
});
|
|
60
|
-
model = provider.responses(modelId);
|
|
61
|
-
break;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
65
|
+
if (middleware) {
|
|
66
|
+
return wrapLanguageModel({ model, middleware });
|
|
67
|
+
}
|
|
64
68
|
|
|
65
|
-
|
|
66
|
-
return wrapLanguageModel({ model, middleware });
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return model;
|
|
69
|
+
return model;
|
|
70
70
|
}
|
|
@@ -1,105 +1,70 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
ProviderId,
|
|
3
|
+
ProviderConfig,
|
|
4
|
+
ProviderApiFormat,
|
|
5
|
+
} from '../types.ts';
|
|
6
|
+
import { setuCatalog } from '../catalog.ts';
|
|
2
7
|
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
apiFormat: 'openai-responses',
|
|
12
|
-
modelPrefix: 'o1',
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
id: 'openai',
|
|
16
|
-
apiFormat: 'openai-responses',
|
|
17
|
-
modelPrefix: 'o3',
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
id: 'openai',
|
|
21
|
-
apiFormat: 'openai-responses',
|
|
22
|
-
modelPrefix: 'o4',
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
id: 'openai',
|
|
26
|
-
apiFormat: 'openai-responses',
|
|
27
|
-
modelPrefix: 'codex-',
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
id: 'anthropic',
|
|
31
|
-
apiFormat: 'anthropic-messages',
|
|
32
|
-
modelPrefix: 'claude-',
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
id: 'google',
|
|
36
|
-
apiFormat: 'google-native',
|
|
37
|
-
modelPrefix: 'gemini-',
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
id: 'moonshot',
|
|
41
|
-
apiFormat: 'openai-chat',
|
|
42
|
-
modelPrefix: 'kimi-',
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
id: 'minimax',
|
|
46
|
-
apiFormat: 'anthropic-messages',
|
|
47
|
-
modelPrefix: 'MiniMax-',
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
id: 'zai',
|
|
51
|
-
apiFormat: 'openai-chat',
|
|
52
|
-
modelPrefix: 'glm-',
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
id: 'zai',
|
|
56
|
-
apiFormat: 'openai-chat',
|
|
57
|
-
modelPrefix: 'z1-',
|
|
58
|
-
},
|
|
59
|
-
];
|
|
8
|
+
const OWNER_API_FORMAT: Record<string, ProviderApiFormat> = {
|
|
9
|
+
openai: 'openai-responses',
|
|
10
|
+
anthropic: 'anthropic-messages',
|
|
11
|
+
google: 'google-native',
|
|
12
|
+
minimax: 'anthropic-messages',
|
|
13
|
+
moonshot: 'openai-chat',
|
|
14
|
+
zai: 'openai-chat',
|
|
15
|
+
};
|
|
60
16
|
|
|
61
17
|
export class ProviderRegistry {
|
|
62
|
-
|
|
63
|
-
|
|
18
|
+
private configs: ProviderConfig[];
|
|
19
|
+
private modelMap: Record<string, ProviderId>;
|
|
64
20
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
21
|
+
constructor(
|
|
22
|
+
customProviders?: ProviderConfig[],
|
|
23
|
+
modelMap?: Record<string, ProviderId>,
|
|
24
|
+
) {
|
|
25
|
+
this.configs = [...(customProviders ?? [])];
|
|
26
|
+
this.modelMap = modelMap ?? {};
|
|
27
|
+
}
|
|
72
28
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
29
|
+
resolve(
|
|
30
|
+
modelId: string,
|
|
31
|
+
): { providerId: ProviderId; apiFormat: ProviderApiFormat } | null {
|
|
32
|
+
if (this.modelMap[modelId]) {
|
|
33
|
+
const providerId = this.modelMap[modelId];
|
|
34
|
+
const config = this.configs.find((c) => c.id === providerId);
|
|
35
|
+
return {
|
|
36
|
+
providerId,
|
|
37
|
+
apiFormat: config?.apiFormat ?? 'openai-chat',
|
|
38
|
+
};
|
|
39
|
+
}
|
|
82
40
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
41
|
+
for (const config of this.configs) {
|
|
42
|
+
if (config.models?.includes(modelId)) {
|
|
43
|
+
return { providerId: config.id, apiFormat: config.apiFormat };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
88
46
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
47
|
+
for (const config of this.configs) {
|
|
48
|
+
if (config.modelPrefix && modelId.startsWith(config.modelPrefix)) {
|
|
49
|
+
return { providerId: config.id, apiFormat: config.apiFormat };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
94
52
|
|
|
95
|
-
|
|
96
|
-
|
|
53
|
+
const entry = setuCatalog.models.find((m) => m.id === modelId);
|
|
54
|
+
if (entry) {
|
|
55
|
+
const providerId = entry.owned_by as ProviderId;
|
|
56
|
+
const apiFormat = OWNER_API_FORMAT[providerId] ?? 'openai-chat';
|
|
57
|
+
return { providerId, apiFormat };
|
|
58
|
+
}
|
|
97
59
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
101
62
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
63
|
+
register(config: ProviderConfig): void {
|
|
64
|
+
this.configs.push(config);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
mapModel(modelId: string, providerId: ProviderId): void {
|
|
68
|
+
this.modelMap[modelId] = providerId;
|
|
69
|
+
}
|
|
105
70
|
}
|