ns = params_kw.copy()
doc_id = ns.get('doc_id', '')
tag = ns.get('tag', '').strip()
kb_id = ns.get('kb_id', '')
env = request._run_ns

if not doc_id or not tag:
    return json.dumps({"status": "error", "error": "doc_id and tag required"}, ensure_ascii=False)

async with get_sor_context(env, 'rag') as sor:
    # Get existing tags
    recs = await sor.sqlExe("SELECT metadata FROM documents WHERE id=${id}$ AND kb_id=${kb_id}$",
                             {"id": doc_id, "kb_id": kb_id})
    if not recs:
        return json.dumps({"status": "error", "error": "document not found"}, ensure_ascii=False)

    import json as _json
    meta = {}
    try:
        meta = _json.loads(recs[0].metadata or '{}')
    except:
        meta = {}

    tags = meta.get('tags', [])
    if not isinstance(tags, list):
        tags = []

    if tag not in tags:
        tags.append(tag)
        meta['tags'] = tags
        await sor.sqlExe(
            "UPDATE documents SET metadata=${meta}$ WHERE id=${id}$",
            {"meta": _json.dumps(meta, ensure_ascii=False), "id": doc_id})
        return _json.dumps({"status": "SUCCEEDED", "tags": tags, "added": tag}, ensure_ascii=False)
    else:
        return _json.dumps({"status": "SUCCEEDED", "tags": tags, "duplicate": True}, ensure_ascii=False)
