teapot-coding-agent 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -8
- package/dist/agent/agent.js +73 -62
- package/dist/agent/tools.js +16 -4
- package/dist/server/api.js +25 -0
- package/package.json +1 -1
- package/public/assets/{index-C4RhCPYd.js → index-JRXeHcww.js} +1 -1
- package/public/index.html +1 -1
package/README.md
CHANGED
|
@@ -110,18 +110,24 @@ master (Hono server, src/master.ts + src/server/api.ts)
|
|
|
110
110
|
never hard-coded.
|
|
111
111
|
- **Tools** (`src/agent/tools.ts`): provider-agnostic JSON-schema function
|
|
112
112
|
specs — `read_file`, `write_file`, `edit_file`, `list_dir`, `bash` (git goes
|
|
113
|
-
through bash), plus meta tools `finish` / `report_progress` / `
|
|
114
|
-
`
|
|
115
|
-
|
|
113
|
+
through bash), plus meta tools `finish` / `report_progress` / `get_goal` /
|
|
114
|
+
`set_goal` / `read_memory` / `set_memory` / `list_skills`. Paths are
|
|
115
|
+
confined to the workspace; bash runs detached in its own process group and
|
|
116
|
+
the whole group is SIGKILLed on timeout.
|
|
117
|
+
- **Cache-friendly prompt design** — the system prompt is byte-identical on
|
|
118
|
+
every turn; session state (goal, memory, skills) is fetched via tools, never
|
|
119
|
+
injected. Combined with the append-only message history this keeps provider
|
|
120
|
+
prefix caches hot, so long sessions pay incremental input prices instead of
|
|
121
|
+
re-sending full context every turn.
|
|
116
122
|
- **Session storage** — everything teapot manages lives under
|
|
117
123
|
`<dataDir>/sessions/<sid>/` (`chat.jsonl`, `goal.md`, `memory.md`), so agent
|
|
118
124
|
workspaces stay clean. Each incarnation gets a fresh `<agentId>-<uuid>`
|
|
119
125
|
directory (no history leaks across projects); restarts reuse the latest one.
|
|
120
126
|
Legacy layouts are migrated automatically.
|
|
121
|
-
- **Goal / knowledge** — goal + memory are harness-managed and
|
|
122
|
-
|
|
123
|
-
`AGENTS.md` is optional project knowledge in the workspace root that
|
|
124
|
-
|
|
127
|
+
- **Goal / knowledge** — goal + memory are harness-managed and read/written
|
|
128
|
+
through tools (`get_goal` / `set_goal` / `read_memory` / `set_memory`);
|
|
129
|
+
`AGENTS.md` is optional project knowledge in the workspace root that agents
|
|
130
|
+
are told to read at session start. Nothing is seeded into your project.
|
|
125
131
|
|
|
126
132
|
### Web UI
|
|
127
133
|
|
|
@@ -221,7 +227,14 @@ GET /brew 418 I'm a teapot (RFC 2324)
|
|
|
221
227
|
Designed for a dedicated agent Linux user; workspaces are path-confined,
|
|
222
228
|
subprocesses run in killable process groups with hard timeouts, and resource
|
|
223
229
|
limits (RLIMIT_* / cgroups) have a natural insertion point in
|
|
224
|
-
`src/agent/tools.ts:runShell`.
|
|
230
|
+
`src/agent/tools.ts:runShell`.
|
|
231
|
+
|
|
232
|
+
**LAN exposure**: the API has no auth by default (localhost-first tool). To
|
|
233
|
+
expose it beyond localhost, set `TEAPOT_API_TOKEN=<secret>` — every `/api/*`
|
|
234
|
+
route then requires `Authorization: Bearer <secret>` (WebSocket handshakes
|
|
235
|
+
accept `?token=<secret>`). In the web UI, open
|
|
236
|
+
`http://host:7788/#token=<secret>` once; the token is stored locally and
|
|
237
|
+
attached automatically. The master survives agent crashes by
|
|
225
238
|
construction: agent errors never escape their own loop, and global handlers
|
|
226
239
|
keep the process alive.
|
|
227
240
|
|
package/dist/agent/agent.js
CHANGED
|
@@ -12,26 +12,29 @@ import { EventLog, readEvents } from "../log/events.js";
|
|
|
12
12
|
import { chat, chatStream } from "./llm.js";
|
|
13
13
|
import { executeTool, toolSpecs, currentSkills } from "./tools.js";
|
|
14
14
|
import { bus } from "../bus.js";
|
|
15
|
+
/**
|
|
16
|
+
* SYSTEM_TEMPLATE must stay byte-identical across every request of a session:
|
|
17
|
+
* provider prefix caches key on it, so changing it (or injecting per-turn
|
|
18
|
+
* state) re-prices the whole context. That is why session state lives behind
|
|
19
|
+
* meta tools instead. The cache rationale itself stays HERE in a comment —
|
|
20
|
+
* the model does not need our cost-engineering notes every turn.
|
|
21
|
+
*/
|
|
15
22
|
const SYSTEM_TEMPLATE = `You are a coding agent working autonomously inside a workspace.
|
|
16
23
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
set_memory(content); they are injected into future prompts.
|
|
27
|
-
- skills/: reusable playbooks via load_skill / save_skill.
|
|
24
|
+
Session state is not injected into prompts — fetch it with tools instead:
|
|
25
|
+
- get_goal() → current objective + status. Call at session start, after a
|
|
26
|
+
compaction notice, or whenever you lose the thread.
|
|
27
|
+
- set_goal(text) → change the objective itself (not routine updates).
|
|
28
|
+
- finish(goalComplete=true, summary) → goal fully achieved.
|
|
29
|
+
- read_memory() / set_memory(content) → your durable notes (memory.md).
|
|
30
|
+
- list_skills() / load_skill(name) / save_skill(...) → reusable playbooks.
|
|
31
|
+
- AGENTS.md in the workspace root (optional) holds project knowledge — read it
|
|
32
|
+
with read_file at session start when present, keep it current.
|
|
28
33
|
|
|
29
34
|
## Rules
|
|
30
35
|
- Work step by step with tools. Verify results (run tests/builds) before claiming progress.
|
|
31
|
-
- When a
|
|
32
|
-
- When you develop a reusable procedure, save_skill it — skills persist and are offered to future sessions.
|
|
36
|
+
- When a loaded skill matches your task, follow its playbook.
|
|
33
37
|
- When you make meaningful progress, call report_progress.
|
|
34
|
-
- When the goal is fully achieved, call finish(goalComplete=true) with a short summary.
|
|
35
38
|
- Be frugal: prefer small precise edits, avoid runaway loops.`;
|
|
36
39
|
export class Agent {
|
|
37
40
|
log;
|
|
@@ -97,17 +100,6 @@ export class Agent {
|
|
|
97
100
|
/* keep previous cache */
|
|
98
101
|
}
|
|
99
102
|
}
|
|
100
|
-
skillsListing() {
|
|
101
|
-
if (this.skillsCache.length === 0) {
|
|
102
|
-
return ("## Skills\n" +
|
|
103
|
-
"No skills exist yet. When you develop a reusable procedure worth keeping " +
|
|
104
|
-
"(build steps, checklists, project conventions), distill it into a durable playbook " +
|
|
105
|
-
"with save_skill so future sessions can load it via load_skill.");
|
|
106
|
-
}
|
|
107
|
-
return ("## Skills (reusable playbooks)\n" +
|
|
108
|
-
"When the current task matches a description below, call load_skill(name) first and follow it.\n" +
|
|
109
|
-
this.skillsCache.map((s) => `- ${s.name}: ${s.description || "(no description)"}`).join("\n"));
|
|
110
|
-
}
|
|
111
103
|
callLlm(messages, tools, onDelta) {
|
|
112
104
|
const fn = this.opts.chatFn ?? chatStream;
|
|
113
105
|
return fn(this.opts.llm, messages, tools, this.abort?.signal, onDelta);
|
|
@@ -479,7 +471,7 @@ export class Agent {
|
|
|
479
471
|
turn: ++this.stats.turns,
|
|
480
472
|
});
|
|
481
473
|
// stream the assistant reply live to connected clients
|
|
482
|
-
const res = await this.llmCall(
|
|
474
|
+
const res = await this.llmCall(this.buildMessages(), allToolSpecs(), (s) => {
|
|
483
475
|
bus.emit("update", {
|
|
484
476
|
kind: "llm-delta",
|
|
485
477
|
agentId: this.opts.id,
|
|
@@ -537,6 +529,31 @@ export class Agent {
|
|
|
537
529
|
});
|
|
538
530
|
continue;
|
|
539
531
|
}
|
|
532
|
+
if (call.function.name === "get_goal") {
|
|
533
|
+
this.messages.push({
|
|
534
|
+
role: "tool",
|
|
535
|
+
tool_call_id: call.id,
|
|
536
|
+
content: JSON.stringify({ goal: this.goal.text || "(none set)", status: this.goal.status }, null, 1),
|
|
537
|
+
});
|
|
538
|
+
continue;
|
|
539
|
+
}
|
|
540
|
+
if (call.function.name === "read_memory") {
|
|
541
|
+
const mem = await fs.readFile(this.memoryFile, "utf8").catch(() => "");
|
|
542
|
+
this.messages.push({
|
|
543
|
+
role: "tool",
|
|
544
|
+
tool_call_id: call.id,
|
|
545
|
+
content: mem.trim() || "(memory.md is empty — nothing noted yet)",
|
|
546
|
+
});
|
|
547
|
+
continue;
|
|
548
|
+
}
|
|
549
|
+
if (call.function.name === "list_skills") {
|
|
550
|
+
await this.refreshSkills();
|
|
551
|
+
const list = this.skillsCache.length
|
|
552
|
+
? this.skillsCache.map((s) => `- ${s.name}: ${s.description || "(no description)"}`).join("\n")
|
|
553
|
+
: "(no skills yet — create one with save_skill)";
|
|
554
|
+
this.messages.push({ role: "tool", tool_call_id: call.id, content: list });
|
|
555
|
+
continue;
|
|
556
|
+
}
|
|
540
557
|
if (call.function.name === "set_memory") {
|
|
541
558
|
const a = safeParse(call.function.arguments);
|
|
542
559
|
const content = String(a.content ?? "").slice(0, 32_000);
|
|
@@ -574,37 +591,10 @@ export class Agent {
|
|
|
574
591
|
}
|
|
575
592
|
throw new Error("runaway detection: too many turns in one round (>200)");
|
|
576
593
|
}
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
async readAgentsMd() {
|
|
580
|
-
try {
|
|
581
|
-
const p = path.join(this.workspace, "AGENTS.md");
|
|
582
|
-
const st = await fs.stat(p);
|
|
583
|
-
if (this.agentsMdCache?.mtimeMs === st.mtimeMs)
|
|
584
|
-
return this.agentsMdCache.text;
|
|
585
|
-
const text = await fs.readFile(p, "utf8");
|
|
586
|
-
this.agentsMdCache = { mtimeMs: st.mtimeMs, text };
|
|
587
|
-
return text;
|
|
588
|
-
}
|
|
589
|
-
catch {
|
|
590
|
-
this.agentsMdCache = null;
|
|
591
|
-
return "";
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
async buildMessages() {
|
|
595
|
-
const sys = [SYSTEM_TEMPLATE];
|
|
596
|
-
if (this.goal.text) {
|
|
597
|
-
sys.push(`## Current goal (${this.goal.status})\n${this.goal.text}`);
|
|
598
|
-
}
|
|
599
|
-
const agentsMd = await this.readAgentsMd();
|
|
600
|
-
if (agentsMd.trim())
|
|
601
|
-
sys.push(`## Project knowledge (AGENTS.md)\n${clipText(agentsMd, 8000)}`);
|
|
602
|
-
const memory = await fs.readFile(this.memoryFile, "utf8").catch(() => "");
|
|
603
|
-
if (memory.trim())
|
|
604
|
-
sys.push(`## Your notes (memory.md)\n${clipText(memory, 4000)}`);
|
|
605
|
-
sys.push(this.skillsListing());
|
|
594
|
+
buildMessages() {
|
|
595
|
+
// deliberately static: [system] + append-only history keeps prefix caches hot
|
|
606
596
|
const hasSystem = this.messages[0]?.role === "system";
|
|
607
|
-
const head = [{ role: "system", content:
|
|
597
|
+
const head = [{ role: "system", content: SYSTEM_TEMPLATE }];
|
|
608
598
|
return hasSystem ? [...head, ...this.messages.slice(1)] : [...head, ...this.messages];
|
|
609
599
|
}
|
|
610
600
|
async handleFinish(argsJson) {
|
|
@@ -629,7 +619,7 @@ export class Agent {
|
|
|
629
619
|
text: request,
|
|
630
620
|
});
|
|
631
621
|
this.messages.push({ role: "user", content: request });
|
|
632
|
-
const res = await this.llmCall(
|
|
622
|
+
const res = await this.llmCall(this.buildMessages(), []); // no tools: pure report
|
|
633
623
|
await this.recordProgress(JSON.stringify({ freeform: res.message.content }));
|
|
634
624
|
await this.log.append("message", this.currentSession, this.currentBranch, {
|
|
635
625
|
role: "assistant",
|
|
@@ -843,7 +833,7 @@ function allToolSpecs() {
|
|
|
843
833
|
type: "function",
|
|
844
834
|
function: {
|
|
845
835
|
name: "set_goal",
|
|
846
|
-
description: "Replace the harness-managed goal text
|
|
836
|
+
description: "Replace the harness-managed goal text. Use when the objective itself changes — not for routine updates.",
|
|
847
837
|
parameters: {
|
|
848
838
|
type: "object",
|
|
849
839
|
properties: { text: { type: "string" } },
|
|
@@ -851,11 +841,27 @@ function allToolSpecs() {
|
|
|
851
841
|
},
|
|
852
842
|
},
|
|
853
843
|
},
|
|
844
|
+
{
|
|
845
|
+
type: "function",
|
|
846
|
+
function: {
|
|
847
|
+
name: "get_goal",
|
|
848
|
+
description: "Fetch the current goal and its status. Cheap — call at session start, after a compaction notice, or when unsure.",
|
|
849
|
+
parameters: { type: "object", properties: {} },
|
|
850
|
+
},
|
|
851
|
+
},
|
|
852
|
+
{
|
|
853
|
+
type: "function",
|
|
854
|
+
function: {
|
|
855
|
+
name: "read_memory",
|
|
856
|
+
description: "Read your durable notes (memory.md).",
|
|
857
|
+
parameters: { type: "object", properties: {} },
|
|
858
|
+
},
|
|
859
|
+
},
|
|
854
860
|
{
|
|
855
861
|
type: "function",
|
|
856
862
|
function: {
|
|
857
863
|
name: "set_memory",
|
|
858
|
-
description: "Overwrite your durable
|
|
864
|
+
description: "Overwrite your durable notes (memory.md). Keep them terse: decisions, gotchas, where you left off.",
|
|
859
865
|
parameters: {
|
|
860
866
|
type: "object",
|
|
861
867
|
properties: { content: { type: "string" } },
|
|
@@ -863,11 +869,16 @@ function allToolSpecs() {
|
|
|
863
869
|
},
|
|
864
870
|
},
|
|
865
871
|
},
|
|
872
|
+
{
|
|
873
|
+
type: "function",
|
|
874
|
+
function: {
|
|
875
|
+
name: "list_skills",
|
|
876
|
+
description: "List available skills (name + description). Call before load_skill or to avoid duplicating an existing skill.",
|
|
877
|
+
parameters: { type: "object", properties: {} },
|
|
878
|
+
},
|
|
879
|
+
},
|
|
866
880
|
];
|
|
867
881
|
}
|
|
868
|
-
function clipText(s, max) {
|
|
869
|
-
return s.length <= max ? s : s.slice(0, max) + `\n… [truncated, ${s.length} chars total]`;
|
|
870
|
-
}
|
|
871
882
|
function str(v) {
|
|
872
883
|
return typeof v === "string" ? v : "";
|
|
873
884
|
}
|
package/dist/agent/tools.js
CHANGED
|
@@ -140,15 +140,27 @@ export const TOOLS = [
|
|
|
140
140
|
},
|
|
141
141
|
async run(args, ctx) {
|
|
142
142
|
const p = safeJoin(ctx.cwd, str(args.path));
|
|
143
|
-
|
|
143
|
+
let text = await readText(p);
|
|
144
144
|
const oldText = str(args.old_text);
|
|
145
|
-
const
|
|
145
|
+
const newText = str(args.new_text);
|
|
146
|
+
let count = text.split(oldText).length - 1;
|
|
147
|
+
let normalized = false;
|
|
148
|
+
// tolerate LF patterns against CRLF files (convert once, on success)
|
|
149
|
+
if (count === 0 && oldText.includes("\n") && text.includes("\r\n")) {
|
|
150
|
+
const lf = text.replace(/\r\n/g, "\n");
|
|
151
|
+
const lfCount = lf.split(oldText).length - 1;
|
|
152
|
+
if (lfCount === 1) {
|
|
153
|
+
text = lf;
|
|
154
|
+
count = 1;
|
|
155
|
+
normalized = true;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
146
158
|
if (count === 0)
|
|
147
159
|
return { ok: false, result: "old_text not found in file" };
|
|
148
160
|
if (count > 1)
|
|
149
161
|
return { ok: false, result: `old_text matched ${count} times; must be unique` };
|
|
150
|
-
await fs.writeFile(p, text.replace(oldText,
|
|
151
|
-
return { ok: true, result: "edited" };
|
|
162
|
+
await fs.writeFile(p, text.replace(oldText, newText), "utf8");
|
|
163
|
+
return { ok: true, result: normalized ? "edited (file converted CRLF→LF)" : "edited" };
|
|
152
164
|
},
|
|
153
165
|
},
|
|
154
166
|
{
|
package/dist/server/api.js
CHANGED
|
@@ -14,6 +14,20 @@ import { bus } from "../bus.js";
|
|
|
14
14
|
import { readEvents } from "../log/events.js";
|
|
15
15
|
export function buildApp(master) {
|
|
16
16
|
const app = new Hono();
|
|
17
|
+
// Optional bearer auth for LAN exposure — set TEAPOT_API_TOKEN to enable.
|
|
18
|
+
// WebSocket handshakes can't send headers, so they accept ?token= instead.
|
|
19
|
+
const apiToken = process.env.TEAPOT_API_TOKEN || "";
|
|
20
|
+
if (apiToken)
|
|
21
|
+
app.use("/api/*", async (c, next) => {
|
|
22
|
+
const h = c.req.header("authorization");
|
|
23
|
+
const provided = h?.startsWith("Bearer ") ? h.slice(7) : undefined;
|
|
24
|
+
const q = c.req.query("token");
|
|
25
|
+
if ((provided && provided === apiToken) || (q && q === apiToken))
|
|
26
|
+
return next();
|
|
27
|
+
return c.json({ error: "unauthorized" }, 401);
|
|
28
|
+
});
|
|
29
|
+
// per-agent terminal spawn guard
|
|
30
|
+
const termCounts = new Map();
|
|
17
31
|
// ---- realtime events over WebSocket (replaces SSE for the web UI) ----
|
|
18
32
|
app.get("/api/ws", upgradeWebSocket(() => {
|
|
19
33
|
let onUpdate = null;
|
|
@@ -81,6 +95,12 @@ export function buildApp(master) {
|
|
|
81
95
|
/* client gone */
|
|
82
96
|
}
|
|
83
97
|
};
|
|
98
|
+
const cur = termCounts.get(agentId) ?? 0;
|
|
99
|
+
if (cur >= 2) {
|
|
100
|
+
send({ kind: "exit", error: "too many terminals for this agent (max 2)" });
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
termCounts.set(agentId, cur + 1);
|
|
84
104
|
if (!agent) {
|
|
85
105
|
send({ kind: "exit", error: `no such agent: ${agentId}` });
|
|
86
106
|
return;
|
|
@@ -122,6 +142,11 @@ export function buildApp(master) {
|
|
|
122
142
|
},
|
|
123
143
|
onClose() {
|
|
124
144
|
cleanup();
|
|
145
|
+
const n = (termCounts.get(agentId) ?? 1) - 1;
|
|
146
|
+
if (n <= 0)
|
|
147
|
+
termCounts.delete(agentId);
|
|
148
|
+
else
|
|
149
|
+
termCounts.set(agentId, n);
|
|
125
150
|
},
|
|
126
151
|
};
|
|
127
152
|
}));
|
package/package.json
CHANGED
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
`);function i(e){return e.replace(/`([^`]+)`/g,`<code>$1</code>`).replace(/\*\*([^*]+)\*\*/g,`<strong>$1</strong>`).replace(/(^|\W)\*([^*]+)\*(?=\W|$)/g,`$1<em>$2</em>`).replace(/\[([^\]]+)\]\((https?:\/\/[^)\s]+)\)/g,`<a href="$2" rel="noopener noreferrer" target="_blank">$1</a>`)}}function be(e){return e.replace(/&/g,`&`).replace(/</g,`<`).replace(/>/g,`>`).replace(/"/g,`"`)}var xe=`modulepreload`,Se=function(e){return`/`+e},Q={},Ce=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=document.getElementsByTagName(`link`),i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?import.meta.resolve(e):new URL(e,import.meta.url).href}r=o(t.map(t=>{if(t=Se(t,n),t=s(t),t in Q)return;Q[t]=!0;let r=t.endsWith(`.css`);for(let n=e.length-1;n>=0;n--){let i=e[n];if(i.href===t&&(!r||i.rel===`stylesheet`))return}let i=document.createElement(`link`);if(i.rel=r?`stylesheet`:xe,r||(i.as=`script`),i.crossOrigin=``,i.href=t,a&&i.setAttribute(`nonce`,a),document.head.appendChild(i),r)return new Promise((e,n)=>{i.addEventListener(`load`,e),i.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${t}`)))})}))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},we=G(`<br>`),Te=G(`<span class=sub>ℹ`),Ee=G(`<header class=chan-head><span class=hash>#</span><span class=title></span><span></span><span class=sub> · <!>/<!> · turns <!> · tools </span><span style=margin-left:auto;display:flex;gap:4px><button class=iconbtn title="terminal (t)">⌨</button><button class=iconbtn title="toggle details panel (d)">▤`),De=G(`<details class=reasoning><summary>💭 reasoning</summary><div class=mono>`),Oe=G(`<div class=content><span class=cursor>▍`),ke=G(`<div class="msg live"><div class=avatar style="background:#5865f233;border:1px solid #5865f266">🫖</div><div class=msg-body><div class=msg-head><span class=author style=color:var(--acc)>agent</span><span class=ts>streaming…`),Ae=G(`<div class=feed>`),je=G(`<button class=jump>↓ `),Me=G(`<div class=termdrawer><div class=termbar><span>⌨ terminal — <span class=mono></span></span><button class=iconbtn title="close terminal (t)">✕</button></div><div class=termhost>`),Ne=G(`<div class=composer><form><input type=text><label><input type=checkbox>auto-start</label><button type=submit>send</button></form><div class=hint>enter send · ↑↓ sessions · / focus · t terminal · d panel · esc stop · prompts queue while the agent works`),Pe=G(`<h3>🎛 session`),Fe=G(`<div class="card sesscard"><div class=sessrow><span class=k>agent</span><b></b><span></span></div><div class=sessrow><span class=k>workspace</span><span class="mono ellip"></span></div><div class=sessrow><span class=k>session</span><span class=mono>/`),Ie=G(`<h3>🧦 model`),Le=G(`<div class=modelbox><select title="provider (OpenAI-compatible endpoint)"></select><div style=display:flex;gap:4px><input type=text list=model-list style=flex:1;min-width:0><datalist id=model-list></datalist><button title="apply model to this session">apply</button></div><div class=meta>current: `),Re=G(`<h3>⏯ controls`),ze=G(`<div class=btnrow><button title="run toward the goal">▶ start</button><button title="interrupt after the current tool finishes">■ stop</button><button>⑂ fork</button><button title="remove agent">🗑`),Be=G(`<h3>🎯 goal <span>`),Ve=G(`<form style=display:flex;gap:4px;margin-bottom:6px><input id=goal-input type=text placeholder="set new goal…"style="flex:1;background:var(--bg-darkest);border:none;border-radius:6px;padding:6px 8px;color:var(--fg);font:inherit"><button type=submit style="background:var(--acc);border:none;border-radius:6px;color:#fff;padding:0 10px;cursor:pointer">✓`),He=G(`<div class=card>`),Ue=G(`<h3>📈 progress`),We=G(`<div class=card>
|
|
6
6
|
<!>
|
|
7
7
|
<span class=muted>`),Ge=G(`<h3>📊 runtime`),Ke=G(`<div class="card muted">turns <!> · tools <!> · compacted <!>
|
|
8
|
-
tokens in/out <!>/`),qe=G(`<h3>🌿 branches`),Je=G(`<div><nav class=sidebar><h1>🫖 teapot<span></span><span style=float:right;display:flex;gap:4px><button class=iconbtn title="new agent">+</button><button class=iconbtn title=settings>⚙</button></span></h1><div class=agent-list></div><div class=metrics></div></nav><section class=channel></section><aside>`),Ye=G(`<span title="goal done">✓`),Xe=G(`<div><span></span><span>`),Ze=G(`<div class=muted style=display:grid;place-items:center;height:100%>select an agent`),Qe=G(`<div class=muted style=display:grid;place-items:center;height:100%>no events yet — say something or press ▶ start`),$e=G(`<div class="content muted">thinking…`),et=G(`<option>`),tt=G(`<div class=muted>none yet`),nt=G(`<div><span>`),rt=G(`<div> → `),it=G(`<div class=avatar>`),at=G(`<div class=msg-head><span class=author></span><span class=ts></span><span class=ts>`),ot=G(`<div><div class=msg-body>`),st=G(`<span style=width:38px>`),ct=G(`<div class=content>`),lt=G(`<div class=msgfoot><span>copy summary`),ut=G(`<details class=embed><summary><b>⚙ </b> <span class=meta></span></summary><div class=mono>`),dt=G(`<details><summary><span class=meta></span></summary><div class=mono></div><div class=meta>ms`),ft=G(`<div class=meta>`),pt=G(`<div class=meta>⚠ `),mt=G(`<div class=meta>→ `),ht=G(`<div class=embed style=border-color:var(--ok)><div>📈 `),gt=G(`<div class="embed fail"><div class=mono>⚠ `),_t=G(`<div class="content muted">`),vt=G(`<button class=copybtn title="copy to clipboard">`),yt=G(`<div class=overlay><div class=modal><div class=modal-head><b></b><button class=iconbtn>✕`),bt=G(`<span style=color:var(--err);font-size:13px>`),xt=G(`<form style=display:flex;flex-direction:column;gap:10px><label>workspace directory<div style=display:flex;gap:6px><input type=text class="w100 mono"><button type=button>go</button><button type=button>↑</button></div></label><div class=dirlist></div><div style=display:flex;gap:10px><label style=flex:1>agent name <input type=text placeholder="(directory name)"></label><label>provider<select></select></label><label style=flex:1>model <input type=text placeholder="(provider default)"></label></div><button type=submit style=align-self:flex-end>create & start`),St=G(`<div class=direntry>📁 `),Ct=G(`<form style=display:flex;flex-direction:column;gap:10px><label>providers (<!>)<textarea rows=8 class="mono w100"></textarea></label><div style=display:flex;gap:10px><label style=flex:1>default provider <input type=text></label><label>progress interval (min) <input type=number min=1 style=width:90px></label></div><label>scheduled tasks (JSON array)<textarea rows=7 class="mono w100"></textarea></label><button type=submit style=align-self:flex-end>save`),wt={user:{name:`you`,icon:`🧑`,color:`#faa81a`},message:{name:`agent`,icon:`🫖`,color:`#5865f2`},tool_call:{name:`tool`,icon:`🔧`,color:`#3ba0c9`},progress:{name:`progress`,icon:`📈`,color:`#3ba55d`}},Tt=e=>wt[e.type]??{name:e.type,icon:`•`,color:`#9298a5`},Et=new Set([`user`,`message`,`prompt`,`tool_call`,`tool_result`,`progress`]),Dt=e=>Et.has(e.type),Ot=e=>{let t=new Date(e);return`${String(t.getHours()).padStart(2,`0`)}:${String(t.getMinutes()).padStart(2,`0`)}`};async function $(e,t){let n=await fetch(e,t);if(!n.ok)throw Error(`${e}: ${n.status}`);return n.json()}function kt(){let[e,t]=v([]),[n,r]=v(null),[i,a]=v([]),[o,s]=v([]),[c,l]=v(null),[u,d]=v(``),[f,p]=v(!0),[m,h]=v({providers:{}}),[g,_]=v(!1),[S,w]=v(!1),[T,te]=v(localStorage.getItem(`teapot.panel`)===null?window.innerWidth>1100:localStorage.getItem(`teapot.panel`)===`1`),ne=()=>{te(!T()),localStorage.setItem(`teapot.panel`,T()?`1`:`0`)},[E,re]=v(``),[D,ie]=v(``),[O,k]=v([]),A=()=>Object.keys(m().providers??{});async function ae(e){if(e)try{let t=await $(`/api/models?provider=${encodeURIComponent(e)}`);k(t.models??[])}catch{k([])}}b(()=>{let e=I();e&&(re(e.provider||m().defaultProvider||A()[0]||``),ie(``),ae(E()))});let[oe,se]=v(!0),[j,M]=v(0),[N,P]=v(null),ce=x(()=>i().filter(Dt)),F=()=>$(`/api/config`).then(h).catch(()=>{}),I=x(()=>e().find(e=>e.id===n())),L=()=>$(`/api/agents`).then(e=>t(e.agents)).catch(()=>{}),R=()=>$(`/api/metrics`).then(l).catch(()=>{});async function le(e){try{let[t,n]=await Promise.all([$(`/api/agents/${e}/events?limit=300`),$(`/api/agents/${e}/branches`)]);a(t.events),s(n.branches)}catch{}}function ue(){return document.querySelector(`.feed`)}function de(){let e=ue();return!e||e.scrollHeight-e.scrollTop-e.clientHeight<80}function U(e=!1){let t=ue();t&&(e||oe())&&(t.scrollTop=t.scrollHeight,M(0))}async function W(e,t=!0){r(e),P(null),localStorage.setItem(`teapot.session`,e),ve(e,t),await le(e),requestAnimationFrame(()=>U(!0))}let[G,fe]=v(!1),q=null,ge=null;C(()=>q?.close());function _e(){let e=location.protocol===`https:`?`wss://`:`ws://`;q=new WebSocket(`${e}${location.host}/api/ws`),q.onopen=()=>fe(!0),q.onclose=()=>{fe(!1),setTimeout(_e,1500)},q.onerror=()=>q?.close(),q.onmessage=e=>{let t=JSON.parse(e.data);if(t.kind!==`ping`&&t.kind!==`pong`){if(t.kind===`llm-delta`){t.agentId===n()&&P({text:t.text??``,reasoning:t.reasoning??``});return}ge||=setTimeout(async()=>{if(ge=null,await L(),await R(),n()){let e=i().length;await le(n()),i().length!==e&&(P(null),de()?U(!0):M(j()+(i().length-e)))}},400)}}}let Y=()=>decodeURIComponent(location.pathname.split(`/`)[2]??``);function ve(e,t=!0){let n=`/session/${encodeURIComponent(e)}`;t?history.pushState(null,``,n):history.replaceState(null,``,n)}window.addEventListener(`popstate`,()=>{let t=Y();t&&e().some(e=>e.id===t)&&t!==n()&&W(t,!1)}),b(()=>{let e=I();document.title=e?`${e.status===`running`?`▶ `:e.status===`error`?`⚠ `:``}${e.id} · teapot`:`teapot`}),window.addEventListener(`keydown`,t=>{let r=t.target;if(r&&(r.tagName===`INPUT`||r.tagName===`TEXTAREA`||r.isContentEditable)){t.key===`Escape`&&r.blur();return}if(t.key===`Escape`){if(g()){_(!1);return}if(S()){w(!1);return}let e=I();if(e?.status===`running`){$(`/api/agents/${e.id}/stop`,{method:`POST`}).then(L);return}T()&&window.innerWidth<=1100&&te(!1);return}if(!(g()||S())){if(t.key===`/`)t.preventDefault(),document.querySelector(`.composer input[type=text]`)?.focus();else if(t.key===`d`)ne();else if(t.key===`t`)ye();else if(t.key===`ArrowDown`||t.key===`ArrowUp`){let r=e();if(r.length===0)return;t.preventDefault();let i=r.findIndex(e=>e.id===n()),a=t.key===`ArrowDown`?Math.min(i+1,r.length-1):Math.max(i-1,0);a!==i&&W(r[a].id)}}});let[X,Z]=v(localStorage.getItem(`teapot.term`)===`1`),ye=()=>{Z(!X()),localStorage.setItem(`teapot.term`,X()?`1`:`0`)},be=null,xe=null,Se=null,Q=null,rt={cols:0,rows:0},it=null;function at(){Q?.disconnect(),Q=null,Se?.close(),Se=null,xe?.dispose(),xe=null}function ot(e){at(),be&&Promise.all([Ce(()=>import(`./xterm-C3BHN0de.js`),[]),Ce(()=>import(`./addon-fit-DIOBYJe3.js`),[])]).then(([{Terminal:t},{FitAddon:n}])=>{let r=new t({cursorBlink:!0,fontSize:12.5,fontFamily:`ui-monospace, Menlo, Consolas, monospace`,theme:{background:`#0d0e12`,foreground:`#dcdee4`}}),i=new n;r.loadAddon(i),r.open(be),i.fit(),xe=r;let a=location.protocol===`https:`?`wss://`:`ws://`,o=new WebSocket(`${a}${location.host}/api/agents/${e}/term`);Se=o,o.onmessage=e=>{let t=JSON.parse(e.data);t.kind===`data`?r.write(t.data):t.kind===`exit`&&r.write(`\r\n\x1b[2m[terminal exited ${t.code??``}]\x1b[0m\r\n`)},r.onData(e=>{o.readyState===WebSocket.OPEN&&o.send(JSON.stringify({kind:`input`,data:e}))});let s=()=>{try{i.fit()}catch{}let{cols:e,rows:t}=r;(e!==rt.cols||t!==rt.rows)&&o.readyState===WebSocket.OPEN&&(rt={cols:e,rows:t},o.send(JSON.stringify({kind:`resize`,cols:e,rows:t})))};Q=new ResizeObserver(()=>{it&&clearTimeout(it),it=setTimeout(s,300)}),Q.observe(be),setTimeout(s,50)})}b(()=>{let e=n();!X()||!e?at():requestAnimationFrame(()=>e&&ot(e))}),C(at),ee(()=>{F(),L().then(()=>{let t=Y()||localStorage.getItem(`teapot.session`)||``,n=e().find(e=>e.id===t)??e()[0];n&&W(n.id,!1)}),R(),_e(),setInterval(R,3e4)});let st=async e=>{if(e.preventDefault(),!n()||!u().trim())return;let t=u();d(``),await $(`/api/agents/${n()}/prompt`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({text:t,start:f()})})},ct=e=>()=>n()&&$(`/api/agents/${n()}${e}`,{method:`POST`}).then(L),lt=async e=>{e.preventDefault();let t=document.getElementById(`goal-input`);!n()||!t.value.trim()||(await $(`/api/agents/${n()}/goal`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({text:t.value})}),t.value=``,L())};return[(()=>{var i=Je(),a=i.firstChild,s=a.firstChild,l=s.firstChild.nextSibling,h=l.nextSibling.firstChild,g=h.nextSibling,v=s.nextSibling,b=v.nextSibling,x=a.nextSibling,S=x.nextSibling;return h.$$click=()=>{F(),_(!0)},g.$$click=()=>{F(),w(!0)},J(v,z(B,{get each(){return e()},children:e=>(()=>{var t=Xe(),r=t.firstChild,i=r.nextSibling;return t.$$click=()=>W(e.id),J(i,()=>e.id),J(t,z(V,{get when(){return e.goal.status===`done`},get children(){return Ye()}}),null),y(i=>{var a=`agent-item`+(e.id===n()?` sel`:``),o=`dot ${e.status}`;return a!==i.e&&K(t,i.e=a),o!==i.t&&K(r,i.t=o),i},{e:void 0,t:void 0}),t})()})),J(b,z(V,{get when(){return c()},get children(){return[`master rss `,H(()=>c().rssMb),`MB · heap `,H(()=>c().heapUsedMb),`MB`,we(),`load1 `,H(()=>c().loadavg1),` · up `,H(()=>Math.floor(c().uptimeSec/60)),`m`]}})),J(x,z(V,{get when(){return I()},get fallback(){return Ze()},get children(){return[(()=>{var e=Ee(),t=e.firstChild.nextSibling,n=t.nextSibling,r=n.nextSibling,i=r.firstChild,a=i.nextSibling,o=a.nextSibling.nextSibling,s=o.nextSibling.nextSibling;s.nextSibling;var c=r.nextSibling,l=c.firstChild,u=l.nextSibling;return J(t,()=>I().id),J(n,()=>I().status),J(r,()=>I().model,i),J(r,()=>I().session,a),J(r,()=>I().branch,o),J(r,()=>I().stats.turns,s),J(r,()=>I().stats.toolCalls,null),J(c,z(V,{get when(){return I().statusReason},get children(){var e=Te();return y(()=>pe(e,`title`,I().statusReason)),e}}),l),l.$$click=ye,u.$$click=ne,y(()=>K(n,`badge ${I().status}`)),e})(),(()=>{var e=Ae();return e.addEventListener(`scroll`,()=>{let e=de();e&&j()&&M(0),se(e)}),J(e,z(V,{get when(){return ce().length>0},get fallback(){return Qe()},get children(){return[z(B,{get each(){return ce()},children:(e,t)=>z(At,{e,get prev(){return ce()[t()-1]}})}),z(V,{get when(){return N()},get children(){var e=ke(),t=e.firstChild.nextSibling;return t.firstChild,J(t,z(V,{get when(){return N().reasoning},get children(){var e=De(),t=e.firstChild.nextSibling;return J(t,()=>N().reasoning),e}}),null),J(t,z(V,{get when(){return N().text},get fallback(){return $e()},get children(){var e=Oe(),t=e.firstChild;return J(e,()=>N().text,t),e}}),null),e}})]}})),e})(),z(V,{get when(){return!oe()||j()>0},get children(){var e=je();return e.firstChild,e.$$click=()=>U(!0),J(e,(()=>{var e=H(()=>j()>0);return()=>e()?`${j()} new message${j()>1?`s`:``}`:`jump to present`})(),null),e}}),z(V,{get when(){return H(()=>!!X())()&&I()},get children(){var e=Me(),t=e.firstChild,n=t.firstChild,r=n.firstChild.nextSibling,i=n.nextSibling,a=t.nextSibling;return J(r,()=>I().workspace),i.$$click=ye,he(e=>be=e,a),e}}),(()=>{var e=Ne(),t=e.firstChild,n=t.firstChild,r=n.nextSibling.firstChild;return t.addEventListener(`submit`,st),n.$$input=e=>d(e.currentTarget.value),r.addEventListener(`change`,e=>p(e.currentTarget.checked)),y(()=>pe(n,`placeholder`,`message #${I().id}`)),y(()=>n.value=u()),y(()=>r.checked=f()),e})()]}})),J(S,z(V,{get when(){return I()},get children(){return[Pe(),(()=>{var e=Fe(),t=e.firstChild,n=t.firstChild.nextSibling,r=n.nextSibling,i=t.nextSibling,a=i.firstChild.nextSibling,o=i.nextSibling.firstChild.nextSibling,s=o.firstChild;return J(n,()=>I().id),J(r,()=>I().status),J(a,()=>I().workspace),J(o,()=>I().session,s),J(o,()=>I().branch,null),y(e=>{var t=`badge ${I().status}`,n=I().workspace;return t!==e.e&&K(r,e.e=t),n!==e.t&&pe(a,`title`,e.t=n),e},{e:void 0,t:void 0}),e})(),Ie(),(()=>{var e=Le(),t=e.firstChild,r=t.nextSibling,i=r.firstChild,a=i.nextSibling,o=a.nextSibling,s=r.nextSibling;return s.firstChild,t.addEventListener(`change`,e=>{re(e.currentTarget.value),ae(e.currentTarget.value)}),J(t,z(B,{get each(){return A()},children:e=>(()=>{var t=et();return t.value=e,J(t,e,null),J(t,()=>e===m().defaultProvider?` ★`:``,null),t})()})),i.$$input=e=>ie(e.currentTarget.value),J(a,z(B,{get each(){return O()},children:e=>(()=>{var t=et();return t.value=e,t})()})),o.$$click=async()=>{n()&&(await $(`/api/agents/${n()}/model`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({provider:E(),model:D().trim()||void 0})}),L())},J(s,()=>I().model,null),J(s,z(V,{get when(){return O().length},get children(){return[` · `,H(()=>O().length),` models loaded`]}}),null),y(()=>pe(i,`placeholder`,I().model)),y(()=>t.value=E()),y(()=>i.value=D()),e})(),Re(),(()=>{var n=ze(),i=n.firstChild,a=i.nextSibling,o=a.nextSibling,s=o.nextSibling;return me(i,`click`,ct(`/start`),!0),me(a,`click`,ct(`/stop`),!0),o.$$click=()=>$(`/api/agents/${I().id}/fork`,{method:`POST`,headers:{"content-type":`application/json`},body:`{}`}).then(()=>W(I().id)),s.$$click=async()=>{confirm(`remove agent ${I().id}? (log is kept)`)&&(await $(`/api/agents/${I().id}`,{method:`DELETE`}),r(null),t(e().filter(e=>e.id!==I().id)))},n})(),(()=>{var e=Be(),t=e.firstChild.nextSibling;return J(t,()=>I().goal.status),y(()=>K(t,`badge ${I().goal.status===`done`?`done`:``}`)),e})(),(()=>{var e=Ve();return e.addEventListener(`submit`,lt),e})(),(()=>{var e=He();return J(e,()=>I().goal.text||`no goal set`),e})(),Ue(),z(V,{get when(){return I().latestProgress},get fallback(){return tt()},get children(){var e=We(),t=e.firstChild,n=t.nextSibling,r=n.nextSibling.nextSibling;return J(e,()=>I().latestProgress.doing,t),J(e,()=>I().latestProgress.recent??``,n),J(r,()=>I().latestProgress.ts),e}}),Ge(),(()=>{var e=Ke(),t=e.firstChild.nextSibling,n=t.nextSibling.nextSibling,r=n.nextSibling.nextSibling,i=r.nextSibling.nextSibling;return i.nextSibling,J(e,()=>I().stats.turns,t),J(e,()=>I().stats.toolCalls,n),J(e,()=>I().stats.compactions??0,r),J(e,()=>I().stats.inputTokens,i),J(e,()=>I().stats.outputTokens,null),e})(),qe(),z(B,{get each(){return o()},children:e=>(()=>{var t=nt(),n=t.firstChild;return J(t,()=>e.branch,n),J(n,()=>e.events),y(()=>K(t,`branch-row`+(e.branch===I().branch?` cur`:``))),t})()})]}})),y(e=>{var t=`layout`+(T()?``:` right-hidden`),n=`conn`+(G()?` ok`:``),r=G()?`live (websocket)`:`reconnecting…`,a=`rightbar`+(T()?` open`:``);return t!==e.e&&K(i,e.e=t),n!==e.t&&K(l,e.t=n),r!==e.a&&pe(l,`title`,e.a=r),a!==e.o&&K(S,e.o=a),e},{e:void 0,t:void 0,a:void 0,o:void 0}),i})(),z(V,{get when(){return g()},get children(){return z(It,{get providers(){return Object.keys(m().providers??{})},onClose:()=>_(!1),onCreated:e=>{_(!1),L(),W(e)}})}}),z(V,{get when(){return S()},get children(){return z(Lt,{get cfg(){return m()},onClose:()=>w(!1),onSaved:F})}})]}function At(e){let t=e.e,n=Tt(t),r=e.prev&&e.prev.type===t.type&&t.session===e.prev.session&&t.branch===e.prev.branch;return t.type===`state`?t.data.from===t.data.to?null:(()=>{var e=rt(),n=e.firstChild;return J(e,()=>t.data.from,n),J(e,()=>t.data.to,null),J(e,(()=>{var e=H(()=>!!t.data.reason);return()=>e()?` — ${t.data.reason}`:``})(),null),y(()=>K(e,`divider-msg`+(t.data.to===`error`?` err`:``))),e})():(()=>{var e=ot(),i=e.firstChild;return K(e,`msg`+(r?` grouped`:``)),J(e,z(V,{when:!r,get fallback(){return st()},get children(){var e=it();return J(e,()=>n.icon),y(t=>{var r=n.color+`33`,i=`1px solid ${n.color}66`;return r!==t.e&&q(e,`background`,t.e=r),i!==t.t&&q(e,`border`,t.t=i),t},{e:void 0,t:void 0}),e}}),i),J(i,z(V,{when:!r,get children(){var e=at(),r=e.firstChild,i=r.nextSibling,a=i.nextSibling;return J(r,()=>n.name),J(i,()=>Ot(t.ts)),J(a,()=>t.branch),y(e=>q(r,`color`,n.color)),e}}),null),J(i,z(jt,{e:t}),null),e})()}function jt(e){let t=e.e;switch(t.type){case`prompt`:return(()=>{var e=ct();return y(()=>e.innerHTML=ye(String(t.data.text??``))),e})();case`message`:return[z(V,{get when(){return H(()=>typeof t.data.reasoning==`string`)()&&t.data.reasoning.trim()},get children(){var e=De(),n=e.firstChild.nextSibling;return J(n,()=>String(t.data.reasoning)),e}}),(()=>{var e=ct();return y(()=>e.innerHTML=ye(String(t.data.content??``))),e})(),z(V,{get when(){return t.data.final},get children(){var e=lt(),n=e.firstChild;return J(e,z(Pt,{get text(){return String(t.data.content??``)}}),n),e}})];case`tool_call`:{let e=JSON.stringify(t.data.args,null,1),n=Nt(JSON.stringify(t.data.args??{}),110);return(()=>{var r=ut(),i=r.firstChild,a=i.firstChild;a.firstChild;var o=a.nextSibling.nextSibling,s=i.nextSibling;return J(a,()=>String(t.data.name),null),J(o,n),J(s,e),r})()}case`tool_result`:{let e=String(t.data.result);return(()=>{var n=dt(),r=n.firstChild,i=r.firstChild,a=r.nextSibling,o=a.nextSibling,s=o.firstChild;return J(i,()=>Nt(e,120)),J(r,z(Pt,{text:e}),null),J(a,()=>Mt(e,4e3)),J(o,()=>t.data.durationMs,s),J(o,()=>t.data.ok?``:` · FAILED`,null),y(()=>K(n,`embed`+(t.data.ok?``:` fail`))),n})()}case`progress`:return(()=>{var e=ht(),n=e.firstChild;return n.firstChild,J(n,()=>String(t.data.doing??``),null),J(e,z(V,{get when(){return t.data.recent},get children(){var e=ft();return J(e,()=>String(t.data.recent)),e}}),null),J(e,z(V,{get when(){return t.data.problems},get children(){var e=pt();return e.firstChild,J(e,()=>String(t.data.problems),null),e}}),null),J(e,z(V,{get when(){return t.data.next},get children(){var e=mt();return e.firstChild,J(e,()=>String(t.data.next),null),e}}),null),e})();case`error`:return(()=>{var e=gt(),n=e.firstChild;return n.firstChild,J(n,()=>String(t.data.message??``),null),e})();default:return(()=>{var e=_t();return J(e,()=>Mt(JSON.stringify(t.data),200)),e})()}}function Mt(e,t){return e.length>t?e.slice(0,t)+` …`:e}function Nt(e,t){return Mt(e.replace(/\s+/g,` `).trim(),t)}function Pt(e){let[t,n]=v(!1);return(()=>{var r=vt();return r.$$click=t=>{t.stopPropagation(),navigator.clipboard.writeText(e.text).then(()=>{n(!0),setTimeout(()=>n(!1),900)})},J(r,()=>t()?`✓`:`⧉`),r})()}function Ft(e){return(()=>{var t=yt(),n=t.firstChild,r=n.firstChild.firstChild,i=r.nextSibling;return t.$$click=t=>t.target===t.currentTarget&&e.onClose(),J(r,()=>e.title),me(i,`click`,e.onClose,!0),J(n,()=>e.children,null),t})()}function It(e){let[t,n]=v(`~`),[r,i]=v([]),[a,o]=v(``),[s,c]=v(e.providers[0]??``),[l,u]=v(``),[d,f]=v(``);async function p(e){let t=await $(`/api/fs${e?`?path=${encodeURIComponent(e)}`:``}`);n(t.path),i(t.entries)}ee(()=>p(t()));let m=async n=>{n.preventDefault(),f(``);try{let n=await $(`/api/agents`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({workspace:t(),id:a(),provider:s()||void 0,model:l()||void 0})});e.onCreated(n.agent.id)}catch(e){f(String(e.message))}};return z(Ft,{title:`new agent`,get onClose(){return e.onClose},get children(){var i=xt(),f=i.firstChild,h=f.firstChild.nextSibling.firstChild,g=h.nextSibling,_=g.nextSibling,v=f.nextSibling,b=v.nextSibling,x=b.firstChild,S=x.firstChild.nextSibling,ee=x.nextSibling,C=ee.firstChild.nextSibling,w=ee.nextSibling.firstChild.nextSibling,T=b.nextSibling;return i.addEventListener(`submit`,m),h.$$input=e=>n(e.currentTarget.value),g.$$click=()=>p(t()),_.$$click=()=>p(`..`),J(v,z(B,{get each(){return r()},children:e=>(()=>{var n=St();return n.firstChild,n.$$click=()=>p(`${t()}/${e}`.replace(/\/+/g,`/`)),J(n,e,null),n})()})),S.$$input=e=>o(e.currentTarget.value),C.addEventListener(`change`,e=>c(e.currentTarget.value)),J(C,z(B,{get each(){return e.providers},children:e=>(()=>{var t=et();return J(t,e),t})()})),w.$$input=e=>u(e.currentTarget.value),J(i,z(V,{get when(){return d()},get children(){var e=bt();return J(e,d),e}}),T),y(()=>h.value=t()),y(()=>S.value=a()),y(()=>C.value=s()),y(()=>w.value=l()),i}})}function Lt(e){let[t,n]=v(JSON.stringify(Object.fromEntries(Object.entries(e.cfg.providers??{}).map(([e,t])=>[e,{baseUrl:t.baseUrl,apiKey:t.apiKey??``,model:t.model??``}])),null,2)),[r,i]=v(e.cfg.defaultProvider??Object.keys(e.cfg.providers??{})[0]??``),[a,o]=v(Math.round((e.cfg.progressIntervalMs??6e5)/6e4)),[s,c]=v(JSON.stringify(e.cfg.tasks??[],null,2)),[l,u]=v(``),d=async n=>{n.preventDefault(),u(``);let i,o;try{i=JSON.parse(t())}catch{return u(`providers: invalid JSON`)}try{o=JSON.parse(s())}catch{return u(`tasks: invalid JSON`)}try{await $(`/api/config`,{method:`PUT`,headers:{"content-type":`application/json`},body:JSON.stringify({providers:i,defaultProvider:r(),progressIntervalMs:Math.max(1,a())*6e4,tasks:o})}),e.onSaved(),e.onClose()}catch(e){u(String(e.message))}};return z(Ft,{title:`settings`,get onClose(){return e.onClose},get children(){var u=Ct(),f=u.firstChild,p=f.firstChild.nextSibling,m=p.nextSibling.nextSibling,h=f.nextSibling,g=h.firstChild,_=g.firstChild.nextSibling,v=g.nextSibling.firstChild.nextSibling,b=h.nextSibling,x=b.firstChild.nextSibling,S=b.nextSibling;return u.addEventListener(`submit`,d),J(f,()=>e.cfg.configPath,p),m.$$input=e=>n(e.currentTarget.value),_.$$input=e=>i(e.currentTarget.value),v.$$input=e=>o(Number(e.currentTarget.value)),x.$$input=e=>c(e.currentTarget.value),J(u,z(V,{get when(){return l()},get children(){var e=bt();return J(e,l),e}}),S),y(()=>m.value=t()),y(()=>_.value=r()),y(()=>v.value=a()),y(()=>x.value=s()),u}})}fe([`click`,`input`]),W(()=>z(kt,{}),document.getElementById(`root`));
|
|
8
|
+
tokens in/out <!>/`),qe=G(`<h3>🌿 branches`),Je=G(`<div><nav class=sidebar><h1>🫖 teapot<span></span><span style=float:right;display:flex;gap:4px><button class=iconbtn title="new agent">+</button><button class=iconbtn title=settings>⚙</button></span></h1><div class=agent-list></div><div class=metrics></div></nav><section class=channel></section><aside>`),Ye=G(`<span title="goal done">✓`),Xe=G(`<div><span></span><span>`),Ze=G(`<div class=muted style=display:grid;place-items:center;height:100%>select an agent`),Qe=G(`<div class=muted style=display:grid;place-items:center;height:100%>no events yet — say something or press ▶ start`),$e=G(`<div class="content muted">thinking…`),et=G(`<option>`),tt=G(`<div class=muted>none yet`),nt=G(`<div><span>`),rt=G(`<div> → `),it=G(`<div class=avatar>`),at=G(`<div class=msg-head><span class=author></span><span class=ts></span><span class=ts>`),ot=G(`<div><div class=msg-body>`),st=G(`<span style=width:38px>`),ct=G(`<div class=content>`),lt=G(`<div class=msgfoot><span>copy summary`),ut=G(`<details class=embed><summary><b>⚙ </b> <span class=meta></span></summary><div class=mono>`),dt=G(`<details><summary><span class=meta></span></summary><div class=mono></div><div class=meta>ms`),ft=G(`<div class=meta>`),pt=G(`<div class=meta>⚠ `),mt=G(`<div class=meta>→ `),ht=G(`<div class=embed style=border-color:var(--ok)><div>📈 `),gt=G(`<div class="embed fail"><div class=mono>⚠ `),_t=G(`<div class="content muted">`),vt=G(`<button class=copybtn title="copy to clipboard">`),yt=G(`<div class=overlay><div class=modal><div class=modal-head><b></b><button class=iconbtn>✕`),bt=G(`<span style=color:var(--err);font-size:13px>`),xt=G(`<form style=display:flex;flex-direction:column;gap:10px><label>workspace directory<div style=display:flex;gap:6px><input type=text class="w100 mono"><button type=button>go</button><button type=button>↑</button></div></label><div class=dirlist></div><div style=display:flex;gap:10px><label style=flex:1>agent name <input type=text placeholder="(directory name)"></label><label>provider<select></select></label><label style=flex:1>model <input type=text placeholder="(provider default)"></label></div><button type=submit style=align-self:flex-end>create & start`),St=G(`<div class=direntry>📁 `),Ct=G(`<form style=display:flex;flex-direction:column;gap:10px><label>providers (<!>)<textarea rows=8 class="mono w100"></textarea></label><div style=display:flex;gap:10px><label style=flex:1>default provider <input type=text></label><label>progress interval (min) <input type=number min=1 style=width:90px></label></div><label>scheduled tasks (JSON array)<textarea rows=7 class="mono w100"></textarea></label><button type=submit style=align-self:flex-end>save`),wt={user:{name:`you`,icon:`🧑`,color:`#faa81a`},message:{name:`agent`,icon:`🫖`,color:`#5865f2`},tool_call:{name:`tool`,icon:`🔧`,color:`#3ba0c9`},progress:{name:`progress`,icon:`📈`,color:`#3ba55d`}},Tt=e=>wt[e.type]??{name:e.type,icon:`•`,color:`#9298a5`},Et=new Set([`user`,`message`,`prompt`,`tool_call`,`tool_result`,`progress`]),Dt=e=>Et.has(e.type),Ot=e=>{let t=new Date(e);return`${String(t.getHours()).padStart(2,`0`)}:${String(t.getMinutes()).padStart(2,`0`)}`};async function $(e,t){let n=localStorage.getItem(`teapot.token`),r=new Headers(t?.headers);n&&!r.has(`authorization`)&&r.set(`authorization`,`Bearer ${n}`);let i=await fetch(e,{...t,headers:r});if(!i.ok)throw Error(`${e}: ${i.status}`);return i.json()}var kt=location.hash.match(/[#&]token=([^&]+)/);kt&&(localStorage.setItem(`teapot.token`,decodeURIComponent(kt[1])),history.replaceState(null,``,location.pathname+location.search));var At=()=>{let e=localStorage.getItem(`teapot.token`);return e?`?token=${encodeURIComponent(e)}`:``};function jt(){let[e,t]=v([]),[n,r]=v(null),[i,a]=v([]),[o,s]=v([]),[c,l]=v(null),[u,d]=v(``),[f,p]=v(!0),[m,h]=v({providers:{}}),[g,_]=v(!1),[S,w]=v(!1),[T,te]=v(localStorage.getItem(`teapot.panel`)===null?window.innerWidth>1100:localStorage.getItem(`teapot.panel`)===`1`),ne=()=>{te(!T()),localStorage.setItem(`teapot.panel`,T()?`1`:`0`)},[E,re]=v(``),[D,ie]=v(``),[O,k]=v([]),A=()=>Object.keys(m().providers??{});async function ae(e){if(e)try{let t=await $(`/api/models?provider=${encodeURIComponent(e)}`);k(t.models??[])}catch{k([])}}b(()=>{let e=I();e&&(re(e.provider||m().defaultProvider||A()[0]||``),ie(``),ae(E()))});let[oe,se]=v(!0),[j,M]=v(0),[N,P]=v(null),ce=x(()=>i().filter(Dt)),F=()=>$(`/api/config`).then(h).catch(()=>{}),I=x(()=>e().find(e=>e.id===n())),L=()=>$(`/api/agents`).then(e=>t(e.agents)).catch(()=>{}),R=()=>$(`/api/metrics`).then(l).catch(()=>{});async function le(e){try{let[t,n]=await Promise.all([$(`/api/agents/${e}/events?limit=300`),$(`/api/agents/${e}/branches`)]);a(t.events),s(n.branches)}catch{}}function ue(){return document.querySelector(`.feed`)}function de(){let e=ue();return!e||e.scrollHeight-e.scrollTop-e.clientHeight<80}function U(e=!1){let t=ue();t&&(e||oe())&&(t.scrollTop=t.scrollHeight,M(0))}async function W(e,t=!0){r(e),P(null),localStorage.setItem(`teapot.session`,e),ve(e,t),await le(e),requestAnimationFrame(()=>U(!0))}let[G,fe]=v(!1),q=null,ge=null;C(()=>q?.close());function _e(){let e=location.protocol===`https:`?`wss://`:`ws://`;q=new WebSocket(`${e}${location.host}/api/ws${At()}`),q.onopen=()=>fe(!0),q.onclose=()=>{fe(!1),setTimeout(_e,1500)},q.onerror=()=>q?.close(),q.onmessage=e=>{let t=JSON.parse(e.data);if(t.kind!==`ping`&&t.kind!==`pong`){if(t.kind===`llm-delta`){t.agentId===n()&&P({text:t.text??``,reasoning:t.reasoning??``});return}ge||=setTimeout(async()=>{if(ge=null,await L(),await R(),n()){let e=i().length;await le(n()),i().length!==e&&(P(null),de()?U(!0):M(j()+(i().length-e)))}},400)}}}let Y=()=>decodeURIComponent(location.pathname.split(`/`)[2]??``);function ve(e,t=!0){let n=`/session/${encodeURIComponent(e)}`;t?history.pushState(null,``,n):history.replaceState(null,``,n)}window.addEventListener(`popstate`,()=>{let t=Y();t&&e().some(e=>e.id===t)&&t!==n()&&W(t,!1)}),b(()=>{let e=I();document.title=e?`${e.status===`running`?`▶ `:e.status===`error`?`⚠ `:``}${e.id} · teapot`:`teapot`}),window.addEventListener(`keydown`,t=>{let r=t.target;if(r&&(r.tagName===`INPUT`||r.tagName===`TEXTAREA`||r.isContentEditable)){t.key===`Escape`&&r.blur();return}if(t.key===`Escape`){if(g()){_(!1);return}if(S()){w(!1);return}let e=I();if(e?.status===`running`){$(`/api/agents/${e.id}/stop`,{method:`POST`}).then(L);return}T()&&window.innerWidth<=1100&&te(!1);return}if(!(g()||S())){if(t.key===`/`)t.preventDefault(),document.querySelector(`.composer input[type=text]`)?.focus();else if(t.key===`d`)ne();else if(t.key===`t`)ye();else if(t.key===`ArrowDown`||t.key===`ArrowUp`){let r=e();if(r.length===0)return;t.preventDefault();let i=r.findIndex(e=>e.id===n()),a=t.key===`ArrowDown`?Math.min(i+1,r.length-1):Math.max(i-1,0);a!==i&&W(r[a].id)}}});let[X,Z]=v(localStorage.getItem(`teapot.term`)===`1`),ye=()=>{Z(!X()),localStorage.setItem(`teapot.term`,X()?`1`:`0`)},be=null,xe=null,Se=null,Q=null,rt={cols:0,rows:0},it=null;function at(){Q?.disconnect(),Q=null,Se?.close(),Se=null,xe?.dispose(),xe=null}function ot(e){at(),be&&Promise.all([Ce(()=>import(`./xterm-C3BHN0de.js`),[]),Ce(()=>import(`./addon-fit-DIOBYJe3.js`),[])]).then(([{Terminal:t},{FitAddon:n}])=>{let r=new t({cursorBlink:!0,fontSize:12.5,fontFamily:`ui-monospace, Menlo, Consolas, monospace`,theme:{background:`#0d0e12`,foreground:`#dcdee4`}}),i=new n;r.loadAddon(i),r.open(be),i.fit(),xe=r;let a=location.protocol===`https:`?`wss://`:`ws://`,o=new WebSocket(`${a}${location.host}/api/agents/${e}/term${At()}`);Se=o,o.onmessage=e=>{let t=JSON.parse(e.data);t.kind===`data`?r.write(t.data):t.kind===`exit`&&r.write(`\r\n\x1b[2m[terminal exited ${t.code??``}]\x1b[0m\r\n`)},r.onData(e=>{o.readyState===WebSocket.OPEN&&o.send(JSON.stringify({kind:`input`,data:e}))});let s=()=>{try{i.fit()}catch{}let{cols:e,rows:t}=r;(e!==rt.cols||t!==rt.rows)&&o.readyState===WebSocket.OPEN&&(rt={cols:e,rows:t},o.send(JSON.stringify({kind:`resize`,cols:e,rows:t})))};Q=new ResizeObserver(()=>{it&&clearTimeout(it),it=setTimeout(s,300)}),Q.observe(be),setTimeout(s,50)})}b(()=>{let e=n();!X()||!e?at():requestAnimationFrame(()=>e&&ot(e))}),C(at),ee(()=>{F(),L().then(()=>{let t=Y()||localStorage.getItem(`teapot.session`)||``,n=e().find(e=>e.id===t)??e()[0];n&&W(n.id,!1)}),R(),_e(),setInterval(R,3e4)});let st=async e=>{if(e.preventDefault(),!n()||!u().trim())return;let t=u();d(``),await $(`/api/agents/${n()}/prompt`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({text:t,start:f()})})},ct=e=>()=>n()&&$(`/api/agents/${n()}${e}`,{method:`POST`}).then(L),lt=async e=>{e.preventDefault();let t=document.getElementById(`goal-input`);!n()||!t.value.trim()||(await $(`/api/agents/${n()}/goal`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({text:t.value})}),t.value=``,L())};return[(()=>{var i=Je(),a=i.firstChild,s=a.firstChild,l=s.firstChild.nextSibling,h=l.nextSibling.firstChild,g=h.nextSibling,v=s.nextSibling,b=v.nextSibling,x=a.nextSibling,S=x.nextSibling;return h.$$click=()=>{F(),_(!0)},g.$$click=()=>{F(),w(!0)},J(v,z(B,{get each(){return e()},children:e=>(()=>{var t=Xe(),r=t.firstChild,i=r.nextSibling;return t.$$click=()=>W(e.id),J(i,()=>e.id),J(t,z(V,{get when(){return e.goal.status===`done`},get children(){return Ye()}}),null),y(i=>{var a=`agent-item`+(e.id===n()?` sel`:``),o=`dot ${e.status}`;return a!==i.e&&K(t,i.e=a),o!==i.t&&K(r,i.t=o),i},{e:void 0,t:void 0}),t})()})),J(b,z(V,{get when(){return c()},get children(){return[`master rss `,H(()=>c().rssMb),`MB · heap `,H(()=>c().heapUsedMb),`MB`,we(),`load1 `,H(()=>c().loadavg1),` · up `,H(()=>Math.floor(c().uptimeSec/60)),`m`]}})),J(x,z(V,{get when(){return I()},get fallback(){return Ze()},get children(){return[(()=>{var e=Ee(),t=e.firstChild.nextSibling,n=t.nextSibling,r=n.nextSibling,i=r.firstChild,a=i.nextSibling,o=a.nextSibling.nextSibling,s=o.nextSibling.nextSibling;s.nextSibling;var c=r.nextSibling,l=c.firstChild,u=l.nextSibling;return J(t,()=>I().id),J(n,()=>I().status),J(r,()=>I().model,i),J(r,()=>I().session,a),J(r,()=>I().branch,o),J(r,()=>I().stats.turns,s),J(r,()=>I().stats.toolCalls,null),J(c,z(V,{get when(){return I().statusReason},get children(){var e=Te();return y(()=>pe(e,`title`,I().statusReason)),e}}),l),l.$$click=ye,u.$$click=ne,y(()=>K(n,`badge ${I().status}`)),e})(),(()=>{var e=Ae();return e.addEventListener(`scroll`,()=>{let e=de();e&&j()&&M(0),se(e)}),J(e,z(V,{get when(){return ce().length>0},get fallback(){return Qe()},get children(){return[z(B,{get each(){return ce()},children:(e,t)=>z(Mt,{e,get prev(){return ce()[t()-1]}})}),z(V,{get when(){return N()},get children(){var e=ke(),t=e.firstChild.nextSibling;return t.firstChild,J(t,z(V,{get when(){return N().reasoning},get children(){var e=De(),t=e.firstChild.nextSibling;return J(t,()=>N().reasoning),e}}),null),J(t,z(V,{get when(){return N().text},get fallback(){return $e()},get children(){var e=Oe(),t=e.firstChild;return J(e,()=>N().text,t),e}}),null),e}})]}})),e})(),z(V,{get when(){return!oe()||j()>0},get children(){var e=je();return e.firstChild,e.$$click=()=>U(!0),J(e,(()=>{var e=H(()=>j()>0);return()=>e()?`${j()} new message${j()>1?`s`:``}`:`jump to present`})(),null),e}}),z(V,{get when(){return H(()=>!!X())()&&I()},get children(){var e=Me(),t=e.firstChild,n=t.firstChild,r=n.firstChild.nextSibling,i=n.nextSibling,a=t.nextSibling;return J(r,()=>I().workspace),i.$$click=ye,he(e=>be=e,a),e}}),(()=>{var e=Ne(),t=e.firstChild,n=t.firstChild,r=n.nextSibling.firstChild;return t.addEventListener(`submit`,st),n.$$input=e=>d(e.currentTarget.value),r.addEventListener(`change`,e=>p(e.currentTarget.checked)),y(()=>pe(n,`placeholder`,`message #${I().id}`)),y(()=>n.value=u()),y(()=>r.checked=f()),e})()]}})),J(S,z(V,{get when(){return I()},get children(){return[Pe(),(()=>{var e=Fe(),t=e.firstChild,n=t.firstChild.nextSibling,r=n.nextSibling,i=t.nextSibling,a=i.firstChild.nextSibling,o=i.nextSibling.firstChild.nextSibling,s=o.firstChild;return J(n,()=>I().id),J(r,()=>I().status),J(a,()=>I().workspace),J(o,()=>I().session,s),J(o,()=>I().branch,null),y(e=>{var t=`badge ${I().status}`,n=I().workspace;return t!==e.e&&K(r,e.e=t),n!==e.t&&pe(a,`title`,e.t=n),e},{e:void 0,t:void 0}),e})(),Ie(),(()=>{var e=Le(),t=e.firstChild,r=t.nextSibling,i=r.firstChild,a=i.nextSibling,o=a.nextSibling,s=r.nextSibling;return s.firstChild,t.addEventListener(`change`,e=>{re(e.currentTarget.value),ae(e.currentTarget.value)}),J(t,z(B,{get each(){return A()},children:e=>(()=>{var t=et();return t.value=e,J(t,e,null),J(t,()=>e===m().defaultProvider?` ★`:``,null),t})()})),i.$$input=e=>ie(e.currentTarget.value),J(a,z(B,{get each(){return O()},children:e=>(()=>{var t=et();return t.value=e,t})()})),o.$$click=async()=>{n()&&(await $(`/api/agents/${n()}/model`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({provider:E(),model:D().trim()||void 0})}),L())},J(s,()=>I().model,null),J(s,z(V,{get when(){return O().length},get children(){return[` · `,H(()=>O().length),` models loaded`]}}),null),y(()=>pe(i,`placeholder`,I().model)),y(()=>t.value=E()),y(()=>i.value=D()),e})(),Re(),(()=>{var n=ze(),i=n.firstChild,a=i.nextSibling,o=a.nextSibling,s=o.nextSibling;return me(i,`click`,ct(`/start`),!0),me(a,`click`,ct(`/stop`),!0),o.$$click=()=>$(`/api/agents/${I().id}/fork`,{method:`POST`,headers:{"content-type":`application/json`},body:`{}`}).then(()=>W(I().id)),s.$$click=async()=>{confirm(`remove agent ${I().id}? (log is kept)`)&&(await $(`/api/agents/${I().id}`,{method:`DELETE`}),r(null),t(e().filter(e=>e.id!==I().id)))},n})(),(()=>{var e=Be(),t=e.firstChild.nextSibling;return J(t,()=>I().goal.status),y(()=>K(t,`badge ${I().goal.status===`done`?`done`:``}`)),e})(),(()=>{var e=Ve();return e.addEventListener(`submit`,lt),e})(),(()=>{var e=He();return J(e,()=>I().goal.text||`no goal set`),e})(),Ue(),z(V,{get when(){return I().latestProgress},get fallback(){return tt()},get children(){var e=We(),t=e.firstChild,n=t.nextSibling,r=n.nextSibling.nextSibling;return J(e,()=>I().latestProgress.doing,t),J(e,()=>I().latestProgress.recent??``,n),J(r,()=>I().latestProgress.ts),e}}),Ge(),(()=>{var e=Ke(),t=e.firstChild.nextSibling,n=t.nextSibling.nextSibling,r=n.nextSibling.nextSibling,i=r.nextSibling.nextSibling;return i.nextSibling,J(e,()=>I().stats.turns,t),J(e,()=>I().stats.toolCalls,n),J(e,()=>I().stats.compactions??0,r),J(e,()=>I().stats.inputTokens,i),J(e,()=>I().stats.outputTokens,null),e})(),qe(),z(B,{get each(){return o()},children:e=>(()=>{var t=nt(),n=t.firstChild;return J(t,()=>e.branch,n),J(n,()=>e.events),y(()=>K(t,`branch-row`+(e.branch===I().branch?` cur`:``))),t})()})]}})),y(e=>{var t=`layout`+(T()?``:` right-hidden`),n=`conn`+(G()?` ok`:``),r=G()?`live (websocket)`:`reconnecting…`,a=`rightbar`+(T()?` open`:``);return t!==e.e&&K(i,e.e=t),n!==e.t&&K(l,e.t=n),r!==e.a&&pe(l,`title`,e.a=r),a!==e.o&&K(S,e.o=a),e},{e:void 0,t:void 0,a:void 0,o:void 0}),i})(),z(V,{get when(){return g()},get children(){return z(Rt,{get providers(){return Object.keys(m().providers??{})},onClose:()=>_(!1),onCreated:e=>{_(!1),L(),W(e)}})}}),z(V,{get when(){return S()},get children(){return z(zt,{get cfg(){return m()},onClose:()=>w(!1),onSaved:F})}})]}function Mt(e){let t=e.e,n=Tt(t),r=e.prev&&e.prev.type===t.type&&t.session===e.prev.session&&t.branch===e.prev.branch;return t.type===`state`?t.data.from===t.data.to?null:(()=>{var e=rt(),n=e.firstChild;return J(e,()=>t.data.from,n),J(e,()=>t.data.to,null),J(e,(()=>{var e=H(()=>!!t.data.reason);return()=>e()?` — ${t.data.reason}`:``})(),null),y(()=>K(e,`divider-msg`+(t.data.to===`error`?` err`:``))),e})():(()=>{var e=ot(),i=e.firstChild;return K(e,`msg`+(r?` grouped`:``)),J(e,z(V,{when:!r,get fallback(){return st()},get children(){var e=it();return J(e,()=>n.icon),y(t=>{var r=n.color+`33`,i=`1px solid ${n.color}66`;return r!==t.e&&q(e,`background`,t.e=r),i!==t.t&&q(e,`border`,t.t=i),t},{e:void 0,t:void 0}),e}}),i),J(i,z(V,{when:!r,get children(){var e=at(),r=e.firstChild,i=r.nextSibling,a=i.nextSibling;return J(r,()=>n.name),J(i,()=>Ot(t.ts)),J(a,()=>t.branch),y(e=>q(r,`color`,n.color)),e}}),null),J(i,z(Nt,{e:t}),null),e})()}function Nt(e){let t=e.e;switch(t.type){case`prompt`:return(()=>{var e=ct();return y(()=>e.innerHTML=ye(String(t.data.text??``))),e})();case`message`:return[z(V,{get when(){return H(()=>typeof t.data.reasoning==`string`)()&&t.data.reasoning.trim()},get children(){var e=De(),n=e.firstChild.nextSibling;return J(n,()=>String(t.data.reasoning)),e}}),(()=>{var e=ct();return y(()=>e.innerHTML=ye(String(t.data.content??``))),e})(),z(V,{get when(){return t.data.final},get children(){var e=lt(),n=e.firstChild;return J(e,z(It,{get text(){return String(t.data.content??``)}}),n),e}})];case`tool_call`:{let e=JSON.stringify(t.data.args,null,1),n=Ft(JSON.stringify(t.data.args??{}),110);return(()=>{var r=ut(),i=r.firstChild,a=i.firstChild;a.firstChild;var o=a.nextSibling.nextSibling,s=i.nextSibling;return J(a,()=>String(t.data.name),null),J(o,n),J(s,e),r})()}case`tool_result`:{let e=String(t.data.result);return(()=>{var n=dt(),r=n.firstChild,i=r.firstChild,a=r.nextSibling,o=a.nextSibling,s=o.firstChild;return J(i,()=>Ft(e,120)),J(r,z(It,{text:e}),null),J(a,()=>Pt(e,4e3)),J(o,()=>t.data.durationMs,s),J(o,()=>t.data.ok?``:` · FAILED`,null),y(()=>K(n,`embed`+(t.data.ok?``:` fail`))),n})()}case`progress`:return(()=>{var e=ht(),n=e.firstChild;return n.firstChild,J(n,()=>String(t.data.doing??``),null),J(e,z(V,{get when(){return t.data.recent},get children(){var e=ft();return J(e,()=>String(t.data.recent)),e}}),null),J(e,z(V,{get when(){return t.data.problems},get children(){var e=pt();return e.firstChild,J(e,()=>String(t.data.problems),null),e}}),null),J(e,z(V,{get when(){return t.data.next},get children(){var e=mt();return e.firstChild,J(e,()=>String(t.data.next),null),e}}),null),e})();case`error`:return(()=>{var e=gt(),n=e.firstChild;return n.firstChild,J(n,()=>String(t.data.message??``),null),e})();default:return(()=>{var e=_t();return J(e,()=>Pt(JSON.stringify(t.data),200)),e})()}}function Pt(e,t){return e.length>t?e.slice(0,t)+` …`:e}function Ft(e,t){return Pt(e.replace(/\s+/g,` `).trim(),t)}function It(e){let[t,n]=v(!1);return(()=>{var r=vt();return r.$$click=t=>{t.stopPropagation(),navigator.clipboard.writeText(e.text).then(()=>{n(!0),setTimeout(()=>n(!1),900)})},J(r,()=>t()?`✓`:`⧉`),r})()}function Lt(e){return(()=>{var t=yt(),n=t.firstChild,r=n.firstChild.firstChild,i=r.nextSibling;return t.$$click=t=>t.target===t.currentTarget&&e.onClose(),J(r,()=>e.title),me(i,`click`,e.onClose,!0),J(n,()=>e.children,null),t})()}function Rt(e){let[t,n]=v(`~`),[r,i]=v([]),[a,o]=v(``),[s,c]=v(e.providers[0]??``),[l,u]=v(``),[d,f]=v(``);async function p(e){let t=await $(`/api/fs${e?`?path=${encodeURIComponent(e)}`:``}`);n(t.path),i(t.entries)}ee(()=>p(t()));let m=async n=>{n.preventDefault(),f(``);try{let n=await $(`/api/agents`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({workspace:t(),id:a(),provider:s()||void 0,model:l()||void 0})});e.onCreated(n.agent.id)}catch(e){f(String(e.message))}};return z(Lt,{title:`new agent`,get onClose(){return e.onClose},get children(){var i=xt(),f=i.firstChild,h=f.firstChild.nextSibling.firstChild,g=h.nextSibling,_=g.nextSibling,v=f.nextSibling,b=v.nextSibling,x=b.firstChild,S=x.firstChild.nextSibling,ee=x.nextSibling,C=ee.firstChild.nextSibling,w=ee.nextSibling.firstChild.nextSibling,T=b.nextSibling;return i.addEventListener(`submit`,m),h.$$input=e=>n(e.currentTarget.value),g.$$click=()=>p(t()),_.$$click=()=>p(`..`),J(v,z(B,{get each(){return r()},children:e=>(()=>{var n=St();return n.firstChild,n.$$click=()=>p(`${t()}/${e}`.replace(/\/+/g,`/`)),J(n,e,null),n})()})),S.$$input=e=>o(e.currentTarget.value),C.addEventListener(`change`,e=>c(e.currentTarget.value)),J(C,z(B,{get each(){return e.providers},children:e=>(()=>{var t=et();return J(t,e),t})()})),w.$$input=e=>u(e.currentTarget.value),J(i,z(V,{get when(){return d()},get children(){var e=bt();return J(e,d),e}}),T),y(()=>h.value=t()),y(()=>S.value=a()),y(()=>C.value=s()),y(()=>w.value=l()),i}})}function zt(e){let[t,n]=v(JSON.stringify(Object.fromEntries(Object.entries(e.cfg.providers??{}).map(([e,t])=>[e,{baseUrl:t.baseUrl,apiKey:t.apiKey??``,model:t.model??``}])),null,2)),[r,i]=v(e.cfg.defaultProvider??Object.keys(e.cfg.providers??{})[0]??``),[a,o]=v(Math.round((e.cfg.progressIntervalMs??6e5)/6e4)),[s,c]=v(JSON.stringify(e.cfg.tasks??[],null,2)),[l,u]=v(``),d=async n=>{n.preventDefault(),u(``);let i,o;try{i=JSON.parse(t())}catch{return u(`providers: invalid JSON`)}try{o=JSON.parse(s())}catch{return u(`tasks: invalid JSON`)}try{await $(`/api/config`,{method:`PUT`,headers:{"content-type":`application/json`},body:JSON.stringify({providers:i,defaultProvider:r(),progressIntervalMs:Math.max(1,a())*6e4,tasks:o})}),e.onSaved(),e.onClose()}catch(e){u(String(e.message))}};return z(Lt,{title:`settings`,get onClose(){return e.onClose},get children(){var u=Ct(),f=u.firstChild,p=f.firstChild.nextSibling,m=p.nextSibling.nextSibling,h=f.nextSibling,g=h.firstChild,_=g.firstChild.nextSibling,v=g.nextSibling.firstChild.nextSibling,b=h.nextSibling,x=b.firstChild.nextSibling,S=b.nextSibling;return u.addEventListener(`submit`,d),J(f,()=>e.cfg.configPath,p),m.$$input=e=>n(e.currentTarget.value),_.$$input=e=>i(e.currentTarget.value),v.$$input=e=>o(Number(e.currentTarget.value)),x.$$input=e=>c(e.currentTarget.value),J(u,z(V,{get when(){return l()},get children(){var e=bt();return J(e,l),e}}),S),y(()=>m.value=t()),y(()=>_.value=r()),y(()=>v.value=a()),y(()=>x.value=s()),u}})}fe([`click`,`input`]),W(()=>z(jt,{}),document.getElementById(`root`));
|
package/public/index.html
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
6
|
<title>teapot</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-JRXeHcww.js"></script>
|
|
8
8
|
<link rel="stylesheet" crossorigin href="/assets/index-DIs0rfrk.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|