Skip to main content

Mapping the Minos decision types

This page sets the Minos decision types next to the experimental decision abstractions in Microsoft.Extensions.AI, as they are at the commit in tools/upstream/decisions-pin.json. Microsoft.Extensions.AI decisions explains the pin and the status of the upstream API. Both sides name their main types the same way (IDecisionClient, DecisionRequest, DecisionResponse, DecisionClientMetadata), so every identifier below says which side it is from. Upstream types are in the Microsoft.Extensions.AI namespace, Minos types in Minos.

How to read the tables​

The Fit column has three values:

  • one to one: the two sides mean the same thing and hold the same values. The adapter copies or renames the value.
  • with a loss: the adapter has to convert, and the row says what goes wrong in the conversion: something is dropped, refused, derived or assumed, or one side accepts values the other side rejects.
  • no counterpart: only one side has it. The row says what the adapter does instead.

The Adapter column describes the two adapters in the project Minos.NET.Extensions.AI.Decisions. They are in the repository and built, but not published until Phase 11.3; its README says how to build them:

  • Over upstream is the Minos IDecisionClient that wraps an upstream client. Minos callers and Minos pipeline stages call it.
  • Over Minos is the upstream IDecisionClient that wraps a Minos client. Code written against the upstream API calls it.

Some Minos values have no upstream slot. Over Minos writes them to the upstream AdditionalProperties of the answer or the response, under keys that start with minos., and Over upstream reads those keys back when they are there. With that rule, a Minos answer that goes to upstream and back comes back the same. A value from a real upstream provider has no such keys, so for it the rows below say what Over upstream assumes.

Client interface and GetService​

MinosUpstreamFitAdapter
Minos: IDecisionClientUpstream: IDecisionClientwith a lossThe two interfaces have the same two members, an evaluation call and GetService, and both are IDisposable. The evaluation calls differ as the next row describes.
Minos: IDecisionClient.EvaluateAsyncUpstream: IDecisionClient.GetResponseAsyncwith a lossMinos returns a ValueTask of Result<DecisionResponse, DecisionError> and reports a failed call as a value. Upstream returns a Task<DecisionResponse> and throws. Minos takes the model on the request; upstream takes it on a separate DecisionOptions. Over upstream catches the exceptions and returns them as DecisionError, as the Errors table describes. Any other exception, apart from cancellation, is returned as Http with no status code, as a non-transient DecisionClientException is, with the exception kept in DecisionError.Exception. Over Minos throws for a failed result: only a null request throws at the call, and every other failure, a disposed client and a state Minos cannot hold included, faults the returned task. Cancellation throws OperationCanceledException on both sides and passes through unchanged.
Minos: IDecisionClient.GetServiceUpstream: IDecisionClient.GetServicewith a lossSame signature: an object for the requested type and key, or null. Upstream documents the exact requested type; the Minos stages return an object that is an instance of the requested type, so a base type or interface finds a derived stage too. Each adapter keeps its own side's rule when it answers for itself. Over upstream answers for itself, then asks the upstream client. Over Minos returns the upstream DecisionClientMetadata it builds and the Minos client it wraps, then asks the Minos client, so an upstream caller can reach the Minos pipeline stages.
Minos: DecisionClientExtensions.GetServiceUpstream: DecisionClientExtensions.GetServiceone to oneBoth are the typed GetService<TService> shortcut over the interface method. The adapters need nothing for it; it inherits the lookup rule of the interface method.
Minos: DecisionClientExtensions.GetRequiredService—no counterpartUpstream has no throwing variant. Nothing to adapt: it works on top of Over upstream as on any Minos client.
Minos: IDecisionClient.DisposeUpstream: IDecisionClient.Disposeone to oneBoth come from IDisposable. Each adapter owns the client it wraps and disposes it, as a Minos DelegatingDecisionClient does.
Minos: DecisionClientExtensions.EvaluateAsync, Minos: IQuestionSet<TSelf>, Minos: QuestionSetUpstream: DecisionClientExtensions.GetResponseAsync, Upstream: DecisionDefinition, Upstream: DecisionResultBindingwith a lossThe typed layers differ: Minos generates a typed question set from a [Questions] type, and upstream builds a DecisionDefinition<TResult> with a builder and binds the answers to a result type. The adapters do not convert one typed layer into the other. Each typed layer is an extension over its own side's neutral call, so the Minos typed calls work on top of Over upstream and the upstream typed calls work on top of Over Minos.

