{"slug": "cadenza-microsoft-agent-framework-microsoft-foundry", "title": "Cadenza + Microsoft Agent Framework + Microsoft Foundry", "summary": "A developer demonstrated how to quickly start coding with Cadenza by using a vibe coding prompt, then run the resulting .NET 10 file-based app with dotnet run or chmod +x. The example included creating a ping tool for Naver, an OpenAPI calculator with a frontend, and an AI agent console using Microsoft Agent Framework and Foundry.", "body_md": "다음과 같이 바이브코딩 프롬프트를 입력하면 쉽게 Cadenza 기반 코드를 빠르게 시작할 수 있습니다. 그 후, dotnet run 명령어나 chmod +x file.cs 명령어로 실행 권한을 부여한 다음 실행하면 손쉽게 실행할 수 있습니다.\n\n```\n먼저 https://raw.githubusercontent.com/rkttu/cadenza/main/README.ko.md 를 읽고, 거기 적힌 Cadenza 규칙(단일 .cs, shebang + #:sdk 지시문, 정확한 버전 핀, Console 대신 ambient helper)을 그대로 지켜 .NET 10 파일 기반 앱으로 다음을 구현하고 dotnet run으로 실행해줘:\n먼저 https://raw.githubusercontent.com/rkttu/cadenza/main/README.ko.md 를 읽고, 거기 적힌 Cadenza 규칙(단일 .cs, shebang + #:sdk 지시문, 정확한 버전 핀, Console 대신 ambient helper)을 그대로 지켜 .NET 10 파일 기반 앱으로 다음을 구현하고 dotnet run으로 실행해줘:\n\nhttps://www.naver.com 사이트를 1초 간격으로 5회 https로 ping 하는 코드를 만들어줘.\n먼저 https://raw.githubusercontent.com/rkttu/cadenza/main/README.ko.md 를 읽고, 거기 적힌 Cadenza 규칙(단일 .cs, shebang + #:sdk 지시문, 정확한 버전 핀, Console 대신 ambient helper)을 그대로 지켜 .NET 10 파일 기반 앱으로 다음을 구현하고 dotnet run으로 실행해줘:\n\n간단한 사칙 연산 계산기를 OpenAPI 형식으로 기능을 구현하고 프론트엔드 HTML 페이지를 담는 웹 사이트를 만들었으면 해.\n먼저 https://raw.githubusercontent.com/rkttu/cadenza/main/README.ko.md 를 읽고, 거기 적힌 Cadenza 규칙(단일 .cs, shebang + #:sdk 지시문, 정확한 버전 핀, Console 대신 ambient helper)을 그대로 지켜 .NET 10 파일 기반 앱으로 다음을 구현하고 dotnet run으로 실행해줘:\n\n콘솔 형태로 사용할 수 있는 AI 에이전트를 만들려고 해. OPENAPI_ENDPOINT, OPENAPI_MODEL, OPENAPI_KEY 라는 환경 변수를 미리 설정해두었고, 임의의 난수를 생성해서 반환하는 도구를 하나 내장한 에이전트를 만들려고 해.\n```\n\n| #!/usr/bin/env dotnet run | |\n| #:sdk Cadenza@1.0.15 | |\n| #:package Azure.AI.Projects@2.0.1 | |\n| #:package Microsoft.Agents.AI@1.10.0 | |\n| #:package Microsoft.Agents.AI.Foundry@1.5.0 | |\n| #:package Azure.Identity@1.21.0 | |\n| using Azure.AI.Projects; | |\n| using Azure.Identity; | |\n| using Microsoft.Extensions.AI; | |\n| // Last successful run context: | |\n| // - FOUNDRY_PROJECT_ENDPOINT | |\n| // - FOUNDRY_MODEL_DEPLOYMENT | |\n| // - AZURE_TENANT_ID | |\n| // - PATH included Azure CLI dir: C:\\Program Files\\Microsoft SDKs\\Azure\\CLI2\\wbin | |\n| // Installed software used: | |\n| // - Microsoft Azure CLI (az.cmd) at C:\\Program Files\\Microsoft SDKs\\Azure\\CLI2\\wbin\\az.cmd | |\n| var endpoint = Env.Get(\"FOUNDRY_PROJECT_ENDPOINT\") | |\n| ?? throw new InvalidOperationException(\"FOUNDRY_PROJECT_ENDPOINT environment variable is required.\"); | |\n| var modelDeployment = Env.Get(\"FOUNDRY_MODEL_DEPLOYMENT\") | |\n| ?? throw new InvalidOperationException(\"FOUNDRY_MODEL_DEPLOYMENT environment variable is required.\"); | |\n| var projectClient = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential()); | |\n| var tools = new List<AITool> | |\n| { | |\n| (AITool)AIFunctionFactory.Create( | |\n| (Func<string>)(() => DateTimeOffset.Now.ToString(\"O\")), | |\n| name: \"get_current_time\", | |\n| description: \"Returns the current local time in ISO-8601 format.\", | |\n| serializerOptions: null) | |\n| }; | |\n| var agent = projectClient.AsAIAgent( | |\n| model: modelDeployment, | |\n| instructions: \"You are a concise assistant. If the user asks for the current time, call get_current_time.\", | |\n| name: \"cadenza-file-agent-console\", | |\n| description: \"Single-file agent with a sample time tool and console chat.\", | |\n| tools: tools); | |\n| // Keep local transcript so each turn includes prior context. | |\n| var history = new List<ChatMessage>(); | |\n| WriteLine(\"Console chat started. Type '/exit' to quit.\"); | |\n| while (true) | |\n| { | |\n| Write(\"you> \"); | |\n| var userInput = Console.ReadLine(); | |\n| if (string.IsNullOrWhiteSpace(userInput)) | |\n| { | |\n| continue; | |\n| } | |\n| if (string.Equals(userInput.Trim(), \"/exit\", StringComparison.OrdinalIgnoreCase)) | |\n| { | |\n| WriteLine(\"bye.\"); | |\n| break; | |\n| } | |\n| history.Add(new ChatMessage(ChatRole.User, userInput)); | |\n| var runResult = await agent.RunAsync(history, session: null, options: null, cancellationToken: default); | |\n| // AgentResponse concrete shape may evolve; reflect common output fields safely. | |\n| var resultType = runResult.GetType(); | |\n| var text = resultType.GetProperty(\"Text\")?.GetValue(runResult)?.ToString(); | |\n| var answer = text ?? runResult.ToString() ?? string.Empty; | |\n| WriteLine($\"agent> {answer}\"); | |\n| history.Add(new ChatMessage(ChatRole.Assistant, answer)); | |\n| } |\n\n| #!/usr/bin/env dotnet run | |\n| #:sdk Cadenza@1.0.15 | |\n| #:package Azure.AI.Projects@2.0.1 | |\n| #:package Microsoft.Agents.AI@1.10.0 | |\n| #:package Microsoft.Agents.AI.Foundry@1.5.0 | |\n| #:package Azure.Identity@1.21.0 | |\n| // Last successful run context: | |\n| // - FOUNDRY_PROJECT_ENDPOINT | |\n| // - FOUNDRY_MODEL_DEPLOYMENT | |\n| // - AZURE_TENANT_ID | |\n| // - PATH included Azure CLI dir: C:\\Program Files\\Microsoft SDKs\\Azure\\CLI2\\wbin | |\n| // Installed software used: | |\n| // - Microsoft Azure CLI (az.cmd) at C:\\Program Files\\Microsoft SDKs\\Azure\\CLI2\\wbin\\az.cmd | |\n| using Azure.AI.Projects; | |\n| using Azure.Identity; | |\n| var endpoint = Env.Get(\"FOUNDRY_PROJECT_ENDPOINT\") | |\n| ?? throw new InvalidOperationException(\"FOUNDRY_PROJECT_ENDPOINT environment variable is required.\"); | |\n| var modelDeployment = Env.Get(\"FOUNDRY_MODEL_DEPLOYMENT\") | |\n| ?? throw new InvalidOperationException(\"FOUNDRY_MODEL_DEPLOYMENT environment variable is required.\"); | |\n| var projectClient = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential()); | |\n| var agent = projectClient.AsAIAgent( | |\n| model: modelDeployment, | |\n| instructions: \"You are a concise assistant. Respond in one sentence.\", | |\n| name: \"cadenza-file-agent\", | |\n| description: \"Single-file agent built with Cadenza + Microsoft Agent Framework + Foundry.\"); | |\n| var prompt = \"Say exactly 'Cadenza Foundry Agent is running.'\"; | |\n| var runResult = await agent.RunAsync(prompt, session: null, options: null, cancellationToken: default); | |\n| // AgentResponse concrete shape may evolve; reflect common output fields safely. | |\n| var resultType = runResult.GetType(); | |\n| var text = resultType.GetProperty(\"Text\")?.GetValue(runResult)?.ToString(); | |\n| WriteLine($\"Prompt: {prompt}\"); | |\n| WriteLine($\"Response: {text ?? runResult.ToString()}\"); |\n\n| #!/usr/bin/env dotnet run | |\n| #:sdk Cadenza.Agent@1.0.15 | |\n| using System.ClientModel; | |\n| using OpenAI; | |\n| var endpoint = Env.Get(\"OPENAPI_ENDPOINT\") | |\n| ?? throw new InvalidOperationException(\"OPENAPI_ENDPOINT environment variable is required.\"); | |\n| var model = Env.Get(\"OPENAPI_MODEL\") | |\n| ?? throw new InvalidOperationException(\"OPENAPI_MODEL environment variable is required.\"); | |\n| var apiKey = Env.Get(\"OPENAPI_KEY\") | |\n| ?? throw new InvalidOperationException(\"OPENAPI_KEY environment variable is required.\"); | |\n| SystemPrompt(\"\"\" | |\n| You are a helpful console AI assistant. | |\n| When users ask for randomness, prefer calling the `random_int` tool. | |\n| Explain the generated random number briefly and clearly. | |\n| \"\"\"); | |\n| Tool(\"random_int\", \"Generate a random integer between min and max (inclusive).\", | |\n| (int min, int max) => | |\n| { | |\n| if (min > max) | |\n| return new { min, max, value = (int?)null, error = \"min must be less than or equal to max.\" }; | |\n| var value = Random.Shared.Next(min, max + 1); | |\n| return new { min, max, value = (int?)value, error = (string?)null }; | |\n| }); | |\n| var options = new OpenAIClientOptions | |\n| { | |\n| Endpoint = new Uri(endpoint) | |\n| }; | |\n| var chatClient = new OpenAI.Chat.ChatClient(model, new ApiKeyCredential(apiKey), options) | |\n| .AsIChatClient(); | |\n| UseChatClient(chatClient); | |\n| WriteLine(\"Console AI agent is ready.\"); | |\n| WriteLine(\"- Backend endpoint: \" + endpoint); | |\n| WriteLine(\"- Model: \" + model); | |\n| WriteLine(\"- Tool: random_int(min, max)\"); | |\n| WriteLine(); | |\n| WriteLine(\"Usage:\"); | |\n| WriteLine(\"- dotnet run .\\\\agent_console_random.cs\"); | |\n| WriteLine(\" (interactive REPL)\"); | |\n| WriteLine(\"- dotnet run .\\\\agent_console_random.cs \\\"Generate a random number between 1 and 100\\\"\"); | |\n| WriteLine(\" (one-shot response)\"); | |\n| WriteLine(); | |\n| if (args.Length > 0) | |\n| { | |\n| var prompt = string.Join(\" \", args); | |\n| var reply = await Reply(prompt); | |\n| WriteLine(reply); | |\n| return; | |\n| } | |\n| await ChatLoop(); |\n\n| #!/usr/bin/env dotnet run | |\n| #:sdk Cadenza.Web@1.0.15 | |\n| using System.Globalization; | |\n| using Microsoft.AspNetCore.Http; | |\n| const string HtmlPage = \"\"\" | |\n| <!doctype html> | |\n| <html lang=\"en\"> | |\n| <head> | |\n| <meta charset=\"utf-8\" /> | |\n| <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" /> | |\n| <title>Cadenza Calculator</title> | |\n| <style> | |\n| :root { | |\n| --bg: #f4f7ff; | |\n| --panel: #ffffff; | |\n| --ink: #1d2433; | |\n| --muted: #5f697d; | |\n| --accent: #0b7a57; | |\n| --line: #d4ddef; | |\n| } | |\n| * { box-sizing: border-box; } | |\n| body { | |\n| margin: 0; | |\n| min-height: 100vh; | |\n| display: grid; | |\n| place-items: center; | |\n| padding: 20px; | |\n| color: var(--ink); | |\n| font-family: \"Segoe UI\", Tahoma, sans-serif; | |\n| background: | |\n| radial-gradient(circle at 10% 10%, #e9f0ff 0%, transparent 40%), | |\n| radial-gradient(circle at 90% 90%, #def6ea 0%, transparent 35%), | |\n| var(--bg); | |\n| } | |\n| main { | |\n| width: min(760px, 100%); | |\n| background: var(--panel); | |\n| border: 1px solid var(--line); | |\n| border-radius: 14px; | |\n| box-shadow: 0 14px 30px rgba(16, 34, 74, 0.12); | |\n| overflow: hidden; | |\n| } | |\n| header { | |\n| padding: 18px 20px; | |\n| border-bottom: 1px solid var(--line); | |\n| background: linear-gradient(135deg, #f8fbff, #eefaf4); | |\n| } | |\n| h1 { margin: 0; font-size: 1.35rem; } | |\n| p { margin: 8px 0 0; color: var(--muted); } | |\n| .content { padding: 20px; display: grid; gap: 12px; } | |\n| .row { display: grid; gap: 10px; grid-template-columns: 1fr 130px 1fr auto; } | |\n| input, select, button { font: inherit; } | |\n| input, select { | |\n| width: 100%; | |\n| border: 1px solid var(--line); | |\n| border-radius: 10px; | |\n| padding: 10px 12px; | |\n| background: #fff; | |\n| } | |\n| button { | |\n| border: 0; | |\n| border-radius: 10px; | |\n| padding: 10px 14px; | |\n| background: var(--accent); | |\n| color: #fff; | |\n| font-weight: 600; | |\n| cursor: pointer; | |\n| } | |\n| pre { | |\n| margin: 0; | |\n| min-height: 130px; | |\n| border: 1px solid var(--line); | |\n| border-radius: 10px; | |\n| padding: 12px; | |\n| background: #fff; | |\n| overflow: auto; | |\n| } | |\n| .links { display: flex; gap: 12px; flex-wrap: wrap; } | |\n| .links a { color: var(--accent); text-underline-offset: 3px; } | |\n| @media (max-width: 640px) { .row { grid-template-columns: 1fr; } } | |\n| </style> | |\n| </head> | |\n| <body> | |\n| <main> | |\n| <header> | |\n| <h1>Arithmetic Calculator</h1> | |\n| <p>Cadenza.Web single-file app with OpenAPI JSON endpoint.</p> | |\n| </header> | |\n| <section class=\"content\"> | |\n| <div class=\"row\"> | |\n| <input id=\"a\" type=\"number\" step=\"any\" value=\"12\" aria-label=\"a\" /> | |\n| <select id=\"op\" aria-label=\"op\"> | |\n| <option value=\"add\">add (+)</option> | |\n| <option value=\"sub\">sub (-)</option> | |\n| <option value=\"mul\">mul (*)</option> | |\n| <option value=\"div\">div (/)</option> | |\n| </select> | |\n| <input id=\"b\" type=\"number\" step=\"any\" value=\"3\" aria-label=\"b\" /> | |\n| <button id=\"run\" type=\"button\">Calculate</button> | |\n| </div> | |\n| <pre id=\"result\">No calculation yet.</pre> | |\n| <div class=\"links\"> | |\n| <a href=\"/openapi/v1.json\" target=\"_blank\" rel=\"noreferrer\">OpenAPI JSON</a> | |\n| <a href=\"/api/calc?a=12&b=3&op=div\" target=\"_blank\" rel=\"noreferrer\">Sample API call</a> | |\n| </div> | |\n| </section> | |\n| </main> | |\n| <script> | |\n| const resultEl = document.getElementById('result'); | |\n| const runBtn = document.getElementById('run'); | |\n| runBtn.addEventListener('click', async () => { | |\n| const a = document.getElementById('a').value; | |\n| const b = document.getElementById('b').value; | |\n| const op = document.getElementById('op').value; | |\n| const url = `/api/calc?a=${encodeURIComponent(a)}&b=${encodeURIComponent(b)}&op=${encodeURIComponent(op)}`; | |\n| resultEl.textContent = 'Calculating...'; | |\n| try { | |\n| const response = await fetch(url); | |\n| const data = await response.json(); | |\n| resultEl.textContent = JSON.stringify(data, null, 2); | |\n| } catch (err) { | |\n| resultEl.textContent = String(err); | |\n| } | |\n| }); | |\n| </script> | |\n| </body> | |\n| </html> | |\n| \"\"\"; | |\n| const string OpenApiJson = \"\"\" | |\n| { | |\n| \"openapi\": \"3.0.3\", | |\n| \"info\": { | |\n| \"title\": \"Cadenza Arithmetic Calculator API\", | |\n| \"version\": \"1.0.0\", | |\n| \"description\": \"Simple arithmetic operations: add, sub, mul, div\" | |\n| }, | |\n| \"servers\": [ | |\n| { \"url\": \"http://localhost:8080\" } | |\n| ], | |\n| \"paths\": { | |\n| \"/api/calc\": { | |\n| \"get\": { | |\n| \"summary\": \"Calculate with query parameters\", | |\n| \"parameters\": [ | |\n| { \"name\": \"a\", \"in\": \"query\", \"required\": true, \"schema\": { \"type\": \"number\", \"format\": \"double\" } }, | |\n| { \"name\": \"b\", \"in\": \"query\", \"required\": true, \"schema\": { \"type\": \"number\", \"format\": \"double\" } }, | |\n| { \"name\": \"op\", \"in\": \"query\", \"required\": true, \"schema\": { \"type\": \"string\", \"enum\": [\"add\", \"sub\", \"mul\", \"div\"] } } | |\n| ], | |\n| \"responses\": { | |\n| \"200\": { \"description\": \"Calculation succeeded\" }, | |\n| \"400\": { \"description\": \"Invalid input\" } | |\n| } | |\n| } | |\n| } | |\n| } | |\n| } | |\n| \"\"\"; | |\n| Get(\"/\", () => Results.Content(HtmlPage, \"text/html; charset=utf-8\")); | |\n| Get(\"/api/calc\", (string a, string b, string op) => | |\n| { | |\n| if (!double.TryParse(a, NumberStyles.Float, CultureInfo.InvariantCulture, out var left)) | |\n| return Results.BadRequest(new { error = \"Parameter 'a' must be a valid number.\" }); | |\n| if (!double.TryParse(b, NumberStyles.Float, CultureInfo.InvariantCulture, out var right)) | |\n| return Results.BadRequest(new { error = \"Parameter 'b' must be a valid number.\" }); | |\n| var normalized = NormalizeOp(op); | |\n| if (!TryCalculate(left, right, normalized, out var result, out var error)) | |\n| return Results.BadRequest(new { error }); | |\n| return Results.Ok(new | |\n| { | |\n| a = left, | |\n| b = right, | |\n| op = normalized, | |\n| expression = $\"{left} {OpSymbol(normalized)} {right}\", | |\n| result | |\n| }); | |\n| }); | |\n| Get(\"/openapi/v1.json\", () => Results.Content(OpenApiJson, \"application/json; charset=utf-8\")); | |\n| await Run(); | |\n| static bool TryCalculate(double a, double b, string op, out double value, out string error) | |\n| { | |\n| value = 0; | |\n| error = string.Empty; | |\n| switch (op) | |\n| { | |\n| case \"add\": | |\n| value = a + b; | |\n| return true; | |\n| case \"sub\": | |\n| value = a - b; | |\n| return true; | |\n| case \"mul\": | |\n| value = a * b; | |\n| return true; | |\n| case \"div\": | |\n| if (b == 0) | |\n| { | |\n| error = \"Division by zero is not allowed.\"; | |\n| return false; | |\n| } | |\n| value = a / b; | |\n| return true; | |\n| default: | |\n| error = \"Parameter 'op' must be one of: add, sub, mul, div.\"; | |\n| return false; | |\n| } | |\n| } | |\n| static string NormalizeOp(string? op) => | |\n| (op ?? string.Empty).Trim().ToLowerInvariant() switch | |\n| { | |\n| \"+\" => \"add\", | |\n| \"-\" => \"sub\", | |\n| \"*\" => \"mul\", | |\n| \"/\" => \"div\", | |\n| var x => x, | |\n| }; | |\n| static string OpSymbol(string op) => op switch | |\n| { | |\n| \"add\" => \"+\", | |\n| \"sub\" => \"-\", | |\n| \"mul\" => \"*\", | |\n| \"div\" => \"/\", | |\n| _ => \"?\" | |\n| }; |\n\n| { | |\n| \"servers\": { | |\n| \"brave-search\": { | |\n| \"command\": \"npx\", | |\n| \"args\": [ | |\n| \"-y\", | |\n| \"@brave/brave-search-mcp-server\", | |\n| \"--transport\", | |\n| \"stdio\" | |\n| ], | |\n| \"env\": { | |\n| \"BRAVE_API_KEY\": \"${input:brave_api_key}\" | |\n| }, | |\n| \"type\": \"stdio\" | |\n| }, | |\n| \"handmirrormcp\": { | |\n| \"type\": \"stdio\", | |\n| \"command\": \"dnx\", | |\n| \"args\": [\"HandMirrorMcp@0.1.1\", \"--yes\"] | |\n| }, | |\n| \"microsoft-learn\": { | |\n| \"type\": \"http\", | |\n| \"url\": \"https://learn.microsoft.com/api/mcp\" | |\n| } | |\n| }, | |\n| \"inputs\": [ | |\n| { | |\n| \"id\": \"brave_api_key\", | |\n| \"type\": \"promptString\", | |\n| \"description\": \"Brave Search API Key\" | |\n| } | |\n| ] | |\n| } |\n\n다음과 같이 바이브코딩 프롬프트를 입력하면 쉽게 Cadenza 기반 코드를 빠르게 시작할 수 있습니다. 그 후, dotnet run 명령어나 chmod +x file.cs 명령어로 실행 권한을 부여한 다음 실행하면 손쉽게 실행할 수 있습니다.\n\n␃WPNCODE0␃\n\n␃WPNCODE1␃\n\n␃WPNCODE2␃\n\n␃WPNCODE3␃", "url": "https://wpnews.pro/news/cadenza-microsoft-agent-framework-microsoft-foundry", "canonical_source": "https://gist.github.com/rkttu/38c23d0f9faa7f5e38e6cb8d4ae61356", "published_at": "2026-06-18 14:50:47+00:00", "updated_at": "2026-06-20 06:06:24.382752+00:00", "lang": "en", "topics": ["developer-tools", "artificial-intelligence", "ai-agents", "large-language-models", "ai-infrastructure"], "entities": ["Cadenza", "Microsoft Agent Framework", "Microsoft Foundry", "Azure.AI.Projects", "Microsoft.Agents.AI", "Microsoft.Agents.AI.Foundry", "Azure.Identity", "Naver"], "alternates": {"html": "https://wpnews.pro/news/cadenza-microsoft-agent-framework-microsoft-foundry", "markdown": "https://wpnews.pro/news/cadenza-microsoft-agent-framework-microsoft-foundry.md", "text": "https://wpnews.pro/news/cadenza-microsoft-agent-framework-microsoft-foundry.txt", "jsonld": "https://wpnews.pro/news/cadenza-microsoft-agent-framework-microsoft-foundry.jsonld"}}