translate Available in: RU VI

QuotyAI Instructions & Automation

Instructions & Automation

Instructions are the backbone of your Sales Assistant’s behavior. They go far beyond simple text prompts β€” each instruction has a category that determines how and when it executes. Some instructions add context to the AI’s brain, others register tools it can use, and some run as deterministic code that triggers actions before or after every customer message.


The Problem With Simple Instructions

Most chatbot platforms let you write a list of instructions. The AI reads them all every time and tries to follow them. This works for simple cases, but it breaks down fast:

  • β€œSend the menu when someone asks about prices” β€” the AI might send it, might forget, or might send the wrong thing. It’s not reliable.
  • β€œMark the customer as β€˜paid’ after they receive an invoice” β€” the AI has to remember to do this every time. It’s easy to forget.
  • β€œOnly show weekend pricing rules on Fridays” β€” the AI gets confused when instructions contradict each other.

QuotyAI fixes this by giving each instruction a category that determines exactly how it behaves β€” as a prompt, a tool, a pre-condition, or automated code. You simply write what you want in plain language β€” the system determines the category, generates the deterministic code, and lets you preview it before it goes live.


Meet the Six Categories

Every instruction you write has a category. The category controls what happens with that instruction at runtime:

Category Where It Runs What It Does
Consistent Prompt Inside the AI’s system prompt Always included β€” gives the AI permanent context
Conditional Prompt Inside the AI’s system prompt Only included when a condition is true
Consistent Prompt + Tool Prompt + LangChain tool registered Permanent context + a callable function the AI can use
Conditional Prompt + Tool Prompt + LangChain tool registered Context + tool, but only when the condition is true
Deterministic Router Before AI processes message Runs code that can intercept, send messages, or short-circuit the AI entirely
Deterministic Callback After AI responds Runs code that updates state, flags customers, or notifies your team

A Real Business Story

A small restaurant in Ho Chi Minh City uses QuotyAI to handle their Facebook and Telegram orders. Here’s how they use each instruction category:

Consistent Prompt:

β€œOur pho is 65,000 VND for a regular bowl, 85,000 VND for a large. Banh mi is 35,000 VND.”

This is always in the AI’s brain β€” the customer can ask anytime and get the right answer.

Conditional Prompt:

β€œAfter 10 PM, only takeout is available. Dine-in closes at 9:30 PM.”

The condition function checks the current time. Before 9:30 PM, this instruction is invisible to the AI. After 9:30 PM, it appears automatically and the AI starts telling customers about takeout only.

Deterministic Router:

β€œIf a customer says β€˜menu’ or β€˜what do you have’, send them the PDF menu and don’t make them wait for the AI to respond.”

No forms, no action builders, no dropdowns β€” just write what you want. The AI coding agent reads your instruction, infers the appropriate actions (send message, send attachment, short-circuit, etc.), and generates the TypeScript function automatically. The router function checks every inbound message. When it detects a menu request, it immediately sends the attachment and short-circuits the AI β€” the customer gets the menu in under 100ms instead of waiting for the AI to generate a response.

Deterministic Callback:

β€œWhen a customer confirms a paid order, mark them as β€˜has_paid_order’ in their conversation state.”

After the AI successfully processes an order and sends a confirmation, the callback fires. It updates the conversation state so the next time this customer messages, the AI knows they’re a paying customer.

Consistent Prompt + Tool:

β€œYou can look up today’s specials using the getDailySpecial tool. Specials change daily based on fresh ingredients.”

The AI knows about this capability from the prompt, and it has a registered function it can call to check what today’s specials are.


How It Works

The Automation Pipeline

Every customer message goes through a deterministic pipeline before and after the AI processes it:

Customer sends a message
        ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  1. Extract Order Details     β”‚
β”‚     Your assistant extracts   β”‚
β”‚     structured order data     β”‚
β”‚     from the message          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  2. Deterministic Router      β”‚  ← Pre-AI automation
β”‚     Runs BEFORE the AI sees    β”‚
β”‚     the message. Can intercept,β”‚
β”‚     send attachments, or       β”‚
β”‚     short-circuit entirely.    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        ↓ (if not intercepted)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  3. AI Agent Processes        β”‚
β”‚     β€’ Consistent prompts      β”‚  ← Always in brain
β”‚     β€’ Conditional prompts     β”‚  ← Only if condition met
β”‚     β€’ Tools registered        β”‚  ← AI can call functions
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  4. Deterministic Callback    β”‚  ← Post-AI automation
β”‚     Runs AFTER the AI replies. β”‚
β”‚     Updates state, flags      β”‚
β”‚     customers, notifies team. β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Deterministic Means Guaranteed

Unlike the AI which might forget or misinterpret an instruction, Deterministic Router and Deterministic Callback instructions run as actual TypeScript code generated by our AI coding agents. You don’t need to configure actions manually β€” just write what you want to happen. When you write:

β€œIf the total is over 1,000,000 VND, offer free delivery”

The AI coding agent analyzes your instruction, infers the appropriate route actions and conditions, and generates an individual TypeScript function at assistant build time. You can preview the generated code directly in the editor β€” expand any router instruction to see the TypeScript with syntax highlighting, copy it, or regenerate it. Each function runs independently β€” if one fails, the others continue without interruption.

function route(ctx: RouterContext): RouterAction[] {
  const actions: RouterAction[] = [];

  if (ctx.order.totalAmount && ctx.order.totalAmount > 1000000) {
    actions.push({
      type: 'send_message',
      message: 'Your order qualifies for free delivery! 🚚',
    });
  }

  actions.push({ type: 'noop' });
  return actions;
}

The RouterContext gives each router function everything it needs to make smart decisions:

| Field | Type | Description | |β€”|β€”|β€”|β€”| | ctx.order | Record<string, unknown> | Structured order parameters extracted from conversation | | ctx.message | string | Raw customer message text β€” use for keyword detection | | ctx.state | Record<string, unknown> | Full conversation state (customer flags, past data) | | ctx.business | object | Business info: timezone, name, industries, customAttributes β€” company-wide user-defined attributes that apply to all contacts/conversations | | ctx.contact | object (optional) | Customer contact: name, email, phone, customAttributes, channelIdentifiers β€” build conditions based on who the customer is | | ctx.conversation | object (optional) | Conversation metadata: channel, externalId, lastInboundMessage, lastOutboundMessage β€” build channel-specific logic | | ctx.now | Date | Current time (deterministic β€” same value for all functions in a run) |

Each generated function runs in a sandboxed environment β€” it never forgets, never guesses, and never hallucinates. Because the context includes contact information, conversation metadata, and business-level custom attributes, functions can build rich conditions like β€œif this is a VIP customer from Telegram”, β€œif the customer’s email domain indicates a corporate account”, or β€œif the business-wide allow_discounts flag is set to true”.

Router Actions

The router function returns actions. The platform interprets them:

Action Effect
send_message Send a static message to the customer immediately
send_linked_attachments Send all linked attachments for this instruction
update_state Change a value in the conversation state
handover Escalate to a human agent with a reason
short_circuit Skip the AI entirely β€” no AI response generated
noop Do nothing, continue normally

Callback Actions

The callback function runs after the AI replies:

Action Effect
update_state Change a value in the conversation state (e.g., mark as paid)
notify_agent Send a private notification to your team
noop Do nothing

Category Reference

Consistent Prompt

Purpose: Instructions that should always be part of the AI’s system prompt. Use for permanent business info, policies, and standard responses.

When to use:

  • Your menu, price list, or service catalog
  • Standard operating hours
  • Frequently asked questions and their answers
  • Business policies (cancellation, refund, etc.)

Example:

β€œOur spa offers: 60-min Swedish massage β€” 500,000 VND, 90-min deep tissue β€” 750,000 VND, add hot stone β€” 150,000 VND.”


Conditional Prompt

Purpose: Instructions that should only appear in the AI’s context when a condition is true. The condition is a generated TypeScript function that evaluates at runtime.

When to use:

  • Time-based rules (after hours, weekends, holidays)
  • Customer status rules (returning customer, VIP, flagged)
  • Order state rules (only after items are selected)
  • Seasonal promotions and limited-time offers

Under the hood, a shouldInclude function is generated from your instruction with the signature function shouldInclude(ctx: ConditionContext): boolean. The ConditionContext provides:

Field Type Description
ctx.order Record<string, unknown> Structured order input parameters from the conversation
ctx.contact object (optional) Customer contact: name, email, phone, customAttributes
ctx.conversation object (optional) Conversation metadata: channel, externalId, lastInboundMessage
ctx.state Record<string, unknown> (optional) Conversation state snapshot (customer flags, past data)
ctx.business object (optional) Business info: timezone, name, industries, customAttributes
ctx.now Date Current time (deterministic)

