You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
improve claude response handling, prepare for fable-5 (#2595)
* fix: harden narrative report generation against max_tokens truncation
claude-sonnet-5 has adaptive thinking on by default, and max_tokens is a
hard cap on thinking + response text combined. Existing max_tokens values
(3000-4000) were sized for text-only output on older models, causing a
minority of narrative/collective-statement responses to truncate mid-JSON.
- Raise max_tokens to 8000 across all Anthropic narrative-generation call
sites (delphi model_provider.py, 801_narrative_report_batch.py,
server collectiveStatement.ts, reportNarrative.ts, sonnet.ts)
- Add output_config: {effort: "medium"} to bound thinking depth
- Log a warning whenever stop_reason == "max_tokens" so truncation is
visible in logs instead of silently producing bad data
- Prompt hardening: instruct the model to prioritize completing the JSON
structure over exhaustive detail if space is limited
- Client-side defense in depth: CommentsReport.jsx no longer requires
report_data to end with "}" before attempting jsonrepair, which can
already recover a valid partial object from truncated responses
- Bump @anthropic-ai/sdk in server/node_modules to the 0.110.0 already
pinned in package.json (needed for output_config typings)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* chore: remove dead per-job model/stage config for Delphi FULL_PIPELINE and batch jobs
jobs.ts built a job_config.stages structure (PCA/UMAP/REPORT configs,
model, include_topics, visualizations) that job_poller.py's FULL_PIPELINE
branch and run_delphi.py never read — confirmed by tracing the full
invocation path. The Anthropic model used for narrative generation is
controlled exclusively by the ANTHROPIC_MODEL environment variable
(job_poller.py reads it directly for both FULL_PIPELINE and
CREATE_NARRATIVE_BATCH jobs, ignoring any per-request model).
Removed the same dead fields from the client since the server never
used them: jobFormData's max_votes/batch_size/model/include_topics, and
the model field on the batchReports request (which was similarly
recorded in job_config but ignored by job_poller.py at generation time).
This keeps a single source of truth for model selection (the
ANTHROPIC_MODEL secret) instead of a misleading per-request parameter
that looked configurable but never was.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* feat(delphi): add claude-fable-5 support with refusal/fallback handling
Claude Fable 5 runs safety classifiers that can decline a request
(stop_reason: "refusal", HTTP 200 - not an error), which none of our
narrative-generation code accounted for. Without handling, a refusal
would silently produce an empty/garbage report.
- Add "claude-fable-5" to model_provider.py's hardcoded model list
- New helpers in model_provider.py: _anthropic_request_extras() (adds
the server-side fallbacks param + required beta header, but only when
the active model is claude-fable-5 - a no-op for every other model),
_narrative_error_json(), and _check_response_for_issues()
- get_response()/get_completion() (the two non-batch HTTP call paths)
now opt into fallback to claude-opus-4-8 on Fable 5, and turn a
refusal into a clear "declined by safety classifier" report instead
of empty content
- get_batch_responses() (unused) explicitly does not add fallbacks,
since the Batch API rejects that param
- 803_check_batch_status.py (the live batch-results parser) detects
stop_reason == "refusal" on batch results - which report
result.type == "succeeded" per Anthropic's docs, so this needed an
explicit check - and stores the same clear error message instead of
silently writing "{}"
Server-side fallback isn't available on the Batch API, so a refused
batch item can't be auto-recovered in place; it now at least fails
visibly instead of looking like a successful empty report.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
You MUST respond with valid JSON that follows the exact schema above. Each clause must have at least one citation.`;
143
+
You MUST respond with valid JSON that follows the exact schema above. Each clause must have at least one citation. The full JSON object, including closing brackets, must fit within the available output length — prioritize finishing the JSON structure over exhaustive detail.`;
144
144
145
145
try{
146
146
constresponse=awaitanthropic.messages.create({
147
147
model: "claude-opus-4-8",
148
-
max_tokens: 3000,
148
+
// max_tokens is a hard cap on thinking + response text combined
149
+
// (adaptive thinking is on by default on Opus 4.8+), so this needs
150
+
// real headroom beyond the visible JSON text length.
151
+
max_tokens: 8000,
152
+
output_config: {effort: "medium"},
149
153
system: systemPrompt,
150
154
messages: [
151
155
{
@@ -155,6 +159,12 @@ You MUST respond with valid JSON that follows the exact schema above. Each claus
155
159
],
156
160
});
157
161
162
+
if(response.stop_reason==="max_tokens"){
163
+
logger.warn(
164
+
"Anthropic collective statement response was truncated by max_tokens; output may be incomplete/invalid JSON."
165
+
);
166
+
}
167
+
158
168
// Parse the JSON response — find text block (adaptive thinking may add thinking blocks)
0 commit comments