Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
| import { idb } from "$lib/remult.js"; | |
| import { dequal } from "dequal"; | |
| import { Entity, Fields, repo, type MembersOnly } from "remult"; | |
| import { PersistedState } from "runed"; | |
| import { checkpoints } from "./checkpoints.svelte"; | |
| import { conversations } from "./conversations.svelte"; | |
| import { createInit } from "$lib/spells/create-init.svelte"; | |
| ("project") | |
| export class ProjectEntity { | |
| .cuid() | |
| id!: string; | |
| .string() | |
| name!: string; | |
| .string() | |
| systemMessage?: string; | |
| .json() | |
| enabledMCPs?: string[]; | |
| .string() | |
| branchedFromId?: string | null; | |
| .number() | |
| branchedFromMessageIndex?: number | null; | |
| } | |
| export type ProjectEntityMembers = MembersOnly<ProjectEntity>; | |
| const projectsRepo = repo(ProjectEntity, idb); | |
| const LOCAL_STORAGE_KEY = "hf_inf_pg_active_pid"; | |
| export const DEFAULT_PROJECT_ID = "default"; | |
| const defaultProj = projectsRepo.create({ id: DEFAULT_PROJECT_ID, name: "Default" }); | |
| class Projects { | |
| #projects: Record<ProjectEntity["id"], ProjectEntity> = $state({ default: defaultProj }); | |
| #activeId = new PersistedState(LOCAL_STORAGE_KEY, "default"); | |
| get activeId() { | |
| return this.#activeId.current; | |
| } | |
| set activeId(id: string) { | |
| this.#activeId.current = id; | |
| } | |
| init = createInit(async () => { | |
| const res = await projectsRepo.find(); | |
| if (!res.some(p => p.id === this.activeId)) this.activeId === DEFAULT_PROJECT_ID; | |
| res.forEach(p => { | |
| if (dequal(this.#projects[p.id], p)) return; | |
| this.#projects[p.id] = p; | |
| }); | |
| }); | |
| async create(args: Omit<ProjectEntity, "id">): Promise<string> { | |
| const p = await projectsRepo.save({ ...args }); | |
| this.#projects[p.id] = p; | |
| return p.id; | |
| } | |
| saveProject = async (args: { name: string; moveCheckpoints?: boolean }) => { | |
| const defaultProject = this.all.find(p => p.id === DEFAULT_PROJECT_ID); | |
| if (!defaultProject) return; | |
| const id = await this.create({ name: args.name, systemMessage: defaultProject.systemMessage }); | |
| if (args.moveCheckpoints) { | |
| checkpoints.migrate(defaultProject.id, id); | |
| } | |
| // conversations.migrate(defaultProject.id, id).then(_ => (this.#activeId.current = id)); | |
| conversations.migrate(defaultProject.id, id).then(() => { | |
| this.activeId = id; | |
| }); | |
| return id; | |
| }; | |
| get current() { | |
| return this.#projects[this.activeId]; | |
| } | |
| get all() { | |
| return Object.values(this.#projects); | |
| } | |
| async update(data: ProjectEntity) { | |
| if (!data.id) return; | |
| await projectsRepo.upsert({ where: { id: data.id }, set: data }); | |
| this.#projects[data.id] = { ...data }; | |
| } | |
| async delete(id: string) { | |
| if (!id) return; | |
| await projectsRepo.delete(id); | |
| await conversations.deleteAllFrom(id); | |
| delete this.#projects[id]; | |
| if (this.activeId === id) { | |
| this.activeId = DEFAULT_PROJECT_ID; | |
| } | |
| } | |
| branch = async (fromProjectId: string, messageIndex: number): Promise<string> => { | |
| const fromProject = this.#projects[fromProjectId]; | |
| if (!fromProject) throw new Error("Source project not found"); | |
| // Create new project with branching info | |
| const newProjectId = await this.create({ | |
| name: `${fromProject.name} (branch)`, | |
| systemMessage: fromProject.systemMessage, | |
| branchedFromId: fromProjectId, | |
| branchedFromMessageIndex: messageIndex, | |
| }); | |
| // Copy conversations up to the specified message index | |
| await conversations.duplicateUpToMessage(fromProjectId, newProjectId, messageIndex); | |
| // Switch to the new project | |
| this.activeId = newProjectId; | |
| return newProjectId; | |
| }; | |
| getBranchedFromProject = (projectId: string) => { | |
| const project = this.#projects[projectId]; | |
| if (!project?.branchedFromId) return null; | |
| const originalProject = this.#projects[project.branchedFromId]; | |
| return originalProject; | |
| }; | |
| clearBranchStatus = async (projectId: string) => { | |
| const project = this.#projects[projectId]; | |
| if (!project?.branchedFromId) return; | |
| await this.update({ | |
| ...project, | |
| branchedFromId: null, | |
| branchedFromMessageIndex: null, | |
| }); | |
| }; | |
| } | |
| export const projects = new Projects(); | |