If the function returns false, the instruction content is invisible to the AI.


Consistent Prompt + Tool

Purpose: Gives the AI permanent context AND registers a deterministic tool function it can call. Use when the AI needs both knowledge about something and the ability to act on it.

When to use:

  • Looking up dynamic data (inventory, daily specials, availability)
  • Performing validations (check address, verify coupon code)
  • Calculating derived values (tax rates, shipping costs)

The tool is registered as a LangChain function tool with a generated JSON schema. The AI can choose to call it during the conversation.


Conditional Prompt + Tool

Purpose: Same as above, but both the prompt content and the tool are only available when the condition is true.

When to use:

  • Weekend-only tools (e.g., a brunch menu lookup)
  • VIP-customer-only capabilities (e.g., apply loyalty discount)
  • Post-order tools (e.g., track delivery status β€” only available after order is placed)

The condition is evaluated once β€” if true, both the prompt content AND the tool are available to the AI.


Deterministic Router

Purpose: Runs as actual TypeScript code before the AI agent sees the message. Can intercept, send attachments, update state, trigger handover, or short-circuit the AI entirely.

When to use:

  • Instant responses: β€œIf customer asks for hours, send hours attachment immediately” β€” no AI latency
  • Guardrails: β€œIf customer mentions competitor names, block and handover”
  • Pre-processing: β€œIf customer says β€˜menu’ in any language, send the PDF”
  • Compliance: β€œIf customer is in a blocked region, send sorry message and short-circuit”
  • Time-based: β€œAfter 10 PM, send a β€˜closed’ message and short-circuit”
  • Customer-state: β€œIf customer already has pending order, block re-ordering”

All router instructions generate individual TypeScript functions at build time β€” one per instruction. Each function receives a full RouterContext object with the raw customer message, structured order data, conversation state, business info, customer contact information, conversation metadata, and current time. This means each rule can independently evaluate against all available context.

Per-instruction isolation: If one router function has an error, the rest continue running. No single buggy instruction can break all your routing rules.

How it works in the pipeline:

  1. Extract structured order data from the customer message
  2. Build RouterContext with the raw message, order data, conversation state, business info, customer contact, conversation metadata, and current time
  3. Run each route(ctx) function in order β€” if short_circuit is returned, remaining functions still run but the AI is skipped
  4. Process accumulated actions: send messages, send attachments, update state, handover, or short-circuit

Deterministic Callback

Purpose: Runs as actual TypeScript code after the AI has responded. For side effects that shouldn’t interrupt the customer experience.

When to use:

  • State tracking: β€œAfter confirming an order, set hasActiveOrder flag”
  • Notifications: β€œAfter a failed payment attempt, notify the team”
  • Audit logging: β€œAfter any quote is provided, log it to the conversation state”
  • Customer segmentation: β€œAfter a customer places their 5th order, flag them as VIP”

Each callback instruction generates its own function with the signature function callback(ctx: CallbackContext): CallbackAction[]. The CallbackContext provides:

Field Type Description
ctx.order Record<string, unknown> Structured order input parameters from the conversation
ctx.aiResponse string The AI-generated response that was just sent to the customer
ctx.contact object (optional) Customer contact: name, email, phone, customAttributes β€” condition on who the customer is
ctx.conversation object (optional) Conversation metadata: channel, externalId β€” condition on which channel the conversation came from
ctx.state Record<string, unknown> (optional) Conversation state snapshot for reading or updating customer flags
ctx.business object (optional) Business info: timezone, name, industries, customAttributes

In addition to the standard actions, callbacks can write back to contacts and conversations:

Action Effect
set_contact_attribute Set a user-defined attribute on the contact document (persisted across conversations)
set_conversation_attribute Set a user-defined attribute on the conversation document

This allows the AI-generated callback to persist data like β€œmark this customer as VIP” or β€œflag this conversation as handled” by writing to ctx.contact.customAttributes or ctx.conversation.customAttributes.

Callbacks are non-blocking β€” the customer gets their response while callbacks process in the background.


Technical Implementation Details

Build Pipeline Integration

During assistant build, instructions go through code generation:

Instructions from DB
        ↓
Builder fetches active instructions
        ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Category Check                     β”‚
