@vertesia/tools-sdk 0.81.1 → 1.0.0-dev.20260203.130115Z
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +9 -8
- package/src/ContentTypesCollection.ts +51 -0
- package/src/InteractionCollection.ts +1 -94
- package/src/SkillCollection.ts +88 -15
- package/src/ToolCollection.ts +65 -17
- package/src/ToolRegistry.ts +101 -9
- package/src/auth.ts +37 -6
- package/src/index.ts +7 -3
- package/src/server/app-package.ts +102 -0
- package/src/server/conyent-types.ts +71 -0
- package/src/server/interactions.ts +100 -0
- package/src/server/mcp.ts +51 -0
- package/src/server/site.ts +53 -0
- package/src/server/skills.ts +133 -0
- package/src/server/tools.ts +128 -0
- package/src/server/types.ts +87 -0
- package/src/server/widgets.ts +38 -0
- package/src/server.ts +80 -359
- package/src/site/styles.ts +71 -0
- package/src/site/templates.ts +215 -119
- package/src/types.ts +22 -18
- package/src/utils.ts +20 -0
- package/lib/cjs/InteractionCollection.js +0 -164
- package/lib/cjs/InteractionCollection.js.map +0 -1
- package/lib/cjs/SkillCollection.js +0 -318
- package/lib/cjs/SkillCollection.js.map +0 -1
- package/lib/cjs/ToolCollection.js +0 -192
- package/lib/cjs/ToolCollection.js.map +0 -1
- package/lib/cjs/ToolRegistry.js +0 -44
- package/lib/cjs/ToolRegistry.js.map +0 -1
- package/lib/cjs/auth.js +0 -89
- package/lib/cjs/auth.js.map +0 -1
- package/lib/cjs/build/validate.js +0 -7
- package/lib/cjs/build/validate.js.map +0 -1
- package/lib/cjs/copy-assets.js +0 -84
- package/lib/cjs/copy-assets.js.map +0 -1
- package/lib/cjs/index.js +0 -30
- package/lib/cjs/index.js.map +0 -1
- package/lib/cjs/package.json +0 -3
- package/lib/cjs/server.js +0 -327
- package/lib/cjs/server.js.map +0 -1
- package/lib/cjs/site/styles.js +0 -621
- package/lib/cjs/site/styles.js.map +0 -1
- package/lib/cjs/site/templates.js +0 -932
- package/lib/cjs/site/templates.js.map +0 -1
- package/lib/cjs/types.js +0 -3
- package/lib/cjs/types.js.map +0 -1
- package/lib/cjs/utils.js +0 -7
- package/lib/cjs/utils.js.map +0 -1
- package/lib/esm/InteractionCollection.js +0 -125
- package/lib/esm/InteractionCollection.js.map +0 -1
- package/lib/esm/SkillCollection.js +0 -311
- package/lib/esm/SkillCollection.js.map +0 -1
- package/lib/esm/ToolCollection.js +0 -154
- package/lib/esm/ToolCollection.js.map +0 -1
- package/lib/esm/ToolRegistry.js +0 -39
- package/lib/esm/ToolRegistry.js.map +0 -1
- package/lib/esm/auth.js +0 -82
- package/lib/esm/auth.js.map +0 -1
- package/lib/esm/build/validate.js +0 -4
- package/lib/esm/build/validate.js.map +0 -1
- package/lib/esm/copy-assets.js +0 -81
- package/lib/esm/copy-assets.js.map +0 -1
- package/lib/esm/index.js +0 -10
- package/lib/esm/index.js.map +0 -1
- package/lib/esm/server.js +0 -323
- package/lib/esm/server.js.map +0 -1
- package/lib/esm/site/styles.js +0 -618
- package/lib/esm/site/styles.js.map +0 -1
- package/lib/esm/site/templates.js +0 -920
- package/lib/esm/site/templates.js.map +0 -1
- package/lib/esm/types.js +0 -2
- package/lib/esm/types.js.map +0 -1
- package/lib/esm/utils.js +0 -4
- package/lib/esm/utils.js.map +0 -1
- package/lib/types/InteractionCollection.d.ts +0 -48
- package/lib/types/InteractionCollection.d.ts.map +0 -1
- package/lib/types/SkillCollection.d.ts +0 -111
- package/lib/types/SkillCollection.d.ts.map +0 -1
- package/lib/types/ToolCollection.d.ts +0 -61
- package/lib/types/ToolCollection.d.ts.map +0 -1
- package/lib/types/ToolRegistry.d.ts +0 -15
- package/lib/types/ToolRegistry.d.ts.map +0 -1
- package/lib/types/auth.d.ts +0 -20
- package/lib/types/auth.d.ts.map +0 -1
- package/lib/types/build/validate.d.ts +0 -2
- package/lib/types/build/validate.d.ts.map +0 -1
- package/lib/types/copy-assets.d.ts +0 -14
- package/lib/types/copy-assets.d.ts.map +0 -1
- package/lib/types/index.d.ts +0 -10
- package/lib/types/index.d.ts.map +0 -1
- package/lib/types/server.d.ts +0 -72
- package/lib/types/server.d.ts.map +0 -1
- package/lib/types/site/styles.d.ts +0 -5
- package/lib/types/site/styles.d.ts.map +0 -1
- package/lib/types/site/templates.d.ts +0 -54
- package/lib/types/site/templates.d.ts.map +0 -1
- package/lib/types/types.d.ts +0 -262
- package/lib/types/types.d.ts.map +0 -1
- package/lib/types/utils.d.ts +0 -2
- package/lib/types/utils.d.ts.map +0 -1
package/src/site/templates.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import type { InteractionCollection } from "../InteractionCollection.js";
|
|
2
|
+
import { ToolServerConfig } from "../server/types.js";
|
|
2
3
|
import type { SkillCollection } from "../SkillCollection.js";
|
|
3
4
|
import type { ToolCollection } from "../ToolCollection.js";
|
|
5
|
+
import type { ContentTypesCollection } from "../ContentTypesCollection.js";
|
|
4
6
|
import type { ICollection, SkillDefinition, Tool } from "../types.js";
|
|
7
|
+
import { join } from "../utils.js";
|
|
5
8
|
import { baseStyles } from "./styles.js";
|
|
6
9
|
|
|
7
10
|
type MCPProviderMeta = {
|
|
8
|
-
|
|
9
|
-
|
|
11
|
+
name: string;
|
|
12
|
+
description?: string;
|
|
10
13
|
};
|
|
11
14
|
|
|
12
15
|
/**
|
|
@@ -228,43 +231,6 @@ ${baseStyles}
|
|
|
228
231
|
white-space: pre-wrap;
|
|
229
232
|
}
|
|
230
233
|
|
|
231
|
-
.endpoint-box {
|
|
232
|
-
display: flex;
|
|
233
|
-
align-items: center;
|
|
234
|
-
gap: 0.75rem;
|
|
235
|
-
background: #f3f4f6;
|
|
236
|
-
padding: 0.75rem 1rem;
|
|
237
|
-
border-radius: 8px;
|
|
238
|
-
margin-top: 0.5rem;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
.endpoint-box code {
|
|
242
|
-
flex: 1;
|
|
243
|
-
font-family: ui-monospace, monospace;
|
|
244
|
-
font-size: 0.875rem;
|
|
245
|
-
color: #1f2937;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
.copy-btn {
|
|
249
|
-
background: #e5e7eb;
|
|
250
|
-
border: none;
|
|
251
|
-
padding: 0.5rem;
|
|
252
|
-
border-radius: 6px;
|
|
253
|
-
cursor: pointer;
|
|
254
|
-
color: #6b7280;
|
|
255
|
-
transition: all 0.15s;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
.copy-btn:hover {
|
|
259
|
-
background: #d1d5db;
|
|
260
|
-
color: #374151;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
.copy-btn svg {
|
|
264
|
-
width: 16px;
|
|
265
|
-
height: 16px;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
234
|
.empty-state {
|
|
269
235
|
text-align: center;
|
|
270
236
|
padding: 3rem;
|
|
@@ -345,24 +311,6 @@ ${baseStyles}
|
|
|
345
311
|
color: #e5e7eb;
|
|
346
312
|
}
|
|
347
313
|
|
|
348
|
-
.endpoint-box {
|
|
349
|
-
background: rgba(31, 41, 55, 0.95);
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
.endpoint-box code {
|
|
353
|
-
color: #e5e7eb;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
.copy-btn {
|
|
357
|
-
background: rgba(55, 65, 81, 0.95);
|
|
358
|
-
color: #e5e7eb;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
.copy-btn:hover {
|
|
362
|
-
background: rgba(75, 85, 99, 0.98);
|
|
363
|
-
color: #f9fafb;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
314
|
.empty-state {
|
|
367
315
|
color: #9ca3af;
|
|
368
316
|
}
|
|
@@ -439,7 +387,7 @@ export function toolCard(tool: Tool<Record<string, unknown>>): string {
|
|
|
439
387
|
* Render an MCP provider card
|
|
440
388
|
*/
|
|
441
389
|
export function mcpProviderCard(provider: MCPProviderMeta): string {
|
|
442
|
-
|
|
390
|
+
return /*html*/`
|
|
443
391
|
<a class="card" href="/api/mcp/${provider.name}">
|
|
444
392
|
<div class="card-title">${provider.name}</div>
|
|
445
393
|
<div class="card-desc">${provider.description || ''}</div>
|
|
@@ -482,9 +430,9 @@ export function toolDetailCard(tool: Tool<Record<string, unknown>>, collectionNa
|
|
|
482
430
|
${properties ? /*html*/`
|
|
483
431
|
<div class="info-grid" style="margin-bottom: 1rem;">
|
|
484
432
|
${Object.entries(properties).map(([key, value]) => {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
433
|
+
const prop = value as Record<string, unknown>;
|
|
434
|
+
const isRequired = required?.includes(key);
|
|
435
|
+
return /*html*/`
|
|
488
436
|
<div class="info-item">
|
|
489
437
|
<div class="info-label">${key}${isRequired ? ' *' : ''}</div>
|
|
490
438
|
<div class="info-value">
|
|
@@ -492,7 +440,7 @@ export function toolDetailCard(tool: Tool<Record<string, unknown>>, collectionNa
|
|
|
492
440
|
${prop.description ? `<br><span style="color: #6b7280; font-size: 0.85rem;">${prop.description}</span>` : ''}
|
|
493
441
|
</div>
|
|
494
442
|
</div>`;
|
|
495
|
-
|
|
443
|
+
}).join('')}
|
|
496
444
|
</div>
|
|
497
445
|
` : ''}
|
|
498
446
|
<details>
|
|
@@ -525,13 +473,34 @@ export function skillCard(skill: SkillDefinition): string {
|
|
|
525
473
|
</div>`;
|
|
526
474
|
}
|
|
527
475
|
|
|
476
|
+
function skillWidgetsTemplate(skillWidgets: string[] | undefined) {
|
|
477
|
+
if (!skillWidgets || skillWidgets.length === 0) {
|
|
478
|
+
return 'n/a';
|
|
479
|
+
}
|
|
480
|
+
return skillWidgets.map(w => `<div style='display: flex; align-items: center; gap: 0.5rem; width:100%;justify-content: space-between;'><span>${w}</span>
|
|
481
|
+
<button class="copy-btn" onclick="navigator.clipboard.writeText(window.location.origin + '/widgets/${w}.js')" title="Copy endpoint URL">
|
|
482
|
+
${copyIcon}
|
|
483
|
+
</button>
|
|
484
|
+
</div>`).join('');
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function renderSkillUrl(skill: SkillDefinition, collectionName: string): string {
|
|
488
|
+
const skillPath = `/api/skills/${collectionName}/${skill.name}`;
|
|
489
|
+
return /*html*/`<div class="script-item" style='display: flex; align-items: center; gap: 0.5rem; width:100%;justify-content: space-between;'><span class="script-name">${skillPath}</span>
|
|
490
|
+
<button class="copy-btn" onclick="navigator.clipboard.writeText(window.location.origin + '${skillPath}')" title="Copy endpoint URL">
|
|
491
|
+
${copyIcon}
|
|
492
|
+
</button>
|
|
493
|
+
</div>`;
|
|
494
|
+
}
|
|
495
|
+
|
|
528
496
|
/**
|
|
529
497
|
* Render a detailed skill card
|
|
530
498
|
*/
|
|
531
|
-
export function skillDetailCard(skill: SkillDefinition): string {
|
|
499
|
+
export function skillDetailCard(skill: SkillDefinition, collection: SkillCollection): string {
|
|
532
500
|
const hasKeywords = skill.context_triggers?.keywords?.length;
|
|
533
501
|
const hasPackages = skill.execution?.packages?.length;
|
|
534
502
|
const hasScripts = skill.scripts?.length;
|
|
503
|
+
const hasRelatedTools = skill.related_tools?.length;
|
|
535
504
|
|
|
536
505
|
return /*html*/`
|
|
537
506
|
<div class="detail-card">
|
|
@@ -539,10 +508,12 @@ export function skillDetailCard(skill: SkillDefinition): string {
|
|
|
539
508
|
<div>
|
|
540
509
|
<h3 class="detail-title">${skill.name}</h3>
|
|
541
510
|
<p class="detail-desc">${skill.description || 'No description'}</p>
|
|
511
|
+
${renderSkillUrl(skill, collection.name)}
|
|
542
512
|
</div>
|
|
543
513
|
<div class="detail-badges">
|
|
544
514
|
<span class="badge skill-type-badge">Skill</span>
|
|
545
515
|
${skill.execution?.language ? `<span class="badge ${skill.execution.language}">${skill.execution.language}</span>` : ''}
|
|
516
|
+
${hasRelatedTools ? `<span class="badge" style="background: #8b5cf6; color: white;">Unlocks ${skill.related_tools?.length} tool${skill.related_tools?.length !== 1 ? 's' : ''}</span>` : ''}
|
|
546
517
|
</div>
|
|
547
518
|
</div>
|
|
548
519
|
<div class="detail-body">
|
|
@@ -557,7 +528,21 @@ export function skillDetailCard(skill: SkillDefinition): string {
|
|
|
557
528
|
<div class="info-value"><code>${skill.execution.language}</code></div>
|
|
558
529
|
</div>
|
|
559
530
|
` : ''}
|
|
531
|
+
<div class="info-item">
|
|
532
|
+
<div class="info-label">Widgets</div>
|
|
533
|
+
<div class="info-value">${skillWidgetsTemplate(skill.widgets)}</div>
|
|
534
|
+
</div>
|
|
535
|
+
</div>
|
|
536
|
+
|
|
537
|
+
${hasRelatedTools ? /*html*/`
|
|
538
|
+
<div class="detail-section">
|
|
539
|
+
<h4 class="detail-section-title">Unlocks Tools</h4>
|
|
540
|
+
<p style="color: #6b7280; font-size: 0.85rem; margin: 0 0 0.75rem 0;">These tools become available when this skill is activated:</p>
|
|
541
|
+
<div class="package-list">
|
|
542
|
+
${skill.related_tools?.map(tool => `<span class="package-tag" style="background: #ede9fe; color: #6d28d9;">${tool}</span>`).join('')}
|
|
543
|
+
</div>
|
|
560
544
|
</div>
|
|
545
|
+
` : ''}
|
|
561
546
|
|
|
562
547
|
${hasKeywords ? /*html*/`
|
|
563
548
|
<div class="detail-section">
|
|
@@ -584,7 +569,7 @@ export function skillDetailCard(skill: SkillDefinition): string {
|
|
|
584
569
|
${skill.scripts?.map(script => /*html*/`
|
|
585
570
|
<div class="script-item">
|
|
586
571
|
${fileIcon}
|
|
587
|
-
<span class="script-name">${script
|
|
572
|
+
<span class="script-name">${join("/scripts", script)}</span>
|
|
588
573
|
</div>
|
|
589
574
|
`).join('')}
|
|
590
575
|
</div>
|
|
@@ -624,6 +609,47 @@ function getInitials(title: string): string {
|
|
|
624
609
|
return initials || "TS";
|
|
625
610
|
}
|
|
626
611
|
|
|
612
|
+
function renderUILinks() {
|
|
613
|
+
const copyIconSvg = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>`;
|
|
614
|
+
|
|
615
|
+
return /*html*/`
|
|
616
|
+
<div style="margin-top: 1rem; padding-top: 1rem; border-top: 1px solid rgba(156, 163, 175, 0.2); display: flex; gap: 1rem; flex-wrap: wrap; align-items: center;">
|
|
617
|
+
<a target="_blank" href="/ui/" class="plugin-link-primary" style="display: inline-flex; align-items: center; gap: 0.5rem; padding: 0.5rem 1rem; background: #3b82f6; color: white; text-decoration: none; border-radius: 6px; font-size: 0.875rem; font-weight: 500; transition: background 0.15s;">
|
|
618
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
619
|
+
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
|
|
620
|
+
<line x1="9" y1="3" x2="9" y2="21"></line>
|
|
621
|
+
</svg>
|
|
622
|
+
UI Plugin Dev
|
|
623
|
+
</a>
|
|
624
|
+
<div style="display: inline-flex; align-items: center; gap: 0.5rem;">
|
|
625
|
+
<a href="/lib/plugin.js" class="plugin-link-secondary" style="display: inline-flex; align-items: center; gap: 0.5rem; padding: 0.5rem 1rem; background: #10b981; color: white; text-decoration: none; border-radius: 6px; font-size: 0.875rem; font-weight: 500; transition: background 0.15s;">
|
|
626
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
627
|
+
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
|
628
|
+
<polyline points="7 10 12 15 17 10"></polyline>
|
|
629
|
+
<line x1="12" y1="15" x2="12" y2="3"></line>
|
|
630
|
+
</svg>
|
|
631
|
+
Plugin Bundle
|
|
632
|
+
</a>
|
|
633
|
+
<button id="copy-plugin-btn" class="copy-btn" onclick="copyPluginUrl(this)" title="Copy plugin URL" style="background: #e5e7eb; border: none; padding: 0.5rem; border-radius: 6px; cursor: pointer; color: #6b7280; transition: all 0.15s; display: inline-flex; align-items: center; justify-content: center; width: 36px; height: 36px;">
|
|
634
|
+
${copyIconSvg}
|
|
635
|
+
</button>
|
|
636
|
+
</div>
|
|
637
|
+
</div>
|
|
638
|
+
<script>
|
|
639
|
+
function copyPluginUrl(btn) {
|
|
640
|
+
navigator.clipboard.writeText(window.location.origin + '/lib/plugin.js');
|
|
641
|
+
const originalHtml = btn.innerHTML;
|
|
642
|
+
btn.innerHTML = '✓';
|
|
643
|
+
btn.style.color = '#10b981';
|
|
644
|
+
setTimeout(function() {
|
|
645
|
+
btn.innerHTML = originalHtml;
|
|
646
|
+
btn.style.color = '#6b7280';
|
|
647
|
+
}, 1500);
|
|
648
|
+
}
|
|
649
|
+
</script>
|
|
650
|
+
`;
|
|
651
|
+
}
|
|
652
|
+
|
|
627
653
|
/**
|
|
628
654
|
* Render the main index page
|
|
629
655
|
*
|
|
@@ -632,25 +658,18 @@ function getInitials(title: string): string {
|
|
|
632
658
|
* - If an array is passed, it is treated as MCP providers and the fifth argument (if any) is the title.
|
|
633
659
|
*/
|
|
634
660
|
export function indexPage(
|
|
635
|
-
|
|
636
|
-
skills: SkillCollection[],
|
|
637
|
-
interactions: InteractionCollection[],
|
|
638
|
-
mcpProvidersOrTitle?: MCPProviderMeta[] | string,
|
|
639
|
-
titleParam?: string
|
|
661
|
+
config: ToolServerConfig
|
|
640
662
|
): string {
|
|
641
|
-
|
|
642
|
-
|
|
663
|
+
const {
|
|
664
|
+
title = 'Tools Server',
|
|
665
|
+
tools = [],
|
|
666
|
+
interactions = [],
|
|
667
|
+
skills = [],
|
|
668
|
+
types = [],
|
|
669
|
+
mcpProviders = [],
|
|
670
|
+
hideUILinks = false,
|
|
671
|
+
} = config;
|
|
643
672
|
|
|
644
|
-
if (Array.isArray(mcpProvidersOrTitle)) {
|
|
645
|
-
mcpProviders = mcpProvidersOrTitle;
|
|
646
|
-
if (typeof titleParam === "string" && titleParam.length > 0) {
|
|
647
|
-
title = titleParam;
|
|
648
|
-
}
|
|
649
|
-
} else if (typeof mcpProvidersOrTitle === "string" && mcpProvidersOrTitle.length > 0) {
|
|
650
|
-
title = mcpProvidersOrTitle;
|
|
651
|
-
} else if (typeof titleParam === "string" && titleParam.length > 0) {
|
|
652
|
-
title = titleParam;
|
|
653
|
-
}
|
|
654
673
|
|
|
655
674
|
return /*html*/`
|
|
656
675
|
<!DOCTYPE html>
|
|
@@ -672,19 +691,28 @@ export function indexPage(
|
|
|
672
691
|
<p class="hero-eyebrow">Tools Server</p>
|
|
673
692
|
<h1 class="hero-title">${title}</h1>
|
|
674
693
|
<p class="hero-tagline">
|
|
675
|
-
Discover the tools, skills, and
|
|
694
|
+
Discover the tools, skills, interactions, and content types exposed by this server.
|
|
676
695
|
</p>
|
|
677
696
|
<div class="hero-summary">
|
|
678
697
|
${tools.length ? /*html*/`<span><dot></dot> ${tools.length} tool collection${tools.length !== 1 ? 's' : ''}</span>` : ''}
|
|
679
698
|
${skills.length ? /*html*/`<span><dot></dot> ${skills.length} skill collection${skills.length !== 1 ? 's' : ''}</span>` : ''}
|
|
680
699
|
${interactions.length ? /*html*/`<span><dot></dot> ${interactions.length} interaction collection${interactions.length !== 1 ? 's' : ''}</span>` : ''}
|
|
700
|
+
${types.length ? /*html*/`<span><dot></dot> ${types.length} content type collection${types.length !== 1 ? 's' : ''}</span>` : ''}
|
|
681
701
|
${mcpProviders.length ? /*html*/`<span><dot></dot> ${mcpProviders.length} MCP provider${mcpProviders.length !== 1 ? 's' : ''}</span>` : ''}
|
|
682
702
|
</div>
|
|
703
|
+
${hideUILinks ? '' : renderUILinks()}
|
|
683
704
|
</div>
|
|
684
705
|
</div>
|
|
685
706
|
<aside class="hero-panel">
|
|
686
707
|
<div class="hero-panel-label">Base endpoint</div>
|
|
687
708
|
<div class="hero-panel-endpoint"><code>/api</code></div>
|
|
709
|
+
<div class="hero-panel-label" style="margin-top: 1rem;">Package endpoint</div>
|
|
710
|
+
<div class="endpoint-box" style="margin-top: 0.5rem;">
|
|
711
|
+
<code id="package-endpoint-url">/api/package</code>
|
|
712
|
+
<button class="copy-btn" onclick="copyPackageUrl(this)" title="Copy package endpoint URL">
|
|
713
|
+
${copyIcon}
|
|
714
|
+
</button>
|
|
715
|
+
</div>
|
|
688
716
|
<p class="hero-panel-hint">
|
|
689
717
|
Use <strong>POST /api/tools/<collection></strong> or
|
|
690
718
|
<strong>POST /api/skills/<collection></strong> to call these from your apps or agents.
|
|
@@ -697,7 +725,7 @@ export function indexPage(
|
|
|
697
725
|
type="search"
|
|
698
726
|
id="collection-search"
|
|
699
727
|
class="search-input"
|
|
700
|
-
placeholder="Search tools, skills, interactions..."
|
|
728
|
+
placeholder="Search tools, skills, interactions, types..."
|
|
701
729
|
aria-label="Search collections"
|
|
702
730
|
autocomplete="off"
|
|
703
731
|
/>
|
|
@@ -730,9 +758,9 @@ export function indexPage(
|
|
|
730
758
|
</div>
|
|
731
759
|
<div class="card-grid">
|
|
732
760
|
${skills.map(s => {
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
761
|
+
const count = Array.from(s).length;
|
|
762
|
+
return collectionCard(s, 'skills', `${count} skill${count !== 1 ? 's' : ''}`);
|
|
763
|
+
}).join('')}
|
|
736
764
|
</div>
|
|
737
765
|
</section>
|
|
738
766
|
` : ''}
|
|
@@ -750,6 +778,22 @@ export function indexPage(
|
|
|
750
778
|
</section>
|
|
751
779
|
` : ''}
|
|
752
780
|
|
|
781
|
+
${types.length > 0 ? /*html*/`
|
|
782
|
+
<section data-section="types">
|
|
783
|
+
<hr>
|
|
784
|
+
<div class="section-header">
|
|
785
|
+
<h2>Content Type Collections</h2>
|
|
786
|
+
<p class="section-subtitle">Schema definitions for structured content in the data store.</p>
|
|
787
|
+
</div>
|
|
788
|
+
<div class="card-grid">
|
|
789
|
+
${types.map((t: ContentTypesCollection) => {
|
|
790
|
+
const count = t.getContentTypes().length;
|
|
791
|
+
return collectionCard(t, 'types', `${count} type${count !== 1 ? 's' : ''}`);
|
|
792
|
+
}).join('')}
|
|
793
|
+
</div>
|
|
794
|
+
</section>
|
|
795
|
+
` : ''}
|
|
796
|
+
|
|
753
797
|
${mcpProviders.length > 0 ? /*html*/`
|
|
754
798
|
<section data-section="mcp">
|
|
755
799
|
<hr>
|
|
@@ -811,6 +855,18 @@ export function indexPage(
|
|
|
811
855
|
update(input.value);
|
|
812
856
|
});
|
|
813
857
|
}());
|
|
858
|
+
|
|
859
|
+
function copyPackageUrl(btn) {
|
|
860
|
+
var url = window.location.origin + '/api/package';
|
|
861
|
+
navigator.clipboard.writeText(url);
|
|
862
|
+
var originalHtml = btn.innerHTML;
|
|
863
|
+
btn.innerHTML = '✓';
|
|
864
|
+
btn.style.color = '#10b981';
|
|
865
|
+
setTimeout(function() {
|
|
866
|
+
btn.innerHTML = originalHtml;
|
|
867
|
+
btn.style.color = '#6b7280';
|
|
868
|
+
}, 1500);
|
|
869
|
+
}
|
|
814
870
|
</script>
|
|
815
871
|
</body>
|
|
816
872
|
</html>`;
|
|
@@ -852,9 +908,9 @@ export function toolCollectionPage(collection: ToolCollection): string {
|
|
|
852
908
|
<h2>${toolsArray.length} Tool${toolsArray.length !== 1 ? 's' : ''}</h2>
|
|
853
909
|
|
|
854
910
|
${toolsArray.length > 0 ?
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
911
|
+
toolsArray.map(tool => toolDetailCard(tool, collection.name)).join('') :
|
|
912
|
+
'<div class="empty-state">No tools in this collection</div>'
|
|
913
|
+
}
|
|
858
914
|
</body>
|
|
859
915
|
</html>`;
|
|
860
916
|
}
|
|
@@ -895,27 +951,18 @@ export function skillCollectionPage(collection: SkillCollection): string {
|
|
|
895
951
|
<h2>${skillsArray.length} Skill${skillsArray.length !== 1 ? 's' : ''}</h2>
|
|
896
952
|
|
|
897
953
|
${skillsArray.length > 0 ?
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
954
|
+
skillsArray.map(skill => skillDetailCard(skill, collection)).join('') :
|
|
955
|
+
'<div class="empty-state">No skills in this collection</div>'
|
|
956
|
+
}
|
|
901
957
|
</body>
|
|
902
958
|
</html>`;
|
|
903
959
|
}
|
|
904
960
|
|
|
905
961
|
/**
|
|
906
|
-
* Render
|
|
962
|
+
* Render a collection header with icon, title, description, and endpoint
|
|
907
963
|
*/
|
|
908
|
-
|
|
964
|
+
function collectionDetailHeader(collection: ICollection, pathPrefix: string): string {
|
|
909
965
|
return /*html*/`
|
|
910
|
-
<!DOCTYPE html>
|
|
911
|
-
<html lang="en">
|
|
912
|
-
<head>
|
|
913
|
-
<meta charset="UTF-8">
|
|
914
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
915
|
-
<title>${collection.title || collection.name} - Interactions</title>
|
|
916
|
-
<style>${detailStyles}</style>
|
|
917
|
-
</head>
|
|
918
|
-
<body>
|
|
919
966
|
<nav class="nav">
|
|
920
967
|
<a href="/">${backArrow} Back to all collections</a>
|
|
921
968
|
</nav>
|
|
@@ -926,30 +973,79 @@ export function interactionCollectionPage(collection: InteractionCollection): st
|
|
|
926
973
|
<h1>${collection.title || collection.name}</h1>
|
|
927
974
|
<p style="color: #6b7280; margin: 0.25rem 0 0 0;">${collection.description || ''}</p>
|
|
928
975
|
<div class="endpoint-box">
|
|
929
|
-
<code>/api
|
|
930
|
-
<button class="copy-btn" onclick="navigator.clipboard.writeText(window.location.origin + '/api
|
|
976
|
+
<code>/api/${pathPrefix}/${collection.name}</code>
|
|
977
|
+
<button class="copy-btn" onclick="navigator.clipboard.writeText(window.location.origin + '/api/${pathPrefix}/${collection.name}')" title="Copy endpoint URL">
|
|
931
978
|
${copyIcon}
|
|
932
979
|
</button>
|
|
933
980
|
</div>
|
|
934
981
|
</div>
|
|
935
|
-
</div
|
|
982
|
+
</div>`;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
/**
|
|
986
|
+
* Render a simple item card with name, description, and tags
|
|
987
|
+
*/
|
|
988
|
+
function simpleItemCard(item: { name: string; description?: string; tags?: string[] }): string {
|
|
989
|
+
return /*html*/`
|
|
990
|
+
<div class="detail-card">
|
|
991
|
+
<div class="detail-header">
|
|
992
|
+
<div>
|
|
993
|
+
<h3 class="detail-title">${item.name}</h3>
|
|
994
|
+
<p class="detail-desc">${item.description || 'No description'}</p>
|
|
995
|
+
</div>
|
|
996
|
+
<div class="detail-badges">
|
|
997
|
+
${item.tags?.map(tag => `<span class="badge">${tag}</span>`).join('') || ''}
|
|
998
|
+
</div>
|
|
999
|
+
</div>
|
|
1000
|
+
</div>`;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
/**
|
|
1004
|
+
* Render an interaction collection detail page
|
|
1005
|
+
*/
|
|
1006
|
+
export function interactionCollectionPage(collection: InteractionCollection): string {
|
|
1007
|
+
return /*html*/`
|
|
1008
|
+
<!DOCTYPE html>
|
|
1009
|
+
<html lang="en">
|
|
1010
|
+
<head>
|
|
1011
|
+
<meta charset="UTF-8">
|
|
1012
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1013
|
+
<title>${collection.title || collection.name} - Interactions</title>
|
|
1014
|
+
<style>${detailStyles}</style>
|
|
1015
|
+
</head>
|
|
1016
|
+
<body>
|
|
1017
|
+
${collectionDetailHeader(collection, 'interactions')}
|
|
936
1018
|
|
|
937
1019
|
<h2>${collection.interactions.length} Interaction${collection.interactions.length !== 1 ? 's' : ''}</h2>
|
|
938
1020
|
|
|
939
1021
|
<div class="item-list">
|
|
940
|
-
${collection.interactions.map(inter =>
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
1022
|
+
${collection.interactions.map(inter => simpleItemCard(inter)).join('')}
|
|
1023
|
+
</div>
|
|
1024
|
+
</body>
|
|
1025
|
+
</html>`;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
/**
|
|
1029
|
+
* Render a content type collection detail page
|
|
1030
|
+
*/
|
|
1031
|
+
export function contentTypeCollectionPage(collection: ContentTypesCollection): string {
|
|
1032
|
+
const typesArray = collection.getContentTypes();
|
|
1033
|
+
return /*html*/`
|
|
1034
|
+
<!DOCTYPE html>
|
|
1035
|
+
<html lang="en">
|
|
1036
|
+
<head>
|
|
1037
|
+
<meta charset="UTF-8">
|
|
1038
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1039
|
+
<title>${collection.title || collection.name} - Content Types</title>
|
|
1040
|
+
<style>${detailStyles}</style>
|
|
1041
|
+
</head>
|
|
1042
|
+
<body>
|
|
1043
|
+
${collectionDetailHeader(collection, 'types')}
|
|
1044
|
+
|
|
1045
|
+
<h2>${typesArray.length} Content Type${typesArray.length !== 1 ? 's' : ''}</h2>
|
|
1046
|
+
|
|
1047
|
+
<div class="item-list">
|
|
1048
|
+
${typesArray.map(type => simpleItemCard(type)).join('')}
|
|
953
1049
|
</div>
|
|
954
1050
|
</body>
|
|
955
1051
|
</html>`;
|
package/src/types.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { ToolDefinition, ToolUse } from "@llumiverse/common";
|
|
2
2
|
import { VertesiaClient } from "@vertesia/client";
|
|
3
|
-
import { AuthTokenPayload, ToolResult, ToolResultContent } from "@vertesia/common";
|
|
3
|
+
import { AgentToolDefinition, AuthTokenPayload, ToolExecutionMetadata, ToolResult, ToolResultContent } from "@vertesia/common";
|
|
4
|
+
|
|
5
|
+
export type { ToolExecutionMetadata };
|
|
4
6
|
|
|
5
7
|
export type ICollection<T = any> = CollectionProperties & Iterable<T>
|
|
6
8
|
|
|
@@ -80,23 +82,30 @@ export interface ToolExecutionPayload<ParamsT extends Record<string, any>> {
|
|
|
80
82
|
/**
|
|
81
83
|
* Optional metadata related to the current execution request
|
|
82
84
|
*/
|
|
83
|
-
metadata?:
|
|
85
|
+
metadata?: ToolExecutionMetadata,
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
export type ToolFn<ParamsT extends Record<string, any>> = (payload: ToolExecutionPayload<ParamsT>, context: ToolExecutionContext) => Promise<ToolExecutionResult>;
|
|
87
89
|
|
|
88
90
|
export interface Tool<ParamsT extends Record<string, any>> extends ToolDefinition {
|
|
89
91
|
run: ToolFn<ParamsT>;
|
|
92
|
+
/**
|
|
93
|
+
* Whether this tool is available by default.
|
|
94
|
+
* - true/undefined: Tool is always available to agents
|
|
95
|
+
* - false: Tool is only available when activated by a skill's related_tools
|
|
96
|
+
*/
|
|
97
|
+
default?: boolean;
|
|
90
98
|
}
|
|
91
99
|
|
|
100
|
+
|
|
92
101
|
/**
|
|
93
|
-
* The interface that should be
|
|
102
|
+
* The interface that should be returned when requesting a collection endpoint using a GET
|
|
94
103
|
*/
|
|
95
104
|
export interface ToolCollectionDefinition {
|
|
96
105
|
title: string;
|
|
97
106
|
description: string;
|
|
98
107
|
src: string;
|
|
99
|
-
tools:
|
|
108
|
+
tools: AgentToolDefinition[];
|
|
100
109
|
}
|
|
101
110
|
|
|
102
111
|
export type { ToolDefinition };
|
|
@@ -167,19 +176,6 @@ export interface SkillExecution {
|
|
|
167
176
|
template?: string;
|
|
168
177
|
}
|
|
169
178
|
|
|
170
|
-
/**
|
|
171
|
-
* Script file bundled with a skill
|
|
172
|
-
*/
|
|
173
|
-
export interface SkillScript {
|
|
174
|
-
/**
|
|
175
|
-
* Filename (e.g., "analyze.py")
|
|
176
|
-
*/
|
|
177
|
-
name: string;
|
|
178
|
-
/**
|
|
179
|
-
* Script content
|
|
180
|
-
*/
|
|
181
|
-
content: string;
|
|
182
|
-
}
|
|
183
179
|
|
|
184
180
|
/**
|
|
185
181
|
* Skill definition - parsed from SKILL.md or SKILL.jst
|
|
@@ -229,7 +225,15 @@ export interface SkillDefinition {
|
|
|
229
225
|
/**
|
|
230
226
|
* Scripts bundled with this skill (synced to sandbox when skill is used)
|
|
231
227
|
*/
|
|
232
|
-
scripts?:
|
|
228
|
+
scripts?: string[];
|
|
229
|
+
/**
|
|
230
|
+
* The name of the widgets provided by this skill (if any)
|
|
231
|
+
* The name will be used to load the widget dynamically from the agent chat
|
|
232
|
+
* and must match the code block language returned by the LLM (e.g., ```my-widget)
|
|
233
|
+
* which will be rendered using the widget.
|
|
234
|
+
* The widget file must be located in the skill directory under the name {{widget-name}}.tsx.
|
|
235
|
+
*/
|
|
236
|
+
widgets?: string[];
|
|
233
237
|
}
|
|
234
238
|
|
|
235
239
|
/**
|
package/src/utils.ts
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
1
|
export function kebabCaseToTitle(name: string) {
|
|
2
2
|
return name.split('-').map(p => p[0].toUpperCase() + p.substring(1)).join(' ');
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function makeScriptUrl(origin: string, script: string) {
|
|
6
|
+
return join(origin, join("/scripts", script));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function join(left: string, right: string) {
|
|
10
|
+
if (left.endsWith('/')) {
|
|
11
|
+
if (right.startsWith('/')) {
|
|
12
|
+
return left + right.slice(1);
|
|
13
|
+
} else {
|
|
14
|
+
return left + right;
|
|
15
|
+
}
|
|
16
|
+
} else if (right.startsWith('/')) {
|
|
17
|
+
return left + right;
|
|
18
|
+
} else if (right.startsWith('./')) {
|
|
19
|
+
return left + '/' + right.slice(2);
|
|
20
|
+
} else {
|
|
21
|
+
return left + '/' + right;
|
|
22
|
+
}
|
|
3
23
|
}
|