mirror of
https://github.com/block/buzz.git
synced 2026-10-28 21:11:48 +00:00
fix(beehive): keep compact provider status and recovery complete
Signed-off-by: Logan Johnson <loganj@squareup.com>
This commit is contained in:
@@ -112,7 +112,7 @@ export class ProviderPanel {
|
||||
if (type === 'openai-compat') fields.push({ label: 'Endpoint', value: row?.endpoint ?? 'https://' }, { label: 'Wire', value: row?.wire ?? 'auto', choices: ['auto', 'chat', 'responses'] });
|
||||
fields.push({ label: row ? 'API key (blank keeps saved)' : 'API key', secret: true });
|
||||
}
|
||||
const result = await this.form(row ? 'EDIT PROVIDER' : 'ADD PROVIDER', fields);
|
||||
const result = await this.form(row ? 'EDIT PROVIDER' : 'CONFIGURE PROVIDER', fields);
|
||||
if (!result || generation !== this.generation) return;
|
||||
await this.client.request({ action: 'save', provider: row?.id ?? `type:${type}`, revision, values: { type, name: result.Name!, endpoint: result['Workspace (DATABRICKS_HOST)'] ?? result.Endpoint ?? '', wire: result.Wire ?? 'auto' } });
|
||||
}
|
||||
@@ -165,14 +165,27 @@ export class ProviderPanel {
|
||||
const commands = this.commands();
|
||||
const compact = this.renderer.height < 28;
|
||||
const ownsResult = this.snapshot.resultTarget === this.selected;
|
||||
const info = row ? [`State ${row.state}${row.modelCount === undefined ? '' : ` · ${row.modelCount} models`}`, `Type ${row.type}`, ...(row.endpoint ? [`Connects to ${row.endpoint}`] : []), '', row.detail] : ['Reload saved providers and check their model catalogs. No owner sign-in is required.'];
|
||||
const wrap = (lines: string[]) => lines.flatMap(line => { const result: string[] = []; for (let start = 0; start < Math.max(1, line.length); start += width) result.push(line.slice(start, start + width)); return result; });
|
||||
const modelCount = row?.modelCount === undefined ? '' : `${row.modelCount} ${row.modelCount === 1 ? 'model' : 'models'}`;
|
||||
const info = row ? [`State ${row.state}${modelCount ? ` · ${modelCount}` : ''}`, `Type ${row.type}`, ...(row.endpoint ? [`Connects to ${row.endpoint}`] : []), '', row.detail] : ['Reload saved providers and check their model catalogs. No owner sign-in is required.'];
|
||||
const wrap = (lines: string[]) => lines.flatMap(line => {
|
||||
const result: string[] = [];
|
||||
while (line.length > width) {
|
||||
const space = line.lastIndexOf(' ', width);
|
||||
const end = space > 0 ? space : width;
|
||||
result.push(line.slice(0, end)); line = line.slice(end).trimStart();
|
||||
}
|
||||
result.push(line); return result;
|
||||
});
|
||||
const fullDetails = wrap(info);
|
||||
// Reserve every action and a result viewport before allocating detail rows.
|
||||
this.detailTitle.top = 1;
|
||||
const detailTop = compact ? 2 : 3;
|
||||
const detailCapacity = compact ? 2 : Math.max(1, height - commands.length - 10);
|
||||
const summary = compact ? wrap(row ? [`${row.state}${row.modelCount === undefined ? '' : ` · ${row.modelCount} models`}`, row.detail] : info).slice(0, detailCapacity) : fullDetails.slice(0, detailCapacity);
|
||||
const compactSummary = row ? [
|
||||
`${row.state}${modelCount ? ` · ${modelCount}` : ''}`,
|
||||
row.state === 'Connected' ? 'Execution not tested' : row.state === 'Failed' ? 'Catalog unavailable' : row.state === 'Checking…' ? 'Checking model access' : row.id.startsWith('type:') ? 'Select Configure to get started' : 'Model access not checked',
|
||||
] : ['Reload saved accounts', 'Check model access'];
|
||||
const summary = compact ? compactSummary : fullDetails.slice(0, detailCapacity);
|
||||
this.details.top = detailTop; this.details.width = width; this.details.height = summary.length; this.details.content = summary.join('\n');
|
||||
this.actionTitle.top = detailTop + summary.length + (compact ? 0 : 1); this.actionTitle.width = width;
|
||||
this.actionTitle.content = 'AVAILABLE ACTIONS ' + '─'.repeat(Math.max(1, width - 18));
|
||||
@@ -186,9 +199,13 @@ export class ProviderPanel {
|
||||
const resultTop = this.actionStart + commands.length;
|
||||
const resultCapacity = Math.max(1, height - 2 - resultTop);
|
||||
this.resultPageSize = resultCapacity;
|
||||
const recovery = row?.state === 'Failed' ? row.type === 'databricks_v2'
|
||||
? 'Check workspace and network. Sign in to Databricks, then Refresh models.'
|
||||
: 'Check API key, endpoint, network and model access. Then Refresh models.' : undefined;
|
||||
const output = [
|
||||
...(recovery ? [recovery] : []),
|
||||
...(ownsResult && this.snapshot.message ? [`${this.snapshot.phase === 'error' ? 'FAILED' : this.snapshot.phase === 'busy' ? 'WORKING' : 'RESULT'}: ${this.snapshot.message}`] : []),
|
||||
...(compact || fullDetails.length > detailCapacity ? ['DETAILS', ...info] : []),
|
||||
...(compact ? row ? [`Type ${row.type}`, ...(row.endpoint ? [`Connects to ${row.endpoint}`] : [])] : [] : fullDetails.length > detailCapacity ? ['DETAILS', ...info] : []),
|
||||
];
|
||||
const wrapped = wrap(output);
|
||||
this.detailOffset = Math.min(this.detailOffset, Math.max(0, wrapped.length - resultCapacity));
|
||||
|
||||
@@ -64,7 +64,7 @@ test('minimum-size results and recovery text remain reachable; only the model co
|
||||
ui.mockInput.pressEnter(); ui.mockInput.pressTab();
|
||||
f.snapshot.resultTarget = 'p'; f.snapshot.phase = 'error'; f.snapshot.message = 'Denied. Check provider access. Reload before retrying.'; f.emit();
|
||||
await ui.renderOnce(); assert.match(ui.captureCharFrame(), /Denied/); assert.match(ui.captureCharFrame(), /retrying/);
|
||||
ui.mockInput.pressKey('\x1b[6~'); await ui.renderOnce(); assert.match(ui.captureCharFrame(), /State/);
|
||||
ui.mockInput.pressKey('\x1b[6~'); await ui.renderOnce(); assert.match(ui.captureCharFrame(), /Type/);
|
||||
f.snapshot.phase = 'idle'; f.snapshot.message = 'Models loaded.'; f.snapshot.rows[0]!.state = 'Connected'; f.snapshot.rows[0]!.modelCount = 2; f.emit();
|
||||
await ui.renderOnce(); assert.match(ui.captureCharFrame(), /Models loaded/);
|
||||
for (let i = 0; i < 12; i++) ui.mockInput.pressKey('\x1b[6~');
|
||||
@@ -248,3 +248,25 @@ for (const [width, height] of [[120, 40], [60, 20]]) test(`provider inventory ha
|
||||
assert.deepEqual(f.snapshot, before);
|
||||
} finally { shell.close(); }
|
||||
});
|
||||
|
||||
for (const [width, height] of [[120, 40], [60, 20]]) test(`provider status is complete before scrolling at ${width}x${height}`, async () => {
|
||||
const ui = await createTestRenderer({ width, height, exitOnCtrlC: false }), f = fixture();
|
||||
f.snapshot.rows[0]!.state = 'Connected'; f.snapshot.rows[0]!.modelCount = 1;
|
||||
f.snapshot.rows[0]!.detail = 'Model catalog reachable. Model execution has not been tested.';
|
||||
const shell = new OpenTuiShell(ui.renderer, f.inventory, undefined, f.client);
|
||||
try {
|
||||
for (let i = 0; i < 3; i++) ui.mockInput.pressArrow('right');
|
||||
ui.mockInput.pressEnter(); await ui.renderOnce();
|
||||
assert.match(ui.captureCharFrame(), /Connected · 1 model/);
|
||||
assert.doesNotMatch(ui.captureCharFrame(), /1 models/);
|
||||
if (height === 20) assert.match(ui.captureCharFrame(), /Execution not tested/);
|
||||
f.snapshot.rows[0]!.state = 'Failed'; delete f.snapshot.rows[0]!.modelCount;
|
||||
f.snapshot.rows[0]!.detail = 'Could not load models. Check the API key, endpoint, network and model access, then retry Refresh models.';
|
||||
f.snapshot.resultTarget = 'p'; f.snapshot.phase = 'error'; f.snapshot.message = 'Provider saved. Existing runs are unchanged. Model catalog failed.'; f.emit();
|
||||
await ui.renderOnce(); const frame = ui.captureCharFrame();
|
||||
assert.match(frame, /Check API key, endpoint/); assert.match(frame.replace(/[│\s]+/g, ' '), /Then Refresh models/);
|
||||
if (height === 20) { assert.match(frame, /Catalog unavailable/); assert.doesNotMatch(frame, /Check th|DETAILS/); }
|
||||
ui.mockInput.pressArrow('down'); ui.mockInput.pressTab(); ui.mockInput.pressEnter(); await ui.renderOnce();
|
||||
assert.match(ui.captureCharFrame(), /CONFIGURE PROVIDER/); assert.doesNotMatch(ui.captureCharFrame(), /ADD PROVIDER/);
|
||||
} finally { shell.close(); }
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user