Phase 3: Skills & Context — skill system, personal context, context layering
Backend: - Skill model + migration (with FK on chats.skill_id) - Personal + general skill CRUD services with access isolation - Admin skill CRUD endpoints (POST/GET/PATCH/DELETE /admin/skills) - User skill CRUD endpoints (POST/GET/PATCH/DELETE /skills/) - Personal context GET/PUT at /users/me/context - Extended context assembly: primary + personal context + skill prompt - Chat creation/update now accepts skill_id with validation Frontend: - Skill selector dropdown in chat header (grouped: general + personal) - Reusable skill editor form component - Admin skills management page (/admin/skills) - Personal skills page (/skills) - Personal context editor page (/profile/context) - Updated sidebar: Skills, My Context nav items + admin skills link - English + Russian translations for all skill/context UI Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -46,7 +46,7 @@ export async function getChat(chatId: string): Promise<Chat> {
|
||||
|
||||
export async function updateChat(
|
||||
chatId: string,
|
||||
updates: { title?: string; is_archived?: boolean }
|
||||
updates: { title?: string; is_archived?: boolean; skill_id?: string }
|
||||
): Promise<Chat> {
|
||||
const { data } = await api.patch<Chat>(`/chats/${chatId}`, updates);
|
||||
return data;
|
||||
|
||||
93
frontend/src/api/skills.ts
Normal file
93
frontend/src/api/skills.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import api from "./client";
|
||||
|
||||
export interface Skill {
|
||||
id: string;
|
||||
user_id: string | null;
|
||||
name: string;
|
||||
description: string | null;
|
||||
system_prompt: string;
|
||||
icon: string | null;
|
||||
is_active: boolean;
|
||||
sort_order: number;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface SkillListResponse {
|
||||
skills: Skill[];
|
||||
}
|
||||
|
||||
export async function getSkills(includeGeneral = true): Promise<Skill[]> {
|
||||
const { data } = await api.get<SkillListResponse>("/skills/", {
|
||||
params: { include_general: includeGeneral },
|
||||
});
|
||||
return data.skills;
|
||||
}
|
||||
|
||||
export async function getSkill(skillId: string): Promise<Skill> {
|
||||
const { data } = await api.get<Skill>(`/skills/${skillId}`);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function createSkill(skill: {
|
||||
name: string;
|
||||
description?: string;
|
||||
system_prompt: string;
|
||||
icon?: string;
|
||||
}): Promise<Skill> {
|
||||
const { data } = await api.post<Skill>("/skills/", skill);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function updateSkill(
|
||||
skillId: string,
|
||||
updates: Partial<{
|
||||
name: string;
|
||||
description: string;
|
||||
system_prompt: string;
|
||||
icon: string;
|
||||
is_active: boolean;
|
||||
sort_order: number;
|
||||
}>
|
||||
): Promise<Skill> {
|
||||
const { data } = await api.patch<Skill>(`/skills/${skillId}`, updates);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function deleteSkill(skillId: string): Promise<void> {
|
||||
await api.delete(`/skills/${skillId}`);
|
||||
}
|
||||
|
||||
// Admin skill functions
|
||||
export async function getGeneralSkills(): Promise<Skill[]> {
|
||||
const { data } = await api.get<SkillListResponse>("/admin/skills");
|
||||
return data.skills;
|
||||
}
|
||||
|
||||
export async function createGeneralSkill(skill: {
|
||||
name: string;
|
||||
description?: string;
|
||||
system_prompt: string;
|
||||
icon?: string;
|
||||
}): Promise<Skill> {
|
||||
const { data } = await api.post<Skill>("/admin/skills", skill);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function updateGeneralSkill(
|
||||
skillId: string,
|
||||
updates: Partial<{
|
||||
name: string;
|
||||
description: string;
|
||||
system_prompt: string;
|
||||
icon: string;
|
||||
is_active: boolean;
|
||||
sort_order: number;
|
||||
}>
|
||||
): Promise<Skill> {
|
||||
const { data } = await api.patch<Skill>(`/admin/skills/${skillId}`, updates);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function deleteGeneralSkill(skillId: string): Promise<void> {
|
||||
await api.delete(`/admin/skills/${skillId}`);
|
||||
}
|
||||
14
frontend/src/api/user-context.ts
Normal file
14
frontend/src/api/user-context.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import api from "./client";
|
||||
import type { ContextFile } from "./admin";
|
||||
|
||||
export async function getPersonalContext(): Promise<ContextFile | null> {
|
||||
const { data } = await api.get<ContextFile | null>("/users/me/context");
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function updatePersonalContext(
|
||||
content: string
|
||||
): Promise<ContextFile> {
|
||||
const { data } = await api.put<ContextFile>("/users/me/context", { content });
|
||||
return data;
|
||||
}
|
||||
Reference in New Issue
Block a user