Skip to content

Commit 18d810c

Browse files
feat(session): add app mode preference to session creation
- Add appMode field to session contracts (coding | work) - Add server-side validation for appMode in session operation - Wire appModePreference through create-application and main.tsx - Carry appMode into task-session-workflows at session creation - Add mode selection UI in settings with accessible radiogroup - Refactor AgentAvatar size mapping into a constant record - Auto-select first agent in management and reduce detail avatar to small - Enable independent scrolling for agent list and detail panels - Reduce usage popover skeleton rows from 8 to 4 for size stability
1 parent cfecdb8 commit 18d810c

29 files changed

Lines changed: 563 additions & 59 deletions

‎.plan/workspace-browser-tab/complete/workspace-browser-tab.acceptance.json‎

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
},
1515
"observed": "the run's selection points at the page the Agent opened, the runtime publishes it, and the strip's reconciliation makes it the active panel tab",
1616
"result": "pass",
17-
"at": "2026-11-04T05:11:13.237Z",
17+
"at": "2026-11-04T05:25:54.616Z",
1818
"os": "linux 7.0.0-38-generic",
1919
"suite": "workspace-browser-tab"
2020
},
@@ -33,7 +33,7 @@
3333
},
3434
"observed": "the page is at the requested url and the frame stream follows the page it opened",
3535
"result": "pass",
36-
"at": "2026-11-04T05:11:14.418Z",
36+
"at": "2026-11-04T05:25:55.809Z",
3737
"os": "linux 7.0.0-38-generic",
3838
"suite": "workspace-browser-tab"
3939
},
@@ -52,7 +52,7 @@
5252
},
5353
"observed": "the action runs on the run's selection, and a reference recorded before the page moved is refused",
5454
"result": "pass",
55-
"at": "2026-11-04T05:11:15.288Z",
55+
"at": "2026-11-04T05:25:56.711Z",
5656
"os": "linux 7.0.0-38-generic",
5757
"suite": "workspace-browser-tab"
5858
},
@@ -71,7 +71,7 @@
7171
},
7272
"observed": "the Agent's page and the person's page are different, and each shows its own picture",
7373
"result": "pass",
74-
"at": "2026-11-04T05:11:15.350Z",
74+
"at": "2026-11-04T05:25:56.789Z",
7575
"os": "linux 7.0.0-38-generic",
7676
"suite": "workspace-browser-tab"
7777
},
@@ -90,7 +90,7 @@
9090
},
9191
"observed": "the run's selection becomes the person's page, so the Agent can act on it",
9292
"result": "pass",
93-
"at": "2026-11-04T05:11:16.257Z",
93+
"at": "2026-11-04T05:25:57.703Z",
9494
"os": "linux 7.0.0-38-generic",
9595
"suite": "workspace-browser-tab"
9696
},
@@ -109,7 +109,7 @@
109109
},
110110
"observed": "the input reaches the person's page, not the Agent's",
111111
"result": "pass",
112-
"at": "2026-11-04T05:11:17.095Z",
112+
"at": "2026-11-04T05:25:58.524Z",
113113
"os": "linux 7.0.0-38-generic",
114114
"suite": "workspace-browser-tab"
115115
},
@@ -128,7 +128,7 @@
128128
},
129129
"observed": "the tab becomes that page, and the url is shown read-only in the toolbar",
130130
"result": "pass",
131-
"at": "2026-11-04T05:11:17.130Z",
131+
"at": "2026-11-04T05:25:58.550Z",
132132
"os": "linux 7.0.0-38-generic",
133133
"suite": "workspace-browser-tab"
134134
},
@@ -147,7 +147,7 @@
147147
},
148148
"observed": "the page is released, and the runtime's page set follows the strip",
149149
"result": "pass",
150-
"at": "2026-11-04T05:11:17.919Z",
150+
"at": "2026-11-04T05:25:59.342Z",
151151
"os": "linux 7.0.0-38-generic",
152152
"suite": "workspace-browser-tab"
153153
},
@@ -166,7 +166,7 @@
166166
},
167167
"observed": "the page moves through its own history, and the generation follows",
168168
"result": "pass",
169-
"at": "2026-11-04T05:11:20.581Z",
169+
"at": "2026-11-04T05:26:01.984Z",
170170
"os": "linux 7.0.0-38-generic",
171171
"suite": "workspace-browser-tab"
172172
},
@@ -185,7 +185,7 @@
185185
},
186186
"observed": "the Agent's open_tab and the person's launcher path are both refused with browser_surface_not_authorized",
187187
"result": "pass",
188-
"at": "2026-11-04T05:11:20.582Z",
188+
"at": "2026-11-04T05:26:01.986Z",
189189
"os": "linux 7.0.0-38-generic",
190190
"suite": "workspace-browser-tab"
191191
},
@@ -204,7 +204,7 @@
204204
},
205205
"observed": "every action except open_tab is refused with browser_target_unknown",
206206
"result": "pass",
207-
"at": "2026-11-04T05:11:20.603Z",
207+
"at": "2026-11-04T05:26:02.010Z",
208208
"os": "linux 7.0.0-38-generic",
209209
"suite": "workspace-browser-tab"
210210
},
@@ -223,7 +223,7 @@
223223
},
224224
"observed": "its pages are released and no page is left behind",
225225
"result": "pass",
226-
"at": "2026-11-04T05:11:21.384Z",
226+
"at": "2026-11-04T05:26:02.796Z",
227227
"os": "linux 7.0.0-38-generic",
228228
"suite": "workspace-browser-tab"
229229
},
@@ -242,7 +242,7 @@
242242
},
243243
"observed": "both are addressable, and the strip shows both",
244244
"result": "pass",
245-
"at": "2026-11-04T05:11:22.304Z",
245+
"at": "2026-11-04T05:26:03.743Z",
246246
"os": "linux 7.0.0-38-generic",
247247
"suite": "workspace-browser-tab"
248248
},
@@ -261,7 +261,7 @@
261261
},
262262
"observed": "its generation advances, and a reference recorded against the old generation is refused — on every tab, not only the first",
263263
"result": "pass",
264-
"at": "2026-11-04T05:11:23.227Z",
264+
"at": "2026-11-04T05:26:04.684Z",
265265
"os": "linux 7.0.0-38-generic",
266266
"suite": "workspace-browser-tab"
267267
}

