@vertesia/client 1.6.0-dev.20260918.090710Z → 1.6.0-dev.20260923.085325Z
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/lib/AppsApi.d.ts +5 -0
- package/lib/AppsApi.d.ts.map +1 -1
- package/lib/AppsApi.js +9 -0
- package/lib/AppsApi.js.map +1 -1
- package/lib/EnvironmentsApi.d.ts +6 -1
- package/lib/EnvironmentsApi.d.ts.map +1 -1
- package/lib/EnvironmentsApi.js +15 -0
- package/lib/EnvironmentsApi.js.map +1 -1
- package/lib/InteractionBase.d.ts +138 -62
- package/lib/InteractionBase.d.ts.map +1 -1
- package/lib/InteractionOutput.d.ts +4 -0
- package/lib/InteractionOutput.d.ts.map +1 -1
- package/lib/InteractionOutput.js +13 -0
- package/lib/InteractionOutput.js.map +1 -1
- package/lib/InternalAccountsApi.d.ts +7 -0
- package/lib/InternalAccountsApi.d.ts.map +1 -0
- package/lib/InternalAccountsApi.js +10 -0
- package/lib/InternalAccountsApi.js.map +1 -0
- package/lib/OAuthServerApi.d.ts +2 -1
- package/lib/OAuthServerApi.d.ts.map +1 -1
- package/lib/OAuthServerApi.js +3 -0
- package/lib/OAuthServerApi.js.map +1 -1
- package/lib/client.d.ts +2 -0
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +3 -0
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/store/AgentsApi.d.ts.map +1 -1
- package/lib/store/AgentsApi.js +15 -0
- package/lib/store/AgentsApi.js.map +1 -1
- package/lib/store/EmbeddingsApi.d.ts +8 -2
- package/lib/store/EmbeddingsApi.d.ts.map +1 -1
- package/lib/store/EmbeddingsApi.js +20 -2
- package/lib/store/EmbeddingsApi.js.map +1 -1
- package/lib/vertesia-client.js +4 -4
- package/lib/vertesia-client.js.map +1 -1
- package/package.json +7 -7
- package/src/AppsApi.ts +11 -0
- package/src/EnvironmentsApi.ts +28 -0
- package/src/InteractionOutput.test.ts +14 -0
- package/src/InteractionOutput.ts +15 -0
- package/src/InternalAccountsApi.ts +12 -0
- package/src/OAuthServerApi.ts +6 -0
- package/src/app-session.test.ts +23 -0
- package/src/client.ts +5 -0
- package/src/index.ts +1 -0
- package/src/store/AgentsApi.stream.test.ts +33 -1
- package/src/store/AgentsApi.ts +17 -0
- package/src/store/EmbeddingsApi.test.ts +31 -0
- package/src/store/EmbeddingsApi.ts +47 -2
- package/src/store/FilesApi.test.ts +13 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vertesia/client",
|
|
3
|
-
"version": "1.6.0-dev.
|
|
3
|
+
"version": "1.6.0-dev.20260923.085325Z",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"types": "./lib/index.d.ts",
|
|
@@ -11,16 +11,16 @@
|
|
|
11
11
|
],
|
|
12
12
|
"license": "Apache-2.0",
|
|
13
13
|
"devDependencies": {
|
|
14
|
-
"@types/node": "^24.13.
|
|
14
|
+
"@types/node": "^24.13.5",
|
|
15
15
|
"@vertesia/tsconfig": "0.1.0",
|
|
16
16
|
"rolldown": "1.2.8",
|
|
17
17
|
"typescript": "7.0.2",
|
|
18
|
-
"vitest": "5.0.
|
|
18
|
+
"vitest": "5.0.1"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@llumiverse/common": "1.6.0-dev.
|
|
22
|
-
"@vertesia/api-fetch-client": "1.6.0-dev.
|
|
23
|
-
"@vertesia/common": "1.6.0-dev.
|
|
21
|
+
"@llumiverse/common": "1.6.0-dev.20260923.085100Z",
|
|
22
|
+
"@vertesia/api-fetch-client": "1.6.0-dev.20260923.085325Z",
|
|
23
|
+
"@vertesia/common": "1.6.0-dev.20260923.085325Z",
|
|
24
24
|
"eventsource": "^5.1.1"
|
|
25
25
|
},
|
|
26
26
|
"exports": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"ai",
|
|
49
49
|
"typescript"
|
|
50
50
|
],
|
|
51
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "8732631fd8099bdcab4f5375da2309f3cff34e19",
|
|
52
52
|
"scripts": {
|
|
53
53
|
"lint": "biome lint src",
|
|
54
54
|
"clean:lib": "rimraf ./lib ./tsconfig.tsbuildinfo",
|
package/src/AppsApi.ts
CHANGED
|
@@ -39,6 +39,7 @@ import type {
|
|
|
39
39
|
StartAppDevelopmentTaskRequest,
|
|
40
40
|
StartAppScaffoldRequest,
|
|
41
41
|
StartAppScaffoldResponse,
|
|
42
|
+
UpdateAppInstallationOAuthApprovalPayload,
|
|
42
43
|
UpdateAppInstallationToolAllowlistPayload,
|
|
43
44
|
UpdateAppPayload,
|
|
44
45
|
UpsertAppVersionRequest,
|
|
@@ -429,6 +430,16 @@ export default class AppsApi extends ApiTopic {
|
|
|
429
430
|
});
|
|
430
431
|
}
|
|
431
432
|
|
|
433
|
+
/**
|
|
434
|
+
* Set project-admin approval for an installation's OAuth scopes.
|
|
435
|
+
* Pass an empty list to revoke approval.
|
|
436
|
+
*/
|
|
437
|
+
updateOAuthApproval(installId: string, approved_scopes: string[]): Promise<AppInstallationWithManifest> {
|
|
438
|
+
return this.put(`/installations/${installId}/oauth-approval`, {
|
|
439
|
+
payload: { approved_scopes } satisfies UpdateAppInstallationOAuthApprovalPayload,
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
|
|
432
443
|
/**
|
|
433
444
|
* Update the tool allowlist for an app installation.
|
|
434
445
|
* Pass null to remove all restrictions (all tools permitted).
|
package/src/EnvironmentsApi.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { AIModel, ModelSearchPayload } from '@llumiverse/common';
|
|
2
2
|
import { ApiTopic, type ClientBase } from '@vertesia/api-fetch-client';
|
|
3
3
|
import type {
|
|
4
|
+
EmbeddingBatchCapabilityRequest,
|
|
5
|
+
EmbeddingBatchCapabilityResponse,
|
|
6
|
+
EmbeddingBatchCreateRequest,
|
|
7
|
+
EmbeddingBatchJobRequest,
|
|
8
|
+
EmbeddingBatchJobResponse,
|
|
4
9
|
EmbeddingsApiRequest,
|
|
5
10
|
EmbeddingsApiResult,
|
|
6
11
|
EnableEnvironmentModelPayload,
|
|
@@ -84,6 +89,29 @@ export default class EnvironmentsApi extends ApiTopic {
|
|
|
84
89
|
});
|
|
85
90
|
}
|
|
86
91
|
|
|
92
|
+
embeddingBatchCapability(
|
|
93
|
+
id: string,
|
|
94
|
+
payload: EmbeddingBatchCapabilityRequest,
|
|
95
|
+
): Promise<EmbeddingBatchCapabilityResponse> {
|
|
96
|
+
return this.post(`/${id}/embedding-batches/capability`, { payload });
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
createEmbeddingBatch(id: string, payload: EmbeddingBatchCreateRequest): Promise<EmbeddingBatchJobResponse> {
|
|
100
|
+
return this.post(`/${id}/embedding-batches`, { payload });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
getEmbeddingBatch(id: string, payload: EmbeddingBatchJobRequest): Promise<EmbeddingBatchJobResponse> {
|
|
104
|
+
return this.post(`/${id}/embedding-batches/get`, { payload });
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
cancelEmbeddingBatch(id: string, payload: EmbeddingBatchJobRequest): Promise<EmbeddingBatchJobResponse> {
|
|
108
|
+
return this.post(`/${id}/embedding-batches/cancel`, { payload });
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
deleteEmbeddingBatch(id: string, payload: EmbeddingBatchJobRequest): Promise<EmbeddingBatchJobResponse> {
|
|
112
|
+
return this.post(`/${id}/embedding-batches/delete`, { payload });
|
|
113
|
+
}
|
|
114
|
+
|
|
87
115
|
/**
|
|
88
116
|
* Batch update the LLM Environment for multiple Interactions, including the model used and the
|
|
89
117
|
* Environment that they belong to.
|
|
@@ -3,6 +3,20 @@ import { describe, expect, it } from 'vitest';
|
|
|
3
3
|
import { InteractionOutput, IS_INTERACTION_OUTPUT } from './InteractionOutput.js';
|
|
4
4
|
|
|
5
5
|
describe('InteractionOutput', () => {
|
|
6
|
+
it('exposes audio metadata and URI without treating it as text or JSON', () => {
|
|
7
|
+
const audio = {
|
|
8
|
+
type: 'audio' as const,
|
|
9
|
+
value: 'gs://bucket/speech.mp3',
|
|
10
|
+
mime_type: 'audio/mpeg',
|
|
11
|
+
container: 'mp3',
|
|
12
|
+
};
|
|
13
|
+
const output = InteractionOutput.from([audio]);
|
|
14
|
+
expect(output.hasAudio()).toBe(true);
|
|
15
|
+
expect(output.audio()).toEqual(audio);
|
|
16
|
+
expect(output.audios()).toEqual([audio]);
|
|
17
|
+
expect(output.text()).toBe('');
|
|
18
|
+
});
|
|
19
|
+
|
|
6
20
|
const sampleResults: CompletionResult[] = [
|
|
7
21
|
{ type: 'text', value: 'Hello, ' },
|
|
8
22
|
{ type: 'text', value: 'World!' },
|
package/src/InteractionOutput.ts
CHANGED
|
@@ -217,6 +217,21 @@ export class InteractionOutput<T = unknown> {
|
|
|
217
217
|
return this.results.filter((r) => r.type === 'image').map((r) => r.value);
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
+
hasAudio(): boolean {
|
|
221
|
+
return this.results.some((r) => r.type === 'audio');
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** Get complete audio metadata and its durable file reference. */
|
|
225
|
+
audios() {
|
|
226
|
+
return this.results.filter((r) => r.type === 'audio');
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
audio() {
|
|
230
|
+
const result = this.audios()[0];
|
|
231
|
+
if (!result) throw new Error('No audio result found');
|
|
232
|
+
return result;
|
|
233
|
+
}
|
|
234
|
+
|
|
220
235
|
/** Get the first video result URI. */
|
|
221
236
|
video(): string {
|
|
222
237
|
const videoResult = this.results.find((r) => r.type === 'video');
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ApiTopic, type ClientBase } from '@vertesia/api-fetch-client';
|
|
2
|
+
import type { AccountApiVersionPolicy } from '@vertesia/common';
|
|
3
|
+
|
|
4
|
+
export default class InternalAccountsApi extends ApiTopic {
|
|
5
|
+
constructor(parent: ClientBase) {
|
|
6
|
+
super(parent, '/internal/accounts');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
getApiVersionPolicy(accountId: string): Promise<AccountApiVersionPolicy> {
|
|
10
|
+
return this.get(`/${encodeURIComponent(accountId)}/api-version-policy`);
|
|
11
|
+
}
|
|
12
|
+
}
|
package/src/OAuthServerApi.ts
CHANGED
|
@@ -7,6 +7,8 @@ import type {
|
|
|
7
7
|
OAuthDeviceAuthorizationRequest,
|
|
8
8
|
OAuthDeviceAuthorizationResponse,
|
|
9
9
|
OAuthGrantableScopesResponse,
|
|
10
|
+
OAuthLoginDecisionResponse,
|
|
11
|
+
OAuthLoginPayload,
|
|
10
12
|
} from '@vertesia/common';
|
|
11
13
|
|
|
12
14
|
export default class OAuthServerApi extends ClientBase {
|
|
@@ -20,6 +22,10 @@ export default class OAuthServerApi extends ClientBase {
|
|
|
20
22
|
this.verboseErrors = parent.verboseErrors;
|
|
21
23
|
}
|
|
22
24
|
|
|
25
|
+
login(requestId: string, payload: OAuthLoginPayload): Promise<OAuthLoginDecisionResponse> {
|
|
26
|
+
return this.post(`/requests/${encodeURIComponent(requestId)}/login`, { payload });
|
|
27
|
+
}
|
|
28
|
+
|
|
23
29
|
get headers() {
|
|
24
30
|
return this.parent.headers;
|
|
25
31
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { expect, it, vi } from 'vitest';
|
|
2
|
+
import { VertesiaClient } from './client.js';
|
|
3
|
+
|
|
4
|
+
it('mints an app session through STS with the caller authorization and declared scopes', async () => {
|
|
5
|
+
const transport = vi.fn<typeof fetch>(async () =>
|
|
6
|
+
Response.json({ token: 'scoped', token_type: 'Bearer', expires_in: 900 }),
|
|
7
|
+
);
|
|
8
|
+
const client = new VertesiaClient({
|
|
9
|
+
serverUrl: 'https://api.example',
|
|
10
|
+
storeUrl: 'https://store.example',
|
|
11
|
+
tokenServerUrl: 'https://sts.example',
|
|
12
|
+
apikey: 'caller',
|
|
13
|
+
fetch: transport,
|
|
14
|
+
});
|
|
15
|
+
const result = await client.mintAppSessionToken({ app_name: 'analytics', scopes: ['content:read'] });
|
|
16
|
+
expect(result.token).toBe('scoped');
|
|
17
|
+
const [url, options] = transport.mock.calls[0];
|
|
18
|
+
const request = new Request(url, options);
|
|
19
|
+
expect(request.url).toBe('https://sts.example/token/app-session');
|
|
20
|
+
expect(request.method).toBe('POST');
|
|
21
|
+
expect(request.headers.get('authorization')).toBe('Bearer caller');
|
|
22
|
+
expect(await request.json()).toEqual({ app_name: 'analytics', scopes: ['content:read'] });
|
|
23
|
+
});
|
package/src/client.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AbstractFetchClient, type FETCH_FN, type IRequestRetryPolicy } from '@vertesia/api-fetch-client';
|
|
2
|
+
import type { AppSessionTokenRequest, AppSessionTokenResponse } from '@vertesia/common';
|
|
2
3
|
import { APP_VERSION_HEADER, type AuthTokenPayload, type AuthTokenResponse } from '@vertesia/common';
|
|
3
4
|
import AccountApi from './AccountApi.js';
|
|
4
5
|
import AccountsApi from './AccountsApi.js';
|
|
@@ -412,6 +413,10 @@ export class VertesiaClient extends AbstractFetchClient<VertesiaClient> {
|
|
|
412
413
|
*
|
|
413
414
|
* @returns AuthTokenResponse
|
|
414
415
|
*/
|
|
416
|
+
async mintAppSessionToken(request: AppSessionTokenRequest): Promise<AppSessionTokenResponse> {
|
|
417
|
+
return this.post<AppSessionTokenResponse>(`${this.tokenServerUrl}/token/app-session`, { payload: request });
|
|
418
|
+
}
|
|
419
|
+
|
|
415
420
|
async getAuthToken(token?: string): Promise<AuthTokenResponse> {
|
|
416
421
|
// Route through the base client (absolute URL) so the call benefits from the
|
|
417
422
|
// retry policy. The default retry methods exclude POST as non-idempotent, but
|
package/src/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ export { default as DelegationGrantsApi } from './DelegationGrantsApi.js';
|
|
|
7
7
|
export type { GroupsQueryOptions } from './GroupsApi.js';
|
|
8
8
|
export * from './InteractionBase.js';
|
|
9
9
|
export * from './InteractionOutput.js';
|
|
10
|
+
export { default as InternalAccountsApi } from './InternalAccountsApi.js';
|
|
10
11
|
export { default as InternalSecretsApi } from './InternalSecretsApi.js';
|
|
11
12
|
export * from './managed-sse.js';
|
|
12
13
|
export { default as OAuthClientsApi } from './OAuthClientsApi.js';
|
|
@@ -72,7 +72,16 @@ function createHarness(): Harness {
|
|
|
72
72
|
}
|
|
73
73
|
const since = Number(url.searchParams.get('since') ?? 0);
|
|
74
74
|
pollSince.push(since);
|
|
75
|
-
|
|
75
|
+
try {
|
|
76
|
+
return Response.json({ messages: pollResponse(since) });
|
|
77
|
+
} catch (err) {
|
|
78
|
+
// A thrown error carrying `status` models an HTTP error response (e.g. 404).
|
|
79
|
+
const status = (err as { status?: unknown }).status;
|
|
80
|
+
if (typeof status === 'number') {
|
|
81
|
+
return Response.json({ error: (err as Error).message }, { status });
|
|
82
|
+
}
|
|
83
|
+
throw err;
|
|
84
|
+
}
|
|
76
85
|
}
|
|
77
86
|
if (url.pathname.endsWith(`/${AGENT_RUN_ID}`)) {
|
|
78
87
|
return Response.json({ id: AGENT_RUN_ID, status: runStatus });
|
|
@@ -337,6 +346,29 @@ describe('AgentsApi.streamMessages reconnection', () => {
|
|
|
337
346
|
await settle();
|
|
338
347
|
});
|
|
339
348
|
|
|
349
|
+
it('stops the polling fallback when the run no longer exists (404)', async () => {
|
|
350
|
+
const harness = createHarness();
|
|
351
|
+
harness.setHistory([{ t: AgentMessageType.UPDATE, m: 'history', ts: 1000 }]);
|
|
352
|
+
harness.setPollResponse(() => {
|
|
353
|
+
throw Object.assign(new Error('Not Found: Agent run not found'), { status: 404 });
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
const abort = new AbortController();
|
|
357
|
+
const done = harness.client.agents.streamMessages(AGENT_RUN_ID, undefined, undefined, abort.signal);
|
|
358
|
+
await settle();
|
|
359
|
+
|
|
360
|
+
for (let i = 0; i < 11; i++) {
|
|
361
|
+
await failCurrentConnection();
|
|
362
|
+
}
|
|
363
|
+
await settle(6000);
|
|
364
|
+
|
|
365
|
+
await expect(done).resolves.toBeNull();
|
|
366
|
+
expect(warnings.some((line) => line.includes('the run no longer exists (404)'))).toBe(true);
|
|
367
|
+
// A single 404 ends the loop: no retry warning, no further poll after the exit.
|
|
368
|
+
expect(warnings.filter((line) => line.includes('GET /updates failed while polling'))).toEqual([]);
|
|
369
|
+
expect(harness.pollSince).toHaveLength(1);
|
|
370
|
+
});
|
|
371
|
+
|
|
340
372
|
it('closes the stream when polling observes a terminal run status', async () => {
|
|
341
373
|
const harness = createHarness();
|
|
342
374
|
const abort = new AbortController();
|
package/src/store/AgentsApi.ts
CHANGED
|
@@ -435,6 +435,15 @@ export class AgentsApi extends ApiTopic {
|
|
|
435
435
|
);
|
|
436
436
|
};
|
|
437
437
|
|
|
438
|
+
// A 404 while polling means the run itself is gone (deleted, or never persisted): nothing
|
|
439
|
+
// will ever arrive, so stop instead of polling the missing resource every 5s forever.
|
|
440
|
+
const isRunGone = (error: unknown): boolean =>
|
|
441
|
+
typeof error === 'object' && error !== null && (error as { status?: unknown }).status === 404;
|
|
442
|
+
const exitBecauseRunGone = () => {
|
|
443
|
+
console.warn(`Agent stream ${id}: the run no longer exists (404); stopping the polling fallback.`);
|
|
444
|
+
exit(null);
|
|
445
|
+
};
|
|
446
|
+
|
|
438
447
|
const pollTick = async () => {
|
|
439
448
|
if (isClosed || !isPolling) return;
|
|
440
449
|
let polledMessages = false;
|
|
@@ -456,6 +465,10 @@ export class AgentsApi extends ApiTopic {
|
|
|
456
465
|
}
|
|
457
466
|
}
|
|
458
467
|
} catch (err) {
|
|
468
|
+
if (isRunGone(err)) {
|
|
469
|
+
exitBecauseRunGone();
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
459
472
|
warnPollFailure('GET /updates', err);
|
|
460
473
|
}
|
|
461
474
|
if (isClosed || !isPolling) return;
|
|
@@ -468,6 +481,10 @@ export class AgentsApi extends ApiTopic {
|
|
|
468
481
|
}
|
|
469
482
|
if (polledMessages) consecutivePollFailures = 0;
|
|
470
483
|
} catch (err) {
|
|
484
|
+
if (isRunGone(err)) {
|
|
485
|
+
exitBecauseRunGone();
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
471
488
|
warnPollFailure('run status check', err);
|
|
472
489
|
}
|
|
473
490
|
if (isClosed || !isPolling) return;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { SupportedEmbeddingTypes } from '@vertesia/common';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { ZenoClient } from './client.js';
|
|
4
|
+
|
|
5
|
+
describe('EmbeddingsApi', () => {
|
|
6
|
+
it('omits the mode by default and sends the explicit sync override when requested', async () => {
|
|
7
|
+
const requests: Request[] = [];
|
|
8
|
+
const client = new ZenoClient({
|
|
9
|
+
serverUrl: 'https://store.example.com',
|
|
10
|
+
apikey: 'token',
|
|
11
|
+
fetch: vi.fn(
|
|
12
|
+
async () =>
|
|
13
|
+
new Response(JSON.stringify({ status: 'success', message: 'started' }), {
|
|
14
|
+
status: 200,
|
|
15
|
+
headers: { 'content-type': 'application/json' },
|
|
16
|
+
}),
|
|
17
|
+
),
|
|
18
|
+
onRequest: (request) => requests.push(request),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
await client.embeddings.recalculate(SupportedEmbeddingTypes.text);
|
|
22
|
+
await client.embeddings.recalculate(SupportedEmbeddingTypes.text, { mode: 'sync' });
|
|
23
|
+
await client.embeddings.recalculate(SupportedEmbeddingTypes.image, { force: true });
|
|
24
|
+
|
|
25
|
+
expect(requests.map(({ url }) => url)).toEqual([
|
|
26
|
+
'https://store.example.com/api/v1/embeddings/text/recalculate',
|
|
27
|
+
'https://store.example.com/api/v1/embeddings/text/recalculate?mode=sync',
|
|
28
|
+
'https://store.example.com/api/v1/embeddings/image/recalculate?force=true',
|
|
29
|
+
]);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import { ApiTopic, type ClientBase } from '@vertesia/api-fetch-client';
|
|
2
2
|
import type {
|
|
3
|
+
EmbeddingBatchApplyRequest,
|
|
4
|
+
EmbeddingBatchApplyResponse,
|
|
5
|
+
EmbeddingBatchPrepareRequest,
|
|
6
|
+
EmbeddingBatchPrepareResponse,
|
|
7
|
+
EmbeddingBatchRenditionPageRequest,
|
|
8
|
+
EmbeddingBatchRenditionPageResponse,
|
|
9
|
+
EmbeddingBatchUpdateRequest,
|
|
3
10
|
EmbeddingsStatusResponse,
|
|
4
11
|
GenericCommandResponse,
|
|
5
12
|
ProjectConfigurationEmbeddingEnablePayload,
|
|
13
|
+
RecalculateEmbeddingsQuery,
|
|
6
14
|
SupportedEmbeddingTypes,
|
|
7
15
|
} from '@vertesia/common';
|
|
8
16
|
|
|
@@ -33,7 +41,44 @@ export class EmbeddingsApi extends ApiTopic {
|
|
|
33
41
|
return this.post(`${type}/disable`);
|
|
34
42
|
}
|
|
35
43
|
|
|
36
|
-
async recalculate(
|
|
37
|
-
|
|
44
|
+
async recalculate(
|
|
45
|
+
type: SupportedEmbeddingTypes,
|
|
46
|
+
query: RecalculateEmbeddingsQuery = {},
|
|
47
|
+
): Promise<GenericCommandResponse> {
|
|
48
|
+
return this.post(`${type}/recalculate`, Object.keys(query).length ? { query } : undefined);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async prepareBatch(
|
|
52
|
+
payload: EmbeddingBatchPrepareRequest,
|
|
53
|
+
timeoutMs: number | false | null = false,
|
|
54
|
+
): Promise<EmbeddingBatchPrepareResponse> {
|
|
55
|
+
return this.post('/batch/prepare', { payload, timeoutMs });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async updateBatch(payload: EmbeddingBatchUpdateRequest): Promise<GenericCommandResponse> {
|
|
59
|
+
return this.post('/batch/update', { payload });
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async prepareBatchRenditionPage(
|
|
63
|
+
payload: EmbeddingBatchRenditionPageRequest,
|
|
64
|
+
): Promise<EmbeddingBatchRenditionPageResponse> {
|
|
65
|
+
return this.post('/batch/renditions/prepare', { payload });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async pollBatchRenditionPage(
|
|
69
|
+
payload: EmbeddingBatchRenditionPageRequest,
|
|
70
|
+
): Promise<EmbeddingBatchRenditionPageResponse> {
|
|
71
|
+
return this.post('/batch/renditions/status', { payload });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async cancelBatchRenditionPage(payload: EmbeddingBatchRenditionPageRequest): Promise<GenericCommandResponse> {
|
|
75
|
+
return this.post('/batch/renditions/cancel', { payload });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async applyBatch(
|
|
79
|
+
payload: EmbeddingBatchApplyRequest,
|
|
80
|
+
timeoutMs: number | false | null = false,
|
|
81
|
+
): Promise<EmbeddingBatchApplyResponse> {
|
|
82
|
+
return this.post('/batch/apply', { payload, timeoutMs });
|
|
38
83
|
}
|
|
39
84
|
}
|
|
@@ -2,6 +2,19 @@ import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
|
2
2
|
import { ZenoClient } from './client.js';
|
|
3
3
|
|
|
4
4
|
describe('FilesApi', () => {
|
|
5
|
+
it('retrieves a durable audio result through the authenticated file API', async () => {
|
|
6
|
+
const bytes = new Uint8Array([82, 73, 70, 70, 1, 2, 3]);
|
|
7
|
+
const sign = vi.fn(async () => Response.json({ url: 'https://signed.example/speech.wav' }));
|
|
8
|
+
vi.stubGlobal(
|
|
9
|
+
'fetch',
|
|
10
|
+
vi.fn(async () => new Response(bytes, { headers: { 'content-type': 'audio/wav' } })),
|
|
11
|
+
);
|
|
12
|
+
const client = new ZenoClient({ serverUrl: 'https://store.test', apikey: 'test-token', fetch: sign });
|
|
13
|
+
const stream = await client.files.downloadFile('gs://bucket/runs/run-1/media/speech.wav');
|
|
14
|
+
expect(new Uint8Array(await new Response(stream).arrayBuffer())).toEqual(bytes);
|
|
15
|
+
expect(sign).toHaveBeenCalledOnce();
|
|
16
|
+
});
|
|
17
|
+
|
|
5
18
|
afterEach(() => {
|
|
6
19
|
vi.restoreAllMocks();
|
|
7
20
|
vi.unstubAllGlobals();
|