Skip to content

Commit 4152fe5

Browse files
authored
Merge pull request #108 from esokullu/codex/cloud-noninteractive-preset
Bypass planning for managed cloud runs
2 parents 0f9f6d0 + dc858e7 commit 4152fe5

4 files changed

Lines changed: 97 additions & 2 deletions

File tree

src/chrome/src/agent/agent.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4382,7 +4382,12 @@ Rules: no prose intro, no conclusion, no "this screenshot shows...", no layout d
43824382
* Plan-before-Act gate: push user message, pin approved plan after it, or stop early.
43834383
*/
43844384
async _maybeRunPlannerGate(tabId, messages, enriched, onUpdate, mode, costState, runId, tabInfo = null, runOptions = {}) {
4385-
const plannerMode = this._isActionMode(mode) ? this._plannerMode() : 'off';
4385+
// Managed cloud runs have no interactive review channel. They must never
4386+
// enter the planner gate, even if the profile later enables planning for
4387+
// manual side-panel runs.
4388+
const plannerMode = this._isActionMode(mode) && runOptions?.cloudRun !== true
4389+
? this._plannerMode()
4390+
: 'off';
43864391
const runPlanner = plannerMode !== 'off';
43874392

43884393
// Snapshot prior turns for the planner digest BEFORE appending, then always

src/chrome/src/cloud-runs.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,11 @@ export function createCloudRunController({
182182
run.summary = result.summary || run.summary;
183183
}
184184
}
185+
if (type === 'plan_review' && run.status === 'running') {
186+
run.status = 'failed';
187+
run.error = 'Managed cloud runs cannot wait for interactive plan review.';
188+
agent.abort(run.tabId);
189+
}
185190
schedulePersist();
186191
}
187192

src/firefox/src/agent/agent.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3637,7 +3637,11 @@ Rules: no prose intro, no conclusion, no "this screenshot shows...", no layout d
36373637
}
36383638

36393639
async _maybeRunPlannerGate(tabId, messages, enriched, onUpdate, mode, costState, runId, tabInfo = null, runOptions = {}) {
3640-
const plannerMode = this._isActionMode(mode) ? this._plannerMode() : 'off';
3640+
// Keep managed cloud behavior aligned with Chrome: unattended runs cannot
3641+
// wait on a side-panel plan review that has no API response channel.
3642+
const plannerMode = this._isActionMode(mode) && runOptions?.cloudRun !== true
3643+
? this._plannerMode()
3644+
: 'off';
36413645
const runPlanner = plannerMode !== 'off';
36423646

36433647
// Snapshot prior turns for the planner digest BEFORE appending, then always

test/run.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4162,6 +4162,48 @@ test('cloud run controller uses the visible tab and persists terminal status', a
41624162
assert.equal(session.webbrainCloudRunSnapshots[0].status, 'completed');
41634163
});
41644164

4165+
test('cloud run controller fails immediately if an interactive plan review leaks through', async () => {
4166+
const session = {};
4167+
const tab = { id: 19, url: 'https://webbrain.one/', active: true, windowId: 3 };
4168+
let abortedTabId = null;
4169+
const agent = {
4170+
isRunning: () => false,
4171+
abort: tabId => { abortedTabId = tabId; },
4172+
processMessage: async (_tabId, _task, onUpdate) => {
4173+
onUpdate('plan_review', { planId: 'plan_unexpected' });
4174+
return '[Stopped by user]';
4175+
},
4176+
};
4177+
const controller = createCloudRunController({
4178+
chromeApi: {
4179+
tabs: {
4180+
query: async () => [tab],
4181+
get: async () => tab,
4182+
update: async () => tab,
4183+
},
4184+
windows: { update: async () => ({}) },
4185+
storage: {
4186+
local: { get: async () => ({ webbrainCloudBridgeEnabled: false }) },
4187+
session: {
4188+
get: async key => ({ [key]: session[key] || [] }),
4189+
set: async value => Object.assign(session, value),
4190+
},
4191+
},
4192+
runtime: { sendMessage: async () => ({ connected: false }) },
4193+
},
4194+
agent,
4195+
ensureOffscreen: async () => {},
4196+
makeRunId: () => 'run_plan_review',
4197+
});
4198+
4199+
await controller.startRun({ task: 'Complex unattended task' });
4200+
await new Promise(resolve => setTimeout(resolve, 0));
4201+
const completed = await controller.status({ run_id: 'run_plan_review' });
4202+
assert.equal(completed.status, 'failed');
4203+
assert.equal(completed.error, 'Managed cloud runs cannot wait for interactive plan review.');
4204+
assert.equal(abortedTabId, 19);
4205+
});
4206+
41654207
test('cloud run controller fails interrupted runs after service-worker restart', async () => {
41664208
const row = { runId: 'run_old', status: 'running', tabId: 2, task: 'Old task', updates: [], createdAt: '2020-01-01T00:00:00.000Z' };
41674209
const session = { webbrainCloudRunSnapshots: [row] };
@@ -21279,6 +21321,45 @@ test('planner gate: scheduled runs auto-approve plan review', async () => {
2127921321
});
2128021322
});
2128121323

21324+
test('planner gate: managed cloud runs bypass planning in Chrome and Firefox', async () => {
21325+
await withPlannerBrowserGlobals(async () => {
21326+
for (const [label, AgentClass] of [['chrome', AgentCh], ['firefox', AgentFx]]) {
21327+
const tabId = label === 'chrome' ? 9223 : 9224;
21328+
const agent = new AgentClass({ getActive: () => ({}) });
21329+
agent.setPlanBeforeActMode('strict');
21330+
agent.setPlanReviewSettings({ mode: 'always', confidenceThreshold: 0.99 });
21331+
agent.conversations.set(tabId, [{ role: 'system', content: 'system' }]);
21332+
let plannerCalls = 0;
21333+
agent._chatWithCostAllowance = async () => {
21334+
plannerCalls += 1;
21335+
return { content: plannerFixtureJson() };
21336+
};
21337+
agent._waitForPlanReview = async () => {
21338+
throw new Error('managed cloud run should never request interactive review');
21339+
};
21340+
21341+
const messages = agent.conversations.get(tabId);
21342+
const updates = [];
21343+
const outcome = await agent._maybeRunPlannerGate(
21344+
tabId,
21345+
messages,
21346+
{ role: 'user', content: 'complex cloud task' },
21347+
type => updates.push(type),
21348+
'act',
21349+
null,
21350+
null,
21351+
null,
21352+
{ cloudRun: true },
21353+
);
21354+
21355+
assert.equal(outcome.proceed, true, `${label} cloud run should proceed without planning`);
21356+
assert.equal(plannerCalls, 0, `${label} cloud run should not call the planner model`);
21357+
assert.equal(updates.includes('plan_review'), false, `${label} cloud run should not emit plan_review`);
21358+
assert.equal(messages.at(-1)?.content, 'complex cloud task', `${label} should retain the user turn`);
21359+
}
21360+
});
21361+
});
21362+
2128221363
test('sidepanel: restored plan review cards rebind approve and cancel actions', () => {
2128321364
for (const file of [
2128421365
'src/chrome/src/ui/sidepanel.js',

0 commit comments

Comments
 (0)