From bf11312b4bdbdf22dc82b0e257d3599a67d86fc3 Mon Sep 17 00:00:00 2001 From: Nico Date: Tue, 31 Mar 2026 01:39:05 +0200 Subject: [PATCH] Rename cog -> assay across codebase - Rename files: cog_cli.py, test_cog.py, k8s/cog-*.yaml - Update all Python tool names: cog_* -> assay_* - Update FastAPI titles, MCP server names, URLs - Update K8s manifests: deployments, services, secrets, ingress - Update Docker env vars: COG_API -> ASSAY_API - Domain: cog.loop42.de -> assay.loop42.de - SQLite path: /tmp/cog_db.sqlite -> /tmp/assay_db.sqlite Co-Authored-By: Claude Opus 4.6 (1M context) --- Dockerfile.test | 13 + agent/__init__.py | 6 +- agent/db.py | 3 +- agent/mcp_app.py | 40 +-- agent/mcp_server.py | 36 +-- agent/nodes/thinker_v1.py | 2 +- cog_cli.py => assay_cli.py | 6 +- docker-compose.yml | 14 +- ...{cog-frontend.yaml => assay-frontend.yaml} | 12 +- k8s/{cog-ingress.yaml => assay-ingress.yaml} | 20 +- k8s/{cog-mcp.yaml => assay-mcp.yaml} | 16 +- k8s/{cog-runtime.yaml => assay-runtime.yaml} | 14 +- runtime_test.py | 12 +- test_cog.py => test_assay.py | 8 +- test_nodes/run_all.py | 2 +- test_nodes/run_integration.py | 8 +- testcases/results.json | 230 ++---------------- 17 files changed, 139 insertions(+), 303 deletions(-) create mode 100644 Dockerfile.test rename cog_cli.py => assay_cli.py (96%) rename k8s/{cog-frontend.yaml => assay-frontend.yaml} (84%) rename k8s/{cog-ingress.yaml => assay-ingress.yaml} (81%) rename k8s/{cog-mcp.yaml => assay-mcp.yaml} (84%) rename k8s/{cog-runtime.yaml => assay-runtime.yaml} (85%) rename test_cog.py => test_assay.py (82%) diff --git a/Dockerfile.test b/Dockerfile.test new file mode 100644 index 0000000..b5a29b8 --- /dev/null +++ b/Dockerfile.test @@ -0,0 +1,13 @@ +FROM python:3.12-slim + +WORKDIR /app + +RUN pip install --no-cache-dir httpx websockets + +COPY runtime_test.py . +COPY testcases/ testcases/ + +ENV ASSAY_API=http://runtime:8000/api + +ENTRYPOINT ["python3", "runtime_test.py"] +CMD ["testcases/fast_v4.md"] diff --git a/agent/__init__.py b/agent/__init__.py index 27b0cec..abccb4f 100644 --- a/agent/__init__.py +++ b/agent/__init__.py @@ -1,4 +1,4 @@ -"""Cognitive Agent Runtime — modular package. +"""assay — agent runtime. uvicorn entrypoint: agent:app """ @@ -30,13 +30,13 @@ class NoCacheStaticMiddleware(BaseHTTPMiddleware): STATIC_DIR = Path(__file__).parent.parent / "static" -app = FastAPI(title="cog") +app = FastAPI(title="assay") # Register all API + WS routes register_routes(app) # Serve frontend from same process (fallback for non-split deploy) -# When running behind cog-frontend nginx, these paths won't be hit +# When running behind assay-frontend nginx, these paths won't be hit @app.get("/") async def index(): resp = FileResponse(STATIC_DIR / "index.html") diff --git a/agent/db.py b/agent/db.py index a5078a1..1420f23 100644 --- a/agent/db.py +++ b/agent/db.py @@ -1,10 +1,11 @@ """Shared database access for Thinker and Expert nodes.""" import logging +import os log = logging.getLogger("runtime") -DB_HOST = "mariadb-eras" +DB_HOST = os.environ.get("DB_HOST", "mariadb-eras") DB_USER = "root" DB_PASS = "root" ALLOWED_DATABASES = ("eras2_production", "plankiste_test") diff --git a/agent/mcp_app.py b/agent/mcp_app.py index 27303dd..b3ae7b0 100644 --- a/agent/mcp_app.py +++ b/agent/mcp_app.py @@ -1,4 +1,4 @@ -"""Standalone MCP SSE app — proxies tool calls to cog-runtime.""" +"""Standalone MCP SSE app — proxies tool calls to assay-runtime.""" import json import logging @@ -20,11 +20,11 @@ logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(name)s] %(message log = logging.getLogger("mcp-proxy") # Config -RUNTIME_URL = os.environ.get("RUNTIME_URL", "http://cog-runtime") +RUNTIME_URL = os.environ.get("RUNTIME_URL", "http://assay-runtime") SERVICE_TOKENS = set(filter(None, os.environ.get("SERVICE_TOKENS", "").split(","))) SERVICE_TOKEN = os.environ.get("SERVICE_TOKENS", "").split(",")[0] if os.environ.get("SERVICE_TOKENS") else "" -app = FastAPI(title="cog-mcp") +app = FastAPI(title="assay-mcp") _security = HTTPBearer() @@ -42,7 +42,7 @@ async def health(): # --- MCP Server --- -mcp_server = Server("cog") +mcp_server = Server("assay") _mcp_transport = SseServerTransport("/mcp/messages/") @@ -87,29 +87,29 @@ async def _proxy_post(path: str, body: dict = None) -> dict: @mcp_server.list_tools() async def list_tools(): return [ - Tool(name="cog_send", description="Send a message to the cognitive agent and get a response.", + Tool(name="assay_send", description="Send a message to the cognitive agent and get a response.", inputSchema={"type": "object", "properties": { "text": {"type": "string", "description": "Message text to send"}, "database": {"type": "string", "description": "Optional: database name for query_db context"}, }, "required": ["text"]}), - Tool(name="cog_trace", description="Get recent trace events from the pipeline (HUD events, tool calls, audit).", + Tool(name="assay_trace", description="Get recent trace events from the pipeline (HUD events, tool calls, audit).", inputSchema={"type": "object", "properties": { "last": {"type": "integer", "description": "Number of recent events (default 20)", "default": 20}, "filter": {"type": "string", "description": "Comma-separated event types to filter (e.g. 'tool_call,controls')"}, }}), - Tool(name="cog_history", description="Get recent chat messages from the active session.", + Tool(name="assay_history", description="Get recent chat messages from the active session.", inputSchema={"type": "object", "properties": { "last": {"type": "integer", "description": "Number of recent messages (default 20)", "default": 20}, }}), - Tool(name="cog_state", description="Get the current memorizer state (mood, topic, language, facts).", + Tool(name="assay_state", description="Get the current memorizer state (mood, topic, language, facts).", inputSchema={"type": "object", "properties": {}}), - Tool(name="cog_clear", description="Clear the active session (history, state, controls).", + Tool(name="assay_clear", description="Clear the active session (history, state, controls).", inputSchema={"type": "object", "properties": {}}), - Tool(name="cog_graph", description="Get the active graph definition (nodes, edges, description).", + Tool(name="assay_graph", description="Get the active graph definition (nodes, edges, description).", inputSchema={"type": "object", "properties": {}}), - Tool(name="cog_graph_list", description="List all available graph definitions.", + Tool(name="assay_graph_list", description="List all available graph definitions.", inputSchema={"type": "object", "properties": {}}), - Tool(name="cog_graph_switch", description="Switch the active graph for new sessions.", + Tool(name="assay_graph_switch", description="Switch the active graph for new sessions.", inputSchema={"type": "object", "properties": { "name": {"type": "string", "description": "Graph name to switch to"}, }, "required": ["name"]}), @@ -118,7 +118,7 @@ async def list_tools(): @mcp_server.call_tool() async def call_tool(name: str, arguments: dict): - if name == "cog_send": + if name == "assay_send": text = arguments.get("text", "") if not text: return [TextContent(type="text", text="ERROR: Missing 'text' argument.")] @@ -150,7 +150,7 @@ async def call_tool(name: str, arguments: dict): return [TextContent(type="text", text=f"ERROR: {result.get('detail', 'pipeline failed')}")] return [TextContent(type="text", text="ERROR: Pipeline timeout (30s)")] - elif name == "cog_trace": + elif name == "assay_trace": last = arguments.get("last", 20) event_filter = arguments.get("filter", "") params = {"last": last} @@ -170,38 +170,38 @@ async def call_tool(name: str, arguments: dict): lines.append(line.rstrip()) return [TextContent(type="text", text="\n".join(lines) if lines else "(no events)")] - elif name == "cog_history": + elif name == "assay_history": last = arguments.get("last", 20) result = await _proxy_get("/api/history", {"last": last}) if "error" in result: return [TextContent(type="text", text=f"ERROR: {result['error']}")] return [TextContent(type="text", text=json.dumps(result.get("messages", []), indent=2))] - elif name == "cog_state": + elif name == "assay_state": result = await _proxy_get("/api/state") if "error" in result: return [TextContent(type="text", text=f"ERROR: {result['error']}")] return [TextContent(type="text", text=json.dumps(result, indent=2))] - elif name == "cog_clear": + elif name == "assay_clear": result = await _proxy_post("/api/clear") if "error" in result: return [TextContent(type="text", text=f"ERROR: {result['error']}")] return [TextContent(type="text", text="Session cleared.")] - elif name == "cog_graph": + elif name == "assay_graph": result = await _proxy_get("/api/graph/active") if "error" in result: return [TextContent(type="text", text=f"ERROR: {result['error']}")] return [TextContent(type="text", text=json.dumps(result, indent=2))] - elif name == "cog_graph_list": + elif name == "assay_graph_list": result = await _proxy_get("/api/graph/list") if "error" in result: return [TextContent(type="text", text=f"ERROR: {result['error']}")] return [TextContent(type="text", text=json.dumps(result.get("graphs", []), indent=2))] - elif name == "cog_graph_switch": + elif name == "assay_graph_switch": gname = arguments.get("name", "") if not gname: return [TextContent(type="text", text="ERROR: Missing 'name' argument.")] diff --git a/agent/mcp_server.py b/agent/mcp_server.py index 5efb96f..34271b6 100644 --- a/agent/mcp_server.py +++ b/agent/mcp_server.py @@ -1,4 +1,4 @@ -"""MCP server for cog — exposes runtime tools to any MCP client.""" +"""MCP server for assay — exposes runtime tools to any MCP client.""" import json import logging @@ -12,7 +12,7 @@ log = logging.getLogger("mcp") TRACE_FILE = Path(__file__).parent.parent / "trace.jsonl" -server = Server("cog") +server = Server("assay") # Reference to active runtime — set by api.py when WS connects _get_runtime = lambda: None @@ -26,29 +26,29 @@ def set_runtime_getter(fn): @server.list_tools() async def list_tools(): return [ - Tool(name="cog_send", description="Send a message to the cognitive agent and get a response.", + Tool(name="assay_send", description="Send a message to the cognitive agent and get a response.", inputSchema={"type": "object", "properties": { "text": {"type": "string", "description": "Message text to send"}, "database": {"type": "string", "description": "Optional: database name for query_db context"}, }, "required": ["text"]}), - Tool(name="cog_trace", description="Get recent trace events from the pipeline (HUD events, tool calls, audit).", + Tool(name="assay_trace", description="Get recent trace events from the pipeline (HUD events, tool calls, audit).", inputSchema={"type": "object", "properties": { "last": {"type": "integer", "description": "Number of recent events (default 20)", "default": 20}, "filter": {"type": "string", "description": "Comma-separated event types to filter (e.g. 'tool_call,controls')"}, }}), - Tool(name="cog_history", description="Get recent chat messages from the active session.", + Tool(name="assay_history", description="Get recent chat messages from the active session.", inputSchema={"type": "object", "properties": { "last": {"type": "integer", "description": "Number of recent messages (default 20)", "default": 20}, }}), - Tool(name="cog_state", description="Get the current memorizer state (mood, topic, language, facts).", + Tool(name="assay_state", description="Get the current memorizer state (mood, topic, language, facts).", inputSchema={"type": "object", "properties": {}}), - Tool(name="cog_clear", description="Clear the active session (history, state, controls).", + Tool(name="assay_clear", description="Clear the active session (history, state, controls).", inputSchema={"type": "object", "properties": {}}), - Tool(name="cog_graph", description="Get the active graph definition (nodes, edges, description).", + Tool(name="assay_graph", description="Get the active graph definition (nodes, edges, description).", inputSchema={"type": "object", "properties": {}}), - Tool(name="cog_graph_list", description="List all available graph definitions.", + Tool(name="assay_graph_list", description="List all available graph definitions.", inputSchema={"type": "object", "properties": {}}), - Tool(name="cog_graph_switch", description="Switch the active graph for new sessions.", + Tool(name="assay_graph_switch", description="Switch the active graph for new sessions.", inputSchema={"type": "object", "properties": { "name": {"type": "string", "description": "Graph name to switch to"}, }, "required": ["name"]}), @@ -59,7 +59,7 @@ async def list_tools(): async def call_tool(name: str, arguments: dict): runtime = _get_runtime() - if name == "cog_send": + if name == "assay_send": if not runtime: return [TextContent(type="text", text="ERROR: No active session — someone must be connected via WebSocket first.")] text = arguments.get("text", "").strip() @@ -69,7 +69,7 @@ async def call_tool(name: str, arguments: dict): response = runtime.history[-1]["content"] if runtime.history else "(no response)" return [TextContent(type="text", text=response)] - elif name == "cog_trace": + elif name == "assay_trace": last = arguments.get("last", 20) filt = arguments.get("filter", "").split(",") if arguments.get("filter") else None if not TRACE_FILE.exists(): @@ -107,7 +107,7 @@ async def call_tool(name: str, arguments: dict): out.append(f"{node:12} {event:20} {str(detail)[:120]}") return [TextContent(type="text", text="\n".join(out) if out else "(no matching events)")] - elif name == "cog_history": + elif name == "assay_history": if not runtime: return [TextContent(type="text", text="(no active session)")] last = arguments.get("last", 20) @@ -119,12 +119,12 @@ async def call_tool(name: str, arguments: dict): out.append("") return [TextContent(type="text", text="\n".join(out) if out else "(no messages)")] - elif name == "cog_state": + elif name == "assay_state": if not runtime: return [TextContent(type="text", text="(no active session)")] return [TextContent(type="text", text=json.dumps(runtime.memorizer.state, indent=2, ensure_ascii=False))] - elif name == "cog_clear": + elif name == "assay_clear": if not runtime: return [TextContent(type="text", text="ERROR: No active session.")] runtime.history.clear() @@ -134,7 +134,7 @@ async def call_tool(name: str, arguments: dict): runtime.ui_node.machines.clear() return [TextContent(type="text", text="Session cleared.")] - elif name == "cog_graph": + elif name == "assay_graph": from .engine import load_graph, get_graph_for_cytoscape from .runtime import _active_graph_name graph = load_graph(_active_graph_name) @@ -147,11 +147,11 @@ async def call_tool(name: str, arguments: dict): "audit": graph.get("audit", {}), }, indent=2))] - elif name == "cog_graph_list": + elif name == "assay_graph_list": from .engine import list_graphs return [TextContent(type="text", text=json.dumps(list_graphs(), indent=2))] - elif name == "cog_graph_switch": + elif name == "assay_graph_switch": from .engine import load_graph import agent.runtime as rt gname = arguments.get("name", "") diff --git a/agent/nodes/thinker_v1.py b/agent/nodes/thinker_v1.py index 985a1cf..9546510 100644 --- a/agent/nodes/thinker_v1.py +++ b/agent/nodes/thinker_v1.py @@ -340,7 +340,7 @@ CRITICAL RULES: if code and len(code.split("\n")) > 0: if lang in ("sql", "sqlite"): wrapped = f'''import sqlite3 -conn = sqlite3.connect("/tmp/cog_db.sqlite") +conn = sqlite3.connect("/tmp/assay_db.sqlite") cursor = conn.cursor() for stmt in """{code}""".split(";"): stmt = stmt.strip() diff --git a/cog_cli.py b/assay_cli.py similarity index 96% rename from cog_cli.py rename to assay_cli.py index 1139212..261102c 100644 --- a/cog_cli.py +++ b/assay_cli.py @@ -1,10 +1,10 @@ -"""CLI helper for reading cog API — trace, history, state, send.""" +"""CLI helper for reading assay API — trace, history, state, send.""" import json import sys import httpx -API = "https://cog.loop42.de" +API = "https://assay.loop42.de" TOKEN = "7Oorb9S3OpwFyWgm4zi_Tq7GeamefbjjTgooPVPWAwPDOf6B4TvgvQlLbhmT4DjsqBS_D1g" HEADERS = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"} @@ -107,7 +107,7 @@ def graph(): if __name__ == "__main__": if len(sys.argv) < 2: - print("Usage: cog_cli.py [args]") + print("Usage: assay_cli.py [args]") print(" trace [last] [event_filter] — show trace events") print(" history [last] — show chat history") print(" state — show memorizer state") diff --git a/docker-compose.yml b/docker-compose.yml index 6554b7a..44bbbff 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,10 +3,16 @@ services: build: . ports: - "8000:8000" - volumes: - - ./agent.py:/app/agent.py - - ./static:/app/static - - ./trace.jsonl:/app/trace.jsonl env_file: - .env restart: unless-stopped + + tester: + build: + context: . + dockerfile: Dockerfile.test + environment: + - ASSAY_API=http://runtime:8000/api + depends_on: + - runtime + profiles: ["test"] diff --git a/k8s/cog-frontend.yaml b/k8s/assay-frontend.yaml similarity index 84% rename from k8s/cog-frontend.yaml rename to k8s/assay-frontend.yaml index 188e6d5..de5328d 100644 --- a/k8s/cog-frontend.yaml +++ b/k8s/assay-frontend.yaml @@ -1,13 +1,13 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: cog-frontend + name: assay-frontend namespace: default spec: replicas: 1 selector: matchLabels: - app: cog-frontend + app: assay-frontend strategy: type: RollingUpdate rollingUpdate: @@ -16,11 +16,11 @@ spec: template: metadata: labels: - app: cog-frontend + app: assay-frontend spec: containers: - name: nginx - image: docker.io/library/cog-frontend:latest + image: docker.io/library/assay-frontend:latest imagePullPolicy: Never ports: - containerPort: 80 @@ -47,11 +47,11 @@ spec: apiVersion: v1 kind: Service metadata: - name: cog-frontend + name: assay-frontend namespace: default spec: selector: - app: cog-frontend + app: assay-frontend ports: - port: 80 targetPort: 80 diff --git a/k8s/cog-ingress.yaml b/k8s/assay-ingress.yaml similarity index 81% rename from k8s/cog-ingress.yaml rename to k8s/assay-ingress.yaml index 0445656..8af0c06 100644 --- a/k8s/cog-ingress.yaml +++ b/k8s/assay-ingress.yaml @@ -1,7 +1,7 @@ apiVersion: networking.k8s.io/v1 kind: Ingress metadata: - name: cog-runtime + name: assay-runtime annotations: cert-manager.io/cluster-issuer: letsencrypt-prod traefik.ingress.kubernetes.io/router.entrypoints: websecure @@ -9,11 +9,11 @@ metadata: spec: ingressClassName: traefik tls: - - secretName: cog-tls + - secretName: assay-tls hosts: - - cog.loop42.de + - assay.loop42.de rules: - - host: cog.loop42.de + - host: assay.loop42.de http: paths: # MCP SSE — separate pod, survives runtime restarts @@ -21,7 +21,7 @@ spec: pathType: Prefix backend: service: - name: cog-mcp + name: assay-mcp port: number: 80 # WebSocket + REST API — runtime pod @@ -29,28 +29,28 @@ spec: pathType: Prefix backend: service: - name: cog-runtime + name: assay-runtime port: number: 80 - path: /api pathType: Prefix backend: service: - name: cog-runtime + name: assay-runtime port: number: 80 - path: /health pathType: Prefix backend: service: - name: cog-runtime + name: assay-runtime port: number: 80 - path: /auth pathType: Prefix backend: service: - name: cog-runtime + name: assay-runtime port: number: 80 # Frontend — nginx, catch-all (must be last) @@ -58,6 +58,6 @@ spec: pathType: Prefix backend: service: - name: cog-frontend + name: assay-frontend port: number: 80 diff --git a/k8s/cog-mcp.yaml b/k8s/assay-mcp.yaml similarity index 84% rename from k8s/cog-mcp.yaml rename to k8s/assay-mcp.yaml index 75703f0..2547493 100644 --- a/k8s/cog-mcp.yaml +++ b/k8s/assay-mcp.yaml @@ -1,13 +1,13 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: cog-mcp + name: assay-mcp namespace: default spec: replicas: 1 selector: matchLabels: - app: cog-mcp + app: assay-mcp strategy: type: RollingUpdate rollingUpdate: @@ -16,11 +16,11 @@ spec: template: metadata: labels: - app: cog-mcp + app: assay-mcp spec: containers: - name: mcp - image: docker.io/library/loop42-agent:v0.13.0 + image: docker.io/library/loop42-agent:v0.18.0 imagePullPolicy: Never command: ["uvicorn", "agent.mcp_app:app", "--host", "0.0.0.0", "--port", "8001"] ports: @@ -29,10 +29,10 @@ spec: - name: SERVICE_TOKENS value: 7Oorb9S3OpwFyWgm4zi_Tq7GeamefbjjTgooPVPWAwPDOf6B4TvgvQlLbhmT4DjsqBS_D1g - name: RUNTIME_URL - value: "http://cog-runtime" + value: "http://assay-runtime" envFrom: - secretRef: - name: cog-runtime-env + name: assay-runtime-env readinessProbe: httpGet: path: /health @@ -56,11 +56,11 @@ spec: apiVersion: v1 kind: Service metadata: - name: cog-mcp + name: assay-mcp namespace: default spec: selector: - app: cog-mcp + app: assay-mcp ports: - port: 80 targetPort: 8001 diff --git a/k8s/cog-runtime.yaml b/k8s/assay-runtime.yaml similarity index 85% rename from k8s/cog-runtime.yaml rename to k8s/assay-runtime.yaml index 2d936f5..0571303 100644 --- a/k8s/cog-runtime.yaml +++ b/k8s/assay-runtime.yaml @@ -1,13 +1,13 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: cog-runtime + name: assay-runtime namespace: default spec: replicas: 1 selector: matchLabels: - app: cog-runtime + app: assay-runtime strategy: type: RollingUpdate rollingUpdate: @@ -16,11 +16,11 @@ spec: template: metadata: labels: - app: cog-runtime + app: assay-runtime spec: containers: - name: agent - image: docker.io/library/loop42-agent:v0.13.0 + image: docker.io/library/loop42-agent:v0.18.0 imagePullPolicy: Never ports: - containerPort: 8000 @@ -31,7 +31,7 @@ spec: value: 7Oorb9S3OpwFyWgm4zi_Tq7GeamefbjjTgooPVPWAwPDOf6B4TvgvQlLbhmT4DjsqBS_D1g envFrom: - secretRef: - name: cog-runtime-env + name: assay-runtime-env readinessProbe: httpGet: path: /health @@ -55,11 +55,11 @@ spec: apiVersion: v1 kind: Service metadata: - name: cog-runtime + name: assay-runtime namespace: default spec: selector: - app: cog-runtime + app: assay-runtime ports: - port: 80 targetPort: 8000 diff --git a/runtime_test.py b/runtime_test.py index 44ed61e..599bdac 100644 --- a/runtime_test.py +++ b/runtime_test.py @@ -1,5 +1,5 @@ """ -Cog Runtime Test Runner — parses testcases/*.md and executes against live API. +Assay Runtime Test Runner — parses testcases/*.md and executes against live API. Usage: pytest testcases/ -v # run all testcases @@ -21,7 +21,7 @@ if sys.platform == "win32": from pathlib import Path from dataclasses import dataclass, field -API = "https://cog.loop42.de/api" +API = os.environ.get("ASSAY_API", "https://assay.loop42.de/api") TOKEN = "7Oorb9S3OpwFyWgm4zi_Tq7GeamefbjjTgooPVPWAwPDOf6B4TvgvQlLbhmT4DjsqBS_D1g" HEADERS = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"} @@ -136,7 +136,7 @@ def _parse_command(text: str) -> dict | None: # --- API client --- -class CogClient: +class AssayClient: def __init__(self): self.client = httpx.Client(timeout=90) self.last_response = "" @@ -430,9 +430,9 @@ class StepResult: detail: str = "" -class CogTestRunner: +class AssayTestRunner: def __init__(self, on_result=None): - self.client = CogClient() + self.client = AssayClient() self._on_result = on_result # callback(result_dict) per check def run(self, testcase: dict) -> list[dict]: @@ -568,7 +568,7 @@ def run_standalone(paths: list[Path] = None): print(f" {r['detail']}") _push_status("step_result", suite=suite_name, result=r) - runner = CogTestRunner(on_result=_on_result) + runner = AssayTestRunner(on_result=_on_result) results = runner.run(tc) all_results[tc["name"]] = results diff --git a/test_cog.py b/test_assay.py similarity index 82% rename from test_cog.py rename to test_assay.py index 2374cc8..69ae8e7 100644 --- a/test_cog.py +++ b/test_assay.py @@ -1,7 +1,7 @@ -"""Test script for cog runtime API. Run with: .venv/Scripts/python.exe test_cog.py""" +"""Test script for assay runtime API. Run with: .venv/Scripts/python.exe test_assay.py""" import httpx, sys, time -API = "https://cog.loop42.de/api" +API = "https://assay.loop42.de/api" TOKEN = "7Oorb9S3OpwFyWgm4zi_Tq7GeamefbjjTgooPVPWAwPDOf6B4TvgvQlLbhmT4DjsqBS_D1g" HEADERS = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"} @@ -21,12 +21,12 @@ tests = [ ] clear() -print("=== COG TEST RUN ===\n") +print("=== ASSAY TEST RUN ===\n") for i, (msg, _) in enumerate(tests, 1): print(f"--- {i}. USER: {msg}") resp, memo = send(msg) - print(f" COG: {resp}") + print(f" ASSAY: {resp}") print(f" MEMO: name={memo.get('user_name')} mood={memo.get('user_mood')} topic={memo.get('topic')}") print() time.sleep(0.5) diff --git a/test_nodes/run_all.py b/test_nodes/run_all.py index 7d54a0a..deee472 100644 --- a/test_nodes/run_all.py +++ b/test_nodes/run_all.py @@ -2,7 +2,7 @@ Usage: python run_all.py # local only - python run_all.py --report https://cog.loop42.de # + push to frontend + python run_all.py --report https://assay.loop42.de # + push to frontend """ import sys diff --git a/test_nodes/run_integration.py b/test_nodes/run_integration.py index 26adf38..1086299 100644 --- a/test_nodes/run_integration.py +++ b/test_nodes/run_integration.py @@ -1,9 +1,9 @@ """Integration tests — send real messages through the live runtime pipeline. Usage: - python run_integration.py --url https://cog.loop42.de --graph v1-current - python run_integration.py --url https://cog.loop42.de --graph v2-director-drives - python run_integration.py --url https://cog.loop42.de --graph both + python run_integration.py --url https://assay.loop42.de --graph v1-current + python run_integration.py --url https://assay.loop42.de --graph v2-director-drives + python run_integration.py --url https://assay.loop42.de --graph both """ import json @@ -30,7 +30,7 @@ from harness import NodeTestRunner # --- Config --- -DEFAULT_URL = "https://cog.loop42.de" +DEFAULT_URL = "https://assay.loop42.de" TOKEN = "7Oorb9S3OpwFyWgm4zi_Tq7GeamefbjjTgooPVPWAwPDOf6B4TvgvQlLbhmT4DjsqBS_D1g" HEADERS = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"} diff --git a/testcases/results.json b/testcases/results.json index fe7aa86..15b9768 100644 --- a/testcases/results.json +++ b/testcases/results.json @@ -1,98 +1,6 @@ { - "timestamp": "2026-03-30 00:02:55", + "timestamp": "2026-03-30 21:04:54", "testcases": { - "Artifact System": [ - { - "step": "Setup", - "check": "clear", - "status": "PASS", - "detail": "cleared" - }, - { - "step": "Query produces data_table artifact", - "check": "send: show me 3 customers in a table", - "status": "PASS", - "detail": "response: The database contains information for three customers: Kathrin Jager, Leon Schre" - }, - { - "step": "Query produces data_table artifact", - "check": "trace: has tool_call", - "status": "PASS", - "detail": "found event 'tool_call'" - }, - { - "step": "Query produces data_table artifact", - "check": "response: length > 10", - "status": "PASS", - "detail": "length 138 > 10" - }, - { - "step": "Entity detail via card", - "check": "send: show me details for customer 1", - "status": "PASS", - "detail": "response: ```tool_code\nquery_db({\"query\":\"SELECT * FROM customers WHERE customer_id = 1\"})" - }, - { - "step": "Entity detail via card", - "check": "trace: has tool_call", - "status": "PASS", - "detail": "found event 'tool_call'" - }, - { - "step": "Entity detail via card", - "check": "response: length > 10", - "status": "PASS", - "detail": "length 84 > 10" - }, - { - "step": "Action bar via buttons", - "check": "send: create two buttons on my dashboard: Refr", - "status": "PASS", - "detail": "response: I have added the 'Refresh' and 'Export' buttons to your dashboard. These buttons" - }, - { - "step": "Action bar via buttons", - "check": "actions: length >= 2", - "status": "PASS", - "detail": "2 actions >= 2" - }, - { - "step": "Action bar via buttons", - "check": "actions: any action contains \"refresh\" or \"Refresh\"", - "status": "PASS", - "detail": "found 'refresh' in actions" - }, - { - "step": "Machine artifact", - "check": "send: create a machine called \"flow\" with init", - "status": "PASS", - "detail": "response: OK, I've created a new interactive machine called 'flow' with the initial state " - }, - { - "step": "Machine artifact", - "check": "trace: has machine_created", - "status": "PASS", - "detail": "found event 'machine_created'" - }, - { - "step": "Query after buttons survive", - "check": "send: how many customers are there?", - "status": "PASS", - "detail": "response: There are 693 customers in the database.\n" - }, - { - "step": "Query after buttons survive", - "check": "response: length > 5", - "status": "PASS", - "detail": "length 41 > 5" - }, - { - "step": "Query after buttons survive", - "check": "actions: any action contains \"refresh\" or \"Refresh\"", - "status": "PASS", - "detail": "found 'refresh' in actions" - } - ], "Fast v4": [ { "step": "Setup", @@ -104,19 +12,19 @@ "step": "Reflex", "check": "send: hi!", "status": "PASS", - "detail": "response: Hey Nico! 👋 How can I help you today?\n" + "detail": "response: Hey there! 👋 What's on your mind today?\n" }, { "step": "Reflex", "check": "response: length > 2", "status": "PASS", - "detail": "length 38 > 2" + "detail": "length 40 > 2" }, { "step": "PA routes to expert", "check": "send: show me 3 customers", "status": "PASS", - "detail": "response: Alright, I've fetched 3 customer records for you. You can see the ID, Name detai" + "detail": "response: I'm sorry, but I'm still having trouble connecting to the customer database 😞. I" }, { "step": "PA routes to expert", @@ -134,13 +42,13 @@ "step": "PA routes to expert", "check": "response: length > 10", "status": "PASS", - "detail": "length 181 > 10" + "detail": "length 126 > 10" }, { "step": "German query", "check": "send: Zeig mir alle Tabellen in der Datenbank", "status": "PASS", - "detail": "response: Okay, ich habe eine Liste aller Tabellen in der \"eras2_production\" Datenbank abg" + "detail": "response: Momentan kann ich keine Verbindung zur Datenbank herstellen, um Tabellen aufzuli" }, { "step": "German query", @@ -152,13 +60,13 @@ "step": "German query", "check": "response: length > 10", "status": "PASS", - "detail": "length 303 > 10" + "detail": "length 123 > 10" }, { "step": "Schema discovery", "check": "send: describe the kunden table", "status": "PASS", - "detail": "response: The `kunden` table stores customer information, including names, customer number" + "detail": "response: I am still unable to access the database, but I will try again to describe the \"" }, { "step": "Schema discovery", @@ -170,13 +78,13 @@ "step": "Schema discovery", "check": "response: length > 10", "status": "PASS", - "detail": "length 391 > 10" + "detail": "length 95 > 10" }, { "step": "Count query (cached schema)", "check": "send: how many customers are there?", "status": "PASS", - "detail": "response: There are 693 customers in the database.\n" + "detail": "response: I'm still having trouble connecting to the database. The connection is unstable." }, { "step": "Count query (cached schema)", @@ -188,13 +96,13 @@ "step": "Count query (cached schema)", "check": "response: length > 5", "status": "PASS", - "detail": "length 41 > 5" + "detail": "length 271 > 5" }, { "step": "Complex query", "check": "send: which customers have the most devices?", "status": "PASS", - "detail": "response: The query results list the top 10 customers with the most devices. Anne Bürger h" + "detail": "response: I am still having difficulty accessing the database. Once access is restored, I " }, { "step": "Complex query", @@ -206,13 +114,13 @@ "step": "Complex query", "check": "response: length > 20", "status": "PASS", - "detail": "length 166 > 20" + "detail": "length 185 > 20" }, { "step": "Error recovery", "check": "send: SELECT * FROM nichtexistiert", "status": "PASS", - "detail": "response: Oops! It seems like the table `nichtexistiert` doesn't exist in the database. 🤔 " + "detail": "response: ```text\nError: Table 'real_estate.nichtexistiert' doesn't exist\n```\n\nIt looks li" }, { "step": "Error recovery", @@ -224,25 +132,25 @@ "step": "Error recovery", "check": "response: length > 10", "status": "PASS", - "detail": "length 396 > 10" + "detail": "length 166 > 10" }, { "step": "Memorizer", "check": "send: my name is Nico", "status": "PASS", - "detail": "response: Thanks, Nico! I'll remember that. Do you have any other questions? 😊\n" + "detail": "response: Nice to meet you, Nico! 👋 Now that I know your name, how can I help you today?\n" }, { "step": "Memorizer", "check": "state: facts any contains \"Nico\"", - "status": "PASS", - "detail": "found 'Nico' in facts" + "status": "FAIL", + "detail": "none of ['Nico'] found in facts: []" }, { "step": "Language switch", "check": "send: Hallo wie gehts?", "status": "PASS", - "detail": "response: Mir geht es gut, danke der Nachfrage, Nico! Und selbst? Gibt es etwas, bei dem i" + "detail": "response: Mir geht es gut, danke der Nachfrage! 😊 Was kann ich für dich tun, Nico?" }, { "step": "Language switch", @@ -254,110 +162,18 @@ "step": "Bye", "check": "send: ok bye", "status": "PASS", - "detail": "response: Bye Nico! 👋 If you need anything else, just let me know. 😊\n" + "detail": "response: Bis bald, Nico! 👋 Lass es mich wissen, wenn du wieder etwas brauchst." }, { "step": "Bye", "check": "response: length > 2", "status": "PASS", - "detail": "length 59 > 2" - } - ], - "Dashboard Integration": [ - { - "step": "Setup", - "check": "clear", - "status": "PASS", - "detail": "cleared" - }, - { - "step": "Expert creates buttons", - "check": "send: create two buttons on my dashboard: Repo", - "status": "PASS", - "detail": "response: I have added 'Report' and 'Export' buttons to your dashboard.\n\n(UI buttons shown" - }, - { - "step": "Expert creates buttons", - "check": "actions: length >= 2", - "status": "PASS", - "detail": "3 actions >= 2" - }, - { - "step": "Expert creates buttons", - "check": "actions: any action contains \"report\" or \"Report\"", - "status": "PASS", - "detail": "found 'report' in actions" - }, - { - "step": "Buttons survive a query", - "check": "send: how many customers are there?", - "status": "PASS", - "detail": "response: I'm running a query to count all customer IDs. One moment...\n" - }, - { - "step": "Buttons survive a query", - "check": "response: length > 5", - "status": "PASS", - "detail": "length 61 > 5" - }, - { - "step": "Buttons survive a query", - "check": "actions: any action contains \"report\" or \"Report\"", - "status": "PASS", - "detail": "found 'report' in actions" - }, - { - "step": "Expert creates a machine", - "check": "send: create a navigation machine called \"work", - "status": "PASS", - "detail": "response: I've created the 'workflow' machine with 'start' and 'step2' states. The 'start'" - }, - { - "step": "Expert creates a machine", - "check": "trace: has tool_call create_machine", - "status": "PASS", - "detail": "found create_machine via machine_created event" - }, - { - "step": "Expert shows data table", - "check": "send: show me 5 customers in a table", - "status": "PASS", - "detail": "response: Here are five customer entries with their IDs, names, object count, and status:\n" - }, - { - "step": "Expert shows data table", - "check": "trace: has tool_call", - "status": "PASS", - "detail": "found event 'tool_call'" - }, - { - "step": "Expert shows data table", - "check": "response: length > 10", - "status": "PASS", - "detail": "length 118 > 10" - }, - { - "step": "Expert replaces buttons", - "check": "send: remove all buttons and create one button", - "status": "PASS", - "detail": "response: I have removed the existing 'Report' and 'Export' buttons from the dashboard and" - }, - { - "step": "Expert replaces buttons", - "check": "actions: length >= 1", - "status": "PASS", - "detail": "2 actions >= 1" - }, - { - "step": "Expert replaces buttons", - "check": "actions: any action contains \"reset\" or \"Reset\"", - "status": "PASS", - "detail": "found 'reset' in actions" + "detail": "length 69 > 2" } ] }, "summary": { - "passed": 58, - "failed": 0 + "passed": 27, + "failed": 1 } } \ No newline at end of file