> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.revvue.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.revvue.ai/_mcp/server.

# CustomerSupportConfigurable

GraphQL object

Reference: https://docs.revvue.ai/api-reference/jonna-ai-agent/types/objects/customer-support-configurable

## Fields

- `sessionId` — The browser session id of the run.
- `uniqueRunId` — The unique run id is unique, represent each unique run, after an interrutp this will be unique.
- `triggerReason` — The reason agent is triggered.
- `configHash` — Config unique hash.
- `testMode` — Sandbox run (the config-dialog Test drawer): the graph runs for real against a synthetic ticket, but every externally-visible side effect — tag publish, ticket status, replies, wiki writes — is recorded into state.test_actions instead of executed. Set per-thread at invoke time, never on saved rows.
- `locationMemoryKey`
- `database` — Database to connect to, legacy to be deleted
- `active` — Master on/off switch for this assistant. When False the agent never engages on EXTERNAL triggers (no replies, no escalations of its own); workflow rules that act on their own — junk, close, assign, tag, template reply, forward, hand off — still run, and a run is started only for those.
- `tagEnabled` — LEGACY — tagging is mandatory. The field remains for stored-row compatibility but heals to True on load (tagging_is_mandatory validator); the consumer no longer gates on it. Use `active` to switch the agent off (workflow rules keep running) and `get_involved` to keep it tagging-only.
- `getInvolved` — Allow the agent to engage (answer / act for) guests on EXTERNAL triggers after tagging. Requires tag_enabled=True. False = tagging only; the run ends after tagging and the workflow rules (which run in both modes). When True the run is still gated by required_tags and the workflow rules.
- `systemPrompt` — Base system prompt for the harness. Applies to all locations. Rendered as a Jinja template with `{{locations}}` (the venue list) and `{{tool_discovery_enabled}}` available; today's date and the live plan are injected separately as a per-turn message, not via this field. A customised prompt that is not valid Jinja is used as literal text.
- `extendedPrompt` — Location-specific instructions appended to the base prompt. Use this to define tone, personality, and voice for this location.
- `model` — Orchestration model (main reasoning/response-generation LLM). Default is controlled by the HARNESS_ORCHESTRATOR_MODEL env var; falls back to Claude Haiku 4.5 when unset.
- `orchestratorThinkingBudgetTokens` — Enable Anthropic extended thinking for the orchestrator with this token budget (Anthropic minimum 1024; e.g. 2048). Reasoning before each tool call measurably improves first-shot tool-argument fidelity on small models (Haiku pattern-matches arg names from description prose without it). None (default) disables thinking. Anthropic orchestrator models only; ignored for other providers.
- `selectedTools` — Tools enabled for this agent instance.
- `enforceToolCallPerTurn` — EXTERNAL only. When True, every orchestrator turn must end in a tool call — text-only responses get bounced back from `reflect` once with a nudge message, and the system prompt carries an explicit rule telling the model to act, not narrate. Turn off for tenants where the orchestrator is doing free-form chat.
- `toolDiscoveryEnabled` — When True, the orchestrator runs the discovery-first model: it starts with only the harness primitives plus `search_tools` (browse/search the catalog and activate by name) and pulls domain tools in on demand, and the system prompt carries the discovery instructions. When False, discovery is turned OFF for speed: `search_tools` is never bound, EVERY tool in `selected_tools` is bound from the first turn, and the system prompt lists the agent's capabilities statically (one reference per bound tool). A tool that is not in `selected_tools` is then truly unreachable — there is no way for the agent to discover it. Chat defaults this to False (latency-tuned, fixed tool set).
- `skipTaggingForChat` — Skip the intent-tag pass for live chat. Lives on the base (not just the chat subclass) so it is part of the generated GraphQL output/input types and round-trips through the assistant editor and save. The chat config overrides the default to True; the chat graph also omits the tag_intent node structurally, so this flag is the operator-facing intent, not a runtime branch on the chat path.
- `interruptSteps` — Executed when the agent pauses and waits for human approval — e.g. set the ticket to IN_PROGRESS and assign a reviewer. Same step model as workflow rules, but only ticket-side types run here (set_status / send_reply / assign / add_tag / mark_junk / close_ticket); agent-flow types (human_handoff, skip_agent, end_run_silent, limit_tools) are logged and skipped. Steps run once per interrupt, at the moment the judge raises it — never again when the run resumes. Empty list = no ticket-side effects beyond the built-in PENDING bookkeeping.
- `judgeModel` — Fast model used by the judge to evaluate critical tool calls.
- `judgeLlmEnabled` — Master switch for the judge LLM. When False (current default — temporarily disabled 2026-08-27, too strict in production) no judge LLM call is made anywhere in the judge node: an InterruptPolicy.JUDGE call passes straight through like NEVER, and the ALWAYS path raises its human interrupt without the correctness pre-check. Deterministic gates (workflow tool bans, guardrail denies, validators, the args-schema check) and human approvals are unaffected. `judge_llm_verdict=False` still promotes JUDGE to ALWAYS regardless of this switch — an agent whose posture is 'a human decides' keeps that posture. `judge_semantic_precheck` only matters while this is True.
- `judgeLlmVerdict` — Let the LLM judge decide an InterruptPolicy.JUDGE call on its own. That is the only option when nobody is watching. Set False where a person is already in the conversation and JUDGE is promoted to ALWAYS instead, so an uncertain call reaches them rather than being refused by a model on their behalf.
- `judgeSemanticPrecheck` — On the ALWAYS (human-approval) path, run the LLM correctness pre-check before raising the interrupt, whenever the tool has semantic_checks or the matched rule has a judge_prompt. Worth it when nobody is watching: a caught mistake never reaches the reviewer. Set False where the approver is already the person in the conversation and the verdict has no second audience — the InterruptPolicy.JUDGE path is unaffected either way.
- `tagModel` — Model for the tag_intent ReAct loop (chooses relevant tags).
- `tagExtractorModel` — Model used by the tag_intent extractor (structured field extraction).
- `emailModel` — DEPRECATED — unused. The compose_reply_email sub-agent was removed; guest replies are written by the orchestrator (`model`).
- `composeEmailSystemPrompt` — DEPRECATED — unused. The compose_reply_email sub-agent was removed; customise the reply style via `system_prompt` and `brand_voice`.
- `composeChatSystemPrompt` — DEPRECATED — unused. The compose_reply_email sub-agent was removed; customise the reply style via `system_prompt` and `brand_voice`.
- `brandVoice` — Restaurant brand voice / writing style for guest replies. Free text. Injected into the orchestrator prompt on both channels — the orchestrator writes every guest reply and reviewer draft itself — to steer HOW it writes: tone, warmth, signature phrasings, words to prefer or avoid. This shapes style only; WHAT to say still comes from the run's lookups and rules. None = the default hospitable voice.
- `scratchpadCompactionModel` — Fast model used to summarise dropped messages during context compaction.
- `cxScoreModel` — Fast model that scores resolution quality in the reflect node.
- `promptShieldModel` — Fast model used by the prompt_shield to classify subtle injection attempts.
- `languageDetectionModel` — Fast model used by the language detection to classify language to reply with.
- `workflowConditionModel` — Fast model that answers `llm` workflow-rule conditions — the free-text yes/no questions an operator writes on a rule ('Is the guest complaining about the food?'). Runs once per inbound message per distinct question, and not at all when no rule uses the source.
- `escalationCategoryModel` — Fast model that classifies WHY a case was escalated, against the tenant's escalation-category registry (the 'questions the agent couldn't answer' taxonomy). Runs once per first hand-off.
- `closeTicketWhenCompleted` — Close the ticket when the agent considers the request completed — on BOTH mediums. Email reads the delivered reply's send intent (answered the question, gave the requested information) and also closes on a judged `finish_no_reply`, the guest's sign-off. Chat has no reply tool to carry an intent, so it asks a classifier whether the conversation is finished, after the reply is delivered. Replies that ask the guest for something, promise a follow-up, or leave a complaint unsettled keep the ticket open, and an unavailable classifier leaves it open too. Default on — turn off to have the team close every ticket manually.
- `closeTicketOnReply` — If True, the support ticket is set to CLOSED whenever the agent's reply is delivered to the guest — email (reply_guest) and live chat (send_chat_reply) alike. Default False — the team closes tickets manually.
- `escalationRules` — Escalation behaviour: the closing message shown to a chat guest on hand-off.
- `costLimitTotalTokens` — Combined input+output token budget per run. When exceeded the run is paused at the next safe boundary (resumable). None disables.
- `triggerMedium` — The channel this assistant is bound to (EMAIL, CHAT, FORM, REVIEW, API, ...). On EXTERNAL requests the dispatcher filters candidates by this field — an EMAIL request only routes to assistants with trigger_medium=EMAIL. At invoke time the runtime overrides this with the actual event's medium so downstream tools see the real channel. Independent of trigger_audience.
- `triggerOn` — THE event that starts a run — exactly one. NEW_MESSAGE (default) = every new inbound guest message on this assistant's channel; ASSIGNMENT = only when a support ticket is explicitly assigned to this assistant in the inbox (the publisher stamps trigger_reason='assignment'; the inbox does not publish these yet). Enforced at the AMQP consumer before any thread or run exists. EXTERNAL runs only.
- `triggerExceptions` — Sender patterns that must never start a run ('*' wildcards: '*@agoda.com', 'badr@*-ops.com', exact addresses). Seeded with the machine-sender patterns (noreply*@*, mailer-daemon@*, …), which are ordinary removable entries. Enforced before intent tagging on EXTERNAL runs — an excepted sender is never tagged, engaged, or replied to, and no automation rule can touch it.
- `escalateOnMissingTools` — Safety default for tool gaps. When the tagger resolves an intent the assistant demonstrably cannot act on (e.g. a request it has no tool for), the run is handed to a human instead of engaging the agent — a guest must never be answered by an agent that cannot actually do what they asked. A workflow rule conditioned on that tag overrides this (the operator has expressed their own policy). Applies to EXTERNAL runs only.
- `requiredTagsEnabled` — If True, the required tags used to gate EXTERNAL runs are enforced.
- `requiredTags` — Tag-label allowlist that gates EXTERNAL runs after tag_intent. Empty list = off (all extracted tags pass). When non-empty, the run only proceeds to the orchestrator if at least one extracted super-tag label is in this list. Tags outside the allowlist route directly to END — the guest is not responded to and no human reviewer is paged. The special entry '__none__' opts in the untagged case (no tags extracted, including skip-tagging-for-chat runs); without it, untagged runs end.
- `mcpConnections` — MCP server connections in this assistant's tool chain. Tools are exposed to the agent as '\{name}\_\_\{tool}' (e.g. 'inbox\_\_reply\_guest') and are Tier-2 discoverable by default (bound up front when tool discovery is off). Per-connection `tool_allowlist` narrows which served tools load; per-tool allow/deny/approval lives in `guardrails`.
- `guardrails` — Per-tool guardrail rules, evaluated first-match top-to-bottom against every pending tool call. tool_name is an exact (namespaced) name, a wildcard suffix ('inbox__*'), or '*'. allow = run autonomously, judge = LLM judge evaluates, require_approval = human must approve, suggest = offered to a human as a draft they send themselves (reply_guest), deny = block (filtered from binding when static; rejected per-call when conditions reference tool args). New assistants start with the deployment defaults; an explicitly empty list means no deployment overrides — every tool falls back to its own default policy.
- `workflowRules` — Ordered workflow rules. Each has a trigger (pre_run / post_tag / post_close), AND'd guardrail-style conditions (sender / medium / location / super_tag), and ordered steps (set_status, send_reply, assign, add_tag, forward_email, set_classification, mark_junk, close_ticket, human_handoff, skip_agent, end_run_silent, limit_tools, pass_to_agent). The first matching rule carrying a terminal step wins. Empty list = no workflow automation.
- `inactivityCloseMinutes` — Auto-close open tickets (NEW / IN_PROGRESS / PENDING) after this many minutes without activity. Executed by the platform time.ping sweeper for this assistant's medium and locations; closed chat tickets then run the post-close analysis (tagging + CX scoring). None = disabled.
- `workingTicketStatus` — Status the ticket is set to while the agent is working on it (NEW / IN_PROGRESS / PENDING / CLOSED — typically IN_PROGRESS). Empty (the default) = the agent never touches the status while working. The waiting-for-approval status is NOT set here — it comes from the operator's interrupt_steps (a set_status step in "Waiting for your approval — do:"). Feature-driven dispositions (escalation PENDING, junk/close rules) are separate and unaffected.
- `lifecycleStatusUpdatesEnabled` — LEGACY — superseded by `working_ticket_status` + an interrupt_steps set_status step. A stored True migrates on load (see migrate_lifecycle_status_updates); the harness no longer reads this flag.
- `wikiMcpEnabled` — Enable the jonna-knowledge wiki MCP server for this assistant. When False, the wiki_* tools are stripped from the agent's tool set even if listed in selected_tools. Mirrors the 'wiki' entry in mcp_connections — disabling either disables both.
- `fallbackLanguage` — Language the agent replies in when the guest's detected language is not in allowed_reply_languages (or detection fails).
- `allowedReplyLanguages` — Languages the agent may reply in. When the guest's detected language is in this list the reply mirrors it; otherwise the reply falls back to fallback_language.
- `languageRules` — Ordered reply-language rules. Each maps detected ISO 639-1 codes to ONE reply language; the first rule whose `detected` list contains the guest's detected code wins ('*' matches any detected language). Example: \[\{detected: \['no','nb','nn'], reply\_language: 'no'}, \{detected: \['*'], reply\_language: 'en'}] keeps Norwegian in Norwegian and answers everything else in English. Empty list = no explicit policy: the venue's country decides instead (its own language for a guest who wrote in it, English for everyone else).
- `defaultReplyLanguage` — ISO 639-1 code the agent replies in when no language rule matches. Empty string = no explicit policy: the venue's country (geoLocation.region) decides — a guest writing the venue's own language is answered in it, everyone else in English. Venues with no country on file fall back to mirroring the guest (subject to allowed_reply_languages / fallback_language).

