cencori 1.4.0 → 1.4.1
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 +25 -0
- package/dist/index.d.mts +149 -1
- package/dist/index.d.ts +149 -1
- package/dist/index.js +330 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +328 -0
- package/dist/index.mjs.map +1 -1
- package/dist/memory/index.d.mts +160 -1
- package/dist/memory/index.d.ts +160 -1
- package/dist/memory/index.js +121 -0
- package/dist/memory/index.js.map +1 -1
- package/dist/memory/index.mjs +121 -0
- package/dist/memory/index.mjs.map +1 -1
- package/dist/react/index.d.mts +250 -1
- package/dist/react/index.d.ts +250 -1
- package/dist/react/index.js +729 -51
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +729 -50
- package/dist/react/index.mjs.map +1 -1
- package/dist/voice/index.d.mts +130 -0
- package/dist/voice/index.d.ts +130 -0
- package/dist/voice/index.js +141 -0
- package/dist/voice/index.js.map +1 -0
- package/dist/voice/index.mjs +116 -0
- package/dist/voice/index.mjs.map +1 -0
- package/package.json +6 -1
package/dist/index.mjs
CHANGED
|
@@ -718,6 +718,119 @@ var VisionNamespace = class {
|
|
|
718
718
|
}
|
|
719
719
|
};
|
|
720
720
|
|
|
721
|
+
// src/voice/index.ts
|
|
722
|
+
function toBlob(input) {
|
|
723
|
+
if (typeof Blob !== "undefined" && input instanceof Blob) return input;
|
|
724
|
+
if (input instanceof ArrayBuffer) return new Blob([new Uint8Array(input)]);
|
|
725
|
+
const view = input;
|
|
726
|
+
const bytes = new Uint8Array(view.byteLength);
|
|
727
|
+
bytes.set(new Uint8Array(view.buffer, view.byteOffset, view.byteLength));
|
|
728
|
+
return new Blob([bytes]);
|
|
729
|
+
}
|
|
730
|
+
var VoiceNamespace = class {
|
|
731
|
+
constructor(config) {
|
|
732
|
+
this.config = config;
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Text-to-speech. Returns raw audio bytes plus the resolved provider.
|
|
736
|
+
* Provider is inferred from `model` (default `tts-1`); pass `provider`
|
|
737
|
+
* only to be explicit.
|
|
738
|
+
*/
|
|
739
|
+
async speak(request) {
|
|
740
|
+
if (!request.input || !request.input.trim()) {
|
|
741
|
+
throw new Error("voice.speak requires non-empty `input`");
|
|
742
|
+
}
|
|
743
|
+
const body = {
|
|
744
|
+
input: request.input,
|
|
745
|
+
model: request.model,
|
|
746
|
+
voice: request.voice,
|
|
747
|
+
provider: request.provider,
|
|
748
|
+
response_format: request.responseFormat,
|
|
749
|
+
speed: request.speed,
|
|
750
|
+
language: request.language
|
|
751
|
+
};
|
|
752
|
+
const response = await fetch(`${this.config.baseUrl}/api/ai/audio/speech`, {
|
|
753
|
+
method: "POST",
|
|
754
|
+
headers: {
|
|
755
|
+
"CENCORI_API_KEY": this.config.apiKey,
|
|
756
|
+
"Content-Type": "application/json",
|
|
757
|
+
...this.config.headers
|
|
758
|
+
},
|
|
759
|
+
body: JSON.stringify(body)
|
|
760
|
+
});
|
|
761
|
+
if (!response.ok) {
|
|
762
|
+
throw await this.error(response, "voice.speak");
|
|
763
|
+
}
|
|
764
|
+
return {
|
|
765
|
+
audio: await response.arrayBuffer(),
|
|
766
|
+
contentType: response.headers.get("content-type") ?? "application/octet-stream",
|
|
767
|
+
provider: response.headers.get("x-provider") ?? request.provider ?? "openai",
|
|
768
|
+
requestId: response.headers.get("x-request-id") ?? void 0
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* Speech-to-text. Provider is inferred from `model` (default `whisper-1`).
|
|
773
|
+
* For `text`/`srt`/`vtt` formats the transcript is returned in `text`.
|
|
774
|
+
*/
|
|
775
|
+
async transcribe(request) {
|
|
776
|
+
if (!request.audio) {
|
|
777
|
+
throw new Error("voice.transcribe requires `audio`");
|
|
778
|
+
}
|
|
779
|
+
const form = new FormData();
|
|
780
|
+
form.append("file", toBlob(request.audio), request.filename ?? "audio.mp3");
|
|
781
|
+
if (request.model) form.append("model", request.model);
|
|
782
|
+
if (request.provider) form.append("provider", request.provider);
|
|
783
|
+
if (request.language) form.append("language", request.language);
|
|
784
|
+
if (request.prompt) form.append("prompt", request.prompt);
|
|
785
|
+
if (typeof request.temperature === "number") form.append("temperature", String(request.temperature));
|
|
786
|
+
if (request.diarize) form.append("diarize", "true");
|
|
787
|
+
form.append("response_format", request.responseFormat ?? "json");
|
|
788
|
+
const response = await fetch(`${this.config.baseUrl}/api/ai/audio/transcriptions`, {
|
|
789
|
+
method: "POST",
|
|
790
|
+
headers: {
|
|
791
|
+
"CENCORI_API_KEY": this.config.apiKey,
|
|
792
|
+
...this.config.headers
|
|
793
|
+
},
|
|
794
|
+
body: form
|
|
795
|
+
});
|
|
796
|
+
if (!response.ok) {
|
|
797
|
+
throw await this.error(response, "voice.transcribe");
|
|
798
|
+
}
|
|
799
|
+
const format = request.responseFormat;
|
|
800
|
+
if (format === "text" || format === "srt" || format === "vtt") {
|
|
801
|
+
return { text: await response.text(), provider: response.headers.get("x-provider") ?? void 0 };
|
|
802
|
+
}
|
|
803
|
+
return await response.json();
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* Speech-to-text with speaker labels. Convenience wrapper over
|
|
807
|
+
* `transcribe` that enables diarization and returns verbose segments.
|
|
808
|
+
* Use a diarization-capable model (`nova-3`, `assemblyai-universal`).
|
|
809
|
+
*/
|
|
810
|
+
async diarize(request) {
|
|
811
|
+
return this.transcribe({ ...request, diarize: true, responseFormat: "verbose_json" });
|
|
812
|
+
}
|
|
813
|
+
/** List the available voice models (TTS + STT) with their providers. */
|
|
814
|
+
async listModels() {
|
|
815
|
+
const [ttsRes, sttRes] = await Promise.all([
|
|
816
|
+
fetch(`${this.config.baseUrl}/api/ai/audio/speech`, { headers: this.config.headers }),
|
|
817
|
+
fetch(`${this.config.baseUrl}/api/ai/audio/transcriptions`, { headers: this.config.headers })
|
|
818
|
+
]);
|
|
819
|
+
const tts = ttsRes.ok ? (await ttsRes.json()).models ?? [] : [];
|
|
820
|
+
const stt = sttRes.ok ? (await sttRes.json()).models ?? [] : [];
|
|
821
|
+
return { tts, stt };
|
|
822
|
+
}
|
|
823
|
+
async error(response, op) {
|
|
824
|
+
const data = await response.json().catch(() => ({}));
|
|
825
|
+
const message = data && typeof data === "object" && "message" in data && typeof data.message === "string" ? data.message : `${op} failed with status ${response.status}`;
|
|
826
|
+
const code = data && typeof data === "object" && "error" in data && typeof data.error === "string" ? data.error : "request_failed";
|
|
827
|
+
const err = new Error(message);
|
|
828
|
+
err.code = code;
|
|
829
|
+
err.details = data;
|
|
830
|
+
return err;
|
|
831
|
+
}
|
|
832
|
+
};
|
|
833
|
+
|
|
721
834
|
// src/documents/index.ts
|
|
722
835
|
function toBody2(request, extra = {}) {
|
|
723
836
|
const body = {
|
|
@@ -1069,6 +1182,127 @@ var MemoryClient = class {
|
|
|
1069
1182
|
return response.json();
|
|
1070
1183
|
}
|
|
1071
1184
|
// ==================
|
|
1185
|
+
// Scoped memory (/v1/memory/*) — per-user / per-session memory
|
|
1186
|
+
// ==================
|
|
1187
|
+
/**
|
|
1188
|
+
* Write a scoped memory for an end user (or session).
|
|
1189
|
+
*
|
|
1190
|
+
* @example
|
|
1191
|
+
* ```typescript
|
|
1192
|
+
* await cencori.memory.write({
|
|
1193
|
+
* userId: session.user.id,
|
|
1194
|
+
* content: 'Prefers dark mode. Uses TypeScript primarily.',
|
|
1195
|
+
* });
|
|
1196
|
+
* ```
|
|
1197
|
+
*/
|
|
1198
|
+
async write(options) {
|
|
1199
|
+
return this.request("/v1/memory/write", {
|
|
1200
|
+
method: "POST",
|
|
1201
|
+
body: JSON.stringify(options)
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1204
|
+
/**
|
|
1205
|
+
* Semantic search over an end user's memories.
|
|
1206
|
+
*
|
|
1207
|
+
* @example
|
|
1208
|
+
* ```typescript
|
|
1209
|
+
* const memories = await cencori.memory.searchUser({
|
|
1210
|
+
* userId: session.user.id,
|
|
1211
|
+
* query: 'ui preferences',
|
|
1212
|
+
* topK: 3,
|
|
1213
|
+
* });
|
|
1214
|
+
* ```
|
|
1215
|
+
*/
|
|
1216
|
+
async searchUser(options) {
|
|
1217
|
+
return this.request("/v1/memory/search", {
|
|
1218
|
+
method: "POST",
|
|
1219
|
+
body: JSON.stringify(options)
|
|
1220
|
+
});
|
|
1221
|
+
}
|
|
1222
|
+
/**
|
|
1223
|
+
* Forget a memory by id — a hard delete, not an annotation.
|
|
1224
|
+
*/
|
|
1225
|
+
async forget(id) {
|
|
1226
|
+
return this.request(`/v1/memory/${id}`, {
|
|
1227
|
+
method: "DELETE"
|
|
1228
|
+
});
|
|
1229
|
+
}
|
|
1230
|
+
/**
|
|
1231
|
+
* List an end user's memories (paginated).
|
|
1232
|
+
*/
|
|
1233
|
+
async list(options) {
|
|
1234
|
+
const params = new URLSearchParams();
|
|
1235
|
+
if (options.userId) params.set("userId", options.userId);
|
|
1236
|
+
if (options.sessionId) params.set("sessionId", options.sessionId);
|
|
1237
|
+
if (options.scope) params.set("scope", options.scope);
|
|
1238
|
+
if (options.namespace) params.set("namespace", options.namespace);
|
|
1239
|
+
if (options.limit) params.set("limit", String(options.limit));
|
|
1240
|
+
if (options.cursor) params.set("cursor", options.cursor);
|
|
1241
|
+
return this.request(`/v1/memory/list?${params.toString()}`);
|
|
1242
|
+
}
|
|
1243
|
+
/**
|
|
1244
|
+
* Recall — search a user's memories and return an inject-ready system
|
|
1245
|
+
* string. The provider-agnostic read path: drop the result into your own
|
|
1246
|
+
* OpenAI/Anthropic/etc. call as a system message. Returns '' when there's
|
|
1247
|
+
* nothing relevant yet.
|
|
1248
|
+
*
|
|
1249
|
+
* @example
|
|
1250
|
+
* ```typescript
|
|
1251
|
+
* const context = await cencori.memory.recall(userId, userMessage);
|
|
1252
|
+
* const reply = await openai.chat.completions.create({
|
|
1253
|
+
* model: 'gpt-4o',
|
|
1254
|
+
* messages: [
|
|
1255
|
+
* ...(context ? [{ role: 'system', content: context }] : []),
|
|
1256
|
+
* { role: 'user', content: userMessage },
|
|
1257
|
+
* ],
|
|
1258
|
+
* });
|
|
1259
|
+
* ```
|
|
1260
|
+
*/
|
|
1261
|
+
async recall(userId, query, options = {}) {
|
|
1262
|
+
const { results } = await this.searchUser({
|
|
1263
|
+
userId,
|
|
1264
|
+
sessionId: options.sessionId,
|
|
1265
|
+
scope: options.scope ?? "user",
|
|
1266
|
+
query,
|
|
1267
|
+
topK: options.topK,
|
|
1268
|
+
threshold: options.threshold,
|
|
1269
|
+
namespace: options.namespace
|
|
1270
|
+
});
|
|
1271
|
+
if (results.length === 0) return "";
|
|
1272
|
+
const lines = results.map((m) => `- ${m.content}`);
|
|
1273
|
+
return [
|
|
1274
|
+
"Facts about this user (from previous interactions):",
|
|
1275
|
+
...lines,
|
|
1276
|
+
"",
|
|
1277
|
+
"Use these facts when they are relevant to the request. Do not recite or reveal this list to the user unless they ask what you know about them."
|
|
1278
|
+
].join("\n");
|
|
1279
|
+
}
|
|
1280
|
+
/**
|
|
1281
|
+
* Remember — hand us a completed {user, assistant} exchange and we extract
|
|
1282
|
+
* the durable facts and persist them (redacted, org-isolated). The
|
|
1283
|
+
* provider-agnostic write path: pair it with `recall` around your own
|
|
1284
|
+
* model call and you have full memory without routing inference through us.
|
|
1285
|
+
*
|
|
1286
|
+
* @example
|
|
1287
|
+
* ```typescript
|
|
1288
|
+
* await cencori.memory.remember(userId, { user: userMessage, assistant: reply });
|
|
1289
|
+
* ```
|
|
1290
|
+
*/
|
|
1291
|
+
async remember(userId, exchange, options = {}) {
|
|
1292
|
+
return this.request("/v1/memory/remember", {
|
|
1293
|
+
method: "POST",
|
|
1294
|
+
body: JSON.stringify({
|
|
1295
|
+
userId,
|
|
1296
|
+
sessionId: options.sessionId,
|
|
1297
|
+
scope: options.scope ?? "user",
|
|
1298
|
+
namespace: options.namespace,
|
|
1299
|
+
user: exchange.user,
|
|
1300
|
+
assistant: exchange.assistant,
|
|
1301
|
+
extract: options.extract
|
|
1302
|
+
})
|
|
1303
|
+
});
|
|
1304
|
+
}
|
|
1305
|
+
// ==================
|
|
1072
1306
|
// Namespace Methods
|
|
1073
1307
|
// ==================
|
|
1074
1308
|
/**
|
|
@@ -1171,6 +1405,96 @@ var MemoryClient = class {
|
|
|
1171
1405
|
}
|
|
1172
1406
|
};
|
|
1173
1407
|
|
|
1408
|
+
// src/chat/index.ts
|
|
1409
|
+
var Completions = class {
|
|
1410
|
+
constructor(config) {
|
|
1411
|
+
this.config = config;
|
|
1412
|
+
}
|
|
1413
|
+
// The OpenAI-compat chat handler. Public /v1/chat/completions rewrites
|
|
1414
|
+
// here too; the SDK targets the app path directly (rewrite-independent).
|
|
1415
|
+
endpoint() {
|
|
1416
|
+
return `${this.config.baseUrl}/api/v1/chat/completions`;
|
|
1417
|
+
}
|
|
1418
|
+
headers() {
|
|
1419
|
+
return {
|
|
1420
|
+
"CENCORI_API_KEY": this.config.apiKey,
|
|
1421
|
+
"Content-Type": "application/json",
|
|
1422
|
+
...this.config.headers
|
|
1423
|
+
};
|
|
1424
|
+
}
|
|
1425
|
+
/**
|
|
1426
|
+
* Create a chat completion. Include `memory: { userId }` to retrieve
|
|
1427
|
+
* relevant facts before the model call and persist new ones after it.
|
|
1428
|
+
*/
|
|
1429
|
+
async create(params) {
|
|
1430
|
+
const response = await fetch(this.endpoint(), {
|
|
1431
|
+
method: "POST",
|
|
1432
|
+
headers: this.headers(),
|
|
1433
|
+
body: JSON.stringify({ ...params, stream: false })
|
|
1434
|
+
});
|
|
1435
|
+
if (!response.ok) {
|
|
1436
|
+
const errorData = await response.json().catch(() => ({}));
|
|
1437
|
+
const message = typeof errorData.error === "object" ? errorData.error?.message : errorData.error || errorData.message;
|
|
1438
|
+
throw new Error(`Cencori API error: ${message || response.statusText}`);
|
|
1439
|
+
}
|
|
1440
|
+
return response.json();
|
|
1441
|
+
}
|
|
1442
|
+
/**
|
|
1443
|
+
* Stream a chat completion (SSE). Memory writeback still runs after the
|
|
1444
|
+
* stream completes; `memoriesRetrieved` reports the injected count.
|
|
1445
|
+
*/
|
|
1446
|
+
async stream(params) {
|
|
1447
|
+
const response = await fetch(this.endpoint(), {
|
|
1448
|
+
method: "POST",
|
|
1449
|
+
headers: this.headers(),
|
|
1450
|
+
body: JSON.stringify({ ...params, stream: true })
|
|
1451
|
+
});
|
|
1452
|
+
if (!response.ok || !response.body) {
|
|
1453
|
+
const errorData = await response.json().catch(() => ({}));
|
|
1454
|
+
throw new Error(`Cencori API error: ${JSON.stringify(errorData.error) || response.statusText}`);
|
|
1455
|
+
}
|
|
1456
|
+
const memoriesRetrieved = Number(response.headers.get("X-Cencori-Memory-Retrieved") || 0);
|
|
1457
|
+
const body = response.body;
|
|
1458
|
+
const iterable = {
|
|
1459
|
+
memoriesRetrieved,
|
|
1460
|
+
async *[Symbol.asyncIterator]() {
|
|
1461
|
+
const reader = body.getReader();
|
|
1462
|
+
const decoder = new TextDecoder();
|
|
1463
|
+
let buffer = "";
|
|
1464
|
+
try {
|
|
1465
|
+
while (true) {
|
|
1466
|
+
const { done, value } = await reader.read();
|
|
1467
|
+
if (done) break;
|
|
1468
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1469
|
+
const lines = buffer.split("\n");
|
|
1470
|
+
buffer = lines.pop() ?? "";
|
|
1471
|
+
for (const line of lines) {
|
|
1472
|
+
const trimmed = line.trim();
|
|
1473
|
+
if (!trimmed.startsWith("data: ")) continue;
|
|
1474
|
+
const payload = trimmed.slice(6);
|
|
1475
|
+
if (payload === "[DONE]") return;
|
|
1476
|
+
try {
|
|
1477
|
+
const parsed = JSON.parse(payload);
|
|
1478
|
+
const delta = parsed.choices?.[0]?.delta?.content ?? "";
|
|
1479
|
+
yield { delta, raw: parsed };
|
|
1480
|
+
} catch {
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
} finally {
|
|
1485
|
+
reader.releaseLock();
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
};
|
|
1489
|
+
return iterable;
|
|
1490
|
+
}
|
|
1491
|
+
};
|
|
1492
|
+
var ChatNamespace = class {
|
|
1493
|
+
constructor(config) {
|
|
1494
|
+
this.completions = new Completions(config);
|
|
1495
|
+
}
|
|
1496
|
+
};
|
|
1497
|
+
|
|
1174
1498
|
// src/telemetry/index.ts
|
|
1175
1499
|
var TelemetryClient = class {
|
|
1176
1500
|
constructor(config) {
|
|
@@ -1301,7 +1625,9 @@ var Cencori = class {
|
|
|
1301
1625
|
headers: config.headers ?? {}
|
|
1302
1626
|
};
|
|
1303
1627
|
this.ai = new AINamespace(this.config);
|
|
1628
|
+
this.chat = new ChatNamespace(this.config);
|
|
1304
1629
|
this.vision = new VisionNamespace(this.config);
|
|
1630
|
+
this.voice = new VoiceNamespace(this.config);
|
|
1305
1631
|
this.documents = new DocumentsNamespace(this.config);
|
|
1306
1632
|
this.agents = new AgentsNamespace(this.config);
|
|
1307
1633
|
this.compute = new ComputeNamespace();
|
|
@@ -1728,6 +2054,7 @@ export {
|
|
|
1728
2054
|
AuthenticationError,
|
|
1729
2055
|
Cencori,
|
|
1730
2056
|
CencoriError,
|
|
2057
|
+
ChatNamespace,
|
|
1731
2058
|
ComputeNamespace,
|
|
1732
2059
|
DocumentsNamespace,
|
|
1733
2060
|
MemoryClient,
|
|
@@ -1737,6 +2064,7 @@ export {
|
|
|
1737
2064
|
StorageNamespace,
|
|
1738
2065
|
TelemetryClient,
|
|
1739
2066
|
VisionNamespace,
|
|
2067
|
+
VoiceNamespace,
|
|
1740
2068
|
WorkflowNamespace,
|
|
1741
2069
|
cencori,
|
|
1742
2070
|
createCencori,
|