Help us shape the future of Go! Take the 2026 Go Developer Survey

ack

package module
v0.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 31, 2026 License: MIT Imports: 15 Imported by: 0

README

ack — trpc-agent-go 的工具调用许可库

ack 是构建在 trpc-agent-go AG-UI 协议栈之上的 Go 公共库,为 Agent 应用提供工具调用许可(tool permission)能力:

  • 层级分类:工具按 allow(默认放行)/ confirm(需人工确认)/ deny(禁用)分级;
  • 策略源:外部裁决系统(如风控)在每次调用时介入,可强制确认、背书降级或直接拒绝;
  • 许可:用户预先授予的授权(会话级/全局级)自动满足确认要求,决定时勾选"记住"即可生成;
  • 人工确认全生命周期:运行存活时阻塞唤醒(live 路径),服务重启后孤儿确认经会话历史软恢复续跑(recovery 路径);
  • 授权终态观察:全部自动放行/拒绝终态经回调外报宿主审计,人工决定归宿主 Decide 路由;
  • HTTP 绑定:确认决定/查询路由可挂载到任意 http.ServeMux。

完整设计(评估管线、事件契约、不变量、部署约束)见 docs/module_design.md;接入步骤、配置项与前端对接见 docs/usage.md;实现原理与机制图解见 docs/mechanism.md。

仓库布局

ack.go / permission.go / policy.go / confirm.go / recovery.go / grants.go / payload.go / errors.go / doc.go
  核心库(包 ack)
ackhttp/   确认决定/查询的 HTTP 路由(仅依赖标准库与 ack)
acktest/   测试夹具:脚本化模型、假续跑 runner
examples/notes/   端到端示例:笔记助手(Go 后端 + Vue3 前端 ack_notes/)
docs/module_design.md   设计文档(唯一设计事实来源)
docs/usage.md   使用文档(接入步骤、配置项、HTTP API、前端对接、测试)
docs/mechanism.md   原理机制文档(实现视角,含图解)

快速开始(示例)

# 1. 构建前端(产物不入库,仓库内有占位页)
cd examples/notes/ack_notes
pnpm install && pnpm build

# 2. 运行示例(离线 mock 模型,内存会话)
cd ../../..
go run ./examples/notes
# 打开 http://127.0.0.1:8080

# 以 MCP 工具模式运行:自动启动 MCP server 并对接 agent
#(启动日志打印 MCP 端点,外部 MCP 客户端可直连观察)
go run ./examples/notes -mcp

默认脚本演示完整许可闭环:读取 n1(allow 直行)→ 删除 n2(确认卡片)→ 删除 n3(勾选"记住授权"后免确认)→ 总结。

示例环境变量
变量 默认 说明
NOTES_ADDR 127.0.0.1:8080 HTTP 监听地址
NOTES_SESSION_BACKEND memory memory / postgres(重启恢复演示需 postgres)
NOTES_PG_DSN 本机默认 PostgreSQL 连接串(库不存在时自动创建)
NOTES_LLM deepseek mock(脚本化模型,离线)或真实提供方
NOTES_API_KEY 空 为空自动回退 mock;也读 DEEPSEEK_API_KEY
NOTES_BASE_URL / NOTES_MODEL DeepSeek OpenAI 兼容接口与模型名
NOTES_RISK_POLICY 0 置 1 启用 mock 风控策略源(演示强制确认/背书/deny 三形态)

命令标记:-mcp 启用 MCP 工具模式——自动启动 MCP server(streamable HTTP)并把同一批笔记工具原样接入 agent,验证 ack 对 MCP 工具同管线生效;默认 function 模式(进程内直接调用)。

示例端点
路由 说明
/ 前端(pnpm build 后嵌入单二进制;开发用 pnpm dev 代理)
POST /agui / POST /agui/history / POST /agui/cancel AG-UI SSE
POST /ack/confirmation 确认决定({threadId, confirmationId, approved, remember?},返回 {path: live|recovery})
GET /ack/confirmations?threadId= 待确认查询(含孤儿,live=false)
GET /api/sessions / DELETE /api/sessions/{id} 会话列表/删除(示例级参考实现)

库接入

