Skip to main content

weft

Python Agent Runtime — long-lived session orchestration, event replay, ask-user interrupt/resume.

weft 把"一次 HTTP 调用"模型升级为长生命周期、可订阅、可重连的 Agent 会话。Transport 层和 Agent 框架解耦——LangGraph / OpenAI Agents SDK / 裸 LLM SDK 都能接入。

核心能力

能力 实现
长生命周期 turn task 客户端断连只 detach listener,agent 后台续跑
断网/换 tab/F5 不丢事件 Ring buffer + last_seq 重连补帧协议
多 listener 同时订阅 每条 listener 独立有界 queue + 后台 pump,慢/死 listener 不反压 emit
ask-user 中断 → resume sync 工具线程内调 ContextVar future,async 主 loop 收答复后续跑
Cancel-safe turn cancel 时把当前 user input 抢救进 agent 自己的 checkpoint
Janitor GC idle runner 自动回收;turn 跑中即使无 listener 也保留

跟生态的关系

对比 关系
LangGraph / OpenAI Agents SDK weft 在它们之上一层,管 graph 之外的 session/lifecycle/transport;通过 AgentProtocol 接入,核心包不 import 它们
Temporal / Sidekiq 单进程 asyncio 范围内的 agent 会话;不抢跨进程 workflow engine 位置
Langfuse / OpenTelemetry weft 暴露 middleware 数据 + emit hook,observability backend 自己接

30 秒 demo

import asyncio
from weft import (
    AskUserHandler, CancelToken, EventEmitter,
    MainBlockStart, MainBlockDelta, MainBlockEnd,
    ThreadRunner, WSListener,
)


class EchoAgent:
    async def run_turn(
        self, user_input: str, *,
        emit: EventEmitter, askuser: AskUserHandler, cancel_token: CancelToken,
    ) -> None:
        await emit(MainBlockStart(block_id="b1", block_type="text"))
        for ch in user_input:
            if cancel_token.cancelled:
                break
            await emit(MainBlockDelta(block_id="b1", delta=ch))
        await emit(MainBlockEnd(block_id="b1"))


async def main():
    runner = ThreadRunner("t-1", EchoAgent())

    captured = []
    async def send(payload): captured.append(payload)

    listener = WSListener(send)
    await runner.attach_listener(listener)
    await runner.start_turn("hi", listener)
    assert runner._turn_task is not None
    await runner._turn_task

asyncio.run(main())

完整 WS server demo:examples/hello_echo/

FastAPI 适配器

weft.adapters.fastapi.run_ws_session 把上面那段"收 client → 路由到 runner"接收循环抽成一行调用; 业务侧扩展走鸭子类型 WSSessionHooks,全部方法可选,不实现等于 no-op。

from fastapi import FastAPI, WebSocket
from weft import RunnerJanitor, RunnerRegistry
from weft.adapters.fastapi import run_ws_session

app = FastAPI()
registry = RunnerRegistry(my_agent_factory)
janitor = RunnerJanitor(registry); janitor.start()

class Hooks:
    async def on_attach(self, listener):
        listener.enqueue(my_usage_snapshot())   # 补一帧客户端 hydrate 用的快照
    async def on_resume_submitted(self, answers):
        await persist_clarify(answers)          # clarify 答案落业务库
    async def on_config(self, msg):
        await update_role_models(msg)           # ConfigUpdate 业务字段由 hook 解释

@app.websocket("/ws/{thread_id}")
async def ws(ws: WebSocket, thread_id: str):
    runner = await registry.get_or_create(thread_id)
    await run_ws_session(ws, thread_id, runner, hooks=Hooks())

run_ws_session 负责: ws.accept / 推 ReadyEvent / 收 hello 触发 attach 补帧 / 路由 user_message / cancel / resume / compact 到 runner / detach 关 listener / pump 死亡时主动 close ws。安装: pip install "weft[fastapi]"

架构

┌─────────────────────────────────────────────────────────────┐
│  Transport adapter (FastAPI WS / SSE / 自定义)             │
│  ↓ attach_listener  ↑ user_message/resume/cancel            │
├─────────────────────────────────────────────────────────────┤
│  ThreadRunner                                              │
│  ├─ state machine: idle / streaming / awaiting_resume       │
│  ├─ ring buffer + compute_replay (last_seq 补帧)            │
│  ├─ WSListener[] (per-transport queue + pump, 背压隔离)     │
│  └─ ask-user future / cancel salvage                        │
├─────────────────────────────────────────────────────────────┤
│  AgentProtocol  (你的实现, 或 weft.adapters.langgraph)      │
│  └─ run_turn(emit, askuser, cancel_token)                   │
└─────────────────────────────────────────────────────────────┘

RunnerRegistry 按 key 索引 runner,RunnerJanitor 周期回收 idle。

安装

pip install weft                    # 核心 (零 langgraph/langchain 依赖)
pip install "weft[langchain]"       # + LangGraph adapter (规划中)
pip install "weft[fastapi]"         # + FastAPI WS adapter (规划中)

Status

v0.0.1 — alpha。核心 transport/lifecycle 层稳定,middleware 套装 + LangGraph adapter 在 v0.1 完成。

详细设计见 docs/architecture.md,事件协议见 docs/protocol.md

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

weft_publish-0.0.7.tar.gz (147.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

weft_publish-0.0.7-py3-none-any.whl (34.6 kB view details)

Uploaded Python 3

File details

Details for the file weft_publish-0.0.7.tar.gz.

File metadata

  • Download URL: weft_publish-0.0.7.tar.gz
  • Upload date:
  • Size: 147.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for weft_publish-0.0.7.tar.gz
Algorithm Hash digest
SHA256 86452727fa95f0c750025a8725e61a2ec57ddff4dffe43b1a6bbaaf33c7b5511
MD5 cfc605b09d98f14783a4fc65c243142b
BLAKE2b-256 a4e616512e93b842055c6abf893ad9a75907cfc9234863fe46c867d238ecf6ff

See more details on using hashes here.

File details

Details for the file weft_publish-0.0.7-py3-none-any.whl.

File metadata

  • Download URL: weft_publish-0.0.7-py3-none-any.whl
  • Upload date:
  • Size: 34.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for weft_publish-0.0.7-py3-none-any.whl
Algorithm Hash digest
SHA256 6b995ad877f8039d5446a6d38606664fd6d9b61d39430b44807195a58551559e
MD5 002e61788a815e26dc509b71a53244e2
BLAKE2b-256 217c516111e531661cc8e68177bd826966d07e0cdcf1f246efe11cf904ee8652

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page