Skip to content

Instantly share code, notes, and snippets.

@gistlyn
Last active September 9, 2026 11:03
Show Gist options
  • Select an option

  • Save gistlyn/c132ee0025f1af60c85431416c6ef922 to your computer and use it in GitHub Desktop.

Select an option

Save gistlyn/c132ee0025f1af60c85431416c6ef922 to your computer and use it in GitHub Desktop.
chat
dotnet add package ServiceStack.AI.Chat
using ServiceStack;
using ServiceStack.AI;
[assembly: HostingStartup(typeof(MyApp.ConfigureAiChat))]
namespace MyApp;
/// <summary>
/// AI Chat using this host's ASP.NET Identity users
/// </summary>
public class ConfigureAiChat : IHostingStartup
{
public void Configure(IWebHostBuilder builder) => builder
.ConfigureServices((context, services) => {
services.AddPlugin(new ChatFeature {
// Require authentication to access /chat
RequireAuth = true,
// RequiredRole = "Admin",
#if DEBUG
Tools =
{
// WARNING: Expands what AI Models can do by letting them execute
// code on the server and read/write files in allowed directories.
// Only enable for trusted users on trusted environments.
EnableCodeExecution = true,
EnableFilesystemTools = true,
},
// Share your best Projects, Threads or AI Media with everyone
// Publish = { Enabled = true },
#endif
// Expose APIs with these tags to API & MCP Tools
// ApiTools = {
// IncludeTags = ["todos"]
// },
// Add this App's own tools to the built-in extensions
// Expose these tools to external AI Agents over MCP at /chat/mcp
Mcp = {
// allow Agents to call any tool in the above groups without approval
// RejectToolsRequiringApproval = false,
},
Setup = (ctx => {
// Advanced setup
}),
});
services.ConfigurePlugin<MetadataFeature>(feature => {
feature.AddPluginLink("/chat", "AI Chat");
});
// Enable https://servicestack.net/pdf
services.AddPlugin(new PdfFeature {
PdfCodeGen = new() {
Namespace = "MyApp.ServiceModel.Pdf",
OutputPath = System.IO.Path.Combine(context.HostingEnvironment.ContentRootPath, "../MyApp.ServiceModel/Pdf"),
}
});
})
.ConfigureAppHost(afterAppHostInit:appHost => {
var log = appHost.GetApplicationServices().GetRequiredService<ILogger<ConfigureAiChat>>();
log.LogInformation("AI Chat configured");
// Keep typed PDF models in sync with published templates on each debug restart.
// Templates you've since edited the model of are left alone, as are any named in Exclude.
StartupTasks.Register("pdf", () => appHost.GetPlugin<PdfFeature>().GeneratePdfs());
});
}
using ServiceStack;
using ServiceStack.Data;
using ServiceStack.OrmLite;
using ServiceStack.Configuration;
[assembly: HostingStartup(typeof(MyApp.ConfigureApiKeys))]
namespace MyApp;
public class ConfigureApiKeys : IHostingStartup
{
public void Configure(IWebHostBuilder builder) => builder
.ConfigureServices(services =>
{
services.AddPlugin(new ApiKeysFeature
{
// Optional: Available Scopes Admin Users can assign to any API Key
// Features = [
// "Paid",
// "Tracking",
// ],
// Optional: Available Features Admin Users can assign to any API Key
// Scopes = [
// "todo:read",
// "todo:write",
// ],
// Optional: Limit available Scopes Users can assign to their own API Keys
// UserScopes = [
// "todo:read",
// ],
// Optional: Limit available Features Users can assign to their own API Keys
// UserFeatures = [
// "Tracking",
// ],
});
})
.ConfigureAppHost(appHost =>
{
using var db = appHost.Resolve<IDbConnectionFactory>().Open();
var feature = appHost.GetPlugin<ApiKeysFeature>();
feature.InitSchema(db);
// Optional: Create API Key for specified Users on Startup
if (feature.ApiKeyCount(db) == 0 && db.TableExists(IdentityUsers.TableName))
{
var createApiKeysFor = new [] { "admin@email.com", "manager@email.com" };
var users = IdentityUsers.GetByUserNames(db, createApiKeysFor);
foreach (var user in users)
{
List<string> scopes = user.UserName == "admin@email.com"
? [RoleNames.Admin]
: [];
feature.Insert(db,
new() { Name = "Seed API Key", UserId = user.Id, UserName = user.UserName, Scopes = scopes });
}
}
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment