Skip to main content

wisruntime — 企业级 Agent Runtime SDK

版本: v0.2.0 (Adapter Layer) | 日期: 2026-07 | 团队: WIS Team


一、项目概述

1.1 定位

wisruntime 是一个企业级 Agent Runtime SDK(Python),以 pip install 方式提供给 AI 应用工程师使用。

它的核心使命:让 Agent 工程师专注 Agent 能力开发,无需关心底层基础设施。

1.2 一句话描述

为 Agent 开发者提供轻量、可扩展、多框架适配的统一运行时 SDK——用框架原生 API 构建 Agent 后,数行代码即可获得完整的生产级服务端点,并自动接入 WIS Hub 平台能力(MCP / Skill / Sandbox)。

1.3 核心价值

              没有 wisruntime                          有了 wisruntime
              ══════════════                          ══════════════

  AI 工程师 → 写 FastAPI 路由               AI 工程师 → 写 invoke_agent 函数
       → 处理 SSE 流式协议                        → create_server(invoke_agent).start(8000)
       → 对接 MCP 协议                            → ✅ Dify SSE 服务就绪
       → 对接 Skill API                           → ✅ 平台能力自动接入
       → 管理 Sandbox                             → ✅ API-KEY 统一鉴权
       → 对接鉴权系统                             → ✅ 开箱即用
       → 每个应用都重复一遍

1.4 对标参考

本架构深度借鉴了阿里云 AgentRun Python SDK 的分层设计思想,在其基础上针对 WIS Hub 平台的差异化特点(统一 API-KEY 鉴权、Dify SSE 协议、DeepAgents 框架、平台能力托管)进行了重新设计。


二、整体架构

2.1 分层架构图

┌──────────────────────────────────────────────────────────────────────┐
│                        WIS Hub 平台 (AI 中台)                         │
│                                                                      │
│  MCP 服务   │  Skill 服务  │  Sandbox 服务  │  Checkpoint 服务       │
│  (REST)     │  (REST)      │  (REST)        │  (REST)               │
│                                                                      │
│  统一 API-KEY 鉴权:  创建应用 → 勾选能力 → 生成 Key                     │
└────────────────────────────┬─────────────────────────────────────────┘
                             │  HTTPS + Bearer <API-KEY>
                             │
┌────────────────────────────┴─────────────────────────────────────────┐
│                         wisruntime SDK                                │
│                                                                      │
│  ┌────────────────────────────────────────────────────────────────┐  │
│  │  Infrastructure 层                                              │  │
│  │  Config (API-KEY / 端点 / 超时)                                  │  │
│  │  CredentialContext (contextvars: 请求级 API-KEY 注入)            │  │
│  │  BaseModel / 异常定义 / 日志                                     │  │
│  └────────────────────────────────────────────────────────────────┘  │
│                                                                      │
│  ┌────────────────────────────────────────────────────────────────┐  │
│  │  Platform Client 层 (框架无关,只写一次)                         │  │
│  │                                                                  │  │
│  │  mcp/MCPClient      skill/SkillClient                           │  │
│  │  sandbox/SandboxClient   memory/CheckpointClient                │  │
│  │                                                                  │  │
│  │  每个 Client: 自动读 API-KEY, 统一错误处理, 异步 HTTP (httpx)    │  │
│  └────────────────────────────────────────────────────────────────┘  │
│                                                                      │
│  ┌────────────────────────────────────────────────────────────────┐  │
│  │  Capability Bridge 层 (每个框架一份)                             │  │
│  │                                                                  │  │
│  │  adapters/deepagents/                                           │  │
│  │    ├── mcp.py       MCPClient   → DeepAgents BaseTool           │  │
│  │    ├── skill.py     SkillClient → DeepAgents BaseTool           │  │
│  │    └── sandbox.py   SandboxClient → DeepAgents BaseTool          │  │
│  │                                                                  │  │
│  │  adapters/agentscope/  (未来)                                    │  │
│  └────────────────────────────────────────────────────────────────┘  │
│                                                                      │
│  ┌────────────────────────────────────────────────────────────────┐  │
│  │  Adapter 层 (用户可选工具: Agent 对象 → invoke_agent 函数)       │  │
│  │                                                                  │  │
│  │  提供两种使用方式:                                                 │  │
│  │  ① wrap_agent(agent) → invoke_agent 函数 (便捷包装)              │  │
│  │  ② 用户在 invoke_agent 内部手动做事件转换                         │  │
│  │                                                                  │  │
│  │  adapters/deepagents/   (DeepAgents 事件 → CanonicalEvent)      │  │
│  │  adapters/agentscope/   (未来)                                   │  │
│  └────────────────────────────────────────────────────────────────┘  │
│                                                                      │
│  ┌────────────────────────────────────────────────────────────────┐  │
│  │  Server 层 (框架无关,只认函数)                                    │  │
│  │                                                                  │  │
│  │  ┌──────────────┐  ┌──────────────┐  ┌───────────────────┐     │  │
│  │  │ DifyHandler  │  │AGUIHandler   │  │  AgentInvoker     │     │  │
│  │  │ SSE+Blocking │  │  (规划中)     │  │  函数归一化引擎    │     │  │
│  │  └──────┬───────┘  └──────┬───────┘  └─────────┬─────────┘     │  │
│  │         └─────────────────┴────────────────────┘                │  │
│  │                           │                                      │  │
│  │                    CanonicalEvent                                │  │
│  │                    ProtocolRegistry                              │  │
│  └────────────────────────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────────────────────────┘

