Documentation
Table of Contents

What is sent

IntentSharp runs inside your process. Apart from your own database and memory file, it sends data to one place: the model providers you configure. This page lists everything a call sends, and what it keeps, so that a security review can say what leaves the process. To see it for yourself, request by request, log it with Seeing every request.

Where it goes: your providers, and nowhere else

A call goes to the client's primary provider, or to the provider the request names. It goes to the fallback provider only when the primary fails with a transient error, or when your rate limiter would make it wait longer than 30 seconds; How a call works lists the errors. A request that names its provider never falls back.

AddIntentSharp and UseProvidersFromEnvironment set up a provider for each API key they find. AddIntentSharp reads the keys from configuration or from the OPENAI_API_KEY and ANTHROPIC_API_KEY environment variables, and UseProvidersFromEnvironment from those variables. With both keys set, one vendor is the primary and the other the fallback, even when your configuration names only one of them. To keep data with one vendor, leave the other key unset, or set FallbackOnTransientErrors to false (Providers).

The judge always asks the primary provider, or the judge you give the client, even when the request names another provider or the answer came from the fallback. To keep a request on the provider it names, also leave the judge off for it (no UseJudge, no judge: true in its intent file, and JudgeMode not Always), or give the client a judge of your own.

An intent file can name the provider its requests go to (its provider field) and turn the judge on (its judge field), among the providers you configured. Whoever can change the intent folder makes those choices, so treat write access to the folder as control over where those requests go.

  • The built-in OpenAI and Anthropic providers send to the vendor's API over HTTPS by default (api.openai.com, api.anthropic.com), or to the address you set: in HttpProviderSettings.BaseAddress, or on an HttpClient you supply, whose own base address wins. They go through your system proxy when one is configured. They send your provider API key to that address, and nowhere else.
  • A chat client provider (UseChatClient) hands the request to your IChatClient, which sends it wherever that client sends it.
  • A provider of your own sends what your code sends.
  • ScriptedProvider sends nothing: it answers in your process.

Nothing goes to C2Consultants. The license key is checked inside your process, with no network call, and the library sends no usage data, telemetry or error reports anywhere. Its log entries and its Activity stay in your process unless your application exports them. The license notices it logs for a key name the licensee, the license id, the edition, the number of developers and the key's dates.

On every attempt

Each attempt sends one request: a system message and one user message, plus the settings below. There is no chat history: a request carries nothing from other calls.

What Where it comes from
The intent The text you pass, or the intent of an intent file, with the white space at either end removed.
Your input, serialized The value you pass. Strings go as they are, dates and times in ISO 8601, a DataTable as a JSON array of rows, a DataRow as one JSON object, and a JsonNode, JsonElement or JsonDocument as its own JSON. Any other object goes as compact JSON, by its actual type, as System.Text.Json writes it: its public properties and its members marked [JsonInclude], with enum values as their names; members marked [JsonIgnore] are left out. The collection methods send each element by the collection's element type.
A description of your input's type The type's name, and the names and types of its members: every public property, including those marked [JsonIgnore] (their names, not their values).
A description of your result type The type's name, and the names and types of its members. For a text result, a request for plain text instead.
The result schema A strict JSON schema built from your result type, or the schema you pass for a shape chosen at run time. None for a text result, for a JSON result with no schema, and for a type a strict schema cannot express (Typed output lists them).
Your output description ExpectedOutputDescription, the ExpectedOutput of [AIIntent], an [AIGuardrail] of the kind GuardrailType.OutputRequirement on an intent method, or an intent file's outputRequirements.
Your system instructions SystemInstructions, the Description of [AIIntent], or an intent file's systemInstructions.
Your examples Each example's input and output, from AIRequestOptions.Examples or an intent file's examples.
The settings The model, when the request or the provider names one; the output token limit; the temperature, when you set one and the provider sends it (the built-in Anthropic provider sends it only when SendTemperature is on); and the response format.
IntentSharp's own instructions Fixed text that asks the model to carry out the intent on the input and to answer in the required form. A request log, as in Seeing every request, shows it in full; this page does not quote it.

Input longer than MaxInputChars (200,000 characters by default) is refused with an ArgumentException before any model call; it is never cut. The limit counts the serialized input only, so the request as a whole is longer: the intent, the descriptions, the schema, your instructions and your examples come on top. Your examples, your system instructions and the findings of a retry have no size limit of their own.

One call makes at most MaxModelCalls model calls (6 by default), attempts and judge calls together, and each one sends your input. Each model call to a built-in provider is at most 1 + MaxRetries HTTP sends (4 by default), and, when it falls back, as many again to the fallback. Neither the provider's own retries nor the fallback count toward MaxModelCalls.

