MentorAgent Docs
Menu

ReferencePackages: Novior.MentorAgent, Novior.MentorAgent.Abstractions, Novior.MentorAgent.Blazor, Novior.MentorAgent.Declarative, Novior.MentorAgent.Server

Changelog

Every MentorAgent version published on NuGet, newest first: its date, what it added, changed, removed and fixed, and the issues known at the time.

View as Markdown
On this page

This page lists every MentorAgent version published on NuGet, newest first. The five packages, Novior.MentorAgent, Novior.MentorAgent.Abstractions, Novior.MentorAgent.Blazor, Novior.MentorAgent.Declarative and Novior.MentorAgent.Server, are released together and share one version number. For the current version, what to do when you upgrade and the defects still open, see What's new.

Up to 1.0.0-rc.15 the packages were published as MentorAgent, MentorAgent.Abstractions, MentorAgent.Blazor, MentorAgent.Declarative and MentorAgent.Server. From 1.0.0 their IDs start with Novior.. The entries of each version use the names of their time. Move to the Novior.MentorAgent packages explains the change.

The entries are those of the library's CHANGELOG.md, in the same order within each section. Since 1.0.0-rc.13 every package contains CHANGELOG.md, and its release notes on NuGet are the section of that version.

Version numbers follow Semantic Versioning 2.0.0: see Versioning and support. The changelog follows the Keep a Changelog 1.1.0 format. Under each version, the changes are grouped as Added, Changed, Deprecated, Removed, Fixed and Security. Known issues lists the defects still open in that version. An entry that concerns one package only starts with the name of that package.

BUG-nnn identifiers are stable references to the maintainers' defect log. The tag next to one, from S1 to S4, is its severity:

  • S1: data loss, a security hole or a crash.
  • S2: a documented feature that does not work, or documentation that leads to a broken result.
  • S3: wrong behavior in an edge case, or documentation that contradicts the code.
  • S4: cosmetic.

The date under each version is the day it was published on NuGet, in UTC. The date in CHANGELOG.md can differ by one day.

MentorAgent succeeds the BlazorMentor (external site) package, published from 0.1.0-preview.1 to 0.5.0-preview and now deprecated on NuGet in favor of MentorAgent. This page does not cover it: 1.0.0-preview is the first version under the MentorAgent name.

Published on NuGet on 13 October 2026 (UTC): Novior.MentorAgent 1.0.0 (external site).

  • Breaking — all packages: the packages are now Novior.MentorAgent, Novior.MentorAgent.Abstractions, Novior.MentorAgent.Blazor, Novior.MentorAgent.Declarative and Novior.MentorAgent.Server. The MentorAgent.* IDs end with 1.0.0-rc.15. The namespaces follow (using Novior.MentorAgent.Extensions;), the widget's static files are served from _content/Novior.MentorAgent.Abstractions/, and the log categories start with Novior.MentorAgent, so a "MentorAgent" filter under Logging:LogLevel no longer matches. The five packages depend on each other at their exact version. These do not change: the types and extension methods (AddMentorAgent, MentorOptions and the others), the routes, the names of the telemetry source, meter and metrics, the format of session snapshots, the MentorAgentMcp CORS policy, MentorAgent.css, MentorAgent.js and window.MentorAgent.
  • Novior.MentorAgent: four warnings outside the tool gate still carried a whole exception, whose text comes from the host's code: a UI action that threw, with a ChatClient or a prebuilt Agent, and an OnToolResult or a McpCallerPrincipal that threw on the MCP server. As in the gate, they now name the type of the exception, and the whole exception is logged at Debug (BUG-152, S3).
  • Breaking — Novior.MentorAgent.Server: AddMentorAgentMcp() or AddMentorAgentA2A() registered nothing and said nothing in two cases: called before AddMentorAgent(), or with McpServerEnabled or A2AServerEnabled turned on after AddMentorAgent() had read them, with a Configure or PostConfigure of MentorOptions. The map call failed later, in the second case naming a call the host had made. The host now stops at startup with the reason and the fix. A host that ran without the server because of it no longer starts (BUG-153, S3).
  • Novior.MentorAgent: the README and the 1.0.0-rc.15 notes said that the warning about writes that run without confirmation comes at startup. It comes the first time the actions are read: at startup only with WarmUpAtStartup or MapMentorAgentA2A(), otherwise with the first conversation or the first MCP or tour request. With [Description] alone it also names the methods that only read, until IsReadOnlyAction or [MentorAction(ReadOnly = true)] declares them. The README now says both (BUG-154, S3).
  • Novior.MentorAgent.Server: the README's minimal SignalR client called Stop, the confirmations and the session save and restore without the hub's credentials. With cookies from another origin, or a bearer token, those calls were anonymous and did nothing. It now sends them, like the complete components. The README also no longer says that the MCP and A2A servers are built into MentorAgent (BUG-155, S3).
  • Novior.MentorAgent: the READMEs, the XML documentation of AddMentorAgent() and the startup warning for a callback that throws listed AppDescription and AgentCard among the options read at registration. Only AppName is read there, as the name of the MCP server. The A2A card is built from the real options when MapMentorAgentA2A() runs (BUG-156, S4).
  • Novior.MentorAgent: the README's MAUI step 3, pasted into the MAUI Blazor Hybrid template, did not compile. It lacked using System.Reflection; and using Microsoft.Extensions.Configuration;, and AddUserSecrets needs Microsoft.Extensions.Configuration.UserSecrets, which neither the template nor MentorAgent brings. The step now names both and the package, and says that AddUserSecrets needs the project's UserSecretsId and finds the secrets only on the development machine (BUG-157, S3).
  • Novior.MentorAgent.Abstractions: its README said that the core package depends on ModelContextProtocol.AspNetCore. Since 1.0.0-rc.15 that transport is in the Server package, and the core references ModelContextProtocol (BUG-158, S3).