gw := ack.New(svc,
    ack.WithApp("biz"),                    // 须与 AG-UI runner 的 AppName 一致
    ack.WithUser("u1"),
    ack.WithTiers(map[string]ack.Tier{"delete_note": ack.TierConfirm}),
    ack.WithPolicies(riskControl),         // 可选:策略源链
    ack.WithGrants(ack.MemoryGrants()),    // 业务可换自有存储
    ack.WithStaticTools(readNote, deleteNote),
    ack.WithPermissionObserver(func(ctx context.Context, e ack.PermissionEvent) {
        log.Println("permission settled", e.Call.ToolName, e.Basis) // 可选:终态外报
    }),
)

r := aguirunner.New(coreRunner,
    aguirunner.WithAppName("biz"),
    aguirunner.WithSessionService(svc),
    aguirunner.WithRunOptionResolver(gw.RunOptionResolver()),
    aguirunner.WithTimeout(10*time.Minute), // 未决确认最终由超时结算为拒绝
)
_ = gw.Bind(r)

ackhttp.Mount(mux, gw) // POST /ack/confirmation、GET /ack/confirmations

前端约定:消费 tool_confirmation 自定义事件渲染确认卡片,决定时调用 POST /ack/confirmation(可携带 remember),重连时以待确认查询补偿孤儿状态,续跑结果经 /agui/history follow 流读取。事件与存储契约见设计文档 §8。

依赖注记:trpc-mcp-go fork

上游 trpc.group/trpc-go/trpc-mcp-go 截至 v0.0.19 的 streamable 客户端存在会话状态并发访问缺陷:GET SSE goroutine 与 POST 响应处理竞争 sessionID / lastEventID,-race 下偶发数据竞争。修复位于 fork github.com/JNinng/trpc-mcp-go(tag 为「上游基线版本 + -N 修补序号」)。

Go 的 replace 只在主模块生效,本库 go.mod 中的 replace 不会被消费方继承,因此每个主模块需自行声明:

go mod edit -replace trpc.group/trpc-go/trpc-mcp-go=github.com/JNinng/trpc-mcp-go@v0.0.19-3

上游发布含该修复的版本后,删除此 replace 并升级依赖即可。

测试

go test -race -count=1 ./...          # 库 + ackhttp + 示例集成测试
cd examples/notes/ack_notes && pnpm exec vitest run   # 前端单测

Go 集成测试对恢复路径的断言采用"快照轮询"编写,不依赖 history follow 流的自然终止(见设计文档 D4 对上游时间戳缺陷的说明)。

许可

MIT

Documentation

Overview

Package ack 在 trpc-agent-go 的 AG-UI 协议栈之上提供工具调用许可 (tool permission)能力。

工具按层级(Tier)分类:默认放行(allow)、需人工确认(confirm)、 禁用(deny)。每次工具调用先经许可评估:外部策略源(PolicySource, 如风控)可介入裁决,用户预先授予的许可(Grant,会话级/全局级)可 满足确认要求,仅当无任何放行依据时才阻塞等待人工决定。全部自动 授权终态可经 WithPermissionObserver 外报宿主审计;人工决定不通知, 归宿主 Decide 路由。

人工确认的完整生命周期由网关(Gateway)承载:

  • 直接路径(live):发出确认的运行存活时,决定唤醒阻塞的运行 继续执行,事件仍走原始 SSE/follow 流;
  • 恢复路径(recovery):运行已不存在(如服务重启)时,由网关 代执行工具或合成拒绝结果,并拉起一次续跑运行,前端经 /history follow 流读取。

前端经 AG-UI 自定义事件 tool_confirmation 渲染确认卡片,经 ackhttp.Mount 挂载的 HTTP 路由提交决定。最小接入:

gw := ack.New(svc,
	ack.WithApp("biz"), // 须与 AG-UI runner 的 AppName 一致
	ack.WithTiers(map[string]ack.Tier{"delete_note": ack.TierConfirm}),
	ack.WithGrants(ack.MemoryGrants()),
	ack.WithStaticTools(readNote, deleteNote),
)
r := aguirunner.New(coreRunner,
	aguirunner.WithAppName("biz"),
	aguirunner.WithSessionService(svc),
	aguirunner.WithRunOptionResolver(gw.RunOptionResolver()),
)
_ = gw.Bind(r)
ackhttp.Mount(mux, gw)

完整契约(事件、状态存储、HTTP 形状、不变量)见 docs/module_design.md。

Index

Constants

