Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
121 lines
3.4 KiB
TypeScript
121 lines
3.4 KiB
TypeScript
import type { AgentGUIProviderSkillOption } from "./agentGuiNodeTypes";
|
|
|
|
export function skillTriggerForPrefix(
|
|
skill: AgentGUIProviderSkillOption,
|
|
prefix: "$" | "/" | undefined
|
|
): string {
|
|
const trigger = skill.trigger.trim();
|
|
if (!trigger) {
|
|
return "";
|
|
}
|
|
if (prefix === undefined || trigger.startsWith(prefix)) {
|
|
return trigger;
|
|
}
|
|
if (trigger.startsWith("$") || trigger.startsWith("/")) {
|
|
return `${prefix}${trigger.slice(1)}`;
|
|
}
|
|
return `${prefix}${trigger}`;
|
|
}
|
|
|
|
export function labelForProviderSkill(
|
|
skill: AgentGUIProviderSkillOption,
|
|
prefix: "$" | "/" | undefined
|
|
): string {
|
|
return stripSkillTriggerPrefix(skillTriggerForPrefix(skill, prefix));
|
|
}
|
|
|
|
export function promptForProviderSkills(input: {
|
|
prompt: string;
|
|
skills: readonly AgentGUIProviderSkillOption[];
|
|
}): string {
|
|
let prompt = input.prompt;
|
|
for (const skill of input.skills) {
|
|
if (!skill.invocation) {
|
|
continue;
|
|
}
|
|
const nativePrefix = skill.invocation === "promptItem" ? "$" : "/";
|
|
const nativeTrigger = skillTriggerForPrefix(skill, nativePrefix);
|
|
const aliasPrefix = nativePrefix === "$" ? "/" : "$";
|
|
const aliasTrigger = skillTriggerForPrefix(skill, aliasPrefix);
|
|
if (!nativeTrigger || !aliasTrigger || nativeTrigger === aliasTrigger) {
|
|
continue;
|
|
}
|
|
prompt = replaceSkillTriggerToken(prompt, aliasTrigger, nativeTrigger);
|
|
}
|
|
return prompt;
|
|
}
|
|
|
|
export function projectLocalConnectorPrompt(input: {
|
|
prompt: string;
|
|
skills: readonly AgentGUIProviderSkillOption[];
|
|
}): { prompt: string; connectorKeys: string[] } {
|
|
let prompt = input.prompt;
|
|
const connectorKeys: string[] = [];
|
|
const seen = new Set<string>();
|
|
for (const skill of input.skills) {
|
|
const connectorKey = skill.connectorKey?.trim();
|
|
if (
|
|
!connectorKey ||
|
|
skill.sourceKind !== "connector" ||
|
|
skill.kind !== "connector" ||
|
|
skill.invocation !== "textTrigger" ||
|
|
skill.status !== "available"
|
|
) {
|
|
continue;
|
|
}
|
|
const trigger = skillTriggerForPrefix(skill, "/");
|
|
if (!trigger || !promptHasTrigger(prompt, trigger)) {
|
|
continue;
|
|
}
|
|
prompt = removePromptTrigger(prompt, trigger);
|
|
if (!seen.has(connectorKey)) {
|
|
seen.add(connectorKey);
|
|
connectorKeys.push(connectorKey);
|
|
}
|
|
}
|
|
return { prompt: prompt.trim(), connectorKeys };
|
|
}
|
|
|
|
export function skillDescriptionForDisplay(
|
|
description: string | undefined
|
|
): string | undefined {
|
|
const line = description
|
|
?.split(/\r?\n/)
|
|
.map((part) => part.trim())
|
|
.find((part) => part !== "");
|
|
return line || undefined;
|
|
}
|
|
|
|
function replaceSkillTriggerToken(
|
|
prompt: string,
|
|
from: string,
|
|
to: string
|
|
): string {
|
|
return prompt.replace(
|
|
new RegExp(`(^|\\s)${escapeRegExp(from)}(?=$|\\s)`, "g"),
|
|
(_match, separator: string) => `${separator}${to}`
|
|
);
|
|
}
|
|
|
|
function promptHasTrigger(prompt: string, trigger: string): boolean {
|
|
return new RegExp(`(^|\\s)${escapeRegExp(trigger)}(?=$|\\s)`).test(prompt);
|
|
}
|
|
|
|
function removePromptTrigger(prompt: string, trigger: string): string {
|
|
return prompt.replace(
|
|
new RegExp(`(^|\\s)${escapeRegExp(trigger)}(?=$|\\s)`, "g"),
|
|
(_match, separator: string) => separator
|
|
);
|
|
}
|
|
|
|
function escapeRegExp(value: string): string {
|
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
}
|
|
|
|
function stripSkillTriggerPrefix(trigger: string): string {
|
|
if (trigger.startsWith("$") || trigger.startsWith("/")) {
|
|
return trigger.slice(1);
|
|
}
|
|
return trigger;
|
|
}
|