#!/usr/bin/env python3 """Built-in agent: UI copy edits (logo/headline/subtitle/footer/chips/bullets). No server or model needed.""" import json, os, re, sys sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) os.environ.pop("AGENT_MARKET_LLM_API_KEY_FILE", None) from market.theme import parse_look_command from market.copyedit import DEFAULT_COPY from market import agent results = [] def check(name, ok, d=""): results.append(bool(ok)); print(("PASS " if ok else "FAIL ") + name + (f" [{d}]" if d else "")) def copy_of(text, theme=None): r = parse_look_command(text, theme or {}) return (r[0], (r[1] or {}).get("copy")) if r else (None, None) LOGO = [ "replace agent market to new internet on the top left corner", # the user's exact phrasing "change Agent Market to New Internet in the top left", "rename the logo to New Internet", "call the site New Internet", "top left should say New Internet", "replace Agent Market with New Internet", "change the top left text to New Internet", "make the logo say new internet", "I want the header to say New Internet", "logo: New Internet", "use New Internet as the site name", "change the brand to new internet please", "rename the website to new internet", "name the site new internet", "change agent market into new internet", "swap Agent Market for New Internet", 'replace "Agent Market" with "New Internet"', "Please change the site name to New Internet.", "the top-left corner should read New Internet", ] for p in LOGO: reply, c = copy_of(p) check(f"logo: {p}", c == {"logo": "New Internet"}, f"{c} / {reply}") cases = [ ("change the title to Hello World", {"headline": "Hello World"}), ("change the headline to Retro vibes", {"headline": "Retro vibes"}), ("replace A marketplace you can just talk to. with Buy and sell anything nearby", {"headline": "Buy and sell anything nearby"}), ("replace marketplace with bazaar", {"headline": "A bazaar you can just talk to."}), ("set the subtitle to Fast and free", {"subhead": "Fast and free"}), ("swap the tagline with Shop by chatting", {"subhead": "Shop by chatting"}), ("swap the footer to Made for testing", {"footer": "Made for testing"}), ("replace market with Internet in the logo", {"logo": "Agent Internet"}), ("the top left should read NEW INTERNET", {"logo": "NEW INTERNET"}), ("change the logo to new Internet", {"logo": "new Internet"}), # mixed case typed -> kept exactly ] for p, want in cases: reply, c = copy_of(p) check(f"copy: {p}", c == want, f"{c}") reply, c = copy_of("rename Tutoring to Lessons") check("chip label edited, emoji + action kept", c and c["chips"][1] == {"label": "📐 Lessons", "say": "find tutoring services"} and c["chips"][3].get("event") == "sell", c and c["chips"][:4]) reply, c = copy_of("replace $0 fee with no fee") check("bullet edited by find-and-replace", c and c["bullets"][1].startswith("no fee when you meet"), c) reply, c = copy_of("replace New Internet with Agent Hub", {"copy": {"logo": "New Internet"}}) check("find-and-replace uses the visitor's current text", c == {"logo": "Agent Hub"}, c) # unclear -> says what it understood + closest option, never silently nothing / listings r = parse_look_command("replace agent with robot", {}) check("ambiguous text -> asks where", r and r[1] is None and "more than one place" in r[0], r and r[0]) r = parse_look_command("replace agnet markt with New Internet", {}) check("typo -> offers the closest slot", r and r[1] is None and "Closest is the top-left logo text" in r[0], r and r[0]) r = parse_look_command("replace foo bar with baz", {}) check("not found -> lists what can be edited", r and r[1] is None and "can't find" in r[0], r and r[0]) # no hijacking of look commands, search or selling for p, key in (("change the background to a sunset gradient", "background"), ("switch to light mode with a green accent", "mode"), ("use a serif font and make the text bigger", "font"), ("replace the background with blue", "background"), ("move the chat to the left", "chat"), ("hide the bullet points", "sections")): r = parse_look_command(p, {}) check(f"look command still works: {p}", r and r[1] and key in r[1] and "copy" not in r[1], r and r[1]) for p in ("show me bikes", "change my order to cash", "I'd like to sell my lamp for $20", "find tutoring services"): check(f"not a copy edit: {p}", parse_look_command(p, {}) is None) r = parse_look_command("make it look retro", {}) check("preset still works", r and r[1] == {"preset": "retro"}) r = parse_look_command("use the Inter font", {}) check("font names are word-bounded (Inter font still works)", r and r[1].get("font") == "Inter") check("'internet' is not the Inter font", "font" not in (parse_look_command("make the headline say internet rocks", {})[1] or {})) # end to end through the built-in agent (what /api/chat returns when no model answers) out = agent.fallback_agent(None, "replace agent market to new internet on the top left corner", [], "t", {}) check("built-in agent: user's exact phrasing -> set_theme copy.logo, no listings", [a["type"] for a in out["actions"]] == ["set_theme"] and out["actions"][0]["payload"]["copy"] == {"logo": "New Internet"}, out["reply"]) out = agent.fallback_agent(None, "replace agent with robot", [], "t", {}) check("built-in agent: unclear edit -> explanation only", out["actions"] == [] and "agent" in out["reply"]) # server copy defaults match the React app's defaults app = open(os.path.join(os.path.dirname(__file__), "..", "web", "src", "App.tsx"), encoding="utf-8").read() ok = all(s in app for s in (DEFAULT_COPY["logo"], DEFAULT_COPY["headline"], DEFAULT_COPY["subhead"]) ) and \ all(c["label"] in app for c in DEFAULT_COPY["chips"]) and all(b.split("{fee}% ")[-1] in app for b in DEFAULT_COPY["bullets"]) check("DEFAULT_COPY in sync with web/src/App.tsx", ok) check("model prompt explains top-left = logo and includes PAGE_TEXT", "TOP-LEFT" in agent.UI_SCHEMA and '"logo": "Agent Market"' in agent._page_text("{}")) print(f"\n{sum(results)}/{len(results)} passed") sys.exit(0 if all(results) else 1)