Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ intentional API changes, and patch releases preserve public API compatibility.

### Added

- Docs: `COMPARISON.md`, `LANGCHAINGO.md`, `VERSIONING.md`; README QuickAgent front door.
- `eval` golden trajectory helpers for tool-order and final-content assertions.
- `a2a` minimal Agent-to-Agent HTTP card + message:send protocol.
- `httpware` bearer auth, session header, and local rate-limit middleware.
- `examples/mcp-secure` GuardTools pattern for MCP tool binding.
- `graph.RunConfig.Durability` (sync supported; async/exit return clear errors).
- `graph.WithDeferred` node marker + `CompiledGraph.IsDeferred`.
- Graph micro-benchmarks (`BenchmarkLinearInvoke`, `BenchmarkFanOutThree`).

### Changed

### Fixed
Expand Down
4 changes: 2 additions & 2 deletions COMPATIBILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ No row below should be interpreted as a drop-in Python API guarantee.

| Area | Status | Notes |
|---|---|---|
| Typed StateGraph | Partial | Typed nodes, reducers, schemas, static/conditional/waiting edges, Send, Command, compilation and inspection. Default compile still requires every node (and END) reachable from START—stricter than Python—but `WithAllowUnreachableNodes` / `WithAllowUnreachableEND` can relax that. Full Python **deferred node** scheduling is not implemented yet. |
| Pregel runtime | Partial | Deterministic BSP execution, concurrency, retries, caching, timeouts, pending-write recovery. No public low-level `Pregel`/`NodeBuilder` facade or configurable `sync`/`async`/`exit` durability. |
| Typed StateGraph | Partial | Typed nodes, reducers, schemas, static/conditional/waiting edges, Send, Command, compilation and inspection. Default compile still requires every node (and END) reachable from START—stricter than Python—but `WithAllowUnreachableNodes` / `WithAllowUnreachableEND` can relax that. `WithDeferred` records deferred nodes (`IsDeferred`); full Python deferred barrier scheduling remains open. |
| Pregel runtime | Partial | Deterministic BSP execution, concurrency, retries, caching, timeouts, pending-write recovery. `RunConfig.Durability` exposes sync/async/exit names; only sync is implemented (`ErrUnsupportedDurability` otherwise). No public low-level `Pregel`/`NodeBuilder` facade. |
| Channels | Supported | Last/Any/Ephemeral/Untracked values, aggregate, topic, named barrier, delta, checkpoint versions, and freshness scheduling. |
| Streaming | Partial | Values, updates, messages, custom, debug, interrupts, subgraphs, backpressure, run-event v3, and native SSE provider chunks. Python stream-transformer and graph-UI APIs are absent. |
| Checkpoints | Supported | Memory, native SQLite/PostgreSQL, optional Redis, history, pending writes, replay, forks, encryption, and typed codecs. Python physical adapters require isolated schemas/databases. |
Expand Down
65 changes: 26 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,15 @@ LangChain product and is not a source-to-source port of the Python package.
## Install

```bash
go get github.com/ybszm/langgraph-go@latest
go get github.com/ybszm/langgraph-go@v0.1.0
```

Go 1.25 or newer is required.
Go 1.25 or newer is required. See [versioning](docs/VERSIONING.md) for pre-1.0
compatibility promises.

## Quick start
## Quick start (agent)

Most applications should start with **QuickAgent**, not a hand-built graph:

```go
package main
Expand All @@ -75,58 +78,42 @@ import (
"fmt"

"github.com/ybszm/langgraph-go/graph"
"github.com/ybszm/langgraph-go/prebuilt"
)

type State struct {
Count int
}
type echo struct{}

type Delta struct {
Increment int
func (echo) Invoke(_ context.Context, state prebuilt.AgentState, _ graph.Runtime) (prebuilt.AssistantMessage, error) {
return prebuilt.AssistantMessage{Content: "hello from quick-agent"}, nil
}

func main() {
builder := graph.NewStateGraph(func(
_ context.Context,
state State,
updates []Delta,
) (State, error) {
for _, update := range updates {
state.Count += update.Increment
}
return state, nil
agent, err := prebuilt.NewQuickAgent(prebuilt.QuickAgentConfig{
Model: echo{},
SystemPrompt: "Be helpful.",
})

if err := builder.AddNode("increment", func(
_ context.Context,
_ State,
_ graph.Runtime,
) (graph.Command[Delta], error) {
return graph.Update(Delta{Increment: 1}), nil
}); err != nil {
panic(err)
}
if err := builder.AddEdge(graph.START, "increment"); err != nil {
panic(err)
}
if err := builder.AddEdge("increment", graph.END); err != nil {
panic(err)
}

compiled, err := builder.Compile()
if err != nil {
panic(err)
}

result, err := compiled.Invoke(context.Background(), State{}, graph.RunConfig{})
state, err := agent.Run(context.Background(), "hi", graph.RunConfig{})
if err != nil {
panic(err)
}
fmt.Println(result.Count) // 1
fmt.Println(state.FinalResponse())
}
```