2.2 分层职责

层 职责 关键组件
Infrastructure 全局配置、凭证注入、基础模型 Config, CredentialContext, BaseModel
Platform Client 封装 WIS Hub REST API 调用,统一鉴权 MCPClient, SkillClient, SandboxClient, CheckpointClient
Capability Bridge 平台客户端 → 框架原生 Tool 对象转换 DeepAgentsMCPTool, DeepAgentsSkillTool
Adapter (用户可选) Agent 对象 → invoke_agent 函数包装,及框架事件 → CanonicalEvent 转换 wrap_agent(), DeepAgentsAdapter
Server HTTP 服务承载、协议路由、请求校验、响应序列化。只接收 invoke_agent 函数 DifyHandler, AgentInvoker, ProtocolRegistry

2.3 关键设计决策

决策 说明 参考来源
API-KEY 唯一鉴权 不引入 AK/SK/STS 签名体系,整个应用只用一个 API-KEY WIS Hub 平台特征
SDK 不管理资源生命周期 资源由 WIS Hub 平台管理,SDK 只做运行时调用(零 CRUD) 与 AgentRun 的核心差异
Platform Client 框架无关 MCP/Skill/Sandbox 客户端只写一次,所有框架共享 AgentRun Resource 层思想
Capability Bridge 每个框架一份 将平台客户端转为框架原生 Tool 对象 AgentRun Integration 层思想
CanonicalEvent 13 种类型 综合 LangChain v2/v3、Dify/Wisknow、AgentRun 四套事件体系 见第三节
Server 只接收 invoke_agent 函数 Server 不知道框架的存在,用户函数 = 唯一入口。与 AgentRun 完全一致 AgentRun AgentRunServer
AgentInvoker 单层归一化 用户函数 yield 的 str/AgentEvent → CanonicalEvent 流 AgentRun AgentInvoker 模式
协议处理器双向负责 Handler 负责请求解析 + 响应序列化 AgentRun Protocol Handler 模式
contextvars 注入 API-KEY Server 模式下从请求 Bearer 头提取 → 注入请求上下文 AgentRun CredentialContext 模式

三、CanonicalEvent 设计

CanonicalEvent 是 wisruntime 的核心抽象——框架事件和协议事件之间唯一的稳定契约。所有 Adapter 产出 CanonicalEvent,所有 ProtocolHandler 消费 CanonicalEvent。

3.1 13 种 CanonicalEvent 类型

┌──────────────────────────────────────────────────────────────────────┐
│                      CanonicalEvent 类型体系 (13 种)                   │
├──────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  ┌──────────────────────────────────────────────────────────────┐   │
│  │  内容流事件                                                     │   │
│  │  TextDelta         文本增量 (token 级)                          │   │
│  │  ReasoningDelta    推理增量 (CoT 思维链 / extended thinking)    │   │
│  │  FileOutput        文件输出 (图片/音频/视频/文件)                 │   │
│  └──────────────────────────────────────────────────────────────┘   │
│                                                                      │
│  ┌──────────────────────────────────────────────────────────────┐   │
│  │  工具调用生命周期                                                │   │
│  │  ToolCallStart     工具调用开始 (name + args_delta 分块流式)     │   │
│  │  ToolCallEnd       工具调用结束 (result 或 error)               │   │
│  └──────────────────────────────────────────────────────────────┘   │
│                                                                      │
│  ┌──────────────────────────────────────────────────────────────┐   │
│  │  子Agent 生命周期 (DeepAgents 子智能体委派)                       │   │
│  │  SubAgentStart     子Agent 开始运行 (agent_name, run_id, task)  │   │
│  │  SubAgentEnd       子Agent 运行结束 (status: completed/failed)  │   │
│  └──────────────────────────────────────────────────────────────┘   │
│                                                                      │
│  ┌──────────────────────────────────────────────────────────────┐   │
│  │  图执行生命周期 (🆕 v0.2)                                        │   │
│  │  NodeLifecycleEvent  LangGraph 节点生命周期                      │   │
│  │    (node_name, node_type, phase=start/end, run_id, metadata)    │   │
│  └──────────────────────────────────────────────────────────────┘   │
│                                                                      │
│  ┌──────────────────────────────────────────────────────────────┐   │
│  │  人机协作 (🆕 v0.2)                                             │   │
│  │  InterruptEvent     Agent 暂停等待人工输入/审批                  │   │
│  │    (interrupt_id, node_name, message, data)                    │   │
│  └──────────────────────────────────────────────────────────────┘   │
│                                                                      │
│  ┌──────────────────────────────────────────────────────────────┐   │
│  │  元事件                                                         │   │
│  │  Usage             Token 用量统计 (prompt/completion/total)     │   │
│  │  Error             错误事件 (message, code, recoverable)        │   │
│  │  Custom            自定义事件 (name + payload 扩展通道)          │   │
│  │  Done              流结束标记 (由 AgentInvoker 自动插入)         │   │
│  └──────────────────────────────────────────────────────────────┘   │
│                                                                      │
└──────────────────────────────────────────────────────────────────────┘

