diff --git a/README.md b/README.md
index 4637d9d0e..80de4b0cf 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-# RSCG - 218 Examples of Roslyn Source Code Generators / 14 created by Microsoft /
+# RSCG - 219 Examples of Roslyn Source Code Generators / 14 created by Microsoft /
-## Latest Update : 2025-08-06 => 06 August 2025
+## Latest Update : 2025-08-07 => 07 August 2025
If you want to see examples with code, please click ***[List V2](https://ignatandrei.github.io/RSCG_Examples/v2/docs/List-of-RSCG)***
@@ -8,7 +8,7 @@ If you want just those from Microsoft, please click ***[Microsoft](https://ignat
If you want to see by category, please click ***[category](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples)***
or click any category below
-[actor](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#actor) -[aop](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#aop) -[api](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#api) -[async](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#async) -[bitwise](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#bitwise) -[blazor](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#blazor) -[builder](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#builder) -[clone](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#clone) -[codetostring](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#codetostring) -[commandline](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#commandline) -[console](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#console) -[constructor](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#constructor) -[database](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#database) -[dependencyinjection](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#dependencyinjection) -[disposer](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#disposer) -[enhancementclass](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#enhancementclass) -[enhancementproject](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#enhancementproject) -[enum](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#enum) -[equals](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#equals) -[filestocode](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#filestocode) -[functionalprogramming](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#functionalprogramming) -[hangfire](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#hangfire) -[interface](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#interface) -[linq](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#linq) -[mapper](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#mapper) -[mediator](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#mediator) -[mvc](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#mvc) -[mvvm](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#mvvm) -[optimizer](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#optimizer) -[primitiveobsession](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#primitiveobsession) -[serializer](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#serializer) -[signalr](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#signalr) -[statemachine](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#statemachine) -[templating](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#templating) -[tests](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#tests) -[winapi](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#winapi) -
+[actor](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#actor) -[ai](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#ai) -[aop](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#aop) -[api](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#api) -[async](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#async) -[bitwise](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#bitwise) -[blazor](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#blazor) -[builder](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#builder) -[clone](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#clone) -[codetostring](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#codetostring) -[commandline](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#commandline) -[console](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#console) -[constructor](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#constructor) -[database](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#database) -[dependencyinjection](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#dependencyinjection) -[disposer](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#disposer) -[enhancementclass](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#enhancementclass) -[enhancementproject](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#enhancementproject) -[enum](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#enum) -[equals](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#equals) -[filestocode](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#filestocode) -[functionalprogramming](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#functionalprogramming) -[hangfire](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#hangfire) -[interface](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#interface) -[linq](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#linq) -[mapper](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#mapper) -[mediator](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#mediator) -[mvc](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#mvc) -[mvvm](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#mvvm) -[optimizer](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#optimizer) -[primitiveobsession](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#primitiveobsession) -[serializer](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#serializer) -[signalr](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#signalr) -[statemachine](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#statemachine) -[templating](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#templating) -[tests](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#tests) -[winapi](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#winapi) -
## If you have a Roslyn Source Code Generator, please create an issue.
@@ -20,8 +20,30 @@ If you want to be notified each time I add a new RSCG example , please click htt
## Content
-Those are the 218 Roslyn Source Code Generators that I have tested you can see and download source code example.
+Those are the 219 Roslyn Source Code Generators that I have tested you can see and download source code example.
( including 14 from Microsoft )
+### 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
+
+Generated on : 2025-08-07 => 07 August 2025
+
+
+ Expand
+
+
+
+Author: Charlie Chen
+
+A source generator to automatically create classes from string prompts.
+
+Nuget: [https://www.nuget.org/packages/SKPromptGenerator/](https://www.nuget.org/packages/SKPromptGenerator/)
+
+
+Link: [https://ignatandrei.github.io/RSCG_Examples/v2/docs/SKPromptGenerator](https://ignatandrei.github.io/RSCG_Examples/v2/docs/SKPromptGenerator)
+
+Source: [https://github.com/CharlieDigital/SKPromptGenerator](https://github.com/CharlieDigital/SKPromptGenerator)
+
+
+
### 218. [Nino](https://ignatandrei.github.io/RSCG_Examples/v2/docs/Nino) , in the [Serializer](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#serializer) category
Generated on : 2025-08-06 => 06 August 2025
diff --git a/later.md b/later.md
index 6c7c6ed7a..c03311ab3 100644
--- a/later.md
+++ b/later.md
@@ -1,6 +1,6 @@
# Just later
-## Latest Update : 2025-08-06 => 06 August 2025
+## Latest Update : 2025-08-07 => 07 August 2025
diff --git a/v2/Generator/DocusaurusExample.txt b/v2/Generator/DocusaurusExample.txt
index 4b6f7a900..fa5863c99 100644
--- a/v2/Generator/DocusaurusExample.txt
+++ b/v2/Generator/DocusaurusExample.txt
@@ -103,17 +103,9 @@ Those are taken from $(BaseIntermediateOutputPath)\GX
{{~ for fileContent in Description.Data.outputFiles.generatedFiles ~}}
-
-{{~ if fileContent.content | string.contains "```" ~}}
-
-{{fileContent.content}}
-
-{{~ else ~}}
-
```csharp showLineNumbers
{{fileContent.content}}
```
-{{end}}
{{~ end ~}}
diff --git a/v2/Generator/MultiGeneratorV2.cs b/v2/Generator/MultiGeneratorV2.cs
index 11f3a5cae..2503b5359 100644
--- a/v2/Generator/MultiGeneratorV2.cs
+++ b/v2/Generator/MultiGeneratorV2.cs
@@ -120,6 +120,7 @@ public string[] SourceNoRSCG()
var text=await File.ReadAllTextAsync(nameFile);
text = text.Replace("(img/", $"({d.Generator!.Source}/img/");
text=text.Replace("(README_IMAGE.png)", $"({d.Generator!.Source}/README_IMAGE.png)");
+ text = text.Replace("(README", $"({d.Generator!.Source}/README");
text = text.Replace("(integ-tests/", $"({d.Generator!.Source}/integ-tests/");
text = text.Replace("(./samples", $"({d.Generator!.Source}/samples");
text = text.Replace("(./tests", $"({d.Generator!.Source}/tests");
diff --git a/v2/Generator/all.csv b/v2/Generator/all.csv
index bbef09e0e..662d5e73f 100644
--- a/v2/Generator/all.csv
+++ b/v2/Generator/all.csv
@@ -217,3 +217,4 @@ Nr,Key,Source,Category
216,SG4MVC, https://github.com/SG4MVC/SG4MVC,MVC
217,EnumsEnhanced, https://github.com/snowberry-software/EnumsEnhanced,Enum
218,Nino, https://github.com/JasonXuDeveloper/Nino,Serializer
+219,SKPromptGenerator, https://github.com/CharlieDigital/SKPromptGenerator,AI
diff --git a/v2/GeneratorData/Category.cs b/v2/GeneratorData/Category.cs
index d02f02f4a..3750f80f3 100644
--- a/v2/GeneratorData/Category.cs
+++ b/v2/GeneratorData/Category.cs
@@ -39,5 +39,6 @@ public enum Category
Console=34,
Async=35,
MVC=36,
+ AI=37,
}
diff --git a/v2/RSCGExamplesData/GeneratorDataRec.json b/v2/RSCGExamplesData/GeneratorDataRec.json
index 661c4374b..b38228316 100644
--- a/v2/RSCGExamplesData/GeneratorDataRec.json
+++ b/v2/RSCGExamplesData/GeneratorDataRec.json
@@ -1317,5 +1317,11 @@
"Category": 16,
"dtStart": "2025-08-06T00:00:00",
"show": true
+},
+{
+ "ID":"SKPromptGenerator",
+ "Category": 37,
+ "dtStart": "2025-08-07T00:00:00",
+ "show": true
}
]
\ No newline at end of file
diff --git a/v2/book/examples/SKPromptGenerator.html b/v2/book/examples/SKPromptGenerator.html
new file mode 100644
index 000000000..17d93386b
--- /dev/null
+++ b/v2/book/examples/SKPromptGenerator.html
@@ -0,0 +1,69 @@
+
+
RSCG nr 219 : SKPromptGenerator
+
+Info
+Nuget : https://www.nuget.org/packages/SKPromptGenerator/
+
+You can find more details at : https://github.com/CharlieDigital/SKPromptGenerator
+
+Author :Charlie Chen
+
+Source: https://github.com/CharlieDigital/SKPromptGenerator
+
+About
+
+Generate typed prompts for Semantic Kernel
+
+
+ How to use
+
+
+ Add reference to the SKPromptGenerator in the csproj
+
+
+
+This was for me the starting code
+
+
+ I have coded the file Program.cs
+
+
+
+
+
+ I have coded the file WeatherCity.cs
+
+
+
+ And here are the generated files
+
+
+ The file generated is WeatherPrompt.g.cs
+
+
+
+
+ The file generated is PromptTemplateAttribute.g.cs
+
+
+
+
+ The file generated is PromptTemplateBase.g.cs
+
+
+
+
+ You can download the code and this page as pdf from
+
+ https://ignatandrei.github.io/RSCG_Examples/v2/docs/SKPromptGenerator
+
+
+
+
+
+ You can see the whole list at
+
+ https://ignatandrei.github.io/RSCG_Examples/v2/docs/List-of-RSCG
+
+
+
diff --git a/v2/book/list.html b/v2/book/list.html
index 7bdcfa523..922c935ee 100644
--- a/v2/book/list.html
+++ b/v2/book/list.html
@@ -17,7 +17,7 @@
-This is the list of 218 RSCG with examples =>
+This is the list of 219 RSCG with examples =>
diff --git a/v2/book/pandocHTML.yaml b/v2/book/pandocHTML.yaml
index 207f3c0b5..a1c3bd536 100644
--- a/v2/book/pandocHTML.yaml
+++ b/v2/book/pandocHTML.yaml
@@ -232,6 +232,7 @@ input-files:
- examples/SG4MVC.html
- examples/EnumsEnhanced.html
- examples/Nino.html
+- examples/SKPromptGenerator.html
# or you may use input-file: with a single value
# defaults:
diff --git a/v2/rscg_examples/SKPromptGenerator/description.json b/v2/rscg_examples/SKPromptGenerator/description.json
new file mode 100644
index 000000000..533e73330
--- /dev/null
+++ b/v2/rscg_examples/SKPromptGenerator/description.json
@@ -0,0 +1,22 @@
+{
+ "generator":{
+ "name":"SKPromptGenerator",
+ "nuget":[
+ "https://www.nuget.org/packages/SKPromptGenerator/"
+ ],
+ "link":"https://github.com/CharlieDigital/SKPromptGenerator",
+ "author":"Charlie Chen",
+ "source":"https://github.com/CharlieDigital/SKPromptGenerator"
+ },
+ "data":{
+ "goodFor":["Generate typed prompts for Semantic Kernel"],
+ "csprojDemo":"DemoAI.csproj",
+ "csFiles":["Program.cs","WeatherCity.cs"],
+ "excludeDirectoryGenerated":[""],
+ "includeAdditionalFiles":[""]
+ },
+ "links":{
+ "blog":"",
+ "video":""
+ }
+}
\ No newline at end of file
diff --git a/v2/rscg_examples/SKPromptGenerator/nuget.txt b/v2/rscg_examples/SKPromptGenerator/nuget.txt
new file mode 100644
index 000000000..30465b85e
--- /dev/null
+++ b/v2/rscg_examples/SKPromptGenerator/nuget.txt
@@ -0,0 +1 @@
+A source generator to automatically create classes from string prompts.
\ No newline at end of file
diff --git a/v2/rscg_examples/SKPromptGenerator/readme.txt b/v2/rscg_examples/SKPromptGenerator/readme.txt
new file mode 100644
index 000000000..5639b31fd
--- /dev/null
+++ b/v2/rscg_examples/SKPromptGenerator/readme.txt
@@ -0,0 +1,298 @@
+# Semantic Kernel (SK) Prompt Generator
+
+SKPromptGenerator is a C# source generator which automatically creates strongly-typed classes for your string prompt templates.
+
+It is intended to be used with [Semantic Kernel](https://github.com/microsoft/semantic-kernel).
+
+https://github.com/user-attachments/assets/a3727ef4-6880-4939-be40-5c5c08948a3e
+
+> π‘ NOTE: As of version 4, the token format is switched from `{name}` to `{{$name}}` to match Semantic Kernel.
+
+## Motivation
+
+When working with prompts, you'll end up doing a lot of string templating and repetitive code.
+
+Wouldn't it be nice if you could just have a strongly-typed class for each prompt automatically created using the prompt?
+
+This library does exactly that.
+
+```csharp
+public static class Prompts
+{
+ // Define a prompt
+ [PromptTemplate]
+ public const string Capitol = """
+ What is the capitol of {{$state}} {{$country}}?
+ Respond directly in a single line
+ """;
+}
+
+// Execute the prompt passing in a Semantic Kernel instance.
+var capitol = await new CapitolPrompt(
+ state: "NJ",
+ country: "USA"
+).ExecuteAsync(kernel);
+```
+
+The tokens in the prompt string become named parameters on the class constructor π
+
+## Limitations
+
+1. Your prompt must be a `const string` because the generator needs to be able to read the string in the source.
+2. 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.
+3. You must add a dependency to `Microsoft.SemanticKernel` since the `ExecuteAsync` method requires the `Kernel` instance.
+4. Currently only targets .NET 8; considering `netstandard2.0`.
+
+## Installing
+
+This generator is built for .NET 8.
+
+To install:
+
+```shell
+dotnet add package SKPromptGenerator
+```
+
+For the latest releases, see: https://www.nuget.org/packages/SKPromptGenerator
+
+## Using
+
+This repository includes a sample project under the `/app` directory.
+
+To use, create a new console app:
+
+```shell
+mkdir sk-prompt-gen-test
+cd sk-prompt-gen-test
+dotnet new console
+dotnet add package SKPromptGenerator
+dotnet add package Microsoft.SemanticKernel
+```
+
+In the project, create a class like so (you can call your class whatever you want):
+
+```csharp
+namespace SomeNamespace;
+
+public static class Prompts
+{
+ [PromptTemplate]
+ public const string Capitol = """
+ What is the capitol of {{$state}} {{$country}}?
+ Respond directly in a single line
+ When writing the state, always write it as the full name
+ Write your output in the format: The capitol of is: .
+ For example: The capitol of California is: Sacramento.
+ """;
+}
+```
+
+> π‘ 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)
+
+In the code above, we've created a prompt with two tokens: `{{$state}}` and `{{$country}}`.
+
+The `[PromptTemplate]` attribute instructs the generator to create a class like so:
+
+```csharp
+using System;
+using Microsoft.SemanticKernel.Connectors.OpenAI;
+using SKPromptGenerator;
+
+namespace SomeNamespace;
+
+public partial class CapitolPrompt(
+ string state, string country
+) : PromptTemplateBase
+{
+ public override string Text => $$"""
+What is the capitol of {{state}} {{country}}?
+Respond directly in a single line
+When writing the state, always write it as the full name
+Write your output in the format: The capitol of is: .
+For example: The capitol of California is: Sacramento.
+""";
+
+ public override OpenAIPromptExecutionSettings Settings => new OpenAIPromptExecutionSettings
+ {
+ MaxTokens = 500,
+ Temperature = 0.5d,
+ TopP = 0d,
+ };
+}
+```
+
+Note the two class parameters `state` and `country` which are extracted from the prompt template are now string literal tokens.
+
+Now we can use the prompt like so:
+
+```csharp
+var capitol = await new CapitolPrompt("NJ", "USA").ExecuteAsync(kernel);
+
+Console.WriteLine($"{capitol}");
+// The capitol of New Jersey is: Trenton.
+
+capitol = await new CapitolPrompt("NY", "USA").ExecuteAsync(kernel);
+
+Console.WriteLine($"{capitol}");
+// The capitol of New York is: Albany.
+```
+
+If your prompt returns JSON, we can also deserialize it into an object:
+
+```csharp
+// Our model that we are serializing to
+public record CapitolResponse(string Country, string State, string Capitol);
+
+// Use ExecuteWithJsonAsync if we also want the raw JSON
+var (sacramento, json) = await new CapitolJsonPrompt(
+ "CA",
+ "US"
+).ExecuteWithJsonAsync(kernel);
+```
+
+NOTE: The underlying code will strip Markdown fences so if you are expecting your result to contain markdown, it will be stripped.
+
+### Typed Parameters
+
+If you want to use typed parameters, you can append the type to the parameter token:
+
+```csharp
+[PromptTemplate]
+public const string Cities = """
+ Write a list of {{$count:int}} cities in {{$region}}, {{$country}}
+ Write each city on a separate line
+ Start you response with: Sure, here are {{$count:int}} cities in {{$region}}, {{$country}}
+ """;
+```
+
+This will generate the signature:
+
+```csharp
+public partial class CitiesPrompt(
+ int count, string region, string country
+) : PromptTemplateBase
+```
+
+Which can then be invoked with a typed, integer parameter for count:
+
+```csharp
+var njCities = await new CitiesPrompt(4, "NJ", "USA").ExecuteAsync(kernel);
+```
+
+This will output:
+
+```
+Sure, here are 4 cities in NJ, USA:
+
+1. Newark
+2. Jersey City
+3. Paterson
+4. Elizabeth
+```
+
+Note 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.
+
+(See the example in the `/app` directory for usage)
+
+### Including History
+
+The `ExecuteAsync` method takes a `historyBuilder` parameter which will receives a `ChatHistory` instance
+
+The unit tests show how this can be used:
+
+```csharp
+[Fact]
+public async void History_Builder_Test()
+{
+ var response = await new HistoryTmplPrompt("Spencer").ExecuteAsync(
+ new Kernel(),
+ // π Here we can build the chat history up before adding the new user prompt
+ historyBuilder: (h) =>
+ {
+ h.Add(new ChatMessageContent(AuthorRole.User, "User question"));
+ h.Add(new ChatMessageContent(AuthorRole.System, "System response"));
+ }
+ );
+
+ // Fake test where we are just going to return the history instead
+ Assert.Equal("User question\nSystem response", response);
+}
+```
+
+You can do the retrieval of the actual history *before* the block and then do the history building in the block.
+
+## Custom Base Class
+
+If you want to customize how the prompt is executed, you can specify a custom base class when assigning the attribute.
+
+Your base class must inherit from `PromptTemplateBase`:
+
+```csharp
+public abstract class CustomBase : PromptTemplateBase
+{
+ public override async Task ExecuteAsync(
+ Kernel kernel,
+ string? serviceId = null,
+ CancellationToken cancellation = default
+ )
+ {
+ return await Task.FromResult("response");
+ }
+}
+```
+
+And then you can specify this custom base class as a generic type:
+
+```csharp
+[PromptTemplate]
+public const string CapitolCustom = """
+ What is the capitol of {{$state}} {{$country}}?
+ Respond directly in a single line
+ When writing the state, always write it as the full name
+ Write your output in the format: The capitol of is: .
+ For example: The capitol of California is: Sacramento.
+ """;
+```
+
+This allows you to take full control of the execution of the prompt (e.g. add logging, telemetry, etc.).
+
+> π‘ Note: you should use a global `using` statement for the namespace of your custom base class.
+
+## Prompt Execution Settings
+
+The `PromptTemplate` attribute also allows specification of the prompt execution settings.
+
+The three parameters are:
+
+|Parameter|Details|Default|
+|--|--|--|
+|`MaxTokens`|The maximum number of tokens in the response|`500`|
+|`Temperature`|The temperature|`0.5`|
+|`TopP`|The TopP|`0`|
+
+For example:
+
+```csharp
+public static class Prompts
+{
+ [PromptTemplate(10, 0.1)]
+ public const string SampleTmpl1 = """
+ What is the capitol of {{$state}} {{$country}}
+ Respond directly on a single line.
+ """;
+}
+```
+
+(See the `PromptTmpl` class for details)
+
+## Using the Sample App
+
+To use the sample app, you'll need to set up user secrets:
+
+```shell
+dotnet user-secrets init
+dotnet user-secrets set "AzureOpenAIKey" "YOUR_AZURE_OPEN_AI_KEY"
+dotnet user-secrets set "AzureOpenAIEndpoint" "YOUR_AZURE_OPEN_AI_ENDPOINT"
+```
+
+If you are using OpenAI, feel free to fork this project and simply change the service type and configuration values.
diff --git a/v2/rscg_examples/SKPromptGenerator/src/.tours/SKPromptGenerator.tour b/v2/rscg_examples/SKPromptGenerator/src/.tours/SKPromptGenerator.tour
new file mode 100644
index 000000000..3a75c29e2
--- /dev/null
+++ b/v2/rscg_examples/SKPromptGenerator/src/.tours/SKPromptGenerator.tour
@@ -0,0 +1,48 @@
+
+{
+ "$schema": "https://aka.ms/codetour-schema",
+ "title": "SKPromptGenerator",
+ "steps":
+ [
+ {
+ "file": "DemoAI/DemoAI.csproj",
+ "description": "First, we add Nuget [SKPromptGenerator](https://www.nuget.org/packages/SKPromptGenerator/) in csproj ",
+ "pattern": "SKPromptGenerator"
+ }
+
+ ,{
+ "file": "DemoAI/WeatherCity.cs",
+ "description": "File WeatherCity.cs ",
+ "pattern": "this is the code"
+ }
+
+ ,{
+ "file": "DemoAI/Program.cs",
+ "description": "File Program.cs \r\n>> dotnet run --project DemoAI/DemoAI.csproj ",
+ "pattern": "this is the code"
+ }
+
+
+ ,{
+ "file": "DemoAI/obj/GX/SKPromptGenerator/SKPromptGenerator.PromptTemplateBaseGenerator/PromptTemplateBase.g.cs",
+ "description": "Generated File 3 from 3 : PromptTemplateBase.g.cs ",
+ "line": 1
+ }
+
+ ,{
+ "file": "DemoAI/obj/GX/SKPromptGenerator/SKPromptGenerator.PromptTemplateAttributeGenerator/PromptTemplateAttribute.g.cs",
+ "description": "Generated File 2 from 3 : PromptTemplateAttribute.g.cs ",
+ "line": 1
+ }
+
+ ,{
+ "file": "DemoAI/obj/GX/SKPromptGenerator/SKPromptGenerator.PromptGenerator/WeatherPrompt.g.cs",
+ "description": "Generated File 1 from 3 : WeatherPrompt.g.cs ",
+ "line": 1
+ }
+
+ ],
+
+ "ref": "main"
+
+}
\ No newline at end of file
diff --git a/v2/rscg_examples/SKPromptGenerator/src/DemoAI.sln b/v2/rscg_examples/SKPromptGenerator/src/DemoAI.sln
new file mode 100644
index 000000000..8c074fec7
--- /dev/null
+++ b/v2/rscg_examples/SKPromptGenerator/src/DemoAI.sln
@@ -0,0 +1,25 @@
+ο»Ώ
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.14.36414.22 d17.14
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DemoAI", "DemoAI\DemoAI.csproj", "{7E2B9DD1-E30E-4990-B3AB-71E1B0DD612D}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7E2B9DD1-E30E-4990-B3AB-71E1B0DD612D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7E2B9DD1-E30E-4990-B3AB-71E1B0DD612D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7E2B9DD1-E30E-4990-B3AB-71E1B0DD612D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7E2B9DD1-E30E-4990-B3AB-71E1B0DD612D}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {15647B26-E02C-48A2-8743-6DD3297D586A}
+ EndGlobalSection
+EndGlobal
diff --git a/v2/rscg_examples/SKPromptGenerator/src/DemoAI/DemoAI.csproj b/v2/rscg_examples/SKPromptGenerator/src/DemoAI/DemoAI.csproj
new file mode 100644
index 000000000..d22bcfc8f
--- /dev/null
+++ b/v2/rscg_examples/SKPromptGenerator/src/DemoAI/DemoAI.csproj
@@ -0,0 +1,21 @@
+ο»Ώ
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+ true
+ $(BaseIntermediateOutputPath)\GX
+
+
diff --git a/v2/rscg_examples/SKPromptGenerator/src/DemoAI/Program.cs b/v2/rscg_examples/SKPromptGenerator/src/DemoAI/Program.cs
new file mode 100644
index 000000000..4397d9ad8
--- /dev/null
+++ b/v2/rscg_examples/SKPromptGenerator/src/DemoAI/Program.cs
@@ -0,0 +1,3 @@
+ο»Ώ// See https://aka.ms/new-console-template for more information
+Console.WriteLine("Hello, World!");
+var capitol = new DemoAI.WeatherPrompt("Bucuresti");
diff --git a/v2/rscg_examples/SKPromptGenerator/src/DemoAI/WeatherCity.cs b/v2/rscg_examples/SKPromptGenerator/src/DemoAI/WeatherCity.cs
new file mode 100644
index 000000000..4105add51
--- /dev/null
+++ b/v2/rscg_examples/SKPromptGenerator/src/DemoAI/WeatherCity.cs
@@ -0,0 +1,13 @@
+ο»Ώusing SKPromptGenerator; // <-- Add namespace here
+
+namespace DemoAI
+{
+ public static partial class MyPrompts
+ {
+ [PromptTemplate] // <-- Remove namespace here
+ public const string Weather = """
+ What is the weather in the city {{$city}} ?
+ Respond directly in a single line
+ """;
+ }
+}
\ No newline at end of file
diff --git a/v2/rscg_examples/SKPromptGenerator/video.json b/v2/rscg_examples/SKPromptGenerator/video.json
new file mode 100644
index 000000000..280d7b9b9
--- /dev/null
+++ b/v2/rscg_examples/SKPromptGenerator/video.json
@@ -0,0 +1,39 @@
+{
+ "scriptName": "SKPromptGenerator",
+ "steps":
+[
+ {"typeStep":"exec","arg":"clipchamp.exe launch"},
+ {"typeStep":"text","arg": "Welcome to Roslyn Examples"},
+ {"typeStep":"text","arg":"If you want to see more examples , see List Of RSCG"},
+ {"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/List-of-RSCG"},
+ {"typeStep":"text","arg": "My name is Andrei Ignat and I am deeply fond of Roslyn Source Code Generator. "},
+
+{"typeStep":"text","arg": "Today I will present SKPromptGenerator . Generate typed prompts for Semantic Kernel ."},
+{"typeStep":"browser","arg":"https://www.nuget.org/packages/SKPromptGenerator/"},
+{"typeStep":"text","arg": "The whole example is here"},
+{"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/SKPromptGenerator"},
+{"typeStep":"text","arg": "You can download the code from here"},
+{"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/SKPromptGenerator#download-example-net--c-"},
+{"typeStep":"text","arg":"Here is the code downloaded "},
+{"typeStep":"exec","arg":"explorer.exe /select,D:\\gth\\RSCG_Examples\\v2\\rscg_examples\\SKPromptGenerator\\src\\DemoAI.sln"},
+{"typeStep":"text","arg": "So , let's start the project with Visual Studio Code "},
+{"typeStep":"stepvscode","arg": "-n D:\\gth\\RSCG_Examples\\v2\\rscg_examples\\SKPromptGenerator\\src"},
+
+{"typeStep":"text","arg": "To use it ,you will put the Nuget SKPromptGenerator into the csproj "},
+
+{"typeStep":"stepvscode","arg": "-r -g D:\\gth\\RSCG_Examples\\v2\\rscg_examples\\SKPromptGenerator\\src\\DemoAI\\DemoAI.csproj"},
+
+{"typeStep":"text","arg": "And now I will show you an example of using SKPromptGenerator"},
+
+{"typeStep":"hide","arg": "now execute the tour in VSCode"},
+{"typeStep":"tour", "arg": "src/.tours/"},
+{"typeStep":"text","arg":" And I will execute the project"},
+{"typeStep":"showproj", "arg":"DemoAI.csproj"},
+{"typeStep":"text","arg":" This concludes the project"},
+{"typeStep":"waitseconds","arg":"30"},
+{"typeStep":"text","arg": "Remember, you can download the code from here"},
+{"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/SKPromptGenerator#download-example-net--c-",
+SpeakTest=" "},
+{"typeStep":"waitseconds","arg":"30"},
+]
+}
diff --git a/v2/rscg_examples_site/docs/Categories/AI.md b/v2/rscg_examples_site/docs/Categories/AI.md
new file mode 100644
index 000000000..1be6cd59f
--- /dev/null
+++ b/v2/rscg_examples_site/docs/Categories/AI.md
@@ -0,0 +1,6 @@
+AI
+
+Number RSCG: 1
+
+ 1 [SKPromptGenerator](/docs/SKPromptGenerator)
+
\ No newline at end of file
diff --git a/v2/rscg_examples_site/docs/Categories/_PrimitiveAI.mdx b/v2/rscg_examples_site/docs/Categories/_PrimitiveAI.mdx
new file mode 100644
index 000000000..1268bac92
--- /dev/null
+++ b/v2/rscg_examples_site/docs/Categories/_PrimitiveAI.mdx
@@ -0,0 +1,7 @@
+### Category "AI" has the following generators:
+
+ 1 [SKPromptGenerator](/docs/SKPromptGenerator)
+
+### See category
+
+[AI](/docs/Categories/AI)
diff --git a/v2/rscg_examples_site/docs/RSCG-Examples/EnumsEnhanced.md b/v2/rscg_examples_site/docs/RSCG-Examples/EnumsEnhanced.md
index 010e22638..6a79a61bf 100644
--- a/v2/rscg_examples_site/docs/RSCG-Examples/EnumsEnhanced.md
+++ b/v2/rscg_examples_site/docs/RSCG-Examples/EnumsEnhanced.md
@@ -614,8 +614,6 @@ Those are taken from $(BaseIntermediateOutputPath)\GX
-
-
```csharp showLineNumbers
#nullable enable
@@ -1009,7 +1007,6 @@ if(subValue.Equals("Mercedes", StringComparison.OrdinalIgnoreCase)) {
#nullable restore
```
-
diff --git a/v2/rscg_examples_site/docs/RSCG-Examples/Nino.md b/v2/rscg_examples_site/docs/RSCG-Examples/Nino.md
index ecd02491b..8cae39f5c 100644
--- a/v2/rscg_examples_site/docs/RSCG-Examples/Nino.md
+++ b/v2/rscg_examples_site/docs/RSCG-Examples/Nino.md
@@ -60,7 +60,7 @@ Jason Xu
[](https://www.nuget.org/packages/Nino)
[](https://openupm.com/packages/com.jasonxudeveloper.nino/)
-[π **Official Website**](https://nino.xgamedev.net/en/) β’ [π **Documentation**](https://nino.xgamedev.net/en/doc/start) β’ [π **Performance**](https://nino.xgamedev.net/en/perf/micro) β’ [π¨π³ **δΈζ**](README.zh.md)
+[π **Official Website**](https://nino.xgamedev.net/en/) β’ [π **Documentation**](https://nino.xgamedev.net/en/doc/start) β’ [π **Performance**](https://nino.xgamedev.net/en/perf/micro) β’ [π¨π³ **δΈζ**](https://github.com/JasonXuDeveloper/Nino/README.zh.md)
*Fast, flexible, and effortless C# binary serialization*
@@ -187,7 +187,7 @@ Nino consistently delivers exceptional performance across various scenarios. See
**Made with β€οΈ by [JasonXuDeveloper](https://github.com/JasonXuDeveloper)**
-*Licensed under [MIT License](LICENSE)*
+*Licensed under [MIT License](https://github.com/JasonXuDeveloper/Nino/LICENSE)*
@@ -283,8 +283,6 @@ Those are taken from $(BaseIntermediateOutputPath)\GX
-
-
```csharp showLineNumbers
//
#pragma warning disable CS8669
@@ -488,13 +486,10 @@ namespace Serializer.NinoGen
}
}
```
-
-
-
```csharp showLineNumbers
//
using System;
@@ -621,13 +616,10 @@ namespace Serializer.NinoGen
}
}
```
-
-
-
```csharp showLineNumbers
//
#pragma warning disable CS8669
@@ -694,13 +686,10 @@ namespace Serializer.NinoGen
}
}
```
-
-
-
```csharp showLineNumbers
/*
Base Types:
@@ -715,13 +704,10 @@ Circular Types:
*/
```
-
-
-
```csharp showLineNumbers
//
#pragma warning disable CS0109, CS8669
@@ -730,13 +716,10 @@ using System.Runtime.CompilerServices;
```
-
-
-
```csharp showLineNumbers
//
@@ -752,13 +735,10 @@ namespace Serializer.NinoGen
}
#endif
```
-
-
-
```csharp showLineNumbers
//
#pragma warning disable CS8669
@@ -947,13 +927,10 @@ namespace Serializer.NinoGen
}
}
```
-
-
-
```csharp showLineNumbers
//
@@ -1077,13 +1054,10 @@ namespace Serializer.NinoGen
}
}
```
-
-
-
```csharp showLineNumbers
//
#pragma warning disable CS8669
@@ -1153,13 +1127,10 @@ namespace Serializer.NinoGen
}
}
```
-
-
-
```csharp showLineNumbers
//
@@ -1210,13 +1181,10 @@ namespace Serializer.NinoGen
}
}
```
-
-
-
```csharp showLineNumbers
/*
Type: SerializerDemo.Person
@@ -1227,7 +1195,6 @@ Members:
*/
```
-
diff --git a/v2/rscg_examples_site/docs/RSCG-Examples/SKPromptGenerator.md b/v2/rscg_examples_site/docs/RSCG-Examples/SKPromptGenerator.md
new file mode 100644
index 000000000..e56f98637
--- /dev/null
+++ b/v2/rscg_examples_site/docs/RSCG-Examples/SKPromptGenerator.md
@@ -0,0 +1,673 @@
+---
+sidebar_position: 2190
+title: 219 - SKPromptGenerator
+description: Generate typed prompts for Semantic Kernel
+slug: /SKPromptGenerator
+---
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+import TOCInline from '@theme/TOCInline';
+import SameCategory from '../Categories/_PrimitiveAI.mdx';
+
+# SKPromptGenerator by Charlie Chen
+
+
+
+
+## NuGet / site data
+[](https://www.nuget.org/packages/SKPromptGenerator/)
+[](https://github.com/CharlieDigital/SKPromptGenerator)
+
+
+## Details
+
+### Info
+:::info
+
+Name: **SKPromptGenerator**
+
+A source generator to automatically create classes from string prompts.
+
+Author: Charlie Chen
+
+NuGet:
+*https://www.nuget.org/packages/SKPromptGenerator/*
+
+
+You can find more details at https://github.com/CharlieDigital/SKPromptGenerator
+
+Source: https://github.com/CharlieDigital/SKPromptGenerator
+
+:::
+
+### Author
+:::note
+Charlie Chen
+
+:::
+
+### Original Readme
+:::note
+
+# Semantic Kernel (SK) Prompt Generator
+
+SKPromptGenerator is a C# source generator which automatically creates strongly-typed classes for your string prompt templates.
+
+It is intended to be used with [Semantic Kernel](https://github.com/microsoft/semantic-kernel).
+
+https://github.com/user-attachments/assets/a3727ef4-6880-4939-be40-5c5c08948a3e
+
+> π‘ NOTE: As of version 4, the token format is switched from `{name}` to `{{$name}}` to match Semantic Kernel.
+
+## Motivation
+
+When working with prompts, you'll end up doing a lot of string templating and repetitive code.
+
+Wouldn't it be nice if you could just have a strongly-typed class for each prompt automatically created using the prompt?
+
+This library does exactly that.
+
+```csharp
+public static class Prompts
+{
+ // Define a prompt
+ [PromptTemplate]
+ public const string Capitol = """
+ What is the capitol of {{$state}} {{$country}}?
+ Respond directly in a single line
+ """;
+}
+
+// Execute the prompt passing in a Semantic Kernel instance.
+var capitol = await new CapitolPrompt(
+ state: "NJ",
+ country: "USA"
+).ExecuteAsync(kernel);
+```
+
+The tokens in the prompt string become named parameters on the class constructor π
+
+## Limitations
+
+1. Your prompt must be a `const string` because the generator needs to be able to read the string in the source.
+2. 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.
+3. You must add a dependency to `Microsoft.SemanticKernel` since the `ExecuteAsync` method requires the `Kernel` instance.
+4. Currently only targets .NET 8; considering `netstandard2.0`.
+
+## Installing
+
+This generator is built for .NET 8.
+
+To install:
+
+```shell
+dotnet add package SKPromptGenerator
+```
+
+For the latest releases, see: https://www.nuget.org/packages/SKPromptGenerator
+
+## Using
+
+This repository includes a sample project under the `/app` directory.
+
+To use, create a new console app:
+
+```shell
+mkdir sk-prompt-gen-test
+cd sk-prompt-gen-test
+dotnet new console
+dotnet add package SKPromptGenerator
+dotnet add package Microsoft.SemanticKernel
+```
+
+In the project, create a class like so (you can call your class whatever you want):
+
+```csharp
+namespace SomeNamespace;
+
+public static class Prompts
+{
+ [PromptTemplate]
+ public const string Capitol = """
+ What is the capitol of {{$state}} {{$country}}?
+ Respond directly in a single line
+ When writing the state, always write it as the full name
+ Write your output in the format: The capitol of is: .
+ For example: The capitol of California is: Sacramento.
+ """;
+}
+```
+
+> π‘ 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)
+
+In the code above, we've created a prompt with two tokens: `{{$state}}` and `{{$country}}`.
+
+The `[PromptTemplate]` attribute instructs the generator to create a class like so:
+
+```csharp
+using System;
+using Microsoft.SemanticKernel.Connectors.OpenAI;
+using SKPromptGenerator;
+
+namespace SomeNamespace;
+
+public partial class CapitolPrompt(
+ string state, string country
+) : PromptTemplateBase
+{
+ public override string Text => $$"""
+What is the capitol of {{state}} {{country}}?
+Respond directly in a single line
+When writing the state, always write it as the full name
+Write your output in the format: The capitol of is: .
+For example: The capitol of California is: Sacramento.
+""";
+
+ public override OpenAIPromptExecutionSettings Settings => new OpenAIPromptExecutionSettings
+ {
+ MaxTokens = 500,
+ Temperature = 0.5d,
+ TopP = 0d,
+ };
+}
+```
+
+Note the two class parameters `state` and `country` which are extracted from the prompt template are now string literal tokens.
+
+Now we can use the prompt like so:
+
+```csharp
+var capitol = await new CapitolPrompt("NJ", "USA").ExecuteAsync(kernel);
+
+Console.WriteLine($"{capitol}");
+// The capitol of New Jersey is: Trenton.
+
+capitol = await new CapitolPrompt("NY", "USA").ExecuteAsync(kernel);
+
+Console.WriteLine($"{capitol}");
+// The capitol of New York is: Albany.
+```
+
+If your prompt returns JSON, we can also deserialize it into an object:
+
+```csharp
+// Our model that we are serializing to
+public record CapitolResponse(string Country, string State, string Capitol);
+
+// Use ExecuteWithJsonAsync if we also want the raw JSON
+var (sacramento, json) = await new CapitolJsonPrompt(
+ "CA",
+ "US"
+).ExecuteWithJsonAsync(kernel);
+```
+
+NOTE: The underlying code will strip Markdown fences so if you are expecting your result to contain markdown, it will be stripped.
+
+### Typed Parameters
+
+If you want to use typed parameters, you can append the type to the parameter token:
+
+```csharp
+[PromptTemplate]
+public const string Cities = """
+ Write a list of {{$count:int}} cities in {{$region}}, {{$country}}
+ Write each city on a separate line
+ Start you response with: Sure, here are {{$count:int}} cities in {{$region}}, {{$country}}
+ """;
+```
+
+This will generate the signature:
+
+```csharp
+public partial class CitiesPrompt(
+ int count, string region, string country
+) : PromptTemplateBase
+```
+
+Which can then be invoked with a typed, integer parameter for count:
+
+```csharp
+var njCities = await new CitiesPrompt(4, "NJ", "USA").ExecuteAsync(kernel);
+```
+
+This will output:
+
+```
+Sure, here are 4 cities in NJ, USA:
+
+1. Newark
+2. Jersey City
+3. Paterson
+4. Elizabeth
+```
+
+Note 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.
+
+(See the example in the `/app` directory for usage)
+
+### Including History
+
+The `ExecuteAsync` method takes a `historyBuilder` parameter which will receives a `ChatHistory` instance
+
+The unit tests show how this can be used:
+
+```csharp
+[Fact]
+public async void History_Builder_Test()
+{
+ var response = await new HistoryTmplPrompt("Spencer").ExecuteAsync(
+ new Kernel(),
+ // π Here we can build the chat history up before adding the new user prompt
+ historyBuilder: (h) =>
+ {
+ h.Add(new ChatMessageContent(AuthorRole.User, "User question"));
+ h.Add(new ChatMessageContent(AuthorRole.System, "System response"));
+ }
+ );
+
+ // Fake test where we are just going to return the history instead
+ Assert.Equal("User question\nSystem response", response);
+}
+```
+
+You can do the retrieval of the actual history *before* the block and then do the history building in the block.
+
+## Custom Base Class
+
+If you want to customize how the prompt is executed, you can specify a custom base class when assigning the attribute.
+
+Your base class must inherit from `PromptTemplateBase`:
+
+```csharp
+public abstract class CustomBase : PromptTemplateBase
+{
+ public override async Task ExecuteAsync(
+ Kernel kernel,
+ string? serviceId = null,
+ CancellationToken cancellation = default
+ )
+ {
+ return await Task.FromResult("response");
+ }
+}
+```
+
+And then you can specify this custom base class as a generic type:
+
+```csharp
+[PromptTemplate]
+public const string CapitolCustom = """
+ What is the capitol of {{$state}} {{$country}}?
+ Respond directly in a single line
+ When writing the state, always write it as the full name
+ Write your output in the format: The capitol of is: .
+ For example: The capitol of California is: Sacramento.
+ """;
+```
+
+This allows you to take full control of the execution of the prompt (e.g. add logging, telemetry, etc.).
+
+> π‘ Note: you should use a global `using` statement for the namespace of your custom base class.
+
+## Prompt Execution Settings
+
+The `PromptTemplate` attribute also allows specification of the prompt execution settings.
+
+The three parameters are:
+
+|Parameter|Details|Default|
+|--|--|--|
+|`MaxTokens`|The maximum number of tokens in the response|`500`|
+|`Temperature`|The temperature|`0.5`|
+|`TopP`|The TopP|`0`|
+
+For example:
+
+```csharp
+public static class Prompts
+{
+ [PromptTemplate(10, 0.1)]
+ public const string SampleTmpl1 = """
+ What is the capitol of {{$state}} {{$country}}
+ Respond directly on a single line.
+ """;
+}
+```
+
+(See the `PromptTmpl` class for details)
+
+## Using the Sample App
+
+To use the sample app, you'll need to set up user secrets:
+
+```shell
+dotnet user-secrets init
+dotnet user-secrets set "AzureOpenAIKey" "YOUR_AZURE_OPEN_AI_KEY"
+dotnet user-secrets set "AzureOpenAIEndpoint" "YOUR_AZURE_OPEN_AI_ENDPOINT"
+```
+
+If you are using OpenAI, feel free to fork this project and simply change the service type and configuration values.
+
+
+:::
+
+### About
+:::note
+
+Generate typed prompts for Semantic Kernel
+
+
+:::
+
+## How to use
+
+### Example (source csproj, source files)
+
+
+
+
+
+This is the CSharp Project that references **SKPromptGenerator**
+```xml showLineNumbers {12}
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+ true
+ $(BaseIntermediateOutputPath)\GX
+
+
+
+```
+
+
+
+
+
+ This is the use of **SKPromptGenerator** in *Program.cs*
+
+```csharp showLineNumbers
+// See https://aka.ms/new-console-template for more information
+Console.WriteLine("Hello, World!");
+var capitol = new DemoAI.WeatherPrompt("Bucuresti");
+
+```
+
+
+
+
+ This is the use of **SKPromptGenerator** in *WeatherCity.cs*
+
+```csharp showLineNumbers
+using SKPromptGenerator; // <-- Add namespace here
+
+namespace DemoAI
+{
+ public static partial class MyPrompts
+ {
+ [PromptTemplate] // <-- Remove namespace here
+ public const string Weather = """
+ What is the weather in the city {{$city}} ?
+ Respond directly in a single line
+ """;
+ }
+}
+```
+
+
+
+
+### Generated Files
+
+Those are taken from $(BaseIntermediateOutputPath)\GX
+
+
+
+
+
+```csharp showLineNumbers
+using System;
+using Microsoft.SemanticKernel.Connectors.OpenAI;
+using SKPromptGenerator;
+
+namespace DemoAI;
+
+///
+/// Generated prompt for `Weather`
+///
+public partial class WeatherPrompt(
+ string city
+) : PromptTemplateBase
+{
+ ///
+ /// The base prompt template string for `Weather`
+ ///
+ public override string Text => $$"""
+What is the weather in the city {{city}} ?
+Respond directly in a single line
+""";
+
+ ///
+ /// Settings for the prompt `Weather`:
+ /// MaxTokens = 500
+ /// Temperature = 0.5d
+ /// TopP = 0d
+ ///
+ public override OpenAIPromptExecutionSettings Settings => new OpenAIPromptExecutionSettings
+ {
+ MaxTokens = 500,
+ Temperature = 0.5d,
+ TopP = 0d,
+ };
+}
+```
+
+
+
+
+```csharp showLineNumbers
+using System;
+using System.Reflection;
+
+namespace SKPromptGenerator;
+
+///
+/// Attribute applied to `const string` class fields to generate a prompt class.
+/// Use this when specifying a custom base class for executing the prompt.
+///
+/// The maximum number of tokens; default is 500
+/// The temperature; default is 0.5
+/// The Top P parameter; default is 0
+/// The base type for the template inheriting from `PromptTemplateBase`
+[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
+public class PromptTemplateAttribute(
+ int maxTokens = 500,
+ double temperature = 0.5,
+ double topP = 0
+) : Attribute where T : PromptTemplateBase {
+ public int MaxTokens => maxTokens;
+ public double Temperature => temperature;
+ public double TopP => topP;
+}
+
+///
+/// Attribute applied to `const string` class fields to generate a prompt class.
+///
+/// The maximum number of tokens; default is 500
+/// The temperature; default is 0.5
+/// The Top P parameter; default is 0
+/// The base type for the template inheriting from `PromptTemplateBase`
+[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
+public class PromptTemplateAttribute(
+ int maxTokens = 500,
+ double temperature = 0.5,
+ double topP = 0
+) : PromptTemplateAttribute(maxTokens, temperature, topP) {
+
+}
+```
+
+
+
+
+```csharp showLineNumbers
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using Microsoft.SemanticKernel;
+using Microsoft.SemanticKernel.ChatCompletion;
+using Microsoft.SemanticKernel.Connectors.OpenAI;
+
+namespace SKPromptGenerator;
+
+///
+/// Abstract base class for executing the prompt. Override this class to
+/// provide custom execution of the prompt.
+///
+public abstract class PromptTemplateBase
+{
+ protected static readonly JsonSerializerOptions SerializerOptions = new() {
+ PropertyNameCaseInsensitive = true
+ };
+
+ ///
+ /// The execution settings for this prompt.
+ ///
+ public abstract OpenAIPromptExecutionSettings Settings \{ get; }
+
+ ///
+ /// The text of this prompt.
+ ///
+ public abstract string Text \{ get; }
+
+ ///
+ /// Executes the prompt using the default execution. Override this method
+ /// to provide custom execution logic (e.g. logging, telemetry, etc.)
+ ///
+ /// The Semantic Kernel instance.
+ /// An optional service ID to specify for execution.
+ /// An optional builder for the chat history.
+ /// An optional cancellation token.
+ /// A string with the results of execution.
+ public virtual async Task ExecuteAsync(
+ Kernel kernel,
+ #nullable enable
+ string? serviceId = null,
+ Action? historyBuilder = null,
+ #nullable disable
+ CancellationToken cancellation = default
+ )
+ {
+ var chat = kernel.GetRequiredService(serviceId);
+
+ var history = new ChatHistory();
+
+ if (historyBuilder != null)
+ {
+ historyBuilder(history);
+ }
+
+ history.AddUserMessage(Text);
+
+ var result = await chat.GetChatMessageContentAsync(history, Settings, kernel, cancellation);
+
+ return result.ToString();
+ }
+
+ ///
+ /// Executes the prompt and expects a JSON response that will be deserialized
+ /// to the type `T`.
+ ///
+ /// The Semantic Kernel instance.
+ /// An optional service ID to specify for execution.
+ /// An optional builder for the chat history.
+ /// An optional cancellation token.
+ /// The type `T` of the response object.
+ /// An instance of type `T` deserialized from the JSON response.
+ #nullable enable
+ public virtual async Task ExecuteAsync(
+ Kernel kernel,
+ #nullable enable
+ string? serviceId = null,
+ Action? historyBuilder = null,
+ #nullable disable
+ CancellationToken cancellation = default
+ ) {
+ var (result, _) = await ExecuteWithJsonAsync(kernel, serviceId, historyBuilder, cancellation);
+
+ return result;
+ }
+ #nullable disable
+
+ ///
+ /// Executes the prompt and expects a JSON response that will be deserialized
+ /// to the type `T`. This call includes the JSON result as part of the tuple.
+ /// This method call will perform trimming of JSON fences if present using
+ /// regular string find/replace.
+ ///
+ /// The Semantic Kernel instance.
+ /// An optional service ID to specify for execution.
+ /// An optional builder for the chat history.
+ /// An optional cancellation token.
+ /// The type `T` of the response object.
+ /// An instance of type `T` deserialized from the JSON response in a tuple with the full JSON response as well..
+ #nullable enable
+ public virtual async Task<(T? Result, string Json)> ExecuteWithJsonAsync(
+ Kernel kernel,
+ #nullable enable
+ string? serviceId = null,
+ Action? historyBuilder = null,
+ #nullable disable
+ CancellationToken cancellation = default
+ ) {
+ var json = await ExecuteAsync(kernel, serviceId, historyBuilder, cancellation);
+
+ json = json.Trim().Replace("```json", "").Replace("```", "");
+
+ return (JsonSerializer.Deserialize(json, SerializerOptions), json);
+ }
+ #nullable disable
+}
+```
+
+
+
+
+
+## Useful
+
+### Download Example (.NET C#)
+
+:::tip
+
+[Download Example project SKPromptGenerator ](/sources/SKPromptGenerator.zip)
+
+:::
+
+
+### Share SKPromptGenerator
+
+
+
+https://ignatandrei.github.io/RSCG_Examples/v2/docs/SKPromptGenerator
+
+aaa
+
+
diff --git a/v2/rscg_examples_site/docs/RSCG-Examples/index.md b/v2/rscg_examples_site/docs/RSCG-Examples/index.md
index fc97d4954..ecf5f3574 100644
--- a/v2/rscg_examples_site/docs/RSCG-Examples/index.md
+++ b/v2/rscg_examples_site/docs/RSCG-Examples/index.md
@@ -1,7 +1,7 @@
---
sidebar_position: 30
-title: 218 RSCG list by category
-description: 218 RSCG list by category
+title: 219 RSCG list by category
+description: 219 RSCG list by category
slug: /rscg-examples
---
@@ -22,6 +22,18 @@ import DocCardList from '@theme/DocCardList';
+## AI
+
+
+ Expand AI =>examples:1
+
+
+
+[SKPromptGenerator](/docs/SKPromptGenerator)
+
+
+
+
## AOP
@@ -1359,6 +1371,8 @@ flowchart LR;
Actor--> ActorSrcGen((ActorSrcGen))
+ AI--> SKPromptGenerator((SKPromptGenerator))
+
AOP--> WhatIAmDoing((WhatIAmDoing))
API--> SkinnyControllersCommon((SkinnyControllersCommon))
diff --git a/v2/rscg_examples_site/docs/about.md b/v2/rscg_examples_site/docs/about.md
index 625ce6b9c..05f3aa535 100644
--- a/v2/rscg_examples_site/docs/about.md
+++ b/v2/rscg_examples_site/docs/about.md
@@ -6,7 +6,7 @@ title: About
## Content
You will find here code examples
-of 218 Roslyn Source Code Generator (RSCG)
+of 219 Roslyn Source Code Generator (RSCG)
that can be useful for you. That means, you will write more elegant and concise code - even if the generators code is not always nice to look.
## Are those examples ready for production?
diff --git a/v2/rscg_examples_site/docs/indexRSCG.md b/v2/rscg_examples_site/docs/indexRSCG.md
index a9158fb3e..13ae32d44 100644
--- a/v2/rscg_examples_site/docs/indexRSCG.md
+++ b/v2/rscg_examples_site/docs/indexRSCG.md
@@ -7,9 +7,9 @@ slug: /List-of-RSCG
import useBaseUrl from '@docusaurus/useBaseUrl';
-## 218 RSCG with examples in descending chronological order
+## 219 RSCG with examples in descending chronological order
-This is the list of 218 ( 14 from Microsoft) RSCG with examples
+This is the list of 219 ( 14 from Microsoft) RSCG with examples
[See by category](/docs/rscg-examples) [See as json](/exports/RSCG.json) [See as Excel](/exports/RSCG.xlsx)
@@ -20,6 +20,7 @@ This is the list of 218 ( 14 from Microsoft) RSCG with examples
| No | Name | Date | Category |
| --------- | ----- | ---- | -------- |
+|219| [SKPromptGenerator by Charlie Chen ](/docs/SKPromptGenerator)|2025-08-07 => 07 August 2025 | [AI](/docs/Categories/AI) |
|218| [Nino by Jason Xu ](/docs/Nino)|2025-08-06 => 06 August 2025 | [Serializer](/docs/Categories/Serializer) |
|217| [EnumsEnhanced by VNCC ](/docs/EnumsEnhanced)|2025-08-05 => 05 August 2025 | [Enum](/docs/Categories/Enum) |
|216| [SG4MVC by Mark Flanagan ](/docs/SG4MVC)|2025-08-04 => 04 August 2025 | [MVC](/docs/Categories/MVC) |
diff --git a/v2/rscg_examples_site/src/components/HomepageFeatures/index.js b/v2/rscg_examples_site/src/components/HomepageFeatures/index.js
index 15c2fb118..a78eb3890 100644
--- a/v2/rscg_examples_site/src/components/HomepageFeatures/index.js
+++ b/v2/rscg_examples_site/src/components/HomepageFeatures/index.js
@@ -4,7 +4,7 @@ import styles from './styles.module.css';
const FeatureList = [
{
-title: '218 Examples (14 from MSFT)',
+title: '219 Examples (14 from MSFT)',
Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default,
description: (
<>
diff --git a/v2/rscg_examples_site/static/exports/RSCG.json b/v2/rscg_examples_site/static/exports/RSCG.json
index 6ee352e49..2e7be95a6 100644
--- a/v2/rscg_examples_site/static/exports/RSCG.json
+++ b/v2/rscg_examples_site/static/exports/RSCG.json
@@ -1745,6 +1745,14 @@
"Source": "https://github.com/JasonXuDeveloper/Nino",
"Category": "Serializer",
"AddedOn": "2025-08-06T00:00:00"
+ },
+ {
+ "Name": "SKPromptGenerator",
+ "Link": "https://ignatandrei.github.io/RSCG_Examples/v2/docs/SKPromptGenerator",
+ "NuGet": "https://www.nuget.org/packages/SKPromptGenerator/",
+ "Source": "https://github.com/CharlieDigital/SKPromptGenerator",
+ "Category": "AI",
+ "AddedOn": "2025-08-07T00:00:00"
}
]
}
\ No newline at end of file
diff --git a/v2/rscg_examples_site/static/exports/RSCG.xlsx b/v2/rscg_examples_site/static/exports/RSCG.xlsx
index 4457a3841..9ccc19e07 100644
Binary files a/v2/rscg_examples_site/static/exports/RSCG.xlsx and b/v2/rscg_examples_site/static/exports/RSCG.xlsx differ
diff --git a/v2/rscg_examples_site/static/sources/SKPromptGenerator.zip b/v2/rscg_examples_site/static/sources/SKPromptGenerator.zip
new file mode 100644
index 000000000..ebbbc6deb
Binary files /dev/null and b/v2/rscg_examples_site/static/sources/SKPromptGenerator.zip differ