Skip to content

Commit eb925c6

Browse files
committed
aa
1 parent feaf2cf commit eb925c6

40 files changed

Lines changed: 6008 additions & 567 deletions

frontend/src/api/types.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,12 +293,24 @@ export interface StartIterationRequest {
293293
no_parallel?: boolean;
294294
enable_literature_search?: boolean;
295295
enable_numerical_tools?: boolean;
296+
/** Per-iteration token cap. Each iteration starts with a fresh
297+
* budget of this many tokens. */
296298
token_cap?: number;
299+
/** Optional total run-level token cap across all iterations.
300+
* 0 (default) = no global cap; only the per-iteration cap
301+
* applies. > 0 = the iteration_manager breaks the run with
302+
* `total_budget_threshold` once cumulative tokens cross this. */
303+
total_token_cap?: number;
297304
wall_clock_seconds?: number;
298305
model?: string | null;
299306
/** How many iterations to run back-to-back. Server caps at 20.
300307
* Default 1 = legacy single-iteration behaviour. */
301308
max_iterations?: number;
309+
/** A0: skip the specialist research round; run Curator + Writer +
310+
* paper-level review only. Use when the research is done and the
311+
* iteration's purpose is exposition / polish only. Replaces the
312+
* pre-A0 autonomous "finalize" mode. */
313+
finalize_only?: boolean;
302314
}
303315

304316
export interface StartIterationResponse {

frontend/src/styles.css

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3818,6 +3818,97 @@ a.iterationDiffToggle {
38183818
color: #17130f;
38193819
}
38203820

3821+
/* Filter + Expand panel — sits directly to the LEFT of the round
3822+
icon toolbar (.researchMapControls at top:84 right:20), sharing
3823+
the same cream/parchment palette so they read as a single
3824+
floating control group. Pre-fix, the filter chips were inline-
3825+
styled in the document flow and overlapped the title; isolating
3826+
them in a position-absolute pill keeps them anchored regardless
3827+
of paper title length. */
3828+
.researchMapFilterPanel {
3829+
position: absolute;
3830+
z-index: 6;
3831+
top: 84px;
3832+
right: 76px; /* leave room for the round toolbar at top:84 right:20 */
3833+
display: inline-flex;
3834+
align-items: center;
3835+
gap: 4px;
3836+
padding: 4px 8px;
3837+
border: 1px solid rgba(37, 33, 29, 0.12);
3838+
border-radius: 16px;
3839+
background: rgba(255, 250, 240, 0.74);
3840+
box-shadow: 0 16px 38px rgba(37, 33, 29, 0.10);
3841+
backdrop-filter: blur(16px);
3842+
pointer-events: auto;
3843+
}
3844+
3845+
/* Prominent labeled action — pulled out of the round icon toolbar
3846+
so its variable-width text doesn't stretch the toolbar's grid
3847+
column. Lives on the left of the filter panel, before the
3848+
"Show" chips. */
3849+
.researchMapFilterAction {
3850+
display: inline-flex;
3851+
align-items: center;
3852+
gap: 5px;
3853+
padding: 4px 10px;
3854+
border: 1px solid transparent;
3855+
border-radius: 12px;
3856+
background: transparent;
3857+
color: #4d4434;
3858+
cursor: pointer;
3859+
font-size: 11px;
3860+
font-weight: 700;
3861+
letter-spacing: 0.02em;
3862+
transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
3863+
}
3864+
3865+
.researchMapFilterAction:hover {
3866+
border-color: rgba(123, 107, 74, 0.28);
3867+
background: rgba(242, 202, 89, 0.18);
3868+
color: #17130f;
3869+
}
3870+
3871+
.researchMapFilterDivider {
3872+
width: 1px;
3873+
height: 18px;
3874+
margin: 0 4px;
3875+
background: rgba(37, 33, 29, 0.18);
3876+
}
3877+
3878+
.researchMapFilterPanelLabel {
3879+
margin-right: 4px;
3880+
color: #8a795b;
3881+
font-size: 9px;
3882+
font-weight: 900;
3883+
letter-spacing: 0.14em;
3884+
text-transform: uppercase;
3885+
}
3886+
3887+
.researchMapFilterChip {
3888+
padding: 4px 10px;
3889+
border: 1px solid transparent;
3890+
border-radius: 12px;
3891+
background: transparent;
3892+
color: #4d4434;
3893+
cursor: pointer;
3894+
font-size: 11px;
3895+
font-weight: 700;
3896+
letter-spacing: 0.02em;
3897+
transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
3898+
}
3899+
3900+
.researchMapFilterChip:hover {
3901+
border-color: rgba(123, 107, 74, 0.28);
3902+
background: rgba(242, 202, 89, 0.18);
3903+
color: #17130f;
3904+
}
3905+
3906+
.researchMapFilterChip.active {
3907+
border-color: rgba(37, 33, 29, 0.60);
3908+
background: #25211d;
3909+
color: #fdf7e6;
3910+
}
3911+
38213912
.branchBackdrop {
38223913
fill: transparent;
38233914
}

frontend/src/views/DirectivesEditor.tsx

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,41 @@ interface Props {
1919

2020
type View = "inbox" | "raw";
2121

22+
// Matches the workflow's `_PI_HOLD_PATTERN` (Python re):
23+
// (?im)^\s*%\s*\[\s*halfseed[-_ ]hold\s*\]
24+
// Mirrored here so the UI can surface the same hold detection without a
25+
// round-trip. Keep in sync with src/halfseed/workflow.py if either side
26+
// is loosened.
27+
const PI_HOLD_LINE_RE = /^\s*%\s*\[\s*halfseed[-_ ]hold\s*\]/im;
28+
29+
function detectPiHold(directivesText: string | null | undefined): boolean {
30+
if (!directivesText) return false;
31+
return PI_HOLD_LINE_RE.test(directivesText);
32+
}
33+
34+
function PiHoldBanner({ active }: { active: boolean }) {
35+
if (!active) return null;
36+
return (
37+
<div
38+
style={{
39+
margin: "10px 0",
40+
padding: "10px 14px",
41+
background: "#3a2a1a",
42+
border: "1px solid #d98c4a",
43+
borderRadius: 6,
44+
color: "#ffc890",
45+
fontSize: 13
46+
}}
47+
title="Phase A0 explicit operator hold. Director will short-circuit every iteration with PIVOT_PENDING until you remove the marker."
48+
>
49+
<strong>HOLD active.</strong> Autonomous research is paused.
50+
Remove the <code style={{ background: "#1a120a", padding: "1px 5px", borderRadius: 3 }}>
51+
% [HALFSEED-HOLD]
52+
</code> line from <code>directives.md</code> to resume.
53+
</div>
54+
);
55+
}
56+
2257
export function DirectivesEditor({ projectId, isRunning }: Props) {
2358
// The Directives tab presents two surfaces:
2459
// inbox — the structured list-of-rows view (default). Shows pending +
@@ -32,6 +67,8 @@ export function DirectivesEditor({ projectId, isRunning }: Props) {
3267
// the inbox the next time the page polls (every 6s).
3368
const [view, setView] = useState<View>("inbox");
3469
const list = useDirectivesList(projectId);
70+
const raw = useDirectives(projectId);
71+
const piHoldActive = detectPiHold(raw.data?.text);
3572
return (
3673
<div className="paperPane">
3774
<header className="paperHeader">
@@ -59,6 +96,8 @@ export function DirectivesEditor({ projectId, isRunning }: Props) {
5996
</div>
6097
</header>
6198

99+
<PiHoldBanner active={piHoldActive} />
100+
62101
{view === "inbox" ? (
63102
<DirectivesInbox projectId={projectId} isRunning={isRunning} />
64103
) : (

0 commit comments

Comments
 (0)