Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 20 additions & 14 deletions src/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1293,21 +1293,27 @@ async function callOpenAI(
// model still learns the rule-compilation pattern. Length caps preserved
// (rule ≤ 1000, clarification ≤ 500) for prompt-injection surface control.
const clarif = clarificationAnswer?.trim().slice(0, 500);
// Flatten to a single line of ASCII without `\n` so the wire body has zero
// newline-escape sequences. PR #34 dropped reasoning_effort + verbosity but
// production v0.0.35 still hit 400; the only remaining variable separating
// our body from probe(f) (the 6 KB single-user 200 OK shape) is escape-char
// density (`\n` and `\"`). Collapsing whitespace eliminates the `\n` family
// entirely. The few-shot OUTPUT examples still produce `\"` from the outer
// JSON.stringify wrapping our content string -- if 400 persists after this,
// we'll need to express few-shot output without quoted keys.
const collapse = (s: string) => s.replace(/\s+/g, ' ').trim();
const exampleLine = (ex: (typeof FEW_SHOT_EXAMPLES)[number], i: number) =>
`EXAMPLE ${i + 1} INPUT: ${collapse(ex.user)} OUTPUT: ${JSON.stringify(ex.assistant)}`;
const compositeContent = [
'=== SYSTEM INSTRUCTIONS ===',
VIBE_MOD_SYSTEM_PROMPT,
'',
'=== EXAMPLES ===',
...FEW_SHOT_EXAMPLES.map(
(ex, i) => `--- Example ${i + 1} ---\nINPUT:\n${ex.user}\n\nOUTPUT:\n${JSON.stringify(ex.assistant)}`,
),
'',
'=== TASK ===',
`INPUT:\n${userRule.slice(0, 1000)}`,
...(clarif ? ['', `CLARIFICATION:\n${clarif}`] : []),
'',
'OUTPUT:',
].join('\n\n');
'SYSTEM INSTRUCTIONS:',
collapse(VIBE_MOD_SYSTEM_PROMPT),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Collapsing the system prompt into a single line while it contains // comments is risky. If the LLM interprets the flattened string as a single line of code-like text, it might treat everything following the first // (which appears early in the prompt at the id field definition) as a comment, effectively ignoring the bulk of the instructions, facts, and examples. Since newlines are being eliminated to avoid HTTP 400 errors, these comments should be stripped before flattening.

    collapse(VIBE_MOD_SYSTEM_PROMPT.replace(/[ \\t]+\\/\\/.*$/gm, '')),

'EXAMPLES:',
...FEW_SHOT_EXAMPLES.map(exampleLine),
'TASK INPUT:',
collapse(userRule.slice(0, 1000)),
...(clarif ? ['TASK CLARIFICATION:', collapse(clarif)] : []),
'OUTPUT (strict JSON only, no prose):',
].join(' ');
const messages: Array<{ role: 'system' | 'user' | 'assistant'; content: string }> = [
{ role: 'user', content: compositeContent },
];
Expand Down