3.2 LangGraph → CanonicalEvent → Dify SSE 完整事件映射表

下表展示从 LangGraph astream_events v2 事件,经 LangGraphEventConverter 转换为 CanonicalEvent,再经 DifyHandler 序列化为 Dify SSE 格式的完整链路。

LangGraph astream_events v2          CanonicalEvent               Dify SSE
══════════════════════════            ════════════════             ════════════

on_chat_model_stream
  chunk.content (str)                TextDeltaEvent               agent_message
                                       delta=<content>              { event, task_id, id<message_id>,
                                                                     answer }

  chunk.tool_call_chunks[]           ToolCallStartEvent            agent_thought
    first chunk: {id, name, args}      tool_call_id=<id>             { event, task_id,
    subsequent: {index, args}          name=<name>                     id<tool_call_id>,
                                       args_delta=<args>              message_id, position,
                                                                       tool, tool_input }

  chunk.reasoning_content            ReasoningDeltaEvent           reasoning_chunk
    (DeepSeek/Claude thinking)         delta=<reasoning>             { event, task_id,
                                                                       reasoning }

on_chat_model_end
  output.token_usage                 UsageEvent                    (累积到 message_end
                                       prompt/completion/total       metadata.usage)

on_tool_start
  name="task"                        SubAgentStartEvent            subagent_start
    input.subagent_type                agent_name=<type>             { agent_name, run_id,
    input.description                  task_description=<desc>         task_description }
  name≠"task"                        ToolCallStartEvent            agent_thought
    (if not via stream)                (去重,避免重复发送)            (同上)

on_tool_end
  name="task"                        SubAgentEndEvent              subagent_end
    output                            status="completed"             { agent_name, run_id, status }
  name≠"task"                        ToolCallEndEvent              agent_thought
    output=<result>                    result=<formatted>             { observation }

on_tool_error                        ErrorEvent                    error
                                       code="TOOL_ERROR"             { message, code, status=500 }

on_chain_start                       NodeLifecycleEvent            node_started
  name="model" / "tools" / ...         phase="start"                 { node_id<run_id>,
                                       node_type=<inferred>            node_type, title }

on_chain_end                         NodeLifecycleEvent            node_finished
                                       phase="end"                   { node_id, node_type, title }

on_custom_event                      CustomEvent                   { event: <name>,
  (from get_stream_writer)             name=<event_name>              ...payload }
                                       payload=<data>

on_chain_error /                     ErrorEvent                    error
on_llm_error /                         code="CHAIN_ERROR" /          { message, code, status=500 }
on_retriever_error                     "LLM_ERROR" / ...

interrupt() / interrupt_on           InterruptEvent                workflow_paused
  (LangGraph interrupt)                interrupt_id, node_name,       { message, node_name }
                                       message, data

(user fn 正常结束)                     DoneEvent                     message_end
  (AgentInvoker 自动插入)              metadata                       { task_id, id<message_id>,
                                                                       metadata: { usage,
                                                                         conversation_id },
                                                                       files: [] }

3.3 数据流

                        ┌─── invoke_agent 函数 (用户编写) ───┐
                        │                                    │
                        │  用户可以在函数内部:                  │
                        │  · 直接 yield str / CanonicalEvent  │
                        │  · 使用 wrap_agent(agent) 自动转换  │
                        │  · 手写 LangGraphEventConverter     │
                        │  · 调用 MCPClient / SkillClient     │
                        │                                    │
                        └────────────┬───────────────────────┘
                                     │
                                     ▼
                        ┌─────────────────────────┐
                        │     AgentInvoker         │  ← 归一化:
                        │                          │     str → TextDelta
                        │  AsyncGenerator[          │     chunk → TextDelta+ReasoningDelta
                        │    CanonicalEvent]        │     异常 → Error, 透传 CanonicalEvent
                        │                          │     自动 Done, 同步生成器支持
                        └────────────┬────────────┘
                                     │
                                     ▼
                        ┌─────────────────────────┐
                        │   ProtocolHandler        │  ← 序列化: CanonicalEvent → SSE/JSON
                        │                          │
                        │  DifyHandler → Dify SSE  │     生成 message_id
                        │  (未来) AGUIHandler      │     回传 conversation_id
                        └─────────────────────────┘

  Adapter 层: wrap_agent → LangGraphEventConverter → CanonicalEvent 流 → yield

四、分层详解

4.1 Infrastructure 层

┌────────────────────────────────────────────────────┐
│  Config                                             │
│  ├── api_key: str          统一 API-KEY             │
│  ├── hub_endpoint: str     WIS Hub 地址             │
│  ├── timeout: int = 600    请求超时(秒)             │
│  └── 获取优先级:                                     │
│      1. 显式传入 Config(api_key="...")              │
│      2. 环境变量 WIS_HUB_API_KEY                    │
│      3. 请求级 contextvars overlay (Server 模式)     │
│                                                     │
│  CredentialContext (contextvars)                    │
│  ├── get_request_api_key() → Optional[str]          │
│  ├── set_request_api_key(key) 上下文管理器          │
│  └── 用途: Server 模式从 Bearer 头注入 → 全局可用    │
│                                                     │
│  ApiKeyMiddleware (纯 ASGI)                          │
│  ├── 每次请求从 Authorization: Bearer <KEY> 解析     │
│  ├── 注入 contextvars overlay                       │
│  └── 请求结束时自动复位                               │
└────────────────────────────────────────────────────┘

与 AgentRun 的差异: AgentRun 使用 AK/SK + STS + RAM 签名三级体系,wisruntime 只使用 API-KEY,结构大幅简化。但 contextvars 注入模式完全复用。

4.2 Platform Client 层

核心原则: 框架无关,只写一次。只做运行时调用,不做资源 CRUD。

WIS Hub 平台负责资源的创建和管理,SDK 不需要 create() / delete() 操作。每个 Client 只需要:

# 统一模式 (以 MCP 为例)
class MCPClient:
    def __init__(self, base_url=None, api_key=None, timeout=600):
        self._base_url = base_url or f"{Config.current().hub_endpoint}/mcp"
        self._api_key = api_key
        self._timeout = timeout

    @property
    def api_key(self) -> str:
        """三级获取: 显式传入 → contextvars → 环境变量"""
        return self._api_key or CredentialContext.get_request_api_key()

    async def call(self, method: str, params: dict) -> dict:
        """调用 MCP 工具"""
        ...

    async def list_tools(self) -> list[dict]:
        """列出可用工具"""
        ...

各 Client 职责:

Client 职责 端点示例
MCPClient 调用 WIS Hub 托管的 MCP 服务 POST /mcp/invoke
SkillClient 调用 WIS Hub 托管的 Skill POST /skill/{name}/invoke
SandboxClient 代码/浏览器沙箱执行 POST /sandbox/execute
CheckpointClient 会话检查点读写 GET/POST /checkpoint/{conversation_id}

4.3 Capability Bridge 层

核心原则: 将平台客户端转换为框架原生的 Tool 对象。每个框架写一份。

# 以 DeepAgents 为例
from wisruntime.adapters.deepagents.mcp import DeepAgentsMCPTool

# MCPClient → DeepAgents BaseTool
tool = DeepAgentsMCPTool(
    client=MCPClient(),
    name="company_search",
    description="搜索公司内部知识库"
)

agent = create_deep_agent(tools=[tool])

为什么需要这一层? DeepAgents 的 BaseTool 有特定的接口要求(如 ainvoke、schema、name)。MCPClient 返回的是原始 HTTP 响应。这层 Bridge 负责把 REST API 调用适配为框架期望的 Tool 协议。

4.4 Adapter 层

定位: 用户可选工具层。Server 不调用 Adapter,Adapter 是用户在 invoke_agent 中使用的辅助工具。

与 AgentRun 的设计一致:AgentRun 的 AgentRunConverter(仅 LangGraph 需要)是用户在 invoke_agent 内部自行使用的,不是 Server 的依赖。

两种使用方式:

方式 A: 用 wrap_agent 把 Agent 对象包装成 invoke_agent 函数 (便捷)
════════════════════════════════════════════════════════════════════

  from wisruntime.adapters.deepagents import wrap_agent

  agent = create_deep_agent(tools=[...])
  create_server(wrap_agent(agent)).start(8000)
  # wrap_agent 内部: Agent.astream_events → CanonicalEvent 流 → invoke_agent 函数


方式 B: 在 invoke_agent 内部手动做事件转换 (完全控制)
════════════════════════════════════════════════════════════════════

  from wisruntime.adapters.deepagents import DeepAgentsAdapter

  async def my_invoke_agent(request: AgentRequest):
      agent = create_deep_agent(tools=[...])
      adapter = DeepAgentsAdapter()
      async for event in agent.astream_events(request.messages):
          canonical = adapter.convert(event)  # 框架事件 → CanonicalEvent
          if canonical:
              yield canonical

  create_server(my_invoke_agent).start(8000)

