import { ArrowLeftIcon, DownloadIcon } from "lucide-react"; import { useState } from "react"; import type { CompiledContextPreview as Preview, CompiledContextCheck as Check, } from "../../../core/compiled-context"; import { Button } from "../components/ui/button"; import { Card, CardContent, CardHeader, CardTitle, } from "../components/ui/card"; import { Input } from "../components/ui/input"; import { Textarea } from "../components/ui/textarea"; import { apiFetch } from "../hooks/use-api"; const MAX_BYTES = 4 * 1024 * 1024; const byteLength = (value: string): number => new TextEncoder().encode(value).length; export default function CompiledContext({ navigate, }: { navigate: (to: string | number) => void; }) { const [capsule, setCapsule] = useState(""); const [markdown, setMarkdown] = useState(""); const [tokens, setTokens] = useState("12000"); const [bytes, setBytes] = useState(""); const [preview, setPreview] = useState(null); const [check, setCheck] = useState(null); const [busy, setBusy] = useState(false); const [error, setError] = useState(null); const invalidate = () => { setPreview(null); setCheck(null); setError(null); }; const upload = async ( file: File | undefined, kind: "capsule" | "markdown" ) => { if (!file) return; invalidate(); if (kind === "capsule") setCapsule(""); else setMarkdown(""); if (file.size > MAX_BYTES) { setError("Files must be 4 MiB or smaller."); return; } setBusy(true); try { const text = await file.text(); if (kind === "capsule") setCapsule(text); else setMarkdown(text); } catch { setError("Could not read this file."); } finally { setBusy(false); } }; const run = async (kind: "preview" | "check") => { invalidate(); setBusy(true); try { if (byteLength(capsule) > MAX_BYTES || byteLength(markdown) > MAX_BYTES) throw new Error("Inputs must be 4 MiB or smaller."); const parsed: unknown = JSON.parse(capsule); if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("Supply a Capsule JSON object."); if (kind === "preview") { const budgetTokens = Number(tokens); const budgetBytes = bytes === "" ? undefined : Number(bytes); if ( !Number.isInteger(budgetTokens) || budgetTokens < 1 || budgetTokens > 1_000_000 || (budgetBytes !== undefined && (!Number.isInteger(budgetBytes) || budgetBytes < 1 || budgetBytes > MAX_BYTES)) ) throw new Error( "Choose a positive budget: at most 1,000,000 tokens and 4 MiB." ); const result = await apiFetch( "/api/context/compiled/preview", { method: "POST", body: JSON.stringify({ capsule: parsed, budgetTokens, budgetBytes, }), } ); if (result.error || !result.data) throw new Error(result.error ?? "No preview returned."); setPreview(result.data); } else { if (!markdown.trim()) throw new Error("Supply the compiled Markdown to check."); const result = await apiFetch("/api/context/compiled/check", { method: "POST", body: JSON.stringify({ capsule: parsed, markdown }), }); if (result.error || !result.data) throw new Error(result.error ?? "No check returned."); setCheck(result.data); } } catch (cause) { setError(cause instanceof Error ? cause.message : "Request failed."); } finally { setBusy(false); } }; const download = () => { if (!preview) return; const url = URL.createObjectURL( new Blob([preview.markdown], { type: "text/markdown;charset=utf-8" }) ); const link = document.createElement("a"); link.href = url; link.download = "project.gno-context.md"; link.click(); setTimeout(() => URL.revokeObjectURL(url), 1000); }; return (

Compiled project context

Turn a verified Context Capsule into a compact, cited Markdown file. Source passages remain untrusted evidence, not agent instructions.

{ event.preventDefault(); void run("preview"); }} >
Compile a Context Capsule 1. Supply a Capsule

Use a Capsule from this GNO instance. Verification checks current sources and access before returning evidence. Inputs are limited to 4 MiB each.