Request, state and options​

MinosUpstreamFitAdapter
Minos: DecisionRequestUpstream: DecisionRequestwith a lossBoth hold the questions and the state. The Minos request also holds the model, images, the retry attempt and a deadline; upstream has none of these on the request.
Minos: DecisionRequest.Definition, Minos: QuestionSetDefinition.QuestionsUpstream: DecisionRequest.Questionswith a lossBoth are an ordered list of questions with unique ids, compared ordinally. Upstream refuses an empty list; Minos accepts a QuestionSetDefinition with no questions. Over upstream returns Validation before sending for an empty set, with the message "The request has no questions." and no QuestionFailure, as the Minos chat client adapter does. Over Minos builds a new QuestionSetDefinition from the upstream questions on each call.
Minos: DecisionRequest.State, Minos: DecisionContentUpstream: DecisionRequest.Statewith a lossMinos state is text or a JSON string, object or array. Upstream state is any JSON value. Over upstream sends text as a JSON string and JSON as it is. Over Minos turns a JSON string back into text, as DecisionContent.FromJson does, and throws a DecisionClientException, not transient, before calling the Minos client for a number, true, false or null state, which Minos cannot hold. That is the same exception it throws for the other Minos refusals, Unsupported and InvalidQuestions.
Minos: DecisionRequest.ModelUpstream: DecisionOptions.ModelIdone to oneBoth are the requested model id, or null for the provider's default. The adapters move it between the Minos request and the upstream options.
Minos: DecisionRequest.Images, Minos: DecisionImage—no counterpartUpstream requests carry no images. Over upstream returns Unsupported before sending for a request with images, as a Minos provider without image support does with MIN206.
Minos: DecisionRequest.RetryAttempt—no counterpartUpstream has no attempt number. Over upstream drops it; Over Minos sends 0.
—Upstream: DecisionOptions.AdditionalProperties, Upstream: DecisionOptions.RawRepresentationFactoryno counterpartMinos has no provider-specific options on the request. Over Minos ignores them. Over upstream sends none.
—Upstream: DecisionOptions.Cloneno counterpartMinos copies a request with with, since DecisionRequest is a record. Nothing to adapt.

Question kinds​

