Questa pagina non è ancora tradotta in italiano: qui la trovi in inglese.
MentorAgent 1.2.0 release notes
What MentorAgent 1.2.0 adds and fixes: only permitted actions reach the model, your own policies, who confirmed, the AI notice, and how to upgrade.
On this page
MentorAgent 1.2.0 was published on NuGet on 27 October 2026 (UTC). It is a minor version: it adds features and fixes defects. It has one intended break, in how a tool result becomes a generative card: see Breaking changes.
The five packages require each other at exactly this version: upgrade them together. MentorAgent 1.2.0 runs on .NET 10. To upgrade, see Upgrade from 1.1.0.
Highlights
Section titled “Highlights”- The model sees only the actions the user may run. An action that needs a role the user lacks is no longer offered, so the agent no longer announces it and then refuses it.
- Your code can decide too: action policies. A permission per company or per record, or a rule on the arguments, applied on every surface.
- Who confirmed, and every decision of the gate. A ledger of your writes can record who approved each one, and why a call was refused.
- A notice and a mark for AI-generated replies. For article 50 of the EU AI Act, shown by default in the widget.
- Generative cards need a declared type. A record of yours is no longer drawn as a card by its shape alone.
New features
Section titled “New features”Action policies
Section titled “Action policies”The roles say who may use an action. Many rules depend on the data instead: a permission per company or per record, or a limit on an amount. An IMentorActionPolicy, registered with AddMentorActionPolicy<T>(), decides whether a user may use an action and whether a call may run. It applies on every surface: the widget, the hub, the MCP server and A2A tasks, the specialists, the teams and the MCP servers that you consume.
public class CaseTeamPolicy : IMentorActionPolicy
{
// Whether the user may use the action: only the support team closes cases
public ValueTask<bool> IsAllowedAsync(
MentorActionRequest request, CancellationToken cancellationToken)
=> ValueTask.FromResult(
request.ToolName != "close_case"
|| request.User?.HasClaim("team", "support") == true);
// Before each call: a case that is already closed is not closed again
public async ValueTask<MentorActionVerdict> BeforeActionAsync(
MentorActionRequest request, CancellationToken cancellationToken)
{
if (request.ToolName != "close_case"
|| request.Arguments?.GetValueOrDefault("caseNumber")?.ToString()
is not { } caseNumber)
return MentorActionVerdict.Proceed;
var store = request.Services.GetRequiredService<ICaseStore>();
var status = await store.GetStatusAsync(caseNumber);
return status.Contains("closed", StringComparison.OrdinalIgnoreCase)
? MentorActionVerdict.Stop($"Case {caseNumber} is already closed.")
: MentorActionVerdict.Proceed;
}
}A policy can let a call proceed, ask for a confirmation or stop it, and the strictest answer wins. A policy that throws, or that does not answer within ActionPolicyTimeout, stops the call. See Action policies and observers.
Who confirmed, and every decision of the gate
Section titled “Who confirmed, and every decision of the gate”A record of who approved a change belongs in your ledger, next to the change. Inside an action that asked for confirmation, MentorActionConfirmation.Current says who confirmed it and when, with the ID of the confirmation and the tool. It works in Blocking and in Native mode, and it is null for an action that nobody confirmed:
public class CaseEscalation(ILogger<CaseEscalation> logger)
{
[MentorAction(
Description = "Escalates a support case to the second line",
RequiresConfirmation = true)]
public string EscalateCase(string caseNumber)
{
// Who confirmed this call, and when: null when nobody confirmed it
var confirmation = MentorActionConfirmation.Current;
logger.LogInformation(
"Case {Case} escalated, confirmed by {User} at {Time}",
caseNumber,
confirmation?.ConfirmedBy?.Identity?.Name,
confirmation?.ConfirmedAt);
return $"Case {caseNumber} escalated.";
}
}An IMentorActionObserver, registered with AddMentorActionObserver<T>(), receives every decision about a tool call, on every surface and for every agent: the outcome, a reason code that stays the same across versions, the tool, the agent, the session, the user and who confirmed. It never receives the arguments, and a decision never waits for it:
public class ActionAuditLog(ILogger<ActionAuditLog> logger) : IMentorActionObserver
{
public ValueTask OnDecisionAsync(
MentorActionDecision decision, CancellationToken cancellationToken)
{
logger.LogInformation(
"{Tool}: {Outcome} ({Reason}) for {User}, confirmed by {ConfirmedBy}",
decision.ToolName, decision.Outcome, decision.ReasonCode,
decision.User?.Identity?.Name ?? "anonymous",
decision.ConfirmedBy?.Identity?.Name ?? "nobody");
return ValueTask.CompletedTask;
}
}IMentorStateService.OnActionStarted also gives the technical name of the tool that starts, next to the text shown.
The list of your actions
Section titled “The list of your actions”A component that shows or checks your actions needs to see them as MentorAgent does. IMentorActionCatalog.GetActions() lists the actions of the coordinator, of the specialists and of the team members, with their roles, whether they ask for a confirmation, whether they only read, and whether the MCP server and the A2A card publish them.
// The writes that the MCP server publishes to every caller, for example
// to fail a test when one appears
public static IEnumerable<string> WritesPublishedToEveryone(
IServiceProvider services) =>
services.GetRequiredService<IMentorActionCatalog>().GetActions()
.Where(action => !action.ReadOnly
&& action.McpExposure == MentorMcpExposure.Published)
.Select(action => action.ToolName);A time limit on confirmations
Section titled “A time limit on confirmations”A confirmation box that nobody answers kept the action waiting. With ConfirmationTimeout, a box that nobody answers in time counts as rejected: the action does not run, and the model is told that nobody confirmed it in time. By default there is no limit, as before.
A notice and a mark for AI-generated replies
Section titled “A notice and a mark for AI-generated replies”Article 50 of the EU AI Act asks that people know when they talk to an AI system, and that generated content can be told apart. The widget shows a notice under its header, ShowAiDisclosure, with a default text in the ten languages, or yours in AiDisclosureMessage. Every reply of the model also carries a machine-readable mark: data-ai-generated="true" in the widget, "aiGenerated": true on /mentor/chat, the hub event ReplyStarted and aiGenerated on A2A. Whether the article applies to your application, and which words to show, is yours to decide.
A language per page
Section titled “A language per page”A site in more than one language needs the widget in the language of the page. <ChatWidget Language="…" /> gives one page a language of its own: the widget's texts, its voice, its tour and the assistant's answers follow it.
<ChatWidget Language="@_language" />
@code {
// From the route (/it/…) or from a language switch in your layout
[Parameter] public MentorLanguage? Lang { get; set; }
private MentorLanguage _language => Lang ?? MentorLanguage.English;
}Clients send it as language on /mentor/chat or with the hub method SendUserMessage. A2A and MCP stay on Language.
Other features
Section titled “Other features”- A theme that follows the system. A site with a light and a dark mode had to pick one theme for the widget.
MentorTheme.Autoshows the light theme,Minimal, or the dark one,Default, as the visitor's system asks. - The context of a request at the end of the conversation. With
SessionContextPlacementset toLastUserMessage, the page, its data and the time go with the user's last message, and the instructions stay the same through the session. A model that caches the prompt by its beginning, such as a local model, then answers sooner.
Improvements
Section titled “Improvements”- Roles: the model sees only the actions the user may run. At the start of every turn, MentorAgent decides which actions the user may run, and offers the model only those: on the coordinator, the specialists, the team members and the agents of an
IMentorAgentSource. The model is told that some actions are not available, without naming them, in the language of the turn. A call to an action left out is still refused, as before. Under Fixes you find what this fixes. Proactiveno longer closes with next steps. WithMentorshipLevel.Proactive, the answers no longer end with suggested next steps: the model offered steps that the application does not have (BUG-074). The explanations and the warnings stay. To bring the suggestions back, setProactiveNextStepstotrue.- The widget shows the AI notice by default. Under its header, the widget now says "You are talking to an AI assistant: its replies are generated automatically.", in the language of
Language. Write your own text withAiDisclosureMessage, or setShowAiDisclosuretofalse. - The hub sends
ReplyStartedbefore each reply. A client that does not register it keeps working, but SignalR logs a warning for every reply. Register it, even with a handler that does nothing, as the components of Any front end do. The WebAssembly client ofNovior.MentorAgent.Blazorregisters it. - Traces and logs. The
mentor.tool.*spans carry the outcome, the reason code, the confirmation and the surface, and a failed call sets the status of the span to error. A call refused for its roles is logged once, at Warning, in both modes. The MCP server tells apart, in its log, a call refused for its roles, an action that it never publishes and an unknown name. - A check of the public API. At pack time, every package is checked against the public API of 1.1.0. An intended break is listed under Breaking changes.
- Security and support policy.
SECURITY.mdsays that a vulnerability report is answered within 5 working days, on a best-effort basis, and how long each version gets security fixes: see Versioning and support.
Each defect has a severity from S1, the most severe, to S4: see Versioning and support.
Generative cards need a declared type
Section titled “Generative cards need a declared type”Breaking. Severity S3 (BUG-212). A tool result became a generative card by its shape alone: any object with a non-empty string kind. So a record of yours with such a property, for example a support ticket with a link that a customer wrote, was drawn as a card, the link became a button, and the other fields never reached the model.
Now a result is read for cards only when its method is declared to return them: MentorCard, or a sequence of MentorCard, directly or through a Task.
What to do. If a method returns cards as object, as a JsonElement built by hand or as a type of your own, declare its return type as MentorCard or IEnumerable<MentorCard>. Otherwise its cards are shown as text. A MentorCard that an OnToolResult hook returns is still a card. The result of an MCP tool never is.
The model is offered only what the user may run
Section titled “The model is offered only what the user may run”Severity S3 (BUG-200, BUG-201, BUG-205) and S2 (BUG-224). The coordinator's model was offered every action, including those the user had no role for. Asked for one, it announced it, and the check of the roles then refused it. Specialists, team members and the agents of an IMentorAgentSource had the same defect (BUG-205). Now each of them is offered only the actions that the user may run. With RequireActionForChangeRequests, such an action is no longer one that the first call can be required to make (BUG-201).
The notice that tells the model that some actions are not available was in English in every language, and in Italian the model still offered the action. The notice now follows the language of the turn, and tells the model not to offer such an action and not to use another tool in its place (BUG-224). A residue remains: see BUG-224.
Stop and confirmations
Section titled “Stop and confirmations”- BUG-204 (S2): a Stop pressed after the user confirmed an action, but before the action started, did not stop it. Now the action does not run, and the model is told that the user stopped the request.
- BUG-203 (S2): in
Nativemode, a tool that theRequiresApprovalpredicate gated after the coordinator was built ran with no confirmation. Now the confirmation box appears, as inBlockingmode. - BUG-208 (S3): in
Nativemode, the confirmation box of an action could take its text from another method with the same tool name, so the user was asked to confirm what the other method does. The box now reads as the method that the call runs, as the 1.1.0 notes said for both modes (BUG-188). - BUG-225 (S2): in
Nativemode, a model response with two calls of one ID broke the conversation until it was reset. Now the second call gets an ID of its own, except withUseServiceManagedHistory.
- BUG-202 (S2): the MCP server read the
RequiresApprovalpredicate once, at the first request. An action that the predicate gated after that stayed intools/listand ran for a caller that nobody could ask. Now the predicate is read for every list and every call. - BUG-198 (S3): a shared MCP server that connected but did not answer
pingwas opened and dropped again in a loop, and the turn never reached the model. Now it is left out for a while, like a server that is down, and a warning says so.
- BUG-197 (S2): on A2A 1.0.0-preview3, a turn delegated to a remote agent came back empty, with no error. Now MentorAgent declares streaming, and streams to a peer only when its card declares it.
- BUG-199 (S2): a caller that cancelled an A2A task was answered
Working, and the task went on. Now cancelling stops the task as Stop does, and the task endsCanceled. - BUG-210 (S2): a Stop pressed while a request was delegated to a remote agent did not tell the remote agent, which finished the task. Now MentorAgent cancels the task on the remote agent.
- BUG-211 (S3): a Stop during the first message, while the card of a remote agent was being read, kept that agent out of the session. Now the next message reaches it.
- BUG-226 (S2): an A2A caller told about the task at once (
ReturnImmediately) could become anonymous, so its actions with roles were refused. Now the caller is read when the task starts.
The widget
Section titled “The widget”- BUG-217 (S1): a message that held the text that the widget uses inside as a placeholder for a code block, such as
@@BMCODE7@@, threw out of the render. On Blazor Server the circuit ended, and the page stopped responding until a reload. The text may come from a user, or from the model repeating data that others wrote. Now it is shown as it is. - BUG-209 (S3): the links to the widget's stylesheet and script kept
?v=10in every release, so a returning visitor's browser could keep the files of the previous release. Now the links carry the package version. If you write the two links yourself, see Upgrade from 1.1.0. - BUG-213 (S3): under a Content-Security-Policy without
style-src 'unsafe-inline', such asdefault-src 'self', theDarkandMinimalthemes, aPrimaryColorand the colors of<MentorDashboard />were dropped. Now they work with any option. - BUG-215 (S3): a Markdown link in a reply was shown as raw text. Now an
httporhttpslink opens in a new tab. Any other address stays text. - BUG-216 (S3): a numbered list with a line of text between its steps started again from 1.
- BUG-214 (S4): IntelliSense described
MentorTheme.Defaultas a light theme.Defaultis dark glass, and the light theme isMinimal: seeTheme.
The onboarding tour
Section titled “The onboarding tour”- BUG-206 (S3): the tour was written from every action, including those that need a role, and
GET /mentor/touranswers anyone. Now it is written from the actions that need no role. - BUG-207 (S4): a visitor who closed the page while the model wrote the tour ended the generation, and every visitor got the built-in tour until a restart. Now the generation does not depend on any visitor.
Language and answers
Section titled “Language and answers”- BUG-221 (S3): with a
Languageother than English, the instructions that MentorAgent writes for the model were in English, and the model could copy them into its reply. Now they followLanguage. - BUG-223 (S2): with
RefuseOutOfScope, a short reply such as "Sì" to the assistant's question was judged on its own, and refused as out of scope. Now it is judged with the end of the assistant's last reply. - BUG-222 (S2):
RequireLookupForRecordQuestionshad no effect without semantic tool filtering, and the model could make up a list of records. Now, without the filter, the first call of a record question must be a declared read that the user may run, or a handoff.
Agent Framework 1.23 and later
Section titled “Agent Framework 1.23 and later”- BUG-195 (S2): an agent offered two tools with the same name failed every turn with "Duplicate tool name". Now each agent is offered one tool per name, the one that a call by that name runs, and a warning names the copies.
- BUG-196 (S2):
MentorDeclarativeOptions.ConfigurationSectiongave a definition of a specialist in YAML no values. Now the package loads the section itself, as before.
Fixes in the README
Section titled “Fixes in the README”- BUG-227 (S4): the option tables of the Server README left out
ConfirmationMessage, although the 1.1.0 notes said that every option was listed (BUG-163). Now a test checks both READMEs.
Security
Section titled “Security”This version fixes no security advisory.
Breaking changes
Section titled “Breaking changes”Generative cards only from a declared return type
Section titled “Generative cards only from a declared return type”- Previous behavior: any tool result with a non-empty string
kindwas drawn as a generative card. - New behavior: a result is read for cards only when its method declares
MentorCard, or a sequence ofMentorCard, as its return type, directly or through aTask. - Reason: a record of yours could be drawn as a card, with a link that someone else wrote as a button, and its other fields never reached the model (BUG-212).
- What to do: declare the return type of the methods that return cards: see the fix.
- APIs affected: the methods that return cards as
object, as aJsonElementor as a type of your own, withEnableGenerativeCardson.
Deprecations
Section titled “Deprecations”This version deprecates nothing.
Dependency updates
Section titled “Dependency updates”| Package | From | To | Why |
|---|---|---|---|
Microsoft.Agents.AI and Microsoft.Agents.AI.Workflows | 1.18.0 | 1.26.0 | The Agent Framework 1.26 line. In 1.26, AgentSessionStore.DeleteSessionAsync is abstract. |
Microsoft.Agents.AI.Declarative (in Novior.MentorAgent.Declarative) | 1.18.0-rc1 | 1.26.0-rc1 | The same line. |
Microsoft.Extensions.AI | 10.7.0 | 10.11.0 | It moves with Agent Framework. |
ModelContextProtocol, and ModelContextProtocol.AspNetCore in Novior.MentorAgent.Server | 1.3.0 | 2.3.0 | The MCP endpoint asks for the stateful transport, so it answers as before. A server that lists a tool without inputSchema is no longer connected. |
A2A, and A2A.AspNetCore in Novior.MentorAgent.Server | 1.0.0-preview2 | 1.0.0-preview3 | See A2A preview3 with MentorAgent 1.1.0. |
Known issues
Section titled “Known issues”The defects that are still open in 1.2.0, with what to do about each one, are on the Known issues page, together with the prerelease packages and the package versions to pin. The limits that are not defects are in Known limitations.
Upgrade from 1.1.0
Section titled “Upgrade from 1.1.0”- Upgrade the five packages together. Each package requires the others at exactly its own version.
- Check the methods that return cards. A method that returns generative cards must declare
MentorCardorIEnumerable<MentorCard>as its return type: see Generative cards need a declared type. - Register
ReplyStartedin your hub clients. A JavaScript, React, Angular or Vue client, or a .NET client of the hub, addsconnection.on("ReplyStarted", () => {}), orhub.On<MentorReplyStarted>("ReplyStarted", _ => { }). Without it, SignalR logs a warning for every reply. - Decide about the AI notice. The widget now shows it by default. Keep it, write your own text with
AiDisclosureMessage, or turn it off withShowAiDisclosure = false. - Update the links you write by hand. If a page links
MentorAgent.cssandMentorAgent.jsitself, as theindex.htmlof a Blazor WebAssembly client or of a .NET MAUI app does, add?v=1.2.0to both links, and change it on every upgrade (BUG-209). - Check
Proactive. If you useMentorshipLevel.Proactiveand want the suggested next steps, setProactiveNextSteps = true. - Check your own session store and MCP servers. In Agent Framework 1.26,
AgentSessionStore.DeleteSessionAsyncis abstract: anAgentSessionStoreof your own implements it. An MCP server that lists a tool withoutinputSchemais no longer connected, and a warning names it. - Remote agents on A2A. A 1.1.0 host that moves
A2AorA2A.AspNetCoreto 1.0.0-preview3 on its own cannot answer A2A tasks. Upgrade MentorAgent with them.
If you upgrade from 1.0.0, first read Upgrade from 1.0.0 in the 1.1.0 notes: 1.1.0 fixed a vulnerable SignalR dependency of the Blazor client (BUG-173). If you still use the MentorAgent.* packages, start from Move to the Novior.MentorAgent packages.
Full list of changes
Section titled “Full list of changes”Every entry of this version is in the 1.2.0 section of CHANGELOG.md (external site), which is also the release notes on NuGet (external site).
Vedi anche
Sezione “Vedi anche”- Release notes — Every stable MentorAgent version, newest first, with its date and what it brings; how versions are numbered and supported, and how dependencies are followed.
- MentorAgent 1.1.0 release notes — What MentorAgent 1.1.0 adds and fixes: your own confirmation text, rules per method, safer page changes and team approval, and how to upgrade.
- Known issues — The open defects of the current MentorAgent version and how to avoid them, the prerelease packages it depends on, and the package versions to pin.
- Known limitations — What MentorAgent does not do by design, as opposed to a defect: platforms, hosted tools, open endpoints, default checks and A2A chains.
- Troubleshooting — Fix common problems with MentorAgent: startup errors, blocked requests, roles, confirmation, local models. And where to get help or report a bug.
