KamiYomu.ActionAgents.Core
0.0.1-alpha1
Prefix Reserved
dotnet add package KamiYomu.ActionAgents.Core --version 0.0.1-alpha1
NuGet\Install-Package KamiYomu.ActionAgents.Core -Version 0.0.1-alpha1
<PackageReference Include="KamiYomu.ActionAgents.Core" Version="0.0.1-alpha1" />
<PackageVersion Include="KamiYomu.ActionAgents.Core" Version="0.0.1-alpha1" />
<PackageReference Include="KamiYomu.ActionAgents.Core" />
paket add KamiYomu.ActionAgents.Core --version 0.0.1-alpha1
#r "nuget: KamiYomu.ActionAgents.Core, 0.0.1-alpha1"
#:package KamiYomu.ActionAgents.Core@0.0.1-alpha1
#addin nuget:?package=KamiYomu.ActionAgents.Core&version=0.0.1-alpha1&prerelease
#tool nuget:?package=KamiYomu.ActionAgents.Core&version=0.0.1-alpha1&prerelease
KamiYomu.ActionAgents.Core
A robust, event-driven action system for KamiYomu that enables extensible automation through triggered actions at key application moments.
Overview
Actions are discrete operations triggered by KamiYomu at significant moments during application execution. They enable you to:
- ✅ Automate tasks in response to system events
- ✅ Create extensible workflows without modifying core code
- ✅ Chain multiple actions together for complex automation
- ✅ Respond to manga and chapter lifecycle events
- ✅ Build custom integrations and notifications
Event Triggers
Actions can be triggered from various sources throughout the KamiYomu lifecycle:
| Trigger | Description |
|---|---|
| Manual | User-initiated action execution |
| Chained | Triggered by the completion of another action |
| Manga Download | When a manga series is successfully downloaded |
| Chapter Discovery | When new chapters are discovered for a series |
| Chapter Download | When a chapter is successfully downloaded |
| Chapter Page Read | When a user reads a chapter page |
| None | Unspecified or unknown trigger (fallback) |
Architecture
The KamiYomu.ActionAgents.Core library provides a lightweight, extensible framework for:
- ✅ Defining custom actions that respond to application events
- ✅ Managing action execution and lifecycle
- ✅ Creating complex automation pipelines
- ✅ Decoupling business logic from event handling
Core Interfaces
IActionAgent: The main interface your action must implementAbstractActionAgent: Base class with common functionality (logging, options, versioning)ActionAgentContext: Provides access to manga, chapter, and trigger source information
Creating Your First Action Agent
Step 1: Create the Project
Create a new class library targeting .NET 8.0:
dotnet new classlib -n [DeveloperName].ActionAgents.[ProductName] -f net8.0
cd [DeveloperName].ActionAgents.[ProductName]
Step 2: Add the Core Package
Install the KamiYomu.ActionAgents.Core NuGet package:
dotnet add package KamiYomu.ActionAgents.Core
Step 3: Create Your Action Agent
Create a new file (e.g., MyFirstActionAgent.cs) with a class implementing IActionAgent:
using KamiYomu.ActionAgents.Core;
using KamiYomu.ActionAgents.Core.Contexts;
using Microsoft.Extensions.Logging;
namespace YourName.ActionAgents.MyAction;
public class MyFirstActionAgent : AbstractActionAgent, IActionAgent
{
public MyFirstActionAgent(IDictionary<string, object> options) : base(options)
{
}
public async Task ExecuteAsync(
ActionAgentContext context,
IDictionary<string, object> options,
CancellationToken cancellationToken)
{
// Receive context information
var mangaTitle = context.Manga?.Title ?? "Unknown Manga";
var chapterNumber = context.Chapter?.Number ?? "Unknown Chapter";
var triggerSource = context.TriggerContext?.Source.ToString() ?? "Unknown";
Logger?.LogInformation($"Action triggered for {mangaTitle}, Chapter {chapterNumber}");
Logger?.LogInformation($"Triggered by: {triggerSource}");
// Perform your action here
await Task.Delay(100, cancellationToken);
Logger?.LogInformation("Action completed successfully!");
}
}
Step 4: Configure Package Metadata
Update your .csproj file to make the package discoverable by KamiYomu:
<PropertyGroup>
<PackageTags>kamiyomu;kamiyomu-action-agents;actions;MyAction;</PackageTags>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
</PropertyGroup>
Step 5: Build and Test
dotnet build
Working with Action Context
The ActionAgentContext provides access to relevant information when your action is triggered:
Manga Context
var mangaTitle = context.Manga?.Title;
var mangaUrl = context.Manga?.Url;
var mangaDescription = context.Manga?.Description;
Chapter Context
var chapterNumber = context.Chapter?.Number;
var chapterUrl = context.Chapter?.URL;
var chapterReleaseDateUtc = context.Chapter?.ReleaseDateUtc;
Trigger Context
var triggerSource = context.TriggerContext?.Source; // See Action Triggers table above
var triggeredAtUtc = context.TriggerContext?.TriggeredAtUtc;
Packaging and Publishing Your Action
Building a Release Package
dotnet pack -c Release
This generates a .nupkg file in the bin/Release/ directory.
Publishing Options
Choose one of the following distribution methods:
1. NuGet.org (Recommended for public actions)
dotnet nuget push bin/Release/YourName.ActionAgents.MyAction.*.nupkg \
--api-key YOUR_NUGET_API_KEY \
--source https://api.nuget.org/v3/index.json
2. GitHub Packages (Good for organization-specific actions)
dotnet nuget push bin/Release/YourName.ActionAgents.MyAction.*.nupkg \
--api-key YOUR_GITHUB_TOKEN \
--source https://nuget.pkg.github.com/YourOrg/index.json
3. Azure Artifacts (Enterprise deployments)
- Configure your credentials in Visual Studio or NuGet.config
- Push using the standard NuGet push command with your feed URL
4. Local Folder (Testing without a feed)
- Place the
.nupkgfile directly in KamiYomu's agent folder - Useful for rapid development and testing
Configuration for Automatic Package Generation
Add this to your .csproj to automatically generate a NuGet package on Debug builds:
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
</PropertyGroup>
Debugging Your Action Agent
Local Debugging
Generate Debug Symbols
- Build your project in Debug mode:
dotnet build - This creates
.pdbfiles alongside your DLL
- Build your project in Debug mode:
Place Symbols in KamiYomu
- Copy the
.pdbfile to KamiYomu's agent folder:C:\Users\[YourUsername]\AppData\Local\KamiYomu\agents\[DeveloperName].ActionAgents.[ProductName]\lib\net8.0\
- Copy the
Enable Debugging in KamiYomu.Web
- Attach to the running KamiYomu process using Visual Studio
- Set breakpoints in your action code
- KamiYomu will pause execution at your breakpoints with full source visibility
Logging Best Practices
public async Task ExecuteAsync(
ActionAgentContext context,
IDictionary<string, object> options,
CancellationToken cancellationToken)
{
try
{
Logger?.LogInformation("Starting action execution");
Logger?.LogDebug($"Manga: {context.Manga?.Title}");
// Your action logic here
Logger?.LogInformation("Action completed successfully");
}
catch (Exception ex)
{
Logger?.LogError(ex, "Action execution failed");
throw;
}
}
Common Implementation Patterns
Common Implementation Patterns
Pattern 1: Sending Notifications
public class NotificationActionAgent : AbstractActionAgent, IActionAgent
{
public async Task ExecuteAsync(
ActionAgentContext context,
IDictionary<string, object> options,
CancellationToken cancellationToken)
{
var message = $"Chapter {context.Chapter?.Number} of {context.Manga?.Title} " +
$"was downloaded at {context.TriggerContext?.TriggeredAtUtc:G}";
// Send notification (e.g., via webhook, email, Discord, etc.)
await SendNotificationAsync(message, cancellationToken);
}
private async Task SendNotificationAsync(string message, CancellationToken cancellationToken)
{
// Implementation here
await Task.CompletedTask;
}
}
Pattern 2: External API Integration
public class WebhookActionAgent : AbstractActionAgent, IActionAgent
{
private readonly HttpClient _httpClient;
public WebhookActionAgent(IDictionary<string, object> options) : base(options)
{
_httpClient = new HttpClient();
}
public async Task ExecuteAsync(
ActionAgentContext context,
IDictionary<string, object> options,
CancellationToken cancellationToken)
{
var payload = new
{
manga = context.Manga?.Title,
chapter = context.Chapter?.Number,
trigger = context.TriggerContext?.Source,
timestamp = context.TriggerContext?.TriggeredAtUtc
};
var content = new StringContent(
JsonSerializer.Serialize(payload),
Encoding.UTF8,
"application/json");
try
{
var response = await _httpClient.PostAsync(
"https://your-webhook-url.com/manga-action",
content,
cancellationToken);
if (response.IsSuccessStatusCode)
{
Logger?.LogInformation("Webhook sent successfully");
}
}
catch (Exception ex)
{
Logger?.LogError(ex, "Failed to send webhook");
throw;
}
}
}
Pattern 3: Conditional Logic Based on Trigger Source
public class ConditionalActionAgent : AbstractActionAgent, IActionAgent
{
public async Task ExecuteAsync(
ActionAgentContext context,
IDictionary<string, object> options,
CancellationToken cancellationToken)
{
var triggerSource = context.TriggerContext?.Source;
switch (triggerSource)
{
case ActionTriggerSource.Manual:
await HandleManualTriggerAsync(context, cancellationToken);
break;
case ActionTriggerSource.ChapterDownloader:
await HandleChapterDownloadAsync(context, cancellationToken);
break;
case ActionTriggerSource.MangaDownloader:
await HandleMangaDownloadAsync(context, cancellationToken);
break;
default:
Logger?.LogWarning($"Unhandled trigger source: {triggerSource}");
break;
}
}
private async Task HandleManualTriggerAsync(ActionAgentContext context, CancellationToken ct)
{
Logger?.LogInformation("User manually triggered this action");
await Task.CompletedTask;
}
private async Task HandleChapterDownloadAsync(ActionAgentContext context, CancellationToken ct)
{
Logger?.LogInformation($"Chapter downloaded: {context.Chapter?.Number}");
await Task.CompletedTask;
}
private async Task HandleMangaDownloadAsync(ActionAgentContext context, CancellationToken ct)
{
Logger?.LogInformation($"Manga series downloaded: {context.Manga?.Title}");
await Task.CompletedTask;
}
}
Quick Reference Commands
Development Workflow
# Create new action agent project
dotnet new classlib -n [DeveloperName].ActionAgents.[ProductName] -f net8.0
cd [DeveloperName].ActionAgents.[ProductName]
# Add the core library
dotnet add package KamiYomu.ActionAgents.Core
# Create test project
cd ..
dotnet new xunit -n [DeveloperName].ActionAgents.[ProductName].Tests -f net8.0
cd [DeveloperName].ActionAgents.[ProductName].Tests
dotnet add package KamiYomu.ActionAgents.Core
dotnet add package Moq
dotnet add reference ../[DeveloperName].ActionAgents.[ProductName]/YourName.ActionAgents.MyAction.csproj
Building and Testing
# Build the project
dotnet build
# Run unit tests
dotnet test
# Build release package
dotnet pack -c Release
# View package contents
dotnet nuget locals all --list
Publishing
# Publish to NuGet.org
dotnet nuget push bin/Release/YourName.ActionAgents.MyAction.*.nupkg \
--api-key YOUR_API_KEY \
--source https://api.nuget.org/v3/index.json
# Publish to GitHub Packages
dotnet nuget push bin/Release/YourName.ActionAgents.MyAction.*.nupkg \
--api-key YOUR_GITHUB_TOKEN \
--source https://nuget.pkg.github.com/YourOrganization/index.json
Troubleshooting
My action isn't being discovered by KamiYomu.Web
Checklist:
- ✅ Package name follows the pattern:
*.ActionAgents.* - ✅
PackageTagsin.csprojinclude bothkamiyomuandkamiyomu-action-agents - ✅ Your class implements
IActionAgentinterface - ✅ The class has a public constructor accepting
IDictionary<string, object> options - ✅ Package is installed in KamiYomu's agent folder
- ✅ All dependencies are included in the package
Debug Steps:
# Verify package contents
unzip -l bin/Release/YourName.ActionAgents.MyAction.*.nupkg
# Check that your class is public and accessible
dotnet build --configuration Release --verbosity diagnostic
Execution fails with "Type not found" error
- ✅ Ensure all NuGet dependencies are listed in your
.csproj - ✅ Verify .NET 8.0 target framework matches KamiYomu's runtime
- ✅ Check that custom types are public and properly namespaced
Logging not appearing in KamiYomu
- ✅ Verify you're calling
Logger?.LogInformation()(with null-coalescing) - ✅ Ensure logger is passed in options with key
"KamiYomuILogger" - ✅ Check KamiYomu's logging configuration level (may filter out Debug messages)
Tests are failing
- ✅ Ensure test project also targets
net8.0 - ✅ Mock dependencies properly (e.g.,
ILogger, HTTP clients) - ✅ Use the provided
ActionAgentContextBuilderfor building test contexts - ✅ Handle
CancellationTokenproperly in async tests
Action takes too long to execute
- ✅ Implement proper async/await patterns
- ✅ Avoid blocking operations (use
async Taskinstead ofTask.Run()) - ✅ Implement cancellation support via
CancellationToken - ✅ Set reasonable timeout values for external calls
// Good: Proper async pattern
public async Task ExecuteAsync(
ActionAgentContext context,
IDictionary<string, object> options,
CancellationToken cancellationToken)
{
using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
cts.CancelAfter(TimeSpan.FromSeconds(30));
try
{
await SomeLongOperationAsync(cts.Token);
}
catch (OperationCanceledException)
{
Logger?.LogWarning("Action execution was cancelled");
}
}
// Avoid: Blocking patterns
// ❌ Task.Run(() => { /* blocking code */ }).Wait();
// ❌ Task.Delay(1000).Wait();
API Reference
ActionAgentContext Properties
| Property | Type | Description |
|---|---|---|
Manga |
MangaContext |
Information about the manga being processed |
Chapter |
ChapterContext |
Information about the chapter being processed |
TriggerContext |
ActionTriggerContext |
Information about what triggered this action |
MangaContext Properties
| Property | Type | Description |
|---|---|---|
Title |
string |
The manga series title |
URL |
string |
The source URL of the manga |
Description |
string |
Manga description or synopsis |
ChapterContext Properties
| Property | Type | Description |
|---|---|---|
Number |
string |
Chapter number or identifier |
URL |
string |
The URL to the chapter |
ReleaseDateUtc |
DateTime? |
When the chapter was released (UTC) |
ActionTriggerContext Properties
| Property | Type | Description |
|---|---|---|
Source |
ActionTriggerSource |
What triggered this action (see table above) |
TriggeredAtUtc |
DateTime |
When the action was triggered (UTC) |
Resources
Official Documentation
- Core Library Repository: https://github.com/KamiYomu/KamiYomu.ActionAgents.Core
- Main KamiYomu Project: https://github.com/KamiYomu/KamiYomu
Community
Join the conversation and be part of the KamiYomu community:
| Action | Link |
|---|---|
| Following | |
| Discord | |
| Sponsor | |
| Report | |
| Contribute |
Best Practices
- Follow SOLID principles in your action design
- Keep actions focused and single-responsibility
- Document all configuration options
- Add comprehensive error logging
- Write unit tests for your actions
- Use semantic versioning for your package
License
This project is licensed under the MIT License for the library code.
See the LICENSE file in the repository for full terms.
Copyright
© KamiYomu. Licensed under AGPL-3.0 for the KamiYomu project itself.
The KamiYomu.ActionAgents.Core library is provided under the MIT License to enable community contributions and third-party action development.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.Extensions.Logging (>= 10.0.11)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.0.1-alpha1 | 77 | 8/30/2026 |