@vertesia/client 0.79.0 → 0.80.0-dev-20251118

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.
Files changed (126) hide show
  1. package/lib/cjs/InteractionCatalogApi.js +64 -0
  2. package/lib/cjs/InteractionCatalogApi.js.map +1 -0
  3. package/lib/cjs/InteractionOutput.js +300 -0
  4. package/lib/cjs/InteractionOutput.js.map +1 -0
  5. package/lib/cjs/InteractionResult.example.js +57 -0
  6. package/lib/cjs/InteractionResult.example.js.map +1 -0
  7. package/lib/cjs/InteractionsApi.js +20 -6
  8. package/lib/cjs/InteractionsApi.js.map +1 -1
  9. package/lib/cjs/ProjectsApi.js +2 -1
  10. package/lib/cjs/ProjectsApi.js.map +1 -1
  11. package/lib/cjs/RunsApi.js +12 -4
  12. package/lib/cjs/RunsApi.js.map +1 -1
  13. package/lib/cjs/client.js +107 -40
  14. package/lib/cjs/client.js.map +1 -1
  15. package/lib/cjs/index.js +6 -0
  16. package/lib/cjs/index.js.map +1 -1
  17. package/lib/cjs/store/CollectionsApi.js +21 -0
  18. package/lib/cjs/store/CollectionsApi.js.map +1 -1
  19. package/lib/cjs/store/FilesApi.js +9 -8
  20. package/lib/cjs/store/FilesApi.js.map +1 -1
  21. package/lib/cjs/store/ObjectsApi.js +5 -4
  22. package/lib/cjs/store/ObjectsApi.js.map +1 -1
  23. package/lib/cjs/store/TypesApi.js +1 -1
  24. package/lib/cjs/store/TypesApi.js.map +1 -1
  25. package/lib/cjs/store/WorkflowsApi.js +151 -2
  26. package/lib/cjs/store/WorkflowsApi.js.map +1 -1
  27. package/lib/cjs/store/client.js.map +1 -1
  28. package/lib/esm/InteractionCatalogApi.js +60 -0
  29. package/lib/esm/InteractionCatalogApi.js.map +1 -0
  30. package/lib/esm/InteractionOutput.js +293 -0
  31. package/lib/esm/InteractionOutput.js.map +1 -0
  32. package/lib/esm/InteractionResult.example.js +55 -0
  33. package/lib/esm/InteractionResult.example.js.map +1 -0
  34. package/lib/esm/InteractionsApi.js +20 -6
  35. package/lib/esm/InteractionsApi.js.map +1 -1
  36. package/lib/esm/ProjectsApi.js +1 -1
  37. package/lib/esm/ProjectsApi.js.map +1 -1
  38. package/lib/esm/RunsApi.js +12 -4
  39. package/lib/esm/RunsApi.js.map +1 -1
  40. package/lib/esm/client.js +106 -39
  41. package/lib/esm/client.js.map +1 -1
  42. package/lib/esm/index.js +3 -0
  43. package/lib/esm/index.js.map +1 -1
  44. package/lib/esm/store/CollectionsApi.js +21 -0
  45. package/lib/esm/store/CollectionsApi.js.map +1 -1
  46. package/lib/esm/store/FilesApi.js +9 -8
  47. package/lib/esm/store/FilesApi.js.map +1 -1
  48. package/lib/esm/store/ObjectsApi.js +5 -4
  49. package/lib/esm/store/ObjectsApi.js.map +1 -1
  50. package/lib/esm/store/TypesApi.js +1 -1
  51. package/lib/esm/store/TypesApi.js.map +1 -1
  52. package/lib/esm/store/WorkflowsApi.js +151 -2
  53. package/lib/esm/store/WorkflowsApi.js.map +1 -1
  54. package/lib/esm/store/client.js.map +1 -1
  55. package/lib/tsconfig.tsbuildinfo +1 -1
  56. package/lib/types/AccountApi.d.ts +1 -0
  57. package/lib/types/AccountsApi.d.ts +1 -0
  58. package/lib/types/AnalyticsApi.d.ts +1 -0
  59. package/lib/types/ApiKeysApi.d.ts +1 -0
  60. package/lib/types/AppsApi.d.ts +1 -0
  61. package/lib/types/CommandsApi.d.ts +1 -0
  62. package/lib/types/EnvironmentsApi.d.ts +1 -0
  63. package/lib/types/GroupsApi.d.ts +1 -0
  64. package/lib/types/IamApi.d.ts +1 -0
  65. package/lib/types/InteractionBase.d.ts +1 -0
  66. package/lib/types/InteractionCatalogApi.d.ts +37 -0
  67. package/lib/types/InteractionCatalogApi.d.ts.map +1 -0
  68. package/lib/types/InteractionOutput.d.ts +175 -0
  69. package/lib/types/InteractionOutput.d.ts.map +1 -0
  70. package/lib/types/InteractionResult.example.d.ts +7 -0
  71. package/lib/types/InteractionResult.example.d.ts.map +1 -0
  72. package/lib/types/InteractionsApi.d.ts +10 -6
  73. package/lib/types/InteractionsApi.d.ts.map +1 -1
  74. package/lib/types/ProjectsApi.d.ts +2 -1
  75. package/lib/types/ProjectsApi.d.ts.map +1 -1
  76. package/lib/types/PromptsApi.d.ts +1 -0
  77. package/lib/types/RefsApi.d.ts +1 -0
  78. package/lib/types/RunsApi.d.ts +7 -4
  79. package/lib/types/RunsApi.d.ts.map +1 -1
  80. package/lib/types/StreamSource.d.ts +1 -0
  81. package/lib/types/TrainingApi.d.ts +1 -0
  82. package/lib/types/UsersApi.d.ts +1 -0
  83. package/lib/types/client.d.ts +10 -5
  84. package/lib/types/client.d.ts.map +1 -1
  85. package/lib/types/execute.d.ts +1 -0
  86. package/lib/types/index.d.ts +6 -1
  87. package/lib/types/index.d.ts.map +1 -1
  88. package/lib/types/nodejs/NodeStreamSource.d.ts +1 -0
  89. package/lib/types/nodejs/index.d.ts +1 -0
  90. package/lib/types/store/AgentsApi.d.ts +1 -0
  91. package/lib/types/store/AnalyzeDocApi.d.ts +1 -0
  92. package/lib/types/store/CollectionsApi.d.ts +8 -0
  93. package/lib/types/store/CollectionsApi.d.ts.map +1 -1
  94. package/lib/types/store/CommandsApi.d.ts +1 -0
  95. package/lib/types/store/EmbeddingsApi.d.ts +1 -0
  96. package/lib/types/store/FilesApi.d.ts +4 -2
  97. package/lib/types/store/FilesApi.d.ts.map +1 -1
  98. package/lib/types/store/ObjectsApi.d.ts +7 -11
  99. package/lib/types/store/ObjectsApi.d.ts.map +1 -1
  100. package/lib/types/store/TypesApi.d.ts +1 -0
  101. package/lib/types/store/WorkflowsApi.d.ts +13 -0
  102. package/lib/types/store/WorkflowsApi.d.ts.map +1 -1
  103. package/lib/types/store/client.d.ts +2 -0
  104. package/lib/types/store/client.d.ts.map +1 -1
  105. package/lib/types/store/errors.d.ts +1 -0
  106. package/lib/types/store/index.d.ts +1 -0
  107. package/lib/types/store/version.d.ts +1 -0
  108. package/lib/vertesia-client.js +1 -1
  109. package/lib/vertesia-client.js.map +1 -1
  110. package/package.json +59 -54
  111. package/src/InteractionCatalogApi.ts +72 -0
  112. package/src/InteractionOutput.test.ts +305 -0
  113. package/src/InteractionOutput.ts +328 -0
  114. package/src/InteractionResult.example.ts +72 -0
  115. package/src/InteractionsApi.ts +34 -9
  116. package/src/ProjectsApi.ts +7 -1
  117. package/src/RunsApi.ts +15 -5
  118. package/src/client.test.ts +2 -0
  119. package/src/client.ts +128 -57
  120. package/src/index.ts +2 -0
  121. package/src/store/CollectionsApi.ts +39 -2
  122. package/src/store/FilesApi.ts +10 -8
  123. package/src/store/ObjectsApi.ts +7 -23
  124. package/src/store/TypesApi.ts +1 -1
  125. package/src/store/WorkflowsApi.ts +171 -2
  126. package/src/store/client.ts +1 -0
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Example usage of InteractionOutput
3
+ * This file demonstrates the Proxy-based approach where the result acts as both
4
+ * an array and has convenience methods.
5
+ */
6
+
7
+ import { CompletionResult } from '@llumiverse/common';
8
+ import { InteractionOutput } from './InteractionOutput.js';
9
+
10
+ // Sample data
11
+ const sampleResults: CompletionResult[] = [
12
+ { type: 'text', value: 'Hello, ' },
13
+ { type: 'text', value: 'World!' },
14
+ { type: 'json', value: { name: 'Alice', age: 30 } },
15
+ { type: 'json', value: { title: 'Engineer', level: 'Senior' } },
16
+ { type: 'image', value: 'data:image/png;base64,iVBORw0K...' }
17
+ ];
18
+
19
+ // Example 1: Using InteractionOutput.from() (Proxy approach - RECOMMENDED)
20
+ console.log('=== Example 1: Proxy Approach ===');
21
+ interface Person { name: string; age: number; }
22
+ const output = InteractionOutput.from<Person>(sampleResults);
23
+
24
+ // Works as an array
25
+ console.log('Array length:', output.length); // 5
26
+ console.log('First item:', output[0]); // { type: 'text', value: 'Hello, ' }
27
+ console.log('Types:', output.map(r => r.type)); // ['text', 'text', 'json', 'json', 'image']
28
+
29
+ // Has convenience methods
30
+ console.log('All text:', output.text); // 'Hello, World!'
31
+ console.log('First object:', output.object()); // { name: 'Alice', age: 30 } (typed as Person)
32
+ console.log('All objects:', output.objects()); // [{ name: 'Alice', age: 30 }, { title: 'Engineer', level: 'Senior' }]
33
+ console.log('First image:', output.image); // 'data:image/png;base64,iVBORw0K...'
34
+
35
+ // Override type for specific objects
36
+ interface Job { title: string; level: string; }
37
+ console.log('Second object:', output.objectAt<Job>(1)); // { title: 'Engineer', level: 'Senior' } (typed as Job)
38
+
39
+ // Example 2: Using InteractionOutput class directly
40
+ console.log('\n=== Example 2: Class Approach ===');
41
+ const wrapper = new InteractionOutput<Person>(sampleResults);
42
+
43
+ // Access through wrapper properties (no array access)
44
+ console.log('All text:', wrapper.text);
45
+ console.log('Raw results:', wrapper.results); // Original array
46
+ console.log('First object:', wrapper.object());
47
+
48
+ // Example 3: Type safety demonstration
49
+ console.log('\n=== Example 3: Type Safety ===');
50
+
51
+ interface Contract { title: string; parties: string[]; }
52
+ const contractResults: CompletionResult[] = [
53
+ { type: 'json', value: { title: 'Sales Agreement', parties: ['Alice', 'Bob'] } }
54
+ ];
55
+
56
+ const contractOutput = InteractionOutput.from<Contract>(contractResults);
57
+ const contract = contractOutput.object(); // TypeScript knows this is Contract
58
+ console.log('Contract title:', contract.title);
59
+ console.log('Parties:', contract.parties.join(', '));
60
+
61
+ // Example 4: Mixed content
62
+ console.log('\n=== Example 4: Mixed Content ===');
63
+ const mixedResults: CompletionResult[] = [
64
+ { type: 'text', value: 'Analysis complete. Results: ' },
65
+ { type: 'json', value: { score: 0.95, confidence: 'high' } },
66
+ { type: 'text', value: '\nThank you!' }
67
+ ];
68
+
69
+ const mixed = InteractionOutput.from(mixedResults);
70
+ console.log('Full text:', mixed.text); // 'Analysis complete. Results: \nThank you!'
71
+ console.log('Analysis:', mixed.object()); // { score: 0.95, confidence: 'high' }
72
+ console.log('Text parts:', mixed.texts); // ['Analysis complete. Results: ', '\nThank you!']
@@ -1,7 +1,17 @@
1
1
  import { ApiTopic, ClientBase, ServerError } from "@vertesia/api-fetch-client";
