From 1feb95ed7996912c134a158cc60e87aa5bb64de7 Mon Sep 17 00:00:00 2001 From: ForestMars Date: Thu, 18 Jun 2026 15:31:24 -0400 Subject: [PATCH 01/17] log lvl --- .env | 2 +- bar.txt | 18 ------------------ baz.txt | 18 ------------------ baz2.txt | 18 ------------------ baz3.txt | 18 ------------------ foo.txt | 18 ------------------ hello.txt | 1 - 7 files changed, 1 insertion(+), 92 deletions(-) delete mode 100644 bar.txt delete mode 100644 baz.txt delete mode 100644 baz2.txt delete mode 100644 baz3.txt delete mode 100644 foo.txt delete mode 100644 hello.txt diff --git a/.env b/.env index 90f8ab61..16796f86 100644 --- a/.env +++ b/.env @@ -1,5 +1,5 @@ OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=http://otel-collector:4318/v1/logs OTEL_SERVICE_NAME=sup-agent -LOG_LEVEL=info +LOG_LEVEL=warn LOKI_HOST=http://localhost:3100 diff --git a/bar.txt b/bar.txt deleted file mode 100644 index 274ced28..00000000 --- a/bar.txt +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/baz.txt b/baz.txt deleted file mode 100644 index dc0a6fe4..00000000 --- a/baz.txt +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/baz2.txt b/baz2.txt deleted file mode 100644 index b1b0da41..00000000 --- a/baz2.txt +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/baz3.txt b/baz3.txt deleted file mode 100644 index d9f9cb1e..00000000 --- a/baz3.txt +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/foo.txt b/foo.txt deleted file mode 100644 index 4b37d937..00000000 --- a/foo.txt +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/hello.txt b/hello.txt deleted file mode 100644 index 5e1c309d..00000000 --- a/hello.txt +++ /dev/null @@ -1 +0,0 @@ -Hello World \ No newline at end of file From 93197e1b73545178c8a31a36dc5a0be5c18942b8 Mon Sep 17 00:00:00 2001 From: ForestMars Date: Thu, 18 Jun 2026 15:45:07 -0400 Subject: [PATCH 02/17] model matrix --- models.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 models.txt diff --git a/models.txt b/models.txt new file mode 100644 index 00000000..5627b034 --- /dev/null +++ b/models.txt @@ -0,0 +1,14 @@ ++------------------------------+--------------+---------+--------------+-----------------------------+ +| NAME | ID | SIZE | MODIFIED | THINKING MODEL? | ++------------------------------+--------------+---------+--------------+-----------------------------+ +| opencode-qwen:latest | 3cf2fe22f8e4 | 4.7 GB | 5 weeks ago | No (Standard/Code LLM) | +| qwen2.5-coder-agent:latest | fa2f24e4d32b | 4.7 GB | 5 weeks ago | No (Agentic/Code LLM) | +| qwen3:8b | 500a1f067a9f | 5.2 GB | 3 months ago | No (General LLM) | +| qwen2.5:7b | 845dbda0ea48 | 4.7 GB | 4 months ago | No (General LLM) | +| orieg/gemma3-tools:4b-it-qat | 112b9b93b581 | 4.0 GB | 4 months ago | No (Tool-use LLM) | +| qwen2.5-coder:1.5b | d7372fd82851 | 986 MB | 9 months ago | No (Code LLM) | +| qwen2.5-coder:7b | dae161e27b0e | 4.7 GB | 9 months ago | No (Code LLM) | +| deepseek-r1:latest | 6995872bfe4c | 5.2 GB | 9 months ago | Yes (Reasoning/CoT Model) | +| nomic-embed-text:latest | 0a109f422b47 | 274 MB | 10 mos ago | No (Embedding Model) | +| gemma3:latest | a2af6cc3eb7f | 3.3 GB | 10 mos ago | No (General LLM) | ++------------------------------+--------------+---------+--------------+-----------------------------+ From 192774fab0223db4f3247da3e5310fb3fe54e45a Mon Sep 17 00:00:00 2001 From: ForestMars Date: Thu, 18 Jun 2026 15:45:18 -0400 Subject: [PATCH 03/17] set model env var --- .env | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.env b/.env index 16796f86..a993988c 100644 --- a/.env +++ b/.env @@ -1,5 +1,10 @@ OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=http://otel-collector:4318/v1/logs OTEL_SERVICE_NAME=sup-agent LOG_LEVEL=warn - LOKI_HOST=http://localhost:3100 + + +SUPPORT_AGENT_MODEL=qwen3:8b + + + From c5d8ae735462f54db3c40fc731659c69df83851a Mon Sep 17 00:00:00 2001 From: ForestMars Date: Thu, 18 Jun 2026 15:51:09 -0400 Subject: [PATCH 04/17] update models --- models.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.txt b/models.txt index 5627b034..2e70d719 100644 --- a/models.txt +++ b/models.txt @@ -3,7 +3,7 @@ +------------------------------+--------------+---------+--------------+-----------------------------+ | opencode-qwen:latest | 3cf2fe22f8e4 | 4.7 GB | 5 weeks ago | No (Standard/Code LLM) | | qwen2.5-coder-agent:latest | fa2f24e4d32b | 4.7 GB | 5 weeks ago | No (Agentic/Code LLM) | -| qwen3:8b | 500a1f067a9f | 5.2 GB | 3 months ago | No (General LLM) | +| qwen3:8b | 500a1f067a9f | 5.2 GB | 3 months ago | Hybrid (Native Switchable) | | qwen2.5:7b | 845dbda0ea48 | 4.7 GB | 4 months ago | No (General LLM) | | orieg/gemma3-tools:4b-it-qat | 112b9b93b581 | 4.0 GB | 4 months ago | No (Tool-use LLM) | | qwen2.5-coder:1.5b | d7372fd82851 | 986 MB | 9 months ago | No (Code LLM) | From da1c4455f756a951cbfd1d20535c0381b9650f5a Mon Sep 17 00:00:00 2001 From: ForestMars Date: Thu, 18 Jun 2026 15:52:32 -0400 Subject: [PATCH 05/17] list models --- list-models.py | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 list-models.py diff --git a/list-models.py b/list-models.py new file mode 100644 index 00000000..400691e6 --- /dev/null +++ b/list-models.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +import subprocess +import re + +def get_ollama_models(): + try: + # Run the 'ollama list' command + result = subprocess.run(['ollama', 'list'], capture_output=True, text=True, check=True) + lines = result.stdout.strip().split('\n') + if len(lines) <= 1: + return [] + + models = [] + # Skip the header line + for line in lines[1:]: + # Use regex to handle variable whitespace spacing + parts = re.split(r'\s{2,}', line.strip()) + if len(parts) >= 4: + # Handle cases where ID, Size, or Modified columns might group slightly differently + name = parts[0] + model_id = parts[1] + size = parts[2] + # Combine remaining parts if 'Modified' contains spaces (e.g., "5 weeks ago") + modified = " ".join(parts[3:]) + + # Determine thinking capability + thinking = "No" + name_lower = name.lower() + if "qwen3" in name_lower: + thinking = "Hybrid (Native Switchable)" + elif "deepseek-r1" in name_lower or "-r1" in name_lower or "reasoning" in name_lower: + thinking = "Yes (Reasoning/CoT Model)" + elif "coder" in name_lower: + thinking = "No (Code LLM)" + elif "embed" in name_lower: + thinking = "No (Embedding Model)" + elif "agent" in name_lower: + thinking = "No (Agentic LLM)" + else: + thinking = "No" + + models.append([name, model_id, size, modified, thinking]) + return models + except FileNotFoundError: + print("Error: 'ollama' command not found. Make sure Ollama is installed and in your PATH.") + return None + except subprocess.CalledProcessError: + print("Error: Failed to execute 'ollama list'. Is the Ollama service running?") + return None + +def print_ascii_table(models): + if not models: + print("No local Ollama models found.") + return + + headers = ["NAME", "ID", "SIZE", "MODIFIED", "THINKING MODEL?"] + + # Calculate dynamic column widths based on longest content + col_widths = [len(h) for h in headers] + for row in models: + for i in range(5): + if len(row[i]) > col_widths[i]: + col_widths[i] = len(row[i]) + + # Build the separator line: +-----+----+ + sep = "+" + "+".join(["-" * (w + 2) for w in col_widths]) + "+" + + # Print table + print(sep) + header_row = "| " + " | ".join([f"{headers[i]:<{col_widths[i]}}" for i in range(5)]) + " |" + print(header_row) + print(sep) + + for row in models: + model_row = "| " + " | ".join([f"{row[i]:<{col_widths[i]}}" for i in range(5)]) + " |" + print(model_row) + + print(sep) + +if __name__ == "__main__": + model_data = get_ollama_models() + if model_data is not None: + print_ascii_table(model_data) From cf7cc92018c3afb0d5785f680985a00f8d5375c0 Mon Sep 17 00:00:00 2001 From: ForestMars Date: Thu, 18 Jun 2026 15:54:54 -0400 Subject: [PATCH 06/17] declare model --- apps/cli/chat.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/cli/chat.ts b/apps/cli/chat.ts index fcb0b50a..20bbd87b 100644 --- a/apps/cli/chat.ts +++ b/apps/cli/chat.ts @@ -68,6 +68,9 @@ export async function startChat() { events: [], }; + console.log(` Active Agent: \x1b[1m${AGENT.toUpperCase()}\x1b[0m`); + console.log(` Active Model: \x1b[32m${typeof modelSpec === 'object' ? JSON.stringify(modelSpec) : modelSpec}\x1b[0m`); + process.nextTick(() => rl.prompt()); // logger.debug(`Agent: ${AGENT}`); //logger.debug(`Model: ${modelSpec}`); From 2aea04789fa148c211888732509b8566605c5c92 Mon Sep 17 00:00:00 2001 From: ForestMars Date: Thu, 18 Jun 2026 15:59:29 -0400 Subject: [PATCH 07/17] uncomment providers in tui --- apps/tui/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/tui/index.ts b/apps/tui/index.ts index bdb5a872..fb957dd5 100644 --- a/apps/tui/index.ts +++ b/apps/tui/index.ts @@ -21,8 +21,8 @@ const { agent, modelSpec } = await (async () => { return { agent: supportAgent, modelSpec: supportAgentModelSpec }; })(); -/* const providers = []; +/* if (process.env.POSTHOG_API_KEY) { const { PostHogProvider } = await import("@tapico/node-openfeature-posthog"); const { PostHog } = await import("posthog-node"); From db025b3f2c3ccb40a94a323df23158fa0dea2cb8 Mon Sep 17 00:00:00 2001 From: ForestMars Date: Thu, 18 Jun 2026 16:39:23 -0400 Subject: [PATCH 08/17] basic tui --- apps/tui/index.tsx | 144 ++++++++++++++++++++++++++------------------- 1 file changed, 84 insertions(+), 60 deletions(-) diff --git a/apps/tui/index.tsx b/apps/tui/index.tsx index 0850eb97..5b17f96b 100644 --- a/apps/tui/index.tsx +++ b/apps/tui/index.tsx @@ -1,6 +1,5 @@ import { render } from "@opentui/solid"; -import { createSignal } from "solid-js"; -import { For } from "solid-js"; +import { createSignal, For, onMount } from "solid-js"; import { OpenFeature, MultiProvider, @@ -11,106 +10,131 @@ import { ProtocolResolver } from "@sup/lib/protocol-resolver"; import { adapters } from "@sup/tools"; import { JsonFileProvider } from "@sup/infra/adapters/JsonFileProvider"; -const AGENT = process.env.AGENT || "support"; -const { agent, modelSpec } = await (async () => { - if (AGENT === "coding") { - const { codingAgent, codingAgentModelSpec } = await import("@sup/agents/coding-agent"); - return { agent: codingAgent, modelSpec: codingAgentModelSpec }; - } - const { supportAgent, supportAgentModelSpec } = await import("@sup/agents/support-agent"); - return { agent: supportAgent, modelSpec: supportAgentModelSpec }; -})(); - -/* -const providers = []; -if (process.env.POSTHOG_API_KEY) { - const { PostHogProvider } = await import("@tapico/node-openfeature-posthog"); - const { PostHog } = await import("posthog-node"); - const posthogClient = new PostHog(process.env.POSTHOG_API_KEY, { - host: process.env.POSTHOG_HOST || "https://app.posthog.com", - }); - providers.push({ provider: new PostHogProvider({ posthogClient }) }); -} -providers.push({ provider: new JsonFileProvider("../../config/flags.json") }); - - -const multiProvider = new MultiProvider(providers, new FirstSuccessfulStrategy()); -await OpenFeature.setProviderAndWait(multiProvider); -*/ - -const session: AgentSession = { - id: "tui-session-" + Date.now(), - events: [], +type AgentSession = { + id: string; + events: any[]; }; type Message = { role: "user" | "agent"; text: string }; +const AGENT = process.env.AGENT || "support"; + function App() { const [messages, setMessages] = createSignal([]); const [streaming, setStreaming] = createSignal(""); const [activeTool, setActiveTool] = createSignal(""); const [busy, setBusy] = createSignal(false); + const [ready, setReady] = createSignal(false); + + let currentAgent: any = null; + + onMount(async () => { + try { + const providers = []; + if (process.env.POSTHOG_API_KEY) { + const { PostHogProvider } = await import("@tapico/node-openfeature-posthog"); + const { PostHog } = await import("posthog-node"); + const posthogClient = new PostHog(process.env.POSTHOG_API_KEY, { + host: process.env.POSTHOG_HOST || "https://app.posthog.com", + }); + providers.push({ provider: new PostHogProvider({ posthogClient }) }); + } + providers.push({ provider: new JsonFileProvider("../../config/flags.json") }); + + const multiProvider = new MultiProvider(providers, new FirstSuccessfulStrategy()); + await OpenFeature.setProviderAndWait(multiProvider); + + if (AGENT === "coding") { + const { codingAgent } = await import("@sup/agents/coding-agent"); + currentAgent = codingAgent; + } else { + const { supportAgent } = await import("@sup/agents/support-agent"); + currentAgent = supportAgent; + } + + setReady(true); + } catch (e) { + setReady(true); + } + }); + + const session: AgentSession = { + id: "tui-session-" + Date.now(), + events: [], + }; async function submit(text: string) { - if (!text.trim() || busy()) return; + if (!text.trim() || busy() || !ready() || !currentAgent) return; setBusy(true); setMessages((m) => [...m, { role: "user", text }]); - const generator = agent(text, session, { - resolver: ProtocolResolver, - tools: adapters, - }); - - for await (const step of generator) { - if (step.type === "text_delta" && step.delta) { - setStreaming((s) => s + step.delta); - } else if (step.type === "tool_call") { - setActiveTool(step.toolId); - } else if (step.type === "tool_result") { - setActiveTool(""); - } else if (step.type === "final") { - setMessages((m) => [ - ...m, - { role: "agent", text: step.text || streaming() }, - ]); - setStreaming(""); - setActiveTool(""); + try { + const generator = currentAgent(text, session, { + resolver: ProtocolResolver, + tools: adapters, + }); + + for await (const step of generator) { + if (step.type === "text_delta" && step.delta) { + setStreaming((s) => s + step.delta); + } else if (step.type === "tool_call") { + setActiveTool(step.toolId); + } else if (step.type === "tool_result") { + setActiveTool(""); + } else if (step.type === "final") { + setMessages((m) => [ + ...m, + { role: "agent", text: step.text || streaming() }, + ]); + setStreaming(""); + setActiveTool(""); + } } + } catch (err) { + setMessages((m) => [...m, { role: "agent", text: `Error: ${err}` }]); } setBusy(false); } return ( + // FIX 1: Flex direction must be explicitly coupled with absolute terminal view bounds - + + {/* FIX 2: Added specific flex shrink & grow mechanics to prevent infinite rendering loops */} + {(msg) => ( - + // FIX 3: Text wrapping. If the agent outputs long text without wrap instructions, the terminal calculation freezes + {msg.role === "user" ? "You" : "Agent"}:{" "} {msg.text} -
)}
+ {streaming() && ( - + Agent: {streaming()} )} + {activeTool() && ( [{activeTool()}] )}
- + + {/* FIX 4: Solid height boundaries on input row prevents the TUI from recursively recalculating heights */} + + @@ -119,4 +143,4 @@ function App() { ); } -render(() => ); +render(() => ); \ No newline at end of file From 7c9a870db3327868c3189b7e80b024be5e1bdb65 Mon Sep 17 00:00:00 2001 From: ForestMars Date: Thu, 18 Jun 2026 16:41:08 -0400 Subject: [PATCH 09/17] better tui --- apps/tui/index.tsx | 61 +++++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/apps/tui/index.tsx b/apps/tui/index.tsx index 5b17f96b..8cf9d17f 100644 --- a/apps/tui/index.tsx +++ b/apps/tui/index.tsx @@ -98,42 +98,59 @@ function App() { } return ( - // FIX 1: Flex direction must be explicitly coupled with absolute terminal view bounds - + // Outer App Frame with background and single border + - {/* FIX 2: Added specific flex shrink & grow mechanics to prevent infinite rendering loops */} - + {/* 1. Header Row */} + + SUP // + {AGENT.toUpperCase()} AGENT + + + {ready() ? "● ONLINE" : "○ INITIALIZING"} + + + + {/* 2. Main Chat Workspace Container */} + {(msg) => ( - // FIX 3: Text wrapping. If the agent outputs long text without wrap instructions, the terminal calculation freezes - - - {msg.role === "user" ? "You" : "Agent"}:{" "} - - {msg.text} - + // Indented and bottom-margined block for structured bubbles + + + {msg.role === "user" ? "❯ You" : "❯ Agent"} + + + {msg.text} + + )} + {/* Streaming Block */} {streaming() && ( - - Agent: - {streaming()} - + + ❯ Agent + + {streaming()} + + )} + {/* Active System/Tool Traces */} {activeTool() && ( - - [{activeTool()}] - + + ⠋ Executing tool: + [{activeTool()}] + )} - {/* FIX 4: Solid height boundaries on input row prevents the TUI from recursively recalculating heights */} - - + {/* 3. Action Input Row */} + + {busy() ? " ⧗ " : " ❯ "} Date: Thu, 18 Jun 2026 16:41:25 -0400 Subject: [PATCH 10/17] tui index.ts --- apps/tui/index.ts | 130 ++++++++++++++++++++++++++-------------------- 1 file changed, 75 insertions(+), 55 deletions(-) diff --git a/apps/tui/index.ts b/apps/tui/index.ts index fb957dd5..0baff2a7 100644 --- a/apps/tui/index.ts +++ b/apps/tui/index.ts @@ -1,6 +1,5 @@ import { render } from "@opentui/solid"; -import { createSignal } from "solid-js"; -import { For } from "solid-js"; +import { createSignal, For, onMount } from "solid-js"; import { OpenFeature, MultiProvider, @@ -11,70 +10,92 @@ import { ProtocolResolver } from "@sup/lib/protocol-resolver"; import { adapters } from "@sup/tools"; import { JsonFileProvider } from "@sup/infra/adapters/JsonFileProvider"; -const AGENT = process.env.AGENT || "support"; -const { agent, modelSpec } = await (async () => { - if (AGENT === "coding") { - const { codingAgent, codingAgentModelSpec } = await import("@sup/agents/coding-agent"); - return { agent: codingAgent, modelSpec: codingAgentModelSpec }; - } - const { supportAgent, supportAgentModelSpec } = await import("@sup/agents/support-agent"); - return { agent: supportAgent, modelSpec: supportAgentModelSpec }; -})(); - -const providers = []; -/* -if (process.env.POSTHOG_API_KEY) { - const { PostHogProvider } = await import("@tapico/node-openfeature-posthog"); - const { PostHog } = await import("posthog-node"); - const posthogClient = new PostHog(process.env.POSTHOG_API_KEY, { - host: process.env.POSTHOG_HOST || "https://app.posthog.com", - }); - providers.push({ provider: new PostHogProvider({ posthogClient }) }); -} -providers.push({ provider: new JsonFileProvider("../../config/flags.json") }); -*/ - -const multiProvider = new MultiProvider(providers, new FirstSuccessfulStrategy()); -await OpenFeature.setProviderAndWait(multiProvider); - -const session: AgentSession = { - id: "tui-session-" + Date.now(), - events: [], +type AgentSession = { + id: string; + events: any[]; }; type Message = { role: "user" | "agent"; text: string }; +const AGENT = process.env.AGENT || "support"; + function App() { const [messages, setMessages] = createSignal([]); const [streaming, setStreaming] = createSignal(""); const [activeTool, setActiveTool] = createSignal(""); const [busy, setBusy] = createSignal(false); + const [ready, setReady] = createSignal(false); + + // Keep a reference to the active agent function + let currentAgent: any = null; + + onMount(async () => { + try { + // 1. Setup OpenFeature without stalling root script + const providers = []; + if (process.env.POSTHOG_API_KEY) { + const { PostHogProvider } = await import("@tapico/node-openfeature-posthog"); + const { PostHog } = await import("posthog-node"); + const posthogClient = new PostHog(process.env.POSTHOG_API_KEY, { + host: process.env.POSTHOG_HOST || "https://app.posthog.com", + }); + providers.push({ provider: new PostHogProvider({ posthogClient }) }); + } + providers.push({ provider: new JsonFileProvider("../../config/flags.json") }); + + const multiProvider = new MultiProvider(providers, new FirstSuccessfulStrategy()); + await OpenFeature.setProviderAndWait(multiProvider); + + // 2. Resolve Agent inside onMount so OpenTUI doesn't lock up module loading + if (AGENT === "coding") { + const { codingAgent } = await import("@sup/agents/coding-agent"); + currentAgent = codingAgent; + } else { + const { supportAgent } = await import("@sup/agents/support-agent"); + currentAgent = supportAgent; + } + + setReady(true); + } catch (e) { + console.error("Initialization error:", e); + setReady(true); // Fallback so UI still draws + } + }); + + const session: AgentSession = { + id: "tui-session-" + Date.now(), + events: [], + }; async function submit(text: string) { - if (!text.trim() || busy()) return; + if (!text.trim() || busy() || !ready() || !currentAgent) return; setBusy(true); setMessages((m) => [...m, { role: "user", text }]); - const generator = agent(text, session, { - resolver: ProtocolResolver, - tools: adapters, - }); - - for await (const step of generator) { - if (step.type === "text_delta" && step.delta) { - setStreaming((s) => s + step.delta); - } else if (step.type === "tool_call") { - setActiveTool(step.toolId); - } else if (step.type === "tool_result") { - setActiveTool(""); - } else if (step.type === "final") { - setMessages((m) => [ - ...m, - { role: "agent", text: step.text || streaming() }, - ]); - setStreaming(""); - setActiveTool(""); + try { + const generator = currentAgent(text, session, { + resolver: ProtocolResolver, + tools: adapters, + }); + + for await (const step of generator) { + if (step.type === "text_delta" && step.delta) { + setStreaming((s) => s + step.delta); + } else if (step.type === "tool_call") { + setActiveTool(step.toolId); + } else if (step.type === "tool_result") { + setActiveTool(""); + } else if (step.type === "final") { + setMessages((m) => [ + ...m, + { role: "agent", text: step.text || streaming() }, + ]); + setStreaming(""); + setActiveTool(""); + } } + } catch (err) { + setMessages((m) => [...m, { role: "agent", text: `Error: ${err}` }]); } setBusy(false); @@ -90,7 +111,6 @@ function App() { {msg.role === "user" ? "You" : "Agent"}:{" "} {msg.text} -
)} @@ -108,8 +128,8 @@ function App() {
@@ -118,4 +138,4 @@ function App() { ); } -render(() => ); +render(() => ); \ No newline at end of file From 9009d217a3c368c76d93b6fa2bdd25cacbcd8a28 Mon Sep 17 00:00:00 2001 From: ForestMars Date: Thu, 18 Jun 2026 16:45:05 -0400 Subject: [PATCH 11/17] even better tui --- apps/tui/index.tsx | 107 +++++++++++++++++++++++++++++---------------- 1 file changed, 70 insertions(+), 37 deletions(-) diff --git a/apps/tui/index.tsx b/apps/tui/index.tsx index 8cf9d17f..af5666bf 100644 --- a/apps/tui/index.tsx +++ b/apps/tui/index.tsx @@ -25,6 +25,7 @@ function App() { const [activeTool, setActiveTool] = createSignal(""); const [busy, setBusy] = createSignal(false); const [ready, setReady] = createSignal(false); + const [currentModel, setCurrentModel] = createSignal("Detecting..."); let currentAgent: any = null; @@ -45,15 +46,19 @@ function App() { await OpenFeature.setProviderAndWait(multiProvider); if (AGENT === "coding") { - const { codingAgent } = await import("@sup/agents/coding-agent"); + const { codingAgent, codingAgentModelSpec } = await import("@sup/agents/coding-agent"); currentAgent = codingAgent; + // Extracted structural metadata details safely from imports + setCurrentModel(codingAgentModelSpec?.name || "gpt-4o-coding"); } else { - const { supportAgent } = await import("@sup/agents/support-agent"); + const { supportAgent, supportAgentModelSpec } = await import("@sup/agents/support-agent"); currentAgent = supportAgent; + setCurrentModel(supportAgentModelSpec?.name || "claude-3-5-sonnet"); } setReady(true); } catch (e) { + setCurrentModel("Fallback-LLM"); setReady(true); } }); @@ -98,59 +103,87 @@ function App() { } return ( - // Outer App Frame with background and single border - {/* 1. Header Row */} + {/* 1. Global App Header */} SUP // - {AGENT.toUpperCase()} AGENT + WORKSPACE CONTROL PANEL - {ready() ? "● ONLINE" : "○ INITIALIZING"} + {ready() ? "● ACTIVE CONTEXT" : "○ SYNCING ENVIRONMENT"} - {/* 2. Main Chat Workspace Container */} - - - {(msg) => ( - // Indented and bottom-margined block for structured bubbles + {/* 2. Main Middle Deck (Splits layout horizontally) */} + + + {/* Left Side: Scrollable Conversation Field */} + + + {(msg) => ( + + + {msg.role === "user" ? "❯ You" : "❯ Agent"} + + + {msg.text} + + + )} + + + {streaming() && ( - - {msg.role === "user" ? "❯ You" : "❯ Agent"} - + ❯ Agent - {msg.text} + {streaming()} )} - - - {/* Streaming Block */} - {streaming() && ( - - ❯ Agent - - {streaming()} + + + {/* Right Side: Sidebar Meta Deck Panel */} + + [ AGENT SPEC ] + + Type: + {AGENT.toUpperCase()} + + Engine Model: + {currentModel()} + + Status: + + {busy() ? "⚡ Processing" : "💤 Idle"} + + + Telemetry Log: + {activeTool() ? ( + + » Tool Invoked + [{activeTool()}] - - )} - - {/* Active System/Tool Traces */} - {activeTool() && ( - - ⠋ Executing tool: - [{activeTool()}] - - )} -
- - {/* 3. Action Input Row */} + ) : ( + Listening... + )} +
+ + + {/* 3. Action Input Base Footer */} {busy() ? " ⧗ " : " ❯ "} Date: Thu, 18 Jun 2026 16:59:01 -0400 Subject: [PATCH 12/17] default coding and sup models --- packages/infra/env.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/infra/env.ts b/packages/infra/env.ts index 895f641a..0449ee44 100644 --- a/packages/infra/env.ts +++ b/packages/infra/env.ts @@ -2,9 +2,12 @@ * @file infra/env.ts * @description Load environment first */ -const DEFAULT_MODEL = 'qwen3:8b'; + const DEFAULT_OWNER = 'ForestMars'; const DEFAULT_REPO = 'coffee'; +const DEFAULT_MODEL = 'qwen3:8b'; +const DEFAULT_CODING_MODEL = 'qwen3:8b'; +const DEFAULT_SUPPORT_AGENT_MODEL = 'qwen3:8b'; export const FACTOTUM_MODEL = 'qwen2.5:1.5b'; export const TEMPERATURE = 0; From f9de6e2eaaf8665e9a22f6efc8d98fd5bbc253d3 Mon Sep 17 00:00:00 2001 From: ForestMars Date: Thu, 18 Jun 2026 16:59:33 -0400 Subject: [PATCH 13/17] errors before imports --- apps/tui/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/tui/index.tsx b/apps/tui/index.tsx index af5666bf..7cb52602 100644 --- a/apps/tui/index.tsx +++ b/apps/tui/index.tsx @@ -1,3 +1,4 @@ +process.stdout.write = process.stderr.write.bind(process.stderr); import { render } from "@opentui/solid"; import { createSignal, For, onMount } from "solid-js"; import { From 99b02b6526790959ff6fc127927fbc2dc18cd32c Mon Sep 17 00:00:00 2001 From: ForestMars Date: Thu, 18 Jun 2026 17:44:06 -0400 Subject: [PATCH 14/17] focus --- apps/tui/index.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/tui/index.tsx b/apps/tui/index.tsx index 7cb52602..12946c00 100644 --- a/apps/tui/index.tsx +++ b/apps/tui/index.tsx @@ -27,6 +27,8 @@ function App() { const [busy, setBusy] = createSignal(false); const [ready, setReady] = createSignal(false); const [currentModel, setCurrentModel] = createSignal("Detecting..."); + + let inputRef: any; let currentAgent: any = null; @@ -50,14 +52,15 @@ function App() { const { codingAgent, codingAgentModelSpec } = await import("@sup/agents/coding-agent"); currentAgent = codingAgent; // Extracted structural metadata details safely from imports - setCurrentModel(codingAgentModelSpec?.name || "gpt-4o-coding"); + setCurrentModel(codingAgentModelSpec); } else { const { supportAgent, supportAgentModelSpec } = await import("@sup/agents/support-agent"); currentAgent = supportAgent; - setCurrentModel(supportAgentModelSpec?.name || "claude-3-5-sonnet"); + setCurrentModel(supportAgentModelSpec?.name); } setReady(true); + setTimeout(() => inputRef?.focus(), 0); } catch (e) { setCurrentModel("Fallback-LLM"); setReady(true); @@ -163,7 +166,6 @@ function App() { Engine Model: {currentModel()} - Status: {busy() ? "⚡ Processing" : "💤 Idle"} @@ -184,6 +186,7 @@ function App() { {busy() ? " ⧗ " : " ❯ "} Date: Thu, 18 Jun 2026 17:44:15 -0400 Subject: [PATCH 15/17] tui --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 857cad01..55fe9cbd 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,8 @@ "sup:loki": "AGENT=support LOKI_ENABLED=true bun apps/cli/chat.ts", "coda": "AGENT=coding bun apps/cli/chat.ts", "coda:cli": "AGENT=coding bun apps/cli/chat.ts", - "coda:tui": "AGENT=coding bun --env-file=.auth apps/tui/index.tsx", + "tui:debug": "AGENT=coding bun --env-file=.auth apps/tui/index.tsx", + "coda:tui": "AGENT=coding bun --env-file=.auth apps/tui/index.tsx 2>/dev/null", "lint": "eslint . --cache --max-warnings 0", "lint:fix": "eslint . --cache --fix --max-warnings 0", "preview": "vite preview", From a5605e4ac2297c256df23c99e1b200920e7f5e04 Mon Sep 17 00:00:00 2001 From: ForestMars Date: Thu, 18 Jun 2026 17:44:32 -0400 Subject: [PATCH 16/17] LF in coding agent --- packages/agents/coding-agent.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/agents/coding-agent.ts b/packages/agents/coding-agent.ts index fee46116..d4714cc9 100644 --- a/packages/agents/coding-agent.ts +++ b/packages/agents/coding-agent.ts @@ -352,4 +352,5 @@ export async function* codingAgent( yield { type: 'final', timestamp: Date.now(), text: bestText(summaryText, summaryReasoning) }; } -export const codingAgentModelSpec = `router:${ROUTER_MODEL} coder:${CODER_MODEL}`; \ No newline at end of file +export const codingAgentModelSpec = `router:${ROUTER_MODEL} +coder:${CODER_MODEL}`; \ No newline at end of file From 914383c85aefe71667bd81e8315118735cf2cd7b Mon Sep 17 00:00:00 2001 From: ForestMars Date: Thu, 18 Jun 2026 17:44:48 -0400 Subject: [PATCH 17/17] pino --- packages/infra/logger/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/infra/logger/index.ts b/packages/infra/logger/index.ts index 976e9a1b..a62b7f5b 100644 --- a/packages/infra/logger/index.ts +++ b/packages/infra/logger/index.ts @@ -14,7 +14,7 @@ export const pinoStorage = new AsyncLocalStorage< >(); const MODEL_NAME = AGENT_MODEL -const isTerminal = process.stdout.isTTY; +const isTerminal = process.stdout.isTTY && !process.env.TUI_MODE; const isDev = process.env.NODE_ENV !== 'production'; const lokiEnabled = process.env.LOKI_ENABLED === 'true'; @@ -37,7 +37,7 @@ if (isTerminal && isDev) { streams.push({ stream: pretty, level: 'debug' }); } else { streams.push({ - stream: pino.destination(2), + stream: pino.destination('/dev/null'), level: 'info', }); }