open-swe/ui/src/components/InstructionsEditor.tsx
Johannes du Plessis da8f003933
feat: per-repo custom instructions for the coding agent (#1460)
* feat: per-repo custom instructions for the coding agent

Adds per-repository custom instructions for the main coding agent,
mirroring the reviewer's per-repo style prompts. Instructions are stored
in the LangGraph Store, managed via dashboard API + UI (Monaco editor),
and appended to the agent's system prompt for runs targeting that repo.

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>

* chore: wire agent instructions route into generated route tree

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>

* fix: enforce repo access on instruction routes

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2026-06-09 15:46:29 -07:00

59 lines
1.4 KiB
TypeScript

import Editor from "@monaco-editor/react";
import { useEffect, useState } from "react";
import { Textarea } from "@/components/ui/textarea";
interface InstructionsEditorProps {
value: string;
onChange: (value: string) => void;
disabled?: boolean;
placeholder?: string;
}
/** Monaco-backed markdown editor that falls back to a textarea before mount (SSR-safe). */
export function InstructionsEditor({
value,
onChange,
disabled,
placeholder,
}: InstructionsEditorProps) {
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
if (!mounted) {
return (
<Textarea
className="min-h-[360px] w-full font-mono text-xs"
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
disabled={disabled}
/>
);
}
return (
<div className="overflow-hidden rounded-md border border-border">
<Editor
height="360px"
defaultLanguage="markdown"
value={value}
onChange={(v) => onChange(v ?? "")}
options={{
readOnly: disabled,
minimap: { enabled: false },
wordWrap: "on",
fontSize: 12,
lineNumbers: "on",
scrollBeyondLastLine: false,
padding: { top: 12, bottom: 12 },
renderLineHighlight: "none",
}}
theme="vs-dark"
/>
</div>
);
}