diff --git a/studio/backend/models/inference.py b/studio/backend/models/inference.py index 66b599962b..df57791eb9 100644 --- a/studio/backend/models/inference.py +++ b/studio/backend/models/inference.py @@ -374,7 +374,9 @@ class ChatMessage(BaseModel): if self.content is None: raise ValueError("tool messages require content") if not self.tool_call_id: - raise ValueError("tool messages require tool_call_id") + raise ValueError( + 'role="tool" messages require "tool_call_id" per the OpenAI spec.' + ) else: if self.content is None: raise ValueError(f"{self.role} messages require content") diff --git a/studio/backend/tests/test_openai_tool_passthrough.py b/studio/backend/tests/test_openai_tool_passthrough.py index 1c0dec1264..056b1a62a2 100644 --- a/studio/backend/tests/test_openai_tool_passthrough.py +++ b/studio/backend/tests/test_openai_tool_passthrough.py @@ -111,9 +111,31 @@ class TestChatMessageToolRoles: ChatMessage(role = "function", content = "x") def test_content_absent_defaults_to_none(self): - msg = ChatMessage(role = "assistant") + msg = ChatMessage( + role = "assistant", + tool_calls = [ + {"id": "c1", "type": "function", "function": {"name": "f", "arguments": "{}"}} + ], + ) assert msg.content is None + def test_tool_role_missing_tool_call_id_rejected(self): + # Per OpenAI spec, role="tool" messages must carry tool_call_id so + # upstream backends can associate the result with its prior call. + # Pin the boundary-level rejection so a malformed tool-result + # message never reaches the passthrough path. + with pytest.raises(ValidationError) as exc_info: + ChatMessage(role = "tool", content = '{"temperature": 72}') + assert "tool_call_id" in str(exc_info.value) + + def test_tool_role_empty_tool_call_id_rejected(self): + with pytest.raises(ValidationError): + ChatMessage( + role = "tool", + tool_call_id = "", + content = '{"temperature": 72}', + ) + # ===================================================================== # ChatCompletionRequest — standard OpenAI tool fields diff --git a/studio/frontend/src/components/app-sidebar.tsx b/studio/frontend/src/components/app-sidebar.tsx index 8264f329a3..329175fa9c 100644 --- a/studio/frontend/src/components/app-sidebar.tsx +++ b/studio/frontend/src/components/app-sidebar.tsx @@ -330,7 +330,7 @@ export function AppSidebar() { { @@ -511,7 +511,7 @@ export function AppSidebar() { />
Unsloth - Studio + Train
diff --git a/studio/frontend/src/features/onboarding/components/wizard-footer.tsx b/studio/frontend/src/features/onboarding/components/wizard-footer.tsx index 4588c0a632..399bf115f1 100644 --- a/studio/frontend/src/features/onboarding/components/wizard-footer.tsx +++ b/studio/frontend/src/features/onboarding/components/wizard-footer.tsx @@ -69,7 +69,7 @@ export function WizardFooter({ if (currentStep === 1 && sessionStorage.getItem("unsloth_chat_only") === "1") { sessionStorage.removeItem("unsloth_chat_only"); markOnboardingDone(); - window.location.assign(returnTo); + window.location.assign("/chat"); } else { nextStep(); } diff --git a/studio/frontend/src/features/settings/tabs/general-tab.tsx b/studio/frontend/src/features/settings/tabs/general-tab.tsx index a79b134e97..874508a6fb 100644 --- a/studio/frontend/src/features/settings/tabs/general-tab.tsx +++ b/studio/frontend/src/features/settings/tabs/general-tab.tsx @@ -12,6 +12,7 @@ import { } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Switch } from "@/components/ui/switch"; +import { usePlatformStore } from "@/config/env"; import { resetOnboardingDone } from "@/features/auth"; import { useChatRuntimeStore } from "@/features/chat/stores/chat-runtime-store"; import { useSettingsDialogStore } from "@/features/settings"; @@ -95,6 +96,7 @@ export function GeneralTab() { const setHfToken = useChatRuntimeStore((s) => s.setHfToken); const autoTitle = useChatRuntimeStore((s) => s.autoTitle); const setAutoTitle = useChatRuntimeStore((s) => s.setAutoTitle); + const chatOnly = usePlatformStore((s) => s.chatOnly); const redirectTo = `${pathname}${search}`; const [draftToken, setDraftToken] = useState(hfToken ?? ""); @@ -170,24 +172,26 @@ export function GeneralTab() { - - - - - + + + + )}