【mitmproxy】提取 OpenCode 的 API 接口

前面介绍了 如何通过 mitmproxy的本地捕获代理模式获取 OpenCode 发起的 AI API 请求的详细信息

本文介绍如何提取 OpenCodeAPI 接口

捕获到opencode.ai的流量后,可以导出https://opencode.ai/zen/v1/messages接口的CURL

简化一下导出的CURL(譬如:简化系统提示词,工具列表),发给AI,让AI 转化为 Python 代码

然后再让AI优化微调一下(譬如:抽取函数send_message,创建SSLContext对象,添加重试机制)

调式成功:

示例代码:

python 复制代码
import json
import ssl
import time
from typing import Optional, Dict, Any

import httpx

URL = "https://opencode.ai/zen/v1/messages"
DEFAULT_HEADERS = {
    "Content-Type": "application/json",
    "User-Agent": "ai-sdk/anthropic/3.0.71 ai-sdk/provider-utils/4.0.23 runtime/bun/1.3.13",
    "anthropic-version": "2023-06-01",
    "x-api-key": "public",
    "x-opencode-client": "cli",
    "Connection": "close",
    "Accept": "*/*",
    "Host": "opencode.ai",
}
DEFAULT_PROJECT = "5941d5072d7e941c77cbda55b6a9a3a45bf3a089"
DEFAULT_SESSION = "ses_23ac15dd8ffeiKiFBtkudFHNd2"


def send_message(
        model: str,
        message: str,
        project: Optional[str] = None,
        session: Optional[str] = None,
        request_id: Optional[str] = None,
        system_prompt: Optional[str] = None,
        max_tokens: int = 32000,
        max_retries: int = 3,
        timeout: int = 60,
) -> Dict[str, Any]:
    """
    向 opencode.ai 发送消息并获取 AI 回复。

    参数:
        model: 模型名称,如 "big-pickle"
        message: 用户消息内容
        project: x-opencode-project(可选)
        session: x-opencode-session(可选)
        request_id: x-opencode-request(可选,默认自动生成)
        system_prompt: 系统提示词(可选)
        max_tokens: 最大 token 数
        max_retries: 失败重试次数
        timeout: 请求超时(秒)

    返回:
        包含以下键的字典:
            - text: AI 文本回复
            - thinking: AI 思考内容(如有)
            - full: 原始完整响应数据列表
    """
    if request_id is None:
        import uuid
        request_id = f"msg_{uuid.uuid4().hex[:20]}"

    headers = {
        **DEFAULT_HEADERS,
        "x-opencode-project": project or DEFAULT_PROJECT,
        "x-opencode-session": session or DEFAULT_SESSION,
        "x-opencode-request": request_id,
    }

    system_text = system_prompt or (
        "You are opencode, an interactive CLI tool that helps users with software engineering tasks. "
        "Use the instructions below and the tools available to you to assist the user."
    )

    payload = {
        "model": model,
        "max_tokens": max_tokens,
        "stream": True,
        "system": [{"type": "text", "text": system_text}],
        "messages": [
            {
                "role": "user",
                "content": [{"type": "text", "text": message}],
            }
        ],
    }

    ssl_context = ssl.create_default_context()

    for attempt in range(max_retries):
        try:
            full_response = []
            with httpx.Client(http2=False, verify=ssl_context, timeout=timeout) as client:
                with client.stream("POST", URL, headers=headers, json=payload) as response:
                    if response.status_code != 200:
                        raise RuntimeError(f"HTTP {response.status_code}: {response.text}")

                    text_parts = []
                    thinking_parts = []
                    current_event = None

                    for line in response.iter_lines():
                        if line.startswith("event:"):
                            current_event = line.split(":", 1)[1].strip()
                        elif line.startswith("data:") and current_event:
                            data_str = line.split(":", 1)[1].strip()
                            try:
                                data_obj = json.loads(data_str)
                                full_response.append(data_obj)
                                delta = data_obj.get("delta", {})
                                if delta.get("type") == "thinking_delta":
                                    thinking_parts.append(delta["thinking"])
                                elif delta.get("type") == "text_delta":
                                    text_parts.append(delta["text"])
                            except json.JSONDecodeError:
                                pass

            return {
                "text": "".join(text_parts),
                "thinking": "".join(thinking_parts),
                "full": full_response,
            }

        except (httpx.ConnectError, httpx.ReadError, httpx.RemoteProtocolError) as e:
            if attempt < max_retries - 1:
                wait_time = 2 ** attempt
                time.sleep(wait_time)
            else:
                raise RuntimeError(f"请求失败(已重试 {max_retries} 次): {e}") from e


if __name__ == "__main__":
    result = send_message("big-pickle", "你好")

    if result["thinking"]:
        print("<thinking>")
        print(result["thinking"])
        print("</thinking>")
    print(result["text"])
相关推荐
dog2501 小时前
圆锥曲线和二次曲线
开发语言·网络·人工智能·算法·php
盟接之桥2 小时前
什么是EDI(电子数据交换)|制造业场景解决方案
大数据·网络·安全·汽车·制造
qq_三哥啊2 小时前
【mitmproxy】通过 mitmproxy 的本地捕获代理模式获取 OpenCode 发起的 AI API 请求的详细信息
网络·系统安全·代理模式
IT摆渡者3 小时前
linux 系统安全检查
运维·网络·经验分享·笔记
学习3人组3 小时前
OEE(设备综合效率)的标准定义、公式、损失分类、以及在工位触屏/MES里怎么采集和统计
大数据·网络·数据库
时空自由民.3 小时前
蓝牙协议栈介绍
linux·网络·单片机
ggabb4 小时前
月壤之下:人类驻月先行者
网络
b55t4ck4 小时前
FortiWeb CVE-2025-64446漏洞深入复现分析
网络·安全·iot
wanhengidc4 小时前
可持续性 云手机运行
运维·服务器·网络·安全·智能手机