From c73c35b36c6c406591c291cc907dedda071a221b Mon Sep 17 00:00:00 2001 From: Nene7ko_ <1604009816@qq.com> Date: Wed, 12 Aug 2026 03:21:28 +0800 Subject: [PATCH 1/2] docs: start public registration quickstart From 6e99b20e0c429f0a8c7ed5c7394be7c7ac1d288d Mon Sep 17 00:00:00 2001 From: Nene7ko_ <1604009816@qq.com> Date: Wed, 12 Aug 2026 03:47:06 +0800 Subject: [PATCH 2/2] docs: use public SDK registration in quickstart --- README.md | 83 +++++++++++++++------------- README.zh-CN.md | 81 ++++++++++++++------------- docs/usage/readme_quickstart_test.go | 60 ++++++++++++++++++++ 3 files changed, 148 insertions(+), 76 deletions(-) create mode 100644 docs/usage/readme_quickstart_test.go diff --git a/README.md b/README.md index 30012e4..6317515 100644 --- a/README.md +++ b/README.md @@ -225,21 +225,26 @@ Consumers never resolve or dial a Provider address. Core owns the registration, heartbeat, lease, and deregistration semantics through [`registry`](https://pkg.go.dev/github.com/NeKiro-project/NeKiro/registry) and [`registry/nacos`](https://pkg.go.dev/github.com/NeKiro-project/NeKiro/registry/nacos). -The Samples adapter only maps explicit `RUNTIME_A_*` / `RUNTIME_B_*` settings, -builds the secured HTTP transport, and connects lease readiness to the process -lifecycle. The endpoint ownership challenge is a separate trusted-publication -check. Since the examples use Samples `internal` packages, copy the pattern -into another Agent module instead of importing those packages directly. +The public SDK +[`agent/registration/nacos`](https://pkg.go.dev/github.com/NeKiro-project/nekiro-sdk-go/agent/registration/nacos) +maps explicit `RUNTIME_A_*` / `RUNTIME_B_*` settings, builds the secured HTTP +transport, and connects the Core lease to the managed host lifecycle. Samples +still owns each Agent's configuration, Router authentication, handlers, and +endpoint ownership challenge. External providers can import the SDK +registration package directly; the Samples `internal/challengeproof` package +remains a sample-owned deployment detail and is not a public API. The complete production sources are [Runtime A main](https://github.com/NeKiro-project/NeKiro-Samples/blob/main/runtime-a/cmd/runtime-a/main.go), [Runtime B main](https://github.com/NeKiro-project/NeKiro-Samples/blob/main/runtime-b/cmd/runtime-b/main.go), and [B -> A nested invocation](https://github.com/NeKiro-project/NeKiro-Samples/blob/main/runtime-b/nested.go). -### 3. Copy the complete Runtime mains +### 3. Read the complete Runtime mains The programs below are complete `package main` entrypoints. They keep Runtime -configuration, Router authentication, TLS/mTLS, challenge proof, and handlers -in Samples, while [`agent/host`](https://pkg.go.dev/github.com/NeKiro-project/nekiro-sdk-go/agent/host) +configuration, Router authentication, challenge proof, and handlers in Samples. +The public [`agent/registration/nacos`](https://pkg.go.dev/github.com/NeKiro-project/nekiro-sdk-go/agent/registration/nacos) +package owns strict registration composition, while +[`agent/host`](https://pkg.go.dev/github.com/NeKiro-project/nekiro-sdk-go/agent/host) owns serving, lease observation, bounded shutdown, and deregistration.
@@ -257,9 +262,9 @@ import ( "time" "github.com/NeKiro-project/NeKiro-Samples/internal/challengeproof" - "github.com/NeKiro-project/NeKiro-Samples/internal/nacosregistration" runtimea "github.com/NeKiro-project/NeKiro-Samples/runtime-a" agenthost "github.com/NeKiro-project/nekiro-sdk-go/agent/host" + registrationnacos "github.com/NeKiro-project/nekiro-sdk-go/agent/registration/nacos" ) func main() { @@ -277,23 +282,13 @@ func runWithLookup(lookup func(string) (string, bool)) error { if err != nil { return agenthost.Wrap(agenthost.StageConfig, "load Runtime A configuration", err) } - registrationConfig, err := nacosregistration.Load(lookup, "RUNTIME_A", config.AgentID, config.InstanceID) + registrationConfig, err := registrationnacos.LoadConfig(lookup, "RUNTIME_A", config.AgentID, config.InstanceID) if err != nil { return agenthost.Wrap(agenthost.StageConfig, "load Runtime A registration configuration", err) } - var registration agenthost.Registration - var readiness runtimea.Readiness = ready(true) - if registrationConfig.Mode == nacosregistration.ModeNacos { - registrationClient, clientErr := nacosregistration.NewHTTPClient(registrationConfig) - if clientErr != nil { - return agenthost.Wrap(agenthost.StageRegistration, "create Runtime A Nacos transport", clientErr) - } - runtimeRegistration, err := nacosregistration.New(registrationConfig, registrationClient) - if err != nil { - return agenthost.Wrap(agenthost.StageRegistration, "create Runtime A registration", err) - } - registration = runtimeRegistration - readiness = runtimeRegistration + registration, readiness, err := newRuntimeRegistration(registrationConfig) + if err != nil { + return agenthost.Wrap(agenthost.StageRegistration, "create Runtime A registration", err) } handler, err := runtimea.NewHandler(config, http.DefaultClient) if err != nil { @@ -323,6 +318,17 @@ func runWithLookup(lookup func(string) (string, bool)) error { type ready bool func (value ready) Ready() bool { return bool(value) } + +func newRuntimeRegistration(config registrationnacos.Config) (agenthost.Registration, runtimea.Readiness, error) { + if config.Mode == registrationnacos.ModeDisabled { + return nil, ready(true), nil + } + registration, err := registrationnacos.New(config) + if err != nil { + return nil, nil, err + } + return registration, registration, nil +} ```
@@ -342,9 +348,9 @@ import ( "time" "github.com/NeKiro-project/NeKiro-Samples/internal/challengeproof" - "github.com/NeKiro-project/NeKiro-Samples/internal/nacosregistration" runtimeb "github.com/NeKiro-project/NeKiro-Samples/runtime-b" agenthost "github.com/NeKiro-project/nekiro-sdk-go/agent/host" + registrationnacos "github.com/NeKiro-project/nekiro-sdk-go/agent/registration/nacos" "github.com/NeKiro-project/nekiro-sdk-go/agent/routerauth" ) @@ -371,23 +377,13 @@ func runWithLookup(lookup func(string) (string, bool)) error { if err != nil { return agenthost.Wrap(agenthost.StageConfig, "load Runtime B configuration", err) } - registrationConfig, err := runtimeb.LoadRegistrationConfig(lookup, config.AgentID, config.InstanceID) + registrationConfig, err := registrationnacos.LoadConfig(lookup, "RUNTIME_B", config.AgentID, config.InstanceID) if err != nil { return agenthost.Wrap(agenthost.StageConfig, "load Runtime B registration configuration", err) } - var registration agenthost.Registration - var readiness runtimeb.Readiness = ready(true) - if registrationConfig.Mode == runtimeb.RegistrationModeNacos { - registrationClient, clientErr := nacosregistration.NewHTTPClient(registrationConfig) - if clientErr != nil { - return agenthost.Wrap(agenthost.StageRegistration, "create Runtime B Nacos transport", clientErr) - } - runtimeRegistration, err := runtimeb.NewNacosRegistration(registrationConfig, registrationClient) - if err != nil { - return agenthost.Wrap(agenthost.StageRegistration, "create Runtime B registration", err) - } - registration = runtimeRegistration - readiness = runtimeRegistration + registration, readiness, err := newRuntimeRegistration(registrationConfig) + if err != nil { + return agenthost.Wrap(agenthost.StageRegistration, "create Runtime B registration", err) } handler, err := runtimeb.NewConfiguredHandler(config, http.DefaultClient) if err != nil { @@ -421,6 +417,17 @@ func runWithLookup(lookup func(string) (string, bool)) error { type ready bool func (value ready) Ready() bool { return bool(value) } + +func newRuntimeRegistration(config registrationnacos.Config) (agenthost.Registration, runtimeb.Readiness, error) { + if config.Mode == registrationnacos.ModeDisabled { + return nil, ready(true), nil + } + registration, err := registrationnacos.New(config) + if err != nil { + return nil, nil, err + } + return registration, registration, nil +} ``` diff --git a/README.zh-CN.md b/README.zh-CN.md index 8f4ee80..3b96dce 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -203,20 +203,23 @@ Runtime A <---- managed A2A ----> Router <---- managed A2A ----> Runtime B Consumer 不会自行解析或直连 Provider 地址。Core 通过 [`registry`](https://pkg.go.dev/github.com/NeKiro-project/NeKiro/registry) 和 [`registry/nacos`](https://pkg.go.dev/github.com/NeKiro-project/NeKiro/registry/nacos) -拥有注册、heartbeat、lease 与 deregistration 语义。Samples adapter 只映射显式的 -`RUNTIME_A_*` / `RUNTIME_B_*` 配置,构造安全 HTTP transport,并把 lease readiness -接入进程生命周期。Endpoint ownership challenge 是另一条可信发布校验。由于示例 -使用 Samples `internal` package,其他 Agent 模块应复制这种接入模式,而不能直接 -import 这些包。 +拥有注册、heartbeat、lease 与 deregistration 语义。公共 SDK +[`agent/registration/nacos`](https://pkg.go.dev/github.com/NeKiro-project/nekiro-sdk-go/agent/registration/nacos) +负责映射显式的 `RUNTIME_A_*` / `RUNTIME_B_*` 配置、构造安全 HTTP transport,并将 +Core lease 接入托管 host 生命周期。Samples 继续拥有各 Agent 的配置、Router 鉴权、 +handler 和 endpoint ownership challenge。外部 Provider 可以直接 import SDK 注册包; +Samples 的 `internal/challengeproof` 仍是 Sample 自有部署细节,不属于公共 API。 完整生产源码见 [Runtime A main](https://github.com/NeKiro-project/NeKiro-Samples/blob/main/runtime-a/cmd/runtime-a/main.go)、 [Runtime B main](https://github.com/NeKiro-project/NeKiro-Samples/blob/main/runtime-b/cmd/runtime-b/main.go) 和 [B -> A 嵌套调用](https://github.com/NeKiro-project/NeKiro-Samples/blob/main/runtime-b/nested.go)。 -### 3. 复制完整 Runtime main +### 3. 阅读完整 Runtime main -下面是完整的 `package main` 入口。Runtime 配置、Router 鉴权、TLS/mTLS、challenge -proof 和 handler 仍由 Samples 拥有; +下面是完整的 `package main` 入口。Runtime 配置、Router 鉴权、challenge proof 和 +handler 仍由 Samples 拥有。公共 +[`agent/registration/nacos`](https://pkg.go.dev/github.com/NeKiro-project/nekiro-sdk-go/agent/registration/nacos) +负责严格的注册组合, [`agent/host`](https://pkg.go.dev/github.com/NeKiro-project/nekiro-sdk-go/agent/host) 统一负责 HTTP serving、lease observation、有界 shutdown 和 deregistration。 @@ -235,9 +238,9 @@ import ( "time" "github.com/NeKiro-project/NeKiro-Samples/internal/challengeproof" - "github.com/NeKiro-project/NeKiro-Samples/internal/nacosregistration" runtimea "github.com/NeKiro-project/NeKiro-Samples/runtime-a" agenthost "github.com/NeKiro-project/nekiro-sdk-go/agent/host" + registrationnacos "github.com/NeKiro-project/nekiro-sdk-go/agent/registration/nacos" ) func main() { @@ -255,23 +258,13 @@ func runWithLookup(lookup func(string) (string, bool)) error { if err != nil { return agenthost.Wrap(agenthost.StageConfig, "load Runtime A configuration", err) } - registrationConfig, err := nacosregistration.Load(lookup, "RUNTIME_A", config.AgentID, config.InstanceID) + registrationConfig, err := registrationnacos.LoadConfig(lookup, "RUNTIME_A", config.AgentID, config.InstanceID) if err != nil { return agenthost.Wrap(agenthost.StageConfig, "load Runtime A registration configuration", err) } - var registration agenthost.Registration - var readiness runtimea.Readiness = ready(true) - if registrationConfig.Mode == nacosregistration.ModeNacos { - registrationClient, clientErr := nacosregistration.NewHTTPClient(registrationConfig) - if clientErr != nil { - return agenthost.Wrap(agenthost.StageRegistration, "create Runtime A Nacos transport", clientErr) - } - runtimeRegistration, err := nacosregistration.New(registrationConfig, registrationClient) - if err != nil { - return agenthost.Wrap(agenthost.StageRegistration, "create Runtime A registration", err) - } - registration = runtimeRegistration - readiness = runtimeRegistration + registration, readiness, err := newRuntimeRegistration(registrationConfig) + if err != nil { + return agenthost.Wrap(agenthost.StageRegistration, "create Runtime A registration", err) } handler, err := runtimea.NewHandler(config, http.DefaultClient) if err != nil { @@ -301,6 +294,17 @@ func runWithLookup(lookup func(string) (string, bool)) error { type ready bool func (value ready) Ready() bool { return bool(value) } + +func newRuntimeRegistration(config registrationnacos.Config) (agenthost.Registration, runtimea.Readiness, error) { + if config.Mode == registrationnacos.ModeDisabled { + return nil, ready(true), nil + } + registration, err := registrationnacos.New(config) + if err != nil { + return nil, nil, err + } + return registration, registration, nil +} ``` @@ -320,9 +324,9 @@ import ( "time" "github.com/NeKiro-project/NeKiro-Samples/internal/challengeproof" - "github.com/NeKiro-project/NeKiro-Samples/internal/nacosregistration" runtimeb "github.com/NeKiro-project/NeKiro-Samples/runtime-b" agenthost "github.com/NeKiro-project/nekiro-sdk-go/agent/host" + registrationnacos "github.com/NeKiro-project/nekiro-sdk-go/agent/registration/nacos" "github.com/NeKiro-project/nekiro-sdk-go/agent/routerauth" ) @@ -349,23 +353,13 @@ func runWithLookup(lookup func(string) (string, bool)) error { if err != nil { return agenthost.Wrap(agenthost.StageConfig, "load Runtime B configuration", err) } - registrationConfig, err := runtimeb.LoadRegistrationConfig(lookup, config.AgentID, config.InstanceID) + registrationConfig, err := registrationnacos.LoadConfig(lookup, "RUNTIME_B", config.AgentID, config.InstanceID) if err != nil { return agenthost.Wrap(agenthost.StageConfig, "load Runtime B registration configuration", err) } - var registration agenthost.Registration - var readiness runtimeb.Readiness = ready(true) - if registrationConfig.Mode == runtimeb.RegistrationModeNacos { - registrationClient, clientErr := nacosregistration.NewHTTPClient(registrationConfig) - if clientErr != nil { - return agenthost.Wrap(agenthost.StageRegistration, "create Runtime B Nacos transport", clientErr) - } - runtimeRegistration, err := runtimeb.NewNacosRegistration(registrationConfig, registrationClient) - if err != nil { - return agenthost.Wrap(agenthost.StageRegistration, "create Runtime B registration", err) - } - registration = runtimeRegistration - readiness = runtimeRegistration + registration, readiness, err := newRuntimeRegistration(registrationConfig) + if err != nil { + return agenthost.Wrap(agenthost.StageRegistration, "create Runtime B registration", err) } handler, err := runtimeb.NewConfiguredHandler(config, http.DefaultClient) if err != nil { @@ -399,6 +393,17 @@ func runWithLookup(lookup func(string) (string, bool)) error { type ready bool func (value ready) Ready() bool { return bool(value) } + +func newRuntimeRegistration(config registrationnacos.Config) (agenthost.Registration, runtimeb.Readiness, error) { + if config.Mode == registrationnacos.ModeDisabled { + return nil, ready(true), nil + } + registration, err := registrationnacos.New(config) + if err != nil { + return nil, nil, err + } + return registration, registration, nil +} ``` diff --git a/docs/usage/readme_quickstart_test.go b/docs/usage/readme_quickstart_test.go new file mode 100644 index 0000000..8c2031c --- /dev/null +++ b/docs/usage/readme_quickstart_test.go @@ -0,0 +1,60 @@ +package usage_test + +import ( + "go/format" + "os" + "path/filepath" + "reflect" + "strings" + "testing" +) + +func TestQuickstartGoBlocksRemainPortableAndSynchronized(t *testing.T) { + english := readGoBlocks(t, filepath.Join("..", "..", "README.md")) + chinese := readGoBlocks(t, filepath.Join("..", "..", "README.zh-CN.md")) + if len(english) != 2 { + t.Fatalf("English Quickstart Go blocks = %d, want 2", len(english)) + } + if !reflect.DeepEqual(english, chinese) { + t.Fatal("English and Chinese Quickstart Go blocks differ") + } + for index, source := range english { + if _, err := format.Source([]byte(source)); err != nil { + t.Fatalf("Quickstart Go block %d does not parse: %v", index+1, err) + } + if strings.Contains(source, "NeKiro-Samples/internal/nacosregistration") { + t.Fatalf("Quickstart Go block %d imports the Samples-internal registration adapter", index+1) + } + if !strings.Contains(source, "nekiro-sdk-go/agent/registration/nacos") { + t.Fatalf("Quickstart Go block %d does not use the public SDK registration package", index+1) + } + } +} + +func readGoBlocks(t *testing.T, path string) []string { + t.Helper() + content, err := os.ReadFile(path) + if err != nil { + t.Fatal(err) + } + lines := strings.Split(strings.ReplaceAll(string(content), "\r\n", "\n"), "\n") + var blocks []string + var current []string + inBlock := false + for _, line := range lines { + switch { + case !inBlock && line == "```go": + inBlock = true + current = nil + case inBlock && line == "```": + blocks = append(blocks, strings.Join(current, "\n")+"\n") + inBlock = false + case inBlock: + current = append(current, line) + } + } + if inBlock { + t.Fatalf("unterminated Go block in %s", path) + } + return blocks +}