MinosUpstreamFitAdapter
Minos: QuestionKindUpstream: DecisionKindone to oneThree kinds on each side, in the same order. The adapters rename the values as the next three rows list.
Minos: QuestionKind.Noul, Minos: QuestionDefinition.NoulUpstream: DecisionKind.Binary, Upstream: BinaryDecisionQuestionwith a lossA yes-or-no question on both sides. Minos requires instructions content but accepts empty text; upstream requires instructions that are not blank unless both the true and the false description are given. Over upstream returns Unsupported before sending for a Noul whose instructions are blank text and that lacks either description. Over Minos sends empty instructions when upstream has none. Instructions and descriptions convert as the rows below describe.
Minos: QuestionKind.Choice, Minos: QuestionDefinition.ChoiceUpstream: DecisionKind.Choice, Upstream: ChoiceDecisionQuestionwith a lossOne option from a fixed set, with unique ids and at least one option. Upstream defines the set as unordered and keeps the candidate list in order only for the wire and for the order of the probabilities; Minos keeps the options in wire order too. The options convert in that order, as the option rows below describe.
Minos: QuestionKind.Score, Minos: QuestionDefinition.ScoreUpstream: DecisionKind.Score, Upstream: ScoreDecisionQuestionwith a lossOrdered levels, lowest first, on both sides. Upstream requires at least two levels; QuestionDefinition.Score accepts one, and Over upstream returns Unsupported before sending for it. The level ids differ, as the level row describes.
Minos: QuestionDefinition.KeyUpstream: DecisionQuestion.Idwith a lossBoth are the caller's id for the question, unique and compared ordinally. Minos refuses only an empty key; upstream also refuses a key of white space only. Over upstream returns Unsupported before sending for such a key. Every upstream id is a valid Minos key.
Minos: QuestionDefinition.InstructionsUpstream: DecisionQuestion.Instructionswith a lossMinos instructions are DecisionContent, text or JSON; upstream instructions are a string. Over upstream sends text as it is and JSON as its JSON text, so the provider no longer knows the instructions were JSON. Over Minos sends the string as text.
Minos: QuestionDefinition.WhenTrue, Minos: QuestionDefinition.WhenFalseUpstream: BinaryDecisionQuestion.TrueDescription, Upstream: BinaryDecisionQuestion.FalseDescriptionwith a lossWhat a yes and a no answer mean, optional on both sides. Content becomes a string as for the instructions. Upstream refuses a description of white space only, and Over upstream returns Unsupported before sending for one.
Minos: OptionDefinition, Minos: OptionDefinition.KeyUpstream: DecisionCandidate, Upstream: DecisionCandidate.Idwith a lossA Choice option and its id, unique and compared ordinally. Minos refuses an empty key; upstream also refuses white space only, and Over upstream returns Unsupported before sending for one.
Minos: OptionDefinition.Criterion, Minos: Criterion.Description, Minos: Criterion.JsonContentUpstream: DecisionCandidate.Descriptionwith a lossUpstream requires a description for every candidate; Minos allows an option without a criterion. Over upstream sends the option key as the description of an undescribed option, since the key is all a Minos provider sees for it, and sends a JSON criterion as its JSON text. Upstream refuses a blank description, so Over upstream returns Unsupported before sending for a Choice option or a Score level whose text criterion is empty or white space only. Over Minos sends the description as a text criterion.
Minos: Criterion.Examples, Minos: Criterion.NotFor—no counterpartAn upstream description is one string with no place for examples or exclusions. Over upstream returns Unsupported before sending for a criterion that has either, instead of folding them into the text in a form the provider was not trained on.
Minos: CriterionUpstream: DecisionScoreLevelwith a lossA Score level. Minos keys levels by position, "0", "1" and so on; upstream levels have caller ids. Over upstream sends the position keys as the level ids. Over Minos sends the levels in order and keeps the upstream ids, which it writes back on the answer's probabilities. A level's criterion converts as a Choice option's does.

Answers and distributions​

