// 网页入口:Minimal API + wwwroot 静态文件。浏览器只调 REST,不接触 API Key。 // 学习顺序建议:/api/catalog → 画布 → POST /api/run → 若 needsDecision 再 POST /api/run/{id}/decide。 using MAF1.Decisions; using MAF1.Utils; using MAF1.Web; WindowsConsole.EnableUtf8(); WebApplicationBuilder builder = WebApplication.CreateBuilder(args); builder.WebHost.UseUrls("http://127.0.0.1:5288"); builder.Services.ConfigureHttpJsonOptions(options => { options.SerializerOptions.PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase; }); builder.Services.AddSingleton(); WebApplication app = builder.Build(); app.UseDefaultFiles(); app.UseStaticFiles(); // 左侧节点列表:系统内置 + 扫描到的插件。 app.MapGet("/api/catalog", (AgentRuntime runtime) => { var snapshot = runtime.Catalog.Load(); return new { pluginsRoot = snapshot.PluginsRoot, system = snapshot.System, plugins = snapshot.Plugins, nodes = snapshot.Nodes, issues = snapshot.Issues, }; }); // 给下拉框用的凭据列表(不含原始 Key)。 app.MapGet("/api/credentials", (AgentRuntime runtime) => runtime.Credentials.ListPublic()); app.MapGet("/api/status", (AgentRuntime runtime) => new { weatherProvider = runtime.WeatherProvider, pluginsRoot = runtime.PluginsRoot, }); // 提交画布 JSON。可能一次跑完,也可能返回 status=needsDecision。 app.MapPost("/api/run", (WorkflowGraph graph, AgentRuntime runtime, CancellationToken cancellationToken) => runtime.Runner.RunAsync(graph, cancellationToken)); // 超时后前端轮询最终结果。 app.MapGet("/api/run/{runId}", (string runId, AgentRuntime runtime) => { WorkflowRunResult? result = runtime.Runner.Get(runId); return result is null ? Results.NotFound(new WorkflowRunResult { Ok = false, Status = WorkflowRunStatus.Failed, Error = "找不到这次运行。" }) : Results.Ok(result); }); // 用户点确认:optionId=stop 或 query-cities(可带 text 城市名)。 app.MapPost("/api/run/{runId}/decide", (string runId, DecisionAnswer answer, AgentRuntime runtime, CancellationToken cancellationToken) => runtime.Runner.DecideAsync(runId, answer, cancellationToken)); Console.WriteLine("可视化编排: http://127.0.0.1:5288"); app.Run();