Skip to content

feat: Injectable MaIN instead of static class#135

Open
srebrek wants to merge 4 commits into
mainfrom
feat/injectable-mainhub
Open

feat: Injectable MaIN instead of static class#135
srebrek wants to merge 4 commits into
mainfrom
feat/injectable-mainhub

Conversation

@srebrek
Copy link
Copy Markdown
Collaborator

@srebrek srebrek commented May 31, 2026

Summary

Introduces IMaINHub as an injectable, DI-friendly entry point for MaIN.NET, replacing the static AIHub facade as the primary API surface (User usage remains the same). Also removes internal dependency on the static AIHub from ChatContext and AgentContext by injecting ModelContext directly.

Changes

  • Add IMaINHub (Transient) injectable interface with Chat(), Agent(), Flow(), Model(), Mcp() factory methods.
  • Add MaINBootstrapper.Hub accessor for zero-config console scenarios.
  • Mark AIHub as [Obsolete] - retained for backward compatibility, will be removed in the future.
  • Inject ModelContext into ChatContext and AgentContext constructors - removes last internal usages of static AIHub.
  • Migrate integration tests off static AIHub to instance-based IMaINHub.
  • Add DI registration unit tests and a minimal ASP.NET Core E2E test (/car/color endpoint).

Pros

  • Enables standard ASP.NET Core DI usage - AddMaIN(), UseMaIN() and inject IMaINHub in controllers and services.
  • Parallel integration tests no longer share static state.
  • Dependencies are explicit in constructor signatures.
  • Zero breaking changes (except Agent/ChatContext.FromExisting but this is explained in Propositions) - existing AIHub code still compiles (with deprecation warning).

Usage

Web API:

builder.Services.AddMaIN(builder.Configuration);
app.MapGet("/ask", async (IMaINHub hub) =>
    await hub.Chat()
        .WithModel(...)
        .WithMessage("Hello")
        .CompleteAsync());

Console:

MaINBootstrapper.Initialize();
await MaINBootstrapper.Hub.Chat()
    .WithModel(...)
    .WithMessage("Hello")
    .CompleteAsync();

Propositions

  • MaINBootstrapper should be renamed to better match its role as the zero-config entry point for console aplications. Maybe MaIN (if it does not conflict with any namespaces)? In that case the usage in the console aplication scenario would look like:
MaIN.Initialize();
await MaIN.Hub.Chat()
    .WithModel(...)
    .WithMessage("Hello")
    .CompleteAsync();
  • Agent/ChatContext.FromExisting() is quite useless. The instance-based hub.Agent().FromExisting(agentId) covers all real use cases so the static version should be removed. Current changes are already breaking as the user facing method gets a new required parameter.
  • If the changes are approved I can migrate examples and frontend to use the new methods.

srebrek added 4 commits May 31, 2026 18:15
- Introduce IMaINHub (Scoped) as the primary API surface for web APIs and testable code.
- AIHub static facade retained as [Obsolete] for backward compatibility.
- Add MaINBootstrapper.Hub accessor for zero-config CLI usage.
- Migrates integration tests off AIHub static state.

Web API:
```cs
builder.Services.AddMaIN(builder.Configuration);
app.MapGet("/ask", async (IMaINHub hub) =>
    await hub.Chat()
        .WithModel(...)
        .WithMessage("Hello")
        .CompleteAsync());
```

Console:
```cs
MaINBootstrapper.Initialize();
await MaINBootstrapper.Hub.Chat()
    .WithModel(...)
    .WithMessage("Hello")
    .CompleteAsync();
```
@srebrek srebrek marked this pull request as ready for review May 31, 2026 18:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant