diff --git a/frontend-web/src/components/workspace/settings/skill-settings-page.tsx b/frontend-web/src/components/workspace/settings/skill-settings-page.tsx
index 2a011b25..67db57a4 100644
--- a/frontend-web/src/components/workspace/settings/skill-settings-page.tsx
+++ b/frontend-web/src/components/workspace/settings/skill-settings-page.tsx
@@ -2,6 +2,7 @@
import {
AlertCircle,
+ Anchor,
ArchiveIcon,
ArrowDownUpIcon,
BookmarkIcon,
@@ -77,6 +78,7 @@ import {
useGenerateSkillNameZh,
useInstallSkillUpload,
useReconcileCustomSkills,
+ useSetSkillAlwaysOn,
useSetSkillFeatured,
useSetSkillNameZh,
useSetSkillPinned,
@@ -84,7 +86,11 @@ import {
useSkills,
useValidateSkillUpload,
} from "@/core/skills/hooks";
-import { usePublishSquares, useViewMode } from "@/core/system-settings/hooks";
+import {
+ usePublishSquares,
+ useSkillCompressionSettings,
+ useViewMode,
+} from "@/core/system-settings/hooks";
import type { Skill } from "@/core/skills/type";
import { formatDateTime } from "@/core/utils/datetime";
import { env } from "@/env";
@@ -181,8 +187,10 @@ function SkillSettingsList({ onClose }: { onClose?: () => void }) {
const isAdmin = storedAuth?.system_role === "admin";
// Name + tag filtering is resolved server-side via the /api/skills query.
- // Non-admins get their 岗位 (position) visibility applied (scope=mine): a
- // position that binds skill tags restricts which skills they can see.
+ // A 岗位 (position) no longer *restricts* the list — it grants skills into the
+ // member's 我的技能 (each such skill comes back with ``favorited: true``), so
+ // the 广场 always shows every visible skill and the 我的 tab includes the
+ // position-granted ones. ``scope`` is kept for API compatibility only.
const { skills, isLoading, error } = useSkills({
search,
tagIds,
@@ -217,7 +225,9 @@ function SkillSettingsList({ onClose }: { onClose?: () => void }) {
if (isBuiltin || !!skill.published) {
all.push(skill);
}
- if (isOwnedByMe) {
+ // "我的" = skills I own OR skills granted into my collection by my 岗位
+ // (position) — mirroring how favorited agents land in 我的智能体.
+ if (isOwnedByMe || !!skill.favorited) {
mine.push(skill);
}
}
@@ -601,6 +611,8 @@ export function SkillRow({
const { data: cardPublishSquares } = usePublishSquares();
const setPinned = useSetSkillPinned();
const setFeatured = useSetSkillFeatured();
+ const setAlwaysOn = useSetSkillAlwaysOn();
+ const { data: compression } = useSkillCompressionSettings();
const deleteSkill = useDeleteCustomSkill();
const duplicateSkillMutation = useDuplicateSkill();
const [confirmDeleteOpen, setConfirmDeleteOpen] = useState(false);
@@ -620,6 +632,17 @@ export function SkillRow({
// Admin can edit/delete/unpublish anyone's skill; non-admin only their own.
const canManage = isCustom && (isOwned || isAdmin);
const canTogglePublish = canManage && !isBuiltin;
+ // 常驻(免压缩):内置技能仅管理员可设;自定义技能其所有者或管理员可设(与后端一致)。
+ const canSetAlwaysOn = isAdmin || isOwned;
+
+ async function handleToggleAlwaysOn(next: boolean) {
+ try {
+ await setAlwaysOn.mutateAsync({ skillName: skill.name, alwaysOn: next });
+ toast.success(next ? "已设为常驻(免压缩)" : "已取消常驻");
+ } catch (err) {
+ toast.error(err instanceof Error ? err.message : String(err));
+ }
+ }
async function handleTogglePublished(next: boolean) {
// Publishing: prompt for which square to publish into (when configured).
@@ -932,6 +955,27 @@ export function SkillRow({
/>
)}
+ {compression?.enabled && canSetAlwaysOn && (
+
+ )}
{canTogglePublish && (