Address review feedback: use effort params, fix model names, add safety checks

This commit is contained in:
pullfrog
2026-01-12 20:51:13 +00:00
committed by Colin McDonnell
parent 89e93d3398
commit c6572f0987
6 changed files with 1291 additions and 1315 deletions
+10 -15
View File
@@ -5,12 +5,12 @@ import { log } from "../utils/cli.ts";
import { addInstructions } from "./instructions.ts";
import { agent, createAgentEnv, installFromNpmTarball } from "./shared.ts";
// model configuration based on effort level
// uses model family aliases that auto-resolve to latest version
const claudeModels: Record<Effort, { model: string; thinking: boolean }> = {
nothink: { model: "claude-haiku-4-5", thinking: false },
think: { model: "claude-sonnet-4-5", thinking: true },
max: { model: "claude-opus-4-5", thinking: true },
// effort levels for Claude Code
// Claude Code automatically selects the best model based on effort
const claudeEffortLevels: Record<Effort, "low" | "medium" | "high"> = {
nothink: "low",
think: "medium",
max: "high",
} as const;
export const claude = agent({
@@ -30,9 +30,9 @@ export const claude = agent({
const prompt = addInstructions({ payload, repo });
log.group("Full prompt", () => log.info(prompt));
// get model configuration based on effort
const modelConfig = claudeModels[effort];
log.info(`Using model: ${modelConfig.model}, thinking: ${modelConfig.thinking}`);
// get effort level - Claude Code automatically selects the best model
const effortLevel = claudeEffortLevels[effort];
log.info(`Using effort: ${effortLevel}`);
// SECURITY: For PUBLIC repos, Claude Code spawns subprocesses with full process.env, leaking API keys.
// disable native Bash; agents use MCP bash tool which filters secrets.
@@ -62,15 +62,10 @@ export const claude = agent({
const queryOptions: Options = {
...sandboxOptions,
mcpServers,
model: modelConfig.model,
effort: effortLevel,
pathToClaudeCodeExecutable: cliPath,
env: createAgentEnv({ ANTHROPIC_API_KEY: apiKey }),
};
// only set maxThinkingTokens when we want to disable thinking (0)
// omit the property to use default when thinking is enabled
if (!modelConfig.thinking) {
queryOptions.maxThinkingTokens = 0;
}
const queryInstance = query({
prompt,
+33 -25
View File
@@ -7,12 +7,12 @@ import { log } from "../utils/cli.ts";
import { addInstructions } from "./instructions.ts";
import { agent, installFromNpmTarball, setupProcessAgentEnv } from "./shared.ts";
// model configuration based on effort level
// uses model family aliases that auto-resolve to latest version
const codexModels: Record<Effort, string> = {
nothink: "gpt-4o-mini",
think: "gpt-5.2-instant",
max: "gpt-5.2-thinking",
// reasoning effort configuration based on effort level
// uses model_reasoning_effort parameter for o1 models
const codexReasoningEffort: Record<Effort, string | undefined> = {
nothink: "low",
think: undefined, // use default
max: "xhigh",
} as const;
interface WriteCodexConfigParams {
@@ -88,9 +88,13 @@ export const codex = agent({
CODEX_HOME: codexDir, // point Codex to our config directory
});
// get model based on effort level
const model = codexModels[effort];
log.info(`Using model: ${model}`);
// get reasoning effort based on effort level
const modelReasoningEffort = codexReasoningEffort[effort];
if (modelReasoningEffort) {
log.info(`Using model_reasoning_effort: ${modelReasoningEffort}`);
} else {
log.info(`Using default reasoning effort`);
}
// Configure Codex
const codexOptions: CodexOptions = {
@@ -103,22 +107,26 @@ export const codex = agent({
}
const codex = new Codex(codexOptions);
const thread = codex.startThread(
payload.sandbox
? {
model,
approvalPolicy: "never",
sandboxMode: "read-only",
networkAccessEnabled: false,
}
: {
model,
approvalPolicy: "never",
// use danger-full-access to allow git operations (workspace-write blocks .git directory writes)
sandboxMode: "danger-full-access",
networkAccessEnabled: true,
}
);
// Build thread options with optional model_reasoning_effort
const baseThreadOptions = payload.sandbox
? {
approvalPolicy: "never" as const,
sandboxMode: "read-only" as const,
networkAccessEnabled: false,
}
: {
approvalPolicy: "never" as const,
// use danger-full-access to allow git operations (workspace-write blocks .git directory writes)
sandboxMode: "danger-full-access" as const,
networkAccessEnabled: true,
};
const threadOptions = modelReasoningEffort
? { ...baseThreadOptions, model_reasoning_effort: modelReasoningEffort }
: baseThreadOptions;
const thread = codex.startThread(threadOptions);
try {
const streamedTurn = await thread.runStreamed(addInstructions({ payload, repo }));
+4 -4
View File
@@ -12,11 +12,11 @@ import {
} from "./shared.ts";
// model configuration based on effort level
// uses model family aliases that auto-resolve to latest version
// auto for default, flash for fast/low-cost, pro for max capability
const geminiModels = {
nothink: "gemini-2.5-pro",
think: "gemini-3-pro",
max: "gemini-3-pro",
nothink: "gemini-2.5-flash",
think: "gemini-2.5-pro", // auto selection
max: "gemini-2.5-pro",
} as const;
// gemini cli event types inferred from stream-json output (NDJSON format)
+1 -1
View File
@@ -68,7 +68,7 @@ export const opencode = agent({
// add API keys from apiKeys object
for (const [key, value] of Object.entries(apiKeys || {})) {
env[key] = value;
env[key.toUpperCase()] = value;
// also set GOOGLE_GENERATIVE_AI_API_KEY for Google provider compatibility
if (key === "GEMINI_API_KEY") {
env.GOOGLE_GENERATIVE_AI_API_KEY = value;
+1241 -1268
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -401,10 +401,10 @@ function parsePayload(inputs: Inputs): Payload {
if (!("~pullfrog" in parsedPrompt)) {
throw new Error();
}
// internal invocation: use effort from payload, fallback to input
// internal invocation: use effort from payload, fallback to input, default to "think"
return {
...parsedPrompt,
effort: parsedPrompt.effort ?? inputs.effort,
effort: parsedPrompt.effort ?? inputs.effort ?? "think",
} as Payload;
} catch {
// external invocation: use effort from input