@@ -124,20 +124,6 @@ class WorkflowOptions:
124124 enable_latex_gate : bool = True
125125 enable_publishing : bool = True
126126 director_options : DirectorOptions | None = None
127- # "default" — full pipeline.
128- # "fast" — skip best-effort passes that don't shape the next
129- # iteration's input: presentation memo (briefing
130- # reads fine without it), analytical math review
131- # (Analytical's specialist round already covers it),
132- # LaTeX compile gate. Strategist + rolling summary
133- # cadence stretched to every 5 iterations, library
134- # refactor to every 10. The trade-off is one
135- # iteration of extra latency on Strategist
136- # observations and a paper.tex that may carry a
137- # LaTeX warning until the user runs latexmk
138- # manually. Wall-clock saving on a real API is
139- # roughly 30-50% per iteration.
140- profile : str = "default"
141127
142128
143129class ResearchWorkflow :
@@ -708,15 +694,7 @@ def _run_iteration_inner(
708694 # passes, or after the cap exhausts (in which case the final
709695 # failure is the recorded result).
710696 latex_result = None
711- # Fast profile: skip the LaTeX compile gate + retry loop. The
712- # paper.tex still gets written, the user can latexmk it
713- # manually if they care; the gate is mainly a guardrail
714- # against the Writer producing un-compilable output, which is
715- # rare and one-iteration-asynchronous to fix anyway.
716- if (
717- self .options .enable_latex_gate
718- and self .options .profile != "fast"
719- ):
697+ if self .options .enable_latex_gate :
720698 latex_result = self ._run_latex_gate (project , state , store )
721699 attempt = 0
722700 MAX_LATEX_FIX_RETRIES = 2
@@ -1559,10 +1537,7 @@ def _emit_strategic_review(
15591537 recent_reviews = store .list_strategic_reviews (project .id , limit = 1 )
15601538 except Exception :
15611539 recent_reviews = []
1562- cadence = 5 if self .options .profile == "fast" else 3
1563- if not _strategist_should_run (
1564- latest_snap , recent_reviews , cadence = cadence ,
1565- ):
1540+ if not _strategist_should_run (latest_snap , recent_reviews ):
15661541 return
15671542
15681543 director_id = self ._agent_id_for_role (ROLE_KIND_DIRECTOR )
@@ -1766,10 +1741,8 @@ def _emit_rolling_summary(
17661741 error, garbage output) skips silently. The legacy prior_summary
17671742 path in `prior_iteration_summary` still works as a fallback.
17681743 """
1769- cadence = 5 if self .options .profile == "fast" else 3
17701744 if not _rolling_summary_should_run (
1771- iteration .iteration_number , project .rolling_summary ,
1772- cadence = cadence ,
1745+ iteration .iteration_number , project .rolling_summary
17731746 ):
17741747 return
17751748
@@ -2493,13 +2466,8 @@ def _run_analytical_math_review(
24932466 for the Writer to address.
24942467
24952468 Returns empty when there is no Analytical agent, no paper, or
2496- the LLM call fails — never raises. In ``profile="fast"`` we
2497- skip this pass entirely; the Analytical specialist already
2498- scrutinises equations during its own specialist round, so the
2499- paper-level math sweep is redundant for fast iterations.
2469+ the LLM call fails — never raises.
25002470 """
2501- if self .options .profile == "fast" :
2502- return []
25032471 analytical_id = self ._analytical_specialist_id ()
25042472 if analytical_id is None or not self ._agent_enabled (analytical_id ):
25052473 return []
@@ -4089,9 +4057,7 @@ def _maybe_run_library_refactor(
40894057 list_modules ,
40904058 )
40914059
4092- LIBRARY_REFACTOR_PERIOD = (
4093- 10 if self .options .profile == "fast" else 5
4094- )
4060+ LIBRARY_REFACTOR_PERIOD = 5
40954061 MIN_MODULES_TO_REFACTOR = 3
40964062 if iteration .iteration_number <= 0 :
40974063 return
@@ -4400,13 +4366,7 @@ def _maybe_run_presentation_memo(
44004366 the memo as an agent_call transcript is intentional — it lets
44014367 the user audit it from the web UI in the same way as Director
44024368 plans and Writer edits.
4403-
4404- ``profile="fast"`` skips this pass — the briefing reads fine
4405- without a memo, and the saving (one LLM call per iteration)
4406- is what fast mode is for.
44074369 """
4408- if self .options .profile == "fast" :
4409- return ""
44104370 presentation_id = self ._agent_id_for_role (ROLE_KIND_PRESENTATION )
44114371 if presentation_id is None or not self ._agent_enabled (presentation_id ):
44124372 return ""
@@ -5876,7 +5836,7 @@ def _refresh_outstanding_section(text: str) -> str:
58765836
58775837
58785838def _rolling_summary_should_run (
5879- iteration_number : int , current_summary : str , * , cadence : int = 3 ,
5839+ iteration_number : int , current_summary : str
58805840) -> bool :
58815841 """Decide whether to refresh the project's rolling summary.
58825842
@@ -5886,16 +5846,16 @@ def _rolling_summary_should_run(
58865846 context as early as possible. Without this a project that
58875847 started before P6 landed would not get a summary until
58885848 iter 3.
5889- * iteration_number is a multiple of ``cadence`` (default 3 ;
5890- fast profile passes 5 to keep token cost lower ).
5849+ * iteration_number is a multiple of 3 (default cadence ;
5850+ keeps token cost predictable ).
58915851
58925852 Pure function so the trigger logic is independently testable.
58935853 """
58945854 if iteration_number < 2 :
58955855 return False
58965856 if not (current_summary or "" ).strip ():
58975857 return True
5898- return iteration_number % max ( 1 , cadence ) == 0
5858+ return iteration_number % 3 == 0
58995859
59005860
59015861def _wants_deep_consolidation (pivots : list [dict [str , Any ]] | None ) -> bool :
@@ -5919,20 +5879,14 @@ def _wants_deep_consolidation(pivots: list[dict[str, Any]] | None) -> bool:
59195879 return False
59205880
59215881
5922- def _strategist_should_run (
5923- latest_snap : Any ,
5924- recent_reviews : list ,
5925- * ,
5926- cadence : int = 3 ,
5927- ) -> bool :
5882+ def _strategist_should_run (latest_snap : Any , recent_reviews : list ) -> bool :
59285883 """Decide whether to run the Strategist this iteration.
59295884
59305885 Triggers (any-of):
59315886 * iteration_number == 1 — establish a baseline review.
59325887 * latest_snap.risk_flags non-empty — react to trouble immediately
59335888 rather than waiting for the periodic cadence.
5934- * ≥ ``cadence`` iterations since the last review — periodic
5935- re-assess (default 3; fast profile passes 5).
5889+ * ≥ 3 iterations since the last review — periodic re-assess.
59365890
59375891 Pure function so the trigger logic is unit-testable without
59385892 needing a full workflow setup.
@@ -5946,7 +5900,7 @@ def _strategist_should_run(
59465900 if not recent_reviews :
59475901 return True # never run before; do an initial review now
59485902 last_review_iter = int (recent_reviews [0 ].iteration_number or 0 )
5949- return (latest_snap .iteration_number - last_review_iter ) >= max ( 1 , cadence )
5903+ return (latest_snap .iteration_number - last_review_iter ) >= 3
59505904
59515905
59525906def _clamp01 (value : Any ) -> float :
0 commit comments