from __future__ import annotations
import asyncio
import json
from ..typing import AsyncResult, Messages
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
from ..errors import ModelNotFoundError
from .. import debug
from .helper import render_messages
def clean_name(name: str) -> str:
return (
name.split("/")[-1]
.replace("-instruct", "")
.replace("-17b-16e", "")
.replace("-chat", "")
.replace("-fp8", "")
.replace("-fast", "")
.replace("-int8", "")
.replace("-awq", "")
.replace("-qvq", "")
.replace("-r1", "")
.replace("meta-llama-", "llama-")
.replace("-it", "")
.replace("qwen-", "qwen")
.replace("qwen", "qwen-")
)
class Cloudflare(AsyncGeneratorProvider, ProviderModelMixin):
label = "Cloudflare AI"
url = "https://playground.ai.cloudflare.com"
working = True
use_nodriver = False
active_by_default = True
supports_stream = True
supports_system_message = True
supports_message_history = True
default_model = "llama-3.3-70b"
model_aliases = {
"deepseek-coder-6.7b": "@hf/thebloke/deepseek-coder-6.7b-instruct-awq",
"deepseek-coder-6.7b-base": "@hf/thebloke/deepseek-coder-6.7b-base-awq",
"deepseek-distill-qwen-32b": "@cf/deepseek-ai/deepseek-r1-distill-qwen-32b",
"deepseek-math-7b": "@cf/deepseek-ai/deepseek-math-7b-instruct",
"discolm-german-7b-v1": "@cf/thebloke/discolm-german-7b-v1-awq",
"falcon-7b": "@cf/tiiuae/falcon-7b-instruct",
"gemma-2b-lora": "@cf/google/gemma-2b-it-lora",
"gemma-3-12b": "@cf/google/gemma-3-12b-it",
"gemma-4-26b-a4b-it": "@cf/google/gemma-4-26b-a4b-it",
"gemma-7b": "@hf/google/gemma-7b-it",
"gemma-7b-it-lora": "@cf/google/gemma-7b-it-lora",
"gemma-sea-lion-v4-27b": "@cf/aisingapore/gemma-sea-lion-v4-27b-it",
"glm-4.7-flash": "@cf/zai-org/glm-4.7-flash",
"glm-5.2": "@cf/zai-org/glm-5.2",
"gpt-oss-120b": "@cf/openai/gpt-oss-120b",
"gpt-oss-20b": "@cf/openai/gpt-oss-20b",
"granite-4.0-h-micro": "@cf/ibm-granite/granite-4.0-h-micro",
"hermes-2-pro-mistral-7b": "@hf/nousresearch/hermes-2-pro-mistral-7b",
"kimi-k2.6": "@cf/moonshotai/kimi-k2.6",
"kimi-k2.7-code": "@cf/moonshotai/kimi-k2.7-code",
"llama-2-13b": "@hf/thebloke/llama-2-13b-chat-awq",
"llama-2-7b": "@cf/meta/llama-2-7b-chat-int8",
"llama-2-7b-fp16": "@cf/meta/llama-2-7b-chat-fp16",
"llama-2-7b-lora": "@cf/meta-llama/llama-2-7b-chat-hf-lora",
"llama-3-8b": "@hf/meta-llama/meta-llama-3-8b-instruct",
"llama-3.1-8b": "@cf/meta/llama-3.1-8b-instruct-fp8",
"llama-3.2-11b-vision": "@cf/meta/llama-3.2-11b-vision-instruct",
"llama-3.2-1b": "@cf/meta/llama-3.2-1b-instruct",
"llama-3.2-3b": "@cf/meta/llama-3.2-3b-instruct",
"llama-3.3-70b": "@cf/meta/llama-3.3-70b-instruct-fp8-fast",
"llama-4-scout": "@cf/meta/llama-4-scout-17b-16e-instruct",
"llama-guard-3-8b": "@cf/meta/llama-guard-3-8b",
"llamaguard-7b": "@hf/thebloke/llamaguard-7b-awq",
"mistral-7b-v0.1": "@hf/thebloke/mistral-7b-instruct-v0.1-awq",
"mistral-7b-v0.2": "@hf/mistral/mistral-7b-instruct-v0.2",
"mistral-7b-v0.2-lora": "@cf/mistral/mistral-7b-instruct-v0.2-lora",
"mistral-small-3.1-24b": "@cf/mistralai/mistral-small-3.1-24b-instruct",
"nemotron-3-120b": "@cf/nvidia/nemotron-3-120b-a12b",
"neural-7b-v3-1": "@hf/thebloke/neural-chat-7b-v3-1-awq",
"openchat-3.5-0106": "@cf/openchat/openchat-3.5-0106",
"openhermes-2.5-mistral-7b": "@hf/thebloke/openhermes-2.5-mistral-7b-awq",
"phi-2": "@cf/microsoft/phi-2",
"qwen-1.5-1.8b": "@cf/qwen/qwen1.5-1.8b-chat",
"qwen-1.5-14b": "@cf/qwen/qwen1.5-14b-chat-awq",
"qwen-1.5-7b": "@cf/qwen/qwen1.5-7b-chat-awq",
"qwen-2.5-coder-32b": "@cf/qwen/qwen2.5-coder-32b-instruct",
"qwen1.5-0.5b": "@cf/qwen/qwen1.5-0.5b-chat",
"qwen3-30b-a3b": "@cf/qwen/qwen3-30b-a3b-fp8",
"qwq-32b": "@cf/qwen/qwq-32b",
"sqlcoder-7b-2": "@cf/defog/sqlcoder-7b-2",
"starling-lm-7b-beta": "@hf/nexusflow/starling-lm-7b-beta",
"tinyllama-1.1b-v1.0": "@cf/tinyllama/tinyllama-1.1b-chat-v1.0",
"una-cybertron-7b-v2-bf16": "@cf/fblgit/una-cybertron-7b-v2-bf16",
"zephyr-7b-beta": "@hf/thebloke/zephyr-7b-beta-awq",
}
models = list(model_aliases.keys())
@classmethod
async def create_async_generator(
cls,
model: str,
messages: Messages,
proxy: str = None,
max_tokens: int = 2048,
**kwargs,
) -> AsyncResult:
try:
from ..requests.cdp import CDPSession
except ImportError:
raise RuntimeError(
"CDP module is required for Cloudflare provider. Please ensure g4f.requests.cdp is available."
)
try:
model = cls.get_model(model)
except ModelNotFoundError:
pass
debug.log("Cloudflare: Starting CDPSession...")
session = CDPSession(headless=False)
await session.start()
try:
await session.navigate(cls.url)
# Wait for Cloudflare validation to pass and React to load
await asyncio.sleep(5)
for _ in range(30):
title = await session.evaluate_js("document.title") or ""
content = await session.evaluate_js("document.body.innerText") or ""
if (
title
and "Just a moment" not in title
and "Attention Required" not in title
and "cf-browser-verification" not in content
):
break
await asyncio.sleep(1)
# Setup event queue for console logs
q = asyncio.Queue()
session.add_event_handler("Runtime.consoleAPICalled", q)
# Render messages to the format expected by Cloudflare UI
cf_messages = [
{
"role": msg["role"],
"parts": [{"type": "text", "text": msg["content"]}],
"id": f"msg_{i}",
}
for i, msg in enumerate(render_messages(messages))
]
# Inject JS to handle the WebSocket stream
js_code = f"""
async function runChat() {{
const pk = crypto.randomUUID();
const agentId = 'playground-' + Math.random().toString(36).substring(2, 15);
const modelStr = {json.dumps(model)};
const wsUrl = `wss://playground.ai.cloudflare.com/agents/playground/${{agentId}}?_pk=${{pk}}&model=${{encodeURIComponent(modelStr)}}`;
const ws = new WebSocket(wsUrl);
ws.onopen = () => {{
ws.send(JSON.stringify({{"type":"cf_agent_stream_resume_request"}}));
ws.send(JSON.stringify({{"name":agentId,"agent":"playground","type":"cf_agent_identity"}}));
ws.send(JSON.stringify({{"state":{{"model":modelStr,"temperature":1,"stream":true,"system":"You are a helpful assistant.","useExternalProvider":false,"externalProvider":"openai","generativeUI":false}},"type":"cf_agent_state"}}));
ws.send(JSON.stringify({{"mcp":{{"prompts":[],"resources":[],"servers":{{}},"tools":[]}},"type":"cf_agent_mcp_servers"}}));
ws.send(JSON.stringify({{"type":"cf_agent_stream_resume_none"}}));
setTimeout(() => {{
const req = {{
"id": "req_" + Math.random().toString(36).substring(2, 10),
"init": {{
"method": "POST",
"body": JSON.stringify({{
"messages": {json.dumps(cf_messages)},
"trigger": "submit-message"
}})
}},
"type": "cf_agent_use_chat_request"
}};
ws.send(JSON.stringify(req));
}}, 1000);
}};
ws.onmessage = (event) => {{
try {{
const data = JSON.parse(event.data);
if (data.type === 'cf_agent_use_chat_response') {{
const body = JSON.parse(data.body);
if (body.type === 'text-delta') {{
console.log("CF_CHUNK: " + body.delta);
}} else if (body.type === 'finish-step' || body.type === 'finish') {{
console.log("CF_DONE");
ws.close();
}}
}}
}} catch (e) {{}}
}};
ws.onerror = () => console.log("CF_ERROR");
ws.onclose = () => console.log("CF_DONE");
}}
runChat();
"""
debug.log("Cloudflare: Injecting WebSocket streaming JS...")
await session.evaluate_js(js_code)
# Yield from the queue
last_val = None
while True:
try:
event = await asyncio.wait_for(q.get(), timeout=30.0)
args = event.get("args", [])
if args and args[0].get("type") == "string":
val = args[0].get("value", "")
if val == last_val:
continue
last_val = val
if val.startswith("CF_CHUNK: "):
yield val[10:]
elif val == "CF_DONE":
break
elif val == "CF_ERROR":
raise RuntimeError(
"WebSocket error inside Cloudflare session"
)
except asyncio.TimeoutError:
raise TimeoutError("Timeout waiting for Cloudflare response")
finally:
session.remove_event_handler("Runtime.consoleAPICalled", q)
await session.close()
from __future__ import annotations
import asyncio
import json
from ..typing import AsyncResult, Messages
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
from ..errors import ModelNotFoundError
from .. import debug
from .helper import render_messages
def clean_name(name: str) -> str:
return (
name.split("/")[-1]
.replace("-instruct", "")
.replace("-17b-16e", "")
.replace("-chat", "")
.replace("-fp8", "")
.replace("-fast", "")
.replace("-int8", "")
.replace("-awq", "")
.replace("-qvq", "")
.replace("-r1", "")
.replace("meta-llama-", "llama-")
.replace("-it", "")
.replace("qwen-", "qwen")
.replace("qwen", "qwen-")
)
class Cloudflare(AsyncGeneratorProvider, ProviderModelMixin):
label = "Cloudflare AI"
url = "https://playground.ai.cloudflare.com"
working = True
use_nodriver = False
active_by_default = True
supports_stream = True
supports_system_message = True
supports_message_history = True
default_model = "llama-3.3-70b"
model_aliases = {
"deepseek-coder-6.7b": "@hf/thebloke/deepseek-coder-6.7b-instruct-awq",
"deepseek-coder-6.7b-base": "@hf/thebloke/deepseek-coder-6.7b-base-awq",
"deepseek-distill-qwen-32b": "@cf/deepseek-ai/deepseek-r1-distill-qwen-32b",
"deepseek-math-7b": "@cf/deepseek-ai/deepseek-math-7b-instruct",
"discolm-german-7b-v1": "@cf/thebloke/discolm-german-7b-v1-awq",
"falcon-7b": "@cf/tiiuae/falcon-7b-instruct",
"gemma-2b-lora": "@cf/google/gemma-2b-it-lora",
"gemma-3-12b": "@cf/google/gemma-3-12b-it",
"gemma-4-26b-a4b-it": "@cf/google/gemma-4-26b-a4b-it",
"gemma-7b": "@hf/google/gemma-7b-it",
"gemma-7b-it-lora": "@cf/google/gemma-7b-it-lora",
"gemma-sea-lion-v4-27b": "@cf/aisingapore/gemma-sea-lion-v4-27b-it",
"glm-4.7-flash": "@cf/zai-org/glm-4.7-flash",
"glm-5.2": "@cf/zai-org/glm-5.2",
"gpt-oss-120b": "@cf/openai/gpt-oss-120b",
"gpt-oss-20b": "@cf/openai/gpt-oss-20b",
"granite-4.0-h-micro": "@cf/ibm-granite/granite-4.0-h-micro",
"hermes-2-pro-mistral-7b": "@hf/nousresearch/hermes-2-pro-mistral-7b",
"kimi-k2.6": "@cf/moonshotai/kimi-k2.6",
"kimi-k2.7-code": "@cf/moonshotai/kimi-k2.7-code",
"llama-2-13b": "@hf/thebloke/llama-2-13b-chat-awq",
"llama-2-7b": "@cf/meta/llama-2-7b-chat-int8",
"llama-2-7b-fp16": "@cf/meta/llama-2-7b-chat-fp16",
"llama-2-7b-lora": "@cf/meta-llama/llama-2-7b-chat-hf-lora",
"llama-3-8b": "@hf/meta-llama/meta-llama-3-8b-instruct",
"llama-3.1-8b": "@cf/meta/llama-3.1-8b-instruct-fp8",
"llama-3.2-11b-vision": "@cf/meta/llama-3.2-11b-vision-instruct",
"llama-3.2-1b": "@cf/meta/llama-3.2-1b-instruct",
"llama-3.2-3b": "@cf/meta/llama-3.2-3b-instruct",
"llama-3.3-70b": "@cf/meta/llama-3.3-70b-instruct-fp8-fast",
"llama-4-scout": "@cf/meta/llama-4-scout-17b-16e-instruct",
"llama-guard-3-8b": "@cf/meta/llama-guard-3-8b",
"llamaguard-7b": "@hf/thebloke/llamaguard-7b-awq",
"mistral-7b-v0.1": "@hf/thebloke/mistral-7b-instruct-v0.1-awq",
"mistral-7b-v0.2": "@hf/mistral/mistral-7b-instruct-v0.2",
"mistral-7b-v0.2-lora": "@cf/mistral/mistral-7b-instruct-v0.2-lora",
"mistral-small-3.1-24b": "@cf/mistralai/mistral-small-3.1-24b-instruct",
"nemotron-3-120b": "@cf/nvidia/nemotron-3-120b-a12b",
"neural-7b-v3-1": "@hf/thebloke/neural-chat-7b-v3-1-awq",
"openchat-3.5-0106": "@cf/openchat/openchat-3.5-0106",
"openhermes-2.5-mistral-7b": "@hf/thebloke/openhermes-2.5-mistral-7b-awq",
"phi-2": "@cf/microsoft/phi-2",
"qwen-1.5-1.8b": "@cf/qwen/qwen1.5-1.8b-chat",
"qwen-1.5-14b": "@cf/qwen/qwen1.5-14b-chat-awq",
"qwen-1.5-7b": "@cf/qwen/qwen1.5-7b-chat-awq",
"qwen-2.5-coder-32b": "@cf/qwen/qwen2.5-coder-32b-instruct",
"qwen1.5-0.5b": "@cf/qwen/qwen1.5-0.5b-chat",
"qwen3-30b-a3b": "@cf/qwen/qwen3-30b-a3b-fp8",
"qwq-32b": "@cf/qwen/qwq-32b",
"sqlcoder-7b-2": "@cf/defog/sqlcoder-7b-2",
"starling-lm-7b-beta": "@hf/nexusflow/starling-lm-7b-beta",
"tinyllama-1.1b-v1.0": "@cf/tinyllama/tinyllama-1.1b-chat-v1.0",
"una-cybertron-7b-v2-bf16": "@cf/fblgit/una-cybertron-7b-v2-bf16",
"zephyr-7b-beta": "@hf/thebloke/zephyr-7b-beta-awq",
}
models = list(model_aliases.keys())
@classmethod
async def create_async_generator(
cls,
model: str,
messages: Messages,
proxy: str = None,
max_tokens: int = 2048,
**kwargs,
) -> AsyncResult:
try:
from ..requests.cdp import CDPSession
except ImportError:
raise RuntimeError(
"CDP module is required for Cloudflare provider. Please ensure g4f.requests.cdp is available."
)
try:
model = cls.get_model(model)
except ModelNotFoundError:
pass
debug.log("Cloudflare: Starting CDPSession...")
session = CDPSession(headless=False)
await session.start()
try:
await session.navigate(cls.url)
# Wait for Cloudflare validation to pass and React to load
await asyncio.sleep(5)
for _ in range(30):
title = await session.evaluate_js("document.title") or ""
content = await session.evaluate_js("document.body.innerText") or ""
if (
title
and "Just a moment" not in title
and "Attention Required" not in title
and "cf-browser-verification" not in content
):
break
await asyncio.sleep(1)
# Setup event queue for console logs
q = asyncio.Queue()
session.add_event_handler("Runtime.consoleAPICalled", q)
# Render messages to the format expected by Cloudflare UI
cf_messages = [
{
"role": msg["role"],
"parts": [{"type": "text", "text": msg["content"]}],
"id": f"msg_{i}",
}
for i, msg in enumerate(render_messages(messages))
]
# Inject JS to handle the WebSocket stream
js_code = f"""
async function runChat() {{
const pk = crypto.randomUUID();
const agentId = 'playground-' + Math.random().toString(36).substring(2, 15);
const modelStr = {json.dumps(model)};
const wsUrl = `wss://playground.ai.cloudflare.com/agents/playground/${{agentId}}?_pk=${{pk}}&model=${{encodeURIComponent(modelStr)}}`;
const ws = new WebSocket(wsUrl);
ws.onopen = () => {{
ws.send(JSON.stringify({{"type":"cf_agent_stream_resume_request"}}));
ws.send(JSON.stringify({{"name":agentId,"agent":"playground","type":"cf_agent_identity"}}));
ws.send(JSON.stringify({{"state":{{"model":modelStr,"temperature":1,"stream":true,"system":"You are a helpful assistant.","useExternalProvider":false,"externalProvider":"openai","generativeUI":false}},"type":"cf_agent_state"}}));
ws.send(JSON.stringify({{"mcp":{{"prompts":[],"resources":[],"servers":{{}},"tools":[]}},"type":"cf_agent_mcp_servers"}}));
ws.send(JSON.stringify({{"type":"cf_agent_stream_resume_none"}}));
setTimeout(() => {{
const req = {{
"id": "req_" + Math.random().toString(36).substring(2, 10),
"init": {{
"method": "POST",
"body": JSON.stringify({{
"messages": {json.dumps(cf_messages)},
"trigger": "submit-message"
}})
}},
"type": "cf_agent_use_chat_request"
}};
ws.send(JSON.stringify(req));
}}, 1000);
}};
ws.onmessage = (event) => {{
try {{
const data = JSON.parse(event.data);
if (data.type === 'cf_agent_use_chat_response') {{
const body = JSON.parse(data.body);
if (body.type === 'text-delta') {{
console.log("CF_CHUNK: " + body.delta);
}} else if (body.type === 'finish-step' || body.type === 'finish') {{
console.log("CF_DONE");
ws.close();
}}
}}
}} catch (e) {{}}
}};
ws.onerror = () => console.log("CF_ERROR");
ws.onclose = () => console.log("CF_DONE");
}}
runChat();
"""
debug.log("Cloudflare: Injecting WebSocket streaming JS...")
await session.evaluate_js(js_code)
# Yield from the queue
last_val = None
while True:
try:
event = await asyncio.wait_for(q.get(), timeout=30.0)
args = event.get("args", [])
if args and args[0].get("type") == "string":
val = args[0].get("value", "")
if val == last_val:
continue
last_val = val
if val.startswith("CF_CHUNK: "):
yield val[10:]
elif val == "CF_DONE":
break
elif val == "CF_ERROR":
raise RuntimeError(
"WebSocket error inside Cloudflare session"
)
except asyncio.TimeoutError:
raise TimeoutError("Timeout waiting for Cloudflare response")
finally:
session.remove_event_handler("Runtime.consoleAPICalled", q)
await session.close()