gorondo

Go agent engine & execution clusterGo agent 引擎与执行集群

An agent loop, written as a rondo. 把 agent 循环,写成一首回旋曲

Model, tool, model, tool — the theme keeps returning until the piece resolves. gorondo is the Go engine that plays that form, and the cluster that runs ten thousand of them at once. 模型、工具、模型、工具——主题不断回归,直到乐曲收束。gorondo 是演奏这个曲式的 Go 引擎,也是同时跑上万遍的执行集群。

$ go get github.com/memohai/gorondo See a turn play看一个 turn 跑完

A turn is a form. The model speaks, a tool answers, sometimes a human nods — and the theme comes back. 一个 turn 就是一种曲式。模型说话,工具回答,有时要等点头——然后主题再次回来。

How many times it comes back is the model's decision, not a number in your config. 它回来几次由模型决定,不是你配置里写死的数字。

One turn, end to end一个 turn,从头到尾 A — B — A — C — A
A model · stream B tool · mcp:search stop_reason = tool_use A model · stream C approval tool · bash A model · stream end_turn
01 — A

The engine · open source引擎 · 开源

Small enough to read in an afternoon.一个下午读得完。

Every agent framework eventually rebuilds the same four moves: call the model, read its intent, run what it asked for, feed the results back. gorondo does exactly that and stops — the rest is interfaces you implement. 所有 agent 框架最终都在重造同样的四个动作:调模型、读意图、执行它点的工具、把结果喂回去。gorondo 做完这四件就收手——剩下的都是留给你实现的接口。

provider.gothe whole model surface模型侧的全部接口

// Provider is the model backend. The loop depends on
// nothing but this injected streaming call.
type Provider interface {
	Name() string

	Stream(ctx context.Context, req Request,
		emit func(Delta)) (*Completion, error)
}

Ships with a direct client for any Anthropic-compatible endpoint — key plus base URL, adaptive auth, backoff on retry. Want to spend a Claude or Grok subscription instead of API credit? That is a Provider, not a fork. 内置直连任意 Anthropic 兼容端点的实现——key + baseURL,鉴权自适应,重试退避。想吃 Claude / Grok 订阅而不是 API 额度?那是写一个 Provider,不是 fork 一份代码。

tool.gothe whole tool surface工具侧的全部接口

// Tool is anything the model can be handed.
// isError = it failed but the model should adapt;
// error = your executor itself is broken.
type Tool interface {
	Def() ToolDef

	Execute(ctx context.Context, id string,
		args json.RawMessage) (
		content string, isError bool, err error)
}

Local Go closures and remote MCP tools implement the same two methods. Results are truncated at a byte budget, so one chatty tool cannot blow up the context window. 本地 Go 闭包和远端 MCP 工具实现的是同两个方法。工具结果按字节预算截断,一个话痨工具撑不爆上下文。

The gate审批门

Turn on approvals and every tool call stops at a barrier: the engine emits a request, then blocks that one call until a decision comes back. A denial is not a crash — it becomes an error result the model reads and works around. 打开审批后,每次工具执行前都会停在门口:引擎发出请求,该次调用阻塞直到决定回来。拒绝不是崩溃——它变成一条错误结果,模型读到后自己绕路。

Steering, mid-turn轮间注入

A user who thinks of something halfway through shouldn't wait for the turn to finish. Input arriving mid-run is queued and injected at the next round boundary, alongside the tool results. 用户跑到一半想起一件事,不该等这个 turn 跑完。运行中到达的输入进队列,在下一轮边界随工具结果一起注入。

Refusing to spin拒绝原地打转

Every round's tool calls are fingerprinted by name and arguments. Three identical rounds in a row is not persistence, it's a loop — the run ends with a diagnosable failure instead of a quiet invoice. 每一轮的工具调用按「名字 + 参数」取指纹。连续三轮完全相同不叫坚持,叫死循环——run 以一条可诊断的失败结束,而不是一张安静的账单。

Nothing to shell out to不 spawn 任何东西