Adapter 内部需要处理的核心问题 (参考 AgentRun AgentRunConverter):

问题 解决方案
流式工具调用 ID 追踪 维护 tool_call_index → id 映射,ToolCallStart 时携带 id
推理/文本分离 检测 reasoning_content 或 reasoning-delta → ReasoningDelta
结束检测 v2: on_chain_end + name="LangGraph"; v3: message-finish
错误降级 on_tool_error → ToolCallEnd(error=...),不升级为全局 Error

4.5 Server 层

核心原则: 与 AgentRun 完全一致——只接收 invoke_agent 函数,不感知框架。

┌──────────────────────────────────────────────────────────────┐
│  WisRuntimeServer                                             │
│                                                              │
│  构造: create_server(invoke_agent, protocols=[DifyHandler()]) │
│                                                              │
│  初始化流程:                                                   │
│   1. 创建 FastAPI app                                         │
│   2. 注入 ApiKeyMiddleware → contextvars                      │
│   3. (可选) checkpoint 自动持久化包装                          │
│   4. 创建 AgentInvoker(invoke_agent)                          │
│   5. 注册 /health 路由                                        │
│   6. 挂载 ProtocolHandler 路由                                 │
│                                                              │
│  两种使用模式:                                                 │
│                                                              │
│  模式 1: 独立服务 (开发/调试)                                   │
│    create_server(invoke_agent).start(port=8000)               │
│                                                              │
│  模式 2: FastAPI 子应用 (生产推荐)                              │
│    app.mount("/agent", create_server(invoke_agent).as_fastapi_app())│
└──────────────────────────────────────────────────────────────┘

AgentInvoker — 唯一的归一化入口

invoke_agent 函数 → AgentInvoker.invoke(fn, request) → CanonicalEvent 流

  自动检测:
  ├── async generator  → 直接迭代
  ├── async function   → await 得到返回值,单次 yield
  ├── sync function    → loop.run_in_executor(线程池) + contextvars 传播
  ├── str              → CanonicalEvent(type=TextDelta, data={delta: str})
  ├── CanonicalEvent   → 透传
  ├── None             → 跳过
  └── Exception        → CanonicalEvent(type=Error, ...)

  设计决策:
  ├── Done 事件: AgentInvoker 在 generator 耗尽时自动插入
  │     (Dify 协议必须有 message_end,AgentRun 不需要)
  ├── str 语义: 用户 yield 的 str 就是模型的文本输出 → TextDelta
  │     高级类型 (Reasoning/ToolCall) 用户通过直接 yield CanonicalEvent 表达
  └── 函数签名: 不强约束,运行时 inspect 检测 (与 AgentRun 一致)
      用户函数接收 AgentRequest 作为第一个位置参数

AgentRequest — 归一化请求模型

class Message(BaseModel):
    role: Literal["system", "user", "assistant", "tool"]
    content: str | list[dict]    # 文本或多模态
    name: str | None = None

class AgentRequest(BaseModel):
    messages: list[Message]            # 归一化消息列表
    stream: bool = True                # 是否流式
    conversation_id: str | None = None # 会话ID
    user_id: str | None = None         # 用户ID
    headers: dict[str, str]            # 关键 header 副本 (可跨线程)
    raw_request: Request | None = None # 原始 Starlette Request (本地可用)
    protocol_extensions: dict = {}     # 协议特有字段 (如 Dify 的 inputs/files)

ProtocolHandler — 响应序列化

┌─────────────────────────────────────────────────────────┐
│  DifyHandler                                              │
│                                                          │
│  端点:                                                    │
│    POST /dify/v1/chat-messages    SSE Streaming          │
│    POST /dify/v1/chat-messages    Blocking (stream=false) │
│    POST /dify/v1/chat-messages/{task_id}/stop (Phase 3)  │
│                                                          │
│  CanonicalEvent → Dify SSE 映射:                           │
│    TextDelta         → agent_message                       │
│                          { task_id, id<message_id>, answer }│
│    ReasoningDelta    → reasoning_chunk                     │
│                          { task_id, reasoning }             │
│    ToolCallStart     → agent_thought                       │
│                          { task_id, id<tool_call_id>,       │
│                            message_id, position,            │
│                            tool, tool_input }               │
│    ToolCallEnd       → agent_thought                       │
│                          { task_id, id<tool_call_id>,       │
│                            message_id, position,            │
│                            observation }                    │
│    SubAgentStart     → subagent_start                      │
│    SubAgentEnd       → subagent_end                        │
│    FileOutput        → message_file                        │
│    NodeLifecycleEvent → node_started / node_finished 🆕    │
│    InterruptEvent    → workflow_paused 🆕                  │
│    Usage             → (累积到 message_end.metadata.usage)  │
│    Error             → error { message, code, status }      │
│    Custom            → { event: name, ...payload }         │
│    Done              → message_end                         │
│                          { task_id, id<message_id>,         │
│                            metadata: { usage,               │
│                              conversation_id },             │
│                            files: [] }                      │
│                                                          │
│  DifyHandler 关键 ID 管理 (🆕 v0.2):                       │
│  ├── task_id:     请求级 UUID,所有 SSE 事件共享           │
│  ├── message_id:  助手消息 UUID,贯穿 agent_message、      │
│  │                agent_thought、message_end               │
│  ├── conversation_id: 请求传入 → message_end.metadata 回传 │
│  ├── agent_thought.id: 使用 ToolCallStart.tool_call_id    │
│  │    (不再新生成 UUID,确保 start/end 配对一致)           │
│  └── 心跳: 每 10 秒自动发送 data: {"event": "ping"}\n\n  │
│        (asyncio background task)                         │
│                                                          │
│  AGUIHandler (规划中)                                      │
│    CanonicalEvent → AG-UI SSE 格式                        │
└─────────────────────────────────────────────────────────┘

