Merge branch 'feat/local-model-harness-choice' into feat/local-model-skill-agents

This commit is contained in:
Codeman maintainer committed 2026-11-11 10:24:06 +01:00
commit d04fb63837
5 files changed
+117 -12

No files matched your search

+65
View File
@@ -510,6 +510,71 @@ describe('the local model window (real Chromium)', () => {
expect(overflow).toBeLessThanOrEqual(0);
});
it('the coding agents: chips that wrap inside the window at every width, the install command included', async () => {
const agents = [
{ cli: 'opencode', cliLabel: 'OpenCode', default: true, status: 'ready', actions: ['start-session'] },
{
cli: 'claude',
cliLabel: 'Claude Code',
default: false,
status: 'ready',
slowFirstTurn: true,
actions: ['start-session'],
},
{
cli: 'pi',
cliLabel: 'Pi',
default: false,
status: 'installable',
installCommand: 'npm install -g --ignore-scripts @earendil-works/pi-coding-agent',
actions: ['install'],
},
{ cli: 'deepseek', cliLabel: 'DeepSeek', default: false, status: 'setup-needed', actions: [] },
];
const answer = {
...INSTALLED,
install: {
...INSTALLED.install,
harnesses: agents,
actions: [...INSTALLED.install.actions, 'install-agent'],
},
};
for (const [width, height] of [
[1440, 900],
[390, 844],
[320, 640],
]) {
await load(width, height, answer);
await open();
// The agent that is not on this Mac: its command is the longest line of the block.
await p.locator('.lm-agent', { hasText: 'Pi' }).click();
const seen = await p.evaluate(() => {
const frame = document.querySelector('.local-model-window')!.getBoundingClientRect();
const body = document.getElementById('localModelWindowBody')!;
const outside = [...document.querySelectorAll('.lm-agent, .lm-agents .lm-command, .lm-buttons button')]
.map((el) => el.getBoundingClientRect())
.filter((box) => box.width > 0 && (box.left < frame.left - 0.5 || box.right > frame.right + 0.5)).length;
const chips = [...document.querySelectorAll<HTMLElement>('.lm-agent')];
return {
chips: chips.length,
outside,
sideways: body.scrollWidth - body.clientWidth,
checked: document.querySelector('.lm-agent[aria-checked="true"] .lm-agent-name')!.textContent,
tabStops: chips.filter((chip) => chip.tabIndex === 0).length,
main: document.querySelector('.lm-buttons .wt-btn-primary')!.textContent,
};
});
expect(seen, `${width}px`).toEqual({
chips: 4,
outside: 0,
sideways: 0,
checked: 'Pi',
tabStops: 1,
main: 'Install Pi',
});
}
});
it('paints above App Settings when it is opened from there', async () => {
await load(1440);
await p.evaluate(() => document.getElementById('appSettingsModal')!.classList.add('active'));
+25 -2
View File
@@ -2898,7 +2898,7 @@ describe('the coding agents of an installed model', () => {
expect(frameOf(page.body).querySelectorAll('.lm-buttons .wt-btn-primary')).toHaveLength(1);
});
it('starts the session with the selected agent, and this device remembers the choice', async () => {
it('starts the session with the selected agent, and this device remembers the agent it started', async () => {
const page = mount();
const { app } = await opened(page, WITH_AGENTS);
const launch = launcher(app);
@@ -2907,11 +2907,13 @@ describe('the coding agents of an installed model', () => {
// What the catalogue says about its first answer.
expect(texts(page.body, '.lm-agent-about .lm-aside')).toEqual(['The first answer can take minutes.']);
expect(verbs(app)).toEqual([]);
// Looking at a chip is not a choice yet.
expect(page.dom.window.localStorage.getItem('codeman-local-model-agent')).toBeNull();
press(page.body, 'Start a session');
await settle();
expect(launch).toHaveBeenCalledWith('claude', 'local-ollama');
// The window opened again later: the last choice stands, not the default.
// The window opened again later: the agent last started stands, not the default.
expect(page.dom.window.localStorage.getItem('codeman-local-model-agent')).toBe('claude');
const again = page.newApp(ok(WITH_AGENTS));
await again.loadLocalModel();
@@ -2920,6 +2922,27 @@ describe('the coding agents of an installed model', () => {
expect(chosen(page)).toBe('Claude Code');
});
it('a chip that was only looked at never hides Start a session when the window is opened again', async () => {
const page = mount();
const { app } = await opened(page, WITH_AGENTS);
pick(page, 'DeepSeek');
expect(buttons(page.body)).toEqual(['Remove', 'Stop']);
app.closeLocalModelWindow();
app.openLocalModelWindow();
await settle();
// Back on the default agent, with the main action in reach.
expect(chosen(page)).toBe('OpenCode');
expect(buttons(page.body)).toEqual(['Remove', 'Stop', 'Start a session']);
// And an agent that was started once and has since been uninstalled does not win either.
page.dom.window.localStorage.setItem('codeman-local-model-agent', 'pi');
app.closeLocalModelWindow();
app.openLocalModelWindow();
await settle();
expect(chosen(page)).toBe('OpenCode');
expect(buttons(page.body)).toEqual(['Remove', 'Stop', 'Start a session']);
});
it('a remembered agent the server no longer lists falls back to the default', async () => {
const page = mount();
page.dom.window.localStorage.setItem('codeman-local-model-agent', 'gone');