fix(ai-builder): Format user message to avoid markdown formatting errors (#21033)

This commit is contained in:
Benjamin Schroth 2025-10-23 09:38:32 +02:00 committed by GitHub
parent 8abc04eb88
commit 70523e19c8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 100 additions and 1 deletions

View File

@ -146,14 +146,37 @@ export async function* createStreamProcessor(
}
}
/**
* Remove context tags from message content that are used for AI context
* but shouldn't be displayed to users
*/
function cleanContextTags(text: string): string {
return text.replace(/\n*<current_workflow_json>[\s\S]*?<\/current_execution_nodes_schemas>/, '');
}
/**
* Format a HumanMessage into the expected output format
*/
function formatHumanMessage(msg: HumanMessage): Record<string, unknown> {
// Handle array content (multi-part messages with text, images, etc.)
if (Array.isArray(msg.content)) {
const textParts = msg.content.filter(
(c): c is { type: string; text: string } =>
typeof c === 'object' && c !== null && 'type' in c && c.type === 'text' && 'text' in c,
);
const text = textParts.map((part) => cleanContextTags(part.text)).join('\n');
return {
role: 'user',
type: 'message',
text,
};
}
// Handle simple string content
return {
role: 'user',
type: 'message',
text: msg.content,
text: cleanContextTags(msg.content),
};
}

View File

@ -274,6 +274,82 @@ describe('stream-processor', () => {
});
});
it('should format HumanMessage with array content (multi-part messages)', () => {
const messages = [
new HumanMessage({
content: [
{ type: 'text', text: 'Part 1' },
{ type: 'text', text: 'Part 2' },
{ type: 'image_url', image_url: 'http://example.com/image.png' },
],
}),
];
const result = formatMessages(messages);
expect(result).toHaveLength(1);
expect(result[0]).toEqual({
role: 'user',
type: 'message',
text: 'Part 1\nPart 2',
});
});
it('should strip context tags from HumanMessage content', () => {
const messageWithContext = `User question here
<current_workflow_json>
{"nodes": [], "connections": {}}
</current_workflow_json>
<current_simplified_execution_data>
{"runData": {}}
</current_simplified_execution_data>
<current_execution_nodes_schemas>
[{"nodeName": "test"}]
</current_execution_nodes_schemas>`;
const messages = [new HumanMessage(messageWithContext)];
const result = formatMessages(messages);
expect(result).toHaveLength(1);
expect(result[0]).toEqual({
role: 'user',
type: 'message',
text: 'User question here',
});
});
it('should strip context tags from HumanMessage array content', () => {
const messages = [
new HumanMessage({
content: [
{
type: 'text',
text: `Workflow executed successfully.
<current_workflow_json>
{"nodes": []}
</current_workflow_json>
<current_simplified_execution_data>
{"runData": {}}
</current_simplified_execution_data>
<current_execution_nodes_schemas>
[{"nodeName": "Manual Trigger"}]
</current_execution_nodes_schemas>`,
},
],
}),
];
const result = formatMessages(messages);
expect(result).toHaveLength(1);
expect(result[0]).toEqual({
role: 'user',
type: 'message',
text: 'Workflow executed successfully.',
});
});
it('should format AIMessage with text content', () => {
const messages = [new AIMessage('Response from AI')];