chore: align config agent proxy defaults

This commit is contained in:
mantrakp04 2026-06-25 18:19:32 -07:00
parent 212502a00b
commit 57188ed78b
6 changed files with 74 additions and 6 deletions

View File

@ -1,4 +1,5 @@
import { ALLOWED_MODEL_IDS } from "@/lib/ai/models";
import { PRODUCTION_AI_PROXY_BASE_URL } from "@/lib/ai/proxy-url";
import { preprocessProxyBody } from "@/private";
import { handleApiRequest } from "@/route-handlers/smart-route-handler";
import { getEnvVariable } from "@hexclave/shared/dist/utils/env";
@ -6,7 +7,6 @@ import { StatusError } from "@hexclave/shared/dist/utils/errors";
import { NextRequest } from "next/server";
const OPENROUTER_BASE_URL = "https://openrouter.ai/api";
const PRODUCTION_PROXY_BASE_URL = "https://api.hexclave.com/api/latest/integrations/ai-proxy";
const OPENROUTER_DEFAULT_MODEL = "anthropic/claude-sonnet-4.6";
function sanitizeBody(raw: ArrayBuffer): Uint8Array {
@ -49,7 +49,7 @@ async function proxyToOpenRouter(req: NextRequest, options: { params: Promise<{
: undefined;
if (apiKey === "FORWARD_TO_PRODUCTION") {
const targetUrl = `${PRODUCTION_PROXY_BASE_URL}/${subpath}${req.nextUrl.search}`;
const targetUrl = `${PRODUCTION_AI_PROXY_BASE_URL}/${subpath}${req.nextUrl.search}`;
const headers: Record<string, string> = {};
if (contentType) {
headers["Content-Type"] = contentType;

View File

@ -2,6 +2,7 @@ import { isLocalEmulatorEnabled } from "@/lib/local-emulator";
import { getNodeEnvironment } from "@hexclave/shared/dist/utils/env";
import { HexclaveAssertionError } from "@hexclave/shared/dist/utils/errors";
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
import { PRODUCTION_AI_PROXY_BASE_URL } from "./proxy-url";
export const MODEL_QUALITIES = ["dumb", "smart", "smartest"] as const;
export const MODEL_SPEEDS = ["slow", "fast"] as const;
@ -62,7 +63,7 @@ export const ALLOWED_MODEL_IDS: ReadonlySet<string> = new Set([
export function createOpenRouterProvider() {
const baseURL = (getNodeEnvironment() === "development" || isLocalEmulatorEnabled())
? "http://localhost:8102/api/latest/integrations/ai-proxy/v1"
: "https://api.hexclave.com/api/latest/integrations/ai-proxy/v1";
: `${PRODUCTION_AI_PROXY_BASE_URL}/v1`;
return createOpenRouter({
apiKey: "forwarded",
baseURL,

View File

@ -0,0 +1 @@
export const PRODUCTION_AI_PROXY_BASE_URL = "https://api.hexclave.com/api/latest/integrations/ai-proxy";

View File

@ -42,13 +42,13 @@
import { getEnvVariable } from "@hexclave/shared/dist/utils/env";
import { captureError } from "@hexclave/shared/dist/utils/errors";
import { Sandbox } from "@vercel/sandbox";
import { PRODUCTION_AI_PROXY_BASE_URL } from "../ai/proxy-url";
const AGENT_SDK_VERSION = "0.2.73";
const BASE = "/vercel/sandbox";
const REPO_DIR = `${BASE}/repo`;
const TOOLS_DIR = BASE; // agent SDK + runner live here, separate from the repo
const DEFAULT_AGENT_MODEL = "anthropic/claude-haiku-4.5";
const DEFAULT_PROXY_URL = "https://api.hexclave.com/api/latest/integrations/ai-proxy";
const SANDBOX_TIMEOUT_MS = 900_000;
const REVIEW_SANDBOX_KEEPALIVE_MS = 5 * 60_000;
const GIT_BOT_NAME = "Hexclave Config Bot";
@ -330,7 +330,7 @@ async function runAgent(sandbox: Sandbox, prompt: string, onProgress?: AgentProg
const agentInput = {
prompt,
model: getEnvVariable("STACK_CONFIG_AGENT_MODEL", DEFAULT_AGENT_MODEL),
baseUrl: getEnvVariable("STACK_CLAUDE_PROXY_URL", DEFAULT_PROXY_URL),
baseUrl: getEnvVariable("STACK_CLAUDE_PROXY_URL", PRODUCTION_AI_PROXY_BASE_URL),
apiKey: "stack-auth-proxy",
};
// Write runner.mjs fresh each run (not baked into the base snapshot) so changes

View File

@ -0,0 +1,66 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
const queryMock = vi.hoisted(() => vi.fn(async function* (_input: unknown) {
yield { type: "result", result: "done" };
}));
vi.mock("@anthropic-ai/claude-agent-sdk", () => ({
query: queryMock,
}));
let originalProxyUrl: string | undefined;
beforeEach(() => {
originalProxyUrl = process.env.STACK_CLAUDE_PROXY_URL;
delete process.env.STACK_CLAUDE_PROXY_URL;
vi.resetModules();
queryMock.mockClear();
});
afterEach(() => {
if (originalProxyUrl === undefined) {
delete process.env.STACK_CLAUDE_PROXY_URL;
} else {
process.env.STACK_CLAUDE_PROXY_URL = originalProxyUrl;
}
});
describe("runHeadlessClaudeAgent", () => {
it("defaults to the latest AI proxy endpoint", async () => {
const { runHeadlessClaudeAgent } = await import("./config-agent");
await runHeadlessClaudeAgent({
prompt: "update the config",
cwd: process.cwd(),
allowedTools: [],
});
expect(queryMock).toHaveBeenCalledWith(expect.objectContaining({
options: expect.objectContaining({
env: expect.objectContaining({
ANTHROPIC_BASE_URL: "https://api.hexclave.com/api/latest/integrations/ai-proxy",
}),
}),
}));
});
it("allows the agent proxy endpoint to be overridden", async () => {
process.env.STACK_CLAUDE_PROXY_URL = "https://example.com/agent-proxy";
const { runHeadlessClaudeAgent } = await import("./config-agent");
await runHeadlessClaudeAgent({
prompt: "update the config",
cwd: process.cwd(),
allowedTools: [],
});
expect(queryMock).toHaveBeenCalledWith(expect.objectContaining({
options: expect.objectContaining({
env: expect.objectContaining({
ANTHROPIC_BASE_URL: "https://example.com/agent-proxy",
}),
}),
}));
});
});

View File

@ -1,7 +1,7 @@
import { query } from "@anthropic-ai/claude-agent-sdk";
import path from "path";
const DEFAULT_PROXY_URL = "https://api.hexclave.com/api/v1/integrations/ai-proxy";
const DEFAULT_PROXY_URL = "https://api.hexclave.com/api/latest/integrations/ai-proxy";
const ANTHROPIC_PROXY_BASE_URL: string = process.env.STACK_CLAUDE_PROXY_URL ?? DEFAULT_PROXY_URL;
export type ClaudeAgentToolName = "Read" | "Write" | "Edit" | "MultiEdit" | "NotebookEdit" | "Bash" | "Glob" | "Grep";