-
Notifications
You must be signed in to change notification settings - Fork 8
fix(temporal): raise Glitter synthesis token cap and retry on truncation #1995
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| import { zodResponseFormat } from "openai/helpers/zod"; | ||
| import { LengthFinishReasonError } from "openai/core/error"; | ||
| import { z } from "zod/v4"; | ||
| import { | ||
| type StyleCard, | ||
|
|
@@ -45,7 +46,14 @@ import { | |
| const EXTRACTION_MODEL = "gpt-5.6-luna"; | ||
| const SYNTHESIS_MODEL = "gpt-5.6-sol"; | ||
| const EXTRACTION_MAX_OUTPUT_TOKENS = 2000; | ||
| const SYNTHESIS_MAX_OUTPUT_TOKENS = 15_000; | ||
| // gpt-5.6-sol is a reasoning model at `reasoning_effort: "medium"`, so its | ||
| // hidden reasoning tokens share `max_completion_tokens` with the (large) style | ||
| // synthesis output. Observed live: reasoning + output crossed the former 15k cap | ||
| // and truncated (finish_reason=length → unparseable → LengthFinishReasonError). | ||
| // 28k gives comfortable headroom over the observed ~15k usage; if a call still | ||
| // truncates, it is retried once at the ceiling below. | ||
| const SYNTHESIS_MAX_OUTPUT_TOKENS = 28_000; | ||
| const SYNTHESIS_TRUNCATION_RETRY_MAX_OUTPUT_TOKENS = 40_000; | ||
| const DETERMINISTIC_SEED = 0; | ||
|
|
||
| // gpt-5.6 sometimes emits an observation citing a message ID outside its | ||
|
|
@@ -379,10 +387,24 @@ async function runSynthesis(input: { | |
| estimatedCallCostUsd({ | ||
| model: SYNTHESIS_MODEL, | ||
| inputTokenUpperBound: inputTokenUpperBound(JSON.stringify(params)), | ||
| outputTokenUpperBound: SYNTHESIS_MAX_OUTPUT_TOKENS, | ||
| outputTokenUpperBound: SYNTHESIS_TRUNCATION_RETRY_MAX_OUTPUT_TOKENS, | ||
| }), | ||
| ); | ||
| const completion = await parseGlitterCompletion(callSite, params); | ||
| // Reasoning + output can still truncate at the base cap; retry once with a | ||
| // higher `max_completion_tokens` on a length finish before giving up. | ||
| const completion = await (async () => { | ||
| try { | ||
| return await parseGlitterCompletion(callSite, params); | ||
| } catch (error: unknown) { | ||
| if (!(error instanceof LengthFinishReasonError)) { | ||
| throw error; | ||
| } | ||
| return await parseGlitterCompletion(callSite, { | ||
| ...params, | ||
| max_completion_tokens: SYNTHESIS_TRUNCATION_RETRY_MAX_OUTPUT_TOKENS, | ||
|
Comment on lines
+395
to
+404
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When the 28k request ends with Useful? React with 👍 / 👎. |
||
| }); | ||
|
Comment on lines
+402
to
+405
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When the 28k call truncates, this stores the 40k completion under a request hash that declares only Useful? React with 👍 / 👎. |
||
| } | ||
| })(); | ||
| const message = completion.choices[0]?.message; | ||
| return glitterCompletionArtifact({ | ||
| model: SYNTHESIS_MODEL, | ||
|
|
@@ -431,18 +453,19 @@ export function estimateStyleGenerationCost(input: { | |
| const synthesisInputUpperBound = | ||
| inputTokenUpperBound(synthesisBase) + | ||
| chunks.length * EXTRACTION_MAX_OUTPUT_TOKENS; | ||
| // Worst-case output is the truncation-retry ceiling, not the base cap. | ||
| const synthesisInitialCall = estimatedCallCostUsd({ | ||
| model: SYNTHESIS_MODEL, | ||
| inputTokenUpperBound: synthesisInputUpperBound, | ||
| outputTokenUpperBound: SYNTHESIS_MAX_OUTPUT_TOKENS, | ||
| outputTokenUpperBound: SYNTHESIS_TRUNCATION_RETRY_MAX_OUTPUT_TOKENS, | ||
| }); | ||
| // A synthesis repair likewise serializes the prior synthesis (bounded by the | ||
| // output cap) plus the error into its request. | ||
| // output ceiling) plus the error into its request. | ||
| const synthesisRepairCall = estimatedCallCostUsd({ | ||
| model: SYNTHESIS_MODEL, | ||
| inputTokenUpperBound: | ||
| synthesisInputUpperBound + SYNTHESIS_MAX_OUTPUT_TOKENS, | ||
| outputTokenUpperBound: SYNTHESIS_MAX_OUTPUT_TOKENS, | ||
| synthesisInputUpperBound + SYNTHESIS_TRUNCATION_RETRY_MAX_OUTPUT_TOKENS, | ||
| outputTokenUpperBound: SYNTHESIS_TRUNCATION_RETRY_MAX_OUTPUT_TOKENS, | ||
| }); | ||
| return ( | ||
| extractionCost + | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This adds the 2026-08-04 implementation work to the plan, but the document still proceeds directly into the old
## Session Log — 2026-07-29section and never records an August Done / Remaining / Caveats summary. Append the required 2026-08-04 session log so the unfinished probe and handoff state are captured in the repository's mandated format.AGENTS.md reference: AGENTS.md:L125-L142
Useful? React with 👍 / 👎.