View Source
const (
	// PathLive 直接路径:发出确认的运行仍存活,决定唤醒阻塞的运行。
	PathLive = "live"
	// PathRecovery 恢复路径:运行已不存在,网关代执行/合成结果并续跑。
	PathRecovery = "recovery"
)

决定实际生效的路径。

View Source
const (
	// EventName 是携带确认 Payload 的 AG-UI 自定义事件名。
	EventName = "tool_confirmation"

	// StateKey 是待确认表在 Session.State 中的键,
	// 让"等待确认"状态可以在服务重启后存活。
	StateKey = "__pending_tool_confirmation__"

	// StatusPending 表示确认正等待用户决定。
	StatusPending = "pending"
	// StatusApproved 表示用户已同意该确认。
	StatusApproved = "approved"
	// StatusDenied 表示用户已拒绝该确认。
	StatusDenied = "denied"
)

以下常量是 wire 与存储的兼容性契约:升级只增不改,否则遗留待确认 指针失联、前端事件配对失效。

Variables

View Source
var (
	// ErrNotFound 表示确认或会话不存在;含已决定(或已取消)后的
	// 重复决定与并发决定中的后到者。
	ErrNotFound = errors.New("ack: confirmation not found")

	// ErrNotBound 表示恢复路径需要续跑 runner 但未 Bind。
	ErrNotBound = errors.New("ack: resume runner not bound")

	// ErrRunActive 表示续跑时会话上仍有运行进行;对框架运行冲突
	// 错误包装,errors.Is 可判。
	ErrRunActive = errors.New("ack: run active on session")
)

Functions

This section is empty.

Types

type Basis

type Basis string

Basis 是授权终态的生效依据词表:一次工具调用的许可流程结束时, 标明放行或拒绝由哪条依据产生。该类型同时用作评估管线的内部依据 (evaluate 的返回值,供日志输出),内部值 basisForced / basisBaseline 保持未导出、不进入终态事件。

const (
	// BasisTier 层级依据:工具的许可层级直接放行或禁用。
	BasisTier Basis = "tier"
	// BasisVerdict 判定依据:首个 deny 判定的策略源拒绝。
	BasisVerdict Basis = "verdict"
	// BasisEndorsement 背书依据:首个 allow 判定的策略源将 confirm
	// 层级降级为放行。
	BasisEndorsement Basis = "endorsement"
	// BasisGrant 许可依据:人工预授予的许可命中放行。
	BasisGrant Basis = "grant"
	// BasisDuplicate 同会话重复确认 ID 的防御性放行。
	BasisDuplicate Basis = "duplicate"
	// BasisCanceled 运行取消或超时的结算拒绝。
	BasisCanceled Basis = "canceled"
	// BasisPersistFailed 确认请求持久化失败的结算拒绝。
	BasisPersistFailed Basis = "persist-failed"
)

type DecideResult

type DecideResult struct {
	Path string // PathLive | PathRecovery
}

DecideResult 是 Decide 的结果。

type Decision

type Decision struct {
	SessionID      string // 会话 ID
	ConfirmationID string // 确认 ID
	Approved       bool   // true=同意,false=拒绝
	DecidedBy      string // 决定人;留空取网关身份
	Remember       Scope  // 空=不生成许可;同意时按作用域写入许可源
}

Decision 是一次人工决定的完整参数;以结构体承载演进空间, 后续以增字段方式扩展。

type DenyTexts added in v0.2.1

type DenyTexts struct {
	// HumanDenied 人工拒绝(Decide 结算)的文案;live 与 recovery 路径一致。
	HumanDenied func(call ToolCall) string
	// TierDisabled 层级 deny 或策略 deny 判定拒绝的文案。
	TierDisabled func(toolName string) string
	// Canceled 运行取消或超时结算拒绝的文案。
	Canceled string
	// PersistFailed 待确认指针持久化失败结算拒绝的文案。
	PersistFailed string
	// Unavailable 恢复路径代执行时工具不可用/失败的文案;detail 为具体原因。
	Unavailable func(toolName, detail string) string
}

DenyTexts 定制各类拒绝时返回给模型的文案。零值字段使用库默认文案 (英文,含"不得重试"指令),自定义文案须自行保留该约束。

type Gateway

type Gateway struct {
	// contains filtered or unexported fields
}

