@directus/api
Version:
Directus is a real-time API and App dashboard for managing SQL database content
115 lines (110 loc) • 4.87 kB
JavaScript
//#region src/ai/chat/utils/format-context.ts
function escapeAngleBrackets(text) {
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
}
function groupAttachments(attachments) {
const groups = {
visualElements: [],
prompts: [],
items: []
};
for (const att of attachments) switch (att.type) {
case "visual-element":
groups.visualElements.push(att);
break;
case "prompt":
groups.prompts.push(att);
break;
case "item":
groups.items.push(att);
break;
}
return groups;
}
function formatVisualElement(att) {
const fields = att.data.fields?.length ? att.data.fields.map((f) => escapeAngleBrackets(f)).join(", ") : "all";
const collection = escapeAngleBrackets(String(att.data.collection));
const item = escapeAngleBrackets(String(att.data.item));
return `### ${collection}/${item} — "${escapeAngleBrackets(att.display)}"
Editable fields: ${fields}
To update: items tool with collection="${collection}", keys=["${item}"], action="update"
\`\`\`json
${escapeAngleBrackets(JSON.stringify(att.snapshot, null, 2))}
\`\`\``;
}
function formatPrompt(att) {
const snapshot = att.snapshot;
const lines = [];
const display = escapeAngleBrackets(att.display);
if (snapshot.text) lines.push(escapeAngleBrackets(snapshot.text));
if (snapshot.messages?.length) {
lines.push("\n### Example Exchange");
for (const msg of snapshot.messages) {
const role = escapeAngleBrackets(msg.role);
const text = escapeAngleBrackets(msg.text);
lines.push(`**${role}**: ${text}`);
}
}
return `### ${display}\n${lines.join("\n")}`;
}
function formatItem(att) {
const display = escapeAngleBrackets(att.display);
const collectionLabel = att.data.collection ? ` (${escapeAngleBrackets(att.data.collection)})` : "";
const keyLabel = ` — key: ${escapeAngleBrackets(String(att.data.key))}`;
const collection = att.data.collection ? escapeAngleBrackets(att.data.collection) : "";
return `[Item: ${display}${collectionLabel}${keyLabel}]${att.data.collection ? `\nTo update this item, use the items tool with: collection="${collection}", keys=["${escapeAngleBrackets(String(att.data.key))}"], action="update"` : "\nUse the items tool to update this item."}\n${escapeAngleBrackets(JSON.stringify(att.snapshot, null, 2))}`;
}
/**
* Format context for appending to system prompt
*/
function formatContextForSystemPrompt(context) {
const attachments = context.attachments ?? [];
const groups = groupAttachments(attachments);
const parts = [];
if (groups.prompts.length > 0) {
const promptBlocks = groups.prompts.map(formatPrompt).join("\n\n");
parts.push(`<custom_instructions>
The user has applied the following prompt(s) to guide your behavior:
${promptBlocks}
</custom_instructions>`);
}
const sections = [];
if (context.page) {
const page = context.page;
const pageLines = [`Path: ${escapeAngleBrackets(String(page.path))}`];
if (page.collection) pageLines.push(`Collection: ${escapeAngleBrackets(String(page.collection))}`);
if (page.item !== void 0) pageLines.push(`Item: ${escapeAngleBrackets(String(page.item))}`);
if (page.module) pageLines.push(`Module: ${escapeAngleBrackets(String(page.module))}`);
sections.push(`## Current Page\n${pageLines.join("\n")}`);
}
if (groups.items.length > 0) {
const itemLines = groups.items.map(formatItem).join("\n\n");
sections.push(`## User-Added Context
The user has attached these items as reference for their request.
All root-level fields the user has access to are shown below — use these exact field names when updating.
Use the items tool to fetch additional fields or update items when asked.
${itemLines}`);
}
const now = /* @__PURE__ */ new Date();
sections.push(`## Current Date\n${now.toISOString().split("T")[0]}`);
if (sections.length > 0) parts.push(`<user_context>\n${sections.join("\n\n")}\n</user_context>`);
if (groups.visualElements.length > 0) {
const elementLines = groups.visualElements.map(formatVisualElement).join("\n\n");
parts.push(`<visual_editing>
## Selected Elements
The user selected these elements for editing in the visual editor.
IMPORTANT: For visual editor elements, ALWAYS use the items tool:
- To UPDATE: items tool with action: 'update', collection, keys, and data
- NEVER use form-values tools for visual editor elements
${elementLines}
</visual_editing>`);
}
if (attachments.length > 0) parts.push(`## Attachment Rules
- User-added attachments have HIGHER PRIORITY than page context.
- To modify attached items, ALWAYS use the items tool with action: 'update'. NEVER use form-values tools for attached items.
- form-values tools ONLY affect the currently open page form, which may be a DIFFERENT item than what the user attached.`);
if (parts.length === 0) return "";
return "\n\n" + parts.join("\n\n");
}
//#endregion
export { formatContextForSystemPrompt };