Files
agent-radar 2ed3415fb7
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
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

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;
}