Gateway 是库的核心对象:评估工具调用处置(放行/确认/拒绝),并承载 人工确认的完整生命周期——登记等待者、持久化待确认指针、结算决定、 恢复孤儿确认。Gateway 并发安全,可被多个 goroutine 同时调用。

网关不拥有会话存储、许可源与续跑 runner 的生命周期,三者由业务 构造与关闭。

func New

func New(svc session.Service, opts ...Option) *Gateway

New 创建许可网关。svc 为会话存储,由业务选择后端(框架自带 inmemory / postgres 等)并负责其生命周期。

func (*Gateway) Bind

func (g *Gateway) Bind(r ResumeRunner) error

Bind 注入恢复路径续跑使用的 AG-UI runner;传入 nil 返回错误。 恢复路径触发时未 Bind 的,Decide 返回 ErrNotBound。

func (*Gateway) Decide

func (g *Gateway) Decide(ctx context.Context, d Decision) (DecideResult, error)

Decide 结算一次人工决定,返回实际生效的路径(PathLive / PathRecovery)。 ctx 约束持久化与续跑的启动,不等待续跑完成。 同一确认的并发决定先到者生效,后到者返回 ErrNotFound。

func (*Gateway) Pending

func (g *Gateway) Pending(ctx context.Context, sessionID string) ([]PendingItem, error)

Pending 列出会话中等待决定的确认项:合并内存中的存活等待者与 Session.State 持久化的记录(含重启后的孤儿)。

func (*Gateway) PolicyFor

func (g *Gateway) PolicyFor(sessionID string) tool.PermissionPolicyFunc

PolicyFor 返回单个会话的权限策略:该会话的每次工具调用先经许可评估, 评估为确认的调用进入人工确认流程。供直接使用 core runner 的业务挂载; 经 AG-UI runner 接入的业务用 RunOptionResolver。

func (*Gateway) RunOptionResolver

func (g *Gateway) RunOptionResolver() func(ctx context.Context, in *adapter.RunAgentInput) ([]agent.RunOption, error)

RunOptionResolver 把许可策略适配为 aguirunner.WithRunOptionResolver 需要的形式,使每次 AG-UI 运行(含恢复路径的续跑)都挂上该策略。

type Grant

type Grant struct {
	UserID    string // 归属用户
	SessionID string // 非空即会话级;空即全局级
	ToolName  string
	CreatedBy string // 决定来源(人工决定的 DecidedBy)
	CreatedAt int64  // 毫秒时间戳
}

Grant 是用户对某工具的预先授权,可满足 confirm 层级的确认要求; 强制确认(策略源 confirm 判定触发)不可被许可满足。

type GrantQuery

type GrantQuery struct {
	UserID    string
	SessionID string
	ToolName  string
}

GrantQuery 是许可查询条件。

type GrantSource

type GrantSource interface {
	Lookup(ctx context.Context, q GrantQuery) (Grant, bool)
	Save(ctx context.Context, g Grant) error
}

GrantSource 是许可存储的接入点,由业务实现(如用户设置系统)。 生命周期归业务管理(列出/吊销/过期);库仅在许可评估时读取、在 Remember 决定时写入。Lookup 须按"会话级先于全局级"的次序命中。

func MemoryGrants

func MemoryGrants() GrantSource

MemoryGrants 返回线程安全的内存许可源,供测试与示例使用; 进程内生效,重启即失。

type NamedPolicy

type NamedPolicy struct {
	Name   string
	Source PolicySource
}

NamedPolicy 是带名字的策略源:名字进入授权终态事件的 Source 字段, 标明生效依据来自哪个外部裁决系统;空名字视同匿名(Source 为空)。

type Option

type Option func(*options)

Option 配置 Gateway。

func WithApp

func WithApp(name string) Option

WithApp 设置应用名(默认 "ack")。它是会话存储键的组成部分, 必须与 AG-UI runner 的 AppName 一致,否则会话定位失败。

func WithDefaultTier

func WithDefaultTier(t Tier) Option

WithDefaultTier 设置未分级工具的层级(默认 TierAllow)。

func WithDenyTexts added in v0.2.1

func WithDenyTexts(t DenyTexts) Option

WithDenyTexts 定制各类拒绝时返回给模型的文案(见 DenyTexts); 零值字段保持默认文案(英文、含"不得重试"指令)。

func WithGrants

func WithGrants(gs GrantSource) Option

