from __future__ import annotations

import hashlib
import difflib
import io
import json
import mimetypes
import re
import sqlite3
import tempfile
import threading
import time
import uuid
import zipfile
from concurrent.futures import ThreadPoolExecutor, as_completed
from contextlib import closing, suppress
from pathlib import Path
from typing import Any, Callable

from flask import Blueprint, Response, current_app, jsonify, request, send_file, session

from .db import connect, json_text, transaction
from .models import build_profiles, normalise_preferences
from .provider import ProviderError, build_payload, complete_together, fake_stream, fake_tool_completion, stream_together
from .tool_runtime import TOOL_DEFINITIONS, ToolRuntimeError, execute_tool, provider_tools, registry_payload, resolve_workspace_path, safe_relative_path


def uid(prefix: str) -> str:
    return f"{prefix}_{uuid.uuid4().hex}"


def api_error(code: str, message: str, status: int, details: dict[str, Any] | None = None):
    return jsonify({"error": {"code": code, "message": message, "retryable": False, "details": details or {}, "request_id": uid("req")}}), status


def _db():
    return connect(current_app.config["DATABASE"])


def require_user(fn: Callable):
    def wrapped(*args, **kwargs):
        user_id = session.get("user_id")
        if not user_id:
            return api_error("KIMU_AUTH_REQUIRED", "Sign in is required.", 401)
        with closing(_db()) as db:
            user = db.execute("SELECT id,username,role FROM users WHERE id=?", (user_id,)).fetchone()
        if not user:
            return api_error("KIMU_AUTH_REQUIRED", "Sign in is required.", 401)
        return fn(str(user_id), *args, **kwargs)
    wrapped.__name__ = fn.__name__
    return wrapped


def _audit(db, user_id: str, action: str, target_type: str | None = None, target_id: str | None = None, detail: dict[str, Any] | None = None):
    db.execute(
        "INSERT INTO audit_log(user_id,action,target_type,target_id,detail_json) VALUES(?,?,?,?,?)",
        (user_id, action, target_type, target_id, json_text(detail or {})),
    )


def _append_event(db, table: str, foreign_key: str, entity_id: str, event_type: str, data: dict[str, Any]) -> int:
    seq = db.execute(f"SELECT COALESCE(MAX(seq),0)+1 FROM {table} WHERE {foreign_key}=?", (entity_id,)).fetchone()[0]
    db.execute(
        f"INSERT INTO {table}({foreign_key},seq,event_type,data_json) VALUES(?,?,?,?)",
        (entity_id, int(seq), event_type, json_text(data)),
    )
    return int(seq)


def _workspace_root(app, user_id: str, workspace_id: str) -> Path:
    root = Path(app.config["INSTANCE_DIR"]) / "workspaces" / user_id / workspace_id
    root.mkdir(parents=True, exist_ok=True)
    return root.resolve()


def _workspace_value(row) -> dict[str, Any]:
    return {"id": row["id"], "name": row["name"], "kind": row["kind"], "created_at": row["created_at"], "updated_at": row["updated_at"]}


def _operation_value(row) -> dict[str, Any]:
    return {
        "id": row["id"], "workspace_id": row["workspace_id"], "tool_id": row["tool_id"], "tool_version": int(row["tool_version"]),
        "risk_class": row["risk_class"], "status": row["status"], "arguments": json.loads(row["arguments_json"] or "{}"),
        "result": json.loads(row["result_json"] or "{}"), "error": json.loads(row["error_json"] or "{}") or None,
        "approval_required": bool(row["approval_required"]), "approved_at": row["approved_at"], "actor_type": row["actor_type"],
        "created_at": row["created_at"], "updated_at": row["updated_at"],
    }


def _execute_operation(app, operation_id: str) -> None:
    parent_session_id: str | None = None
    completed = False
    with closing(connect(app.config["DATABASE"])) as db:
        row = db.execute("SELECT * FROM tool_operations WHERE id=?", (operation_id,)).fetchone()
        if not row or row["status"] not in {"queued", "running"}:
            return
        parent_session_id = str(row["parent_session_id"]) if row["parent_session_id"] else None
        definition = TOOL_DEFINITIONS.get(row["tool_id"])
        workspace = db.execute("SELECT * FROM workspaces WHERE id=? AND user_id=?", (row["workspace_id"], row["user_id"])).fetchone()
        if not definition or not workspace:
            db.execute("UPDATE tool_operations SET status='failed',error_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text({"code": "KIMU_TOOL_CONFIGURATION", "message": "Tool or workspace is unavailable."}), operation_id))
            return
        db.execute("UPDATE tool_operations SET status='running',updated_at=CURRENT_TIMESTAMP WHERE id=?", (operation_id,))
        _append_event(db, "tool_events", "operation_id", operation_id, "status", {"status": "running"})
        root = _workspace_root(app, row["user_id"], row["workspace_id"])
        try:
            result = execute_tool(
                definition,
                root,
                json.loads(row["arguments_json"] or "{}"),
                cancel_check=lambda: bool(db.execute("SELECT cancel_requested FROM tool_operations WHERE id=?", (operation_id,)).fetchone()[0]),
            )
            if db.execute("SELECT cancel_requested FROM tool_operations WHERE id=?", (operation_id,)).fetchone()[0]:
                db.execute("UPDATE tool_operations SET status='cancelled',updated_at=CURRENT_TIMESTAMP WHERE id=?", (operation_id,))
                _append_event(db, "tool_events", "operation_id", operation_id, "cancelled", {"status": "cancelled"})
                return
            db.execute("UPDATE tool_operations SET status='successful',result_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text(result), operation_id))
            _append_event(db, "tool_events", "operation_id", operation_id, "result", result)
            _audit(db, row["user_id"], "tool.completed", "tool_operation", operation_id, {"tool_id": definition.id, "workspace_id": row["workspace_id"]})
            completed = True
        except ToolRuntimeError as exc:
            status = "cancelled" if exc.code == "KIMU_TOOL_CANCELLED" else "failed"
            error = {"code": exc.code, "message": str(exc), "details": exc.details}
            db.execute("UPDATE tool_operations SET status=?,error_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (status, json_text(error), operation_id))
            _append_event(db, "tool_events", "operation_id", operation_id, "error", error)
        except Exception as exc:  # pragma: no cover - defensive runtime boundary
            error = {"code": "KIMU_TOOL_INTERNAL", "message": str(exc)}
            db.execute("UPDATE tool_operations SET status='failed',error_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text(error), operation_id))
            _append_event(db, "tool_events", "operation_id", operation_id, "error", error)
    # Approved model-driven tool calls resume automatically after the audited tool reaches a terminal state.
    if parent_session_id and completed:
        with closing(connect(app.config["DATABASE"])) as db:
            db.execute("UPDATE tool_agent_sessions SET status='queued',updated_at=CURRENT_TIMESTAMP WHERE id=? AND status='awaiting_approval'", (parent_session_id,))
            _append_tool_agent_step(db, parent_session_id, "approval.executed", {"operation_id": operation_id})
        _start_tool_agent(app, parent_session_id)

def _start_operation(app, operation_id: str) -> None:
    threading.Thread(target=_execute_operation, args=(app, operation_id), daemon=True, name=f"kimu-tool-{operation_id[-8:]}").start()


def _execute_agent_tool(db, user_id: str, workspace_id: str, tool_id: str, root: Path, arguments: dict[str, Any], idempotency_key: str) -> tuple[str, dict[str, Any]]:
    """Execute a bounded swarm tool while preserving agent-attributed operation evidence."""
    definition = TOOL_DEFINITIONS[tool_id]
    existing = db.execute(
        "SELECT * FROM tool_operations WHERE user_id=? AND idempotency_key=?",
        (user_id, idempotency_key),
    ).fetchone()
    if existing and existing["status"] == "successful":
        return str(existing["id"]), json.loads(existing["result_json"] or "{}")
    operation_id = str(existing["id"]) if existing else uid("top")
    if existing:
        db.execute(
            "UPDATE tool_operations SET status='running',arguments_json=?,result_json='{}',error_json='{}',cancel_requested=0,approved_at=CURRENT_TIMESTAMP,updated_at=CURRENT_TIMESTAMP WHERE id=?",
            (json_text(arguments), operation_id),
        )
    else:
        db.execute(
            "INSERT INTO tool_operations(id,user_id,workspace_id,tool_id,tool_version,risk_class,status,arguments_json,approval_required,approved_at,idempotency_key,actor_type) VALUES(?,?,?,?,?,?,'running',?,0,CURRENT_TIMESTAMP,?,'agent')",
            (operation_id, user_id, workspace_id, tool_id, definition.version, definition.risk_class, json_text(arguments), idempotency_key),
        )
    _append_event(db, "tool_events", "operation_id", operation_id, "status", {"status": "running", "actor_type": "agent"})
    try:
        result = execute_tool(definition, root, arguments)
        db.execute(
            "UPDATE tool_operations SET status='successful',result_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?",
            (json_text(result), operation_id),
        )
        _append_event(db, "tool_events", "operation_id", operation_id, "result", result)
        _audit(db, user_id, "tool.completed", "tool_operation", operation_id, {"tool_id": tool_id, "workspace_id": workspace_id, "actor_type": "agent"})
        return operation_id, result
    except Exception as exc:
        error = {"code": getattr(exc, "code", "KIMU_TOOL_INTERNAL"), "message": str(exc)}
        db.execute(
            "UPDATE tool_operations SET status='failed',error_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?",
            (json_text(error), operation_id),
        )
        _append_event(db, "tool_events", "operation_id", operation_id, "error", error)
        raise



def _append_tool_agent_step(db, session_id: str, step_type: str, data: dict[str, Any]) -> int:
    sequence = db.execute("SELECT COALESCE(MAX(sequence),0)+1 FROM tool_agent_steps WHERE session_id=?", (session_id,)).fetchone()[0]
    db.execute("INSERT INTO tool_agent_steps(session_id,sequence,step_type,data_json) VALUES(?,?,?,?)", (session_id, int(sequence), step_type, json_text(data)))
    return int(sequence)


def _tool_agent_value(db, row, include_steps: bool = False) -> dict[str, Any]:
    value = {
        "id": row["id"], "workspace_id": row["workspace_id"], "model_key": row["model_key"],
        "approval_mode": row["approval_mode"], "status": row["status"], "prompt": row["prompt"],
        "max_steps": int(row["max_steps"]), "used_steps": int(row["used_steps"]),
        "max_tool_calls": int(row["max_tool_calls"]), "used_tool_calls": int(row["used_tool_calls"]),
        "current_operation_id": row["current_operation_id"],
        "result": json.loads(row["result_json"] or "{}"), "error": json.loads(row["error_json"] or "{}") or None,
        "created_at": row["created_at"], "updated_at": row["updated_at"],
    }
    if include_steps:
        value["steps"] = [
            {"sequence": int(item["sequence"]), "type": item["step_type"], "data": json.loads(item["data_json"] or "{}"), "created_at": item["created_at"]}
            for item in db.execute("SELECT * FROM tool_agent_steps WHERE session_id=? ORDER BY sequence", (row["id"],)).fetchall()
        ]
    return value


def _tool_policy(db, user_id: str, workspace_id: str, tool_id: str, mode: str) -> str:
    row = db.execute("SELECT decision FROM tool_policies WHERE user_id=? AND workspace_id=? AND tool_id=?", (user_id, workspace_id, tool_id)).fetchone()
    if row:
        return str(row["decision"])
    definition = TOOL_DEFINITIONS[tool_id]
    if mode == "manual":
        return "ask" if definition.risk_class != "read" else "allow"
    if mode == "autonomous":
        return "ask" if definition.risk_class in {"destructive", "external"} else "allow"
    return "ask" if definition.approval_required else "allow"


def _run_tool_agent(app, session_id: str) -> None:
    with closing(connect(app.config["DATABASE"])) as db:
        row = db.execute("SELECT * FROM tool_agent_sessions WHERE id=?", (session_id,)).fetchone()
        if not row or row["status"] in {"successful", "failed", "cancelled"}:
            return
        db.execute("UPDATE tool_agent_sessions SET status='running',updated_at=CURRENT_TIMESTAMP WHERE id=?", (session_id,))
        messages = json.loads(row["messages_json"] or "[]")
        if not messages:
            messages = [
                {"role": "system", "content": "You are KIMU's bounded workspace tool agent. Use only supplied tools. Never invent execution evidence. Finish with a concise result."},
                {"role": "user", "content": row["prompt"]},
            ]
        workspace = db.execute("SELECT * FROM workspaces WHERE id=? AND user_id=?", (row["workspace_id"], row["user_id"])).fetchone()
        if not workspace:
            db.execute("UPDATE tool_agent_sessions SET status='failed',error_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text({"code": "KIMU_WORKSPACE_NOT_FOUND", "message": "Workspace not found."}), session_id))
            return
        root = _workspace_root(app, row["user_id"], row["workspace_id"])
        # If this is a resume, append the completed approved operation as a tool result.
        if row["current_operation_id"]:
            operation = db.execute("SELECT * FROM tool_operations WHERE id=?", (row["current_operation_id"],)).fetchone()
            if not operation or operation["status"] not in {"successful", "rejected", "cancelled", "failed"}:
                db.execute("UPDATE tool_agent_sessions SET status='awaiting_approval',updated_at=CURRENT_TIMESTAMP WHERE id=?", (session_id,))
                return
            if operation["status"] != "successful":
                error = {"code": "KIMU_TOOL_AGENT_APPROVAL_STOP", "message": f"The pending tool operation ended as {operation['status']}."}
                db.execute("UPDATE tool_agent_sessions SET status='failed',error_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text(error), session_id))
                _append_tool_agent_step(db, session_id, "approval.stopped", error)
                return
            result = json.loads(operation["result_json"] or "{}")
            call_id = None
            for message in reversed(messages):
                calls = message.get("tool_calls") if isinstance(message, dict) else None
                if calls:
                    call_id = calls[0].get("id")
                    break
            messages.append({"role": "tool", "tool_call_id": call_id or operation["id"], "name": operation["tool_id"], "content": json.dumps(result, ensure_ascii=False)[:200000]})
            db.execute("UPDATE tool_agent_sessions SET current_operation_id=NULL,messages_json=?,used_tool_calls=used_tool_calls+1,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text(messages), session_id))
            _append_tool_agent_step(db, session_id, "tool.result", {"operation_id": operation["id"], "tool_id": operation["tool_id"], "result": result})

        while True:
            current = db.execute("SELECT * FROM tool_agent_sessions WHERE id=?", (session_id,)).fetchone()
            if current["cancel_requested"]:
                db.execute("UPDATE tool_agent_sessions SET status='cancelled',updated_at=CURRENT_TIMESTAMP WHERE id=?", (session_id,))
                _append_tool_agent_step(db, session_id, "cancelled", {})
                return
            if int(current["used_steps"]) >= int(current["max_steps"]):
                result = {"message": "The bounded tool loop reached its step limit.", "messages": messages[-8:]}
                db.execute("UPDATE tool_agent_sessions SET status='partial',result_json=?,messages_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text(result), json_text(messages), session_id))
                _append_tool_agent_step(db, session_id, "budget.steps", result)
                return
            if int(current["used_tool_calls"]) >= int(current["max_tool_calls"]):
                error = {"code": "KIMU_TOOL_AGENT_BUDGET", "message": "The tool-call budget was exhausted."}
                db.execute("UPDATE tool_agent_sessions SET status='failed',error_json=?,messages_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text(error), json_text(messages), session_id))
                _append_tool_agent_step(db, session_id, "budget.tools", error)
                return
            profile = build_profiles(app.config)[current["model_key"]]
            preferences = normalise_preferences(profile, None)
            payload = build_payload(profile.model_id, messages, preferences, current["model_key"])
            payload.update({"tools": provider_tools(), "tool_choice": "auto", "parallel_tool_calls": False})
            try:
                completion = fake_tool_completion(messages, payload["tools"]) if app.config["FAKE_PROVIDER"] else complete_together(app.config["TOGETHER_BASE_URL"], app.config["TOGETHER_API_KEY"], payload)
            except Exception as exc:
                error = {"code": getattr(exc, "code", "KIMU_TOOL_AGENT_PROVIDER"), "message": str(exc)}
                db.execute("UPDATE tool_agent_sessions SET status='failed',error_json=?,messages_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text(error), json_text(messages), session_id))
                _append_tool_agent_step(db, session_id, "provider.error", error)
                return
            assistant = completion["message"]
            messages.append(assistant)
            usage = completion.get("usage") or {}
            db.execute("UPDATE tool_agent_sessions SET used_steps=used_steps+1,messages_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text(messages), session_id))
            _append_tool_agent_step(db, session_id, "model", {"message": assistant, "usage": usage})
            calls = assistant.get("tool_calls") or []
            if not calls:
                result = {"text": str(assistant.get("content") or "").strip(), "usage": usage}
                db.execute("UPDATE tool_agent_sessions SET status='successful',result_json=?,messages_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text(result), json_text(messages), session_id))
                _append_tool_agent_step(db, session_id, "done", result)
                _audit(db, row["user_id"], "tool_agent.completed", "tool_agent_session", session_id, {"workspace_id": row["workspace_id"]})
                return
            call = calls[0]
            function = call.get("function") or {}
            tool_id = str(function.get("name") or "")
            definition = TOOL_DEFINITIONS.get(tool_id)
            if not definition:
                error = {"code": "KIMU_TOOL_UNKNOWN", "message": f"The model requested unknown tool {tool_id}."}
                db.execute("UPDATE tool_agent_sessions SET status='failed',error_json=?,messages_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text(error), json_text(messages), session_id))
                _append_tool_agent_step(db, session_id, "tool.invalid", error)
                return
            try:
                arguments = json.loads(function.get("arguments") or "{}")
                from .tool_runtime import validate_arguments
                arguments = validate_arguments(definition, arguments)
            except Exception as exc:
                error = {"code": getattr(exc, "code", "KIMU_TOOL_ARGUMENTS_INVALID"), "message": str(exc)}
                db.execute("UPDATE tool_agent_sessions SET status='failed',error_json=?,messages_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text(error), json_text(messages), session_id))
                _append_tool_agent_step(db, session_id, "tool.invalid", error)
                return
            decision = _tool_policy(db, row["user_id"], row["workspace_id"], tool_id, current["approval_mode"])
            if decision == "deny":
                error = {"code": "KIMU_TOOL_POLICY_DENIED", "message": f"Policy denied {tool_id}."}
                db.execute("UPDATE tool_agent_sessions SET status='failed',error_json=?,messages_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text(error), json_text(messages), session_id))
                _append_tool_agent_step(db, session_id, "tool.denied", {"tool_id": tool_id})
                return
            idempotency_key = f"tool-agent:{session_id}:{int(current['used_steps'])}:{call.get('id') or tool_id}"
            if decision == "ask":
                operation_id = uid("top")
                db.execute("INSERT INTO tool_operations(id,user_id,workspace_id,tool_id,tool_version,risk_class,status,arguments_json,approval_required,idempotency_key,actor_type,parent_session_id) VALUES(?,?,?,?,?,?,'awaiting_approval',?,1,?,'agent',?)", (operation_id, row["user_id"], row["workspace_id"], tool_id, definition.version, definition.risk_class, json_text(arguments), idempotency_key, session_id))
                _append_event(db, "tool_events", "operation_id", operation_id, "status", {"status": "awaiting_approval", "parent_session_id": session_id})
                db.execute("UPDATE tool_agent_sessions SET status='awaiting_approval',current_operation_id=?,messages_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (operation_id, json_text(messages), session_id))
                _append_tool_agent_step(db, session_id, "tool.awaiting_approval", {"operation_id": operation_id, "tool_id": tool_id, "arguments": arguments})
                return
            try:
                operation_id, result = _execute_agent_tool(db, row["user_id"], row["workspace_id"], tool_id, root, arguments, idempotency_key)
                db.execute("UPDATE tool_operations SET parent_session_id=? WHERE id=?", (session_id, operation_id))
                messages.append({"role": "tool", "tool_call_id": call.get("id") or operation_id, "name": tool_id, "content": json.dumps(result, ensure_ascii=False)[:200000]})
                db.execute("UPDATE tool_agent_sessions SET used_tool_calls=used_tool_calls+1,messages_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text(messages), session_id))
                _append_tool_agent_step(db, session_id, "tool.result", {"operation_id": operation_id, "tool_id": tool_id, "result": result})
            except Exception as exc:
                error = {"code": getattr(exc, "code", "KIMU_TOOL_FAILED"), "message": str(exc)}
                db.execute("UPDATE tool_agent_sessions SET status='failed',error_json=?,messages_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text(error), json_text(messages), session_id))
                _append_tool_agent_step(db, session_id, "tool.error", error)
                return


def _start_tool_agent(app, session_id: str) -> None:
    threading.Thread(target=_run_tool_agent, args=(app, session_id), daemon=True, name=f"kimu-tool-agent-{session_id[-8:]}").start()


def _starter_files(name: str, project_type: str, brief: str) -> dict[str, str]:
    safe_name = re.sub(r"[^A-Za-z0-9 _-]+", "", name).strip() or "New Website"
    title = safe_name.replace("<", "").replace(">", "")
    description = (brief.strip() or f"A modern mobile-first website for {title}.")[:500]
    css = """:root{font-family:Inter,system-ui,sans-serif;color:#17191d;background:#f7f8fa}*{box-sizing:border-box}body{margin:0}header{position:sticky;top:0;background:#ffffffee;backdrop-filter:blur(14px);border-bottom:1px solid #e4e7ec;padding:16px 20px;display:flex;justify-content:space-between;align-items:center}main{max-width:980px;margin:auto;padding:48px 20px}.hero{min-height:68vh;display:grid;align-content:center;gap:18px}.eyebrow{letter-spacing:.12em;text-transform:uppercase;font-size:.75rem;color:#687080}h1{font-size:clamp(2.5rem,10vw,5.8rem);line-height:.94;margin:0;max-width:900px}.lead{font-size:clamp(1.05rem,3vw,1.35rem);line-height:1.6;color:#555d69;max-width:680px}.actions{display:flex;gap:12px;flex-wrap:wrap}.button{display:inline-flex;padding:13px 18px;border-radius:14px;background:#17191d;color:white;text-decoration:none;font-weight:700}.button.alt{background:white;color:#17191d;border:1px solid #d8dde5}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:14px}.card{background:white;border:1px solid #e0e4ea;border-radius:20px;padding:20px;box-shadow:0 12px 30px #20242a0a}footer{padding:30px 20px;color:#687080;text-align:center}@media(max-width:560px){header{padding:13px 15px}main{padding:30px 16px}.hero{min-height:72vh}.actions{display:grid}.button{justify-content:center}}"""
    html = f"""<!doctype html><html lang=\"en-GB\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><meta name=\"description\" content=\"{description}\"><title>{title}</title><link rel=\"stylesheet\" href=\"styles.css\"></head><body><header><strong>{title}</strong><a href=\"#contact\">Contact</a></header><main><section class=\"hero\"><span class=\"eyebrow\">Mobile-first website</span><h1>{title}</h1><p class=\"lead\">{description}</p><div class=\"actions\"><a class=\"button\" href=\"#features\">Explore</a><a class=\"button alt\" href=\"#contact\">Get in touch</a></div></section><section id=\"features\" class=\"grid\"><article class=\"card\"><h2>Fast</h2><p>Lightweight, responsive and ready to deploy.</p></article><article class=\"card\"><h2>Clear</h2><p>A focused information hierarchy for small screens.</p></article><article class=\"card\"><h2>Editable</h2><p>Every file remains available in the KIMU builder.</p></article></section><section id=\"contact\" class=\"hero\"><span class=\"eyebrow\">Contact</span><h2>Start the conversation.</h2><p class=\"lead\">Replace this section with your contact details or form integration.</p></section></main><footer>Built with KIMU Website Builder.</footer><script src=\"app.js\"></script></body></html>"""
    js = "document.documentElement.dataset.kimuBuilder='ready';\n"
    if project_type == "react":
        return {
            "index.html": html.replace('<script src="app.js"></script>', '<div id="app-note" class="card">Vendored React project shell. Add the approved React runtime during export.</div><script src="app.js"></script>'),
            "styles.css": css,
            "app.js": js + "document.querySelector('#app-note')?.setAttribute('data-ready','true');\n",
            "README.md": f"# {title}\n\nVendored React-compatible website project created by KIMU.\n",
        }
    return {"index.html": html, "styles.css": css, "app.js": js, "README.md": f"# {title}\n\nStatic website project created by KIMU.\n"}



def _website_slug(value: str) -> str:
    slug = re.sub(r"[^a-z0-9]+", "-", str(value or "").lower()).strip("-")
    return slug or "page"


def _starter_files(name: str, project_type: str, brief: str, requirements: dict[str, Any] | None = None, theme: dict[str, Any] | None = None) -> dict[str, str]:
    """Create a complete multi-page, mobile-first starter from the visual wizard."""
    requirements = requirements or {}
    theme = theme or {}
    title = re.sub(r"[^A-Za-z0-9 &'-]+", "", name).strip() or "New Website"
    description = (brief.strip() or f"A modern mobile-first website for {title}.")[:500]
    pages = requirements.get("pages") if isinstance(requirements.get("pages"), list) else ["Home", "About", "Services", "Contact"]
    pages = [str(item).strip()[:60] for item in pages if str(item).strip()][:12] or ["Home"]
    features = requirements.get("features") if isinstance(requirements.get("features"), list) else []
    primary = re.sub(r"[^#a-fA-F0-9(),.%\\s-]", "", str(theme.get("primary") or "#17191d"))[:40]
    accent = re.sub(r"[^#a-fA-F0-9(),.%\\s-]", "", str(theme.get("accent") or "#eef1f5"))[:40]
    radius = min(32, max(0, int(theme.get("radius") or 18)))
    density = str(theme.get("density") or "comfortable")
    spacing = "14px" if density == "compact" else "20px"
    nav = []
    page_map: list[tuple[str, str]] = []
    for index, page in enumerate(pages):
        filename = "index.html" if index == 0 or page.lower() == "home" else f"{_website_slug(page)}.html"
        page_map.append((page, filename))
        nav.append(f'<a href="{filename}">{page}</a>')
    nav_html = "".join(nav)
    css = f":root{{--primary:{primary};--accent:{accent};--radius:{radius}px;--space:{spacing};font-family:Inter,system-ui,-apple-system,sans-serif;color:#17191d;background:#f7f8fa}}*{{box-sizing:border-box}}body{{margin:0}}a{{color:inherit}}header{{position:sticky;top:0;z-index:10;background:#ffffffed;backdrop-filter:blur(16px);border-bottom:1px solid #e1e5eb;padding:14px max(16px,calc((100vw - 1080px)/2));display:flex;gap:18px;align-items:center;justify-content:space-between}}nav{{display:flex;gap:8px;overflow:auto}}nav a{{text-decoration:none;padding:8px 10px;border-radius:999px;white-space:nowrap}}nav a[aria-current=page]{{background:var(--accent)}}main{{max-width:1080px;margin:auto;padding:48px 20px}}.hero{{min-height:64vh;display:grid;align-content:center;gap:18px}}.eyebrow{{letter-spacing:.12em;text-transform:uppercase;font-size:.76rem;color:#687080}}h1{{font-size:clamp(2.5rem,9vw,5.7rem);line-height:.96;margin:0;max-width:900px}}h2{{font-size:clamp(1.8rem,5vw,3rem)}}.lead{{font-size:clamp(1.05rem,3vw,1.35rem);line-height:1.6;color:#555d69;max-width:720px}}.button{{display:inline-flex;padding:13px 18px;border-radius:var(--radius);background:var(--primary);color:white;text-decoration:none;font-weight:750}}.grid{{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:var(--space)}}.card{{background:white;border:1px solid #e0e4ea;border-radius:var(--radius);padding:var(--space);box-shadow:0 12px 30px #20242a0a}}form{{display:grid;gap:14px;max-width:680px}}input,textarea{{width:100%;font:inherit;padding:13px;border:1px solid #cfd5dd;border-radius:12px}}footer{{padding:32px 20px;color:#687080;text-align:center}}@media(max-width:640px){{header{{align-items:flex-start;flex-direction:column;padding:12px 16px}}main{{padding:30px 16px}}.hero{{min-height:66vh}}}}"
    files: dict[str, str] = {"styles.css": css, "app.js": "document.documentElement.dataset.kimuBuilder='ready';\n", "README.md": f"# {title}\n\nGenerated by the KIMU visual website wizard.\n"}
    for index, (page, filename) in enumerate(page_map):
        is_contact = page.lower() == "contact" or ("contact-form" in features and index == len(page_map)-1)
        labels = ["Fast", "Clear", "Editable"] if index == 0 else [f"{page} section one", f"{page} section two", f"{page} section three"]
        cards = "".join(f'<article class="card"><h2>{label}</h2><p>Replace this guided content in the KIMU editor.</p></article>' for label in labels)
        form = '<form><label>Name<input name="name" autocomplete="name"></label><label>Email<input name="email" type="email" autocomplete="email"></label><label>Message<textarea name="message" rows="5"></textarea></label><button class="button" type="submit">Send enquiry</button></form>' if is_contact else ""
        current_nav = nav_html.replace(f'href="{filename}"', f'href="{filename}" aria-current="page"')
        html = f'<!doctype html><html lang="en-GB"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="description" content="{description}"><title>{page} - {title}</title><link rel="stylesheet" href="styles.css"></head><body><header><strong>{title}</strong><nav aria-label="Primary">{current_nav}</nav></header><main><section class="hero"><span class="eyebrow">{page}</span><h1>{title}</h1><p class="lead">{description}</p><a class="button" href="{page_map[-1][1]}">Get started</a></section><section class="grid">{cards}</section>{form}</main><footer>Built with KIMU Website Builder.</footer><script src="app.js"></script></body></html>'
        files[filename] = html
    if "pwa" in features:
        manifest = {
            "name": title, "short_name": title[:24], "start_url": "./index.html", "scope": "./",
            "display": "standalone", "background_color": "#f7f8fa", "theme_color": primary,
            "icons": [{"src": "icon.svg", "sizes": "any", "type": "image/svg+xml", "purpose": "any maskable"}],
        }
        files["manifest.webmanifest"] = json.dumps(manifest, ensure_ascii=False, indent=2)
        files["icon.svg"] = f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><rect width="512" height="512" rx="112" fill="{primary}"/><text x="256" y="320" text-anchor="middle" font-size="230" font-family="system-ui" fill="white">{title[:1].upper()}</text></svg>'
        files["sw.js"] = "const CACHE='site-v1';const CORE=['./','./index.html','./styles.css','./app.js','./manifest.webmanifest','./icon.svg'];self.addEventListener('install',e=>e.waitUntil(caches.open(CACHE).then(c=>c.addAll(CORE))));self.addEventListener('activate',e=>e.waitUntil(caches.keys().then(keys=>Promise.all(keys.filter(k=>k!==CACHE).map(k=>caches.delete(k))))));self.addEventListener('fetch',e=>{if(e.request.method==='GET')e.respondWith(caches.match(e.request).then(r=>r||fetch(e.request).then(x=>{const y=x.clone();caches.open(CACHE).then(c=>c.put(e.request,y));return x}).catch(()=>caches.match('./index.html'))))});\n"
        files["app.js"] += "if('serviceWorker' in navigator){window.addEventListener('load',()=>navigator.serviceWorker.register('./sw.js'));}\n"
        for page, filename in page_map:
            files[filename] = files[filename].replace('</head>', '<link rel="manifest" href="manifest.webmanifest"><meta name="theme-color" content="' + primary + '"></head>')
        files["README.md"] += "\nProgressive Web App files and offline shell are enabled.\n"
    if project_type == "react":
        files["README.md"] += "\nProject type: vendored React-compatible. Runtime dependencies must remain local.\n"
    return files


def _save_project_version(db, project_id: str, summary: str) -> int:
    project = db.execute("SELECT current_version FROM website_projects WHERE id=?", (project_id,)).fetchone()
    current = int(project[0]) if project else 0
    next_version = current + 1 if current else 1
    files = db.execute("SELECT path,content,mime_type,sha256 FROM website_files WHERE project_id=? ORDER BY path", (project_id,)).fetchall()
    manifest = [{"path": row["path"], "sha256": row["sha256"], "mime_type": row["mime_type"]} for row in files]
    previous = {}
    if current:
        previous = {row["path"]: dict(row) for row in db.execute("SELECT path,content,mime_type,sha256 FROM website_version_files WHERE project_id=? AND version=?", (project_id, current)).fetchall()}
    current_files = {row["path"]: dict(row) for row in files}
    db.execute("INSERT INTO website_versions(project_id,version,parent_version,summary,manifest_json) VALUES(?,?,?,?,?)", (project_id, next_version, current or None, summary, json_text(manifest)))
    for row in files:
        db.execute("INSERT INTO website_version_files(project_id,version,path,content,mime_type,sha256) VALUES(?,?,?,?,?,?)", (project_id, next_version, row["path"], row["content"], row["mime_type"], row["sha256"]))
    for path in sorted(set(previous) | set(current_files)):
        before = previous.get(path)
        after = current_files.get(path)
        if before and after and before["sha256"] == after["sha256"]:
            continue
        change_type = "added" if after and not before else "deleted" if before and not after else "modified"
        before_lines = str(before["content"] if before else "").splitlines(keepends=True)
        after_lines = str(after["content"] if after else "").splitlines(keepends=True)
        unified = "".join(difflib.unified_diff(before_lines, after_lines, fromfile=f"a/{path}", tofile=f"b/{path}", n=3))
        db.execute("INSERT INTO website_diffs(id,project_id,version,path,change_type,before_sha256,after_sha256,unified_diff) VALUES(?,?,?,?,?,?,?,?)", (uid("wdiff"), project_id, next_version, path, change_type, before["sha256"] if before else None, after["sha256"] if after else None, unified[:500000]))
    db.execute("UPDATE website_projects SET current_version=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (next_version, project_id))
    return next_version


def _project_value(db, row, include_files: bool = False) -> dict[str, Any]:
    value = {
        "id": row["id"], "workspace_id": row["workspace_id"], "name": row["name"], "project_type": row["project_type"],
        "model_key": row["model_key"], "status": row["status"], "requirements": json.loads(row["requirements_json"] or "{}"),
        "theme": json.loads(row["theme_json"] or "{}"), "wizard_stage": int(row["wizard_stage"]),
        "current_version": int(row["current_version"]), "created_at": row["created_at"], "updated_at": row["updated_at"],
        "preview_url": f"/api/v1/websites/{row['id']}/preview/index.html", "export_url": f"/api/v1/websites/{row['id']}/export.zip",
    }
    if include_files:
        value["files"] = [dict(file) for file in db.execute("SELECT path,content,mime_type,sha256,version,updated_at FROM website_files WHERE project_id=? ORDER BY path", (row["id"],)).fetchall()]
        value["versions"] = [dict(version) for version in db.execute("SELECT version,parent_version,summary,created_at FROM website_versions WHERE project_id=? ORDER BY version DESC", (row["id"],)).fetchall()]
        value["diffs"] = [dict(item) for item in db.execute("SELECT id,version,path,change_type,before_sha256,after_sha256,unified_diff,created_at FROM website_diffs WHERE project_id=? ORDER BY version DESC,path LIMIT 300", (row["id"],)).fetchall()]
    return value



def _validate_website_files(files: dict[str, str]) -> dict[str, Any]:
    if not files or "index.html" not in files:
        return {"passed": False, "checked": [], "failures": [{"path": "index.html", "message": "A website project must contain index.html."}]}
    forbidden = ("unpkg.com", "cdn.jsdelivr.net", "cdnjs.cloudflare.com", "fonts.googleapis.com", "fonts.gstatic.com")
    failures: list[dict[str, str]] = []
    normalised: dict[str, str] = {}
    for raw_path, content in files.items():
        try:
            path = safe_relative_path(raw_path).as_posix()
        except ToolRuntimeError as exc:
            failures.append({"path": str(raw_path), "message": str(exc)})
            continue
        if len(content) > 2_000_000:
            failures.append({"path": path, "message": "Website text files are limited to 2,000,000 characters."})
            continue
        if any(host in content for host in forbidden):
            failures.append({"path": path, "message": "Remote CDN dependencies are not allowed."})
        normalised[path] = content
    if failures:
        return {"passed": False, "checked": sorted(normalised), "failures": failures}
    with tempfile.TemporaryDirectory(prefix="kimu-website-check-") as directory:
        root = Path(directory)
        for path, content in normalised.items():
            target = resolve_workspace_path(root, path)
            target.parent.mkdir(parents=True, exist_ok=True)
            target.write_text(content, encoding="utf-8")
        result = execute_tool(TOOL_DEFINITIONS["checks.static"], root, {"path": ".", "limit": 2000})
    return result


def _import_website_zip(body: bytes) -> tuple[dict[str, str], list[str]]:
    if len(body) > 32 * 1024 * 1024:
        raise ToolRuntimeError("KIMU_WEBSITE_IMPORT_TOO_LARGE", "Website ZIP imports are limited to 32 MiB.")
    files: dict[str, str] = {}
    ignored: list[str] = []
    total = 0
    with zipfile.ZipFile(io.BytesIO(body)) as archive:
        infos = archive.infolist()
        if len(infos) > 2000:
            raise ToolRuntimeError("KIMU_WEBSITE_IMPORT_ENTRIES", "Website ZIP imports are limited to 2,000 entries.")
        candidates = [info for info in infos if not info.is_dir()]
        names = [safe_relative_path(info.filename).as_posix() for info in candidates]
        if len(names) != len(set(names)):
            raise ToolRuntimeError("KIMU_WEBSITE_IMPORT_DUPLICATE", "Duplicate file paths are not allowed in website ZIP imports.")
        prefix = ""
        first_parts = {name.split("/", 1)[0] for name in names if "/" in name}
        if len(first_parts) == 1 and all(name.startswith(next(iter(first_parts)) + "/") for name in names):
            prefix = next(iter(first_parts)) + "/"
        for info, original_name in zip(candidates, names):
            mode = (info.external_attr >> 16) & 0o170000
            if mode == 0o120000:
                raise ToolRuntimeError("KIMU_WEBSITE_IMPORT_SYMLINK", "Symbolic links are not allowed in website ZIP imports.")
            total += int(info.file_size)
            if total > 64 * 1024 * 1024:
                raise ToolRuntimeError("KIMU_WEBSITE_IMPORT_EXPANDED", "The expanded website ZIP exceeds 64 MiB.")
            path = original_name[len(prefix):] if prefix and original_name.startswith(prefix) else original_name
            path = safe_relative_path(path).as_posix()
            try:
                raw = archive.read(info)
            except RuntimeError as exc:
                raise ToolRuntimeError("KIMU_WEBSITE_IMPORT_ENCRYPTED", "Encrypted ZIP members are not supported.") from exc
            try:
                text = raw.decode("utf-8")
            except UnicodeDecodeError:
                ignored.append(path)
                continue
            files[path] = text
    validation = _validate_website_files(files)
    if not validation.get("passed"):
        raise ToolRuntimeError("KIMU_WEBSITE_IMPORT_INVALID", "The imported website failed validation.", {"failures": validation.get("failures", [])})
    return files, ignored


def _acquire_file_lease(db, workspace_id: str, swarm_id: str, task_id: str, path: str) -> str:
    token = uid("lease")
    db.execute("DELETE FROM workspace_file_leases WHERE expires_at<=CURRENT_TIMESTAMP")
    try:
        db.execute("INSERT INTO workspace_file_leases(workspace_id,path,swarm_id,task_id,lease_token,expires_at) VALUES(?,?,?,?,?,datetime('now','+10 minutes'))", (workspace_id, path, swarm_id, task_id, token))
    except sqlite3.IntegrityError as exc:
        raise ToolRuntimeError("KIMU_SWARM_FILE_LEASE", f"The file is already leased: {path}") from exc
    db.execute("UPDATE swarm_tasks SET lease_paths_json=? WHERE id=?", (json_text([path]), task_id))
    return token


def _release_file_lease(db, workspace_id: str, path: str, token: str) -> None:
    db.execute("DELETE FROM workspace_file_leases WHERE workspace_id=? AND path=? AND lease_token=?", (workspace_id, path, token))


def _save_swarm_checkpoint(db, swarm_id: str, outputs: dict[str, str]) -> int:
    sequence = int(db.execute("SELECT COALESCE(MAX(sequence),0)+1 FROM swarm_checkpoints WHERE swarm_id=?", (swarm_id,)).fetchone()[0])
    state = {"completed_roles": list(outputs), "output_lengths": {key: len(value) for key, value in outputs.items()}}
    db.execute("INSERT INTO swarm_checkpoints(swarm_id,sequence,state_json) VALUES(?,?,?)", (swarm_id, sequence, json_text(state)))
    return sequence

def _collect_model_text(app, model_key: str, prompt: str, system: str = "") -> str:
    profiles = build_profiles(app.config)
    profile = profiles[model_key]
    if app.config["FAKE_PROVIDER"]:
        return "".join(item["text"] for item in fake_stream(model_key, prompt) if item["type"] == "content")
    if not profile.configured:
        raise ProviderError("KIMU_MODEL_NOT_CONFIGURED", f"{profile.display_name} is not configured.")
    preferences = normalise_preferences(profile, None)
    messages = []
    if system:
        messages.append({"role": "system", "content": system})
    messages.append({"role": "user", "content": prompt})
    payload = build_payload(profile.model_id, messages, preferences, model_key)
    return "".join(item["text"] for item in stream_together(app.config["TOGETHER_BASE_URL"], app.config["TOGETHER_API_KEY"], payload) if item["type"] == "content").strip()


def _swarm_roles() -> list[tuple[str, str, str, list[str]]]:
    # Tester and Reviewer are deliberately independent branches after Builder.
    return [
        ("coordinator", "Clarify objective and create the task graph", "k2.6", []),
        ("architect", "Define architecture, constraints and acceptance criteria", "k2.6", ["coordinator"]),
        ("builder", "Produce the implementation or primary deliverable", "k2.7-code", ["architect"]),
        ("tester", "Test the deliverable and catalogue defects", "k2.7-code", ["builder"]),
        ("reviewer", "Independently review quality, safety and completeness", "k2.6", ["builder"]),
        ("release", "Package the accepted result and evidence", "k2.7-code", ["tester", "reviewer"]),
    ]


def _swarm_requires_approval(mode: str, role: str) -> bool:
    if mode == "manual":
        return True
    if mode == "balanced":
        return role in {"builder", "release"}
    return False


def _run_swarm_task(app, swarm_id: str, task_id: str) -> dict[str, Any]:
    with closing(connect(app.config["DATABASE"])) as db:
        swarm = db.execute("SELECT * FROM swarms WHERE id=?", (swarm_id,)).fetchone()
        task = db.execute("SELECT * FROM swarm_tasks WHERE id=? AND swarm_id=?", (task_id, swarm_id)).fetchone()
        if not swarm or not task:
            return {"task_id": task_id, "status": "missing"}
        if swarm["cancel_requested"]:
            db.execute("UPDATE swarm_tasks SET status='cancelled',updated_at=CURRENT_TIMESTAMP WHERE id=?", (task_id,))
            return {"task_id": task_id, "status": "cancelled"}
        dependencies = json.loads(task["depends_on_json"] or "[]")
        outputs: dict[str, str] = {}
        for item in db.execute("SELECT role,result_json FROM swarm_tasks WHERE swarm_id=? AND status='successful'", (swarm_id,)).fetchall():
            result = json.loads(item["result_json"] or "{}")
            if result.get("text"):
                outputs[item["role"]] = str(result["text"])
        if any(dep not in outputs for dep in dependencies):
            return {"task_id": task_id, "status": "blocked"}
        db.execute("UPDATE swarm_tasks SET status='running',updated_at=CURRENT_TIMESTAMP WHERE id=?", (task_id,))
        _append_event(db, "swarm_events", "swarm_id", swarm_id, "task.started", {"task_id": task_id, "role": task["role"], "iteration": int(task["iteration"])})
        context = "\n\n".join(f"## {role.title()} output\n{text}" for role, text in outputs.items())[-50000:]
        prompt = f"Objective: {swarm['objective']}\n\nYour role: {task['role']}\nTask: {task['title']}\nIteration: {task['iteration']}\n\nPrior verified outputs:\n{context or 'None yet.'}\n\nReturn a concise, actionable result with explicit evidence, risks, blockers and a final VERDICT: PASS or VERDICT: FAIL where applicable."
        try:
            result_text = _collect_model_text(app, task["model_key"], prompt, "You are one controlled KIMU swarm agent. Stay within the assigned role, respect evidence boundaries and never claim unverified execution.")
            if app.config["FAKE_PROVIDER"]:
                result_text = f"{task['role'].title()} completed the controlled test task for: {swarm['objective']}\n\nEvidence mode: fake provider.\n\n{result_text}\n\nVERDICT: PASS"
            estimated_tokens = max(1, (len(prompt) + len(result_text)) // 4)
            fresh = db.execute("SELECT used_tokens,max_tokens,used_tool_calls,max_tool_calls,cancel_requested FROM swarms WHERE id=?", (swarm_id,)).fetchone()
            if fresh["cancel_requested"]:
                raise ToolRuntimeError("KIMU_SWARM_CANCELLED", "The swarm was cancelled.")
            if int(fresh["used_tokens"]) + estimated_tokens > int(fresh["max_tokens"]):
                raise ToolRuntimeError("KIMU_SWARM_TOKEN_BUDGET", "The swarm token budget would be exceeded.")
            if int(fresh["used_tool_calls"]) + 1 > int(fresh["max_tool_calls"]):
                raise ToolRuntimeError("KIMU_SWARM_TOOL_BUDGET", "The swarm tool-call budget would be exceeded.")
            output_path = f"swarm_outputs/{int(task['sequence']):02d}_{task['role']}_i{int(task['iteration'])}.md"
            root = _workspace_root(app, swarm["user_id"], swarm["workspace_id"])
            lease_token = _acquire_file_lease(db, swarm["workspace_id"], swarm_id, task_id, output_path)
            try:
                tool_operation_id, tool_result = _execute_agent_tool(
                    db, str(swarm["user_id"]), str(swarm["workspace_id"]), "workspace.write", root,
                    {"path": output_path, "content": result_text, "expected_sha256": None},
                    f"swarm:{swarm_id}:{task_id}:i{int(task['iteration'])}:workspace.write",
                )
            finally:
                _release_file_lease(db, swarm["workspace_id"], output_path, lease_token)
            with transaction(db):
                db.execute("UPDATE swarm_tasks SET status='successful',result_json=?,lease_paths_json='[]',updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text({"text": result_text, "artifact": output_path, "tool_operation_id": tool_operation_id, "tool_result": tool_result, "estimated_tokens": estimated_tokens}), task_id))
                db.execute("UPDATE swarms SET used_tool_calls=used_tool_calls+1,used_tokens=used_tokens+?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (estimated_tokens, swarm_id))
                completed_outputs = {item["role"]: json.loads(item["result_json"] or "{}").get("text", "") for item in db.execute("SELECT role,result_json FROM swarm_tasks WHERE swarm_id=? AND status='successful'", (swarm_id,)).fetchall()}
                checkpoint = _save_swarm_checkpoint(db, swarm_id, completed_outputs)
                _append_event(db, "swarm_events", "swarm_id", swarm_id, "task.completed", {"task_id": task_id, "role": task["role"], "artifact": output_path, "checkpoint": checkpoint, "estimated_tokens": estimated_tokens})
            return {"task_id": task_id, "status": "successful", "role": task["role"]}
        except Exception as exc:
            error = {"code": getattr(exc, "code", "KIMU_SWARM_TASK_FAILED"), "message": str(exc), "role": task["role"]}
            db.execute("UPDATE swarm_tasks SET status='failed',error_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text(error), task_id))
            _append_event(db, "swarm_events", "swarm_id", swarm_id, "task.failed", {"task_id": task_id, **error})
            return {"task_id": task_id, "status": "failed", "error": error}


def _run_swarm(app, swarm_id: str) -> None:
    started = time.monotonic()
    with ThreadPoolExecutor(max_workers=6, thread_name_prefix=f"kimu-swarm-{swarm_id[-6:]}") as executor:
        while True:
            with closing(connect(app.config["DATABASE"])) as db:
                swarm = db.execute("SELECT * FROM swarms WHERE id=?", (swarm_id,)).fetchone()
                if not swarm:
                    return
                if swarm["status"] in {"successful", "failed", "cancelled"}:
                    return
                if swarm["cancel_requested"]:
                    db.execute("UPDATE swarm_tasks SET status='cancelled',updated_at=CURRENT_TIMESTAMP WHERE swarm_id=? AND status IN ('blocked','queued','awaiting_approval','running')", (swarm_id,))
                    db.execute("UPDATE swarms SET status='cancelled',error_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text({"code": "KIMU_SWARM_CANCELLED", "message": "The swarm was cancelled."}), swarm_id))
                    _append_event(db, "swarm_events", "swarm_id", swarm_id, "cancelled", {})
                    return
                if time.monotonic() - started > int(swarm["max_seconds"]):
                    error = {"code": "KIMU_SWARM_TIME_BUDGET", "message": "The swarm runtime budget was exhausted."}
                    db.execute("UPDATE swarms SET status='failed',error_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text(error), swarm_id))
                    db.execute("UPDATE swarm_tasks SET status='cancelled',error_json=?,updated_at=CURRENT_TIMESTAMP WHERE swarm_id=? AND status NOT IN ('successful','failed')", (json_text(error), swarm_id))
                    _append_event(db, "swarm_events", "swarm_id", swarm_id, "budget.exhausted", error)
                    return
                tasks = db.execute("SELECT * FROM swarm_tasks WHERE swarm_id=? ORDER BY sequence", (swarm_id,)).fetchall()
                failed = [task for task in tasks if task["status"] == "failed"]
                if failed:
                    error = json.loads(failed[0]["error_json"] or "{}") or {"code": "KIMU_SWARM_TASK_FAILED", "message": "A swarm task failed."}
                    db.execute("UPDATE swarms SET status='failed',error_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text(error), swarm_id))
                    _append_event(db, "swarm_events", "swarm_id", swarm_id, "failed", error)
                    return
                verdict_failures = []
                for task in tasks:
                    if task["status"] != "successful" or task["role"] not in {"tester", "reviewer"}:
                        continue
                    result = json.loads(task["result_json"] or "{}")
                    if "VERDICT: FAIL" in str(result.get("text") or "").upper():
                        verdict_failures.append(task)
                if verdict_failures:
                    builder = next((task for task in tasks if task["role"] == "builder"), None)
                    current_iteration = max(int(task["iteration"] or 1) for task in tasks)
                    if builder and current_iteration < int(swarm["max_iterations"]):
                        next_iteration = current_iteration + 1
                        reset_roles = ("builder", "tester", "reviewer", "release")
                        for task in tasks:
                            if task["role"] not in reset_roles:
                                continue
                            next_status = "queued" if task["role"] == "builder" else "blocked"
                            db.execute("UPDATE swarm_tasks SET status=?,iteration=?,result_json=NULL,error_json=NULL,lease_paths_json='[]',updated_at=CURRENT_TIMESTAMP WHERE id=?", (next_status, next_iteration, task["id"]))
                            db.execute("DELETE FROM swarm_approvals WHERE swarm_id=? AND task_id=?", (swarm_id, task["id"]))
                        _append_event(db, "swarm_events", "swarm_id", swarm_id, "repair.iteration", {"iteration": next_iteration, "failed_roles": [task["role"] for task in verdict_failures]})
                        continue
                    error = {"code": "KIMU_SWARM_VERDICT_FAILED", "message": "Tester or reviewer returned VERDICT: FAIL and the repair-iteration budget was exhausted.", "failed_roles": [task["role"] for task in verdict_failures]}
                    db.execute("UPDATE swarms SET status='failed',error_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text(error), swarm_id))
                    _append_event(db, "swarm_events", "swarm_id", swarm_id, "release.blocked", error)
                    return
                if tasks and all(task["status"] == "successful" for task in tasks):
                    roles = [task["role"] for task in tasks]
                    if not {"tester", "reviewer", "release"}.issubset(set(roles)):
                        error = {"code": "KIMU_SWARM_RELEASE_GATE", "message": "Tester, reviewer and release gates did not all complete."}
                        db.execute("UPDATE swarms SET status='partial',error_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text(error), swarm_id))
                        _append_event(db, "swarm_events", "swarm_id", swarm_id, "release.blocked", error)
                        return
                    summary = {"objective": swarm["objective"], "roles": roles, "release_artifact": next((json.loads(task["result_json"] or "{}").get("artifact") for task in tasks if task["role"] == "release"), None), "workspace_id": swarm["workspace_id"], "checkpoints": db.execute("SELECT COUNT(*) FROM swarm_checkpoints WHERE swarm_id=?", (swarm_id,)).fetchone()[0], "used_tokens": int(swarm["used_tokens"]), "used_tool_calls": int(swarm["used_tool_calls"]), "approval_mode": swarm["approval_mode"]}
                    db.execute("UPDATE swarms SET status='successful',result_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text(summary), swarm_id))
                    _append_event(db, "swarm_events", "swarm_id", swarm_id, "done", summary)
                    _audit(db, swarm["user_id"], "swarm.completed", "swarm", swarm_id, summary)
                    return
                completed = {task["role"] for task in tasks if task["status"] == "successful"}
                ready: list[Any] = []
                pending_approval = False
                for task in tasks:
                    if task["status"] in {"successful", "running", "failed", "cancelled", "skipped"}:
                        continue
                    dependencies = json.loads(task["depends_on_json"] or "[]")
                    if not all(dep in completed for dep in dependencies):
                        if task["status"] != "blocked":
                            db.execute("UPDATE swarm_tasks SET status='blocked',updated_at=CURRENT_TIMESTAMP WHERE id=?", (task["id"],))
                        continue
                    if _swarm_requires_approval(str(swarm["approval_mode"]), str(task["role"])):
                        approval = db.execute("SELECT * FROM swarm_approvals WHERE swarm_id=? AND task_id=?", (swarm_id, task["id"])).fetchone()
                        if not approval:
                            approval_id = uid("sapp")
                            db.execute("INSERT INTO swarm_approvals(id,swarm_id,task_id,status,rationale) VALUES(?,?,?,'pending',?)", (approval_id, swarm_id, task["id"], f"Approval required by {swarm['approval_mode']} mode for {task['role']} role."))
                            db.execute("UPDATE swarm_tasks SET status='awaiting_approval',updated_at=CURRENT_TIMESTAMP WHERE id=?", (task["id"],))
                            _append_event(db, "swarm_events", "swarm_id", swarm_id, "approval.requested", {"approval_id": approval_id, "task_id": task["id"], "role": task["role"]})
                            pending_approval = True
                            continue
                        if approval["status"] == "pending":
                            pending_approval = True
                            continue
                        if approval["status"] == "rejected":
                            error = {"code": "KIMU_SWARM_APPROVAL_REJECTED", "message": f"The {task['role']} task was rejected."}
                            db.execute("UPDATE swarm_tasks SET status='failed',error_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text(error), task["id"]))
                            continue
                    if task["status"] != "queued":
                        db.execute("UPDATE swarm_tasks SET status='queued',updated_at=CURRENT_TIMESTAMP WHERE id=?", (task["id"],))
                    ready.append(task)
                if pending_approval and not ready:
                    db.execute("UPDATE swarms SET status='awaiting_approval',updated_at=CURRENT_TIMESTAMP WHERE id=?", (swarm_id,))
                elif ready:
                    db.execute("UPDATE swarms SET status='running',updated_at=CURRENT_TIMESTAMP WHERE id=?", (swarm_id,))
                max_parallel = min(6, max(1, int(swarm["max_parallelism"])))
                selected = ready[:max_parallel]
            if not selected:
                time.sleep(0.35)
                continue
            futures = [executor.submit(_run_swarm_task, app, swarm_id, task["id"]) for task in selected]
            for future in as_completed(futures):
                with suppress(Exception):
                    future.result()


def register_advanced_routes(app) -> None:
    api = Blueprint("kimu_advanced", __name__, url_prefix="/api/v1")

    @api.get("/tools")
    @require_user
    def list_tools(user_id: str):
        return jsonify({"tools": registry_payload(), "risk_order": ["read", "write", "execute", "external", "destructive"]})

    @api.get("/workspaces")
    @require_user
    def list_workspaces(user_id: str):
        kind = request.args.get("kind")
        with closing(_db()) as db:
            if kind:
                rows = db.execute("SELECT * FROM workspaces WHERE user_id=? AND kind=? ORDER BY updated_at DESC", (user_id, kind)).fetchall()
            else:
                rows = db.execute("SELECT * FROM workspaces WHERE user_id=? ORDER BY updated_at DESC", (user_id,)).fetchall()
        return jsonify({"workspaces": [_workspace_value(row) for row in rows]})

    @api.post("/workspaces")
    @require_user
    def create_workspace(user_id: str):
        data = request.get_json(silent=True) or {}
        name = str(data.get("name") or "New workspace").strip()[:120] or "New workspace"
        kind = str(data.get("kind") or "tools")
        if kind not in {"tools", "website", "swarm"}:
            return api_error("KIMU_WORKSPACE_KIND", "Unsupported workspace kind.", 400)
        workspace_id = uid("wsp")
        root = _workspace_root(current_app, user_id, workspace_id)
        with closing(_db()) as db:
            db.execute("INSERT INTO workspaces(id,user_id,name,kind,root_path) VALUES(?,?,?,?,?)", (workspace_id, user_id, name, kind, str(root)))
            row = db.execute("SELECT * FROM workspaces WHERE id=?", (workspace_id,)).fetchone()
            _audit(db, user_id, "workspace.created", "workspace", workspace_id, {"kind": kind})
        return jsonify({"workspace": _workspace_value(row)}), 201

    @api.get("/tool-operations")
    @require_user
    def list_tool_operations(user_id: str):
        with closing(_db()) as db:
            rows = db.execute("SELECT * FROM tool_operations WHERE user_id=? ORDER BY created_at DESC LIMIT 200", (user_id,)).fetchall()
        return jsonify({"operations": [_operation_value(row) for row in rows]})

    @api.post("/tool-operations")
    @require_user
    def create_tool_operation(user_id: str):
        data = request.get_json(silent=True) or {}
        tool_id = str(data.get("tool_id") or "")
        definition = TOOL_DEFINITIONS.get(tool_id)
        if not definition:
            return api_error("KIMU_TOOL_UNKNOWN", "Unknown tool.", 404)
        workspace_id = str(data.get("workspace_id") or "")
        arguments = data.get("arguments") or {}
        try:
            from .tool_runtime import validate_arguments
            arguments = validate_arguments(definition, arguments)
        except ToolRuntimeError as exc:
            return api_error(exc.code, str(exc), 400, exc.details)
        idempotency_key = str(data.get("idempotency_key") or uid("idem"))[:120]
        operation_id = uid("top")
        approval_required = bool(definition.approval_required)
        status = "awaiting_approval" if approval_required else "queued"
        with closing(_db()) as db:
            workspace = db.execute("SELECT * FROM workspaces WHERE id=? AND user_id=?", (workspace_id, user_id)).fetchone()
            if not workspace:
                return api_error("KIMU_WORKSPACE_NOT_FOUND", "Workspace not found.", 404)
            existing = db.execute("SELECT * FROM tool_operations WHERE user_id=? AND idempotency_key=?", (user_id, idempotency_key)).fetchone()
            if existing:
                return jsonify({"operation": _operation_value(existing), "idempotent": True})
            db.execute("INSERT INTO tool_operations(id,user_id,workspace_id,tool_id,tool_version,risk_class,status,arguments_json,approval_required,idempotency_key) VALUES(?,?,?,?,?,?,?,?,?,?)", (operation_id, user_id, workspace_id, tool_id, definition.version, definition.risk_class, status, json_text(arguments), int(approval_required), idempotency_key))
            _append_event(db, "tool_events", "operation_id", operation_id, "status", {"status": status})
            row = db.execute("SELECT * FROM tool_operations WHERE id=?", (operation_id,)).fetchone()
            _audit(db, user_id, "tool.requested", "tool_operation", operation_id, {"tool_id": tool_id, "risk_class": definition.risk_class})
        if status == "queued":
            _start_operation(current_app._get_current_object(), operation_id)
        return jsonify({"operation": _operation_value(row), "idempotent": False}), 202

    @api.post("/tool-operations/<operation_id>/approve")
    @require_user
    def approve_tool_operation(user_id: str, operation_id: str):
        with closing(_db()) as db:
            row = db.execute("SELECT * FROM tool_operations WHERE id=? AND user_id=?", (operation_id, user_id)).fetchone()
            if not row:
                return api_error("KIMU_TOOL_OPERATION_NOT_FOUND", "Tool operation not found.", 404)
            if row["status"] != "awaiting_approval":
                return api_error("KIMU_TOOL_OPERATION_STATE", "This operation is not awaiting approval.", 409)
            db.execute("UPDATE tool_operations SET status='queued',approved_at=CURRENT_TIMESTAMP,updated_at=CURRENT_TIMESTAMP WHERE id=?", (operation_id,))
            _append_event(db, "tool_events", "operation_id", operation_id, "approved", {"status": "queued"})
            updated = db.execute("SELECT * FROM tool_operations WHERE id=?", (operation_id,)).fetchone()
            _audit(db, user_id, "tool.approved", "tool_operation", operation_id, {"tool_id": row["tool_id"]})
        _start_operation(current_app._get_current_object(), operation_id)
        return jsonify({"operation": _operation_value(updated)}), 202

    @api.post("/tool-operations/<operation_id>/reject")
    @require_user
    def reject_tool_operation(user_id: str, operation_id: str):
        with closing(_db()) as db:
            row = db.execute("SELECT * FROM tool_operations WHERE id=? AND user_id=?", (operation_id, user_id)).fetchone()
            if not row:
                return api_error("KIMU_TOOL_OPERATION_NOT_FOUND", "Tool operation not found.", 404)
            if row["status"] != "awaiting_approval":
                return api_error("KIMU_TOOL_OPERATION_STATE", "This operation is not awaiting approval.", 409)
            db.execute("UPDATE tool_operations SET status='rejected',updated_at=CURRENT_TIMESTAMP WHERE id=?", (operation_id,))
            _append_event(db, "tool_events", "operation_id", operation_id, "rejected", {"status": "rejected"})
            updated = db.execute("SELECT * FROM tool_operations WHERE id=?", (operation_id,)).fetchone()
        return jsonify({"operation": _operation_value(updated)})

    @api.post("/tool-operations/<operation_id>/cancel")
    @require_user
    def cancel_tool_operation(user_id: str, operation_id: str):
        with closing(_db()) as db:
            row = db.execute("SELECT * FROM tool_operations WHERE id=? AND user_id=?", (operation_id, user_id)).fetchone()
            if not row:
                return api_error("KIMU_TOOL_OPERATION_NOT_FOUND", "Tool operation not found.", 404)
            if row["status"] in {"successful", "failed", "cancelled", "rejected"}:
                return jsonify({"operation": _operation_value(row), "terminal": True})
            db.execute("UPDATE tool_operations SET cancel_requested=1,status=CASE WHEN status='awaiting_approval' THEN 'cancelled' ELSE status END,updated_at=CURRENT_TIMESTAMP WHERE id=?", (operation_id,))
            _append_event(db, "tool_events", "operation_id", operation_id, "cancel.requested", {})
            updated = db.execute("SELECT * FROM tool_operations WHERE id=?", (operation_id,)).fetchone()
        return jsonify({"operation": _operation_value(updated)})

    @api.get("/tool-operations/<operation_id>")
    @require_user
    def get_tool_operation(user_id: str, operation_id: str):
        with closing(_db()) as db:
            row = db.execute("SELECT * FROM tool_operations WHERE id=? AND user_id=?", (operation_id, user_id)).fetchone()
            if not row:
                return api_error("KIMU_TOOL_OPERATION_NOT_FOUND", "Tool operation not found.", 404)
            events = [{**dict(event), "data": json.loads(event["data_json"] or "{}")} for event in db.execute("SELECT seq,event_type,data_json,created_at FROM tool_events WHERE operation_id=? ORDER BY seq", (operation_id,)).fetchall()]
        return jsonify({"operation": _operation_value(row), "events": events})

    @api.get("/tool-policies")
    @require_user
    def list_tool_policies(user_id: str):
        workspace_id = str(request.args.get("workspace_id") or "")
        with closing(_db()) as db:
            rows = db.execute("SELECT tool_id,decision,updated_at FROM tool_policies WHERE user_id=? AND workspace_id=? ORDER BY tool_id", (user_id, workspace_id)).fetchall()
        return jsonify({"policies": [dict(row) for row in rows]})

    @api.put("/tool-policies/<tool_id>")
    @require_user
    def set_tool_policy(user_id: str, tool_id: str):
        if tool_id not in TOOL_DEFINITIONS:
            return api_error("KIMU_TOOL_UNKNOWN", "Unknown tool.", 404)
        data = request.get_json(silent=True) or {}
        workspace_id = str(data.get("workspace_id") or "")
        decision = str(data.get("decision") or "ask")
        if decision not in {"ask", "allow", "deny"}:
            return api_error("KIMU_TOOL_POLICY_INVALID", "Tool policy must be ask, allow or deny.", 400)
        with closing(_db()) as db:
            workspace = db.execute("SELECT id FROM workspaces WHERE id=? AND user_id=?", (workspace_id, user_id)).fetchone()
            if not workspace:
                return api_error("KIMU_WORKSPACE_NOT_FOUND", "Workspace not found.", 404)
            db.execute("INSERT INTO tool_policies(user_id,workspace_id,tool_id,decision) VALUES(?,?,?,?) ON CONFLICT(user_id,workspace_id,tool_id) DO UPDATE SET decision=excluded.decision,updated_at=CURRENT_TIMESTAMP", (user_id, workspace_id, tool_id, decision))
            _audit(db, user_id, "tool.policy_changed", "workspace", workspace_id, {"tool_id": tool_id, "decision": decision})
        return jsonify({"tool_id": tool_id, "workspace_id": workspace_id, "decision": decision})

    @api.get("/tool-agent/sessions")
    @require_user
    def list_tool_agent_sessions(user_id: str):
        with closing(_db()) as db:
            rows = db.execute("SELECT * FROM tool_agent_sessions WHERE user_id=? ORDER BY updated_at DESC LIMIT 100", (user_id,)).fetchall()
            values = [_tool_agent_value(db, row) for row in rows]
        return jsonify({"sessions": values})

    @api.post("/tool-agent/sessions")
    @require_user
    def create_tool_agent_session(user_id: str):
        data = request.get_json(silent=True) or {}
        workspace_id = str(data.get("workspace_id") or "")
        prompt = str(data.get("prompt") or "").strip()[:20000]
        model_key = str(data.get("model_key") or "k2.6")
        approval_mode = str(data.get("approval_mode") or "balanced")
        if len(prompt) < 3:
            return api_error("KIMU_TOOL_AGENT_PROMPT", "Enter a tool-agent instruction.", 400)
        if model_key not in {"k2.6", "k2.7-code"} or approval_mode not in {"manual", "balanced", "autonomous"}:
            return api_error("KIMU_TOOL_AGENT_CONFIGURATION", "Unsupported tool-agent configuration.", 400)
        if model_key == "k2.7-code" and not build_profiles(current_app.config)[model_key].configured:
            return api_error("KIMU_MODEL_NOT_CONFIGURED", "Kimi K2.7 Coder is not configured.", 409)
        max_steps = min(20, max(1, int(data.get("max_steps") or 8)))
        max_tool_calls = min(40, max(1, int(data.get("max_tool_calls") or 12)))
        with closing(_db()) as db:
            workspace = db.execute("SELECT id FROM workspaces WHERE id=? AND user_id=?", (workspace_id, user_id)).fetchone()
            if not workspace:
                return api_error("KIMU_WORKSPACE_NOT_FOUND", "Workspace not found.", 404)
            session_id = uid("tagent")
            db.execute("INSERT INTO tool_agent_sessions(id,user_id,workspace_id,model_key,approval_mode,status,prompt,max_steps,max_tool_calls) VALUES(?,?,?,?,?,'queued',?,?,?)", (session_id, user_id, workspace_id, model_key, approval_mode, prompt, max_steps, max_tool_calls))
            _append_tool_agent_step(db, session_id, "created", {"model_key": model_key, "approval_mode": approval_mode, "max_steps": max_steps, "max_tool_calls": max_tool_calls})
            row = db.execute("SELECT * FROM tool_agent_sessions WHERE id=?", (session_id,)).fetchone()
            _audit(db, user_id, "tool_agent.created", "tool_agent_session", session_id, {"workspace_id": workspace_id})
        _start_tool_agent(current_app._get_current_object(), session_id)
        return jsonify({"session": _tool_agent_value(None, row)}), 202

    @api.get("/tool-agent/sessions/<session_id>")
    @require_user
    def get_tool_agent_session(user_id: str, session_id: str):
        with closing(_db()) as db:
            row = db.execute("SELECT * FROM tool_agent_sessions WHERE id=? AND user_id=?", (session_id, user_id)).fetchone()
            if not row:
                return api_error("KIMU_TOOL_AGENT_NOT_FOUND", "Tool-agent session not found.", 404)
            value = _tool_agent_value(db, row, include_steps=True)
            if row["current_operation_id"]:
                operation = db.execute("SELECT * FROM tool_operations WHERE id=?", (row["current_operation_id"],)).fetchone()
                value["current_operation"] = _operation_value(operation) if operation else None
        return jsonify({"session": value})

    @api.post("/tool-agent/sessions/<session_id>/resume")
    @require_user
    def resume_tool_agent_session(user_id: str, session_id: str):
        with closing(_db()) as db:
            row = db.execute("SELECT * FROM tool_agent_sessions WHERE id=? AND user_id=?", (session_id, user_id)).fetchone()
            if not row:
                return api_error("KIMU_TOOL_AGENT_NOT_FOUND", "Tool-agent session not found.", 404)
            if row["status"] not in {"awaiting_approval", "partial", "failed"}:
                return api_error("KIMU_TOOL_AGENT_STATE", "The tool-agent session cannot resume from its current state.", 409)
            if row["current_operation_id"]:
                operation = db.execute("SELECT status FROM tool_operations WHERE id=?", (row["current_operation_id"],)).fetchone()
                if operation and operation["status"] not in {"successful", "rejected", "cancelled", "failed"}:
                    return api_error("KIMU_TOOL_AGENT_APPROVAL_PENDING", "The pending tool operation has not reached a final state.", 409)
            db.execute("UPDATE tool_agent_sessions SET status='queued',cancel_requested=0,error_json='{}',updated_at=CURRENT_TIMESTAMP WHERE id=?", (session_id,))
            _append_tool_agent_step(db, session_id, "resumed", {})
        _start_tool_agent(current_app._get_current_object(), session_id)
        return jsonify({"id": session_id, "status": "queued"}), 202

    @api.post("/tool-agent/sessions/<session_id>/cancel")
    @require_user
    def cancel_tool_agent_session(user_id: str, session_id: str):
        with closing(_db()) as db:
            row = db.execute("SELECT * FROM tool_agent_sessions WHERE id=? AND user_id=?", (session_id, user_id)).fetchone()
            if not row:
                return api_error("KIMU_TOOL_AGENT_NOT_FOUND", "Tool-agent session not found.", 404)
            db.execute("UPDATE tool_agent_sessions SET cancel_requested=1,status=CASE WHEN status IN ('queued','awaiting_approval') THEN 'cancelled' ELSE status END,updated_at=CURRENT_TIMESTAMP WHERE id=?", (session_id,))
            _append_tool_agent_step(db, session_id, "cancel.requested", {})
        return jsonify({"id": session_id, "cancel_requested": True})

    @api.get("/websites")
    @require_user
    def list_websites(user_id: str):
        with closing(_db()) as db:
            rows = db.execute("SELECT * FROM website_projects WHERE user_id=? AND status!='archived' ORDER BY updated_at DESC", (user_id,)).fetchall()
            values = [_project_value(db, row) for row in rows]
        return jsonify({"projects": values})


    @api.post("/websites/import")
    @require_user
    def import_website(user_id: str):
        uploaded = request.files.get("file")
        if not uploaded or not uploaded.filename:
            return api_error("KIMU_WEBSITE_IMPORT_REQUIRED", "Select a website ZIP file.", 400)
        name = str(request.form.get("name") or Path(uploaded.filename).stem or "Imported website").strip()[:120]
        model_key = str(request.form.get("model_key") or "k2.7-code")
        project_type = str(request.form.get("project_type") or "static")
        if model_key not in {"k2.6", "k2.7-code"} or project_type not in {"static", "react"}:
            return api_error("KIMU_WEBSITE_CONFIGURATION", "Unsupported website project configuration.", 400)
        try:
            files, ignored = _import_website_zip(uploaded.read(32 * 1024 * 1024 + 1))
        except (zipfile.BadZipFile, ToolRuntimeError) as exc:
            return api_error(getattr(exc, "code", "KIMU_WEBSITE_IMPORT_INVALID"), str(exc), 400, getattr(exc, "details", None))
        project_id, workspace_id = uid("web"), uid("wsp")
        root = _workspace_root(current_app, user_id, workspace_id)
        with closing(_db()) as db, transaction(db):
            db.execute("INSERT INTO workspaces(id,user_id,name,kind,root_path) VALUES(?,?,?,'website',?)", (workspace_id, user_id, name, str(root)))
            db.execute("INSERT INTO website_projects(id,user_id,workspace_id,name,project_type,model_key,status,requirements_json,current_version) VALUES(?,?,?,?,?,?,'ready',?,0)", (project_id, user_id, workspace_id, name, project_type, model_key, json_text({"imported": True, "ignored_binary_files": ignored})))
            for path, content in files.items():
                digest = hashlib.sha256(content.encode()).hexdigest()
                mime = mimetypes.guess_type(path)[0] or "text/plain"
                db.execute("INSERT INTO website_files(project_id,path,content,mime_type,sha256,version) VALUES(?,?,?,?,?,1)", (project_id, path, content, mime, digest))
                target = resolve_workspace_path(root, path); target.parent.mkdir(parents=True, exist_ok=True); target.write_text(content, encoding="utf-8")
            version = _save_project_version(db, project_id, "Imported validated website ZIP")
            row = db.execute("SELECT * FROM website_projects WHERE id=?", (project_id,)).fetchone()
            _audit(db, user_id, "website.imported", "website_project", project_id, {"version": version, "ignored": ignored})
        return jsonify({"project": _project_value(None, row), "ignored_binary_files": ignored}), 201

    @api.post("/websites")
    @require_user
    def create_website(user_id: str):
        data = request.get_json(silent=True) or {}
        name = str(data.get("name") or "New website").strip()[:120] or "New website"
        project_type = str(data.get("project_type") or "static")
        model_key = str(data.get("model_key") or "k2.7-code")
        brief = str(data.get("brief") or "").strip()[:5000]
        requirements = data.get("requirements") if isinstance(data.get("requirements"), dict) else {}
        theme = data.get("theme") if isinstance(data.get("theme"), dict) else {}
        requirements = {**requirements, "brief": brief}
        if project_type not in {"static", "react"} or model_key not in {"k2.6", "k2.7-code"}:
            return api_error("KIMU_WEBSITE_CONFIGURATION", "Unsupported website project configuration.", 400)
        project_id, workspace_id = uid("web"), uid("wsp")
        root = _workspace_root(current_app, user_id, workspace_id)
        files = _starter_files(name, project_type, brief, requirements, theme)
        with closing(_db()) as db, transaction(db):
            db.execute("INSERT INTO workspaces(id,user_id,name,kind,root_path) VALUES(?,?,?,'website',?)", (workspace_id, user_id, name, str(root)))
            db.execute("INSERT INTO website_projects(id,user_id,workspace_id,name,project_type,model_key,status,requirements_json,current_version,wizard_stage,theme_json) VALUES(?,?,?,?,?,?,'ready',?,0,4,?)", (project_id, user_id, workspace_id, name, project_type, model_key, json_text(requirements), json_text(theme)))
            for path, content in files.items():
                digest = hashlib.sha256(content.encode()).hexdigest()
                mime = mimetypes.guess_type(path)[0] or "text/plain"
                db.execute("INSERT INTO website_files(project_id,path,content,mime_type,sha256,version) VALUES(?,?,?,?,?,1)", (project_id, path, content, mime, digest))
                target = resolve_workspace_path(root, path)
                target.parent.mkdir(parents=True, exist_ok=True)
                target.write_text(content, encoding="utf-8")
            _save_project_version(db, project_id, "Initial mobile-first project")
            row = db.execute("SELECT * FROM website_projects WHERE id=?", (project_id,)).fetchone()
            _audit(db, user_id, "website.created", "website_project", project_id, {"project_type": project_type})
        return jsonify({"project": _project_value(None, row)}), 201

    @api.get("/websites/<project_id>")
    @require_user
    def get_website(user_id: str, project_id: str):
        with closing(_db()) as db:
            row = db.execute("SELECT * FROM website_projects WHERE id=? AND user_id=?", (project_id, user_id)).fetchone()
            if not row:
                return api_error("KIMU_WEBSITE_NOT_FOUND", "Website project not found.", 404)
            value = _project_value(db, row, include_files=True)
        return jsonify({"project": value})

    @api.patch("/websites/<project_id>")
    @require_user
    def update_website(user_id: str, project_id: str):
        data = request.get_json(silent=True) or {}
        with closing(_db()) as db:
            project = db.execute("SELECT * FROM website_projects WHERE id=? AND user_id=?", (project_id, user_id)).fetchone()
            if not project:
                return api_error("KIMU_WEBSITE_NOT_FOUND", "Website project not found.", 404)
            name = str(data.get("name") or project["name"]).strip()[:120] or project["name"]
            model_key = str(data.get("model_key") or project["model_key"])
            if model_key not in {"k2.6", "k2.7-code"}:
                return api_error("KIMU_WEBSITE_CONFIGURATION", "Unsupported model profile.", 400)
            requirements = data.get("requirements") if isinstance(data.get("requirements"), dict) else json.loads(project["requirements_json"] or "{}")
            theme = data.get("theme") if isinstance(data.get("theme"), dict) else json.loads(project["theme_json"] or "{}")
            stage = min(4, max(1, int(data.get("wizard_stage") or project["wizard_stage"] or 4)))
            db.execute("UPDATE website_projects SET name=?,model_key=?,requirements_json=?,theme_json=?,wizard_stage=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (name, model_key, json_text(requirements), json_text(theme), stage, project_id))
            row = db.execute("SELECT * FROM website_projects WHERE id=?", (project_id,)).fetchone()
            _audit(db, user_id, "website.settings_updated", "website_project", project_id, {"wizard_stage": stage})
            value = _project_value(db, row, include_files=True)
        return jsonify({"project": value})

    @api.get("/websites/<project_id>/versions/<int:version>/diffs")
    @require_user
    def website_version_diffs(user_id: str, project_id: str, version: int):
        with closing(_db()) as db:
            project = db.execute("SELECT id FROM website_projects WHERE id=? AND user_id=?", (project_id, user_id)).fetchone()
            if not project:
                return api_error("KIMU_WEBSITE_NOT_FOUND", "Website project not found.", 404)
            rows = db.execute("SELECT id,version,path,change_type,before_sha256,after_sha256,unified_diff,created_at FROM website_diffs WHERE project_id=? AND version=? ORDER BY path", (project_id, version)).fetchall()
        return jsonify({"version": version, "diffs": [dict(row) for row in rows]})

    @api.put("/websites/<project_id>/files")
    @require_user
    def save_website_file(user_id: str, project_id: str):
        data = request.get_json(silent=True) or {}
        path = str(data.get("path") or "")
        content = str(data.get("content") or "")
        if len(content) > 2_000_000:
            return api_error("KIMU_WEBSITE_FILE_TOO_LARGE", "Website text files are limited to 2,000,000 characters.", 413)
        with closing(_db()) as db:
            project = db.execute("SELECT * FROM website_projects WHERE id=? AND user_id=?", (project_id, user_id)).fetchone()
            if not project:
                return api_error("KIMU_WEBSITE_NOT_FOUND", "Website project not found.", 404)
            try:
                target = resolve_workspace_path(_workspace_root(current_app, user_id, project["workspace_id"]), path)
            except ToolRuntimeError as exc:
                return api_error(exc.code, str(exc), 400)
            current = db.execute("SELECT sha256 FROM website_files WHERE project_id=? AND path=?", (project_id, path)).fetchone()
            expected = data.get("expected_sha256")
            if expected is not None and (not current or current["sha256"] != expected):
                return api_error("KIMU_WEBSITE_VERSION_CONFLICT", "The file changed before it could be saved.", 409, {"canonical_sha256": current["sha256"] if current else None})
            digest = hashlib.sha256(content.encode()).hexdigest()
            mime = mimetypes.guess_type(path)[0] or "text/plain"
            target.parent.mkdir(parents=True, exist_ok=True)
            target.write_text(content, encoding="utf-8")
            db.execute("INSERT INTO website_files(project_id,path,content,mime_type,sha256,version) VALUES(?,?,?,?,?,1) ON CONFLICT(project_id,path) DO UPDATE SET content=excluded.content,mime_type=excluded.mime_type,sha256=excluded.sha256,version=website_files.version+1,updated_at=CURRENT_TIMESTAMP", (project_id, path, content, mime, digest))
            version = _save_project_version(db, project_id, f"Saved {path}")
            row = db.execute("SELECT path,content,mime_type,sha256,version,updated_at FROM website_files WHERE project_id=? AND path=?", (project_id, path)).fetchone()
            _audit(db, user_id, "website.file_saved", "website_project", project_id, {"path": path, "version": version})
        return jsonify({"file": dict(row), "project_version": version})

    @api.post("/websites/<project_id>/generate")
    @require_user
    def generate_website(user_id: str, project_id: str):
        data = request.get_json(silent=True) or {}
        instruction = str(data.get("instruction") or "Improve this website while preserving its purpose.").strip()[:12000]
        with closing(_db()) as db:
            project = db.execute("SELECT * FROM website_projects WHERE id=? AND user_id=?", (project_id, user_id)).fetchone()
            if not project:
                return api_error("KIMU_WEBSITE_NOT_FOUND", "Website project not found.", 404)
            files = {row["path"]: row["content"] for row in db.execute("SELECT path,content FROM website_files WHERE project_id=?", (project_id,)).fetchall()}
            requirements = json.loads(project["requirements_json"] or "{}")
            theme = json.loads(project["theme_json"] or "{}")
            build_id = uid("wbuild")
            db.execute("INSERT INTO website_builds(id,project_id,status,model_key,instruction) VALUES(?,?,'running',?,?)", (build_id, project_id, project["model_key"], instruction))
            db.execute("UPDATE website_projects SET status='generating',updated_at=CURRENT_TIMESTAMP WHERE id=?", (project_id,))
        try:
            planning_prompt = "Create a concise implementation plan and acceptance checklist for this website revision. Do not write code yet.\n\nRequirements:\n" + json.dumps(requirements, ensure_ascii=False) + "\n\nTheme:\n" + json.dumps(theme, ensure_ascii=False) + "\n\nInstruction:\n" + instruction
            if current_app.config["FAKE_PROVIDER"]:
                plan = "K2.6 plan: preserve all pages, implement the requested change, validate links and keep dependencies vendored."
                if "styles.css" in files:
                    files["styles.css"] += "\n/* KIMU generated and reviewed revision */\n"
                summary = f"Applied deterministic fake-provider revision: {instruction}"
                review = "K2.6 review: static validation passed and the requested revision is represented."
            else:
                plan = _collect_model_text(current_app, "k2.6", planning_prompt, "You are the KIMU Website Architect. Produce a precise plan and acceptance checklist.")
                prompt = "You are revising a mobile-first website. Return ONLY valid JSON with shape {\"summary\":string,\"files\":{path:string}}. Implement the K2.6 plan, preserve all required files, use no remote CDNs, and return complete deployment-ready files.\n\nK2.6 plan:\n" + plan + "\n\nInstruction:\n" + instruction + "\n\nCurrent files:\n" + json.dumps(files, ensure_ascii=False)[:120000]
                text = _collect_model_text(current_app, project["model_key"], prompt, "You are KIMU Website Builder. Produce complete deployment-ready files and valid JSON only.")
                json_start, json_end = text.find("{"), text.rfind("}")
                parsed = json.loads(text[json_start:json_end + 1])
                generated = parsed.get("files")
                if not isinstance(generated, dict) or not generated:
                    raise ValueError("The model did not return a non-empty files object.")
                files = {safe_relative_path(str(path)): str(content) for path, content in generated.items() if isinstance(path, str) and isinstance(content, str)}
                summary = str(parsed.get("summary") or instruction)[:1000]
                review_prompt = "Review this implementation against the plan and instruction. Identify any material failure. End with VERDICT: PASS or VERDICT: FAIL.\n\nPlan:\n" + plan + "\n\nInstruction:\n" + instruction + "\n\nFiles:\n" + json.dumps(files, ensure_ascii=False)[:120000]
                review = _collect_model_text(current_app, "k2.6", review_prompt, "You are the independent KIMU Website Reviewer. Do not claim tests that are not shown.")
                if "VERDICT: FAIL" in review.upper():
                    raise ToolRuntimeError("KIMU_WEBSITE_REVIEW_FAILED", "The independent K2.6 review rejected the generated revision.", {"review": review[:12000]})
            test_result = _validate_website_files(files)
            if not test_result.get("passed"):
                raise ToolRuntimeError("KIMU_WEBSITE_TEST_FAILED", "Generated website files failed static validation.", {"failures": test_result.get("failures", [])})
            with closing(_db()) as db, transaction(db):
                project = db.execute("SELECT * FROM website_projects WHERE id=? AND user_id=?", (project_id, user_id)).fetchone()
                root = _workspace_root(current_app, user_id, project["workspace_id"])
                existing_paths = {row[0] for row in db.execute("SELECT path FROM website_files WHERE project_id=?", (project_id,)).fetchall()}
                generated_paths = set(files)
                for removed in sorted(existing_paths - generated_paths):
                    db.execute("DELETE FROM website_files WHERE project_id=? AND path=?", (project_id, removed))
                    target = resolve_workspace_path(root, removed)
                    if target.exists() and target.is_file():
                        target.unlink()
                for path, content in files.items():
                    target = resolve_workspace_path(root, path)
                    target.parent.mkdir(parents=True, exist_ok=True)
                    target.write_text(content, encoding="utf-8")
                    digest = hashlib.sha256(content.encode()).hexdigest()
                    mime = mimetypes.guess_type(path)[0] or "text/plain"
                    db.execute("INSERT INTO website_files(project_id,path,content,mime_type,sha256,version) VALUES(?,?,?,?,?,1) ON CONFLICT(project_id,path) DO UPDATE SET content=excluded.content,mime_type=excluded.mime_type,sha256=excluded.sha256,version=website_files.version+1,updated_at=CURRENT_TIMESTAMP", (project_id, path, content, mime, digest))
                version = _save_project_version(db, project_id, summary)
                test_id = uid("wtest")
                db.execute("INSERT INTO website_test_results(id,project_id,version,status,result_json) VALUES(?,?,?,'successful',?)", (test_id, project_id, version, json_text(test_result)))
                result = {"summary": summary, "version": version, "test_id": test_id, "test": test_result, "plan": plan, "review": review}
                db.execute("UPDATE website_builds SET status='successful',result_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text(result), build_id))
                db.execute("UPDATE website_projects SET status='ready',updated_at=CURRENT_TIMESTAMP WHERE id=?", (project_id,))
                _audit(db, user_id, "website.generated", "website_project", project_id, {"build_id": build_id, "version": version, "planner": "k2.6", "builder": project["model_key"], "reviewer": "k2.6"})
            return jsonify({"build": {"id": build_id, "status": "successful", **result}})
        except Exception as exc:
            with closing(_db()) as db:
                db.execute("UPDATE website_builds SET status='failed',error_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text({"code": getattr(exc, "code", "KIMU_WEBSITE_GENERATION_FAILED"), "message": str(exc), "details": getattr(exc, "details", {})}), build_id))
                db.execute("UPDATE website_projects SET status='failed',updated_at=CURRENT_TIMESTAMP WHERE id=?", (project_id,))
            return api_error(getattr(exc, "code", "KIMU_WEBSITE_GENERATION_FAILED"), str(exc), 502, getattr(exc, "details", None))

    @api.post("/websites/<project_id>/test")
    @require_user
    def test_website(user_id: str, project_id: str):
        with closing(_db()) as db:
            project = db.execute("SELECT * FROM website_projects WHERE id=? AND user_id=?", (project_id, user_id)).fetchone()
            if not project:
                return api_error("KIMU_WEBSITE_NOT_FOUND", "Website project not found.", 404)
            files = {row["path"]: row["content"] for row in db.execute("SELECT path,content FROM website_files WHERE project_id=?", (project_id,)).fetchall()}
            result = _validate_website_files(files)
            test_id = uid("wtest")
            status = "successful" if result.get("passed") else "failed"
            db.execute("INSERT INTO website_test_results(id,project_id,version,status,result_json) VALUES(?,?,?,?,?)", (test_id, project_id, int(project["current_version"]), status, json_text(result)))
            db.execute("UPDATE website_projects SET status=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", ("ready" if result.get("passed") else "failed", project_id))
            _audit(db, user_id, "website.tested", "website_project", project_id, {"test_id": test_id, "passed": bool(result.get("passed"))})
        return jsonify({"test": {"id": test_id, "status": status, **result}}), (200 if result.get("passed") else 422)

    @api.post("/websites/<project_id>/rollback/<int:version>")
    @require_user
    def rollback_website(user_id: str, project_id: str, version: int):
        with closing(_db()) as db, transaction(db):
            project = db.execute("SELECT * FROM website_projects WHERE id=? AND user_id=?", (project_id, user_id)).fetchone()
            if not project:
                return api_error("KIMU_WEBSITE_NOT_FOUND", "Website project not found.", 404)
            files = db.execute("SELECT path,content,mime_type,sha256 FROM website_version_files WHERE project_id=? AND version=? ORDER BY path", (project_id, version)).fetchall()
            if not files:
                return api_error("KIMU_WEBSITE_VERSION_NOT_FOUND", "Website version not found.", 404)
            db.execute("DELETE FROM website_files WHERE project_id=?", (project_id,))
            root = _workspace_root(current_app, user_id, project["workspace_id"])
            for path in root.rglob("*"):
                if path.is_file():
                    path.unlink()
            for row in files:
                db.execute("INSERT INTO website_files(project_id,path,content,mime_type,sha256,version) VALUES(?,?,?,?,?,1)", (project_id, row["path"], row["content"], row["mime_type"], row["sha256"]))
                target = resolve_workspace_path(root, row["path"])
                target.parent.mkdir(parents=True, exist_ok=True)
                target.write_text(row["content"], encoding="utf-8")
            new_version = _save_project_version(db, project_id, f"Rolled back to version {version}")
            db.execute("UPDATE website_projects SET status='ready' WHERE id=?", (project_id,))
            _audit(db, user_id, "website.rolled_back", "website_project", project_id, {"source_version": version, "new_version": new_version})
        return jsonify({"ok": True, "version": new_version})

    @api.get("/websites/<project_id>/preview/<path:path>")
    @require_user
    def preview_website(user_id: str, project_id: str, path: str):
        with closing(_db()) as db:
            project = db.execute("SELECT id FROM website_projects WHERE id=? AND user_id=?", (project_id, user_id)).fetchone()
            if not project:
                return api_error("KIMU_WEBSITE_NOT_FOUND", "Website project not found.", 404)
            row = db.execute("SELECT content,mime_type FROM website_files WHERE project_id=? AND path=?", (project_id, path)).fetchone()
            if not row:
                return api_error("KIMU_WEBSITE_FILE_NOT_FOUND", "Website file not found.", 404)
        response = Response(row["content"], mimetype=row["mime_type"])
        response.headers["Content-Security-Policy"] = "default-src 'self'; img-src 'self' data: blob:; style-src 'self' 'unsafe-inline'; script-src 'self'; connect-src 'none'; frame-ancestors 'self'; base-uri 'none'; form-action 'none'"
        response.headers["X-Frame-Options"] = "SAMEORIGIN"
        response.headers["Cache-Control"] = "no-store"
        return response

    @api.get("/websites/<project_id>/export.zip")
    @require_user
    def export_website(user_id: str, project_id: str):
        with closing(_db()) as db:
            project = db.execute("SELECT * FROM website_projects WHERE id=? AND user_id=?", (project_id, user_id)).fetchone()
            if not project:
                return api_error("KIMU_WEBSITE_NOT_FOUND", "Website project not found.", 404)
            files = db.execute("SELECT path,content FROM website_files WHERE project_id=? ORDER BY path", (project_id,)).fetchall()
        buffer = io.BytesIO()
        with zipfile.ZipFile(buffer, "w", zipfile.ZIP_DEFLATED) as archive:
            for row in files:
                archive.writestr(row["path"], row["content"])
            report = {
                "project": project["name"], "version": int(project["current_version"]), "model_key": project["model_key"],
                "project_type": project["project_type"], "file_count": len(files),
                "requirements": json.loads(project["requirements_json"] or "{}"),
                "theme": json.loads(project["theme_json"] or "{}"),
                "generated_by": "KIMU Website Builder",
                "secrets_included": False,
            }
            archive.writestr("KIMU_BUILD_REPORT.json", json.dumps(report, ensure_ascii=False, indent=2))
        buffer.seek(0)
        filename = re.sub(r"[^A-Za-z0-9._-]+", "_", project["name"]).strip("_") or "kimu-website"
        return send_file(buffer, mimetype="application/zip", as_attachment=True, download_name=f"{filename}.zip")

    @api.get("/swarms")
    @require_user
    def list_swarms(user_id: str):
        with closing(_db()) as db:
            rows = db.execute("SELECT * FROM swarms WHERE user_id=? ORDER BY updated_at DESC LIMIT 100", (user_id,)).fetchall()
        return jsonify({"swarms": [{
            "id": row["id"], "objective": row["objective"], "status": row["status"], "workspace_id": row["workspace_id"],
            "approval_mode": row["approval_mode"], "max_parallelism": int(row["max_parallelism"]),
            "used_tool_calls": int(row["used_tool_calls"]), "max_tool_calls": int(row["max_tool_calls"]),
            "used_tokens": int(row["used_tokens"]), "max_tokens": int(row["max_tokens"]),
            "created_at": row["created_at"], "updated_at": row["updated_at"],
        } for row in rows]})

    @api.post("/swarms")
    @require_user
    def create_swarm(user_id: str):
        data = request.get_json(silent=True) or {}
        objective = str(data.get("objective") or "").strip()[:20000]
        if len(objective) < 10:
            return api_error("KIMU_SWARM_OBJECTIVE_REQUIRED", "Provide a clear swarm objective.", 400)
        approval_mode = str(data.get("approval_mode") or "balanced")
        if approval_mode not in {"manual", "balanced", "autonomous"}:
            return api_error("KIMU_SWARM_APPROVAL_MODE", "Approval mode must be manual, balanced or autonomous.", 400)
        swarm_id, workspace_id = uid("swrm"), uid("wsp")
        max_tool_calls = min(200, max(6, int(data.get("max_tool_calls") or 40)))
        max_seconds = min(7200, max(60, int(data.get("max_seconds") or 900)))
        max_parallelism = min(6, max(1, int(data.get("max_parallelism") or 2)))
        max_tokens = min(500000, max(4000, int(data.get("max_tokens") or 32000)))
        root = _workspace_root(current_app, user_id, workspace_id)
        with closing(_db()) as db, transaction(db):
            db.execute("INSERT INTO workspaces(id,user_id,name,kind,root_path) VALUES(?,?,?,'swarm',?)", (workspace_id, user_id, objective[:100], str(root)))
            db.execute("INSERT INTO swarms(id,user_id,workspace_id,objective,status,max_tool_calls,max_seconds,approval_mode,max_parallelism,max_tokens) VALUES(?,?,?,?,'draft',?,?,?,?,?)", (swarm_id, user_id, workspace_id, objective, max_tool_calls, max_seconds, approval_mode, max_parallelism, max_tokens))
            role_ids = {}
            for sequence, (role, title, model_key, dependencies) in enumerate(_swarm_roles(), 1):
                task_id = uid("stask")
                role_ids[role] = task_id
                db.execute("INSERT INTO swarm_tasks(id,swarm_id,role,title,sequence,depends_on_json,model_key,status,input_json) VALUES(?,?,?,?,?,?,?,'blocked',?)", (task_id, swarm_id, role, title, sequence, json_text(dependencies), model_key, json_text({"objective": objective})))
            db.execute("UPDATE swarm_tasks SET status='queued' WHERE swarm_id=? AND sequence=1", (swarm_id,))
            _append_event(db, "swarm_events", "swarm_id", swarm_id, "created", {"roles": list(role_ids), "max_tool_calls": max_tool_calls, "max_seconds": max_seconds, "approval_mode": approval_mode, "max_parallelism": max_parallelism, "max_tokens": max_tokens})
            _audit(db, user_id, "swarm.created", "swarm", swarm_id, {"workspace_id": workspace_id, "approval_mode": approval_mode})
        return jsonify({"swarm": {"id": swarm_id, "status": "draft", "objective": objective, "workspace_id": workspace_id, "approval_mode": approval_mode}}), 201

    @api.get("/swarms/<swarm_id>")
    @require_user
    def get_swarm(user_id: str, swarm_id: str):
        with closing(_db()) as db:
            row = db.execute("SELECT * FROM swarms WHERE id=? AND user_id=?", (swarm_id, user_id)).fetchone()
            if not row:
                return api_error("KIMU_SWARM_NOT_FOUND", "Swarm not found.", 404)
            tasks = [{**dict(task), "depends_on": json.loads(task["depends_on_json"] or "[]"), "result": json.loads(task["result_json"] or "{}"), "error": json.loads(task["error_json"] or "{}") or None} for task in db.execute("SELECT * FROM swarm_tasks WHERE swarm_id=? ORDER BY sequence", (swarm_id,)).fetchall()]
            events = [{**dict(event), "data": json.loads(event["data_json"] or "{}")} for event in db.execute("SELECT seq,event_type,data_json,created_at FROM swarm_events WHERE swarm_id=? ORDER BY seq DESC LIMIT 200", (swarm_id,)).fetchall()]
            approvals = [dict(item) for item in db.execute("SELECT id,task_id,status,rationale,decided_at,created_at FROM swarm_approvals WHERE swarm_id=? ORDER BY created_at", (swarm_id,)).fetchall()]
            checkpoints = [{"sequence": int(item["sequence"]), "state": json.loads(item["state_json"] or "{}"), "created_at": item["created_at"]} for item in db.execute("SELECT sequence,state_json,created_at FROM swarm_checkpoints WHERE swarm_id=? ORDER BY sequence DESC LIMIT 25", (swarm_id,)).fetchall()]
        return jsonify({"swarm": {
            "id": row["id"], "objective": row["objective"], "status": row["status"], "workspace_id": row["workspace_id"],
            "approval_mode": row["approval_mode"], "max_parallelism": int(row["max_parallelism"]),
            "used_tool_calls": int(row["used_tool_calls"]), "max_tool_calls": int(row["max_tool_calls"]),
            "used_tokens": int(row["used_tokens"]), "max_tokens": int(row["max_tokens"]), "max_seconds": int(row["max_seconds"]),
            "result": json.loads(row["result_json"] or "{}"), "error": json.loads(row["error_json"] or "{}") or None,
            "tasks": tasks, "events": events, "approvals": approvals, "checkpoints": checkpoints,
        }})

    @api.post("/swarms/<swarm_id>/start")
    @require_user
    def start_swarm(user_id: str, swarm_id: str):
        with closing(_db()) as db, transaction(db):
            row = db.execute("SELECT * FROM swarms WHERE id=? AND user_id=?", (swarm_id, user_id)).fetchone()
            if not row:
                return api_error("KIMU_SWARM_NOT_FOUND", "Swarm not found.", 404)
            if row["status"] not in {"draft", "partial", "failed", "awaiting_approval"}:
                return api_error("KIMU_SWARM_STATE", "The swarm cannot be started from its current state.", 409)
            db.execute("UPDATE swarms SET status='queued',cancel_requested=0,error_json='{}',updated_at=CURRENT_TIMESTAMP WHERE id=?", (swarm_id,))
            tasks = db.execute("SELECT id,role,status,depends_on_json FROM swarm_tasks WHERE swarm_id=? ORDER BY sequence", (swarm_id,)).fetchall()
            completed = {task["role"] for task in tasks if task["status"] == "successful"}
            for task in tasks:
                if task["status"] == "successful":
                    continue
                dependencies = json.loads(task["depends_on_json"] or "[]")
                next_status = "queued" if all(dep in completed for dep in dependencies) else "blocked"
                db.execute("UPDATE swarm_tasks SET status=?,error_json='{}',lease_paths_json='[]',updated_at=CURRENT_TIMESTAMP WHERE id=?", (next_status, task["id"]))
            _append_event(db, "swarm_events", "swarm_id", swarm_id, "status", {"status": "queued", "resume": bool(completed), "completed_roles": sorted(completed)})
        threading.Thread(target=_run_swarm, args=(current_app._get_current_object(), swarm_id), daemon=True, name=f"kimu-swarm-{swarm_id[-8:]}").start()
        return jsonify({"id": swarm_id, "status": "queued"}), 202

    @api.post("/swarms/<swarm_id>/approvals/<approval_id>/<decision>")
    @require_user
    def decide_swarm_approval(user_id: str, swarm_id: str, approval_id: str, decision: str):
        if decision not in {"approve", "reject"}:
            return api_error("KIMU_SWARM_APPROVAL_DECISION", "Decision must be approve or reject.", 400)
        with closing(_db()) as db, transaction(db):
            swarm = db.execute("SELECT * FROM swarms WHERE id=? AND user_id=?", (swarm_id, user_id)).fetchone()
            approval = db.execute("SELECT * FROM swarm_approvals WHERE id=? AND swarm_id=?", (approval_id, swarm_id)).fetchone()
            if not swarm or not approval:
                return api_error("KIMU_SWARM_APPROVAL_NOT_FOUND", "Swarm approval not found.", 404)
            if approval["status"] != "pending":
                return api_error("KIMU_SWARM_APPROVAL_STATE", "This approval has already been decided.", 409)
            status = "approved" if decision == "approve" else "rejected"
            db.execute("UPDATE swarm_approvals SET status=?,decided_at=CURRENT_TIMESTAMP WHERE id=?", (status, approval_id))
            if status == "approved":
                db.execute("UPDATE swarm_tasks SET status='queued',error_json='{}',updated_at=CURRENT_TIMESTAMP WHERE id=?", (approval["task_id"],))
                db.execute("UPDATE swarms SET status='queued',error_json='{}',updated_at=CURRENT_TIMESTAMP WHERE id=?", (swarm_id,))
            else:
                rejection = {
                    "code": "KIMU_SWARM_APPROVAL_REJECTED",
                    "message": "The pending Swarm action was rejected by the user.",
                    "details": {"approval_id": approval_id, "task_id": approval["task_id"]},
                }
                db.execute("UPDATE swarm_tasks SET status='failed',error_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text(rejection), approval["task_id"]))
                db.execute("UPDATE swarms SET status='failed',error_json=?,updated_at=CURRENT_TIMESTAMP WHERE id=?", (json_text(rejection), swarm_id))
            _append_event(db, "swarm_events", "swarm_id", swarm_id, f"approval.{status}", {"approval_id": approval_id, "task_id": approval["task_id"]})
            if status == "rejected":
                _append_event(db, "swarm_events", "swarm_id", swarm_id, "failed", rejection)
            _audit(db, user_id, f"swarm.approval_{status}", "swarm", swarm_id, {"approval_id": approval_id, "task_id": approval["task_id"]})
        if status == "approved":
            threading.Thread(target=_run_swarm, args=(current_app._get_current_object(), swarm_id), daemon=True, name=f"kimu-swarm-{swarm_id[-8:]}").start()
        return jsonify({"approval_id": approval_id, "status": status, "swarm_status": "queued" if status == "approved" else "failed"})

    @api.post("/swarms/<swarm_id>/cancel")
    @require_user
    def cancel_swarm(user_id: str, swarm_id: str):
        with closing(_db()) as db:
            row = db.execute("SELECT * FROM swarms WHERE id=? AND user_id=?", (swarm_id, user_id)).fetchone()
            if not row:
                return api_error("KIMU_SWARM_NOT_FOUND", "Swarm not found.", 404)
            db.execute("UPDATE swarms SET cancel_requested=1,updated_at=CURRENT_TIMESTAMP WHERE id=?", (swarm_id,))
            _append_event(db, "swarm_events", "swarm_id", swarm_id, "cancel.requested", {})
        return jsonify({"id": swarm_id, "cancel_requested": True})

    @api.get("/audio/config")
    @require_user
    def audio_config(user_id: str):
        return jsonify({
            "conversation_mode": True,
            "dictation": True,
            "websocket_path": "/api/v1/audio/conversation/ws",
            "stt": {"model": current_app.config["WHISPER_MODEL_ID"], "format": "pcm_s16le_16000", "sample_rate": 16000, "exclusive": True},
            "tts": {"model": current_app.config["SONIC_MODEL_ID"], "sample_rate": current_app.config["TTS_SAMPLE_RATE"], "voices": current_app.config["TTS_VOICES"], "default_voice": current_app.config["TTS_DEFAULT_VOICE"], "exclusive": True},
            "vad": current_app.config["AUDIO_VAD_DEFAULTS"],
            "barge_in": {"enabled": True, "cancels_audio": True, "cancels_model": True, "rejects_stale_turns": True},
            "fake_provider": bool(current_app.config["FAKE_PROVIDER"]),
        })

    app.register_blueprint(api)

    try:
        from .conversation_gateway import register_conversation_gateway
        register_conversation_gateway(app)
        app.config["CONVERSATION_GATEWAY_REGISTERED"] = True
    except Exception as exc:  # package may be absent before install; readiness exposes this
        app.config["CONVERSATION_GATEWAY_REGISTERED"] = False
        app.config["CONVERSATION_GATEWAY_ERROR"] = str(exc)