The runnable example is available at [`examples/basic`](examples/basic).
Runnable demos:

| Example | Concept |
|---|---|
| [`examples/quick-agent`](examples/quick-agent) | Smallest agent entry |
| [`examples/multi-agent`](examples/multi-agent) | Supervisor + parallel sub-agents |
| [`examples/basic`](examples/basic) | Typed StateGraph without LLM |

Multi-agent, handoff, and deep-agent patterns: [docs/agents.md](docs/agents.md).
Interop with langchaingo: [docs/LANGCHAINGO.md](docs/LANGCHAINGO.md).
How we compare to other Go stacks: [docs/COMPARISON.md](docs/COMPARISON.md).

## Packages

Expand Down
80 changes: 20 additions & 60 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,73 +54,33 @@ LangGraph Go 是由社区独立维护的 Go 实现,借鉴了
## 安装

```bash
go get github.com/ybszm/langgraph-go@latest
go get github.com/ybszm/langgraph-go@v0.1.0
```

需要 Go 1.25 或更高版本。
需要 Go 1.25 或更高版本。版本承诺见 [docs/VERSIONING.md](docs/VERSIONING.md)。

## 快速开始
## 快速开始(Agent)

多数应用应从 **QuickAgent** 入手:

```go
package main

import (
"context"
"fmt"

"github.com/ybszm/langgraph-go/graph"
)

type State struct {
Count int
}

type Delta struct {
Increment int
}

func main() {
builder := graph.NewStateGraph(func(
_ context.Context,
state State,
updates []Delta,
) (State, error) {
for _, update := range updates {
state.Count += update.Increment
}
return state, nil
})

if err := builder.AddNode("increment", func(
_ context.Context,
_ State,
_ graph.Runtime,
) (graph.Command[Delta], error) {
return graph.Update(Delta{Increment: 1}), nil
}); err != nil {
panic(err)
}
if err := builder.AddEdge(graph.START, "increment"); err != nil {
panic(err)
}
if err := builder.AddEdge("increment", graph.END); err != nil {
panic(err)
}

compiled, err := builder.Compile()
if err != nil {
panic(err)
}

result, err := compiled.Invoke(context.Background(), State{}, graph.RunConfig{})
if err != nil {
panic(err)
}
fmt.Println(result.Count) // 1
}
agent, err := prebuilt.NewQuickAgent(prebuilt.QuickAgentConfig{
Model: model, // 实现 prebuilt.ChatModel[prebuilt.AgentState]
SystemPrompt: "简洁回答。",
})
state, err := agent.Run(ctx, "你好", graph.RunConfig{})
fmt.Println(state.FinalResponse())
```

可运行示例位于 [`examples/basic`](examples/basic)。
| 示例 | 说明 |
|---|---|
| [`examples/quick-agent`](examples/quick-agent) | 最小 Agent 入口 |
| [`examples/multi-agent`](examples/multi-agent) | 监督者 + 并行子 Agent |
| [`examples/basic`](examples/basic) | 无 LLM 的类型化 StateGraph |

多 Agent 见 [docs/agents.md](docs/agents.md);与 langchaingo 协作见
[docs/LANGCHAINGO.md](docs/LANGCHAINGO.md);对比见
[docs/COMPARISON.md](docs/COMPARISON.md)。

## 包结构

Expand Down
45 changes: 45 additions & 0 deletions a2a/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# A2A subset (langgraph-go)

Minimal Agent-to-Agent HTTP protocol for services that already use
langgraph-go agents. This is **not** a full multi-vendor A2A implementation.

## Endpoints

| Method | Path | Purpose |
|---|---|---|
| `GET` | `/a2a/v1/card` | Agent card (name, skills, metadata) |
| `POST` | `/a2a/v1/message:send` | Send a user/agent message, receive agent reply |

Header: `X-A2A-Protocol: langgraph-go-a2a/0.1`

## Server

```go
srv := &a2a.Server{
Card: a2a.AgentCard{Name: "ops-agent", Skills: []string{"diagnose"}},
Handler: func(ctx context.Context, req a2a.SendRequest) (a2a.SendResponse, error) {
// Call prebuilt.QuickAgent / MultiAgentCoordinator here.
return a2a.SendResponse{
SessionID: req.SessionID,
Message: a2a.Message{Role: "agent", Content: "ok"},
}, nil
},
}
http.Handle("/a2a/", srv)
```

## Client

```go
client := &a2a.Client{BaseURL: "http://127.0.0.1:8080"}
card, _ := client.GetCard(ctx)
resp, _ := client.Send(ctx, a2a.SendRequest{
SessionID: "s1",
Message: a2a.Message{Role: "user", Content: "check redis"},
})
```

## Security

Put TLS, authentication, and rate limits in front of these handlers. See the
`httpware` package for bearer auth and rate limiting helpers.
Loading