@vertesia/tools-sdk 1.4.0-dev.20260615.042549Z → 1.4.0-dev.20260629.130134Z
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/ToolRegistry.js +1 -1
- package/lib/ToolRegistry.js.map +1 -1
- package/lib/index.d.ts +0 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +0 -1
- package/lib/index.js.map +1 -1
- package/lib/server/app-package.d.ts +0 -8
- package/lib/server/app-package.d.ts.map +1 -1
- package/lib/server/app-package.js +30 -65
- package/lib/server/app-package.js.map +1 -1
- package/lib/server/content-types.d.ts.map +1 -1
- package/lib/server/content-types.js +10 -40
- package/lib/server/content-types.js.map +1 -1
- package/lib/server/types.d.ts +1 -5
- package/lib/server/types.d.ts.map +1 -1
- package/lib/server.d.ts.map +1 -1
- package/lib/server.js +1 -4
- package/lib/server.js.map +1 -1
- package/lib/types.d.ts +13 -5
- package/lib/types.d.ts.map +1 -1
- package/package.json +10 -9
- package/src/ToolRegistry.ts +1 -1
- package/src/index.ts +0 -2
- package/src/server/app-package.ts +34 -82
- package/src/server/content-types.ts +10 -43
- package/src/server/types.ts +1 -10
- package/src/server.ts +0 -4
- package/src/types.ts +14 -5
- package/lib/server/dashboards.d.ts +0 -4
- package/lib/server/dashboards.d.ts.map +0 -1
- package/lib/server/dashboards.js +0 -25
- package/lib/server/dashboards.js.map +0 -1
- package/src/server/app-package.test.ts +0 -140
- package/src/server/content-types.test.ts +0 -64
- package/src/server/dashboards.ts +0 -31
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
AppDashboardDefinition,
|
|
3
2
|
AppPackage,
|
|
4
3
|
AppPackageScope,
|
|
5
4
|
AppWidgetInfo,
|
|
@@ -16,19 +15,14 @@ function getRequestPayload<T>(c: Context): Promise<T | undefined> {
|
|
|
16
15
|
return c.req.method === 'POST' ? c.req.json<T>() : Promise.resolve(undefined);
|
|
17
16
|
}
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
type AppPackageBuilder = (pkg: AppPackage, config: ToolServerConfig, options: BuildAppPackageOptions) => Promise<void>;
|
|
26
|
-
|
|
27
|
-
const builders: Record<Exclude<AppPackageScope, 'all'>, AppPackageBuilder> = {
|
|
28
|
-
async tools(pkg: AppPackage, config: ToolServerConfig, options: BuildAppPackageOptions) {
|
|
18
|
+
const builders: Record<
|
|
19
|
+
Exclude<AppPackageScope, 'all'>,
|
|
20
|
+
(pkg: AppPackage, config: ToolServerConfig, c: Context) => Promise<void>
|
|
21
|
+
> = {
|
|
22
|
+
async tools(pkg: AppPackage, config: ToolServerConfig, c: Context) {
|
|
29
23
|
const { tools: toolCollections = [], skills: skillCollections = [] } = config;
|
|
30
24
|
|
|
31
|
-
const filterContext =
|
|
25
|
+
const filterContext = await getRequestPayload<ToolUseContext>(c);
|
|
32
26
|
|
|
33
27
|
// Aggregate all tools from all collections
|
|
34
28
|
const allTools = toolCollections.flatMap((collection) => collection.getToolDefinitions(filterContext));
|
|
@@ -65,23 +59,13 @@ const builders: Record<Exclude<AppPackageScope, 'all'>, AppPackageBuilder> = {
|
|
|
65
59
|
pkg.interactions = allInteractions;
|
|
66
60
|
},
|
|
67
61
|
async types(pkg: AppPackage, config: ToolServerConfig) {
|
|
68
|
-
// A type's public id is its BARE name: stored objects reference it as the portable
|
|
69
|
-
// `app:<app>:<type>` string, so the in-code collection (a code-organization grouping,
|
|
70
|
-
// unlike tool/skill collections which are semantic) must NOT leak into the id.
|
|
71
|
-
// Names must therefore be unique across collections — fail the package build otherwise.
|
|
72
62
|
const allTypes: InCodeTypeDefinition[] = [];
|
|
73
|
-
const seen = new Map<string, string>();
|
|
74
63
|
for (const coll of config.types || []) {
|
|
75
64
|
for (const type of coll.types) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
`Type names must be unique across collections so the portable 'app:<app>:${type.name}' ref resolves.`,
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
seen.set(type.name, coll.name);
|
|
84
|
-
allTypes.push({ ...type, id: type.name });
|
|
65
|
+
allTypes.push({
|
|
66
|
+
...type,
|
|
67
|
+
id: `${coll.name}:${type.name}`,
|
|
68
|
+
});
|
|
85
69
|
}
|
|
86
70
|
}
|
|
87
71
|
pkg.types = allTypes;
|
|
@@ -102,19 +86,6 @@ const builders: Record<Exclude<AppPackageScope, 'all'>, AppPackageBuilder> = {
|
|
|
102
86
|
})),
|
|
103
87
|
);
|
|
104
88
|
},
|
|
105
|
-
async dashboards(pkg: AppPackage, config: ToolServerConfig) {
|
|
106
|
-
const seen = new Set<string>();
|
|
107
|
-
const dashboards: AppDashboardDefinition[] = [];
|
|
108
|
-
for (const dashboard of config.dashboards || []) {
|
|
109
|
-
if (seen.has(dashboard.id)) {
|
|
110
|
-
console.warn(`[app-package] Duplicate dashboard id "${dashboard.id}", skipping`);
|
|
111
|
-
continue;
|
|
112
|
-
}
|
|
113
|
-
seen.add(dashboard.id);
|
|
114
|
-
dashboards.push(dashboard);
|
|
115
|
-
}
|
|
116
|
-
pkg.dashboards = dashboards;
|
|
117
|
-
},
|
|
118
89
|
async widgets(pkg: AppPackage, config: ToolServerConfig) {
|
|
119
90
|
const { skills: skillCollections = [] } = config;
|
|
120
91
|
const widgets: Record<string, AppWidgetInfo> = {};
|
|
@@ -131,10 +102,10 @@ const builders: Record<Exclude<AppPackageScope, 'all'>, AppPackageBuilder> = {
|
|
|
131
102
|
}
|
|
132
103
|
pkg.widgets = widgets;
|
|
133
104
|
},
|
|
134
|
-
async ui(pkg: AppPackage, config: ToolServerConfig,
|
|
105
|
+
async ui(pkg: AppPackage, config: ToolServerConfig, c: Context) {
|
|
135
106
|
if (config.uiConfig) {
|
|
136
107
|
pkg.ui = { ...config.uiConfig };
|
|
137
|
-
const origin =
|
|
108
|
+
const origin = new URL(c.req.url).origin;
|
|
138
109
|
pkg.ui.src = new URL(pkg.ui.src, origin).toString();
|
|
139
110
|
if (!pkg.ui.isolation) {
|
|
140
111
|
pkg.ui.isolation = 'shadow';
|
|
@@ -157,71 +128,52 @@ const builders: Record<Exclude<AppPackageScope, 'all'>, AppPackageBuilder> = {
|
|
|
157
128
|
},
|
|
158
129
|
};
|
|
159
130
|
|
|
160
|
-
function
|
|
161
|
-
const
|
|
162
|
-
return new Set(values.filter(Boolean) as AppPackageScope[]);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
export async function buildAppPackage(
|
|
166
|
-
config: ToolServerConfig,
|
|
167
|
-
options: BuildAppPackageOptions = {},
|
|
168
|
-
): Promise<AppPackage> {
|
|
131
|
+
async function handlePackageRequest(c: Context, config: ToolServerConfig) {
|
|
132
|
+
const scope = c.req.query('scope') || 'all';
|
|
169
133
|
const pkg: AppPackage = {};
|
|
170
134
|
|
|
171
|
-
const scopes =
|
|
135
|
+
const scopes = new Set<AppPackageScope>(scope.split(',') as AppPackageScope[]);
|
|
136
|
+
// TODO build pkg based on the query param scope
|
|
172
137
|
if (scopes.has('all')) {
|
|
173
|
-
await builders.tools(pkg, config,
|
|
174
|
-
await builders.interactions(pkg, config,
|
|
175
|
-
await builders.types(pkg, config,
|
|
176
|
-
await builders.processes(pkg, config,
|
|
177
|
-
await builders.templates(pkg, config,
|
|
178
|
-
await builders.
|
|
179
|
-
await builders.
|
|
180
|
-
await builders.
|
|
181
|
-
await builders.
|
|
182
|
-
await builders.activities(pkg, config, options);
|
|
138
|
+
await builders.tools(pkg, config, c);
|
|
139
|
+
await builders.interactions(pkg, config, c);
|
|
140
|
+
await builders.types(pkg, config, c);
|
|
141
|
+
await builders.processes(pkg, config, c);
|
|
142
|
+
await builders.templates(pkg, config, c);
|
|
143
|
+
await builders.widgets(pkg, config, c);
|
|
144
|
+
await builders.ui(pkg, config, c);
|
|
145
|
+
await builders.settings(pkg, config, c);
|
|
146
|
+
await builders.activities(pkg, config, c);
|
|
183
147
|
} else {
|
|
184
148
|
if (scopes.has('tools')) {
|
|
185
|
-
await builders.tools(pkg, config,
|
|
149
|
+
await builders.tools(pkg, config, c);
|
|
186
150
|
}
|
|
187
151
|
if (scopes.has('interactions')) {
|
|
188
|
-
await builders.interactions(pkg, config,
|
|
152
|
+
await builders.interactions(pkg, config, c);
|
|
189
153
|
}
|
|
190
154
|
if (scopes.has('types')) {
|
|
191
|
-
await builders.types(pkg, config,
|
|
155
|
+
await builders.types(pkg, config, c);
|
|
192
156
|
}
|
|
193
157
|
if (scopes.has('processes')) {
|
|
194
|
-
await builders.processes(pkg, config,
|
|
158
|
+
await builders.processes(pkg, config, c);
|
|
195
159
|
}
|
|
196
160
|
if (scopes.has('templates')) {
|
|
197
|
-
await builders.templates(pkg, config,
|
|
198
|
-
}
|
|
199
|
-
if (scopes.has('dashboards')) {
|
|
200
|
-
await builders.dashboards(pkg, config, options);
|
|
161
|
+
await builders.templates(pkg, config, c);
|
|
201
162
|
}
|
|
202
163
|
if (scopes.has('widgets')) {
|
|
203
|
-
await builders.widgets(pkg, config,
|
|
164
|
+
await builders.widgets(pkg, config, c);
|
|
204
165
|
}
|
|
205
166
|
if (scopes.has('ui')) {
|
|
206
|
-
await builders.ui(pkg, config,
|
|
167
|
+
await builders.ui(pkg, config, c);
|
|
207
168
|
}
|
|
208
169
|
if (scopes.has('settings')) {
|
|
209
|
-
await builders.settings(pkg, config,
|
|
170
|
+
await builders.settings(pkg, config, c);
|
|
210
171
|
}
|
|
211
172
|
if (scopes.has('activities')) {
|
|
212
|
-
await builders.activities(pkg, config,
|
|
173
|
+
await builders.activities(pkg, config, c);
|
|
213
174
|
}
|
|
214
175
|
}
|
|
215
176
|
|
|
216
|
-
return pkg;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
async function handlePackageRequest(c: Context, config: ToolServerConfig) {
|
|
220
|
-
const pkg = await buildAppPackage(config, {
|
|
221
|
-
scope: c.req.query('scope') || 'all',
|
|
222
|
-
origin: new URL(c.req.url).origin,
|
|
223
|
-
toolUseContext: await getRequestPayload<ToolUseContext>(c),
|
|
224
|
-
});
|
|
225
177
|
return c.json(pkg);
|
|
226
178
|
}
|
|
227
179
|
|
|
@@ -10,15 +10,13 @@ import type { ToolServerConfig } from './types.js';
|
|
|
10
10
|
export function createContentTypesRoute(app: Hono, basePath: string, config: ToolServerConfig) {
|
|
11
11
|
const { types = [] } = config;
|
|
12
12
|
|
|
13
|
-
// GET /api/types - Returns all
|
|
14
|
-
// A type's public id is its declared BARE name, verbatim (`app:<app>:<type>` once
|
|
15
|
-
// app-prefixed): collections organize code, they are not part of the type identity.
|
|
13
|
+
// GET /api/types - Returns all interactions from all collections
|
|
16
14
|
app.get(basePath, (c) => {
|
|
17
15
|
const allTypes: InCodeTypeDefinition[] = [];
|
|
18
16
|
|
|
19
17
|
for (const coll of types) {
|
|
20
18
|
for (const type of coll.types) {
|
|
21
|
-
allTypes.push({ ...type, id: type.name });
|
|
19
|
+
allTypes.push({ ...type, id: `${coll.name}:${toPathName(type.name)}` });
|
|
22
20
|
}
|
|
23
21
|
}
|
|
24
22
|
|
|
@@ -39,51 +37,20 @@ export function createContentTypesRoute(app: Hono, basePath: string, config: Too
|
|
|
39
37
|
app.route(`${basePath}/${coll.name}`, createContentTypeEndpoints(coll));
|
|
40
38
|
}
|
|
41
39
|
|
|
42
|
-
// GET /api/types/:name - Direct access to content type
|
|
43
|
-
// Canonical form is the BARE type name (`<type>`), matching the portable
|
|
44
|
-
// `app:<app>:<type>` ref convention used by objects.create/search — the
|
|
45
|
-
// collection is an in-code grouping, not part of the type's public id.
|
|
46
|
-
// `<collection>:<type>` is also accepted as a backward-compatible alias.
|
|
40
|
+
// GET /api/types/:name - Direct access to content type
|
|
47
41
|
app.get(`${basePath}/:name`, async (c) => {
|
|
48
42
|
const name = c.req.param('name');
|
|
49
43
|
const parts = name.split(':');
|
|
50
|
-
if (parts.length === 1) {
|
|
51
|
-
// Match the declared name verbatim; fall back to the toPathName variant for
|
|
52
|
-
// leniency with legacy refs that used the path-mangled form.
|
|
53
|
-
const matches = types.flatMap((coll) =>
|
|
54
|
-
coll.types
|
|
55
|
-
.filter((t) => t.name === name || toPathName(t.name) === name)
|
|
56
|
-
.map((t) => ({ coll, type: t })),
|
|
57
|
-
);
|
|
58
|
-
if (matches.length === 1) {
|
|
59
|
-
return c.json({ ...matches[0].type, id: matches[0].type.name });
|
|
60
|
-
}
|
|
61
|
-
if (matches.length > 1) {
|
|
62
|
-
const colls = matches.map((m) => m.coll.name).join(', ');
|
|
63
|
-
throw new HTTPException(409, {
|
|
64
|
-
message:
|
|
65
|
-
`Ambiguous content type name '${name}': defined in collections ${colls}. ` +
|
|
66
|
-
'Type names must be unique across collections so the portable ' +
|
|
67
|
-
`'app:<app>:${name}' ref resolves; rename one of them, or address it as '<collection>:<type>'.`,
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
throw new HTTPException(404, {
|
|
71
|
-
message: `No content type found with name: ${name}`,
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
44
|
if (parts.length !== 2) {
|
|
75
45
|
throw new HTTPException(400, {
|
|
76
|
-
message: "Invalid content type name. Expected
|
|
46
|
+
message: "Invalid content type name. Expected format 'collection:type'",
|
|
77
47
|
});
|
|
78
48
|
}
|
|
79
49
|
const collName = parts[0];
|
|
80
|
-
const typeName = parts[1];
|
|
81
|
-
const ctype = types
|
|
82
|
-
.find((t) => t.name === collName)
|
|
83
|
-
?.types.find((t) => t.name === typeName || toPathName(t.name) === toPathName(typeName));
|
|
50
|
+
const typeName = toPathName(parts[1]);
|
|
51
|
+
const ctype = types.find((t) => t.name === collName)?.getTypeByName(typeName);
|
|
84
52
|
if (ctype) {
|
|
85
|
-
|
|
86
|
-
return c.json({ ...ctype, id: ctype.name });
|
|
53
|
+
return c.json({ ...ctype, id: `${collName}:${typeName}` });
|
|
87
54
|
}
|
|
88
55
|
|
|
89
56
|
throw new HTTPException(404, {
|
|
@@ -96,12 +63,12 @@ function createContentTypeEndpoints(coll: ContentTypesCollection): Hono {
|
|
|
96
63
|
const endpoint = new Hono();
|
|
97
64
|
|
|
98
65
|
endpoint.get('/', (c: Context) => {
|
|
99
|
-
return c.json(coll.types.map((t) => ({ ...t, id: t.name })));
|
|
66
|
+
return c.json(coll.types.map((t) => ({ ...t, id: `${coll.name}:${toPathName(t.name)}` })));
|
|
100
67
|
});
|
|
101
68
|
|
|
102
69
|
endpoint.get('/:name', (c: Context) => {
|
|
103
70
|
const name = c.req.param('name');
|
|
104
|
-
const ctype = coll.types.find((t) =>
|
|
71
|
+
const ctype = coll.types.find((t) => toPathName(t.name) === name);
|
|
105
72
|
if (!ctype) {
|
|
106
73
|
throw new HTTPException(404, {
|
|
107
74
|
message: `No content type found with name: ${name}`,
|
|
@@ -109,7 +76,7 @@ function createContentTypeEndpoints(coll: ContentTypesCollection): Hono {
|
|
|
109
76
|
}
|
|
110
77
|
return c.json({
|
|
111
78
|
...ctype,
|
|
112
|
-
id: ctype.name
|
|
79
|
+
id: `${coll.name}:${toPathName(ctype.name)}`,
|
|
113
80
|
});
|
|
114
81
|
});
|
|
115
82
|
|
package/src/server/types.ts
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import type { JSONSchema } from '@llumiverse/common';
|
|
2
|
-
import type {
|
|
3
|
-
AppDashboardDefinition,
|
|
4
|
-
AppUIConfig,
|
|
5
|
-
InCodeProcessDefinition,
|
|
6
|
-
ProjectConfiguration,
|
|
7
|
-
} from '@vertesia/common';
|
|
2
|
+
import type { AppUIConfig, InCodeProcessDefinition, ProjectConfiguration } from '@vertesia/common';
|
|
8
3
|
import type { Context } from 'hono';
|
|
9
4
|
import type { ActivityCollection } from '../ActivityCollection.js';
|
|
10
5
|
import type { AuthSession } from '../auth.js';
|
|
@@ -68,10 +63,6 @@ export interface ToolServerConfig {
|
|
|
68
63
|
* Process definitions to expose as app-contributed processes.
|
|
69
64
|
*/
|
|
70
65
|
processes?: InCodeProcessDefinition[];
|
|
71
|
-
/**
|
|
72
|
-
* Dashboard definitions to expose as app-contributed dashboards.
|
|
73
|
-
*/
|
|
74
|
-
dashboards?: AppDashboardDefinition[];
|
|
75
66
|
/**
|
|
76
67
|
* Skill collections to expose
|
|
77
68
|
*/
|
package/src/server.ts
CHANGED
|
@@ -5,7 +5,6 @@ import { z } from 'zod';
|
|
|
5
5
|
import { createActivitiesRoute } from './server/activities.js';
|
|
6
6
|
import { createPackageRoute } from './server/app-package.js';
|
|
7
7
|
import { createContentTypesRoute } from './server/content-types.js';
|
|
8
|
-
import { createDashboardsRoute } from './server/dashboards.js';
|
|
9
8
|
import { createInteractionsRoute } from './server/interactions.js';
|
|
10
9
|
import { createMcpRoute } from './server/mcp.js';
|
|
11
10
|
import { createProcessesRoute } from './server/processes.js';
|
|
@@ -50,7 +49,6 @@ export function createToolServer(config: ToolServerConfig): Hono {
|
|
|
50
49
|
skills = [],
|
|
51
50
|
templates = [],
|
|
52
51
|
activities = [],
|
|
53
|
-
dashboards = [],
|
|
54
52
|
mcpProviders = [],
|
|
55
53
|
disableHtml = false,
|
|
56
54
|
} = config;
|
|
@@ -102,7 +100,6 @@ export function createToolServer(config: ToolServerConfig): Hono {
|
|
|
102
100
|
interactions: interactions.map((col) => `${prefix}/interactions/${col.name}`),
|
|
103
101
|
templates: templates.map((col) => `${prefix}/templates/${col.name}`),
|
|
104
102
|
processes: `${prefix}/processes`,
|
|
105
|
-
dashboards: dashboards.length > 0 ? `${prefix}/dashboards` : undefined,
|
|
106
103
|
activities: activities.map((col) => `${prefix}/activities/${col.name}`),
|
|
107
104
|
mcp: mcpProviders.map((p) => `${prefix}/mcp/${p.name}`),
|
|
108
105
|
},
|
|
@@ -118,7 +115,6 @@ export function createToolServer(config: ToolServerConfig): Hono {
|
|
|
118
115
|
createTemplatesRoute(app, `${prefix}/templates`, config);
|
|
119
116
|
createContentTypesRoute(app, `${prefix}/types`, config);
|
|
120
117
|
createProcessesRoute(app, `${prefix}/processes`, config);
|
|
121
|
-
createDashboardsRoute(app, `${prefix}/dashboards`, config);
|
|
122
118
|
createMcpRoute(app, `${prefix}/mcp`, config);
|
|
123
119
|
|
|
124
120
|
// Global error handler - returns ToolExecutionResponseError format
|
package/src/types.ts
CHANGED
|
@@ -99,6 +99,16 @@ export type ToolFn<ParamsT extends object = object> = (
|
|
|
99
99
|
context: ToolExecutionContext,
|
|
100
100
|
) => Promise<ToolExecutionResult>;
|
|
101
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Approval behavior class for a tool.
|
|
104
|
+
*
|
|
105
|
+
* - `read_only`: reads or inspects state without changing Vertesia, external systems, or user-visible artifacts.
|
|
106
|
+
* - `side_effecting`: can create, update, delete, send, execute, schedule, or otherwise change state.
|
|
107
|
+
* - `control`: affects agent control flow or tool availability, not user data or external systems.
|
|
108
|
+
* - `requires_confirmation`: high-impact action that must ask the user even in interactive full-control mode.
|
|
109
|
+
*/
|
|
110
|
+
export type ToolApprovalClassification = 'read_only' | 'side_effecting' | 'control' | 'requires_confirmation';
|
|
111
|
+
|
|
102
112
|
export interface ToolUseContext {
|
|
103
113
|
project_id?: string;
|
|
104
114
|
account_id?: string;
|
|
@@ -124,12 +134,11 @@ export interface Tool<ParamsT extends object = object> extends ToolDefinition {
|
|
|
124
134
|
annotations?: MCPToolAnnotations;
|
|
125
135
|
|
|
126
136
|
/**
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
* hard contract.
|
|
137
|
+
* Internal approval classification used by interactive agent approval modes.
|
|
138
|
+
* Use `requires_confirmation` for actions that must prompt even in full-control mode.
|
|
139
|
+
* Remote/MCP tools can omit this and rely on annotations.
|
|
131
140
|
*/
|
|
132
|
-
|
|
141
|
+
approval_class?: ToolApprovalClassification;
|
|
133
142
|
|
|
134
143
|
/**
|
|
135
144
|
* Optional filter to check if the tool is enabled for the given project configuration.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dashboards.d.ts","sourceRoot":"","sources":["../../src/server/dashboards.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAEjC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,QAqB1F"}
|
package/lib/server/dashboards.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { HTTPException } from 'hono/http-exception';
|
|
2
|
-
export function createDashboardsRoute(app, basePath, config) {
|
|
3
|
-
const { dashboards = [] } = config;
|
|
4
|
-
app.get(basePath, (c) => {
|
|
5
|
-
return c.json({
|
|
6
|
-
title: 'All Dashboards',
|
|
7
|
-
description: 'All available dashboard definitions',
|
|
8
|
-
dashboards,
|
|
9
|
-
});
|
|
10
|
-
});
|
|
11
|
-
app.get(`${basePath}/:id`, (c) => {
|
|
12
|
-
const id = c.req.param('id');
|
|
13
|
-
const dashboard = findDashboard(dashboards, id);
|
|
14
|
-
if (!dashboard) {
|
|
15
|
-
throw new HTTPException(404, {
|
|
16
|
-
message: `No dashboard found with id: ${id}`,
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
return c.json(dashboard);
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
function findDashboard(dashboards, id) {
|
|
23
|
-
return dashboards.find((dashboard) => dashboard.id === id || dashboard.name === id || dashboard.title === id);
|
|
24
|
-
}
|
|
25
|
-
//# sourceMappingURL=dashboards.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dashboards.js","sourceRoot":"","sources":["../../src/server/dashboards.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGpD,MAAM,UAAU,qBAAqB,CAAC,GAAS,EAAE,QAAgB,EAAE,MAAwB;IACvF,MAAM,EAAE,UAAU,GAAG,EAAE,EAAE,GAAG,MAAM,CAAC;IAEnC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE;QACpB,OAAO,CAAC,CAAC,IAAI,CAAC;YACV,KAAK,EAAE,gBAAgB;YACvB,WAAW,EAAE,qCAAqC;YAClD,UAAU;SACb,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,GAAG,QAAQ,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE;QAC7B,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,SAAS,GAAG,aAAa,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;QAChD,IAAI,CAAC,SAAS,EAAE,CAAC;YACb,MAAM,IAAI,aAAa,CAAC,GAAG,EAAE;gBACzB,OAAO,EAAE,+BAA+B,EAAE,EAAE;aAC/C,CAAC,CAAC;QACP,CAAC;QACD,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACP,CAAC;AAED,SAAS,aAAa,CAAC,UAAoC,EAAE,EAAU;IACnE,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,SAAS,CAAC,IAAI,KAAK,EAAE,IAAI,SAAS,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;AAClH,CAAC"}
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import { PromptRole } from '@llumiverse/common';
|
|
2
|
-
import { PROCESS_DEFINITION_FORMAT_VERSION, TemplateType } from '@vertesia/common';
|
|
3
|
-
import { describe, expect, it } from 'vitest';
|
|
4
|
-
import { ContentTypesCollection } from '../ContentTypesCollection.js';
|
|
5
|
-
import { InteractionCollection } from '../InteractionCollection.js';
|
|
6
|
-
import { buildAppPackage } from './app-package.js';
|
|
7
|
-
import type { ToolServerConfig } from './types.js';
|
|
8
|
-
|
|
9
|
-
describe('buildAppPackage', () => {
|
|
10
|
-
it('builds the same package artifact inventory used by the package route', async () => {
|
|
11
|
-
const config = {
|
|
12
|
-
interactions: [
|
|
13
|
-
new InteractionCollection({
|
|
14
|
-
name: 'claims',
|
|
15
|
-
interactions: [
|
|
16
|
-
{
|
|
17
|
-
name: 'review',
|
|
18
|
-
title: 'Review Claim',
|
|
19
|
-
prompts: [
|
|
20
|
-
{
|
|
21
|
-
role: PromptRole.user,
|
|
22
|
-
content: '{{user_prompt}}',
|
|
23
|
-
content_type: TemplateType.handlebars,
|
|
24
|
-
},
|
|
25
|
-
],
|
|
26
|
-
},
|
|
27
|
-
],
|
|
28
|
-
}),
|
|
29
|
-
],
|
|
30
|
-
types: [
|
|
31
|
-
new ContentTypesCollection({
|
|
32
|
-
name: 'claims',
|
|
33
|
-
types: [
|
|
34
|
-
{
|
|
35
|
-
name: 'claim',
|
|
36
|
-
object_schema: {
|
|
37
|
-
type: 'object',
|
|
38
|
-
properties: {
|
|
39
|
-
status: { type: 'string' },
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
},
|
|
43
|
-
],
|
|
44
|
-
}),
|
|
45
|
-
],
|
|
46
|
-
processes: [
|
|
47
|
-
{
|
|
48
|
-
id: 'claims:intake',
|
|
49
|
-
name: 'Claims Intake',
|
|
50
|
-
definition: {
|
|
51
|
-
format_version: PROCESS_DEFINITION_FORMAT_VERSION,
|
|
52
|
-
process: 'claims_intake',
|
|
53
|
-
initial: 'done',
|
|
54
|
-
context: {
|
|
55
|
-
schema: {
|
|
56
|
-
type: 'object',
|
|
57
|
-
additionalProperties: true,
|
|
58
|
-
},
|
|
59
|
-
initial: {},
|
|
60
|
-
},
|
|
61
|
-
nodes: {
|
|
62
|
-
done: { type: 'final', title: 'Done' },
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
},
|
|
66
|
-
],
|
|
67
|
-
dashboards: [
|
|
68
|
-
{
|
|
69
|
-
id: 'claims:ops',
|
|
70
|
-
title: 'Claims Ops',
|
|
71
|
-
spec: {},
|
|
72
|
-
},
|
|
73
|
-
],
|
|
74
|
-
uiConfig: {
|
|
75
|
-
src: '/lib/plugin.js',
|
|
76
|
-
available_in: ['app_portal'],
|
|
77
|
-
},
|
|
78
|
-
} satisfies ToolServerConfig;
|
|
79
|
-
|
|
80
|
-
const pkg = await buildAppPackage(config, {
|
|
81
|
-
origin: 'https://apps.example.test',
|
|
82
|
-
scope: 'all',
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
expect(pkg.interactions?.map((interaction) => interaction.id)).toEqual(['claims:review']);
|
|
86
|
-
expect(pkg.types?.map((type) => type.id)).toEqual(['claim']);
|
|
87
|
-
expect(pkg.processes?.map((process) => process.id)).toEqual(['claims:intake']);
|
|
88
|
-
expect(pkg.dashboards?.map((dashboard) => dashboard.id)).toEqual(['claims:ops']);
|
|
89
|
-
expect(pkg.ui?.src).toBe('https://apps.example.test/lib/plugin.js');
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it('honors package scopes', async () => {
|
|
93
|
-
const config = {
|
|
94
|
-
interactions: [
|
|
95
|
-
new InteractionCollection({
|
|
96
|
-
name: 'claims',
|
|
97
|
-
interactions: [{ name: 'review', prompts: [] }],
|
|
98
|
-
}),
|
|
99
|
-
],
|
|
100
|
-
types: [
|
|
101
|
-
new ContentTypesCollection({
|
|
102
|
-
name: 'claims',
|
|
103
|
-
types: [{ name: 'claim' }],
|
|
104
|
-
}),
|
|
105
|
-
],
|
|
106
|
-
} satisfies ToolServerConfig;
|
|
107
|
-
|
|
108
|
-
const pkg = await buildAppPackage(config, { scope: 'types' });
|
|
109
|
-
|
|
110
|
-
expect(pkg.types?.map((type) => type.id)).toEqual(['claim']);
|
|
111
|
-
expect(pkg.interactions).toBeUndefined();
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
describe('buildAppPackage type identity', () => {
|
|
116
|
-
it('exposes the bare type name as the public id (collections are code organization only)', async () => {
|
|
117
|
-
const config = {
|
|
118
|
-
types: [
|
|
119
|
-
new ContentTypesCollection({ name: 'claims', types: [{ name: 'claim' }] }),
|
|
120
|
-
new ContentTypesCollection({ name: 'audit', types: [{ name: 'audit_event' }] }),
|
|
121
|
-
],
|
|
122
|
-
} satisfies ToolServerConfig;
|
|
123
|
-
|
|
124
|
-
const pkg = await buildAppPackage(config, { scope: 'types' });
|
|
125
|
-
expect(pkg.types?.map((type) => type.id)).toEqual(['claim', 'audit_event']);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
it('fails the package build when a type name is duplicated across collections', async () => {
|
|
129
|
-
const config = {
|
|
130
|
-
types: [
|
|
131
|
-
new ContentTypesCollection({ name: 'claims', types: [{ name: 'claim' }] }),
|
|
132
|
-
new ContentTypesCollection({ name: 'legacy', types: [{ name: 'claim' }] }),
|
|
133
|
-
],
|
|
134
|
-
} satisfies ToolServerConfig;
|
|
135
|
-
|
|
136
|
-
await expect(buildAppPackage(config, { scope: 'types' })).rejects.toThrow(
|
|
137
|
-
/Duplicate content type name 'claim'/,
|
|
138
|
-
);
|
|
139
|
-
});
|
|
140
|
-
});
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { Hono } from 'hono';
|
|
2
|
-
import { describe, expect, it } from 'vitest';
|
|
3
|
-
import { ContentTypesCollection } from '../ContentTypesCollection.js';
|
|
4
|
-
import { createContentTypesRoute } from './content-types.js';
|
|
5
|
-
import type { ToolServerConfig } from './types.js';
|
|
6
|
-
|
|
7
|
-
function makeApp(config: ToolServerConfig): Hono {
|
|
8
|
-
const app = new Hono();
|
|
9
|
-
createContentTypesRoute(app, '/api/types', config);
|
|
10
|
-
return app;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const config = {
|
|
14
|
-
types: [
|
|
15
|
-
new ContentTypesCollection({
|
|
16
|
-
name: 'contracts',
|
|
17
|
-
types: [{ name: 'contract' }, { name: 'review_note' }],
|
|
18
|
-
}),
|
|
19
|
-
new ContentTypesCollection({
|
|
20
|
-
name: 'audit',
|
|
21
|
-
types: [{ name: 'audit_event' }],
|
|
22
|
-
}),
|
|
23
|
-
],
|
|
24
|
-
} satisfies ToolServerConfig;
|
|
25
|
-
|
|
26
|
-
describe('content types route', () => {
|
|
27
|
-
it('lists all types with bare ids (collection is not part of the type identity)', async () => {
|
|
28
|
-
const res = await makeApp(config).request('/api/types');
|
|
29
|
-
expect(res.status).toBe(200);
|
|
30
|
-
const body = (await res.json()) as { types: Array<{ id: string }> };
|
|
31
|
-
expect(body.types.map((t) => t.id)).toEqual(['contract', 'review_note', 'audit_event']);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('resolves the canonical bare type name (the app:<app>:<type> ref convention)', async () => {
|
|
35
|
-
const res = await makeApp(config).request('/api/types/contract');
|
|
36
|
-
expect(res.status).toBe(200);
|
|
37
|
-
const body = (await res.json()) as { id: string; name: string };
|
|
38
|
-
expect(body.id).toBe('contract');
|
|
39
|
-
expect(body.name).toBe('contract');
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('still resolves the legacy collection:type alias, returning the bare id', async () => {
|
|
43
|
-
const res = await makeApp(config).request('/api/types/contracts:contract');
|
|
44
|
-
expect(res.status).toBe(200);
|
|
45
|
-
const body = (await res.json()) as { id: string };
|
|
46
|
-
expect(body.id).toBe('contract');
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('409s on an ambiguous bare name so the collision is loud, not silent', async () => {
|
|
50
|
-
const ambiguous = {
|
|
51
|
-
types: [
|
|
52
|
-
new ContentTypesCollection({ name: 'a', types: [{ name: 'note' }] }),
|
|
53
|
-
new ContentTypesCollection({ name: 'b', types: [{ name: 'note' }] }),
|
|
54
|
-
],
|
|
55
|
-
} satisfies ToolServerConfig;
|
|
56
|
-
const res = await makeApp(ambiguous).request('/api/types/note');
|
|
57
|
-
expect(res.status).toBe(409);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('404s for an unknown type name', async () => {
|
|
61
|
-
const res = await makeApp(config).request('/api/types/nope');
|
|
62
|
-
expect(res.status).toBe(404);
|
|
63
|
-
});
|
|
64
|
-
});
|
package/src/server/dashboards.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import type { AppDashboardDefinition } from '@vertesia/common';
|
|
2
|
-
import type { Hono } from 'hono';
|
|
3
|
-
import { HTTPException } from 'hono/http-exception';
|
|
4
|
-
import type { ToolServerConfig } from './types.js';
|
|
5
|
-
|
|
6
|
-
export function createDashboardsRoute(app: Hono, basePath: string, config: ToolServerConfig) {
|
|
7
|
-
const { dashboards = [] } = config;
|
|
8
|
-
|
|
9
|
-
app.get(basePath, (c) => {
|
|
10
|
-
return c.json({
|
|
11
|
-
title: 'All Dashboards',
|
|
12
|
-
description: 'All available dashboard definitions',
|
|
13
|
-
dashboards,
|
|
14
|
-
});
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
app.get(`${basePath}/:id`, (c) => {
|
|
18
|
-
const id = c.req.param('id');
|
|
19
|
-
const dashboard = findDashboard(dashboards, id);
|
|
20
|
-
if (!dashboard) {
|
|
21
|
-
throw new HTTPException(404, {
|
|
22
|
-
message: `No dashboard found with id: ${id}`,
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
return c.json(dashboard);
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function findDashboard(dashboards: AppDashboardDefinition[], id: string): AppDashboardDefinition | undefined {
|
|
30
|
-
return dashboards.find((dashboard) => dashboard.id === id || dashboard.name === id || dashboard.title === id);
|
|
31
|
-
}
|