Published on NuGet on 7 October 2026 (UTC): MentorAgent 1.0.0-rc.15 (external site).

  • MentorAgent.Server: AddMentorAgentMcp() and AddMentorAgentA2A() register the MCP server and the A2A agent. Each one registers only when its option is on, McpServerEnabled or A2AServerEnabled, as AddMentorAgent did up to 1.0.0-rc.14. AddMentorAgentServer() calls both, so a host that calls it changes nothing. Without them, MapMentorAgentMcp() and MapMentorAgentA2A() stop the host at startup, with an error that names the method to add.
  • MentorAgent: a RAG source can see who is asking, from where and after what. MentorAgent now calls IMentorRagSource.SearchAsync(MentorRagRequest, CancellationToken). The request carries the message, RagResultCount, the last three turns of the conversation, the signed-in user (ClaimsPrincipal), and the name and data of the current page. The default implementation calls SearchAsync(query, maxResults), so every existing source compiles and works as before.
  • MentorAgent.Abstractions: MentorRagResult.Metadata holds key/value facts about a document, such as a date or a version. The model sees them under the document's title. They also travel with the citation chips: hub clients receive metadata in RagSourcesReady. It is an init property, so the constructor with four values does not change.
  • MentorAgent: IMentorRagSource.DefaultMinScore lets a source declare the relevance threshold for its own scale. It applies when the host has not set RagMinScore, in code or in configuration. A vector source that declares one, say 0.6, now gets its documents to the model with the default options. Before, the default of 2 discarded every cosine score. The warning about a wrong scale now says which threshold discarded everything: the option, the source's or the default.
  • MentorAgent: MentorOptions.ChatReducer replaces the reducer of the built-in in-memory history. MentorChatReducer, in the MentorAgent.Core namespace, is the new default, and you can give it to a history provider of your own. A ChatReducer that cannot apply logs a warning: next to a history provider you supply, or with UseServiceManagedHistory.
  • The five packages are licensed under the Apache License 2.0 from this version, with a NOTICE file next to LICENSE. Versions up to and including 1.0.0-rc.14 keep the MIT License.
  • Package metadata: the authors are the copyright holders named in NOTICE, and the project page is mentoragent.net.
  • Breaking — MentorAgent: the MCP server and the A2A agent moved to MentorAgent.Server, together with MapMentorAgentMcp() and MapMentorAgentA2A(), which stay in the MentorAgent.Extensions namespace. AddMentorAgent no longer registers them. The reason: their packages need Microsoft.AspNetCore.App, which does not exist on Android, iOS or Mac Catalyst. A MAUI app that referenced MentorAgent built only for Windows (NETSDK1082). Now the MAUI Blazor Hybrid template builds for net10.0-android unchanged, and it no longer needs a higher Microsoft.Extensions.Logging.Debug (NU1605). MentorAgent now references ModelContextProtocol 1.3.0 and A2A 1.0.0-preview2, for the MCP and A2A clients. MentorAgent.Server references ModelContextProtocol.AspNetCore 1.3.0 and A2A.AspNetCore 1.0.0-preview2 (BUG-119, S2).
    • Migration. A host that calls AddMentorAgentServer() changes nothing in its code. A Blazor Server host that serves MCP or A2A without the hub adds the MentorAgent.Server package, and calls builder.Services.AddMentorAgentMcp(), AddMentorAgentA2A() or both after AddMentorAgent(). Its using lines stay as they are. Code compiled against 1.0.0-rc.14 must be rebuilt, because the types changed assembly.
    • A host no longer receives the hosting packages through MentorAgent, so it references the ones it uses: Microsoft.Agents.AI.Hosting, Microsoft.Agents.AI.Hosting.A2A, Microsoft.Agents.AI.Hosting.AspNetCore, Microsoft.Agents.AI.Hosting.A2A.AspNetCore, Microsoft.Extensions.Hosting, Microsoft.Extensions.Logging.Console, and the other Microsoft.Extensions.Configuration.* and Logging.* packages that came with them.
  • MentorAgent: the READMEs now describe MCP and A2A in MentorAgent.Server, where the code is.
  • Breaking — MentorAgent: writes ask for confirmation by default, with RequireConfirmationForWrites, new and on by default. A [MentorAction] that declares neither ReadOnly = true nor RequiresConfirmation is treated as an action that changes data. It shows the confirmation banner like one declared RequiresConfirmation = true, in the Blocking flow and with HitlMode.Native alike. Since it needs confirmation, it is also withheld from the MCP server (tools/list) and from the A2A agent card. And it is no longer one of the actions without rules that tool filtering may send when a message matches nothing. With RequireActionForChangeRequests on, more actions can now be required as the first call, because only actions that ask for confirmation are ever required. Only [MentorAction] methods are covered: a method with [Description] alone asks for nothing and stays on /mcp, as before. Mark it [MentorAction] to get the default. See Roles, confirmation and governance.
    • Migration. Declare ReadOnly = true on the actions that only read, and RequiresConfirmation = false on the writes that must run without asking. Or set options.RequireConfirmationForWrites = false for the 1.0.0-rc.14 behavior. The first time MentorAgent reads your actions, a warning lists the writes that run without confirmation, in two lists: the [MentorAction] methods opted out, and the [Description] methods not declared read-only with IsReadOnlyAction.
  • Breaking — MentorAgent: the package brings no AI provider SDK any more (BUG-120, S2). It no longer references Azure.AI.OpenAI 2.9.0-beta.1, Azure.Identity and Microsoft.Extensions.AI.OpenAI 10.6.0, which the library never used. It references System.ClientModel 1.10.0, the version those packages brought, to read the HTTP status of a provider's ClientResultException. Your app now adds its provider at the version it chooses: see Model providers. For Azure OpenAI that is Azure.AI.OpenAI and Microsoft.Extensions.AI.OpenAI, for AsIChatClient(), plus Azure.Identity for DefaultAzureCredential.
    • With the Azure Responses API, keep OpenAI at 2.10, with Microsoft.Extensions.AI.OpenAI pinned to 10.6.0. With 2.11 or later, GetResponsesClient() from Azure.AI.OpenAI 2.9.0-beta.1 throws when it is called: MissingMethodException: Method not found: 'Void OpenAI.Responses.ResponsesClient..ctor(System.ClientModel.Primitives.ClientPipeline, OpenAI.OpenAIClientOptions)'.
    • Chat Completions needs no pin: with OpenAI 2.14 its client is built where the Responses one throws.
  • Breaking — MentorAgent: the built-in history keeps tool calls and their results (BUG-121, S2). Up to 1.0.0-rc.14 it was trimmed by MessageCountingChatReducer, which drops every message with a function call or result. From the next turn on, the model no longer saw the data a tool had read, and answered a follow-up by guessing or by calling the tool again. The default is now MentorChatReducer. It counts every message against MaxSessionMessages, tool calls and results included. It trims whole turns, oldest first, and never sends a result without the call that produced it. In a lab run of 84 turns, the turns answered correctly went from 85% to 95%, and tokens grew by about 9%. With the same MaxSessionMessages, a session holds fewer turns.
    • Migration. Nothing to change. For the 1.0.0-rc.14 behavior, set options.ChatReducer = new MessageCountingChatReducer(50), which is experimental (MEAI001).
  • Breaking — MentorAgent: the options are validated when the host starts (ValidateOnStart) (BUG-123, S4). An ASP.NET Core or worker host with an invalid configuration now stops at start, with the reason. Examples: no ChatClient or Agent, an empty ScanAssemblies, or both ChatHistoryProvider and ChatHistoryProviderFactory. Up to 1.0.0-rc.14 it started, listened and failed on the first request, although the READMEs said that it threw at startup. A MAUI app has no such start: it still gets the error the first time it uses MentorAgent.
    • Migration. A host that started with an invalid configuration fixes it.
  • Breaking — MentorAgent: a class listed in [TeamMember(Tools = ...)] is the toolbox of that member only (BUG-125, S3). Up to 1.0.0-rc.14 the scan also made its methods actions of the coordinator, published on /mcp and on the A2A card, because the class is registered in dependency injection. A [MentorSkill] class keeps its coordinator tools, because of its role as a skill. Member tools are now found by the same rules as every other action: public instance methods declared on the class itself, with [MentorAction] or a non-empty [Description]. A member no longer gets inherited or static methods, or a method with an empty [Description] (BUG-126, S3). See Level 3: teams.
    • Migration. When MentorAgent finds your actions, an Information line names each class taken from the coordinator, the members that list it and its methods (… is listed in the Tools of …). An action that the coordinator must offer too goes on a class not listed in Tools. A member tool inherited from a base class must be declared on the listed class.
  • Breaking — MentorAgent.Server: POST /mentor/approve answers 404 when no turn waits for the answer any more: it was answered already, the turn was stopped, or the connection that raised it has closed. Up to 1.0.0-rc.14 every call got 200, so a client could not tell an approval that ran from one that reached nothing.
    • Migration. A client that treats any answer other than 2xx as an error should treat 404 as "nothing left to answer", and close its dialog. The WebAssembly client of MentorAgent.Blazor already does. See Any front end.
  • Breaking — MentorAgent: IMentorStateService.OnApprovalResponse is no longer raised for an answer that found no turn waiting: after Stop, after the connection or the circuit closed, or a second time (BUG-129). Up to 1.0.0-rc.14 it was, in process and in the WebAssembly client. So a custom confirmation dialog that closed only on this event closed in those cases too. Now it stays open.
    • Migration. Close a custom dialog when its buttons are clicked and on OnBusyChanged(false), as the README's Custom HITL confirmation dialog example does. Keep OnApprovalResponse for an audit trail of the decisions that were carried out.
  • Breaking — MentorAgent: on the hub, on /mentor/chat and over A2A, MentorAgent takes the caller from the request: the user of the hub connection, or HttpContext.User (BUG-131). It asks the host's AuthenticationStateProvider only where no MentorAgent transport runs, such as a Blazor circuit. If your own provider added claims or roles to the user, they are no longer seen there.
    • Migration. Add them with an IClaimsTransformation. ASP.NET Core applies it to HttpContext.User, and so to the user of the hub connection too.
  • Breaking — MentorAgent: memory and RateLimitPerUser identify a signed-in user by NameIdentifier, as before. Otherwise they use sub, oid or the name, with the claim in the key (sub:…, name:…), like the owner checks (BUG-142). A user known by name alone in 1.0.0-rc.14, as with Windows authentication, gets a new key.
    • Migration. In your memory store, rename those users' keys from <name> to name:<name>.
  • MentorAgent: README: ReadOnly and IsReadOnlyAction say what readOnlyHint means on /mcp. Some MCP clients skip their own confirmation for such a tool, so a write declared read-only by mistake runs from them with nobody asked. The MentorAgent.Server README says the same in its MCP section.
  • MentorAgent: README: OnActionExecuting carries the text shown to the user, not the tool name. That text is the action's Description, or a label for a routing, a team or a hosted tool. OnActionCompleted carries the tool name, and OnActionFailed the tool name and the error. The MentorAgent.Server (ActionExecuting) and MentorAgent.Blazor READMEs say the same.
  • MentorAgent: README: a tool result is drawn as a card by its shape, not by its .NET type: an object with a non-empty string kind, or an array of them. Your own records with a kind property are drawn as cards too, and the README says how to avoid it.
  • MentorAgent: README: the banner of the five READMEs says that this is a release candidate for 1.0.0, not a public preview. The Extensibility table lists IMentorAgentSource, IMentorQueryEmbedding, ClassifierChatClient and SkillSources/SkillFilter. Its row on history providers points to ChatHistoryProviderFactory: ChatHistoryProvider is one instance shared by every user.
  • MentorAgent: the XML documentation of MentorOptions matches the code. RequiresApproval gets tool names: MCP tools without a prefix, never a remote agent. DashboardRole guards the metrics endpoint only. Routing follows RoutingStrategy. AgentCardUrl is a base URL (agent-card.json). There is no ITextSearch wrapper. RagSystemPromptTemplate is in English.
  • MentorAgent.Server: the A2A comments say that a task runs as the user of the request, and that RateLimitPerUser does not hold an anonymous caller across tasks.
  • Breaking — MentorAgent: the MENTOR001 build check (buildTransitive/MentorAgent.targets) and its MentorAgentSkipOpenAIVersionCheck switch (BUG-120). They stopped every build that resolved OpenAI 2.11 or later, including a project on the current Agent Framework that never calls GetResponsesClient().
  • MentorAgent: README: the Requirements table lists the package's real references. Its Blazor row no longer contradicts the server package: any ASP.NET Core app works with MentorAgent.Server. The MENTOR001 section is replaced by Provider package versions, which says which call fails and on which versions.
  • MentorAgent: BUG-122 (S3): the warm-up (WarmUpAtStartup) is now always registered, and decided on the real options when the host starts. It was registered only if the snapshot taken at registration asked for it, and that snapshot swallowed any exception from the AddMentorAgent callback. So a callback that failed before WarmUpAtStartup = true lost the warm-up without a word. Such an exception is now logged as a warning at start, naming the options decided at registration.
  • MentorAgent: the warm-up starts on ApplicationStarted, after a web host is listening, as documented. It started inside StartAsync, before the other hosted services.
  • MentorAgent: BUG-124 (S3): README, When the options are read and checked. The AddMentorAgent callback runs twice. EnableObservability, ObservabilitySourceName, McpServerEnabled, A2AServerEnabled, AppName, AppDescription and AgentCard are read at registration, so a Configure<MentorOptions> registered later does not reach them. The MentorAgent.Server README and the XML documentation of AddMentorAgent have the same note.
  • MentorAgent: BUG-125: a team member is told "These tools are read-only." only when all its tools are declared read-only (ReadOnly = true or IsReadOnlyAction) and none asks for confirmation. Every member was told so, whatever its tools did.
  • MentorAgent: BUG-127 (S4): README, Which methods become tools. Inherited and static methods are not found. A method with [Description] alone has no roles and no confirmation, so with tool filtering it can be sent when a message matches nothing. The MentorAgent.Server README says the same.
  • MentorAgent.Server: BUG-128 (S2): a confirmation outlived the connection that raised it. When the owner's hub connection closed, the hub forgot who had raised it, but the turn kept waiting. Anybody who knew the action id could approve it with POST /mentor/approve, with no owner left to check, and the action ran. Now the end of a connection, or of a Blazor Server circuit, cancels the turn running in it, with its confirmation.
  • MentorAgent: BUG-129 (S3): OnApprovalResponse is raised only when the answer reached the turn waiting for it. After Stop the request stayed pending, so a late Confirm raised OnApprovalResponse(…, true) for an action that never ran. It happened in process, and in the WebAssembly client, which raised the event before sending the answer. Now the request leaves the pending list with its wait, and the WebAssembly client raises the event once the server has accepted the answer.
  • MentorAgent.Server: BUG-130 (S3): the owner of a connection is recognized without a NameIdentifier claim. /mentor/approve, /mentor/cancel and /mentor/session read NameIdentifier alone, and so did the key that binds a session snapshot to its owner. With Windows authentication, or JwtBearer with MapInboundClaims = false, the owner was refused (403) its own confirmations, Stop and session. Now they read NameIdentifier, then sub, then oid, then the identity's name, as the MCP rate limit does. A name never matches another user's identifier. Snapshots saved by 1.0.0-rc.14 for a user with NameIdentifier still restore.
  • MentorAgent.Server: BUG-131 (S2): in a Blazor Web App, the hub, /mentor/chat and A2A know who is calling. MentorAgent read the user from the host's AuthenticationStateProvider. With AddRazorComponents() that is Blazor's provider, which throws outside a circuit, and the server's bridge, registered with TryAdd, lost to it. Every RequiredRoles action was refused to everyone, with an error logged on each call, and memory and RateLimitPerUser followed a connection instead of a person. A Blazor Server app serving A2A without the hub had no bridge at all. Now each transport records its caller, and MentorAgent reads it first. The host's registration stays as it is, in any order of AddRazorComponents() and AddMentorAgentServer(). When the server's own provider is registered, it also takes a circuit's user from Blazor (IHostEnvironmentAuthenticationStateProvider), as Blazor's own provider does.
  • MentorAgent: BUG-142 (S3): a signed-in user with only sub or oid, as with JwtBearer and MapInboundClaims = false, got a new identity for each session. So memory and RateLimitPerUser did not follow the person.
  • MentorAgent.Server: BUG-132 (S2): README, CORS and the JWT example under Authentication show the whole pipeline: UseCors, UseAuthentication, UseAuthorization, then Map…. A Program.cs that protected the hub without calling UseAuthentication() and UseAuthorization() itself got them from ASP.NET Core ahead of UseCors. The browser's preflight for /mentor-hub/negotiate was answered 401 without CORS headers, and a client on another origin never connected. The MentorAgent.Blazor README says the same under Stop and confirmations. See Secure the endpoints.
  • MentorAgent.Server: BUG-133 (S2): README, the complete React, Angular and Vue components send the hub's identity on approve, cancel and session: a getToken function, or cookies with credentials: 'include'. They show an error when the server refuses an answer or a Stop. They sent a bare fetch: with an authenticated hub the server answered 401, the dialog closed and the turn stayed waiting, with nothing on screen. The Angular and Vue components also take an absolute hub URL (MENTOR_HUB_CONFIG, useMentorHub(hubUrl, getToken)), and send approve and cancel to the hub's origin.
  • MentorAgent.Server: BUG-134 (S3): README, the three components free the UI when the connection drops (onreconnecting, onclose), and restore the saved conversation in onreconnected. The events table lists the three callbacks. A connection lost during a turn left the UI busy, even after the client reconnected: the new connection never sends BusyChanged(false) for that turn.
  • MentorAgent.Server: BUG-136 (S2): README, the complete React component shows the assistant's replies. It added an empty bubble for every reply, because it reset the streaming buffer before React ran the update that read it. The three components no longer add an empty bubble when a segment closes before a confirmation.
  • MentorAgent.Blazor: BUG-135 (S3): README, the client setup example has using MentorAgent.Abstractions.Models;. Without it, MentorLanguage and MentorTheme did not compile (CS0103).
  • MentorAgent: BUG-137 (S3): README and XML documentation. RequireConfirmation = false turns off the confirmations of your actions, of the MCP servers you connect and of RequiresApproval. It does not turn off the approvals that a hosted MCP server asks for (RequireApproval, AlwaysRequireApprovalTools). Both said that it disabled every confirmation dialog.
  • MentorAgent: BUG-138 (S3): README, voice input. Your server receives only the transcript, but some browsers, Chrome among them, send the audio to their maker's speech service. The README said that nothing left the page except the transcript. The MentorAgent.Blazor README says the same now.
  • MentorAgent: BUG-143 (S3): with HitlMode.Blocking, Confirm ran a RequiredRoles action for a user who had lost the role while the banner waited, because the roles were read only before the banner. They are read again after the answer, as with Native, in specialists and teams too.
  • MentorAgent: BUG-144 (S3): after Cancel on a specialist's confirmation, reached through route_to_specialist, the answer could report a problem that never happened. The coordinator got only the specialists' words, and a team with HandoffTo had just told it to carry out the action. The result of the delegation now starts with DECLINED BY THE USER, names the declined action and any that ran beside it, and carries the rule for a declined action. An approved team's result says that a declined confirmation is the user's decision.
  • MentorAgent: BUG-140 (S2): README, Blazor Web App. @rendermode="InteractiveServer" on <ChatWidget />, the simplest setup for every Auto app, needs Interactivity location: Per page/component. With Global it throws NotSupportedException once the layout runs in WebAssembly, and the WebAssembly template fails with HTTP 500 until its server adds AddInteractiveServerComponents() and AddInteractiveServerRenderMode(). The README also sent the CSS and JS links to an index.html that a Web App does not have: when prerendered, the widget writes them itself, otherwise they go in App.razor. The MentorAgent.Blazor README says the same. See Blazor WebAssembly and Auto.
  • MentorAgent.Blazor: BUG-139 (S2): README, the client project of a Blazor Web App registers no HttpClient, and without one the WebAssembly runtime did not start (CannotResolveService). The README said the template's was enough. The client examples now register one. The MentorAgent and MentorAgent.Server READMEs say the same.
  • MentorAgent.Blazor: BUG-145 (S2): on WebAssembly a relative HubUrl, including the default /mentor-hub, never reached the server. The .NET SignalR client read it as file:///mentor-hub, and the widget did not connect (TypeError: Failed to fetch). It is now resolved against the page's base address, as a browser does.
  • MentorAgent: BUG-146 (S2): a [MentorTeam] stopped discussing after its first runs in a session. Every run shared one group chat manager, whose count of iterations was never reset. Once MaxIterations was spent, the team ran with no member speaking and returned nothing. Each run now gets its own manager.
  • MentorAgent: BUG-147 (S2): a tool that threw showed the exception's text in the chat, even with OnException set. A failure after the action, in OnToolResult, the cards or a screen update, reported an action that had run as failed, so the model could run it again. Now only the tool's own exception is a failure. With OnException set, the chat shows the app's message, or a localized "The action could not be completed.", never the exception's text. The model still gets the app's message, or else the exception's. An OnToolResult that throws withholds the result, as on the MCP server. A Stop during the action is not logged as a failure. The widget no longer shows the text of a send that failed.
  • MentorAgent: BUG-148 (S3): the gate's warnings named the user and carried a tool's whole exception. They now name a fingerprint (caller#…, the same as the MCP audit line) and the exception's type. The whole exception is logged at Debug.
  • MentorAgent: BUG-149 (S3): with a Language other than English, the input box of a widget hosted on the server still read "Type a message...". MentorOptions.InputPlaceholder defaulted to that text and hid the translation. It is now string? with no default, as in MentorAgent.Blazor, and an unset placeholder uses the localized text. In English the default text is now "Write a message...".
  • MentorAgent.Abstractions: BUG-150 (S2): the widget's stylesheet loaded the Sora and JetBrains Mono fonts from Google Fonts. That is a request to a third party on every page with the widget, refused under default-src 'self' and missing offline. The two fonts now ship in the package, in wwwroot/fonts: variable WOFF2, Latin and Latin Extended, under the SIL Open Font License 1.1. The package is about 110 KB larger, and the stylesheet requests nothing from another origin. The avatar's size and the alignment of a table column moved from style attributes to the stylesheet, so with the default options the widget needs no style-src 'unsafe-inline'. Theme Dark or Minimal and PrimaryColor still write a <style> block, and MentorDashboard uses style attributes.
  • MentorAgent: BUG-151 (S3): the error for a missing model suggested new OllamaChatClient(...), a type that no package of the library brings, and AIProjectClient without its package. Each example now names its package, and Ollama goes through its OpenAI-compatible endpoint.
  • MentorAgent.Declarative: BUG-141 (S3): README, the install command lacked --prerelease, which dotnet add package needs while only prereleases exist. So did the two MentorAgent.Server commands in the MentorAgent README. The License sections point to the package's LICENSE.
  • MentorAgent: BUG-074 (S3): with MentorshipLevel.Proactive, the assistant can still offer next steps that the application does not have. On the Blazor Server sample it happened in 3 turns of 15 after the 1.0.0-rc.14 rule, and in 5 before. For example "add it to the cart", "the available deals", "plan a reorder". It stays open for 1.0.0 by the product owner's decision: the closing offers keep their wording.
  • MentorAgent: BUG-118 (S2) is closed for the hosts that turn on RequireActionForChangeRequests, added in 1.0.0-rc.14. Without it, the model can still describe an action it never performed: "Stock aggiornato" with no tool called, or "Ecco la pagina Prodotti" with no navigation. With it, a complete request that the classifier does not recognize runs as it would without the option.
  • The rest of BUG-106 is closed for the hosts that turn on RequireLookupForRecordQuestions, added in 1.0.0-rc.14. Without it, a catalog question can still be answered with an offer to look the value up.
  • MentorAgent: with HitlMode.Native, a confirmation closed by Stop is closed only in memory. A snapshot saved in that state and restored still carries the open request, which can make the next turn fail as in BUG-116.

Published on NuGet on 3 October 2026 (UTC): MentorAgent 1.0.0-rc.14 (external site).

  • MentorAgent: [MentorAction(ReadOnly = true)] and MentorOptions.IsReadOnlyAction declare the actions that only read. IsReadOnlyAction takes a tool name, for [Description] methods. MentorAgent takes the host's word for it: the MCP server publishes such an action with readOnlyHint. An action that needs confirmation is never read-only.
  • MentorAgent: MentorOptions.RequireLookupForRecordQuestions, off by default. It closes the rest of BUG-106 for the hosts that turn it on. A classifier model reads each message. When it says that the message asks for a value of the application's records, the first model call must call a declared read-only action that the tool filter selected for that message. The model can also hand the request to a specialist (ChatToolMode.RequireAny).
    • Cost. One classifier call on each turn whose selection holds a declared read. It uses ClassifierChatClient when set, within SafetyCheckTimeout. On the ApiServer sample, the median latency grew by about one second. It grew by two to three seconds where a read now happens that did not happen before.
    • Failures. A classifier that fails, or answers anything else, leaves the turn as it would be without the option.
    • Measured on the ApiServer sample, against the previous build. A product's price came from a read 19 times in 19, against 17 in 20. A stock level, 20 in 20 against 19 in 20. A product that does not exist was answered without an invented figure 10 times in 10, on both builds.
    • Requirements. EnableToolFiltering, an EmbeddingGenerator and declared reads. A startup warning says when the option has no effect.
  • MentorAgent: MentorOptions.RequireActionForChangeRequests, off by default (BUG-118). The classifier can say that a message asks to carry out one of the actions that need confirmation and that the tool filter selected for it. If the message also gives every input that action needs, the first model call must call one of those actions, or hand the request to a specialist or a team. So the confirmation banner comes before any sentence. When the message asks for a page, the first call must be navigate_to.
    • Incomplete requests are not forced. The classifier sees the required inputs of each action. A request is not forced, and the assistant may ask, when it leaves an input out ("Annulla l'ordine 1004" when cancel_order also needs a reason). The same holds when it only describes the record ("the last order"), gives a name where the input is an ID, or needs the current value ("add 5 units").
    • Only actions that show a banner are required: declared confirmation, with RequireConfirmation on. With HitlMode.Native, no AutoApprovalRules rule is consulted for the required call. An action is never required when its input schema cannot be shown faithfully: a $ref, a combination of schemas, or no parameter marked required.
    • Pages. A page request is matched against the application's [MentorPage] pages. A request from another agent is never required to navigate.
    • Cost. One classifier call per turn while the application has a page or the message selected such an action. With RequireLookupForRecordQuestions on as well, it is the same call.
    • Measured before release on Azure gpt-4.1, three repetitions per message. With the two actions that a stock or price request usually selects, the classifier was right 207 times in 207 on 69 development messages. It was right 60 times in 60 on 20 messages written after the last change. With all nine actions of the ApiServer sample that need confirmation, it was right 204 times in 207 and 58 in 60: the misses were complete requests left unforced. An incomplete request or a read question was never labelled as an action.
    • Measured live on the ApiServer sample (3 October), on the same build with the option off and on in turn. Asked "Imposta lo stock dell'iPad Air a 30" with the option off, the assistant said it was done without calling a tool 11 times in 25. With the option on, it showed the banner 25 times in 25, and 15 times in 15 on the final build. "Portami alla pagina prodotti" navigated 5 times in 10 with the option off, and 10 in 10 and 8 in 8 with it on. Requests missing a value were always asked about. Reads and greetings did not change.
    • Requirements. EnableToolFiltering and an EmbeddingGenerator. A startup warning says when the option has no effect, or covers page requests only.
  • Breaking — MentorAgent: MapMentorAgentMcp() no longer attaches the MentorAgentMcp CORS policy (BUG-108). MCP clients that are not browsers need none. For a browser-based client, call app.UseCors() and MapMentorAgentMcp(configure: e => e.RequireCors("MentorAgentMcp")). A host that replaced that policy, as the 1.0.0-rc.13 README suggested, needs the configure line too. A MentorAgentMcp policy that the host registers before AddMentorAgent is no longer replaced by the one that allows any origin. See MCP server.
  • Breaking — MentorAgent.Server: the body of /mentor/session is opaque: see Security. Snapshots that clients saved before 1.0.0-rc.14 are refused with 400, so save the conversation again. To restore after a restart, or on another instance, persist and share the Data Protection key ring.
  • MentorAgent: the classifier of RequireLookupForRecordQuestions runs at temperature 0, like the other classifiers: its wording was measured at that temperature. No difference was measured on the 1.0.0-rc.14 messages: 141 right in 141 at either temperature. RequireActionForChangeRequests adds its labels to the question only when that option is on. The turn that answers an approval left open by Stop (BUG-116) is never forced. On that turn the stopped action is declared for its answer, and calling it again could satisfy the required call.
  • MentorAgent: tool filtering: when no action clears ToolFilterMinScore, the three best-ranked actions that need no confirmation and no role are sent anyway, within ToolFilterMaxTools. An MCP tool qualifies only when its server marks it readOnlyHint. This costs about 80 input tokens per model call on such turns, greetings included. Give RequiresConfirmation to every action that changes data (BUG-106).
  • MentorAgent: the coordinator's prompt says to state record values only from a tool, the page data or the documents. The web search capability no longer mentions prices (BUG-106).
  • MentorAgent: RateLimitPerUser, OnToolResult and the top actions of the dashboard now cover MCP tools/call (BUG-107). MCP calls have their own allowance, separate from chat messages, counted per NameIdentifier, sub or oid claim. A caller with none of them is counted by remote address when IHttpContextAccessor is registered. Otherwise all such callers share one allowance. Each call writes one Information log line with a fingerprint of the caller.
  • MentorAgent: RefuseOutOfScope refusals now count in GuardrailBlockCount and in the mentoragent.guardrail_blocks counter. With RefuseOutOfScope and the safety check on, the scope check of hosted tools asks its own question on the turns where a hosted tool is about to be declared (BUG-105).
  • MentorAgent: compaction is not installed with UseServiceManagedHistory: it had nothing to compact. A reset of the conversation writes one Information log line.
  • MentorAgent.Abstractions: the widget's "New conversation" button is disabled from the moment a message is sent until its reply ends, and while a confirmation is pending. A confirmation banner still open when the turn ends, after Stop, is dismissed.
  • MentorAgent: A2A: a navigation, a UI action, a memory write or a skill no longer counts as grounding. So the request behind such a reply is sent once more, as for a reply that used no tool (BUG-106).
  • MentorAgent: tool filtering: a message that matches no action carries the actions selected for the previous message. Only one message back, never actions that were carried themselves, and never an action that needs confirmation alone. Before, the answer to the assistant's own question ("Sì, procedi", or the reason it asked for) arrived without the action that the question was about. A new or restored conversation carries nothing.
  • MentorAgent: MentorshipLevel.Proactive: the assistant may offer a next step only when a tool of the current request, a page, a skill, a specialist or a team can carry it out. Otherwise it offers none. It never offers an export, an e-mail, a ticket, a reminder, an alert or parcel tracking (BUG-074). With tool filtering on, the prompt no longer presents the number of actions as the tools at hand.
  • MentorAgent: BUG-104 (S1): with EnableCompaction on and a local history, the question of every turn that called a tool or ran a UI action was not stored. A local history is the built-in provider, ChatHistoryProviderFactory or ChatHistoryProvider. The Agent Framework's compaction marked the question as history in place (Agent Framework issue microsoft/agent-framework#8441), and stamped stored messages with its attribution. Now compaction works on copies. Questions lost on earlier versions cannot be recovered from their snapshots.

  • MentorAgent: BUG-105 (S2): RefuseOutOfScope refused price questions about the application's own catalogue, 4 times in 4 measured. It judged messages against the cost rule of hosted tools, and saw the page names only. Now it asks its own question, which defaults to answering, and sees the pages' descriptions. The classifier's labels are read by position: Contains("OUT") matched "about" and "without".

  • MentorAgent: BUG-106 (S2): a catalogue question that matched no action was sent with the core tools only. The reply invented a price range, or said that the catalogue did not have it. See Changed.

  • MentorAgent: BUG-107 (S2): MCP tools/call skipped OnToolResult, the per-user rate limit and the tool metrics. A host that redacts results served them unredacted to MCP callers. Now a hook that throws withholds the result (isError).

  • MentorAgent: BUG-108 (S2): the README's MCP steps, followed as written, answered 500 to every request on a pipeline without app.UseCors(). See Changed.

  • MentorAgent.Blazor: BUG-109 (S3): on WebAssembly, "New conversation" before the first message raised the Blazor error bar, because the hub was not connected yet.

  • BUG-110 (S3): /mentor/session and RestoreSessionAsync:

    • a marker that was not an integer answered 500;
    • a snapshot saved by a host that keeps its history another way was accepted, then failed every turn or restored an empty conversation. Another way means Responses instead of Chat Completions, or another history provider;
    • a restored conversation that the service no longer knew failed every turn until a reset. Now, when the first turn after the restore fails because the provider does not know the conversation, a new one starts. A content filter, a missing deployment, a 429 or a 5xx keep the restored conversation.

    On WebAssembly, the NotSupportedException points to /mentor/session.

  • MentorAgent.Server: BUG-111 (S3): the package README now has the rule of BUG-102, keep the transcript in the session, with its recipe. It no longer says that a reset clears the history.

  • MentorAgent: BUG-114 (S3): over A2A, the judge of a second reply without data withheld policies that contain a number, such as a spending limit, as NOT GROUNDED. And it passed "the catalogue does not list the price", when nobody had looked. Measured on Azure gpt-4.1 with fourteen replies, three times each: 25 right in 42 before, 42 in 42 now.

  • MentorAgent: BUG-115 (S2): after the user declined a confirmation, the reply could invent why the action had not run. For example "the order is probably already being processed", for an order that was Pending. The localized text said "the operation was cancelled", even for a request to cancel an order, and the Native flow sent no instruction at all. Now both modes send the same structured result: nothing was checked or changed, and no other reason or record state is to be given. The confirm.denied text no longer uses the verb for cancelling, in all 10 languages.

  • MentorAgent: BUG-116 (S2): with HitlMode.Native, Stop pressed while a confirmation waited made every later turn fail until "New conversation", with ToolApprovalRequestContent found … no matching ToolApprovalResponseContent. Now the open request is answered, as not run, at the start of the next turn, with no extra model call. The fix also covers:

    • a second Stop, or a failure, before that answer is stored;
    • a run that fails after the user confirmed: the action may have run, so it is reported with an unknown outcome and never run again;
    • the cap on approval rounds.

    On that turn the tool filter and the router decide on the new message. A snapshot saved in that state and restored, on the same host or elsewhere, still carries the open request.

  • MentorAgent: BUG-117 (S2): a provider error that arrived inside the stream, on a run that wrote no text, ended the turn with nothing on screen: no reply and no Error event. Examples are a 429 on the Responses API, or a hosted tool that failed. Now it takes the path of a thrown provider error: the localized message, OnException and the error metrics. Text written after the last tool call is kept, with no error under it. A sentence written before a tool call is not an answer. A model refusal reads as a block (guardrail.blocked), not as an error.

  • MentorAgent: BUG-103 (S1): with McpCallerPrincipal set and roles in a claim type other than ClaimTypes.Role, a signed-in caller with no roles could list and call a role-gated action, once a caller with the role had asked first. Entra ID tokens carry such a roles claim, and so does JwtBearer with MapInboundClaims = false. The tool list was cached per caller under a key built from the ClaimTypes.Role claims, while the decision used IsInRole. Now the list is decided on every request: the resolver is asked once, and ClaimsPrincipal.IsInRole is the only test, for tools/list and tools/call alike.
  • MentorAgent.Server: BUG-110 (S3): GET /mentor/session gave the client the conversation in clear. An edited snapshot was restored as history, and another user's snapshot could be restored into one's own connection. Now the snapshot is protected with ASP.NET Core Data Protection, under a purpose that names the user of the connection. It is opaque, tamper-evident, and restorable only for that user. On a host without sign-in, every visitor is the same anonymous user. POST checks the owner before it reads the body.
  • MentorAgent: BUG-074 (S3): with MentorshipLevel.Proactive, the assistant can still offer next steps that the application does not have. On the Blazor Server sample it happened in 3 turns of 15 after the new rule, and in 5 before. For example "add it to the cart", "the available deals", "plan a reorder".
  • MentorAgent: BUG-118 (S2) is closed for the hosts that turn on RequireActionForChangeRequests: see Added. Without it, the model can still describe an action it never performed: "Stock aggiornato" with no tool called, or "Ecco la pagina Prodotti" with no navigation. With it, a complete request that the classifier does not recognize runs as without the option.
  • The rest of BUG-106 is closed for the hosts that turn on RequireLookupForRecordQuestions: see Added. Without it, a catalogue question can still be answered with an offer to look the value up.

Published on NuGet on 29 September 2026 (UTC): MentorAgent 1.0.0-rc.13 (external site).

CHANGELOG.md lists no known issues for this version, but BUG-074 is still open: see Known issues.

  • THIRD-PARTY-NOTICES.md in every package, with the notices for the Feather (MIT) and Lucide (ISC) icons used by the components of MentorAgent.Abstractions. They were missing.
  • Tool filtering (EnableToolFiltering): when every action above ToolFilterMinScore needs confirmation, the three best-ranked actions that do not need it are now sent with them, within ToolFilterMaxTools. An action needs confirmation through RequiresConfirmation, the RequiresApproval predicate, or an MCP server that requires approval. A single match that needs no confirmation is still sent alone. This is the structural fix for BUG-099, under Fixed.
  • The release notes of each package now come from CHANGELOG.md, and every package contains that file.
  • Breaking: MentorRemoteAgent.RequiredRoles. It was never enforced: setting it only logged a warning, and any user could reach the agent. To restrict a remote agent, authorize on the remote side: protect the peer's /a2a endpoint and give its actions roles. Or do not configure the agent on hosts whose users may not use it. See A2A server.
  • Breaking (dependencies): MentorAgent no longer depends on Microsoft.Agents.AI.Foundry and Azure.AI.Projects, which the library never used. To keep using AIProjectClient or FoundryEvals, add <PackageReference Include="Microsoft.Agents.AI.Foundry" Version="[1.17.0-preview.260804.1]" /> to your project. A newer version needs OpenAI 2.11 or later, and the build stops with MENTOR001: see Provider package versions.
  • BUG-099 (S1): with EnableToolFiltering on, a read question could reach the model with a single write action, and a question about stock set the stock to 0. 1.0.0-rc.12 mitigated it with confirmation on the actions that change data. Now an action that needs confirmation never reaches the model alone.
  • BUG-101 (S3): an MCP tools/call could name a tool that the MCP server does not list: an action that needs confirmation, which the server withholds, or a name that never existed. The call was logged as an unhandled exception with a stack trace, and the caller got "An error occurred invoking '…'". Now the server answers "Unknown tool: '…'" with isError, the same for both kinds of name, and logs nothing as an error.
  • BUG-102 (S3): a custom history provider that kept the transcript in a field carried the previous conversation into a new one. This happened after ResetSessionAsync, the widget's reset button or the hub's ResetSession, because the provider lives as long as the circuit or connection. The README now says to keep the transcript in the session, with a recipe that uses ProviderSessionState<T>. The built-in provider was not affected.

Published on NuGet on 23 September 2026 (UTC): MentorAgent 1.0.0-rc.12 (external site).

  • MentorAgent: MentorOptions.ToolFilterMinTools, default 0. With 0, tool selection stays exactly as in 1.0.0-rc.11. With EnableToolFiltering on, once one action scores above ToolFilterMinScore, at least this many of the best-ranked actions are sent, whatever their score. It is opt-in because it can help or hurt. A minimum can stop a single write action from being offered for a read question. But it can also add a candidate that the model then wrongly prefers (see BUG-099 under Known issues).
  • MentorAgent: BUG-100 (S2): an action that needs confirmation (RequiresConfirmation, or the RequiresApproval predicate) could be called during an A2A task. It then held the task open until the calling agent gave up, because both the blocking and the native approval path waited for an answer nobody could give. Such an action is now refused at once in both HITL modes, and the model is told that it has to be performed from the application itself. The A2A agent card already left these actions out.

  • MentorAgent: BUG-098 (S2): on a turn served without a Blazor circuit, such as an A2A task on a Blazor Server host, an action with NavigateTo ran. Then the automatic navigation threw while reading NavigationManager.Uri, and the action was reported as failed. So the model ran it again, and the caller was told that it had not happened. Now:

    • a turn from another agent does not navigate automatically;
    • a page URL that cannot be read no longer turns a completed action into a failure.

    An exception thrown by your own OnToolResult hook still reports an action that already ran as failed, so make sure that the hook does not throw.

  • MentorAgent: BUG-097 (S3): on a Blazor Server host with memory or RateLimitPerUser on, every A2A task logged a warning that the AuthenticationStateProvider threw. A role-gated tool that the model reached for was logged as an Error with a stack trace, and answered "Error during authorization check". The provider is still asked, so a headless host keeps the identity of an authenticated peer. When the identity cannot be read on a task from another agent, the task is treated as anonymous (logged at Debug), and a gated tool is refused as for any anonymous caller.

  • MentorAgent: BUG-099 (S1, mitigated; present since tool filtering was introduced): with EnableToolFiltering on (off by default), the filter sends only the actions whose score is above ToolFilterMinScore. So a read question can end up with a single write action above the line. It was observed as a question about stock levels, answered by calling the stock-update action with a quantity of 0. What to do: mark every action that changes data with [MentorAction(RequiresConfirmation = true)]. A person is then asked first, and over A2A the action is refused (BUG-100). ToolFilterMinTools is an additional, opt-in lever. A structural fix (declaring actions read-only) is planned for a later version. Fixed in 1.0.0-rc.13 in a different way: actions that need no confirmation are now sent along with the ones that do.
  • MentorAgent: BUG-074 (S3): with MentorshipLevel.Proactive, the assistant can offer next steps the application does not have.

Published on NuGet on 23 September 2026 (UTC): MentorAgent 1.0.0-rc.11 (external site).

  • MentorAgent: MentorOptions.SafetyCheckTimeout and MentorOptions.SafetyCheckFailure (BUG-084). SafetyCheckTimeout defaults to 15 seconds; zero or negative means no limit, and Stop still cancels the check. SafetyCheckFailure is MentorSafetyCheckFailure.Allow, the default and the previous behavior, or Block. Block refuses the message with a localized "can't check it right now, try again", or withholds the reply. Both options apply to the input and the output check, built-in or custom. A timeout logs one line naming what to change. Nothing changes for a host that sets neither option.
  • MentorAgent: MapMentorAgentMcp() and MapMentorAgentA2A() now take their default path from McpServerPath and A2AServerPath: the path parameter is now string? path = null. Before, nothing read those options (BUG-091, S3). If you set either option to a value other than the default and map the endpoint without an explicit path, the endpoint now moves to the configured path.
  • MentorAgent: the output safety check now runs on ClassifierChatClient, like the input check, and is metered under the model id of that client (BUG-096, S3).
  • MentorAgent: BUG-082 (S2): on a host with remote A2A agents, a local specialist's answer could reach the user presented as the remote agent's, with no remote call made. Every delegated answer now states its source to the coordinator:

    • a local specialist, with a note that no remote agent was contacted, and an instruction to call once more with specialist set if the user meant one;
    • the remote agent ("that system's data, not this application's");
    • a named remote agent that never took part ("NOT X'S ANSWER", plus a warning for the operator).

    Every configured peer counts as remote, including one whose card could not be fetched when the session was built, and the router's list marks remote entries. Hosts without remote agents, and turns that arrived over A2A, are unchanged.

  • MentorAgent: BUG-083 (S2, present in 1.0.0-rc.10): a Blazor Server host could not answer another agent. Every A2A task it received completed with an empty message: a turn served over A2A has no circuit, and reading NavigationManager.Uri threw. Now the read is guarded, and the A2A handler fails a task that produced no text, instead of completing it empty. Headless hosts (MentorAgent.Server) were not affected.

  • MentorAgent: BUG-084 (S2): the safety checks had a fixed limit of 15 seconds, and a check that failed or timed out let the message or the reply through. So on a slow model the input check was skipped on every message. Stop could not interrupt the input check. A custom InputGuardrail that honored its cancellation token threw out of SendMessageAsync, and the widget stayed busy for good. See the new options above. An error now produces a single stack trace per turn.

  • MentorAgent.Blazor: BUG-086 (S2): on WebAssembly, answering a confirmation and pressing Stop used the host's HttpClient with a relative URL and no token, so the owner check refused the requests of a signed-in user. They now go to the hub's origin with the hub's bearer token (AccessTokenProvider).

  • MentorAgent: BUG-087 (S2): ConfigureChatClientPipeline is now built with the host's services. The documented b => b.UseLogging() made every coordinator build fail.

  • MentorAgent.Abstractions: BUG-088 (S2): the buttons of a MentorCardView rendered inside a ChatWidget.CardTemplate did nothing. They now reach the widget's action dispatcher.

  • BUG-089 (S2): UI actions registered by a hub client (WebAssembly, React, MAUI) now keep their parameter hint, and the WebAssembly page context generates the same hints as Blazor Server.

  • MentorAgent: BUG-090 (S3): navigate_to no longer waits for SignalReady on hub, SSE and A2A turns, where no page can send it. Each navigation to a page with HasUIActions used to cost the full ReadyTimeout and a warning.

  • MentorAgent: BUG-092 (S2): [MentorAction(ProactiveHint = ...)] was stored and never read. It now reaches the model, appended to the tool description as "Guidance: ...". Semantic tool filtering does not use it.

  • MentorAgent: BUG-093 (S2): SkillsRefreshInterval had no effect, because every session built its own cache. The composed skill sources are now cached once per process.

  • MentorAgent.Abstractions: BUG-095 (S2): a ChatInput composed without ChatWidget threw on the first message (an unguarded JavaScript call), which ended the Blazor Server circuit.

  • Documentation: corrections across the five READMEs, among them:

    • attribute examples that did not compile;
    • SignalR enums arriving as numbers;
    • the text on the anonymous identity and the rate limit (per session since 1.0.0-rc.5);
    • how to protect /mcp and /a2a, and what to expect from them.

    The XML docs and the server's startup warning now match the PerSession default.

  • MentorAgent.Declarative: BUG-094 (S2): webSearch, codeInterpreter, fileSearch and mcp tool entries in a YAML definition created provider-hosted tools outside MentorAgent's gate, against the package's guarantee that a definition file cannot add a capability the application does not already have. They are now removed with a warning, and only kind: function entries are kept. Breaking: a definition that relied on those entries loses them. Provider-hosted tools are configured by the host application (MentorOptions.HostedTools), not by a definition file.
  • MentorAgent: BUG-074 (S3): with MentorshipLevel.Proactive, the assistant can offer next steps the application does not have.

Published on NuGet on 19 September 2026 (UTC): MentorAgent 1.0.0-rc.10 (external site).

  • MentorAgent: a MentorAgent A2A caller now sends its own name for the peer as A2A message metadata (mentoragent.addressedAs), and a MentorAgent peer reads it into the turn's context, so it knows that the name refers to itself. The value comes from another machine and goes into a prompt, so only a single token of letters, digits, -, _ and . (at most 64 characters) is accepted. Anything else is dropped whole.
  • MentorAgent: BUG-081 (S2): a turn served over A2A could state figures no tool had returned. Two changes:

    • The A2A turn notice is now a procedure: call the tool first; take every number, name, date or status from a tool result of this turn; if no tool has it, reply only that the application cannot provide it.
    • As a structural backstop, when an A2A turn ends without the coordinator calling any tool, the reply is discarded. The request runs once more, with a tool call required on the first model call of that attempt. If that attempt also ends without a tool call, the classifier model is asked whether the reply states a value from the application's live records. Unless the answer is a clear no, the caller receives "NOT GROUNDED: ..." instead of the value.

    There are never more than two attempts, and only A2A requests without a tool call pay for the extra one. A reply without a tool call that states no data is returned unchanged.

  • MentorAgent: BUG-081 (second part): a peer did not know that the caller's name for it, carried inside the request, meant itself, and answered that it had no access to that system. The notice now says so, backed by the mentoragent.addressedAs metadata above.

  • MentorAgent: BUG-074 (S3): with MentorshipLevel.Proactive, the assistant can offer next steps the application does not have.

Published on NuGet on 19 September 2026 (UTC): MentorAgent 1.0.0-rc.9 (external site).

  • MentorAgent: BUG-080 (S2): two hosts that list each other as remote A2A agents could delegate one request back and forth without end, each hop a paid turn. The cause: route_to_specialist adds an internal [Specialist requested: NAME] marker for the local router (since 1.0.0-rc.8). The marker crossed the wire, and the peer read it as its own instruction. The A2A client now strips it, on both the streaming and the non-streaming path. In addition, a turn that arrived over A2A is no longer offered the host's remote agents. They are absent from the coordinator's prompt, the router's prompt and the description of route_to_specialist, and one Debug line names what was withheld. The host's own specialists, declarative agents, teams and tools still serve the request.
  • MentorAgent: chaining A → B → C through a MentorAgent host is not supported in 1.0: a turn that arrives over A2A is not offered the host's own remote agents.
  • MentorAgent: BUG-073 (residual): on a Chat Completions host, the cold first turn of a process can still narrate a handoff without calling route_to_specialist. The fix in 1.0.0-rc.7 lowers the rate; it does not remove the behavior.
  • MentorAgent: BUG-074 (S3): with MentorshipLevel.Proactive, the assistant can offer next steps the application does not have.

Published on NuGet on 18 September 2026 (UTC): MentorAgent 1.0.0-rc.8 (external site).

  • MentorAgent: route_to_specialist, the coordinator's delegation tool, takes an optional second argument, specialist, naming the specialist to use when the user named one or one clearly fits. When it is omitted, the router chooses. Additive.
  • MentorAgent: a turn that arrives over A2A now tells the model that no human is present: carry the request out and reply with the result, with no follow-up questions, offers or announcements in place of action. Hub and SSE turns are unchanged. (Tightened in 1.0.0-rc.10, BUG-081.)
  • MentorAgent: the router at the entry of the handoff workflow now has a short prompt of its own (about 400 tokens) instead of the coordinator's entire prompt, which was paid a second time on every delegated turn (part of BUG-076).
  • MentorAgent: BUG-078 (S2): the A2A server had never completed a round trip with any client. On the server side:

    • the agent card advertised the protocol binding HTTP+JSON while MapMentorAgentA2A maps the SDK's JSON-RPC endpoint (it now says JSONRPC);
    • the handler changed a task's status without submitting the task first;
    • it disposed a DI scope in a way that threw after the turn had already run and been billed.

    On the client side, A2AChatClient read only Message events inside the handoff workflow. So it could not read the answer of a MentorAgent server, which arrives as the final status update of a task. It now reads a final Task or StatusUpdate too, and skips Working statuses.

  • MentorAgent: BUG-076 (S2): the router was told to call route_to_specialist, the tool it runs inside, so it narrated a handoff instead of performing one, and the narration was returned as the specialist's answer. The router now has a router's prompt: who the specialists are; call exactly one handoff function; never answer; never say you are forwarding. The tool returns what the specialists said, as text. When only the router spoke, the result is "NOT DELEGATED ..." and the operator gets a warning. When a specialist threw an exception, it is reported as "DELEGATION FAILED", with the error in the warning.

  • MentorAgent: BUG-077 (S3): model calls made under the coordinator (the router, Level-2 specialists, Level-3 team members and agents built by an IMentorAgentSource) ran on the raw host client and were never metered. They now run inside the metering wrapper. Azure's first streamed chunk carries an empty (not null) model id. So the wrapper now takes the first id that is not empty, and falls back to the client's own deployment. This way, a ClassifierChatClient on its own deployment gets its own dashboard row.

  • MentorAgent: BUG-079 (S3): specialists had no rule against inventing data. Generated specialist prompts and the prompt of every team member now carry a grounding rule: state only facts a tool returned; if nothing provides what is asked, say so, and never estimate or invent a number, name, date or status. Custom [MentorAgent(Instructions = ...)] prompts are left exactly as written: a custom prompt replaces the rule too, so add it to your own instructions.

  • MentorAgent: BUG-075 (S3), second pass: on hosts with memory on, the safety classifier is now told that the secrets its rules protect are the system's, and that what users tell the assistant about themselves is theirs to give and to ask back. Asking the assistant to remember a private code, and asking for it back, are no longer classified unsafe. The model itself may still decline to keep something its user calls private, and says why.

  • MentorAgent: BUG-074 (S3): with MentorshipLevel.Proactive, the assistant can offer next steps the application does not have.

Published on NuGet on 16 September 2026 (UTC): MentorAgent 1.0.0-rc.7 (external site).

  • MentorAgent: BUG-073 (S2): the coordinator was told it could delegate to its specialists but never how: route_to_specialist appeared nowhere in the prompt, and its description named no agent. So the model announced handoffs and ended the turn without calling anything. The capabilities block now says how to delegate and forbids announcing a handoff that was not performed, and the tool's description names every specialist it reaches: declared with attributes, supplied by a source, and remote.
  • MentorAgent: BUG-075 (S3): asking the assistant to remember a personal fact was classified unsafe on a host with memory on. Remembering what the user asks to keep is now named to the classifier as a configured capability (completed in 1.0.0-rc.8).
  • MentorAgent: BUG-072 (S3): a signed-in user whose AuthenticationStateProvider threw was silently keyed as anonymous, and since 1.0.0-rc.5 as a different anonymous in every circuit. The fallback that fails closed stays; it is now logged once per session, without a stack trace per visitor.
  • MentorAgent: BUG-068 (addendum): the "Remote agent 'X' connected" line was still logged at Information for every circuit. It now follows the once-per-process rule.
  • MentorAgent: BUG-074 (S3): with MentorshipLevel.Proactive, the assistant can still offer actions the application does not have. The rule is in the prompt; a structural fix is left open as a product decision.

Published on NuGet on 14 September 2026 (UTC): MentorAgent 1.0.0-rc.6 (external site).

  • MentorAgent: BUG-068 (S3): the configuration summary was not written once per process, as the notes of 1.0.0-rc.5 stated. A second browser circuit printed the whole summary again, at Information: the skills catalog, the external agents, the hosted image model, the note on the Azure image header, the hosted MCP server, the list of hosted tools and the declarative handoff. It is now written once per process; later builds log it at Debug instead of dropping it. Degradation warnings stay per session.
  • MentorAgent: BUG-069 (S2): an agent supplied by an IMentorAgentSource (a declarative YAML specialist, or one of the host's own) joined the handoff graph but was never named in the coordinator's instructions, so the assistant said it did not exist. Agents supplied by a source are now listed with their descriptions, beside the ones declared with attributes.
  • MentorAgent: BUG-070 (S4): every skill on the published A2A agent card carried a flattened name (for example Getallordersforanalysis). Skill names are now readable.
  • MentorAgent: BUG-071 (S4): a turn in which the input safety check was the first to fail printed two stack traces instead of one.

Published on NuGet on 13 September 2026 (UTC): MentorAgent 1.0.0-rc.5 (external site).

  • MentorAgent: MentorOptions.ClassifierChatClient: the client MentorAgent uses for its own one-word decisions (input safety, hosted-tool scope, extraction of facts after the turn). Point it at a small deployment, because those calls sit in front of the reply. It defaults to ChatClient and is metered under its own model id.
  • MentorAgent: MentorOptions.AnonymousIdentity (MentorAnonymousIdentity.PerSession by default, or Shared): who a signed-out visitor is, for memory and for the rate-limit counter. See Changed.
  • MentorAgent: MentorOptions.RefuseOutOfScope (off by default): refuse a message that is not about this application, using the scope verdict the classifier already produces. It is free when EnableSafetyCheck is on, because both questions travel in one call.
  • MentorAgent: MentorOptions.WarmUpAtStartup (off by default): build one coordinator when the application starts, so the first visitor does not pay for the catalog embeddings, the shared MCP sessions and the remote agent cards.
  • MentorAgent: MentorMcpServer.Shared (bool?, default null): one connection per process, or one per session. When it is unset, a server reached over ServerUrl is shared and a server started from Command is not, because a local child process can hold state for the person who started it.
  • MentorAgent: MapMentorAgentMcp(path, configure) and MapMentorAgentA2A(path, configure) take an optional Action<IEndpointConventionBuilder>, so the host can apply RequireAuthorization() or other conventions to /mcp and /a2a: see Secure the endpoints. Both previously discarded their convention builders.
  • MentorAgent: IMentorQueryEmbedding: the embedding of the current message, computed once per turn. Inject it into your IMentorRagSource instead of embedding the query a second time.
  • MentorAgent: Breaking: signed-out visitors are now isolated per session by default (AnonymousIdentity = PerSession). Before, every unauthenticated session shared the literal key anonymous, so one visitor's facts were recalled for the next, and one visitor could spend everybody's rate-limit allowance. Single-user hosts, such as MAUI, desktop and kiosk apps, may want the old behavior: there it is what makes memory survive a restart. They must set AnonymousIdentity = MentorAnonymousIdentity.Shared. A warning is logged when a host opts back into the shared bucket and a second session reaches it.

  • MentorAgent: faster turns and lower cost per visitor:

    • Routing, tool filtering and memory relevance share one embedding per text per turn, instead of embedding the same sentence two to four times.
    • The tool catalog and the routing exemplars are embedded once per process instead of once per browser circuit.
    • The input safety check and the hosted-tool scope check ask both questions in one classifier call.
    • The composer is handed back when the answer is complete, not after the extraction of facts that follows the turn.
    • MCP sessions and A2A agent cards are shared per process, with a failure backoff for the card cache.

    The measured time to the first character fell from 2.6–3.0 s to 1.6–2.0 s on the same question.

  • MentorAgent: RAG citation chips show only the documents the answer actually cited: documents are numbered in the prompt, and the model is asked to cite them. If it cites none, no chips are shown.

  • MentorAgent: MentorshipLevel.Proactive asks for one sentence before acting instead of a plan, and may offer only next steps the application can actually perform.

  • MentorAgent: the A2A agent card now publishes the application's ungated actions as skills, its input and output modes and its streaming capability. Before, it carried only a name and a description.

  • MentorAgent: one provider failure now produces one stack trace instead of one per component that met it, and the coordinator's configuration summary is logged once per process instead of once per session (completed in 1.0.0-rc.6 and 1.0.0-rc.7, BUG-068).

  • MentorAgent: BUG-062 (S3): text written before a tool call was glued to the text after it, and a Markdown table opening the second part stopped rendering as a table.
  • MentorAgent: BUG-063 (S3): in HitlMode.Native, a user without the required role was shown the confirmation box and refused only after approving it. The role gate now runs first, as it always did in Blocking mode.
  • MentorAgent: BUG-065 (S4): the RAG "wrong scale" warning fired for thresholds that were on the source's own scale, and did so once per visitor.
  • MentorAgent: BUG-066 (S3): the hosted-tool scope classifier was built on the raw ChatClient, so its billed calls appeared in no dashboard.
  • MentorAgent: BUG-067 (S3): the safety classifier was never told what the application is equipped with (for example an MCP filesystem server or image input), and refused legitimate messages. It is now told, and a refused message is logged by fingerprint rather than by its text.
  • MentorAgent: BUG-064 (S1): two anonymous visitors of the same site shared one memory. Anonymous visitors are now isolated per session by default (see Changed).

Published on NuGet on 9 September 2026 (UTC): MentorAgent 1.0.0-rc.4 (external site).

  • MentorAgent: BUG-061 (S3): the classifier of provider errors recognized an unreachable image URL only in the Chat Completions wording. So on the Responses API, the client that hosted tools require, the user saw the generic error instead of the specific message. The Responses API wording is now recognized too. It is keyed on the pair "error while downloading file" and "parameter: url", so a failure on a file supplied by the operator, such as a vector-store document, still falls through to the generic message.

Published on NuGet on 4 September 2026 (UTC): MentorAgent 1.0.0-rc.3 (external site).

  • MentorAgent.Blazor: MentorAgentBlazorOptions.AccessTokenProvider supplies the bearer token for the hub connection, read on every connect and reconnect. It is the WebAssembly equivalent of the JavaScript client's accessTokenFactory. Return null while nobody is signed in; the connection then behaves as before. The hub connection is a singleton, opened on the first render of the widget, and the token is read only on connect and reconnect. So a sign-in that happens later takes effect on the next reload or reconnect: restore a persisted token before the host runs.
  • MentorAgent.Blazor: MentorAgentBlazorOptions.ConfigureConnection, an escape hatch onto HttpConnectionOptions for anything the named options do not cover (a custom header, a transport restriction, cookies, UseDefaultCredentials).
  • MentorAgent.Server: MapMentorAgentServer(configureTransports: e => e.RequireAuthorization()) applies an endpoint convention to the hub and to both /mentor/chat endpoints. It is optional: omitting it changes nothing.
  • MentorAgent.Server: a one-line startup warning when the SSE endpoint ends up with no authorization metadata while memory is on, and a README section listing every endpoint, what an anonymous caller can do with it and how to protect it. See Secure the endpoints.
  • MentorAgent.Server: GET /mentor/session?connectionId=... returns the session snapshot of the connection (204 when there is nothing to save, 404 for an unknown connection), and POST /mentor/session?connectionId=... restores one (400 for a snapshot that is not MentorAgent's, without touching the live conversation). This gives WebAssembly, React, Vue and MAUI clients a way to survive a reconnect, which starts a new conversation. Both verbs are restricted to the owner of the connection (see Security).
  • MentorAgent: MentorOptions.ChatHistoryProviderFactory (Func<IServiceProvider, ChatHistoryProvider>), invoked once per coordinator with the service provider of that coordinator, so a provider can key its storage by whatever identifies the caller. Prefer it in any application with more than one user. Setting both it and ChatHistoryProvider throws in MentorOptions.Validate() at startup.
  • MentorAgent: MentorOptions.McpCallerPrincipal resolves the ClaimsPrincipal of the MCP caller. A role-gated action is then published over MCP only when that principal is authenticated and holds one of the action's roles. The action is withheld when there is no resolver (the default), when the principal is null or unauthenticated, or when the resolver throws. Confirmation gates (RequiresConfirmation, the RequiresApproval predicate) are never satisfied by it, because there is no human on the far end of an MCP call. The published tool list is evaluated per caller identity.
  • MentorAgent: provider errors the user can act on are now shown as specific localized messages, instead of "An error occurred while processing the response". These errors are: an unreachable image URL, quoted back; a conversation past the context window; a throttled provider; a rejected image; a timeout. Everything else (an expired key, a missing deployment, a firewall rule) stays generic. Provider text is never forwarded, IncludeWorkflowExceptionDetails keeps its meaning and default, and the full exception is still logged. There are seven new localizer keys, in all ten languages, including the generic fallback, which was previously hard-coded in English.
  • MentorAgent: Breaking: the package now ships an MSBuild guard (buildTransitive). It fails the build with error MENTOR001 when the resolved OpenAI package is 2.11.0 or later (BUG-045, S1). Before, the application built and then died at startup with a MissingMethodException from AzureOpenAIClient.GetResponsesClient(). The pins are now exact ranges: Microsoft.Extensions.AI.OpenAI [10.6.0] and Microsoft.Agents.AI.Foundry [1.17.0-preview.260804.1]. If the guard fires, remove your direct reference to Microsoft.Extensions.AI.OpenAI 10.7.0 or later, or to Microsoft.Agents.AI.Foundry 1.18.0 or later, and let MentorAgent supply them; or pin them to those versions. To override the check deliberately, set the MSBuild property MentorAgentSkipOpenAIVersionCheck=true. See Provider package versions.
  • MentorAgent: on a turn that calls a UI action, the sentence the model writes alongside the call now reaches the user (a consequence of the streaming fix, BUG-052).
  • MentorAgent: the input safety classifier now receives the application's scope (AppName, AppDescription, the names of the discovered pages) and is told that reading the application's own business data is safe however broadly it is phrased. Attempts to override the instructions are still refused (BUG-047).
  • MentorAgent: the scope text the hosted-tool domain gate derives now names the hosted capabilities that are enabled, and states the decision rule as a constraint on the subject. A custom HostedToolDomainScope is left exactly as written (BUG-050).
  • MentorAgent.Abstractions: the README gives every component a worked example (MentorCardView, MessageBubble, ChatInput, OnboardingTour, ConfirmationBanner, WelcomePanel, RagSourcePanel, the MCP and A2A badges, TypingIndicator), plus a "Composing your own chat surface" walkthrough.
  • MentorAgent.Server: BUG-051 (S1): the hub method SendMessage takes (string text, IReadOnlyList<MentorAttachment>? attachments). SignalR binds arguments by count, so a C# default value never applies. The documented clients all invoked it with one argument: the JavaScript quickstart, the React hook, the Angular service, the Vue composable, the .NET MAUI or console client, and the UI-actions walkthrough. The server rejected these calls with "Invocation provides 1 argument(s) but target expects 2", and the client saw "Failed to invoke 'SendMessage' due to an error on the server". All six snippets are corrected. If you wrote a client from them, pass null (or []) as the second argument; nothing changed on the server. See Any front end.
  • MentorAgent: BUG-054 (S1): MentorAgent could not start at all on .NET MAUI (Blazor Hybrid), even with skills off. The skills builder read IHostEnvironment.ContentRootPath, which throws on MAUI, and the exception killed the whole Blazor renderer. The content root now falls back to AppContext.BaseDirectory, where the content files of a MAUI app land, so a relative SkillsFolder still resolves.
  • MentorAgent: BUG-053 (S2): the documented Blazor Hybrid (MAUI) render mode failed its first build with NU1605. The core README now has a setup section for Blazor Hybrid (MAUI), including the package pin that resolves the error. See .NET MAUI.
  • MentorAgent: BUG-047 (S2): with EnableSafetyCheck on, ordinary requests for the application's own records were refused depending on their wording (see Changed).
  • MentorAgent: BUG-052 (S2): registering one UI action switched token streaming off for every turn on that page, and the whole reply arrived in a single frame. The UI-actions loop now streams, withholding only calls to its own registered actions (filtered by name), so genuine tool calls of the outer pipeline pass through untouched.
  • MentorAgent: BUG-050 (S3): with HostedToolDomainCheck on, the README's own image-generation example was refused as out of scope (see Changed).
  • MentorAgent: BUG-044 (S3): the core README's first Azure OpenAI Responses API example, and the same form in the doc comment of MentorOptions, did not compile. They now show GetResponsesClient().AsIChatClient("deployment").
  • MentorAgent.Abstractions: BUG-048 (S3): seven of the nine buttons of an open panel were icon-only and named by title alone, so screen readers announced them as unnamed buttons. Every icon-only control now also carries an aria-label from the same localizer key.
  • MentorAgent.Abstractions: BUG-049 (S3): the text of the MCP and A2A badges was hard-coded (Italian in ChatWidget, English in McpStatusBadge). Six new localizer keys in all ten languages (mcp.connecting, mcp.allOnline, mcp.someOnline, mcp.offline, a2a.pill, a2a.agents), read by both components.
  • MentorAgent.Blazor: BUG-046 (S1): the WebAssembly client could not authenticate its hub connection, so the server saw every user as anonymous:

    • every RequiredRoles action was blocked;
    • RateLimitPerUser became one global limit;
    • all users shared the memory key anonymous. With MemoryAutoCapture on by default, personal facts extracted from one person's conversation reached the next person's prompt.

    Fixed by AccessTokenProvider and ConfigureConnection (see Added). Upgrade MentorAgent.Blazor and MentorAgent.Server together. A WebSocket handshake cannot send an Authorization header, so a JWT host must read the access_token query parameter for /mentor-hub. The Server README has a JwtBearerEvents.OnMessageReceived recipe.

  • MentorAgent: BUG-055 (S1): MentorOptions is a singleton, so an object assigned to ChatHistoryProvider served every circuit, connection and user in the process, and one user's conversation could be served to another. Use ChatHistoryProviderFactory in any application with more than one user. ChatHistoryProvider is kept for single-user hosts and for providers that partition their own storage, and now logs at Debug that it is shared.

  • MentorAgent.Server: BUG-060 (S1): the hub and SSE endpoints could not be protected through MapMentorAgentServer(), because it discarded their endpoint builders. So an anonymous caller could run paid turns, with one memory bucket and one rate-limit counter that all anonymous callers shared. Use configureTransports (see Added).

  • MentorAgent.Server: BUG-058 (S1, present since before 1.0.0-rc.2): POST /mentor/approve let anyone who learned an action id approve a gated action that its owner had not answered, or deny one that the owner wanted. The server now records which connection raised each pending confirmation. It accepts an answer only from the owner of that connection, with the same ownership check as /mentor/session, and POST /mentor/cancel gets the same check. Breaking: on an authenticated host, approve and cancel requests must carry the same identity as the hub connection. An anonymous caller against an authenticated connection is refused with 401, and a different user with 403. Hosts with no authentication, SSE confirmations and in-process Blazor Server confirmations are unchanged.

Published on NuGet on 24 August 2026 (UTC): MentorAgent 1.0.0-rc.2 (external site).

  • MentorAgent: MentorOptions.SkillSources accepts any Agent Framework AgentSkillsSource: a database, a remote catalog, a store per tenant or Microsoft's AgentFileSkillsSource.
    • Its skills reach the assistant through the same load_skill and read_skill_resource tools, catalog prompt and gate as MentorAgent's own.
    • Sources are composed with the framework's aggregating, filtering, deduplicating and caching decorators.
    • An application skill always wins a name collision: the duplicate is skipped with a warning.
    • Sources need a model. MentorAgent uses Agent when it is set, otherwise a plain agent over ChatClient. With neither, sources are skipped with a warning.
    • MentorAgent's own SKILL.md convention is unchanged: register the framework's file source as well if you want both dialects.
  • MentorAgent: MentorOptions.SkillFilter (it applies to skills from sources only, never to your own) and MentorOptions.SkillsRefreshInterval (it adds caching of the sources; it had no effect until 1.0.0-rc.11, because every session built its own cache: BUG-093).
  • MentorAgent: MentorOptions.AutoApprovalRules (with HitlMode.Native) approves a tool call before any confirmation box appears, through the framework's ToolApprovalAgent middleware. It also turns on "don't ask again": after a user approves a call, matching calls stop asking for the rest of the session. It is opt-in: HitlMode.Native alone does not add the middleware. A rule skips the question, never the permission: RequiredRoles is still checked. A call that is not approved automatically still arrives as ConfirmationRequired, and is answered with POST /mentor/approve.
  • MentorAgent: MentorOptions.MaxAutoApprovalIterations caps how many times one turn may run again because every approval it surfaced was auto-approved. Each extra run is a billable model call.
  • The family moves onto the Microsoft Agent Framework 1.18.0 line (Microsoft.Agents.AI 1.18.0) and Microsoft.Extensions.AI 10.7.0. Microsoft.Agents.AI.Foundry stays on 1.17.0-preview and Microsoft.Extensions.AI.OpenAI on 10.6.0, so that OpenAI stays at 2.10.0. Version 2.11.0 removes a constructor that Azure.AI.OpenAI 2.9.0-beta.1 still calls. With it, a host using Azure OpenAI hosted tools or service-managed history would die at startup with a MissingMethodException from AzureOpenAIClient.GetResponsesClient() (BUG-043, S1, fixed before this release). See Known issues.
  • MentorAgent.Declarative: Microsoft.Agents.AI.Declarative moves to 1.18.0-rc1, on the same line as the core package.
  • MentorAgent: a bare GET /mcp (mapped by MapMentorAgentMcp()) now answers 400 with a JSON-RPC error naming the missing Mcp-Session-Id header. Before, it answered 406 (the behavior of the MCP SDK).
  • BUG-045 (S1): the hold on OpenAI is a minimum, not a ceiling. A project that references Microsoft.Extensions.AI.OpenAI (10.7.0 or later) or Microsoft.Agents.AI.Foundry (1.18.0 or later) directly resolves OpenAI 2.11.0 or later, builds cleanly and dies at startup. Keep those two packages at 10.6.0 and 1.17.0-preview. Fixed in 1.0.0-rc.3 by exact pins and the MENTOR001 build error.

Published on NuGet on 19 August 2026 (UTC): MentorAgent 1.0.0-rc.1 (external site).

  • IMentorOrchestrator.SerializeSessionAsync and IMentorOrchestrator.RestoreSessionAsync, to save and restore a conversation. The equivalent IMentorSessionManager methods take the coordinator AIAgent, which no public API returns, so they could not be called (BUG-025, S2).
  • MentorModelUsage.RequestsWithoutUsage: requests that were billed but reported no token counts (for example a turn the user stopped), disclosed instead of counted as zero.
  • MentorAgent.Server: two SSE frames. {"type":"confirmationRequired","actionId":"...","tool":"...","message":"..."}: answer it with POST /mentor/approve?actionId=...&approved=true|false on a second request while the stream is open, and the parked turn resumes. And {"type":"navigation","url":"..."} for navigate_to (BUG-037, S2). The README now documents the complete set of SSE frames: chunk, cards, navigation, confirmationRequired, completed, error.
  • MentorAgent.Server: Breaking: the SSE frame {"type":"completed"} now means the turn is over. Before, it fired when the streaming segment ended, including for a turn parked on a human confirmation, which was reported as completed with no action id to approve (BUG-038, S2). A client that treated completed as "the answer is finished" keeps working; a client that used it to decide the request had succeeded must now also handle confirmationRequired.
  • MentorAgent: Breaking: session snapshots are now stamped ({"mentorAgentSession":1,"session":...}), and anything else is refused before the live session is touched. Before, arbitrary JSON restored as an empty session that silently replaced the live conversation (BUG-026, S3). Snapshots written by 1.0.0-preview.5 are refused: discard them rather than migrating.
  • MentorAgent: refusals now reach the model with a structural marker (declined_by_user or stopped_by_user), and the instruction travels in the tool result, instead of looking like a crashed tool that the model offers to retry (BUG-031, S3).
  • MentorAgent: MentorAgent's own last_session bookkeeping is still written, but no longer injected into the memory context, where it always took a slot (BUG-014, S3).
  • MentorAgent: the output of the evaluation report meant for machines (including FailureReason) uses the invariant culture (BUG-020, S4).
  • MentorAgent: the stale second copy of the widget stylesheet and script that the core package shipped under its own _content path, referenced by nothing (BUG-023, S4).
  • MentorAgent: BUG-018 (S1): a [TeamTerminationCondition] on a Level-3 team removed the iteration cap instead of tightening it, so a predicate that never fired ran the group chat without bound. Custom conditions now run in addition to MaxIterations, never instead of it.
  • MentorAgent: BUG-013 (S2): on Path B (options.Agent) the tool list was built and logged but never sent to the model, so the assistant had no application actions, navigate_to, invoke_ui_action or memory tools. The list is now passed through ChatClientAgentRunOptions, whose tools are added to the agent's own.
  • MentorAgent: BUG-015 (S2): Path B also received none of MentorAgent's instructions and none of the context of each turn (page, memory, RAG, skills); they are now added alongside the host's own persona. BUG-006 (S2): a custom AIAgent could fail to start at all, telling the user to reload the page. BUG-007 (S3): the diagnostics of Path B were unreachable.
  • MentorAgent: BUG-027 (S3): RagMinScore defaults to 2, a scale that suits keyword-scored sources. Vector stores, instead, return a cosine similarity between 0 and 1, so on a vector store every document was silently discarded. A warning is now logged once per provider, naming the threshold, the document count and the highest score seen. For a vector store, set RagMinScore between 0.5 (loose) and 0.75 (strict), or 0 to disable filtering.
  • MentorAgent: BUG-016 (S3): UseRag = true with no IMentorRagSource registered now warns when the coordinator is built. BUG-017 (S3): a RagSystemPromptTemplate without the {documents} placeholder now warns (it dropped every document while still showing citation chips).
  • MentorAgent: BUG-028 (S2): MaxSessionMessages = 0 (or negative, or an empty key in appsettings.json) threw while the coordinator was assembled. It is now guarded, and read like the neighbouring options that use 0 for "no limit".
  • MentorAgent: BUG-011 (S2): an assembly listed twice in ScanAssemblies registered everything twice, and the coordinator failed to build. Duplicates are now removed with a warning. BUG-008 (S3): "Native HITL is enabled but no tool requires approval" is now logged at a level operators watch.
  • MentorAgent: fixes to the token and cost metrics:
    • BUG-030 (S2): Azure OpenAI does not reliably report the response model id, and a blank id was attributed to the cheap model, so escalated turns were priced as cheap ones.
    • BUG-034 (S2): a dated model id (gpt-4.1-2025-04-14 for a deployment named gpt-4.1) produced a separate dashboard row with no price. It is now folded onto the configured or priced model by an exact match of the trailing date, never by prefix.
    • BUG-033 (S3): MentorAgent's own model calls (memory auto-capture, the safety check, the hosted-tool domain gate) are now metered.
    • BUG-032 (S3): a turn the user stopped is now counted, with its latency, instead of vanishing from the metrics.
  • MentorAgent: BUG-012 (S2): answering a confirmation synchronously (an auto-approval policy, a client that approves in advance) parked the turn forever, with no error.
  • MentorAgent: BUG-019 (S3): a UI action requested by the model ran against the page registrations captured before the model call, so navigating away during the turn ran a handler on a disposed component. Registrations are now resolved when the action runs.
  • MentorAgent: BUG-010 (S3): tool results containing a tab or another control character produced JSON the model could not parse.
  • MentorAgent: BUG-029 (S2): AgentCardInfo.IconUrl, Provider, DocumentationUrl and the version override now reach the published A2A agent card. AgentCardInfo.Tags is documented as reserved and not published, because the A2A specification attaches tags to skills, not to the card.
  • MentorAgent.Abstractions: BUG-024 (S2): in hands-free voice mode the microphone stayed open during playback, so the assistant transcribed its own answer and sent it back as the next question. The microphone now closes when an answer begins, and the half-heard fragment is discarded.
  • MentorAgent.Abstractions: BUG-039 (S3): loading MentorAgent.js twice (the configuration recommended on WebAssembly, where index.html carries a script tag and the widget injects a second one) reset the voice state machine during a session. The state now survives. Upgrade MentorAgent.Abstractions and MentorAgent.Blazor together.
  • MentorAgent.Abstractions: BUG-022 (S4): the RAG citation chips read a CSS variable no stylesheet declares and rendered at full brightness. They now use the theme's secondary text level.
  • MentorAgent.Blazor: BUG-009 (S2): IMentorOrchestrator.RespondToApprovalAsync on WebAssembly went through the RespondToApproval hub method, which deadlocks while the turn awaiting approval holds the connection. It now posts to /mentor/approve. CancelCurrentRequest no longer invokes the hub on a dead connection.
  • MentorAgent.Server: BUG-036 (S2): the documented SSE cards frame was lost, because several handlers wrote to the response concurrently inside an empty catch block. All frames now go through a single ordered writer, and a failed write is logged.
  • Documentation (each of these broke custom clients written from the READMEs):
    • the streaming event is StreamingChunk, not ReceiveChunk (BUG-001, S2);
    • navigation arrives as NavigationRequested, not NavigateTo (BUG-005, S2);
    • the protocol reference now lists all 18 events from server to client, including Cards and HostedToolsDeclared (BUG-002, S2), and marks CancelRequest and RespondToApproval as not to be used, in favor of the HTTP routes;
    • the memory tool is forget_all, not forget (BUG-003, S3);
    • the skills example follows the tool-naming rule (BUG-004, S3);
    • CancelCurrentRequest, RespondToApprovalAsync and the metrics snapshot served over HTTP (including DeflectionRate) are documented with reference tables and examples (BUG-040, BUG-041, S3);
    • the READMEs now state that a SignalR reconnect is a new connection, a new DI scope and therefore a new conversation.
  • MentorAgent: BUG-021 (S1): the MCP server published every [MentorAction], including actions restricted with RequiredRoles and actions marked RequiresConfirmation, to any client that could reach /mcp: an endpoint mapped with permissive CORS by default, whose requests carry no signed-in principal. Gated actions are now withheld from the MCP surface, and the withheld set is logged with each tool and the reason.
  • MentorAgent: BUG-035 (S1): the same hole existed for actions gated by the RequiresApproval predicate; both routes now fail closed. Breaking: a gated action is no longer reachable over MCP, and there is no opt-in to publish it anyway. If an MCP client relied on one, perform that action from the application instead. (1.0.0-rc.3 added McpCallerPrincipal for publishing role-gated actions to authenticated callers.)
  • On Blazor WebAssembly, SerializeSessionAsync and RestoreSessionAsync throw NotSupportedException, because the session lives in the DI scope of the server. (1.0.0-rc.3 added GET and POST /mentor/session for remote clients.)
  • A SignalR reconnect, including with withAutomaticReconnect(), is a new connection and therefore a new conversation.
  • MentorAgent.Server: the SSE stream forwards six of the hub's eighteen events. GeneratedImages, RAG citations and the line on hosted-tool activity are hub-only.
  • MentorAgent.Server: the hub's limit on received messages is sized from the image options. An oversized argument aborts the connection instead of returning an error.
  • MentorAgent: with A2AServerUrl unset, the A2A agent card advertises a bare path, which is useless to a client on another host. Set it to the absolute URL.

Published on NuGet on 12 August 2026 (UTC): MentorAgent 1.0.0-preview.5 (external site).

  • MentorAgent.Declarative: first release. AddMentorAgentDeclarative(options) defines Level-2 specialists in YAML instead of C# classes. It loads *.agent.yaml files from Directory and inline Definitions. SearchPattern defaults to *.agent.yaml, and Recursive to false. It can also expose one configuration section through ConfigurationSection. The agents join the same handoff graph as [MentorAgent] classes. A YAML file names tools; it does not define them. Each tool is resolved from the Level-1 tools that the application already registers, already wrapped in MentorAgent's gate. So RequiredRoles, human approval, action feedback and per-tool metrics keep working. A malformed definition is logged and skipped, and never stops the assistant from starting. Definition files are code: load them only from paths fixed at deploy time. The Agent Framework's declarative stack (Power Fx and its dependencies) stays out of the core package. See The three agent levels.

  • MentorAgent: IMentorAgentSource (with MentorAgentSourceContext): supply Level-2 specialists that the scan for the [MentorAgent] attribute cannot see. They join the same handoff graph, and the tools handed to a source arrive already gated.

  • Generative UI Level 2, cards: a tool can return a MentorCard (or several) instead of a string. The widget renders it as a card with a title, a subtitle, label and value fields, an accent color, and buttons. A button can send a message, navigate, or run a UI action that the page registered. New in this version:

    • the contracts MentorCard, MentorCardField, MentorCardAction, MentorCardActionKind and MentorCardAccent;
    • the MentorCardView component (XSS-safe: no MarkupString);
    • IMentorStateService.OnCardsReady and NotifyCardsReady;
    • MentorOptions.EnableGenerativeCards (default true; false restores the previous text behavior).

    Because cards come from application code, the conversation cannot add a button or change where one points. The model is told that the card is on screen, and receives the data in compact form.

  • MentorAgent.Abstractions: ChatWidget.CardTemplate renders a kind of card your own way; the other kinds use the built-in renderer. The buttons of a MentorCardView inside a template did nothing until 1.0.0-rc.11 (BUG-088).

  • MentorAgent.Server: cards are forwarded to remote clients as a Cards hub event and a {"type":"cards"} SSE frame, serialized in camelCase with string enums. Additive: a client that ignores them still receives the whole answer as text.

  • Onboarding tour: EnableOnboardingTour (default false, on MentorOptions, MentorWidgetOptions and MentorAgentBlazorOptions), IMentorTour, MentorTourStep and the OnboardingTour component. A short tour when a user first opens the widget, generated once per process from the [MentorPage] pages and the assistant's tools. Each step can carry a ready-made question. A generated URL that matches no registered page is dropped; without a ChatClient, a deterministic tour is built from the same data. Register your own IMentorTour to script it by hand.

  • MentorAgent.Server: GET /mentor/tour returns the tour steps as JSON for headless and WebAssembly clients; enable EnableOnboardingTour on the server as well. It is unauthenticated by design: the payload is the public screen names and capability descriptions, identical for every user and cached per process.

  • MentorAgent.Blazor: MentorAgentBlazorOptions.TourUrl, to fetch the tour from the server. If the fetch fails, the widget opens normally.

  • Voice options, on MentorOptions, MentorWidgetOptions and MentorAgentBlazorOptions:

    • VoiceStreaming (default true);
    • VoiceBargeIn (default true): playback stops when the user presses the microphone, sends a message, presses Stop or starts a new conversation;
    • VoiceHandsFree (opt-in): the transcript is sent on silence, and the microphone reopens when the spoken answer ends;
    • VoiceRate (default 1.0).
  • Voice output now speaks each sentence while the answer streams, instead of reading the finished reply back. A decimal point is not treated as a full stop, and fenced code blocks are skipped rather than read out.
  • MentorAgent.Server: the endpoint table in the README now lists /mentor/approve, /mentor/cancel, /mentor/admin/metrics and /mentor/tour.

Published on NuGet on 4 August 2026 (UTC): MentorAgent 1.0.0-preview.4 (external site).

  • MentorAgent: provider-hosted tools. MentorOptions.HostedTools (MentorHostedTools.WebSearch | CodeInterpreter | FileSearch | ImageGeneration | HostedMcp) lets the model provider run these tools on its own infrastructure: web search, a sandboxed code interpreter, file search, image generation and remote MCP calls.

    • Related options: FileSearchVectorStoreIds (required for file search), FileSearchMaxResults, HostedMcpServers (MentorHostedMcpServer, with RequireApproval, AlwaysRequireApprovalTools and NeverRequireApprovalTools), HostedImageModel and HostedImageSize (WIDTHxHEIGHT; a value that cannot be parsed is ignored with a warning).
    • They fail closed: without vector store ids, file search is skipped with a warning; without servers, hosted MCP is skipped with a warning too.
    • Availability depends on the provider client. The Responses API and Foundry support the full set; Chat Completions supports only web search. The Responses API also needs UseServiceManagedHistory.
    • The enabled set is logged at startup and listed in the coordinator's system prompt. When a tool is withheld on a turn, the model is told so in that request (appended to ChatOptions.Instructions), so it refuses instead of inventing a result.
  • MentorAgent: MentorOptions.ShowHostedToolActivity (default true) reports the work done on the provider's side through the existing channels: action-feedback lines such as "Searching the web…", web-search and file-search sources as citation chips, and generated images attached to the message.

  • MentorAgent.Server: the hub events GeneratedImages(string[]) (data: URIs or absolute URLs, ready for <img src>) and HostedToolsDeclared(int) (sent once on connect, with the active MentorHostedTools flags). Hosted-tool activity also arrives on the existing ActionExecuting, ActionCompleted and RagSourcesReady events. Additive.

  • MentorAgent.Abstractions: a hosted-tools badge in the widget header, driven by MentorWidgetOptions.ShowHostedToolsStatus and HostedTools (mirrored on MentorAgentBlazorOptions), plus IMentorStateService.OnHostedToolsDeclared and NotifyHostedToolsDeclared: the widget prefers the set the server declares over its local option. New CSS variables --bm-hosted-text and --bm-a2a-text, overridden per theme.

  • MentorAgent: cost controls for hosted tools:

    • FilterHostedTools (default true) puts hosted tools through the semantic tool filter, with their own threshold HostedToolFilterMinScore (effective default 0.15).
    • MaxHostedToolCallsPerSession limits the hosted-tool calls per session (0 = unlimited).
    • HostedToolDomainCheck, with HostedToolDomainScope and HostedToolDomainClassifier, lets a small model decide whether the message concerns the application at all. It runs once per turn, and only when a hosted tool would otherwise run. If the check itself fails, the turn goes on (it fails open).

    All three require EnableToolFiltering and an EmbeddingGenerator: without them nothing is filtered, and a startup warning names the ignored options.

  • MentorAgent: MentorOptions.HitlMode: MentorHitlMode.Blocking (the default, unchanged) or Native. Native uses the Agent Framework approval flow (ApprovalRequiredAIFunction and ToolApprovalRequestContent), with one extra round trip for each approved call. The confirmation box and the client protocol are the same in both modes. MentorOptions.RequiresApproval is a predicate on the tool name: when it returns true, that tool requires confirmation. It works for any tool, including tools you do not own (MCP, skills, remote agents). See Governance.

  • Multimodal image input: EnableImageInput, AllowedImageTypes (default png, jpeg, gif, webp), MaxImageBytes (default 4 MB) and MaxImagesPerMessage (default 4), all validated again on the server: the copies on the widget only drive the checks in the browser. Rejected attachments are dropped with a warning, and the turn still runs. It requires a chat model with vision. New contracts MentorAttachment and MentorUserMessage, and IMentorOrchestrator.SendMessageAsync(text, attachments); a turn with only images is valid. The composer accepts file upload, clipboard paste, drag and drop and a remote URL. In the browser, it scales down an image larger than MaxImageBytes: to at most 2000 px, with the original type kept. Animated GIFs are not re-encoded.

  • MentorAgent.Blazor: WasmMentorOrchestrator and MentorHubClient gain SendMessageAsync(text, attachments).

  • MentorAgent.Server: POST /mentor/chat, accepting { "message": "...", "attachments": [ { "mimeType", "dataBase64" | "url", "fileName" } ] } (GET remains for text only). With EnableImageInput on, AddMentorAgentServer() raises HubOptions<MentorHub>.MaximumReceiveMessageSize to MaxImageBytes * MaxImagesPerMessage * 4/3 + 512 KB, scoped to the MentorAgent hub and only ever raising an existing value: keep the image options tight.

  • MentorAgent.Server: POST /mentor/cancel?connectionId=... stops a turn in progress from outside the hub. SignalR dispatches one hub invocation at a time per connection, so the CancelRequest hub method could only run after the turn it was meant to stop.

  • MentorAgent: MentorOptions.UseServiceManagedHistory, for providers that keep the conversation on the service (the Responses API, Foundry, Copilot Studio): the Agent Framework refuses to combine their conversation id with a local history provider. With it on, no history provider is installed, and MaxSessionMessages and EnableCompaction no longer apply.

  • MentorAgent: duplicate tool names among the filterable tools are reported at startup.

  • MentorAgent.Server: Breaking: the hub method SendMessage now takes a second argument, attachments. SignalR binds arguments by count, so every client must pass both: send null (or []) when there are no attachments. A one-argument invocation is rejected. (This release documented the argument as optional; corrected in 1.0.0-rc.3, BUG-051.)
  • MentorAgent.Abstractions: Breaking: ChatInput.OnSend is now EventCallback<MentorUserMessage> instead of EventCallback<string>. Update handlers to take a MentorUserMessage and read Text (and Attachments).
  • MentorAgent: tool filtering and model routing now decide once per turn instead of once per request, because providers that keep the conversation reject a change of tool list or deployment in the middle of a turn.
  • MentorAgent: provider-side errors that arrive inside the stream are logged at Error level with message, code and details, instead of a bare "Stream content: ErrorContent" line.
  • MentorAgent.Server: the RespondToApproval and CancelRequest hub methods are kept for backwards compatibility only (CancelRequest works only while the connection is idle). Use POST /mentor/approve and POST /mentor/cancel.
  • MentorAgent: ChatOptions was copied property by property in two middlewares, dropping Tools, so a page registering UI actions offered the model only those actions instead of the full tool list, and ConversationId, which broke every local tool call under service-managed history. Options are now cloned.
  • Stop never worked for SignalR clients, including the WebAssembly widget, because the CancelRequest hub method queued behind the SendMessage still streaming. WasmMentorOrchestrator.CancelCurrentRequest and the README client examples now use POST /mentor/cancel. Upgrade MentorAgent.Blazor and MentorAgent.Server together: the WebAssembly client's Stop needs the new endpoint, and the hosted-tools badge and image attachments need the server of this version (a mismatched pair falls back to the local badge option).
  • MentorAgent.Abstractions: a citation with no URL (a document matched in a vector store, a file produced by the code interpreter) rendered as a link to "#" that jumped to the top of the host page. The chip now has no href and is styled as non-interactive.
  • MentorAgent.Abstractions: a failure in the send itself (for example the transport rejecting the payload) left the chat with no reply, no error and no busy indicator. It now surfaces as an error bubble and clears the busy state.
  • MentorAgent.Abstractions: the A2A (indigo) and hosted-tools (amber) chips hard-coded pale text meant for the dark theme, and were nearly invisible on the Minimal (light) theme.
  • MentorAgent: tools invoked inside a Level-2 specialist or a Level-3 team bypassed the confirmation box and the RequiredRoles check, because those agents run their own function-calling loop inside the workflow. The gate is now attached to the function itself, so role checks, confirmation, action feedback, NavigateTo, OnToolResult, OnException and per-tool metrics apply at every level. Nested tools always use the blocking approval flow, even under HitlMode.Native; the user is asked exactly once.
  • MentorAgent: MentorMcpServer.RequiresConfirmation was documented but not enforced. Tools from such a server now require confirmation in both HITL modes.
  • MentorAgent: provider-hosted tools run on the provider and never pass through the function-calling middleware, so RequiredRoles, RequiresConfirmation and per-tool metrics do not apply to them. Hosted MCP servers can require approval through MentorHostedMcpServer.RequireApproval.
  • MentorAgent: the counter of MaxHostedToolCallsPerSession lives in the orchestrator scope. Over SignalR it spans the connection, while each POST /mentor/chat call is its own session, so a stateless HTTP client gets a cap per request, not per user.
  • MentorAgent: on Azure OpenAI, hosted image generation also needs the x-ms-oai-image-generation-deployment request header, which MentorAgent cannot add to an IChatClient that is already built. Attach it as a pipeline policy where you construct the AzureOpenAIClient. A startup log line restates this whenever image generation is on.

Published on NuGet on 24 July 2026 (UTC): MentorAgent 1.0.0-preview.3 (external site).

  • Token and cost dashboard: the admin-only MentorDashboard component (never shown in the end-user widget), over an IMentorMetrics snapshot (MentorMetricsSnapshot).
    • It attributes usage to each model: the cheap chat model, the strong routing model and the embedding model (MentorModelUsage, MentorModelKind).
    • It has hourly time series (MentorUsagePoint), a model selector, time charts in inline SVG (no JavaScript, CSP-safe, theme-aware), a cost table per model and the top actions.
    • Cost comes from the ModelPricing you supply (ModelPrice; there are no built-in prices).
    • History is kept for MetricsRetention (default 7 days). A pluggable IMentorMetricsStore (RAM only by default) adds persistence, saved every MetricsPersistenceInterval (default 30 s).
    • Labels are localized in 10 languages. In WebAssembly, pass the fetched snapshot and set the component's Language parameter.
  • MentorAgent.Server: GET /mentor/admin/metrics returns the metrics snapshot for headless dashboards, gated by MentorOptions.DashboardRole (default "Admin").
  • MentorAgent: model routing: StrongChatClient with RoutingStrategy (MentorRoutingStrategy.Semantic, Classifier, Cascade or Custom, the default), RoutingThreshold (default 0.35), RoutingComplexExemplars, RoutingClassifierClient, and the UseStrongModel and UseStrongModelAsync predicates.
  • MentorAgent: token and cost controls:
    • a token counter and a log line per call;
    • EmbeddingGenerator;
    • opt-in semantic tool filtering (EnableToolFiltering, ToolFilterMaxTools default 12, ToolFilterMinScore default 0.35);
    • opt-in history compaction (EnableCompaction, CompactionTokenThreshold default 4000, CompactionMaxTurns default 8);
    • memory ranked by embeddings (MemoryRelevanceFiltering). It requires EmbeddingGenerator and falls back to the last N; identity and preference facts are always kept.
  • MentorAgent: MentorOptions.MemoryAutoCapture (default true): after each turn, a dedicated small model call saves durable user facts (name, role, team, preferences), so memory no longer depends on the model calling the remember tool. Set it to false to avoid the extra call per user message.
  • MentorAgent: MentorOptions.EnableRichResponses (default true): the coordinator is asked to format tabular data as Markdown tables and enumerations as lists, which the widget renders safely (Generative UI, Level 1).
  • MentorAgent: middleware hooks: an output safety check (EnableOutputSafetyCheck) alongside the existing input check; InputGuardrail and OutputGuardrail; OnToolResult, to transform a tool result before it reaches the model; OnException; and ConfigureChatClientPipeline, to add your own delegating chat clients.
  • MentorAgent: OpenTelemetry observability: EnableObservability, ObservabilitySourceName (default "MentorAgent") and ObservabilityIncludeSensitiveData (prompt and response content, for development). It produces traces and metrics that follow the GenAI conventions for model calls, plus spans and counters per turn and per tool.
  • MentorAgent: structured outputs: IMentorStructured.GenerateAsync<T> returns a strongly typed result, with a JSON schema derived from T.
  • MentorAgent: evaluation kit: MentorEvaluator over the Agent Framework's native evaluation, running EvalCases (MentorEvalOptions, MentorEvalReport, MentorEvalResult) and gating on token budget and quality with report.ThrowIfFailed().
  • MentorAgent.Server: identity bridge: AddMentorAgentServer() passes the authenticated SignalR or HTTP principal to the core, so per-user memory, per-user rate limiting and RequiredRoles work for headless clients, not only for Blazor Server.
  • MentorAgent.Server: the coordinator is built once per SignalR connection instead of once per hub method call, so external MCP servers connect once and the conversation persists across messages.
  • MentorAgent: with MemoryAutoCapture on and a ChatClient configured, the remember tool and its prompt block are dropped. The forget tool is always available.
  • MentorAgent: the HITL confirmation message now spells out the concrete arguments the assistant is about to pass, over every transport (including the ConfirmationRequired event for headless clients). The full text is available as a tooltip.
  • MentorAgent: a slimmer system prompt that works better with prompt caching. RAG relevance relies on the vector search and RagMinScore alone.
  • MentorAgent.Abstractions: event handlers (@onclick, @onchange, @bind) in the shipped components compiled to literal HTML attributes and never fired, which broke the suggestion chips of WelcomePanel, the buttons of the confirmation box and the MCP and A2A status badges. Upgrade to get working handlers.
  • MentorAgent: the system prompt no longer includes a bare "User: not authenticated" line for anonymous users, which made the model invent authorization rules and refuse tools with no role requirement. Role-gated tools remain enforced by the middleware.

Published on NuGet on 22 June 2026 (UTC): MentorAgent 1.0.0-preview.2 (external site).

  • New package icon for all packages.
  • MentorAgent.Server: README: the HITL examples for Angular, Vue and .NET MAUI or console use POST /mentor/approve instead of the RespondToApproval hub call, which deadlocks, and every client example (React, Angular, Vue, MAUI) handles the McpServerStatusChanged event.
  • MentorAgent.Blazor: README: OnMcpServerStatusChanged is forwarded over the SignalR hub and fires on the client.

Published on NuGet on 22 June 2026 (UTC): MentorAgent 1.0.0-preview (external site).

  • First release under the MentorAgent name, as the successor of BlazorMentor. It targets .NET 10 and Microsoft Agent Framework 1.6.1. The packages:
    • MentorAgent: the core library and widget for Blazor Server and in-process hosts, AddMentorAgent();
    • MentorAgent.Server: AddMentorAgentServer() and MapMentorAgentServer(), exposing the /mentor-hub SignalR hub, the /mentor/chat SSE stream and POST /mentor/approve for headless clients such as React, Angular, Vue and .NET MAUI;
    • MentorAgent.Blazor: the Blazor WebAssembly and Auto client, AddMentorAgentBlazor() with HubUrl;
    • MentorAgent.Abstractions: shared components and contracts, installed transitively.
  • MentorAgent: MCP server: expose MentorAgent as an MCP server (McpServerEnabled, McpServerPath, ShowMcpStatus). Nothing read McpServerPath until 1.0.0-rc.11 (BUG-091): pass the path to MapMentorAgentMcp() instead.
  • MentorAgent: MCP client: consume external MCP servers configured through McpServers.
  • MentorAgent: A2A server: expose MentorAgent as an A2A agent (A2AServerEnabled, A2AServerPath, A2AServerUrl, ShowA2AStatus). Nothing read A2AServerPath until 1.0.0-rc.11 (BUG-091): pass the path to MapMentorAgentA2A() instead.
  • MentorAgent: A2A consumer: delegate to remote A2A agents through the handoff workflow (RemoteAgents, MentorRemoteAgent, with authentication Headers for each agent). Remote agents are listed in the coordinator's system prompt. MentorRemoteAgent.RequiredRoles is accepted but not enforced: a startup warning says the roles are not checked.
  • MentorAgent: Agent Skills with progressive disclosure (EnableSkills, SkillsFolder, [MentorSkill]).
  • MentorAgent: RAG through IMentorRagSource (UseRag, RagResultCount, RagMinScore, ShowRagSources).
  • MentorAgent: Level-3 group-chat teams, for deliberation among several agents before acting ([MentorTeam], [TeamMember]).
  • MentorAgent: detection of prompt injection and jailbreaks by a model (EnableSafetyCheck) and per-user rate limiting (RateLimitPerUser).
  • MentorAgent: memory context for user preferences (UseMemoryContext, MemoryContextCount).
  • MentorAgent: typed and async overloads for UI actions: RegisterUIAction<T>, RegisterUIActionAsync, RegisterUIActionAsync<T>.
  • MentorAgent: IncludeWorkflowExceptionDetails, to surface internal errors during development.
  • MentorAgent: a reworked system prompt compared with BlazorMentor: a Communication Style block, more natural memory instructions, and cleaner prompts for Level-2 and Level-3 agents.
  • MentorAgent: compared with BlazorMentor, the A2A consumer threw UriFormatException when a remote agent card contained relative SupportedInterfaces URLs, and the coordinator did not route to remote A2A agents after a successful connection.
  • MentorAgent: MentorRemoteAgent.RequiredRoles is not enforced: any user can reach a remote agent. The property was removed in 1.0.0-rc.13.
  • What's new — What changed in the current MentorAgent version, what to do when you upgrade, its known issues and limitations, and how versions are numbered.
  • Choose your packages — Which MentorAgent package to install for Blazor, MAUI, or a backend for React, Angular, Vue and mobile apps, and what each one contains.