Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions api/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
# When set, all requests must include: Authorization: Bearer <key>
# Health and root endpoints are exempt.
GATHM_API_KEY = os.environ.get("GATHM_API_KEY", "")
PUBLIC_PATHS = {"", "/", "/api", "/api/v1", "/api/v1/health"}
PUBLIC_PATHS = {"", "/", "/api", "/api/v1", "/api/v1/health", "/api/v1/ping"}
# GUI static files are also public (any path not starting with /api/)

import hashlib
Expand Down Expand Up @@ -288,7 +288,13 @@ def do_GET(self):
else:
self._send_json({"error": f"Tool '{tool_name}' not found"}, 404)

# GET /api/v1/health
# GET /api/v1/ping — lightweight liveness probe used by the GUI.
# Unlike /health it does NOT shell out to the orchestrator, so it
# returns instantly and never makes the UI look "offline".
elif path == "/api/v1/ping":
self._send_json({"status": "ok", "service": "gathm-api"})

# GET /api/v1/health (full system health — checks every tool, slow)
elif path == "/api/v1/health":
result = run_agent_command("health", "all")
self._send_json(result)
Expand Down Expand Up @@ -434,7 +440,10 @@ def main():
else:
i += 1

server = http.server.HTTPServer((host, port), GathmAPIHandler)
# ThreadingHTTPServer so a slow request (e.g. the full /health sweep
# across all tools) never blocks the GUI from loading or other
# requests from being served concurrently.
server = http.server.ThreadingHTTPServer((host, port), GathmAPIHandler)
print(f"""
╔══════════════════════════════════════════════════╗
║ Gathm Enterprise API Server ║
Expand Down
37 changes: 32 additions & 5 deletions gui/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ let isOnline = false;

async function checkConnectivity() {
try {
const res = await fetch(`${API_BASE}/api/v1/health`, {
signal: AbortSignal.timeout(5000),
// /ping is instant — /health sweeps every tool and would time out.
const res = await fetch(`${API_BASE}/api/v1/ping`, {
signal: AbortSignal.timeout(4000),
});
isOnline = res.ok;
} catch {
Expand Down Expand Up @@ -96,6 +97,34 @@ function hideTyping() {
typingEl = null;
}

// ── Render agent reply ─────────────────────────────────────────
// The /agent/ask endpoint is a tool ROUTER, not a chat LLM. It returns
// structured JSON; translate it into something human-readable instead of
// dumping raw JSON into the chat.
function formatAgentReply(data) {
// A tool was matched to the query
if (data.matched_tool && data.matched_tool !== 'null') {
const desc = data.description ? `\n\n${data.description}` : '';
const action = data.action ? `\n\n→ ${data.action}` : `\n\n→ Run: gathm run ${data.matched_tool}`;
return `I can help with that using the “${data.matched_tool}” tool.${desc}${action}`;
}

// No tool matched — give a friendly, useful nudge instead of an error blob
if (data.error && /no matching tool/i.test(data.error)) {
return "I'm a tool-running assistant, so I work best with task requests. " +
"Try things like:\n" +
" • weather in Tokyo\n" +
" • dns records for github.com\n" +
" • ip info 8.8.8.8\n" +
" • define serendipity\n" +
" • crypto price bitcoin";
}

// Any other shape: prefer real output, fall back to the error text
return data.raw_output || data.output || data.result || data.error
|| JSON.stringify(data, null, 2);
}

// ── Send via API ───────────────────────────────────────────────
let isSending = false;

Expand Down Expand Up @@ -125,9 +154,7 @@ async function sendMessage() {
}

const data = await res.json();
const reply = data.raw_output || data.output || data.result
|| JSON.stringify(data, null, 2);
addMessage(reply, 'bot');
addMessage(formatAgentReply(data), 'bot');

} catch (err) {
hideTyping();
Expand Down
2 changes: 2 additions & 0 deletions gui/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,8 @@ body {
.message p {
font-size: 14px;
line-height: 1.55;
white-space: pre-wrap; /* preserve newlines / bullet lists in replies */
word-break: break-word;
}

.bot-text {
Expand Down
4 changes: 3 additions & 1 deletion install
Original file line number Diff line number Diff line change
Expand Up @@ -1529,7 +1529,9 @@ main() {
install_ollama "$platform"
install_llmfit_and_select_model

install_engineer_deps
# TODO(engineer): temporarily disabled — re-enable when resuming the
# engineer agent. Uncomment the line below to restore engineer setup.
# install_engineer_deps
install_pilot_deps
install_playwright_browser
setup_shortcuts "$platform"
Expand Down
Loading