@spekoai/sdk 0.3.0 → 0.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/CHANGELOG.md +13 -0
- package/README.md +4 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/lib/client.d.ts +11 -4
- package/dist/lib/client.d.ts.map +1 -1
- package/dist/lib/client.js +23 -8
- package/dist/lib/http.d.ts +14 -0
- package/dist/lib/http.d.ts.map +1 -1
- package/dist/lib/http.js +167 -1
- package/dist/lib/resources/agents.d.ts +68 -0
- package/dist/lib/resources/agents.d.ts.map +1 -0
- package/dist/lib/resources/agents.js +90 -0
- package/dist/lib/resources/complete.d.ts +3 -2
- package/dist/lib/resources/complete.d.ts.map +1 -1
- package/dist/lib/resources/complete.js +31 -2
- package/dist/lib/resources/credits.d.ts +1 -2
- package/dist/lib/resources/credits.d.ts.map +1 -1
- package/dist/lib/resources/credits.js +1 -2
- package/dist/lib/resources/knowledge-bases.d.ts +60 -0
- package/dist/lib/resources/knowledge-bases.d.ts.map +1 -0
- package/dist/lib/resources/knowledge-bases.js +138 -0
- package/dist/lib/resources/phone-numbers.d.ts.map +1 -1
- package/dist/lib/resources/realtime.d.ts +1 -1
- package/dist/lib/resources/realtime.d.ts.map +1 -1
- package/dist/lib/resources/realtime.js +28 -3
- package/dist/lib/resources/synthesize.d.ts +3 -2
- package/dist/lib/resources/synthesize.d.ts.map +1 -1
- package/dist/lib/resources/synthesize.js +32 -4
- package/dist/lib/resources/transcribe.d.ts +3 -2
- package/dist/lib/resources/transcribe.d.ts.map +1 -1
- package/dist/lib/resources/transcribe.js +36 -2
- package/dist/lib/resources/usage.d.ts +1 -1
- package/dist/lib/resources/usage.d.ts.map +1 -1
- package/dist/lib/types/index.d.ts +316 -5
- package/dist/lib/types/index.d.ts.map +1 -1
- package/package.json +3 -3
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { HttpClient } from '../http.js';
|
|
2
2
|
import type { CreditLedgerPage, CreditLedgerQueryParams, OrganizationBalance } from '../types/index.js';
|
|
3
3
|
/**
|
|
4
|
-
* Prepaid credit balance + append-only ledger. Balance is reported in
|
|
5
|
-
* micro-USD (`1_000_000` µ$ = $1) alongside a float USD helper.
|
|
4
|
+
* Prepaid credit balance + append-only ledger. Balance is reported in USD.
|
|
6
5
|
*/
|
|
7
6
|
export declare class Credits {
|
|
8
7
|
private readonly http;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credits.d.ts","sourceRoot":"","sources":["../../../src/lib/resources/credits.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EACV,gBAAgB,EAChB,uBAAuB,EACvB,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAE3B
|
|
1
|
+
{"version":3,"file":"credits.d.ts","sourceRoot":"","sources":["../../../src/lib/resources/credits.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EACV,gBAAgB,EAChB,uBAAuB,EACvB,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAE3B;;GAEG;AACH,qBAAa,OAAO;IACN,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,UAAU;IAE7C;;;;;;;;OAQG;IACH,UAAU,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAI1C;;;;;OAKG;IACH,SAAS,CAAC,MAAM,CAAC,EAAE,uBAAuB,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAQvE"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { HttpClient } from '../http.js';
|
|
2
|
+
import type { KnowledgeBaseCreateParams, KnowledgeBaseDocumentCreateParams, KnowledgeBaseDocumentCreateResult, KnowledgeBaseDocumentPollOptions, KnowledgeBaseDocumentRow, KnowledgeBaseDocumentUploadParams, KnowledgeBaseListParams, KnowledgeBaseRow } from '../types/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Per-agent knowledge bases. Each KB owns documents that get embedded
|
|
5
|
+
* into a Chroma collection so the agent can retrieve relevant chunks
|
|
6
|
+
* during a call. Every agent created via {@link Agents.create}
|
|
7
|
+
* auto-provisions a `Default` KB; additional KBs can be created
|
|
8
|
+
* explicitly with {@link KnowledgeBases.create}.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* const kb = await speko.knowledgeBases.create({
|
|
13
|
+
* agentId: agent.id,
|
|
14
|
+
* name: 'Product FAQ',
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* const doc = await speko.knowledgeBases.uploadDocument(kb.id, {
|
|
18
|
+
* filename: 'faq.md',
|
|
19
|
+
* contentType: 'text/markdown',
|
|
20
|
+
* data: await readFile('faq.md'),
|
|
21
|
+
* });
|
|
22
|
+
*
|
|
23
|
+
* const ready = await speko.knowledgeBases.pollDocumentReady(kb.id, doc.id);
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare class KnowledgeBases {
|
|
27
|
+
private readonly http;
|
|
28
|
+
constructor(http: HttpClient);
|
|
29
|
+
create(params: KnowledgeBaseCreateParams): Promise<KnowledgeBaseRow>;
|
|
30
|
+
list(params?: KnowledgeBaseListParams): Promise<KnowledgeBaseRow[]>;
|
|
31
|
+
get(kbId: string): Promise<KnowledgeBaseRow>;
|
|
32
|
+
delete(kbId: string): Promise<{
|
|
33
|
+
deleted: boolean;
|
|
34
|
+
}>;
|
|
35
|
+
listDocuments(kbId: string): Promise<KnowledgeBaseDocumentRow[]>;
|
|
36
|
+
getDocument(kbId: string, docId: string): Promise<KnowledgeBaseDocumentRow>;
|
|
37
|
+
createDocument(kbId: string, params: KnowledgeBaseDocumentCreateParams): Promise<KnowledgeBaseDocumentCreateResult>;
|
|
38
|
+
finalizeDocument(kbId: string, docId: string): Promise<KnowledgeBaseDocumentRow>;
|
|
39
|
+
deleteDocument(kbId: string, docId: string): Promise<{
|
|
40
|
+
deleted: boolean;
|
|
41
|
+
}>;
|
|
42
|
+
/**
|
|
43
|
+
* Convenience wrapper: register a document, upload its bytes to the
|
|
44
|
+
* signed PUT URL the server mints, then call finalize. Returns the
|
|
45
|
+
* document with status flipped to `processing`. Call
|
|
46
|
+
* {@link pollDocumentReady} to wait for ingest completion.
|
|
47
|
+
*
|
|
48
|
+
* The server's signed upload URL expires 600 seconds after issuance,
|
|
49
|
+
* so do not hold the result of {@link createDocument} for long before
|
|
50
|
+
* uploading. This wrapper performs all three steps back-to-back.
|
|
51
|
+
*/
|
|
52
|
+
uploadDocument(kbId: string, params: KnowledgeBaseDocumentUploadParams): Promise<KnowledgeBaseDocumentRow>;
|
|
53
|
+
/**
|
|
54
|
+
* Poll a document until it reaches `ready` or `failed` status, or the
|
|
55
|
+
* timeout elapses. Throws {@link SpekoApiError} on `failed` (with the
|
|
56
|
+
* server's `errorMessage`) or on timeout.
|
|
57
|
+
*/
|
|
58
|
+
pollDocumentReady(kbId: string, docId: string, opts?: KnowledgeBaseDocumentPollOptions): Promise<KnowledgeBaseDocumentRow>;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=knowledge-bases.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"knowledge-bases.d.ts","sourceRoot":"","sources":["../../../src/lib/resources/knowledge-bases.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EACV,yBAAyB,EACzB,iCAAiC,EACjC,iCAAiC,EACjC,gCAAgC,EAChC,wBAAwB,EACxB,iCAAiC,EACjC,uBAAuB,EACvB,gBAAgB,EACjB,MAAM,mBAAmB,CAAC;AAK3B;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,cAAc;IACb,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,UAAU;IAE7C,MAAM,CAAC,MAAM,EAAE,yBAAyB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAIpE,IAAI,CAAC,MAAM,GAAE,uBAA4B,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAOvE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAI5C,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAMnD,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,EAAE,CAAC;IAMhE,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAM3E,cAAc,CACZ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,iCAAiC,GACxC,OAAO,CAAC,iCAAiC,CAAC;IAO7C,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAOhF,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAM1E;;;;;;;;;OASG;IACG,cAAc,CAClB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,iCAAiC,GACxC,OAAO,CAAC,wBAAwB,CAAC;IA4BpC;;;;OAIG;IACG,iBAAiB,CACrB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,gCAAqC,GAC1C,OAAO,CAAC,wBAAwB,CAAC;CAwBrC"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { SpekoApiError } from '../errors.js';
|
|
2
|
+
const DEFAULT_POLL_INTERVAL_MS = 2_000;
|
|
3
|
+
const DEFAULT_POLL_TIMEOUT_MS = 120_000;
|
|
4
|
+
/**
|
|
5
|
+
* Per-agent knowledge bases. Each KB owns documents that get embedded
|
|
6
|
+
* into a Chroma collection so the agent can retrieve relevant chunks
|
|
7
|
+
* during a call. Every agent created via {@link Agents.create}
|
|
8
|
+
* auto-provisions a `Default` KB; additional KBs can be created
|
|
9
|
+
* explicitly with {@link KnowledgeBases.create}.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* const kb = await speko.knowledgeBases.create({
|
|
14
|
+
* agentId: agent.id,
|
|
15
|
+
* name: 'Product FAQ',
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* const doc = await speko.knowledgeBases.uploadDocument(kb.id, {
|
|
19
|
+
* filename: 'faq.md',
|
|
20
|
+
* contentType: 'text/markdown',
|
|
21
|
+
* data: await readFile('faq.md'),
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* const ready = await speko.knowledgeBases.pollDocumentReady(kb.id, doc.id);
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export class KnowledgeBases {
|
|
28
|
+
http;
|
|
29
|
+
constructor(http) {
|
|
30
|
+
this.http = http;
|
|
31
|
+
}
|
|
32
|
+
create(params) {
|
|
33
|
+
return this.http.post('/v1/knowledge-bases', params);
|
|
34
|
+
}
|
|
35
|
+
list(params = {}) {
|
|
36
|
+
const query = new URLSearchParams();
|
|
37
|
+
if (params.agentId)
|
|
38
|
+
query.set('agentId', params.agentId);
|
|
39
|
+
const qs = query.toString();
|
|
40
|
+
return this.http.get(`/v1/knowledge-bases${qs ? `?${qs}` : ''}`);
|
|
41
|
+
}
|
|
42
|
+
get(kbId) {
|
|
43
|
+
return this.http.get(`/v1/knowledge-bases/${encodeURIComponent(kbId)}`);
|
|
44
|
+
}
|
|
45
|
+
delete(kbId) {
|
|
46
|
+
return this.http.delete(`/v1/knowledge-bases/${encodeURIComponent(kbId)}`);
|
|
47
|
+
}
|
|
48
|
+
listDocuments(kbId) {
|
|
49
|
+
return this.http.get(`/v1/knowledge-bases/${encodeURIComponent(kbId)}/documents`);
|
|
50
|
+
}
|
|
51
|
+
getDocument(kbId, docId) {
|
|
52
|
+
return this.http.get(`/v1/knowledge-bases/${encodeURIComponent(kbId)}/documents/${encodeURIComponent(docId)}`);
|
|
53
|
+
}
|
|
54
|
+
createDocument(kbId, params) {
|
|
55
|
+
return this.http.post(`/v1/knowledge-bases/${encodeURIComponent(kbId)}/documents`, params);
|
|
56
|
+
}
|
|
57
|
+
finalizeDocument(kbId, docId) {
|
|
58
|
+
return this.http.post(`/v1/knowledge-bases/${encodeURIComponent(kbId)}/documents/${encodeURIComponent(docId)}/finalize`, {});
|
|
59
|
+
}
|
|
60
|
+
deleteDocument(kbId, docId) {
|
|
61
|
+
return this.http.delete(`/v1/knowledge-bases/${encodeURIComponent(kbId)}/documents/${encodeURIComponent(docId)}`);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Convenience wrapper: register a document, upload its bytes to the
|
|
65
|
+
* signed PUT URL the server mints, then call finalize. Returns the
|
|
66
|
+
* document with status flipped to `processing`. Call
|
|
67
|
+
* {@link pollDocumentReady} to wait for ingest completion.
|
|
68
|
+
*
|
|
69
|
+
* The server's signed upload URL expires 600 seconds after issuance,
|
|
70
|
+
* so do not hold the result of {@link createDocument} for long before
|
|
71
|
+
* uploading. This wrapper performs all three steps back-to-back.
|
|
72
|
+
*/
|
|
73
|
+
async uploadDocument(kbId, params) {
|
|
74
|
+
const sizeBytes = byteLengthOf(params.data);
|
|
75
|
+
const { document, upload } = await this.createDocument(kbId, {
|
|
76
|
+
filename: params.filename,
|
|
77
|
+
contentType: params.contentType,
|
|
78
|
+
sizeBytes,
|
|
79
|
+
metadata: params.metadata,
|
|
80
|
+
});
|
|
81
|
+
const putResponse = await fetch(upload.url, {
|
|
82
|
+
method: upload.method,
|
|
83
|
+
headers: upload.headers,
|
|
84
|
+
body: toBodyInit(params.data),
|
|
85
|
+
});
|
|
86
|
+
if (!putResponse.ok) {
|
|
87
|
+
const text = await safeReadText(putResponse);
|
|
88
|
+
throw new SpekoApiError(`Document upload failed: ${putResponse.status} ${text || putResponse.statusText}`, putResponse.status, 'DOCUMENT_UPLOAD_FAILED');
|
|
89
|
+
}
|
|
90
|
+
return this.finalizeDocument(kbId, document.id);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Poll a document until it reaches `ready` or `failed` status, or the
|
|
94
|
+
* timeout elapses. Throws {@link SpekoApiError} on `failed` (with the
|
|
95
|
+
* server's `errorMessage`) or on timeout.
|
|
96
|
+
*/
|
|
97
|
+
async pollDocumentReady(kbId, docId, opts = {}) {
|
|
98
|
+
const intervalMs = opts.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
99
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_POLL_TIMEOUT_MS;
|
|
100
|
+
const deadline = Date.now() + timeoutMs;
|
|
101
|
+
while (Date.now() < deadline) {
|
|
102
|
+
const doc = await this.getDocument(kbId, docId);
|
|
103
|
+
if (doc.status === 'ready')
|
|
104
|
+
return doc;
|
|
105
|
+
if (doc.status === 'failed') {
|
|
106
|
+
throw new SpekoApiError(doc.errorMessage ?? 'Document ingest failed', 500, 'DOCUMENT_INGEST_FAILED');
|
|
107
|
+
}
|
|
108
|
+
await delay(intervalMs);
|
|
109
|
+
}
|
|
110
|
+
throw new SpekoApiError(`Document ingest timed out after ${timeoutMs}ms`, 408, 'DOCUMENT_INGEST_TIMEOUT');
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function byteLengthOf(data) {
|
|
114
|
+
if (data instanceof Blob)
|
|
115
|
+
return data.size;
|
|
116
|
+
if (data instanceof Uint8Array)
|
|
117
|
+
return data.byteLength;
|
|
118
|
+
return data.byteLength;
|
|
119
|
+
}
|
|
120
|
+
function toBodyInit(data) {
|
|
121
|
+
if (data instanceof Blob)
|
|
122
|
+
return data;
|
|
123
|
+
if (data instanceof Uint8Array) {
|
|
124
|
+
return data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
|
|
125
|
+
}
|
|
126
|
+
return data;
|
|
127
|
+
}
|
|
128
|
+
async function safeReadText(r) {
|
|
129
|
+
try {
|
|
130
|
+
return await r.text();
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return '';
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function delay(ms) {
|
|
137
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
138
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"phone-numbers.d.ts","sourceRoot":"","sources":["../../../src/lib/resources/phone-numbers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EACV,oBAAoB,EACpB,uBAAuB,EACvB,cAAc,EACd,uBAAuB,EACvB,uBAAuB,EACxB,MAAM,mBAAmB,CAAC;AAE3B;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,UAAU;IAE7C,IAAI,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAIjC;;;;;;;;;;OAUG;IACH,eAAe,
|
|
1
|
+
{"version":3,"file":"phone-numbers.d.ts","sourceRoot":"","sources":["../../../src/lib/resources/phone-numbers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EACV,oBAAoB,EACpB,uBAAuB,EACvB,cAAc,EACd,uBAAuB,EACvB,uBAAuB,EACxB,MAAM,mBAAmB,CAAC;AAE3B;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,UAAU;IAE7C,IAAI,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAIjC;;;;;;;;;;OAUG;IACH,eAAe,CAAC,MAAM,GAAE,uBAA4B,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAWtF,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAIxC,MAAM,CAAC,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAAC,cAAc,CAAC;IAIhE,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAAC,cAAc,CAAC;IAI5E,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;CAGnD"}
|
|
@@ -7,7 +7,7 @@ export declare class Realtime {
|
|
|
7
7
|
* Open a speech-to-speech session. Posts `/v1/sessions` with `mode: 's2s'`
|
|
8
8
|
* to mint a short-lived WebSocket token, then opens a direct WS to the
|
|
9
9
|
* server's S2S proxy. The proxy bridges to the underlying provider
|
|
10
|
-
* (OpenAI Realtime, Gemini Live, xAI Grok Voice) so the client sees a
|
|
10
|
+
* (OpenAI Realtime, Gemini Live, xAI Grok Voice, Inworld) so the client sees a
|
|
11
11
|
* single transport regardless of which backend is in use.
|
|
12
12
|
*/
|
|
13
13
|
connect(params: RealtimeConnectParams): Promise<RealtimeSessionHandle>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../../../src/lib/resources/realtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EACV,qBAAqB,EAGrB,qBAAqB,EACtB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../../../src/lib/resources/realtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EACV,qBAAqB,EAGrB,qBAAqB,EACtB,MAAM,mBAAmB,CAAC;AAY3B,qBAAa,QAAQ;IACP,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,UAAU;IAE7C;;;;;;OAMG;IACG,OAAO,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,qBAAqB,CAAC;CA0B7E"}
|
|
@@ -7,7 +7,7 @@ export class Realtime {
|
|
|
7
7
|
* Open a speech-to-speech session. Posts `/v1/sessions` with `mode: 's2s'`
|
|
8
8
|
* to mint a short-lived WebSocket token, then opens a direct WS to the
|
|
9
9
|
* server's S2S proxy. The proxy bridges to the underlying provider
|
|
10
|
-
* (OpenAI Realtime, Gemini Live, xAI Grok Voice) so the client sees a
|
|
10
|
+
* (OpenAI Realtime, Gemini Live, xAI Grok Voice, Inworld) so the client sees a
|
|
11
11
|
* single transport regardless of which backend is in use.
|
|
12
12
|
*/
|
|
13
13
|
async connect(params) {
|
|
@@ -26,18 +26,22 @@ export class Realtime {
|
|
|
26
26
|
metadata: params.metadata,
|
|
27
27
|
ttlSeconds: params.ttlSeconds,
|
|
28
28
|
});
|
|
29
|
-
return new BrowserRealtimeHandle(response.sessionId, response.wsUrl, response.wsToken, response.expiresAt);
|
|
29
|
+
return new BrowserRealtimeHandle(response.sessionId, response.wsUrl, response.wsToken, response.expiresAt, response.inputSampleRate, response.outputSampleRate);
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
class BrowserRealtimeHandle {
|
|
33
33
|
sessionId;
|
|
34
34
|
expiresAt;
|
|
35
|
+
inputSampleRate;
|
|
36
|
+
outputSampleRate;
|
|
35
37
|
ws;
|
|
36
38
|
handlers = new Set();
|
|
37
39
|
closed = false;
|
|
38
|
-
constructor(sessionId, wsUrl, wsToken, expiresAt) {
|
|
40
|
+
constructor(sessionId, wsUrl, wsToken, expiresAt, inputSampleRate, outputSampleRate) {
|
|
39
41
|
this.sessionId = sessionId;
|
|
40
42
|
this.expiresAt = expiresAt;
|
|
43
|
+
this.inputSampleRate = inputSampleRate;
|
|
44
|
+
this.outputSampleRate = outputSampleRate;
|
|
41
45
|
// Pass the token as the first subprotocol — browsers can't set headers
|
|
42
46
|
// on `new WebSocket()`, so subprotocol is the only auth carrier that
|
|
43
47
|
// doesn't leak through URL params.
|
|
@@ -134,6 +138,27 @@ class BrowserRealtimeHandle {
|
|
|
134
138
|
final: Boolean(parsed['final']),
|
|
135
139
|
});
|
|
136
140
|
break;
|
|
141
|
+
case 'ready':
|
|
142
|
+
this.emit({
|
|
143
|
+
type: 'ready',
|
|
144
|
+
inputSampleRate: Number(parsed['inputSampleRate'] ?? this.inputSampleRate),
|
|
145
|
+
outputSampleRate: Number(parsed['outputSampleRate'] ?? this.outputSampleRate),
|
|
146
|
+
});
|
|
147
|
+
break;
|
|
148
|
+
case 'interruption':
|
|
149
|
+
this.emit({
|
|
150
|
+
type: 'interruption',
|
|
151
|
+
at: parsed['at'] === 'assistant' ? 'assistant' : 'user',
|
|
152
|
+
});
|
|
153
|
+
break;
|
|
154
|
+
case 'server_tool_call':
|
|
155
|
+
this.emit({
|
|
156
|
+
type: 'server_tool_call',
|
|
157
|
+
id: String(parsed['id'] ?? ''),
|
|
158
|
+
name: String(parsed['name'] ?? ''),
|
|
159
|
+
status: String(parsed['status'] ?? 'started'),
|
|
160
|
+
});
|
|
161
|
+
break;
|
|
137
162
|
case 'tool_call':
|
|
138
163
|
this.emit({
|
|
139
164
|
type: 'tool_call',
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { HttpClient } from '../http.js';
|
|
2
|
-
import type { SynthesizeOptions, SynthesizeResult } from '../types/index.js';
|
|
2
|
+
import type { SynthesizeOptions, SynthesizeResult, SynthesizeStreamResult } from '../types/index.js';
|
|
3
3
|
export declare class Synthesize {
|
|
4
4
|
private readonly http;
|
|
5
5
|
constructor(http: HttpClient);
|
|
6
6
|
/**
|
|
7
7
|
* Synthesize text into audio. The Speko router picks the best TTS provider
|
|
8
|
-
* for your `(language, optimizeFor)` and falls over automatically.
|
|
8
|
+
* for your `(language, region, optimizeFor)` and falls over automatically.
|
|
9
9
|
*
|
|
10
10
|
* The returned audio's format depends on the chosen provider — check the
|
|
11
11
|
* `contentType` field on the result. ElevenLabs returns `audio/mpeg`,
|
|
@@ -20,5 +20,6 @@ export declare class Synthesize {
|
|
|
20
20
|
* ```
|
|
21
21
|
*/
|
|
22
22
|
call(text: string, options: SynthesizeOptions, abortSignal?: AbortSignal): Promise<SynthesizeResult>;
|
|
23
|
+
stream(text: string, options: SynthesizeOptions, abortSignal?: AbortSignal): Promise<SynthesizeStreamResult>;
|
|
23
24
|
}
|
|
24
25
|
//# sourceMappingURL=synthesize.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"synthesize.d.ts","sourceRoot":"","sources":["../../../src/lib/resources/synthesize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EACV,iBAAiB,EACjB,gBAAgB,
|
|
1
|
+
{"version":3,"file":"synthesize.d.ts","sourceRoot":"","sources":["../../../src/lib/resources/synthesize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EACV,iBAAiB,EACjB,gBAAgB,EAChB,sBAAsB,EACvB,MAAM,mBAAmB,CAAC;AAE3B,qBAAa,UAAU;IACT,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,UAAU;IAE7C;;;;;;;;;;;;;;;OAeG;IACG,IAAI,CACR,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,iBAAiB,EAC1B,WAAW,CAAC,EAAE,WAAW,GACxB,OAAO,CAAC,gBAAgB,CAAC;IAiBtB,MAAM,CACV,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,iBAAiB,EAC1B,WAAW,CAAC,EAAE,WAAW,GACxB,OAAO,CAAC,sBAAsB,CAAC;CAgCnC"}
|
|
@@ -5,7 +5,7 @@ export class Synthesize {
|
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
7
|
* Synthesize text into audio. The Speko router picks the best TTS provider
|
|
8
|
-
* for your `(language, optimizeFor)` and falls over automatically.
|
|
8
|
+
* for your `(language, region, optimizeFor)` and falls over automatically.
|
|
9
9
|
*
|
|
10
10
|
* The returned audio's format depends on the chosen provider — check the
|
|
11
11
|
* `contentType` field on the result. ElevenLabs returns `audio/mpeg`,
|
|
@@ -20,6 +20,21 @@ export class Synthesize {
|
|
|
20
20
|
* ```
|
|
21
21
|
*/
|
|
22
22
|
async call(text, options, abortSignal) {
|
|
23
|
+
const streamed = await this.stream(text, options, abortSignal);
|
|
24
|
+
const chunks = [];
|
|
25
|
+
for await (const chunk of streamed) {
|
|
26
|
+
chunks.push(chunk);
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
audio: concatChunks(chunks),
|
|
30
|
+
contentType: streamed.contentType,
|
|
31
|
+
provider: streamed.provider,
|
|
32
|
+
model: streamed.model,
|
|
33
|
+
failoverCount: streamed.failoverCount,
|
|
34
|
+
scoresRunId: streamed.scoresRunId,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
async stream(text, options, abortSignal) {
|
|
23
38
|
const intent = {
|
|
24
39
|
language: options.language,
|
|
25
40
|
...(options.region !== undefined && { region: options.region }),
|
|
@@ -32,14 +47,27 @@ export class Synthesize {
|
|
|
32
47
|
body['speed'] = options.speed;
|
|
33
48
|
if (options.constraints !== undefined)
|
|
34
49
|
body['constraints'] = options.constraints;
|
|
35
|
-
const {
|
|
36
|
-
|
|
37
|
-
audio: bytes,
|
|
50
|
+
const { chunks, headers } = await this.http.requestBinaryStream('POST', '/v1/synthesize', body, abortSignal);
|
|
51
|
+
const result = {
|
|
38
52
|
contentType: headers['content-type'] ?? 'application/octet-stream',
|
|
39
53
|
provider: headers['x-speko-provider'] ?? 'unknown',
|
|
40
54
|
model: headers['x-speko-model'] ?? 'unknown',
|
|
41
55
|
failoverCount: parseInt(headers['x-speko-failover-count'] ?? '0', 10),
|
|
42
56
|
scoresRunId: headers['x-speko-scores-run-id'] || null,
|
|
57
|
+
[Symbol.asyncIterator]() {
|
|
58
|
+
return chunks;
|
|
59
|
+
},
|
|
43
60
|
};
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function concatChunks(chunks) {
|
|
65
|
+
const total = chunks.reduce((sum, chunk) => sum + chunk.byteLength, 0);
|
|
66
|
+
const out = new Uint8Array(total);
|
|
67
|
+
let offset = 0;
|
|
68
|
+
for (const chunk of chunks) {
|
|
69
|
+
out.set(chunk, offset);
|
|
70
|
+
offset += chunk.byteLength;
|
|
44
71
|
}
|
|
72
|
+
return out;
|
|
45
73
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { HttpClient } from '../http.js';
|
|
2
|
-
import type { TranscribeOptions, TranscribeResult } from '../types/index.js';
|
|
2
|
+
import type { TranscribeOptions, TranscribeResult, TranscribeStreamEvent } from '../types/index.js';
|
|
3
3
|
export declare class Transcribe {
|
|
4
4
|
private readonly http;
|
|
5
5
|
constructor(http: HttpClient);
|
|
6
6
|
/**
|
|
7
7
|
* Transcribe audio. The Speko router picks the best STT provider for
|
|
8
|
-
* your `(language, optimizeFor)` and falls over automatically.
|
|
8
|
+
* your `(language, region, optimizeFor)` and falls over automatically.
|
|
9
9
|
*
|
|
10
10
|
* @example
|
|
11
11
|
* ```ts
|
|
@@ -16,5 +16,6 @@ export declare class Transcribe {
|
|
|
16
16
|
* ```
|
|
17
17
|
*/
|
|
18
18
|
call(audio: Uint8Array, options: TranscribeOptions, abortSignal?: AbortSignal): Promise<TranscribeResult>;
|
|
19
|
+
stream(audio: Uint8Array, options: TranscribeOptions, abortSignal?: AbortSignal): AsyncIterableIterator<TranscribeStreamEvent>;
|
|
19
20
|
}
|
|
20
21
|
//# sourceMappingURL=transcribe.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transcribe.d.ts","sourceRoot":"","sources":["../../../src/lib/resources/transcribe.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"transcribe.d.ts","sourceRoot":"","sources":["../../../src/lib/resources/transcribe.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAEpG,qBAAa,UAAU;IACT,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,UAAU;IAE7C;;;;;;;;;;;OAWG;IACG,IAAI,CACR,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,iBAAiB,EAC1B,WAAW,CAAC,EAAE,WAAW,GACxB,OAAO,CAAC,gBAAgB,CAAC;IAsBrB,MAAM,CACX,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,iBAAiB,EAC1B,WAAW,CAAC,EAAE,WAAW,GACxB,qBAAqB,CAAC,qBAAqB,CAAC;CAkChD"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SpekoApiError } from '../errors.js';
|
|
1
2
|
export class Transcribe {
|
|
2
3
|
http;
|
|
3
4
|
constructor(http) {
|
|
@@ -5,7 +6,7 @@ export class Transcribe {
|
|
|
5
6
|
}
|
|
6
7
|
/**
|
|
7
8
|
* Transcribe audio. The Speko router picks the best STT provider for
|
|
8
|
-
* your `(language, optimizeFor)` and falls over automatically.
|
|
9
|
+
* your `(language, region, optimizeFor)` and falls over automatically.
|
|
9
10
|
*
|
|
10
11
|
* @example
|
|
11
12
|
* ```ts
|
|
@@ -16,6 +17,28 @@ export class Transcribe {
|
|
|
16
17
|
* ```
|
|
17
18
|
*/
|
|
18
19
|
async call(audio, options, abortSignal) {
|
|
20
|
+
let done;
|
|
21
|
+
for await (const event of this.stream(audio, options, abortSignal)) {
|
|
22
|
+
if (event.type === 'done') {
|
|
23
|
+
done = {
|
|
24
|
+
text: event.text,
|
|
25
|
+
provider: event.provider,
|
|
26
|
+
model: event.model,
|
|
27
|
+
confidence: event.confidence,
|
|
28
|
+
failoverCount: event.failoverCount,
|
|
29
|
+
scoresRunId: event.scoresRunId,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
else if (event.type === 'error') {
|
|
33
|
+
throw new SpekoApiError(event.error, 200, event.code);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (!done) {
|
|
37
|
+
throw new SpekoApiError('Transcribe stream ended without a done event', 200, 'STREAM_ENDED');
|
|
38
|
+
}
|
|
39
|
+
return done;
|
|
40
|
+
}
|
|
41
|
+
async *stream(audio, options, abortSignal) {
|
|
19
42
|
const intent = {
|
|
20
43
|
language: options.language,
|
|
21
44
|
...(options.region !== undefined && { region: options.region }),
|
|
@@ -28,6 +51,17 @@ export class Transcribe {
|
|
|
28
51
|
if (options.constraints) {
|
|
29
52
|
headers['X-Speko-Constraints'] = JSON.stringify(options.constraints);
|
|
30
53
|
}
|
|
31
|
-
|
|
54
|
+
if (options.keywords && options.keywords.length > 0) {
|
|
55
|
+
headers['X-Speko-Stt-Options'] = JSON.stringify({
|
|
56
|
+
keywords: [...options.keywords],
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
const stream = await this.http.requestRawSse('POST', '/v1/transcribe', audio, headers, abortSignal);
|
|
60
|
+
for await (const event of stream) {
|
|
61
|
+
yield {
|
|
62
|
+
...event.data,
|
|
63
|
+
type: event.event,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
32
66
|
}
|
|
33
67
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { HttpClient } from '../http.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { UsageQueryParams, UsageSummary } from '../types/index.js';
|
|
3
3
|
export declare class Usage {
|
|
4
4
|
private readonly http;
|
|
5
5
|
constructor(http: HttpClient);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../../src/lib/resources/usage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../../src/lib/resources/usage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAExE,qBAAa,KAAK;IACJ,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,UAAU;IAE7C;;;;;;;;OAQG;IACG,GAAG,CAAC,MAAM,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;CAQ5D"}
|