set default agent based on available agents
This commit is contained in:
@@ -6,6 +6,7 @@ import { flatMorph } from "@ark/util";
|
|||||||
import { type } from "arktype";
|
import { type } from "arktype";
|
||||||
import { agents } from "./agents/index.ts";
|
import { agents } from "./agents/index.ts";
|
||||||
import type { AgentName, AgentName as AgentNameType, Payload } from "./external.ts";
|
import type { AgentName, AgentName as AgentNameType, Payload } from "./external.ts";
|
||||||
|
import { agentsManifest } from "./external.ts";
|
||||||
import { createMcpConfigs } from "./mcp/config.ts";
|
import { createMcpConfigs } from "./mcp/config.ts";
|
||||||
import { modes } from "./modes.ts";
|
import { modes } from "./modes.ts";
|
||||||
import packageJson from "./package.json" with { type: "json" };
|
import packageJson from "./package.json" with { type: "json" };
|
||||||
@@ -22,7 +23,7 @@ import { setupGitAuth, setupGitBranch, setupGitConfig } from "./utils/setup.ts";
|
|||||||
// runtime validation using agents (needed for ArkType)
|
// runtime validation using agents (needed for ArkType)
|
||||||
// Note: The AgentName type is defined in external.ts, this is the runtime validator
|
// Note: The AgentName type is defined in external.ts, this is the runtime validator
|
||||||
|
|
||||||
const AGENT_OVERRIDE: AgentName | null = "cursor";
|
const AGENT_OVERRIDE: AgentName | null = null;
|
||||||
export const AgentInputKey = type.enumerated(
|
export const AgentInputKey = type.enumerated(
|
||||||
...Object.values(agents).flatMap((agent) => agent.apiKeyNames)
|
...Object.values(agents).flatMap((agent) => agent.apiKeyNames)
|
||||||
);
|
);
|
||||||
@@ -83,6 +84,26 @@ export async function main(inputs: Inputs): Promise<MainResult> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get agents that have matching API keys in the inputs
|
||||||
|
*/
|
||||||
|
function getAvailableAgents(inputs: Inputs): (typeof agents)[AgentNameType][] {
|
||||||
|
return Object.values(agents).filter((agent) =>
|
||||||
|
agent.apiKeyNames.some((inputKey) => inputs[inputKey])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all possible API key names from agentsManifest using flatMorph
|
||||||
|
*/
|
||||||
|
function getAllPossibleKeyNames(): string[] {
|
||||||
|
return Object.keys(
|
||||||
|
flatMorph(agentsManifest, (_, manifest) =>
|
||||||
|
manifest.apiKeyNames.map((keyName) => [keyName, true] as const)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Throw an error for missing API key with helpful message linking to repo settings
|
* Throw an error for missing API key with helpful message linking to repo settings
|
||||||
*/
|
*/
|
||||||
@@ -90,12 +111,10 @@ function throwMissingApiKeyError({
|
|||||||
agentName,
|
agentName,
|
||||||
inputKeys,
|
inputKeys,
|
||||||
repoContext,
|
repoContext,
|
||||||
inputs,
|
|
||||||
}: {
|
}: {
|
||||||
agentName: string;
|
agentName: string | null;
|
||||||
inputKeys: string[];
|
inputKeys: string[];
|
||||||
repoContext: RepoContext;
|
repoContext: RepoContext;
|
||||||
inputs: Inputs;
|
|
||||||
}): never {
|
}): never {
|
||||||
const apiUrl = process.env.API_URL || "https://pullfrog.ai";
|
const apiUrl = process.env.API_URL || "https://pullfrog.ai";
|
||||||
const settingsUrl = `${apiUrl}/console/${repoContext.owner}/${repoContext.name}`;
|
const settingsUrl = `${apiUrl}/console/${repoContext.owner}/${repoContext.name}`;
|
||||||
@@ -107,12 +126,11 @@ function throwMissingApiKeyError({
|
|||||||
const githubRepoUrl = `https://github.com/${repoContext.owner}/${repoContext.name}`;
|
const githubRepoUrl = `https://github.com/${repoContext.owner}/${repoContext.name}`;
|
||||||
const githubSecretsUrl = `${githubRepoUrl}/settings/secrets/actions`;
|
const githubSecretsUrl = `${githubRepoUrl}/settings/secrets/actions`;
|
||||||
|
|
||||||
// Find which agents have inputKeys that match the provided inputs
|
let message = `${
|
||||||
const availableAgents = Object.values(agents).filter((agent) =>
|
agentName === null
|
||||||
agent.apiKeyNames.some((inputKey) => inputs[inputKey])
|
? "Pullfrog has no agent configured and no API keys are available in the environment."
|
||||||
);
|
: `Pullfrog is configured to use ${agentName}, but the associated API key was not provided.`
|
||||||
|
}
|
||||||
let message = `Pullfrog is configured to use ${agentName}, but the associated API key was not provided.
|
|
||||||
|
|
||||||
To fix this, add the required secret to your GitHub repository:
|
To fix this, add the required secret to your GitHub repository:
|
||||||
|
|
||||||
@@ -122,10 +140,8 @@ To fix this, add the required secret to your GitHub repository:
|
|||||||
4. Set the value to your API key
|
4. Set the value to your API key
|
||||||
5. Click "Add secret"`;
|
5. Click "Add secret"`;
|
||||||
|
|
||||||
// If other credentials are present, suggest alternative agents
|
if (agentName === null) {
|
||||||
if (availableAgents.length > 0) {
|
message += `\n\nAlternatively, configure Pullfrog to use an agent at ${settingsUrl}`;
|
||||||
const agentNames = availableAgents.map((agent) => agent.name).join(", ");
|
|
||||||
message += `\n\nAlternatively, configure Pullfrog to use an agent with existing credentials in your environment (${agentNames}) at ${settingsUrl}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.error(message);
|
log.error(message);
|
||||||
@@ -177,14 +193,38 @@ async function determineAgent(
|
|||||||
repoContext: ctx.repoContext,
|
repoContext: ctx.repoContext,
|
||||||
});
|
});
|
||||||
|
|
||||||
// precedence: override agent > payload.agent > inputs.defaultAgent > repoSettings.defaultAgent > "claude"
|
// precedence: override agent > payload.agent > inputs.defaultAgent > repoSettings.defaultAgent > first available agent
|
||||||
ctx.agentName =
|
const configuredAgentName =
|
||||||
(process.env.NODE_ENV === "development" && AGENT_OVERRIDE) ||
|
(process.env.NODE_ENV === "development" && AGENT_OVERRIDE) ||
|
||||||
ctx.payload.agent ||
|
ctx.payload.agent ||
|
||||||
ctx.inputs.defaultAgent ||
|
ctx.inputs.defaultAgent ||
|
||||||
repoSettings.defaultAgent ||
|
repoSettings.defaultAgent ||
|
||||||
"claude"; // TODO: look at env vars
|
null;
|
||||||
ctx.agent = agents[ctx.agentName];
|
|
||||||
|
if (configuredAgentName) {
|
||||||
|
ctx.agentName = configuredAgentName;
|
||||||
|
ctx.agent = agents[ctx.agentName];
|
||||||
|
log.info(`Selected configured agent: ${ctx.agentName}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if no agent is configured, default to first available agent
|
||||||
|
// const availableAgents = getAvailableAgents(ctx.inputs);
|
||||||
|
const availableAgents = getAvailableAgents(ctx.inputs);
|
||||||
|
const availableAgentNames = availableAgents.map((agent) => agent.name).join(", ");
|
||||||
|
log.debug(`Available agents: ${availableAgentNames || "none"}`);
|
||||||
|
|
||||||
|
if (availableAgents.length === 0) {
|
||||||
|
throwMissingApiKeyError({
|
||||||
|
agentName: null,
|
||||||
|
inputKeys: getAllPossibleKeyNames(),
|
||||||
|
repoContext: ctx.repoContext,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.agentName = availableAgents[0].name;
|
||||||
|
ctx.agent = availableAgents[0];
|
||||||
|
log.info(`No agent configured, defaulting to first available agent: ${ctx.agentName}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setupTempDirectory(
|
async function setupTempDirectory(
|
||||||
@@ -250,7 +290,6 @@ function validateApiKey(ctx: MainContext): void {
|
|||||||
agentName: ctx.agentName,
|
agentName: ctx.agentName,
|
||||||
inputKeys: ctx.agent.apiKeyNames,
|
inputKeys: ctx.agent.apiKeyNames,
|
||||||
repoContext: ctx.repoContext,
|
repoContext: ctx.repoContext,
|
||||||
inputs: ctx.inputs,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ctx.apiKey = ctx.inputs[matchingInputKey as AgentInputKey]!;
|
ctx.apiKey = ctx.inputs[matchingInputKey as AgentInputKey]!;
|
||||||
|
|||||||
Reference in New Issue
Block a user