MinosUpstreamFitAdapter
Minos: DecisionResponse, Minos: DecisionResponse.AnswersUpstream: DecisionResponse.Answerswith a lossOne answer per question, in question order, on both sides. Minos answers are QuestionAnswer values that share one probability buffer; upstream answers are objects of a type per kind.
Minos: DecisionResponse.DefinitionUpstream: DecisionResponse.Requestwith a lossMinos keeps the question set the answers belong to; upstream keeps the whole request, state included. Over upstream checks that the upstream response's request has the state and the questions it sent, since the upstream check ValidateAgainst is internal, and returns InvalidResponse when they differ. It builds the Minos response on the request's own QuestionSetDefinition instance, which a Minos typed call checks by reference. Over Minos sets the request it was given.
Minos: QuestionAnswer.KeyUpstream: DecisionAnswer.QuestionIdone to oneThe id of the question the answer belongs to. Over Minos pairs each Minos answer with the upstream question at the same position and throws DecisionProtocolException when the answer's key is not that question's id, compared ordinally, as for any answer that does not match its question.
Minos: QuestionAnswer.KindUpstream: DecisionAnswer.Kindone to oneRenamed as in the question kinds.
Minos: QuestionAnswer.Probability, Minos: Noul.ProbabilityUpstream: BinaryDecisionAnswer.TrueProbabilityone to oneThe probability that the answer is yes, a finite number from 0 to 1 on both sides.
Minos: Noul.Value—no counterpartMinos reads a Noul as yes from a probability of 0.5. Upstream applies no threshold and has no yes-or-no value. Over Minos does not need it; Over upstream derives it from the probability.
Minos: QuestionAnswer.ChosenIndex, Minos: Choice.Value, Minos: KeyedChoice.ValueUpstream: ChoiceDecisionAnswer.SelectedCandidateIdwith a lossThe chosen option, as a position in Minos and as a candidate id upstream. No value is lost: both sides require the probabilities in option order, so the adapters convert between position and id through the question's options. Neither side requires the chosen option to be the most probable one, and the adapters keep it as it is.
Minos: QuestionAnswer.Probabilities, Minos: ProbabilityMap, Minos: KeyedProbabilityMapUpstream: ChoiceDecisionAnswer.Probabilities, Upstream: ScoreDecisionAnswer.Probabilities, Upstream: DecisionProbabilitywith a lossOne probability per option or level, in definition order. Minos holds plain numbers, keyed by the option; upstream holds id and value pairs. Minos checks only that each value is from 0 to 1. Upstream also requires the values to sum to 1, within a tolerance that depends on the declared precision. Minos providers report rounded values, so Over Minos declares TwoDecimalPlaces: upstream then accepts a sum within 0.005 per value, plus 0.000001, of 1, and treats each value as rounded by up to 0.005. A Minos distribution further off makes the upstream answer constructor throw DecisionProtocolException.
Minos: QuestionAnswer.Expected, Minos: Score.Expected, Minos: KeyedScore.ExpectedUpstream: ScoreDecisionAnswer.Score, Upstream: ScoreDecisionAnswer.ExpectedScorewith a lossThe Minos expected level is the probability-weighted mean level index, as the provider returns it, and is always set. Upstream keeps two values: Score, the provider's own scalar, which may be null, and ExpectedScore, computed from the distribution. Over upstream takes Score and falls back to ExpectedScore when it is null. Over Minos reports the Minos expected level as Score; upstream checks that it agrees with the distribution under the declared precision, and throws DecisionProtocolException when it does not. Under TwoDecimalPlaces the score may be off by 0.005, plus 0.000001, from the range of expected levels the rounded distribution allows; under HighPrecision it must match the distribution within 0.000001. Replaying the recordings of the Guardrails sample, 7 of its 15 Score answers fail that check under HighPrecision, for example a score of 2.97 for the distribution 0, 0, 0.02, 0.98, whose expected level is 2.98, and all 15 pass under TwoDecimalPlaces.
Minos: Score.Value, Minos: KeyedScore.Level—no counterpartMinos reports a chosen level for a Score, held in QuestionAnswer.ChosenIndex as for a Choice; the typed answer documents it as the most probable level, the lower one on a tie. An upstream score answer has no selected level. Over Minos writes it under minos.chosenLevel. Over upstream reads that key, and otherwise assumes the most probable level by that rule; the provider did not report a level.
Minos: Score.Normalized, Minos: KeyedScore.Normalized—no counterpartDerived from the expected level and the level count, so the adapters need nothing for it.
Minos: QuestionAnswer.Confidence, Minos: Choice.Confidence, Minos: Score.Confidence—no counterpartA Minos Choice or Score answer carries the provider's confidence; upstream answers have none. Over Minos writes it under minos.confidence. Over upstream reads that key, and otherwise assumes the probability of the chosen option, or of the most probable level for a Score. That is the rule the Minos chat client adapter uses, and it is an assumption: the provider did not report a confidence.
Minos: ProbabilitySource, Minos: QuestionAnswer.ProbabilitySource, Minos: DecisionResponse.ProbabilitySource—no counterpartMinos records how the probabilities were made: reported by the model, from token log probabilities, or stated in text. Upstream does not record it. Over Minos writes it under minos.probabilitySource, as one of the strings model, logprobs or verbalized, the names Minos recordings use. Over upstream reads that key, returns InvalidResponse for any other value, and otherwise reports Model. That is an assumption: an upstream provider may have derived its probabilities from log probabilities, and nothing in the upstream answer says so. The declared precision says how the values were rounded, not how they were made, so the adapter does not derive the source from it.
—Upstream: DecisionPrecision, Upstream: DecisionAnswer.Precision, Upstream: DecisionProvenance.Precisionno counterpartUpstream declares how the provider rounded the probabilities: not at all, to four decimal places or to two. Minos does not record rounding. Over upstream drops it and keeps the values as reported, which Minos accepts, since it does not check the sum. Over Minos declares TwoDecimalPlaces on every answer, as the distribution and score rows describe.
—Upstream: DecisionAnswer.AdditionalProperties, Upstream: DecisionResponse.AdditionalPropertiesno counterpartMinos answers and responses have no extension data. Over upstream reads the minos. keys and drops the rest. Over Minos writes only minos. keys.
—Upstream: DecisionAnswer.RawRepresentation, Upstream: DecisionResponse.RawRepresentationno counterpartMinos keeps no raw provider object. Over upstream drops it; Over Minos sets the Minos DecisionResponse as the response's raw representation and leaves the answers' empty.
—Upstream: DecisionFeatureSchema, Upstream: DecisionFeatureProjectionno counterpartUpstream can project complete answers onto named numeric features. It runs on an upstream response, so it works on top of Over Minos. Minos has no counterpart.

