motif64

m64_ed4181ee0b62 / 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 &lt;this capsule's id&gt; 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>