WithGrants 设置许可源;缺省时许可评估视为永不命中,Remember 被忽略。

func WithLogger

func WithLogger(l *slog.Logger) Option

WithLogger 设置结构化日志器(默认 slog.Default())。

func WithNamedPolicies

func WithNamedPolicies(ps ...NamedPolicy) Option

WithNamedPolicies 设置具名策略源,名字进入授权终态事件的 Source 字段,标明生效依据来自哪个外部裁决系统;与 WithPolicies 合成一条 咨询链(具名源在前、匿名源在后)。空名字视同匿名。

func WithPermissionObserver

func WithPermissionObserver(ob PermissionObserver) Option

WithPermissionObserver 设置授权终态观察者,订阅全部自动授权终态; 人工决定不通知,归宿主 Decide 路由审计。缺省 nil 零行为, 调用契约见 PermissionObserver。

func WithPolicies

func WithPolicies(src ...PolicySource) Option

WithPolicies 设置匿名策略源,每次工具调用逐个同步咨询;与 WithNamedPolicies 合成一条咨询链(具名源在前、匿名源在后),匿名 登记不产生授权终态事件的 Source。

func WithStaticTools

func WithStaticTools(tools ...tool.Tool) Option

WithStaticTools 是 WithTools 的静态糖:直接给出工具集合, 裁决时刻按声明名解析。

func WithTierFunc

func WithTierFunc(fn func(ctx context.Context, call ToolCall) Tier) Option

WithTierFunc 设置动态分级,可依据入参分类;优先于静态表, 静态表优先于默认层级。

func WithTiers

func WithTiers(m map[string]Tier) Option

WithTiers 按工具名静态分级。

func WithTools

func WithTools(res ToolResolver) Option

WithTools 设置工具解析器:恢复路径代执行时调用,返回"工具名 → 可调用工具"。缺省时同意的孤儿确认降级为"工具不可用"拒绝。

func WithUser

func WithUser(id string) Option

WithUser 设置固定用户 ID(默认 "user"),是会话存储键与许可查询的 组成部分。多用户场景改用 WithUserFunc。

func WithUserFunc

func WithUserFunc(fn func(ctx context.Context, threadID string) string) Option

WithUserFunc 设置动态身份:从请求上下文取鉴权结果 (鉴权中间件将用户写入 ctx)。优先于 WithUser。

type Payload

type Payload struct {
	ConfirmationID string          `json:"confirmationId"`      // 确认 ID(即工具调用 ID)
	ToolCallID     string          `json:"toolCallId"`          // 关联的工具调用 ID
	ToolName       string          `json:"toolName"`            // 工具名
	Arguments      json.RawMessage `json:"arguments,omitempty"` // 工具入参(JSON)
	SessionID      string          `json:"sessionId"`           // 所属会话 ID
	Status         string          `json:"status"`              // pending | approved | denied
	DecidedBy      string          `json:"decidedBy,omitempty"` // 做出决定的用户
	CreatedAt      int64           `json:"createdAt"`           // 创建时间(毫秒时间戳)
}

Payload 是一次工具确认的完整描述:随 AG-UI CustomEvent 下发前端, 同时以待确认指针的形式持久化在 Session.State 中。

func (Payload) CustomEvent

func (p Payload) CustomEvent() *aguievents.CustomEvent

CustomEvent 把 Payload 包装为 AG-UI 自定义事件。

type PendingItem

type PendingItem struct {
	Payload
	Live bool `json:"live"`
}

PendingItem 是待确认列表项;Live 标记阻塞中的运行是否仍存活 (false 表示已成孤儿,例如服务重启之后)。

type PermissionEvent

type PermissionEvent struct {
	// Call 是发生授权的调用视图。
	Call ToolCall
	// Allowed 是终态是否放行。
	Allowed bool
	// Basis 是生效依据,取值见 Basis 词表。
	Basis Basis
	// Source 是生效的具名策略源名:Basis 为 verdict 或 endorsement
	// 时是首个生效源的名字,其余依据与匿名策略源为空。已知信息损失:
	// 策略源咨询出错按 confirm 判定处理(fail-safe),该调用若最终以
	// canceled 结算,事件不携带出错源的名字,出错细节以网关日志为准。
	Source string
}

