Drops every `definition.module.*` call and legacy id hardcode (claude_local, codex_local, gemini_local, claude_compat_*) from the connector services. Health checks now evaluate stored credentials against the declarative auth descriptor, model policy reads provider models via pi-ai, matching keys off provider ids, and hire-hook logs activity without invoking an adapter hook. Introduces a local normalizeCommandValue helper to replace the deleted @agentcompany/adapter-utils/server-utils import.
100 lines
3.2 KiB
TypeScript
100 lines
3.2 KiB
TypeScript
import { getModels } from "@mariozechner/pi-ai";
|
|
import type { ConnectorId } from "@shared/types";
|
|
import { getConnectorDefinition } from "./connectors";
|
|
|
|
interface ConnectorModelPolicyDeps {
|
|
getConnector: (id: ConnectorId) => { id: ConnectorId; label?: string | null; model: string | null };
|
|
getDisabledModels: (connectorId: string) => Array<{ id: string; label: string }>;
|
|
}
|
|
|
|
export interface ConnectorModelPolicyResult {
|
|
connectorId: ConnectorId;
|
|
connectorLabel: string;
|
|
enabledModels: Array<{ id: string; label: string }>;
|
|
defaultModel: string | null;
|
|
}
|
|
|
|
function uniqueModels(models: Array<{ id: string; label: string }>) {
|
|
const byId = new Map<string, { id: string; label: string }>();
|
|
for (const model of models) {
|
|
const id = model.id.trim();
|
|
if (!id) continue;
|
|
if (!byId.has(id)) {
|
|
byId.set(id, { id, label: model.label || id });
|
|
}
|
|
}
|
|
return Array.from(byId.values());
|
|
}
|
|
|
|
function listProviderModels(provider: string): Array<{ id: string; label: string }> {
|
|
try {
|
|
const models = getModels(provider as never);
|
|
return models.map((model) => ({ id: model.id, label: model.name ?? model.id }));
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
export function getConnectorModelPolicy(
|
|
deps: ConnectorModelPolicyDeps,
|
|
connectorId: ConnectorId,
|
|
): ConnectorModelPolicyResult {
|
|
const connector = deps.getConnector(connectorId);
|
|
const definition = getConnectorDefinition(connectorId);
|
|
const disabledModels = new Set(deps.getDisabledModels(connectorId).map((model) => model.id));
|
|
|
|
const catalog = listProviderModels(definition.provider);
|
|
const enabledModels = uniqueModels(catalog).filter((model) => !disabledModels.has(model.id));
|
|
|
|
return {
|
|
connectorId,
|
|
connectorLabel: connector.label?.trim() || definition.label,
|
|
enabledModels,
|
|
defaultModel: connector.model?.trim() || definition.defaultModel,
|
|
};
|
|
}
|
|
|
|
export function validateConnectorModelSelection(
|
|
deps: ConnectorModelPolicyDeps,
|
|
connectorId: ConnectorId,
|
|
model: string | null | undefined,
|
|
): { ok: true; effectiveModel: string | null } | { ok: false; error: string } {
|
|
const policy = getConnectorModelPolicy(deps, connectorId);
|
|
const selectedModel = model?.trim() || null;
|
|
|
|
if (policy.enabledModels.length === 0) {
|
|
return {
|
|
ok: false,
|
|
error: `${policy.connectorLabel} has no enabled models available.`,
|
|
};
|
|
}
|
|
|
|
if (selectedModel) {
|
|
if (!policy.enabledModels.some((entry) => entry.id === selectedModel)) {
|
|
return {
|
|
ok: false,
|
|
error: `${policy.connectorLabel} does not allow model "${selectedModel}".`,
|
|
};
|
|
}
|
|
return { ok: true, effectiveModel: selectedModel };
|
|
}
|
|
|
|
if (policy.defaultModel && policy.enabledModels.some((entry) => entry.id === policy.defaultModel)) {
|
|
return { ok: true, effectiveModel: policy.defaultModel };
|
|
}
|
|
|
|
return { ok: true, effectiveModel: policy.enabledModels[0]?.id ?? null };
|
|
}
|
|
|
|
/**
|
|
* Pi-mono catalog does not have free-form compat connectors; every connector
|
|
* has a fixed pi-ai provider. The configuration-level model validator is a
|
|
* no-op retained for IPC contract compatibility.
|
|
*/
|
|
export function validateConnectorConfigurationModel(
|
|
_connectorId: ConnectorId,
|
|
_model: string | null | undefined,
|
|
): { ok: true } | { ok: false; error: string } {
|
|
return { ok: true };
|
|
}
|