We want Monaco to treat the prompt constructor as Typescript so we get type checks, but we actually want to save the prompt constructor as Javascript so we can run it directly without transpiling.
103 lines
2.8 KiB
TypeScript
103 lines
2.8 KiB
TypeScript
import { type RouterOutputs } from "~/utils/api";
|
|
import { type SliceCreator } from "./store";
|
|
import loader from "@monaco-editor/loader";
|
|
import openAITypes from "~/codegen/openai.types.ts.txt";
|
|
import formatPromptConstructor from "~/utils/formatPromptConstructor";
|
|
|
|
export const editorBackground = "#fafafa";
|
|
|
|
export type SharedVariantEditorSlice = {
|
|
monaco: null | ReturnType<typeof loader.__getMonacoInstance>;
|
|
loadMonaco: () => Promise<void>;
|
|
scenarios: RouterOutputs["scenarios"]["list"];
|
|
updateScenariosModel: () => void;
|
|
setScenarios: (scenarios: RouterOutputs["scenarios"]["list"]) => void;
|
|
};
|
|
|
|
export const createVariantEditorSlice: SliceCreator<SharedVariantEditorSlice> = (set, get) => ({
|
|
monaco: loader.__getMonacoInstance(),
|
|
loadMonaco: async () => {
|
|
// We only want to run this client-side
|
|
if (typeof window === "undefined") return;
|
|
|
|
const monaco = await loader.init();
|
|
|
|
monaco.editor.defineTheme("customTheme", {
|
|
base: "vs",
|
|
inherit: true,
|
|
rules: [],
|
|
colors: {
|
|
"editor.background": editorBackground,
|
|
},
|
|
});
|
|
|
|
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
|
|
allowNonTsExtensions: true,
|
|
lib: ["esnext"],
|
|
});
|
|
|
|
monaco.editor.createModel(
|
|
`
|
|
${openAITypes}
|
|
|
|
declare var prompt: components["schemas"]["CreateChatCompletionRequest"];
|
|
`,
|
|
"typescript",
|
|
monaco.Uri.parse("file:///openai.types.ts"),
|
|
);
|
|
|
|
monaco.languages.registerDocumentFormattingEditProvider("typescript", {
|
|
provideDocumentFormattingEdits: async (model) => {
|
|
return [
|
|
{
|
|
range: model.getFullModelRange(),
|
|
text: await formatPromptConstructor(model.getValue()),
|
|
},
|
|
];
|
|
},
|
|
});
|
|
|
|
set((state) => {
|
|
state.sharedVariantEditor.monaco = monaco;
|
|
});
|
|
get().sharedVariantEditor.updateScenariosModel();
|
|
},
|
|
scenarios: [],
|
|
// scenariosModel: null,
|
|
setScenarios: (scenarios) => {
|
|
set((state) => {
|
|
state.sharedVariantEditor.scenarios = scenarios;
|
|
});
|
|
|
|
get().sharedVariantEditor.updateScenariosModel();
|
|
},
|
|
|
|
updateScenariosModel: () => {
|
|
const monaco = get().sharedVariantEditor.monaco;
|
|
if (!monaco) return;
|
|
|
|
const modelContents = `
|
|
const scenarios = ${JSON.stringify(
|
|
get().sharedVariantEditor.scenarios.map((s) => s.variableValues),
|
|
null,
|
|
2,
|
|
)} as const;
|
|
|
|
type Scenario = typeof scenarios[number];
|
|
declare var scenario: Scenario | null;
|
|
`;
|
|
|
|
const scenariosModel = monaco.editor.getModel(monaco.Uri.parse("file:///scenarios.ts"));
|
|
|
|
if (scenariosModel) {
|
|
scenariosModel.setValue(modelContents);
|
|
} else {
|
|
monaco.editor.createModel(
|
|
modelContents,
|
|
"typescript",
|
|
monaco.Uri.parse("file:///scenarios.ts"),
|
|
);
|
|
}
|
|
},
|
|
});
|