2
- import { AsyncExecutionPayload, ComputeInteractionFacetPayload, ExecutionRun, GenerateInteractionPayload, GenerateTestDataPayload, ImprovePromptPayload, Interaction, InteractionCreatePayload, InteractionEndpoint, InteractionEndpointQuery, InteractionExecutionPayload, InteractionExecutionResult, InteractionForkPayload, InteractionPublishPayload, InteractionRef, InteractionRefWithSchema, InteractionSearchPayload, InteractionSearchQuery, InteractionUpdatePayload, InteractionsExportPayload, RateLimitRequestPayload, RateLimitRequestResponse } from "@vertesia/common";
2
+ import {
3
+ AsyncExecutionPayload, ComputeInteractionFacetPayload, GenerateInteractionPayload, GenerateTestDataPayload, ImprovePromptPayload,
4
+ ImprovePromptPayloadConfig,
5
+ Interaction, InteractionCreatePayload, InteractionEndpoint, InteractionEndpointQuery,
6
+ InteractionExecutionPayload, InteractionForkPayload,
7
+ InteractionPublishPayload, InteractionRef, InteractionRefWithSchema, InteractionSearchPayload, InteractionSearchQuery,
8
+ InteractionsExportPayload, InteractionUpdatePayload,
9
+ RateLimitRequestPayload, RateLimitRequestResponse
10
+ } from "@vertesia/common";
3
11
  import { VertesiaClient } from "./client.js";
