{"id":30424950,"url":"https://github.com/CharlieDigital/SKPromptGenerator","last_synced_at":"2025-08-22T11:04:34.033Z","repository":{"id":245606846,"uuid":"818822303","full_name":"CharlieDigital/SKPromptGenerator","owner":"CharlieDigital","description":"Generates strongly typed classes for Semantic Kernel using prompt strings.","archived":false,"fork":false,"pushed_at":"2024-09-25T19:32:59.000Z","size":3997,"stargazers_count":12,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-01T00:55:13.070Z","etag":null,"topics":["ai","llm","semantic-kernel","source-generator"],"latest_commit_sha":null,"homepage":"https://www.nuget.org/packages/SKPromptGenerator","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CharlieDigital.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-06-23T01:12:30.000Z","updated_at":"2025-05-31T13:15:44.000Z","dependencies_parsed_at":null,"dependency_job_id":"5d8216d7-c7d0-4e82-a493-05589ca03587","html_url":"https://github.com/CharlieDigital/SKPromptGenerator","commit_stats":null,"previous_names":["charliedigital/skpromptgenerator"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/CharlieDigital/SKPromptGenerator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CharlieDigital%2FSKPromptGenerator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CharlieDigital%2FSKPromptGenerator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CharlieDigital%2FSKPromptGenerator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CharlieDigital%2FSKPromptGenerator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CharlieDigital","download_url":"https://codeload.github.com/CharlieDigital/SKPromptGenerator/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CharlieDigital%2FSKPromptGenerator/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271628166,"owners_count":24792821,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-22T02:00:08.480Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","llm","semantic-kernel","source-generator"],"created_at":"2025-08-22T11:02:24.640Z","updated_at":"2025-08-22T11:04:34.013Z","avatar_url":"https://github.com/CharlieDigital.png","language":"C#","readme":"# Semantic Kernel (SK) Prompt Generator\n\nSKPromptGenerator is a C# source generator which automatically creates strongly-typed classes for your string prompt templates.\n\nIt is intended to be used with [Semantic Kernel](https://github.com/microsoft/semantic-kernel).\n\nhttps://github.com/user-attachments/assets/a3727ef4-6880-4939-be40-5c5c08948a3e\n\n\u003e 💡 NOTE: As of version 4, the token format is switched from `{name}` to `{{$name}}` to match Semantic Kernel.\n\n## Motivation\n\nWhen working with prompts, you'll end up doing a lot of string templating and repetitive code.\n\nWouldn't it be nice if you could just have a strongly-typed class for each prompt automatically created using the prompt?\n\nThis library does exactly that.\n\n```csharp\npublic static class Prompts\n{\n  // Define a prompt\n  [PromptTemplate]\n  public const string Capitol = \"\"\"\n    What is the capitol of {{$state}} {{$country}}?\n    Respond directly in a single line\n    \"\"\";\n}\n\n// Execute the prompt passing in a Semantic Kernel instance.\nvar capitol = await new CapitolPrompt(\n  state: \"NJ\",\n  country: \"USA\"\n).ExecuteAsync(kernel);\n```\n\nThe tokens in the prompt string become named parameters on the class constructor 🎉\n\n## Limitations\n\n1. Your prompt must be a `const string` because the generator needs to be able to read the string in the source.\n2. Your prompts must live in some class in a namespace.  If you get the error `error CS1001: Identifier expected`, then you are probably missing a namespace around your prompt.\n3. You must add a dependency to `Microsoft.SemanticKernel` since the `ExecuteAsync` method requires the `Kernel` instance.\n4. Currently only targets .NET 8; considering `netstandard2.0`.\n\n## Installing\n\nThis generator is built for .NET 8.\n\nTo install:\n\n```shell\ndotnet add package SKPromptGenerator\n```\n\nFor the latest releases, see: https://www.nuget.org/packages/SKPromptGenerator\n\n## Using\n\nThis repository includes a sample project under the `/app` directory.\n\nTo use, create a new console app:\n\n```shell\nmkdir sk-prompt-gen-test\ncd sk-prompt-gen-test\ndotnet new console\ndotnet add package SKPromptGenerator\ndotnet add package Microsoft.SemanticKernel\n```\n\nIn the project, create a class like so (you can call your class whatever you want):\n\n```csharp\nnamespace SomeNamespace;\n\npublic static class Prompts\n{\n  [PromptTemplate]\n  public const string Capitol = \"\"\"\n    What is the capitol of {{$state}} {{$country}}?\n    Respond directly in a single line\n    When writing the state, always write it as the full name\n    Write your output in the format: The capitol of \u003cSTATE\u003e is: \u003cCAPITOL\u003e.\n    For example: The capitol of California is: Sacramento.\n    \"\"\";\n}\n```\n\n\u003e 💡 Note the usage of a namespace for the class.  The prompt need not be in a standalone class.  It can also be placed in an existing `Controller` (for example)\n\nIn the code above, we've created a prompt with two tokens: `{{$state}}` and `{{$country}}`.\n\nThe `[PromptTemplate]` attribute instructs the generator to create a class like so:\n\n```csharp\nusing System;\nusing Microsoft.SemanticKernel.Connectors.OpenAI;\nusing SKPromptGenerator;\n\nnamespace SomeNamespace;\n\npublic partial class CapitolPrompt(\n  string state, string country\n) : PromptTemplateBase\n{\n  public override string Text =\u003e $$\"\"\"\nWhat is the capitol of {{state}} {{country}}?\nRespond directly in a single line\nWhen writing the state, always write it as the full name\nWrite your output in the format: The capitol of \u003cSTATE\u003e is: \u003cCAPITOL\u003e.\nFor example: The capitol of California is: Sacramento.\n\"\"\";\n\n  public override OpenAIPromptExecutionSettings Settings =\u003e new OpenAIPromptExecutionSettings\n  {\n    MaxTokens = 500,\n    Temperature = 0.5d,\n    TopP = 0d,\n  };\n}\n```\n\nNote the two class parameters `state` and `country` which are extracted from the prompt template are now string literal tokens.\n\nNow we can use the prompt like so:\n\n```csharp\nvar capitol = await new CapitolPrompt(\"NJ\", \"USA\").ExecuteAsync(kernel);\n\nConsole.WriteLine($\"{capitol}\");\n// The capitol of New Jersey is: Trenton.\n\ncapitol = await new CapitolPrompt(\"NY\", \"USA\").ExecuteAsync(kernel);\n\nConsole.WriteLine($\"{capitol}\");\n// The capitol of New York is: Albany.\n```\n\nIf your prompt returns JSON, we can also deserialize it into an object:\n\n```csharp\n// Our model that we are serializing to\npublic record CapitolResponse(string Country, string State, string Capitol);\n\n// Use ExecuteWithJsonAsync if we also want the raw JSON\nvar (sacramento, json) = await new CapitolJsonPrompt(\n  \"CA\",\n  \"US\"\n).ExecuteWithJsonAsync\u003cCapitolResponse\u003e(kernel);\n```\n\nNOTE: The underlying code will strip Markdown fences so if you are expecting your result to contain markdown, it will be stripped.\n\n### Typed Parameters\n\nIf you want to use typed parameters, you can append the type to the parameter token:\n\n```csharp\n[PromptTemplate]\npublic const string Cities = \"\"\"\n  Write a list of {{$count:int}} cities in {{$region}}, {{$country}}\n  Write each city on a separate line\n  Start you response with: Sure, here are {{$count:int}} cities in {{$region}}, {{$country}}\n  \"\"\";\n```\n\nThis will generate the signature:\n\n```csharp\npublic partial class CitiesPrompt(\n  int count, string region, string country\n) : PromptTemplateBase\n```\n\nWhich can then be invoked with a typed, integer parameter for count:\n\n```csharp\nvar njCities = await new CitiesPrompt(4, \"NJ\", \"USA\").ExecuteAsync(kernel);\n```\n\nThis will output:\n\n```\nSure, here are 4 cities in NJ, USA:\n\n1. Newark\n2. Jersey City\n3. Paterson\n4. Elizabeth\n```\n\nNote that if you are using your own types, those types should be added using a global `using` statement or specify the full type name since the generated class does not know about your namespaces.\n\n(See the example in the `/app` directory for usage)\n\n### Including History\n\nThe `ExecuteAsync` method takes a `historyBuilder` parameter which will receives a `ChatHistory` instance\n\nThe unit tests show how this can be used:\n\n```csharp\n[Fact]\npublic async void History_Builder_Test()\n{\n  var response = await new HistoryTmplPrompt(\"Spencer\").ExecuteAsync(\n    new Kernel(),\n    // 👇 Here we can build the chat history up before adding the new user prompt\n    historyBuilder: (h) =\u003e\n    {\n      h.Add(new ChatMessageContent(AuthorRole.User, \"User question\"));\n      h.Add(new ChatMessageContent(AuthorRole.System, \"System response\"));\n    }\n  );\n\n  // Fake test where we are just going to return the history instead\n  Assert.Equal(\"User question\\nSystem response\", response);\n}\n```\n\nYou can do the retrieval of the actual history *before* the block and then do the history building in the block.\n\n## Custom Base Class\n\nIf you want to customize how the prompt is executed, you can specify a custom base class when assigning the attribute.\n\nYour base class must inherit from `PromptTemplateBase`:\n\n```csharp\npublic abstract class CustomBase : PromptTemplateBase\n{\n  public override async Task\u003cstring\u003e ExecuteAsync(\n    Kernel kernel,\n    string? serviceId = null,\n    CancellationToken cancellation = default\n  )\n  {\n    return await Task.FromResult(\"response\");\n  }\n}\n```\n\nAnd then you can specify this custom base class as a generic type:\n\n```csharp\n[PromptTemplate\u003cCustomBase\u003e]\npublic const string CapitolCustom = \"\"\"\n  What is the capitol of {{$state}} {{$country}}?\n  Respond directly in a single line\n  When writing the state, always write it as the full name\n  Write your output in the format: The capitol of \u003cSTATE\u003e is: \u003cCAPITOL\u003e.\n  For example: The capitol of California is: Sacramento.\n  \"\"\";\n```\n\nThis allows you to take full control of the execution of the prompt (e.g. add logging, telemetry, etc.).\n\n\u003e 💡 Note: you should use a global `using` statement for the namespace of your custom base class.\n\n## Prompt Execution Settings\n\nThe `PromptTemplate` attribute also allows specification of the prompt execution settings.\n\nThe three parameters are:\n\n|Parameter|Details|Default|\n|--|--|--|\n|`MaxTokens`|The maximum number of tokens in the response|`500`|\n|`Temperature`|The temperature|`0.5`|\n|`TopP`|The TopP|`0`|\n\nFor example:\n\n```csharp\npublic static class Prompts\n{\n  [PromptTemplate(10, 0.1)]\n  public const string SampleTmpl1 = \"\"\"\n    What is the capitol of {{$state}} {{$country}}\n    Respond directly on a single line.\n    \"\"\";\n}\n```\n\n(See the `PromptTmpl` class for details)\n\n## Using the Sample App\n\nTo use the sample app, you'll need to set up user secrets:\n\n```shell\ndotnet user-secrets init\ndotnet user-secrets set \"AzureOpenAIKey\" \"YOUR_AZURE_OPEN_AI_KEY\"\ndotnet user-secrets set \"AzureOpenAIEndpoint\" \"YOUR_AZURE_OPEN_AI_ENDPOINT\"\n```\n\nIf you are using OpenAI, feel free to fork this project and simply change the service type and configuration values.\n","funding_links":[],"categories":["Content"],"sub_categories":["219. [SKPromptGenerator](https://ignatandrei.github.io/RSCG_Examples/v2/docs/SKPromptGenerator) , in the [AI](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#ai) category"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FCharlieDigital%2FSKPromptGenerator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FCharlieDigital%2FSKPromptGenerator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FCharlieDigital%2FSKPromptGenerator/lists"}