Add whisper docker dependency controls to dashboard

This commit is contained in:
William Valentin
2026-02-22 19:48:27 -08:00
parent 453eb264df
commit abaa9be3f1
9 changed files with 501 additions and 8 deletions
+62 -1
View File
@@ -11,7 +11,7 @@ import { createCanvasHandlers } from './canvas.js';
import { createConfigHandlers, redactConfig } from './config.js';
import { createPairingHandlers } from './pairing.js';
import type { LocalBackendStatus, LocalBackendControlResult } from './localBackends.js';
import type { DockerDependencyStatus } from './dockerDependencies.js';
import type { DockerDependencyStatus, DockerDependencyControlResult } from './dockerDependencies.js';
import { PairingManager } from '../../channels/pairing.js';
import { LaneQueue } from '../lane-queue.js';
import { CanvasStore } from '../canvas-store.js';
@@ -301,6 +301,7 @@ describe('system handlers', () => {
health: 'healthy',
statusText: 'Up 10 minutes (healthy)',
containerName: 'flynn-whisper-server-1',
availableActions: ['restart', 'stop', 'update'],
},
]));
const handlers = createSystemHandlers({
@@ -314,6 +315,66 @@ describe('system handlers', () => {
expect(getPath(result.result, 'dependencies', '0', 'state')).toBe('running');
});
it('system.dockerDependencyControl validates required params', async () => {
const handlers = createSystemHandlers({
...deps,
controlDockerDependency: vi.fn(),
});
const missingDependency = await handlers['system.dockerDependencyControl']({
id: 44,
method: 'system.dockerDependencyControl',
params: { action: 'restart' },
}) as GatewayError;
expect(missingDependency.error.code).toBe(ErrorCode.InvalidRequest);
const missingAction = await handlers['system.dockerDependencyControl']({
id: 45,
method: 'system.dockerDependencyControl',
params: { dependency: 'whisper' },
}) as GatewayError;
expect(missingAction.error.code).toBe(ErrorCode.InvalidRequest);
const badAction = await handlers['system.dockerDependencyControl']({
id: 46,
method: 'system.dockerDependencyControl',
params: { dependency: 'whisper', action: 'reload' },
}) as GatewayError;
expect(badAction.error.code).toBe(ErrorCode.InvalidRequest);
});
it('system.dockerDependencyControl forwards action to callback', async () => {
const controlDockerDependency = vi.fn(async (): Promise<DockerDependencyControlResult> => ({
dependency: 'whisper' as const,
action: 'restart' as const,
status: {
id: 'whisper' as const,
name: 'Whisper (whisper.cpp)',
service: 'whisper-server',
configured: true,
state: 'running',
health: 'healthy',
statusText: 'running (healthy)',
containerName: 'whisper-server',
availableActions: ['restart', 'stop', 'update'],
},
message: 'Restarted whisper-server container.',
}));
const handlers = createSystemHandlers({
...deps,
controlDockerDependency,
});
const req: GatewayRequest = {
id: 47,
method: 'system.dockerDependencyControl',
params: { dependency: 'whisper', action: 'restart' },
};
const result = await handlers['system.dockerDependencyControl'](req) as GatewayResponse;
expect(controlDockerDependency).toHaveBeenCalledWith('whisper', 'restart');
expect(getPath(result.result, 'status', 'state')).toBe('running');
expect(getPath(result.result, 'action')).toBe('restart');
});
it('system.presence returns empty result when getPresence is not provided', async () => {
const req: GatewayRequest = { id: 4, method: 'system.presence' };
const result = await handlers['system.presence'](req) as GatewayResponse;