import type { AgentFileNode, AgentKnowledgeRetrievalItem, AgentSkill, AgentTool, } from './form-state' const getKnowledgeRetrievalName = (item: AgentKnowledgeRetrievalItem) => item.name ?? item.nameKey ?? item.id const escapeRegExp = (value: string) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') const createReferenceToken = (kind: string, id: string, label: string) => `[§${kind}:${id}${label ? `:${label}` : ''}§]` const syncReferenceLabels = ({ prompt, kind, currentItems, nextItems, }: { prompt: string kind: string currentItems: Array<{ id: string; name: string }> nextItems: Array<{ id: string; name: string }> }) => { const currentItemById = new Map(currentItems.map((item) => [item.id, item])) return nextItems.reduce((nextPrompt, nextItem) => { const currentItem = currentItemById.get(nextItem.id) if (!currentItem) return nextPrompt if (currentItem.name === nextItem.name) return nextPrompt return nextPrompt.replace( new RegExp(`\\[§${escapeRegExp(kind)}:${escapeRegExp(nextItem.id)}(?::[^§\\]]*)?§\\]`, 'g'), createReferenceToken(kind, nextItem.id, nextItem.name), ) }, prompt) } const toReferenceLabelItems = ( items: Item[], getName: (item: Item) => string, ) => items.map((item) => ({ id: item.id, name: getName(item), })) export const syncKnowledgeReferenceLabels = ({ prompt, currentRetrievals, nextRetrievals, }: { prompt: string currentRetrievals: AgentKnowledgeRetrievalItem[] nextRetrievals: AgentKnowledgeRetrievalItem[] }) => syncReferenceLabels({ prompt, kind: 'knowledge', currentItems: toReferenceLabelItems(currentRetrievals, getKnowledgeRetrievalName), nextItems: toReferenceLabelItems(nextRetrievals, getKnowledgeRetrievalName), }) export const syncCliToolReferenceLabels = ({ prompt, currentTools, nextTools, }: { prompt: string currentTools: AgentTool[] nextTools: AgentTool[] }) => syncReferenceLabels({ prompt, kind: 'cli_tool', currentItems: toReferenceLabelItems( currentTools.filter((tool) => tool.kind === 'cli'), (tool) => tool.name, ), nextItems: toReferenceLabelItems( nextTools.filter((tool) => tool.kind === 'cli'), (tool) => tool.name, ), }) export const syncSkillReferenceLabels = ({ prompt, currentSkills, nextSkills, }: { prompt: string currentSkills: AgentSkill[] nextSkills: AgentSkill[] }) => syncReferenceLabels({ prompt, kind: 'skill', currentItems: toReferenceLabelItems(currentSkills, (skill) => skill.name), nextItems: toReferenceLabelItems(nextSkills, (skill) => skill.name), }) const flattenFileNodes = (files: AgentFileNode[]): AgentFileNode[] => files.flatMap((file) => (file.children?.length ? flattenFileNodes(file.children) : [file])) export const syncFileReferenceLabels = ({ prompt, currentFiles, nextFiles, }: { prompt: string currentFiles: AgentFileNode[] nextFiles: AgentFileNode[] }) => syncReferenceLabels({ prompt, kind: 'file', currentItems: toReferenceLabelItems(flattenFileNodes(currentFiles), (file) => file.name), nextItems: toReferenceLabelItems(flattenFileNodes(nextFiles), (file) => file.name), })