WisRuntimeServer — 组装

class ServerConfig(BaseModel):
    cors_origins: list[str] = ["*"]
    health_path: str = "/health"

class WisRuntimeServer:
    def __init__(self, invoker: AgentInvoker, protocols: list[ProtocolHandler], config: ServerConfig):
        # 1. 创建 FastAPI app
        # 2. (Phase 2) 注入 ApiKeyMiddleware
        # 3. for handler in protocols: handler.install(app, invoker)
        # 4. 注册 health 路由
        # 5. 配置 CORS

    def start(self, host="0.0.0.0", port=8000):
        """模式 1: 独立服务 (内部调 uvicorn.run)"""

    def as_fastapi_app(self) -> FastAPI:
        """模式 2: 导出为 FastAPI 子应用,供 app.mount()"""

    # 模式 3 (as_router) 不做。用户如需 include_router 级别的控制,
    # 可以手动创建 AgentInvoker + DifyHandler 自行组装。

def create_server(
    invoke_agent: Callable,
    *,
    protocols: list[ProtocolHandler] | None = None,  # 默认 [DifyHandler()]
    config: ServerConfig | None = None,
    checkpoint_enabled: bool = False,                 # Phase 3
) -> WisRuntimeServer:
    ...

五、用户故事与实施蓝图

5.1 用户故事总览

故事 1 ──────────────────────────────────────────────────────────────
│  用户故事: 作为 AI 工程师,我只需写一个 invoke_agent 函数,              │
│           就能获得一个 Dify 兼容的 SSE 服务端点                       │
│                                                                   │
│  验收标准:                                                          │
│    from wisruntime import create_server                             │
│    from wisruntime.model import AgentRequest                        │
│                                                                   │
│    async def my_invoke_agent(request: AgentRequest):                 │
│        # 用户可以自由使用任何框架、任意逻辑                            │
│        async for chunk in llm.astream(request.messages):             │
│            yield chunk.content   # yield str 即可                    │
│                                                                   │
│    create_server(my_invoke_agent).start(port=8000)                   │
│    # → curl -X POST http://localhost:8000/dify/v1/chat-messages     │
│    #       -d '{"query": "你好", "response_mode": "streaming"}'      │
│    # → SSE 流式响应,包含 agent_message / agent_thought / message_end│
└─────────────────────────────────────────────────────────────────────┘

故事 2 ──────────────────────────────────────────────────────────────
│  用户故事: 作为 AI 工程师,我接入 WIS Hub MCP 服务时,                  │
│           只需创建一个 MCPClient,它能自动处理鉴权和协议转换             │
│                                                                   │
│  验收标准:                                                          │
│    from wisruntime.mcp import MCPClient                             │
│    from wisruntime.adapters.deepagents.mcp import DeepAgentsMCPTool  │
│    from wisruntime.adapters.deepagents import wrap_agent             │
│    from deepagents import create_deep_agent                          │
│                                                                   │
│    client = MCPClient()           # 自动读 WIS_HUB_API_KEY          │
│    tool = DeepAgentsMCPTool(client, name="search")                   │
│    agent = create_deep_agent(tools=[tool])                            │
│    create_server(wrap_agent(agent)).start(8000)                       │
│    # → Agent 调用工具时,MCPClient 自动携带 Bearer 头请求 WIS Hub     │
└─────────────────────────────────────────────────────────────────────┘

故事 3 ──────────────────────────────────────────────────────────────
│  用户故事: 作为 AI 工程师,我可以将 wisruntime 服务嵌入到已有            │
│           FastAPI 应用中,作为子路由挂载                               │
│                                                                   │
│  验收标准:                                                          │
│    from fastapi import FastAPI                                      │
│    app = FastAPI()                                                  │
│    app.mount("/agent", create_server(my_invoke_agent).as_fastapi_app())│
│    # → /agent/dify/v1/chat-messages 就绪                            │
│    # → 复用主应用的 middleware 和 lifecycle                          │
└─────────────────────────────────────────────────────────────────────┘

