feat(KB-196): load extension providers for dashboard model selector

- Load pi extensions on dashboard startup to register custom model providers
- Include extension-provided models in the dashboard model selector
- Add comprehensive tests for extension model loading and error handling
- Create changeset for patch release fixing model selector extensions
This commit is contained in:
gsxdsm
2026-03-31 03:21:16 -07:00
parent dac4705761
commit ab12b30751
6 changed files with 159 additions and 12 deletions

View File

@@ -5,7 +5,7 @@ import { TaskStore, AutomationStore } from "@kb/core";
import type { Settings, TaskDetail, PrInfo } from "@kb/core";
import { createServer, GitHubClient } from "@kb/dashboard";
import { TriageProcessor, TaskExecutor, Scheduler, AgentSemaphore, WorktreePool, aiMergeTask, UsageLimitPauser, PRIORITY_MERGE, scanIdleWorktrees, cleanupOrphanedWorktrees, NtfyNotifier, PrMonitor, PrCommentHandler, CronRunner, StuckTaskDetector } from "@kb/engine";
import { AuthStorage, ModelRegistry } from "@mariozechner/pi-coding-agent";
import { AuthStorage, ModelRegistry, discoverAndLoadExtensions, createExtensionRuntime } from "@mariozechner/pi-coding-agent";
/**
* Prompt the user for a port number interactively.
@@ -453,6 +453,31 @@ export async function runDashboard(port: number, opts: { paused?: boolean; dev?:
const authStorage = AuthStorage.create();
const modelRegistry = new ModelRegistry(authStorage);
try {
const extensionsResult = await discoverAndLoadExtensions([], cwd, undefined);
for (const { path, error } of extensionsResult.errors) {
console.log(`[extensions] Failed to load ${path}: ${error}`);
}
for (const { name, config, extensionPath } of extensionsResult.runtime.pendingProviderRegistrations) {
try {
modelRegistry.registerProvider(name, config);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
console.log(`[extensions] Failed to register provider from ${extensionPath}: ${message}`);
}
}
extensionsResult.runtime.pendingProviderRegistrations = [];
modelRegistry.refresh();
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
console.log(`[extensions] Failed to discover extensions: ${message}`);
createExtensionRuntime();
modelRegistry.refresh();
}
// Start the web server with AI merge, auth, and model registry wired in
const app = createServer(store, { onMerge, authStorage, modelRegistry, automationStore });