初始提交

This commit is contained in:
2026-08-26 18:06:02 +08:00
commit 5544788917
53 changed files with 4101 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
.env
**/bin/
**/obj/
+20
View File
@@ -0,0 +1,20 @@
# 插件目录
每个子文件夹是一个插件。软件启动后扫描**执行目录**下的 `plugins/`(即 `MAF1.exe` 旁边),不是源码目录。
## 必备文件
- `plugin.json`:id、启动命令、凭据声明、inputs、outputs
- `README.md`:给使用者看的说明
- 可执行文件 / 脚本 / 源码:由 `launch.command` + `launch.args` 原样启动
## 凭据(不要写进 plugin.json
n8n / Dify 一类产品把 API Key 放在宿主凭据库,节点只声明「我需要哪种凭据」。本项目同样:
- Key 和 endpoint 配在宿主的环境变量或 `appsettings.json`
- 节点可选 `credentialId`(默认 `llm-default`
- 启动子进程时注入环境变量,并在 stdin JSON 的 `credentials` 里再传一份
- 浏览器和流程图 JSON **不会**包含 apiKey
第三方若要用自己的模型,可在插件目录放 `.env`(不要提交)。节点选中的宿主凭据会覆盖其中的同名变量。
+23
View File
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\MAF1.Core\MAF1.Core.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="plugin.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="README.md">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
+11
View File
@@ -0,0 +1,11 @@
using MAF1.Agents.FileCity;
using MAF1.PluginContract;
using MAF1.Utils;
PluginRequest request = await PluginStdio.ReadRequestAsync();
PluginStdio.ApplyCredentialsToEnvironment(request.Credentials);
AgentFactory factory = new(AgentFactory.Load(PluginStdio.LoadHostConfiguration()));
var result = await FileCityAgent.RunAsync(FileCityAgent.Create(factory), request.Inputs);
await PluginStdio.WriteOutputsAsync(result.Outputs);
return 0;
+34
View File
@@ -0,0 +1,34 @@
# FileCity 插件
独立进程。宿主只读取本目录的 `plugin.json`,按 `launch` 原样启动,不会替你拼命令。
## 输入 / 输出
字段名必须和 `plugin.json` 以及 `Program.cs` 里读写的 JSON 键一致。
- 输入 `filePath`
- 输出 `hasValidCities``cities``reason``raw`
## 凭据
不要把 API Key 写进 `plugin.json` 或流程图。本插件声明需要 `openai-compatible` 凭据。运行时宿主会:
1. 把选中的凭据写入本进程环境变量 `OPENAI_ENDPOINT` / `OPENAI_API_KEY` / `OPENAI_CHAT_MODEL`
2. 通过 stdin JSON 的 `credentials.llm` 再传一份
可选:在本目录放 `.env` 作为插件自己的默认环境(适合第三方自带模型)。节点上选中的宿主凭据会覆盖 `.env` 里的同名变量。
## 协议
stdin
```json
{
"inputs": { "filePath": "Data/cities.txt" },
"credentials": {
"llm": { "id": "llm-default", "type": "openai-compatible", "endpoint": "...", "apiKey": "...", "model": "..." }
}
}
```
stdout:单个 JSON 对象,字段等于 outputs。日志请写 stderr。
+33
View File
@@ -0,0 +1,33 @@
{
"id": "fileCity",
"name": "FileCityAgent",
"description": "读取指定文本文件,判断并抽出有效城市名。",
"version": "1.0.0",
"timeoutSeconds": 120,
"launch": {
"command": "dotnet",
"args": ["FileCityPlugin.dll"]
},
"credentials": [
{
"name": "llm",
"type": "openai-compatible",
"required": true,
"description": "由宿主注入 OpenAI 兼容的 endpoint / apiKey / model,不要写进本文件。"
}
],
"inputs": [
{
"name": "filePath",
"type": "string",
"required": true,
"description": "本地文件路径,例如 Data/cities.txt"
}
],
"outputs": [
{ "name": "hasValidCities", "type": "bool", "description": "是否存在有效城市" },
{ "name": "cities", "type": "string[]", "description": "有效城市名列表" },
{ "name": "reason", "type": "string", "description": "判断说明" },
{ "name": "raw", "type": "string", "description": "Agent 原始文本" }
]
}
+18
View File
@@ -0,0 +1,18 @@
using MAF1.Agents.Weather;
using MAF1.PluginContract;
using MAF1.Tools;
using MAF1.Utils;
using Microsoft.Extensions.Configuration;
PluginRequest request = await PluginStdio.ReadRequestAsync();
PluginStdio.ApplyCredentialsToEnvironment(request.Credentials);
IConfiguration config = PluginStdio.LoadHostConfiguration();
AgentFactory factory = new(AgentFactory.Load(config));
WeatherOptions weatherOptions = config.GetSection("Weather").Get<WeatherOptions>() ?? new WeatherOptions();
using HttpClient http = WeatherTools.CreateHttpClient();
var result = await WeatherAgent.RunAsync(
WeatherAgent.Create(factory, new WeatherTools(weatherOptions, http)),
request.Inputs);
await PluginStdio.WriteOutputsAsync(result.Outputs);
return 0;
+12
View File
@@ -0,0 +1,12 @@
# Weather 插件
独立进程。启动命令只看 `plugin.json``launch`
## 输入 / 输出
- 输入 `cities`(字符串数组,与代码、清单同名)
- 输出 `summary`
## 凭据
LLM 的 endpoint / apiKey 由宿主注入,不出现在流程图端口上。天气 HTTP 配置走宿主 `appsettings.json`(通过环境变量 `MAF1_CONTENT_ROOT` 定位)。
+23
View File
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\MAF1.Core\MAF1.Core.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="plugin.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="README.md">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
+30
View File
@@ -0,0 +1,30 @@
{
"id": "weather",
"name": "WeatherAgent",
"description": "按城市列表查询天气并汇总。",
"version": "1.0.0",
"timeoutSeconds": 180,
"launch": {
"command": "dotnet",
"args": ["WeatherPlugin.dll"]
},
"credentials": [
{
"name": "llm",
"type": "openai-compatible",
"required": true,
"description": "由宿主注入 OpenAI 兼容的 endpoint / apiKey / model,不要写进本文件。"
}
],
"inputs": [
{
"name": "cities",
"type": "string[]",
"required": true,
"description": "要查询的城市名列表"
}
],
"outputs": [
{ "name": "summary", "type": "string", "description": "天气汇总文本" }
]
}