Errors​

MinosUpstreamFitAdapter
Minos: DecisionErrorUpstream: DecisionClientExceptionwith a lossMinos returns a failure as a value with a kind, a message and optional detail. Upstream throws an exception that says only whether the provider called the failure transient. DecisionClientException is sealed, so a Minos exception type cannot derive from it. For every kind except InvalidResponse, which the row for that kind covers, Over Minos throws a DecisionClientException with the error's message, whose inner exception is a MinosDecisionException from the adapter package that carries the DecisionError, so an upstream caller that catches DecisionClientException still catches it.
Minos: DecisionError.MessageUpstream: DecisionClientException.Messageone to oneThe failure's message, copied. Neither adapter adds the request state to it.
Minos: DecisionError.Kind, Minos: DecisionErrorKindUpstream: DecisionClientException.IsTransientwith a lossThirteen kinds against one flag. Over Minos sets IsTransient with DecisionRetryOptions.IsTransient: rate limiting, overload, server failures, network failures, time-outs and HTTP 408. Over upstream maps a transient failure to Server and any other to Http, with no status code, so the Minos retry stage retries the first and not the second, and the fallback stage moves on after both. The names describe HTTP causes that the upstream exception does not report.
Minos: DecisionErrorKind.InvalidResponseUpstream: DecisionProtocolExceptionwith a lossA provider result that breaks the protocol. Over upstream maps DecisionProtocolException, including the one an upstream constructor throws for a bad distribution, to InvalidResponse and keeps its message. Over Minos throws DecisionProtocolException, not DecisionClientException, for InvalidResponse, with the MinosDecisionException that carries the DecisionError as its inner exception, so the status code and request id stay reachable there.
Minos: DecisionError.StatusCode, Minos: DecisionError.RetryAfter, Minos: DecisionError.Detail, Minos: DecisionError.RequestId—no counterpartUpstream exceptions carry none of these. Over upstream leaves them empty. Over Minos keeps them only on the DecisionError that the inner MinosDecisionException carries.
Minos: DecisionError.ExceptionUpstream: DecisionClientException.InnerExceptionwith a lossOver upstream sets the caught exception as the error's exception. Over Minos sets the MinosDecisionException that carries the DecisionError as the inner exception, not the Minos error's own exception.
Minos: DecisionError.Failures, Minos: QuestionFailure, Minos: DecisionErrorKind.Unsupported, Minos: DecisionErrorKind.InvalidQuestions—no counterpartMinos reports each question that breaks a rule as a failure with a rule code. Upstream constructors throw ArgumentException for an invalid question or request. Over upstream checks before sending every rule this page marks with Unsupported: images, a blank question, option or level id, a blank description, a Noul with blank instructions and no description pair, a one-level Score, and examples or exclusions on a criterion. It returns Unsupported with one QuestionFailure per question and rule: MIN206 for images, MIN207 for a blank id, MIN208 for a blank description, MIN209 for the Noul, MIN210 for a one-level Score and MIN205 for examples or exclusions. An empty set is refused before these checks with Validation, as the request row says. Over Minos throws DecisionClientException, not transient, for these kinds.
Minos: DecisionErrorKind.Refused, Minos: DecisionErrorKind.Timeout, Minos: DecisionErrorKind.Disposed—no counterpartUpstream has no refusal, time-out or disposal error. Over Minos throws DecisionClientException, transient for Timeout only. Over upstream never returns Refused; a disposal while a call is in flight returns Disposed, as the Minos interface documents, and a call after disposal throws ObjectDisposedException.

Metadata and capabilities​

MinosUpstreamFitAdapter
Minos: DecisionClientMetadataUpstream: DecisionClientMetadatawith a lossBoth describe the provider and are returned by GetService. Upstream also lists the supported kinds; Minos keeps those on DecisionCapabilities and has a cache scope.
Minos: DecisionClientMetadata.ProviderNameUpstream: DecisionClientMetadata.ProviderNamewith a lossMinos requires a provider name; upstream allows null. Over upstream uses the upstream name, or the fixed adapter name upstream when it is null.
Minos: DecisionClientMetadata.EndpointUpstream: DecisionClientMetadata.ProviderUrione to oneThe provider's address, or null.
Minos: DecisionClientMetadata.DefaultModelUpstream: DecisionClientMetadata.DefaultModelIdone to oneThe model used when the request names none, or null.
Minos: DecisionCapabilities, Minos: DecisionCapabilities.QuestionKinds, Minos: QuestionKindsUpstream: DecisionClientMetadata.SupportedKindswith a lossThe kinds the provider accepts: flags in Minos, a list upstream. Upstream null means unknown; a Minos client resolves every capability. Over upstream reports All when the list is null, which assumes the provider accepts every kind, and checks the kinds before sending when the list is there. Over Minos lists the kinds of the Minos capabilities.
Minos: DecisionCapabilities.MaxQuestions, Minos: DecisionCapabilities.MaxChoiceOptions, Minos: DecisionCapabilities.SupportsImages, Minos: DecisionCapabilities.SupportsModelListing—no counterpartUpstream metadata has no limits and no image or model listing support. Over upstream reports MaxQuestions and MaxChoiceOptions as null, which in the resolved capabilities a Minos client returns from GetService means no limit, and SupportsImages and SupportsModelListing as false. Over Minos still returns the Minos DecisionCapabilities from GetService.
Minos: DecisionResponse.ModelUpstream: DecisionProvenance.ModelIdone to oneThe model that answered, or null when the provider did not say.
Minos: DecisionResponse.IdUpstream: DecisionProvenance.ResponseIdone to oneThe provider's id for the response, or null.
—Upstream: DecisionProvenance.ProviderName, Upstream: DecisionProvenance.ProviderUrino counterpartA Minos response does not name its provider; the client metadata does. Over upstream drops them. Over Minos fills them from the Minos client metadata.
Minos: DecisionResponse.UpstreamProvider—no counterpartThe host an aggregator routed the call to. Upstream provenance has no such field, and its provider name is the provider itself, not the routed host. Over Minos writes it under minos.upstreamProvider.

Minos-only parts​

MinosUpstreamFitAdapter
Minos: DecisionClientBuilder, Minos: DelegatingDecisionClient—no counterpartAt the pinned commit, upstream has no builder and no delegating base for decision clients. A Minos pipeline is built on top of Over upstream as on any Minos client, and Over Minos exposes a whole Minos pipeline as one upstream client.
Minos: RetryingDecisionClient—no counterpartRetries by error kind, so on top of Over upstream it retries what the provider called transient, as the Errors table maps it.
Minos: EscalatingDecisionClient, Minos: FallbackDecisionClient, Minos: ConfidenceThresholds—no counterpartRouting between deciders by certainty or by failure. Upstream applies no thresholds. On top of Over upstream these stages read the certainty they need from the confidence and the probabilities, with the assumptions in the answers table.
Minos: DecisionResponse.Path, Minos: DecisionPath, Minos: QuestionRoute, Minos: DecisionCall—no counterpartWhich client answered each question and why, and each call a routing stage made. Over Minos writes the path under minos.path on the response as a JSON object, not as the Minos object, so the upstream response still serializes with AIJsonUtilities.DefaultOptions and without reflection. Its names are camelCase and null members are left out: routes holds one object per question with key, answeredBy, reason, primaryCertainty and targetCertainty, and calls one object per call with clientName, model, isCached, status, errorKind, inputTokens, outputTokens and cost. reason, status and errorKind are the Minos enum names in camelCase, such as confident, fellBack, answered and rateLimited. A call cost that is not a finite number is written as the string NaN, Infinity or -Infinity. The path's internal routing telemetry is left out on purpose: it is not public data and feeds only the routing stage's own spans and metrics. Over upstream sets no path; a routing stage above it sets its own.
Minos: DecisionRequest.Deadline—no counterpartThe time by which a routing stage must have its answer. Upstream requests have no deadline. The routing stages above Over upstream enforce it by cancelling the call they make, and the adapter passes the cancellation on. Over Minos sends no deadline.
Minos: DecisionResponse.Usage, Minos: DecisionUsageUpstream: DecisionResponse.Usage, Upstream: UsageDetailswith a lossToken usage on both sides; the next three rows give the parts.
Minos: DecisionUsage.InputTokens, Minos: DecisionUsage.OutputTokensUpstream: UsageDetails.InputTokenCount, Upstream: UsageDetails.OutputTokenCountwith a lossMinos counts in int, upstream in long. Over Minos widens. Over upstream narrows, and leaves a count above int.MaxValue empty.
Minos: DecisionUsage.Cost—no counterpartThe reported cost of the call. UsageDetails has token counts only. Over Minos writes it under minos.cost. It refuses a Minos response whose cost is negative or not a finite number, as it refuses answers upstream rejects: it throws DecisionProtocolException with a message that names the cost but not its value, and the inner MinosDecisionException carries an InvalidResponse error. So no invalid cost reaches the upstream caller.
—Upstream: UsageDetails.TotalTokenCount, Upstream: UsageDetails.CachedInputTokenCount, Upstream: UsageDetails.ReasoningTokenCount, Upstream: UsageDetails.AdditionalCountsno counterpartMinos keeps input and output counts only. Over upstream drops the rest. Over Minos sets the total to the sum when both counts are known.
Minos: CachingDecisionClient, Minos: CachingDecisionClientBuilderExtensions.UseCaching, Minos: DecisionResponse.IsCached, Minos: DecisionCall.IsCached, Minos: DecisionClientMetadata.CacheScope—no counterpartCaching, with UseCaching from Minos.NET.Caching. Upstream has no cache stage. CachingDecisionClient works on top of Over upstream, and its key takes the provider name and the default model from the metadata Over upstream reports. Over Minos writes IsCached under minos.isCached.
Minos: RecordingDecisionClient, Minos: RecordingDecisionClientBuilderExtensions.UseRecording—no counterpartRecording, from Minos.NET.Recording. Upstream has no recording. The stage records on top of Over upstream as on any Minos client.
Minos: LoggingDecisionClient, Minos: OpenTelemetryDecisionClient—no counterpartLogging and OpenTelemetry stages. Upstream has none for decision clients at the pinned commit. Both work on top of Over upstream.

Next​