@seanhogg/builderforce-sdk 0.2.0 → 0.4.0
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/LICENSE +21 -21
- package/README.md +363 -98
- package/dist/index.cjs +98 -89
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +208 -15
- package/dist/index.d.ts +208 -15
- package/dist/index.mjs +97 -87
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -20,11 +20,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
-
AI_USE_CASES: () => AI_USE_CASES,
|
|
24
23
|
BuilderforceApiError: () => BuilderforceApiError,
|
|
25
24
|
BuilderforceClient: () => BuilderforceClient,
|
|
26
25
|
ChatCompletionStream: () => ChatCompletionStream,
|
|
27
|
-
|
|
26
|
+
EmbeddingsApi: () => EmbeddingsApi
|
|
28
27
|
});
|
|
29
28
|
module.exports = __toCommonJS(index_exports);
|
|
30
29
|
|
|
@@ -72,20 +71,63 @@ var ChatCompletionStream = class {
|
|
|
72
71
|
return full;
|
|
73
72
|
}
|
|
74
73
|
};
|
|
74
|
+
function splitTransportOptions(params) {
|
|
75
|
+
const { timeoutMs, signal, idempotencyKey, ...rest } = params;
|
|
76
|
+
const headers = {};
|
|
77
|
+
if (idempotencyKey) headers["Idempotency-Key"] = idempotencyKey;
|
|
78
|
+
return {
|
|
79
|
+
body: rest,
|
|
80
|
+
request: {
|
|
81
|
+
timeoutMs,
|
|
82
|
+
signal,
|
|
83
|
+
...Object.keys(headers).length > 0 ? { headers } : {}
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
75
87
|
var ChatCompletionsApi = class {
|
|
76
88
|
http;
|
|
77
89
|
constructor(http) {
|
|
78
90
|
this.http = http;
|
|
79
91
|
}
|
|
80
92
|
async create(params) {
|
|
93
|
+
const { body, request } = splitTransportOptions(params);
|
|
81
94
|
if (params.stream) {
|
|
82
|
-
const response = await this.http.postRaw("/llm/v1/chat/completions",
|
|
95
|
+
const response = await this.http.postRaw("/llm/v1/chat/completions", body, request);
|
|
83
96
|
if (!response.body) {
|
|
84
97
|
throw new Error("Streaming response body is missing");
|
|
85
98
|
}
|
|
86
99
|
return new ChatCompletionStream(response.body);
|
|
87
100
|
}
|
|
88
|
-
return this.http.postJson("/llm/v1/chat/completions",
|
|
101
|
+
return this.http.postJson("/llm/v1/chat/completions", body, request);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// src/application/EmbeddingsApi.ts
|
|
106
|
+
function splitTransportOptions2(params) {
|
|
107
|
+
const { timeoutMs, signal, idempotencyKey, ...rest } = params;
|
|
108
|
+
const headers = {};
|
|
109
|
+
if (idempotencyKey) headers["Idempotency-Key"] = idempotencyKey;
|
|
110
|
+
return {
|
|
111
|
+
body: rest,
|
|
112
|
+
request: {
|
|
113
|
+
timeoutMs,
|
|
114
|
+
signal,
|
|
115
|
+
...Object.keys(headers).length > 0 ? { headers } : {}
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
var EmbeddingsApi = class {
|
|
120
|
+
http;
|
|
121
|
+
constructor(http) {
|
|
122
|
+
this.http = http;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Create one or more text embeddings. Wired to OpenRouter (default model
|
|
126
|
+
* `nvidia/llama-nemotron-embed-vl-1b-v2:free`). Override via `model`.
|
|
127
|
+
*/
|
|
128
|
+
create(params) {
|
|
129
|
+
const { body, request } = splitTransportOptions2(params);
|
|
130
|
+
return this.http.postJson("/llm/v1/embeddings", body, request);
|
|
89
131
|
}
|
|
90
132
|
};
|
|
91
133
|
|
|
@@ -131,62 +173,68 @@ var HttpClient = class {
|
|
|
131
173
|
apiKey;
|
|
132
174
|
baseUrl;
|
|
133
175
|
fetchFn;
|
|
134
|
-
|
|
176
|
+
defaultTimeoutMs;
|
|
135
177
|
constructor(options) {
|
|
136
178
|
this.apiKey = options.apiKey;
|
|
137
179
|
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
138
180
|
this.fetchFn = options.fetchFn ?? fetch;
|
|
139
|
-
this.
|
|
181
|
+
this.defaultTimeoutMs = options.timeoutMs ?? 6e4;
|
|
140
182
|
}
|
|
141
|
-
async getJson(path) {
|
|
183
|
+
async getJson(path, options) {
|
|
142
184
|
const res = await this.fetchWithTimeout(`${this.baseUrl}${path}`, {
|
|
143
185
|
method: "GET",
|
|
144
|
-
headers: this.
|
|
145
|
-
});
|
|
186
|
+
headers: this.mergeHeaders(options)
|
|
187
|
+
}, options);
|
|
146
188
|
return this.parseJsonResponse(res);
|
|
147
189
|
}
|
|
148
|
-
async postJson(path, body) {
|
|
190
|
+
async postJson(path, body, options) {
|
|
149
191
|
const res = await this.fetchWithTimeout(`${this.baseUrl}${path}`, {
|
|
150
192
|
method: "POST",
|
|
151
|
-
headers: {
|
|
152
|
-
...this.authHeaders(),
|
|
153
|
-
"Content-Type": "application/json"
|
|
154
|
-
},
|
|
193
|
+
headers: this.mergeHeaders(options, { "Content-Type": "application/json" }),
|
|
155
194
|
body: JSON.stringify(body)
|
|
156
|
-
});
|
|
195
|
+
}, options);
|
|
157
196
|
return this.parseJsonResponse(res);
|
|
158
197
|
}
|
|
159
|
-
async postRaw(path, body) {
|
|
198
|
+
async postRaw(path, body, options) {
|
|
160
199
|
const res = await this.fetchWithTimeout(`${this.baseUrl}${path}`, {
|
|
161
200
|
method: "POST",
|
|
162
|
-
headers: {
|
|
163
|
-
...this.authHeaders(),
|
|
164
|
-
"Content-Type": "application/json"
|
|
165
|
-
},
|
|
201
|
+
headers: this.mergeHeaders(options, { "Content-Type": "application/json" }),
|
|
166
202
|
body: JSON.stringify(body)
|
|
167
|
-
});
|
|
203
|
+
}, options);
|
|
168
204
|
if (!res.ok) {
|
|
169
205
|
throw await this.toApiError(res);
|
|
170
206
|
}
|
|
171
207
|
return res;
|
|
172
208
|
}
|
|
173
|
-
|
|
209
|
+
mergeHeaders(options, base) {
|
|
174
210
|
return {
|
|
175
|
-
Authorization: `Bearer ${this.apiKey}
|
|
211
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
212
|
+
...base ?? {},
|
|
213
|
+
...options?.headers ?? {}
|
|
176
214
|
};
|
|
177
215
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
216
|
+
/**
|
|
217
|
+
* Wrap a fetch in a combined abort signal: an internal timeout AND any
|
|
218
|
+
* caller-provided signal. Either firing aborts the request. Single source of
|
|
219
|
+
* abort plumbing — every method routes through here (DRY).
|
|
220
|
+
*/
|
|
221
|
+
async fetchWithTimeout(input, init, options) {
|
|
222
|
+
const timeoutMs = options?.timeoutMs ?? this.defaultTimeoutMs;
|
|
223
|
+
const timeoutCtl = new AbortController();
|
|
224
|
+
const timer = setTimeout(() => timeoutCtl.abort(), timeoutMs);
|
|
225
|
+
const signal = combineSignals(timeoutCtl.signal, options?.signal);
|
|
181
226
|
try {
|
|
182
|
-
return await this.fetchFn(input, { ...init, signal
|
|
227
|
+
return await this.fetchFn(input, { ...init, signal });
|
|
183
228
|
} catch (error) {
|
|
184
|
-
if (
|
|
185
|
-
throw new BuilderforceApiError(`Request timed out after ${
|
|
229
|
+
if (timeoutCtl.signal.aborted) {
|
|
230
|
+
throw new BuilderforceApiError(`Request timed out after ${timeoutMs}ms`, 408, "timeout");
|
|
231
|
+
}
|
|
232
|
+
if (options?.signal?.aborted) {
|
|
233
|
+
throw new BuilderforceApiError("Request aborted by caller", 499, "aborted");
|
|
186
234
|
}
|
|
187
235
|
throw error;
|
|
188
236
|
} finally {
|
|
189
|
-
clearTimeout(
|
|
237
|
+
clearTimeout(timer);
|
|
190
238
|
}
|
|
191
239
|
}
|
|
192
240
|
async parseJsonResponse(res) {
|
|
@@ -207,10 +255,28 @@ var HttpClient = class {
|
|
|
207
255
|
}
|
|
208
256
|
}
|
|
209
257
|
};
|
|
258
|
+
function combineSignals(...signals) {
|
|
259
|
+
const live = signals.filter((s) => s !== void 0);
|
|
260
|
+
if (live.length === 1) return live[0];
|
|
261
|
+
const anyImpl = AbortSignal.any;
|
|
262
|
+
if (typeof anyImpl === "function") {
|
|
263
|
+
return anyImpl(live);
|
|
264
|
+
}
|
|
265
|
+
const ctl = new AbortController();
|
|
266
|
+
for (const s of live) {
|
|
267
|
+
if (s.aborted) {
|
|
268
|
+
ctl.abort(s.reason);
|
|
269
|
+
break;
|
|
270
|
+
}
|
|
271
|
+
s.addEventListener("abort", () => ctl.abort(s.reason), { once: true });
|
|
272
|
+
}
|
|
273
|
+
return ctl.signal;
|
|
274
|
+
}
|
|
210
275
|
|
|
211
276
|
// src/BuilderforceClient.ts
|
|
212
277
|
var BuilderforceClient = class {
|
|
213
278
|
chat;
|
|
279
|
+
embeddings;
|
|
214
280
|
models;
|
|
215
281
|
usage;
|
|
216
282
|
constructor(options) {
|
|
@@ -231,73 +297,16 @@ var BuilderforceClient = class {
|
|
|
231
297
|
this.chat = {
|
|
232
298
|
completions: new ChatCompletionsApi(http)
|
|
233
299
|
};
|
|
300
|
+
this.embeddings = new EmbeddingsApi(http);
|
|
234
301
|
this.models = new ModelsApi(http);
|
|
235
302
|
this.usage = new UsageApi(http);
|
|
236
303
|
}
|
|
237
304
|
};
|
|
238
|
-
|
|
239
|
-
// src/domain/aiUseCases.ts
|
|
240
|
-
var AI_USE_CASES = [
|
|
241
|
-
"ide.chat",
|
|
242
|
-
"ide.code_complete",
|
|
243
|
-
"training.dataset_generate",
|
|
244
|
-
"training.dataset_evaluate",
|
|
245
|
-
"agent.inference",
|
|
246
|
-
"coder.code",
|
|
247
|
-
"coder.review",
|
|
248
|
-
"coder.test",
|
|
249
|
-
"coder.debug",
|
|
250
|
-
"coder.refactor",
|
|
251
|
-
"coder.document",
|
|
252
|
-
"coder.architect",
|
|
253
|
-
"coach.chat",
|
|
254
|
-
"coach.insight",
|
|
255
|
-
"coach.classify",
|
|
256
|
-
"studio.compose",
|
|
257
|
-
"studio.script",
|
|
258
|
-
"studio.brief",
|
|
259
|
-
"pitch_deck.generate",
|
|
260
|
-
"investor.update",
|
|
261
|
-
"ask.general",
|
|
262
|
-
"tool.classify_email",
|
|
263
|
-
"tool.categorize_expense",
|
|
264
|
-
"tool.contract_analyze",
|
|
265
|
-
"tool.competitor_scan",
|
|
266
|
-
"tool.feature_score",
|
|
267
|
-
"tool.market_research",
|
|
268
|
-
"tool.health_score",
|
|
269
|
-
"tool.journey_insight",
|
|
270
|
-
"vision.describe",
|
|
271
|
-
"ocr.extract",
|
|
272
|
-
"embed.text",
|
|
273
|
-
"match",
|
|
274
|
-
"match_tailor",
|
|
275
|
-
"match_insights",
|
|
276
|
-
"resume_roast",
|
|
277
|
-
"skill_extract",
|
|
278
|
-
"job_parser",
|
|
279
|
-
"autofill",
|
|
280
|
-
"article_writer",
|
|
281
|
-
"studio_script",
|
|
282
|
-
"studio_edit_script",
|
|
283
|
-
"studio_misc",
|
|
284
|
-
"linkedin_post",
|
|
285
|
-
"interview_questions",
|
|
286
|
-
"interview_analyze",
|
|
287
|
-
"chat",
|
|
288
|
-
"career",
|
|
289
|
-
"discovery",
|
|
290
|
-
"dashboard_summary"
|
|
291
|
-
];
|
|
292
|
-
function isAIUseCase(value) {
|
|
293
|
-
return AI_USE_CASES.includes(value);
|
|
294
|
-
}
|
|
295
305
|
// Annotate the CommonJS export names for ESM import in node:
|
|
296
306
|
0 && (module.exports = {
|
|
297
|
-
AI_USE_CASES,
|
|
298
307
|
BuilderforceApiError,
|
|
299
308
|
BuilderforceClient,
|
|
300
309
|
ChatCompletionStream,
|
|
301
|
-
|
|
310
|
+
EmbeddingsApi
|
|
302
311
|
});
|
|
303
312
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/infrastructure/sse.ts","../src/application/ChatCompletionsApi.ts","../src/application/ModelsApi.ts","../src/application/UsageApi.ts","../src/infrastructure/httpClient.ts","../src/BuilderforceClient.ts","../src/domain/aiUseCases.ts"],"sourcesContent":["export { BuilderforceClient, type BuilderforceClientOptions } from './BuilderforceClient';\r\n\r\nexport {\r\n AI_USE_CASES,\r\n isAIUseCase,\r\n type AIUseCase,\r\n} from './domain/aiUseCases';\r\n\r\nexport type {\r\n ChatRole,\r\n ChatMessage,\r\n ChatCompletionCreateParams,\r\n ChatCompletionChunk,\r\n ChatCompletionResponse,\r\n ModelsListResponse,\r\n UsageByModel,\r\n UsageByDay,\r\n UsageByUser,\r\n UsageResponse,\r\n UsageGetParams,\r\n} from './domain/types';\r\n\r\nexport { ChatCompletionStream } from './application/ChatCompletionsApi';\r\nexport { BuilderforceApiError } from './infrastructure/httpClient';\r\n","export async function* parseSseJson<T>(\r\n stream: ReadableStream<Uint8Array>,\r\n): AsyncGenerator<T, void, unknown> {\r\n const reader = stream.getReader();\r\n const decoder = new TextDecoder();\r\n let buffer = '';\r\n\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n\r\n buffer += decoder.decode(value, { stream: true });\r\n const lines = buffer.split('\\n');\r\n buffer = lines.pop() ?? '';\r\n\r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n if (!trimmed.startsWith('data: ')) continue;\r\n\r\n const data = trimmed.slice(6).trim();\r\n if (data === '[DONE]') return;\r\n\r\n try {\r\n yield JSON.parse(data) as T;\r\n } catch {\r\n // Skip malformed chunks instead of breaking the stream.\r\n }\r\n }\r\n }\r\n}\r\n","import type { ChatCompletionChunk, ChatCompletionCreateParams, ChatCompletionResponse } from '../domain/types';\r\nimport { HttpClient } from '../infrastructure/httpClient';\r\nimport { parseSseJson } from '../infrastructure/sse';\r\n\r\nexport class ChatCompletionStream implements AsyncIterable<ChatCompletionChunk> {\r\n private readonly stream: ReadableStream<Uint8Array>;\r\n\r\n constructor(stream: ReadableStream<Uint8Array>) {\r\n this.stream = stream;\r\n }\r\n\r\n [Symbol.asyncIterator](): AsyncIterator<ChatCompletionChunk, void, unknown> {\r\n return parseSseJson<ChatCompletionChunk>(this.stream);\r\n }\r\n\r\n async toText(): Promise<string> {\r\n let full = '';\r\n for await (const chunk of this) {\r\n const delta = chunk.choices?.[0]?.delta?.content;\r\n if (typeof delta === 'string') {\r\n full += delta;\r\n }\r\n }\r\n return full;\r\n }\r\n}\r\n\r\nexport class ChatCompletionsApi {\r\n private readonly http: HttpClient;\r\n\r\n constructor(http: HttpClient) {\r\n this.http = http;\r\n }\r\n\r\n async create(params: ChatCompletionCreateParams & { stream: true }): Promise<ChatCompletionStream>;\r\n async create(params: ChatCompletionCreateParams & { stream?: false | undefined }): Promise<ChatCompletionResponse>;\r\n async create(\r\n params: ChatCompletionCreateParams,\r\n ): Promise<ChatCompletionResponse | ChatCompletionStream> {\r\n if (params.stream) {\r\n const response = await this.http.postRaw('/llm/v1/chat/completions', params);\r\n if (!response.body) {\r\n throw new Error('Streaming response body is missing');\r\n }\r\n return new ChatCompletionStream(response.body);\r\n }\r\n\r\n return this.http.postJson<ChatCompletionResponse>('/llm/v1/chat/completions', params);\r\n }\r\n}\r\n","import type { ModelsListResponse } from '../domain/types';\r\nimport { HttpClient } from '../infrastructure/httpClient';\r\n\r\nexport class ModelsApi {\r\n private readonly http: HttpClient;\r\n\r\n constructor(http: HttpClient) {\r\n this.http = http;\r\n }\r\n\r\n list(): Promise<ModelsListResponse> {\r\n return this.http.getJson<ModelsListResponse>('/llm/v1/models');\r\n }\r\n}\r\n","import type { UsageGetParams, UsageResponse } from '../domain/types';\r\nimport { HttpClient } from '../infrastructure/httpClient';\r\n\r\nexport class UsageApi {\r\n private readonly http: HttpClient;\r\n\r\n constructor(http: HttpClient) {\r\n this.http = http;\r\n }\r\n\r\n get(params: UsageGetParams = {}): Promise<UsageResponse> {\r\n const query = typeof params.days === 'number' ? `?days=${encodeURIComponent(String(params.days))}` : '';\r\n return this.http.getJson<UsageResponse>(`/llm/v1/usage${query}`);\r\n }\r\n}\r\n","export class BuilderforceApiError extends Error {\r\n public readonly status: number;\r\n public readonly code?: string;\r\n public readonly details?: unknown;\r\n public readonly requestId?: string;\r\n\r\n constructor(message: string, status: number, code?: string, details?: unknown, requestId?: string) {\r\n super(message);\r\n this.name = 'BuilderforceApiError';\r\n this.status = status;\r\n this.code = code;\r\n this.details = details;\r\n this.requestId = requestId;\r\n }\r\n}\r\n\r\nexport interface HttpClientOptions {\r\n apiKey: string;\r\n baseUrl: string;\r\n fetchFn?: typeof fetch;\r\n timeoutMs?: number;\r\n}\r\n\r\nexport class HttpClient {\r\n private readonly apiKey: string;\r\n private readonly baseUrl: string;\r\n private readonly fetchFn: typeof fetch;\r\n private readonly timeoutMs: number;\r\n\r\n constructor(options: HttpClientOptions) {\r\n this.apiKey = options.apiKey;\r\n this.baseUrl = options.baseUrl.replace(/\\/$/, '');\r\n this.fetchFn = options.fetchFn ?? fetch;\r\n this.timeoutMs = options.timeoutMs ?? 60_000;\r\n }\r\n\r\n async getJson<T>(path: string): Promise<T> {\r\n const res = await this.fetchWithTimeout(`${this.baseUrl}${path}`, {\r\n method: 'GET',\r\n headers: this.authHeaders(),\r\n });\r\n return this.parseJsonResponse<T>(res);\r\n }\r\n\r\n async postJson<T>(path: string, body: unknown): Promise<T> {\r\n const res = await this.fetchWithTimeout(`${this.baseUrl}${path}`, {\r\n method: 'POST',\r\n headers: {\r\n ...this.authHeaders(),\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n return this.parseJsonResponse<T>(res);\r\n }\r\n\r\n async postRaw(path: string, body: unknown): Promise<Response> {\r\n const res = await this.fetchWithTimeout(`${this.baseUrl}${path}`, {\r\n method: 'POST',\r\n headers: {\r\n ...this.authHeaders(),\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n if (!res.ok) {\r\n throw await this.toApiError(res);\r\n }\r\n return res;\r\n }\r\n\r\n private authHeaders(): Record<string, string> {\r\n return {\r\n Authorization: `Bearer ${this.apiKey}`,\r\n };\r\n }\r\n\r\n private async fetchWithTimeout(input: RequestInfo | URL, init: RequestInit): Promise<Response> {\r\n const controller = new AbortController();\r\n const timeout = setTimeout(() => controller.abort(), this.timeoutMs);\r\n try {\r\n return await this.fetchFn(input, { ...init, signal: controller.signal });\r\n } catch (error) {\r\n if (controller.signal.aborted) {\r\n throw new BuilderforceApiError(`Request timed out after ${this.timeoutMs}ms`, 408, 'timeout');\r\n }\r\n throw error;\r\n } finally {\r\n clearTimeout(timeout);\r\n }\r\n }\r\n\r\n private async parseJsonResponse<T>(res: Response): Promise<T> {\r\n if (!res.ok) {\r\n throw await this.toApiError(res);\r\n }\r\n return res.json() as Promise<T>;\r\n }\r\n\r\n private async toApiError(res: Response): Promise<BuilderforceApiError> {\r\n const fallback = `Request failed (${res.status})`;\r\n const requestId = res.headers.get('x-request-id') ?? undefined;\r\n try {\r\n const payload = await res.json() as { error?: string; code?: string; details?: unknown };\r\n return new BuilderforceApiError(payload.error ?? fallback, res.status, payload.code, payload.details, requestId);\r\n } catch {\r\n const text = await res.text().catch(() => '');\r\n return new BuilderforceApiError(text || fallback, res.status, undefined, undefined, requestId);\r\n }\r\n }\r\n}\r\n","import { ChatCompletionsApi } from './application/ChatCompletionsApi';\r\nimport { ModelsApi } from './application/ModelsApi';\r\nimport { UsageApi } from './application/UsageApi';\r\nimport { BuilderforceApiError, HttpClient } from './infrastructure/httpClient';\r\n\r\nexport interface BuilderforceClientOptions {\r\n apiKey: string;\r\n baseUrl?: string;\r\n fetch?: typeof fetch;\r\n timeoutMs?: number;\r\n}\r\n\r\nexport class BuilderforceClient {\r\n public readonly chat: {\r\n completions: ChatCompletionsApi;\r\n };\r\n public readonly models: ModelsApi;\r\n public readonly usage: UsageApi;\r\n\r\n constructor(options: BuilderforceClientOptions) {\r\n const apiKey = options.apiKey?.trim();\r\n if (!apiKey) {\r\n throw new BuilderforceApiError(\r\n 'BuilderforceClient requires a non-empty apiKey',\r\n 400,\r\n 'missing_api_key',\r\n );\r\n }\r\n\r\n const http = new HttpClient({\r\n apiKey,\r\n baseUrl: options.baseUrl ?? 'https://api.builderforce.ai',\r\n fetchFn: options.fetch,\r\n timeoutMs: options.timeoutMs,\r\n });\r\n\r\n this.chat = {\r\n completions: new ChatCompletionsApi(http),\r\n };\r\n this.models = new ModelsApi(http);\r\n this.usage = new UsageApi(http);\r\n }\r\n}\r\n","// Keep this list aligned with api/src/application/llm/aiUseCases.ts.\r\nexport const AI_USE_CASES = [\r\n 'ide.chat',\r\n 'ide.code_complete',\r\n 'training.dataset_generate',\r\n 'training.dataset_evaluate',\r\n 'agent.inference',\r\n 'coder.code',\r\n 'coder.review',\r\n 'coder.test',\r\n 'coder.debug',\r\n 'coder.refactor',\r\n 'coder.document',\r\n 'coder.architect',\r\n 'coach.chat',\r\n 'coach.insight',\r\n 'coach.classify',\r\n 'studio.compose',\r\n 'studio.script',\r\n 'studio.brief',\r\n 'pitch_deck.generate',\r\n 'investor.update',\r\n 'ask.general',\r\n 'tool.classify_email',\r\n 'tool.categorize_expense',\r\n 'tool.contract_analyze',\r\n 'tool.competitor_scan',\r\n 'tool.feature_score',\r\n 'tool.market_research',\r\n 'tool.health_score',\r\n 'tool.journey_insight',\r\n 'vision.describe',\r\n 'ocr.extract',\r\n 'embed.text',\r\n 'match',\r\n 'match_tailor',\r\n 'match_insights',\r\n 'resume_roast',\r\n 'skill_extract',\r\n 'job_parser',\r\n 'autofill',\r\n 'article_writer',\r\n 'studio_script',\r\n 'studio_edit_script',\r\n 'studio_misc',\r\n 'linkedin_post',\r\n 'interview_questions',\r\n 'interview_analyze',\r\n 'chat',\r\n 'career',\r\n 'discovery',\r\n 'dashboard_summary',\r\n] as const;\r\n\r\nexport type AIUseCase = (typeof AI_USE_CASES)[number];\r\n\r\nexport function isAIUseCase(value: string): value is AIUseCase {\r\n return (AI_USE_CASES as readonly string[]).includes(value);\r\n}\r\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/infrastructure/sse.ts","../src/application/ChatCompletionsApi.ts","../src/application/EmbeddingsApi.ts","../src/application/ModelsApi.ts","../src/application/UsageApi.ts","../src/infrastructure/httpClient.ts","../src/BuilderforceClient.ts"],"sourcesContent":["export { BuilderforceClient, type BuilderforceClientOptions } from './BuilderforceClient';\n\nexport type {\n // Roles & content\n ChatRole,\n ChatMessage,\n ContentPart,\n TextContentPart,\n ImageUrlContentPart,\n // Tool calling\n ToolSpec,\n ToolCall,\n ToolCallFunction,\n ToolCallDelta,\n ToolChoice,\n FunctionDefinition,\n // Structured output\n ResponseFormat,\n JsonSchemaSpec,\n // Per-call options\n PerCallOptions,\n // Chat completions\n ChatCompletionCreateParams,\n ChatCompletionChunk,\n ChatCompletionResponse,\n // Models / usage\n ModelsListResponse,\n UsageByModel,\n UsageByDay,\n UsageByUser,\n UsageResponse,\n UsageGetParams,\n // Embeddings\n EmbeddingsCreateParams,\n EmbeddingsResponse,\n EmbeddingObject,\n} from './domain/types';\n\nexport { ChatCompletionStream } from './application/ChatCompletionsApi';\nexport { EmbeddingsApi } from './application/EmbeddingsApi';\nexport { BuilderforceApiError } from './infrastructure/httpClient';\n","export async function* parseSseJson<T>(\n stream: ReadableStream<Uint8Array>,\n): AsyncGenerator<T, void, unknown> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed.startsWith('data: ')) continue;\n\n const data = trimmed.slice(6).trim();\n if (data === '[DONE]') return;\n\n try {\n yield JSON.parse(data) as T;\n } catch {\n // Skip malformed chunks instead of breaking the stream.\n }\n }\n }\n}\n","import type { ChatCompletionChunk, ChatCompletionCreateParams, ChatCompletionResponse } from '../domain/types';\nimport { HttpClient, type RequestOptions } from '../infrastructure/httpClient';\nimport { parseSseJson } from '../infrastructure/sse';\n\nexport class ChatCompletionStream implements AsyncIterable<ChatCompletionChunk> {\n private readonly stream: ReadableStream<Uint8Array>;\n\n constructor(stream: ReadableStream<Uint8Array>) {\n this.stream = stream;\n }\n\n [Symbol.asyncIterator](): AsyncIterator<ChatCompletionChunk, void, unknown> {\n return parseSseJson<ChatCompletionChunk>(this.stream);\n }\n\n async toText(): Promise<string> {\n let full = '';\n for await (const chunk of this) {\n const delta = chunk.choices?.[0]?.delta?.content;\n if (typeof delta === 'string') {\n full += delta;\n }\n }\n return full;\n }\n}\n\n/**\n * Pull SDK-level transport options (timeout, signal, idempotency key) out of\n * the params object so they don't get JSON-serialized into the request body.\n * Returns the request options AND the cleaned-up body.\n */\nfunction splitTransportOptions(params: ChatCompletionCreateParams): {\n body: Record<string, unknown>;\n request: RequestOptions;\n} {\n const { timeoutMs, signal, idempotencyKey, ...rest } = params;\n const headers: Record<string, string> = {};\n if (idempotencyKey) headers['Idempotency-Key'] = idempotencyKey;\n return {\n body: rest as unknown as Record<string, unknown>,\n request: {\n timeoutMs,\n signal,\n ...(Object.keys(headers).length > 0 ? { headers } : {}),\n },\n };\n}\n\nexport class ChatCompletionsApi {\n private readonly http: HttpClient;\n\n constructor(http: HttpClient) {\n this.http = http;\n }\n\n async create(params: ChatCompletionCreateParams & { stream: true }): Promise<ChatCompletionStream>;\n async create(params: ChatCompletionCreateParams & { stream?: false | undefined }): Promise<ChatCompletionResponse>;\n async create(\n params: ChatCompletionCreateParams,\n ): Promise<ChatCompletionResponse | ChatCompletionStream> {\n const { body, request } = splitTransportOptions(params);\n\n if (params.stream) {\n const response = await this.http.postRaw('/llm/v1/chat/completions', body, request);\n if (!response.body) {\n throw new Error('Streaming response body is missing');\n }\n return new ChatCompletionStream(response.body);\n }\n\n return this.http.postJson<ChatCompletionResponse>('/llm/v1/chat/completions', body, request);\n }\n}\n","import type { EmbeddingsCreateParams, EmbeddingsResponse } from '../domain/types';\nimport { HttpClient, type RequestOptions } from '../infrastructure/httpClient';\n\n/**\n * Pull SDK-level transport options out of the params so they don't ride\n * along inside the JSON body. Same shape as ChatCompletionsApi (DRY pattern).\n */\nfunction splitTransportOptions(params: EmbeddingsCreateParams): {\n body: Record<string, unknown>;\n request: RequestOptions;\n} {\n const { timeoutMs, signal, idempotencyKey, ...rest } = params;\n const headers: Record<string, string> = {};\n if (idempotencyKey) headers['Idempotency-Key'] = idempotencyKey;\n return {\n body: rest as unknown as Record<string, unknown>,\n request: {\n timeoutMs,\n signal,\n ...(Object.keys(headers).length > 0 ? { headers } : {}),\n },\n };\n}\n\nexport class EmbeddingsApi {\n private readonly http: HttpClient;\n\n constructor(http: HttpClient) {\n this.http = http;\n }\n\n /**\n * Create one or more text embeddings. Wired to OpenRouter (default model\n * `nvidia/llama-nemotron-embed-vl-1b-v2:free`). Override via `model`.\n */\n create(params: EmbeddingsCreateParams): Promise<EmbeddingsResponse> {\n const { body, request } = splitTransportOptions(params);\n return this.http.postJson<EmbeddingsResponse>('/llm/v1/embeddings', body, request);\n }\n}\n","import type { ModelsListResponse } from '../domain/types';\nimport { HttpClient } from '../infrastructure/httpClient';\n\nexport class ModelsApi {\n private readonly http: HttpClient;\n\n constructor(http: HttpClient) {\n this.http = http;\n }\n\n list(): Promise<ModelsListResponse> {\n return this.http.getJson<ModelsListResponse>('/llm/v1/models');\n }\n}\n","import type { UsageGetParams, UsageResponse } from '../domain/types';\nimport { HttpClient } from '../infrastructure/httpClient';\n\nexport class UsageApi {\n private readonly http: HttpClient;\n\n constructor(http: HttpClient) {\n this.http = http;\n }\n\n get(params: UsageGetParams = {}): Promise<UsageResponse> {\n const query = typeof params.days === 'number' ? `?days=${encodeURIComponent(String(params.days))}` : '';\n return this.http.getJson<UsageResponse>(`/llm/v1/usage${query}`);\n }\n}\n","export class BuilderforceApiError extends Error {\n public readonly status: number;\n public readonly code?: string;\n public readonly details?: unknown;\n public readonly requestId?: string;\n\n constructor(message: string, status: number, code?: string, details?: unknown, requestId?: string) {\n super(message);\n this.name = 'BuilderforceApiError';\n this.status = status;\n this.code = code;\n this.details = details;\n this.requestId = requestId;\n }\n}\n\nexport interface HttpClientOptions {\n apiKey: string;\n baseUrl: string;\n fetchFn?: typeof fetch;\n /** Default per-request timeout in ms. Overridable per call. */\n timeoutMs?: number;\n}\n\n/** Per-request overrides — passed by the API layer, not by SDK consumers directly. */\nexport interface RequestOptions {\n /** Override the client default timeout for just this request. */\n timeoutMs?: number;\n /** Caller-provided AbortSignal. Linked together with the SDK's internal timeout\n * signal — whichever fires first aborts the request. */\n signal?: AbortSignal;\n /** Extra headers to merge in (e.g. `Idempotency-Key`). */\n headers?: Record<string, string>;\n}\n\nexport class HttpClient {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly fetchFn: typeof fetch;\n private readonly defaultTimeoutMs: number;\n\n constructor(options: HttpClientOptions) {\n this.apiKey = options.apiKey;\n this.baseUrl = options.baseUrl.replace(/\\/$/, '');\n this.fetchFn = options.fetchFn ?? fetch;\n this.defaultTimeoutMs = options.timeoutMs ?? 60_000;\n }\n\n async getJson<T>(path: string, options?: RequestOptions): Promise<T> {\n const res = await this.fetchWithTimeout(`${this.baseUrl}${path}`, {\n method: 'GET',\n headers: this.mergeHeaders(options),\n }, options);\n return this.parseJsonResponse<T>(res);\n }\n\n async postJson<T>(path: string, body: unknown, options?: RequestOptions): Promise<T> {\n const res = await this.fetchWithTimeout(`${this.baseUrl}${path}`, {\n method: 'POST',\n headers: this.mergeHeaders(options, { 'Content-Type': 'application/json' }),\n body: JSON.stringify(body),\n }, options);\n return this.parseJsonResponse<T>(res);\n }\n\n async postRaw(path: string, body: unknown, options?: RequestOptions): Promise<Response> {\n const res = await this.fetchWithTimeout(`${this.baseUrl}${path}`, {\n method: 'POST',\n headers: this.mergeHeaders(options, { 'Content-Type': 'application/json' }),\n body: JSON.stringify(body),\n }, options);\n if (!res.ok) {\n throw await this.toApiError(res);\n }\n return res;\n }\n\n private mergeHeaders(options?: RequestOptions, base?: Record<string, string>): Record<string, string> {\n return {\n Authorization: `Bearer ${this.apiKey}`,\n ...(base ?? {}),\n ...(options?.headers ?? {}),\n };\n }\n\n /**\n * Wrap a fetch in a combined abort signal: an internal timeout AND any\n * caller-provided signal. Either firing aborts the request. Single source of\n * abort plumbing — every method routes through here (DRY).\n */\n private async fetchWithTimeout(\n input: RequestInfo | URL,\n init: RequestInit,\n options?: RequestOptions,\n ): Promise<Response> {\n const timeoutMs = options?.timeoutMs ?? this.defaultTimeoutMs;\n const timeoutCtl = new AbortController();\n const timer = setTimeout(() => timeoutCtl.abort(), timeoutMs);\n\n // Combine internal timeout signal + caller signal. Native AbortSignal.any\n // (Node 20+ / modern Workers) is preferred; fall back to manual linking.\n const signal = combineSignals(timeoutCtl.signal, options?.signal);\n\n try {\n return await this.fetchFn(input, { ...init, signal });\n } catch (error) {\n if (timeoutCtl.signal.aborted) {\n throw new BuilderforceApiError(`Request timed out after ${timeoutMs}ms`, 408, 'timeout');\n }\n if (options?.signal?.aborted) {\n throw new BuilderforceApiError('Request aborted by caller', 499, 'aborted');\n }\n throw error;\n } finally {\n clearTimeout(timer);\n }\n }\n\n private async parseJsonResponse<T>(res: Response): Promise<T> {\n if (!res.ok) {\n throw await this.toApiError(res);\n }\n return res.json() as Promise<T>;\n }\n\n private async toApiError(res: Response): Promise<BuilderforceApiError> {\n const fallback = `Request failed (${res.status})`;\n const requestId = res.headers.get('x-request-id') ?? undefined;\n try {\n const payload = await res.json() as { error?: string; code?: string; details?: unknown };\n return new BuilderforceApiError(payload.error ?? fallback, res.status, payload.code, payload.details, requestId);\n } catch {\n const text = await res.text().catch(() => '');\n return new BuilderforceApiError(text || fallback, res.status, undefined, undefined, requestId);\n }\n }\n}\n\n/**\n * Combine multiple AbortSignals into one. Uses native `AbortSignal.any` when\n * available (Node 20+, modern Workers); falls back to manual event linking.\n */\nfunction combineSignals(...signals: Array<AbortSignal | undefined>): AbortSignal {\n const live = signals.filter((s): s is AbortSignal => s !== undefined);\n if (live.length === 1) return live[0]!;\n\n const anyImpl = (AbortSignal as unknown as { any?: (signals: AbortSignal[]) => AbortSignal }).any;\n if (typeof anyImpl === 'function') {\n return anyImpl(live);\n }\n\n const ctl = new AbortController();\n for (const s of live) {\n if (s.aborted) { ctl.abort(s.reason); break; }\n s.addEventListener('abort', () => ctl.abort(s.reason), { once: true });\n }\n return ctl.signal;\n}\n","import { ChatCompletionsApi } from './application/ChatCompletionsApi';\nimport { EmbeddingsApi } from './application/EmbeddingsApi';\nimport { ModelsApi } from './application/ModelsApi';\nimport { UsageApi } from './application/UsageApi';\nimport { BuilderforceApiError, HttpClient } from './infrastructure/httpClient';\n\nexport interface BuilderforceClientOptions {\n apiKey: string;\n baseUrl?: string;\n fetch?: typeof fetch;\n /** Default request timeout in ms (default 60_000). Per-call override available\n * via `chat.completions.create({ timeoutMs })` and `embeddings.create({ timeoutMs })`. */\n timeoutMs?: number;\n}\n\nexport class BuilderforceClient {\n public readonly chat: {\n completions: ChatCompletionsApi;\n };\n public readonly embeddings: EmbeddingsApi;\n public readonly models: ModelsApi;\n public readonly usage: UsageApi;\n\n constructor(options: BuilderforceClientOptions) {\n const apiKey = options.apiKey?.trim();\n if (!apiKey) {\n throw new BuilderforceApiError(\n 'BuilderforceClient requires a non-empty apiKey',\n 400,\n 'missing_api_key',\n );\n }\n\n const http = new HttpClient({\n apiKey,\n baseUrl: options.baseUrl ?? 'https://api.builderforce.ai',\n fetchFn: options.fetch,\n timeoutMs: options.timeoutMs,\n });\n\n this.chat = {\n completions: new ChatCompletionsApi(http),\n };\n this.embeddings = new EmbeddingsApi(http);\n this.models = new ModelsApi(http);\n this.usage = new UsageApi(http);\n }\n}\n"],"mappings":"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","names":["splitTransportOptions"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,21 +1,131 @@
|
|
|
1
|
-
declare const AI_USE_CASES: readonly ["ide.chat", "ide.code_complete", "training.dataset_generate", "training.dataset_evaluate", "agent.inference", "coder.code", "coder.review", "coder.test", "coder.debug", "coder.refactor", "coder.document", "coder.architect", "coach.chat", "coach.insight", "coach.classify", "studio.compose", "studio.script", "studio.brief", "pitch_deck.generate", "investor.update", "ask.general", "tool.classify_email", "tool.categorize_expense", "tool.contract_analyze", "tool.competitor_scan", "tool.feature_score", "tool.market_research", "tool.health_score", "tool.journey_insight", "vision.describe", "ocr.extract", "embed.text", "match", "match_tailor", "match_insights", "resume_roast", "skill_extract", "job_parser", "autofill", "article_writer", "studio_script", "studio_edit_script", "studio_misc", "linkedin_post", "interview_questions", "interview_analyze", "chat", "career", "discovery", "dashboard_summary"];
|
|
2
|
-
type AIUseCase = (typeof AI_USE_CASES)[number];
|
|
3
|
-
declare function isAIUseCase(value: string): value is AIUseCase;
|
|
4
|
-
|
|
5
1
|
type ChatRole = 'system' | 'user' | 'assistant' | 'tool';
|
|
2
|
+
interface TextContentPart {
|
|
3
|
+
type: 'text';
|
|
4
|
+
text: string;
|
|
5
|
+
}
|
|
6
|
+
interface ImageUrlContentPart {
|
|
7
|
+
type: 'image_url';
|
|
8
|
+
image_url: {
|
|
9
|
+
/** Either an `https://...` URL or a `data:image/...;base64,...` data URI. */
|
|
10
|
+
url: string;
|
|
11
|
+
/** Image detail hint — `'low' | 'high' | 'auto'`. Vendor-specific behaviour. */
|
|
12
|
+
detail?: 'low' | 'high' | 'auto';
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
type ContentPart = TextContentPart | ImageUrlContentPart;
|
|
16
|
+
interface FunctionDefinition {
|
|
17
|
+
name: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
/** JSON-Schema describing the function's argument shape. */
|
|
20
|
+
parameters?: Record<string, unknown>;
|
|
21
|
+
}
|
|
22
|
+
interface ToolSpec {
|
|
23
|
+
type: 'function';
|
|
24
|
+
function: FunctionDefinition;
|
|
25
|
+
}
|
|
26
|
+
interface ToolCallFunction {
|
|
27
|
+
name: string;
|
|
28
|
+
/** JSON-encoded argument string. Caller is responsible for `JSON.parse`. */
|
|
29
|
+
arguments: string;
|
|
30
|
+
}
|
|
31
|
+
interface ToolCall {
|
|
32
|
+
id: string;
|
|
33
|
+
type: 'function';
|
|
34
|
+
function: ToolCallFunction;
|
|
35
|
+
}
|
|
36
|
+
type ToolChoice = 'auto' | 'none' | 'required' | {
|
|
37
|
+
type: 'function';
|
|
38
|
+
function: {
|
|
39
|
+
name: string;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
/** Streaming-mode tool-call delta. Each chunk carries an `index` so callers
|
|
43
|
+
* can stitch fragments together by call slot. */
|
|
44
|
+
interface ToolCallDelta {
|
|
45
|
+
index: number;
|
|
46
|
+
id?: string;
|
|
47
|
+
type?: 'function';
|
|
48
|
+
function?: {
|
|
49
|
+
name?: string;
|
|
50
|
+
/** Partial JSON-encoded arguments — concatenate across deltas to reassemble. */
|
|
51
|
+
arguments?: string;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
interface JsonSchemaSpec {
|
|
55
|
+
name: string;
|
|
56
|
+
description?: string;
|
|
57
|
+
/** JSON-Schema document. Use `strict: true` for vendor-side conformance retry. */
|
|
58
|
+
schema: Record<string, unknown>;
|
|
59
|
+
strict?: boolean;
|
|
60
|
+
}
|
|
61
|
+
type ResponseFormat = {
|
|
62
|
+
type: 'text';
|
|
63
|
+
} | {
|
|
64
|
+
type: 'json_object';
|
|
65
|
+
} | {
|
|
66
|
+
type: 'json_schema';
|
|
67
|
+
json_schema: JsonSchemaSpec;
|
|
68
|
+
};
|
|
6
69
|
interface ChatMessage {
|
|
7
70
|
role: ChatRole;
|
|
8
|
-
|
|
71
|
+
/** String for plain text. `ContentPart[]` for vision (text + image_url). `null`
|
|
72
|
+
* is allowed on assistant turns that only carry `tool_calls`. */
|
|
73
|
+
content: string | ContentPart[] | null;
|
|
9
74
|
name?: string;
|
|
75
|
+
/** Assistant-turn tool calls. Caller executes each and replies with a `tool` message
|
|
76
|
+
* whose `tool_call_id` matches `tool_calls[i].id`. */
|
|
77
|
+
tool_calls?: ToolCall[];
|
|
78
|
+
/** Required on `role: 'tool'` messages — the id of the assistant tool call this
|
|
79
|
+
* message is responding to. */
|
|
80
|
+
tool_call_id?: string;
|
|
81
|
+
}
|
|
82
|
+
interface PerCallOptions {
|
|
83
|
+
/** Override the client-level timeout for just this call. Useful when use
|
|
84
|
+
* cases have a wide latency spread (autofill ~2s vs `career_360` ~30s). */
|
|
85
|
+
timeoutMs?: number;
|
|
86
|
+
/** Caller-supplied AbortSignal for user-cancellable generation. Fires alongside
|
|
87
|
+
* the SDK's internal timeout signal — whichever fires first wins. */
|
|
88
|
+
signal?: AbortSignal;
|
|
89
|
+
/** Sent as `Idempotency-Key` header — gateway dedupes retries within its TTL. */
|
|
90
|
+
idempotencyKey?: string;
|
|
10
91
|
}
|
|
11
|
-
interface ChatCompletionCreateParams {
|
|
92
|
+
interface ChatCompletionCreateParams extends PerCallOptions {
|
|
93
|
+
/**
|
|
94
|
+
* Model **hint** (not a hard pin). When set, the gateway puts this id at the
|
|
95
|
+
* head of its candidate chain so it's tried first — but the gateway retains
|
|
96
|
+
* the right to substitute on cooldown, vendor outage, or plan-tier mismatch.
|
|
97
|
+
* The actual model used is reported via `_builderforce.resolvedModel`; check
|
|
98
|
+
* it if you need to detect substitution.
|
|
99
|
+
*
|
|
100
|
+
* Vendor prefixes (`openrouter/<id>`, `cerebras/<id>`, `ollama/<id>`) route
|
|
101
|
+
* to the named vendor when that model is selected. Bare ids fall back to
|
|
102
|
+
* catalog lookup.
|
|
103
|
+
*
|
|
104
|
+
* When unset, the gateway picks from the tenant-plan model pool with
|
|
105
|
+
* shape-based reordering (tools / response_format / vision content blocks).
|
|
106
|
+
*/
|
|
12
107
|
model?: string;
|
|
13
108
|
messages: ChatMessage[];
|
|
14
109
|
stream?: boolean;
|
|
15
|
-
useCase?: AIUseCase;
|
|
16
110
|
temperature?: number;
|
|
17
111
|
max_tokens?: number;
|
|
18
112
|
top_p?: number;
|
|
113
|
+
/** Tool / function-calling spec. */
|
|
114
|
+
tools?: ToolSpec[];
|
|
115
|
+
tool_choice?: ToolChoice;
|
|
116
|
+
/** Structured-output mode. `'json_object'` is loose JSON; `'json_schema'` requests
|
|
117
|
+
* gateway-side schema validation with retry across the failover chain. */
|
|
118
|
+
response_format?: ResponseFormat;
|
|
119
|
+
/**
|
|
120
|
+
* Opaque telemetry slug. The gateway treats this as a free-form string —
|
|
121
|
+
* persisted to `llm_usage_log.use_case` and echoed back in `_builderforce.useCase`
|
|
122
|
+
* for confirmation, but **never used for routing**. The taxonomy is yours.
|
|
123
|
+
*/
|
|
124
|
+
useCase?: string;
|
|
125
|
+
/** Free-form key/value pairs persisted to `llm_usage_log.metadata` for billing
|
|
126
|
+
* trace-back ({ toolRunId, sessionId, userId, featureKey, … }). Echoed back
|
|
127
|
+
* in `_builderforce.metadata`. Not forwarded to vendors. */
|
|
128
|
+
metadata?: Record<string, string>;
|
|
19
129
|
[key: string]: unknown;
|
|
20
130
|
}
|
|
21
131
|
interface ChatCompletionChunk {
|
|
@@ -27,7 +137,8 @@ interface ChatCompletionChunk {
|
|
|
27
137
|
index?: number;
|
|
28
138
|
delta?: {
|
|
29
139
|
role?: ChatRole;
|
|
30
|
-
content?: string;
|
|
140
|
+
content?: string | null;
|
|
141
|
+
tool_calls?: ToolCallDelta[];
|
|
31
142
|
};
|
|
32
143
|
finish_reason?: string | null;
|
|
33
144
|
}>;
|
|
@@ -46,8 +157,10 @@ interface ChatCompletionResponse {
|
|
|
46
157
|
index?: number;
|
|
47
158
|
message?: {
|
|
48
159
|
role?: ChatRole;
|
|
49
|
-
content?: string;
|
|
160
|
+
content?: string | null;
|
|
161
|
+
tool_calls?: ToolCall[];
|
|
50
162
|
};
|
|
163
|
+
/** `'stop' | 'length' | 'tool_calls' | 'content_filter' | …` */
|
|
51
164
|
finish_reason?: string | null;
|
|
52
165
|
}>;
|
|
53
166
|
usage?: {
|
|
@@ -56,11 +169,32 @@ interface ChatCompletionResponse {
|
|
|
56
169
|
total_tokens?: number;
|
|
57
170
|
};
|
|
58
171
|
_builderforce?: {
|
|
172
|
+
/** The model the gateway dispatched against. Equals `request.model` when caller pinned. */
|
|
59
173
|
resolvedModel?: string;
|
|
174
|
+
/** How many vendor retries happened inside the failover chain. */
|
|
60
175
|
retries?: number;
|
|
61
176
|
pool?: number;
|
|
62
177
|
product?: string;
|
|
63
178
|
effectivePlan?: string;
|
|
179
|
+
/** Number of vendor retries the gateway performed for json_schema conformance. */
|
|
180
|
+
schemaRetries?: number;
|
|
181
|
+
/** Echo of `request.useCase` (opaque telemetry slug). */
|
|
182
|
+
useCase?: string;
|
|
183
|
+
/** Echo of `request.metadata` for caller-side billing trace-back. */
|
|
184
|
+
metadata?: Record<string, string>;
|
|
185
|
+
/** Mirror of the `x-request-id` response header. */
|
|
186
|
+
requestId?: string;
|
|
187
|
+
/**
|
|
188
|
+
* Daily token budget snapshot at request time. Use `remaining` to
|
|
189
|
+
* pre-emptively throttle before the gateway returns 429
|
|
190
|
+
* `plan_token_limit_exceeded`. Same numbers are exposed via the
|
|
191
|
+
* `x-builderforce-daily-tokens-{used,limit,remaining}` response headers.
|
|
192
|
+
*/
|
|
193
|
+
dailyTokens?: {
|
|
194
|
+
used: number;
|
|
195
|
+
limit: number;
|
|
196
|
+
remaining: number;
|
|
197
|
+
};
|
|
64
198
|
};
|
|
65
199
|
[key: string]: unknown;
|
|
66
200
|
}
|
|
@@ -124,6 +258,36 @@ interface UsageResponse {
|
|
|
124
258
|
interface UsageGetParams {
|
|
125
259
|
days?: number;
|
|
126
260
|
}
|
|
261
|
+
interface EmbeddingsCreateParams extends PerCallOptions {
|
|
262
|
+
model?: string;
|
|
263
|
+
/** Single string or array of strings to embed. */
|
|
264
|
+
input: string | string[];
|
|
265
|
+
/** Opaque telemetry slug — same semantics as chat. */
|
|
266
|
+
useCase?: string;
|
|
267
|
+
/** Free-form attribution metadata (same semantics as chat). */
|
|
268
|
+
metadata?: Record<string, string>;
|
|
269
|
+
[key: string]: unknown;
|
|
270
|
+
}
|
|
271
|
+
interface EmbeddingObject {
|
|
272
|
+
object: 'embedding';
|
|
273
|
+
index: number;
|
|
274
|
+
embedding: number[];
|
|
275
|
+
}
|
|
276
|
+
interface EmbeddingsResponse {
|
|
277
|
+
object: 'list';
|
|
278
|
+
data: EmbeddingObject[];
|
|
279
|
+
model: string;
|
|
280
|
+
usage?: {
|
|
281
|
+
prompt_tokens?: number;
|
|
282
|
+
total_tokens?: number;
|
|
283
|
+
};
|
|
284
|
+
_builderforce?: {
|
|
285
|
+
resolvedModel?: string;
|
|
286
|
+
retries?: number;
|
|
287
|
+
product?: string;
|
|
288
|
+
};
|
|
289
|
+
[key: string]: unknown;
|
|
290
|
+
}
|
|
127
291
|
|
|
128
292
|
declare class BuilderforceApiError extends Error {
|
|
129
293
|
readonly status: number;
|
|
@@ -136,18 +300,34 @@ interface HttpClientOptions {
|
|
|
136
300
|
apiKey: string;
|
|
137
301
|
baseUrl: string;
|
|
138
302
|
fetchFn?: typeof fetch;
|
|
303
|
+
/** Default per-request timeout in ms. Overridable per call. */
|
|
304
|
+
timeoutMs?: number;
|
|
305
|
+
}
|
|
306
|
+
/** Per-request overrides — passed by the API layer, not by SDK consumers directly. */
|
|
307
|
+
interface RequestOptions {
|
|
308
|
+
/** Override the client default timeout for just this request. */
|
|
139
309
|
timeoutMs?: number;
|
|
310
|
+
/** Caller-provided AbortSignal. Linked together with the SDK's internal timeout
|
|
311
|
+
* signal — whichever fires first aborts the request. */
|
|
312
|
+
signal?: AbortSignal;
|
|
313
|
+
/** Extra headers to merge in (e.g. `Idempotency-Key`). */
|
|
314
|
+
headers?: Record<string, string>;
|
|
140
315
|
}
|
|
141
316
|
declare class HttpClient {
|
|
142
317
|
private readonly apiKey;
|
|
143
318
|
private readonly baseUrl;
|
|
144
319
|
private readonly fetchFn;
|
|
145
|
-
private readonly
|
|
320
|
+
private readonly defaultTimeoutMs;
|
|
146
321
|
constructor(options: HttpClientOptions);
|
|
147
|
-
getJson<T>(path: string): Promise<T>;
|
|
148
|
-
postJson<T>(path: string, body: unknown): Promise<T>;
|
|
149
|
-
postRaw(path: string, body: unknown): Promise<Response>;
|
|
150
|
-
private
|
|
322
|
+
getJson<T>(path: string, options?: RequestOptions): Promise<T>;
|
|
323
|
+
postJson<T>(path: string, body: unknown, options?: RequestOptions): Promise<T>;
|
|
324
|
+
postRaw(path: string, body: unknown, options?: RequestOptions): Promise<Response>;
|
|
325
|
+
private mergeHeaders;
|
|
326
|
+
/**
|
|
327
|
+
* Wrap a fetch in a combined abort signal: an internal timeout AND any
|
|
328
|
+
* caller-provided signal. Either firing aborts the request. Single source of
|
|
329
|
+
* abort plumbing — every method routes through here (DRY).
|
|
330
|
+
*/
|
|
151
331
|
private fetchWithTimeout;
|
|
152
332
|
private parseJsonResponse;
|
|
153
333
|
private toApiError;
|
|
@@ -170,6 +350,16 @@ declare class ChatCompletionsApi {
|
|
|
170
350
|
}): Promise<ChatCompletionResponse>;
|
|
171
351
|
}
|
|
172
352
|
|
|
353
|
+
declare class EmbeddingsApi {
|
|
354
|
+
private readonly http;
|
|
355
|
+
constructor(http: HttpClient);
|
|
356
|
+
/**
|
|
357
|
+
* Create one or more text embeddings. Wired to OpenRouter (default model
|
|
358
|
+
* `nvidia/llama-nemotron-embed-vl-1b-v2:free`). Override via `model`.
|
|
359
|
+
*/
|
|
360
|
+
create(params: EmbeddingsCreateParams): Promise<EmbeddingsResponse>;
|
|
361
|
+
}
|
|
362
|
+
|
|
173
363
|
declare class ModelsApi {
|
|
174
364
|
private readonly http;
|
|
175
365
|
constructor(http: HttpClient);
|
|
@@ -186,15 +376,18 @@ interface BuilderforceClientOptions {
|
|
|
186
376
|
apiKey: string;
|
|
187
377
|
baseUrl?: string;
|
|
188
378
|
fetch?: typeof fetch;
|
|
379
|
+
/** Default request timeout in ms (default 60_000). Per-call override available
|
|
380
|
+
* via `chat.completions.create({ timeoutMs })` and `embeddings.create({ timeoutMs })`. */
|
|
189
381
|
timeoutMs?: number;
|
|
190
382
|
}
|
|
191
383
|
declare class BuilderforceClient {
|
|
192
384
|
readonly chat: {
|
|
193
385
|
completions: ChatCompletionsApi;
|
|
194
386
|
};
|
|
387
|
+
readonly embeddings: EmbeddingsApi;
|
|
195
388
|
readonly models: ModelsApi;
|
|
196
389
|
readonly usage: UsageApi;
|
|
197
390
|
constructor(options: BuilderforceClientOptions);
|
|
198
391
|
}
|
|
199
392
|
|
|
200
|
-
export {
|
|
393
|
+
export { BuilderforceApiError, BuilderforceClient, type BuilderforceClientOptions, type ChatCompletionChunk, type ChatCompletionCreateParams, type ChatCompletionResponse, ChatCompletionStream, type ChatMessage, type ChatRole, type ContentPart, type EmbeddingObject, EmbeddingsApi, type EmbeddingsCreateParams, type EmbeddingsResponse, type FunctionDefinition, type ImageUrlContentPart, type JsonSchemaSpec, type ModelsListResponse, type PerCallOptions, type ResponseFormat, type TextContentPart, type ToolCall, type ToolCallDelta, type ToolCallFunction, type ToolChoice, type ToolSpec, type UsageByDay, type UsageByModel, type UsageByUser, type UsageGetParams, type UsageResponse };
|