echospace 0.1.0-alpha.1 → 0.1.0-alpha.3

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 CHANGED
@@ -1,6 +1,10 @@
1
- # EchoSpace
1
+ <p align="center">
2
+ <img src="assets/echospace-logo/echospace-logo.png" alt="EchoSpace" width="128" />
3
+ </p>
2
4
 
3
- **The open-source, local-first prompt debugging workspace for LLM developers.**
5
+ <h1 align="center">EchoSpace</h1>
6
+
7
+ <p align="center"><strong>The open-source, local-first prompt debugging workspace for LLM developers.</strong></p>
4
8
 
5
9
  Debug, iterate, and manage your prompts across OpenAI, Anthropic, and Google — all from your terminal. No cloud, no accounts, no lock-in.
6
10
 
@@ -18,7 +22,7 @@ MIT-licensed. Pluggable provider adapters (OpenAI, Anthropic, Google). YAML-base
18
22
 
19
23
  ### CLI & SDK
20
24
 
21
- `npx echospace` to launch. Core TypeScript modules (`parseEcho`, `serializeEcho`, `smartParse`, provider registry) can be imported as a library for building your own tools.
25
+ `npx echospace@alpha` to launch. Core TypeScript modules (`parseEcho`, `serializeEcho`, `smartParse`, provider registry) can be imported as a library for building your own tools.
22
26
 
23
27
  ---
24
28
 
@@ -41,28 +45,36 @@ MIT-licensed. Pluggable provider adapters (OpenAI, Anthropic, Google). YAML-base
41
45
 
