Skip to content

Conversation

@Flash-LHR
Copy link
Contributor

@Flash-LHR Flash-LHR commented Sep 18, 2025

No description provided.

@codecov
Copy link

codecov bot commented Sep 18, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 74.94735%. Comparing base (d286d8d) to head (2fa5e13).
⚠️ Report is 190 commits behind head on main.

Additional details and impacted files
@@                 Coverage Diff                  @@
##                main        #379          +/-   ##
====================================================
+ Coverage   58.42422%   74.94735%   +16.52313%     
====================================================
  Files             97         142          +45     
  Lines          12286       21367        +9081     
====================================================
+ Hits            7178       16014        +8836     
+ Misses          4608        4457         -151     
- Partials         500         896         +396     
Flag Coverage Δ
unittests 74.94735% <ø> (+16.52313%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Flash-LHR Flash-LHR changed the title {server/agui, examples}: support agui [WIP] {server/agui, examples}: support agui Sep 18, 2025
@@ -0,0 +1,37 @@
module trpc.group/trpc-go/trpc-agent-go/server/agui

go 1.24.4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

注意下go 版本

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

// New wraps a trpc-agent-go runner with AG-UI specific translation logic.
func New(r trunner.Runner, opt ...Option) Runner {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个还要单独封装一个runner吗,如果用户自己创建runner,并添加memory和session,这个和用户的不是有冲突?
是不是反过来,和memory,session一样,通过runner传入

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里封装的 AGUI Runner 不会和用户自定义的 Runner 产生冲突,原因:

  1. New 接收用户自定义的 Runner,memory/session 逻辑由用户在自己的 Runner 中实现,AG-UI Runner 相当于 Wrap 了自定义 Runner,只做事件翻译,不会覆盖 memory/session 逻辑。
  2. AGUI Runner 与 Runner 的 Option 类型不互通,不支持传入 memory/session

之所以抽象出 AGUI Runner 接口,是为了让用户根据需要换成本地实现(例如 mock AGUI 事件输出)。

"github.com/charmbracelet/bubbles/spinner"
"github.com/charmbracelet/bubbles/textinput"
"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个是什么,会不会有点不好理解

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bubbletea是 CLI 开发框架,这个 example 演示了 client 如何自己解析 AGUI 协议。
另外,还使用 CopilotKit 开发了一个 web ui 作为 client,在另一个 example。

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UPDATE:移除了 bubbletea,提供了最小样例

if err != nil {
log.Fatalf("failed to create AG-UI server: %v", err)
}
if err := server.Serve(context.Background()); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ip port要如何设置、

Copy link
Contributor Author

@Flash-LHR Flash-LHR Sep 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

通过 WithAddressWithPath 设置,在 example 中显式写出来了

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UPDATE
address(ipport)在http.ListenAndServe(*address, server.Handler())中指定,见最新的 server example

}

// NewBridge creates a new event bridge.
func NewBridge(threadID, runID string) Bridge {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bridge 这些相关的看上去可以放到 internal

Copy link
Contributor Author

@Flash-LHR Flash-LHR Sep 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agui 有一种 custom event 类型,抽象出 Bridge interface 可以让用户自行处理自定义 event 的转换

}

// New creates a AG-UI server instance.
func New(agent agent.Agent, opt ...Option) (*Server, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

除了这个 agui.New 之外,service package 和 runner package 这些是不是都可以放到 internal?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agui 协议没有规定 transport,框架提供了 sse 实现,也可以有 websocket/私有协议 实现,所以抽象出 service interface,支持协议扩展。

}

// WithSessionService sets the session service.
func WithSessionService(svc session.Service) Option {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里不太好,trpc-agent-go 的 runner 还有其他 option,不只有 session service 的 option,你要在这里一一复刻一遍吗?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

去除WithSessionService了,使用WithRunnerOptions统一设置 runner 的 option

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

为什么不考虑在原来的runner里面去传入ag-ui相关的东西?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. AGUI要启动一个服务,如果通过通过 runner 传递的话,拿不到 HTTP handler
  2. AGUI 与 A2A/DebugServer 类似,都是向外提供服务,放在 server 下面,使用方法应该相近

}

// Serve starts the SSE service and listens on the address.
func (s *sse) Serve(ctx context.Context) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

serve 这里可以考虑监听 ctx.Done 来对 server 做 shutdown 操作

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

否则传入的 ctx 就没有什么用了

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

刚才更新了,去除了 Serve/Close 方法,改用 Handler 方法,能够让用户显式与 trpc 结合

llmagent.WithGenerationConfig(generationConfig),
llmagent.WithInstruction("You are a helpful assistant."),
)
server, err := agui.New(agent, agui.WithPath(*path))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

