Syllm.Brickly.Sdk 0.12.0

dotnet add package Syllm.Brickly.Sdk --version 0.12.0
                    
NuGet\Install-Package Syllm.Brickly.Sdk -Version 0.12.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Syllm.Brickly.Sdk" Version="0.12.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Syllm.Brickly.Sdk" Version="0.12.0" />
                    
Directory.Packages.props
<PackageReference Include="Syllm.Brickly.Sdk" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Syllm.Brickly.Sdk --version 0.12.0
                    
#r "nuget: Syllm.Brickly.Sdk, 0.12.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Syllm.Brickly.Sdk@0.12.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Syllm.Brickly.Sdk&version=0.12.0
                    
Install as a Cake Addin
#tool nuget:?package=Syllm.Brickly.Sdk&version=0.12.0
                    
Install as a Cake Tool

Syllm.Brickly.Sdk(.NET 8+)

Brickly Brick 原生 .NET runtime SDK。生产协议为 brickly.runtime.v1(loopback gRPC invoke / interact),语义与 Node / Go / Python SDK 对齐。

  • 原生 Follower:C# 直接实现协议,不包装 Go DLL。
  • 内嵌 gRPC server:Host 会主动拨入 Brick 进程的 BrickCommandService,SDK 用 Kestrel 在 127.0.0.1:0 起 HTTP/2 明文服务。
  • framework-dependent:用户机器需要 .NET 8 运行时(含 ASP.NET Core),下载 https://dotnet.microsoft.com/download/dotnet/8.0(选 "ASP.NET Core Runtime")。宿主要拉起 Brick 前可用 dotnet --list-runtimes 预检。

快速上手

using System.Text.Json;
using Syllm.Brickly.Sdk;

var runtime = new BricklyRuntime();

runtime.OnCommand("hello", (ctx, input) =>
{
    var name = input.TryGetProperty("name", out var value) ? value.GetString() : null;
    ctx.Info("hello", new Dictionary<string, object?> { ["name"] = name });
    return Task.FromResult<object?>(new Dictionary<string, object?>
    {
        ["message"] = "Hello, " + (name ?? "Brickly"),
    });
});

await runtime.StartAsync();        // 缺 BRICKLY_HOST_ENDPOINT 会抛 PROTOCOL_ERROR
await runtime.WaitForShutdownAsync();

StartAsync 完成注册后返回;WaitForShutdownAsync(或 DisposeAsync)负责进程存活与退出清理。

SDK 自动完成:

  • 连接 BRICKLY_HOST_ENDPOINT 并注册 gRPC Runtime
  • invoke / interact 命令分发
  • Host 平台 / Resource / Event / Connector / Storage 客户端路由
  • CancellationToken 取消信号
  • OnShutdown 钩子

核心 API

BricklyRuntime(new BricklyRuntime())

成员 作用
OnCommand(id, handler) 注册命令处理器(链式)
OnSearch(id, handler) 注册快速搜索 Provider 端点(manifest provider: 'search' 命令,链式)
InvokeAsync(commandId, input, ct) 再跑自己的一条命令;已有占用则不 Dispose
InteractAsync(commandId, input, opts, ct) 已有占用上再开会话;必须传 OnEvent
CallAsync(commandId, input, opts, ct) Interact + 半关闭的糖;与命令 mode=call 对齐
OnReady(fn) / OnShutdown(fn) 注册 / 关闭钩子
UI.CreateBrowserWindowAsync(url, opts) 创建 Session 子窗口
UI.ListWindowsAsync() 列出本 Brick 持有的窗口
Events.On(event, fn) 订阅公共事件(命名空间:主题),返回 IDisposable
Events.PublishAsync(event, payload) 发布事件
Platform.* / System.* 宿主系统能力
Dependencies.Require(alias) 获取 Host 握手绑定的依赖客户端
OpenResource(ref) 惰性绑定已有 ResourceRef
CreateResourceAsync(content, options) 创建资源;超过 1 MiB 自动走 Writer
CreateResourceFromAsync(stream, options) 从 Stream 流式创建
CreateResourceWriterAsync(options) 多次 WriteAsync,Finish 后返回 Handle
StartAsync(ct) / WaitForShutdownAsync() 启动 / 等待退出
Debug/Info/Warn/Error 经 Host diagnostics.log 进入日志中心

CommandContext

成员 作用
RequestID / CommandID 当前请求与命令 id
Invocation 宿主注入的可信调用来源;缺省 Source = "unknown"
CancellationToken 命令取消时被取消
SendAsync(event) 推给调用方(仅 interact)
OnEvent(handler) 收调用方事件(仅 interact)
HandleRequests(handler, concurrency?) 会话内 request handler;return 就是那条 request 的结果
Closed 等到调用方 end / 断开
Dependencies().Require(alias) 绑定当前 command parent / Profile 的依赖客户端
UI() / Events / Platform() / System() 与 Runtime 同源
Config / Storage() Profile 配置快照 / 本机持久存储
CreateResourceAsync / CreateResourceFromAsync / CreateResourceWriterAsync 命令作用域资源创建

命令处理器签名:

public delegate Task<object?> CommandHandler(CommandContext context, JsonElement input);

返回结果或抛 BppException(保留 code 回传宿主);其他异常映射为 INTERNAL。


跨 Brick 调用

调用方 manifest 必须在 dependencies 中声明目标 Brick 和允许调用的命令。业务代码只使用 alias,精确来源与版本由 Host 握手绑定:

runtime.OnCommand("ask", async (ctx, _) =>
{
    var openAi = ctx.Dependencies().Require("openai");
    var result = await openAi.InvokeAsync(
        "chat",
        new Dictionary<string, object?> { ["prompt"] = "hello" },
        new InvokeOptions { ProfileId = "work" });
    return result;
});

有状态交互用 InteractAsync(必须传 OnEvent),说完用 EndAsync;CallAsync 是 Interact + 半关闭的糖。

命令内长期占用:await ctx.Dependencies().Require(alias).StartAsync(),返回 StartedToolHandle(InvokeAsync / InteractAsync / CallAsync / DisposeAsync / StopAsync),跟这次 Call,return 自动放手。命令外 StartAsync 抛 PARENT_INVOCATION_REQUIRED。


资源

普通 InvokeAsync 结果保持 ResourceRef;读取先 OpenResource:

var handle = runtime.OpenResource(reference);
await using var stream = handle;             // ResourceHandle : Stream,按 gRPC 块读
var bytes = await handle.BytesAsync();       // 上限 200 MiB;更大用流式读取
await handle.SaveToAsync("out.bin");

创建:

var note = await runtime.CreateResourceAsync("hello", new ResourceCreateOptions { Name = "note.txt" });
var big = await runtime.CreateResourceFromAsync(sourceStream, new ResourceCreateOptions { Name = "large.bin" });

var writer = await runtime.CreateResourceWriterAsync();
await writer.WriteAsync(chunk);
var handle = await writer.FinishAsync();      // 幂等

单帧 1 MiB、gRPC 消息 12 MiB、整份读取 200 MiB、并发上传 8。string 默认 text/plain; charset=utf-8,byte[] 默认 application/octet-stream。


窗口

var win = await runtime.UI.CreateBrowserWindowAsync("ui/pet.html", new WindowOptions
{
    ["width"] = 480,
    ["height"] = 320,
});

var title = await win.GetTitleAsync();
await win.SetBoundsAsync(new Bounds { X = 10, Y = 20 });
var closeResult = await win.CloseAsync();     // closed | prevented | pending | not-found
unsub();                                      // IDisposable
  • ctx.UI() 创建 Call 窗口(binding=call,随这次调用消失);Runtime.UI 创建 Session 窗口(binding=session)。
  • 105 个反射方法 + 2 个宿主合成方法(StartDragAsync/EndDragAsync,frameless 浮窗原生拖拽)按 specs/window-protocol.schema.json 对齐并强类型包装;win.CallAsync(method, args) 可兜底调用宿主新方法。
  • win.WebContents() 提供 webContents.*;命令外发送必须带 parent(否则 PARENT_INVOCATION_REQUIRED)。
  • win.On(event, handler) 订阅 closed / focus / blur / resize / ...;win.ExposeAsync(method, handler) 处理子窗 request。

快速搜索

Provider:manifest 中 commands[].provider: 'search' 标记的命令是快速搜索协议端点(只能被宿主搜索调用,不暴露普通入口),用 OnSearch 注册:

runtime.OnSearch("find-files", ctx =>
{
    IReadOnlyList<SearchResultItem> results =
    [
        new SearchResultItem
        {
            Id = "a.txt",
            Title = "a.txt",
            Activate = new SearchRouteRef
            {
                Command = "open-file",
                Input = new Dictionary<string, object?> { ["path"] = "a.txt" },
            },
        },
    ];
    return Task.FromResult(results);
});

ctx 是 SearchContext:固定入参 Query(宿主已 trim,空查询不会到达)/ Sequence / Limit / Caller,能力面复用 Platform() / Storage() / Dependencies() / CancellationToken。Activate / Actions[].Command 的路由载荷只存宿主路由表,不下发消费方。

Consumer:manifest 声明 quickSearch.consumer 后经 runtime.Platform.Search.* 调宿主搜索服务:

var resp = await runtime.Platform.Search.QueryAsync(new SearchQueryRequest { Query = "open", Limit = 8 });
var first = resp.Results.FirstOrDefault();
if (first?.Activatable == true)
{
    await runtime.Platform.Search.ActivateAsync(first.Id!);
    await runtime.Platform.Search.RunActionAsync(first.Id!, "reveal");
}

错误

throw new BppException("INVALID_INPUT", "text is required");

常见 code:INVALID_INPUT / PROTOCOL_ERROR / COMMAND_NOT_FOUND / PARENT_INVOCATION_REQUIRED / DEPENDENCY_NOT_DECLARED / CANCELLED / RESOURCE_UPLOAD_CLOSED / RESOURCE_MATERIALIZATION_TOO_LARGE / INTERNAL。错误码字符串与 Node / Go / Python 完全一致;gRPC status details 携带 brickly.runtime.v1.BrickError。


协议与版本

  • 协议:brickly.runtime.v1(Protocol.ProtocolVersion)
  • SDK 版本:0.12.0(Protocol.SdkVersion),与 Node / Go / Python 基线一致
  • 生成绑定:buf.gen.yaml 的 csharp 插件输出到 src/Syllm.Brickly.Sdk/Grpc/Generated,由 npm run check:runtime-proto 做漂移检查(禁止手改)

构建与测试

dotnet build
dotnet test

测试自带 FakeHost(进程内假 Host:Registry / Platform / Resource / Event / Connector / BrickStorage),不依赖真实宿主。

发布

cd Brickly
node scripts/publish-dotnet-sdk.mjs 0.11.0            # 导出独立仓库 + dotnet pack + tag
node scripts/publish-dotnet-sdk.mjs 0.11.0 --dry-run  # 只校验
node scripts/publish-dotnet-sdk.mjs 0.11.0 --push-nuget --api-key <key>  # 可选推 NuGet
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.12.0 88 9/17/2026
0.11.0 90 9/14/2026