Some methods add their own wording and data to the intent and the input:

  • The collection methods send the whole collection in one request. Map, filter, sort, group and map-values add their own instruction to your intent; reduce sends your intent as it is. Filter, sort and group send each element with its position in the list, and the model answers with positions. Map-values sends the dictionary's keys as text. See Collections.
  • AIConvertAsync and AIClassifyAsync send IntentSharp's own intent in place of one of yours. For AIClassifyAsync it names your enum's members, and your criteria follow it when you give them.
  • The database runtime sends your request, the SQL dialect, the schema-qualified name of each table it may use, and each column's name, type, primary-key and NOT NULL flags, plus its own instruction for the statement. A retry also sends the previous plan, with its SQL and the parameter values the model chose. It never sends rows: the rows a statement returns stay in your process. UpsertAsync sends the source data you pass, with the same description of its one table. See Database queries.

On a retry

An attempt after a failed one sends the same request with two additions:

  • The previous reply, up to its first 6,000 characters.
  • The findings: the message of every check that failed on that attempt. These include the messages of your own rules and validators, the problems a judge listed, and IntentSharp's own check messages.

Your rule and validator messages go to the model, so keep secrets and personal data out of them. When a validator throws, the exception's message becomes a finding and is sent on the next attempt, so catch exceptions in your validators and return a message of your own.

On a provider error

A provider error sends the same request again, unchanged. A built-in provider that meets a 429, a 5xx or a transport error sends it again itself (the counts are above), and a request that still fails with a transient error goes to the fallback provider when there is one; a built-in fallback retries in the same way. Providers lists which errors are retried and which fall back.

When the call ends on a provider error, the provider's error text, up to 2,000 characters of its reply, is in the result's Issues and FailureSummary, in the exception from GetValueOrThrow, and in the Warning a fallback logs. No further attempt follows, so the call does not send it to a model. An agent tool does pass it on to your agent's model, as below.

On a judge call

When the judge is on for a call, each attempt that passes the checks sends one more request, to the primary provider by default, including an attempt answered from the cache. It carries:

  • the intent, your serialized input and the description of its type;
  • the reply being judged;
  • your output description, when you set one;
  • IntentSharp's own instructions for the judge, and a schema for its verdict;
  • JudgeModel when you set it, and an output token limit of 1,024.

A judge call does not carry your system instructions or your examples. A judge of your own (WithJudge) sends what your code sends.

Other calls that send data

  • Embeddings. IntentClient.EmbedAsync sends the text you pass to the first provider that supports embeddings, which can be the fallback.
  • Memory with an embedding provider. A memory store you create with an embedding provider sends the intent text of each recorded call, and the text of each recall query, to that provider. The default memory never does: it keeps its entries in your process and sends nothing.
  • Agent tools. An intent tool made by AsAIFunction or AsAIFunctions sends data to the model that runs your agent, wherever its IChatClient sends it, besides the request IntentSharp sends to its own provider. The tool's description holds the intent file's description and its intent text. Each tool call's answer is the checked value, or the failure: the issue messages, or an exception's type and message. A failure can hold a provider's error text.

What stays on your machine

By default IntentSharp writes nothing to disk, apart from what you ask the database runtime to write to your own database.

  • The memory. Every client records each completed call that asked a model, failures included, in an in-process memory of the last 10,000 calls, unless you turn it off; a call answered from the cache is not recorded. Each entry holds the intent, the first 2,000 characters of the serialized input, the full final reply and the tags. Any code that holds the client can read the entries through client.Memory. Turn recording off with WithMemory(null), with IntentClientOptions.RecordInMemory set to false, or for one call with DoNotRecord. DoNotRecord does not keep the reply out of the request cache; set BypassCache as well for a call whose reply should not be kept. Memory, cache and rate limiting lists the fields.
  • A SQLite memory. One created with SqliteSemanticMemory, or by the IntentSharp:MemoryPath setting, writes the same fields, plus an embedding of each intent when it has an embedding provider, to the file at that path. The file is not encrypted and keeps every entry until ClearAsync removes them. Protect it with file permissions or disk encryption.
  • The request cache. None on the builder by default, and an in-process cache under AddIntentSharp. The built-in cache holds each provider reply in your process, for one hour by default.
  • Logs. IntentSharp never logs the serialized input, a whole request or a whole reply. Some lines carry part of a call's text; Logging and telemetry lists them.

What is never sent

  • Tags: the request's Tags and the tags an intent file adds to each run, which include the file's path, are never sent by the built-in or chat client providers. A provider of your own receives them on each request, so keep them out of what it sends. They are written to the memory, and with a SQLite memory to its file.
  • The code of your validators, and the rules of an intent file as rules. Only a failed check's message is sent, on the next attempt.
  • Your license key.
  • The memory's entries and the cache's replies, apart from the intent text a memory with an embedding provider sends.
  • Anything for a cache hit, unless the judge is on for the call: the judge still asks the primary provider about the cached answer. How a call works lists the calls that need no model.

What it does not cover

What a provider does with a request, such as how long it keeps it and whether it trains on it, is set by your agreement with that provider, not by IntentSharp. Choose the provider, its region and its data terms to fit your data. The Security page covers reporting a problem.