m64_958790edae53 / human/index.html
79 lines, 4.4 KBraw
1<!doctype html>2<html lang="en">3<meta charset="utf-8">4<meta name="viewport" content="width=device-width, initial-scale=1">5<title>hello-world · an m64 capsule</title>6<style>7 :root { color-scheme: light dark; --fg: #1d1d1f; --bg: #f6f5f2; --card: #fff; --muted: #6b6b70; --line: #d8d6d0; --accent: #0f766e; --code: #efede8; }8 @media (prefers-color-scheme: dark) { :root { --fg: #ecebe8; --bg: #161616; --card: #1f1f1f; --muted: #9a9a9f; --line: #333; --accent: #2dd4bf; --code: #262626; } }9 * { box-sizing: border-box; }10 body { margin: 0; padding: 24px 16px; font: 15px/1.5 system-ui, sans-serif; color: var(--fg); background: var(--bg); }11 main { max-width: 760px; margin: 0 auto; }12 h1 { font-size: 22px; margin: 0 0 4px; }13 h2 { font-size: 16px; margin: 26px 0 6px; }14 .sub { color: var(--muted); margin: 0 0 18px; font-size: 14px; }15 a { color: var(--accent); }16 code { background: var(--code); border-radius: 4px; padding: 0 4px; font-size: 13px; }17 pre { background: var(--code); border-radius: 6px; padding: 10px; overflow-x: auto; font-size: 13px; }18 table { border-collapse: collapse; width: 100%; font-size: 14px; }19 td, th { border-bottom: 1px solid var(--line); padding: 6px 8px; text-align: left; vertical-align: top; }20 form { display: flex; gap: 8px; }21 input, button { font: inherit; color: inherit; background: var(--card); border: 1px solid var(--line); border-radius: 6px; padding: 6px 10px; }22 input { flex: 1; min-width: 0; }23 button { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; cursor: pointer; }24 #out { background: var(--card); border: 1px solid var(--line); border-radius: 8px; padding: 10px 12px; min-height: 2.6em; margin-top: 8px; white-space: pre-wrap; }25</style>26<main>27 <h1>hello-world</h1>28 <p class="sub">The smallest m64 capsule. Status: <span id="phase">checking…</span> · For agents: <a href="../agent">/agent</a></p>2930 <h2>Try it</h2>31 <form id="f"><input id="msg" value="hi there" aria-label="message"><button>Send</button></form>32 <div id="out"></div>3334 <h2>What a capsule is</h2>35 <p>A capsule is a small folder that <code>m64</code> turns into a sandboxed local server. Its id36 (<code>m64_…</code>) is the hash of its files: the same id always means the same code.</p>37 <table>38 <tr><th>File</th><th>What it does here</th></tr>39 <tr><td><code>capsule.toml</code></td><td>The manifest: kind <code>chat</code>, CPU only, a pinned Python image, port 9000.</td></tr>40 <tr><td><code>start.sh</code></td><td>The entrypoint the container runs: it starts <code>server.py</code>.</td></tr>41 <tr><td><code>server.py</code></td><td>The whole "model": it answers <em>Hello, world! You said: …</em></td></tr>42 <tr><td><code>AGENT.md</code></td><td>What an agent reads at <a href="../agent">/agent</a>, with the URL filled in.</td></tr>43 <tr><td><code>human/</code></td><td>This page, served at <code>/human/</code>.</td></tr>44 </table>4546 <h2>What m64 does around it</h2>47 <ul>48 <li>Runs it in a container as an unprivileged user, with no network at all.</li>49 <li>Serves <code>/status</code>, <code>/agent</code> and <code>/human/</code> itself.</li>50 </ul>5152 <h2>From the command line</h2>53 <pre id="curl">…</pre>5455 <h2>Make your own</h2>56 <pre>m64 fork <this capsule's id> my-capsule # copy it57$EDITOR my-capsule/server.py58m64 check my-capsule # the same checks motif64.sh runs59m64 my-capsule # serve it and open this page</pre>60</main>61<script>62const $ = (id) => document.getElementById(id);63const base = location.href.replace(/\/human\/.*$/, "");64$("curl").textContent = `curl -s ${base}/v1/chat/completions \\\n -H 'Content-Type: application/json' \\\n -d '{"messages":[{"role":"user","content":"hi there"}]}'`;65fetch("../status").then((r) => r.json()).then((s) => { $("phase").textContent = s.phase || "?"; })66 .catch(() => { $("phase").textContent = "status unavailable"; });67$("f").addEventListener("submit", async (e) => {68 e.preventDefault();69 $("out").textContent = "…";70 try {71 const r = await fetch("../v1/chat/completions", {72 method: "POST", headers: { "Content-Type": "application/json" },73 body: JSON.stringify({ messages: [{ role: "user", content: $("msg").value }] }),74 });75 const d = await r.json();76 $("out").textContent = r.ok ? d.choices[0].message.content : `HTTP ${r.status}: ${JSON.stringify(d)}`;77 } catch (err) { $("out").textContent = String(err); }78});79</script>