@amigo-ai/sdk 0.60.0 → 0.62.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/README.md +15 -0
- package/dist/index.cjs +781 -0
- package/dist/index.cjs.map +7 -0
- package/dist/{index.js → index.mjs} +7 -4
- package/dist/{index.js.map → index.mjs.map} +2 -2
- package/dist/types/generated/api-types.d.ts +814 -1012
- package/dist/types/resources/conversation.d.ts +3 -3
- package/package.json +7 -4
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,781 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
31
|
+
|
|
32
|
+
// src/index.ts
|
|
33
|
+
var index_exports = {};
|
|
34
|
+
__export(index_exports, {
|
|
35
|
+
AmigoClient: () => AmigoClient,
|
|
36
|
+
errors: () => errors_exports
|
|
37
|
+
});
|
|
38
|
+
module.exports = __toCommonJS(index_exports);
|
|
39
|
+
|
|
40
|
+
// src/core/errors.ts
|
|
41
|
+
var errors_exports = {};
|
|
42
|
+
__export(errors_exports, {
|
|
43
|
+
AmigoError: () => AmigoError,
|
|
44
|
+
AuthenticationError: () => AuthenticationError,
|
|
45
|
+
BadRequestError: () => BadRequestError,
|
|
46
|
+
ConfigurationError: () => ConfigurationError,
|
|
47
|
+
ConflictError: () => ConflictError,
|
|
48
|
+
NetworkError: () => NetworkError,
|
|
49
|
+
NotFoundError: () => NotFoundError,
|
|
50
|
+
ParseError: () => ParseError,
|
|
51
|
+
PermissionError: () => PermissionError,
|
|
52
|
+
RateLimitError: () => RateLimitError,
|
|
53
|
+
ServerError: () => ServerError,
|
|
54
|
+
ServiceUnavailableError: () => ServiceUnavailableError,
|
|
55
|
+
ValidationError: () => ValidationError,
|
|
56
|
+
createApiError: () => createApiError,
|
|
57
|
+
createErrorMiddleware: () => createErrorMiddleware,
|
|
58
|
+
isAmigoError: () => isAmigoError
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// src/core/utils.ts
|
|
62
|
+
async function extractData(responsePromise) {
|
|
63
|
+
const result = await responsePromise;
|
|
64
|
+
const data = result.data;
|
|
65
|
+
if (data === void 0 || data === null) {
|
|
66
|
+
throw new ParseError("Expected response data to be present for successful request", "response");
|
|
67
|
+
}
|
|
68
|
+
return data;
|
|
69
|
+
}
|
|
70
|
+
async function* parseNdjsonStream(response) {
|
|
71
|
+
const body = response.body;
|
|
72
|
+
if (!body) return;
|
|
73
|
+
const reader = body.getReader();
|
|
74
|
+
const decoder = new TextDecoder();
|
|
75
|
+
let bufferedText = "";
|
|
76
|
+
try {
|
|
77
|
+
while (true) {
|
|
78
|
+
const { done, value } = await reader.read();
|
|
79
|
+
if (done) break;
|
|
80
|
+
bufferedText += decoder.decode(value, { stream: true });
|
|
81
|
+
let newlineIndex;
|
|
82
|
+
while ((newlineIndex = bufferedText.indexOf("\n")) !== -1) {
|
|
83
|
+
const line = bufferedText.slice(0, newlineIndex).trim();
|
|
84
|
+
bufferedText = bufferedText.slice(newlineIndex + 1);
|
|
85
|
+
if (!line) continue;
|
|
86
|
+
try {
|
|
87
|
+
yield JSON.parse(line);
|
|
88
|
+
} catch (err) {
|
|
89
|
+
throw new ParseError("Failed to parse NDJSON line", "json", err);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const trailing = bufferedText.trim();
|
|
94
|
+
if (trailing) {
|
|
95
|
+
try {
|
|
96
|
+
yield JSON.parse(trailing);
|
|
97
|
+
} catch (err) {
|
|
98
|
+
throw new ParseError("Failed to parse trailing NDJSON line", "json", err);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
} finally {
|
|
102
|
+
reader.releaseLock();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async function parseResponseBody(response) {
|
|
106
|
+
try {
|
|
107
|
+
const text = await response.text();
|
|
108
|
+
if (!text) return void 0;
|
|
109
|
+
try {
|
|
110
|
+
return JSON.parse(text);
|
|
111
|
+
} catch {
|
|
112
|
+
return text;
|
|
113
|
+
}
|
|
114
|
+
} catch {
|
|
115
|
+
return void 0;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function isNetworkError(error) {
|
|
119
|
+
if (!(error instanceof Error)) return false;
|
|
120
|
+
return error instanceof TypeError || error.message.includes("fetch") || error.message.includes("Failed to fetch") || error.message.includes("Network request failed") || error.message.includes("ECONNREFUSED") || error.message.includes("ETIMEDOUT") || error.message.includes("ENOTFOUND") || error.message.includes("network");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// src/core/errors.ts
|
|
124
|
+
var AmigoError = class extends Error {
|
|
125
|
+
constructor(message, options) {
|
|
126
|
+
super(message);
|
|
127
|
+
/**
|
|
128
|
+
* Unique error code for programmatic error handling
|
|
129
|
+
*/
|
|
130
|
+
__publicField(this, "errorCode");
|
|
131
|
+
/**
|
|
132
|
+
* HTTP status code if applicable
|
|
133
|
+
*/
|
|
134
|
+
__publicField(this, "statusCode");
|
|
135
|
+
/**
|
|
136
|
+
* Additional context data
|
|
137
|
+
*/
|
|
138
|
+
__publicField(this, "context");
|
|
139
|
+
this.name = this.constructor.name;
|
|
140
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
141
|
+
if (Error.captureStackTrace) {
|
|
142
|
+
Error.captureStackTrace(this, this.constructor);
|
|
143
|
+
}
|
|
144
|
+
Object.assign(this, options);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Returns a JSON-serializable representation of the error
|
|
148
|
+
*/
|
|
149
|
+
toJSON() {
|
|
150
|
+
return {
|
|
151
|
+
name: this.name,
|
|
152
|
+
message: this.message,
|
|
153
|
+
code: this.errorCode,
|
|
154
|
+
statusCode: this.statusCode,
|
|
155
|
+
context: this.context,
|
|
156
|
+
stack: this.stack
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
var BadRequestError = class extends AmigoError {
|
|
161
|
+
};
|
|
162
|
+
var AuthenticationError = class extends AmigoError {
|
|
163
|
+
};
|
|
164
|
+
var PermissionError = class extends AmigoError {
|
|
165
|
+
};
|
|
166
|
+
var NotFoundError = class extends AmigoError {
|
|
167
|
+
};
|
|
168
|
+
var ConflictError = class extends AmigoError {
|
|
169
|
+
};
|
|
170
|
+
var RateLimitError = class extends AmigoError {
|
|
171
|
+
};
|
|
172
|
+
var ServerError = class extends AmigoError {
|
|
173
|
+
};
|
|
174
|
+
var ServiceUnavailableError = class extends ServerError {
|
|
175
|
+
};
|
|
176
|
+
var ConfigurationError = class extends AmigoError {
|
|
177
|
+
constructor(message, field) {
|
|
178
|
+
super(message);
|
|
179
|
+
this.field = field;
|
|
180
|
+
this.context = { field };
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
var ValidationError = class extends BadRequestError {
|
|
184
|
+
constructor(msg, fieldErrors) {
|
|
185
|
+
super(msg);
|
|
186
|
+
this.fieldErrors = fieldErrors;
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
var NetworkError = class extends AmigoError {
|
|
190
|
+
constructor(message, originalError, request) {
|
|
191
|
+
super(message, { cause: originalError });
|
|
192
|
+
this.originalError = originalError;
|
|
193
|
+
this.request = request;
|
|
194
|
+
this.context = { request };
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
var ParseError = class extends AmigoError {
|
|
198
|
+
constructor(message, parseType, originalError) {
|
|
199
|
+
super(message, { cause: originalError });
|
|
200
|
+
this.parseType = parseType;
|
|
201
|
+
this.originalError = originalError;
|
|
202
|
+
this.context = { parseType };
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
function isAmigoError(error) {
|
|
206
|
+
return error instanceof AmigoError;
|
|
207
|
+
}
|
|
208
|
+
function createApiError(response, body) {
|
|
209
|
+
const map = {
|
|
210
|
+
400: BadRequestError,
|
|
211
|
+
401: AuthenticationError,
|
|
212
|
+
403: PermissionError,
|
|
213
|
+
404: NotFoundError,
|
|
214
|
+
409: ConflictError,
|
|
215
|
+
422: ValidationError,
|
|
216
|
+
429: RateLimitError,
|
|
217
|
+
500: ServerError,
|
|
218
|
+
503: ServiceUnavailableError
|
|
219
|
+
};
|
|
220
|
+
const errorMessageKeys = ["message", "error", "detail"];
|
|
221
|
+
const ErrorClass = map[response.status] ?? AmigoError;
|
|
222
|
+
let message = `HTTP ${response.status} ${response.statusText}`;
|
|
223
|
+
if (body && typeof body === "object") {
|
|
224
|
+
for (const key of errorMessageKeys) {
|
|
225
|
+
if (key in body) {
|
|
226
|
+
message = String(body[key]);
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
const options = {
|
|
232
|
+
status: response.status,
|
|
233
|
+
code: body && typeof body === "object" && "code" in body ? body.code : void 0,
|
|
234
|
+
response: body
|
|
235
|
+
};
|
|
236
|
+
const error = new ErrorClass(message, options);
|
|
237
|
+
return error;
|
|
238
|
+
}
|
|
239
|
+
function createErrorMiddleware() {
|
|
240
|
+
return {
|
|
241
|
+
onResponse: async ({ response }) => {
|
|
242
|
+
if (!response.ok) {
|
|
243
|
+
const body = await parseResponseBody(response);
|
|
244
|
+
throw createApiError(response, body);
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
onError: async ({ error, request }) => {
|
|
248
|
+
if (isNetworkError(error)) {
|
|
249
|
+
throw new NetworkError(
|
|
250
|
+
`Network error: ${error instanceof Error ? error.message : String(error)}`,
|
|
251
|
+
error instanceof Error ? error : new Error(String(error)),
|
|
252
|
+
{
|
|
253
|
+
url: request?.url,
|
|
254
|
+
method: request?.method
|
|
255
|
+
}
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
throw error;
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// src/core/openapi-client.ts
|
|
264
|
+
var import_openapi_fetch = __toESM(require("openapi-fetch"), 1);
|
|
265
|
+
|
|
266
|
+
// src/core/auth.ts
|
|
267
|
+
async function getBearerToken(config) {
|
|
268
|
+
const url = `${config.baseUrl}/v1/${config.orgId}/user/signin_with_api_key`;
|
|
269
|
+
try {
|
|
270
|
+
const response = await fetch(url, {
|
|
271
|
+
method: "POST",
|
|
272
|
+
headers: {
|
|
273
|
+
"x-api-key": config.apiKey,
|
|
274
|
+
"x-api-key-id": config.apiKeyId,
|
|
275
|
+
"x-user-id": config.userId
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
if (!response.ok) {
|
|
279
|
+
const body = await parseResponseBody(response);
|
|
280
|
+
const apiError = createApiError(response, body);
|
|
281
|
+
if (response.status === 401) {
|
|
282
|
+
throw new AuthenticationError(`Authentication failed: ${apiError.message}`, {
|
|
283
|
+
...apiError,
|
|
284
|
+
context: { ...apiError.context, endpoint: "signin_with_api_key" }
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
throw apiError;
|
|
288
|
+
}
|
|
289
|
+
return await response.json();
|
|
290
|
+
} catch (err) {
|
|
291
|
+
if (err instanceof AmigoError) {
|
|
292
|
+
throw err;
|
|
293
|
+
}
|
|
294
|
+
if (isNetworkError(err)) {
|
|
295
|
+
throw new NetworkError("Failed to connect to authentication endpoint", err, {
|
|
296
|
+
url,
|
|
297
|
+
method: "POST"
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
throw new ParseError(
|
|
301
|
+
"Failed to parse authentication response",
|
|
302
|
+
"json",
|
|
303
|
+
err instanceof Error ? err : new Error(String(err))
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
function createAuthMiddleware(config) {
|
|
308
|
+
let token = null;
|
|
309
|
+
let refreshPromise = null;
|
|
310
|
+
const shouldRefreshToken = (tokenData) => {
|
|
311
|
+
if (!tokenData.expires_at) return false;
|
|
312
|
+
const expiryTime = new Date(tokenData.expires_at).getTime();
|
|
313
|
+
const currentTime = Date.now();
|
|
314
|
+
const timeUntilExpiry = expiryTime - currentTime;
|
|
315
|
+
const refreshThreshold = 5 * 60 * 1e3;
|
|
316
|
+
return timeUntilExpiry <= refreshThreshold;
|
|
317
|
+
};
|
|
318
|
+
const ensureValidToken = async () => {
|
|
319
|
+
if (!token || shouldRefreshToken(token)) {
|
|
320
|
+
if (!refreshPromise) {
|
|
321
|
+
refreshPromise = getBearerToken(config);
|
|
322
|
+
try {
|
|
323
|
+
token = await refreshPromise;
|
|
324
|
+
} finally {
|
|
325
|
+
refreshPromise = null;
|
|
326
|
+
}
|
|
327
|
+
} else {
|
|
328
|
+
token = await refreshPromise;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return token;
|
|
332
|
+
};
|
|
333
|
+
return {
|
|
334
|
+
onRequest: async ({ request }) => {
|
|
335
|
+
try {
|
|
336
|
+
const validToken = await ensureValidToken();
|
|
337
|
+
if (validToken?.id_token) {
|
|
338
|
+
request.headers.set("Authorization", `Bearer ${validToken.id_token}`);
|
|
339
|
+
}
|
|
340
|
+
} catch (error) {
|
|
341
|
+
token = null;
|
|
342
|
+
throw error;
|
|
343
|
+
}
|
|
344
|
+
return request;
|
|
345
|
+
},
|
|
346
|
+
onResponse: async ({ response }) => {
|
|
347
|
+
if (response.status === 401) {
|
|
348
|
+
token = null;
|
|
349
|
+
}
|
|
350
|
+
},
|
|
351
|
+
onError: async ({ error }) => {
|
|
352
|
+
token = null;
|
|
353
|
+
throw error;
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// src/core/retry.ts
|
|
359
|
+
var DEFAULT_RETRYABLE_STATUS = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504]);
|
|
360
|
+
var DEFAULT_RETRYABLE_METHODS = /* @__PURE__ */ new Set(["GET"]);
|
|
361
|
+
function resolveRetryOptions(options) {
|
|
362
|
+
return {
|
|
363
|
+
maxAttempts: options?.maxAttempts ?? 3,
|
|
364
|
+
backoffBaseMs: options?.backoffBaseMs ?? 250,
|
|
365
|
+
maxDelayMs: options?.maxDelayMs ?? 3e4,
|
|
366
|
+
retryOnStatus: new Set(options?.retryOnStatus ?? DEFAULT_RETRYABLE_STATUS),
|
|
367
|
+
retryOnMethods: new Set(options?.retryOnMethods ?? DEFAULT_RETRYABLE_METHODS)
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
function clamp(value, min, max) {
|
|
371
|
+
return Math.max(min, Math.min(max, value));
|
|
372
|
+
}
|
|
373
|
+
function parseRetryAfterMs(headerValue, maxDelayMs) {
|
|
374
|
+
if (!headerValue) return null;
|
|
375
|
+
const seconds = Number(headerValue);
|
|
376
|
+
if (Number.isFinite(seconds)) {
|
|
377
|
+
return clamp(seconds * 1e3, 0, maxDelayMs);
|
|
378
|
+
}
|
|
379
|
+
const date = new Date(headerValue);
|
|
380
|
+
const ms = date.getTime() - Date.now();
|
|
381
|
+
if (Number.isFinite(ms)) {
|
|
382
|
+
return clamp(ms, 0, maxDelayMs);
|
|
383
|
+
}
|
|
384
|
+
return null;
|
|
385
|
+
}
|
|
386
|
+
function computeBackoffWithJitterMs(attemptIndexZeroBased, baseMs, capMs) {
|
|
387
|
+
const windowMs = Math.min(capMs, baseMs * Math.pow(2, attemptIndexZeroBased));
|
|
388
|
+
return Math.random() * windowMs;
|
|
389
|
+
}
|
|
390
|
+
function isAbortError(err) {
|
|
391
|
+
return typeof err === "object" && err !== null && "name" in err && err["name"] === "AbortError";
|
|
392
|
+
}
|
|
393
|
+
function isNetworkError2(err) {
|
|
394
|
+
return err instanceof TypeError && !isAbortError(err);
|
|
395
|
+
}
|
|
396
|
+
async function abortableSleep(ms, signal) {
|
|
397
|
+
if (ms <= 0) {
|
|
398
|
+
signal?.throwIfAborted?.();
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
await new Promise((resolve, reject) => {
|
|
402
|
+
const rejectWith = signal?.reason instanceof Error ? signal.reason : signal?.reason ?? new Error("AbortError");
|
|
403
|
+
if (signal?.aborted) {
|
|
404
|
+
reject(rejectWith);
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
const t = setTimeout(() => {
|
|
408
|
+
off();
|
|
409
|
+
resolve();
|
|
410
|
+
}, ms);
|
|
411
|
+
const onAbort = () => {
|
|
412
|
+
off();
|
|
413
|
+
clearTimeout(t);
|
|
414
|
+
reject(rejectWith);
|
|
415
|
+
};
|
|
416
|
+
const off = () => signal?.removeEventListener("abort", onAbort);
|
|
417
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
function createRetryingFetch(retryOptions, baseFetch) {
|
|
421
|
+
const resolved = resolveRetryOptions(retryOptions);
|
|
422
|
+
const underlying = baseFetch ?? globalThis.fetch;
|
|
423
|
+
const retryingFetch = async (input, init) => {
|
|
424
|
+
const inputMethod = typeof Request !== "undefined" && input instanceof Request ? input.method : void 0;
|
|
425
|
+
const method = (init?.method ?? inputMethod ?? "GET").toUpperCase();
|
|
426
|
+
const signal = init?.signal;
|
|
427
|
+
const isMethodRetryableByDefault = resolved.retryOnMethods.has(method);
|
|
428
|
+
const maxAttempts = Math.max(1, resolved.maxAttempts);
|
|
429
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
430
|
+
let response = null;
|
|
431
|
+
let error = null;
|
|
432
|
+
try {
|
|
433
|
+
response = await underlying(input, init);
|
|
434
|
+
} catch (err) {
|
|
435
|
+
error = err;
|
|
436
|
+
}
|
|
437
|
+
if (!error && response && response.ok) {
|
|
438
|
+
return response;
|
|
439
|
+
}
|
|
440
|
+
let shouldRetry = false;
|
|
441
|
+
let delayMs = null;
|
|
442
|
+
if (isNetworkError2(error)) {
|
|
443
|
+
shouldRetry = isMethodRetryableByDefault;
|
|
444
|
+
if (shouldRetry) {
|
|
445
|
+
delayMs = computeBackoffWithJitterMs(
|
|
446
|
+
attempt - 1,
|
|
447
|
+
resolved.backoffBaseMs,
|
|
448
|
+
resolved.maxDelayMs
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
} else if (response) {
|
|
452
|
+
const status = response.status;
|
|
453
|
+
if (method === "POST") {
|
|
454
|
+
if (status === 429) {
|
|
455
|
+
const ra = response.headers.get("Retry-After");
|
|
456
|
+
const parsed = parseRetryAfterMs(ra, resolved.maxDelayMs);
|
|
457
|
+
if (parsed !== null) {
|
|
458
|
+
shouldRetry = true;
|
|
459
|
+
delayMs = parsed;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
} else if (isMethodRetryableByDefault && resolved.retryOnStatus.has(status)) {
|
|
463
|
+
const ra = response.headers.get("Retry-After");
|
|
464
|
+
delayMs = parseRetryAfterMs(ra, resolved.maxDelayMs) ?? computeBackoffWithJitterMs(attempt - 1, resolved.backoffBaseMs, resolved.maxDelayMs);
|
|
465
|
+
shouldRetry = true;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
const attemptsRemain = attempt < maxAttempts;
|
|
469
|
+
if (!shouldRetry || !attemptsRemain) {
|
|
470
|
+
if (error) throw error;
|
|
471
|
+
return response;
|
|
472
|
+
}
|
|
473
|
+
if (signal?.aborted) {
|
|
474
|
+
if (error) throw error;
|
|
475
|
+
return response;
|
|
476
|
+
}
|
|
477
|
+
await abortableSleep(delayMs ?? 0, signal ?? void 0);
|
|
478
|
+
}
|
|
479
|
+
throw new Error("Retry loop exited unexpectedly");
|
|
480
|
+
};
|
|
481
|
+
return retryingFetch;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// src/core/openapi-client.ts
|
|
485
|
+
function createAmigoFetch(config, mockFetch) {
|
|
486
|
+
const wrappedFetch = createRetryingFetch(
|
|
487
|
+
config.retry,
|
|
488
|
+
mockFetch ?? globalThis.fetch
|
|
489
|
+
);
|
|
490
|
+
const client = (0, import_openapi_fetch.default)({
|
|
491
|
+
baseUrl: config.baseUrl,
|
|
492
|
+
fetch: wrappedFetch
|
|
493
|
+
});
|
|
494
|
+
client.use(createErrorMiddleware());
|
|
495
|
+
client.use(createAuthMiddleware(config));
|
|
496
|
+
return client;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// src/resources/organization.ts
|
|
500
|
+
var OrganizationResource = class {
|
|
501
|
+
constructor(c, orgId) {
|
|
502
|
+
this.c = c;
|
|
503
|
+
this.orgId = orgId;
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Get organization details
|
|
507
|
+
* @param headers - The headers
|
|
508
|
+
* @returns The organization details
|
|
509
|
+
*/
|
|
510
|
+
async getOrganization(headers) {
|
|
511
|
+
return extractData(
|
|
512
|
+
this.c.GET("/v1/{organization}/organization/", {
|
|
513
|
+
params: { path: { organization: this.orgId } },
|
|
514
|
+
headers
|
|
515
|
+
})
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
|
|
520
|
+
// src/resources/conversation.ts
|
|
521
|
+
var ConversationResource = class {
|
|
522
|
+
constructor(c, orgId) {
|
|
523
|
+
this.c = c;
|
|
524
|
+
this.orgId = orgId;
|
|
525
|
+
}
|
|
526
|
+
async createConversation(body, queryParams, headers, options) {
|
|
527
|
+
const resp = await this.c.POST("/v1/{organization}/conversation/", {
|
|
528
|
+
params: { path: { organization: this.orgId }, query: queryParams },
|
|
529
|
+
body,
|
|
530
|
+
headers: {
|
|
531
|
+
Accept: "application/x-ndjson",
|
|
532
|
+
...headers ?? {}
|
|
533
|
+
},
|
|
534
|
+
// Ensure we receive a stream for NDJSON
|
|
535
|
+
parseAs: "stream",
|
|
536
|
+
...options?.signal && { signal: options.signal }
|
|
537
|
+
});
|
|
538
|
+
return parseNdjsonStream(
|
|
539
|
+
resp.response
|
|
540
|
+
);
|
|
541
|
+
}
|
|
542
|
+
async interactWithConversation(conversationId, input, queryParams, headers, options) {
|
|
543
|
+
let bodyToSend;
|
|
544
|
+
const mergedHeaders = {
|
|
545
|
+
Accept: "application/x-ndjson",
|
|
546
|
+
...headers ?? {}
|
|
547
|
+
};
|
|
548
|
+
if (queryParams.request_format === "text") {
|
|
549
|
+
if (typeof input !== "string") {
|
|
550
|
+
throw new BadRequestError("textMessage is required when request_format is 'text'");
|
|
551
|
+
}
|
|
552
|
+
const form = new FormData();
|
|
553
|
+
const blob = new Blob([input], { type: "text/plain; charset=utf-8" });
|
|
554
|
+
form.append("recorded_message", blob, "message.txt");
|
|
555
|
+
bodyToSend = form;
|
|
556
|
+
} else if (queryParams.request_format === "voice") {
|
|
557
|
+
if (typeof input === "string") {
|
|
558
|
+
throw new BadRequestError(
|
|
559
|
+
"voice input must be a byte source when request_format is 'voice'"
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
bodyToSend = input;
|
|
563
|
+
} else {
|
|
564
|
+
throw new BadRequestError("Unsupported or missing request_format in params");
|
|
565
|
+
}
|
|
566
|
+
if (queryParams.request_format === "text") {
|
|
567
|
+
delete mergedHeaders["content-type"];
|
|
568
|
+
delete mergedHeaders["Content-Type"];
|
|
569
|
+
}
|
|
570
|
+
if (queryParams.request_format === "voice") {
|
|
571
|
+
const hasContentType = mergedHeaders["content-type"] !== void 0 || mergedHeaders["Content-Type"] !== void 0;
|
|
572
|
+
if (!hasContentType && typeof Blob !== "undefined" && input instanceof Blob && input.type) {
|
|
573
|
+
mergedHeaders["content-type"] = input.type;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
const headersToSend = mergedHeaders;
|
|
577
|
+
const normalizedQuery = {
|
|
578
|
+
...queryParams,
|
|
579
|
+
request_audio_config: typeof queryParams.request_audio_config === "object" && queryParams.request_audio_config !== null ? JSON.stringify(queryParams.request_audio_config) : queryParams.request_audio_config ?? void 0
|
|
580
|
+
};
|
|
581
|
+
const resp = await this.c.POST("/v1/{organization}/conversation/{conversation_id}/interact", {
|
|
582
|
+
params: {
|
|
583
|
+
path: { organization: this.orgId, conversation_id: conversationId },
|
|
584
|
+
query: normalizedQuery,
|
|
585
|
+
header: headersToSend
|
|
586
|
+
},
|
|
587
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
588
|
+
body: bodyToSend,
|
|
589
|
+
// FormData/Blob not represented in generated OpenAPI types
|
|
590
|
+
parseAs: "stream",
|
|
591
|
+
...options?.signal && { signal: options.signal }
|
|
592
|
+
});
|
|
593
|
+
return parseNdjsonStream(resp.response);
|
|
594
|
+
}
|
|
595
|
+
async getConversations(queryParams, headers) {
|
|
596
|
+
return extractData(
|
|
597
|
+
this.c.GET("/v1/{organization}/conversation/", {
|
|
598
|
+
params: { path: { organization: this.orgId }, query: queryParams },
|
|
599
|
+
headers
|
|
600
|
+
})
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
async getConversationMessages(conversationId, queryParams, headers) {
|
|
604
|
+
return extractData(
|
|
605
|
+
this.c.GET("/v1/{organization}/conversation/{conversation_id}/messages/", {
|
|
606
|
+
params: {
|
|
607
|
+
path: { organization: this.orgId, conversation_id: conversationId },
|
|
608
|
+
query: queryParams
|
|
609
|
+
},
|
|
610
|
+
headers
|
|
611
|
+
})
|
|
612
|
+
);
|
|
613
|
+
}
|
|
614
|
+
async finishConversation(conversationId, headers) {
|
|
615
|
+
await this.c.POST("/v1/{organization}/conversation/{conversation_id}/finish/", {
|
|
616
|
+
params: { path: { organization: this.orgId, conversation_id: conversationId } },
|
|
617
|
+
headers,
|
|
618
|
+
// No content is expected; parse as text to access raw Response
|
|
619
|
+
parseAs: "text"
|
|
620
|
+
});
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
async recommendResponsesForInteraction(conversationId, interactionId, body, headers) {
|
|
624
|
+
return extractData(
|
|
625
|
+
this.c.POST(
|
|
626
|
+
"/v1/{organization}/conversation/{conversation_id}/interaction/{interaction_id}/recommend_responses",
|
|
627
|
+
{
|
|
628
|
+
params: {
|
|
629
|
+
path: {
|
|
630
|
+
organization: this.orgId,
|
|
631
|
+
conversation_id: conversationId,
|
|
632
|
+
interaction_id: interactionId
|
|
633
|
+
}
|
|
634
|
+
},
|
|
635
|
+
body,
|
|
636
|
+
headers
|
|
637
|
+
}
|
|
638
|
+
)
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
async getInteractionInsights(conversationId, interactionId, headers) {
|
|
642
|
+
return extractData(
|
|
643
|
+
this.c.GET(
|
|
644
|
+
"/v1/{organization}/conversation/{conversation_id}/interaction/{interaction_id}/insights",
|
|
645
|
+
{
|
|
646
|
+
params: {
|
|
647
|
+
path: {
|
|
648
|
+
organization: this.orgId,
|
|
649
|
+
conversation_id: conversationId,
|
|
650
|
+
interaction_id: interactionId
|
|
651
|
+
}
|
|
652
|
+
},
|
|
653
|
+
headers
|
|
654
|
+
}
|
|
655
|
+
)
|
|
656
|
+
);
|
|
657
|
+
}
|
|
658
|
+
// Note: the OpenAPI response schema isn't correct for this endpoint.
|
|
659
|
+
// TODO -- fix response typing.
|
|
660
|
+
async getMessageSource(conversationId, messageId, headers) {
|
|
661
|
+
return extractData(
|
|
662
|
+
this.c.GET("/v1/{organization}/conversation/{conversation_id}/messages/{message_id}/source", {
|
|
663
|
+
params: {
|
|
664
|
+
path: {
|
|
665
|
+
organization: this.orgId,
|
|
666
|
+
conversation_id: conversationId,
|
|
667
|
+
message_id: messageId
|
|
668
|
+
}
|
|
669
|
+
},
|
|
670
|
+
headers
|
|
671
|
+
})
|
|
672
|
+
);
|
|
673
|
+
}
|
|
674
|
+
async generateConversationStarters(body, headers) {
|
|
675
|
+
return extractData(
|
|
676
|
+
this.c.POST("/v1/{organization}/conversation/conversation_starter", {
|
|
677
|
+
params: { path: { organization: this.orgId } },
|
|
678
|
+
body,
|
|
679
|
+
headers
|
|
680
|
+
})
|
|
681
|
+
);
|
|
682
|
+
}
|
|
683
|
+
};
|
|
684
|
+
|
|
685
|
+
// src/resources/services.ts
|
|
686
|
+
var ServiceResource = class {
|
|
687
|
+
constructor(c, orgId) {
|
|
688
|
+
this.c = c;
|
|
689
|
+
this.orgId = orgId;
|
|
690
|
+
}
|
|
691
|
+
/**
|
|
692
|
+
* Get services
|
|
693
|
+
* @param headers - The headers
|
|
694
|
+
* @returns The services
|
|
695
|
+
*/
|
|
696
|
+
async getServices(queryParams, headers) {
|
|
697
|
+
return extractData(
|
|
698
|
+
this.c.GET("/v1/{organization}/service/", {
|
|
699
|
+
params: { path: { organization: this.orgId }, query: queryParams },
|
|
700
|
+
headers
|
|
701
|
+
})
|
|
702
|
+
);
|
|
703
|
+
}
|
|
704
|
+
};
|
|
705
|
+
|
|
706
|
+
// src/resources/user.ts
|
|
707
|
+
var UserResource = class {
|
|
708
|
+
constructor(c, orgId) {
|
|
709
|
+
this.c = c;
|
|
710
|
+
this.orgId = orgId;
|
|
711
|
+
}
|
|
712
|
+
async getUsers(queryParams, headers) {
|
|
713
|
+
return extractData(
|
|
714
|
+
this.c.GET("/v1/{organization}/user/", {
|
|
715
|
+
params: { path: { organization: this.orgId }, query: queryParams },
|
|
716
|
+
headers
|
|
717
|
+
})
|
|
718
|
+
);
|
|
719
|
+
}
|
|
720
|
+
async createUser(body, headers) {
|
|
721
|
+
return extractData(
|
|
722
|
+
this.c.POST("/v1/{organization}/user/", {
|
|
723
|
+
params: { path: { organization: this.orgId } },
|
|
724
|
+
body,
|
|
725
|
+
headers
|
|
726
|
+
})
|
|
727
|
+
);
|
|
728
|
+
}
|
|
729
|
+
async deleteUser(userId, headers) {
|
|
730
|
+
await this.c.DELETE("/v1/{organization}/user/{requested_user_id}", {
|
|
731
|
+
params: { path: { organization: this.orgId, requested_user_id: userId } },
|
|
732
|
+
headers
|
|
733
|
+
});
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
async updateUser(userId, body, headers) {
|
|
737
|
+
await this.c.POST("/v1/{organization}/user/{requested_user_id}", {
|
|
738
|
+
params: { path: { organization: this.orgId, requested_user_id: userId } },
|
|
739
|
+
body,
|
|
740
|
+
headers
|
|
741
|
+
});
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
};
|
|
745
|
+
|
|
746
|
+
// src/index.ts
|
|
747
|
+
var defaultBaseUrl = "https://api.amigo.ai";
|
|
748
|
+
var AmigoClient = class {
|
|
749
|
+
constructor(config) {
|
|
750
|
+
__publicField(this, "organizations");
|
|
751
|
+
__publicField(this, "conversations");
|
|
752
|
+
__publicField(this, "services");
|
|
753
|
+
__publicField(this, "users");
|
|
754
|
+
__publicField(this, "config");
|
|
755
|
+
this.config = validateConfig(config);
|
|
756
|
+
const api = createAmigoFetch(this.config);
|
|
757
|
+
this.organizations = new OrganizationResource(api, this.config.orgId);
|
|
758
|
+
this.conversations = new ConversationResource(api, this.config.orgId);
|
|
759
|
+
this.services = new ServiceResource(api, this.config.orgId);
|
|
760
|
+
this.users = new UserResource(api, this.config.orgId);
|
|
761
|
+
}
|
|
762
|
+
};
|
|
763
|
+
function validateConfig(config) {
|
|
764
|
+
if (!config.apiKey) {
|
|
765
|
+
throw new ConfigurationError("API key is required", "apiKey");
|
|
766
|
+
}
|
|
767
|
+
if (!config.apiKeyId) {
|
|
768
|
+
throw new ConfigurationError("API key ID is required", "apiKeyId");
|
|
769
|
+
}
|
|
770
|
+
if (!config.userId) {
|
|
771
|
+
throw new ConfigurationError("User ID is required", "userId");
|
|
772
|
+
}
|
|
773
|
+
if (!config.orgId) {
|
|
774
|
+
throw new ConfigurationError("Organization ID is required", "orgId");
|
|
775
|
+
}
|
|
776
|
+
if (!config.baseUrl) {
|
|
777
|
+
config.baseUrl = defaultBaseUrl;
|
|
778
|
+
}
|
|
779
|
+
return config;
|
|
780
|
+
}
|
|
781
|
+
//# sourceMappingURL=index.cjs.map
|