@vertesia/client 1.5.0 → 1.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vertesia/client",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
4
4
  "type": "module",
5
5
  "main": "./lib/index.js",
6
6
  "types": "./lib/index.d.ts",
@@ -19,9 +19,9 @@
19
19
  },
20
20
  "dependencies": {
21
21
  "eventsource": "^5.0.0",
22
- "@llumiverse/common": "1.5.0",
23
- "@vertesia/api-fetch-client": "1.5.0",
24
- "@vertesia/common": "1.5.0"
22
+ "@llumiverse/common": "1.5.1",
23
+ "@vertesia/api-fetch-client": "1.5.1",
24
+ "@vertesia/common": "1.5.1"
25
25
  },
26
26
  "exports": {
27
27
  ".": {
@@ -48,7 +48,7 @@
48
48
  "ai",
49
49
  "typescript"
50
50
  ],
51
- "gitHead": "3485742020066ab1fd3292487cf3a9577b5e4d91",
51
+ "gitHead": "7ab3acd95af12b8c254e1b3852e67d5078790f98",
52
52
  "scripts": {
53
53
  "lint": "biome lint src",
54
54
  "clean:lib": "rimraf ./lib ./tsconfig.tsbuildinfo",
@@ -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.
@@ -30,6 +30,7 @@ import type {
30
30
  RateLimitRequestPayload,
31
31
  RateLimitRequestResponse,
32
32
  ResolvedInteractionExecutionInfo,
33
+ ResolveInteractionQuery,
33
34
  } from '@vertesia/common';
34
35
  import type { VertesiaClient } from './client.js';
35
36
  import { checkRateLimit, executeInteraction, executeInteractionAsync, executeInteractionByName } from './execute.js';
@@ -339,15 +340,7 @@ export default class InteractionsApi extends ApiTopic {
339
340
  * @param options Optional environment and/or model to resolve with
340
341
  * @returns ResolvedInteractionExecutionInfo with the resolved environment and model
341
342
  */
342
- resolve(
343
- nameOrId: string,
344
- options?: {
345
- environment?: string;
346
- model?: string;
347
- hasImage?: boolean;
348
- hasVideo?: boolean;
349
- },
350
- ): Promise<ResolvedInteractionExecutionInfo> {
343
+ resolve(nameOrId: string, options?: ResolveInteractionQuery): Promise<ResolvedInteractionExecutionInfo> {
351
344
  return this.get(`/resolve/${encodeURIComponent(nameOrId)}`, {
352
345
  query: options,
353
346
  });
@@ -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/index.ts CHANGED
@@ -6,6 +6,7 @@ export * from './client.js';
6
6
  export type { GroupsQueryOptions } from './GroupsApi.js';
7
7
  export * from './InteractionBase.js';
8
8
  export * from './InteractionOutput.js';
9
+ export { default as InternalAccountsApi } from './InternalAccountsApi.js';
9
10
  export { default as InternalSecretsApi } from './InternalSecretsApi.js';
10
11
  export * from './managed-sse.js';
11
12
  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
- return Response.json({ messages: pollResponse(since) });
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();
@@ -417,6 +417,15 @@ export class AgentsApi extends ApiTopic {
417
417
  );
418
418
  };
419
419
 
420
+ // A 404 while polling means the run itself is gone (deleted, or never persisted): nothing
421
+ // will ever arrive, so stop instead of polling the missing resource every 5s forever.
422
+ const isRunGone = (error: unknown): boolean =>
423
+ typeof error === 'object' && error !== null && (error as { status?: unknown }).status === 404;
424
+ const exitBecauseRunGone = () => {
425
+ console.warn(`Agent stream ${id}: the run no longer exists (404); stopping the polling fallback.`);
426
+ exit(null);
427
+ };
428
+
420
429
  const pollTick = async () => {
421
430
  if (isClosed || !isPolling) return;
422
431
  let polledMessages = false;
@@ -438,6 +447,10 @@ export class AgentsApi extends ApiTopic {
438
447
  }
439
448
  }
440
449
  } catch (err) {
450
+ if (isRunGone(err)) {
451
+ exitBecauseRunGone();
452
+ return;
453
+ }
441
454
  warnPollFailure('GET /updates', err);
442
455
  }
443
456
  if (isClosed || !isPolling) return;
@@ -450,6 +463,10 @@ export class AgentsApi extends ApiTopic {
450
463
  }
451
464
  if (polledMessages) consecutivePollFailures = 0;
452
465
  } catch (err) {
466
+ if (isRunGone(err)) {
467
+ exitBecauseRunGone();
468
+ return;
469
+ }
453
470
  warnPollFailure('run status check', err);
454
471
  }
455
472
  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(type: SupportedEmbeddingTypes): Promise<GenericCommandResponse> {
37
- return this.post(`${type}/recalculate`);
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
  }