Skip to content

Commit f53195b

Browse files
committed
Keep malformed provider objects out of chat bubbles
The AI response normalizer handled valid fenced JSON but still displayed malformed object-shaped provider output such as {content:"..."}. Treat malformed brace-prefixed machine output as invalid while preserving human bracket-prefixed chat text. Constraint: Chat bubbles render generated content directly after server normalization. Rejected: Try to recover text from malformed object syntax | that risks inventing parser behavior for invalid machine output; safe fallback is preferable. Confidence: high Scope-risk: narrow Directive: Provider output that looks like a machine container must normalize to plain text or be rejected before generated=true. Tested: python3 -m py_compile scripts/check_repository.py; python3 scripts/check_repository.py; npm run verify; npm audit --omit=dev; git diff --check Not-tested: Live DeepSeek malformed object output frequency.
1 parent d227376 commit f53195b

3 files changed

Lines changed: 12 additions & 1 deletion

File tree

lib/ai/deepseek.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ function unwrapJsonContent(content) {
132132
}
133133
}
134134
} catch {
135-
return content;
135+
return content.startsWith("{") ? "" : content;
136136
}
137137

138138
return "";

scripts/check_repository.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,8 @@
188188
raise SystemExit('AI response normalization must unwrap JSON-shaped provider replies before display')
189189
if 'Bracket-prefixed chat text should not be rejected as JSON' not in ai_verify_source or 'content.startsWith("[")' not in deepseek_source:
190190
raise SystemExit('AI response normalization must distinguish bracket-prefixed chat text from parseable JSON arrays')
191+
if 'Malformed object-shaped AI replies should be rejected instead of displayed' not in ai_verify_source or 'content.startsWith("{") ? "" : content' not in deepseek_source:
192+
raise SystemExit('AI response normalization must reject malformed object-shaped provider replies')
191193
if "process.env.DEEPSEEK_MODEL = ' '" not in ai_verify_source or 'whitespace-only DEEPSEEK_MODEL must fall back' not in ai_verify_source:
192194
raise SystemExit('AI integration verifier must assert whitespace-only DEEPSEEK_MODEL falls back to the default')
193195
if "thinkingType !== 'disabled'" not in ai_verify_source:

scripts/verify_ai_integration.mjs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,14 @@ if (jsonArrayResponse.status !== 502 || jsonArrayData.error !== 'empty_ai_conten
202202
throw new Error(`Parseable JSON arrays should be rejected instead of displayed: ${JSON.stringify({ status: jsonArrayResponse.status, jsonArrayData })}`);
203203
}
204204

205+
nextMockContent = '{content:"别想太多啦。"}';
206+
const malformedObjectResponse = await POST(buildRequest(validPayload));
207+
const malformedObjectData = await malformedObjectResponse.json();
208+
209+
if (malformedObjectResponse.status !== 502 || malformedObjectData.error !== 'empty_ai_content') {
210+
throw new Error(`Malformed object-shaped AI replies should be rejected instead of displayed: ${JSON.stringify({ status: malformedObjectResponse.status, malformedObjectData })}`);
211+
}
212+
205213
nextMockContent = '{"debug":true}';
206214
const invalidJsonShapedResponse = await POST(buildRequest(validPayload));
207215
const invalidJsonShapedData = await invalidJsonShapedResponse.json();
@@ -371,6 +379,7 @@ console.log(JSON.stringify({
371379
oversized_error: oversizedData.error,
372380
json_shaped_content: jsonShapedData.content,
373381
bracket_prefixed_content: bracketPrefixedData.content,
382+
malformed_object_error: malformedObjectData.error,
374383
overlong_error: overlongData.error,
375384
max_tokens: captured.maxTokens,
376385
inherited_time_label: clientAiPayload.scene.timeLabel,

0 commit comments

Comments
 (0)