Documentation
Table of Contents

How it works

Every IntentSharp call keeps one contract: on a value, a collection, a method marked [AIIntent], an intent from a file or a database question. The Overview draws it.

What you give

An intent in plain words, in code or in an intent file; any .NET value, sent in full and never cut ([JsonIgnore] keeps a member's value out, not its name); the type you want back, or a JSON schema chosen at run time; and, optionally, rules, examples, instructions, limits, the judge and the provider, on AIRequestOptions or in the file.

What you get back

Every call returns an AIResult<T>. Read Success before Value.

Member What it holds
Success True when an answer passed every check and the judge, when it ran, did not reject it. An unreadable verdict does not reject.
Value The checked value on success; the type's default otherwise.
Issues Every problem, with its Source, its attempt and its message.
Attempts One record per attempt that finished its checks: provider, model, tokens, time, reply and issues. A cached answer's record shows the tokens it first cost.
Usage Tokens for this call's model calls, judge calls included; a cached answer adds none, though its judge call does. A reply that a limit or a provider error stopped is counted only in the client's TotalUsage.
FromCache True when the answer came from the request cache. A judge, when on, still made one model call.

The client's TotalUsage and TotalModelCalls add up every model reply since it was built, judge replies and failed attempts included, but no cached answer; TotalModelCalls also counts EmbedAsync.

What is checked

Every answer is checked in your process before your code sees it.

  • Your type: required members present, no null your type does not allow, enum values by name. A refusal, a reply cut off at the output token limit and an empty reply fail.
  • Your rules: Require<T>, Validate<T>, and an intent file's rules and named validators. Their messages, and the message of a check that throws, go to the model on the next attempt, so keep secrets out of them.
  • The judge, when on: one more model call per answer that passed, set by JudgeMode (Never, OnRequest, the default, or Always). The default judge asks the primary provider, even when the request names another, and never falls back. An unreadable verdict accepts the answer and logs a Warning; a judge call that fails fails the call.

Most result types reach the provider as a strict schema; a dictionary, object, a JSON type, a type that contains itself, or a type with a member of one of these (not marked [JsonIgnore]) does not, and then only these checks hold the answer to your type. Ranges, lengths and patterns are never in the schema: check them in your rules. The model must fill every member and every schema property, so make one the input may not give nullable (DateOnly?, or a schema type that lists null), or the model invents it. For a schema chosen at run time, IntentSharp checks only that the reply is JSON and not null.

A failed check is retried with the previous reply and the findings; a refusal is not retried. A cached answer is checked against the current rules, and one that fails is replaced. A pass means the checks passed, not that the answer is right.

What leaves your process

Your intent, input, type descriptions, instructions, output description, examples and, on a retry, the previous reply (up to 6,000 characters) and the findings go to the provider you chose and to no one else: the primary; the fallback only after a transient error; or the provider a request or an intent file names, with no fallback. With the default judge on, the intent, the input and each passing answer also go to the primary. When AddIntentSharp or UseProvidersFromEnvironment finds both API keys, the second vendor becomes the fallback, so leave one unset to keep your data with one vendor. EmbedAsync, and a memory with an embedding provider, send their text to that provider; an agent tool's description and answers go to your agent's model. Tags never leave through the built-in or IChatClient providers; a provider of your own receives them. Your license key goes nowhere: it is checked in your process. Nothing goes to C2Consultants, and the rows a database question returns stay with you.

The client keeps each call in an in-process memory of its last 10,000 calls (the intent, the first 2,000 characters of the input, the reply and the tags), and writes nothing to disk unless you choose a SQLite memory (Memory, cache and rate limiting).

Limits

Limit Default What it counts When it is reached
MaxAttempts 2 Attempts: one request and its checks Success false, with the findings
MaxModelCalls 6 Attempts and judge calls; not cached answers, provider retries or the fallback Success false, Guardrail issue
MaxOutputTokens 4,096 Tokens of each reply The reply is cut off and fails
Timeout none The whole call Success false, Guardrail issue
MaxInputChars 200,000 Characters of the serialized input ArgumentException, no model call
Provider MaxRetries, Timeout 3, 120 seconds Resends after a 429, a 5xx or a transport error; each send Provider issue, or the fallback
Rate limiter wait 30 seconds A model call's wait for its turn Like a 429

Set MaxAttempts, MaxModelCalls, MaxOutputTokens and the time budget (DefaultTimeout) on IntentClientOptions, and override them for one call on AIRequestOptions (Timeout for the time budget). MaxInputChars is set on the client only, the provider's retries and send timeout on HttpProviderSettings (Providers), and the rate limiter's 30-second wait is fixed. Judge replies are capped at 1,024 tokens. Limits count calls, tokens and time, not money.

When a call fails

A wrong answer, a refusal, a provider error and a reached limit do not throw: Success is false and Issues says why. A call throws only for a mistake in the call, before any model call:

Exception When
ArgumentException An empty intent, input over MaxInputChars, or an unknown provider name.
ArgumentOutOfRangeException A limit out of range.
InvalidOperationException A method without a client parameter, outside client.AsAmbient().
IntentNotFoundException, IntentDisabledException, IntentShapeMismatchException, IntentSharpException An intent file: unknown name, enabled: false, a shape that does not fit T, or an unregistered validator or type.

Your own CancellationToken throws OperationCanceledException, and an exception from your own provider that is not an IntentSharp provider exception reaches your code. QueryAsync and UpsertAsync throw SemanticDatabaseException when no safe statement results (Database queries).