4
12
  import { checkRateLimit, executeInteraction, executeInteractionAsync, executeInteractionByName } from "./execute.js";
13
+ import { InteractionCatalogApi } from "./InteractionCatalogApi.js";
14
+ import { EnhancedExecutionRun, EnhancedInteractionExecutionResult, enhanceExecutionRun, enhanceInteractionExecutionResult } from "./InteractionOutput.js";
5
15
 
6
16
  export interface ComputeInteractionFacetsResponse {
7
17
  tags?: { _id: string, count: number }[];
@@ -14,8 +24,11 @@ export interface AsyncExecutionResult {
14
24
  }
15
25
 
16
26
  export default class InteractionsApi extends ApiTopic {
27
+ catalog: InteractionCatalogApi;
28
+
17
29
  constructor(parent: ClientBase) {
18
30
  super(parent, "/api/v1/interactions");
31
+ this.catalog = new InteractionCatalogApi(parent);
19
32
  }
20
33
 
21
34
  /**
@@ -132,15 +145,16 @@ export default class InteractionsApi extends ApiTopic {
132
145
  * @throws 500 if interaction execution fails
133
146
  * @throws 500 if interaction execution times out
134
147
  **/
135
- execute<P = any>(id: string, payload: InteractionExecutionPayload = {},
136
- onChunk?: (chunk: string) => void): Promise<ExecutionRun<P>> {
137
- return executeInteraction<P>(this.client as VertesiaClient, id, payload, onChunk).catch(err => {
148
+ async execute<ResultT = any, ParamsT = any>(id: string, payload: InteractionExecutionPayload = {},
149
+ onChunk?: (chunk: string) => void): Promise<EnhancedInteractionExecutionResult<ResultT, ParamsT>> {
150
+ const r = await executeInteraction<ParamsT>(this.client as VertesiaClient, id, payload, onChunk).catch(err => {
138
151
  if (err instanceof ServerError && err.payload?.id) {
139
152
  throw err.updateDetails({ run_id: err.payload.id });
140
153
  } else {
141
154
  throw err;
142
155
  }
143
156
  });
157
+ return enhanceInteractionExecutionResult<ResultT, ParamsT>(r);
144
158
  }
145
159
 
146
160
  /**
@@ -158,15 +172,16 @@ export default class InteractionsApi extends ApiTopic {
158
172
  * @param onChunk
159
173
  * @returns
160
174
  */
161
- executeByName<P = any>(nameWithTag: string, payload: InteractionExecutionPayload = {},
162
- onChunk?: (chunk: string) => void): Promise<InteractionExecutionResult<P>> {
163
- return executeInteractionByName<P>(this.client as VertesiaClient, nameWithTag, payload, onChunk).catch(err => {
175
+ async executeByName<ResultT = any, ParamsT = any>(nameWithTag: string, payload: InteractionExecutionPayload = {},
176
+ onChunk?: (chunk: string) => void): Promise<EnhancedInteractionExecutionResult<ResultT, ParamsT>> {
177
+ const r = await executeInteractionByName<ParamsT>(this.client as VertesiaClient, nameWithTag, payload, onChunk).catch(err => {
164
178
  if (err instanceof ServerError && err.payload?.id) {
165
179
  throw err.updateDetails({ run_id: err.payload.id });
166
180
  } else {
167
181
  throw err;
168
182
  }
169
183
  });
184
+ return enhanceInteractionExecutionResult<ResultT, ParamsT>(r);
170
185
  }
171
186
 
172
187
  /**
@@ -213,13 +228,23 @@ export default class InteractionsApi extends ApiTopic {
213
228
 
214
229
  /**
215
230
  * Suggest Improvement for a prompt
231
+ * @deprecated use suggestPromptImprovements instead
216
232
  */
217
- suggestImprovements(id: string, payload: ImprovePromptPayload): Promise<{ result: string; }> {
218
- return this.post(`${id}/suggest-prompt-improvements`, {
233
+ async suggestImprovements<ResultT = any, ParamsT = any>(id: string, payload: ImprovePromptPayloadConfig): Promise<EnhancedExecutionRun<ResultT, ParamsT>> {
234
+ const r = await this.post(`${id}/suggest-prompt-improvements`, {
235
+ payload
236
+ });
237
+ return enhanceExecutionRun<ResultT, ParamsT>(r);
238
+ }
239
+
240
+ async suggestPromptImprovements<ResultT = any, ParamsT = any>(payload: ImprovePromptPayload): Promise<EnhancedInteractionExecutionResult<ResultT, ParamsT>> {
241
+ const r = await this.post(`/improve`, {
219
242
  payload
220
243
  });
244
+ return enhanceInteractionExecutionResult<ResultT, ParamsT>(r);
221
245
  }
222
246
 
247
+
223
248
  /**
224
249
  * List the versions of the interaction. Returns an empty array if no versions are found
225
250
  * @param id
@@ -1,5 +1,5 @@
1
1
  import { ApiTopic, ClientBase } from "@vertesia/api-fetch-client";
2
- import { AwsConfiguration, GithubConfiguration, GladiaConfiguration, ICreateProjectPayload, MagicPdfConfiguration, Project, ProjectIntegrationListEntry, ProjectRef, SupportedIntegrations } from "@vertesia/common";
2
+ import { AwsConfiguration, GithubConfiguration, GladiaConfiguration, ICreateProjectPayload, MagicPdfConfiguration, Project, ProjectConfiguration, ProjectIntegrationListEntry, ProjectRef, SupportedIntegrations } from "@vertesia/common";
3
3
 
4
4
  export default class ProjectsApi extends ApiTopic {
5
5
  constructor(parent: ClientBase) {
@@ -26,6 +26,12 @@ export default class ProjectsApi extends ApiTopic {
26
26
  });
27
27
  }
28
28
 
29
+ updateConfiguration(projectId: string, payload: Partial<ProjectConfiguration>): Promise<ProjectConfiguration> {
30
+ return this.put(`/${projectId}/configuration`, {
31
+ payload
32
+ });
33
+ }
34
+
29
35
  integrations: IntegrationsConfigurationApi = new IntegrationsConfigurationApi(this);
30
36
 
31
37
  }
package/src/RunsApi.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { ExecutionResponse } from "@llumiverse/common";
1
2
  import { ApiTopic, ClientBase } from "@vertesia/api-fetch-client";
2
3
  import {
3
4
  CheckpointConversationPayload,
@@ -5,6 +6,7 @@ import {
5
6
  ExecutionRun,
6
7
  ExecutionRunRef,
7
8
  FindPayload,
9
+ PopulatedExecutionRun,
8
10
  RunCreatePayload,
9
11
  RunListingFilters,
10
12
  RunListingQueryOptions,
@@ -13,7 +15,7 @@ import {
13
15
  UserMessagePayload,
14
16
  } from "@vertesia/common";
15
17
  import { VertesiaClient } from "./client.js";
16
- import type { ExecutionResponse } from "@llumiverse/common";
18
+ import { EnhancedExecutionRun, enhanceExecutionRun } from "./InteractionOutput.js";
17
19
 
18
20
  export interface FilterOption {
19
21
  id: string;
@@ -63,8 +65,15 @@ export class RunsApi extends ApiTopic {
63
65
  * @param id
64
66
  * @returns InteractionResult
65
67
  **/
66
- retrieve<P = any>(id: string): Promise<ExecutionRun<P>> {
67
- return this.get("/" + id);
68
+ async retrieve<ResultT = any, ParamsT = any>(id: string): Promise<EnhancedExecutionRun<ResultT, ParamsT>> {
69
+ const r = await this.get("/" + id);
70
+ return enhanceExecutionRun<ResultT, ParamsT>(r);
71
+ }
72
+
73
+ retrievePopulated<P = any>(id: string): Promise<PopulatedExecutionRun<P>> {
74
+ return this.get("/" + id, {
75
+ query: { populate: "true" },
76
+ });
68
77
  }
69
78
 
70
79
  /**
@@ -78,7 +87,7 @@ export class RunsApi extends ApiTopic {
78
87
  return this.get(`/filter-options/${field}`, { query });
79
88
  }
80
89
 
81
- create(payload: RunCreatePayload): Promise<ExecutionRun> {
90
+ async create<ResultT = any, ParamsT = any>(payload: RunCreatePayload): Promise<EnhancedExecutionRun<ResultT, ParamsT>> {
82
91
  const sessionTags = (this.client as VertesiaClient).sessionTags;
83
92
  if (sessionTags) {
84
93
  let tags = Array.isArray(sessionTags) ? sessionTags : [sessionTags];
@@ -89,9 +98,10 @@ export class RunsApi extends ApiTopic {
89
98
  }
90
99
  payload = { ...payload, tags };
91
100
  }
92
- return this.post("/", {
101
+ const r = await this.post("/", {
93
102
  payload,
94
103
  });
104
+ return enhanceExecutionRun<ResultT, ParamsT>(r);
95
105
  }
96
106
 
97
107
  /**
@@ -6,6 +6,7 @@ describe('Test Vertesia Client', () => {
6
6
  const client = new VertesiaClient({
7
7
  serverUrl: 'https://api.vertesia.io',
8
8
  storeUrl: 'https://api.vertesia.io',
9
+ tokenServerUrl: 'https://sts.vertesia.io',
9
10
  apikey: '1234',
10
11
  });
11
12
  expect(client).toBeDefined();
@@ -73,6 +74,7 @@ describe('Test Vertesia Client', () => {
73
74
  const client = new VertesiaClient({
74
75
  serverUrl: 'http://localhost:8091',
75
76
  storeUrl: 'http://localhost:8092',
77
+ tokenServerUrl: 'http://localhost:8093',
76
78
  });
77
79
 
78
80
  expect(client).toBeDefined();
package/src/client.ts CHANGED
@@ -37,18 +37,21 @@ export type VertesiaClientProps = {
37
37
  * @default api.vertesia.io
38
38
  * @since 0.52.0
39
39
  */
40
- site?: 'api.vertesia.io' | 'api-preview.vertesia.io' | 'api-staging.vertesia.io';
40
+ site?:
41
+ | "api.vertesia.io"
42
+ | "api-preview.vertesia.io"
43
+ | "api-staging.vertesia.io";
41
44
  serverUrl?: string;
42
45
  storeUrl?: string;
46
+ tokenServerUrl?: string;
43
47
  apikey?: string;
44
48
  projectId?: string;
45
49
  sessionTags?: string | string[];
46
50
  onRequest?: (request: Request) => void;
47
51
  onResponse?: (response: Response) => void;
48
- }
52
+ };
49
53
 
50
54
  export class VertesiaClient extends AbstractFetchClient<VertesiaClient> {
51
-
52
55
  /**
53
56
  * The JWT token linked to the API KEY (sk or pk)
54
57
  */
@@ -64,11 +67,15 @@ export class VertesiaClient extends AbstractFetchClient<VertesiaClient> {
64
67
  */
65
68
  sessionTags?: string | string[];
66
69
 
70
+ /**
71
+ * tokenServerUrl
72
+ */
73
+ tokenServerUrl: string;
67
74
 
68
75
  /**
69
- * Create a client from the given token.
76
+ * Create a client from the given token.
70
77
  * If you already have the decoded token you can pass it as the second argument to avoid decodinf it again.
71
- *
78
+ *
72
79
  * @param token the raw JWT token
73
80
  * @param payload the decoded JWT token as an AuthTokenPayload - optional
74
81
  */
@@ -76,21 +83,21 @@ export class VertesiaClient extends AbstractFetchClient<VertesiaClient> {
76
83
  if (!payload) {
77
84
  payload = decodeJWT(token);
78
85
  }
79
- const endpoints = decodeEndpoints(payload!.endpoints);
86
+
87
+ const endpoints = decodeEndpoints(payload.endpoints);
80
88
  return await new VertesiaClient({
81
89
  serverUrl: endpoints.studio,
82
- storeUrl: endpoints.store
90
+ storeUrl: endpoints.store,
91
+ tokenServerUrl: payload.iss,
83
92
  }).withApiKey(token);
84
93
  }
85
94
 
86
- static decodeEndpoints() {
87
-
88
- }
95
+ static decodeEndpoints() {}
89
96
 
90
97
  constructor(
91
98
  opts: VertesiaClientProps = {
92
- site: 'api.vertesia.io',
93
- }
99
+ site: "api.vertesia.io",
100
+ },
94
101
  ) {
95
102
  let studioServerUrl: string;
96
103
  let zenoServerUrl: string;
@@ -100,7 +107,9 @@ export class VertesiaClient extends AbstractFetchClient<VertesiaClient> {
100
107
  } else if (opts.site) {
101
108
  studioServerUrl = `https://${opts.site}`;
102
109
  } else {
103
- throw new Error("Parameter 'site' or 'serverUrl' is required for VertesiaClient");
110
+ throw new Error(
111
+ "Parameter 'site' or 'serverUrl' is required for VertesiaClient",
112
+ );
104
113
  }
105
114
 
106
115
  if (opts.storeUrl) {
@@ -108,25 +117,67 @@ export class VertesiaClient extends AbstractFetchClient<VertesiaClient> {
108
117
  } else if (opts.site) {
109
118
  zenoServerUrl = `https://${opts.site}`;
110
119
  } else {
111
- throw new Error("Parameter 'site' or 'storeUrl' is required for VertesiaClient");
120
+ throw new Error(
121
+ "Parameter 'site' or 'storeUrl' is required for VertesiaClient",
122
+ );
112
123
  }
113
124
 
114
125
  super(studioServerUrl);
115
126
 
127
+ if (opts.tokenServerUrl) {
128
+ this.tokenServerUrl = opts.tokenServerUrl;
129
+ } else if (opts.site) {
130
+ this.tokenServerUrl = `https://${opts.site.replace(/^api/, "sts")}`;
131
+ } else if (opts.serverUrl || opts.storeUrl) {
132
+ // Determine STS URL based on environment in serverUrl or storeUrl
133
+ const urlToCheck = opts.serverUrl || opts.storeUrl || "";
134
+ try {
135
+ const url = new URL(urlToCheck);
136
+ // Check for environment patterns
137
+ if (url.hostname.includes("-production.")) {
138
+ // zeno-server-production.api.vertesia.io -> sts.vertesia.io
139
+ this.tokenServerUrl = "https://sts.vertesia.io";
140
+ } else if (url.hostname.includes("-preview.")) {
141
+ // zeno-server-preview.api.vertesia.io -> sts-preview.vertesia.io
142
+ this.tokenServerUrl = "https://sts-preview.vertesia.io";
143
+ } else if (url.hostname === "api.vertesia.io") {
144
+ // api.vertesia.io -> sts.vertesia.io
145
+ this.tokenServerUrl = "https://sts.vertesia.io";
146
+ } else if (url.hostname === "api-preview.vertesia.io") {
147
+ // api-preview.vertesia.io -> sts-preview.vertesia.io
148
+ this.tokenServerUrl = "https://sts-preview.vertesia.io";
149
+ } else if (url.hostname === "api-staging.vertesia.io") {
150
+ // api-staging.vertesia.io -> sts-staging.vertesia.io
151
+ this.tokenServerUrl = "https://sts-staging.vertesia.io";
152
+ } else if (url.hostname.startsWith("api")) {
153
+ // Generic api.* pattern replacement
154
+ url.hostname = url.hostname.replace(/^api/, "sts");
155
+ this.tokenServerUrl = url.toString();
156
+ } else {
157
+ // Default to staging for everything else
158
+ this.tokenServerUrl = "https://sts-staging.vertesia.io";
159
+ }
160
+ } catch (e) {
161
+ // Default to staging if URL parsing fails
162
+ this.tokenServerUrl = "https://sts-staging.vertesia.io";
163
+ }
164
+ } else {
165
+ // Default to staging if no URL provided
166
+ this.tokenServerUrl = "https://sts-staging.vertesia.io";
167
+ }
168
+
116
169
  this.store = new ZenoClient({
117
170
  serverUrl: zenoServerUrl,
171
+ tokenServerUrl: this.tokenServerUrl,
118
172
  apikey: opts.apikey,
119
173
  onRequest: opts.onRequest,
120
- onResponse: opts.onResponse
174
+ onResponse: opts.onResponse,
121
175
  });
122
176
 
123
177
  if (opts.apikey) {
124
178
  this.withApiKey(opts.apikey);
125
179
  }
126
- //TODO: this is no more used, remove in next major version
127
- if (opts.projectId) {
128
- this.headers["x-project-id"] = opts.projectId;
129
- }
180
+
130
181
  this.onRequest = opts.onRequest;
131
182
  this.onResponse = opts.onResponse;
132
183
  this.sessionTags = opts.sessionTags;
@@ -153,25 +204,28 @@ export class VertesiaClient extends AbstractFetchClient<VertesiaClient> {
153
204
 
154
205
  async withApiKey(apiKey: string | null) {
155
206
  return this.withAuthCallback(
156
- apiKey ? async () => {
157
- if (!isApiKey(apiKey)) {
158
- return `Bearer ${apiKey}`
159
- }
160
-
161
- if (isTokenExpired(this._jwt)) {
162
- const jwt = await this.getAuthToken(apiKey);
163
- this._jwt = jwt.token;
164
- }
165
- return `Bearer ${this._jwt}`
166
- } : undefined
207
+ apiKey
208
+ ? async () => {
209
+ if (!isApiKey(apiKey)) {
210
+ return `Bearer ${apiKey}`;
211
+ }
212
+
213
+ if (isTokenExpired(this._jwt)) {
214
+ const jwt = await this.getAuthToken(apiKey);
215
+ this._jwt = jwt.token;
216
+ }
217
+ return `Bearer ${this._jwt}`;
218
+ }
219
+ : undefined,
167
220
  );
168
221
  }
169
222
 
170
223
  async getRawJWT() {
171
224
  if (!this._jwt && this._auth) {
172
225
  const auth = await this._auth();
173
- if (!this._jwt) { // the _jwt may be set by the auth callback
174
- this._jwt = auth.trim().split(' ')[1]; // remove Bearer prefix
226
+ if (!this._jwt) {
227
+ // the _jwt may be set by the auth callback
228
+ this._jwt = auth.trim().split(" ")[1]; // remove Bearer prefix
175
229
  }
176
230
  }
177
231
  return this._jwt || null;
@@ -221,21 +275,29 @@ export class VertesiaClient extends AbstractFetchClient<VertesiaClient> {
221
275
  return this.store.baseUrl;
222
276
  }
223
277
 
224
-
225
278
  /**
226
279
  *
227
- * Generate a token for use with other Composable's services
280
+ * Generate a token for use with other Vertesia's services
228
281
  *
229
- * @param accountId: selected account to generate the token for
230
282
  * @returns AuthTokenResponse
231
283
  */
232
- async getAuthToken(token?: string, accountId?: string): Promise<AuthTokenResponse> {
233
- const query = {
234
- accountId,
235
- token
236
- };
237
-
238
- return this.get('/auth/token', { query: query, headers: { "authorization": undefined } as any });
284
+ async getAuthToken(token?: string): Promise<AuthTokenResponse> {
285
+ return fetch(`${this.tokenServerUrl}/token/issue`, {
286
+ method: "POST",
287
+ headers: {
288
+ "Content-Type": "application/json",
289
+ Authorization: `Bearer ${token}`,
290
+ },
291
+ })
292
+ .then((response) => response.json())
293
+ .then((data) => data as AuthTokenResponse)
294
+ .catch((error) => {
295
+ console.error(
296
+ `Error fetching token from ${this.tokenServerUrl}:`,
297
+ { error },
298
+ );
299
+ throw error;
300
+ });
239
301
  }
240
302
 
241
303
  get initialHeaders() {
@@ -263,7 +325,7 @@ export class VertesiaClient extends AbstractFetchClient<VertesiaClient> {
263
325
  }
264
326
 
265
327
  function isApiKey(apiKey: string) {
266
- return (apiKey.startsWith('pk-') || apiKey.startsWith('sk-'));
328
+ return apiKey.startsWith("pk-") || apiKey.startsWith("sk-");
267
329
  }
268
330
 
269
331
  function isTokenExpired(token: string | null) {
@@ -274,38 +336,45 @@ function isTokenExpired(token: string | null) {
274
336
  const decoded = decodeJWT(token);
275
337
  const exp = decoded.exp;
276
338
  const currentTime = Date.now();
277
- return (currentTime <= exp * 1000 - EXPIRATION_THRESHOLD);
339
+ return currentTime <= exp * 1000 - EXPIRATION_THRESHOLD;
278
340
  }
279
341
 
280
342
  export function decodeJWT(jwt: string): AuthTokenPayload {
281
- const payloadBase64 = jwt.split('.')[1];
343
+ const payloadBase64 = jwt.split(".")[1];
282
344
  const decodedJson = base64UrlDecode(payloadBase64);
283
- return JSON.parse(decodedJson)
345
+ return JSON.parse(decodedJson);
284
346
  }
285
347
 
286
348
  function base64UrlDecode(input: string): string {
287
349
  // Convert base64url to base64
288
- const base64 = input.replace(/-/g, '+').replace(/_/g, '/')
350
+ const base64 = input
351
+ .replace(/-/g, "+")
352
+ .replace(/_/g, "/")
289
353
  // Pad with '=' to make length a multiple of 4
290
- .padEnd(Math.ceil(input.length / 4) * 4, '=');
354
+ .padEnd(Math.ceil(input.length / 4) * 4, "=");
291
355
 
292
- if (typeof Buffer !== 'undefined') {
356
+ if (typeof Buffer !== "undefined") {
293
357
  // Node.js
294
- return Buffer.from(base64, 'base64').toString('utf-8');
295
- } else if (typeof atob !== 'undefined' && typeof TextDecoder !== 'undefined') {
358
+ return Buffer.from(base64, "base64").toString("utf-8");
359
+ } else if (
360
+ typeof atob !== "undefined" &&
361
+ typeof TextDecoder !== "undefined"
362
+ ) {
296
363
  // Browser
297
364
  const binary = atob(base64);
298
- const bytes = Uint8Array.from(binary, c => c.charCodeAt(0));
365
+ const bytes = Uint8Array.from(binary, (c) => c.charCodeAt(0));
299
366
  // decode to utf8
300
367
  return new TextDecoder().decode(bytes);
301
368
  } else {
302
- throw new Error('No base64 decoder available');
369
+ throw new Error("No base64 decoder available");
303
370
  }
304
371
  }
305
372
 
306
- export function decodeEndpoints(endpoints: string | Record<string, string> | undefined): Record<string, string> {
373
+ export function decodeEndpoints(
374
+ endpoints: string | Record<string, string> | undefined,
375
+ ): Record<string, string> {
307
376
  if (!endpoints) {
308
- return getEndpointsFromDomain("api.vertesia.io")
377
+ return getEndpointsFromDomain("api.vertesia.io");
309
378
  }
310
379
  if (typeof endpoints === "string") {
311
380
  return getEndpointsFromDomain(endpoints);
@@ -319,12 +388,14 @@ function getEndpointsFromDomain(domain: string) {
319
388
  return {
320
389
  studio: `http://localhost:8091`,
321
390
  store: `http://localhost:8092`,
322
- }
391
+ token: process.env.STS_URL ?? "https://sts-staging.vertesia.io",
392
+ };
323
393
  } else {
324
394
  const url = `https://${domain}`;
325
395
  return {
326
396
  studio: url,
327
397
  store: url,
328
- }
398
+ token: url.replace("api", "sts"),
399
+ };
329
400
  }
330
401
  }
package/src/index.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  export * from './client.js';
2
2
  export * from './InteractionBase.js';
3
+ export * from './InteractionOutput.js';
3
4
  export type { AsyncExecutionResult, ComputeInteractionFacetsResponse } from './InteractionsApi.js';
4
5
  export type { ComputePromptFacetsResponse, ListInteractionsResponse } from './PromptsApi.js';
5
6
  export type { ComputeRunFacetsResponse, FilterOption } from './RunsApi.js';
6
7
  export type { GroupsQueryOptions } from './GroupsApi.js';
7
8
  export * from "./store/index.js";
8
9
  export * from "./StreamSource.js";
10
+ export type { OrphanedAppInstallation } from "./AppsApi.js";
@@ -91,6 +91,30 @@ export class CollectionsApi extends ApiTopic {
91
91
  });
92
92
  }
93
93
 
94
+ addChildren(collectionId: string, children: string[]): Promise<{ count: number }> {
95
+ return this.post(`/${collectionId}/children`, {
96
+ payload: {
97
+ action: 'add',
98
+ children
99
+ }
100
+ });
101
+ }
102
+
103
+ deleteChildren(collectionId: string, children: string[]): Promise<{ count: number }> {
104
+ return this.post(`/${collectionId}/children`, {
105
+ payload: {
106
+ action: 'delete',
107
+ children
108
+ }
109
+ });
110
+ }
111
+
112
+ searchChildren(collectionId: string, query: ComplexCollectionSearchQuery = {}): Promise<CollectionItem[]> {
113
+ return this.post(`/${collectionId}/children/search`, {
114
+ payload: query
115
+ });
116
+ }
117
+
94
118
  delete(id: string) {
95
119
  return this.del(`/${id}`);
96
120
  }
@@ -104,7 +128,6 @@ export class CollectionsApi extends ApiTopic {
104
128
  updatePermissions(collectionId: string, permissions: Record<string, string[]>): Promise<{
105
129
  id: string;
106
130
  security: Record<string, string[]>;
107
- objectsUpdated: number;
108
131
  }> {
109
132
  return this.put(`/${collectionId}/permissions`, {
110
133
  payload: permissions
@@ -121,9 +144,23 @@ export class CollectionsApi extends ApiTopic {
121
144
  id: string;
122
145
  message: string;
123
146
  security?: Record<string, string[]>;
124
- objectsUpdated: number;
125
147
  }> {
126
148
  return this.post(`/${collectionId}/propagate-permissions`);
127
149
  }
128
150
 
151
+ /**
152
+ * Manually trigger shared properties propagation from collection to member objects
153
+ * Useful for debugging and fixing shared properties issues
154
+ * @param collectionId - The collection ID
155
+ * @returns Object with collection id, message, and number of objects updated
156
+ */
157
+ propagateSharedProperties(collectionId: string): Promise<{
158
+ id: string;
159
+ message: string;
160
+ shared_properties: string[]
161
+ }> {
162
+ return this.post(`/${collectionId}/propagate-shared-props`);
163
+ }
164
+
165
+
129
166
  }