Skip to content

Instantly share code, notes, and snippets.

@rkttu
Last active June 20, 2026 05:51
Show Gist options
  • Select an option

  • Save rkttu/38c23d0f9faa7f5e38e6cb8d4ae61356 to your computer and use it in GitHub Desktop.

Select an option

Save rkttu/38c23d0f9faa7f5e38e6cb8d4ae61356 to your computer and use it in GitHub Desktop.
Cadenza + Microsoft Agent Framework + Microsoft Foundry
#!/usr/bin/env dotnet run
#:sdk Cadenza@1.0.15
#:package Azure.AI.Projects@2.0.1
#:package Microsoft.Agents.AI@1.10.0
#:package Microsoft.Agents.AI.Foundry@1.5.0
#:package Azure.Identity@1.21.0
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Extensions.AI;
// Last successful run context:
// - FOUNDRY_PROJECT_ENDPOINT
// - FOUNDRY_MODEL_DEPLOYMENT
// - AZURE_TENANT_ID
// - PATH included Azure CLI dir: C:\Program Files\Microsoft SDKs\Azure\CLI2\wbin
// Installed software used:
// - Microsoft Azure CLI (az.cmd) at C:\Program Files\Microsoft SDKs\Azure\CLI2\wbin\az.cmd
var endpoint = Env.Get("FOUNDRY_PROJECT_ENDPOINT")
?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT environment variable is required.");
var modelDeployment = Env.Get("FOUNDRY_MODEL_DEPLOYMENT")
?? throw new InvalidOperationException("FOUNDRY_MODEL_DEPLOYMENT environment variable is required.");
var projectClient = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential());
var tools = new List<AITool>
{
(AITool)AIFunctionFactory.Create(
(Func<string>)(() => DateTimeOffset.Now.ToString("O")),
name: "get_current_time",
description: "Returns the current local time in ISO-8601 format.",
serializerOptions: null)
};
var agent = projectClient.AsAIAgent(
model: modelDeployment,
instructions: "You are a concise assistant. If the user asks for the current time, call get_current_time.",
name: "cadenza-file-agent-console",
description: "Single-file agent with a sample time tool and console chat.",
tools: tools);
// Keep local transcript so each turn includes prior context.
var history = new List<ChatMessage>();
WriteLine("Console chat started. Type '/exit' to quit.");
while (true)
{
Write("you> ");
var userInput = Console.ReadLine();
if (string.IsNullOrWhiteSpace(userInput))
{
continue;
}
if (string.Equals(userInput.Trim(), "/exit", StringComparison.OrdinalIgnoreCase))
{
WriteLine("bye.");
break;
}
history.Add(new ChatMessage(ChatRole.User, userInput));
var runResult = await agent.RunAsync(history, session: null, options: null, cancellationToken: default);
// AgentResponse concrete shape may evolve; reflect common output fields safely.
var resultType = runResult.GetType();
var text = resultType.GetProperty("Text")?.GetValue(runResult)?.ToString();
var answer = text ?? runResult.ToString() ?? string.Empty;
WriteLine($"agent> {answer}");
history.Add(new ChatMessage(ChatRole.Assistant, answer));
}
#!/usr/bin/env dotnet run
#:sdk Cadenza@1.0.15
#:package Azure.AI.Projects@2.0.1
#:package Microsoft.Agents.AI@1.10.0
#:package Microsoft.Agents.AI.Foundry@1.5.0
#:package Azure.Identity@1.21.0
// Last successful run context:
// - FOUNDRY_PROJECT_ENDPOINT
// - FOUNDRY_MODEL_DEPLOYMENT
// - AZURE_TENANT_ID
// - PATH included Azure CLI dir: C:\Program Files\Microsoft SDKs\Azure\CLI2\wbin
// Installed software used:
// - Microsoft Azure CLI (az.cmd) at C:\Program Files\Microsoft SDKs\Azure\CLI2\wbin\az.cmd
using Azure.AI.Projects;
using Azure.Identity;
var endpoint = Env.Get("FOUNDRY_PROJECT_ENDPOINT")
?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT environment variable is required.");
var modelDeployment = Env.Get("FOUNDRY_MODEL_DEPLOYMENT")
?? throw new InvalidOperationException("FOUNDRY_MODEL_DEPLOYMENT environment variable is required.");
var projectClient = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential());
var agent = projectClient.AsAIAgent(
model: modelDeployment,
instructions: "You are a concise assistant. Respond in one sentence.",
name: "cadenza-file-agent",
description: "Single-file agent built with Cadenza + Microsoft Agent Framework + Foundry.");
var prompt = "Say exactly 'Cadenza Foundry Agent is running.'";
var runResult = await agent.RunAsync(prompt, session: null, options: null, cancellationToken: default);
// AgentResponse concrete shape may evolve; reflect common output fields safely.
var resultType = runResult.GetType();
var text = resultType.GetProperty("Text")?.GetValue(runResult)?.ToString();
WriteLine($"Prompt: {prompt}");
WriteLine($"Response: {text ?? runResult.ToString()}");
#!/usr/bin/env dotnet run
#:sdk Cadenza.Agent@1.0.15
using System.ClientModel;
using OpenAI;
var endpoint = Env.Get("OPENAPI_ENDPOINT")
?? throw new InvalidOperationException("OPENAPI_ENDPOINT environment variable is required.");
var model = Env.Get("OPENAPI_MODEL")
?? throw new InvalidOperationException("OPENAPI_MODEL environment variable is required.");
var apiKey = Env.Get("OPENAPI_KEY")
?? throw new InvalidOperationException("OPENAPI_KEY environment variable is required.");
SystemPrompt("""
You are a helpful console AI assistant.
When users ask for randomness, prefer calling the `random_int` tool.
Explain the generated random number briefly and clearly.
""");
Tool("random_int", "Generate a random integer between min and max (inclusive).",
(int min, int max) =>
{
if (min > max)
return new { min, max, value = (int?)null, error = "min must be less than or equal to max." };
var value = Random.Shared.Next(min, max + 1);
return new { min, max, value = (int?)value, error = (string?)null };
});
var options = new OpenAIClientOptions
{
Endpoint = new Uri(endpoint)
};
var chatClient = new OpenAI.Chat.ChatClient(model, new ApiKeyCredential(apiKey), options)
.AsIChatClient();
UseChatClient(chatClient);
WriteLine("Console AI agent is ready.");
WriteLine("- Backend endpoint: " + endpoint);
WriteLine("- Model: " + model);
WriteLine("- Tool: random_int(min, max)");
WriteLine();
WriteLine("Usage:");
WriteLine("- dotnet run .\\agent_console_random.cs");
WriteLine(" (interactive REPL)");
WriteLine("- dotnet run .\\agent_console_random.cs \"Generate a random number between 1 and 100\"");
WriteLine(" (one-shot response)");
WriteLine();
if (args.Length > 0)
{
var prompt = string.Join(" ", args);
var reply = await Reply(prompt);
WriteLine(reply);
return;
}
await ChatLoop();
#!/usr/bin/env dotnet run
#:sdk Cadenza.Web@1.0.15
using System.Globalization;
using Microsoft.AspNetCore.Http;
const string HtmlPage = """
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Cadenza Calculator</title>
<style>
:root {
--bg: #f4f7ff;
--panel: #ffffff;
--ink: #1d2433;
--muted: #5f697d;
--accent: #0b7a57;
--line: #d4ddef;
}
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
padding: 20px;
color: var(--ink);
font-family: "Segoe UI", Tahoma, sans-serif;
background:
radial-gradient(circle at 10% 10%, #e9f0ff 0%, transparent 40%),
radial-gradient(circle at 90% 90%, #def6ea 0%, transparent 35%),
var(--bg);
}
main {
width: min(760px, 100%);
background: var(--panel);
border: 1px solid var(--line);
border-radius: 14px;
box-shadow: 0 14px 30px rgba(16, 34, 74, 0.12);
overflow: hidden;
}
header {
padding: 18px 20px;
border-bottom: 1px solid var(--line);
background: linear-gradient(135deg, #f8fbff, #eefaf4);
}
h1 { margin: 0; font-size: 1.35rem; }
p { margin: 8px 0 0; color: var(--muted); }
.content { padding: 20px; display: grid; gap: 12px; }
.row { display: grid; gap: 10px; grid-template-columns: 1fr 130px 1fr auto; }
input, select, button { font: inherit; }
input, select {
width: 100%;
border: 1px solid var(--line);
border-radius: 10px;
padding: 10px 12px;
background: #fff;
}
button {
border: 0;
border-radius: 10px;
padding: 10px 14px;
background: var(--accent);
color: #fff;
font-weight: 600;
cursor: pointer;
}
pre {
margin: 0;
min-height: 130px;
border: 1px solid var(--line);
border-radius: 10px;
padding: 12px;
background: #fff;
overflow: auto;
}
.links { display: flex; gap: 12px; flex-wrap: wrap; }
.links a { color: var(--accent); text-underline-offset: 3px; }
@media (max-width: 640px) { .row { grid-template-columns: 1fr; } }
</style>
</head>
<body>
<main>
<header>
<h1>Arithmetic Calculator</h1>
<p>Cadenza.Web single-file app with OpenAPI JSON endpoint.</p>
</header>
<section class="content">
<div class="row">
<input id="a" type="number" step="any" value="12" aria-label="a" />
<select id="op" aria-label="op">
<option value="add">add (+)</option>
<option value="sub">sub (-)</option>
<option value="mul">mul (*)</option>
<option value="div">div (/)</option>
</select>
<input id="b" type="number" step="any" value="3" aria-label="b" />
<button id="run" type="button">Calculate</button>
</div>
<pre id="result">No calculation yet.</pre>
<div class="links">
<a href="/openapi/v1.json" target="_blank" rel="noreferrer">OpenAPI JSON</a>
<a href="/api/calc?a=12&b=3&op=div" target="_blank" rel="noreferrer">Sample API call</a>
</div>
</section>
</main>
<script>
const resultEl = document.getElementById('result');
const runBtn = document.getElementById('run');
runBtn.addEventListener('click', async () => {
const a = document.getElementById('a').value;
const b = document.getElementById('b').value;
const op = document.getElementById('op').value;
const url = `/api/calc?a=${encodeURIComponent(a)}&b=${encodeURIComponent(b)}&op=${encodeURIComponent(op)}`;
resultEl.textContent = 'Calculating...';
try {
const response = await fetch(url);
const data = await response.json();
resultEl.textContent = JSON.stringify(data, null, 2);
} catch (err) {
resultEl.textContent = String(err);
}
});
</script>
</body>
</html>
""";
const string OpenApiJson = """
{
"openapi": "3.0.3",
"info": {
"title": "Cadenza Arithmetic Calculator API",
"version": "1.0.0",
"description": "Simple arithmetic operations: add, sub, mul, div"
},
"servers": [
{ "url": "http://localhost:8080" }
],
"paths": {
"/api/calc": {
"get": {
"summary": "Calculate with query parameters",
"parameters": [
{ "name": "a", "in": "query", "required": true, "schema": { "type": "number", "format": "double" } },
{ "name": "b", "in": "query", "required": true, "schema": { "type": "number", "format": "double" } },
{ "name": "op", "in": "query", "required": true, "schema": { "type": "string", "enum": ["add", "sub", "mul", "div"] } }
],
"responses": {
"200": { "description": "Calculation succeeded" },
"400": { "description": "Invalid input" }
}
}
}
}
}
""";
Get("/", () => Results.Content(HtmlPage, "text/html; charset=utf-8"));
Get("/api/calc", (string a, string b, string op) =>
{
if (!double.TryParse(a, NumberStyles.Float, CultureInfo.InvariantCulture, out var left))
return Results.BadRequest(new { error = "Parameter 'a' must be a valid number." });
if (!double.TryParse(b, NumberStyles.Float, CultureInfo.InvariantCulture, out var right))
return Results.BadRequest(new { error = "Parameter 'b' must be a valid number." });
var normalized = NormalizeOp(op);
if (!TryCalculate(left, right, normalized, out var result, out var error))
return Results.BadRequest(new { error });
return Results.Ok(new
{
a = left,
b = right,
op = normalized,
expression = $"{left} {OpSymbol(normalized)} {right}",
result
});
});
Get("/openapi/v1.json", () => Results.Content(OpenApiJson, "application/json; charset=utf-8"));
await Run();
static bool TryCalculate(double a, double b, string op, out double value, out string error)
{
value = 0;
error = string.Empty;
switch (op)
{
case "add":
value = a + b;
return true;
case "sub":
value = a - b;
return true;
case "mul":
value = a * b;
return true;
case "div":
if (b == 0)
{
error = "Division by zero is not allowed.";
return false;
}
value = a / b;
return true;
default:
error = "Parameter 'op' must be one of: add, sub, mul, div.";
return false;
}
}
static string NormalizeOp(string? op) =>
(op ?? string.Empty).Trim().ToLowerInvariant() switch
{
"+" => "add",
"-" => "sub",
"*" => "mul",
"/" => "div",
var x => x,
};
static string OpSymbol(string op) => op switch
{
"add" => "+",
"sub" => "-",
"mul" => "*",
"div" => "/",
_ => "?"
};
{
"servers": {
"brave-search": {
"command": "npx",
"args": [
"-y",
"@brave/brave-search-mcp-server",
"--transport",
"stdio"
],
"env": {
"BRAVE_API_KEY": "${input:brave_api_key}"
},
"type": "stdio"
},
"handmirrormcp": {
"type": "stdio",
"command": "dnx",
"args": ["HandMirrorMcp@0.1.1", "--yes"]
},
"microsoft-learn": {
"type": "http",
"url": "https://learn.microsoft.com/api/mcp"
}
},
"inputs": [
{
"id": "brave_api_key",
"type": "promptString",
"description": "Brave Search API Key"
}
]
}
#!/usr/bin/env dotnet run
#:sdk Cadenza@1.0.15
using System.Net;
using System.Net.Http;
var targetUrl = "https://www.naver.com";
using var http = new HttpClient
{
Timeout = TimeSpan.FromSeconds(10),
};
for (var i = 1; i <= 5; i++)
{
var startedAt = DateTime.UtcNow;
try
{
using var request = new HttpRequestMessage(HttpMethod.Get, targetUrl);
using var response = await http.SendAsync(
request,
HttpCompletionOption.ResponseHeadersRead);
var elapsed = DateTime.UtcNow - startedAt;
var status = (int)response.StatusCode;
WriteLine($"[{i}/5] HTTPS probe OK: {targetUrl} -> {status} {response.ReasonPhrase} ({elapsed.TotalMilliseconds:N0} ms)");
}
catch (Exception ex)
{
var elapsed = DateTime.UtcNow - startedAt;
WriteLine($"[{i}/5] HTTPS probe FAIL: {targetUrl} -> {ex.GetType().Name}: {ex.Message} ({elapsed.TotalMilliseconds:N0} ms)");
}
if (i < 5)
await Task.Delay(TimeSpan.FromSeconds(1));
}