故事 4 ──────────────────────────────────────────────────────────────
│  用户故事: 作为 AI 工程师,我用 wrap_agent 包装 deepagents Agent,      │
│           一行代码就生成 invoke_agent 函数                             │
│                                                                   │
│  验收标准:                                                          │
│    from deepagents import create_deep_agent                          │
│    from wisruntime.adapters.deepagents import wrap_agent             │
│                                                                   │
│    agent = create_deep_agent(tools=[...])                             │
│    create_server(wrap_agent(agent)).start(8000)                       │
│    # → wrap_agent 内部: astream_events → CanonicalEvent → yield      │
└─────────────────────────────────────────────────────────────────────┘

故事 5 ──────────────────────────────────────────────────────────────
│  用户故事: 作为 AI 工程师,我的 Agent 需要调用 WIS Hub 的 Skill 和       │
│           Sandbox 能力,使用与 MCP 相同的简洁 API                       │
│                                                                   │
│  验收标准:                                                          │
│    from wisruntime.skill import SkillClient                          │
│    from wisruntime.sandbox import SandboxClient                       │
│    from wisruntime.adapters.deepagents.skill import DeepAgentsSkillTool│
│    from wisruntime.adapters.deepagents.sandbox import DeepAgentsSandboxTool│
│    agent = create_deep_agent(tools=[                                   │
│        DeepAgentsSkillTool(SkillClient(), name="data_analysis"),       │
│        DeepAgentsSandboxTool(SandboxClient(), name="code_executor"),   │
│    ])                                                                  │
│    create_server(wrap_agent(agent)).start(8000)                        │
└─────────────────────────────────────────────────────────────────────┘

故事 6 ──────────────────────────────────────────────────────────────
│  用户故事: 作为 AI 工程师,我的 Agent 对话历史可以自动持久化到           │
│           WIS Hub Checkpoint 服务,支持断点续传                         │
│                                                                   │
│  验收标准:                                                          │
│    create_server(my_invoke_agent, checkpoint_enabled=True).start(8000) │
│    # → 每次对话自动保存到 WIS Hub                                      │
│    # → 下次请求带有相同 conversation_id 时恢复上下文                    │
└─────────────────────────────────────────────────────────────────────┘

5.2 实施阶段

Phase 0: 项目骨架 (已完成)
══════════════════════════
  ✅ 清理旧代码,确定新的架构方向
  ✅ 分析 AgentRun、LangChain、Dify 参考架构
  ✅ 确定 CanonicalEvent 11 种类型
  ✅ 确定分层架构

Phase 1: 核心基础设施 + MVP Server (✅ 已完成)
═══════════════════════════════════════════
  目标: 用户故事 1 — 写 invoke_agent 函数,获得 Dify SSE 端点

  ✅ CanonicalEvent 13 种类型定义 (v0.2 扩至 13 种)
  ✅ AgentRequest + Message 模型
  ✅ Config + CredentialContext (contextvars 定义)
  ✅ AgentInvoker (async/sync/iterator 检测, str→TextDelta,
     模型 chunk 智能提取, 同步生成器支持, 自动 Done)
  ✅ DifyHandler (parse_request + _format_stream + 心跳 + Blocking)
     - message_id 生成与全链路透传
     - agent_thought.id 使用 tool_call_id (start/end 配对一致)
     - conversation_id 回传
  ✅ WisRuntimeServer (start + as_fastapi_app)
  ✅ ProtocolRegistry + create_server 顶层 API
  ✅ create_server 自动检测 CompiledStateGraph → wrap_agent

Phase 2: LangGraph 适配器层 (✅ 已完成 — v0.2)
═══════════════════════════════════
  目标: 用户故事 4 — wrap_agent、LangGraphEventConverter

  ✅ LangGraphEventConverter (astream_events v2 → CanonicalEvent)
     - 工具调用 ID 追踪 (tool_call_id_map)
     - 子智能体检测 (task 工具 → SubAgentStart/End)
     - 节点生命周期 (on_chain_start/end → NodeLifecycleEvent)
     - CustomEvent、ErrorEvent、UsageEvent 映射
     - updates/values 兼容模式
  ✅ wrap_agent(agent_graph) 工厂函数
     - 支持 astream_events (默认)、updates、values 三种模式
  ✅ AgentInvoker 模型 chunk 智能提取
     - content → TextDeltaEvent
     - reasoning_content → ReasoningDeltaEvent
  ✅ CanonicalEvent 扩展: +InterruptEvent, +NodeLifecycleEvent
  ✅ DifyHandler SSE 格式合规修复
     - message_id, conversation_id, agent_thought id 一致性

Phase 3: 平台能力接入 (规划中)
══════════════════════════
  目标: 用户故事 2 + 5 — MCP/Skill/Sandbox 接入

  □ MCPClient + MCP 数据模型
  □ SkillClient + Skill 数据模型
  □ SandboxClient + Sandbox 数据模型
  □ DeepAgentsMCPTool (MCPClient → BaseTool)
  □ DeepAgentsSkillTool (SkillClient → BaseTool)
  □ DeepAgentsSandboxTool (SandboxClient → BaseTool)

Phase 4: 高级特性
════════════════
  目标: 用户故事 6 — Checkpoint、多协议

  □ CheckpointClient + 自动持久化
  □ AGUIHandler
  □ Stop endpoint
  □ ApiKeyMiddleware

Phase 4: 多框架 + 多协议
══════════════════════
  目标: 验证可扩展性

  □ AgentScope Adapter
  □ AGUI Handler
  □ 内部 PyPI 发布
  □ 性能基准测试

5.3 目录结构 (目标态)

wisruntime/
├── __init__.py                  # 顶层导出: create_server, Config
├── config.py                    # Config, CredentialContext
├── middleware.py                # ApiKeyMiddleware (纯 ASGI)
├── model.py                     # CanonicalEvent, AgentRequest 等核心模型
├── exceptions.py                # 自定义异常
│
├── mcp/                         # Platform Client: MCP
│   ├── __init__.py
│   ├── client.py                #   MCPClient
│   └── model.py                 #   MCP 请求/响应模型
│
├── skill/                       # Platform Client: Skill
│   ├── __init__.py
│   ├── client.py                #   SkillClient
│   └── model.py
│
├── sandbox/                     # Platform Client: Sandbox
│   ├── __init__.py
│   ├── client.py                #   SandboxClient
│   └── model.py
│
├── memory/                      # Platform Client: Checkpoint
│   ├── __init__.py
│   ├── client.py                #   CheckpointClient
│   └── model.py
│
├── adapters/                    # Adapter + Capability Bridge (用户可选工具)
│   ├── __init__.py              #   包说明
│   └── langgraph/               #   LangGraph/LangChain/DeepAgents 框架 (✅ v0.2)
│       ├── __init__.py          #     导出 LangGraphEventConverter, wrap_agent
│       ├── converter.py         #     LangGraphEventConverter (事件转换器)
│       └── wrap_agent.py        #     wrap_agent() 糖函数
│   # (未来) llamaindex/         #   LlamaIndex 框架适配
│   # (未来) crewai/             #   CrewAI 框架适配
│
├── server/                      # Server 层
│   ├── __init__.py
│   ├── server.py                #   WisRuntimeServer (FastAPI 组装)
│   ├── invoker.py               #   AgentInvoker (函数归一化)
│   ├── model.py                 #   AgentRequest, ProtocolRegistry
│   ├── dify_handler.py          #   DifyHandler (SSE + Blocking)
│   └── agui_handler.py          #   AGUIHandler (规划中)
│
└── integration/                 # 会话持久化 + 框架 Memory 适配
    ├── __init__.py
    └── deepagents/
        └── memory.py            #   WISCheckpointMemory (CheckpointClient → DeepAgents Memory)

六、技术规格

6.1 运行时依赖

包 版本 用途
fastapi ≥ 0.110 Web 框架
uvicorn[standard] ≥ 0.27 ASGI 服务器
sse-starlette ≥ 2.0 SSE 流式响应
pydantic ≥ 2.0 数据校验与序列化
httpx ≥ 0.27 异步 HTTP 客户端

6.2 环境变量

变量 用途 必填
WIS_HUB_API_KEY WIS Hub 统一 API-KEY 使用 MCP/Skill/Sandbox/Checkpoint 时必填
WIS_HUB_ENDPOINT WIS Hub 地址 可选,默认读取 SDK 内置配置

6.3 Python 版本

≥ 3.11


七、参考资源

Metadata

Release files for wisruntime 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for wisruntime 0.1.1
File Size Uploaded
wisruntime-0.1.1.tar.gz 58.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for wisruntime 0.1.1
File Interpreter ABI Platform
wisruntime-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 99.6 kB

Release files / wisruntime-0.1.1.tar.gz

Download URL wisruntime-0.1.1.tar.gz
Size 58.1 kB
Tags Source
SHA-256 checksum
How to use checksums
cbfb3d1e2d21a08a65b65154cb4a988109d21b756f88060c4a480813c98dccac
BLAKE2b-256 checksum
How to use checksums
59adea651f7dd87bfdbfffef7d8d94709d12bbf1846cc07493390cb51bd56aff
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.5

Release files / wisruntime-0.1.1-py3-none-any.whl

Download URL wisruntime-0.1.1-py3-none-any.whl
Size 41.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2e3d3f46cf833f211519a2c814fd2fcb1f8d2d232971a150c126146684372c42
BLAKE2b-256 checksum
How to use checksums
3e5ed17ae1d1a08ec1df91ac4f921e729c7236afb42b316cedd9d7ac5a297c32
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.5

Release history Release notifications | RSS feed

0.5.0

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.1

2 release files

0.3.0

2 release files

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page