feat(cli-tools): allow setting Claude Code max context tokens
Add a context-window selector on ClaudeToolCard that writes CLAUDE_CODE_MAX_CONTEXT_TOKENS into settings.json (nudged 2K under the labeled cap), and clear it on reset/default. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,16 @@ import { matchKnownEndpoint } from "./cliEndpointMatch";
|
||||
|
||||
const CLOUD_URL = process.env.NEXT_PUBLIC_CLOUD_URL;
|
||||
|
||||
// Context window presets. UI shows the round number; the value written is nudged
|
||||
// down 2K to stay safely under the upstream hard cap.
|
||||
const CONTEXT_OPTIONS = [
|
||||
{ label: "Default", value: "" },
|
||||
{ label: "200K", value: "198000" },
|
||||
{ label: "300K", value: "298000" },
|
||||
{ label: "500K", value: "498000" },
|
||||
{ label: "1M", value: "998000" },
|
||||
];
|
||||
|
||||
export default function ClaudeToolCard({
|
||||
tool,
|
||||
isExpanded,
|
||||
@@ -40,6 +50,7 @@ export default function ClaudeToolCard({
|
||||
const [customBaseUrl, setCustomBaseUrl] = useState("");
|
||||
const [ccFilterNaming, setCcFilterNaming] = useState(false);
|
||||
const [exaMcpEnabled, setExaMcpEnabled] = useState(false);
|
||||
const [maxContextTokens, setMaxContextTokens] = useState("");
|
||||
const hasInitializedModels = useRef(false);
|
||||
|
||||
const getConfigStatus = () => {
|
||||
@@ -65,6 +76,11 @@ export default function ClaudeToolCard({
|
||||
}
|
||||
}, [initialStatus]);
|
||||
|
||||
useEffect(() => {
|
||||
const v = claudeStatus?.settings?.env?.CLAUDE_CODE_MAX_CONTEXT_TOKENS;
|
||||
setMaxContextTokens(v || "");
|
||||
}, [claudeStatus?.settings?.env?.CLAUDE_CODE_MAX_CONTEXT_TOKENS]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isExpanded) {
|
||||
if (!claudeStatus) checkClaudeStatus();
|
||||
@@ -163,10 +179,13 @@ export default function ClaudeToolCard({
|
||||
const targetModel = modelMappings[model.alias];
|
||||
if (targetModel && model.envKey) env[model.envKey] = targetModel;
|
||||
});
|
||||
if (maxContextTokens) {
|
||||
env.CLAUDE_CODE_MAX_CONTEXT_TOKENS = maxContextTokens;
|
||||
}
|
||||
const res = await fetch("/api/cli-tools/claude-settings", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ env, exaMcpEnabled }),
|
||||
body: JSON.stringify({ env, exaMcpEnabled, maxContextTokens }),
|
||||
});
|
||||
const data = await res.json();
|
||||
if (res.ok) {
|
||||
@@ -193,6 +212,7 @@ export default function ClaudeToolCard({
|
||||
tool.defaultModels.forEach((model) => onModelMappingChange(model.alias, model.defaultValue || ""));
|
||||
setSelectedApiKey("");
|
||||
setExaMcpEnabled(false);
|
||||
setMaxContextTokens("");
|
||||
} else {
|
||||
setMessage({ type: "error", text: data.error || "Failed to reset settings" });
|
||||
}
|
||||
@@ -222,6 +242,9 @@ export default function ClaudeToolCard({
|
||||
const targetModel = modelMappings[model.alias];
|
||||
if (targetModel && model.envKey) env[model.envKey] = targetModel;
|
||||
});
|
||||
if (maxContextTokens) {
|
||||
env.CLAUDE_CODE_MAX_CONTEXT_TOKENS = maxContextTokens;
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
@@ -345,6 +368,17 @@ export default function ClaudeToolCard({
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* Context Window */}
|
||||
<div className="grid grid-cols-1 gap-1.5 sm:grid-cols-[8rem_auto_1fr_auto] sm:items-center sm:gap-2">
|
||||
<span className="text-xs font-semibold text-text-main sm:text-right sm:text-sm">Context window</span>
|
||||
<span className="material-symbols-outlined hidden text-text-muted text-[14px] sm:inline">arrow_forward</span>
|
||||
<select value={maxContextTokens} onChange={(e) => setMaxContextTokens(e.target.value)} className="w-full min-w-0 px-2 py-2 bg-surface rounded border border-border text-xs focus:outline-none focus:ring-1 focus:ring-primary/50 sm:py-1.5">
|
||||
{CONTEXT_OPTIONS.map((opt) => (
|
||||
<option key={opt.label} value={opt.value}>{opt.label}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{/* CC Filter Naming */}
|
||||
<div className="grid grid-cols-1 gap-1.5 sm:grid-cols-[8rem_auto_1fr_auto] sm:items-center sm:gap-2">
|
||||
<span className="text-xs font-semibold text-text-main sm:text-right sm:text-sm">Filter naming</span>
|
||||
|
||||
@@ -123,7 +123,7 @@ export async function GET() {
|
||||
// POST - Backup old fields and write new settings
|
||||
export async function POST(request) {
|
||||
try {
|
||||
const { env, exaMcpEnabled } = await request.json();
|
||||
const { env, exaMcpEnabled, maxContextTokens } = await request.json();
|
||||
|
||||
if (!env || typeof env !== "object") {
|
||||
return NextResponse.json(
|
||||
@@ -166,6 +166,14 @@ export async function POST(request) {
|
||||
},
|
||||
};
|
||||
|
||||
// CLAUDE_CODE_MAX_CONTEXT_TOKENS — only set when a concrete value is chosen;
|
||||
// "Default" removes the key so Claude Code falls back to the model's window.
|
||||
if (maxContextTokens) {
|
||||
newSettings.env.CLAUDE_CODE_MAX_CONTEXT_TOKENS = String(maxContextTokens);
|
||||
} else {
|
||||
delete newSettings.env.CLAUDE_CODE_MAX_CONTEXT_TOKENS;
|
||||
}
|
||||
|
||||
// Write new settings
|
||||
await fs.writeFile(settingsPath, JSON.stringify(newSettings, null, 2));
|
||||
|
||||
@@ -195,6 +203,7 @@ const RESET_ENV_KEYS = [
|
||||
"ANTHROPIC_DEFAULT_SONNET_MODEL",
|
||||
"ANTHROPIC_DEFAULT_HAIKU_MODEL",
|
||||
"API_TIMEOUT_MS",
|
||||
"CLAUDE_CODE_MAX_CONTEXT_TOKENS",
|
||||
];
|
||||
|
||||
// DELETE - Reset settings (remove env fields)
|
||||
|
||||
Reference in New Issue
Block a user