바이브코딩 프롬프트 예시

다음과 같이 바이브코딩 프롬프트를 입력하면 쉽게 Cadenza 기반 코드를 빠르게 시작할 수 있습니다. 그 후, dotnet run 명령어나 chmod +x file.cs 명령어로 실행 권한을 부여한 다음 실행하면 손쉽게 실행할 수 있습니다.

먼저 https://raw.githubusercontent.com/rkttu/cadenza/main/README.ko.md 를 읽고, 거기 적힌 Cadenza 규칙(단일 .cs, shebang + #:sdk 지시문, 정확한 버전 핀, Console 대신 ambient helper)을 그대로 지켜 .NET 10 파일 기반 앱으로 다음을 구현하고 dotnet run으로 실행해줘:

간단한 웹 Ping 도구 만들기 프롬프트

먼저 https://raw.githubusercontent.com/rkttu/cadenza/main/README.ko.md 를 읽고, 거기 적힌 Cadenza 규칙(단일 .cs, shebang + #:sdk 지시문, 정확한 버전 핀, Console 대신 ambient helper)을 그대로 지켜 .NET 10 파일 기반 앱으로 다음을 구현하고 dotnet run으로 실행해줘:

https://www.naver.com 사이트를 1초 간격으로 5회 https로 ping 하는 코드를 만들어줘.