‎packages/local-runtime-v2/src/application/agent/management-application.ts‎

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ interface IncludeFlags {
2626
readonly identity: boolean;
2727
readonly persona: boolean;
2828
readonly systemPrompt: boolean;
29+
readonly model: boolean;
2930
}
3031

3132
/** V2 Agent RPC adapter. All persistence and root sequencing stays in AgentApplication. */
@@ -63,7 +64,10 @@ export class AgentManagementApplication {
6364
includeContent: true,
6465
})
6566
: agent;
66-
return toAgentDetail(detail, include);
67+
const model = include.model
68+
? (await application.getConfigDocument(agent.requestRef)).configured.model
69+
: undefined;
70+
return toAgentDetail(detail, include, model);
6771
}),
6872
);
6973
return { agents };
@@ -127,7 +131,10 @@ export class AgentManagementApplication {
127131
const agent = await application.get(name, {
128132
includeContent: include.persona || include.systemPrompt,
129133
});
130-
return { agent: toAgentDetail(agent, include) };
134+
const model = include.model
135+
? (await application.getConfigDocument(name)).configured.model
136+
: undefined;
137+
return { agent: toAgentDetail(agent, include, model) };
131138
});
132139
}
133140

@@ -156,7 +163,10 @@ export class AgentManagementApplication {
156163
const detail = await application.get(updated.requestRef, {
157164
includeContent: true,
158165
});
159-
return { success: true, agent: toAgentDetail(detail, ALL_INCLUDE) };
166+
const model = (
167+
await application.getConfigDocument(updated.requestRef)
168+
).configured.model;
169+
return { success: true, agent: toAgentDetail(detail, ALL_INCLUDE, model) };
160170
});
161171
}
162172

@@ -189,6 +199,7 @@ const ALL_INCLUDE: IncludeFlags = {
189199
identity: true,
190200
persona: true,
191201
systemPrompt: true,
202+
model: true,
192203
};
193204

194205
function readInclude(raw: string | undefined): IncludeFlags {
@@ -207,6 +218,7 @@ function readInclude(raw: string | undefined): IncludeFlags {
207218
tokens.has("prompt") ||
208219
tokens.has("system_prompt") ||
209220
tokens.has("systemprompt"),
221+
model: all || tokens.has("model"),
210222
};
211223
}
212224

@@ -221,10 +233,12 @@ function toAgentDetail(
221233
readonly systemPrompt?: string;
222234
},
223235
include: IncludeFlags,
236+
model?: string,
224237
): AgentDetail {
225238
return {
226239
...toAgentIdentity(agent, include),
227240
...toAgentContent(agent, include),
241+
...(include.model && model ? { model } : {}),
228242
};
229243
}
230244

‎packages/protocol/src/local.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1386,6 +1386,7 @@ export interface AgentDetail {
13861386
description?: string;
13871387
persona?: string;
13881388
systemPrompt?: string;
1389+
model?: string;
13891390
}
13901391

13911392
export interface ListAgentsInput {

‎packages/webui/src/client/application/create-application.ts‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,13 @@ export interface WebuiApplicationDeps {
196196
* Read when a session is created, so the choice takes effect on the next
197197
* session rather than on a running one — the runtime reads it at creation.
198198
*/
199+
/**
200+
* 设置 › 通用 › Agent 控制权限 › 自动打开浏览器面板, injected from the
201+
* composition root: the shell may not read platform storage itself (plan §5.3).
202+
*/
203+
readonly browserAutoOpen?: {
204+
readonly read: () => boolean;
205+
};
199206
readonly appModePreference?: {
200207
readonly read: () => "coding" | "work";
201208
};
@@ -278,6 +285,10 @@ export interface WebuiApplication {
278285
* ingress; `disposed` is terminal and refuses to restart.
279286
*/
280287
readonly state: () => WebuiApplicationLifecycleState;
288+
/** Whether a page the Agent starts brings the browser panel up with it. */
289+
readonly browserAutoOpen?: {
290+
readonly read: () => boolean;
291+
};
281292
/**
282293
* Install the assembly's routes and open the one event ingress.
283294
*
@@ -998,6 +1009,7 @@ export function createWebuiApplication(
9981009

9991010
return {
10001011
state: () => lifecycle,
1012+
...(deps.browserAutoOpen ? { browserAutoOpen: deps.browserAutoOpen } : {}),
10011013
disposalFailures: () => disposalFailures,
10021014
start: (options) => {
10031015
// A disposed instance is terminal: no hydration, no ingress, no second
Binary file not shown.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"source": "user-provided coral-octopus-3d-white.webm",
3+
"destination": "minimax-octopus-composer.webm",
4+
"description": "Animated transparent coral MiniMax octopus mascot for the WebUI composer."
5+
}

‎packages/webui/src/client/features/browser/ui/BrowserAuthorizationSwitches.public.tsx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -353,8 +353,8 @@ function BrowserInstallationKeyDialog({
353353
</WebuiButtonLink>
354354
) : (
355355
<p className="text-[13px] text-text_default_secondary">
356-
这个扩展还没有连接过这台主机,主机不知道它的选项页地址。请在浏览器的扩展管理页里找到「MiniMax Code Browser
357-
Bridge」,点「扩展选项」后粘贴密钥。
356+
这台主机还没有见过这个扩展的连接,不知道它的选项页地址。请在浏览器的扩展管理页(edge://extensions
357+
或 chrome://extensions)里找到「MiniMax Code Browser Bridge」,点「扩展选项」后粘贴密钥。
358358
</p>
359359
)}
360360
</WebuiStack>

‎packages/webui/src/client/features/composer/ui/WebuiComposer.tsx‎

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,29 @@ export function WebuiComposer({
257257
}): ReactElement {
258258

259259
const { dom } = useWebuiBrowserCapabilities();
260+
const composerMascotVideoRef = useRef<HTMLVideoElement | null>(null);
261+
const [prefersReducedMotion, setPrefersReducedMotion] = useState(() =>
262+
typeof window !== "undefined" &&
263+
typeof window.matchMedia === "function" &&
264+
window.matchMedia("(prefers-reduced-motion: reduce)").matches,
265+
);
266+
useEffect(() => {
267+
if (typeof window.matchMedia !== "function") return undefined;
268+
const query = window.matchMedia("(prefers-reduced-motion: reduce)");
269+
const sync = () => setPrefersReducedMotion(query.matches);
270+
sync();
271+
query.addEventListener("change", sync);
272+
return () => query.removeEventListener("change", sync);
273+
}, []);
274+
useEffect(() => {
275+
const video = composerMascotVideoRef.current;
276+
if (!video) return;
277+
if (prefersReducedMotion) {
278+
video.pause();
279+
return;
280+
}
281+
void video.play().catch(() => undefined);
282+
}, [prefersReducedMotion]);
260283
const { stream, sending, transcript } = useWebuiSessionState(sessionId);
261284
const turnCommands = useWebuiSessionCommands(sessionId);
262285
// The per-session effects registry the shell provides. The composer registers
@@ -1086,11 +1109,16 @@ export function WebuiComposer({
10861109
<WebuiStack gap="compact" align="center" className="message-input-home-container rounded-[20px] bg-bg_default_scrim pb-2">
10871110
<div className="w-full rounded-[20px] border border-border_default bg-bg_grouped_secondary_elevated p-3 webui-composer-card">
10881111
{sessionLayout && sessionId ? (
1089-
<img
1112+
<video
1113+
ref={composerMascotVideoRef}
10901114
className="webui-composer-mascot"
1091-
src="/assets/img/minimax-octopus-composer.png"
1092-
alt=""
1115+
src="/assets/img/minimax-octopus-composer.webm"
10931116
aria-hidden="true"
1117+
autoPlay={!prefersReducedMotion}
1118+
loop
1119+
muted
1120+
playsInline
1121+
preload="auto"
10941122
draggable="false"
10951123
/>
10961124
) : null}

‎packages/webui/src/client/features/composer/ui/composer.css‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
.webui-composer-mascot {
1818
position: absolute;
1919
z-index: 1;
20-
top: -50px;
21-
right: 8px;
20+
top: -90px;
21+
right: var(--spacing_24);
2222
width: 60px;
2323
height: auto;
2424
pointer-events: none;

‎packages/webui/src/client/features/plugins/application/plugin-workflows.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,7 @@ export function createWebuiPluginWorkflows(deps: {
579579
const result = await call("listAgents", {
580580
limit: 100,
581581
search: query || undefined,
582-
include: "identity,persona,system_prompt",
582+
include: "identity,persona,system_prompt,model",
583583
});
584584
const base = webuiPluginRows(result, "agents");
585585
const rows = await Promise.all(

0 commit comments

Comments
 (0)