|
@@ -58,10 +58,14 @@ export interface ResolvedPiAiProviderProfile extends Omit<PiAiProviderProfile, '
|
|
|
retryPolicy: ResolvedRetryPolicy
|
|
retryPolicy: ResolvedRetryPolicy
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-/** Plugin configuration: the non-empty provider routes this instance owns. */
|
|
|
|
|
|
|
+/** Plugin configuration: the provider routes this instance owns. */
|
|
|
export interface Config {
|
|
export interface Config {
|
|
|
- /** Non-empty dict of pi-ai provider routes, keyed by provider. */
|
|
|
|
|
- providers: Record<string, PiAiProviderProfile>
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * pi-ai provider routes, keyed by provider. An empty (or omitted) dict is
|
|
|
|
|
+ * the dormant settings-driven posture: the adapter mounts with no routes
|
|
|
|
|
+ * and registers them the moment a settings section supplies profiles.
|
|
|
|
|
+ */
|
|
|
|
|
+ providers?: Record<string, PiAiProviderProfile>
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const thinkingBudgets = z.object({
|
|
const thinkingBudgets = z.object({
|
|
@@ -88,21 +92,24 @@ const profile = z.object({
|
|
|
|
|
|
|
|
/** Runtime schema for {@link Config}. */
|
|
/** Runtime schema for {@link Config}. */
|
|
|
export const Config: z<Config> = z.object({
|
|
export const Config: z<Config> = z.object({
|
|
|
- providers: z.dict(profile).required(),
|
|
|
|
|
|
|
+ providers: z.dict(profile).default({}),
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* Validate profiles against the installed pi-ai catalog and return a detached
|
|
* Validate profiles against the installed pi-ai catalog and return a detached
|
|
|
- * route-keyed map suitable for per-request reads.
|
|
|
|
|
|
|
+ * route-keyed map suitable for per-request reads. This is the one explicit
|
|
|
|
|
+ * resolve step, so an omitted dict resolves to the empty (dormant) route set
|
|
|
|
|
+ * here rather than through a hidden fallback.
|
|
|
* @param providers - configured provider profiles keyed by route.
|
|
* @param providers - configured provider profiles keyed by route.
|
|
|
* @returns validated profiles in configuration order.
|
|
* @returns validated profiles in configuration order.
|
|
|
*/
|
|
*/
|
|
|
-export function resolveProfiles(providers: Readonly<Record<string, PiAiProviderProfile>>): Map<string, ResolvedPiAiProviderProfile> {
|
|
|
|
|
|
|
+export function resolveProfiles(
|
|
|
|
|
+ providers: Readonly<Record<string, PiAiProviderProfile>> | undefined,
|
|
|
|
|
+): Map<string, ResolvedPiAiProviderProfile> {
|
|
|
if (Array.isArray(providers)) {
|
|
if (Array.isArray(providers)) {
|
|
|
throw new Error('llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles')
|
|
throw new Error('llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles')
|
|
|
}
|
|
}
|
|
|
- const entries = Object.entries(providers)
|
|
|
|
|
- if (entries.length === 0) throw new Error('llm-pi-ai: providers must contain at least one profile')
|
|
|
|
|
|
|
+ const entries = Object.entries(providers ?? {})
|
|
|
const supported = new Set<string>(getBuiltinProviders())
|
|
const supported = new Set<string>(getBuiltinProviders())
|
|
|
const resolved = new Map<string, ResolvedPiAiProviderProfile>()
|
|
const resolved = new Map<string, ResolvedPiAiProviderProfile>()
|
|
|
for (const [provider, source] of entries) {
|
|
for (const [provider, source] of entries) {
|