docs: 为 CLI、网页编排器和插件协议补充学习向注释

在核心类型、图执行器、stdio 插件和前端入口写清职责与对照路径,不改运行行为。
This commit is contained in:
2026-08-28 11:51:48 +08:00
parent a3cca78592
commit 950d09ddb0
38 changed files with 206 additions and 3 deletions
+6
View File
@@ -4,6 +4,7 @@ using Microsoft.Extensions.Configuration;
namespace MAF1.Plugins;
/// <summary>内存中的完整凭据。只给插件进程用,不要序列化给浏览器。</summary>
public sealed class CredentialRecord
{
public string Id { get; init; } = "";
@@ -15,6 +16,7 @@ public sealed class CredentialRecord
public Dictionary<string, string> Extra { get; init; } = new(StringComparer.OrdinalIgnoreCase);
}
/// <summary>GET /api/credentials 的形状:有没有 Key 用布尔值表示,不返回 Key 本身。</summary>
public sealed class CredentialPublicView
{
public string Id { get; init; } = "";
@@ -25,6 +27,9 @@ public sealed class CredentialPublicView
public bool HasApiKey { get; init; }
}
/// <summary>
/// 从 Llm 段和 Credentials 段组装凭据。节点 config.credentialId 默认 llm-default。
/// </summary>
public sealed class CredentialStore
{
private readonly IConfiguration _config;
@@ -64,6 +69,7 @@ public sealed class CredentialStore
}
}
/// <summary>给前端的列表。Endpoint 目前未打码(学习项目);ApiKey 绝不会出现在这里。</summary>
public IReadOnlyList<CredentialPublicView> ListPublic()
=> _named.Values
.OrderBy(item => item.Id, StringComparer.OrdinalIgnoreCase)
@@ -3,6 +3,7 @@ using MAF1.Web;
namespace MAF1.Plugins;
/// <summary>一次目录快照:系统节点 + 插件节点合并后的 Nodes 列表给画布用。</summary>
public sealed class NodeCatalogSnapshot
{
public string PluginsRoot { get; init; } = "";
@@ -13,6 +14,7 @@ public sealed class NodeCatalogSnapshot
public IReadOnlyList<LoadedPlugin> LoadedPlugins { get; init; } = [];
}
/// <summary>把扫描结果和 AgentCatalog 拼在一起。同名时插件覆盖系统实现。</summary>
public sealed class NodeCatalogService(PluginScanner scanner)
{
public NodeCatalogSnapshot Load()
+3
View File
@@ -2,6 +2,7 @@ using Microsoft.Extensions.Configuration;
namespace MAF1.Plugins;
/// <summary>Plugins:Directory 相对网页 exe,不是源码树里的 plugins/ 文件夹。</summary>
public sealed class PluginOptions
{
public string Directory { get; set; } = "plugins";
@@ -21,6 +22,7 @@ public sealed class PluginOptions
=> config.GetSection("Plugins").Get<PluginOptions>() ?? new PluginOptions();
}
/// <summary>扫描成功后的一个插件:目录 + 已解析的 plugin.json。</summary>
public sealed class LoadedPlugin
{
public required string FolderName { get; init; }
@@ -28,6 +30,7 @@ public sealed class LoadedPlugin
public required PluginContract.PluginManifest Manifest { get; init; }
}
/// <summary>扫描问题,前端左侧「扫描说明」会显示。error 的插件不会进画布。</summary>
public sealed class CatalogIssue
{
public string Level { get; init; } = "error";
@@ -6,6 +6,10 @@ using MAF1.Utils;
namespace MAF1.Plugins;
/// <summary>
/// 启动子进程跑插件:stdin 写 PluginRequeststdout 读输出 JSON,超时 Kill。
/// 这是「进程外 Agent」的完整示例,对照 FileCityPlugin/Program.cs 一起看。
/// </summary>
public sealed class PluginProcessRunner(PluginOptions options, CredentialStore credentials)
{
public async Task<Dictionary<string, object?>> RunAsync(
@@ -97,6 +101,7 @@ public sealed class PluginProcessRunner(PluginOptions options, CredentialStore c
return map;
}
/// <summary>工作目录=插件文件夹;环境变量带上 OPENAI_* 和 MAF1_CONTENT_ROOT。</summary>
private ProcessStartInfo CreateStartInfo(LoadedPlugin plugin, Dictionary<string, PluginCredentialPayload> payload)
{
string command = plugin.Manifest.Launch.Command;
+3
View File
@@ -3,6 +3,9 @@ using MAF1.PluginContract;
namespace MAF1.Plugins;
/// <summary>
/// 扫描 exe 旁边的 plugins/*/plugin.json。源码目录 Plugins/ 不会被运行时直接读到,要先 build 复制到输出目录。
/// </summary>
public sealed class PluginScanner(PluginOptions options)
{
public PluginScanResult Scan()