@base44-preview/sdk 0.8.52-pr.295.865dd57 → 0.8.52-pr.297.05dc385
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.
|
@@ -51,15 +51,15 @@ export interface AiGatewayModuleConfig {
|
|
|
51
51
|
* against the provider directly, no separate account, API key, or billing
|
|
52
52
|
* setup with the underlying model provider required.
|
|
53
53
|
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
54
|
+
* `connection()` takes an optional `provider`, and each provider serves a different API:
|
|
55
|
+
*
|
|
56
|
+
* - `openai` (default): OpenAI-compatible chat completions and image endpoints.
|
|
57
|
+
* - `typesafe`: structured evaluations with the `jev` model.
|
|
57
58
|
*
|
|
58
59
|
* Call `connection()` from a backend function rather than the browser. This
|
|
59
60
|
* keeps your instructions, tools, and business logic server-side, and lets
|
|
60
|
-
* you enforce your own auth, rate, and spend limits around the call.
|
|
61
|
-
*
|
|
62
|
-
* used for every other SDK call.
|
|
61
|
+
* you enforce your own auth, rate, and spend limits around the call. Which
|
|
62
|
+
* token it returns depends on the authentication mode, described below.
|
|
63
63
|
*
|
|
64
64
|
* ## OpenAI-compatible models
|
|
65
65
|
*
|
|
@@ -76,13 +76,23 @@ export interface AiGatewayModuleConfig {
|
|
|
76
76
|
* `'gemini_3_1_flash_image'` or `'gpt_image_2'`. For request options, the
|
|
77
77
|
* full model list, and limits, see [Generate images with the AI Gateway](/developers/references/sdk/getting-started/ai-gateway-images).
|
|
78
78
|
*
|
|
79
|
+
* ## Structured evaluations
|
|
80
|
+
*
|
|
81
|
+
* The `typesafe` provider runs the `jev` evaluation model through
|
|
82
|
+
* `@ai-sdk/typesafe-ai` and `experimental_evaluate` from the `ai` package,
|
|
83
|
+
* version 7.0.105 or later. Pass `evaluationModel("jev")`; the gateway rejects
|
|
84
|
+
* other model IDs, such as `"jev-latest"`. Give it some app state and a set of
|
|
85
|
+
* questions, each a `choice`, `score`, or `boolean`. Choice and score answers
|
|
86
|
+
* come back with `probabilities` per option; boolean answers with a single
|
|
87
|
+
* `probability` of `true`. Use it to classify, score, or route records, then
|
|
88
|
+
* apply your own thresholds and actions in code.
|
|
89
|
+
*
|
|
79
90
|
* ## Authentication Modes
|
|
80
91
|
*
|
|
81
|
-
*
|
|
82
|
-
* token `connection()` returns:
|
|
92
|
+
* The mode determines which token `connection()` returns:
|
|
83
93
|
*
|
|
84
94
|
* - **User authentication** (`base44.aiGateway`): Returns the signed-in app user's token.
|
|
85
|
-
* - **Service role authentication** (`base44.asServiceRole.aiGateway`): Returns the service-role token instead, for
|
|
95
|
+
* - **Service role authentication** (`base44.asServiceRole.aiGateway`): Returns the service-role token instead. Use it from backend functions: apps that restrict Core integrations, the default for new apps, reject user-token gateway calls on public apps. It also works when there's no signed-in user, such as from a scheduled automation.
|
|
86
96
|
*
|
|
87
97
|
* ## Billing and limits
|
|
88
98
|
*
|
|
@@ -111,7 +121,7 @@ export interface AiGatewayModule {
|
|
|
111
121
|
*
|
|
112
122
|
* // Runs inside a backend function
|
|
113
123
|
* const base44 = createClientFromRequest(request);
|
|
114
|
-
* const { baseURL, token, headers } = base44.aiGateway.connection();
|
|
124
|
+
* const { baseURL, token, headers } = base44.asServiceRole.aiGateway.connection();
|
|
115
125
|
* const openai = new OpenAI({ baseURL, apiKey: token, defaultHeaders: headers });
|
|
116
126
|
*
|
|
117
127
|
* const response = await openai.chat.completions.create({
|
|
@@ -133,7 +143,7 @@ export interface AiGatewayModule {
|
|
|
133
143
|
* // Runs inside a backend function, reviewing a return request
|
|
134
144
|
* const base44 = createClientFromRequest(request);
|
|
135
145
|
* const returnRequest = await base44.entities.ReturnRequest.get(returnId);
|
|
136
|
-
* const { baseURL, token, headers } = base44.aiGateway.connection();
|
|
146
|
+
* const { baseURL, token, headers } = base44.asServiceRole.aiGateway.connection();
|
|
137
147
|
* // Point any OpenAI-compatible client at `baseURL` with `apiKey: token` and `headers`.
|
|
138
148
|
* const models = createOpenAICompatible({ name: "base44", baseURL, apiKey: token, headers });
|
|
139
149
|
*
|
|
@@ -174,7 +184,7 @@ export interface AiGatewayModule {
|
|
|
174
184
|
*
|
|
175
185
|
* // Runs inside a backend function
|
|
176
186
|
* const base44 = createClientFromRequest(request);
|
|
177
|
-
* const { baseURL, token, headers } = base44.aiGateway.connection();
|
|
187
|
+
* const { baseURL, token, headers } = base44.asServiceRole.aiGateway.connection();
|
|
178
188
|
* const models = createOpenAICompatible({ name: "base44", baseURL, apiKey: token, headers });
|
|
179
189
|
*
|
|
180
190
|
* const { image } = await generateImage({
|
|
@@ -187,6 +197,45 @@ export interface AiGatewayModule {
|
|
|
187
197
|
* const file = new File([image.uint8Array], "lighthouse.png", { type: image.mediaType });
|
|
188
198
|
* const { file_url } = await base44.integrations.Core.UploadFile({ file });
|
|
189
199
|
* ```
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```typescript
|
|
203
|
+
* // Route a support ticket with a structured evaluation
|
|
204
|
+
* import { createClientFromRequest } from "@base44/sdk";
|
|
205
|
+
* import { experimental_evaluate as evaluate } from "ai";
|
|
206
|
+
* import { createTypeSafeAi } from "@ai-sdk/typesafe-ai";
|
|
207
|
+
*
|
|
208
|
+
* // Runs inside a backend function
|
|
209
|
+
* const base44 = createClientFromRequest(request);
|
|
210
|
+
* const { baseURL, token, headers } = base44.asServiceRole.aiGateway.connection({ provider: "typesafe" });
|
|
211
|
+
* const typesafe = createTypeSafeAi({ baseURL, apiKey: token, headers });
|
|
212
|
+
*
|
|
213
|
+
* const { answers, providerMetadata } = await evaluate({
|
|
214
|
+
* model: typesafe.evaluationModel("jev"),
|
|
215
|
+
* maxRetries: 0, // Avoid automatic replays of billed requests
|
|
216
|
+
* state: { message: "Please refund today's duplicate charge." },
|
|
217
|
+
* questions: {
|
|
218
|
+
* department: {
|
|
219
|
+
* type: "choice",
|
|
220
|
+
* instructions: "Which team should handle this?",
|
|
221
|
+
* criteria: { billing: "Payments and refunds", support: "Other requests" },
|
|
222
|
+
* },
|
|
223
|
+
* urgency: {
|
|
224
|
+
* type: "score",
|
|
225
|
+
* instructions: "How urgent is this?",
|
|
226
|
+
* criteria: ["No deadline", "Requested today", "Immediate emergency"],
|
|
227
|
+
* },
|
|
228
|
+
* refund: { type: "boolean", instructions: "Is a refund explicitly requested?" },
|
|
229
|
+
* },
|
|
230
|
+
* });
|
|
231
|
+
*
|
|
232
|
+
* // answers.department → { type: "choice", choice: "billing", probabilities: { billing: 0.97, support: 0.03 } }
|
|
233
|
+
* // answers.urgency → { type: "score", score: 1.2, probabilities: { 0: 0.1, 1: 0.6, 2: 0.3 } }
|
|
234
|
+
* // answers.refund → { type: "boolean", probability: 0.99 }
|
|
235
|
+
* // Choice and score confidence is in providerMetadata.typesafe.confidence
|
|
236
|
+
* // Pick your own thresholds and act on them in code
|
|
237
|
+
* const autoRefund = answers.department.choice === "billing" && answers.refund.probability > 0.9;
|
|
238
|
+
* ```
|
|
190
239
|
*/
|
|
191
240
|
connection(options?: AiGatewayConnectionOptions): AiGatewayConnection;
|
|
192
241
|
}
|
|
@@ -127,7 +127,7 @@ export interface UploadPrivateFileResult {
|
|
|
127
127
|
export interface CreateFileSignedUrlParams {
|
|
128
128
|
/** URI of the uploaded private file. */
|
|
129
129
|
file_uri: string;
|
|
130
|
-
/** How long the signed URL should be valid for, in seconds.
|
|
130
|
+
/** How long the signed URL should be valid for, in seconds. Must be between `60` (1 minute) and `3600` (1 hour).
|
|
131
131
|
* @default 300 (5 minutes)
|
|
132
132
|
*/
|
|
133
133
|
expires_in?: number;
|
|
@@ -352,7 +352,7 @@ export interface CoreIntegrations {
|
|
|
352
352
|
* // Create a signed URL for a private file
|
|
353
353
|
* const { signed_url } = await base44.integrations.Core.CreateFileSignedUrl({
|
|
354
354
|
* file_uri: "private/user123/document.pdf",
|
|
355
|
-
* expires_in:
|
|
355
|
+
* expires_in: 1800 // URL expires in 30 minutes
|
|
356
356
|
* });
|
|
357
357
|
* console.log(signed_url); // https://...?signature=...
|
|
358
358
|
* ```
|
|
@@ -101,38 +101,6 @@ function safeErrorLog(prefix, error) {
|
|
|
101
101
|
console.error(`${prefix} ${error instanceof Error ? error.message : String(error)}`);
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
|
-
const CREDENTIAL_HEADERS = new Set([
|
|
105
|
-
"authorization",
|
|
106
|
-
"on-behalf-of",
|
|
107
|
-
"base44-service-authorization",
|
|
108
|
-
]);
|
|
109
|
-
/**
|
|
110
|
-
* Removes credentials from a failed request's error before app code sees it.
|
|
111
|
-
*
|
|
112
|
-
* An axios error carries its request config and the raw Node request, so
|
|
113
|
-
* logging it (for example `console.log(error)`) printed the bearer token.
|
|
114
|
-
*
|
|
115
|
-
* @param error - The axios error to scrub in place
|
|
116
|
-
* @internal
|
|
117
|
-
*/
|
|
118
|
-
function redactCredentials(error) {
|
|
119
|
-
var _a;
|
|
120
|
-
const headers = (_a = error === null || error === void 0 ? void 0 : error.config) === null || _a === void 0 ? void 0 : _a.headers;
|
|
121
|
-
if (headers) {
|
|
122
|
-
const names = Object.keys(typeof headers.toJSON === "function" ? headers.toJSON() : headers);
|
|
123
|
-
for (const name of names) {
|
|
124
|
-
if (CREDENTIAL_HEADERS.has(name.toLowerCase())) {
|
|
125
|
-
headers[name] = "[REDACTED]";
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
// The Node request object also holds the raw header block (`_header`).
|
|
130
|
-
for (const target of [error, error === null || error === void 0 ? void 0 : error.response]) {
|
|
131
|
-
if (target && "request" in target) {
|
|
132
|
-
Object.defineProperty(target, "request", { enumerable: false });
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
104
|
/**
|
|
137
105
|
* Creates an axios client with default configuration and interceptors.
|
|
138
106
|
*
|
|
@@ -160,11 +128,6 @@ export function createAxiosClient({ baseURL, headers = {}, token, interceptRespo
|
|
|
160
128
|
if (token) {
|
|
161
129
|
client.defaults.headers.common["Authorization"] = `Bearer ${token}`;
|
|
162
130
|
}
|
|
163
|
-
// Registered first so it also covers clients that skip the Base44Error wrapper.
|
|
164
|
-
client.interceptors.response.use(undefined, (error) => {
|
|
165
|
-
redactCredentials(error);
|
|
166
|
-
return Promise.reject(error);
|
|
167
|
-
});
|
|
168
131
|
// Add origin URL in browser environment
|
|
169
132
|
client.interceptors.request.use((config) => {
|
|
170
133
|
// `window.location` is absent on React Native (where `window` still exists),
|