β”‚                                     β”‚
β”‚  CONSISTENT_* β†’ No code generation β”‚
β”‚                 (prompt-only)       β”‚
β”‚                                     β”‚
β”‚  CONDITIONAL_* β†’ Generate          β”‚
β”‚  shouldInclude() per instruction    β”‚
β”‚                                     β”‚
β”‚  DETERMINISTIC_ROUTER β†’ Generate   β”‚
β”‚  route() PER instruction β€”         β”‚
β”‚  each function runs independently  β”‚
β”‚  with full RouterContext            β”‚
β”‚                                     β”‚
β”‚  DETERMINISTIC_CALLBACK β†’ Generate β”‚
β”‚  callback() per instruction         β”‚
β”‚                                     β”‚
β”‚  *_PROMPT_AND_TOOL β†’ Generate       β”‚
β”‚  tool function + JSON schema       β”‚
β”‚  per instruction                    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        ↓
Code written back to instruction doc (for preview)
        ↓
Code stored in aiExecutableSource (source of truth)
        ↓
Snapshot frozen in immutable assistant

Generated Code Storage

Generated code is written to two places for different purposes:

  • Instruction doc (generatedCode field) β€” for instant preview in the editor with syntax highlighting
  • Assistant’s aiExecutableSource β€” the source of truth that gets frozen in immutable snapshots and used at runtime

The storage layout in aiExecutableSource, keyed by instruction ID:

Category Storage Example Key
Router (per instruction) deterministicRouterInstructions[instructionId].code One entry per router instruction β€” isolated and independent
Callback (per instruction) deterministicCallbacks[instructionId].code One entry per callback instruction
Condition (per instruction) conditionFunctions[instructionId].code One entry per conditional instruction
Tool (per instruction) instructionTools[instructionId] One entry per tool instruction

Sandboxed Execution

All generated TypeScript functions run in the same sandboxed environment as pricing formulas:

  • Bun’s native Function constructor
  • No file system access, no network, no environment variables
  • Overridden console methods for audit logging
  • Returns typed action objects that the pipeline interprets


Custom Attributes at Three Levels

All three context types (RouterContext, CallbackContext, ConditionContext) expose custom attributes at three levels, letting you build conditions based on business-wide settings, customer identity, or conversation context:

Level Access Path Scope Example
Business ctx.business.customAttributes All contacts and conversations inherit these allow_discounts: true, max_order_limit: 5000000
Contact ctx.contact.customAttributes Specific customer across all their conversations vip_tier: 'gold', preferred_language: 'vi'
Conversation ctx.conversation.customAttributes Specific conversation only no_ai: true, priority: 'urgent'

Attributes are entirely user-defined β€” you decide the keys and values. The AI-generated code reads them directly:

// Router β€” offer discount only if business and contact both allow it
if (ctx.business.customAttributes?.allow_discounts && ctx.contact.customAttributes?.vip_tier === 'gold') {
  actions.push({ type: 'send_message', message: 'You get a 10% discount!' });
}
// Callback β€” persist a flag after successful order
if (ctx.order.totalAmount > 1000000) {
  actions.push({ type: 'set_contact_attribute', key: 'high_value', value: true });
}
// Condition β€” hide instructions for flagged conversations
if (ctx.conversation.customAttributes?.no_ai) {
  return false;
}

Best Practices

For Consistent Prompts

  • Keep them factual and precise: exact prices, exact hours, exact policies
  • One concept per instruction (don’t bundle unrelated rules)
  • Use the same language your customers will use

For Conditional Prompts

  • Make the condition obvious in the instruction content: β€œAfter 10 PM…” works better than β€œLate night rules”
  • Don’t overuse conditions β€” the AI works best with a stable context
  • Test your conditions by simulating different scenarios

For Deterministic Routers

  • Use for anything time-sensitive β€” the router runs in milliseconds, the AI takes seconds
  • Preview the generated code in the editor to verify the AI inferred the right actions
  • If the generated code doesn’t match your intent, rewrite the instruction in clearer language
  • short_circuit is powerful: use it when the AI has nothing useful to add
  • Routers can’t access the AI’s knowledge β€” they work with structured order data only

For Deterministic Callbacks

  • Use for state mutations that should always happen after specific events
  • Don’t use callbacks for customer-facing actions β€” the customer already got their response
  • Callbacks are ideal for compliance and audit trails

General

  • The order of instructions doesn’t matter for routers (they’re consolidated into one function)
  • For prompts, order matters β€” earlier instructions appear higher in the AI’s context
  • If an instruction doesn’t fit a category, it’s skipped β€” every instruction needs a valid category