오픈 API로 사칙 연산 API 만들고 이를 활용하는 웹 사이트 한번에 만들기

먼저 https://raw.githubusercontent.com/rkttu/cadenza/main/README.ko.md 를 읽고, 거기 적힌 Cadenza 규칙(단일 .cs, shebang + #:sdk 지시문, 정확한 버전 핀, Console 대신 ambient helper)을 그대로 지켜 .NET 10 파일 기반 앱으로 다음을 구현하고 dotnet run으로 실행해줘:

간단한 사칙 연산 계산기를 OpenAPI 형식으로 기능을 구현하고 프론트엔드 HTML 페이지를 담는 웹 사이트를 만들었으면 해.

난수 생성 도구를 담은 MS Foundry GPT-5.5 기반 콘솔 에이전트 만들기

먼저 https://raw.githubusercontent.com/rkttu/cadenza/main/README.ko.md 를 읽고, 거기 적힌 Cadenza 규칙(단일 .cs, shebang + #:sdk 지시문, 정확한 버전 핀, Console 대신 ambient helper)을 그대로 지켜 .NET 10 파일 기반 앱으로 다음을 구현하고 dotnet run으로 실행해줘:

콘솔 형태로 사용할 수 있는 AI 에이전트를 만들려고 해. OPENAPI_ENDPOINT, OPENAPI_MODEL, OPENAPI_KEY 라는 환경 변수를 미리 설정해두었고, 임의의 난수를 생성해서 반환하는 도구를 하나 내장한 에이전트를 만들려고 해.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment