@vertesia/client 1.5.0-dev.20260807.073259Z → 1.5.0-dev.20260901.005903Z
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 +9 -8
- package/lib/AppsApi.d.ts.map +1 -1
- package/lib/AppsApi.js +11 -4
- package/lib/AppsApi.js.map +1 -1
- package/lib/GroupsApi.d.ts +4 -11
- package/lib/GroupsApi.d.ts.map +1 -1
- package/lib/GroupsApi.js.map +1 -1
- package/lib/InteractionBase.d.ts +114 -0
- package/lib/InteractionBase.d.ts.map +1 -1
- package/lib/InteractionCatalogApi.d.ts +3 -3
- package/lib/InteractionCatalogApi.d.ts.map +1 -1
- package/lib/InteractionCatalogApi.js +1 -1
- package/lib/InteractionOutput.d.ts +13 -3
- package/lib/InteractionOutput.d.ts.map +1 -1
- package/lib/InteractionOutput.js +33 -3
- package/lib/InteractionOutput.js.map +1 -1
- package/lib/OAuthServerApi.d.ts +1 -1
- package/lib/OAuthServerApi.d.ts.map +1 -1
- package/lib/OAuthServerApi.js +9 -2
- package/lib/OAuthServerApi.js.map +1 -1
- package/lib/ProjectsApi.d.ts +3 -3
- package/lib/ProjectsApi.d.ts.map +1 -1
- package/lib/ProjectsApi.js.map +1 -1
- package/lib/RunsApi.d.ts +6 -28
- package/lib/RunsApi.d.ts.map +1 -1
- package/lib/RunsApi.js +3 -3
- package/lib/RunsApi.js.map +1 -1
- package/lib/ToolsApi.d.ts +2 -1
- package/lib/ToolsApi.d.ts.map +1 -1
- package/lib/ToolsApi.js +9 -0
- package/lib/ToolsApi.js.map +1 -1
- package/lib/ViewsApi.d.ts +1 -1
- package/lib/ViewsApi.js +1 -1
- package/lib/client.d.ts +1 -0
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +3 -0
- package/lib/client.js.map +1 -1
- package/lib/execute.js +2 -2
- package/lib/execute.js.map +1 -1
- package/lib/store/AgentsApi.d.ts +4 -1
- package/lib/store/AgentsApi.d.ts.map +1 -1
- package/lib/store/AgentsApi.js +6 -4
- package/lib/store/AgentsApi.js.map +1 -1
- package/lib/store/CollectionsApi.d.ts +5 -2
- package/lib/store/CollectionsApi.d.ts.map +1 -1
- package/lib/store/CollectionsApi.js.map +1 -1
- package/lib/store/EmailApi.d.ts +9 -107
- package/lib/store/EmailApi.d.ts.map +1 -1
- package/lib/store/EmailApi.js.map +1 -1
- package/lib/store/FilesApi.d.ts +3 -1
- package/lib/store/FilesApi.d.ts.map +1 -1
- package/lib/store/FilesApi.js +7 -0
- package/lib/store/FilesApi.js.map +1 -1
- package/lib/store/ObjectsApi.d.ts +29 -4
- package/lib/store/ObjectsApi.d.ts.map +1 -1
- package/lib/store/ObjectsApi.js +0 -2
- package/lib/store/ObjectsApi.js.map +1 -1
- package/lib/store/PendingAsksApi.d.ts +2 -53
- package/lib/store/PendingAsksApi.d.ts.map +1 -1
- package/lib/store/PendingAsksApi.js.map +1 -1
- package/lib/store/ProcessApi.d.ts +15 -8
- package/lib/store/ProcessApi.d.ts.map +1 -1
- package/lib/store/ProcessApi.js +27 -1
- package/lib/store/ProcessApi.js.map +1 -1
- package/lib/store/ProcessTestRunApi.d.ts +26 -0
- package/lib/store/ProcessTestRunApi.d.ts.map +1 -0
- package/lib/store/ProcessTestRunApi.js +36 -0
- package/lib/store/ProcessTestRunApi.js.map +1 -0
- package/lib/store/QueryApi.d.ts +9 -51
- package/lib/store/QueryApi.d.ts.map +1 -1
- package/lib/store/QueryApi.js.map +1 -1
- package/lib/store/WorkflowsApi.d.ts +3 -3
- package/lib/store/WorkflowsApi.d.ts.map +1 -1
- package/lib/store/WorkflowsApi.js.map +1 -1
- package/lib/store/client.d.ts +2 -2
- package/lib/store/client.d.ts.map +1 -1
- package/lib/store/client.js +2 -2
- package/lib/store/client.js.map +1 -1
- package/lib/store/index.d.ts +1 -1
- package/lib/store/index.d.ts.map +1 -1
- package/lib/store/index.js +1 -1
- package/lib/store/index.js.map +1 -1
- package/lib/store/stream-termination.d.ts +2 -2
- package/lib/store/stream-termination.d.ts.map +1 -1
- package/lib/store/stream-termination.js +6 -4
- package/lib/store/stream-termination.js.map +1 -1
- package/lib/vertesia-client.js +8 -9
- package/lib/vertesia-client.js.map +1 -1
- package/package.json +7 -7
- package/src/AppsApi.ts +22 -8
- package/src/GroupsApi.ts +4 -10
- package/src/InteractionCatalogApi.ts +3 -3
- package/src/InteractionOutput.test.ts +41 -5
- package/src/InteractionOutput.ts +39 -3
- package/src/OAuthServerApi.test.ts +56 -0
- package/src/OAuthServerApi.ts +12 -2
- package/src/ProjectsApi.ts +4 -2
- package/src/RunsApi.ts +15 -14
- package/src/ToolsApi.ts +10 -0
- package/src/ViewsApi.test.ts +3 -1
- package/src/ViewsApi.ts +1 -1
- package/src/client.ts +4 -0
- package/src/execute.ts +2 -2
- package/src/store/AgentsApi.stream.test.ts +56 -0
- package/src/store/AgentsApi.ts +8 -4
- package/src/store/CollectionsApi.ts +8 -1
- package/src/store/EmailApi.ts +25 -107
- package/src/store/FilesApi.ts +12 -0
- package/src/store/ObjectsApi.ts +28 -4
- package/src/store/PendingAsksApi.ts +15 -57
- package/src/store/ProcessApi.test.ts +24 -0
- package/src/store/ProcessApi.ts +49 -8
- package/src/store/ProcessTestRunApi.ts +41 -0
- package/src/store/QueryApi.ts +9 -45
- package/src/store/WorkflowsApi.ts +4 -3
- package/src/store/client.ts +2 -2
- package/src/store/index.ts +1 -1
- package/src/store/stream-termination.test.ts +24 -0
- package/src/store/stream-termination.ts +10 -4
- package/lib/store/HiveMemoryApi.d.ts +0 -161
- package/lib/store/HiveMemoryApi.d.ts.map +0 -1
- package/lib/store/HiveMemoryApi.js +0 -170
- package/lib/store/HiveMemoryApi.js.map +0 -1
- package/src/store/HiveMemoryApi.ts +0 -220
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vertesia/client",
|
|
3
|
-
"version": "1.5.0-dev.
|
|
3
|
+
"version": "1.5.0-dev.20260901.005903Z",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"types": "./lib/index.d.ts",
|
|
@@ -12,16 +12,16 @@
|
|
|
12
12
|
"license": "Apache-2.0",
|
|
13
13
|
"devDependencies": {
|
|
14
14
|
"@types/node": "^24.13.3",
|
|
15
|
-
"rolldown": "1.2.
|
|
15
|
+
"rolldown": "1.2.4",
|
|
16
16
|
"typescript": "7.0.2",
|
|
17
17
|
"vitest": "^4.1.10",
|
|
18
18
|
"@vertesia/tsconfig": "0.1.0"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"eventsource": "^
|
|
22
|
-
"@
|
|
23
|
-
"@vertesia/common": "1.5.0-dev.
|
|
24
|
-
"@
|
|
21
|
+
"eventsource": "^5.0.0",
|
|
22
|
+
"@llumiverse/common": "1.5.0-dev.20260831.235912Z",
|
|
23
|
+
"@vertesia/common": "1.5.0-dev.20260901.005903Z",
|
|
24
|
+
"@vertesia/api-fetch-client": "1.5.0-dev.20260901.005903Z"
|
|
25
25
|
},
|
|
26
26
|
"exports": {
|
|
27
27
|
".": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"ai",
|
|
49
49
|
"typescript"
|
|
50
50
|
],
|
|
51
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "73de8716696201bda20b5ec0d0134bafd597387e",
|
|
52
52
|
"scripts": {
|
|
53
53
|
"lint": "biome lint src",
|
|
54
54
|
"clean:lib": "rimraf ./lib ./tsconfig.tsbuildinfo",
|
package/src/AppsApi.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ApiTopic, type ClientBase, type ServerError } from '@vertesia/api-fetch-client';
|
|
2
2
|
import type {
|
|
3
|
+
AgentRunResponse,
|
|
3
4
|
AppApiKeyCollectionParams,
|
|
4
5
|
AppBuildProgress,
|
|
5
6
|
AppDeleteSummary,
|
|
@@ -21,6 +22,7 @@ import type {
|
|
|
21
22
|
AppRepoRefs,
|
|
22
23
|
AppRepoTree,
|
|
23
24
|
AppScaffoldProgress,
|
|
25
|
+
AppsQuery,
|
|
24
26
|
AppToolCollection,
|
|
25
27
|
AppVersionListQuery,
|
|
26
28
|
AppVersionRecord,
|
|
@@ -34,17 +36,17 @@ import type {
|
|
|
34
36
|
SetMcpApiKeyRequest,
|
|
35
37
|
StartAppBuildRequest,
|
|
36
38
|
StartAppBuildResponse,
|
|
39
|
+
StartAppDevelopmentTaskRequest,
|
|
37
40
|
StartAppScaffoldRequest,
|
|
38
41
|
StartAppScaffoldResponse,
|
|
39
42
|
UpdateAppInstallationToolAllowlistPayload,
|
|
43
|
+
UpdateAppPayload,
|
|
40
44
|
UpsertAppVersionRequest,
|
|
41
45
|
ValidateUrlRequest,
|
|
42
46
|
ValidateUrlResponse,
|
|
43
47
|
} from '@vertesia/common';
|
|
44
48
|
|
|
45
|
-
export
|
|
46
|
-
manifest: null;
|
|
47
|
-
}
|
|
49
|
+
export type { OrphanedAppInstallation } from '@vertesia/common';
|
|
48
50
|
|
|
49
51
|
export default class AppsApi extends ApiTopic {
|
|
50
52
|
constructor(parent: ClientBase) {
|
|
@@ -55,7 +57,7 @@ export default class AppsApi extends ApiTopic {
|
|
|
55
57
|
return this.post('/', { payload: manifest });
|
|
56
58
|
}
|
|
57
59
|
|
|
58
|
-
update(id: string, manifest:
|
|
60
|
+
update(id: string, manifest: UpdateAppPayload): Promise<AppManifest> {
|
|
59
61
|
return this.put(`/${id}`, { payload: manifest });
|
|
60
62
|
}
|
|
61
63
|
|
|
@@ -251,11 +253,22 @@ export default class AppsApi extends ApiTopic {
|
|
|
251
253
|
return this.get(`/${encodeURIComponent(appIdOrName)}/development-tasks`);
|
|
252
254
|
}
|
|
253
255
|
|
|
254
|
-
/** Get a development task and its latest
|
|
256
|
+
/** Get a development task and its latest App Builder parent run, when started. */
|
|
255
257
|
getDevelopmentTask(appIdOrName: string, taskId: string): Promise<AppDevelopmentTaskDetails> {
|
|
256
258
|
return this.get(`/${encodeURIComponent(appIdOrName)}/development-tasks/${encodeURIComponent(taskId)}`);
|
|
257
259
|
}
|
|
258
260
|
|
|
261
|
+
/** Start the policy-controlled App Builder parent on an existing development-task branch. */
|
|
262
|
+
startDevelopmentTask(
|
|
263
|
+
appIdOrName: string,
|
|
264
|
+
taskId: string,
|
|
265
|
+
payload: StartAppDevelopmentTaskRequest,
|
|
266
|
+
): Promise<AgentRunResponse> {
|
|
267
|
+
return this.post(`/${encodeURIComponent(appIdOrName)}/development-tasks/${encodeURIComponent(taskId)}/runs`, {
|
|
268
|
+
payload,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
|
|
259
272
|
/** Create a repository branch from an existing branch, tag, or commit. */
|
|
260
273
|
createRepoBranch(appIdOrName: string, payload: CreateAppRepoBranchRequest): Promise<AppRepoBranch> {
|
|
261
274
|
return this.post(`/${encodeURIComponent(appIdOrName)}/repo/branches`, { payload });
|
|
@@ -296,11 +309,12 @@ export default class AppsApi extends ApiTopic {
|
|
|
296
309
|
}
|
|
297
310
|
|
|
298
311
|
/**
|
|
299
|
-
* @param
|
|
312
|
+
* @param query - pass `{ scope: 'project' }` to list only the apps installed in, or built in,
|
|
313
|
+
* the current project. Defaults to every app visible to the account, including the public catalog.
|
|
300
314
|
* @returns the app manifests but without the agent.tool property which can be big.
|
|
301
315
|
*/
|
|
302
|
-
list(): Promise<AppManifest[]> {
|
|
303
|
-
return this.get('/');
|
|
316
|
+
list(query?: AppsQuery): Promise<AppManifest[]> {
|
|
317
|
+
return this.get('/', { query: { ...(query?.scope && { scope: query.scope }) } });
|
|
304
318
|
}
|
|
305
319
|
|
|
306
320
|
/**
|
package/src/GroupsApi.ts
CHANGED
|
@@ -2,20 +2,14 @@ import { ApiTopic, type ClientBase } from '@vertesia/api-fetch-client';
|
|
|
2
2
|
import type {
|
|
3
3
|
CreateUserGroupPayload,
|
|
4
4
|
DeleteByIdResult,
|
|
5
|
+
ListUserGroupsQuery,
|
|
5
6
|
UpdateUserGroupPayload,
|
|
6
7
|
UserGroup,
|
|
7
8
|
UserRef,
|
|
8
9
|
} from '@vertesia/common';
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
tags?: string[];
|
|
13
|
-
limit?: number;
|
|
14
|
-
offset?: number;
|
|
15
|
-
/** Only return groups usable in this project (org-wide + restricted-to-this-project). */
|
|
16
|
-
project?: string;
|
|
17
|
-
[key: string]: string | string[] | number | undefined;
|
|
18
|
-
}
|
|
11
|
+
/** @deprecated Use ListUserGroupsQuery from @vertesia/common. */
|
|
12
|
+
export type GroupsQueryOptions = ListUserGroupsQuery;
|
|
19
13
|
|
|
20
14
|
export class GroupsApi extends ApiTopic {
|
|
21
15
|
constructor(parent: ClientBase) {
|
|
@@ -27,7 +21,7 @@ export class GroupsApi extends ApiTopic {
|
|
|
27
21
|
* @param options Query options for filtering and pagination
|
|
28
22
|
* @returns Array of UserGroup objects
|
|
29
23
|
*/
|
|
30
|
-
list(options?:
|
|
24
|
+
list(options?: ListUserGroupsQuery): Promise<UserGroup[]> {
|
|
31
25
|
return this.get('/', { query: options });
|
|
32
26
|
}
|
|
33
27
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ApiTopic, type ClientBase } from '@vertesia/api-fetch-client';
|
|
2
|
-
import type { CatalogInteractionRef,
|
|
2
|
+
import type { CatalogInteractionRef, InteractionStatus, ResolvedCatalogInteraction } from '@vertesia/common';
|
|
3
3
|
|
|
4
4
|
export class InteractionCatalogApi extends ApiTopic {
|
|
5
5
|
constructor(parent: ClientBase) {
|
|
@@ -58,10 +58,10 @@ export class InteractionCatalogApi extends ApiTopic {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
|
-
* Resolve an interaction
|
|
61
|
+
* Resolve an interaction by ID to its complete executable definition.
|
|
62
62
|
* @param id Interaction id
|
|
63
63
|
*/
|
|
64
|
-
resolve(id: string): Promise<
|
|
64
|
+
resolve(id: string): Promise<ResolvedCatalogInteraction> {
|
|
65
65
|
return this.get(`/resolve/${id}`);
|
|
66
66
|
}
|
|
67
67
|
}
|
|
@@ -10,6 +10,7 @@ describe('InteractionOutput', () => {
|
|
|
10
10
|
{ type: 'json', value: { title: 'Engineer', level: 'Senior' } },
|
|
11
11
|
{ type: 'image', value: 'data:image/png;base64,iVBORw0K...' },
|
|
12
12
|
{ type: 'image', value: 'https://example.com/image.jpg' },
|
|
13
|
+
{ type: 'video', value: 'gs://project-bucket/runs/run-1/media/video.mp4' },
|
|
13
14
|
];
|
|
14
15
|
|
|
15
16
|
describe('text accessors', () => {
|
|
@@ -29,6 +30,22 @@ describe('InteractionOutput', () => {
|
|
|
29
30
|
});
|
|
30
31
|
});
|
|
31
32
|
|
|
33
|
+
describe('thought accessors', () => {
|
|
34
|
+
it('keeps thoughts separate from normal answer text', () => {
|
|
35
|
+
const output = InteractionOutput.from([
|
|
36
|
+
{ type: 'thoughts', value: 'First reason' },
|
|
37
|
+
{ type: 'thoughts', value: 'Second reason' },
|
|
38
|
+
{ type: 'text', value: 'Answer' },
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
expect(output.hasThoughts()).toBe(true);
|
|
42
|
+
expect(output.thoughts(' | ')).toBe('First reason | Second reason');
|
|
43
|
+
expect(output.thoughtParts()).toEqual(['First reason', 'Second reason']);
|
|
44
|
+
expect(output.text()).toBe('Answer');
|
|
45
|
+
expect(output.stringify()).toBe('Answer');
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
32
49
|
describe('object accessors', () => {
|
|
33
50
|
it('should return first JSON object', () => {
|
|
34
51
|
const output = InteractionOutput.from<{ name: string; age: number }>(sampleResults);
|
|
@@ -78,6 +95,24 @@ describe('InteractionOutput', () => {
|
|
|
78
95
|
});
|
|
79
96
|
});
|
|
80
97
|
|
|
98
|
+
describe('video accessors', () => {
|
|
99
|
+
it('should return video results', () => {
|
|
100
|
+
const output = InteractionOutput.from(sampleResults);
|
|
101
|
+
|
|
102
|
+
expect(output.hasVideo()).toBe(true);
|
|
103
|
+
expect(output.video()).toBe('gs://project-bucket/runs/run-1/media/video.mp4');
|
|
104
|
+
expect(output.videos()).toEqual(['gs://project-bucket/runs/run-1/media/video.mp4']);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should throw when no video result exists', () => {
|
|
108
|
+
const output = InteractionOutput.from([{ type: 'text', value: 'hello' }]);
|
|
109
|
+
|
|
110
|
+
expect(output.hasVideo()).toBe(false);
|
|
111
|
+
expect(output.videos()).toEqual([]);
|
|
112
|
+
expect(() => output.video()).toThrow('No video result found');
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
81
116
|
describe('utility methods', () => {
|
|
82
117
|
it('should convert to string (concatenated text)', () => {
|
|
83
118
|
const output = InteractionOutput.from(sampleResults);
|
|
@@ -99,7 +134,8 @@ describe('InteractionOutput', () => {
|
|
|
99
134
|
'{"name":"Alice","age":30}\n' +
|
|
100
135
|
'{"title":"Engineer","level":"Senior"}\n' +
|
|
101
136
|
'data:image/png;base64,iVBORw0K...\n' +
|
|
102
|
-
'https://example.com/image.jpg'
|
|
137
|
+
'https://example.com/image.jpg\n' +
|
|
138
|
+
'gs://project-bucket/runs/run-1/media/video.mp4',
|
|
103
139
|
);
|
|
104
140
|
});
|
|
105
141
|
|
|
@@ -147,11 +183,11 @@ describe('InteractionOutput', () => {
|
|
|
147
183
|
expect(output[1]).toEqual({ type: 'text', value: 'World!' });
|
|
148
184
|
|
|
149
185
|
// Array properties
|
|
150
|
-
expect(output.length).toBe(
|
|
186
|
+
expect(output.length).toBe(7);
|
|
151
187
|
|
|
152
188
|
// Array methods
|
|
153
189
|
const types = output.map((r) => r.type);
|
|
154
|
-
expect(types).toEqual(['text', 'text', 'json', 'json', 'image', 'image']);
|
|
190
|
+
expect(types).toEqual(['text', 'text', 'json', 'json', 'image', 'image', 'video']);
|
|
155
191
|
|
|
156
192
|
const textResults = output.filter((r) => r.type === 'text');
|
|
157
193
|
expect(textResults).toHaveLength(2);
|
|
@@ -161,7 +197,7 @@ describe('InteractionOutput', () => {
|
|
|
161
197
|
const output = InteractionOutput.from<{ name: string; age: number }>(sampleResults);
|
|
162
198
|
|
|
163
199
|
// Should work as array AND have custom methods
|
|
164
|
-
expect(output.length).toBe(
|
|
200
|
+
expect(output.length).toBe(7);
|
|
165
201
|
expect(output.text('')).toBe('Hello, World!');
|
|
166
202
|
expect(output.object()).toEqual({ name: 'Alice', age: 30 });
|
|
167
203
|
});
|
|
@@ -185,7 +221,7 @@ describe('InteractionOutput', () => {
|
|
|
185
221
|
|
|
186
222
|
// Verify it still works correctly
|
|
187
223
|
expect(output2.text()).toBe('Hello, \nWorld!');
|
|
188
|
-
expect(output2.length).toBe(
|
|
224
|
+
expect(output2.length).toBe(7);
|
|
189
225
|
});
|
|
190
226
|
|
|
191
227
|
it('should not double-wrap when passing an InteractionOutputArray', () => {
|
package/src/InteractionOutput.ts
CHANGED
|
@@ -23,7 +23,7 @@ export function enhanceExecutionRun<ResultT = unknown, ParamsT = unknown>(
|
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* A convenient wrapper around CompletionResult[] that provides ergonomic accessors
|
|
26
|
-
* for different result types (text, JSON/objects, images) from interaction executions.
|
|
26
|
+
* for different result types (text, thoughts, JSON/objects, images) from interaction executions.
|
|
27
27
|
*
|
|
28
28
|
* Use the static from() method to create a proxied array that acts as both
|
|
29
29
|
* an array and has these convenience methods.
|
|
@@ -112,10 +112,18 @@ export class InteractionOutput<T = unknown> {
|
|
|
112
112
|
return this.results.some((r) => r.type === 'text');
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
hasThoughts() {
|
|
116
|
+
return this.results.some((r) => r.type === 'thoughts');
|
|
117
|
+
}
|
|
118
|
+
|
|
115
119
|
hasImage() {
|
|
116
120
|
return this.results.some((r) => r.type === 'image');
|
|
117
121
|
}
|
|
118
122
|
|
|
123
|
+
hasVideo() {
|
|
124
|
+
return this.results.some((r) => r.type === 'video');
|
|
125
|
+
}
|
|
126
|
+
|
|
119
127
|
/**
|
|
120
128
|
* Get the concatenated text from all text results.
|
|
121
129
|
* Returns an empty string if no text results exist.
|
|
@@ -134,6 +142,18 @@ export class InteractionOutput<T = unknown> {
|
|
|
134
142
|
return this.results.filter((r) => r.type === 'text').map((r) => r.value);
|
|
135
143
|
}
|
|
136
144
|
|
|
145
|
+
/** Get visible reasoning without mixing it into the assistant answer. */
|
|
146
|
+
thoughts(delimiter = '\n'): string {
|
|
147
|
+
return this.results
|
|
148
|
+
.filter((r) => r.type === 'thoughts')
|
|
149
|
+
.map((r) => r.value)
|
|
150
|
+
.join(delimiter);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
thoughtParts(): string[] {
|
|
154
|
+
return this.results.filter((r) => r.type === 'thoughts').map((r) => r.value);
|
|
155
|
+
}
|
|
156
|
+
|
|
137
157
|
/**
|
|
138
158
|
* Get the first JSON result as a parsed object.
|
|
139
159
|
* If no JSON result exists, attempts to parse the concatenated text as JSON.
|
|
@@ -197,9 +217,24 @@ export class InteractionOutput<T = unknown> {
|
|
|
197
217
|
return this.results.filter((r) => r.type === 'image').map((r) => r.value);
|
|
198
218
|
}
|
|
199
219
|
|
|
220
|
+
/** Get the first video result URI. */
|
|
221
|
+
video(): string {
|
|
222
|
+
const videoResult = this.results.find((r) => r.type === 'video');
|
|
223
|
+
if (!videoResult) {
|
|
224
|
+
throw new Error('No video result found');
|
|
225
|
+
}
|
|
226
|
+
return videoResult.value;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** Get all video result URIs. */
|
|
230
|
+
videos(): string[] {
|
|
231
|
+
return this.results.filter((r) => r.type === 'video').map((r) => r.value);
|
|
232
|
+
}
|
|
233
|
+
|
|
200
234
|
/**
|
|
201
|
-
* Convert all results to a string representation.
|
|
202
|
-
*
|
|
235
|
+
* Convert all answer results to a string representation.
|
|
236
|
+
* Thoughts are available through thoughts() and remain separate from the answer.
|
|
237
|
+
* Text and media results are used as-is, JSON results are stringified with the specified indent.
|
|
203
238
|
* All parts are joined using the specified separator.
|
|
204
239
|
*
|
|
205
240
|
* @param separator - The separator to use between parts (default: '\n')
|
|
@@ -216,6 +251,7 @@ export class InteractionOutput<T = unknown> {
|
|
|
216
251
|
*/
|
|
217
252
|
stringify(separator = '\n', indent = 2): string {
|
|
218
253
|
return this.results
|
|
254
|
+
.filter((r) => r.type !== 'thoughts')
|
|
219
255
|
.map((r) => {
|
|
220
256
|
switch (r.type) {
|
|
221
257
|
case 'json':
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { CreateOAuthAuthorizationRequestPayload } from '@vertesia/common';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { VertesiaClient } from './client.js';
|
|
4
|
+
|
|
5
|
+
const payload: CreateOAuthAuthorizationRequestPayload = {
|
|
6
|
+
response_type: 'code',
|
|
7
|
+
client_id: 'client-1',
|
|
8
|
+
redirect_uri: 'http://127.0.0.1/callback',
|
|
9
|
+
resource: 'https://mcp-dev-main.api.dev1.vertesia.io/mcp',
|
|
10
|
+
code_challenge: 'A'.repeat(43),
|
|
11
|
+
code_challenge_method: 'S256',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function createClient(requests: Request[]) {
|
|
15
|
+
return new VertesiaClient({
|
|
16
|
+
serverUrl: 'https://studio.example.com',
|
|
17
|
+
storeUrl: 'https://zeno.example.com',
|
|
18
|
+
tokenServerUrl: 'https://sts.dev1.vertesia.io',
|
|
19
|
+
fetch: vi.fn(async () =>
|
|
20
|
+
Response.json({
|
|
21
|
+
request_id: 'vor_1',
|
|
22
|
+
client_id: 'client-1',
|
|
23
|
+
client_name: 'Codex',
|
|
24
|
+
redirect_uri: payload.redirect_uri,
|
|
25
|
+
redirect_origin: 'http://127.0.0.1',
|
|
26
|
+
requested_scopes: [],
|
|
27
|
+
project_binding_mode: 'user_select',
|
|
28
|
+
status: 'pending',
|
|
29
|
+
created_at: '2026-08-10T00:00:00.000Z',
|
|
30
|
+
expires_at: '2026-08-10T00:10:00.000Z',
|
|
31
|
+
}),
|
|
32
|
+
),
|
|
33
|
+
onRequest: (request) => requests.push(request),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
describe('OAuthServerApi.createAuthorizationRequest', () => {
|
|
38
|
+
it('posts the initial request to the path-based tenant issuer', async () => {
|
|
39
|
+
const requests: Request[] = [];
|
|
40
|
+
const client = createClient(requests);
|
|
41
|
+
|
|
42
|
+
await client.oauthServer.createAuthorizationRequest(payload, '/env/dev1/dev-main');
|
|
43
|
+
|
|
44
|
+
expect(requests[0]?.url).toBe('https://sts.dev1.vertesia.io/env/dev1/dev-main/requests');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('rejects an untrusted authorization-server path before making a request', async () => {
|
|
48
|
+
const requests: Request[] = [];
|
|
49
|
+
const client = createClient(requests);
|
|
50
|
+
|
|
51
|
+
await expect(
|
|
52
|
+
client.oauthServer.createAuthorizationRequest(payload, 'https://attacker.example.com/oauth'),
|
|
53
|
+
).rejects.toThrow('Invalid OAuth authorization server path');
|
|
54
|
+
expect(requests).toHaveLength(0);
|
|
55
|
+
});
|
|
56
|
+
});
|
package/src/OAuthServerApi.ts
CHANGED
|
@@ -44,8 +44,18 @@ export default class OAuthServerApi extends ClientBase {
|
|
|
44
44
|
return this.parent.getRetryPolicy();
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
createAuthorizationRequest(
|
|
48
|
-
|
|
47
|
+
createAuthorizationRequest(
|
|
48
|
+
payload: CreateOAuthAuthorizationRequestPayload,
|
|
49
|
+
authorizationServerPath?: string,
|
|
50
|
+
): Promise<OAuthAuthorizationRequest> {
|
|
51
|
+
if (!authorizationServerPath) {
|
|
52
|
+
return this.post('/requests', { payload });
|
|
53
|
+
}
|
|
54
|
+
if (!/^\/env\/[a-z][a-z0-9-]{1,15}\/dev-[a-z0-9-]+$/.test(authorizationServerPath)) {
|
|
55
|
+
return Promise.reject(new Error('Invalid OAuth authorization server path'));
|
|
56
|
+
}
|
|
57
|
+
const url = new URL(`${authorizationServerPath}/requests`, this.baseUrl).toString();
|
|
58
|
+
return this.post(url, { payload });
|
|
49
59
|
}
|
|
50
60
|
|
|
51
61
|
createDeviceAuthorization(payload: OAuthDeviceAuthorizationRequest): Promise<OAuthDeviceAuthorizationResponse> {
|
package/src/ProjectsApi.ts
CHANGED
|
@@ -19,6 +19,8 @@ import type {
|
|
|
19
19
|
RenderingTemplateDefinition,
|
|
20
20
|
RenderingTemplateDefinitionRef,
|
|
21
21
|
SupportedIntegrations,
|
|
22
|
+
UpdateProjectConfigurationPayload,
|
|
23
|
+
UpdateProjectPayload,
|
|
22
24
|
} from '@vertesia/common';
|
|
23
25
|
|
|
24
26
|
export default class ProjectsApi extends ApiTopic {
|
|
@@ -43,7 +45,7 @@ export default class ProjectsApi extends ApiTopic {
|
|
|
43
45
|
});
|
|
44
46
|
}
|
|
45
47
|
|
|
46
|
-
update(projectId: string, payload:
|
|
48
|
+
update(projectId: string, payload: UpdateProjectPayload): Promise<Project> {
|
|
47
49
|
return this.put(`/${projectId}`, {
|
|
48
50
|
payload,
|
|
49
51
|
});
|
|
@@ -53,7 +55,7 @@ export default class ProjectsApi extends ApiTopic {
|
|
|
53
55
|
return this.del(`/${projectId}`);
|
|
54
56
|
}
|
|
55
57
|
|
|
56
|
-
updateConfiguration(projectId: string, payload:
|
|
58
|
+
updateConfiguration(projectId: string, payload: UpdateProjectConfigurationPayload): Promise<ProjectConfiguration> {
|
|
57
59
|
return this.put(`/${projectId}/configuration`, {
|
|
58
60
|
payload,
|
|
59
61
|
});
|
package/src/RunsApi.ts
CHANGED
|
@@ -2,10 +2,13 @@ import type { ExecutionResponse } from '@llumiverse/common';
|
|
|
2
2
|
import { ApiTopic, type ClientBase } from '@vertesia/api-fetch-client';
|
|
3
3
|
import type {
|
|
4
4
|
ComputeRunFacetPayload,
|
|
5
|
+
ComputeRunFacetsResponse,
|
|
5
6
|
ExecutionRun,
|
|
6
7
|
ExecutionRunDocRef,
|
|
7
8
|
ExecutionRunRef,
|
|
8
9
|
FindPayload,
|
|
10
|
+
FindRunResult,
|
|
11
|
+
InteractionExecutionResult,
|
|
9
12
|
PopulatedExecutionRun,
|
|
10
13
|
RunClonePayload,
|
|
11
14
|
RunCreatePayload,
|
|
@@ -16,7 +19,12 @@ import type {
|
|
|
16
19
|
UserMessagePayload,
|
|
17
20
|
} from '@vertesia/common';
|
|
18
21
|
import type { VertesiaClient } from './client.js';
|
|
19
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
type EnhancedExecutionRun,
|
|
24
|
+
type EnhancedInteractionExecutionResult,
|
|
25
|
+
enhanceExecutionRun,
|
|
26
|
+
enhanceInteractionExecutionResult,
|
|
27
|
+
} from './InteractionOutput.js';
|
|
20
28
|
|
|
21
29
|
export interface FilterOption {
|
|
22
30
|
id: string;
|
|
@@ -24,14 +32,7 @@ export interface FilterOption {
|
|
|
24
32
|
count: number;
|
|
25
33
|
}
|
|
26
34
|
|
|
27
|
-
export
|
|
28
|
-
environments?: { _id: string; count: number }[];
|
|
29
|
-
interactions?: { _id: string; count: number }[];
|
|
30
|
-
models?: { _id: string; count: number }[];
|
|
31
|
-
tags?: { _id: string; count: number }[];
|
|
32
|
-
status?: { _id: string; count: number }[];
|
|
33
|
-
total?: number;
|
|
34
|
-
}
|
|
35
|
+
export type { ComputeRunFacetsResponse } from '@vertesia/common';
|
|
35
36
|
|
|
36
37
|
export class RunsApi extends ApiTopic {
|
|
37
38
|
constructor(parent: ClientBase) {
|
|
@@ -54,7 +55,7 @@ export class RunsApi extends ApiTopic {
|
|
|
54
55
|
return this.get('/', { query: query });
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
find(payload: FindPayload): Promise<
|
|
58
|
+
find(payload: FindPayload): Promise<FindRunResult[]> {
|
|
58
59
|
return this.post('/find', {
|
|
59
60
|
payload,
|
|
60
61
|
});
|
|
@@ -91,7 +92,7 @@ export class RunsApi extends ApiTopic {
|
|
|
91
92
|
async create<ResultT = unknown, ParamsT = unknown>(
|
|
92
93
|
payload: RunCreatePayload,
|
|
93
94
|
options?: { timeoutMs?: number | false | null; signal?: AbortSignal },
|
|
94
|
-
): Promise<
|
|
95
|
+
): Promise<EnhancedInteractionExecutionResult<ResultT, ParamsT>> {
|
|
95
96
|
const sessionTags = (this.client as VertesiaClient).sessionTags;
|
|
96
97
|
if (sessionTags) {
|
|
97
98
|
let tags = Array.isArray(sessionTags) ? sessionTags : [sessionTags];
|
|
@@ -102,12 +103,12 @@ export class RunsApi extends ApiTopic {
|
|
|
102
103
|
}
|
|
103
104
|
payload = { ...payload, tags };
|
|
104
105
|
}
|
|
105
|
-
const r = await this.post<
|
|
106
|
+
const r = await this.post<InteractionExecutionResult<ParamsT>>('/', {
|
|
106
107
|
payload,
|
|
107
108
|
timeoutMs: options?.timeoutMs,
|
|
108
109
|
signal: options?.signal,
|
|
109
110
|
});
|
|
110
|
-
return
|
|
111
|
+
return enhanceInteractionExecutionResult<ResultT, ParamsT>(r);
|
|
111
112
|
}
|
|
112
113
|
|
|
113
114
|
/**
|
|
@@ -145,7 +146,7 @@ export class RunsApi extends ApiTopic {
|
|
|
145
146
|
/**
|
|
146
147
|
* Get the list of all runs facets
|
|
147
148
|
* @param payload query payload to filter facet search
|
|
148
|
-
* @returns
|
|
149
|
+
* @returns Facet buckets and the total number of matching runs
|
|
149
150
|
**/
|
|
150
151
|
computeFacets(query: ComputeRunFacetPayload): Promise<ComputeRunFacetsResponse> {
|
|
151
152
|
return this.post('/facets', {
|
package/src/ToolsApi.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { ApiTopic, type ClientBase } from '@vertesia/api-fetch-client';
|
|
2
2
|
import type {
|
|
3
3
|
AggregatedTool,
|
|
4
|
+
InspectProjectToolQuery,
|
|
4
5
|
ListProjectToolsQuery,
|
|
6
|
+
ToolInspection,
|
|
5
7
|
ValidateToolNamesPayload,
|
|
6
8
|
ValidateToolNamesResponse,
|
|
7
9
|
} from '@vertesia/common';
|
|
@@ -37,9 +39,17 @@ export default class ToolsApi extends ApiTopic {
|
|
|
37
39
|
const params: Record<string, string> = {};
|
|
38
40
|
if (query?.sources?.length) params.sources = query.sources.join(',');
|
|
39
41
|
if (query?.exclude?.length) params.exclude = query.exclude.join(',');
|
|
42
|
+
if (query?.context) params.context = query.context;
|
|
40
43
|
return this.get('/', { query: Object.keys(params).length > 0 ? params : undefined });
|
|
41
44
|
}
|
|
42
45
|
|
|
46
|
+
inspect(name: string, query?: InspectProjectToolQuery): Promise<ToolInspection> {
|
|
47
|
+
if (!name.trim()) throw new Error('Tool name must not be empty');
|
|
48
|
+
return this.get(`/${encodeURIComponent(name)}`, {
|
|
49
|
+
query: query?.context ? { context: query.context } : undefined,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
43
53
|
/**
|
|
44
54
|
* List only Vertesia-provided builtin tools and system skills.
|
|
45
55
|
*/
|
package/src/ViewsApi.test.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { describe, expect, it, vi } from 'vitest';
|
|
|
2
2
|
import { VertesiaClient } from './client.js';
|
|
3
3
|
|
|
4
4
|
describe('ViewsApi', () => {
|
|
5
|
-
it('keeps CRUD on Studio and proxies execution to Zeno', async () => {
|
|
5
|
+
it('keeps CRUD on Studio and proxies persisted and app-contributed execution to Zeno', async () => {
|
|
6
6
|
const requests: Request[] = [];
|
|
7
7
|
const fetchMock = vi.fn(async () => {
|
|
8
8
|
return new Response(JSON.stringify({}), {
|
|
@@ -19,6 +19,7 @@ describe('ViewsApi', () => {
|
|
|
19
19
|
|
|
20
20
|
await client.views.retrieve('document-library');
|
|
21
21
|
await client.views.execute('document-library');
|
|
22
|
+
await client.views.execute('app:content:document-library');
|
|
22
23
|
await client.views.preview({
|
|
23
24
|
configuration: {
|
|
24
25
|
name: 'Document library',
|
|
@@ -30,6 +31,7 @@ describe('ViewsApi', () => {
|
|
|
30
31
|
expect(requests.map((request) => request.url)).toEqual([
|
|
31
32
|
'https://studio.example.com/api/v1/views/document-library',
|
|
32
33
|
'https://zeno.example.com/api/v1/view-executions/document-library/execute',
|
|
34
|
+
'https://zeno.example.com/api/v1/view-executions/app%3Acontent%3Adocument-library/execute',
|
|
33
35
|
'https://zeno.example.com/api/v1/view-executions/preview',
|
|
34
36
|
]);
|
|
35
37
|
});
|
package/src/ViewsApi.ts
CHANGED
|
@@ -45,7 +45,7 @@ export default class ViewsApi extends ApiTopic {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
|
-
* Execute a persisted or app-contributed View through the content service.
|
|
48
|
+
* Execute a persisted, built-in system, or app-contributed View through the content service.
|
|
49
49
|
*/
|
|
50
50
|
execute(id: string, payload: ExecuteViewRequest = {}): Promise<ViewExecutionResult> {
|
|
51
51
|
return this.executionApi.execute(id, payload);
|
package/src/client.ts
CHANGED
package/src/execute.ts
CHANGED
|
@@ -47,7 +47,7 @@ export async function executeInteraction<P = unknown>(
|
|
|
47
47
|
onChunk?: (chunk: string) => void,
|
|
48
48
|
): Promise<InteractionExecutionResult<P>> {
|
|
49
49
|
const stream = !!onChunk;
|
|
50
|
-
const response =
|
|
50
|
+
const response = await client.runs.create<P, P>(
|
|
51
51
|
{
|
|
52
52
|
...payload,
|
|
53
53
|
interaction: interactionId,
|
|
@@ -56,7 +56,7 @@ export async function executeInteraction<P = unknown>(
|
|
|
56
56
|
// Synchronous interaction execution blocks on the model; keep a long client timeout.
|
|
57
57
|
// (Streaming returns the run immediately, then streams over a separate channel — see below.)
|
|
58
58
|
{ timeoutMs: stream ? undefined : INTERACTION_EXECUTION_TIMEOUT_MS },
|
|
59
|
-
)
|
|
59
|
+
);
|
|
60
60
|
if (stream) {
|
|
61
61
|
if (response.status === ExecutionRunStatus.failed) {
|
|
62
62
|
return response;
|