42
46
  EchoSpace ships with agent skills that work with any coding agent — [Claude Code](https://docs.anthropic.com/en/docs/claude-code), [OpenAI Codex](https://openai.com/index/codex/), or any tool that supports the skills/SKILL.md convention.
43
47
 
44
- **Claude Code:**
45
-
46
48
  ```bash
47
- claude install-skill https://github.com/stonexer/echospace/tree/master/skills/echospace
49
+ npx skills add https://github.com/stonexer/echospace/tree/master/skills/echospace
48
50
  ```
49
51
 
50
- **Other agents:** Copy the `skills/echospace/` directory into your project's skills folder.
51
-
52
52
  ### 2. Configure providers
53
53
 
54
- Run the interactive setup wizard in your coding agent:
54
+ ```bash
55
+ npx echospace init
56
+ ```
55
57
 
56
58
  ```
57
- /echospace:init
59
+ ◆ Which LLM service do you use?
60
+ │ ○ OpenAI
61
+ │ ○ Anthropic (Claude)
62
+ │ ○ Google (Gemini)
63
+ │ ○ Vercel AI Gateway
64
+ │ ○ Custom Gateway (OpenAI-compatible)
65
+
66
+ ◆ Enter your API Key:
67
+ │ sk-xxxxxxxx
68
+
69
+ ✓ Config saved to ~/.echospace/config.yaml
58
70
  ```
59
71
 
60
- This will guide you through selecting LLM providers (OpenAI, Anthropic, Google, Vercel AI Gateway) and entering API keys. The config is saved to `~/.echospace/config.yaml`.
72
+ Or use the agent skill: `/echospace:init`
61
73
 
62
74
  ### 3. Launch
63
75
 
64
76
  ```bash
65
- npx echospace
77
+ npx echospace@alpha
66
78
  ```
67
79
 
68
80
  Or install globally:
@@ -82,7 +94,7 @@ This will:
82
94
  ║ EchoSpace v0.1.0 ║
83
95
  ╠══════════════════════════════════════╣
84
96
  ║ Workspace: /my-project/.echo ║
85
- ║ URL: http://localhost:7788
97
+ ║ URL: http://localhost:3240
86
98
  ╚══════════════════════════════════════╝
87
99
  ```
88
100
 
@@ -100,7 +112,7 @@ This will:
100
112
  echospace [workdir] [options]
101
113
 
102
114
  [workdir] Workspace directory (default: ".")
103
- -p, --port <port> Port to serve on (default: auto-select 7788-7799)
115
+ -p, --port <port> Port to serve on (default: auto-select 3240-3249)
104
116
  --no-open Don't open browser automatically
105
117
  ```
106
118
 
@@ -120,24 +132,6 @@ Each message can contain multiple part types: `text`, `thinking`, `tool_call`, `
120
132
 
121
133
  ---
122
134
 
123
- ## Architecture
124
-
125
- ```
126
- ┌─────────┐ ┌──────────────┐ ┌──────────────────┐
127
- │ CLI │──────▶│ Hono Server │──────▶│ Provider Adapters│
128
- │ (Commander) │ (localhost) │ │ ┌──────────────┐ │
129
- └─────────┘ │ │ │ │ OpenAI │ │──▶ LLM APIs
130
- │ /api/* │ │ │ Anthropic │ │
131
- ┌─────────┐ │ │ │ │ Google │ │
132
- │ React UI│◀─────▶│ Static files│ │ └──────────────┘ │
133
- │ (browser)│ └──────────────┘ └──────────────────┘
134
- └─────────┘
135
- ```
136
-
137
- **Tech stack:** React 19 · Hono · Zustand · Tailwind CSS 4 · Vite · CodeMirror · tiktoken
138
-
139
- ---
140
-
141
135
  ## Configuration
142
136
 
143
137
  On first launch, EchoSpace creates `~/.echospace/config.yaml`. Fill in the `api_key` for the providers you want to use — unconfigured providers are automatically ignored.
@@ -177,38 +171,13 @@ providers:
177
171
 
178
172
  ---
179
173
 
180
- ## SDK / Programmatic Usage
181
-
182
- Core modules can be imported directly for building your own tooling:
183
-
184
- ```typescript
185
- import { parseEcho, serializeEcho } from "echospace/core/echo";
186
- import { smartParse, detectFormat } from "echospace/core/smart-paste";
187
- import { createProviderRegistry } from "echospace/core/providers/registry";
188
-
189
- // Parse a .echo file
190
- const conversation = parseEcho(fileContents);
191
- console.log(conversation.meta.title);
192
- console.log(conversation.messages.length);
193
-
194
- // Detect and convert from other formats
195
- const format = detectFormat(clipboardText); // "openai" | "anthropic" | "google" | "raw" | ...
196
- const messages = smartParse(clipboardText);
197
-
198
- // Create a provider registry
199
- const registry = createProviderRegistry();
200
- const adapter = registry.get("openai");
201
- ```
202
-
203
- ---
204
-
205
174
  ## Development
206
175
 
207
176
  ```bash
208
177
  # Install dependencies
209
178
  pnpm install
210
179
 
211
- # Start dev server (UI on :5173, API on :7788)
180
+ # Start dev server (UI on :5173, API on :3240)
212
181
  pnpm dev
213
182
 
214
183
  # Other scripts
package/dist/cli/index.js CHANGED
@@ -4,8 +4,8 @@
4
4
  import { Command } from "commander";
5
5
  import getPort, { portNumbers } from "get-port";
6
6
  import fs3 from "fs";
7
- import { homedir } from "os";
8
- import path4 from "path";
7
+ import { homedir as homedir2 } from "os";
8
+ import path5 from "path";
9
9
  import open from "open";
10
10
 
11
11
  // src/server/services/config.ts
@@ -104,7 +104,7 @@ function toAnthropicContent(msg) {
104
104
  case "tool_result":
105
105
  blocks.push({
106
106
  type: "tool_result",
107
- tool_use_id: part.id,
107
+ tool_use_id: part.tool_call_id,
108
108
  content: typeof part.output === "string" ? part.output : JSON.stringify(part.output),
109
109
  is_error: part.is_error
110
110
  });
@@ -132,7 +132,7 @@ var anthropicAdapter = {
132
132
  const url = `${baseUrl.replace(/\/$/, "")}/v1/messages`;
133
133
  const systemMessages = messages.filter((m) => m.role === "system");
134
134
  const nonSystemMessages = messages.filter((m) => m.role !== "system");
135
- const system = systemMessages.flatMap((m) => m.parts.filter((p) => p.type === "text")).map((p) => p.text).join("\n\n");
135
+ const system = systemMessages.flatMap((m) => m.parts.filter((p2) => p2.type === "text")).map((p2) => p2.text).join("\n\n");
136
136
  const body = {
137
137
  model: settings.model ?? config.models[0],
138
138
  messages: nonSystemMessages.map((msg) => ({
@@ -232,7 +232,7 @@ function toGeminiContent(msg) {
232
232
  case "tool_result":
233
233
  parts.push({
234
234
  functionResponse: {
235
- name: part.id,
235
+ name: part.tool_call_id,
236
236
  response: { result: part.output }
237
237
  }
238
238
  });
@@ -262,7 +262,7 @@ var googleAdapter = {
262
262
  const nonSystemMessages = messages.filter((m) => m.role !== "system");
263
263
  const systemInstruction = systemMessages.length > 0 ? {
264
264
  parts: systemMessages.flatMap(
265
- (m) => m.parts.filter((p) => p.type === "text").map((p) => ({ text: p.text }))
265
+ (m) => m.parts.filter((p2) => p2.type === "text").map((p2) => ({ text: p2.text }))
266
266
  )
267
267
  } : void 0;
268
268
  const body = {
@@ -332,20 +332,20 @@ var googleAdapter = {
332
332
  // src/core/providers/openai.ts
333
333
  function toOpenAIMessage(msg) {
334
334
  const result = { role: msg.role };
335
- const textParts = msg.parts.filter((p) => p.type === "text");
336
- const toolCalls = msg.parts.filter((p) => p.type === "tool_call");
337
- const toolResults = msg.parts.filter((p) => p.type === "tool_result");
338
- const thinkingParts = msg.parts.filter((p) => p.type === "thinking");
335
+ const textParts = msg.parts.filter((p2) => p2.type === "text");
336
+ const toolCalls = msg.parts.filter((p2) => p2.type === "tool_call");
337
+ const toolResults = msg.parts.filter((p2) => p2.type === "tool_result");
338
+ const thinkingParts = msg.parts.filter((p2) => p2.type === "thinking");
339
339
  if (msg.role === "tool" && toolResults.length > 0) {
340
340
  const tr = toolResults[0];
341
341
  result.content = typeof tr.output === "string" ? tr.output : JSON.stringify(tr.output);
342
- result.tool_call_id = tr.id;
342
+ result.tool_call_id = tr.tool_call_id;
343
343
  return result;
344
344
  }
345
345
  if (msg.role === "assistant") {
346
- result.content = textParts.map((p) => p.text).join("") || null;
346
+ result.content = textParts.map((p2) => p2.text).join("") || null;
347
347
  if (thinkingParts.length > 0) {
348
- result.reasoning_content = thinkingParts.map((p) => p.text).join("");
348
+ result.reasoning_content = thinkingParts.map((p2) => p2.text).join("");
349
349
  }
350
350
  if (toolCalls.length > 0) {
351
351
  result.tool_calls = toolCalls.map((tc) => ({
@@ -359,7 +359,7 @@ function toOpenAIMessage(msg) {
359
359
  }
360
360
  return result;
361
361
  }
362
- result.content = textParts.map((p) => p.text).join("");
362
+ result.content = textParts.map((p2) => p2.text).join("");
363
363
  return result;
364
364
  }
365
365
  var openaiAdapter = {
@@ -471,7 +471,7 @@ function chatRoutes(options) {
471
471
  const config = loadConfig(options.configDir);
472
472
  const providerList = config.providers ?? [];
473
473
  const providerConfig = providerList.find(
474
- (p) => p.name === providerName
474
+ (p2) => p2.name === providerName
475
475
  );
476
476
  if (!providerConfig) {
477
477
  return c.json(
@@ -589,22 +589,22 @@ function normalizeMessage(message) {
589
589
  if (!msg.created_at && (raw.ts || raw.timestamp)) {
590
590
  msg = { ...msg, created_at: raw.ts ?? raw.timestamp };
591
591
  }
592
- const needsPartNormalization = msg.parts.some((p) => {
593
- if (p.type !== "tool_result") return false;
594
- const r = p;
595
- return !r.id && (r.tool_call_id || r.tool_use_id);
592
+ const needsPartNormalization = msg.parts.some((p2) => {
593
+ if (p2.type !== "tool_result") return false;
594
+ const r = p2;
595
+ return !r.tool_call_id && (r.id || r.tool_use_id);
596
596
  });
597
597
  if (needsPartNormalization) {
598
598
  msg = {
599
599
  ...msg,
600
- parts: msg.parts.map((p) => {
601
- if (p.type !== "tool_result") return p;
602
- const r = p;
603
- if (!r.id && (r.tool_call_id || r.tool_use_id)) {
604
- const { tool_call_id, tool_use_id, ...rest } = r;
605
- return { ...rest, id: tool_call_id ?? tool_use_id };
600
+ parts: msg.parts.map((p2) => {
601
+ if (p2.type !== "tool_result") return p2;
602
+ const r = p2;
603
+ if (!r.tool_call_id && (r.id || r.tool_use_id)) {
604
+ const { id, tool_use_id, ...rest } = r;
605
+ return { ...rest, tool_call_id: id ?? tool_use_id };
606
606
  }
607
- return p;
607
+ return p2;
608
608
  })
609
609
  };
610
610
  }
@@ -804,14 +804,14 @@ function configRoutes(options) {
804
804
  app.get("/providers", async (c) => {
805
805
  const config = loadConfig(options.configDir);
806
806
  const providerList = config.providers ?? [];
807
- const providers = providerList.filter((p) => {
808
- if (p.api_key == null) return true;
809
- const resolved = p.api_key.replace(/\$\{(\w+)\}/g, (_, name) => process.env[name] ?? "");
807
+ const providers = providerList.filter((p2) => {
808
+ if (p2.api_key == null) return true;
809
+ const resolved = p2.api_key.replace(/\$\{(\w+)\}/g, (_, name) => process.env[name] ?? "");
810
810
  return resolved.length > 0;
811
- }).map((p) => ({
812
- name: p.name,
813
- type: p.type,
814
- models: p.models ?? []
811
+ }).map((p2) => ({
812
+ name: p2.name,
813
+ type: p2.type,
814
+ models: p2.models ?? []
815
815
  }));
816
816
  return c.json({ providers });
817
817
  });
@@ -862,11 +862,156 @@ function startServer(options) {
862
862
  return app;
863
863
  }
864
864
 
865
- // src/cli/index.ts
866
- var VERSION = "0.1.0-alpha.1";
865
+ // src/cli/init.ts
866
+ import * as p from "@clack/prompts";
867
+ import { homedir } from "os";
868
+ import path4 from "path";
867
869
  var CONFIG_DIR = path4.join(homedir(), ".echospace");
870
+ var PROVIDER_PRESETS = {
871
+ openai: {
872
+ name: "openai",
873
+ type: "openai",
874
+ models: [
875
+ "gpt-4.1",
876
+ "gpt-4.1-mini",
877
+ "gpt-4.1-nano",
878
+ "gpt-4o",
879
+ "gpt-4o-mini",
880
+ "o3",
881
+ "o3-mini",
882
+ "o4-mini"
883
+ ]
884
+ },
885
+ anthropic: {
886
+ name: "anthropic",
887
+ type: "anthropic",
888
+ models: ["claude-sonnet-4-6", "claude-haiku-4-5"]
889
+ },
890
+ google: {
891
+ name: "google",
892
+ type: "google",
893
+ models: ["gemini-2.5-pro", "gemini-2.5-flash", "gemini-2.0-flash"]
894
+ },
895
+ vercel: {
896
+ name: "vercel-ai-gateway",
897
+ type: "openai",
898
+ base_url: "https://ai-gateway.vercel.sh/v1",
899
+ models: [
900
+ "anthropic/claude-sonnet-4-6",
901
+ "anthropic/claude-haiku-4-5",
902
+ "openai/gpt-4.1",
903
+ "openai/gpt-4.1-mini",
904
+ "openai/gpt-4o",
905
+ "openai/gpt-4o-mini",
906
+ "google/gemini-2.5-pro",
907
+ "google/gemini-2.5-flash",
908
+ "google/gemini-2.0-flash"
909
+ ]
910
+ }
911
+ };
912
+ function isCancel2(value) {
913
+ return p.isCancel(value);
914
+ }
915
+ async function runInit() {
916
+ p.intro("EchoSpace Setup");
917
+ const service = await p.select({
918
+ message: "Which LLM service do you use?",
919
+ options: [
920
+ { value: "openai", label: "OpenAI" },
921
+ { value: "anthropic", label: "Anthropic (Claude)" },
922
+ { value: "google", label: "Google (Gemini)" },
923
+ { value: "vercel", label: "Vercel AI Gateway" },
924
+ { value: "custom", label: "Custom Gateway (OpenAI-compatible)" }
925
+ ]
926
+ });
927
+ if (isCancel2(service)) {
928
+ p.cancel("Setup cancelled.");
929
+ process.exit(0);
930
+ }
931
+ const apiKey = await p.password({
932
+ message: "Enter your API Key:"
933
+ });
934
+ if (isCancel2(apiKey)) {
935
+ p.cancel("Setup cancelled.");
936
+ process.exit(0);
937
+ }
938
+ let provider;
939
+ if (service === "custom") {
940
+ const baseUrl = await p.text({
941
+ message: "Base URL (e.g. https://my-proxy.example.com/v1):",
942
+ validate: (v) => {
943
+ if (!v.trim()) return "URL is required";
944
+ try {
945
+ new URL(v.trim());
946
+ } catch {
947
+ return "Invalid URL";
948
+ }
949
+ }
950
+ });
951
+ if (isCancel2(baseUrl)) {
952
+ p.cancel("Setup cancelled.");
953
+ process.exit(0);
954
+ }
955
+ const apiType = await p.select({
956
+ message: "Compatible API type:",
957
+ options: [
958
+ { value: "openai", label: "OpenAI" },
959
+ { value: "anthropic", label: "Anthropic" },
960
+ { value: "google", label: "Google" }
961
+ ]
962
+ });
963
+ if (isCancel2(apiType)) {
964
+ p.cancel("Setup cancelled.");
965
+ process.exit(0);
966
+ }
967
+ const modelsInput = await p.text({
968
+ message: "Model names (comma-separated, or press enter to skip):",
969
+ defaultValue: ""
970
+ });
971
+ if (isCancel2(modelsInput)) {
972
+ p.cancel("Setup cancelled.");
973
+ process.exit(0);
974
+ }
975
+ const models = modelsInput.split(",").map((m) => m.trim()).filter(Boolean);
976
+ provider = {
977
+ name: "custom",
978
+ type: apiType,
979
+ api_key: apiKey,
980
+ base_url: baseUrl.trim(),
981
+ models
982
+ };
983
+ } else {
984
+ const preset = PROVIDER_PRESETS[service];
985
+ provider = {
986
+ ...preset,
987
+ api_key: apiKey
988
+ };
989
+ }
990
+ const config = loadConfig(CONFIG_DIR);
991
+ const providers = config.providers ?? [];
992
+ const existingIdx = providers.findIndex((existing) => {
993
+ if (provider.base_url || existing.base_url) {
994
+ return existing.type === provider.type && existing.base_url === provider.base_url;
995
+ }
996
+ return existing.type === provider.type;
997
+ });
998
+ if (existingIdx >= 0) {
999
+ providers[existingIdx] = provider;
1000
+ } else {
1001
+ providers.push(provider);
1002
+ }
1003
+ config.providers = providers;
1004
+ saveConfig(CONFIG_DIR, config);
1005
+ const configPath = path4.join(CONFIG_DIR, "config.yaml");
1006
+ p.log.success(`Config saved to ${configPath}`);
1007
+ p.outro("You're all set! Run `npx echospace` to start.");
1008
+ }
1009
+
1010
+ // src/cli/index.ts
1011
+ var VERSION = "0.1.0-alpha.3";
1012
+ var CONFIG_DIR2 = path5.join(homedir2(), ".echospace");
868
1013
  function loadEnvFile(dir) {
869
- const envPath = path4.join(dir, ".env");
1014
+ const envPath = path5.join(dir, ".env");
870
1015
  if (!fs3.existsSync(envPath)) return;
871
1016
  const lines = fs3.readFileSync(envPath, "utf-8").split("\n");
872
1017
  for (const line of lines) {
@@ -883,26 +1028,28 @@ function loadEnvFile(dir) {
883
1028
  }
884
1029
  var program = new Command();
885
1030
  program.name("echospace").description("The best open-source local prompt debugging tool").version(VERSION).argument("[workdir]", "Workspace directory", ".").option("-p, --port <port>", "Port to serve on").option("--no-open", "Don't open browser automatically").action(async (workdir, options) => {
886
- const baseDir = path4.resolve(process.cwd(), workdir);
887
- const workspaceDir = path4.join(baseDir, ".echo");
1031
+ const baseDir = path5.resolve(process.cwd(), workdir);
1032
+ const workspaceDir = path5.join(baseDir, ".echo");
888
1033
  loadEnvFile(baseDir);
889
1034
  loadEnvFile(process.cwd());
890
1035
  if (!fs3.existsSync(workspaceDir)) {
891
1036
  fs3.mkdirSync(workspaceDir, { recursive: true });
892
1037
  }
893
- fs3.mkdirSync(CONFIG_DIR, { recursive: true });
894
- ensureConfig(CONFIG_DIR);
895
- const port = options.port ? parseInt(options.port, 10) : await getPort({ port: portNumbers(7788, 7799) });
1038
+ fs3.mkdirSync(CONFIG_DIR2, { recursive: true });
1039
+ ensureConfig(CONFIG_DIR2);
1040
+ const port = options.port ? parseInt(options.port, 10) : await getPort({ port: portNumbers(3240, 3249) });
1041
+ const url = `http://localhost:${port}`;
896
1042
  console.log(`
897
- \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
898
- \u2551 EchoSpace v${VERSION.padEnd(12)}\u2551
899
- \u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563
900
- \u2551 Workspace: ${workspaceDir.padEnd(24)}\u2551
901
- \u2551 URL: http://localhost:${String(port).padEnd(8)}\u2551
902
- \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
1043
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588
1044
+ \u2588\u2588 \u2588\u2588 EchoSpace v${VERSION}
1045
+ \u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588
1046
+ \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 Workspace ${workspaceDir}
1047
+ \u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588 URL ${url}
1048
+ \u2588\u2588 \u2588\u2588
1049
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588
903
1050
  `);
904
1051
  const isDev = process.env.NODE_ENV !== "production" && import.meta.url.includes("/src/");
905
- startServer({ port, workspaceDir, configDir: CONFIG_DIR, dev: isDev });
1052
+ startServer({ port, workspaceDir, configDir: CONFIG_DIR2, dev: isDev });
906
1053
  if (options.open) {
907
1054
  await open(`http://localhost:${port}`);
908
1055
  }
@@ -913,4 +1060,5 @@ program.name("echospace").description("The best open-source local prompt debuggi
913
1060
  process.on("SIGINT", shutdown);
914
1061
  process.on("SIGTERM", shutdown);
915
1062
  });
1063
+ program.command("init").description("Interactive setup for LLM provider configuration").action(runInit);
916
1064
  program.parse();
@@ -0,0 +1 @@
1
+ /*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:"Geist", -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", "noto sans", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;--font-serif:"Geist Pixel Square", ui-monospace, monospace;--font-mono:"Geist Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-amber-400:oklch(82.8% .189 84.429);--color-amber-500:oklch(76.9% .188 70.08);--color-amber-600:oklch(66.6% .179 58.318);--color-black:#000;--color-white:#fff;--spacing:.25rem;--font-weight-medium:500;--tracking-wider:.05em;--radius-sm:2px;--radius-md:4px;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-bg-1:var(--bg-1);--color-bg-1-1:var(--bg-1-1);--color-bg-1-2:var(--bg-1-2);--color-bg-2:var(--bg-2);--color-bg-3:var(--bg-3);--color-bg-4:var(--bg-4);--color-bg-5:var(--bg-5);--color-primary:var(--primary);--color-destructive:var(--danger);--color-border:var(--border-1);--color-text-normal:var(--text-normal);--color-text-secondary:var(--text-secondary);--color-text-desc:var(--text-desc);--color-text-placeholder:var(--text-placeholder)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.collapse{visibility:collapse}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-0{inset:calc(var(--spacing) * 0)}.inset-y-0{inset-block:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.-top-1{top:calc(var(--spacing) * -1)}.-top-3{top:calc(var(--spacing) * -3)}.top-\[7px\]{top:7px}.top-\[calc\(100\%\+2px\)\]{top:calc(100% + 2px)}.top-full{top:100%}.-right-1{right:calc(var(--spacing) * -1)}.right-0{right:calc(var(--spacing) * 0)}.right-2{right:calc(var(--spacing) * 2)}.bottom-full{bottom:100%}.left-0{left:calc(var(--spacing) * 0)}.left-\[3px\]{left:3px}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-50{z-index:50}.mx-1{margin-inline:calc(var(--spacing) * 1)}.mx-3{margin-inline:calc(var(--spacing) * 3)}.mx-auto{margin-inline:auto}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-2\.5{margin-top:calc(var(--spacing) * 2.5)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mb-0\.5{margin-bottom:calc(var(--spacing) * .5)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.ml-1{margin-left:calc(var(--spacing) * 1)}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.size-5{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5)}.size-\[7px\]{width:7px;height:7px}.size-\[9px\]{width:9px;height:9px}.size-\[10px\]{width:10px;height:10px}.size-\[11px\]{width:11px;height:11px}.size-\[80px\]{width:80px;height:80px}.h-0{height:calc(var(--spacing) * 0)}.h-3{height:calc(var(--spacing) * 3)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-10{height:calc(var(--spacing) * 10)}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-\[200px\]{max-height:200px}.min-h-0{min-height:calc(var(--spacing) * 0)}.min-h-\[36px\]{min-height:36px}.w-7{width:calc(var(--spacing) * 7)}.w-12{width:calc(var(--spacing) * 12)}.w-16{width:calc(var(--spacing) * 16)}.w-20{width:calc(var(--spacing) * 20)}.w-56{width:calc(var(--spacing) * 56)}.w-full{width:100%}.w-px{width:1px}.w-screen{width:100vw}.max-w-\[120px\]{max-width:120px}.max-w-\[240px\]{max-width:240px}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-\[180px\]{min-width:180px}.flex-1{flex:1}.shrink-0{flex-shrink:0}.translate-y-1{--tw-translate-y:calc(var(--spacing) * 1);translate:var(--tw-translate-x) var(--tw-translate-y)}.scale-\[1\.4\]{scale:1.4}.scale-\[1\.6\]{scale:1.6}.rotate-90{rotate:90deg}.rotate-180{rotate:180deg}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-pulse{animation:var(--animate-pulse)}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.resize-y{resize:vertical}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-end{align-items:flex-end}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-start{justify-content:flex-start}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-\[3px\]{gap:3px}.gap-x-2{column-gap:calc(var(--spacing) * 2)}.gap-y-0\.5{row-gap:calc(var(--spacing) * .5)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-\[var\(--success\)\]\/30{border-color:var(--success)}@supports (color:color-mix(in lab,red,red)){.border-\[var\(--success\)\]\/30{border-color:color-mix(in oklab,var(--success) 30%,transparent)}}.border-border,.border-border\/60{border-color:var(--color-border)}@supports (color:color-mix(in lab,red,red)){.border-border\/60{border-color:color-mix(in oklab,var(--color-border) 60%,transparent)}}.border-destructive\/30{border-color:var(--color-destructive)}@supports (color:color-mix(in lab,red,red)){.border-destructive\/30{border-color:color-mix(in oklab,var(--color-destructive) 30%,transparent)}}.border-primary,.border-primary\/40{border-color:var(--color-primary)}@supports (color:color-mix(in lab,red,red)){.border-primary\/40{border-color:color-mix(in oklab,var(--color-primary) 40%,transparent)}}.bg-\[var\(--role-assistant-bg\)\]{background-color:var(--role-assistant-bg)}.bg-\[var\(--role-system-bg\)\]{background-color:var(--role-system-bg)}.bg-\[var\(--role-tool-bg\)\]{background-color:var(--role-tool-bg)}.bg-\[var\(--role-user-bg\)\]{background-color:var(--role-user-bg)}.bg-\[var\(--success\)\]\/10{background-color:var(--success)}@supports (color:color-mix(in lab,red,red)){.bg-\[var\(--success\)\]\/10{background-color:color-mix(in oklab,var(--success) 10%,transparent)}}.bg-\[var\(--success\)\]\/60{background-color:var(--success)}@supports (color:color-mix(in lab,red,red)){.bg-\[var\(--success\)\]\/60{background-color:color-mix(in oklab,var(--success) 60%,transparent)}}.bg-amber-500{background-color:var(--color-amber-500)}.bg-amber-500\/15{background-color:#f99c0026}@supports (color:color-mix(in lab,red,red)){.bg-amber-500\/15{background-color:color-mix(in oklab,var(--color-amber-500) 15%,transparent)}}.bg-bg-1{background-color:var(--color-bg-1)}.bg-bg-1-1{background-color:var(--color-bg-1-1)}.bg-bg-1-2{background-color:var(--color-bg-1-2)}.bg-bg-2{background-color:var(--color-bg-2)}.bg-bg-3{background-color:var(--color-bg-3)}.bg-bg-5{background-color:var(--color-bg-5)}.bg-black\/20{background-color:#0003}@supports (color:color-mix(in lab,red,red)){.bg-black\/20{background-color:color-mix(in oklab,var(--color-black) 20%,transparent)}}.bg-border{background-color:var(--color-border)}.bg-destructive,.bg-destructive\/5{background-color:var(--color-destructive)}@supports (color:color-mix(in lab,red,red)){.bg-destructive\/5{background-color:color-mix(in oklab,var(--color-destructive) 5%,transparent)}}.bg-destructive\/90{background-color:var(--color-destructive)}@supports (color:color-mix(in lab,red,red)){.bg-destructive\/90{background-color:color-mix(in oklab,var(--color-destructive) 90%,transparent)}}.bg-primary,.bg-primary\/15{background-color:var(--color-primary)}@supports (color:color-mix(in lab,red,red)){.bg-primary\/15{background-color:color-mix(in oklab,var(--color-primary) 15%,transparent)}}.bg-primary\/50{background-color:var(--color-primary)}@supports (color:color-mix(in lab,red,red)){.bg-primary\/50{background-color:color-mix(in oklab,var(--color-primary) 50%,transparent)}}.bg-text-normal{background-color:var(--color-text-normal)}.bg-transparent{background-color:#0000}.bg-white{background-color:var(--color-white)}.object-cover{object-fit:cover}.p-1{padding:calc(var(--spacing) * 1)}.p-2\.5{padding:calc(var(--spacing) * 2.5)}.p-\[3px\]{padding:3px}.px-0\.5{padding-inline:calc(var(--spacing) * .5)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-\[1px\]{padding-block:1px}.py-\[3px\]{padding-block:3px}.py-\[5px\]{padding-block:5px}.py-\[6px\]{padding-block:6px}.pt-1{padding-top:calc(var(--spacing) * 1)}.pt-1\.5{padding-top:calc(var(--spacing) * 1.5)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-2\.5{padding-top:calc(var(--spacing) * 2.5)}.pr-4{padding-right:calc(var(--spacing) * 4)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pl-1{padding-left:calc(var(--spacing) * 1)}.pl-2{padding-left:calc(var(--spacing) * 2)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.font-serif{font-family:var(--font-serif)}.text-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.text-\[18px\]{font-size:18px}.leading-\[16px\]{--tw-leading:16px;line-height:16px}.leading-\[18px\]{--tw-leading:18px;line-height:18px}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.tracking-\[0\.08em\]{--tw-tracking:.08em;letter-spacing:.08em}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-\[\#7a5a96\]{color:#7a5a96}.text-\[\#9a7030\]{color:#9a7030}.text-\[var\(--role-assistant-text\)\]{color:var(--role-assistant-text)}.text-\[var\(--role-system-text\)\]{color:var(--role-system-text)}.text-\[var\(--role-tool-text\)\]{color:var(--role-tool-text)}.text-\[var\(--role-user-text\)\]{color:var(--role-user-text)}.text-\[var\(--success\)\]{color:var(--success)}.text-amber-600{color:var(--color-amber-600)}.text-primary{color:var(--color-primary)}.text-text-desc{color:var(--color-text-desc)}.text-text-normal{color:var(--color-text-normal)}.text-text-placeholder{color:var(--color-text-placeholder)}.text-text-secondary{color:var(--color-text-secondary)}.text-transparent{color:#0000}.text-white{color:var(--color-white)}.capitalize{text-transform:capitalize}.uppercase{text-transform:uppercase}.italic{font-style:italic}.accent-primary{accent-color:var(--color-primary)}.opacity-0{opacity:0}.opacity-90{opacity:.9}.opacity-100{opacity:1}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[0_0_12px_var\(--shadow-streaming\)\]{--tw-shadow:0 0 12px var(--tw-shadow-color,var(--shadow-streaming));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-panel{--tw-shadow:var(--shadow-panel-value);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.outline-none{--tw-outline-style:none;outline-style:none}.\[animation-duration\:2s\]{animation-duration:2s}@media(hover:hover){.group-hover\:block:is(:where(.group):hover *){display:block}.group-hover\:bg-\[var\(--success\)\]:is(:where(.group):hover *){background-color:var(--success)}.group-hover\:bg-amber-400:is(:where(.group):hover *){background-color:var(--color-amber-400)}.group-hover\:bg-text-desc:is(:where(.group):hover *){background-color:var(--color-text-desc)}.group-hover\:text-text-desc:is(:where(.group):hover *){color:var(--color-text-desc)}.group-hover\/img\:opacity-100:is(:where(.group\/img):hover *){opacity:1}.group-hover\/stats\:pointer-events-auto:is(:where(.group\/stats):hover *){pointer-events:auto}.group-hover\/stats\:opacity-100:is(:where(.group\/stats):hover *){opacity:1}}.placeholder\:text-text-placeholder::placeholder{color:var(--color-text-placeholder)}@media(hover:hover){.hover\:border-bg-5:hover{border-color:var(--color-bg-5)}.hover\:bg-\[var\(--success\)\]:hover{background-color:var(--success)}.hover\:bg-amber-500\/25:hover{background-color:#f99c0040}@supports (color:color-mix(in lab,red,red)){.hover\:bg-amber-500\/25:hover{background-color:color-mix(in oklab,var(--color-amber-500) 25%,transparent)}}.hover\:bg-bg-1-2:hover{background-color:var(--color-bg-1-2)}.hover\:bg-bg-2:hover{background-color:var(--color-bg-2)}.hover\:bg-bg-4:hover{background-color:var(--color-bg-4)}.hover\:bg-destructive:hover,.hover\:bg-destructive\/90:hover{background-color:var(--color-destructive)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-destructive\/90:hover{background-color:color-mix(in oklab,var(--color-destructive) 90%,transparent)}}.hover\:bg-primary\/10:hover{background-color:var(--color-primary)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-primary\/10:hover{background-color:color-mix(in oklab,var(--color-primary) 10%,transparent)}}.hover\:bg-primary\/40:hover{background-color:var(--color-primary)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-primary\/40:hover{background-color:color-mix(in oklab,var(--color-primary) 40%,transparent)}}.hover\:bg-primary\/90:hover{background-color:var(--color-primary)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab,var(--color-primary) 90%,transparent)}}.hover\:bg-text-desc:hover{background-color:var(--color-text-desc)}.hover\:text-destructive:hover{color:var(--color-destructive)}.hover\:text-text-secondary:hover{color:var(--color-text-secondary)}.hover\:opacity-80:hover{opacity:.8}.hover\:opacity-100:hover{opacity:1}}.focus\:border-bg-5:focus{border-color:var(--color-bg-5)}.focus\:border-primary:focus{border-color:var(--color-primary)}.active\:bg-primary\/60:active{background-color:var(--color-primary)}@supports (color:color-mix(in lab,red,red)){.active\:bg-primary\/60:active{background-color:color-mix(in oklab,var(--color-primary) 60%,transparent)}}.disabled\:opacity-30:disabled{opacity:.3}@media not all and (min-width:48rem){.max-md\:opacity-100{opacity:1}}@media(min-width:48rem){.md\:opacity-0{opacity:0}@media(hover:hover){.md\:group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}}}@font-face{font-family:Geist;src:url(/assets/Geist-Variable-CrgPqtmy.woff2)format("woff2");font-weight:100 900;font-style:normal;font-display:swap}@font-face{font-family:Geist;src:url(/assets/Geist-Italic-Variable-vKc54d3Z.woff2)format("woff2");font-weight:100 900;font-style:italic;font-display:swap}@font-face{font-family:Geist Mono;src:url(/assets/GeistMono-Variable-BNLlm6Cd.woff2)format("woff2");font-weight:100 900;font-style:normal;font-display:swap}@font-face{font-family:Geist Mono;src:url(/assets/GeistMono-Italic-Variable-MBthCoE1.woff2)format("woff2");font-weight:100 900;font-style:italic;font-display:swap}@font-face{font-family:Geist Pixel Square;src:url(/assets/GeistPixel-Square-CwnHaJd_.woff2)format("woff2");font-weight:400;font-style:normal;font-display:swap}:root{--bg-1:#faf7f1;--bg-1-1:#f5f1e9;--bg-1-2:#efeadf;--bg-2:#e9e3d6;--bg-3:#e2dace;--bg-4:#d6cebf;--bg-5:#c7bead;--text-emphasize:#1a1510;--text-normal:#2e2720;--text-secondary:#544b40;--text-desc:#847768;--text-placeholder:#b0a393;--text-disable:#ccc2b4;--border-1:#d8d0c2;--primary:#a3623a;--primary-light:#a3623a1a;--danger:#b04a3a;--danger-light:#b04a3a14;--success:#5a7e45;--success-light:#5a7e451a;--role-system-bg:#785a961a;--role-system-text:#7a5a96;--role-user-bg:#a3623a1a;--role-user-text:#a3623a;--role-assistant-bg:#5a7e451a;--role-assistant-text:#4a7040;--role-tool-bg:#b282321a;--role-tool-text:#9a7030;--selection-color:#a3623a2e;--shadow-card-value:0 1px 3px 0 #503c1e0f, 0 1px 2px -1px #503c1e0f;--shadow-panel-value:0 4px 12px 0 #503c1e14;--shadow-modal-value:0 8px 24px 0 #503c1e1f;--shadow-focus-value:0 0 0 3px #a3623a26;--shadow-streaming:#a3623a14}[data-theme=dusk]{--bg-1:#f4f5f6;--bg-1-1:#edeff2;--bg-1-2:#e4e7eb;--bg-2:#dcdfe5;--bg-3:#d4d7de;--bg-4:#c8ccd4;--bg-5:#bcc1ca;--text-emphasize:#191c21;--text-normal:#282c33;--text-secondary:#444952;--text-desc:#747a85;--text-placeholder:#a0a5ae;--text-disable:#c0c4cb;--border-1:#d0d3d9;--primary:#6a7fa8;--primary-light:#6a7fa81a;--danger:#b04a3a;--danger-light:#b04a3a14;--success:#5a8060;--success-light:#5a80601a;--role-system-bg:#8264961a;--role-system-text:#7a5a96;--role-user-bg:#6a7fa81f;--role-user-text:#4a6590;--role-assistant-bg:#50915f1f;--role-assistant-text:#3d7a4a;--role-tool-bg:#aa8c3c1a;--role-tool-text:#8a7030;--selection-color:#6a7fa82e;--shadow-card-value:0 1px 3px 0 #3237410f, 0 1px 2px -1px #3237410f;--shadow-panel-value:0 4px 12px 0 #32374114;--shadow-modal-value:0 8px 24px 0 #3237411f;--shadow-focus-value:0 0 0 3px #6a7fa826;--shadow-streaming:#6a7fa814}[data-theme=ember]{--bg-1:#1a1815;--bg-1-1:#222019;--bg-1-2:#2a2722;--bg-2:#2e2b26;--bg-3:#3a352e;--bg-4:#454037;--bg-5:#544e44;--text-emphasize:#f5e1c0;--text-normal:#dcd2bc;--text-secondary:#b8ab94;--text-desc:#8a7e6a;--text-placeholder:#665c4d;--text-disable:#4d453a;--border-1:#3a352e;--primary:#c4784a;--primary-light:#c4784a1f;--danger:#b04a3a;--danger-light:#b04a3a1f;--success:#5a7e45;--success-light:#5a7e451f;--role-system-bg:#8264a026;--role-system-text:#a088c0;--role-user-bg:#c4784a33;--role-user-text:#c4784a;--role-assistant-bg:#5a7e4526;--role-assistant-text:#7eaa62;--role-tool-bg:#b2823226;--role-tool-text:#d4a017;--selection-color:#c4784a40;--shadow-card-value:0 1px 4px 0 #00000080, 0 1px 2px -1px #0000004d;--shadow-panel-value:0 4px 12px 0 #0006;--shadow-modal-value:0 8px 24px 0 #00000080;--shadow-focus-value:0 0 0 3px #c4784a33;--shadow-streaming:#c4784a1a}[data-theme=slate]{--bg-1:#191c21;--bg-1-1:#1e2128;--bg-1-2:#262a32;--bg-2:#2d323d;--bg-3:#363c4a;--bg-4:#414858;--bg-5:#4d5568;--text-emphasize:#f1f3f5;--text-normal:#e4e7eb;--text-secondary:#a0a5ae;--text-desc:#747a85;--text-placeholder:#5c6370;--text-disable:#444b5a;--border-1:#2d323d;--primary:#6a7fa8;--primary-light:#6a7fa81f;--danger:#c55a4a;--danger-light:#c55a4a1f;--success:#5a8060;--success-light:#5a80601f;--role-system-bg:#8264a026;--role-system-text:#a088c0;--role-user-bg:#6a7fa826;--role-user-text:#7a9bcc;--role-assistant-bg:#5a806026;--role-assistant-text:#81c784;--role-tool-bg:#aa8c3c26;--role-tool-text:#e2b340;--selection-color:#6a7fa840;--shadow-card-value:0 1px 4px 0 #00000080, 0 1px 2px -1px #0000004d;--shadow-panel-value:0 4px 12px 0 #0006;--shadow-modal-value:0 8px 24px 0 #00000080;--shadow-focus-value:0 0 0 3px #6a7fa833;--shadow-streaming:#6a7fa81a}*{border-color:var(--border-1)}body{background-color:var(--bg-1);color:var(--text-normal);font-family:var(--font-sans);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;margin:0;padding:0;font-size:12.5px;line-height:19px}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:0 0}::-webkit-scrollbar-thumb{background:var(--bg-5);border-radius:3px}::-webkit-scrollbar-thumb:hover{background:var(--text-disable)}.scrollbar-none{-ms-overflow-style:none;scrollbar-width:none}.scrollbar-none::-webkit-scrollbar{display:none}::selection{background:var(--selection-color)}textarea{font-family:inherit}textarea:focus{outline:none}.section-label{font-family:var(--font-serif);letter-spacing:.04em;color:var(--text-desc);font-size:11px}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@keyframes pulse{50%{opacity:.5}}