除了 example 这里用户会使用到的导出方法以外,其他的都要考虑下是否可以放到 internal 中

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

导出符号整理如下:

  • package agui
    • DefaultNewService 变量:service 创建的工厂函数,用于匿名导入覆盖;
  • package adapter
    • RunAgentInput 结构体:AG-UI 协议的请求包,自定义 UserIDResolver/TranslatorFactory 时需要用到
  • package runner
    • Options 结构体、NewOptions 工厂函数、WithUserIDResolver、WithTranslatorFactory Option。
  • package service
    • Service 接口:用于自定义通信协议;
    • Options 结构体、WithPath Option
    • package sse
      • New 方法:用于创建 sse 服务
  • package translate
    • Translator 接口与 New 构造器:用于自定义翻译器。

o(&opts)
}
s := &sse{
path: opts.Path,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

opts.Path 需要判空兜底默认 /,否则 HandleFunc 那里会 panic

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done,默认使用"/"

}

// handle handles an AG-UI run request.
func (s *sse) handle(w http.ResponseWriter, r *http.Request) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

需要过滤下 http method,只支持 GET POST

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

以及 OPTIONS(给 CORS 用)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

pnpm dev
```

3. Ask a question such as `Calculate 2*(10+11)` and watch the live event stream in the terminal. A full transcript example is documented in [`client/copilotkit/README.md`](client/bubblecopilotkittea/README.md).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个路径和实际的不符

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix

@Flash-LHR Flash-LHR changed the title [WIP] {server/agui, examples}: support agui {server/agui, examples}: support agui Sep 26, 2025
@Flash-LHR Flash-LHR changed the title {server/agui, examples}: support agui {server/agui, examples, docs}: support agui Sep 26, 2025
}

// New creates a new event translator.
func New(threadID, runID string) Translator {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

threadID 指的是啥,go 又没thread

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RunAgentInput 是 AGUI协议规定的请求包格式,这些字段都是 AGUI 协议规定的。
其中,ThreadID和RunID分别对应了框架的SessionID和InvcationID

// RunAgentInput represents the parameters for an AG-UI run request.
type RunAgentInput struct {
// ThreadID is the ID of the conversation thread, which is the session ID.
ThreadID string `json:"threadId"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

为啥不叫session id

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RunAgentInput 是 AGUI协议规定的请求包格式,这些字段都是 AGUI 协议规定的。
其中,ThreadID和RunID分别对应了框架的SessionID和InvcationID

llmagent.WithModel(modelInstance),
llmagent.WithGenerationConfig(generationConfig),
llmagent.WithInstruction("You are a helpful assistant."),
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里有个问题,如果要传入session,或者memory,要怎么做呢?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

通过 WithRunnerOptions 传入,例如:

// 创建 AG-UI 服务
server, err := agui.New(
    agent,
    agui.WithPath("/agui"), // 指定 HTTP 路由
    agui.WithRunnerOptions(runner.WithSessionService(sessionService)), // 注入 Session Service
)

文档新增了 Runner 示例

// 创建 Agent
agent := newAgent()
// 创建 AG-UI 服务,指定 HTTP 路由
server, err := agui.New(agent, agui.WithPath("/agui"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agui.New 改成了传入 runner

)

// options holds the options for the AG-UI server.
type options struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这些还需要保留吗

//
//

package runner
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个还要保留吗

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

需要的,用户自定义事件需要用到 option,所以要导出。倘若把 Runner option 放到 agui option中,则会有循环依赖的问题。
暂时没有自定义 Runner 实现的需求,所以 Runner 接口定义放到 internal/runner 了。

@sandyskies sandyskies merged commit 087c82f into trpc-group:main Sep 29, 2025
7 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Sep 29, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants