n8n
Version:
n8n Workflow Automation Tool
136 lines • 6.11 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildResolveLlmTool = buildResolveLlmTool;
const agents_1 = require("@n8n/agents");
const zod_1 = require("zod");
const builder_tool_names_1 = require("../builder-tool-names");
const llm_provider_defaults_1 = require("./llm-provider-defaults");
function findProviderDefault(provider) {
const requestedProvider = provider.trim();
return Object.entries(llm_provider_defaults_1.LLM_PROVIDER_DEFAULTS).find(([, defaults]) => defaults.provider === requestedProvider);
}
function toLlmResolution(credential, defaults, model) {
return {
ok: true,
provider: defaults.provider,
model: model?.trim() || defaults.defaultModel,
credentialId: credential.id,
credentialName: credential.name,
};
}
async function resolveModelAgainstLookup(credential, defaults, requestedModel, modelLookup) {
const trimmedModel = requestedModel.trim();
if (!defaults.modelLookup || !trimmedModel) {
return toLlmResolution(credential, defaults, requestedModel);
}
let availableModels;
try {
availableModels = await modelLookup.list(credential.id, credential.type, defaults.modelLookup);
}
catch (error) {
return {
ok: false,
reason: 'model_lookup_failed',
provider: defaults.provider,
requestedModel: trimmedModel,
error: error instanceof Error ? error.message : String(error),
};
}
const lowerHint = trimmedModel.toLowerCase();
const exactMatch = availableModels.find((m) => m.value.toLowerCase() === lowerHint);
if (exactMatch) {
return toLlmResolution(credential, defaults, exactMatch.value);
}
const candidates = availableModels.filter((m) => m.value.toLowerCase().includes(lowerHint) || m.name.toLowerCase().includes(lowerHint));
if (candidates.length === 1) {
return toLlmResolution(credential, defaults, candidates[0].value);
}
return {
ok: false,
reason: 'unknown_model',
provider: defaults.provider,
requestedModel: trimmedModel,
availableModels: candidates.length > 0 ? candidates : availableModels,
};
}
function buildResolveLlmTool(deps) {
return new agents_1.Tool(builder_tool_names_1.BUILDER_TOOLS.RESOLVE_LLM)
.description('Resolve the agent main LLM without showing a picker. Use this when the user ' +
'explicitly requests a provider/model, or when a fresh agent needs a default LLM. ' +
'If provider is given, resolves only that provider; if model is omitted, uses the ' +
'provider default model. For "Anthropic via OpenRouter", pass provider="openrouter" ' +
'and omit model unless the user named a concrete OpenRouter model id. Returns ok=false ' +
'when credentials are missing, unsupported, or ambiguous; use ask_llm only when the ' +
'user must choose.')
.input(zod_1.z.object({
provider: zod_1.z
.string()
.optional()
.describe('Requested provider, e.g. "anthropic", "openai", or "openrouter".'),
model: zod_1.z
.string()
.optional()
.describe('Requested model without the selected provider prefix. For OpenRouter use the routed id, e.g. "anthropic/claude-sonnet-4.6".'),
}))
.handler(async ({ provider, model }) => {
const all = await deps.credentialProvider.list();
const llmCredentials = all.filter((credential) => llm_provider_defaults_1.LLM_PROVIDER_DEFAULTS[credential.type]);
if (provider) {
const providerEntry = findProviderDefault(provider);
if (!providerEntry) {
return {
ok: false,
reason: 'unsupported_provider',
provider,
supportedProviders: Object.values(llm_provider_defaults_1.LLM_PROVIDER_DEFAULTS).map((defaults) => defaults.provider),
};
}
const [credentialType, defaults] = providerEntry;
const matchingCredentials = llmCredentials.filter((credential) => credential.type === credentialType);
if (matchingCredentials.length === 1) {
const credential = matchingCredentials[0];
if (model?.trim()) {
return await resolveModelAgainstLookup(credential, defaults, model, deps.modelLookup);
}
return toLlmResolution(credential, defaults);
}
return {
ok: false,
reason: matchingCredentials.length === 0
? 'missing_credential'
: 'ambiguous_credential',
provider: defaults.provider,
credentialType,
credentials: matchingCredentials.map((credential) => ({
id: credential.id,
name: credential.name,
})),
};
}
if (llmCredentials.length === 1) {
const credential = llmCredentials[0];
const defaults = llm_provider_defaults_1.LLM_PROVIDER_DEFAULTS[credential.type];
if (model?.trim()) {
return await resolveModelAgainstLookup(credential, defaults, model, deps.modelLookup);
}
return toLlmResolution(credential, defaults);
}
return {
ok: false,
reason: llmCredentials.length === 0
? 'missing_credential'
: 'ambiguous_provider_or_credential',
credentials: llmCredentials.map((credential) => {
const defaults = llm_provider_defaults_1.LLM_PROVIDER_DEFAULTS[credential.type];
return {
id: credential.id,
name: credential.name,
type: credential.type,
provider: defaults.provider,
};
}),
};
})
.build();
}
//# sourceMappingURL=resolve-llm.tool.js.map