AI
Verified against source (23)
Extensions/AttachmentExtensions.csExtensions/AbstractExtensions.csExtensions/LabelExtensions.csExtensions/MessageExtensions.csExtensions/ImportFormExtensions.csExtensions/ReportExtensions.csExtensions/ImportFileExtensions.csExtensions/QueueObjectBatchExtensions.csqbo4.AI.Bridge/AiBatchEngine.csqbo4.AI.Bridge/AiDocumentBatchEngine.csqbo4.AI.Bridge/ReadOnlySqlGuard.csqbo4.AI.Bridge/SqlAgentOrchestrator.csqbo4.AI.Bridge/AiBridgeOptions.csUsage/LedgerUsageHandler.csqbo4.AI/CompleteManager.csqbo4.AI/GenerativeAI.csExtensions/ServiceCollectionExtensions.csExtensions/ServiceCollectionExtensions.csExtensions/ServiceCollectionExtensions.csExtensions/ServiceCollectionExtensions.csExtensions/ServiceCollectionExtensions.csConfig/CustomRoutes.configAttachment/Attachment.Search.xslt
AI methods are ordinary QBO operations, added to modules as extension methods. They follow the standard route pattern:
/api/{module}/{operation}runs synchronously on the web server./api/{module}/queue/{operation}queues the operation for an app server. The document menu’s Classify and Transcribe options use the queued form; use it for anything that touches many records.
Every call runs as the authenticated user, against records that user can reach.
Choosing a model
Section titled “Choosing a model”Most methods take an agent name in AgentName (AiName is accepted as a synonym). There are two registries behind that name:
| Registry | Interface | Used by | Configured in |
|---|---|---|---|
| Agents | IAgentManager → IChatClient |
Review, update, document import, form completion, the AI modal and import engines, batch engines, aitoquery |
GenerativeAI:Agents:{Claude|Gemini|OpenAI|Bedrock}, plus AiAgent rows in the database |
| Completion services | ICompleteManager → IComplete |
Classify, label, reply drafting, the AI score engine, web-search aiimport |
Provider sections such as OpenAI and Google:Gemini |
Completion services fall back to the configured default when no name is passed. Agent-based methods require a name, except aitoquery, which defaults to the SQL agent.
Chat options
Section titled “Chat options”On agent-based methods, any parameter prefixed Chat_ binds to the request’s chat options, for example Chat_Temperature=0 or Chat_MaxOutputTokens=4000. Chat_ parameters that aren’t chat options travel with the request as tags; Chat_LedgerID is how you post token cost to a ledger (see Token cost tracking).
Operations
Section titled “Operations”| Operation | Module | What it does | Key parameters |
|---|---|---|---|
aiclassify |
attachment |
Sets AttachmentTemplateID by classifying the description against template descriptions. OCRs first when the description is empty and OcrCommand is configured. |
ID (list allowed), AgentName, DefaultTemplateID, Template_* filters, Template_nocache |
aitranscribe |
attachment |
Transcribes an mp3 (audio/mpeg) with the configured transcription service (OpenAI) and appends the text to Description. Optionally calculates a score afterward. |
ID, ScoreTemplateID |
ailabel |
any | Adds a CollectionMember for each label (collection) that applies, from labels whose SourceObject is this table. |
ID, AgentName, Prompt, LabelName, Label_* filters |
aireview |
any | Reviews the record’s summary, plus its file if it is a document and any AttachmentIDs, and saves a Message bound to the record. |
ID, AgentName, Template or MessageTemplateID, MessageType, AttachmentIDs |
aiupdate |
any | Sends the record’s summary (and its file, for documents) and sets fields from the JSON response. | ID, AgentName, Template (import template) or MessageTemplate, IncludeXml |
aiupdatexml |
any | Like aiupdate, but writes response keys that aren’t table columns into XmlData. |
Same as aiupdate |
aiimport |
any | Imports records the model returns. With a document (AttachmentIDs, or called on an attachment) it uses an agent; otherwise it asks a completion service to research the prompt. |
Prompt, AgentName, AttachmentIDs, SqlColumns, Preview, AddMessage, SubscriberURN, any column value |
aicomplete |
importform |
Fills a form’s standard fields and question answers from its parent record. | ID, AgentName, MessageTemplateID |
airesponsedraft |
message |
Drafts an HTML reply to an inbound message. Returns it unsaved. | ID, AgentName, IncludeRecipients |
airesponsesave |
message |
Drafts and saves the reply without sending it. | Same as airesponsedraft |
airesponsesend |
message |
Drafts, saves, and sends the reply. | Same as airesponsedraft |
aitoquery |
report |
Turns a prompt into one validated read-only SELECT. |
Prompt, AgentName, ConnectionStringName |
Classify a document
Section titled “Classify a document”GET /api/attachment/aiclassify?ID=127&AgentName=Gemini&DefaultTemplateID=4GET /api/attachment/queue/aiclassify?ID=127,128,129&AgentName=GeminiCandidate templates default to every attachment template with a description. Narrow them with Template_ parameters, which are passed to the template search, and add Template_nocache=true after editing descriptions; the candidate list is cached per filter.
Review a record
Section titled “Review a record”GET /api/attachment/aireview?ID=1042&AgentName=DocumentReview&Template=Intake ReviewGET /api/contact/aireview?ID=88&AgentName=DocumentReview&MessageTemplateID=105&AttachmentIDs=1060,1061The message template’s body becomes the instructions. The model returns Message, BodyText (Markdown, also rendered to BodyHTML), Priority, Status, and MessageType, and QBO saves it as a message on the record.
Import records from a document or a prompt
Section titled “Import records from a document or a prompt”GET /api/contact/aiimport?AgentName=DocumentImport&AttachmentIDs=2207&Object=Organization&ObjectID=123&Preview=trueGET /api/contact/aiimport?Prompt=Who handles employment verification at this organization?&Object=Organization&ObjectID=123&ContactType=Employment VerificationThe prompt is extended with the target table’s columns (or SqlColumns) and asks for {Table}Collection / {Table}Item XML, with the source in SourceUrlFromAi. Every other parameter is added to each imported item, with substitution from the item, so VerificationSource={SourceUrlFromAi} works. SubscriberID defaults to the table name and the item’s own name field, for example quandis.ai-Contact-{Contact} for contacts. Unless AddMessage=false, the raw response is also saved as an AI Response message. Preview=true returns the XML without importing.
Draft a reply
Section titled “Draft a reply”GET /api/message/airesponsedraft?ID=5512&IncludeRecipients=trueThe prompt carries the parent record’s summary and the inbound body. The reply’s subject is prefixed RE:, it inherits type, priority, status, and secure-delivery settings, and ParentMessageID threads it. Without IncludeRecipients, it is addressed to the sender only.
Generate SQL
Section titled “Generate SQL”GET /api/report/aitoquery?Prompt=Open claims over 10000 by adjuster<AiToQuery> <Query>SELECT …</Query> <Message>Assumed "open" means no closed date.</Message></AiToQuery>The agent (default qbo-sql, from AiBridgeOptions.SqlAgent) answers with a fenced SQL block or with prose. Prose is returned in Message with no retry. SQL goes through ReadOnlySqlGuard, which parses T-SQL and rejects anything but a single SELECT (including SELECT … INTO and multi-statement batches), and then through sys.sp_describe_first_result_set on ConnectionStringName (default qbo.AdHoc), which binds the query without executing it. Failures trigger up to two corrective retries; after that the last SQL is returned with a warning in Message.
Scoring and import engines
Section titled “Scoring and import engines”| Engine | Plugs into | Notes |
|---|---|---|
AIScoreEngine |
Score templates | Text-based extraction from Attachment.Description (converted to text if empty) or Message/BodyText. Uses a completion service. |
AiModalEngine |
Score templates | Sends the original file as document content; also builds content from data reader rows. Uses an agent. |
AiImportEngine |
Import templates | Instructions in ImportFileTemplate.Description; target in AppliesTo; optional ContextClassName / ContextObjectID. Saves through ImportXmlAsync, so nested collections import with their parent. |
AiDocumentBatchEngine, ClassificationBatchEngine |
Import templates | Submit an Attachment/Search result as a provider batch and apply results per document. |
Engine parameters for score templates go in ScoreTemplate.EngineParameters (AgentName, UseConfidence, FileExpirationMinutes, ContentBuilders). When AgentName is omitted, the engine’s configured name minus the Engine suffix is used.
GET /api/score/calculate?ScoreTemplateID=12&Object=Attachment&ObjectID=2207Batch processing
Section titled “Batch processing”Claude, Gemini, and OpenAI agents, and Bedrock agents with batch enabled, support provider batch jobs (IBatchChatClient), typically at lower cost for work that isn’t urgent. QBO drives batches through its own queue and scheduler:
- Document batches. An import file using a batch engine searches attachments, submits one job (splitting oversized documents into chunks), and stores the provider’s batch ID on the import file.
ImportFile/AiBatchPollre-schedules itself everyPollIntervalMinutes(default 60) until the job completes, then invokes the template’sResultMethodonce per document. - Queue batches. The queue object’s
AiBatchDrainoperation reads up toMaxItems(default 1,000) messages from an input queue, each carrying aPromptand optionalInstructionsandCustomId, submits them as a job, and schedulesAiBatchPoll. On completion, theCallbackMethodSignatureruns once per result with the response attached.
aiupdate and aisave accept a completed batch response (ChatResponse) in place of a live call, so a batch ResultMethod can point straight at them.
Token cost tracking
Section titled “Token cost tracking”Agent calls report token usage (input, cached input, output, reasoning) to registered IUsageHandlers. Configuring GenerativeAI:LedgerUsage registers LedgerUsageHandler, which writes LedgerItems when a call carries a ledger:
GET /api/attachment/aireview?ID=1042&AgentName=DocumentReview&Template=Intake Review&Chat_LedgerID=310For each non-zero token type it saves a debit with Units set to the token type, UnitCount the token count, LedgerItemType the model ID, AmountMoney from the configured per-million rate, and a shared TransactionNumber (the conversation ID when present). Chat_LedgerTemplateItemID overrides the default line item per call; LedgerTemplateItemIDs maps each token type to its own line. Usage is posted only when the acting user was captured on the request thread; batch attributes are never trusted for identity.
Redaction
Section titled “Redaction”Completion services can redact before sending: list SSN under GenerativeAI:Redactors and Social Security numbers are replaced with placeholders in the prompt and restored in the answer. Redaction applies to the completion-service path (classify, label, reply drafting, the AI score engine, web-search import). It does not apply to agent-based methods, which send record summaries and original files; control what those see through the agent’s instructions, the record’s security, and your choice of provider.