# Conversation State Machine ## Purpose The conversation state machine enforces the safe order of an AI Operator call. The assistant cannot answer business questions, search a knowledge base, or execute business tools until both language and region are selected in code. ## States ```text CALL_STARTED -> GREETING -> LANGUAGE_SELECTION -> REGION_SELECTION -> READY_TO_HELP -> QUESTION_ANSWERING -> READY_TO_HELP -> CLOSING -> ENDED ``` `HANDOFF` can be entered from any non-ended state. `CLOSING` and `ENDED` can also be entered from any non-ended state. `ENDED` is immutable. ## Transition Table | From | Event | To | Requirement | | --- | --- | --- | --- | | CALL_STARTED | call.started | GREETING | call session exists | | GREETING | greeting.played | LANGUAGE_SELECTION | bilingual greeting prepared | | LANGUAGE_SELECTION | language.selected | REGION_SELECTION | language is `ru` or `kk` | | REGION_SELECTION | region.selected | READY_TO_HELP | normalized region code is selected | | READY_TO_HELP | question.received | QUESTION_ANSWERING | language and region selected | | QUESTION_ANSWERING | answer.completed | READY_TO_HELP | answer flow completed | | any non-ended | handoff.requested | HANDOFF | none | | any non-ended | closing.requested | CLOSING | none | | any non-ended | call.ended | ENDED | none | Invalid transitions return errors and do not mutate state. Denied actions are recorded in session history. ## Tool Permission Matrix | State | Allowed Tools | | --- | --- | | CALL_STARTED | none | | GREETING | none | | LANGUAGE_SELECTION | `set_language`, `request_human_handoff`, `end_call` | | REGION_SELECTION | `set_region`, `set_language`, `request_human_handoff`, `end_call` | | READY_TO_HELP | `search_knowledge_base`, `set_language`, `set_region`, `request_human_handoff`, `end_call` | | QUESTION_ANSWERING | `search_knowledge_base`, `request_human_handoff`, `end_call`, `set_language`, `set_region` | | HANDOFF | `end_call` | | CLOSING | `end_call` | | ENDED | none | ## Hard Guardrail `search_knowledge_base` is denied unless all of these are true: - language is `ru` or `kk`; - region status is `selected`; - region code is not empty; - state is `READY_TO_HELP` or `QUESTION_ANSWERING`. This is enforced in Go code by `internal/dialogue/policy`, independently of prompts. ## Messages The message catalog has bilingual initial greeting plus Russian and Kazakh fragments for language, region, ready, denial, handoff, and closing states. Initial greeting: ```text Здравствуйте! Это AI-оператор. Выберите язык обслуживания: русский или қазақша. Сәлеметсіз бе! Бұл AI-оператор. Қызмет көрсету тілін таңдаңыз: қазақша немесе русский. ``` ## Prompt Fragments `internal/dialogue/prompt` builds state-aware prompt fragments that include current state, language, region, next action, and forbidden actions. Prompt fragments are secondary; policy enforcement remains in Go code. ## CLI Usage ```bash ./bin/ai-operator doctor --env /etc/ai-operator/ai-operator.env --check-dialogue ./bin/ai-operator dialogue-self-test --env /etc/ai-operator/ai-operator.env ./bin/ai-operator dialogue-self-test --env /etc/ai-operator/ai-operator.env --json ``` The self-test runs without Asterisk calls, OpenAI, database, or external services. ## Integration For the test route only, Call Manager creates a Dialogue Orchestrator session before starting the voice provider. The provider receives a state-aware system prompt. On hangup, Call Manager ends and cleans the dialogue session. Production Kazakhtelecom routes remain disabled. ## Not Implemented Yet - language detection from speech; - region resolver; - Knowledge Base/RAG; - final agent prompt; - real business tools; - production route switch. ## TZ-07 Language Detector Language selection is now handled by `internal/dialogue/language`. The state machine still stores strict `ru` or `kk`, while detector input can be natural text such as `русский`, `қазақша`, `russian`, or `kazakh`. ## TZ-08 Region Resolver Update TZ-08 adds an offline Kazakhstan Region Resolver with 20 enabled regions, stable `region_code` values, Almaty city/region clarification, false-positive protection, and explicit region-change policy. Production routing remains disabled; OpenAI, PostgreSQL, and Knowledge Base/RAG are still not used at this stage. ## TZ-09 Knowledge Base Update TZ-09 adds PostgreSQL + pgvector, KGA JSONL ingestion, fake embeddings, hybrid KB search, cross-language fallback for KK queries, citations, and `search_knowledge_base` integration behind the existing language/region guardrail. OpenAI is not called automatically and production routing remains disabled. ## TZ-10 Agent Integration The state machine remains the hard gate for business answers. Agent prompt instructions are secondary; `search_knowledge_base` is still denied before language and region are selected. ToolCall results now flow back to the VoiceProvider. ## TZ-11 Handoff `request_human_handoff` moves active conversations to `HANDOFF`. Repeated handoff requests are idempotent. `ENDED` remains immutable.