PermissionEvent 是一次工具调用的授权终态:该调用的许可流程已结束, 结论不再变更。人工决定(Decide 结算,live 与 recovery 路径均是) 不产生事件——每次工具调用恰好一条授权终态:要么 PermissionEvent、 要么 Decide 结算,二者互斥且共同覆盖全部调用;人工决定由宿主在 Decide 自身的路由与日志中审计。

type PermissionObserver

type PermissionObserver func(ctx context.Context, event PermissionEvent)

PermissionObserver 订阅网关产出的全部自动授权终态,供宿主外报审计。 网关在授权流程结束的同步路径上回调:回调应快速返回,重负载的外报 由宿主自行异步化。回调 ctx 经 context.WithoutCancel 处理、保证未取消 (取消/超时终态亦然),回调内可安全执行 IO,需要超时自行派生。 回调无返回值:观察不改变授权结论,回调内部错误由宿主自行处理。

type PolicySource

type PolicySource interface {
	Consult(ctx context.Context, call ToolCall) (Verdict, error)
}

PolicySource 是外部裁决系统(如风控)在库中的接入点,每次工具调用 被同步咨询。咨询出错时网关按 confirm 判定处理并记录日志(fail-safe: 裁决权威不可达时不静默放行);业务需要 fail-open 时,可在自身实现内 吞掉错误并返回 abstain。咨询位于工具调用的同步关键路径,源应低延迟 或由业务侧缓存。

type ResumeRunner

type ResumeRunner interface {
	Run(ctx context.Context, runAgentInput *adapter.RunAgentInput) (<-chan aguievents.Event, error)
}

ResumeRunner 与 AG-UI runner 的运行接口一致,恢复路径用它拉起续跑 运行。aguirunner.New 的返回值直接满足该接口。

type Scope

type Scope string

Scope 是许可的作用域。

const (
	// ScopeSession 会话级:绑定单个会话。
	ScopeSession Scope = "session"
	// ScopeGlobal 全局级:对该用户的全部会话生效。
	ScopeGlobal Scope = "global"
)

type Tier

type Tier string

Tier 是工具的基线许可层级。

const (
	// TierAllow 默认放行。
	TierAllow Tier = "allow"
	// TierConfirm 需人工确认;可被背书或已授予的许可满足。
	TierConfirm Tier = "confirm"
	// TierDeny 禁用;不可经判定、许可或人工决定放行。
	TierDeny Tier = "deny"
)

type ToolCall

type ToolCall struct {
	SessionID  string
	ToolCallID string
	ToolName   string
	Arguments  json.RawMessage
}

ToolCall 是评估与分级看到的调用视图。

type ToolResolver

type ToolResolver func(ctx context.Context) map[string]tool.CallableTool

ToolResolver 在裁决时刻返回"工具名 → 可调用工具"注册表,供恢复路径 代执行使用。做成函数形式使 MCP 等动态工具集可以在决定时刻实时解析。

type Verdict

type Verdict string

Verdict 是策略源对一次工具调用返回的意见。

const (
	// VerdictAbstain 无立场,不参与裁决。
	VerdictAbstain Verdict = "abstain"
	// VerdictAllow 背书:可将 confirm 层级降级为放行。
	VerdictAllow Verdict = "allow"
	// VerdictConfirm 强制确认:必须由人工决定,不可被许可满足。
	VerdictConfirm Verdict = "confirm"
	// VerdictDeny 拒绝:绝对,不可降级。
	VerdictDeny Verdict = "deny"
)

Directories

Path Synopsis
Package ackhttp 把确认决定/查询路由挂载到任意 http.ServeMux, 仅依赖标准库与 ack。
Package ackhttp 把确认决定/查询路由挂载到任意 http.ServeMux, 仅依赖标准库与 ack。
Package acktest 提供无真实 LLM 时的确定性测试夹具:脚本化模型 (model.Model 实现)与假续跑 runner,供库自身的测试与业务侧的 确认流集成测试使用。
Package acktest 提供无真实 LLM 时的确定性测试夹具:脚本化模型 (model.Model 实现)与假续跑 runner,供库自身的测试与业务侧的 确认流集成测试使用。
examples
notes command
notes 示例后端入口:基于 trpc-agent-go 的 AG-UI SSE 服务与 ack 许可网关。
notes 示例后端入口:基于 trpc-agent-go 的 AG-UI SSE 服务与 ack 许可网关。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL