@wjarka/cezarion 0.11.1 → 0.11.2-pr50.83
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/automations/task-template.js +1 -0
- package/dist/automations/task-template.js.map +1 -1
- package/dist/automations/types.d.ts +2 -0
- package/dist/automations/types.js +1 -0
- package/dist/automations/types.js.map +1 -1
- package/dist/contract/automations.d.ts +8 -0
- package/dist/contract/effort.d.ts +18 -0
- package/dist/contract/index.d.ts +1 -0
- package/dist/contract/index.js +919 -898
- package/dist/contract/runs.d.ts +7 -0
- package/dist/contract/skills.d.ts +1 -0
- package/dist/core/agent-runner.d.ts +4 -0
- package/dist/core/agent-runner.js.map +1 -1
- package/dist/core/claude-cli-runner.js +4 -0
- package/dist/core/claude-cli-runner.js.map +1 -1
- package/dist/core/codex-app-server-runner.d.ts +9 -0
- package/dist/core/codex-app-server-runner.js +14 -1
- package/dist/core/codex-app-server-runner.js.map +1 -1
- package/dist/core/opencode-server-runner.js +4 -0
- package/dist/core/opencode-server-runner.js.map +1 -1
- package/dist/core/pi-runner.js +4 -0
- package/dist/core/pi-runner.js.map +1 -1
- package/dist/runs/store.d.ts +3 -0
- package/dist/runs/store.js +4 -0
- package/dist/runs/store.js.map +1 -1
- package/dist/server/server.d.ts +68 -0
- package/dist/server/server.js +14 -3
- package/dist/server/server.js.map +1 -1
- package/dist/workflows/run.d.ts +7 -0
- package/dist/workflows/run.js +109 -52
- package/dist/workflows/run.js.map +1 -1
- package/package.json +3 -3
- package/scripts/mock-claude.mjs +72 -2
- package/web/dist/assets/{alert-dialog-B4Ofsgv7.js → alert-dialog-g-GVThSw.js} +1 -1
- package/web/dist/assets/arrow-down-BzmL0uj0.js +1 -0
- package/web/dist/assets/arrow-left-DtUM7GFU.js +1 -0
- package/web/dist/assets/{centered-state-duPW0phQ.js → centered-state-DdbE_pNl.js} +2 -2
- package/web/dist/assets/chevron-right-DnLh0uM2.js +1 -0
- package/web/dist/assets/{collapsible-DdcNBdSk.js → collapsible-R1r7zUOB.js} +1 -1
- package/web/dist/assets/{commit-list-CgvN9vec.js → commit-list-Bgb1DHBX.js} +1 -1
- package/web/dist/assets/{compare-variants-CQA2nd65.js → compare-variants-UA_0n_5a.js} +1 -1
- package/web/dist/assets/{diff-B6Agp5Hl.js → diff-Cv3z9esx.js} +2 -2
- package/web/dist/assets/{diff-stat-BoXuGkgq.js → diff-stat-ydfu0_5T.js} +1 -1
- package/web/dist/assets/{diff-view-CD8XI-fj.js → diff-view-DnPdkmk2.js} +1 -1
- package/web/dist/assets/{dropdown-menu-B3SYw-k5.js → dropdown-menu-CPP9gEmn.js} +1 -1
- package/web/dist/assets/{editable-title-B-hjp5wl.js → editable-title-D_bWdmY0.js} +1 -1
- package/web/dist/assets/{ellipsis-vertical-BYwzw0xl.js → ellipsis-vertical-WNkaehnw.js} +1 -1
- package/web/dist/assets/{file-BRj5eISx.js → file-RvhJlchx.js} +1 -1
- package/web/dist/assets/{folder-z4oT5981.js → folder-Dz-weqBo.js} +1 -1
- package/web/dist/assets/{git-toolbar-owSEkYld.js → git-toolbar-BEKuAjHk.js} +1 -1
- package/web/dist/assets/github-CmFHDNje.js +1 -0
- package/web/dist/assets/{image-preview-h3WFluuy.js → image-preview-DYiOSYoY.js} +1 -1
- package/web/dist/assets/index-BQTfjxFm.js +7 -0
- package/web/dist/assets/{markdown-DqBKYPiB.js → markdown-DQHRRO9e.js} +1 -1
- package/web/dist/assets/new-task-form-D2KlpqYC.js +1 -0
- package/web/dist/assets/{pill-BQfmfpYp.js → pill-FAFXjmY6.js} +1 -1
- package/web/dist/assets/{project-router-DxgFZY1l.js → project-router-Dzc0JK2j.js} +1 -1
- package/web/dist/assets/{prompt-templates-B6m16gq-.js → prompt-templates-DmqtzSPL.js} +1 -1
- package/web/dist/assets/{refresh-cw-mhSpxf2a.js → refresh-cw-BP4TkA4M.js} +1 -1
- package/web/dist/assets/{repo-git-CUNRxR3_.js → repo-git-C20pc5tT.js} +1 -1
- package/web/dist/assets/{run-diff-DsmmDVfx.js → run-diff-CvcsWwew.js} +1 -1
- package/web/dist/assets/run-header-xFlbebSJ.js +1 -0
- package/web/dist/assets/{search-x-BqDMB2g8.js → search-x-Drnmsmd0.js} +1 -1
- package/web/dist/assets/{skill-empty-hint-BWEvTggc.js → skill-empty-hint-D2l_OqZ5.js} +1 -1
- package/web/dist/assets/{skills-DwIxnnWO.js → skills-Cn2ppPow.js} +1 -1
- package/web/dist/assets/{sparkles-DIoTQpyx.js → sparkles-B9ja4FHw.js} +1 -1
- package/web/dist/assets/{square-terminal-Cc7CuQxc.js → square-terminal-CB2du-YG.js} +1 -1
- package/web/dist/assets/{tab-link-D1fQgpmO.js → tab-link-C5FWJ66Y.js} +1 -1
- package/web/dist/assets/{task-changes-BKeLlDpK.js → task-changes-CuUmQArS.js} +1 -1
- package/web/dist/assets/{task-commits-gcEFZIa5.js → task-commits-DgIWIhW9.js} +1 -1
- package/web/dist/assets/{task-files-BGAqoXTW.js → task-files-BeDXPyz5.js} +1 -1
- package/web/dist/assets/task-thread-2nmi0vcz.js +9 -0
- package/web/dist/assets/{textarea-BOVbfy5C.js → textarea-Sm6doUPO.js} +1 -1
- package/web/dist/assets/{thread-loading-CypW73KD.js → thread-loading-DojNeADh.js} +1 -1
- package/web/dist/assets/{trash-2-CJq6LHWn.js → trash-2-C_lGBXG2.js} +1 -1
- package/web/dist/assets/{triangle-alert-CjDFvU27.js → triangle-alert-Brk_ldFl.js} +1 -1
- package/web/dist/assets/{upload-CPDZlJeK.js → upload-Cxs1UROt.js} +1 -1
- package/web/dist/assets/{use-desktop-5JsLmi0a.js → use-desktop-Cmrz3npD.js} +1 -1
- package/web/dist/assets/{use-submit-shortcut-CHVFevty.js → use-submit-shortcut-DzeqN3GK.js} +1 -1
- package/web/dist/assets/{utils-DiO6zyJd.js → utils-Unt0mZvU.js} +1 -1
- package/web/dist/assets/{workflows-rQDFzWRt.js → workflows-D_GyBbup.js} +1 -1
- package/web/dist/assets/{zoomable-image-COWqb11v.js → zoomable-image-ByySCppM.js} +1 -1
- package/web/dist/index.html +22 -22
- package/web/dist/assets/arrow-down-Dy8dup7j.js +0 -1
- package/web/dist/assets/arrow-left-BJaucbhn.js +0 -1
- package/web/dist/assets/chevron-right-Be4A5TCS.js +0 -1
- package/web/dist/assets/github-Bz2VgRX3.js +0 -1
- package/web/dist/assets/index-EtQQQ6Kj.js +0 -7
- package/web/dist/assets/new-task-form-BdJKRBJX.js +0 -1
- package/web/dist/assets/run-header-BkhrseLJ.js +0 -1
- package/web/dist/assets/task-thread-DT8aUYTS.js +0 -9
package/dist/workflows/run.d.ts
CHANGED
|
@@ -73,6 +73,9 @@ export declare function runAccountKey(run: Pick<RunRecord, 'runner' | 'agentProf
|
|
|
73
73
|
export interface StartRunInput {
|
|
74
74
|
task: string;
|
|
75
75
|
model?: string;
|
|
76
|
+
/** Reasoning-effort pin (#45). Canonical `low`/`medium`/`high`/`xhigh`/`max`.
|
|
77
|
+
* Unset = harness default. Same class of override as `model`. */
|
|
78
|
+
effort?: string;
|
|
76
79
|
/** Agent backend chosen for this task (GUI). Unset = the config default. */
|
|
77
80
|
runner?: RunnerId;
|
|
78
81
|
/** Agent account for this task (spec 2026-07-29-agent-profiles), applying to steps that run
|
|
@@ -591,6 +594,8 @@ export declare class RunManager {
|
|
|
591
594
|
images?: ContentBlock[];
|
|
592
595
|
runner?: RunnerId;
|
|
593
596
|
model?: string;
|
|
597
|
+
/** Reasoning-effort pin (#45). Omitted keeps the run's pin; empty string clears it. */
|
|
598
|
+
effort?: string;
|
|
594
599
|
/** Agent account for the reopened session (spec 2026-07-29-agent-profiles). Omitted = the
|
|
595
600
|
* account the run is already on. */
|
|
596
601
|
agentProfile?: string;
|
|
@@ -615,6 +620,8 @@ export declare class RunManager {
|
|
|
615
620
|
* item-shape cache are session-scoped, like the mapper state feeding them.
|
|
616
621
|
*/
|
|
617
622
|
private makeUiSink;
|
|
623
|
+
/** Continue autonomous runs and markerless tool turns through one bounded path. */
|
|
624
|
+
private tryAutoContinueTurn;
|
|
618
625
|
/** Native backend asks arrive before turn-end. Persist and park immediately
|
|
619
626
|
* so the cockpit shows attention and the run releases its workspace slot. */
|
|
620
627
|
private handleRunnerUiEvent;
|
package/dist/workflows/run.js
CHANGED
|
@@ -55,6 +55,13 @@ const DONE_MARKER_RE = /CEZ:DONE\s*$/;
|
|
|
55
55
|
* backends can't split the marker across text events.
|
|
56
56
|
*/
|
|
57
57
|
const MONITORING_MARKER_RE = /CEZ:MONITORING\s*$/;
|
|
58
|
+
/** Claude's native scheduler is the backend-level equivalent of the textual
|
|
59
|
+
* monitoring marker. Keep this recognition here, at the workflow boundary,
|
|
60
|
+
* so the v1 event protocol stays unchanged and other backends do not acquire
|
|
61
|
+
* semantics from a coincidentally named tool (#46). */
|
|
62
|
+
function isClaudeScheduleWakeup(event, backend) {
|
|
63
|
+
return backend === 'claude' && event.type === 'tool-call' && event.tool === 'ScheduleWakeup';
|
|
64
|
+
}
|
|
58
65
|
/**
|
|
59
66
|
* Preserve boundaries between complete assistant text blocks while a turn is
|
|
60
67
|
* accumulated for marker parsing. The runners join these same v1 blocks with
|
|
@@ -122,6 +129,17 @@ const REPOSITORY_ROOT_LOCK_DISABLED_NOTE = 'repository-root lock disabled by CEZ
|
|
|
122
129
|
const MAX_AUTO_CONTINUES = 40;
|
|
123
130
|
const AUTONOMOUS_NUDGE = 'Continue working autonomously until the task is fully complete. Do not ask me for confirmation or clarification — make reasonable assumptions and proceed. When everything is done, end the session with your done signal.';
|
|
124
131
|
const MONITORING_WAKE_NUDGE = 'Re-check the downstream work you were monitoring. Continue toward the task goal; emit CEZ:MONITORING again only if it is still pending.';
|
|
132
|
+
/** A question at the handoff boundary may be followed by Markdown answer choices. */
|
|
133
|
+
function hasUserQuestion(text) {
|
|
134
|
+
const lines = stripTaskMarkers(text).trimEnd().split('\n');
|
|
135
|
+
while (lines.length > 0) {
|
|
136
|
+
const line = lines.pop().trim();
|
|
137
|
+
if (!line || /^(?:[-*+]|\d+[.)])\s+\S/.test(line))
|
|
138
|
+
continue;
|
|
139
|
+
return /\?[*_~`]*(?:\s*\([^()]*\))?$/.test(line);
|
|
140
|
+
}
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
125
143
|
/**
|
|
126
144
|
* Auto-resume after a provider usage limit (spec 2026-08-03-auto-resume-after-usage-limit).
|
|
127
145
|
*
|
|
@@ -540,13 +558,14 @@ export class RunManager {
|
|
|
540
558
|
// Sanitize at the manager boundary so CLI runs, workflows, variants, and
|
|
541
559
|
// direct callers cannot bypass the HTTP policy.
|
|
542
560
|
const effectiveInput = agentModelsLocked(this.repoRoot)
|
|
543
|
-
? { ...input, model: undefined }
|
|
561
|
+
? { ...input, model: undefined, effort: undefined }
|
|
544
562
|
: input;
|
|
545
563
|
const run = this.store.createRun({
|
|
546
564
|
title: makeRunTitle(input.task, workflow) + (group ? ` (${group.variant})` : ''),
|
|
547
565
|
workflow: workflow.name,
|
|
548
566
|
task: input.task,
|
|
549
567
|
model: effectiveInput.model,
|
|
568
|
+
effort: effectiveInput.effort,
|
|
550
569
|
runner: input.runner,
|
|
551
570
|
// The composer's per-task account (spec 2026-07-29-agent-profiles). Persisted at creation
|
|
552
571
|
// so a queued run picks it up at dequeue and every later resume reads the same answer.
|
|
@@ -849,6 +868,7 @@ export class RunManager {
|
|
|
849
868
|
input: this.hydrateQueuedInput(run.id, {
|
|
850
869
|
task: run.task,
|
|
851
870
|
model: run.model,
|
|
871
|
+
effort: run.effort,
|
|
852
872
|
runner: run.runner,
|
|
853
873
|
generateFollowups,
|
|
854
874
|
// Re-thread autonomy (#489): the rebuilt input feeds `execute`, whose mid-run auto-nudge
|
|
@@ -1769,7 +1789,7 @@ export class RunManager {
|
|
|
1769
1789
|
/** Restart recovery may discover several interrupted tasks at once. Those
|
|
1770
1790
|
* continuations are queued; an explicit user Continue remains immediate. */
|
|
1771
1791
|
deferForCapacity = false) {
|
|
1772
|
-
if (agentModelsLocked(this.repoRoot) && opts.model?.trim()) {
|
|
1792
|
+
if (agentModelsLocked(this.repoRoot) && (opts.model?.trim() || opts.effort?.trim())) {
|
|
1773
1793
|
return { ok: false, error: AGENT_MODELS_LOCKED_ERROR };
|
|
1774
1794
|
}
|
|
1775
1795
|
if (this.active.has(runId))
|
|
@@ -1804,7 +1824,10 @@ export class RunManager {
|
|
|
1804
1824
|
// run's current backend — `runContinuation` reads it off the record, later continuations
|
|
1805
1825
|
// default to it, and the header reflects the active engine. An empty model ('') clears the
|
|
1806
1826
|
// pin, letting the runner pick the model (auto).
|
|
1807
|
-
if (opts.runner !== undefined ||
|
|
1827
|
+
if (opts.runner !== undefined ||
|
|
1828
|
+
opts.model !== undefined ||
|
|
1829
|
+
opts.effort !== undefined ||
|
|
1830
|
+
opts.agentProfile !== undefined) {
|
|
1808
1831
|
// Guard the pairing before persisting anything: the model override applies to the runner
|
|
1809
1832
|
// this continuation will actually use (`opts.runner ?? record.runner ?? 'claude'` — the
|
|
1810
1833
|
// same resolution `runContinuation` reads off the record). A model that is recognizably
|
|
@@ -1842,6 +1865,9 @@ export class RunManager {
|
|
|
1842
1865
|
: inheritedAccountIsForeign
|
|
1843
1866
|
? { agentProfile: undefined }
|
|
1844
1867
|
: {}),
|
|
1868
|
+
// Effort is shared vocabulary, not per-backend, so a runner switch keeps the pin.
|
|
1869
|
+
// Empty string clears it the same way `model: ''` clears auto.
|
|
1870
|
+
...(opts.effort !== undefined ? { effort: opts.effort === '' ? undefined : opts.effort } : {}),
|
|
1845
1871
|
});
|
|
1846
1872
|
}
|
|
1847
1873
|
// Everything that could refuse this continuation has now passed, so a pending usage-limit
|
|
@@ -1976,6 +2002,8 @@ export class RunManager {
|
|
|
1976
2002
|
});
|
|
1977
2003
|
let stepCost = 0;
|
|
1978
2004
|
let turnText = '';
|
|
2005
|
+
let sawClaudeScheduleWakeup = false;
|
|
2006
|
+
let sawToolUse = false;
|
|
1979
2007
|
let sessionError;
|
|
1980
2008
|
const sink = this.makeUiSink(runId, stepId);
|
|
1981
2009
|
const onEvent = (event) => {
|
|
@@ -2010,6 +2038,10 @@ export class RunManager {
|
|
|
2010
2038
|
stepCost += event.usd;
|
|
2011
2039
|
this.store.updateStep(runId, stepId, { costUsd: stepCost });
|
|
2012
2040
|
}
|
|
2041
|
+
if (event.type === 'tool-call')
|
|
2042
|
+
sawToolUse = true;
|
|
2043
|
+
if (isClaudeScheduleWakeup(event, backend))
|
|
2044
|
+
sawClaudeScheduleWakeup = true;
|
|
2013
2045
|
if (event.type === 'turn-end') {
|
|
2014
2046
|
// Belt-and-braces: v2 `turn.completed` already flushed the delta
|
|
2015
2047
|
// coalescers; the v1 turn boundary flushes again (idempotent) so no
|
|
@@ -2023,8 +2055,14 @@ export class RunManager {
|
|
|
2023
2055
|
const askResult = sessionOpen && !done ? parseAskMarkerResult(turnText) : undefined;
|
|
2024
2056
|
const ask = askResult?.kind === 'valid' ? askResult.request : null;
|
|
2025
2057
|
const askRejection = askResult ? askMarkerRejection(askResult) : undefined;
|
|
2026
|
-
const monitoring = sessionOpen &&
|
|
2058
|
+
const monitoring = sessionOpen &&
|
|
2059
|
+
!done &&
|
|
2060
|
+
!ask &&
|
|
2061
|
+
(MONITORING_MARKER_RE.test(turnText.trimEnd()) || sawClaudeScheduleWakeup);
|
|
2062
|
+
const markerlessMidWork = askResult?.kind === 'none' && !monitoring && sawToolUse && !hasUserQuestion(turnText);
|
|
2027
2063
|
turnText = '';
|
|
2064
|
+
sawClaudeScheduleWakeup = false;
|
|
2065
|
+
sawToolUse = false;
|
|
2028
2066
|
if (askRejection)
|
|
2029
2067
|
this.store.appendEvent(runId, { type: 'note', message: askRejection, stepId });
|
|
2030
2068
|
if (done) {
|
|
@@ -2034,29 +2072,15 @@ export class RunManager {
|
|
|
2034
2072
|
state.session?.end();
|
|
2035
2073
|
return;
|
|
2036
2074
|
}
|
|
2075
|
+
let autoContinued = false;
|
|
2037
2076
|
if (sessionOpen) {
|
|
2038
|
-
|
|
2039
|
-
// keep going (bounded by MAX_AUTO_CONTINUES) instead of parking at `waiting`.
|
|
2040
|
-
const autoContinued = state.autonomous &&
|
|
2041
|
-
(state.autoContinues ?? 0) < MAX_AUTO_CONTINUES &&
|
|
2042
|
-
!state.cancelled &&
|
|
2043
|
-
(() => {
|
|
2044
|
-
const sent = state.session?.sendMessage([{ type: 'text', text: AUTONOMOUS_NUDGE }]);
|
|
2045
|
-
if (!sent)
|
|
2046
|
-
return false;
|
|
2047
|
-
state.autoContinues = (state.autoContinues ?? 0) + 1;
|
|
2048
|
-
this.store.appendEvent(runId, {
|
|
2049
|
-
type: 'note',
|
|
2050
|
-
message: `autonomous — continuing without pausing (${state.autoContinues}/${MAX_AUTO_CONTINUES})`,
|
|
2051
|
-
});
|
|
2052
|
-
return true;
|
|
2053
|
-
})();
|
|
2077
|
+
autoContinued = this.tryAutoContinueTurn(runId, state, state.autonomous === true || markerlessMidWork);
|
|
2054
2078
|
if (!autoContinued) {
|
|
2055
2079
|
// `CEZ:ASK` → park `waiting` (attention) AND surface the structured
|
|
2056
|
-
// question as an ask card (#473). `CEZ:MONITORING`
|
|
2057
|
-
// `running`/`activity:'monitoring'`
|
|
2058
|
-
//
|
|
2059
|
-
// nudge above still wins over either.
|
|
2080
|
+
// question as an ask card (#473). `CEZ:MONITORING` or Claude's native
|
|
2081
|
+
// `ScheduleWakeup` → non-attention `running`/`activity:'monitoring'`
|
|
2082
|
+
// (#490, #46). Both free the slot; only genuine user waits keep the
|
|
2083
|
+
// idle timer. The autonomous nudge above still wins over either.
|
|
2060
2084
|
if (ask)
|
|
2061
2085
|
emitAskRequested(sink, ask);
|
|
2062
2086
|
if (monitoring) {
|
|
@@ -2086,7 +2110,7 @@ export class RunManager {
|
|
|
2086
2110
|
if (this.store.getRun(runId)?.autoResumeAttempts !== undefined) {
|
|
2087
2111
|
this.store.updateRun(runId, { autoResumeAttempts: undefined });
|
|
2088
2112
|
}
|
|
2089
|
-
appendHandoffHeartbeat(this.dataDir, runId, `turn complete — status=${monitoring ? 'monitoring' : sessionOpen ? 'waiting' : 'running'}`);
|
|
2113
|
+
appendHandoffHeartbeat(this.dataDir, runId, `turn complete — status=${autoContinued ? 'running' : monitoring ? 'monitoring' : sessionOpen ? 'waiting' : 'running'}`);
|
|
2090
2114
|
}
|
|
2091
2115
|
};
|
|
2092
2116
|
// Backend + model come off the record: the run's current backend by default, or the
|
|
@@ -2196,6 +2220,7 @@ export class RunManager {
|
|
|
2196
2220
|
additionalDirectories: agentDirectories(join(this.dataDir, 'runs'), continueProfile.env),
|
|
2197
2221
|
env: continueProfile.env,
|
|
2198
2222
|
model: continueModel,
|
|
2223
|
+
effort: agentModelsLocked(this.repoRoot) ? undefined : record?.effort,
|
|
2199
2224
|
sessionId,
|
|
2200
2225
|
resume: sessionId !== undefined,
|
|
2201
2226
|
timeoutMs: 0,
|
|
@@ -2587,6 +2612,8 @@ export class RunManager {
|
|
|
2587
2612
|
const startTokens = stepRecord?.tokensUsed ?? 0;
|
|
2588
2613
|
let stepCost = stepRecord?.costUsd ?? 0;
|
|
2589
2614
|
let turnText = '';
|
|
2615
|
+
let sawClaudeScheduleWakeup = false;
|
|
2616
|
+
let sawToolUse = false;
|
|
2590
2617
|
let sessionError;
|
|
2591
2618
|
const sink = this.makeUiSink(runId, step.id);
|
|
2592
2619
|
const onEvent = (event) => {
|
|
@@ -2622,6 +2649,10 @@ export class RunManager {
|
|
|
2622
2649
|
stepCost += event.usd;
|
|
2623
2650
|
this.store.updateStep(runId, step.id, { costUsd: stepCost });
|
|
2624
2651
|
}
|
|
2652
|
+
if (event.type === 'tool-call')
|
|
2653
|
+
sawToolUse = true;
|
|
2654
|
+
if (isClaudeScheduleWakeup(event, backend))
|
|
2655
|
+
sawClaudeScheduleWakeup = true;
|
|
2625
2656
|
if (event.type === 'turn-end') {
|
|
2626
2657
|
// v2 `turn.completed` already flushed the coalescers; the v1 turn
|
|
2627
2658
|
// boundary flushes again (idempotent) as a backstop.
|
|
@@ -2638,8 +2669,11 @@ export class RunManager {
|
|
|
2638
2669
|
sessionOpen &&
|
|
2639
2670
|
!done &&
|
|
2640
2671
|
!ask &&
|
|
2641
|
-
MONITORING_MARKER_RE.test(turnText.trimEnd());
|
|
2672
|
+
(MONITORING_MARKER_RE.test(turnText.trimEnd()) || sawClaudeScheduleWakeup);
|
|
2673
|
+
const markerlessMidWork = askResult?.kind === 'none' && !monitoring && sawToolUse && !hasUserQuestion(turnText);
|
|
2642
2674
|
turnText = '';
|
|
2675
|
+
sawClaudeScheduleWakeup = false;
|
|
2676
|
+
sawToolUse = false;
|
|
2643
2677
|
if (askRejection)
|
|
2644
2678
|
emit({ type: 'note', stepId: step.id, message: askRejection });
|
|
2645
2679
|
if (done) {
|
|
@@ -2651,33 +2685,36 @@ export class RunManager {
|
|
|
2651
2685
|
return;
|
|
2652
2686
|
}
|
|
2653
2687
|
const waiting = interactive && sessionOpen;
|
|
2688
|
+
let autoContinued = false;
|
|
2654
2689
|
if (waiting) {
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2690
|
+
autoContinued = this.tryAutoContinueTurn(runId, state, !ask && (state.autonomous === true || markerlessMidWork));
|
|
2691
|
+
if (!autoContinued) {
|
|
2692
|
+
// Turn over, session open. Either the ball is in the user's court
|
|
2693
|
+
// (`waiting`) — optionally with a structured `CEZ:ASK` question the
|
|
2694
|
+
// cockpit renders as an ask card (#473) — or the agent declared it is
|
|
2695
|
+
// still working through `CEZ:MONITORING` or Claude's native
|
|
2696
|
+
// `ScheduleWakeup`. Monitoring parks as `running` with no user-wait
|
|
2697
|
+
// idle timer, so the cockpit stays non-attention (#490, #46).
|
|
2698
|
+
if (ask)
|
|
2699
|
+
emitAskRequested(sink, ask);
|
|
2700
|
+
if (monitoring) {
|
|
2701
|
+
this.store.updateRun(runId, { status: 'running', activity: 'monitoring' });
|
|
2702
|
+
this.store.updateStep(runId, step.id, { status: 'running' });
|
|
2703
|
+
this.monitoring.add(runId);
|
|
2704
|
+
this.clearIdleTimer(state);
|
|
2705
|
+
this.armMonitoringWakeTimer(runId, state);
|
|
2706
|
+
}
|
|
2707
|
+
else {
|
|
2708
|
+
this.store.updateRun(runId, { status: 'waiting', activity: undefined });
|
|
2709
|
+
this.store.updateStep(runId, step.id, { status: 'waiting' });
|
|
2710
|
+
this.monitoring.delete(runId);
|
|
2711
|
+
this.clearMonitoringWakeTimer(state, runId);
|
|
2712
|
+
}
|
|
2713
|
+
this.waiting.add(runId);
|
|
2714
|
+
if (!monitoring)
|
|
2715
|
+
this.armIdleTimer(runId, state);
|
|
2716
|
+
this.releaseSlot(); // the freed slot can start a queued run right away — in any project
|
|
2676
2717
|
}
|
|
2677
|
-
this.waiting.add(runId);
|
|
2678
|
-
if (!monitoring)
|
|
2679
|
-
this.armIdleTimer(runId, state);
|
|
2680
|
-
this.releaseSlot(); // the freed slot can start a queued run right away — in any project
|
|
2681
2718
|
}
|
|
2682
2719
|
// The window is proven open — see the twin in `runContinuation`.
|
|
2683
2720
|
if (this.store.getRun(runId)?.autoResumeAttempts !== undefined) {
|
|
@@ -2685,7 +2722,7 @@ export class RunManager {
|
|
|
2685
2722
|
}
|
|
2686
2723
|
// Cez's own heartbeat — the handoff stays current even when the
|
|
2687
2724
|
// agent forgets to write (spec 007).
|
|
2688
|
-
appendHandoffHeartbeat(this.dataDir, runId, `turn complete — status=${monitoring ? 'monitoring' : waiting ? 'waiting' : 'running'}`);
|
|
2725
|
+
appendHandoffHeartbeat(this.dataDir, runId, `turn complete — status=${autoContinued ? 'running' : monitoring ? 'monitoring' : waiting ? 'waiting' : 'running'}`);
|
|
2689
2726
|
}
|
|
2690
2727
|
};
|
|
2691
2728
|
const stepBackend = step.runner ?? taskBackend;
|
|
@@ -2747,6 +2784,9 @@ export class RunManager {
|
|
|
2747
2784
|
additionalDirectories: agentDirectories(join(this.dataDir, 'runs'), stepProfile.env),
|
|
2748
2785
|
env: stepProfile.env,
|
|
2749
2786
|
model: backendModel,
|
|
2787
|
+
effort: agentModelsLocked(this.repoRoot)
|
|
2788
|
+
? undefined
|
|
2789
|
+
: this.store.getRun(runId)?.effort ?? input.effort,
|
|
2750
2790
|
sessionId,
|
|
2751
2791
|
// Interactive sessions have no wall clock — the idle timer rules.
|
|
2752
2792
|
timeoutMs: interactive ? 0 : undefined,
|
|
@@ -2809,6 +2849,23 @@ export class RunManager {
|
|
|
2809
2849
|
emitLive: (event) => this.store.emitEphemeral(runId, { ...event, stepId }),
|
|
2810
2850
|
});
|
|
2811
2851
|
}
|
|
2852
|
+
/** Continue autonomous runs and markerless tool turns through one bounded path. */
|
|
2853
|
+
tryAutoContinueTurn(runId, state, shouldContinue) {
|
|
2854
|
+
if (!shouldContinue || (state.autoContinues ?? 0) >= MAX_AUTO_CONTINUES) {
|
|
2855
|
+
return false;
|
|
2856
|
+
}
|
|
2857
|
+
if (state.cancelled)
|
|
2858
|
+
return false;
|
|
2859
|
+
const sent = state.session?.sendMessage([{ type: 'text', text: AUTONOMOUS_NUDGE }]);
|
|
2860
|
+
if (!sent)
|
|
2861
|
+
return false;
|
|
2862
|
+
state.autoContinues = (state.autoContinues ?? 0) + 1;
|
|
2863
|
+
this.store.appendEvent(runId, {
|
|
2864
|
+
type: 'note',
|
|
2865
|
+
message: `${state.autonomous ? 'autonomous' : 'work still in progress'} — continuing without pausing (${state.autoContinues}/${MAX_AUTO_CONTINUES})`,
|
|
2866
|
+
});
|
|
2867
|
+
return true;
|
|
2868
|
+
}
|
|
2812
2869
|
/** Native backend asks arrive before turn-end. Persist and park immediately
|
|
2813
2870
|
* so the cockpit shows attention and the run releases its workspace slot. */
|
|
2814
2871
|
handleRunnerUiEvent(runId, state, sink, event) {
|