feat: gate claw runtime selection by availability

This commit is contained in:
kris
2026-04-03 02:11:41 +08:00
parent 6c999fb951
commit 8e2350e89d
19 changed files with 564 additions and 123 deletions

View File

@@ -5,6 +5,7 @@ import {
hasPersistedProject,
updateProjectAgentControls,
} from "@/lib/boss-data";
import { getClawBackendAvailability } from "@/lib/execution/backends/claw-config";
const reasoningEffortValues = new Set(["low", "medium", "high"]);
@@ -27,8 +28,11 @@ export async function GET(
return NextResponse.json({ ok: false, message: "UNAUTHORIZED" }, { status: 401 });
}
const controls = await getProjectAgentControls(projectId, session.account);
return NextResponse.json({ ok: true, controls });
const [controls, clawAvailability] = await Promise.all([
getProjectAgentControls(projectId, session.account),
getClawBackendAvailability(),
]);
return NextResponse.json({ ok: true, controls, clawAvailability });
}
export async function POST(
@@ -102,6 +106,16 @@ export async function POST(
}
try {
if (hasBackendOverride && payload.backendOverride === "claw-runtime") {
const clawAvailability = await getClawBackendAvailability();
if (!clawAvailability.selectable) {
return NextResponse.json(
{ ok: false, message: clawAvailability.reasonLabel, clawAvailability },
{ status: 400 },
);
}
}
const controls = await updateProjectAgentControls(
projectId,
{
@@ -112,7 +126,11 @@ export async function POST(
},
session.account,
);
return NextResponse.json({ ok: true, controls: controls ?? null });
return NextResponse.json({
ok: true,
controls: controls ?? null,
clawAvailability: await getClawBackendAvailability(),
});
} catch (error) {
return NextResponse.json(
{ ok: false, message: error instanceof Error ? error.message : "UNKNOWN_ERROR" },

View File

@@ -9,6 +9,7 @@ import {
updateProjectAgentControls,
updateUserMasterPrompt,
} from "@/lib/boss-data";
import { getClawBackendAvailability } from "@/lib/execution/backends/claw-config";
export async function GET(
request: NextRequest,
@@ -25,10 +26,11 @@ export async function GET(
return NextResponse.json({ ok: false, message: "PROJECT_NOT_FOUND" }, { status: 404 });
}
const [promptPolicy, userPrompt, projectControls] = await Promise.all([
const [promptPolicy, userPrompt, projectControls, clawAvailability] = await Promise.all([
getMasterAgentPromptPolicy(),
getUserMasterPrompt(session.account),
getProjectAgentControls(projectId, session.account),
getClawBackendAvailability(),
]);
return NextResponse.json({
@@ -38,6 +40,7 @@ export async function GET(
userPrompt,
projectControls,
projectPromptOverride: projectControls?.promptOverride ?? null,
clawAvailability,
account: session.account,
});
}
@@ -105,6 +108,24 @@ export async function POST(
}
try {
if (
hasBackendOverride &&
typeof payload.backendOverride === "string" &&
payload.backendOverride.trim() === "claw-runtime"
) {
const clawAvailability = await getClawBackendAvailability();
if (!clawAvailability.selectable) {
return NextResponse.json(
{
ok: false,
message: clawAvailability.reasonLabel,
clawAvailability,
},
{ status: 400 },
);
}
}
if (hasUserPromptContent) {
const userPromptContent = typeof payload.userPromptContent === "string" ? payload.userPromptContent.trim() : "";
if (userPromptContent) {
@@ -121,10 +142,11 @@ export async function POST(
}, session.account);
}
const [promptPolicy, userPrompt, projectControls] = await Promise.all([
const [promptPolicy, userPrompt, projectControls, clawAvailability] = await Promise.all([
getMasterAgentPromptPolicy(),
getUserMasterPrompt(session.account),
getProjectAgentControls(projectId, session.account),
getClawBackendAvailability(),
]);
return NextResponse.json({
@@ -134,6 +156,7 @@ export async function POST(
userPrompt,
projectControls,
projectPromptOverride: projectControls?.promptOverride ?? null,
clawAvailability,
account: session.account,
});
} catch (error) {