## Definition

```graphql
type CustomerSupportConfigurable {
  sessionId: String
  uniqueRunId: String
  triggerReason: String
  configHash: String
  testMode: Boolean!
  locationMemoryKey: String
  database: String
  active: Boolean!
  tagEnabled: Boolean!
  getInvolved: Boolean!
  systemPrompt: String!
  extendedPrompt: String
  model: LlmModel!
  orchestratorThinkingBudgetTokens: Int
  selectedTools: [AgentToolName!]!
  enforceToolCallPerTurn: Boolean!
  toolDiscoveryEnabled: Boolean!
  skipTaggingForChat: Boolean!
  interruptSteps: [WorkflowStep!]!
  judgeModel: LlmModel!
  judgeLlmEnabled: Boolean!
  judgeLlmVerdict: Boolean!
  judgeSemanticPrecheck: Boolean!
  tagModel: LlmModel!
  tagExtractorModel: LlmModel!
  emailModel: LlmModel!
  composeEmailSystemPrompt: String
  composeChatSystemPrompt: String
  brandVoice: String
  scratchpadCompactionModel: LlmModel!
  cxScoreModel: LlmModel!
  promptShieldModel: LlmModel!
  languageDetectionModel: LlmModel!
  workflowConditionModel: LlmModel!
  escalationCategoryModel: LlmModel!
  closeTicketWhenCompleted: Boolean!
  closeTicketOnReply: Boolean!
  escalationRules: EscalationConfig!
  costLimitTotalTokens: Int
  triggerMedium: TriggerMedium!
  triggerOn: TriggerReason!
  triggerExceptions: TriggerExceptions!
  escalateOnMissingTools: Boolean!
  requiredTagsEnabled: Boolean!
  requiredTags: [String!]!
  mcpConnections: [McpConnection!]!
  guardrails: [ToolGuardrail!]!
  workflowRules: [WorkflowRule!]!
  inactivityCloseMinutes: Int
  workingTicketStatus: SupportTicketStatus
  lifecycleStatusUpdatesEnabled: Boolean!
  wikiMcpEnabled: Boolean!
  fallbackLanguage: LanguageCode!
  allowedReplyLanguages: [LanguageCode!]!
  languageRules: [LanguageRule!]!
  defaultReplyLanguage: String!
}
```