No CLI subprocess, no node runtime, no sidecar. One Go binary, one goroutine per run, context cancellation all the way down — which is what makes ten thousand concurrent turns a scheduling problem rather than a process-management problem. 不 spawn CLI 子进程,不带 node 运行时,不挂 sidecar。一个 Go 二进制、一个 run 一个 goroutine、context 取消贯穿到底——这才使得「同时跑一万个 turn」是个调度问题,而不是进程管理问题。

The cluster · hosted or self-run集群 · 托管或自建

One engine is a solo. Products need an orchestra.单个引擎是独奏。产品要的是乐队。

Work has to survive a broker, a rebalance, a pod eviction, and a user who sends a second message before the first is done. Five channels cross the boundary, and each one's promise is part of the contract. 任务要熬过 broker、rebalance、pod 驱逐,还有一个在上条消息跑完前就发下一条的用户。跨边界的东西只走五个通道,每个通道的承诺都是契约的一部分。

① task.turn ② run context ③ live stream ④ turn.results ⑤ control kafka · at-least-once grpc · pulled, retried redis · droppable kafka · must not be lost redis · directed turn arrives session lease history · tools · limits tokens · tool events · heartbeats approval · steering · abort round facts · epoch-fenced run_finished ack + lease released

Exactly one turn恰好一个 turn

The broker promises at-least-once. The session lease promises at-most-one executor. Multiply them and you get the property you actually wanted: for any session, exactly one turn is running, on exactly one worker, right now. 消息中间件保证「至少一次」,session 租约保证「至多一个执行者」。两者相乘,得到你真正想要的性质:对任一 session,此刻恰好有一个 turn 在跑,在恰好一个 worker 上。

Yielding isn't failing让路不是失败

Two workers reaching for the same session is normal traffic, not an incident. A duplicate delivery is acked and dropped; a genuinely busy session is postponed — backed off and requeued with its attempt count untouched. Retries are reserved for things that actually went wrong. 两个 worker 同时够到同一个 session 是正常流量,不是事故。重复投递直接 ack 丢弃;真的 busy 则让路——退避后原样回队,attempt 计数不动。重试次数只留给真正出错的情况。

Zombies get fenced僵尸产出被围栏挡住

A worker that froze, lost its lease, then woke up still holds a keyboard. Every fact carries a session epoch that only ever increases, so late output from a superseded run is rejected on arrival rather than written over fresh state. 一个卡住、丢了租约、然后又醒过来的 worker,手里还握着话筒。每条事实都带 session 域 epoch(只增不减),被取代的旧 run 的迟到产出在入口就被拒收,不会盖掉新状态。

No database of ours集群零 DB 依赖

The cluster is a pure executor. It reads context over the wire, emits facts over the wire, and owns no authoritative state — so your database stays yours, single-writer, and we stay something you can restart at three in the morning without thinking. 集群是纯执行器:上下文经网络读入,事实经网络发出,不持有任何权威状态——数据库仍然只归你、只有一个写入者;而我们是那种可以在凌晨三点无脑重启的东西。

Two paths两条路

Same engine, either way.两条路,同一个引擎。

  Engine, self-hosted自建引擎 gorondo cloudgorondo 云
what you get拿到什么 The Go package. Import it, inject a provider, run a turn.一个 Go 包。import 进去,注入 provider,跑一个 turn。 Workers, brokers, leases, fencing, dashboards — an endpoint.worker、broker、租约、fencing、看板——一个端点。
you operate你运维 Everything around the loop.循环之外的一切。 Nothing. Your database still writes itself.不用。数据库仍然只由你写。
good when适合 One process, embedded agents, or you enjoy Kafka.单进程、内嵌 agent,或者你就是喜欢 Kafka。 Many sessions, real users, on-call rotations you'd rather not staff.大量 session、真实用户、你不想排的 on-call。
price价格 Free, MIT.免费,MIT。 Per concurrent run →按并发 run 计 →

Start with the solo part. 先从独奏声部开始。

Pull the package, point it at any Anthropic-compatible endpoint, and watch a turn play. Move to the cluster when one process stops being enough. 拉下包,指向任意 Anthropic 兼容端点,看一个 turn 跑完。等单进程不够用了,再上集群。

$ go get github.com/memohai/gorondo Read the docs读文档