fix: patch help_improve bug (#1455)

Co-authored-by: Wendong-Fan <133094783+Wendong-Fan@users.noreply.github.com>
This commit is contained in:
Ahmed Awelkair A 2026-03-05 15:35:33 +00:00 committed by GitHub
parent 1d6a8550e0
commit 737bd1eaeb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 135 additions and 51 deletions

View file

@ -77,7 +77,7 @@ def get_privacy(session: Session = Depends(session), auth: Auth = Depends(auth_m
return UserPrivacySettings.default_settings()
logger.debug("Privacy settings retrieved", extra={"user_id": user_id})
return model.pricacy_setting
return UserPrivacySettings(**model.pricacy_setting).to_response()
@router.put("/user/privacy", name="update user privacy")
@ -97,7 +97,7 @@ def put_privacy(data: UserPrivacySettings, session: Session = Depends(session),
model.save(session)
logger.info("Privacy settings created", extra={"user_id": user_id})
return model.pricacy_setting
return UserPrivacySettings(**model.pricacy_setting).to_response()
@router.get("/user/current_credits", name="get user current credits")

View file

@ -1,16 +1,18 @@
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
from typing import ClassVar
from pydantic import BaseModel
from sqlalchemy import JSON
@ -31,6 +33,21 @@ class UserPrivacySettings(BaseModel):
access_your_address: bool | None = False
password_storage: bool | None = False
# Fields that must all be True for the user to proceed
REQUIRED_FIELDS: ClassVar[list[str]] = [
'take_screenshot',
'access_local_software',
'access_your_address',
'password_storage',
]
@classmethod
def default_settings(cls) -> dict:
return cls().model_dump()
instance = cls()
return {**instance.model_dump(), "all_required_granted": instance.all_required_granted()}
def all_required_granted(self) -> bool:
return all(getattr(self, f) for f in self.REQUIRED_FIELDS)
def to_response(self) -> dict:
return {**self.model_dump(), "all_required_granted": self.all_required_granted()}

80
server/tests/user.http Normal file
View file

@ -0,0 +1,80 @@
### ============================================
### Eigent Server API Tests
### ============================================
### VSCode Extension: "REST Client" by Huachao Mao
### Extension ID: humao.rest-client
### ============================================
@baseUrl = http://localhost:3001/api
@token = YOUR_TOKEN_HERE
### ──────────────────────────────────────────
### Auth (no token required)
### ──────────────────────────────────────────
### Register a new user
POST {{baseUrl}}/register
Content-Type: application/json
{
"email": "test@example.com",
"password": "testpassword123"
}
### Login
# @name login
POST {{baseUrl}}/login
Content-Type: application/json
{
"email": "test@example.com",
"password": "testpassword123"
}
### Save token from login response (use this after running login)
@authToken = {{login.response.body.token}}
### ──────────────────────────────────────────
### User
### ──────────────────────────────────────────
### Get current user info
GET {{baseUrl}}/user
Authorization: Bearer {{authToken}}
### ──────────────────────────────────────────
### Privacy Settings
### ──────────────────────────────────────────
### Get privacy settings
GET {{baseUrl}}/user/privacy
Authorization: Bearer {{authToken}}
### Update privacy settings
PUT {{baseUrl}}/user/privacy
Authorization: Bearer {{authToken}}
Content-Type: application/json
{
"take_screenshot": true,
"access_local_software": false,
"access_your_address": false,
"password_storage": false
}
### Update only help_improve
PUT {{baseUrl}}/user/privacy
Authorization: Bearer {{authToken}}
Content-Type: application/json
{
"help_improve": true
}
### ──────────────────────────────────────────
### User Stats
### ──────────────────────────────────────────
### Get user stats
GET {{baseUrl}}/user/stat
Authorization: Bearer {{authToken}}

View file

@ -65,14 +65,7 @@ export default function ChatBox(): JSX.Element {
useEffect(() => {
proxyFetchGet('/api/user/privacy')
.then((res) => {
let _privacy = 0;
Object.keys(res).forEach((key) => {
if (!res[key]) {
_privacy++;
return;
}
});
setPrivacy(_privacy === 0 ? true : false);
setPrivacy(res.all_required_granted);
})
.catch((err) => console.error('Failed to fetch settings:', err));
@ -989,7 +982,7 @@ export default function ChatBox(): JSX.Element {
}
return (
<div className="rounded-2xl border-border-tertiary bg-surface-secondary h-full w-full flex-none items-center justify-center overflow-hidden border-solid">
<div className="h-full w-full flex-none items-center justify-center overflow-hidden rounded-2xl border-solid border-border-tertiary bg-surface-secondary">
{/* Unified ChatBox Structure */}
<div className="relative flex h-full w-full flex-col overflow-hidden">
{/* Header Box - Always visible */}
@ -1006,10 +999,10 @@ export default function ChatBox(): JSX.Element {
<div className="relative flex flex-1 flex-col overflow-hidden">
{/* Project Chat Container - Show when has messages (absolute, full height) */}
<div
className={`inset-0 ease-in-out absolute flex h-full flex-col transition-all duration-300 ${
className={`absolute inset-0 flex h-full flex-col transition-all duration-300 ease-in-out ${
hasAnyMessages
? 'translate-y-0 pointer-events-auto opacity-100'
: '-translate-y-4 pointer-events-none opacity-0'
? 'pointer-events-auto translate-y-0 opacity-100'
: 'pointer-events-none -translate-y-4 opacity-0'
}`}
>
<ProjectChatContainer
@ -1020,15 +1013,15 @@ export default function ChatBox(): JSX.Element {
{/* Init State Container - Welcome + BottomBox + Suggestions (vertically centered) */}
<div
className={`ease-in-out flex flex-1 flex-col transition-all duration-300 ${
className={`flex flex-1 flex-col transition-all duration-300 ease-in-out ${
hasAnyMessages
? 'inset-0 pointer-events-none absolute opacity-0'
? 'pointer-events-none absolute inset-0 opacity-0'
: 'pointer-events-auto opacity-100'
}`}
>
{/* Welcome Message - Top area, flex-1 to push content down */}
<div className="gap-1 pb-4 flex flex-1 flex-col items-center justify-end">
<div className="text-body-lg font-bold text-text-heading text-center">
<div className="flex flex-1 flex-col items-center justify-end gap-1 pb-4">
<div className="text-center text-body-lg font-bold text-text-heading">
{t('layout.welcome-to-eigent')}
</div>
</div>
@ -1067,24 +1060,24 @@ export default function ChatBox(): JSX.Element {
)}
{/* Suggestion Area - Bottom area, flex-1 to push content up */}
<div className="mt-3 gap-2 flex h-[210px] flex-1 items-start justify-center">
<div className="mt-3 flex h-[210px] flex-1 items-start justify-center gap-2">
{!hasModel ? (
<div className="gap-2 flex items-center">
<div className="flex items-center gap-2">
<div
onClick={() => {
navigate('/history?tab=agents');
}}
className="gap-2 rounded-md bg-surface-warning px-sm py-xs flex cursor-pointer items-center"
className="flex cursor-pointer items-center gap-2 rounded-md bg-surface-warning px-sm py-xs"
>
<TriangleAlert size={20} className="text-icon-warning" />
<span className="text-xs font-medium text-text-warning flex-1 leading-[20px]">
<span className="flex-1 text-xs font-medium leading-[20px] text-text-warning">
{t('layout.please-select-model')}
</span>
</div>
</div>
) : null}
{hasModel && !privacy ? (
<div className="gap-2 flex items-center">
<div className="flex items-center gap-2">
<div
onClick={(e) => {
const target = e.target as HTMLElement;
@ -1106,13 +1099,13 @@ export default function ChatBox(): JSX.Element {
proxyFetchPut('/api/user/privacy', requestData);
setPrivacy(true);
}}
className="gap-1 rounded-md bg-surface-information px-sm py-xs flex cursor-pointer items-center"
className="flex cursor-pointer items-center gap-1 rounded-md bg-surface-information px-sm py-xs"
>
<TriangleAlert
size={20}
className="text-icon-information"
/>
<span className="text-xs font-medium text-text-information flex-1 leading-[20px]">
<span className="flex-1 text-xs font-medium leading-[20px] text-text-information">
{t('layout.by-messaging-eigent')}{' '}
<a
href="https://www.eigent.ai/terms-of-use"
@ -1138,7 +1131,7 @@ export default function ChatBox(): JSX.Element {
</div>
</div>
) : (
<div className="mr-2 gap-2 flex flex-col items-center">
<div className="mr-2 flex flex-col items-center gap-2">
{[
{
label: t('layout.it-ticket-creation'),
@ -1155,7 +1148,7 @@ export default function ChatBox(): JSX.Element {
].map(({ label, message }) => (
<div
key={label}
className="rounded-md bg-surface-tertiary px-sm py-xs text-xs font-medium text-button-tertiery-text-default cursor-pointer leading-none opacity-70 transition-all duration-300 hover:opacity-100"
className="cursor-pointer rounded-md bg-surface-tertiary px-sm py-xs text-xs font-medium leading-none text-button-tertiery-text-default opacity-70 transition-all duration-300 hover:opacity-100"
onClick={() => {
setMessage(message);
}}

View file

@ -59,19 +59,13 @@ export default function SettingPrivacy() {
useEffect(() => {
proxyFetchGet('/api/user/privacy')
.then((res) => {
let hasFalse = false;
setSettings((prev) =>
prev.map((item, index) => {
if (!res[API_FIELDS[index]]) {
hasFalse = true;
}
return {
...item,
checked: res[API_FIELDS[index]] || false,
};
})
prev.map((item, index) => ({
...item,
checked: res[API_FIELDS[index]] || false,
}))
);
setPrivacy(!hasFalse);
setPrivacy(res.all_required_granted);
})
.catch((err) => console.error('Failed to fetch settings:', err));
}, [API_FIELDS]);