Created
May 5, 2026 01:21
-
-
Save limcheekin/49ca8210543fa6a982930a55e27a261c to your computer and use it in GitHub Desktop.
Parlant Repository Wiki — generated by GitNexus
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>parlant — Wiki</title> | |
| <script src="https://cdn.jsdelivr.net/npm/marked@11.0.0/marked.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script> | |
| <style> | |
| *{margin:0;padding:0;box-sizing:border-box} | |
| :root{ | |
| --bg:#ffffff;--sidebar-bg:#f8f9fb;--border:#e5e7eb; | |
| --text:#1e293b;--text-muted:#64748b;--primary:#2563eb; | |
| --primary-soft:#eff6ff;--hover:#f1f5f9;--code-bg:#f1f5f9; | |
| --radius:8px;--shadow:0 1px 3px rgba(0,0,0,.08); | |
| } | |
| body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif; | |
| line-height:1.65;color:var(--text);background:var(--bg)} | |
| .layout{display:flex;min-height:100vh} | |
| .sidebar{width:280px;background:var(--sidebar-bg);border-right:1px solid var(--border); | |
| position:fixed;top:0;left:0;bottom:0;overflow-y:auto;padding:24px 16px; | |
| display:flex;flex-direction:column;z-index:10} | |
| .content{margin-left:280px;flex:1;padding:48px 64px;max-width:960px} | |
| .sidebar-header{margin-bottom:20px;padding-bottom:16px;border-bottom:1px solid var(--border)} | |
| .sidebar-title{font-size:16px;font-weight:700;color:var(--text);display:flex;align-items:center;gap:8px} | |
| .sidebar-title svg{flex-shrink:0} | |
| .sidebar-meta{font-size:11px;color:var(--text-muted);margin-top:6px} | |
| .nav-section{margin-bottom:2px} | |
| .nav-item{display:block;padding:7px 12px;border-radius:var(--radius);cursor:pointer; | |
| font-size:13px;color:var(--text);text-decoration:none;transition:all .15s; | |
| white-space:nowrap;overflow:hidden;text-overflow:ellipsis} | |
| .nav-item:hover{background:var(--hover)} | |
| .nav-item.active{background:var(--primary-soft);color:var(--primary);font-weight:600} | |
| .nav-item.overview{font-weight:600;margin-bottom:4px} | |
| .nav-children{padding-left:14px;border-left:1px solid var(--border);margin-left:12px} | |
| .nav-group-label{font-size:11px;font-weight:600;color:var(--text-muted); | |
| text-transform:uppercase;letter-spacing:.5px;padding:12px 12px 4px;user-select:none} | |
| .sidebar-footer{margin-top:auto;padding-top:16px;border-top:1px solid var(--border); | |
| font-size:11px;color:var(--text-muted);text-align:center} | |
| .content h1{font-size:28px;font-weight:700;margin-bottom:8px;line-height:1.3} | |
| .content h2{font-size:22px;font-weight:600;margin:32px 0 12px;padding-bottom:6px;border-bottom:1px solid var(--border)} | |
| .content h3{font-size:17px;font-weight:600;margin:24px 0 8px} | |
| .content h4{font-size:15px;font-weight:600;margin:20px 0 6px} | |
| .content p{margin:12px 0} | |
| .content ul,.content ol{margin:12px 0 12px 24px} | |
| .content li{margin:4px 0} | |
| .content a{color:var(--primary);text-decoration:none} | |
| .content a:hover{text-decoration:underline} | |
| .content blockquote{border-left:3px solid var(--primary);padding:8px 16px;margin:16px 0; | |
| background:var(--primary-soft);border-radius:0 var(--radius) var(--radius) 0; | |
| color:var(--text-muted);font-size:14px} | |
| .content code{font-family:'SF Mono',Consolas,'Courier New',monospace;font-size:13px; | |
| background:var(--code-bg);padding:2px 6px;border-radius:4px} | |
| .content pre{background:#1e293b;color:#e2e8f0;border-radius:var(--radius);padding:16px; | |
| overflow-x:auto;margin:16px 0} | |
| .content pre code{background:none;padding:0;font-size:13px;line-height:1.6;color:inherit} | |
| .content table{border-collapse:collapse;width:100%;margin:16px 0} | |
| .content th,.content td{border:1px solid var(--border);padding:8px 12px;text-align:left;font-size:14px} | |
| .content th{background:var(--sidebar-bg);font-weight:600} | |
| .content img{max-width:100%;border-radius:var(--radius)} | |
| .content hr{border:none;border-top:1px solid var(--border);margin:32px 0} | |
| .content .mermaid{margin:20px 0;text-align:center} | |
| .menu-toggle{display:none;position:fixed;top:12px;left:12px;z-index:20; | |
| background:var(--bg);border:1px solid var(--border);border-radius:var(--radius); | |
| padding:8px 12px;cursor:pointer;font-size:18px;box-shadow:var(--shadow)} | |
| @media(max-width:768px){ | |
| .sidebar{transform:translateX(-100%);transition:transform .2s} | |
| .sidebar.open{transform:translateX(0);box-shadow:2px 0 12px rgba(0,0,0,.1)} | |
| .content{margin-left:0;padding:24px 20px;padding-top:56px} | |
| .menu-toggle{display:block} | |
| } | |
| .empty-state{text-align:center;padding:80px 20px;color:var(--text-muted)} | |
| .empty-state h2{font-size:20px;margin-bottom:8px;border:none} | |
| </style> | |
| </head> | |
| <body> | |
| <button class="menu-toggle" id="menu-toggle" aria-label="Toggle menu">☰</button> | |
| <div class="layout"> | |
| <nav class="sidebar" id="sidebar"> | |
| <div class="sidebar-header"> | |
| <div class="sidebar-title"> | |
| <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M2 3h6a4 4 0 014 4v14a3 3 0 00-3-3H2z"/><path d="M22 3h-6a4 4 0 00-4 4v14a3 3 0 013-3h7z"/></svg> | |
| parlant | |
| </div> | |
| <div class="sidebar-meta" id="meta-info"></div> | |
| </div> | |
| <div id="nav-tree"></div> | |
| <div class="sidebar-footer">Generated by GitNexus</div> | |
| </nav> | |
| <main class="content" id="content"> | |
| <div class="empty-state"><h2>Loading…</h2></div> | |
| </main> | |
| </div> | |
| <script> | |
| var PAGES = {"ai-reasoning-engine-parlant":"# AI Reasoning Engine — parlant\n\n# AI Reasoning Engine — parlant\n\nThe `AlphaEngine` is the primary orchestration module for AI reasoning within the Parlant framework. It manages the lifecycle of a session turn, transforming raw input and session history into structured agent actions and natural language responses.\n\n## Core Architecture\n\nThe engine operates on a stateful processing model where each turn is treated as a series of preparation iterations followed by a generation phase.\n\n### EngineContext and ResponseState\nEvery request is encapsulated in an `EngineContext`, which provides a unified view of the entities involved:\n- **Agent**: The AI persona and its configuration.\n- **Customer**: The identity of the user interacting with the agent.\n- **Session**: The persistent record of the conversation.\n- **Interaction**: A snapshot of the event history.\n\nThe `ResponseState` (found within the context) tracks the evolution of the current turn, including matched guidelines, executed tool calls, and pending message events.\n\n### EntityContext\nTo allow deep-stack components (like tools or hooks) to access the current environment without explicit prop-drilling, the module uses `EntityContext`. This class leverages Python `contextvars` to provide static access to the current `Agent`, `Customer`, and `Session` within the same asyncio task.\n\n```python\n# Example: Accessing the current agent from anywhere in the call stack\nagent = EntityContext.get_agent()\n```\n\n---\n\n## The Processing Lifecycle\n\nThe engine's main entry point is the `process()` method. It follows a structured execution flow:\n\n```mermaid\ngraph TD\n A[Load Context] --> B[Initialize Response State]\n B --> C[Preparation Iterations]\n C --> D{Prepared to Respond?}\n D -- No --> C\n D -- Yes --> E[Inject Tool Insights]\n E --> F[Generate Messages]\n F --> G[Update Session State]\n G --> H[Emit Ready Event]\n```\n\n### 1. Context Loading and Initialization\nThe engine loads the full entity models from storage via `EntityQueries`. It initializes the `ResponseState` by loading relevant context variables, glossary terms, and agent capabilities.\n\n### 2. Preparation Iterations\nThe engine performs one or more iterations to \"prepare\" the response. This is a feedback loop where tool outputs can influence subsequent reasoning.\n- **Guideline Matching**: The `GuidelineMatcher` identifies relevant instructions based on the current context.\n- **Journey Projection**: The engine evaluates `Journey` states to determine which nodes in a predefined flow are active.\n- **Tool Inference**: The `ToolEventGenerator` determines if any tools should be called based on the matched guidelines.\n- **Execution**: Tools are executed, and their results (including any `TransientGuideline` objects they return) are injected back into the state for the next iteration.\n\nThe loop terminates when the `Planner` determines no further information is needed or when `max_engine_iterations` is reached.\n\n### 3. Message Generation\nOnce prepared, the engine uses a `MessageEventComposer` (either `MessageGenerator` for fluid responses or `CannedResponseGenerator` for template-based responses) to produce the final output. This phase is wrapped in an \"uncancellable section\" to ensure that once generation begins, the resulting events are properly emitted and the session state is updated.\n\n---\n\n## Planners and Plans\n\nThe `Planner` is responsible for the high-level strategy of a turn. It creates a `Plan` object that provides hooks at critical stages of the engine's execution:\n\n- `on_guidelines_matched`: Intervene after the initial match but before relational resolution.\n- `on_guidelines_resolved`: React to the final set of active guidelines.\n- `on_tools_inferred`: Filter or reorder tool calls before they are executed.\n- `on_tools_called`: Process the results of tool execution to decide if more iterations are needed.\n\nThe `NullPlanner` provides a default pass-through implementation, while `BasicPlanner` offers a foundation for custom reasoning logic.\n\n---\n\n## Engine Hooks\n\n`EngineHooks` allow developers to inject logic at specific lifecycle events without modifying the core engine code. Hooks return an `EngineHookResult`:\n- `CALL_NEXT`: Continue the chain.\n- `RESOLVE`: Stop the chain but continue engine processing.\n- `BAIL`: Stop the chain and interrupt the engine (e.g., to prevent a message from being sent).\n\n### Key Hook Points\n- `on_preparing`: Before the first preparation iteration.\n- `on_generating_messages`: After preparation is complete but before LLM generation.\n- `on_message_generated`: After the LLM produces a draft but before it is emitted to the session.\n- `on_guideline_selected_handlers`: Triggered when specific `GuidelineId`s are matched.\n\n---\n\n## Utterance Requests\n\nThe `utter()` method allows for manual or programmatic overrides. It bypasses the standard reasoning loop by accepting a sequence of `UtteranceRequest` objects. These requests are converted into synthetic guidelines with high priority, forcing the engine to generate a response that adheres to the specified actions (e.g., \"Buy time\" or \"Follow up\").\n\n---\n\n## Health and Monitoring\n\nThe engine integrates with `HealthReporter` and `Meter` to track performance:\n- **Latency**: Measured via `eng.process` and `eng.utter` histograms.\n- **Turn Health**: Success/failure rates and error classifications are reported to the `ENGINE_TURN_KIND` health view.\n- **Tracing**: Detailed spans are created for `guideline_matcher`, `tool_caller`, and `message_generation`, with tool arguments and results attached as trace events.","ai-reasoning-engine-production":"# AI Reasoning Engine — production\n\n# AI Reasoning Engine — Production\n\nThe AI Reasoning Engine is the core behavioral layer of the Parlant framework. Unlike traditional deterministic systems, this engine manages **probabilistic behavior** by layering semantic constraints, structured state machines, and strict response templates over Large Language Models (LLMs).\n\nThe engine's primary goal is to transform unpredictable LLM outputs into reliable, business-compliant agent interactions through a methodology known as **Semantic Design**.\n\n## Core Behavioral Primitives\n\nThe engine utilizes three primary primitives to control agent behavior. These are managed via the `agent` instance and are evaluated dynamically during every interaction cycle.\n\n### 1. Guidelines\nGuidelines are the fundamental unit of behavioral control. They consist of a `condition` (when to act) and an `action` (what to do).\n\n* **Condition Precision:** Guidelines should avoid vague triggers like \"Customer is unhappy\" in favor of specific states like \"Customer has explicitly declined a premium upgrade.\"\n* **Temporal Scope:** Instructions should specify how long an action persists (e.g., \"...immediately,\" \"...throughout the conversation,\" or \"...until the customer provides an email\").\n\n```python\nawait agent.create_guideline(\n condition=\"Customer asks about pricing\",\n action=\"Explain our pricing tiers clearly, emphasize value, and ask about their needs.\"\n)\n```\n\n### 2. Journeys\nFor complex, multi-step processes where guidelines alone might lose track of state, the engine uses **Journeys**. A journey is a conversational state machine that guides the agent through a defined flow while maintaining the flexibility to handle digressions.\n\n* **`chat_state`**: Defines what the agent should say or ask.\n* **`tool_state`**: Triggers a specific function call.\n* **`transition_to`**: Defines the logic for moving between states.\n\n```python\nbooking_journey = await agent.create_journey(\n title=\"Book Appointment\",\n conditions=[\"Customer wants to schedule an appointment\"]\n)\n\n# Define the flow\nstep1 = await booking_journey.initial_state.transition_to(\n chat_state=\"Ask what type of service they need\"\n)\n```\n\n### 3. Canned Responses\nIn high-stakes scenarios where the LLM must not deviate from legal or brand-approved language, the engine supports **Canned Responses**. When the agent's composition mode is set to `STRICT`, these templates override generated text entirely.\n\n```python\nawait agent.create_canned_response(\n template=\"I can help with account questions, but I must connect you with a specialist for policy details.\"\n)\n```\n\n## Tool Integration and Parameterization\n\nThe engine interacts with external systems through **Tools**. Because LLMs must \"guess\" parameters based on conversation context, the reasoning engine implements safeguards against common failure patterns:\n\n1. **Missing Information**: Preventing tool execution when required parameters are absent from the context.\n2. **Type Confusion**: Validating that strings (like emails) aren't passed into integer fields (like IDs).\n3. **False Positive Bias**: Ensuring the engine doesn't call the first \"relevant-looking\" tool without verifying it is the *best* fit for the current state.\n\n## Execution Flow: The Reasoning Loop\n\nThe engine follows a non-linear execution path to determine the next best action. It evaluates the current conversation context against the behavior model (Guidelines + Journeys) before generating a response.\n\n```mermaid\ngraph TD\n A[User Input] --> B{Context Analysis}\n B --> C[Guideline Matching]\n B --> D[Journey State Check]\n C --> E[Action Selection]\n D --> E\n E --> F{Composition Mode}\n F -- STRICT --> G[Canned Response]\n F -- FLEXIBLE --> H[LLM Generation]\n G --> I[Final Output]\n H --> I\n```\n\n## Operational Methodology: Iterative Refinement\n\nProduction agents are not \"finished\" at deployment. The engine is designed for a three-phase lifecycle:\n\n### Phase 1: Core Implementation\nFocus on the \"happy path\" using basic guidelines. Do not attempt to map every edge case initially.\n\n### Phase 2: Monitoring and Analysis\nObserve real-world interactions to identify **Interpretation Variability**. LLMs may interpret \"be helpful\" as \"give unauthorized discounts.\" These deviations are the primary data source for Phase 3.\n\n### Phase 3: Targeted Refinement\nApply specific guidelines to resolve observed issues.\n* **Problem:** Agent repeats rejected offers.\n* **Solution:** Add a guideline with a condition: `\"Customer has explicitly declined... in this session\"`.\n\n## Compliance and Safety\n\nThe engine provides a \"Defense in Depth\" approach to safety:\n* **Guidance-Based Boundaries:** Using guidelines to nudge the agent away from sensitive topics.\n* **Retrievers:** Grounding the agent in external knowledge bases to prevent hallucinations.\n* **Strict Composition:** Forcing the use of pre-approved templates for high-risk interactions.\n\nBy separating **Instruction Articulation** (the developer's role) from **Instruction Enforcement** (the engine's role), the AI Reasoning Engine ensures that once a behavior is defined, it is followed consistently at scale.","ai-reasoning-engine":"# AI Reasoning Engine\n\n# AI Reasoning Engine\n\nThe AI Reasoning Engine is the core behavioral layer of the Parlant framework. It transforms Large Language Models (LLMs) from unpredictable text generators into reliable, business-compliant agents through a methodology known as **Semantic Design**. \n\nBy layering semantic constraints, structured state machines, and strict response templates over LLMs, the engine ensures that agent interactions remain within defined operational boundaries while maintaining the flexibility of natural language.\n\n## Architecture Overview\n\nThe engine operates as a stateful orchestration layer that manages the lifecycle of a session turn. It transitions from raw input to structured action through a series of preparation iterations and a final generation phase.\n\n```mermaid\ngraph TD\n Input[User Input] --> AlphaEngine[AlphaEngine Orchestrator]\n AlphaEngine --> Context[EngineContext: Agent, Customer, Session]\n \n subgraph Preparation Phase\n Context --> GM[GuidelineMatcher]\n GM --> PB[PromptBuilder]\n Context --> TC[ToolCaller]\n TC --> PB\n end\n \n PB --> LLM[LLM Generation]\n LLM --> RS[ResponseState]\n RS --> Output[Agent Response]\n \n subgraph Lifecycle Hooks\n AlphaEngine -.-> Hooks[OnAcknowledged, OnGenerating, OnDraftGenerated]\n end\n```\n\n## Key Sub-Modules\n\n### [AlphaEngine](alpha-engine.md)\nThe primary orchestrator for the reasoning process. It manages the `EngineContext` and `ResponseState`, ensuring that every turn is processed through the necessary preparation iterations before a response is generated. It coordinates the flow between guideline matching, tool execution, and prompt assembly.\n\n### [PromptBuilder](prompt-builder.md)\nThe assembly layer that constructs the final instructions sent to the LLM. It dynamically synthesizes various data points into a coherent prompt, including:\n* **Interaction History:** Contextualizing the current turn within the session.\n* **Semantic Constraints:** Integrating matched guidelines and glossary terms.\n* **Staged Events:** Incorporating the results of tool executions and context variables.\n\n### [GuidelineMatcher](guideline-matcher.md)\nThe logic engine responsible for \"Semantic Design.\" It evaluates the current state against a library of **Guidelines**—the fundamental behavioral primitives of the framework. It filters and selects the most relevant business rules and behavioral constraints to apply to the current interaction.\n\n### [ToolCalling](tool-calling.md)\nThe execution interface for external actions. This module handles the detection of required tools, manages batching via the `DefaultToolCallBatcher`, and executes service calls. The results are fed back into the `PromptBuilder` to inform the final response.\n\n### [Planners & Hooks](planners-hooks.md)\n* **Planners:** Define the strategy for how the engine should approach a turn, including how guidelines are matched and applied.\n* **Hooks:** Provide a system for intercepting the reasoning lifecycle (e.g., `on_generating_preamble`, `on_draft_generated`), allowing for external monitoring, logging, or real-time adjustments to the agent's behavior.\n\n## Core Workflow\n\n1. **Context Initialization:** The `AlphaEngine` encapsulates the agent persona, customer identity, and session history into an `EngineContext`.\n2. **Guideline Matching:** The `GuidelineMatcher` identifies which behavioral primitives apply to the current user intent.\n3. **Action Detection & Execution:** The `ToolCaller` identifies if any external services are required to fulfill the request and executes them.\n4. **Prompt Synthesis:** The `PromptBuilder` merges the context, matched guidelines, and tool outputs into a structured prompt.\n5. **Response Generation:** The LLM generates a response based on the synthesized prompt, which is then captured in the `ResponseState` and delivered to the user.","behavioral-customization-concepts":"# Behavioral Customization — concepts\n\n# Behavioral Customization\n\nBehavioral customization in Parlant allows developers to move beyond generic LLM responses by defining specific logic, domain knowledge, and output constraints. Instead of relying solely on prompt engineering, Parlant uses a structured approach to model agent behavior through guidelines, glossary terms, relationships, variables, and retrievers.\n\n## Guidelines: The Core Logic\n\nGuidelines are the primary mechanism for nudging agent behavior in specific contexts. Each guideline consists of a **condition** (when the rule applies) and an **action** (what the agent should do).\n\n```python\nawait agent.create_guideline(\n condition=\"The customer wants to buy a laptop\",\n action=\"First, determine whether they prefer Mac or Windows\"\n)\n```\n\n### Tool Association\nGuidelines can be associated with [Tools](https://parlant.io/docs/concepts/customization/tools) to prevent LLM \"false-positives.\" By linking a tool to a guideline, the agent only considers calling that tool when the guideline's condition is met.\n\n```python\nawait agent.create_guideline(\n condition=\"The customer asks about the newest laptops\",\n action=\"First recommend the latest Mac laptops\",\n tools=[find_products_in_stock],\n)\n```\n\n### Execution Pipeline\nParlant evaluates guidelines *before* response generation. This ensures the LLM's context is dynamically managed, loading only relevant instructions to minimize \"cognitive load.\"\n\n```mermaid\ngraph LR\n Engine -->|Match guidelines| GuidelineMatcher\n GuidelineMatcher -->|Call associated tools| ToolCaller\n ToolCaller -->|Compose message| MessageComposer\n MessageComposer -.->|Generated response| Engine\n```\n\n## Glossary: Domain Knowledge\n\nThe Glossary defines the professional dictionary of your agent. It ensures the agent understands domain-specific terms and interprets guidelines correctly.\n\n* **Term:** The word or phrase.\n* **Description:** The context-specific meaning.\n* **Synonyms:** Alternative phrases users might use.\n\n```python\nawait agent.create_term(\n name=\"Ocean View\",\n description=\"Our premium rooms on floors 15-20 facing the Atlantic\",\n synonyms=[\"seaside rooms\", \"beach view\"],\n)\n```\n\nThe glossary is static knowledge (\"what things are\"), whereas **Tools** provide dynamic data access (\"fetch current status\").\n\n## Relationships: Orchestrating Behavior\n\nWhen multiple guidelines are active, relationships define how they interact. This prevents conflicting instructions and manages conversation flow.\n\n| Relationship | Method | Description |\n| :--- | :--- | :--- |\n| **Priority** | `s.prioritize_over(t)` | If both are active, only the source (S) is executed. |\n| **Entailment** | `s.entail(t)` | If S is activated, the target (T) must also be activated. |\n| **Dependency** | `s.depend_on(t)` | S is only activated if T is also active. |\n| **Disambiguation** | `s.disambiguate([t1, t2])` | If multiple targets match, the agent asks the user for clarification. |\n\n### Observational Guidelines\nYou can create guidelines without actions using `agent.create_observation(condition=...)`. These are used purely to establish context for relationships, such as deactivating a set of guidelines when a specific state is observed.\n\n## Variables: Personalization\n\nVariables provide persistent context about a customer (e.g., subscription tier, preferences). They are automatically injected into the agent's context during interactions.\n\n* **Manual Variables:** Set via `variable.set_value_for_customer()`.\n* **Tool-Enabled Variables:** Automatically updated by a tool. You can define `freshness_rules` using cron syntax to control update frequency.\n\n```python\nvariable = await agent.create_variable(\n name=\"subscription_plan\",\n description=\"The customer's subscription plan\",\n tool=get_subscription_plan,\n freshness_rules=\"0 * * * *\" # Update hourly\n)\n```\n\n## Retrievers: Contextual Grounding\n\nRetrievers implement Retrieval-Augmented Generation (RAG). While **Tools** are for actions or specific data lookups, **Retrievers** fetch information to ground the agent's general knowledge.\n\nRetrievers run in parallel with guideline matching and tool calling, reducing overall response latency.\n\n```python\nasync def answer_retriever(context: p.RetrieverContext) -> p.RetrieverResult:\n if last_msg := context.interaction.last_customer_message:\n docs = await my_vector_db.search(last_msg.content)\n return p.RetrieverResult(docs)\n return p.RetrieverResult(None)\n\nawait agent.attach_retriever(answer_retriever)\n```\n\n## Canned Responses: Output Control\n\nCanned responses eliminate hallucinations by forcing the agent to select from pre-approved templates.\n\n### Composition Modes\nThe `p.CompositionMode` determines how strictly the agent adheres to templates:\n* **Fluid:** Uses templates if a match is found; otherwise, generates a response.\n* **Composited:** Mimics the style of templates to alter a generated draft.\n* **Strict:** Only outputs approved templates. Sends a \"no-match\" message if no template fits.\n\n### Template Syntax\nTemplates use Jinja2 and can reference standard fields (`std.customer.name`), tool results, or `generative.` fields for localized LLM generation.\n\n```python\n# Template with tool-based field\nawait agent.create_canned_response(\n template=\"Your current balance is {{account_balance}}\",\n signals=[\"How much money do I have?\", \"Check my balance\"]\n)\n```\n\n**Signals** are example draft messages that help the engine retrieve the correct template even when the template contains complex dynamic fields.","behavioral-customization-parlant":"# Behavioral Customization — parlant\n\n# Behavioral Customization — parlant\n\nThe **Behavioral Customization** module provides the framework for defining, managing, and fine-tuning how agents interact with users. It moves beyond static prompting by providing structured entities for behavioral logic (Guidelines), domain knowledge (Glossary), deterministic outputs (Canned Responses), and dynamic state (Context Variables).\n\n## Core Components\n\n### Guidelines\nGuidelines are the primary mechanism for controlling agent behavior. They follow a \"Condition-Action\" pattern: **\"When [condition] occurs, then [action] should be taken.\"**\n\n* **`Guideline`**: The core data class containing `GuidelineContent` (condition, action, description), `Criticality` (LOW, MEDIUM, HIGH), and `CompositionMode`.\n* **`GuidelineStore`**: An abstract interface for persistence. The implementation, `GuidelineDocumentStore`, handles complex document migrations (from v0.1.0 up to v0.10.0) and manages associations between guidelines and tags.\n* **Tool Associations**: Guidelines can be linked to specific tools via `GuidelineToolAssociation`. This allows the system to automatically trigger tool invocations when a guideline's conditions are met.\n\n### Relationships\nRelationships define the semantic and logical connections between guidelines, tags, and tools. These connections form a graph that the orchestration engine uses to resolve conflicts or chain behaviors.\n\n* **`RelationshipKind`**: Defines the nature of the connection:\n * `ENTAILMENT`: One entity implies another.\n * `PRIORITY`: One entity takes precedence.\n * `DEPENDENCY`: One entity requires another.\n * `DISAMBIGUATION`: Used to clarify between similar guidelines.\n * `OVERLAP`: Indicates redundant or similar logic between tools or guidelines.\n* **`RelationshipStore`**: Manages the persistence and retrieval of these connections. It supports finding both direct and indirect (transitive) relationships via `_get_relationships_graph`.\n\n### Glossary\nThe Glossary allows developers to define domain-specific terminology that the agent must understand to maintain context and accuracy.\n\n* **`Term`**: Consists of a name, a detailed description, and a list of synonyms.\n* **`GlossaryStore`**: Handles the lifecycle of terms. It allows filtering terms by `TagId`, enabling different agents or contexts to share or isolate specific vocabularies.\n\n### Context Variables\nContext Variables store dynamic, stateful information about users or entities (e.g., `user_balance`, `subscription_tier`).\n\n* **`ContextVariable`**: Defines the schema, including an optional `tool_id` for automated updates and `freshness_rules`.\n* **Freshness Rules**: Uses cron expressions (validated via `croniter`) to define when a variable's data is considered stale and needs refreshing.\n* **`ContextVariableStore`**: Manages both the variable definitions and the actual `ContextVariableValue` instances keyed by unique identifiers (like a user ID).\n\n### Canned Responses\nCanned Responses provide a way to return deterministic, pre-approved text fragments while still allowing for dynamic interpolation.\n\n* **`CannedResponse`**: Contains a `value` string with placeholders (e.g., `\"Your balance is {balance}\"`).\n* **`CannedResponseField`**: Defines the requirements for placeholders, including descriptions and examples.\n* **Signals**: A sequence of strings used to match user intent to a specific canned response.\n* **Field Dependencies**: Ensures a response is only considered if specific context data is available.\n\n---\n\n## Architecture and Data Flow\n\nThe module follows a layered architecture where FastAPI routers delegate logic to core services, which in turn interact with a document-based persistence layer.\n\n```mermaid\ngraph TD\n API[API Routers: Guidelines, Glossary, etc.] --> Auth[AuthorizationPolicy]\n Auth --> App[Application Core]\n App --> Stores[Stores: GuidelineStore, RelationshipStore, etc.]\n Stores --> DB[(Document Database)]\n \n subgraph \"Entity Relationships\"\n G[Guideline] -- \"Kind\" --> R[Relationship]\n R --> T[Tag]\n G --> TA[Tool Association]\n end\n```\n\n### Execution Flow: Updating a Guideline\n1. **API Entry**: `update_guideline` in `parlant/api/guidelines.py` receives a `GuidelineUpdateParamsDTO`.\n2. **Authorization**: The `AuthorizationPolicy` is invoked with `Operation.UPDATE_GUIDELINE`.\n3. **Core Logic**: `app.guidelines.update` is called. This coordinates multiple sub-tasks:\n * Updating the guideline's basic content in `GuidelineStore`.\n * Modifying tool associations via `GuidelineToolAssociationUpdateParams`.\n * Updating tags and metadata.\n4. **Persistence**: `GuidelineDocumentStore` acquires a `ReaderWriterLock` (writer mode), serializes the `Guideline` object, and updates the underlying `DocumentCollection`.\n5. **Response**: The updated guideline is re-read, combined with its relationships and tool associations, and returned as a `GuidelineWithRelationshipsAndToolAssociationsDTO`.\n\n---\n\n## Implementation Details\n\n### Persistence and Migrations\nThe module uses a versioned document schema. `GuidelineDocumentStore` and other stores implement `_document_loader` methods that use `DocumentMigrationHelper`. This ensures that as the behavioral models evolve (e.g., adding `composition_mode` in v0.7.0 or `priority` in v0.10.0), older data is transparently upgraded upon retrieval.\n\n### Tagging System\nTags are a cross-cutting concern used to group Guidelines, Terms, and Context Variables.\n* **Filtering**: Most `list` and `find` operations (e.g., `list_guidelines`, `list_terms`) accept a `tag_id` to scope the results.\n* **Associations**: Associations are often stored in separate collections (e.g., `GuidelineTagAssociationDocument`) to allow for efficient many-to-many lookups without bloating the primary entity documents.\n\n### Validation\n* **Cron Expressions**: `ContextVariableUpdateParamsDTO` uses a `@field_validator` to ensure `freshness_rules` are valid cron strings before they reach the core logic.\n* **Relationship Integrity**: The API layer prevents invalid graph states, such as a guideline relating to itself or a relationship having both a source guideline and a source tag simultaneously.","behavioral-customization":"# Behavioral Customization\n\n# Behavioral Customization\n\nThe **Behavioral Customization** module provides a structured framework for defining how an agent interacts, reasons, and maintains domain-specific knowledge. Rather than relying on monolithic prompt engineering, this module decomposes agent behavior into manageable, programmatic entities that govern logic, state, and vocabulary.\n\n## Architecture Overview\n\nBehavioral customization is built on four pillars that work in concert to produce deterministic and context-aware agent responses:\n\n1. **Logic & Constraints**: [Guidelines](guidelines.md) and [Canned Responses](canned-responses.md) define the \"what\" and \"how\" of agent actions. Guidelines use a **Condition-Action** pattern to trigger specific behaviors, while Canned Responses ensure consistent, template-based output for recurring scenarios.\n2. **Domain Knowledge**: The [Glossary](glossary.md) acts as the agent's specialized dictionary, ensuring it understands and uses industry-specific terminology correctly.\n3. **Dynamic State**: [Context Variables](context-variables.md) allow the agent to track user-specific or session-specific data, which can then be referenced by Guidelines to tailor the interaction.\n4. **Connectivity**: [Relationships](relationships.md) and [Tool Associations](guideline-tool-associations.md) bind these entities together, allowing the system to understand how a specific guideline relates to a glossary term or which tools should be invoked under certain conditions.\n\n## How Sub-modules Interact\n\nThe power of the Behavioral Customization module lies in the interplay between its components. A typical execution flow involves the system evaluating the current state against defined logic:\n\n* **Contextual Evaluation**: When a user interacts with the agent, the system retrieves relevant **Context Variables** and **Glossary** terms.\n* **Guideline Triggering**: The system evaluates **Guidelines**. If a \"Condition\" is met (often based on the presence of a specific term or a variable value), the corresponding \"Action\" is queued.\n* **Relationship Resolution**: The **Relationships** engine determines the priority and relevance of guidelines, ensuring that high-criticality rules take precedence and that related entities are considered together.\n* **Response Generation**: The agent produces a response that adheres to the active guidelines, potentially utilizing a **Canned Response** template if the situation matches a predefined output requirement.\n\n```mermaid\ngraph TD\n UserRequest[User Request] --> Engine{Behavior Engine}\n \n subgraph Knowledge & State\n Glossary[Glossary Terms]\n Variables[Context Variables]\n end\n \n subgraph Logic Layer\n Guidelines[Guidelines: Condition-Action]\n Canned[Canned Responses]\n end\n \n Knowledge & State --> Engine\n Logic Layer --> Engine\n Relationships[Relationships & Associations] -.-> Logic Layer\n \n Engine --> FinalResponse[Tailored Agent Response]\n```\n\n## Key Components\n\n* **[Guidelines](guidelines.md)**: The primary mechanism for nudging behavior. Includes `Criticality` levels and `CompositionMode` to handle how multiple rules blend.\n* **[Glossary](glossary.md)**: Manages `Terms` to ensure domain-specific accuracy and prevent LLM hallucination regarding technical jargon.\n* **[Context Variables](context-variables.md)**: Stores dynamic data (e.g., user preferences, cart contents) that Guidelines can use to make logic-based decisions.\n* **[Canned Responses](canned-responses.md)**: Provides validated templates for high-stakes or standardized communication.\n* **[Relationships](relationships.md)**: A graph-based system that connects guidelines, terms, and tools, allowing for complex behavioral dependencies.","core-entities":"# Core Entities\n\n# Core Entities\n\nThe Core Entities module defines the fundamental building blocks of the Parlant ecosystem: **Agents**, **Customers**, and **Tags**. These entities provide the identity, behavioral configuration, and categorization necessary for orchestrating AI-driven conversations.\n\n## Module Architecture\n\nParlant follows a layered architecture for entity management:\n1. **API Layer (`parlant.api`)**: FastAPI routers that handle REST requests, DTO validation, and authorization.\n2. **Application Module (`parlant.core.app_modules`)**: Orchestration logic that bridges the API and the storage layer, handling cross-entity validation (e.g., ensuring a tag exists before attaching it to an agent).\n3. **Store Layer (`parlant.core`)**: Abstract interfaces (`AgentStore`, `CustomerStore`) and concrete implementations (`AgentDocumentStore`, `CustomerDocumentStore`) that manage persistence, indexing, and data migrations.\n\n```mermaid\ngraph TD\n API[API Routers] --> Module[App Modules]\n Module --> Store[Document Stores]\n Store --> DB[(Document Database)]\n Module -.-> TagStore[Tag Store]\n```\n\n---\n\n## Agents\n\nAn **Agent** is a customized AI personality. Unlike \"task-specific\" agents in other frameworks, a Parlant agent represents a single, coherent entity that a customer interacts with.\n\n### Key Components\n- **`Agent` (Dataclass)**: The domain model containing identity (`id`, `name`, `description`) and behavioral settings.\n- **`CompositionMode`**: Controls how the agent generates responses (e.g., `FLUID`, `CANNED_STRICT`).\n- **`MessageOutputMode`**: Determines if the agent sends responses as a single `BLOCK` or via a `STREAM`.\n- **`max_engine_iterations`**: A safety limit on the number of internal processing cycles the agent can perform per request.\n\n### Implementation Details\nThe `AgentModule` manages the lifecycle of an agent. When calling `AgentModule.update`, the system performs partial updates via `AgentUpdateParams`. It also uses `_ensure_tag` to validate that any `TagId` being associated with the agent actually exists in the `TagStore`.\n\nThe `AgentDocumentStore` handles complex version migrations (from `0.1.0` through `0.5.0`), ensuring that legacy agent configurations (like older utterance modes) are mapped to the current `CompositionMode` schema.\n\n---\n\n## Customers\n\nA **Customer** represents any entity interacting with an agent. This can be a human user, a third-party bot, or a system process.\n\n### Identity and Metadata\n- **`extra`**: A `Mapping[str, str]` used to store arbitrary metadata (e.g., email, location, subscription tier). This metadata is often used by tools to provide context-aware responses.\n- **Guest Access**: The system reserves a special `CustomerStore.GUEST_ID` (\"guest\"). The `list_customers` method is designed to always include the guest customer in the results unless specific tag filters are applied.\n\n### Persistence and Storage\nCustomers can be stored in-memory, in local JSON files, or in MongoDB. The `CustomerDocumentStore` implements `upsert_extra` and `remove_extra` to allow granular updates to the metadata dictionary without overwriting the entire customer record.\n\n---\n\n## Tags\n\n**Tags** are the primary mechanism for categorization and group-based behavior. Both Agents and Customers can be associated with multiple tags.\n\n### Specialized Tags\nThe `Tag` class provides static utility methods to handle system-generated tags that link entities to other Parlant concepts:\n- `Tag.for_agent_id(agent_id)`\n- `Tag.for_journey_id(journey_id)`\n- `Tag.for_guideline_id(guideline_id)`\n\nThese methods use a prefixing convention (e.g., `agent:ID`) which can be parsed back using extractors like `Tag.extract_agent_id`.\n\n### Tag Associations\nAssociations are managed through dedicated collections (`agent_tags` and `customer_tag_associations`). When an agent or customer is deleted, the respective store (`AgentStore.delete_agent` or `CustomerStore.delete_customer`) automatically cleans up these associations to maintain referential integrity.\n\n---\n\n## Data Flow and Persistence\n\n### Execution Flow: Creating an Entity\n1. **API**: `create_agent` or `create_customer` receives a DTO.\n2. **Authorization**: The `AuthorizationPolicy` checks for the required permission (e.g., `Operation.CREATE_AGENT`).\n3. **Module**: `AgentModule.create` validates that any provided `TagIds` exist.\n4. **Store**: `AgentDocumentStore.create_agent` generates a unique ID (using `IdGenerator` and an MD5 checksum of the entity's properties), serializes the data via `_serialize_agent`, and inserts it into the `DocumentCollection`.\n\n### Concurrency Control\nAll stores utilize a `ReaderWriterLock` to ensure thread-safe operations. \n- **Reader Lock**: Used for `read_agent`, `list_agents`, and `find` operations to allow concurrent reads.\n- **Writer Lock**: Used for `create`, `update`, `delete`, and `upsert_tag` operations to ensure data consistency during modifications.\n\n### Pagination\nThe `CustomerStore.list_customers` method supports cursor-based pagination. It returns a `CustomerListing` containing the current page of items, the `total_count`, and a `next_cursor` for subsequent fetches. This is exposed via the API as `PaginatedCustomersDTO`.","evaluation-moderation-advanced":"# Evaluation & Moderation — advanced\n\n# Evaluation & Moderation: Enforcement & Explainability\n\nParlant ensures behavioral consistency and transparency through **Attentive Reasoning Queries (ARQs)**. Unlike standard prompting, which relies on the LLM's latent ability to follow instructions, ARQs implement structured reasoning blueprints that force the model to validate its decisions against specific guidelines and constraints before generating a response.\n\n## Attentive Reasoning Queries (ARQs)\n\nARQs are domain-specialized reasoning patterns embedded into the agent's execution flow. They function as a \"mental checklist\" that the LLM must complete during the inference process. This method is designed to maximize adherence to the conversation model while producing auditable artifacts for every decision made.\n\n### The Reasoning Blueprint\nAn ARQ typically guides the model through four distinct stages:\n1. **Context Assessment:** Evaluating the current state of the conversation and identifying relevant environmental factors.\n2. **Solution Exploration:** Identifying potential actions or responses based on the available guidelines and tools.\n3. **Critique:** Evaluating proposed actions against constraints and safety boundaries.\n4. **Decision Formation:** Finalizing the output based on the preceding reasoning steps.\n\nThis structured approach reduces the likelihood of the model overlooking critical instructions, especially in complex scenarios with conflicting guidelines.\n\n## Runtime Enforcement\n\nARQs are applied dynamically across different stages of the message generation pipeline. Parlant specializes these queries based on the specific entity being evaluated.\n\n### Guideline Matching\nWhen the `GuidelineMatcher` evaluates whether a specific guideline applies to a user's input, it uses an ARQ to generate a rationale. This prevents \"hallucinated\" applications of guidelines by requiring the model to justify the connection between the user's intent and the guideline's condition.\n\n### Tool-Calling and Composition\nBeyond guidelines, ARQs are utilized during:\n* **Tool Selection:** Reasoning through why a specific tool is necessary and how its parameters should be mapped.\n* **Message Composition:** Ensuring the final response tone and content align with the agent's persona and the active guidelines.\n\n```mermaid\ngraph TD\n Input[User Input] --> ARQ[ARQ Engine]\n ARQ --> Assessment[Context Assessment]\n Assessment --> Exploration[Solution Exploration]\n Exploration --> Critique[Critique & Validation]\n Critique --> Decision[Final Decision/Action]\n Decision --> Artifacts[Reasoning Artifacts]\n```\n\n## Explainability and Troubleshooting\n\nEvery ARQ execution produces structured artifacts. These artifacts are the primary tool for developers to debug \"why\" an agent behaved in a certain way.\n\n### Analyzing ARQ Artifacts\nARQ logs provide a granular breakdown of the model's logic. For example, when a guideline is evaluated, the system produces a JSON object detailing the application rationale:\n\n* **`condition_application_rationale`**: A natural language explanation of why the model believes a guideline's condition was met.\n* **`action_application_rationale`**: A segment-by-segment breakdown of how the model intends to execute the guideline's instructions.\n* **`applies_score`**: A numerical confidence value (typically 1-10) indicating the strength of the match.\n\n### Example Artifact\n```json\n{\n \"guideline_id\": \"fl00LGUyZX\",\n \"condition\": \"the customer wants to return an item\",\n \"condition_application_rationale\": \"The customer explicitly stated that they need to return a sweater that doesn't fit.\",\n \"condition_applies\": true,\n \"action\": \"get the order number and item name and then help them return it\",\n \"action_application_rationale\": [\n {\n \"action_segment\": \"Get the order number and item name\",\n \"rationale\": \"I've yet to get the order number and item name from the customer.\"\n }\n ],\n \"applies_score\": 9\n}\n```\n\n### Debugging Workflow\nWhen an agent fails to follow a guideline or provides an incorrect response, developers should:\n1. **Inspect the `applies_score`**: If the score is low but the guideline should have applied, the `condition` text may be too ambiguous.\n2. **Review the `rationale`**: If the rationale shows a misunderstanding of the user's intent, the `Context Assessment` stage of the ARQ may need more specific context or the guideline may need a `precedence` adjustment.\n3. **Validate `action_segments`**: If the agent identifies the correct guideline but fails to execute the action, the `action` description in the guideline may need to be broken down into more explicit steps.\n\nBy treating these reasoning paths as auditable logs, Parlant allows for iterative refinement of the conversation model without the guesswork typically associated with LLM prompt engineering.","evaluation-moderation-parlant":"# Evaluation & Moderation — parlant\n\n# Evaluation & Moderation — parlant\n\nThe **Evaluation & Moderation** module provides a framework for analyzing and validating behavioral instructions (Guidelines) and structured conversation flows (Journeys). It uses LLM-based \"proposers\" and \"detectors\" to determine the actionability, coherence, and technical requirements of agent instructions before they are deployed or during system audits.\n\n## Core Concepts\n\n### Evaluation\nAn `Evaluation` is a top-level task tracking the analysis of one or more payloads. It transitions through states: `PENDING`, `RUNNING`, `COMPLETED`, or `FAILED`.\n\n### Payload\nA `Payload` represents the unit of work being evaluated. There are two primary kinds:\n- **GuidelinePayload**: Contains `GuidelineContent` (condition/action) and associated `ToolId`s.\n- **JourneyPayload**: References a `JourneyId` to evaluate a multi-step conversation flow.\n\n### Invoice\nAn `Invoice` is the result of evaluating a single payload. It contains:\n- **Checksum**: A hash of the input payload to detect changes.\n- **Data**: The analysis results (e.g., proposed actions, tool requirements).\n- **Approved**: A boolean indicating if the evaluation task is considered valid.\n\n---\n\n## Architecture\n\nThe module follows a layered architecture where the API triggers background tasks handled by specialized evaluators.\n\n```mermaid\ngraph TD\n API[Evaluations API] --> Mod[EvaluationModule]\n Mod --> BCE[BehavioralChangeEvaluator]\n BCE --> GE[GuidelineEvaluator]\n BCE --> JE[JourneyEvaluator]\n GE --> Detectors[Specialized Detectors/Proposers]\n BCE --> Store[EvaluationStore]\n```\n\n### BehavioralChangeEvaluator\nThe central service orchestrating the evaluation process. It validates payloads, creates the initial evaluation record in the `EvaluationStore`, and spawns a background task via `BackgroundTaskService` to execute the analysis.\n\n### GuidelineEvaluator\nAnalyzes individual guidelines using a suite of specialized components:\n- **GuidelineActionProposer**: If a guideline has tools but no action text, this component generates a natural language action based on the tool's schema and parameters.\n- **CustomerDependentActionDetector**: Determines if an action requires input from the user (e.g., \"ask for account number\") or can be completed by the agent alone.\n- **AgentIntentionProposer**: Identifies if a condition describes a future intention (e.g., \"You are going to discuss...\") rather than a reactive state.\n- **ToolRunningActionDetector**: Checks if an action is exclusively fulfilled by tool execution.\n\n### JourneyEvaluator\nEvaluates structured flows by projecting journeys into guidelines. It uses the `JourneyGuidelineProjection` to map nodes to instructions and then runs the `GuidelineEvaluator` on each node. It also utilizes:\n- **RelativeActionProposer**: Analyzes how actions change relative to the journey's progression.\n- **JourneyReachableNodesEvaluator**: Determines the logical flow and reachability of follow-up steps.\n\n---\n\n## Execution Flow: Running an Evaluation\n\nWhen `create_evaluation_task` is called, the following flow occurs:\n\n1. **Validation**: `validate_payloads` ensures the request is not empty.\n2. **Persistence**: The `EvaluationStore` creates a record with `PENDING` status.\n3. **Backgrounding**: `run_evaluation` starts as a background task.\n4. **Analysis**:\n - The status is updated to `RUNNING`.\n - `GuidelineEvaluator.evaluate()` and `JourneyEvaluator.evaluate()` are called concurrently using `asyncio.gather`.\n - Each evaluator uses a `ProgressReport` to update the `progress` field (0.0 to 100.0) in the store.\n5. **Invoice Generation**: Results from the detectors are packed into `InvoiceGuidelineData` or `InvoiceJourneyData`.\n6. **Completion**: The evaluation is updated with the final invoices and marked as `COMPLETED","evaluation-moderation-production":"# Evaluation & Moderation — production\n\n# Evaluation & Moderation\n\nThe Moderation module provides a protective layer between raw user input and the AI agent. By filtering content before it reaches the LLM, Parlant ensures that agents remain professional, avoid sensitive topics, and resist manipulation attempts like jailbreaking.\n\n## Overview\n\nModeration in Parlant is applied at the point of event creation. When an input is flagged by the moderation layer, the actual content is intercepted and replaced with a metadata-rich placeholder. This prevents the LLM from being exposed to harmful patterns while allowing it to respond gracefully to the fact that a violation occurred.\n\n```mermaid\ngraph LR\n User[User Input] --> Mod{Moderation Layer}\n Mod -- Flagged --> Agent[Agent sees 'Censored']\n Mod -- Clean --> Agent[Agent sees Message]\n Agent --> Response[Guideline-based Response]\n```\n\n## Moderation Modes\n\nParlant supports two levels of moderation, configured via the `moderation` parameter during event creation.\n\n### 1. Standard Moderation (`auto`)\nThis mode utilizes **OpenAI’s Omni Moderation API**. It is designed to filter content across several categories, including:\n* Harassment and hate speech.\n* Self-harm and violence.\n* Sexual content.\n* Illicit activities.\n\n### 2. Jailbreak Protection (`paranoid`)\nThis mode integrates with **Lakera Guard** to provide advanced protection against prompt injection and jailbreaking. It is intended for production environments where users might attempt to bypass agent instructions or extract system prompts.\n\n> **Note:** To use `paranoid` mode, you must set the `LAKERA_API_KEY` environment variable on the Parlant server.\n\n## Implementation\n\nModeration is enabled by passing the `moderation` argument to the session's event creation method.\n\n### Python SDK\n```python\nfrom parlant.client import ParlantClient\n\nclient = ParlantClient(base_url=SERVER_ADDRESS)\n\nclient.sessions.create_event(\n session_id=SESSION_ID,\n kind=\"message\",\n source=\"customer\",\n message=\"User input here\",\n moderation=\"auto\", # or \"paranoid\"\n)\n```\n\n### TypeScript SDK\n```typescript\nimport { ParlantClient } from 'parlant-client';\n\nconst client = new ParlantClient({ environment: SERVER_ADDRESS });\n\nawait client.sessions.createEvent(SESSION_ID, {\n kind: \"message\",\n source: \"customer\",\n message: \"User input here\",\n moderation: \"auto\", // or \"paranoid\"\n});\n```\n\n## Agent Perception and Guidelines\n\nWhen a message is flagged, the agent does not receive the original text. Instead, it receives a system-generated notification indicating that the message was censored and the specific reason for the flag (e.g., \"harassment\").\n\nThis allows developers to use **Guidelines** to define how the agent should behave when moderation is triggered. Rather than the system simply returning an error code to the user, the agent can provide a contextual, polite refusal.\n\n### Example Guideline\n* **Condition:** The customer's last message is censored.\n* **Action:** Acknowledge that the message violated safety guidelines, inform them you cannot fulfill the request, and offer to connect them to a human representative.\n\n## Configuration Summary\n\n| Feature | Mode | Provider | Required Config |\n| :--- | :--- | :--- | :--- |\n| Content Filtering | `auto` | OpenAI | `OPENAI_API_KEY` |\n| Jailbreak Protection | `paranoid` | Lakera | `LAKERA_API_KEY` |\n\nBy decoupling the moderation logic from the agent's core instructions, Parlant ensures that safety measures are robust and cannot be easily bypassed by the LLM's own \"statistical pattern matching\" tendencies.","evaluation-moderation":"# Evaluation & Moderation\n\n# Evaluation & Moderation\n\nThe **Evaluation & Moderation** module provides a multi-layered governance framework for Parlant agents. It ensures that agents remain safe, follow complex behavioral instructions, and possess technically sound guidelines. This is achieved through a combination of real-time input filtering, structured reasoning during inference, and automated auditing of agent instructions.\n\n## Architecture Overview\n\nThe module operates across three distinct stages of the agent lifecycle:\n\n1. **Input Defense (Production):** The [Moderation Layer](production.md) intercepts raw user input at the point of event creation. It identifies harmful patterns or jailbreak attempts, replacing violating content with metadata-rich placeholders before the LLM processes the event.\n2. **Inference Enforcement (Advanced):** Once input is cleared, [Attentive Reasoning Queries (ARQs)](advanced.md) force the LLM to follow structured reasoning blueprints. This \"mental checklist\" ensures the agent validates its intended response against specific guidelines and constraints before final generation.\n3. **Instruction Validation (Parlant):** The [Evaluation Framework](parlant.md) acts as an offline audit system. It uses specialized \"proposers\" and \"detectors\" to analyze `GuidelinePayloads`, ensuring that the instructions provided to the agent are actionable, coherent, and correctly mapped to technical tools.\n\n```mermaid\ngraph TD\n User[User Input] --> Mod[Moderation Layer]\n Mod -- \"Filtered Input\" --> ARQ[ARQ Reasoning Blueprint]\n \n subgraph \"Evaluation Framework (Offline/Audit)\"\n Eval[Evaluation Task] --> Proposer[Action Proposers]\n Eval --> Detector[Tool/Behavior Detectors]\n Proposer --> Guidelines\n Detector --> Guidelines\n end\n\n Guidelines -.-> ARQ\n ARQ --> Response[Validated Agent Response]\n \n style Eval fill:#f9f,stroke:#333\n style Mod fill:#bbf,stroke:#333\n style ARQ fill:#bfb,stroke:#333\n```\n\n## Key Workflows\n\n### Behavioral Consistency\nThe synergy between **Guidelines** and **ARQs** ensures that high-level behavioral requirements are not just suggestions but enforced constraints. While the Evaluation sub-module validates that a `Guideline` is technically sound (e.g., checking tool requirements via `tool_running_action_detector`), the Advanced sub-module ensures that same guideline is actively reasoned about during a live conversation.\n\n### Content Safety & Explainability\nSafety is handled both by suppression and transparency. The [Moderation](production.md) sub-module prevents exposure to harmful content, while [ARQs](advanced.md) provide an auditable trail of *why* an agent chose a specific path, making the agent's decision-making process transparent to developers.\n\n### Automated Auditing\nThe [Evaluation](parlant.md) sub-module automates the maintenance of complex agents. By running `Evaluation` tasks, developers can detect if new guidelines conflict with existing ones or if the agent's intended actions (via `guideline_action_proposer`) require tools that are not yet implemented.\n\n## Sub-modules\n\n* **[Evaluation & Moderation — advanced](advanced.md):** Focuses on Attentive Reasoning Queries (ARQs) for behavioral enforcement and explainability.\n* **[Evaluation & Moderation — production](production.md):** Details the moderation layer used to filter and intercept harmful user inputs.\n* **[Evaluation & Moderation — parlant](parlant.md):** The core framework for analyzing guidelines and journeys using LLM-based proposers and detectors.","getting-started-examples":"# Getting Started & Examples\n\n# Getting Started & Examples\n\nParlant is an open-source **Agentic Behavior Modeling (ABM) Engine**. Unlike traditional flow engines that rely on rigid scripts or free-form prompt engineering that lacks consistency, Parlant uses structured behavior models to define how agents interact with users.\n\n## Installation\n\nParlant requires **Python 3.10+**. Install the core package via pip:\n\n```bash\npip install parlant\n```\n\nFor specific NLP providers like Cerebras, install the corresponding extra:\n```bash\npip install parlant[cerebras]\n```\n\n### Environment Setup\nParlant uses OpenAI as the default NLP provider. Ensure your API key is available in your environment:\n\n```bash\nexport OPENAI_API_KEY=\"<YOUR_API_KEY>\"\n```\n\n## Core Implementation Pattern\n\nEvery Parlant application follows a standard asynchronous lifecycle using the `parlant.sdk` (typically imported as `p`).\n\n```python\nimport parlant.sdk as p\nimport asyncio\n\nasync def main():\n # Initialize the server context\n async with p.Server() as server:\n # Create a persistent agent instance\n agent = await server.create_agent(\n name=\"Healthcare Agent\",\n description=\"Empathetic and calming healthcare assistant.\",\n )\n \n # Define behavior here...\n\nif __name__ == \"__main__\":\n asyncio.run(main())\n```\n\n## Domain Adaptation (Glossary)\n\nTo ensure the agent understands business-specific terminology without bloating the system prompt, use the Glossary API. This allows the agent to resolve synonyms and understand specific entities.\n\n```python\nasync def add_domain_glossary(agent: p.Agent) -> None:\n await agent.create_term(\n name=\"Charles Xavier\",\n synonyms=[\"Professor X\"],\n description=\"The doctor who specializes in neurology.\",\n )\n```\n\n## Modeling Conversational Journeys\n\nJourneys define structured paths for specific customer goals. They consist of **states** and **transitions** triggered by conditions.\n\n### 1. Defining Tools\nTools connect the agent to external data. Use the `@p.tool` decorator.\n\n```python\n@p.tool\nasync def get_upcoming_slots(context: p.ToolContext) -> p.ToolResult:\n # Logic to fetch data from an API\n return p.ToolResult(data=[\"Monday 10 AM\", \"Tuesday 2 PM\"])\n```\n\n### 2. Constructing the Journey\nA journey starts at an `initial_state` and moves through `chat_state` (agent speaks) or `tool_state` (agent executes code).\n\n```python\nasync def create_scheduling_journey(agent: p.Agent) -> p.Journey:\n journey = await agent.create_journey(\n title=\"Schedule Appointment\",\n description=\"Helps patients find a time.\",\n triggers=[\"The patient wants to schedule an appointment\"],\n )\n\n # Initial interaction\n t0 = await journey.initial_state.transition_to(\n chat_state=\"Determine the reason for the visit\"\n )\n\n # Execute a tool\n t1 = await t0.target.transition_to(tool_state=get_upcoming_slots)\n\n # Conditional transition based on user input\n await t1.target.transition_to(\n chat_state=\"Confirm details\",\n condition=\"The patient picks a time\"\n )\n \n return journey\n```\n\n### Journey Architecture\nThe following diagram represents the state machine logic used in the Healthcare example:\n\n```mermaid\nstateDiagram-v2\n [*] --> DetermineReason: Initial State\n DetermineReason --> GetSlots: transition_to(tool_state)\n GetSlots --> ListTimes: transition_to(chat_state)\n ListTimes --> Confirm: condition=\"Patient picks time\"\n ListTimes --> GetLater: condition=\"None work\"\n Confirm --> Book: transition_to(tool_state)\n Book --> [*]: p.END_JOURNEY\n```\n\n## Behavioral Guidelines\n\nGuidelines provide granular control over agent behavior in specific contexts. They are composed of a **condition** (when to act) and an **action** (what to do).\n\n### Scoped Guidelines\nGuidelines added to a `Journey` only apply while the patient is within that specific flow.\n```python\nawait journey.create_guideline(\n condition=\"The patient says their visit is urgent\",\n action=\"Tell them to call the office immediately\",\n)\n```\n\n### Global Guidelines\nGuidelines added directly to the `Agent` apply across all interactions.\n```python\nawait agent.create_guideline(\n condition=\"The patient asks about insurance\",\n action=\"List accepted providers and suggest calling the office\",\n tools=[get_insurance_providers],\n)\n```\n\n## Intent Disambiguation\n\nWhen a user's query is vague and could trigger multiple journeys, use **Observations** to force clarification.\n\n```python\n# Create an observation of a vague intent\nstatus_inquiry = await agent.create_observation(\n \"The patient asks to follow up, but it's not clear how\",\n)\n\n# Link the observation to potential journeys\nawait status_inquiry.disambiguate([scheduling_journey, lab_results_journey])\n```\n\n## Voice and Performance Optimization\n\nFor voice-based agents, Parlant provides specialized policies to manage perceived latency and streaming.\n\n```python\nasync def configure_container(container: p.Container) -> p.Container:\n # Optimize for voice interaction speed\n container[p.PerceivedPerformancePolicy] = p.VoiceOptimizedPerceivedPerformancePolicy()\n return container\n\nasync def main():\n async with p.Server(configure_container=configure_container) as server:\n agent = await server.create_agent(\n name=\"Walker\",\n output_mode=p.OutputMode.STREAM, # Enable streaming for lower TTFT\n )\n```\n\n## Testing and Integration\n\n### Local Testing\nOnce the server is running (`python main.py`), the built-in testing dashboard is available at:\n`http://localhost:8800`\n\n### Frontend Integration\nParlant provides a React widget for rapid deployment:\n```bash\nnpm install parlant-chat-react\n```\n\n```jsx\nimport ParlantChatbox from 'parlant-chat-react';\n\n<ParlantChatbox \n server=\"http://localhost:8800\" \n agentId=\"YOUR_AGENT_ID\" \n/>\n```\n\nFor custom integrations, use the `parlant-client` SDK available for Python and TypeScript.","infrastructure-observability-parlant":"# Infrastructure & Observability — parlant\n\n# Infrastructure & Observability — parlant\n\nThe **Infrastructure & Observability** module provides the foundational cross-cutting concerns for the Parlant server. It manages the FastAPI application lifecycle, structured logging, distributed tracing, performance metrics, and a sophisticated health reporting system.\n\n## Application Lifecycle and API\n\nThe API is built on FastAPI and initialized via `create_api_app`. It uses the `lagom` library for dependency injection, ensuring that core services like the `Logger`, `Tracer`, and `Application` logic are consistently available.\n\n### Request Pipeline\nEvery HTTP request passes through a series of specialized middlewares:\n1. **Context Propagation**: Injects `ContextVar` values into the request task.\n2. **Cancellation Handling**: Catches `asyncio.CancelledError` to return a `503 Service Unavailable` instead of allowing the server to crash or leak resources.\n3. **Tracing & Metrics**: Generates a unique Request ID, starts a tracer span, and measures request duration using a histogram.\n4. **Authorization**: Validates permissions and enforces rate limits based on the active `AuthorizationPolicy`.\n\n```mermaid\ngraph TD\n A[Incoming Request] --> B[Context Middleware]\n B --> C[Cancellation Middleware]\n C --> D[Tracing & Metrics Middleware]\n D --> E[Authorization Policy]\n E --> F[Route Handler]\n F --> G[Exception Handlers]\n```\n\n## Observability Stack\n\n### Logging\nParlant uses a structured logging approach via the `Logger` abstraction.\n- **TracingLogger**: Wraps `structlog` to provide ISO timestamps, log levels, and automatic injection of `trace_id` and `scope` identifiers.\n- **CompositeLogger**: Allows multiplexing logs to multiple destinations (e.g., Stdout and File).\n- **WebSocketLogger**: Enables real-time log streaming to the frontend via the `/logs` endpoint.\n\n### Tracing\nThe `Tracer` interface manages execution spans. The `LocalTracer` implementation utilizes `contextvars` to maintain trace and span IDs across asynchronous boundaries without manual passing of context objects.\n- **Spans**: Created via `with tracer.span(\"name\", attributes):`.\n- **Attributes**: Key-value pairs that provide metadata for spans, accessible via `get_attribute` and `set_attribute`.\n\n### Metrics (Meter)\nThe `Meter` system tracks system performance through:\n- **Counters**: For discrete events (e.g., `nlp.requests`).\n- **Histograms**: Specifically `DurationHistogram` for measuring latencies in milliseconds.\n\n## Health Reporting System\n\nThe `/healthz` endpoint provides a detailed snapshot of system vitality. Unlike simple \"up/down\" checks, Parlant uses a report-based aggregation system.\n\n### Components\n- **HealthReporter**: A central registry that collects `HealthReport` objects. It manages data retention (window-based and count-based) and caches snapshots to prevent performance degradation from frequent polling.\n- **HealthView**: Protocols that interpret raw reports into status levels (`HEALTHY`, `DEGRADED`, `UNHEALTHY`).\n - **NLPHealthView**: Monitors LLM request success rates and latency percentiles (p50/p95) per schema.\n - **EngineHealthView**: Tracks turn-processing success and \"Time to First Message\" (TTFM).\n - **EventLoopHealthView**: Interfaces with the `EventLoopMonitor` to detect if the Python event loop is blocked.\n\n### Event Loop Monitoring\nThe `EventLoopMonitor` runs a periodic background task that measures the \"overshoot\" of `asyncio.sleep`. If the actual wake-up time significantly exceeds the scheduled time, the loop is flagged as degraded (>200ms) or unhealthy (>500ms).\n\n## Authorization and Rate Limiting\n\nAccess control is governed by the `AuthorizationPolicy` abstract class, which separates permission logic from the API routes.\n\n- **DevelopmentAuthorizationPolicy**: Disables rate limits and enables permissive CORS for local development.\n- **ProductionAuthorizationPolicy**: Enforces strict permission checks and utilizes `BasicRateLimiter`.\n- **Rate Limiting**: Uses the `limits` library with various strategies (Moving Window, Fixed Window). Limits are typically keyed by Client IP and the specific `Operation` enum (e.g., `Operation.CREATE_AGENT`).\n\n## Concurrency and Async Utilities\n\nThe module provides several utilities to handle Python's asynchronous nature safely:\n\n- **BackgroundTaskService**: Manages long-running background tasks. It provides `start`, `restart`, and `cancel` methods with tagging, ensuring tasks are cleaned up during application shutdown (`__aexit__`).\n- **safe_gather**: A robust wrapper around `asyncio.gather` that ensures if one task is cancelled, all other pending tasks in the group are also cancelled and their exceptions handled.\n- **Timeout & Stopwatch**: Clock-aware utilities for measuring elapsed time or enforcing deadlines relative to the event loop's monotonic clock.\n- **ReaderWriterLock**: An asynchronous implementation of a shared/exclusive lock to manage concurrent resource access.\n- **latched_shield**: A specialized utility to prevent task cancellation during critical sections (e.g., database commits) while still allowing the caller to eventually receive the result or the cancellation signal.\n\n## Common Data Structures\n\nThe `parlant.api.common` and `parlant.core.common` modules define the shared DTOs (Data","infrastructure-observability-production":"# Infrastructure & Observability — production\n\n# Infrastructure & Observability — Production\n\nThe Production module provides the security and stability layer for Parlant deployments. It focuses on **API Hardening** through a dual-layered approach: fine-grained authorization and configurable rate limiting.\n\n## Architecture Overview\n\nThe hardening system sits between the incoming FastAPI requests and the core agent logic. It is governed by the `AuthorizationPolicy` interface, which dictates whether a request is both permitted (identity/permissions) and safe (rate limits).\n\n```mermaid\ngraph TD\n Req[FastAPI Request] --> Auth[AuthorizationPolicy]\n subgraph \"AuthorizationPolicy\"\n CheckP[check_permission]\n CheckR[check_rate_limit]\n end\n CheckP -- Denied --> 403[403 Forbidden]\n CheckR -- Denied --> 429[429 Too Many Requests]\n CheckP -- Allowed --> CheckR\n CheckR -- Allowed --> Logic[Agent Logic / Service]\n```\n\n## Authorization Policies\n\nAll authorization logic must implement the `AuthorizationPolicy` abstract base class. This class defines the contract for securing API operations.\n\n### Core Interface\n\n- `check_permission(request, permission)`: Validates if the requester has the rights to perform a specific `AuthorizationPermission` (e.g., `CREATE_AGENT`, `LIST_SESSIONS`).\n- `check_rate_limit(request, permission)`: Validates if the requester has exceeded their allocated quota.\n- `authorize(request, permission)`: The entry point used by the server. It calls the above methods sequentially and raises an `HTTPException` if either fails.\n\n### Built-in Implementations\n\n1. **`DevelopmentAuthorizationPolicy`**: A permissive policy that returns `True` for all checks. This is the default for local development but should never be used in production.\n2. **`ProductionAuthorizationPolicy`**: A strict, extensible policy designed for live environments. It provides a foundation for integrating identity providers (like JWT) and sophisticated rate-limiting backends.\n\n## Rate Limiting\n\nRate limiting in Parlant is primarily handled by the `BasicRateLimiter`, which wraps the `limits` Python library.\n\n### BasicRateLimiter\nBy default, this limiter tracks requests per **IP Address**. It supports:\n- **Window Strategies**: `MovingWindowRateLimiter`, `FixedWindowRateLimiter`, and `SlidingWindowCounterRateLimiter`.\n- **Storage Backends**: `MemoryStorage` (default) or `RedisStorage` for distributed environments.\n\n### Configuration\nYou can customize limits per operation by mapping `p.Operation` enums to `RateLimitItem` objects:\n\n```python\nself.default_limiter = p.BasicRateLimiter(\n rate_limit_item_per_operation={\n p.Operation.READ_SESSION: RateLimitItemPerMinute(200),\n p.Operation.LIST_EVENTS: RateLimitItemPerMinute(1000),\n },\n storage=RedisStorage(\"redis://localhost:6379\")\n)\n```\n\n## Implementing Custom Security\n\nFor production environments, you should subclass `ProductionAuthorizationPolicy` to implement your specific authentication logic (e.g., JWT, API Keys, or OAuth2).\n\n### Custom Permission Logic\nOverride `check_permission` to extract credentials from the `fastapi.Request` object.\n\n```python\nclass CustomAuthorizationPolicy(p.ProductionAuthorizationPolicy):\n async def check_permission(\n self,\n request: fastapi.Request,\n operation: p.Operation\n ) -> bool:\n # 1. Extract token from headers\n # 2. Validate token (e.g., JWT decode)\n # 3. Check if the user/service has the required 'operation' scope\n token = await self._extract_token(request)\n \n if token.get(\"role\") == \"admin\":\n return True\n \n return await super().check_permission(request, operation)\n```\n\n### Specific Limiters\nIf certain operations require logic beyond simple IP-based counting (e.g., tier-based limits based on a User ID in the JWT), use the `specific_limiters` dictionary:\n\n```python\nself.specific_limiters[p.Operation.DELETE_AGENT] = self._tier_based_limiter\n\nasync def _tier_based_limiter(self, request, operation):\n # Custom logic to check database for user quotas\n return True \n```\n\n## Integration\n\nThe hardening module is injected into the Parlant `Server` via the `Container`. This allows the infrastructure layer to be swapped or configured without modifying the core business logic.\n\n```python\nasync def configure_container(container: p.Container) -> p.Container:\n # Bind the abstract policy to your concrete implementation\n container[p.AuthorizationPolicy] = CustomAuthorizationPolicy(\n secret_key=\"...\",\n algorithm=\"HS256\"\n )\n return container\n\n# Start the server with the hardened configuration\nasync with p.Server(configure_container=configure_container) as server:\n await server.serve()\n```\n\n## Key Operations (Permissions)\nThe system uses the `p.Operation` (or `AuthorizationPermission`) enum to identify actions. Common operations include:\n- **Agent**: `CREATE_AGENT`, `READ_AGENT`, `UPDATE_AGENT`, `DELETE_AGENT`\n- **Customer**: `CREATE_CUSTOMER`, `READ_CUSTOMER`\n- **Session**: `CREATE_CUSTOMER_SESSION`, `LIST_SESSIONS`, `READ_SESSION`\n- **Events**: `LIST_EVENTS`, `EMIT_EVENT`","infrastructure-observability":"# Infrastructure & Observability\n\n# Infrastructure & Observability\n\nThe **Infrastructure & Observability** module provides the foundational runtime environment, security hardening, and operational visibility for the Parlant server. It integrates the core FastAPI application lifecycle with robust monitoring and protective layers to ensure production-grade stability.\n\n## Module Integration\n\nThis module is composed of two primary functional areas that work in tandem to manage the request lifecycle and system health:\n\n* **[Parlant (Core Infrastructure)](parlant.md)**: Manages the FastAPI application lifecycle, dependency injection via `lagom`, and the observability stack (structured logging, distributed tracing, and performance metrics).\n* **[Production (API Hardening)](production.md)**: Implements the security layer, providing fine-grained authorization and rate limiting to protect core services.\n\n## Key Workflows\n\n### Request Hardening and Execution\nWhen a request enters the system, it is processed through a unified pipeline that combines the application framework with security policies:\n1. **Initialization**: The `create_api_app` factory sets up the FastAPI environment.\n2. **Contextualization**: Middlewares inject `ContextVar` values for distributed tracing and logging.\n3. **Authorization**: The `AuthorizationPolicy` intercepts the request to execute `check_permission` and `check_rate_limit`.\n4. **Execution**: If permitted, the request is routed to the core logic, with background tasks managed by the `BackgroundTasks` utility to ensure non-blocking execution.\n\n### Observability and Health Monitoring\nThe module provides a multi-layered view of system performance:\n* **Telemetry**: OpenTelemetry adapters for `Tracer` and `Meter` capture execution flows and performance data.\n* **Health Reporting**: The `HealthReporter` collects real-time metrics, which are then processed by the `NLPView` to provide human-readable system status.\n* **Runtime Safety**: An `EventLoopMonitor` tracks latency and classifies event loop stalls to detect performance bottlenecks in the async runtime.\n\n## Architecture Overview\n\nThe following diagram illustrates how the infrastructure components wrap the core application logic to provide security and visibility.\n\n```mermaid\ngraph TD\n Req[Incoming Request] --> Middleware[Context & Tracing Middleware]\n Middleware --> Auth{AuthorizationPolicy}\n \n subgraph \"Production Layer\"\n Auth --> |check_permission| Perm[Permission Logic]\n Auth --> |check_rate_limit| Rate[Rate Limiter]\n end\n \n Perm --> App[FastAPI App / Core Logic]\n Rate --> App\n \n subgraph \"Observability Stack\"\n App --> Log[Structured Logging]\n App --> Trace[Distributed Tracing]\n App --> Health[Health Reporter]\n Monitor[Event Loop Monitor] -.-> Health\n end\n \n Health --> NLP[NLP Health View]\n```\n\n## Sub-modules\n\n| Module | Focus | Key Components |\n| :--- | :--- | :--- |\n| **[Production](production.md)** | Security & Stability | `AuthorizationPolicy`, Rate Limiting, API Hardening |\n| **[Parlant](parlant.md)** | Application & Monitoring | `create_api_app`, `HealthReporter`, OpenTelemetry Adapters, Background Tasks |","journeys-state-management":"# Journeys & State Management\n\n# Journeys & State Management\n\nThe Journeys module provides a framework for defining and managing structured conversation flows. Unlike rigid state machines, Parlant journeys serve as a guiding framework that allows the agent to maintain context and progress toward a goal while remaining adaptive to natural human interaction.\n\n## Core Components\n\n### Journey\nA `Journey` is the top-level container for a conversational flow. It is defined by:\n- **Triggers**: A set of `GuidelineId`s (conditions) that activate the journey when matched against the conversation context.\n- **Root Node**: The entry point of the state diagram.\n- **Metadata**: Title, description, tags, and priority.\n\n### JourneyNode\nNodes represent specific states within a journey.\n- **Chat States**: Defined by an `action` string containing conversational instructions.\n- **Tool States**: Defined by a list of `tools` (via `ToolId`) to be executed.\n- **Composition Mode**: Determines how instructions in this state are combined with other active guidelines.\n\n### JourneyEdge\nEdges represent the transitions between nodes.\n- **Direct Transitions**: Transitions without a condition that the agent should follow sequentially.\n- **Conditional Transitions**: Transitions containing a `condition` string that must be met for the agent to move to the target node.\n\n## Architecture and Data Flow\n\nThe module is split into a persistence layer (`JourneyStore`), an application logic layer (`JourneyModule`), and a projection layer that translates graphs into actionable engine instructions.\n\n```mermaid\ngraph TD\n API[Journeys API] --> JM[JourneyModule]\n JM --> JS[JourneyStore / JourneyVectorStore]\n JS --> DB[(Document & Vector DB)]\n GP[JourneyGuidelineProjection] --> JS\n GP --> Engine[Alpha Engine]\n```\n\n### Persistence: JourneyVectorStore\nThe `JourneyVectorStore` implements the `JourneyStore` interface using a hybrid storage approach:\n1. **Document Database**: Stores the structural graph data (nodes, edges) and metadata.\n2. **Vector Database**: Stores semantic representations of the journey's content to enable relevance-based retrieval via `find_relevant_journeys`.\n\n### Projection: JourneyGuidelineProjection\nThe engine does not execute the journey graph directly. Instead, the `JourneyGuidelineProjection` class transforms the graph into a sequence of `Guideline` objects.\n\n- **Node to Guideline**: Each `JourneyNode` is projected into a `Guideline`.\n- **Edge to Condition**: The `condition` on a `JourneyEdge` becomes the `condition` of the resulting guideline.\n- **Metadata Injection**: The projector injects a `journey_node` object into the guideline's metadata, containing the `journey_id`, `node_index`, and `follow_ups` (IDs of guidelines representing reachable next states).\n\n## Implementation Patterns\n\n### Creating a Journey\nThe `JourneyModule.create` method handles the atomic creation of a journey and its associated trigger guidelines.\n\n```python\n# Internal flow of JourneyModule.create\njourney, guidelines = await journey_module.create(\n title=\"Refund Process\",\n description=\"Guides the user through returning an item\",\n triggers=[\"The user wants a refund\"],\n tags=[support_tag_id]\n)\n```\n\n### State Transitions\nTransitions are managed by creating `JourneyEdge` records. The `JourneyStore` provides `create_edge` to link nodes. In the SDK, this is typically abstracted through `transition_to` calls which manage the underlying node and edge creation.\n\n### Visualization\nThe module includes a Mermaid generator (`_build_mermaid_chart` in `parlant/api/journeys.py`) that traverses the graph to produce a `stateDiagram-v2` string. This is exposed via the `/journeys/{journey_id}/mermaid` endpoint.\n\n## Context Management & Latency\nTo minimize LLM context bloat and latency, the system performs dynamic management:\n1. **Guideline Matching**: The `GuidelineMatcher` identifies which journey triggers are active.\n2. **State Retrieval**: The engine retrieves only the nodes and edges associated with active journeys.\n3. **Parallel Prediction**: The engine attempts to predict the next state in parallel with guideline matching to reduce response time.\n\n## Journey-Scoped Guidelines\nGuidelines can be associated with specific journeys using tags. When a journey is deleted via `JourneyModule.delete`, the module automatically cleans up associated trigger guidelines if they are not referenced by other journeys, ensuring the `GuidelineStore` remains synchronized with the `JourneyStore`.","messaging-sessions-concepts":"# Messaging & Sessions — concepts\n\n# Messaging & Sessions\n\nA session is the primary container for interactions between a Parlant **agent** and a **customer**. Unlike traditional turn-based chat systems, Parlant sessions are designed as continuous, event-driven timelines that support asynchronous communication, multi-message bursts, and background processing.\n\n## The Event-Driven Timeline\n\nEvery interaction within a session is recorded as an **Event**. These events are stored in a linear sequence, ordered by a strictly increasing integer called an **offset**, starting at `0`.\n\n### Event Structure\nEach event contains:\n* **Offset**: The position in the timeline.\n* **Kind**: The category of event (`message`, `status`, `tool`, `custom`).\n* **Source**: The originator of the event (e.g., `customer`, `ai_agent`, `system`).\n* **Trace ID**: A unique identifier used to correlate related events, such as linking an agent's message to the specific tool calls that informed it.\n* **Data**: A payload specific to the event kind.\n\n```mermaid\ngraph LR\n E0[Offset 0: Message] --> E1[Offset 1: Status]\n E1 --> E2[Offset 2: Tool Call]\n E2 --> E3[Offset 3: Status]\n E3 --> E4[Offset 4: Message]\n \n subgraph \"Trace ID: abc-123\"\n E1\n E2\n E3\n E4\n end\n```\n\n## Interaction Model\n\nParlant moves away from the rigid \"Customer Message -> Agent Response\" loop. The engine supports:\n1. **Message Aggregation**: The agent can process multiple customer messages sent in quick succession before responding.\n2. **Proactive Messaging**: The agent can initiate messages or follow-ups without a direct customer trigger.\n3. **Ambient Updates**: Status events (like `typing` or `processing`) provide real-time feedback to the frontend while the agent is working.\n\n## Session Persistence\n\nBy default, sessions are stored in-memory and cleared on server restart. For production or persistent development, the `parlant.sdk.Server` can be configured with different storage backends.\n\n### Local File Storage\nUses a JSON file located at `$PARLANT_HOME/sessions.json`.\n```python\nasync with p.Server(session_store=\"local\") as server:\n ...\n```\n\n### MongoDB\nFor distributed or production environments.\n```python\nasync with p.Server(session_store=\"mongodb://db.example.com:27017\") as server:\n ...\n```\n\n## Working with Sessions via SDK\n\nDevelopers typically interact with sessions using the `AsyncParlantClient`.\n\n### Creating a Session\nA session links an agent to a customer. If no `customer_id` is provided, a guest ID is assigned.\n```python\nsession = await client.sessions.create(\n agent_id=\"agent_id_123\",\n customer_id=\"customer_id_456\",\n title=\"Order Support\"\n)\n```\n\n### Sending Events\nTo send a message, you create a new event of kind `message` with the source `customer`.\n```python\nawait client.sessions.create_event(\n session_id=session.id,\n kind=\"message\",\n source=\"customer\",\n message=\"Where is my package?\"\n)\n```\n\n### Consuming Events (Polling)\nBecause the agent operates asynchronously, the client must poll for new events. Use the `min_offset` parameter to fetch only events that have occurred since the last check.\n\n```python\n# Long-polling for new events\nnew_events = await client.sessions.list_events(\n session_id=SESSION_ID,\n min_offset=last_known_offset + 1,\n wait_for_data=60 # Seconds to hold the connection open\n)\n```\n\n## Event Reference\n\n### Message Events\nContains the actual text communication and participant metadata.\n* **Source**: `customer`, `ai_agent`, `human_agent`.\n* **Data Fields**: `message`, `participant` (id, display_name).\n\n### Status Events\nUsed to drive UI indicators.\n* **Kinds**:\n * `acknowledged`: Request received.\n * `processing`: Engine is evaluating instructions and context.\n * `typing`: Agent is generating the response string.\n * `ready`: Agent is idle.\n * `cancelled`: Generation interrupted (e.g., by a new customer message).\n * `error`: Processing failure.\n\n### Tool Events\nRecords the execution and results of tools called by the agent.\n* **Source**: `system`.\n* **Data Fields**: `tool_calls` (list of tool IDs, arguments, and `ToolResult` data).\n* **Usage**: Frontend clients can use the `trace_id` to find tool events associated with a specific message to display \"sources\" or \"citations.\"\n\n### Custom Events\nAllows the application to inject arbitrary state into the session timeline.\n* **Source**: `customer_ui`.\n* **Usage**: Informing the agent of UI state changes, such as \"Customer navigated to the Pricing page.\"","messaging-sessions-docs":"# Messaging & Sessions — docs\n\n# Messaging & Sessions\n\nThe Messaging & Sessions module governs the asynchronous exchange of information between human users and AI agents. Unlike traditional request-reply chatbot architectures, Parlant treats a session as a continuous stream of events where both parties can contribute multiple messages independently.\n\n## Core Philosophy: Asynchronous Interaction\n\nParlant moves away from the \"Single Message In -> Single Message Out\" model. It is designed to support:\n1. **Multi-message turns:** A human may send three messages to express one intent.\n2. **Agent Proactivity:** The agent can initiate messages without a direct human trigger (e.g., follow-ups or status updates).\n3. **Contextual Processing:** The engine evaluates the entire session history rather than just the most recent event.\n\n## Event Creation Flows\n\nInteraction with a session occurs through the creation of events. The behavior of the system depends on the source and type of the event being created.\n\n### 1. Customer Messages\nWhen a client sends a message on behalf of a customer, the API:\n* Persists the message to the session store.\n* Returns the created event details (ID, offset) immediately.\n* **Asynchronously** triggers the AI agent's reaction engine.\n* *Note:* The response to this API call does **not** contain the AI's reply.\n\n### 2. AI Agent Messages (Triggering)\nThis flow is used to manually prompt the agent to evaluate the current state of the session and generate a response.\n* It activates the full reaction engine (guideline matching, tool calls, etc.).\n* The API returns a **status event** containing a `Trace ID`.\n* The actual message generated by the agent will eventually appear in the event stream with a matching `Trace ID`.\n\n### 3. Human Agent Messages\nAllows a developer or human operator to inject a message into the session on behalf of the AI.\n* The message is persisted immediately.\n* The API returns the created message event.\n* This does not trigger the AI reaction engine.\n\n## Receiving Events: The Long-Polling Pattern\n\nBecause messages are generated asynchronously, clients must implement a continuous synchronization loop. Parlant facilitates this through a long-polling mechanism using `list_events` and `wait_for_events`.\n\n### The Synchronization Loop\nTo maintain a real-time UI, the client should follow this logic:\n1. Track the `offset` of the last received event.\n2. Call the events endpoint with `min_offset = last_known_offset + 1`.\n3. The server holds the request open (via `wait_for_events`) until a new event occurs or a timeout is reached.\n4. Upon receiving events, update the UI and repeat the request with the new highest offset.\n\n```mermaid\nsequenceDiagram\n participant Client\n participant API\n participant Store\n \n Note over Client: last_offset = 5\n Client->>API: list_events(min_offset=6, timeout=60s)\n API->>Store: wait_for_events(6)\n Note over Store: Idle until new event...\n Store-->>API: New Event (Offset 6)\n API-->>Client: [Event 6]\n Note over Client: last_offset = 6\n Client->>API: list_events(min_offset=7, timeout=60s)\n```\n\n## Key API Components\n\n### `list_events(min_offset, ...)`\nThe primary method for retrieving session history. It allows filtering by event type and ensures that clients only download data they haven't seen yet.\n\n### `wait_for_events(min_offset, timeout)`\nAn internal mechanism used by the REST API to block the request execution. If no events with an offset $\\ge$ `min_offset` exist, the connection remains open for the duration of the `timeout`. This reduces overhead compared to frequent short-polling.\n\n### Trace IDs\nWhen the AI agent processes a session, it may generate multiple internal logs or status updates before producing a final message. All events resulting from a single \"reaction\" cycle share the same `Trace ID`, allowing developers to group related background processes with the resulting UI message.","messaging-sessions-parlant":"# Messaging & Sessions — parlant\n\n# Messaging & Sessions — parlant\n\nThe **Messaging & Sessions** module manages the lifecycle of conversations between agents and customers. It provides a persistent, offset-based event log that supports real-time communication through long-polling and Server-Sent Events (SSE).\n\n## Core Concepts\n\n### Sessions\nA `Session` represents a unique conversational context between an `Agent` and a `Customer`. \n- **Identity**: Every session has a `SessionId` and is linked to an `AgentId` and a `CustomerId`.\n- **Mode**: Sessions operate in either `auto` (AI agent responds automatically) or `manual` (human intervention required) mode.\n- **Consumption Offsets**: A mechanism for clients to track their progress in the event log, ensuring they can resume or synchronize state reliably.\n\n### Events\nThe conversation history is stored as a sequence of `Event` objects. Each event is immutable once created (except for metadata updates) and is assigned a sequential `offset`.\n\n| Event Kind | Description |\n| :--- | :--- |\n| `MESSAGE` | Textual communication between participants. |\n| `TOOL` | Records of tool calls and their results. |\n| `STATUS` | Transient states like `typing`, `processing`, or `error`. |\n| `CUSTOM` | Arbitrary data for frontend-specific logic. |\n\n### Event Sources\nEvents are tagged with a `source` to identify the originator:\n- `CUSTOMER` / `CUSTOMER_UI`: The end-user.\n- `AI_AGENT`: The Parlant engine.\n- `HUMAN_AGENT`: A person intervening in the session.\n- `HUMAN_AGENT_ON_BEHALF_OF_AI_AGENT`: A human correcting or approving an AI response.\n- `SYSTEM`: Internal triggers or tool execution results.\n\n---\n\n## Architecture and Data Flow\n\nThe module is split into an API layer (`parlant.api.sessions`) and a core persistence/logic layer (`parlant.core.sessions`).\n\n```mermaid\ngraph TD\n API[API Router] --> App[Application Sessions Module]\n App --> Store[SessionStore / DocumentStore]\n App --> Listener[SessionListener]\n Store --> DB[(Document Database)]\n App --> Engine[Processing Engine]\n \n subgraph \"Event Loop\"\n API -- \"create_event\" --> App\n App -- \"dispatch_processing_task\" --> Engine\n Engine -- \"create_event (AI_AGENT)\" --> App\n end\n```\n\n### Event Processing\nWhen a customer message is created via `create_customer_message`, the system typically triggers a background processing task.\n1. **Creation**: The message is saved as an event with `source=CUSTOMER`.\n2. **Moderation**: If configured, the content is checked via `Moderation` settings (`AUTO`, `PARANOID`, or `NONE`).\n3. **Dispatch**: `dispatch_processing_task` initiates `_process_session`.\n4. **Generation**: The engine generates a response, which is appended to the session as a new event with `source=AI_AGENT`.\n\n---\n\n## Real-time Event Retrieval\n\nThe module supports two primary patterns for retrieving events in real-time via the `list_events` and `read_event` endpoints.\n\n### Long Polling\nBy setting `wait_for_data > 0`, the server holds the request open until new events matching the criteria (e.g., `min_offset`) appear.\n- **Timeout**: If no events appear within the `wait_for_data` period, the server returns a `504 Gateway Timeout`.\n- **Implementation**: Handled by `PollingSessionListener.wait_for_more_events`.\n\n### Server-Sent Events (SSE)\nBy setting `sse=true`, the server returns a `text/event-stream`.\n- **Streaming Messages**: For `MESSAGE` events that are generated in chunks, the `read_event` endpoint can stream individual chunks as they arrive.\n- **Completion**: A streaming event is considered complete when its `chunks` list contains a `None` terminator.\n\n---\n\n## Persistence and Storage\n\n### SessionStore\nThe `SessionStore` abstract base class defines the interface for session and event management. The primary implementation is `SessionDocumentStore`, which uses a `DocumentDatabase`.\n\nKey methods include:\n- `create_session(...)`: Initializes a session with default `consumption_offsets`.\n- `list_sessions(...)`: Supports filtering by `agent_id`, `customer_id`, and `labels` with cursor-based pagination.\n- `create_event(...)`: Appends an event and automatically increments the session `offset`.\n- `update_event(...)`: Allows updating `metadata` or `data` (used for appending chunks to a message).\n\n### Schema Migrations\nThe `SessionDocumentStore` includes a `DocumentMigrationHelper` to handle evolution of the session and event schemas. It manages transitions across versions (e.g., from `0.1.0` to `0.9.0`), ensuring that legacy data is transformed into the current `_SessionDocument` and `_EventDocument` formats upon loading.\n\n---\n\n## Developer Usage Patterns\n\n### Creating an Event Manually\nTo inject a message from a human agent:\n```python\nawait app.sessions.create_human_agent_message_event(\n session_id=session_id,\n message=\"Hello, I am taking over this chat.\",\n participant={\"display_name\": \"Support Agent Alpha\"},\n)\n```\n\n### Updating Metadata\nMetadata can be updated on both sessions and events without affecting the core conversation log:\n```python\nawait app.sessions.update_event(\n session_id=session_id,\n event_id=event_id,\n params={\"metadata\": {\"set\": {\"reviewed_by\": \"admin\"}}}\n)\n```\n\n### Waiting for Completion\nWhen consuming a streaming AI response, use `wait_for_event_completion` to block until the full message is available:\n```python\nawait session_listener.wait_for_event_completion(\n session_id=session_id,\n event_id=event_id,\n timeout=Timeout(30)\n)\n```","messaging-sessions":"# Messaging & Sessions\n\n# Messaging & Sessions\n\nThe **Messaging & Sessions** module manages the lifecycle and execution of conversations between Parlant agents and customers. Moving away from traditional request-reply architectures, this module implements an asynchronous, event-driven timeline that allows for multi-message bursts, agent proactivity, and continuous background processing.\n\n## Core Architecture\n\nThe module is built on three pillars that enable fluid, non-linear communication:\n\n* **[Sessions](parlant.md):** The primary container for interaction, linking a specific `Agent` and `Customer`. Sessions maintain state, including the operational `Mode` (auto vs. manual) and `Consumption Offsets` used by clients to synchronize their local state with the server.\n* **[Event-Driven Timeline](concepts.md):** Every interaction—whether a message, a tool call, or a status update—is recorded as an `Event`. These events are stored in a linear sequence identified by a strictly increasing integer called an `offset`.\n* **[Asynchronous Processing](docs.md):** The module decouples message reception from response generation. This allows the engine to evaluate the entire session history and context before the agent decides to emit one or more events in return.\n\n## Key Workflows\n\n### Message Processing Flow\nWhen a customer sends a message, the module initiates a background execution chain to determine the agent's next action:\n\n1. **Ingestion:** `create_customer_message` generates a new event and appends it to the timeline.\n2. **Dispatch:** `dispatch_processing_task` triggers the session's processing logic without blocking the caller.\n3. **Evaluation:** `_process_session` analyzes the timeline. If the session is in `auto` mode, the agent determines if a response or tool execution is required.\n4. **Emission:** The agent uses the `event_publisher` to emit `message`, `tool`, or `status` events back to the timeline.\n\n### Real-time Synchronization\nClients stay in sync with the session timeline using two primary mechanisms:\n* **Long-polling/SSE:** Utilizing `wait_for_more_events` to receive real-time updates as they are appended to the log.\n* **Offset Tracking:** Clients provide their last known offset to resume conversations or fetch missed events, ensuring no data loss in unstable network conditions.\n\n## Module Relationship\n\n```mermaid\ngraph TD\n subgraph Messaging & Sessions\n C[Concepts] -->|Defines| T[Event Timeline]\n D[Docs] -->|Defines| A[Asynchronous Patterns]\n P[Parlant] -->|Implements| S[Session & Event Logic]\n end\n\n Customer((Customer)) -->|create_customer_message| S\n S -->|offset-based log| T\n T -->|trigger| A\n A -->|dispatch_processing_task| P\n P -->|emit_event| T\n T -->|wait_for_more_events| Customer\n```\n\n## Sub-modules\n\n* **[Messaging & Sessions — Concepts](concepts.md):** Detailed explanation of the event-driven timeline, event structures, and the offset system.\n* **[Messaging & Sessions — Docs](docs.md):** High-level philosophy regarding asynchronous interaction, multi-message turns, and agent proactivity.\n* **[Messaging & Sessions — Parlant](parlant.md):** Technical implementation details, including session identity, consumption offsets, and internal processing tasks.","nlp-llm-adapters-adapters":"# NLP & LLM Adapters — adapters\n\n# NLP & LLM Adapters\n\nThe `adapters` module provides a standardized interface between the Parlant core and various Large Language Model (LLM) and Natural Language Processing (NLP) providers. By abstracting provider-specific API logic, authentication schemes, and model-specific quirks, this module allows Parlant to remain provider-agnostic while supporting a wide range of cloud-based and local inference engines.\n\n## Architecture Overview\n\nEach adapter implements the `NLPService` interface, which acts as a factory for three primary components:\n1. **Schematic Generators**: Handle structured text generation (JSON) and prompt execution.\n2. **Embedders**: Convert text into vector representations for semantic search and retrieval.\n3. **Tokenizers**: Estimate or calculate token counts for context window management.\n\n```mermaid\ngraph TD\n Core[Parlant Core] --> NLPService[NLPService Interface]\n NLPService --> Azure[AzureService]\n NLPService --> Ollama[OllamaService]\n NLPService --> OpenRouter[OpenRouterService]\n NLPService --> Vertex[VertexAIService]\n NLPService --> Snowflake[Snowflake Cortex]\n \n Azure --> Gen[SchematicGenerator]\n Azure --> Emb[Embedder]\n```\n\n## Supported Adapters\n\n### Azure OpenAI (`AzureService`)\nIntegrates with Azure OpenAI Service, supporting both legacy API keys and modern Azure Active Directory (Azure AD) authentication.\n\n* **Key Classes**: `CustomAzureSchematicGenerator`, `CustomAzureEmbedder`.\n* **Authentication**: Supports Service Principals, Managed Identities, and Workload Identities via the Azure Identity SDK.\n* **Model Selection**: Defaults to `gpt-4o` and `text-embedding-3-large` but allows overrides via `AZURE_GENERATIVE_MODEL_NAME` and `AZURE_EMBEDDING_MODEL_NAME`.\n\n### Ollama (`OllamaService`)\nEnables local inference for privacy-conscious or offline development environments.\n\n* **Key Classes**: `OllamaGemma3_4B`, `OllamaLlama31_8B`.\n* **Capabilities**: Supports local text generation and embeddings (e.g., `nomic-embed-text`).\n* **Configuration**: Managed via `OLLAMA_BASE_URL` and `OLLAMA_MODEL`. It includes logic to handle local timeouts and GPU memory constraints.\n\n### OpenRouter (`OpenRouterService`)\nA unified aggregator providing access to over 400 models (GPT, Claude, Llama, Qwen) through a single API.\n\n* **Key Classes**: `OpenRouterGPT4O`, `OpenRouterClaude35Sonnet`, `OpenRouterEmbedder`.\n* **Dynamic Resolution**: Automatically detects embedding dimensions from API responses if the model is not pre-configured.\n* **Optimization**: Uses specialized generators for known models to ensure optimal prompt formatting and JSON mode support.\n\n### Vertex AI (`VertexAIService`)\nGoogle Cloud's enterprise AI platform, supporting both Google Gemini and Anthropic Claude models.\n\n* **Key Classes**: `VertexAIClaudeSchematicGenerator`, `VertexAIGeminiSchematicGenerator`, `VertexAIEmbedder`.\n* **Authentication**: Uses Google Application Default Credentials (ADC).\n* **Tokenization**: Implements `VertexAIEstimatingTokenizer`, which switches between `tiktoken` (for Claude) and the Google Gen AI API (for Gemini) to ensure accurate context management.\n\n### Snowflake Cortex\nDirect integration with Snowflake-hosted LLMs, allowing inference to happen within the Snowflake data perimeter.\n\n* **Endpoints**: Communicates with `/api/v2/cortex/inference:complete` and `/api/v2/cortex/inference:embed`.\n* **Authentication**: Requires a Snowflake JWT or Personal Access Token (PAT).\n\n## Common Implementation Patterns\n\n### Schematic Generation\nAll adapters implement a `generate` method that accepts a `PromptBuilder` and a schema type. The adapters handle:\n* **Retry Logic**: Exponential backoff for rate limits (429) and server errors (5xx).\n* **JSON Repair**: Ensuring the LLM output conforms to the requested Pydantic schema.\n* **Usage Tracking**: Extracting token usage metadata from provider-specific response headers or bodies.\n\n### Embedding Dimension Management\nDifferent models produce different vector sizes (e.g., 768 for Gemini, 3072 for OpenAI). The `Embedder` implementations provide a `dimensions` property used by Parlant's vector database to initialize collections correctly.\n\n### Environment Configuration\nAdapters are typically configured via environment variables. Common patterns include:\n* `*_API_KEY` or `*_AUTH_TOKEN`: For authentication.\n* `*_MODEL`: To specify the primary LLM.\n* `*_MAX_TOKENS`: To set safety limits on generation.\n\n## Usage in Parlant\n\nThe choice of adapter is determined at server startup via the `NLPServices` enum:\n\n```python\nimport parlant.sdk as p\nfrom parlant.sdk import NLPServices\n\n# Example: Starting a server with the Vertex AI adapter\nasync with p.Server(nlp_service=NLPServices.vertex) as server:\n agent = await server.create_agent(name=\"Assistant\")\n```\n\n## Error Handling\nAdapters map provider-specific exceptions to internal Parlant exceptions. For example:\n* Authentication failures (e.g., expired Azure AD tokens) raise `VertexAIAuthError` or similar provider-specific errors with actionable troubleshooting steps.\n* Rate limits trigger internal retry loops before surfacing a failure to the core engine.","nlp-llm-adapters-advanced":"# NLP & LLM Adapters — advanced\n\n# NLP & LLM Adapters — Advanced\n\nThe NLP & LLM Adapters module provides the abstraction layer necessary to integrate custom Large Language Models (LLMs), embedding models, and moderation services into the Parlant engine. While Parlant includes built-in support for providers like OpenAI, the `NLPService` interface allows developers to swap these components for local models (SLMs), specialized providers, or fine-tuned internal services.\n\n## Architecture Overview\n\nThe `NLPService` acts as a central factory for three primary functional components. Every interaction between the Parlant engine and an NLP provider passes through one of these interfaces.\n\n```mermaid\ngraph TD\n Server[Parlant Server] --> NLP[NLPService]\n NLP --> SG[SchematicGenerator]\n NLP --> EM[Embedder]\n NLP --> MS[ModerationService]\n SG --> ET[EstimatingTokenizer]\n EM --> ET\n```\n\n## The NLPService Interface\n\nTo implement a custom provider, you must subclass `NLPService`. This class is responsible for instantiating the specific generators, embedders, and moderation tools required by the engine.\n\n```python\nclass NLPService(ABC):\n @abstractmethod\n async def get_schematic_generator(self, t: type[T]) -> SchematicGenerator[T]:\n \"\"\"Returns a generator for a specific Pydantic model type.\"\"\"\n ...\n\n @abstractmethod\n async def get_embedder(self) -> Embedder:\n \"\"\"Returns the default embedder for semantic search.\"\"\"\n ...\n\n @abstractmethod\n async def get_moderation_service(self) -> ModerationService:\n \"\"\"Returns the service used for content filtering.\"\"\"\n ...\n```\n\n## Schematic Generation\n\nParlant relies heavily on structured output. Instead of raw text, the engine requests specific Pydantic models. Any custom LLM integrated via `SchematicGenerator[T]` must be capable of producing valid JSON that conforms to the requested schema.\n\n### Implementing SchematicGenerator\nThe generator must handle the transformation of a `PromptBuilder` or string into a `SchematicGenerationResult[T]`.\n\n* **`generate()`**: The core method where the LLM call occurs. It receives `hints` (e.g., temperature, top_p) which should be mapped to the specific provider's API.\n* **`tokenizer`**: Returns an `EstimatingTokenizer`. This is critical for the engine to calculate context window usage before sending a request.\n* **`schema`**: A convenience property that identifies the Pydantic model the generator is currently responsible for.\n\n### Tokenization\nBecause different models use different encoding schemes (e.g., Tiktoken, SentencePiece), the `EstimatingTokenizer` interface ensures the engine can approximate token counts to prevent context overflow.\n\n```python\nclass EstimatingTokenizer(ABC):\n @abstractmethod\n async def estimate_token_count(self, prompt: str) -> int:\n ...\n```\n\n## Semantic Retrieval (Embedder)\n\nThe `Embedder` interface is used for vectorizing tools, documents, and conversation history. \n\nKey requirements for a custom `Embedder`:\n1. **`dimensions`**: Must return the fixed integer size of the vector space (e.g., 1536 for `text-embedding-3-small`).\n2. **`embed()`**: Accepts a list of strings and returns an `EmbeddingResult` containing a sequence of float sequences.\n3. **`max_tokens`**: Defines the maximum input length the embedding model can process in a single pass.\n\n## Content Safety (ModerationService)\n\nThe `ModerationService` filters customer input before it reaches the processing pipeline. It uses a standardized set of `ModerationTag` values to ensure consistent behavior across different providers.\n\nStandard tags include:\n* `jailbreak`: Detection of prompt injection.\n* `harassment`, `hate`, `violence`: Safety violations.\n* `sexual`, `self-harm`, `illicit`: Policy violations.\n\nWhen implementing `moderate_customer`, the service receives a `CustomerModerationContext` containing the session and the raw message. It must return a `ModerationCheck` indicating if the content was `flagged` and which `tags` were triggered.\n\n## Advanced Prompt Customization\n\nWhen using custom models, standard Parlant prompts may need adjustment to fit the model's specific prompting style (e.g., Alpaca vs. ChatML). The `SchematicGenerator` can intercept and modify prompts using the `PromptBuilder`.\n\n### Section Editing\nParlant prompts are modular. You can target specific sections of a prompt by name and modify their templates or properties dynamically:\n\n```python\nasync def generate(self, prompt: str | PromptBuilder, hints: Mapping[str, Any] = {}):\n if isinstance(prompt, PromptBuilder):\n prompt.edit_section(\n name=\"canned-response-generator-draft-general-instructions\",\n editor_func=lambda section: self._apply_custom_logic(section)\n )\n return await super().generate(prompt, hints)\n```\n\n## Integration and Injection\n\nCustom NLP services are injected into the Parlant `Server` during initialization. This is typically done via a loader function that has access to the system's dependency injection `Container`.\n\n```python\ndef load_custom_nlp_service(container: p.Container) -> p.NLPService:\n # Access system services like the logger\n logger = container[p.Logger]\n return MyNLPService(logger=logger)\n\n# Server initialization\nasync with p.Server(nlp_service=load_custom_nlp_service) as server:\n await server.serve()\n```\n\nThis pattern ensures that your custom adapter has access to the same logging and configuration infrastructure as the rest of the engine.","nlp-llm-adapters-parlant":"# NLP & LLM Adapters — parlant\n\n# NLP & LLM Adapters — parlant\n\nThe `parlant.adapters.nlp` module provides concrete implementations of the core NLP interfaces defined in `parlant.core.nlp`. These adapters bridge Parlant’s internal logic—which relies on structured schematic generation and embeddings—with external LLM providers such as Anthropic, Azure OpenAI, AWS Bedrock, Google Gemini, and Emcie’s optimized inference service.\n\n## Architecture Overview\n\nEach adapter implements the `NLPService` abstract base class, acting as a factory for three primary components:\n1. **Schematic Generators**: For structured JSON output validated against Pydantic models.\n2. **Embedders**: For converting text into vector representations.\n3. **Moderation Services**: For content filtering (often defaulting to `NoModeration` if handled by the provider).\n\n```mermaid\ngraph TD\n Core[Core Engine] --> Service[NLPService Implementation]\n Service --> Gen[SchematicGenerator]\n Service --> Emb[Embedder]\n Gen --> API[External Provider API]\n Emb --> API\n Gen -.-> Common[Common Utilities: JSON Normalization]\n```\n\n## Common Utilities (`common.py`)\n\nTo ensure consistency across different LLM providers, the module utilizes shared utilities for post-processing and observability:\n\n* **`normalize_json_output(raw_output: str)`**: Extracts JSON content from LLM responses, specifically handling cases where models wrap JSON in Markdown code blocks (e.g., ` ```json ... ``` `).\n* **`record_llm_metrics(...)`**: Uses the `Meter` system to track `input_tokens`, `output_tokens`, and `cached_input_tokens`. Metrics are tagged with `model_name` and `schema_name` for granular cost and usage analysis.\n\n## Schematic Generation\n\nThe core of Parlant’s intelligence relies on `BaseSchematicGenerator[T]`. Unlike standard text generation, these adapters ensure that the LLM output strictly conforms to a Pydantic schema `T`.\n\n### The Generation Flow\n1. **Prompt Preparation**: Accepts a `PromptBuilder` or string.\n2. **API Call**: Executes the request using provider-specific SDKs (e.g., `AsyncAnthropic`, `AsyncAzureOpenAI`).\n3. **Extraction**: Uses `jsonfinder.only_json()` to locate the JSON object within the raw string.\n4. **Validation**: Validates the object against `self.schema.model_validate()`.\n5. **Metrics**: Records token usage via `record_llm_metrics`.\n\n### Resilience and Policies\nMost generators use the `@policy` decorator to handle transient API failures:\n* **Retries**: Configured for `RateLimitError`, `APITimeoutError`, and `InternalServerError`.\n* **Backoff**: Implements wait times (e.g., 1.0s, 5.0s) to handle service pressure.\n\n---\n\n## Provider Implementations\n\n### Anthropic Service (`anthropic_service.py`)\nSupports Claude 3.5 Sonnet and Claude 4 models.\n* **Tokenization**: Uses `AnthropicEstimatingTokenizer` which calls the Anthropic API's `count_tokens` endpoint for high accuracy.\n* **Model Mapping**: Automatically routes specific internal schemas (like `JourneyBacktrackNodeSelectionSchema`) to higher-capability models like `Claude_Opus_4_1`.\n\n### Azure Service (`azure_service.py`)\nA robust implementation for enterprise environments.\n* **Authentication**: Supports both `AZURE_API_KEY` and **Azure AD (Managed Identity)** via `DefaultAzureCredential`.\n* **Strict Mode**: If `hints.get(\"strict\")` is true, it utilizes Azure's `.beta.chat.completions.parse()` for native schema enforcement.\n* **Customization**: Allows overriding models and context windows via environment variables like `AZURE_GENERATIVE_MODEL_NAME`.\n\n### Emcie Service (`emcie_service.py`)\nParlant's optimized inference adapter.\n* **Tiers**: Offers `jackal` (fast/efficient) and `bison` (high-reasoning) tiers.\n* **Streaming**: Implements `EmcieStreamingTextGenerator` with a unique word-boundary buffer. It accumulates tokens and yields them in `_WORDS_PER_CHUNK` increments to ensure smooth UI rendering.\n* **Model Roles**: Supports `teacher`, `student`, and `auto` roles to optimize cost","nlp-llm-adapters":"# NLP & LLM Adapters\n\n# NLP & LLM Adapters\n\nThe **NLP & LLM Adapters** module serves as the abstraction layer between Parlant’s core logic and the various Large Language Model (LLM) and Natural Language Processing (NLP) providers. By standardizing how the system interacts with different inference engines, this module allows Parlant to remain provider-agnostic while supporting cloud-based APIs, local models (SLMs), and specialized internal services.\n\n## Architecture Overview\n\nThe module is built around the `NLPService` interface, which acts as a central factory. Every interaction between the Parlant engine and an NLP provider is routed through one of three primary functional components produced by this service.\n\n```mermaid\ngraph TD\n Core[Parlant Core] --> Service[NLPService]\n Service --> SG[Schematic Generator]\n Service --> EM[Embedder]\n Service --> MS[Moderation Service]\n \n SG --> Providers[External Providers: OpenAI, Azure, Bedrock, Gemini, etc.]\n EM --> Providers\n MS --> Providers\n```\n\n## Sub-Modules\n\n* [**Adapters**](adapters.md): Defines the standardized interfaces and base logic for the module. It abstracts provider-specific API quirks and authentication schemes, ensuring that the core engine receives consistent data structures regardless of the backend.\n* [**Advanced**](advanced.md): Provides the extension points necessary for integrating custom models, specialized moderation services, or fine-tuned internal LLMs. This is the primary entry point for developers looking to swap default providers for local or proprietary alternatives.\n* [**Parlant**](parlant.md): Contains the concrete implementations of the `NLPService`. This sub-module bridges Parlant’s internal requirements—such as structured JSON generation validated against Pydantic models—with specific external providers like Anthropic, AWS Bedrock, and Google Gemini.\n\n## Key Workflows\n\n### Structured Generation\nThe `SchematicGenerator` handles the execution of prompts and the generation of structured text. It ensures that LLM outputs conform to specific JSON schemas required by Parlant’s internal logic, often wrapping calls with policy-based decorators to manage function-calling states and error handling.\n\n### Semantic Retrieval\nThe `Embedder` component converts text into vector representations. This workflow is tightly integrated with vector database adapters (such as Chroma or MongoDB). When a collection is indexed, the `Embedder` generates the necessary vectors to facilitate semantic search and context retrieval.\n\n### Content Safety\nThe `ModerationService` provides a hook for content filtering. It intercepts inputs and outputs to ensure compliance with safety guidelines, either using provider-native moderation APIs (like OpenAI's moderation endpoint) or custom internal logic.","other-adapters":"# Other — adapters\n\n# Database Adapters\n\nThe `adapters` module provides concrete implementations of Parlant’s persistence interfaces. These adapters bridge the core domain logic (like sessions, agents, and glossary terms) to specific storage technologies, including vector databases and document-oriented stores.\n\n## Overview\n\nParlant uses a collection-based abstraction for data persistence. Every adapter follows a consistent pattern for document lifecycle management, including:\n- **Schema Evolution:** Using `document_loader` functions to migrate data on-the-fly.\n- **Pagination:** Cursor-based navigation using `creation_utc` and `id` as tie-breakers.\n- **Filtering:** A MongoDB-like query syntax (`$eq`, `$in`, `$gt`, etc.) mapped to the underlying storage engine.\n\n---\n\n## Document Database Adapters\n\nDocument adapters implement the `DocumentDatabase` and `DocumentCollection` interfaces. They are responsible for storing structured JSON-like data.\n\n### MongoDB (`MongoDocumentDatabase`)\nThe production-standard adapter. It maps Parlant collections to MongoDB collections and automatically manages indexes for performance.\n\n- **Indexing:** Automatically creates indexes on `creation_utc` and `id` for all collections. It also applies specialized indexes for hot paths, such as `session_id` and `offset` in the session store.\n- **Query Mapping:** Translates Parlant `Where` filters directly into MongoDB query objects.\n- **Failed Migrations:** If a document fails to load via the `document_loader`, it is moved to a specialized collection named `{collection_name}_failed_migrations`.\n\n### JSON File (`JSONFileDocumentDatabase`)\nA lightweight, single-file persistence layer primarily used for local development and testing.\n\n- **Storage:** Serializes all collections into a single JSON file.\n- **Concurrency:** Handles atomic writes to ensure data integrity during local execution.\n- **Sorting:** Implements in-memory sorting and filtering to mimic database behavior.\n\n### Snowflake (`SnowflakeDocumentDatabase`)\nAn enterprise-grade adapter that stores documents in Snowflake tables using `VARIANT` columns.\n\n- **SQL Mapping:** The `_build_where_clause` utility translates JSON filters into Snowflake SQL. It handles nested `$or` and `$and` logic and maps JSON paths to `DATA:\"field\"` syntax.\n- **Serialization:** Automatically handles the serialization of complex types (like `Version` or `ObjectId`) into JSON strings before insertion.\n- **Migration:** Supports bulk migration of existing rows through `load_documents_with_loader`.\n\n---\n\n## Vector Database Adapters\n\nVector adapters are used for semantic search, primarily within the Glossary and Tool discovery systems.\n\n### Chroma (`ChromaDatabase`)\nThe primary vector store adapter. It manages `ChromaCollection` instances which combine vector embeddings with metadata storage.\n\n- **Semantic Search:** The `find_similar_documents` method performs k-nearest neighbor (k-NN) searches based on embeddings generated by an `Embedder`.\n- **Metadata Filtering:** Supports standard filtering alongside vector queries, allowing for scoped searches (e.g., searching only terms associated with a specific `AgentId`).\n- **Embedder Integration:** Collections are tied to specific `Embedder` types (e.g., `OpenAITextEmbedding3Large`). If the embedder type changes, the adapter facilitates re-indexing.\n\n---\n\n## Schema Evolution and Migrations\n\nAll adapters utilize a \"Load-Time Migration\" pattern. Instead of running blocking migration scripts, documents are transformed as they are read from the database.\n\n### The Document Loader\nWhen accessing a collection via `get_or_create_collection`, a `document_loader` coroutine must be provided.\n\n```python\nasync def my_loader(doc: BaseDocument) -> Optional[MySchemaV2]:\n if doc[\"version\"] == \"1.0.0\":\n # Transform V1 to V2\n return MySchemaV2(...)\n return cast(MySchemaV2, doc)\n```\n\n### Migration Workflow\n1. **Version Check:** The `DocumentStoreMigrationHelper` compares the version stored in the database metadata against the `VERSION` defined in the Store class.\n2. **On-Demand Transformation:** As documents are fetched, the `document_loader` is applied.\n3. **Persistence:** If `allow_migration` is enabled, the adapter writes the transformed (upgraded) documents back to the store.\n4. **Error Handling:** Documents that cause exceptions in the loader are moved to a `failed_migrations` collection to prevent data loss while allowing the application to continue.\n\n---\n\n## Querying and Pagination\n\nAdapters support a unified `find` interface returning a `FindResult[T]`.\n\n### Filter Syntax\nFilters use a dictionary-based syntax:\n- **Comparison:** `{\"field\": {\"$eq\": value}}`, `{\"field\": {\"$gt\": value}}`, `{\"field\": {\"$in\": [a, b]}}`\n- **Logic:** `{\"$or\": [{...}, {...}]}`, `{\"$and\": [...]}`\n\n### Cursor-Based Pagination\nTo ensure stable ordering across pages, adapters sort by `creation_utc` (primary) and `id` (tie-breaker).\n\n```mermaid\ngraph TD\n A[Request Page 1] --> B[Sort by creation_utc, id]\n B --> C[Return items + next_cursor]\n C --> D[Request Page 2 with cursor]\n D --> E[Filter: creation_utc > cursor.time OR <br>creation_utc == cursor.time AND id > cursor.id]\n E --> F[Return next set]\n```\n\nThe `Cursor` object encapsulates the `creation_utc` and `id` of the last seen document, ensuring that even if documents have identical timestamps, the pagination remains deterministic.","other-api":"# Other — api\n\n# API Module\n\nThe `api` module provides the RESTful interface for the Parlant system. It exposes endpoints for managing agents, customers, guidelines, and sessions, while handling cross-cutting concerns such as rate limiting, health monitoring, and resource evaluation.\n\n## Core Architecture\n\nThe API is built on FastAPI and follows a pattern where HTTP handlers interact with underlying `Store` classes (e.g., `AgentStore`, `GuidelineStore`) to persist and retrieve data.\n\n```mermaid\ngraph TD\n Client[HTTP Client] --> API[FastAPI Endpoints]\n API --> Auth[BasicRateLimiter]\n API --> Stores[Core Stores / Services]\n Stores --> DB[(Persistence)]\n API --> Monitor[EventLoopMonitor]\n```\n\n## Infrastructure and Middleware\n\n### Authorization and Rate Limiting\nThe module implements a `BasicRateLimiter` to protect endpoints. It uses the `limits` library to enforce quotas based on the `Operation` type and the client's IP address.\n\n- **IP Detection**: The limiter prioritizes the `X-Forwarded-For` header to identify clients behind proxies, falling back to the request's client host.\n- **Isolation**: Limits are isolated per `Operation` bucket (e.g., `LIST_EVENTS`) and per client IP.\n- **Exception Handling**: If a client IP cannot be determined, an `AuthorizationException` is raised.\n\n### Health Monitoring\nThe `/healthz` endpoint provides system status by checking the health of the asyncio event loop via the `EventLoopMonitor`.\n\n- **Healthy**: Latency is within normal bounds.\n- **Degraded**: Event loop latency exceeds 200ms.\n- **Unhealthy**: Event loop latency exceeds 500ms (typically caused by blocking synchronous code).\n\n## Resource Management\n\n### Agents\nAgents are the primary entities in Parlant. The API supports full CRUD operations with specific configurations:\n- **Composition Mode**: Determines how the agent generates responses (e.g., `fluid`, `strict_canned`, `composited_canned`).\n- **Max Engine Iterations**: Controls the depth of the agent's reasoning loop (default is 3).\n- **Custom IDs**: Agents can be created with user-defined string IDs.\n\n### Customers and Pagination\nThe `/customers` endpoint manages user profiles and metadata. It implements cursor-based pagination for listing:\n- **Query Parameters**: `limit`, `cursor`, and `sort` (asc/desc).\n- **Response Structure**: Returns an `items` list, `total_count`, and a `next_cursor` if more data is available.\n\n### Guidelines and Relationships\nGuidelines define agent behavior through `condition` and `action` pairs.\n- **Entailment**: Guidelines can have relationships (e.g., `RelationshipKind.ENTAILMENT`) managed via the `RelationshipStore`.\n- **Propositions**: During creation or evaluation, guidelines can be checked for `action_proposition` or `properties_proposition`.\n\n### Context Variables\nContext variables allow tools to store stateful information associated with specific keys.\n- **Tool Association**: Variables are linked to a `tool_id` (service name and tool name).\n- **Key-Value Storage**: Values are managed via sub-resources: `PUT /context-variables/{id}/{key}`.\n- **Freshness**: Supports `freshness_rules` (cron-like strings) to determine when data should be considered stale.\n\n## Specialized Services\n\n### Evaluations\nThe `/evaluations` endpoint allows developers to test guideline logic without executing a full session.\n- **Payloads**: Accepts a list of guideline contents to evaluate.\n- **Invoices**: Returns an \"invoice\" containing the results of the evaluation, including whether the guideline was `approved` and the data generated by the `properties_proposition`.\n- **Polling**: Supports a `wait_for_completion` parameter to handle long-running evaluation tasks.\n\n### Canned Responses\nCanned responses provide templated snippets for agents.\n- **Fields**: Supports placeholders (e.g., `{{balance}}`) with descriptions and examples.\n- **Signals**: Semantic triggers used to filter relevant responses via `filter_relevant_canned_responses`.\n\n## Common Data Patterns\n\n### Tagging System\nMost resources (Agents, Customers, Guidelines, Terms, Capabilities) support a unified tagging system.\n- **Add/Remove**: Updates are performed via `PATCH` requests using an atomic `add`/`remove` schema.\n- **Automatic Tags**: The system supports specialized tags like `agent-id:<id>` and `journey-id:<id>` to link resources to specific entities.\n\n### Metadata\nResources often include a `metadata` dictionary for arbitrary key-value storage. The API provides a standard interface to `set` or `unset` specific keys within this dictionary during `PATCH` operations.\n\n## Error Handling\nThe API uses standard HTTP status codes:\n- `201 Created`: Successful resource creation.\n- `204 No Content`: Successful deletion.\n- `404 Not Found`: Resource or associated tag does not exist.\n- `422 Unprocessable Content`: Validation errors (e.g., duplicate IDs, missing required fields in evaluations).\n- `429 Too Many Requests`: Rate limit exceeded.","other-ci":"# Other — ci\n\n# CI Disk Space Management\n\nThe `ci` module contains utility scripts designed to optimize the environment of Continuous Integration runners. Specifically, it addresses the storage constraints of GitHub Actions hosted runners by aggressively removing pre-installed software and caches that are not required for the project's build process.\n\n## GitHub Action Ubuntu 24.04 Free Space Script\n\nThe primary component is `scripts/ci/github_action_ubuntu_2404_free_space.sh`. This script is intended to be executed as an early step in a GitHub Actions workflow to maximize the available disk space on the `/` partition.\n\n### Cleanup Strategy\n\nThe script follows a multi-stage destructive cleanup process to reclaim space:\n\n1. **Docker Pruning**: Removes all existing Docker images using `docker rmi`.\n2. **SDK & Toolchain Removal**: Deletes large, pre-installed development environments from `/opt/hostedtoolcache` and `/usr/local`. This includes:\n * Android SDKs\n * .NET and Swift toolchains\n * Haskell (GHC/GHCup)\n * Java (JVM)\n * Julia, vcpkg, and Chromium\n3. **Package Uninstallation**: Uses `apt-get remove` to purge heavy CLI tools and services:\n * Cloud SDKs (Azure, Google Cloud)\n * Browsers (Firefox, Chrome, Edge)\n * Databases (MySQL, MongoDB)\n * Language runtimes (PHP, .NET)\n4. **System Cache Purging**: Cleans the package manager cache (`apt clean`), removes snapd data, and clears `/var/lib/docker` and `/var/cache`.\n\n### Execution Flow\n\nThe script provides immediate feedback on the storage state before and after execution.\n\n```mermaid\ngraph TD\n A[Start] --> B[Log Initial Disk Space]\n B --> C[Remove Docker Images]\n C --> D[Delete SDKs & Toolchains]\n D --> E[Apt-Get Purge Packages]\n E --> F[Clear System Caches]\n F --> G[Log Final Disk Space]\n G --> H[End]\n```\n\n### Usage\n\nTo use this script in a GitHub Actions workflow, it should be invoked before any steps that require significant disk space (e.g., building large binaries or pulling heavy Docker images).\n\n```yaml\njobs:\n build:\n runs-on: ubuntu-24.04\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n\n - name: Free Disk Space\n run: ./scripts/ci/github_action_ubuntu_2404_free_space.sh\n```\n\n### Metrics and Reporting\n\nThe script outputs a summary to the CI logs using `awk` to parse `df -h` results. It calculates the total space freed during the process:\n\n* **Before cleanup**: Displays used and free space.\n* **After cleanup**: Displays used and free space, plus the total \"G\" (Gigabytes) reclaimed.\n\n### Important Considerations\n\n* **Destructive Action**: This script removes tools that may be needed by subsequent steps. If your build requires the Android SDK, Java, or .NET, you must modify the script or avoid using it, as these directories are deleted.\n* **Environment Specificity**: The script is tailored for the `ubuntu-24.04` runner image. While it may work on `ubuntu-22.04`, the paths and package names are optimized for the 24.04 environment.\n* **Permissions**: The script uses `sudo` for most operations, which is standard and permitted on GitHub-hosted runners.","other-claude-md":"# Other — CLAUDE.md\n\n# Project Guidelines and Development Standards (CLAUDE.md)\n\nThe `CLAUDE.md` file serves as the primary orchestration and standards document for the Parlant repository. It defines the architectural patterns, development workflows, and safety protocols required for contributing to the framework.\n\n## Architecture Overview\n\nParlant follows a **Hexagonal Architecture (Ports and Adapters)** pattern to ensure high decoupling between business logic and external dependencies.\n\n* **`src/parlant/core`**: Contains the domain logic and port interfaces. This is the heart of the framework, independent of external frameworks or delivery mechanisms.\n* **`src/parlant/adapters`**: Implements the interfaces defined in the core using third-party tools (e.g., database drivers, LLM providers).\n* **`src/parlant/api`**: The delivery layer, implemented using **FastAPI**. It consumes modules from the core to expose functionality via REST.\n* **`tests`**: Mirrors the `src` structure.\n\n```mermaid\ngraph TD\n API[API Layer - FastAPI] --> Core[Core Framework Logic]\n Adapters[Adapters - 3rd Party Tools] --> Core\n Core --> Ports[Interfaces/Ports]\n Ports -.-> Adapters\n```\n\n## Development Workflow\n\n### Test-Driven Development (TDD)\nThe project strictly adheres to TDD. The mandatory flow for any change is:\n1. Define the implementation plan.\n2. Write a failing test that describes the desired behavior.\n3. Implement the minimum code necessary to pass the test.\n4. Refactor and format.\n\n### Testing Standards\n* **Naming**: Tests must follow the pattern `test_that_[context]_[action]_[expected_result]`.\n* **SDK Testing**: When testing engine behavior or `sdk.py`, classes must inherit from `SDKTest`.\n* **Execution**: Use `uv run pytest` for execution.\n\n### Type Safety and Linting\n* **MyPy**: Strict mode is enabled. Every function parameter and return value must be explicitly type-annotated.\n* **Ruff**: Used for code formatting and linting.\n* **Verification**: Before submission, run `uv run python scripts/lint.py --mypy --ruff`.\n\n## GitNexus Code Intelligence\n\nThe repository integrates with **GitNexus** for impact analysis and safe navigation. Developers and AI agents must follow specific safety protocols before modifying the codebase.\n\n### Mandatory Safety Checks\n1. **Impact Analysis**: Before editing any symbol (class, function, or method), you must run `gitnexus_impact` with `direction: \"upstream\"`.\n2. **Risk Assessment**: If the impact analysis returns a **HIGH** or **CRITICAL** risk level, you must warn the user and document the potential \"blast radius\" before proceeding.\n3. **Change Detection**: After modifications but before committing, run `gitnexus_detect_changes()` to ensure only the intended symbols and execution flows were affected.\n\n### Navigation Tools\n* **`gitnexus_query`**: Used to find execution flows by concept rather than string matching.\n* **`gitnexus_context`**: Provides full context on a symbol, including its callers, callees, and participation in execution flows.\n* **`gitnexus_rename`**: Must be used instead of global find-and-replace to ensure call-graph integrity.\n\n## Implementation Protocol\n\nWhen tasked with a feature or bug fix, the following sequence is required:\n1. **Analyze**: Evaluate the codebase structure and run impact analysis on affected areas.\n2. **Plan**: Describe the implementation, specifically naming the test files and explaining why tests will initially fail.\n3. **Confirm**: Obtain plan approval before writing code.\n4. **Iterate**: Implement tests first, then the code, followed by formatting and linting.","other-core":"# Other — core\n\n# Alpha Engine BDD Step Definitions\n\nThis module provides a comprehensive suite of `pytest-bdd` step definitions used to test the **Alpha Engine**. These steps allow developers to write high-level user story scenarios in Gherkin syntax while interacting directly with the core Parlant services.\n\nThe module acts as a bridge between the BDD feature files and the underlying asynchronous API, utilizing a `ContextOfTest` object to maintain state across steps.\n\n## Core Functional Areas\n\n### 1. Agent Configuration\nSteps in `agents.py` manage the lifecycle and configuration of agents within the `AgentStore`.\n\n* **Creation:** Agents can be created with specific descriptions (\"jobs\"), names, and iteration limits.\n* **Composition Mode:** Supports switching between `FLUID`, `CANNED_STRICT`, `CANNED_COMPOSITED`, and `CANNED_FLUID` modes via `given_that_the_agent_uses_a_message_composition`.\n* **State:** Most steps return or target an `agent_id` fixture to be used by subsequent steps.\n\n### 2. Engine Execution and Control\nThe `engines.py` module contains the logic for triggering the Alpha Engine's processing cycles.\n\n* **Processing:** `when_processing_is_triggered` invokes `AlphaEngine.process()`.\n* **Detection & Analysis:** `when_detection_and_processing_are_triggered` simulates a more complex flow including guideline matching and session state updates before calling the engine.\n* **Cancellation:** `when_processing_is_triggered_and_cancelled_in_the_middle` tests the engine's resilience to task cancellation using `asyncio.sleep` and task interruption.\n* **Utterance:** `when_uttering_is_triggered` allows testing the `utter` API specifically for follow-up actions.\n\n### 3. Guideline and Relationship Management\n`guidelines.py` provides steps to define the behavioral logic of the agent.\n\n* **Definition:** Guidelines are created with conditions and actions. The module uses a `GuidelineEvaluator` to automatically generate metadata properties for these guidelines.\n* **Relationships:** Supports defining complex inter-guideline logic:\n * **Entailment:** One guideline implies another.\n * **Dependency:** A guideline depends on a tool or a journey.\n * **Disambiguation:** Grouping guidelines under a \"head\" to resolve conflicting rules.\n* **Criticality:** Guidelines can be assigned `HIGH`, `MEDIUM`, or `LOW` criticality.\n\n### 4. Context Variables and State\n`context_variables.py` manages the dynamic state associated with sessions and customers.\n\n* **Scoping:** Variables can be set globally, for specific customers, or for specific tags.\n* **Integration:** Variables can be connected to tools (`given_a_context_variable_with_tool`) or assigned `freshness_rules`.\n* **Helper Logic:** The `get_or_create_variable` utility ensures that variables are correctly tagged for the current agent during test setup.\n\n### 5. Event Verification and Simulation\n`events.py` is used to both populate session history and assert the engine's output.\n\n* **Input Simulation:** Steps like `given_a_customer_message` or `given_an_agent_message` manually insert events into the `SessionStore`.\n* **Output Assertion:**\n * **Messages:** Verify content using string matching or NLP-based semantic checks (`nlp_test`).\n * **Status:** Assert that the engine emitted specific `SessionStatus` events (e.g., `typing`, `processing`, `ready`, `error`).\n * **Tools:** Verify that specific tools were called and check the validity of their parameters via `ToolInsights`.\n* **Staging:** Allows inspection of \"staged\" events that have been prepared but not yet emitted.\n\n### 6. Journeys\n`journeys.py` defines multi-step procedural workflows. It includes complex pre-defined templates for common scenarios:\n* `Lock a Card` (Tool-heavy flow)\n* `Reset Password` (Conditional branching)\n* `Book Flight` / `Book Taxi` (Data collection flows)\n\n## Technical Patterns\n\n### Synchronous Wrapper for Async Calls\nSince `pytest-bdd` steps are often executed in a context where a direct `await` is not available or desired in the step signature, the module heavily relies on `context.sync_await()`. This utility executes coroutines on the test's event loop and returns the result synchronously to the step function.\n\n### State Persistence\nThe `ContextOfTest` object (passed as `context`) is the central repository for:\n* **Service Containers:** Access to `AgentStore`, `GuidelineStore`, `SessionStore`, etc.\n* **Entity Mapping:** Dictionaries like `context.guidelines` and `context.journeys` map human-readable names from Gherkin to actual UUIDs.\n* **Event Tracking:** `context.events` stores the history of the current test session.\n\n### NLP-Based Assertions\nFor non-deterministic or complex text output, the module uses `nlp_test`. This allows assertions like:\n`Then the message contains a polite refusal`\nInstead of exact string matching, this triggers an LLM-backed check to verify the semantic content of the agent's response.\n\n## Execution Flow\n\n```mermaid\ngraph TD\n G[Gherkin Feature] -->|Triggers| S[BDD Step Definition]\n S -->|Uses| C[ContextOfTest]\n C -->|Accesses| ST[Stores: Agent, Session, Guideline]\n S -->|sync_await| E[AlphaEngine.process]\n E -->|Emits| EV[EmittedEvents]\n S -->|Asserts| EV\n```\n\n## Usage Example\n\nA typical test flow using these steps:\n\n```gherkin\nScenario: Agent follows a guideline\n Given an agent whose job is \"helping with banking\"\n And a customer named \"Alice\"\n And a guideline to \"ask for a PIN\" when \"the customer wants to withdraw money\"\n When a customer message, \"I want to withdraw 100 dollars\"\n And processing is triggered\n Then a single message event is emitted\n And the message contains \"PIN\"\n```\n\nIn this flow:\n1. `given_an_agent_with_description` creates the agent in the store.\n2. `given_a_guideline_to_when` creates the rule and tags it for the agent.\n3. `given_a_customer_message` populates the `SessionStore`.\n4. `when_processing_is_triggered` runs the `AlphaEngine`.\n5. `then_the_message_contains_the_text` inspects the `EventBuffer` populated by the engine.","other-data":"# Other — data\n\n# Product Test Data Fixture\n\nThe `tests/data/get_products_by_type_data.json` file serves as a static data repository for testing product retrieval and filtering logic. It contains a comprehensive list of hardware components, peripherals, and laptops used to verify the behavior of the system's product management and search APIs.\n\n## Data Schema\n\nEach entry in the JSON array represents a single product entity with the following structure:\n\n| Field | Type | Description |\n| :--- | :--- | :--- |\n| `title` | String | The full commercial name of the product. |\n| `type` | String | The primary category (e.g., \"Graphics Card\", \"Laptop\"). |\n| `vendor` | String | The manufacturer or brand name. |\n| `description` | String | A detailed text summary of product features. |\n| `tags` | Array<String> | Metadata keywords used for filtering and search indexing. |\n| `qty` | Integer | The current stock level available for the test scenario. |\n| `price` | Float | The unit price of the product. |\n\n### Example Entry\n```json\n{\n \"title\": \"Samsung T7 Portable SSD\",\n \"type\": \"Storage\",\n \"vendor\": \"Samsung\",\n \"description\": \"Portable SSD with USB 3.2 Gen 2 speeds.\",\n \"tags\": [\"storage\", \"portable\", \"external\"],\n \"qty\": 40,\n \"price\": 119.99\n}\n```\n\n## Categorization and Coverage\n\nThe dataset is designed to provide high coverage across various hardware segments to ensure robust testing of filtering logic.\n\n### Product Types\nThe data includes, but is not limited to:\n* **Core Components:** Processors, Motherboards, Graphics Cards, Memory, Power Supplies.\n* **Storage:** NVMe SSDs, SATA SSDs, HDDs.\n* **Peripherals:** Keyboards, Mice, Monitors, Headsets, Audio Interfaces.\n* **Systems:** Laptops (Gaming, Ultrabooks, Creative, Business).\n* **Accessories:** Cables, LED Strips, Desk Pads, Monitor Mounts.\n\n### Vendor Diversity\nThe fixture includes products from major industry vendors such as **ASUS, MSI, Intel, AMD, Samsung, Corsair, Apple, and Logitech**, as well as niche manufacturers like **Artisan, Lian Li, and Framework**. This diversity allows for testing vendor-specific filtering and case-sensitive string matching.\n\n## Integration in Testing\n\nThis module is primarily consumed by test suites targeting product filtering functions. Based on the filename, it is the primary data source for validating the `get_products_by_type` functionality.\n\n```mermaid\ngraph TD\n Data[get_products_by_type_data.json] -->|Loaded by| TestRunner[Test Suite]\n TestRunner -->|Injects into| FilterFunc[get_products_by_type]\n FilterFunc -->|Returns| Results[Filtered Product List]\n Results -->|Assert against| Expected[Expected JSON Subset]\n```\n\n### Usage Patterns\n1. **Type Filtering:** Verifying that requesting \"Monitor\" returns all 27-inch and 24-inch displays while excluding \"Graphics Cards\".\n2. **Inventory Logic:** Testing functions that calculate total stock or identify out-of-stock items based on the `qty` field.\n3. **Price Sorting:** Validating that the system correctly sorts items ranging from budget accessories ($19.99) to premium laptops ($4499.99).\n4. **Tag Searching:** Ensuring that a search for the tag \"gaming\" correctly aggregates products across different types (e.g., Mice, Keyboards, and Laptops).\n\n## Maintenance Notes\nWhen adding new entries to this dataset:\n* Ensure the `type` string matches existing categories exactly to avoid breaking existing filter tests.\n* Maintain the `price` as a float and `qty` as an integer.\n* Use descriptive `tags` that overlap with other products to test multi-item result sets.","other-dco-md":"# Other — DCO.md\n\n# Developer Certificate of Origin (DCO)\n\nThe `DCO.md` file defines the legal terms under which contributions are accepted into this project. It implements the **Developer Certificate of Origin Version 1.1**, a standard mechanism used by open-source projects (notably the Linux kernel) to ensure that contributors have the right to submit their code and agree to its distribution.\n\n## Purpose\n\nThe DCO is a statement of ownership and rights. By \"signing off\" on a contribution, a developer certifies that they created the work, based it on allowed open-source work, or received it from someone else who could certify the same. This protects the project from legal issues regarding copyright infringement or unlicensed intellectual property.\n\n## The Certification Clauses\n\nThe DCO consists of four primary assertions:\n\n* **Clause (a):** You authored the contribution or have the right to submit it under the project's open-source license.\n* **Clause (b):** The work is based on previous work covered by appropriate licenses that allow you to submit modifications.\n* **Clause (c):** The contribution was provided to you by someone else who certified (a), (b), or (c), and you have not modified it.\n* **Clause (d):** You acknowledge that the contribution and your personal information (the sign-off) are public and will be maintained indefinitely.\n\n## Implementation in Workflow\n\nUnlike a Contributor License Agreement (CLA), which often requires a separate signing process, the DCO is implemented via a \"sign-off\" line in every Git commit message.\n\n### The Sign-off Format\nTo certify a commit, developers must add a `Signed-off-by` tag to the end of the commit message:\n\n```text\nAuthor: Jane Doe <jane.doe@example.com>\nDate: Mon Jan 1 12:00:00 2024 -0500\n\n Refactor the authentication module logic\n \n Signed-off-by: Jane Doe <jane.doe@example.com>\n```\n\n### Automation\nThe sign-off can be automated using the `-s` (or `--signoff`) flag in Git:\n\n```bash\ngit commit -s -m \"Your commit message\"\n```\n\n## Contribution Pipeline\n\nThe DCO acts as a gatekeeper in the project's CI/CD and contribution pipeline. While `DCO.md` contains no executable code, it is referenced by repository maintenance tools to validate incoming Pull Requests.\n\n```mermaid\ngraph TD\n A[Developer Writes Code] --> B[Commit with -s flag]\n B --> C[Push to Repository]\n C --> D{DCO Check Bot}\n D -- Signed-off-by exists --> E[PR Eligible for Review]\n D -- Missing Sign-off --> F[PR Blocked / Request Sign-off]\n```\n\n## Compliance\nContributions that do not include a valid `Signed-off-by` line matching the commit author are generally rejected. If you have forgotten to sign a commit, you must amend your commit history:\n\n```bash\ngit commit --amend --no-edit -s\ngit push --force-with-lease\n```\n\nThis ensures the project maintains a clear, legally auditable trail of contributions as required by the Linux Foundation standards.","other-e2e":"# Other — e2e\n\n# End-to-End (E2E) Testing Module\n\nThe **Other — e2e** module provides a comprehensive suite of integration tests that validate the interaction between the Parlant server, the CLI client, and external tool services (SDK, MCP, and OpenAPI). These tests ensure that the system components work together correctly in a real-world environment, including process management, network communication, and data persistence.\n\n## Overview\n\nThe E2E suite is designed to run the Parlant system as a black box. It spawns actual server and client processes, interacts with them via REST and CLI commands, and verifies state changes through a dedicated API helper.\n\n### Key Components\n\n| Component | Description |\n| :--- | :--- |\n| `ContextOfTest` | A dataclass providing a sandboxed environment, including a temporary `PARLANT_HOME` directory and an `API` instance. |\n| `API` | A high-level wrapper around `httpx.AsyncClient` used to programmatically interact with the server's REST endpoints. |\n| `run_server` | A context manager that manages the lifecycle of the `parlant-server` process. |\n| `run_cli` | An asynchronous helper that executes the `parlant` CLI client as a subprocess. |\n\n## Test Infrastructure\n\n### Environment Isolation\nTests use the `context` fixture (defined in `conftest.py`), which creates a unique `TemporaryDirectory` for every test case. This directory is passed to the server via the `PARLANT_HOME` environment variable, ensuring that database files and configurations do not leak between tests.\n\n### Process Management\nThe module handles the complexities of starting and stopping asynchronous processes:\n- **Port Selection:** The `API` class uses `get_random_port` to avoid collisions during parallel execution.\n- **Readiness Probing:** `_wait_for_port_ready` uses socket connections to block test execution until the server is actually listening.\n- **Graceful Shutdown:** `run_server` attempts to shut down the server using `SIGINT` first, falling back to `SIGTERM` and eventually `SIGKILL` to ensure no zombie processes remain.\n\n### Architecture Flow\n\n```mermaid\ngraph TD\n TR[Test Runner] -->|Subprocess| CLI[CLI Client]\n TR -->|HTTP| API[API Helper]\n CLI -->|REST| SVR[Parlant Server]\n API -->|REST| SVR\n SVR -->|SDK/MCP/OpenAPI| MS[Mock Services]\n```\n\n## Testing Patterns\n\n### CLI Validation\nTests in `test_client_cli_via_api.py` follow a pattern of executing a CLI command and then verifying the result via the REST API.\n\n```python\nasync def test_example(context: ContextOfTest):\n with run_server(context):\n # 1. Run CLI command\n process = await run_cli(\"agent\", \"create\", \"--name\", \"Test\", address=context.api.server_address)\n await process.wait()\n \n # 2. Verify side-effect via API\n agents = await context.api.list_agents()\n assert any(a[\"name\"] == \"Test\" for a in agents)\n```\n\n### Server Persistence\nTests in `test_server_cli.py` verify that data is correctly persisted to the database by restarting the server process between operations.\n\n1. Start server.\n2. Create a resource (e.g., `create_guideline`).\n3. Kill server process.\n4. Start server again.\n5. Verify resource still exists via `list_guidelines`.\n\n### External Service Integration\nThe suite integrates with mock services to test tool calling:\n- **SDK Services:** Uses `run_service_server` to host Python functions decorated with `@tool`.\n- **OpenAPI Services:** Uses `run_openapi_server` to serve dynamic OpenAPI specifications.\n- **MCP Services:** Uses `run_mcp_server` to validate Model Context Protocol integration.\n\n## API Helper Reference\n\nThe `API` class in `test_utilities.py` simplifies server interaction. Key methods include:\n\n- **Agent Management:** `create_agent()`, `list_agents()`, `get_first_agent()`.\n- **Session Interaction:** `create_session()`, `read_session()`, `get_agent_replies()`.\n- **Knowledge Base:** `create_term()`, `create_guideline()`, `update_guideline()`.\n- **Context Variables:** `create_context_variable()`, `update_context_variable_value()`.\n- **Service Registration:** `create_sdk_service()`, `create_openapi_service()`.\n\n### Agent Communication\nThe `get_agent_replies` method is a critical utility for testing LLM interactions. It posts a customer message to a session and polls the `/events` endpoint until the expected number of agent message events are received, handling offsets and timeouts automatically.\n\n## Production Mode Testing\nThe suite includes tests that set `PARLANT_ENV=production` to verify behavior that is disabled in development, such as rate limiting on specific endpoints like `read_session` or `list_events`.","other-fern":"# Other — fern\n\n# Fern SDK and Documentation Management\n\nThe `scripts/fern` directory contains the configuration for **Fern**, the toolchain used by Parlant to generate client SDKs and host the API documentation portal. This module transforms the project's OpenAPI specification into idiomatic libraries for TypeScript and Python, ensuring that the external developer experience remains synchronized with the core API.\n\n## Architecture Overview\n\nFern acts as a transformation layer that consumes the Parlant OpenAPI definition and produces multiple outputs.\n\n```mermaid\ngraph TD\n OpenAPI[openapi/parlant.openapi.json] --> Fern[Fern Engine]\n Fern --> TS_SDK[sdks/typescript]\n Fern --> PY_SDK[sdks/python]\n Fern --> Docs[docs.parlant.io]\n \n subgraph Configuration\n fern.config.json\n generators.yml\n docs.yml\n end\n Configuration -.-> Fern\n```\n\n## Configuration Files\n\n### `fern.config.json`\nDefines the project identity within the Fern ecosystem.\n* **Organization**: `parlant`\n* **Version**: Locked to `0.61.22` to ensure deterministic builds across environments.\n\n### `generators.yml`\nThis file defines the transformation rules for turning the OpenAPI spec into code. It is configured to use the `local` group by default, which outputs files directly into the repository's `sdks/` directory.\n\n| Generator | Version | Output Path | Key Configuration |\n| :--- | :--- | :--- | :--- |\n| `fern-typescript-node-sdk` | `0.49.2` | `../sdks/typescript` | Exports under the `Parlant` namespace. |\n| `fern-python-sdk` | `4.3.3` | `../sdks/python` | Uses `ParlantClient` as the main entry point. |\n\nThe generators source their data from the relative path: `openapi/parlant.openapi.json`.\n\n### `docs.yml`\nConfigures the public-facing documentation hosted at [docs.parlant.io](https://docs.parlant.io).\n* **Branding**: Uses a high-contrast dark theme (Background: `#000000`, Accent: `#ffffff`).\n* **Navigation**: Automatically generates an API Reference section based on the OpenAPI endpoints.\n\n## Development Workflow\n\n### Updating SDKs\nWhen changes are made to the Parlant API (and subsequently the `parlant.openapi.json` file), the SDKs must be regenerated. This is typically handled via the Fern CLI:\n\n1. Ensure the OpenAPI spec is up to date in the `openapi/` directory.\n2. Run the Fern generation command (usually `fern generate --group local`).\n3. The files in `../sdks/typescript` and `../sdks/python` will be updated to reflect the new API surface.\n\n### Documentation Updates\nChanges to `docs.yml` or the OpenAPI descriptions will update the documentation portal. Fern handles the rendering of request/response schemas, endpoint descriptions, and code snippets for the generated SDKs.\n\n## SDK Specifics\n\n### TypeScript SDK\n* **Namespace**: `Parlant`\n* **Environment**: Node.js compatible.\n* **Location**: `sdks/typescript`\n\n### Python SDK\n* **Client Class**: `ParlantClient`\n* **Location**: `sdks/python`\n* **Pattern**: Uses standard Python type hints and provides a synchronous/asynchronous client interface.","other-graphify-out":"# Other — graphify-out\n\n# Other — graphify-out\n\nThe `graphify-out` module contains the generated structural analysis and relationship mapping for the Parlant codebase. It serves as a meta-documentation layer, providing a high-level overview of the system's architecture, dependency clusters, and core abstractions.\n\n## Overview\n\nThe module is the output of a semantic and AST-based extraction process that maps the interactions between 475 files and over 1,000,000 words of source code. It identifies how disparate parts of the system—such as NLP adapters, session management, and guideline matching—interconnect.\n\n### Key Metrics\n- **Nodes:** 7,655 (Functions, Classes, Modules, UI Components)\n- **Edges:** 72,042 (Calls, Imports, Inferred Semantic Relationships)\n- **Communities:** 333 (Detected clusters of highly related code)\n\n## Core Abstractions (God Nodes)\n\nThe analysis identifies several \"God Nodes\"—components with the highest degree of connectivity. These represent the foundational infrastructure of the Parlant engine:\n\n1. **`Logger` / `Tracer` / `Meter`:** The primary observability stack. These nodes bridge almost every community, from low-level database operations to high-level prompt engineering.\n2. **`PromptBuilder`:** The central utility for LLM interaction, connecting the engine's logic to the NLP services.\n3. **`GuidelineMatch`:** The core data structure for the behavioral engine, linking the `AlphaEngine` to the `GuidelineStore`.\n4. **`ToolId`:** A critical identifier used across canned responses, tool calling, and session management.\n5. **`Embedder`:** The interface for vector operations, connecting the glossary, capabilities, and canned response stores.\n\n## Community Architecture\n\nThe codebase is partitioned into \"Communities\" based on cohesion. Developers should use these clusters to understand the boundaries of specific sub-systems.\n\n### High-Cohesion Clusters\n- **Canned Response System (Communities 0, 1, 2, 5):** A massive cluster covering storage, extraction, and generation logic. This is one of the most complex sub-systems in the repository.\n- **Behavioral Evaluation (Community 33):** Contains the logic for `BehavioralChangeEvaluator`, `GuidelineEvaluator`, and `JourneyEvaluator`. This cluster defines how the agent decides to act based on guidelines.\n- **NLP Adapters (Community 40):** A specialized cluster for external service integrations (Anthropic, Cerebras, Gemini, Mistral, etc.).\n- **Health & Monitoring (Community 52):** Includes `HealthReporter` and various `HealthView` implementations for system telemetry.\n\n### Cross-Community Bridges\nThe graph identifies \"Hyperedges\" that represent logical flows across different modules:\n- **Chat Message Flow:** Connects UI components (`MessageBubble`) to backend event triggers.\n- **Engine Process Flow:** Maps the execution path from `AlphaEngine` through the `RelationalResolver` to `JourneyNodeSelection`.\n\n## Relationship Types\n\nThe module distinguishes between two types of code relationships:\n\n| Type | Description |\n| :--- | :--- |\n| **Extracted** | Relationships explicitly defined in code via imports, function calls, or class inheritance (AST-based). |\n| **Inferred** | Semantic relationships detected via LLM analysis, often linking tests to the implementation details they exercise (e.g., `create_guideline()` calling `ToolId`). |\n\n## Visualization and Usage\n\nThe module provides two primary ways to consume the architectural data:\n\n### 1. GRAPH_REPORT.md\nA human-readable summary of the system's health, surprising connections (e.g., unexpected dependencies between tests and core tools), and knowledge gaps (isolated nodes with no connections).\n\n### 2. graph.html\nAn interactive, browser-based visualization using `vis-network`. \n- **Search:** Locate specific functions or classes to see their immediate neighbors.\n- **Community Filtering:** Toggle entire sub-systems to see how they interface with the rest of the application.\n- **Node Inspection:** Click nodes to view their source file and degree of connectivity.\n\n## Data Generation Flow\n\n```mermaid\ngraph TD\n Source[Source Code / 475 Files] --> AST[AST Extraction]\n Source --> Semantic[Semantic Extraction]\n AST --> GraphBuilder[Graph Construction]\n Semantic --> GraphBuilder\n GraphBuilder --> Community[Leiden Community Detection]\n Community --> Output[graphify-out]\n Output --> MD[GRAPH_REPORT.md]\n Output --> HTML[graph.html]\n```\n\n## Maintenance\nThe contents of `graphify-out` are ephemeral and should be regenerated whenever significant architectural changes occur. The `cost.json` file tracks the token expenditure of the semantic extraction process to manage API costs during large-scale re-indexing.","other-llms-txt":"# Other — llms.txt\n\n# Other — llms.txt\n\nThe `llms.txt` file serves as a comprehensive, LLM-friendly manifest and documentation entry point for the Parlant framework. It defines the primary patterns for building customer-facing AI agents that prioritize rule compliance and structured behavior over raw prompting.\n\n## Module Overview\n\nParlant is designed to move away from \"black-box\" prompting by using structured **Guidelines**, **Journeys**, and **Tools**. This module provides the blueprint for:\n1. **Agent Definition**: Creating persistent AI personalities.\n2. **Behavioral Control**: Implementing if-then logic via Guidelines.\n3. **State Management**: Defining multi-step flows via Journeys.\n4. **Extensibility**: Connecting business logic via Tools.\n5. **Validation**: Testing agent compliance using NLP-based assertions.\n\n## Core API Components\n\n### 1. The Server Context\nThe `parlant.sdk.Server` class acts as the primary entry point, managing the lifecycle of agents and their underlying connections.\n\n```python\nasync with p.Server() as server:\n agent = await server.create_agent(name=\"Assistant\", description=\"...\")\n```\n\n### 2. Guidelines\nGuidelines are the primary mechanism for behavior control. Unlike system prompts, they are evaluated contextually based on a condition.\n\n* **Function**: `agent.create_guideline(condition, action, tools=[])`\n* **Logic**: If the `condition` (natural language) is met, the agent must execute the `action` and is permitted to use the specified `tools`.\n\n### 3. Journeys (State Machines)\nJourneys allow developers to define rigid multi-step flows where the agent must follow a specific path.\n\n* **Initial State**: `journey.initial_state`\n* **Transitions**: `state.transition_to(chat_state, tool_state, condition)`\n* **Termination**: `p.END_JOURNEY`\n\n### 4. Tools\nTools are Python functions decorated with `@p.tool`. They must be `async` and return a `p.ToolResult`.\n\n```python\n@p.tool\nasync def my_tool(context: p.ToolContext, param: str) -> p.ToolResult:\n return p.ToolResult(data={\"result\": \"value\"})\n```\nThe `ToolContext` provides automatic access to `customer_id` and other session metadata.\n\n## Execution Flow\n\nThe following diagram illustrates how Parlant processes a user interaction through its core components:\n\n```mermaid\ngraph TD\n User[User Message] --> Agent[Agent Context]\n Agent --> Guidelines{Guideline Matcher}\n Agent --> Journey{Journey State}\n Guidelines -->|Match| Action[Execute Action]\n Journey -->|Transition| State[New State]\n Action --> Tool[Invoke Tool]\n State --> Tool\n Tool --> Response[Final Response]\n```\n\n## Behavioral Customization\n\n| Component | Method | Purpose |\n| :--- | :--- | :--- |\n| **Glossary** | `create_term()` | Defines domain-specific jargon and synonyms to prevent hallucination. |\n| **Canned Responses** | `add_canned_response()` | Ensures specific phrases are used for common scenarios (e.g., greetings). |\n| **Streaming** | `MessageOutputMode.STREAMING` | Enables real-time token delivery and usage metadata. |\n\n## Testing Framework (`parlant.testing`)\n\nParlant includes a specialized testing suite that uses LLMs to verify the behavior of other LLM agents.\n\n### NLP Assertions\nThe `response.should()` method allows for semantic validation of agent responses without requiring exact string matching.\n\n```python\nawait response.should(\"be polite and ask for the order number\")\n```\n\n### Multi-Turn Validation (`unfold`)\nThe `session.unfold()` method is used to test complex conversations. It breaks a dialogue into sub-tests, where each step with a `should` property is validated in isolation while maintaining the preceding conversation history.\n\n```python\nawait session.unfold([\n CustomerMessage(\"I need help\"),\n AgentMessage(text=\"How can I help?\", should=\"be a greeting\"),\n CustomerMessage(\"My order is late\"),\n AgentMessage(text=\"I'm sorry...\", should=\"apologize for the delay\")\n])\n```\n\n## Configuration\nThe framework relies on environment variables for LLM provider integration:\n* `OPENAI_API_KEY`\n* `ANTHROPIC_API_KEY`\n* `AZURE_OPENAI_API_KEY` / `AZURE_OPENAI_ENDPOINT`","other-modules":"# Other — modules\n\n# Test Modules\n\nThe `tests/modules` directory contains reference implementations of external tool services used for integration testing and as architectural templates. These modules demonstrate how to extend Parlant's capabilities using both the native SDK `PluginServer` and the Model Context Protocol (MCP).\n\n## Module Lifecycle Pattern\n\nEvery module in this directory follows a standardized lifecycle managed by the system's `Container`. This ensures that services are correctly provisioned, registered, and disposed of.\n\n1. **`configure_module(container: Container)`**: \n * Instantiates the server (`PluginServer` or `MCPToolServer`).\n * Uses the `BackgroundTaskService` to start the server's event loop without blocking the main application.\n * Stores the server instance in a module-level global for later shutdown.\n2. **`initialize_module(container: Container)`**: \n * Accesses the `ServiceRegistry`.\n * Registers the tool service with a specific `kind` (\"sdk\" or \"mcp\") and its local loopback URL.\n * Sets `transient=True` to ensure the service is cleaned up after the test session.\n3. **`shutdown_module()`**: \n * Triggers the server's shutdown sequence to release network ports and stop background tasks.\n\n```mermaid\ngraph TD\n A[Container] --> B[BackgroundTaskService]\n A --> C[ServiceRegistry]\n B --> D[Server Instance]\n C -->|Register| D\n D --> E[Tools/Functions]\n```\n\n---\n\n## Bank Module (`bank.py`)\n\nThe Bank module is a standard SDK-based plugin. It demonstrates basic tool definition and the use of `canned_response_fields`.\n\n* **Service Kind**: `sdk`\n* **Port**: `8094`\n* **Key Tools**:\n * `read_account_balance`: Returns a `ToolResult` containing both raw data and a canned response field for the agent to use in its natural language output.\n * `get_account_details`: Returns structured dictionary data.\n\n---\n\n## Tech Store Module (`tech_store.py`)\n\nThe Tech Store module demonstrates advanced SDK features, specifically side-effect events and asynchronous tool execution.\n\n* **Service Kind**: `sdk`\n* **Port**: `8095`\n* **Key Tools**:\n * `consult_expert`: An `async` tool that uses `httpx` to post a \"thinking\" event back to the Parlant session API (`/sessions/{context.session_id}/events`) before returning its final result. This pattern is used to \"buy time\" or provide status updates during long-running tool executions.\n * `list_categories`: A simple tool returning a list of strings.\n\n---\n\n## MCP Parrot Module (`mcp_parrot.py`)\n\nThe MCP Parrot module implements the Model Context Protocol (MCP). Unlike the SDK plugins, it does not use the `@tool` decorator but instead maps standard Python functions to an `MCPToolServer`.\n\n* **Service Kind**: `mcp`\n* **Port**: `DEFAULT_MCP_PORT` (typically 8000)\n* **Key Features**:\n * **Type Handling**: Demonstrates how MCP handles complex Python types including `list[int]`, `list[float]`, `Optional[bool]`, and Enums.\n * **Enum Integration**: Uses the `ParrotSpecies(Enum)` to show how categorical constraints are passed through the MCP layer to the LLM.\n * **Tools**: `parrot_numbers`, `parrot_bools`, and `parrot_enums` serve as echo functions to verify type integrity across the protocol.\n\n---\n\n## Implementation Details\n\n### Tool Context\nSDK-based tools receive a `ToolContext` object. This context is critical for tools that need to interact with the wider system, as it provides the `session_id` required for emitting side-effect events or looking up session-specific metadata.\n\n### Background Task Integration\nServers are started using `_background_task_service.start(server.serve(), tag=...)`. This ensures that if the server fails to start or crashes, the error is captured within the Parlant background task management system rather than silently failing or hanging the test suite.","other-mypy-ini":"# Other — mypy.ini\n\n# Mypy Configuration (`mypy.ini`)\n\nThe `mypy.ini` file serves as the central configuration for static type checking across the project. It defines the strictness levels, path resolution logic, and plugin integrations required to maintain type safety in both the core source code and the test suite.\n\n## Core Type-Checking Policy\n\nThe project adopts a \"Strict-First\" approach to type safety.\n\n* **`strict = True`**: This enables all optional error-checking flags in Mypy. It mandates type annotations for all function signatures, disallows implicit `Optional` types, and prevents the use of untyped decorators or expressions.\n* **`disable_error_code = type-abstract`**: This specific error code is suppressed globally. It allows the codebase to reference or instantiate patterns that Mypy might otherwise flag as \"abstract,\" often necessary when working with complex inheritance patterns or specific factory designs.\n* **`warn_unused_ignores = False`**: Unlike the default strict mode, this configuration does not warn developers if a `# type: ignore` comment is no longer necessary. This reduces noise during refactoring phases where type signatures are in flux.\n\n## Project Structure and Discovery\n\nThe configuration explicitly defines the boundaries of the type-checked environment:\n\n| Setting | Value | Description |\n| :--- | :--- | :--- |\n| `files` | `src, tests` | Mypy targets both the production code and the test suite. |\n| `mypy_path` | `src` | Sets the base directory for module resolution. |\n| `exclude` | `scripts` | Prevents Mypy from analyzing utility scripts that may not adhere to strict typing. |\n\n### Module Resolution Logic\nTo support modern Python packaging standards (PEP 420), the following settings are enabled:\n* **`namespace_packages = True`**: Allows Mypy to recognize packages that do not contain an `__init__.py` file.\n* **`explicit_package_bases = True`**: Works in tandem with `mypy_path` to ensure that Mypy correctly maps file paths to module names (e.g., ensuring `src/module/file.py` is recognized as `module.file` rather than `src.module.file`).\n\n## Plugin Integrations\n\nThe configuration integrates external plugins to extend Mypy's capabilities for specific libraries:\n\n* **`plugins = pydantic.mypy`**: This is critical for projects using Pydantic models. It ensures that Mypy understands Pydantic's custom validation logic, field aliases, and the `BaseModel` constructor, which would otherwise result in false-positive type errors.\n\n## Execution Context\n\nMypy uses this configuration to build a dependency graph of the project before performing analysis.\n\n```mermaid\ngraph TD\n Config[mypy.ini] -->|Defines Rules| Engine[Mypy Static Analyzer]\n Engine -->|Scans| SRC[src/ directory]\n Engine -->|Scans| TESTS[tests/ directory]\n Engine -->|Ignores| SCRIPTS[scripts/ directory]\n Plugin[Pydantic Plugin] -.->|Enhances| Engine\n```\n\n## Usage in Development\n\nWhen running Mypy from the command line, the tool automatically detects this file in the project root:\n\n```bash\n# Runs type checking based on the rules in mypy.ini\nmypy .\n```\n\nAny deviations from the rules defined in this file (e.g., missing return type hints) will result in a non-zero exit code, typically enforced during CI/CD pipelines to ensure code quality.","other-parlant":"# Other — parlant\n\n# Parlant Chat UI and Core Metadata\n\nThe **parlant** module encompasses the primary web-based chat interface and the core package metadata. The frontend is a React-based Single Page Application (SPA) designed for real-time interaction with Parlant agents, while the core files define versioning and type-checking compatibility for the Python package.\n\n## Frontend Architecture (src/parlant/api/chat)\n\nThe chat interface is built with **React 18** and **TypeScript**, utilizing **Vite** as the build tool and dev server. It provides a high-fidelity environment for testing agents, viewing internal logs, and managing conversation sessions.\n\n### Tech Stack\n- **State Management**: [Jotai](https://jotai.org/) for atomic, reactive state.\n- **Styling**: [Tailwind CSS](https://tailwindcss.com/) with custom theme extensions for brand colors (`green-main`, `blue-main`) and animations.\n- **UI Components**: [Radix UI](https://www.radix-ui.com/) primitives for accessible dialogs, dropdowns, and tooltips.\n- **Icons**: [Lucide React](https://lucide.dev/).\n- **Markdown**: `react-markdown` with `rehype-highlight` for rendering agent responses and code blocks.\n- **Editor**: [CodeMirror](https://codemirror.net/) for specialized text input and data viewing.\n\n### Component Structure\nThe UI is organized into functional areas that facilitate both conversation and debugging:\n\n```mermaid\ngraph TD\n App --> Chatbot\n Chatbot --> SessionList\n Chatbot --> SessionView\n Chatbot --> MessageDetails\n SessionView --> MessageList\n MessageList --> Message\n Message --> Markdown\n MessageDetails --> MessageLog\n MessageDetails --> IndexedDBData\n```\n\n- **SessionView**: The central area where the conversation history is rendered. It uses `VirtualScroll` for performance and `DateHeader` for chronological organization.\n- **MessageDetails**: A diagnostic panel that allows developers to inspect the \"thought process\" of an agent, including logs, flags, and metadata associated with specific messages.\n- **AgentList / SessionList**: Navigation components for switching between different AI agents and historical conversation threads.\n- **UI Primitives**: Located in `src/components/ui/`, these are reusable, low-level components (Buttons, Inputs, Selects) built on Radix UI and styled with `class-variance-authority`.\n\n### Styling and Theming\nThe application uses a custom Tailwind configuration (`tailwind.config.js`) that defines:\n- **Custom Keyframes**: `fade-in-fast` for smooth UI transitions and `background-shift` for animated gradients.\n- **Typography**: Integration of IBM Plex Mono and Ubuntu Sans/Mono fonts, served locally from the `public/fonts` directory.\n- **Color Palette**: A semantic color system mapping HSL variables to UI states (primary, accent, destructive, etc.), supporting both light and dark modes via `next-themes`.\n\n## Core Metadata\n\nOutside of the frontend application, the module contains essential package-level files:\n\n### Versioning (`src/parlant/core/version.py`)\nThis file serves as the single source of truth for the Parlant package version.\n- **Current Version**: `3.3.1`\n- **Usage**: This constant is typically imported by `setup.py` or `__init__.py` to ensure consistency across the ecosystem.\n\n### Type Distribution (`src/parlant/py.typed`)\nAn empty marker file that signifies to PEP 561-compliant type checkers (like `mypy` or `pyright`) that the `parlant` package provides inline type annotations.\n\n## Development and Tooling\n\n### Scripts\nManaged via `package.json` in the chat directory:\n- `npm run dev`: Starts the Vite development server on `127.0.0.1:8002`.\n- `npm run build`: Compiles TypeScript and runs the Vite production build.\n- `npm run lint`: Executes ESLint using the `typescript-eslint` configuration.\n- `npm run test`: Runs unit tests via **Vitest** with a JSDOM environment.\n\n### Configuration\n- **TypeScript**: Split into `tsconfig.app.json` (application code) and `tsconfig.node.json` (Vite configuration). It uses `bundler` module resolution and strict type checking.\n- **Vite**: Configured in `vite.config.ts` with a base path of `/chat/` and path aliases (`@/*` mapping to `src/*`).\n- **PostCSS**: Handles Tailwind CSS nesting and Autoprefixer for cross-browser CSS compatibility.","other-pyproject-toml":"# Other — pyproject.toml\n\n# Project Configuration: pyproject.toml\n\nThe `pyproject.toml` file serves as the primary manifest for the Parlant project. It defines project metadata, runtime dependencies, development environment constraints, and CLI entry points. The project uses **Hatchling** as the build backend and is optimized for the **uv** package manager.\n\n## Project Metadata\n\n* **Name:** `parlant`\n* **Version:** `3.3.1`\n* **License:** Apache-2.0\n* **Python Requirement:** `>=3.10, <3.15`\n * *Note:* The upper bound is strictly enforced to ensure compatibility between `torch 2.8+` and `triton`.\n\n## CLI Entry Points\n\nThe module defines three primary executable scripts mapped to internal entry points:\n\n| Command | Entry Point | Description |\n| :--- | :--- | :--- |\n| `parlant` | `parlant.bin.client:main` | The primary CLI client for interacting with Parlant. |\n| `parlant-server` | `parlant.bin.server:main` | Starts the Parlant backend server. |\n| `parlant-prepare-migration` | `parlant.bin.prepare_migration:main` | Utility for handling database schema migrations. |\n\n## Dependency Management\n\n### Core Dependencies\nThe project relies on several key frameworks for its operation:\n* **Web Framework:** `fastapi`, `uvicorn`, and `starlette`.\n* **LLM & AI:** `openai`, `tiktoken`, and `parlant-client` (sourced directly from GitHub).\n* **Observability:** Full `opentelemetry` suite (API, SDK, OTLP Exporter, and Instrumentation).\n* **Data & Logic:** `pydantic` (via transitive requirements), `networkx`, and `jsonschema`.\n* **Tooling Compatibility:** \n * `griffe` is pinned to `<2` to maintain compatibility with `fastmcp`.\n * `aiopenapi3` is restricted to `<0.9.0` to avoid Pydantic version conflicts.\n\n### Optional Dependencies (Extras)\nParlant supports various pluggable backends and LLM providers via optional extras:\n\n* **Vector Databases:** `chroma`, `qdrant`.\n* **Document Stores:** `mongo`.\n* **LLM Providers:** \n * `anthropic`, `gemini`, `vertex`, `ollama`, `litellm`, `mistral`, `zhipu`, `cerebras`, `together`, `deepseek`.\n * *Note:* `fireworks` is currently disabled due to a security vulnerability (CVE-2025-4565) in its `protobuf` pin.\n* **Cloud & Integration:** `aws`, `azure`, `snowflake`.\n\n### Development Environment\nThe `[dependency-groups].dev` section defines the toolchain for contributors:\n* **Linting/Formatting:** `ruff`.\n* **Type Checking:** `mypy` with various `types-*` stubs.\n* **Testing:** `pytest` with plugins for `asyncio`, `bdd`, `cov`, and `xdist`.\n* **Custom Testing:** Includes `pytest-timing`, a custom internal tool for performance regression tracking.\n\n## Build and Resolution Logic\n\n### UV Configuration\nThe project utilizes `tool.uv` to manage complex dependency resolutions and security patches:\n\n* **Overrides:** Forces `pyjwt>=2.11.1` to resolve conflicts between `zhipuai` and `mcp`, addressing CVE-2025-66416.\n* **Constraints:** Defines minimum safe versions for transitive dependencies (e.g., `aiohttp`, `cryptography`, `urllib3`) to ensure the environment is protected against known CVEs without forcing these packages as direct dependencies.\n\n### Build System\n```mermaid\ngraph TD\n A[pyproject.toml] --> B[Hatchling Build Backend]\n B --> C[Wheel Distribution]\n C --> D[src/parlant package]\n A --> E[uv Package Manager]\n E --> F[Dependency Resolution]\n F --> G[Constraint/Override Enforcement]\n```\n\nThe build system is configured to include the `src/parlant` directory in the distribution wheel and allows direct references to git repositories (required for `parlant-client`).","other-pytest-ini":"# Other — pytest.ini\n\n# pytest.ini Configuration\n\nThe `pytest.ini` file serves as the primary configuration entry point for the project's test suite. It defines the execution environment, plugin behaviors, and metadata markers used to categorize and filter tests.\n\n## Core Configuration\n\n### Asyncio Integration\n```ini\nasyncio_mode = auto\n```\nThe project uses `pytest-asyncio` for handling asynchronous test cases. Setting `asyncio_mode = auto` ensures that any test function defined with `async def` is automatically treated as an asynchronous test, eliminating the need to explicitly apply the `@pytest.mark.asyncio` decorator to every coroutine.\n\n### Behavior Driven Development (BDD)\n```ini\nbdd_features_base_dir = tests/\n```\nThe `pytest-bdd` plugin is configured to look for Gherkin `.feature` files within the `tests/` directory. This establishes the root path for feature file discovery when using the `scenario()` or `scenarios()` functions in test modules.\n\n### Import Behavior\n```ini\naddopts = \"--import-mode=importlib\"\n```\nThe test runner is configured to use `importlib` for importing test modules. This is the modern pytest standard which avoids modifying `sys.path` and prevents naming conflicts between test files in different directories that share the same filename (e.g., `test_utils.py` in multiple subpackages).\n\n## Warning Management\n\nThe `filterwarnings` section suppresses specific non-critical warnings to maintain clean CI/CD output and developer logs:\n\n* **`ignore::pytest.PytestDeprecationWarning:pytest_bdd.*`**: Suppresses deprecation warnings originating from the `pytest_bdd` library, ensuring compatibility during library version transitions.\n* **`ignore::pytest.PytestWarning:.*usefixtures.*has no effect`**: Suppresses warnings when `usefixtures` is applied in contexts where pytest deems it redundant, preventing log noise in complex fixture hierarchies.\n\n## Custom Test Markers\n\nMarkers allow developers to categorize tests and execute specific subsets of the suite using the `-m` flag (e.g., `pytest -m engine`).\n\n| Marker | Description |\n| :--- | :--- |\n| `engine` | Targets tests related to the core execution engine behavior. |\n| `evaluation` | Targets tests related to preprocessing evaluations and data validation logic. |\n\n## Execution Flow\n\nThe following diagram illustrates how `pytest.ini` influences the test lifecycle:\n\n```mermaid\ngraph TD\n INI[pytest.ini] --> Discovery[Test Discovery]\n INI --> Runtime[Runtime Environment]\n \n Discovery --> BDD[Locate .feature files in tests/]\n Discovery --> Import[Import via importlib]\n \n Runtime --> Async[Auto-handle async def]\n Runtime --> Filter[Filter Deprecation Warnings]\n Runtime --> Markers[Apply engine/evaluation markers]\n```\n\n## Usage Examples\n\n**Running only engine-related tests:**\n```bash\npytest -m engine\n```\n\n**Running tests while ignoring evaluation logic:**\n```bash\npytest -m \"not evaluation\"\n```","other-pytest-stochastics-json":"# Other — pytest_stochastics.json\n\n# pytest_stochastics.json Configuration\n\nThe `pytest_stochastics.json` file is the central configuration for managing stochastic (probabilistic) and deterministic tests. It defines execution strategies, success thresholds for flaky tests, and logical groupings of test suites.\n\nThis configuration is typically consumed by a custom pytest runner or plugin to determine how many times a test should be retried and what constitutes a \"pass\" for a specific test category.\n\n## Core Concepts\n\nThe configuration is built on three primary components:\n1. **Policies**: Rules defining the pass/fail criteria (e.g., \"must pass 2 out of 3 times\").\n2. **Test Plans**: Named collections that map file paths or regex patterns to specific policies.\n3. **Plan Fallbacks**: An inheritance mechanism allowing plans to override a base configuration.\n\n---\n\n## Policies (`policy_list`)\n\nPolicies define the execution logic for any test assigned to them.\n\n| Policy | `at_least` | `out_of` | Description |\n| :--- | :--- | :--- | :--- |\n| `default` | 1 | 1 | Standard deterministic behavior. Must pass once. |\n| `disable` | 0 | 0 | Prevents the test from running. |\n| `strict3` | 3 | 3 | Stochastic test that must be 100% stable over 3 runs. |\n| `majority3` | 2 | 3 | Stochastic test allowing for one failure across 3 runs. |\n| `experimental`| 0 | 3 | Runs 3 times but does not trigger a failure if all fail (`at_least: 0`). |\n\n### Policy Attributes\n- **`at_least`**: The minimum number of successful runs required for the test to be marked as passed.\n- **`out_of`**: The total number of times the test will be executed.\n- **`pass_fast`**: (Optional) If `false`, the runner will complete all `out_of` runs even if the `at_least` threshold is already met or impossible to reach.\n\n---\n\n## Test Plans (`test_plan_list`)\n\nTest plans aggregate tests by directory or regex and assign them a policy.\n\n### Key Plans\n- **`complete`**: A master plan used for full suite validation and IDE integration (e.g., VS Code Test Explorer). It maps `tests/core/stable` to `strict3`, `tests/core/unstable` to `majority3`, and everything else to `default`.\n- **`deterministic`**: Targets only non-stochastic tests by using a negative lookahead regex: `tests/(?!core)`.\n- **`core_stable` / `core_unstable`**: Targeted plans for specific stochastic tiers within the `tests/core` directory.\n- **`default_disabled`**: A baseline plan that sets the `disable` policy on the entire `tests/` directory. This is used as a foundation for other plans to ensure only explicitly included tests run.\n\n### Path Matching\nTests are matched using string paths or regular expressions. For example:\n- `tests/core/stable`: Matches all tests in that specific directory.\n- `tests/(?!core)`: Matches all tests in the `tests` folder except those in the `core` subfolder.\n\n---\n\n## Plan Fallbacks (`plan_fallback_list`)\n\nThe fallback list defines an inheritance hierarchy. This allows for a \"deny-by-default\" strategy.\n\n```mermaid\ngraph TD\n DD[default_disabled] -->|Overrides| D[deterministic]\n DD -->|Overrides| CS[core_stable]\n DD -->|Overrides| CU[core_unstable]\n```\n\nIn this configuration, `deterministic`, `core_stable`, and `core_unstable` all inherit from `default_disabled`. This ensures that when running the `deterministic` plan, any test not matching the `tests/(?!core)` regex is automatically disabled rather than falling back to a global default.\n\n---\n\n## Usage in Development\n\n### Adding a New Stochastic Test\nIf a test is inherently probabilistic (e.g., a model convergence test):\n1. Place the test in `tests/core/stable` or `tests/core/unstable`.\n2. The `complete` plan will automatically apply the `strict3` or `majority3` policy based on the directory.\n\n### Creating a New Policy\nTo add a policy with a different threshold (e.g., 4 out of 5):\n1. Add a new object to `policy_list`:\n ```json\n {\n \"policy\": \"high_confidence\",\n \"at_least\": 4,\n \"out_of\": 5\n }\n ```\n2. Reference `\"policy\": \"high_confidence\"` within a plan in `test_plan_list`.","other-readme-md":"# Other — README.md\n\n# Parlant: Interaction Control Harness\n\nParlant is a production-ready agentic harness designed for conversational governance. Unlike traditional frameworks that rely on massive system prompts or rigid state machines, Parlant uses **Context Engineering** to dynamically assemble the most relevant instructions, tools, and knowledge for every individual turn of a conversation.\n\n## Core Architecture: The Matching Engine\n\nThe central component of Parlant is the **Contextual Matching Engine**. Instead of passing the entire configuration to an LLM, the engine performs a pre-processing step to narrow the context window.\n\n```mermaid\ngraph LR\n Input[User Input] --> Engine[Matching Engine]\n subgraph Context Assembly\n Engine --> Guidelines\n Engine --> Journeys\n Engine --> Tools\n end\n Guidelines --> Generator[Message Generation]\n Journeys --> Generator\n Tools --> Generator\n Generator --> Output[Agent Response]\n```\n\n1. **Evaluation:** The engine evaluates the current conversation state against defined `Guidelines`, `Observations`, and `Journeys`.\n2. **Resolution:** It resolves conflicts using `Relationships` (Exclusions and Dependencies).\n3. **Assembly:** It constructs a focused prompt containing only the active context.\n4. **Execution:** It triggers tools or generates a response based on the narrowed context.\n\n---\n\n## Behavioral Control\n\n### Guidelines and Relationships\nGuidelines are the primary unit of behavioral control, defined as condition-action pairs. To prevent context bloat and conflicting instructions, Parlant uses relationships to manage how guidelines interact.\n\n* **Exclusions:** Prevents a guideline from entering the context if a more specific or higher-priority guideline is matched.\n* **Dependencies:** Ensures a guideline only activates if a prerequisite \"Observation\" or \"Guideline\" is met.\n\n```python\n# Example: Managing conflicting instructions\nexpert_guideline = await agent.create_guideline(\n condition=\"customer uses financial terminology\",\n action=\"respond with technical depth\",\n)\n\nbeginner_guideline = await agent.create_guideline(\n condition=\"customer seems new to the topic\",\n action=\"simplify and use concrete examples\",\n)\n\n# Ensure the beginner logic overrides the expert logic if both match\nawait beginner_guideline.exclude(expert_guideline)\n```\n\n### Journeys (SOPs)\nJourneys represent multi-turn Standard Operating Procedures. They allow agents to follow structured flows (like flight booking or troubleshooting) while remaining flexible enough to handle non-linear user behavior.\n\n* **States:** Can be `chat_state` (instructional) or `tool_state` (functional).\n* **Transitions:** Defined by conditions that allow the agent to move forward, skip steps, or loop back based on user input.\n\n---\n\n## Tool Integration and Observations\n\nTools in Parlant are not permanently attached to the LLM's context. Instead, they are associated with **Observations**. A tool is only \"visible\" to the agent when its specific condition is met.\n\n```python\n@p.tool\nasync def research_deep_answer(context: p.ToolContext, query: str) -> p.ToolResult:\n # Implementation logic\n return p.ToolResult(data=...)\n\n# Tool only enters context when financial terms are detected\nawait agent.create_observation(\n condition=\"customer uses financial terminology like DTI or amortization\",\n tools=[research_deep_answer],\n)\n```\n\n---\n\n## Safety and Compliance\n\n### Canned Responses\nFor high-stakes interactions where hallucinations are unacceptable, Parlant provides **Canned Responses**. When a guideline is set to `CompositionMode.STRICT`, the agent is forced to select from a list of pre-approved templates rather than generating free-form text.\n\n```python\nawait agent.create_guideline(\n condition=\"The customer discusses unrelated topics\",\n action=\"Tell them you can't help with that\",\n composition_mode=p.CompositionMode.STRICT,\n canned_responses=[\n await agent.create_canned_response(\"I'm sorry, I can only assist with airline inquiries.\")\n ],\n)\n```\n\n### Explainability\nParlant integrates with **OpenTelemetry** to provide full traceability. Every turn includes logs and traces detailing:\n* Which guidelines were matched.\n* Which guidelines were excluded and why.\n* The specific tool outputs that influenced the final response.\n\n---\n\n## Framework Interoperability\n\nParlant is designed to act as a governance layer on top of existing stacks. It can wrap workflows from other frameworks (like LangGraph or LlamaIndex) as tools.\n\n```python\n@p.tool\nasync def run_legacy_workflow(context: p.ToolContext, user_id: str) -> p.ToolResult:\n # Call an external LangGraph or custom workflow\n result = await my_external_system.run(user_id)\n \n return p.ToolResult(\n data=result[\"data\"],\n # Dynamically inject guidelines based on workflow results\n guidelines=[{\"action\": \"Follow-up on pending invoice\", \"priority\": 5}]\n )\n```\n\nThis allows developers to use Parlant for conversational \"guarding\" and behavioral consistency while leveraging other libraries for complex backend processing.","other-ruff-toml":"# Other — ruff.toml\n\n# Ruff Configuration (`ruff.toml`)\n\nThis module defines the linting and formatting standards for the project using [Ruff](https://docs.astral.sh/ruff/). It ensures code consistency, enforces Python 3.12 best practices, and automates style corrections.\n\n## Global Settings\n\nThe configuration targets a modern Python environment and establishes basic layout constraints.\n\n| Setting | Value | Description |\n|:---|:---|:---|\n| `target-version` | `py312` | Enables syntax and linting checks specific to Python 3.12 features. |\n| `line-length` | `100` | Maximum characters per line (slightly more permissive than the standard Black 88). |\n| `indent-width` | `4` | Standard 4-space indentation. |\n\n### Exclusions\nThe configuration ignores standard development artifacts, virtual environments, and cache directories to prevent Ruff from processing non-source files. This includes `.git`, `.venv`, `__pycache__`, `build`, `dist`, and various IDE-specific folders.\n\n## Linting Configuration (`[lint]`)\n\nThe project uses a selective approach to linting, enabling specific rule sets while maintaining a roadmap for future strictness.\n\n### Enabled Rules\nThe `select` list activates the following categories:\n* **F (Pyflakes):** Logic errors, unused imports, and undefined names.\n* **E4, E7, E9 (pycodestyle):** Basic PEP8 violations and syntax errors.\n* **W293:** Blank line contains whitespace.\n* **PLR1722:** Use `sys.exit()` instead of `exit` or `quit`.\n* **PTH204:** Use `Path.abspath()` (pathlib) instead of `os.path.abspath`.\n* **PLW2901:** Outer for loop variable overwritten by inner assignment.\n\n### Ignored Rules\n* **E203:** Whitespace before ':'. This is ignored to maintain compatibility with certain formatting patterns where Ruff and other tools might conflict.\n\n### Technical Debt & Roadmap\nSeveral rules are currently commented out in the `select` block, indicating planned future adoption:\n* `ASYNC230`: Prohibiting synchronous `open()` calls within `async` functions.\n* `PTH123`: Preferring `Path.open()` over the built-in `open()`.\n* `I001`: Automated import sorting (isort compatibility).\n* `UP035` / `UP017`: Modernizing type hints and datetime usage.\n\n### Fixability\n* **fixable = [\"ALL\"]**: Ruff is permitted to automatically fix all enabled rules when the `--fix` flag is provided.\n* **dummy-variable-rgx**: Variables matching `^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$` (e.g., `_`, `_unused`) are ignored by unused variable checks.\n\n## Formatter Configuration (`[format]`)\n\nThe formatter is configured to mirror **Black** behavior, ensuring a predictable and standard code style.\n\n```mermaid\ngraph TD\n Code[Source Code] --> Ruff{Ruff Engine}\n Ruff -->|Check| Lint[Linting Violations]\n Ruff -->|Format| Styled[Standardized Code]\n subgraph Standards\n Lint --- Rules[F, E, PLR, PTH]\n Styled --- Style[Double Quotes, 100 Char Limit]\n end\n```\n\n* **Quotes:** Uses `double` quotes for strings.\n* **Indentation:** Uses `space` instead of tabs.\n* **Trailing Commas:** Respects \"magic trailing commas\" (if a trailing comma is present in a multi-line construct, the formatter will keep it expanded).\n* **Line Endings:** Set to `auto` for cross-platform compatibility.\n\n## Usage in Development\n\nDevelopers should interact with this configuration via the Ruff CLI:\n\n1. **Linting:** Run `ruff check .` to identify issues.\n2. **Auto-fixing:** Run `ruff check . --fix` to resolve fixable linting errors.\n3. **Formatting:** Run `ruff format .` to apply the style rules defined in the `[format]` section.","other-scripts":"# Other — scripts\n\n# Repository Management Scripts\n\nThe `scripts` module provides a suite of automation tools for the Parlant development lifecycle. These scripts handle environment initialization, linting, version management, SDK generation, and multi-platform publishing.\n\n## Core Utilities (`utils.py`)\n\nMost scripts in this module rely on `utils.py` for consistent interaction with the repository structure and package management.\n\n### The `Package` Dataclass\nThe `Package` class represents a manageable unit within the repository (currently focused on the main `parlant` package). It encapsulates:\n- `path`: The filesystem path to the package.\n- `cmd_prefix`: The execution wrapper (e.g., `uv run`).\n- `run_cmd()`: A helper to execute shell commands within the package context.\n\n### Iteration Pattern\nThe module uses a functional approach to apply operations across the codebase via `for_each_package(f: Callable[[Package], None])`. This function handles directory navigation and ensures commands are executed in the correct context.\n\n---\n\n## Development Lifecycle\n\n### Repository Initialization\n- **`initialize_repo.py`**: The entry point for new contributors. It triggers package installation and configures Git hooks by setting `core.hooksPath` to `.githooks`.\n- **`install_packages.py`**: Uses `uv sync --all-extras` to set up Python virtual environments for all packages defined in `utils.get_packages()`.\n\n### Quality Control (`lint.py`)\nThe linting script provides a wrapper around `mypy` and `ruff`.\n- `--mypy`: Runs static type checking.\n- `--ruff`: Runs both `ruff check` (linting) and `ruff format --check` (formatting).\n\n---\n\n## SDK Generation (`generate_client_sdk.py`)\n\nThis script automates the generation of Python and TypeScript client SDKs using [Fern](https://buildwithfern.com/).\n\n### Workflow\n1. **OpenAPI Fetch**: Connects to a running Parlant server (default port `8800`) to download the latest `openapi.json`.\n2. **Fern Invocation**: Runs `fern generate` to produce SDKs in the `scripts/sdks` directory.\n3. **Post-Processing**: \n - For Python, it performs a regex rewrite of imports, changing `from parlant import` to `from parlant.client import` to avoid namespace collisions.\n - Injects a `py.typed` file to ensure PEP 561 compliance.\n4. **Distribution**: Synchronizes the generated code with the target repositories defined in `PATHDICT_SDK_REPO_TARGETS` (e.g., `parlant-client-python` and `parlant-client-typescript`).\n\n---\n\n## Release Management\n\n### Versioning (`version.py`)\nHandles Semantic Versioning (SemVer) updates across the repository. It supports bumping `major`, `minor`, `patch`, and pre-release labels (`alpha`, `beta`, `rc`).\n\n```mermaid\ngraph TD\n A[version.py] --> B{Bump Type?}\n B --> C[Update pyproject.toml]\n B --> D[Update core/version.py]\n C --> E[uv lock]\n D --> F[Git Commit & Tag]\n E --> F\n```\n\n**Key Functions:**\n- `update_version()`: Calculates the next version string using the `semver` library.\n- `set_package_version()`: Performs regex replacement in `pyproject.toml` and refreshes the `uv.lock` file.\n- `update_version_variable_in_code()`: Synchronizes the `VERSION` constant in `src/parlant/core/version.py`.\n\n### Publishing (`publish.py`)\nAutomates the distribution of artifacts to PyPI and Docker Hub.\n\n1. **Python Packages**: Iterates through packages where `publish=True` and executes `uv build` followed by `uv publish`.\n2. **Docker Images**: \n - Retrieves the current server version from `pyproject.toml`.\n - Uses `docker buildx` to build multi-platform images (`linux/amd64`, `linux/arm64`).\n - Tags images based on the version (e.g., `latest`, `1`, `1.2`, `1.2.3`) and pushes them to `ghcr.io/emcie-co/parlant`.\n\n---\n\n## Usage Reference\n\n| Task | Command |\n| :--- | :--- |\n| **Setup** | `python scripts/initialize_repo.py` |\n| **Linting** | `python scripts/lint.py --mypy --ruff` |\n| **SDK Gen** | `python scripts/generate_client_sdk.py [port]` |\n| **Release** | `python scripts/version.py --minor` (or `--patch`, `--rc`, etc.) |\n| **Publish** | `python scripts/publish.py` |","other-sdk":"# Other — sdk\n\n# Parlant SDK\n\nThe `parlant.sdk` module provides a high-level, developer-friendly interface for interacting with the Parlant engine. It abstracts complex internal state management into a set of intuitive classes and methods for defining agents, guidelines, customers, and structured interaction journeys.\n\n## Core Entities\n\n### Server\nThe `Server` class is the entry point for the SDK. It manages the lifecycle of agents and customers and provides access to the underlying engine configuration.\n\n* **Creation:** Agents and customers are created directly through the server instance using `create_agent()` and `create_customer()`.\n* **Discovery:** Use `list_agents()`, `find_agent()`, `list_customers()`, and `find_customer()` to retrieve existing entities.\n* **Global Context:** Within execution contexts (like tools or hooks), the active server can be accessed via `p.Server.current`.\n\n### Agent\nThe `Agent` represents the AI persona. It is configured with a name, description, and behavioral policies.\n\n* **Composition Mode:** Determines how the agent combines multiple guidelines. Modes include `STRICT`, `COMPOSITED`, and `FLUID`.\n* **Output Mode:** Supports `STREAM` for chunked responses or default blocking responses.\n* **Performance Policies:** Control perceived performance, such as `BasicPerceivedPerformancePolicy` (which may send preambles) or `NullPerceivedPerformancePolicy`.\n\n### Customer\nRepresents the end-user interacting with the agent.\n* **Metadata:** Supports arbitrary key-value pairs via the `metadata` parameter.\n* **Guest Access:** A default `Customer.guest` is provided for unauthenticated sessions.\n\n---\n\n## Behavioral Logic: Guidelines and Glossary\n\n### Guidelines\nGuidelines are the primary way to control agent behavior. They consist of a `condition` (when to act) and an `action` (what to do).\n\n* **Creation:** `agent.create_guideline(condition=..., action=...)`.\n* **Relationships:** Guidelines can be linked to resolve conflicts or define logic flows:\n * `prioritize_over(other)`: Ensures one guideline takes precedence.\n * `entail(other)`: Defines a logical consequence.\n * `depend_on(other)`: Makes a guideline active only if another is met.\n * `disambiguate([others])`: Helps the engine choose between similar conditions.\n* **Custom Matchers:** Developers can override the default NLP matching logic by providing a `matcher` function.\n* **Handlers:** Register callbacks like `on_selected` (triggered when a guideline matches) or `on_message` (triggered when it generates a response).\n\n### Glossary\nThe Glossary manages domain-specific terminology to ensure the agent understands specialized vocabulary.\n* **Terms:** Created via `agent.create_term()`.\n* **Synonyms:** Allows mapping multiple words to a single defined concept.\n\n---\n\n## Structured Interactions: Journeys\n\nJourneys allow developers to define state-machine-like interactions for complex workflows (e.g., booking a flight or troubleshooting).\n\n### Journey Structure\nA Journey is initiated by `triggers` (conditions or specific guidelines). It consists of a graph of states and transitions.\n\n```mermaid\ngraph TD\n Start((Initial State)) -->|transition_to| StateA[Chat State]\n StateA -->|condition| StateB[Tool State]\n StateB -->|transition_to| End((End Journey))\n```\n\n### Transitions and States\n* **Chat States:** Transitions that result in the agent saying something specific.\n* **Tool States:** Transitions that trigger a function call (e.g., `tool_state=my_function`).\n* **Conditions:** Transitions can be gated (e.g., `condition=\"if the customer says yes\"`). If a state has multiple outgoing transitions, all must have conditions.\n* **Reevaluation:** The engine can be forced to reevaluate the journey state after a tool call using `reevaluate_after()`.\n\n---\n\n## Extensibility and Hooks\n\n### Tools and Retrievers\nAgents can be extended with custom logic:\n* **Tools:** Attached via `agent.attach_tool()`. They allow the agent to perform actions.\n* **Retrievers:** Attached to specific guidelines via `guideline.attach_retriever()`. They provide external data context only when that specific guideline is relevant.\n\n### Engine Hooks\nHooks allow for deep integration into the engine's processing pipeline. They are registered via `EngineHooks`.\n\n* **`on_message_generated`:** Intercept the agent's response before it reaches the customer. Returning `p.EngineHookResult.BAIL` allows a hook to suppress or replace the generated message.\n* **`on_acknowledged`:** Triggered when the engine acknowledges a new event.\n* **Context Access:** Hooks receive an `EngineContext` providing access to the session state, tracer, and event emitter.\n\n---\n\n## Canned Responses\n\nCanned responses provide templates for consistent agent output.\n\n* **Templates:** Support variables (e.g., `\"Hello, {user}!\"`).\n* **Field Providers:** Guidelines can define a `canned_response_field_provider`—an async function that supplies data to fill template variables at runtime.\n* **Dependencies:** Canned responses can have `field_dependencies`. If a required field is unavailable (e.g., no tool provided the data), the response is automatically disqualified.\n\n## Tags and Scoping\n\nThe SDK uses a tagging system to manage relationships across different entity types.\n* **Custom Tags:** Created via `server.create_tag(\"name\")`.\n* **Tag Relationships:** Tags can `prioritize_over` or `depend_on` guidelines and journeys, allowing for group-based behavior control.\n* **Logic Semantics:** When depending on a tag, `p.AnyOf(tag=...)` specifies that at least one member of the tag group must be active, whereas a bare tag requires all members to match.","other-tests":"# Other — tests\n\n# Testing Infrastructure\n\nThe `tests` module provides the core infrastructure, fixtures, and utility functions required to perform unit, integration, and end-to-end testing of the Parlant system. It focuses on providing a transient, high-performance environment that mimics production behavior without requiring persistent storage or external service dependencies.\n\n## Core Architecture: The Test Container\n\nThe testing environment is centered around a `lagom` dependency injection container defined in `tests/conftest.py`. This container wires the system's interfaces to transient, in-memory implementations.\n\n### Transient Adapters\nTo ensure test isolation and speed, the container replaces persistent storage with transient versions:\n- **Database:** `TransientDocumentDatabase` is used for all stores (Agents, Guidelines, Sessions, etc.).\n- **Vector DB:** `TransientVectorDatabase` handles embeddings for the `GlossaryStore`, `JourneyStore`, and `CapabilityStore`.\n- **NLP:** Uses `EmcieService` by default, but wraps generators in caching layers.\n\n### The `container` Fixture\nThe `container` fixture is the primary entry point for most tests. It initializes the `BackgroundTaskService`, sets up all core stores, and registers `SchematicGenerator` instances for every schema used by the `AlphaEngine`.\n\n```mermaid\ngraph TD\n subgraph Fixtures\n C[container] --> T[tracer]\n C --> L[logger]\n C --> CO[cache_options]\n end\n subgraph Transient_Services\n C --> AS[AgentStore]\n C --> GS[GuidelineStore]\n C --> SS[SessionStore]\n C --> SR[ServiceRegistry]\n end\n SR --> NLP[NLPService]\n NLP --> SG[SchematicGenerators]\n```\n\n## LLM Generation and Caching\n\nTesting LLM-heavy workflows is expensive and slow. The module includes a sophisticated caching mechanism for `SchematicGenerator` results.\n\n### `CachedSchematicGenerator`\nThis wrapper intercepts calls to `generate()`. It creates a unique hash based on the prompt and hints.\n- **Cache Hit:** Returns a serialized `SchematicGenerationResult` from a local JSON file (`schematic_generation_test_cache.json`).\n- **Cache Miss:** Executes the real LLM call and persists the result to the cache.\n\n**Usage:**\nCaching is enabled by default. To bypass the cache for a specific test run, use the CLI flag:\n```bash\npytest --no-cache\n```\n\n### Semantic Assertions\nThe `nlp_test(context, condition)` utility allows for \"fuzzy\" assertions. It uses an LLM to determine if a specific condition holds true given a context, which is useful for verifying agent responses where exact string matching is impossible.\n\n## Mock Service Integration\n\nThe module provides utilities to simulate external services that the agent might interact with via tools.\n\n### OpenAPI and MCP Servers\n- `run_openapi_server(app)`: Spins up a transient FastAPI instance on a random port to test OpenAPI service integration.\n- `run_mcp_server(tools)`: Starts a Model Context Protocol (MCP) server.\n- `run_service_server(tools)`: Runs a Parlant `PluginServer` for testing SDK-based tool services.\n\n### Port Management\nThe `get_random_port()` and `is_port_available()` utilities ensure that mock servers do not collide during parallel test execution.\n\n## Entity Creation Helpers\n\n`tests/test_utilities.py` contains high-level wrappers for common setup tasks. These functions handle the boilerplate of interacting with multiple stores.\n\n| Function | Description |\n| :--- | :--- |\n| `create_agent` | Creates an agent with a default engine configuration. |\n| `create_guideline` | Creates a guideline and optionally associates it with a local tool. |\n| `create_session` | Initializes a session between an agent and a customer. |\n| `post_message` | Simulates a customer message and optionally waits for the agent's response. |\n| `read_reply` | Retrieves the latest AI-generated message from a session. |\n\n## Mock Tool Library\n\n`tests/tool_utilities.py` contains a library of pre-defined tools used to verify engine logic, tool-calling accuracy, and parameter parsing.\n\n- **Simple Tools:** `add`, `multiply`, `check_fruit_price`.\n- **Complex Types:** `set_a_bbq_appointment` (tests `datetime` and `Enum` parsing).\n- **Stateful Mocks:** `get_account_balance`, `transfer_money`.\n- **Contextual Tools:** `recommend_drink` (logic based on boolean flags).\n\nThese tools are typically registered via `LocalToolService` during tests to verify that the `AlphaEngine` can correctly identify, sequence, and execute tool calls based on guidelines.\n\n## Execution Hooks\n\nThe `JournalingEngineHooks` class is used to inspect the internal state of the `AlphaEngine` during execution. It captures the `EngineContext` for every trace ID, allowing tests to assert on:\n- Which guidelines were matched.\n- Which tools were considered.\n- The internal reasoning steps of the engine.","other-transcripts":"# Other — transcripts\n\n# Transcripts: Loading Animation\n\nThe `transcripts/loading.txt` module serves as a static asset within the chat application's transcript system. It provides a standardized text-based representation of a loading state, typically used when the system is processing a request or awaiting a response from an AI model or backend service.\n\n## Overview\n\nThis module is a non-executable text resource. Unlike functional modules in the codebase, it does not contain logic, classes, or function definitions. Instead, it acts as a template or placeholder used by the UI layer to signal asynchronous activity to the user.\n\n## Content and Structure\n\nThe module consists of a single string:\n`A loading animation for a chat application.`\n\nIn the context of a chat transcript, this string is used to:\n1. **Represent Latency:** Occupy the space where a message will eventually appear.\n2. **UI Consistency:** Ensure that the \"loading\" state is documented and consistent across different transcript exports or logs.\n\n## Integration Pattern\n\nWhile the module has no incoming or outgoing code calls (as verified by the call graph), it is typically consumed by the frontend rendering engine or a transcript parser. \n\n### Typical Consumption Flow\n1. **State Trigger:** The application initiates an asynchronous fetch (e.g., a user sends a message).\n2. **Placeholder Injection:** The system retrieves the content of `loading.txt`.\n3. **Rendering:** The UI displays the text (or a visual animation mapped to this text identifier) within the chat bubble area.\n4. **Replacement:** Once the actual message transcript is received, the loading state is unmounted and replaced with the final content.\n\n## Developer Notes\n\n- **Static Nature:** This file is a raw text asset. Do not attempt to import it as a JavaScript/TypeScript module unless using a raw-loader or similar build-tool plugin.\n- **Customization:** If the visual representation of the loading state needs to change at the transcript level, this file serves as the central point for that text definition.","other":"# Other\n\n# Project Infrastructure and Lifecycle\n\nThe **Other** module group serves as the foundational layer for the Parlant framework. It encompasses the project's governance standards, build configurations, automation scripts, and the comprehensive testing infrastructure required to maintain a production-ready agentic harness.\n\n## Architecture and Governance\n\nThe project's structural integrity is governed by a set of core standards and architectural patterns:\n\n* **Development Standards**: [CLAUDE.md](CLAUDE.md) defines the Hexagonal Architecture (Ports and Adapters) pattern, ensuring that [Core](core.md) logic remains decoupled from external [Adapters](adapters.md).\n* **Legal and Contribution**: [DCO.md](DCO.md) establishes the Developer Certificate of Origin for contributions, while the [README.md](README.md) introduces the **Contextual Matching Engine**, the central component for conversational governance.\n* **Structural Analysis**: The [graphify-out](graphify-out.md) module provides a meta-documentation layer, mapping the semantic relationships between the system's 7,000+ nodes and 70,000+ edges.\n\n## Build and Configuration\n\nThe development environment and package lifecycle are managed through standardized configuration files:\n\n* **Package Management**: [pyproject.toml](pyproject.toml) defines the project metadata, dependencies (optimized for the `uv` manager), and CLI entry points for the `parlant` command.\n* **Code Quality**: Static analysis is enforced via [mypy.ini](mypy.ini) (strict type checking) and [ruff.toml](ruff.toml) (linting and formatting), ensuring consistency across the Python 3.12 codebase.\n* **LLM Manifest**: [llms.txt](llms.txt) provides an LLM-friendly blueprint of the framework's patterns, focusing on Guidelines, Journeys, and Tools.\n\n## Automation and SDK Generation\n\nA suite of scripts and tools automates the transition from source code to distributable assets:\n\n* **Repository Management**: The [scripts](scripts.md) module handles environment initialization, versioning, and multi-platform publishing.\n* **SDK and Documentation**: [Fern](fern.md) consumes the OpenAPI definitions generated by the [API](api.md) module to produce idiomatic TypeScript and Python SDKs, as well as the public documentation portal.\n* **CI Optimization**: The [ci](ci.md) module provides utility scripts to manage disk space on GitHub Actions runners during intensive build processes.\n\n## Testing and Validation\n\nParlant employs a multi-layered testing strategy to ensure reliability in both deterministic and stochastic (AI-driven) scenarios:\n\n* **Infrastructure**: The [tests](tests.md) module provides a `lagom` dependency injection container that swaps persistent [Adapters](adapters.md) for transient, in-memory versions.\n* **Execution**: [pytest.ini](pytest.ini) configures the async environment and BDD features, while [pytest_stochastics.json](pytest_stochastics.json) manages success thresholds for probabilistic AI tests.\n* **End-to-End**: The [e2e](e2e.md) module validates the interaction between the server, CLI, and external [Modules](modules.md) (MCP/SDK tools) in sandboxed environments.\n\n```mermaid\ngraph TD\n subgraph \"Development & Standards\"\n CLAUDE[CLAUDE.md] --> Patterns[Hexagonal Architecture]\n RUFF[ruff.toml] --> Quality[Linting/Formatting]\n MYPY[mypy.ini] --> Quality\n end\n\n subgraph \"Build & Distribution\"\n PYPROJ[pyproject.toml] --> SCRIPTS[scripts]\n SCRIPTS --> FERN[Fern SDK Gen]\n FERN --> SDK[parlant.sdk]\n end\n\n subgraph \"Runtime & UI\"\n CORE[core] --> API[api]\n API --> UI[parlant UI]\n API --> ADAPTERS[adapters]\n end\n\n subgraph \"Validation\"\n TESTS[tests] --> E2E[e2e]\n STOCH[pytest_stochastics.json] --> E2E\n end\n\n Quality --> SCRIPTS\n Patterns --> CORE\n SDK --> E2E\n```\n\n## Core System Integration\n\nThe framework's functionality is exposed through three primary layers:\n1. **The Engine**: [Core](core.md) logic and [Adapters](adapters.md) handle the heavy lifting of guideline matching and state persistence.\n2. **The Interface**: The [API](api.md) provides RESTful endpoints, which are consumed by the [SDK](sdk.md) for programmatic use and the [parlant](parlant.md) React-based chat UI for human interaction.\n3. **The Assets**: Static resources like [transcripts](transcripts.md) and [data](data.md) fixtures support the UI and testing suites respectively.","overview":"# parlant — Wiki\n\n# Welcome to Parlant\n\nParlant is an open-source **Agentic Behavior Modeling (ABM) Engine**. It serves as a sophisticated interaction control harness for customer-facing AI agents. Unlike traditional frameworks that rely on rigid state machines or unpredictable prompt engineering, Parlant uses structured behavior models to ensure agents remain consistent, helpful, and within defined operational boundaries.\n\nBy layering semantic constraints and structured reasoning over Large Language Models (LLMs), Parlant transforms unpredictable text generators into reliable business-grade agents.\n\n## High-Level Architecture\n\nParlant is designed using a modular architecture that separates the conversational interface from the underlying reasoning and data persistence layers.\n\n```mermaid\ngraph TD\n User((User/Client)) --> SDK[SDK & API Layer]\n SDK --> Sessions[Messaging & Sessions]\n Sessions --> Reasoning[AI Reasoning Engine]\n Reasoning --> Behavior[Behavioral Customization]\n Reasoning --> Tools[Tooling & Integration]\n Reasoning --> NLP[NLP & LLM Adapters]\n Behavior --> Persistence[(Persistence Layer)]\n Tools --> External[External Services]\n```\n\n## Core Concepts\n\nTo get started with the codebase, it is helpful to understand the primary pillars of the system:\n\n* **The Interaction Loop**: Conversations are managed within [Messaging & Sessions](messaging-sessions.md). Unlike simple request-response cycles, Parlant uses an asynchronous, event-driven timeline that supports multi-message bursts and proactive agent behavior.\n* **Behavioral Modeling**: Instead of monolithic prompts, agent behavior is defined through [Behavioral Customization](behavioral-customization.md). This includes **Guidelines** (logic and constraints) and [Journeys & State Management](journeys-state-management.md) which guide the agent toward specific goals while remaining adaptive to natural conversation.\n* **The Reasoning Core**: The [AI Reasoning Engine](ai-reasoning-engine.md) is the \"brain\" of the system. It coordinates between the user's intent, the agent's defined guidelines, and available [Tooling & Service Integration](tooling-service-integration.md) to generate governed responses.\n* **Safety and Governance**: Every interaction is passed through the [Evaluation & Moderation](evaluation-moderation.md) module, which provides real-time input filtering and automated auditing of agent instructions to ensure technical and ethical soundness.\n\n## Getting Started\n\n### Installation\nParlant requires **Python 3.10 to 3.14**. You can install the core engine via pip:\n\n```bash\npip install parlant\n```\n\nFor specific NLP providers (like Cerebras or specialized LLMs), you can install the corresponding extras:\n```bash\npip install parlant[cerebras]\n```\n\n### System Foundation\nThe entire framework is supported by a robust [Infrastructure & Observability](infrastructure-observability.md) layer that manages the FastAPI lifecycle and system health. Data integrity is maintained by the [Persistence & Data Layer](persistence-data-layer.md), which abstracts document and vector databases to support everything from local development to cloud-scale production.\n\nFor developers looking to extend the system or integrate it into existing applications, the [SDK & Integration](sdk-integration.md) module provides the necessary high-level abstractions and delivery mechanisms.\n\n## Project Standards\nWe follow a hexagonal architecture (Ports and Adapters) to ensure the core logic remains decoupled from external dependencies. For detailed coding standards and architectural patterns used in this repository, please refer to the development guidelines in the [Infrastructure](infrastructure-observability.md) and project governance documentation.","persistence-data-layer-adapters":"# Persistence & Data Layer — adapters\n\n# Persistence & Data Layer — Adapters\n\nThe Persistence Adapter layer provides production-ready implementations for Parlant's storage interfaces. By default, Parlant uses transient or local file-based storage. These adapters allow you to swap those implementations for managed cloud services like **Snowflake** (for document/state storage) and **Qdrant** (for vector/semantic storage).\n\n## Architecture Overview\n\nParlant separates the storage logic into two main categories:\n1. **Document Stores**: Handle structured state like sessions, customers, and context variables.\n2. **Vector Stores**: Handle embedding-based data like glossary terms, canned responses, and agent capabilities.\n\nAdapters plug into the system via the `configure_container` hook, replacing the default transient implementations with persistent backends.\n\n```mermaid\ngraph TD\n subgraph Core Stores\n SS[SessionStore]\n CS[CustomerStore]\n GS[GlossaryStore]\n end\n\n subgraph Adapters\n SD[SnowflakeDocumentDatabase]\n QD[QdrantDatabase]\n end\n\n SS --> SD\n CS --> SD\n GS --> QD\n \n SD --> Snowflake[(Snowflake)]\n QD --> Qdrant[(Qdrant)]\n```\n\n---\n\n## Snowflake Persistence Adapter\n\nThe Snowflake adapter enables long-term persistence of conversation state, allowing Parlant deployments to remain stateless while sessions and customer data survive restarts.\n\n### Key Components\n- **`SnowflakeDocumentDatabase`**: The primary engine that manages connections and query execution. It uses the `snowflake-connector-python`.\n- **Table Prefixing**: To prevent collisions between different stores (e.g., Sessions vs. Customers), the adapter uses a `table_prefix` (e.g., `PARLANT_SESSIONS_`).\n\n### Supported Stores\nThe following stores are typically backed by Snowflake:\n- `SessionDocumentStore`\n- `CustomerDocumentStore`\n- `ContextVariableDocumentStore`\n\n### Configuration\nAuthentication is handled via environment variables. The adapter supports both standard password authentication and OAuth tokens.\n\n| Variable | Description |\n| :--- | :--- |\n| `SNOWFLAKE_ACCOUNT` | Account locator (e.g., `abc-xy123`). |\n| `SNOWFLAKE_USER` | Authentication username. |\n| `SNOWFLAKE_PASSWORD` | Password (omit if using OAuth). |\n| `SNOWFLAKE_TOKEN` | OAuth access token (triggers OAuth mode). |\n| `SNOWFLAKE_WAREHOUSE` | Compute warehouse for queries. |\n| `SNOWFLAKE_DATABASE` | Target database. |\n| `SNOWFLAKE_SCHEMA` | Target schema. |\n\n---\n\n## Qdrant Vector Database Adapter\n\nThe Qdrant adapter provides persistent vector storage, replacing the default in-memory vector search. This is critical for agents that rely on large glossaries or extensive sets of canned responses.\n\n### Key Components\n- **`QdrantDatabase`**: Manages the connection to either a local Qdrant instance (via file path) or Qdrant Cloud (via URL/API Key).\n- **Collection Management**: Collections are automatically namespaced by the embedder type (e.g., `glossary_OpenAITextEmbedding3Large`). This ensures that if you change your embedding model, the system correctly identifies that a new vector index is required.\n\n### Supported Stores\nThe following stores utilize the `QdrantDatabase` through their respective `VectorStore` implementations:\n- `GlossaryVectorStore`\n- `CannedResponseVectorStore`\n- `CapabilityVectorStore`\n- `JourneyVectorStore`\n\n### Operational Behavior\n- **Auto-Sync**: Collections automatically synchronize when schemas or embedders change.\n- **Payload Indexing**: While local mode is supported for development, Qdrant Cloud or a dedicated server is recommended for production to utilize payload indexes for filtered searches.\n- **Windows Support**: Includes automatic handling for file locks when running in local mode on Windows.\n\n---\n\n## Integration Pattern\n\nBoth adapters are integrated into the Parlant `Server` using the `configure_container` pattern. Because these adapters manage external resources, they must be handled within an `AsyncExitStack` to ensure connections are closed gracefully during shutdown.\n\n### Implementation Example\n\n```python\nasync def configure_container(container: p.Container) -> p.Container:\n container = container.clone()\n \n # 1. Initialize the Database Adapter\n snowflake_db = await EXIT_STACK.enter_async_context(\n SnowflakeDocumentDatabase(\n logger=container[p.Logger],\n table_prefix=\"PARLANT_SESSIONS_\",\n )\n )\n\n # 2. Bind the Store to the Adapter\n session_store = p.SessionDocumentStore(database=snowflake_db, allow_migration=True)\n \n # 3. Register in the Container\n container[p.SessionStore] = await EXIT_STACK.enter_async_context(session_store)\n \n return container\n```\n\n### Lifecycle Management\nWhen using these adapters, the application lifecycle should follow this flow:\n1. Initialize an `AsyncExitStack`.\n2. Pass the `configure_container` function to the `parlant.sdk.Server`.\n3. Inside `configure_container`, use `enter_async_context` to register the adapters.\n4. Call `stack.aclose()` during the application's final shutdown phase to release database connections and file locks.","persistence-data-layer-parlant":"# Persistence & Data Layer — parlant\n\n# Persistence & Data Layer — parlant\n\nThe persistence layer provides a unified abstraction for document-based and vector-based storage. It allows the core logic of Parlant to remain agnostic of the underlying database technology, supporting local development (JSON, Transient), production-grade document stores (MongoDB, Snowflake), and specialized vector search engines (Chroma, Qdrant, MongoDB Atlas).\n\n## Architecture Overview\n\nThe module is divided into two primary hierarchies: **Document Databases** for structured state and **Vector Databases** for semantic search.\n\n```mermaid\ngraph TD\n subgraph Core Interfaces\n DB[DocumentDatabase]\n VDB[VectorDatabase]\n end\n\n subgraph Document Adapters\n JSON[JSONFileDocumentDatabase]\n Mongo[MongoDocumentDatabase]\n Snow[SnowflakeDocumentDatabase]\n Trans[TransientDocumentDatabase]\n end\n\n subgraph Vector Adapters\n Chroma[ChromaDatabase]\n MV[MongoVectorDatabase]\n Qdrant[QdrantDatabase]\n end\n\n JSON -.-> DB\n Mongo -.-> DB\n Snow -.-> DB\n Trans -.-> DB\n\n Chroma -.-> VDB\n MV -.-> VDB\n Qdrant -.-> VDB\n```\n\n---\n\n## Document Databases\n\nDocument databases implement the `DocumentDatabase` and `DocumentCollection` interfaces. They support CRUD operations, complex filtering via `Where` clauses, and cursor-based pagination.\n\n### JSON & Transient Adapters\n* **`JSONFileDocumentDatabase`**: Persists data to a single JSON file. It uses a `ReaderWriterLock` to ensure thread-safe asynchronous I/O via `aiofiles`. Data is flushed to disk on every write operation.\n* **`TransientDocumentDatabase`**: An in-memory implementation. It is primarily used for unit testing and ephemeral sessions where persistence is not required.\n\n### MongoDB Adapter\nThe `MongoDocumentDatabase` maps collections directly to MongoDB collections. It utilizes `pymongo`'s asynchronous driver. \n* **Index Management**: Automatically ensures indexes on `creation_utc` and `id` for efficient pagination.\n* **Codec Options**: Uses `CodecOptions` to map MongoDB documents directly to the provided schema types.\n\n### Snowflake Adapter\nThe `SnowflakeDocumentDatabase` implements a document-store pattern on top of Snowflake's relational engine using the `VARIANT` data type.\n* **Schema**: Tables consist of `ID`, `VERSION`, `CREATION_UTC`, and a `DATA` (VARIANT) column.\n* **Query Translation**: The `_WhereTranslator` class converts MongoDB-style `Where` filters into SQL. It maps top-level fields (like `id`) to columns and nested fields to JSON paths (e.g., `DATA:\"user\":\"name\"`).\n* **Identifier Sanitization**: Automatically sanitizes collection names to valid Snowflake identifiers using `_sanitize_identifier`.\n\n---\n\n## Vector Databases\n\nVector databases extend storage capabilities to include semantic similarity search. They manage the relationship between raw document content and their high-dimensional embeddings.\n\n### Chroma Adapter\nChroma is used for local persistent vector storage.\n* **Dual-Collection Strategy**: For every logical collection, Chroma maintains an `_unembedded` collection (Source of Truth) and an `_embedded` collection (for search).\n* **Consistency**: The `_index_collection` method syncs these collections, re-embedding documents only when their `checksum` changes.\n* **Distance Metric**: Configured to use `cosine` similarity by default.\n\n### MongoDB Atlas Vector Search\nThe `MongoVectorDatabase` leverages MongoDB Atlas's `$vectorSearch` capabilities.\n* **Index Readiness**: Unlike standard indexes, Atlas vector indexes are built asynchronously. The adapter includes a `_wait_for_index_ready` polling mechanism to ensure the database is queryable after collection creation.\n* **Search Pipeline**: Executes similarity searches using an aggregation pipeline with `$vectorSearch` and `$addFields` to project the `vectorSearchScore`.\n\n### Qdrant Adapter\nA high-performance adapter supporting both local path-based storage and remote cloud instances.\n* **ID Mapping**: Since Qdrant requires specific ID formats, the adapter uses `_string_id_to_int` (a SHA-256 based hash) to map Parlant's `ObjectId` to Qdrant-compatible integers.\n* **Retry Logic**: Implements `_retry_on_timeout_async` with exponential backoff to handle transient network issues or lock contention on Windows systems.\n\n---\n\n## Key Data Patterns\n\n### 1. Document Loading & Migration\nAll `get_collection` methods accept a `document_loader` (often `identity_loader`). This function is called for every document retrieved during initialization.\n* **Schema Evolution**: If the loader modifies a document (e.g., adding missing fields), the adapter automatically updates the record in the database.\n* **Failed Migrations**: If a document fails to load or migrate, it is moved to a specialized `failed_migrations` collection to prevent data loss while allowing the application to continue.\n\n### 2. Filtering (`Where` Clauses)\nFilters are structured as mappings, supporting operators like `$eq`, `$gt`, `$in`, and logical operators `$and` / `$or`.\n* **In-Memory Filtering**: Used by JSON and Transient adapters via `matches_filters`.\n* **Native Filtering**: MongoDB and Vector adapters translate these filters into native query DSLs for performance.\n\n### 3. Pagination\nPagination is standardized across all adapters using a `Cursor` object containing `creation_utc` and `id`.\n* **Sort Order**: Documents are always sorted by `creation_utc` (primary) and `id` (tiebreaker).\n* **Logic**: To find the next page, the adapters query for documents where `(creation_utc > cursor.utc) OR (creation_utc == cursor.utc AND id > cursor.id)`.\n\n### 4. Concurrency Control\nAdapters that manage local state (JSON, Chroma, Transient) utilize a `ReaderWriterLock`. \n* **Reader Lock**: Acquired during `find` and `find_one` operations.\n* **Writer Lock**: Acquired during `insert_one`, `update_one`, and `delete_one` to prevent data corruption during state mutations.","persistence-data-layer":"# Persistence & Data Layer\n\n# Persistence & Data Layer\n\nThe Persistence & Data Layer provides a decoupled architecture for managing Parlant's state and semantic data. By separating abstract storage interfaces from concrete database implementations, the system supports a range of environments—from volatile in-memory storage for testing to distributed cloud databases for production.\n\n## Architecture Overview\n\nThe layer is organized into two primary sub-modules:\n\n1. **[Persistence & Data Layer — parlant](parlant.md)**: Defines the core abstractions (`DocumentDatabase` and `VectorDatabase`) and common utilities. It ensures the application logic remains agnostic of the underlying storage technology.\n2. **[Persistence & Data Layer — adapters](adapters.md)**: Contains the production-ready implementations of the core interfaces, including drivers for Snowflake, MongoDB, Qdrant, and Chroma.\n\n```mermaid\ngraph TD\n subgraph Core Abstractions [parlant]\n DD[DocumentDatabase Interface]\n VD[VectorDatabase Interface]\n Common[Common Filtering & Helpers]\n end\n\n subgraph Concrete Adapters [adapters]\n Snowflake[SnowflakeDocumentDatabase]\n Mongo[MongoVectorDatabase]\n Chroma[ChromaVectorDatabase]\n Transient[Transient/In-Memory Adapters]\n JSON[JSONFileDocumentDatabase]\n end\n\n DD --> Snowflake\n DD --> JSON\n DD --> Transient\n VD --> Mongo\n VD --> Chroma\n VD --> Transient\n```\n\n## Key Storage Categories\n\n### Document Storage\nUsed for structured, schema-based data such as user sessions, customer profiles, and context variables. \n* **Core Interface:** `DocumentDatabase`\n* **Primary Adapters:** `SnowflakeDocumentDatabase` for enterprise persistence and `JSONFileDocumentDatabase` for local development.\n* **Key Workflow:** Operations like `update_one` utilize internal serialization and SQL/JSON rendering logic (e.g., `_build_where_clause` in Snowflake) to map application objects to persistent records.\n\n### Vector Storage\nUsed for high-dimensional embedding data required for semantic search, such as glossary terms, agent capabilities, and canned responses.\n* **Core Interface:** `VectorDatabase`\n* **Primary Adapters:** `QdrantVectorDatabase`, `ChromaVectorDatabase`, and `MongoVectorDatabase`.\n* **Key Workflow:** The system uses `get_or_create_collection` to handle automatic collection initialization, metadata indexing, and document migration. Semantic queries are processed through `find_similar_documents`, which abstracts distance calculations and similarity thresholds.\n\n## Cross-Module Integration\n\nThe sub-modules interact through a dependency injection pattern, typically initialized via a `configure_container` hook. \n\n* **Filtering Logic:** The `parlant` module provides `matches_filters` and `vector_database_helper.py`, which adapters use to ensure consistent query behavior across different database engines.\n* **Initialization & Migration:** Adapters implement specialized logic (like `_ensure_vector_index` in MongoDB or `_migrate_documents` in Snowflake) to satisfy the lifecycle requirements defined by the core interfaces.\n* **Error Handling:** Common execution flows, such as `_execute` and `_ensure_connection`, provide a unified way to handle database-specific connectivity issues while exposing a clean API to the rest of the application.","sdk-integration-advanced":"# SDK & Integration — advanced\n\n# SDK & Integration — Advanced\n\nParlant is designed around the **Open/Closed Principle**, allowing developers to extend engine behavior without modifying the core source code. This is achieved through two primary mechanisms: **Engine Hooks** for intercepting the execution pipeline and **Dependency Injection** for overriding internal components.\n\n## Engine Hooks\n\nEngine hooks allow you to inject custom logic into specific stages of the agent's response generation process. By registering hook functions, you can inspect data, modify payloads, or terminate the standard execution flow.\n\n### Hook Lifecycle and Control Flow\n\nHooks receive a `p.LoadedContext`, which provides access to the current interaction, session event emitters, tracers, and loggers. Every hook must return a `p.EngineHookResult` to determine the next step in the pipeline:\n\n* `p.EngineHookResult.CALL_NEXT`: Continues the process to the next hook or the default engine logic.\n* `p.EngineHookResult.BAIL`: Stops the current process. This is used when a hook has already handled the response (e.g., a manual override) or when a security/compliance check fails.\n\n### Common Hook Points\n\nThe `p.EngineHooks` object contains several lists of callbacks. Key hook points include:\n\n| Hook | Description |\n| :--- | :--- |\n| `on_acknowledged` | Triggered after the engine acknowledges a new customer message. Ideal for early interceptions (e.g., simple greetings). |\n| `on_message_generated` | Triggered after the LLM or engine has produced a response but before it is sent. Used for compliance and filtering. |\n\n### Example: Interception and Compliance\n\n```python\nimport parlant.sdk as p\n\nasync def intercept_greeting(ctx: p.LoadedContext, payload: Any, exc: Exception | None) -> p.EngineHookResult:\n # Check if the message is just a greeting\n if is_greeting(ctx.interaction.last_customer_message):\n await ctx.session_event_emitter.emit_message_event(\n trace_id=ctx.tracer.trace_id,\n data=\"Hello! How can I help you today?\",\n )\n return p.EngineHookResult.BAIL # Skip standard LLM generation\n return p.EngineHookResult.CALL_NEXT\n\nasync def check_compliance(ctx: p.LoadedContext, payload: Any, exc: Exception | None) -> p.EngineHookResult:\n # payload contains the generated message string\n if not is_compliant(payload):\n return p.EngineHookResult.BAIL # Prevent sending\n return p.EngineHookResult.CALL_NEXT\n```\n\n## Dependency Injection (DI)\n\nParlant uses a central `p.Container` to manage its internal components. You can use DI to replace entire subsystems—such as the guideline evaluator or the message generator—with custom implementations.\n\n### Configuration vs. Initialization\n\nThere are two phases for interacting with the DI container:\n\n1. **`configure_container`**: Used to **register** or **override** components. This happens before the container is \"frozen.\" You return a modified `p.Container`.\n2. **`initialize_container`**: Used to **access** or **modify** existing instances. This happens after all components are registered but before the server starts processing requests.\n\n```python\nasync def configure_container(container: p.Container) -> p.Container:\n # Register a custom implementation of an internal service\n # container.register(MyCustomEvaluator)\n return container\n\nasync def initialize_container(container: p.Container) -> None:\n # Access a component to adjust its internal state or log its setup\n evaluator = container.get(GuidelineEvaluator)\n evaluator.set_mode(\"strict\")\n```\n\n## Server Integration\n\nTo apply hooks and container configurations, pass them as arguments when instantiating the `p.Server`.\n\n```python\nasync def configure_hooks(hooks: p.EngineHooks) -> p.EngineHooks:\n hooks.on_acknowledged.append(intercept_greeting)\n hooks.on_message_generated.append(check_compliance)\n return hooks\n\nasync def main():\n async with p.Server(\n configure_hooks=configure_hooks,\n configure_container=configure_container,\n initialize_container=initialize_container,\n ) as server:\n await server.serve_forever()\n```\n\n## Architecture Overview\n\nThe following diagram illustrates how hooks and the container integrate into the server lifecycle:\n\n```mermaid\ngraph TD\n Start[Server Start] --> ConfCont[configure_container]\n ConfCont --> InitCont[initialize_container]\n InitCont --> Running((Server Running))\n \n Running --> MsgIn[Message Received]\n MsgIn --> HookAck[on_acknowledged Hooks]\n HookAck -- BAIL --> End[End Interaction]\n HookAck -- CALL_NEXT --> Engine[Engine Processing]\n \n Engine --> HookGen[on_message_generated Hooks]\n HookGen -- BAIL --> End\n HookGen -- CALL_NEXT --> MsgOut[Message Sent]\n MsgOut --> End\n```\n\n## Advanced Use Cases\n\n* **Custom Model Evaluation**: Replace the default LLM-based guideline evaluation with a specialized local model (e.g., BERT) for performance or cost optimization.\n* **Cross-Cutting Concerns**: Wrap engine components to add custom OpenTelemetry spans, detailed audit logging, or real-time monitoring.\n* **Canned Response Logic**: Override the default \"no-match\" behavior to redirect users to a human agent or a specific help document when no guidelines apply.\n* **Hybrid Generation**: Use Parlant's tool execution and guideline matching, but pipe the final context into a proprietary message generation pipeline.","sdk-integration-parlant":"# SDK & Integration — parlant\n\n# SDK & Integration — parlant\n\nThe `parlant.sdk` module provides the primary high-level interface for developers to build, configure, and deploy AI agents. It abstracts the complexity of the underlying core engine, persistence layers, and NLP services into a declarative, developer-friendly API.\n\n## Overview\n\nThe SDK is designed around the concept of a **Server** that orchestrates **Agents**. Agents are governed by **Guidelines** (rules) and **Journeys** (structured state machines). The SDK handles dependency injection via `lagom`, manages the lifecycle of integrated tool servers, and provides hooks for real-time interaction logic.\n\n## Core Components\n\n### The Server\nThe `Server` class is the central entry point. It manages the environment, database connections, and the lifecycle of the Parlant engine.\n\n* **Initialization**: Typically started via `start_parlant`. It configures the `NLPService` (e.g., OpenAI, Anthropic, Azure) and sets up the `PluginServer` for integrated tools.\n* **Context Management**: Uses `contextvars` and `asyncio` to maintain state across requests.\n* **Entity Management**: Provides methods to create and retrieve `Agent`, `Customer`, `Tag`, and `Variable` objects.\n\n### Agents\nAn `Agent` represents the AI persona. It is the container for guidelines, journeys, and context variables.\n* **Creation**: `server.create_agent(name=\"...\")`.\n* **Capabilities**: Agents can be assigned `Capability` objects to define specific functional domains.\n\n### Guidelines and Relationships\nGuidelines are the primary way to control agent behavior. A `Guideline` consists of a `condition` (when it applies) and an `action` (what the agent should do).\n\nThe SDK emphasizes **Relationships** to resolve conflicts and define logic flow:\n* `prioritize_over`/`exclude`: Resolves conflicts when multiple guidelines match.\n* `depend_on`: Ensures a guideline only activates if another entity is active.\n* `entail`: Links the logic of one guideline to another.\n\n### Journeys\nJourneys allow for structured, multi-step interactions, functioning as a managed state machine.\n\n* **States**:\n * `InitialJourneyState`: The entry point.\n * `ChatJourneyState`: Represents a conversational turn.\n * `ToolJourneyState`: Represents a state where a specific tool must be invoked.\n * `ForkJourneyState`: A conditional branching point.\n* **Transitions**: Defined via `transition_to`, which can be triggered by natural language conditions.\n* **Sub-journeys**: Journeys can be nested, allowing complex flows to be modularized.\n\n```mermaid\ngraph TD\n Server --> Agent\n Agent --> Guidelines\n Agent --> Journeys\n Journeys --> States\n States --> Transitions\n Transitions --> States\n Guidelines -.-> Relationships\n Relationships -.-> Journeys\n```\n\n## Context and Variables\nThe SDK provides a robust system for managing stateful data through `Variable` and `Customer` objects.\n\n* **Variables**: Can be scoped to a specific `Customer`, a `Tag` (group), an `Agent`, or `Global`.\n* **Customer Metadata**: The `CustomerMetadata` class provides async-aware access to persistent customer attributes, allowing agents to \"remember\" user-specific details across sessions.\n\n## Integration: Tools and Retrievers\n\n### Tools\nTools are external functions the agent can call. The SDK supports:\n* **Integrated Tools**: Defined using the `@tool` decorator and hosted on the internal `PluginServer`.\n* **External Tools**: Referenced via `ToolId` for services hosted elsewhere.\n\n### Retrievers\nRetrievers are specialized functions used to fetch data during the inference process.\n* **RetrieverContext**: Provides the retriever with access to the current `Session`, `Agent`, `Customer`, and `Interaction` history.\n* **DeferredRetriever**: A pattern allowing a retriever to start work early (e.g., during acknowledgment) but defer the final data return until the message generation phase, when more context is available.\n\n## NLP Services\nThe `NLPServices` class provides static factory methods to initialize various LLM providers. Supported providers include:\n* `openai`, `anthropic`, `azure`, `gemini`, `vertex`\n* `ollama`, `mistral`, `deepseek` (for local or specialized deployments)\n* `litellm` (for universal proxying)\n\n## Execution Flow: Guideline Matching\nWhen an interaction occurs, the SDK follows a specific evaluation flow:\n1. **Matching**: The engine identifies relevant Guidelines and Journey states based on the conversation.\n2. **Custom Matchers**: Developers can provide a `matcher` callback to override standard NLP matching with custom logic.\n3. **Hooks**: \n * `on_selected`: Triggered when a guideline is chosen by the engine.\n * `on_message`: Triggered when the engine is about to generate a message based on a guideline.\n4. **Canned Responses**: If `CompositionMode` is set to `STRICT` or `COMPOSITED`, the engine uses templates associated with the matched guidelines/states.\n\n## Error Handling\n* `SDKError`: Base class for all SDK exceptions.\n* `NLPServiceConfigurationError`: Raised when environment variables or provider settings are missing.\n* `AuthorizationException`: Raised during rate limiting or policy violations.","sdk-integration-production":"# SDK & Integration — production\n\n# SDK & Integration — Production\n\nThe Parlant SDK and integration layer provide the tools necessary to embed AI agents into production environments. This module supports two primary integration paths: a high-level React widget for rapid deployment and a low-level TypeScript/Python SDK for custom implementations and complex human-in-the-loop workflows.\n\n## Integration Architecture\n\nParlant follows an event-driven architecture where the session is the single source of truth. Whether using the pre-built widget or a custom client, the integration relies on long-polling session events to synchronize state between the server and the UI.\n\n```mermaid\ngraph LR\n A[Frontend/Client] -- createEvent --> B(Parlant Server)\n B -- listEvents long-polling --> A\n B -- Tool Trigger --> C{Handoff Logic}\n C -- update session mode: manual --> B\n D[External Support System] -- createEvent source: human_agent --> B\n```\n\n## React Integration\n\nThe `parlant-chat-react` library is the fastest way to integrate. It handles session persistence, event polling, and UI state management out of the box.\n\n### The ParlantChatbox Component\nThe primary interface is the `ParlantChatbox` component. It can be used as an inline element or a floating popup.\n\n```jsx\n<ParlantChatbox\n server=\"http://localhost:8800\"\n agentId=\"your-agent-id\"\n float={true}\n classNames={{\n chatbox: \"custom-container\",\n agentMessage: \"ai-bubble\"\n }}\n/>\n```\n\n### Customization Hooks\nDevelopers can override default behavior using two main patterns:\n1. **`classNames`**: For CSS-based styling of wrappers, messages, and inputs.\n2. **`components`**: For functional replacement of UI elements like the `popupButton` or `agentMessage` rendering logic.\n\n## Custom Client Implementation\n\nFor non-React environments or highly bespoke UIs, use the `ParlantClient`. This requires manual management of the session lifecycle.\n\n### 1. Session Initialization\nSessions must be created to associate a customer with an agent.\n```typescript\nconst session = await client.sessions.create({\n agentId: \"agent-123\",\n customerId: \"customer-456\"\n});\n```\n\n### 2. The Event Loop (Long Polling)\nTo receive real-time updates, the client must implement a polling loop using `listEvents`. The `waitForData` parameter enables long-polling, reducing network overhead while maintaining responsiveness.\n\n```typescript\nconst events = await client.sessions.listEvents(sessionId, {\n minOffset: lastOffset,\n waitForData: 30, // Seconds to hold the connection\n kinds: [\"message\", \"status\"]\n});\n```\n\n### 3. Event Sources and Kinds\nThe integration must handle different event sources to distinguish between participants:\n* `customer`: Messages sent by the end-user.\n* `ai_agent`: Automated responses generated by Parlant.\n* `human_agent`: Messages sent by a human operator during handoff.\n* `human_agent_on_behalf_of_ai_agent`: Human messages styled as the AI to maintain a consistent persona.\n\n## Human Handoff & Manual Control\n\nParlant supports a \"Tier 1 Automation\" model where the AI handles standard inquiries and escalates complex issues to \"Tier 2\" human agents.\n\n### Switching to Manual Mode\nBy default, sessions are in `auto` mode. To stop the AI from responding and allow a human to take over, the session `mode` must be set to `manual`. This can be triggered in two ways:\n\n1. **Via Tool (AI-Initiated):** An agent can trigger its own handoff using a tool defined with `p.tool`.\n ```python\n return p.ToolResult(control={\"mode\": \"manual\"})\n ```\n2. **Via SDK (System-Initiated):** An external dashboard can force the session into manual mode.\n ```typescript\n await client.sessions.update(sessionId, { mode: \"manual\" });\n ```\n\n### External System Integration\nWhen integrating with platforms like Zendesk or HubSpot, Parlant should remain the authoritative record. \n* **Outbound:** When a human types in the external system, call `client.sessions.createEvent` with `source: \"human_agent\"`.\n* **Inbound:** The external system should poll `listEvents` just like the frontend client to display the AI's previous context and the customer's new messages.\n\n## Best Practices\n\n* **Offset Management:** Always track the `lastOffset` from events. When polling, set `minOffset` to `lastOffset + 1` to avoid duplicate processing.\n* **Status Events:** Monitor `kind: \"status\"` to display \"Agent is typing...\" or \"Processing...\" indicators, improving the perceived speed of the AI.\n* **Optimistic UI:** Avoid optimistic UI updates for messages. Wait for the event to return from the server via the polling loop to ensure the message was successfully processed and sequenced.\n* **Graceful Degradation:** Implement a retry strategy with exponential backoff for the `listEvents` loop to handle transient network failures.","sdk-integration":"# SDK & Integration\n\n# SDK & Integration\n\nThe SDK & Integration module provides the comprehensive toolkit required to build, deploy, and extend Parlant agents. It bridges the gap between the core engine and production environments by offering high-level abstractions for configuration, robust delivery mechanisms for client applications, and low-level hooks for behavioral customization.\n\n## Module Synergy\n\nThe integration layer is structured to support a progressive development workflow:\n\n1. **Definition**: Developers use the [parlant](parlant.md) sub-module to define the `Server` environment and configure `Agents` with `Guidelines` and `Journeys`.\n2. **Deployment**: The [production](production.md) sub-module provides the infrastructure to expose these agents via TypeScript/Python SDKs or a pre-built React widget, utilizing an event-driven architecture for real-time communication.\n3. **Extension**: For complex requirements, the [advanced](advanced.md) sub-module allows developers to intercept the execution pipeline using Engine Hooks or override internal components via Dependency Injection.\n\n```mermaid\ngraph TD\n subgraph \"parlant (Configuration)\"\n S[Server] --> A[Agents]\n A --> G[Guidelines & Journeys]\n end\n\n subgraph \"advanced (Extensibility)\"\n H[Engine Hooks] -.-> S\n DI[Dependency Injection] -.-> S\n end\n\n subgraph \"production (Delivery)\"\n S --> SDK[TS/Python SDKs]\n S --> W[React Widget]\n SDK <--> SE[Session Events]\n end\n```\n\n## Key Components\n\n### [parlant](parlant.md)\nThe primary entry point for agent orchestration. It manages the lifecycle of the `Server` class and uses `lagom` for internal dependency management. It is responsible for translating declarative rules into executable agent behavior.\n\n### [production](production.md)\nFocuses on the \"Human-in-the-loop\" and client-side integration. It treats the session as the single source of truth, using long-polling and event-driven patterns to synchronize state between the Parlant server and external frontends.\n\n### [advanced](advanced.md)\nProvides the \"Open/Closed\" extensibility layer. By utilizing `p.LoadedContext`, developers can implement custom logic within the response generation process without modifying the core SDK, allowing for sophisticated data inspection and flow control.","tooling-service-integration-concepts":"# Tooling & Service Integration — concepts\n\n# Tooling & Service Integration — Concepts\n\nParlant provides a guided approach to tool usage, tightly integrated with its guidance system. Unlike standard LLM tool-calling, Parlant tools are not left to the LLM's sole discretion; they are bound to specific guidelines that determine when and why a tool should execute.\n\n## Core Philosophy: Separation of Concerns\n\nParlant distinguishes between **business logic** (Tools) and **conversational behavior** (Guidelines).\n\n* **Tools:** Deterministic, programmatic logic written in code (e.g., API calls, database queries).\n* **Guidelines:** Natural-language instructions that define the conditions under which tools are invoked.\n\nThis separation allows developers to maintain robust API logic while business experts or prompt engineers refine the conversational UI independently.\n\n## Defining Tools\n\nA tool is a Python function decorated with `@p.tool`. It must accept a `p.ToolContext` as its first argument and return a `p.ToolResult`.\n\n```python\nimport parlant.sdk as p\n\n@p.tool\nasync def fetch_user_balance(context: p.ToolContext, account_id: str) -> p.ToolResult:\n \"\"\"Fetches the current balance for a specific account.\"\"\"\n balance = await my_api.get_balance(account_id)\n \n # Data must be JSON-serializable\n return p.ToolResult(data={\"balance\": balance, \"currency\": \"USD\"})\n```\n\n### Tool Context\nThe `p.ToolContext` provides metadata about the current execution environment:\n* `agent_id`, `customer_id`, `session_id`: Identifiers for the current interaction.\n* `emit_message(message: str)`: Sends an intermediate message to the user (useful for long-running tasks).\n* `emit_status(status: p.SessionStatus)`: Updates the session state.\n\nTo access server-level resources (like other agents or guidelines) within a tool, use the `ToolContextAccessor`:\n```python\nserver = p.ToolContextAccessor(context).server\nagent = await server.get_agent(id=context.agent_id)\n```\n\n## Connecting Tools to Agents\n\nTools are associated with agents via guidelines. This ensures tools are only called when specific conversational conditions are met.\n\n### Manual Association\nYou can explicitly define the condition and action that triggers a tool:\n```python\nawait agent.create_guideline(\n condition=\"The user asks for their account balance\",\n action=\"Retrieve the balance using the fetch_user_balance tool\",\n tools=[fetch_user_balance],\n)\n```\n\n### Implicit Association\nIf the tool's docstring clearly implies the action, you can attach it directly:\n```python\nawait agent.attach_tool(\n condition=\"The user asks for their account balance\",\n tool=fetch_user_balance\n)\n```\n\n## Tool Results and Session Lifespan\n\nThe `p.ToolResult` object manages how the output of a tool is handled by the agent.\n\n### Properties\n* **`data`**: The primary output. Required for the agent to understand the result and use it in future reasoning.\n* **`metadata`**: Optional dictionary for the frontend (e.g., source URLs, image links). The agent does not \"see\" this.\n* **`control`**: Directives for the engine.\n * `mode`: Set to `p.SessionMode.MANUAL` for human-handoff.\n * `lifespan`: Set to `p.Lifespan.RESPONSE` for transient data or `p.Lifespan.SESSION` (default) to persist the data in the conversation history.\n\n### Persistence\nBy default, tool results are saved to the session. This allows the agent to automatically parameterize subsequent tool calls. For example, if `get_products` returns a list of IDs, and the user selects one, the agent can automatically pass that ID to a `get_product_details` tool without explicit re-prompting.\n\n## Advanced Parameter Control\n\nParlant uses **Tool Insights** to bridge the gap between tool execution and message composition. If a tool cannot be called (e.g., missing arguments), the agent uses these insights to ask the user for the missing information.\n\n### ToolParameterOptions\nUse `Annotated` and `p.ToolParameterOptions` to fine-tune how the agent handles parameters:\n\n```python\nfrom typing import Annotated\n\n@p.tool\nasync def process_refund(\n context: p.ToolContext,\n order_id: Annotated[str, p.ToolParameterOptions(\n source=\"customer\",\n description=\"The 10-digit order reference number\",\n significance=\"Required to locate the transaction in our ledger\"\n )]\n) -> p.ToolResult:\n ...\n```\n\n| Option | Description |\n| :--- | :--- |\n| `source` | Specifies if the value should come from the `customer` or the `context`. |\n| `precedence` | Groups parameters to control the order in which the agent asks for them. |\n| `hidden` | If `True`, the agent will not mention this parameter to the user if it is missing. |\n| `choice_provider` | A callable that returns a dynamic list of valid options for the parameter. |\n\n## Execution Flow and Reevaluation\n\nParlant supports dynamic behavior where a tool's output triggers a change in guideline logic.\n\n```mermaid\ngraph TD\n A[User Message] --> B[Guideline Matcher]\n B --> C[Tool Execution]\n C --> D{Reevaluation?}\n D -- Yes --> B\n D -- No --> E[Message Composition]\n E --> F[Response to User]\n```\n\n### Guideline Reevaluation\nYou can instruct the agent to re-run the guideline matcher immediately after a tool executes. This is useful if the tool result (e.g., a low bank balance) should trigger a different set of behaviors (e.g., a warning guideline).\n\n```python\nawait guideline.reevaluate_after(my_tool)\n```\n\n## Parameter Constraints\n\nTo ensure type safety and valid inputs, Parlant supports three constraint mechanisms:\n1. **Enums:** For static, hard-coded choices.\n2. **Choice Providers:** For dynamic choices (e.g., fetching a list of the user's active subscriptions from a DB).\n3. **Pydantic Models:** For complex, nested data structures requiring validation.","tooling-service-integration-parlant":"# Tooling & Service Integration — parlant\n\n# Tooling & Service Integration — parlant\n\nThe **Tooling & Service Integration** module is the extensibility layer of Parlant. It enables agents to interact with external systems and defines \"Capabilities\"—high-level functional skills that agents can leverage during a session.\n\nThe module manages three primary integration types:\n1. **SDK (Plugins):** Native Python integrations using the Parlant SDK protocol.\n2. **MCP (Model Context Protocol):** Integration with third-party tool servers using the MCP standard.\n3. **OpenAPI:** (Deprecated) Integration via OpenAPI/Swagger specifications.\n\n---\n\n## Core Architecture\n\nThe integration architecture separates the definition of a tool from its execution environment.\n\n```mermaid\ngraph TD\n A[Agent/Engine] --> B[ServiceRegistry]\n B --> C[PluginClient - SDK]\n B --> D[MCPToolClient - MCP]\n B --> E[OpenAPIClient - Deprecated]\n C & D & E --> F[ToolService Interface]\n F --> G[Tool Definition]\n F --> H[Tool Execution]\n```\n\n### Tool Definition\nA `Tool` is a dataclass representing a unit of functionality. It includes:\n* **Parameters:** Defined via `ToolParameterDescriptor` (type, enum, description) and `ToolParameterOptions` (significance, source, hidden status).\n* **Overlap:** A `ToolOverlap` enum (`NONE`, `AUTO`, `ALWAYS`) that dictates how the engine handles multiple tools in the same context.\n* **Consequentiality:** A boolean flag indicating if the tool has significant side effects.\n\n### Tool Execution Context\nWhen a tool is called, it receives a `ToolContext`. This object provides:\n* **Identity:** `agent_id`, `session_id`, and `customer_id`.\n* **Emissions:** Methods to interact with the session directly without waiting for the tool to return (`emit_message`, `emit_status`, `emit_custom`).\n* **Plugin Data:** Arbitrary mapping for data passed through the engine that bypasses LLM evaluation.\n\n---\n\n## Service Integration Types\n\n### 1. SDK Services (Plugins)\nSDK services are the most robust integration type, supporting bidirectional communication and complex type handling.\n\n* **The `@tool` Decorator:** Used in plugin implementations to register functions. It automatically inspects Python type hints to generate `ToolParameterDescriptor` objects.\n* **Dynamic Choices:** Supports `choice_provider`, a callable that dynamically populates enums (e.g., fetching a list of active projects from a DB at runtime).\n* **Argument Casting:** The `cast_tool_argument` and `normalize_tool_arguments` functions handle the conversion of raw JSON inputs into Python types, including `datetime`, `Enum`, and Pydantic models.\n\n### 2. MCP (Model Context Protocol)\nThe `MCPToolClient` allows Parlant to act as an MCP host.\n* **Transport:** Uses `StreamableHttpTransport` via the `fastmcp` library.\n* **Resilience:** Implements an exponential backoff retry logic in `_connect` and session recovery in `_with_reconnect`.\n* **Type Mapping:** Maps MCP types (number, integer, string with formats like `date-time` or `uuid`) to Parlant's internal `ToolParameterType`.\n\n### 3. OpenAPI (Deprecated)\nThe `OpenAPIClient` parses OpenAPI 3.0 specifications. It maps HTTP operations to tools, where query parameters and JSON request bodies become tool parameters. \n*Note: This integration type is deprecated in favor of SDK services.*\n\n---\n\n## Capabilities\n\nCapabilities represent high-level skills or features (e.g., \"Reset Password\", \"Check Weather\"). Unlike raw tools, capabilities are optimized for discovery via semantic search.\n\n### Capability Storage & Retrieval\nThe `CapabilityVectorStore` manages capabilities using a dual-database approach:\n1. **Document Database:** Stores the structured metadata (`CapabilityDocument`).\n2. **Vector Database:** Stores embeddings of the capability's title, description, and \"signals\" (example user phrases).\n\n### Semantic Discovery\nThe `find_relevant_capabilities` method enables the engine to locate skills based on user intent:\n1. The input query is embedded using an `Embedder`.\n2. The system performs a similarity search across the `CapabilityVectorDocument` collection.\n3. Results are filtered by `available_capabilities` and ranked by distance.\n\n### Tagging System\nCapabilities can be associated with `TagId`s. This allows for logical grouping (e.g., tagging all capabilities belonging to a specific agent or department). The `CapabilityModule` ensures that tags are validated against the `AgentStore` or `TagStore` before association.\n\n---\n\n## Tool Execution Flow\n\nWhen the engine executes a tool, the following flow occurs within `parlant.core.tools`:\n\n1. **Validation:** `validate_tool_arguments` checks that all `required` parameters are present and no unknown arguments are provided.\n2. **Normalization:** `normalize_tool_arguments` iterates through the expected function signature.\n3. **Casting:** `cast_tool_argument` converts string/JSON inputs into the target Python types.\n * Lists are handled by `split_arg_list`, which supports both JSON arrays and comma-separated strings.\n4. **Execution:** The underlying function is called (locally or via RPC).\n5. **Result Handling:** The tool returns a `ToolResult`, which may contain:\n * `data`: The primary output.\n * `control`: Instructions for the engine (e.g., changing session `mode` or result `lifespan`).\n * `guidelines`: `TransientGuideline` objects that temporarily influence agent behavior for the current response.\n\n---\n\n## API Management\n\nThe module exposes REST endpoints via `parlant.api.services` and `parlant.api.capabilities`.\n\n* **Service Management:** `PUT /services/{name}` allows developers to register or update service configurations. Updating a service triggers a reconnection logic where the `ServiceRegistry` re-initializes the client.\n* **Capability Management:** Supports standard CRUD operations. The `PATCH /capabilities/{id}` endpoint allows for partial updates to titles, descriptions, or signals, and manages tag additions/removals via `CapabilityTagUpdateParamsDTO`.","tooling-service-integration":"# Tooling & Service Integration\n\n# Tooling & Service Integration\n\nThe **Tooling & Service Integration** module serves as Parlant’s extensibility layer, bridging the gap between natural language guidance and programmatic execution. It allows agents to interact with external systems through a governed framework that separates business logic from conversational behavior.\n\n## Architecture Overview\n\nThis module functions by mapping external technical interfaces into high-level **Capabilities** that an agent can understand and utilize.\n\n* **[Concepts](concepts.md):** Defines the governance model. It establishes the \"Separation of Concerns\" where **Tools** (deterministic code) are decoupled from **Guidelines** (natural language instructions). Guidelines act as the trigger mechanism, ensuring tools are only invoked under specific business conditions.\n* **[Parlant (Implementation)](parlant.md):** Provides the technical machinery for this integration. It manages the lifecycle of **Services** (SDK, MCP, or OpenAPI), handles the discovery of capabilities, and manages the execution flow, including argument normalization and validation.\n\n## How Sub-modules Work Together\n\nThe integration flow moves from abstract instructions to concrete execution:\n\n1. **Definition:** A developer registers a **Service** (via the `ServiceRegistry`) using the Parlant SDK or the Model Context Protocol (MCP).\n2. **Abstraction:** Individual functions within these services are exposed as **Tools**, which are then grouped into **Capabilities**.\n3. **Governance:** Using the logic defined in **Concepts**, these capabilities are bound to agents. The engine uses `GuidelineActionProposer` and `ToolRunningActionDetector` to determine if a tool should be used based on the conversation context.\n4. **Execution:** When an action is proposed, the module triggers the `call_tool` workflow. This involves `normalize_tool_arguments` and `cast_tool_argument` to ensure the LLM's string-based output matches the technical requirements of the underlying Python or API function.\n\n```mermaid\ngraph LR\n subgraph \"Behavioral Layer (Concepts)\"\n G[Guidelines] -->|Trigger| C[Capabilities]\n end\n\n subgraph \"Integration Layer (Parlant)\"\n C -->|Group| T[Tools]\n T -->|Provided by| S[Services]\n S --- SDK[Python SDK]\n S --- MCP[MCP Servers]\n end\n\n subgraph \"Execution Flow\"\n T -->|Normalize| Arg[Arguments]\n Arg -->|Invoke| Ext[External Systems]\n end\n```\n\n## Key Workflows\n\n* **Capability Discovery:** The system uses `list_capabilities` and `find_relevant_capabilities` to present the agent with a subset of available tools relevant to the current state of the conversation.\n* **Argument Normalization:** Before execution, the module runs `normalize_tool_arguments` to transform unstructured model output into the specific types (via `cast_tool_argument`) required by the service's signature.\n* **Service Management:** The `ServiceRegistry` handles the connection state for various integration types, ensuring that whether a tool is a local Python function or a remote MCP tool, the agent interacts with it through a unified interface."}; | |
| var TREE = [{"name":"Getting Started & Examples","slug":"getting-started-examples","files":["docs/quickstart/examples.md","docs/quickstart/installation.md","docs/quickstart/motivation.md","examples/healthcare.py","examples/travel_voice_agent.py"]},{"name":"Core Entities","slug":"core-entities","files":["docs/concepts/entities/agents.md","docs/concepts/entities/customers.md","src/parlant/api/agents.py","src/parlant/api/customers.py","src/parlant/api/tags.py","src/parlant/core/agents.py","src/parlant/core/customers.py","src/parlant/core/tags.py","src/parlant/core/app_modules/agents.py","src/parlant/core/app_modules/customers.py","src/parlant/core/app_modules/tags.py"]},{"name":"Messaging & Sessions","slug":"messaging-sessions","files":[],"children":[{"name":"Messaging & Sessions — concepts","slug":"messaging-sessions-concepts","files":["docs/concepts/sessions.md"]},{"name":"Messaging & Sessions — docs","slug":"messaging-sessions-docs","files":["docs/interactions.md"]},{"name":"Messaging & Sessions — parlant","slug":"messaging-sessions-parlant","files":["src/parlant/api/sessions.py","src/parlant/core/sessions.py","src/parlant/core/app_modules/sessions.py","src/parlant/core/emissions.py","src/parlant/core/emission/event_buffer.py","src/parlant/core/emission/event_publisher.py"]}]},{"name":"Behavioral Customization","slug":"behavioral-customization","files":[],"children":[{"name":"Behavioral Customization — concepts","slug":"behavioral-customization-concepts","files":["docs/concepts/customization/guidelines.md","docs/concepts/customization/glossary.md","docs/concepts/customization/relationships.md","docs/concepts/customization/canned-responses.md","docs/concepts/customization/variables.md","docs/concepts/customization/retrievers.md"]},{"name":"Behavioral Customization — parlant","slug":"behavioral-customization-parlant","files":["src/parlant/api/guidelines.py","src/parlant/api/glossary.py","src/parlant/api/relationships.py","src/parlant/api/canned_responses.py","src/parlant/api/context_variables.py","src/parlant/core/guidelines.py","src/parlant/core/glossary.py","src/parlant/core/relationships.py","src/parlant/core/canned_responses.py","src/parlant/core/context_variables.py","src/parlant/core/app_modules/guidelines.py","src/parlant/core/app_modules/glossary.py","src/parlant/core/app_modules/relationships.py","src/parlant/core/app_modules/canned_responses.py","src/parlant/core/app_modules/context_variables.py","src/parlant/core/guideline_tool_associations.py"]}]},{"name":"Journeys & State Management","slug":"journeys-state-management","files":["docs/concepts/customization/journeys.md","src/parlant/api/journeys.py","src/parlant/core/journeys.py","src/parlant/core/app_modules/journeys.py","src/parlant/core/journey_guideline_projection.py"]},{"name":"Tooling & Service Integration","slug":"tooling-service-integration","files":[],"children":[{"name":"Tooling & Service Integration — concepts","slug":"tooling-service-integration-concepts","files":["docs/concepts/customization/tools.md"]},{"name":"Tooling & Service Integration — parlant","slug":"tooling-service-integration-parlant","files":["src/parlant/api/services.py","src/parlant/api/capabilities.py","src/parlant/core/tools.py","src/parlant/core/capabilities.py","src/parlant/core/app_modules/capabilities.py","src/parlant/core/app_modules/services.py","src/parlant/core/services/tools/mcp_service.py","src/parlant/core/services/tools/openapi.py","src/parlant/core/services/tools/plugins.py","src/parlant/core/services/tools/service_registry.py"]}]},{"name":"AI Reasoning Engine","slug":"ai-reasoning-engine","files":[],"children":[{"name":"AI Reasoning Engine — production","slug":"ai-reasoning-engine-production","files":["docs/production/agentic-design.md"]},{"name":"AI Reasoning Engine — parlant","slug":"ai-reasoning-engine-parlant","files":["src/parlant/core/engines/alpha/engine.py","src/parlant/core/engines/alpha/engine_context.py","src/parlant/core/engines/alpha/entity_context.py","src/parlant/core/engines/alpha/hooks.py","src/parlant/core/engines/alpha/planners.py","src/parlant/core/engines/alpha/prompt_builder.py","src/parlant/core/engines/alpha/relational_resolver.py","src/parlant/core/engines/alpha/message_generator.py","src/parlant/core/engines/alpha/message_event_composer.py","src/parlant/core/engines/alpha/tool_event_generator.py","src/parlant/core/engines/alpha/canned_response_generator.py","src/parlant/core/engines/alpha/optimization_policy.py","src/parlant/core/engines/alpha/perceived_performance_policy.py","src/parlant/core/engines/alpha/utils.py","src/parlant/core/engines/alpha/planning/__init__.py","src/parlant/core/engines/alpha/guideline_matching/common.py","src/parlant/core/engines/alpha/guideline_matching/custom_guideline_matching_strategy.py","src/parlant/core/engines/alpha/guideline_matching/generic_guideline_matching_strategy_resolver.py","src/parlant/core/engines/alpha/guideline_matching/guideline_match.py","src/parlant/core/engines/alpha/guideline_matching/guideline_matcher.py","src/parlant/core/engines/alpha/guideline_matching/guideline_matching_context.py","src/parlant/core/engines/alpha/guideline_matching/generic/common.py","src/parlant/core/engines/alpha/guideline_matching/generic/disambiguation_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/generic_guideline_matching_strategy.py","src/parlant/core/engines/alpha/guideline_matching/generic/guideline_actionable_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/guideline_low_criticality_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/guideline_previously_applied_actionable_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/guideline_previously_applied_actionable_customer_dependent_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/observational_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/response_analysis_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/journey/journey_backtrack_check.py","src/parlant/core/engines/alpha/guideline_matching/generic/journey/journey_backtrack_node_selection.py","src/parlant/core/engines/alpha/guideline_matching/generic/journey/journey_next_step_selection.py","src/parlant/core/engines/alpha/guideline_matching/generic/journey/journey_node_selection_batch.py","src/parlant/core/engines/alpha/tool_calling/default_tool_call_batcher.py","src/parlant/core/engines/alpha/tool_calling/overlapping_tools_batch.py","src/parlant/core/engines/alpha/tool_calling/single_tool_batch.py","src/parlant/core/engines/alpha/tool_calling/tool_caller.py","src/parlant/core/engines/types.py","src/parlant/core/entity_cq.py","src/parlant/core/shots.py"]}]},{"name":"NLP & LLM Adapters","slug":"nlp-llm-adapters","files":[],"children":[{"name":"NLP & LLM Adapters — adapters","slug":"nlp-llm-adapters-adapters","files":["docs/adapters/nlp/azure.md","docs/adapters/nlp/ollama.md","docs/adapters/nlp/openrouter.md","docs/adapters/nlp/snowflake-cortex.md","docs/adapters/nlp/vertex.md"]},{"name":"NLP & LLM Adapters — advanced","slug":"nlp-llm-adapters-advanced","files":["docs/advanced/custom-llms.md"]},{"name":"NLP & LLM Adapters — parlant","slug":"nlp-llm-adapters-parlant","files":["src/parlant/adapters/nlp/anthropic_service.py","src/parlant/adapters/nlp/aws_service.py","src/parlant/adapters/nlp/azure_service.py","src/parlant/adapters/nlp/cerebras_service.py","src/parlant/adapters/nlp/common.py","src/parlant/adapters/nlp/deepseek_service.py","src/parlant/adapters/nlp/emcie_service.py","src/parlant/adapters/nlp/fireworks_service.py","src/parlant/adapters/nlp/gemini_service.py","src/parlant/adapters/nlp/hugging_face.py","src/parlant/adapters/nlp/lakera.py","src/parlant/adapters/nlp/litellm_service.py","src/parlant/adapters/nlp/mistral_service.py","src/parlant/adapters/nlp/modelscope_service.py","src/parlant/adapters/nlp/novita_service.py","src/parlant/adapters/nlp/ollama_service.py","src/parlant/adapters/nlp/openai_service.py","src/parlant/adapters/nlp/openrouter_service.py","src/parlant/adapters/nlp/qwen_service.py","src/parlant/adapters/nlp/snowflake_cortex_service.py","src/parlant/adapters/nlp/together_service.py","src/parlant/adapters/nlp/vertex_service.py","src/parlant/adapters/nlp/zhipu_service.py","src/parlant/core/nlp/embedding.py","src/parlant/core/nlp/generation.py","src/parlant/core/nlp/generation_info.py","src/parlant/core/nlp/moderation.py","src/parlant/core/nlp/policies.py","src/parlant/core/nlp/service.py","src/parlant/core/nlp/tokenization.py"]}]},{"name":"Persistence & Data Layer","slug":"persistence-data-layer","files":[],"children":[{"name":"Persistence & Data Layer — adapters","slug":"persistence-data-layer-adapters","files":["docs/adapters/persistence/snowflake.md","docs/adapters/vector_db/qdrant.md"]},{"name":"Persistence & Data Layer — parlant","slug":"persistence-data-layer-parlant","files":["src/parlant/adapters/db/json_file.py","src/parlant/adapters/db/mongo_db.py","src/parlant/adapters/db/snowflake_db.py","src/parlant/adapters/db/transient.py","src/parlant/adapters/vector_db/chroma.py","src/parlant/adapters/vector_db/mongo.py","src/parlant/adapters/vector_db/qdrant.py","src/parlant/adapters/vector_db/transient.py","src/parlant/core/persistence/common.py","src/parlant/core/persistence/data_collection.py","src/parlant/core/persistence/document_database.py","src/parlant/core/persistence/document_database_helper.py","src/parlant/core/persistence/vector_database.py","src/parlant/core/persistence/vector_database_helper.py"]}]},{"name":"Evaluation & Moderation","slug":"evaluation-moderation","files":[],"children":[{"name":"Evaluation & Moderation — advanced","slug":"evaluation-moderation-advanced","files":["docs/advanced/explainability.md"]},{"name":"Evaluation & Moderation — production","slug":"evaluation-moderation-production","files":["docs/production/input-moderation.md"]},{"name":"Evaluation & Moderation — parlant","slug":"evaluation-moderation-parlant","files":["src/parlant/api/evaluations.py","src/parlant/core/evaluations.py","src/parlant/core/app_modules/evaluations.py","src/parlant/core/services/indexing/behavioral_change_evaluation.py","src/parlant/core/services/indexing/common.py","src/parlant/core/services/indexing/customer_dependent_action_detector.py","src/parlant/core/services/indexing/guideline_action_proposer.py","src/parlant/core/services/indexing/guideline_agent_intention_proposer.py","src/parlant/core/services/indexing/guideline_continuous_proposer.py","src/parlant/core/services/indexing/journey_reachable_nodes_evaluation.py","src/parlant/core/services/indexing/relative_action_proposer.py","src/parlant/core/services/indexing/tool_running_action_detector.py"]}]},{"name":"Infrastructure & Observability","slug":"infrastructure-observability","files":[],"children":[{"name":"Infrastructure & Observability — production","slug":"infrastructure-observability-production","files":["docs/production/api-hardening.md"]},{"name":"Infrastructure & Observability — parlant","slug":"infrastructure-observability-parlant","files":["src/parlant/api/app.py","src/parlant/api/authorization.py","src/parlant/api/common.py","src/parlant/api/health.py","src/parlant/api/logs.py","src/parlant/core/application.py","src/parlant/core/async_utils.py","src/parlant/core/background_tasks.py","src/parlant/core/common.py","src/parlant/core/event_loop_monitor.py","src/parlant/core/loggers.py","src/parlant/core/meter.py","src/parlant/core/tracer.py","src/parlant/core/app_modules/common.py","src/parlant/core/health/__init__.py","src/parlant/core/health/engine_view.py","src/parlant/core/health/event_loop_view.py","src/parlant/core/health/nlp_view.py","src/parlant/core/health/reporter.py","src/parlant/adapters/loggers/opentelemetry.py","src/parlant/adapters/loggers/websocket.py","src/parlant/adapters/meter/opentelemetry.py","src/parlant/adapters/tracing/opentelemetry.py"]}]},{"name":"SDK & Integration","slug":"sdk-integration","files":[],"children":[{"name":"SDK & Integration — advanced","slug":"sdk-integration-advanced","files":["docs/advanced/contributing.md","docs/advanced/engine-extensions.md"]},{"name":"SDK & Integration — production","slug":"sdk-integration-production","files":["docs/production/custom-frontend.md","docs/production/human-handoff.md"]},{"name":"SDK & Integration — parlant","slug":"sdk-integration-parlant","files":["src/parlant/sdk.py"]}]},{"name":"Chat UI","slug":"chat-ui","files":["src/parlant/api/chat/components.json","src/parlant/api/chat/index.html","src/parlant/api/chat/manifest.webmanifest","src/parlant/api/chat/public/fonts/Inter/inter.css","src/parlant/api/chat/public/fonts/ibm-plex-mono/ibm-plex-mono.css","src/parlant/api/chat/public/fonts/ubuntu-mono/ubuntu_mono.css","src/parlant/api/chat/public/fonts/ubuntu-sans/ubuntu_sans.css","src/parlant/api/chat/setupTests.ts","src/parlant/api/chat/src/App.css","src/parlant/api/chat/src/App.tsx","src/parlant/api/chat/src/index.css","src/parlant/api/chat/src/main.tsx","src/parlant/api/chat/src/store.ts","src/parlant/api/chat/src/components/agents-list/agent-list.module.scss","src/parlant/api/chat/src/components/agents-list/agent-list.tsx","src/parlant/api/chat/src/components/avatar/avatar.tsx","src/parlant/api/chat/src/components/canned-response/canned-response.tsx","src/parlant/api/chat/src/components/canned-responses/canned-responses.tsx","src/parlant/api/chat/src/components/chat-header/chat-header.tsx","src/parlant/api/chat/src/components/chatbot/chatbot.tsx","src/parlant/api/chat/src/components/dark-mode-toggle/dark-mode-toggle.tsx","src/parlant/api/chat/src/components/error-boundary/error-boundary.tsx","src/parlant/api/chat/src/components/gradient-button/gradient-button.module.scss","src/parlant/api/chat/src/components/gradient-button/gradient-button.tsx","src/parlant/api/chat/src/components/header-wrapper/header-wrapper.tsx","src/parlant/api/chat/src/components/log-filters/log-filters.tsx","src/parlant/api/chat/src/components/markdown/markdown.tsx","src/parlant/api/chat/src/components/message-details/empty-state.tsx","src/parlant/api/chat/src/components/message-details/filter-tabs.tsx","src/parlant/api/chat/src/components/message-details/flag-message.tsx","src/parlant/api/chat/src/components/message-details/indexeddb-data.tsx","src/parlant/api/chat/src/components/message-details/message-details-header.tsx","src/parlant/api/chat/src/components/message-details/message-details.tsx","src/parlant/api/chat/src/components/message-details/message-log.tsx","src/parlant/api/chat/src/components/message-details/message-logs.tsx","src/parlant/api/chat/src/components/message/draft-bubble.tsx","src/parlant/api/chat/src/components/message/message-bubble.tsx","src/parlant/api/chat/src/components/message/message-relative-time.tsx","src/parlant/api/chat/src/components/message/message.module.scss","src/parlant/api/chat/src/components/message/message.tsx","src/parlant/api/chat/src/components/progress-logo/progress-logo.tsx","src/parlant/api/chat/src/components/session-list/session-list-item/session-list-item.module.scss","src/parlant/api/chat/src/components/session-list/session-list-item/session-list-item.tsx","src/parlant/api/chat/src/components/session-list/session-list.tsx","src/parlant/api/chat/src/components/session-view/date-header/date-header.tsx","src/parlant/api/chat/src/components/session-view/session-view-header/session-view-header.tsx","src/parlant/api/chat/src/components/session-view/session-view.module.scss","src/parlant/api/chat/src/components/session-view/session-view.tsx","src/parlant/api/chat/src/components/ui/button.tsx","src/parlant/api/chat/src/components/ui/checkbox.tsx","src/parlant/api/chat/src/components/ui/custom/copy-text.tsx","src/parlant/api/chat/src/components/ui/custom/line-no-div.tsx","src/parlant/api/chat/src/components/ui/custom/spacer.tsx","src/parlant/api/chat/src/components/ui/custom/tooltip.tsx","src/parlant/api/chat/src/components/ui/dialog.tsx","src/parlant/api/chat/src/components/ui/drawer.tsx","src/parlant/api/chat/src/components/ui/dropdown-menu.tsx","src/parlant/api/chat/src/components/ui/input.tsx","src/parlant/api/chat/src/components/ui/radio-group.tsx","src/parlant/api/chat/src/components/ui/resizable.tsx","src/parlant/api/chat/src/components/ui/select.tsx","src/parlant/api/chat/src/components/ui/sheet.tsx","src/parlant/api/chat/src/components/ui/skeleton.tsx","src/parlant/api/chat/src/components/ui/sonner.tsx","src/parlant/api/chat/src/components/ui/switch.tsx","src/parlant/api/chat/src/components/ui/textarea.tsx","src/parlant/api/chat/src/components/ui/tooltip.tsx","src/parlant/api/chat/src/components/virtual-scroll/virtual-scroll.tsx","src/parlant/api/chat/src/hooks/useDialog.tsx","src/parlant/api/chat/src/hooks/useFetch.tsx","src/parlant/api/chat/src/hooks/useLocalStorage.ts","src/parlant/api/chat/src/hooks/useQuestionDialog.tsx","src/parlant/api/chat/src/hooks/useWebSocket.ts","src/parlant/api/chat/src/lib/broadcast-channel.ts","src/parlant/api/chat/src/lib/utils.ts","src/parlant/api/chat/src/utils/api.ts","src/parlant/api/chat/src/utils/date.tsx","src/parlant/api/chat/src/utils/interfaces.tsx","src/parlant/api/chat/src/utils/logs.ts","src/parlant/api/chat/src/utils/methods.tsx","src/parlant/api/chat/src/utils/obj.tsx","src/parlant/api/chat/src/utils/sounds.ts"]},{"name":"Other","slug":"other","files":[],"children":[{"name":"Other — CLAUDE.md","slug":"other-claude-md","files":["CLAUDE.md"]},{"name":"Other — DCO.md","slug":"other-dco-md","files":["DCO.md"]},{"name":"Other — README.md","slug":"other-readme-md","files":["README.md"]},{"name":"Other — graphify-out","slug":"other-graphify-out","files":["graphify-out/GRAPH_REPORT.md","graphify-out/cost.json","graphify-out/graph.html","graphify-out/manifest.json"]},{"name":"Other — transcripts","slug":"other-transcripts","files":["graphify-out/transcripts/loading.txt"]},{"name":"Other — llms.txt","slug":"other-llms-txt","files":["llms.txt"]},{"name":"Other — mypy.ini","slug":"other-mypy-ini","files":["mypy.ini"]},{"name":"Other — pyproject.toml","slug":"other-pyproject-toml","files":["pyproject.toml"]},{"name":"Other — pytest.ini","slug":"other-pytest-ini","files":["pytest.ini"]},{"name":"Other — pytest_stochastics.json","slug":"other-pytest-stochastics-json","files":["pytest_stochastics.json"]},{"name":"Other — ruff.toml","slug":"other-ruff-toml","files":["ruff.toml"]},{"name":"Other — ci","slug":"other-ci","files":["scripts/ci/github_action_ubuntu_2404_free_space.sh"]},{"name":"Other — fern","slug":"other-fern","files":["scripts/fern/docs.yml","scripts/fern/fern.config.json","scripts/fern/generators.yml"]},{"name":"Other — scripts","slug":"other-scripts","files":["scripts/generate_client_sdk.py","scripts/initialize_repo.py","scripts/install_packages.py","scripts/lint.py","scripts/publish.py","scripts/utils.py","scripts/version.py"]},{"name":"Other — parlant","slug":"other-parlant","files":["src/parlant/api/chat/eslint.config.js","src/parlant/api/chat/package.json","src/parlant/api/chat/postcss.config.js","src/parlant/api/chat/public/fonts/ibm-plex-mono/static/OFL.txt","src/parlant/api/chat/public/fonts/ubuntu-mono/static/UFL.txt","src/parlant/api/chat/public/fonts/ubuntu-sans/README.txt","src/parlant/api/chat/public/fonts/ubuntu-sans/UFL.txt","src/parlant/api/chat/tailwind.config.js","src/parlant/api/chat/tsconfig.app.json","src/parlant/api/chat/tsconfig.app.tsbuildinfo","src/parlant/api/chat/tsconfig.json","src/parlant/api/chat/tsconfig.node.json","src/parlant/api/chat/tsconfig.node.tsbuildinfo","src/parlant/api/chat/vite.config.ts","src/parlant/core/version.py","src/parlant/py.typed"]},{"name":"Other — tests","slug":"other-tests","files":["tests/__init__.py","tests/conftest.py","tests/test_utilities.py","tests/tool_utilities.py"]},{"name":"Other — adapters","slug":"other-adapters","files":["tests/adapters/db/test_chroma.py","tests/adapters/db/test_json_file.py","tests/adapters/db/test_mongodb.py","tests/adapters/db/test_snowflake_db.py","tests/adapters/nlp/test_azure_service.py","tests/adapters/nlp/test_litellm_service.py","tests/adapters/nlp/test_openrouter_service.py","tests/adapters/nlp/test_qwen_service.py","tests/adapters/nlp/test_zhipu_service.py","tests/adapters/vector_db/test_mongo_vector.py","tests/adapters/vector_db/test_qdrant.py","tests/adapters/vector_db/test_transient.py"]},{"name":"Other — api","slug":"other-api","files":["tests/api/conftest.py","tests/api/test_agents.py","tests/api/test_app.py","tests/api/test_authorization.py","tests/api/test_canned_responses.py","tests/api/test_capabilities.py","tests/api/test_context_variables.py","tests/api/test_customers.py","tests/api/test_evaluations.py","tests/api/test_glossary.py","tests/api/test_guidelines.py","tests/api/test_journeys.py","tests/api/test_relationships.py","tests/api/test_services.py","tests/api/test_sessions.py","tests/api/test_tags.py","tests/api/test_websocket_logger.py"]},{"name":"Other — core","slug":"other-core","files":["tests/core/common/engines/alpha/steps/agents.py","tests/core/common/engines/alpha/steps/canned_responses.py","tests/core/common/engines/alpha/steps/capabilities.py","tests/core/common/engines/alpha/steps/context_variables.py","tests/core/common/engines/alpha/steps/customers.py","tests/core/common/engines/alpha/steps/engines.py","tests/core/common/engines/alpha/steps/events.py","tests/core/common/engines/alpha/steps/guidelines.py","tests/core/common/engines/alpha/steps/journeys.py","tests/core/common/engines/alpha/steps/sessions.py","tests/core/common/engines/alpha/steps/tags.py","tests/core/common/engines/alpha/steps/terms.py","tests/core/common/engines/alpha/steps/tools.py","tests/core/common/engines/alpha/utils.py","tests/core/common/utils.py","tests/core/conftest.py","tests/core/stable/engines/alpha/features/baseline/capabilities.feature","tests/core/stable/engines/alpha/features/baseline/context_variables.feature","tests/core/stable/engines/alpha/features/baseline/conversation.feature","tests/core/stable/engines/alpha/features/baseline/errors.feature","tests/core/stable/engines/alpha/features/baseline/glossary.feature","tests/core/stable/engines/alpha/features/baseline/journeys.feature","tests/core/stable/engines/alpha/features/baseline/moderation.feature","tests/core/stable/engines/alpha/features/baseline/proactivity.feature","tests/core/stable/engines/alpha/features/baseline/relationships.feature","tests/core/stable/engines/alpha/features/baseline/strict_canned_responses.feature","tests/core/stable/engines/alpha/features/baseline/strict_canned_responses_capabilities.feature","tests/core/stable/engines/alpha/features/baseline/supervision.feature","tests/core/stable/engines/alpha/features/baseline/tools.feature","tests/core/stable/engines/alpha/features/baseline/triggered_utterances.feature","tests/core/stable/engines/alpha/features/user_stories/conversation.feature","tests/core/stable/engines/alpha/test_baseline_scenarios.py","tests/core/stable/engines/alpha/test_context_variable_loading.py","tests/core/stable/engines/alpha/test_disambiguation_batch.py","tests/core/stable/engines/alpha/test_generic_response_analysis.py","tests/core/stable/engines/alpha/test_guideline_actionable_batch.py","tests/core/stable/engines/alpha/test_guideline_low_criticality_batch.py","tests/core/stable/engines/alpha/test_guideline_matcher.py","tests/core/stable/engines/alpha/test_journey_node_selection.py","tests/core/stable/engines/alpha/test_mcp.py","tests/core/stable/engines/alpha/test_previously_applied_actionable_batch.py","tests/core/stable/engines/alpha/test_previously_applied_actionable_customer_dependent_batch.py","tests/core/stable/engines/alpha/test_relational_resolver.py","tests/core/stable/engines/alpha/test_tool_caller.py","tests/core/stable/engines/alpha/test_user_story_scenarios.py","tests/core/stable/nlp/test_embedding.py","tests/core/stable/nlp/test_generation.py","tests/core/stable/persistence/test_matches_filters.py","tests/core/stable/services/indexing/test_agent_intention_proposer.py","tests/core/stable/services/indexing/test_continuous_guideline_proposer.py","tests/core/stable/services/indexing/test_customer_dependent_action_detector.py","tests/core/stable/services/indexing/test_guideline_action_proposer.py","tests/core/stable/services/indexing/test_relative_action_step_proposer.py","tests/core/stable/services/indexing/test_tool_running_action_detector.py","tests/core/stable/services/tools/test_mcp_client.py","tests/core/stable/services/tools/test_openapi.py","tests/core/stable/services/tools/test_plugin_client.py","tests/core/stable/test_application.py","tests/core/stable/test_capability_vector_store.py","tests/core/stable/test_entity_cq.py","tests/core/stable/test_health_reporter.py","tests/core/stable/test_journey_guideline_projection.py","tests/core/stable/test_relationships.py","tests/core/test_cancellation_suppression_latch.py","tests/core/test_id_generator.py","tests/core/unstable/engines/alpha/features/baseline/conversation.feature","tests/core/unstable/engines/alpha/features/baseline/fluid_canned_responses.feature","tests/core/unstable/engines/alpha/features/baseline/glossary.feature","tests/core/unstable/engines/alpha/features/baseline/strict_canned_responses.feature","tests/core/unstable/engines/alpha/features/baseline/supervision.feature","tests/core/unstable/engines/alpha/features/baseline/tools.feature","tests/core/unstable/engines/alpha/features/user_stories/conversation.feature","tests/core/unstable/engines/alpha/test_agent_intention_proposer.py","tests/core/unstable/engines/alpha/test_baseline_scenarios.py","tests/core/unstable/engines/alpha/test_disambiguation_batch.py","tests/core/unstable/engines/alpha/test_guideline_matcher.py","tests/core/unstable/engines/alpha/test_journey_node_selection.py","tests/core/unstable/engines/alpha/test_previously_applied_actionable_batch.py","tests/core/unstable/engines/alpha/test_user_story_scenarios.py"]},{"name":"Other — data","slug":"other-data","files":["tests/data/get_products_by_type_data.json"]},{"name":"Other — e2e","slug":"other-e2e","files":["tests/e2e/conftest.py","tests/e2e/test_client_cli_via_api.py","tests/e2e/test_server_cli.py","tests/e2e/test_utilities.py"]},{"name":"Other — modules","slug":"other-modules","files":["tests/modules/bank.py","tests/modules/mcp_parrot.py","tests/modules/tech_store.py"]},{"name":"Other — sdk","slug":"other-sdk","files":["tests/sdk/conftest.py","tests/sdk/test_agents.py","tests/sdk/test_canned_responses.py","tests/sdk/test_current_entities.py","tests/sdk/test_customers.py","tests/sdk/test_dynamic_composition_mode.py","tests/sdk/test_glossary.py","tests/sdk/test_guidelines.py","tests/sdk/test_journeys.py","tests/sdk/test_labels.py","tests/sdk/test_planners.py","tests/sdk/test_retrievers.py","tests/sdk/test_sdk_validation.py","tests/sdk/test_server.py","tests/sdk/test_tools.py","tests/sdk/test_variables.py","tests/sdk/utils.py"]}]}]; | |
| var META = {"fromCommit":"d39edb4e0d76d64af9baddf63236e895ca206d2d","generatedAt":"2026-05-05T00:25:30.204Z","model":"gemini-3-flash-preview","moduleFiles":{"Getting Started & Examples":["docs/quickstart/examples.md","docs/quickstart/installation.md","docs/quickstart/motivation.md","examples/healthcare.py","examples/travel_voice_agent.py"],"Core Entities":["docs/concepts/entities/agents.md","docs/concepts/entities/customers.md","src/parlant/api/agents.py","src/parlant/api/customers.py","src/parlant/api/tags.py","src/parlant/core/agents.py","src/parlant/core/customers.py","src/parlant/core/tags.py","src/parlant/core/app_modules/agents.py","src/parlant/core/app_modules/customers.py","src/parlant/core/app_modules/tags.py"],"Messaging & Sessions":["docs/concepts/sessions.md","docs/interactions.md","src/parlant/api/sessions.py","src/parlant/core/sessions.py","src/parlant/core/app_modules/sessions.py","src/parlant/core/emissions.py","src/parlant/core/emission/event_buffer.py","src/parlant/core/emission/event_publisher.py"],"Messaging & Sessions — concepts":["docs/concepts/sessions.md"],"Messaging & Sessions — docs":["docs/interactions.md"],"Messaging & Sessions — parlant":["src/parlant/api/sessions.py","src/parlant/core/sessions.py","src/parlant/core/app_modules/sessions.py","src/parlant/core/emissions.py","src/parlant/core/emission/event_buffer.py","src/parlant/core/emission/event_publisher.py"],"Behavioral Customization":["docs/concepts/customization/guidelines.md","docs/concepts/customization/glossary.md","docs/concepts/customization/relationships.md","docs/concepts/customization/canned-responses.md","docs/concepts/customization/variables.md","docs/concepts/customization/retrievers.md","src/parlant/api/guidelines.py","src/parlant/api/glossary.py","src/parlant/api/relationships.py","src/parlant/api/canned_responses.py","src/parlant/api/context_variables.py","src/parlant/core/guidelines.py","src/parlant/core/glossary.py","src/parlant/core/relationships.py","src/parlant/core/canned_responses.py","src/parlant/core/context_variables.py","src/parlant/core/app_modules/guidelines.py","src/parlant/core/app_modules/glossary.py","src/parlant/core/app_modules/relationships.py","src/parlant/core/app_modules/canned_responses.py","src/parlant/core/app_modules/context_variables.py","src/parlant/core/guideline_tool_associations.py"],"Behavioral Customization — concepts":["docs/concepts/customization/guidelines.md","docs/concepts/customization/glossary.md","docs/concepts/customization/relationships.md","docs/concepts/customization/canned-responses.md","docs/concepts/customization/variables.md","docs/concepts/customization/retrievers.md"],"Behavioral Customization — parlant":["src/parlant/api/guidelines.py","src/parlant/api/glossary.py","src/parlant/api/relationships.py","src/parlant/api/canned_responses.py","src/parlant/api/context_variables.py","src/parlant/core/guidelines.py","src/parlant/core/glossary.py","src/parlant/core/relationships.py","src/parlant/core/canned_responses.py","src/parlant/core/context_variables.py","src/parlant/core/app_modules/guidelines.py","src/parlant/core/app_modules/glossary.py","src/parlant/core/app_modules/relationships.py","src/parlant/core/app_modules/canned_responses.py","src/parlant/core/app_modules/context_variables.py","src/parlant/core/guideline_tool_associations.py"],"Journeys & State Management":["docs/concepts/customization/journeys.md","src/parlant/api/journeys.py","src/parlant/core/journeys.py","src/parlant/core/app_modules/journeys.py","src/parlant/core/journey_guideline_projection.py"],"Tooling & Service Integration":["docs/concepts/customization/tools.md","src/parlant/api/services.py","src/parlant/api/capabilities.py","src/parlant/core/tools.py","src/parlant/core/capabilities.py","src/parlant/core/app_modules/capabilities.py","src/parlant/core/app_modules/services.py","src/parlant/core/services/tools/mcp_service.py","src/parlant/core/services/tools/openapi.py","src/parlant/core/services/tools/plugins.py","src/parlant/core/services/tools/service_registry.py"],"Tooling & Service Integration — concepts":["docs/concepts/customization/tools.md"],"Tooling & Service Integration — parlant":["src/parlant/api/services.py","src/parlant/api/capabilities.py","src/parlant/core/tools.py","src/parlant/core/capabilities.py","src/parlant/core/app_modules/capabilities.py","src/parlant/core/app_modules/services.py","src/parlant/core/services/tools/mcp_service.py","src/parlant/core/services/tools/openapi.py","src/parlant/core/services/tools/plugins.py","src/parlant/core/services/tools/service_registry.py"],"AI Reasoning Engine":["docs/production/agentic-design.md","src/parlant/core/engines/alpha/engine.py","src/parlant/core/engines/alpha/engine_context.py","src/parlant/core/engines/alpha/entity_context.py","src/parlant/core/engines/alpha/hooks.py","src/parlant/core/engines/alpha/planners.py","src/parlant/core/engines/alpha/prompt_builder.py","src/parlant/core/engines/alpha/relational_resolver.py","src/parlant/core/engines/alpha/message_generator.py","src/parlant/core/engines/alpha/message_event_composer.py","src/parlant/core/engines/alpha/tool_event_generator.py","src/parlant/core/engines/alpha/canned_response_generator.py","src/parlant/core/engines/alpha/optimization_policy.py","src/parlant/core/engines/alpha/perceived_performance_policy.py","src/parlant/core/engines/alpha/utils.py","src/parlant/core/engines/alpha/planning/__init__.py","src/parlant/core/engines/alpha/guideline_matching/common.py","src/parlant/core/engines/alpha/guideline_matching/custom_guideline_matching_strategy.py","src/parlant/core/engines/alpha/guideline_matching/generic_guideline_matching_strategy_resolver.py","src/parlant/core/engines/alpha/guideline_matching/guideline_match.py","src/parlant/core/engines/alpha/guideline_matching/guideline_matcher.py","src/parlant/core/engines/alpha/guideline_matching/guideline_matching_context.py","src/parlant/core/engines/alpha/guideline_matching/generic/common.py","src/parlant/core/engines/alpha/guideline_matching/generic/disambiguation_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/generic_guideline_matching_strategy.py","src/parlant/core/engines/alpha/guideline_matching/generic/guideline_actionable_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/guideline_low_criticality_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/guideline_previously_applied_actionable_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/guideline_previously_applied_actionable_customer_dependent_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/observational_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/response_analysis_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/journey/journey_backtrack_check.py","src/parlant/core/engines/alpha/guideline_matching/generic/journey/journey_backtrack_node_selection.py","src/parlant/core/engines/alpha/guideline_matching/generic/journey/journey_next_step_selection.py","src/parlant/core/engines/alpha/guideline_matching/generic/journey/journey_node_selection_batch.py","src/parlant/core/engines/alpha/tool_calling/default_tool_call_batcher.py","src/parlant/core/engines/alpha/tool_calling/overlapping_tools_batch.py","src/parlant/core/engines/alpha/tool_calling/single_tool_batch.py","src/parlant/core/engines/alpha/tool_calling/tool_caller.py","src/parlant/core/engines/types.py","src/parlant/core/entity_cq.py","src/parlant/core/shots.py"],"AI Reasoning Engine — production":["docs/production/agentic-design.md"],"AI Reasoning Engine — parlant":["src/parlant/core/engines/alpha/engine.py","src/parlant/core/engines/alpha/engine_context.py","src/parlant/core/engines/alpha/entity_context.py","src/parlant/core/engines/alpha/hooks.py","src/parlant/core/engines/alpha/planners.py","src/parlant/core/engines/alpha/prompt_builder.py","src/parlant/core/engines/alpha/relational_resolver.py","src/parlant/core/engines/alpha/message_generator.py","src/parlant/core/engines/alpha/message_event_composer.py","src/parlant/core/engines/alpha/tool_event_generator.py","src/parlant/core/engines/alpha/canned_response_generator.py","src/parlant/core/engines/alpha/optimization_policy.py","src/parlant/core/engines/alpha/perceived_performance_policy.py","src/parlant/core/engines/alpha/utils.py","src/parlant/core/engines/alpha/planning/__init__.py","src/parlant/core/engines/alpha/guideline_matching/common.py","src/parlant/core/engines/alpha/guideline_matching/custom_guideline_matching_strategy.py","src/parlant/core/engines/alpha/guideline_matching/generic_guideline_matching_strategy_resolver.py","src/parlant/core/engines/alpha/guideline_matching/guideline_match.py","src/parlant/core/engines/alpha/guideline_matching/guideline_matcher.py","src/parlant/core/engines/alpha/guideline_matching/guideline_matching_context.py","src/parlant/core/engines/alpha/guideline_matching/generic/common.py","src/parlant/core/engines/alpha/guideline_matching/generic/disambiguation_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/generic_guideline_matching_strategy.py","src/parlant/core/engines/alpha/guideline_matching/generic/guideline_actionable_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/guideline_low_criticality_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/guideline_previously_applied_actionable_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/guideline_previously_applied_actionable_customer_dependent_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/observational_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/response_analysis_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/journey/journey_backtrack_check.py","src/parlant/core/engines/alpha/guideline_matching/generic/journey/journey_backtrack_node_selection.py","src/parlant/core/engines/alpha/guideline_matching/generic/journey/journey_next_step_selection.py","src/parlant/core/engines/alpha/guideline_matching/generic/journey/journey_node_selection_batch.py","src/parlant/core/engines/alpha/tool_calling/default_tool_call_batcher.py","src/parlant/core/engines/alpha/tool_calling/overlapping_tools_batch.py","src/parlant/core/engines/alpha/tool_calling/single_tool_batch.py","src/parlant/core/engines/alpha/tool_calling/tool_caller.py","src/parlant/core/engines/types.py","src/parlant/core/entity_cq.py","src/parlant/core/shots.py"],"NLP & LLM Adapters":["docs/adapters/nlp/azure.md","docs/adapters/nlp/ollama.md","docs/adapters/nlp/openrouter.md","docs/adapters/nlp/snowflake-cortex.md","docs/adapters/nlp/vertex.md","docs/advanced/custom-llms.md","src/parlant/adapters/nlp/anthropic_service.py","src/parlant/adapters/nlp/aws_service.py","src/parlant/adapters/nlp/azure_service.py","src/parlant/adapters/nlp/cerebras_service.py","src/parlant/adapters/nlp/common.py","src/parlant/adapters/nlp/deepseek_service.py","src/parlant/adapters/nlp/emcie_service.py","src/parlant/adapters/nlp/fireworks_service.py","src/parlant/adapters/nlp/gemini_service.py","src/parlant/adapters/nlp/hugging_face.py","src/parlant/adapters/nlp/lakera.py","src/parlant/adapters/nlp/litellm_service.py","src/parlant/adapters/nlp/mistral_service.py","src/parlant/adapters/nlp/modelscope_service.py","src/parlant/adapters/nlp/novita_service.py","src/parlant/adapters/nlp/ollama_service.py","src/parlant/adapters/nlp/openai_service.py","src/parlant/adapters/nlp/openrouter_service.py","src/parlant/adapters/nlp/qwen_service.py","src/parlant/adapters/nlp/snowflake_cortex_service.py","src/parlant/adapters/nlp/together_service.py","src/parlant/adapters/nlp/vertex_service.py","src/parlant/adapters/nlp/zhipu_service.py","src/parlant/core/nlp/embedding.py","src/parlant/core/nlp/generation.py","src/parlant/core/nlp/generation_info.py","src/parlant/core/nlp/moderation.py","src/parlant/core/nlp/policies.py","src/parlant/core/nlp/service.py","src/parlant/core/nlp/tokenization.py"],"NLP & LLM Adapters — adapters":["docs/adapters/nlp/azure.md","docs/adapters/nlp/ollama.md","docs/adapters/nlp/openrouter.md","docs/adapters/nlp/snowflake-cortex.md","docs/adapters/nlp/vertex.md"],"NLP & LLM Adapters — advanced":["docs/advanced/custom-llms.md"],"NLP & LLM Adapters — parlant":["src/parlant/adapters/nlp/anthropic_service.py","src/parlant/adapters/nlp/aws_service.py","src/parlant/adapters/nlp/azure_service.py","src/parlant/adapters/nlp/cerebras_service.py","src/parlant/adapters/nlp/common.py","src/parlant/adapters/nlp/deepseek_service.py","src/parlant/adapters/nlp/emcie_service.py","src/parlant/adapters/nlp/fireworks_service.py","src/parlant/adapters/nlp/gemini_service.py","src/parlant/adapters/nlp/hugging_face.py","src/parlant/adapters/nlp/lakera.py","src/parlant/adapters/nlp/litellm_service.py","src/parlant/adapters/nlp/mistral_service.py","src/parlant/adapters/nlp/modelscope_service.py","src/parlant/adapters/nlp/novita_service.py","src/parlant/adapters/nlp/ollama_service.py","src/parlant/adapters/nlp/openai_service.py","src/parlant/adapters/nlp/openrouter_service.py","src/parlant/adapters/nlp/qwen_service.py","src/parlant/adapters/nlp/snowflake_cortex_service.py","src/parlant/adapters/nlp/together_service.py","src/parlant/adapters/nlp/vertex_service.py","src/parlant/adapters/nlp/zhipu_service.py","src/parlant/core/nlp/embedding.py","src/parlant/core/nlp/generation.py","src/parlant/core/nlp/generation_info.py","src/parlant/core/nlp/moderation.py","src/parlant/core/nlp/policies.py","src/parlant/core/nlp/service.py","src/parlant/core/nlp/tokenization.py"],"Persistence & Data Layer":["docs/adapters/persistence/snowflake.md","docs/adapters/vector_db/qdrant.md","src/parlant/adapters/db/json_file.py","src/parlant/adapters/db/mongo_db.py","src/parlant/adapters/db/snowflake_db.py","src/parlant/adapters/db/transient.py","src/parlant/adapters/vector_db/chroma.py","src/parlant/adapters/vector_db/mongo.py","src/parlant/adapters/vector_db/qdrant.py","src/parlant/adapters/vector_db/transient.py","src/parlant/core/persistence/common.py","src/parlant/core/persistence/data_collection.py","src/parlant/core/persistence/document_database.py","src/parlant/core/persistence/document_database_helper.py","src/parlant/core/persistence/vector_database.py","src/parlant/core/persistence/vector_database_helper.py"],"Persistence & Data Layer — adapters":["docs/adapters/persistence/snowflake.md","docs/adapters/vector_db/qdrant.md"],"Persistence & Data Layer — parlant":["src/parlant/adapters/db/json_file.py","src/parlant/adapters/db/mongo_db.py","src/parlant/adapters/db/snowflake_db.py","src/parlant/adapters/db/transient.py","src/parlant/adapters/vector_db/chroma.py","src/parlant/adapters/vector_db/mongo.py","src/parlant/adapters/vector_db/qdrant.py","src/parlant/adapters/vector_db/transient.py","src/parlant/core/persistence/common.py","src/parlant/core/persistence/data_collection.py","src/parlant/core/persistence/document_database.py","src/parlant/core/persistence/document_database_helper.py","src/parlant/core/persistence/vector_database.py","src/parlant/core/persistence/vector_database_helper.py"],"Evaluation & Moderation":["docs/advanced/explainability.md","docs/production/input-moderation.md","src/parlant/api/evaluations.py","src/parlant/core/evaluations.py","src/parlant/core/app_modules/evaluations.py","src/parlant/core/services/indexing/behavioral_change_evaluation.py","src/parlant/core/services/indexing/common.py","src/parlant/core/services/indexing/customer_dependent_action_detector.py","src/parlant/core/services/indexing/guideline_action_proposer.py","src/parlant/core/services/indexing/guideline_agent_intention_proposer.py","src/parlant/core/services/indexing/guideline_continuous_proposer.py","src/parlant/core/services/indexing/journey_reachable_nodes_evaluation.py","src/parlant/core/services/indexing/relative_action_proposer.py","src/parlant/core/services/indexing/tool_running_action_detector.py"],"Evaluation & Moderation — advanced":["docs/advanced/explainability.md"],"Evaluation & Moderation — production":["docs/production/input-moderation.md"],"Evaluation & Moderation — parlant":["src/parlant/api/evaluations.py","src/parlant/core/evaluations.py","src/parlant/core/app_modules/evaluations.py","src/parlant/core/services/indexing/behavioral_change_evaluation.py","src/parlant/core/services/indexing/common.py","src/parlant/core/services/indexing/customer_dependent_action_detector.py","src/parlant/core/services/indexing/guideline_action_proposer.py","src/parlant/core/services/indexing/guideline_agent_intention_proposer.py","src/parlant/core/services/indexing/guideline_continuous_proposer.py","src/parlant/core/services/indexing/journey_reachable_nodes_evaluation.py","src/parlant/core/services/indexing/relative_action_proposer.py","src/parlant/core/services/indexing/tool_running_action_detector.py"],"Infrastructure & Observability":["docs/production/api-hardening.md","src/parlant/api/app.py","src/parlant/api/authorization.py","src/parlant/api/common.py","src/parlant/api/health.py","src/parlant/api/logs.py","src/parlant/core/application.py","src/parlant/core/async_utils.py","src/parlant/core/background_tasks.py","src/parlant/core/common.py","src/parlant/core/event_loop_monitor.py","src/parlant/core/loggers.py","src/parlant/core/meter.py","src/parlant/core/tracer.py","src/parlant/core/app_modules/common.py","src/parlant/core/health/__init__.py","src/parlant/core/health/engine_view.py","src/parlant/core/health/event_loop_view.py","src/parlant/core/health/nlp_view.py","src/parlant/core/health/reporter.py","src/parlant/adapters/loggers/opentelemetry.py","src/parlant/adapters/loggers/websocket.py","src/parlant/adapters/meter/opentelemetry.py","src/parlant/adapters/tracing/opentelemetry.py"],"Infrastructure & Observability — production":["docs/production/api-hardening.md"],"Infrastructure & Observability — parlant":["src/parlant/api/app.py","src/parlant/api/authorization.py","src/parlant/api/common.py","src/parlant/api/health.py","src/parlant/api/logs.py","src/parlant/core/application.py","src/parlant/core/async_utils.py","src/parlant/core/background_tasks.py","src/parlant/core/common.py","src/parlant/core/event_loop_monitor.py","src/parlant/core/loggers.py","src/parlant/core/meter.py","src/parlant/core/tracer.py","src/parlant/core/app_modules/common.py","src/parlant/core/health/__init__.py","src/parlant/core/health/engine_view.py","src/parlant/core/health/event_loop_view.py","src/parlant/core/health/nlp_view.py","src/parlant/core/health/reporter.py","src/parlant/adapters/loggers/opentelemetry.py","src/parlant/adapters/loggers/websocket.py","src/parlant/adapters/meter/opentelemetry.py","src/parlant/adapters/tracing/opentelemetry.py"],"SDK & Integration":["docs/advanced/contributing.md","docs/advanced/engine-extensions.md","docs/production/custom-frontend.md","docs/production/human-handoff.md","src/parlant/sdk.py"],"SDK & Integration — advanced":["docs/advanced/contributing.md","docs/advanced/engine-extensions.md"],"SDK & Integration — production":["docs/production/custom-frontend.md","docs/production/human-handoff.md"],"SDK & Integration — parlant":["src/parlant/sdk.py"],"Chat UI":["src/parlant/api/chat/components.json","src/parlant/api/chat/index.html","src/parlant/api/chat/manifest.webmanifest","src/parlant/api/chat/public/fonts/Inter/inter.css","src/parlant/api/chat/public/fonts/ibm-plex-mono/ibm-plex-mono.css","src/parlant/api/chat/public/fonts/ubuntu-mono/ubuntu_mono.css","src/parlant/api/chat/public/fonts/ubuntu-sans/ubuntu_sans.css","src/parlant/api/chat/setupTests.ts","src/parlant/api/chat/src/App.css","src/parlant/api/chat/src/App.tsx","src/parlant/api/chat/src/index.css","src/parlant/api/chat/src/main.tsx","src/parlant/api/chat/src/store.ts","src/parlant/api/chat/src/components/agents-list/agent-list.module.scss","src/parlant/api/chat/src/components/agents-list/agent-list.tsx","src/parlant/api/chat/src/components/avatar/avatar.tsx","src/parlant/api/chat/src/components/canned-response/canned-response.tsx","src/parlant/api/chat/src/components/canned-responses/canned-responses.tsx","src/parlant/api/chat/src/components/chat-header/chat-header.tsx","src/parlant/api/chat/src/components/chatbot/chatbot.tsx","src/parlant/api/chat/src/components/dark-mode-toggle/dark-mode-toggle.tsx","src/parlant/api/chat/src/components/error-boundary/error-boundary.tsx","src/parlant/api/chat/src/components/gradient-button/gradient-button.module.scss","src/parlant/api/chat/src/components/gradient-button/gradient-button.tsx","src/parlant/api/chat/src/components/header-wrapper/header-wrapper.tsx","src/parlant/api/chat/src/components/log-filters/log-filters.tsx","src/parlant/api/chat/src/components/markdown/markdown.tsx","src/parlant/api/chat/src/components/message-details/empty-state.tsx","src/parlant/api/chat/src/components/message-details/filter-tabs.tsx","src/parlant/api/chat/src/components/message-details/flag-message.tsx","src/parlant/api/chat/src/components/message-details/indexeddb-data.tsx","src/parlant/api/chat/src/components/message-details/message-details-header.tsx","src/parlant/api/chat/src/components/message-details/message-details.tsx","src/parlant/api/chat/src/components/message-details/message-log.tsx","src/parlant/api/chat/src/components/message-details/message-logs.tsx","src/parlant/api/chat/src/components/message/draft-bubble.tsx","src/parlant/api/chat/src/components/message/message-bubble.tsx","src/parlant/api/chat/src/components/message/message-relative-time.tsx","src/parlant/api/chat/src/components/message/message.module.scss","src/parlant/api/chat/src/components/message/message.tsx","src/parlant/api/chat/src/components/progress-logo/progress-logo.tsx","src/parlant/api/chat/src/components/session-list/session-list-item/session-list-item.module.scss","src/parlant/api/chat/src/components/session-list/session-list-item/session-list-item.tsx","src/parlant/api/chat/src/components/session-list/session-list.tsx","src/parlant/api/chat/src/components/session-view/date-header/date-header.tsx","src/parlant/api/chat/src/components/session-view/session-view-header/session-view-header.tsx","src/parlant/api/chat/src/components/session-view/session-view.module.scss","src/parlant/api/chat/src/components/session-view/session-view.tsx","src/parlant/api/chat/src/components/ui/button.tsx","src/parlant/api/chat/src/components/ui/checkbox.tsx","src/parlant/api/chat/src/components/ui/custom/copy-text.tsx","src/parlant/api/chat/src/components/ui/custom/line-no-div.tsx","src/parlant/api/chat/src/components/ui/custom/spacer.tsx","src/parlant/api/chat/src/components/ui/custom/tooltip.tsx","src/parlant/api/chat/src/components/ui/dialog.tsx","src/parlant/api/chat/src/components/ui/drawer.tsx","src/parlant/api/chat/src/components/ui/dropdown-menu.tsx","src/parlant/api/chat/src/components/ui/input.tsx","src/parlant/api/chat/src/components/ui/radio-group.tsx","src/parlant/api/chat/src/components/ui/resizable.tsx","src/parlant/api/chat/src/components/ui/select.tsx","src/parlant/api/chat/src/components/ui/sheet.tsx","src/parlant/api/chat/src/components/ui/skeleton.tsx","src/parlant/api/chat/src/components/ui/sonner.tsx","src/parlant/api/chat/src/components/ui/switch.tsx","src/parlant/api/chat/src/components/ui/textarea.tsx","src/parlant/api/chat/src/components/ui/tooltip.tsx","src/parlant/api/chat/src/components/virtual-scroll/virtual-scroll.tsx","src/parlant/api/chat/src/hooks/useDialog.tsx","src/parlant/api/chat/src/hooks/useFetch.tsx","src/parlant/api/chat/src/hooks/useLocalStorage.ts","src/parlant/api/chat/src/hooks/useQuestionDialog.tsx","src/parlant/api/chat/src/hooks/useWebSocket.ts","src/parlant/api/chat/src/lib/broadcast-channel.ts","src/parlant/api/chat/src/lib/utils.ts","src/parlant/api/chat/src/utils/api.ts","src/parlant/api/chat/src/utils/date.tsx","src/parlant/api/chat/src/utils/interfaces.tsx","src/parlant/api/chat/src/utils/logs.ts","src/parlant/api/chat/src/utils/methods.tsx","src/parlant/api/chat/src/utils/obj.tsx","src/parlant/api/chat/src/utils/sounds.ts"],"Other":["CLAUDE.md","DCO.md","README.md","graphify-out/GRAPH_REPORT.md","graphify-out/cost.json","graphify-out/graph.html","graphify-out/manifest.json","graphify-out/transcripts/loading.txt","llms.txt","mypy.ini","pyproject.toml","pytest.ini","pytest_stochastics.json","ruff.toml","scripts/ci/github_action_ubuntu_2404_free_space.sh","scripts/fern/docs.yml","scripts/fern/fern.config.json","scripts/fern/generators.yml","scripts/generate_client_sdk.py","scripts/initialize_repo.py","scripts/install_packages.py","scripts/lint.py","scripts/publish.py","scripts/utils.py","scripts/version.py","src/parlant/api/chat/eslint.config.js","src/parlant/api/chat/package.json","src/parlant/api/chat/postcss.config.js","src/parlant/api/chat/public/fonts/ibm-plex-mono/static/OFL.txt","src/parlant/api/chat/public/fonts/ubuntu-mono/static/UFL.txt","src/parlant/api/chat/public/fonts/ubuntu-sans/README.txt","src/parlant/api/chat/public/fonts/ubuntu-sans/UFL.txt","src/parlant/api/chat/tailwind.config.js","src/parlant/api/chat/tsconfig.app.json","src/parlant/api/chat/tsconfig.app.tsbuildinfo","src/parlant/api/chat/tsconfig.json","src/parlant/api/chat/tsconfig.node.json","src/parlant/api/chat/tsconfig.node.tsbuildinfo","src/parlant/api/chat/vite.config.ts","src/parlant/core/version.py","src/parlant/py.typed","tests/__init__.py","tests/conftest.py","tests/test_utilities.py","tests/tool_utilities.py","tests/adapters/db/test_chroma.py","tests/adapters/db/test_json_file.py","tests/adapters/db/test_mongodb.py","tests/adapters/db/test_snowflake_db.py","tests/adapters/nlp/test_azure_service.py","tests/adapters/nlp/test_litellm_service.py","tests/adapters/nlp/test_openrouter_service.py","tests/adapters/nlp/test_qwen_service.py","tests/adapters/nlp/test_zhipu_service.py","tests/adapters/vector_db/test_mongo_vector.py","tests/adapters/vector_db/test_qdrant.py","tests/adapters/vector_db/test_transient.py","tests/api/conftest.py","tests/api/test_agents.py","tests/api/test_app.py","tests/api/test_authorization.py","tests/api/test_canned_responses.py","tests/api/test_capabilities.py","tests/api/test_context_variables.py","tests/api/test_customers.py","tests/api/test_evaluations.py","tests/api/test_glossary.py","tests/api/test_guidelines.py","tests/api/test_journeys.py","tests/api/test_relationships.py","tests/api/test_services.py","tests/api/test_sessions.py","tests/api/test_tags.py","tests/api/test_websocket_logger.py","tests/core/common/engines/alpha/steps/agents.py","tests/core/common/engines/alpha/steps/canned_responses.py","tests/core/common/engines/alpha/steps/capabilities.py","tests/core/common/engines/alpha/steps/context_variables.py","tests/core/common/engines/alpha/steps/customers.py","tests/core/common/engines/alpha/steps/engines.py","tests/core/common/engines/alpha/steps/events.py","tests/core/common/engines/alpha/steps/guidelines.py","tests/core/common/engines/alpha/steps/journeys.py","tests/core/common/engines/alpha/steps/sessions.py","tests/core/common/engines/alpha/steps/tags.py","tests/core/common/engines/alpha/steps/terms.py","tests/core/common/engines/alpha/steps/tools.py","tests/core/common/engines/alpha/utils.py","tests/core/common/utils.py","tests/core/conftest.py","tests/core/stable/engines/alpha/features/baseline/capabilities.feature","tests/core/stable/engines/alpha/features/baseline/context_variables.feature","tests/core/stable/engines/alpha/features/baseline/conversation.feature","tests/core/stable/engines/alpha/features/baseline/errors.feature","tests/core/stable/engines/alpha/features/baseline/glossary.feature","tests/core/stable/engines/alpha/features/baseline/journeys.feature","tests/core/stable/engines/alpha/features/baseline/moderation.feature","tests/core/stable/engines/alpha/features/baseline/proactivity.feature","tests/core/stable/engines/alpha/features/baseline/relationships.feature","tests/core/stable/engines/alpha/features/baseline/strict_canned_responses.feature","tests/core/stable/engines/alpha/features/baseline/strict_canned_responses_capabilities.feature","tests/core/stable/engines/alpha/features/baseline/supervision.feature","tests/core/stable/engines/alpha/features/baseline/tools.feature","tests/core/stable/engines/alpha/features/baseline/triggered_utterances.feature","tests/core/stable/engines/alpha/features/user_stories/conversation.feature","tests/core/stable/engines/alpha/test_baseline_scenarios.py","tests/core/stable/engines/alpha/test_context_variable_loading.py","tests/core/stable/engines/alpha/test_disambiguation_batch.py","tests/core/stable/engines/alpha/test_generic_response_analysis.py","tests/core/stable/engines/alpha/test_guideline_actionable_batch.py","tests/core/stable/engines/alpha/test_guideline_low_criticality_batch.py","tests/core/stable/engines/alpha/test_guideline_matcher.py","tests/core/stable/engines/alpha/test_journey_node_selection.py","tests/core/stable/engines/alpha/test_mcp.py","tests/core/stable/engines/alpha/test_previously_applied_actionable_batch.py","tests/core/stable/engines/alpha/test_previously_applied_actionable_customer_dependent_batch.py","tests/core/stable/engines/alpha/test_relational_resolver.py","tests/core/stable/engines/alpha/test_tool_caller.py","tests/core/stable/engines/alpha/test_user_story_scenarios.py","tests/core/stable/nlp/test_embedding.py","tests/core/stable/nlp/test_generation.py","tests/core/stable/persistence/test_matches_filters.py","tests/core/stable/services/indexing/test_agent_intention_proposer.py","tests/core/stable/services/indexing/test_continuous_guideline_proposer.py","tests/core/stable/services/indexing/test_customer_dependent_action_detector.py","tests/core/stable/services/indexing/test_guideline_action_proposer.py","tests/core/stable/services/indexing/test_relative_action_step_proposer.py","tests/core/stable/services/indexing/test_tool_running_action_detector.py","tests/core/stable/services/tools/test_mcp_client.py","tests/core/stable/services/tools/test_openapi.py","tests/core/stable/services/tools/test_plugin_client.py","tests/core/stable/test_application.py","tests/core/stable/test_capability_vector_store.py","tests/core/stable/test_entity_cq.py","tests/core/stable/test_health_reporter.py","tests/core/stable/test_journey_guideline_projection.py","tests/core/stable/test_relationships.py","tests/core/test_cancellation_suppression_latch.py","tests/core/test_id_generator.py","tests/core/unstable/engines/alpha/features/baseline/conversation.feature","tests/core/unstable/engines/alpha/features/baseline/fluid_canned_responses.feature","tests/core/unstable/engines/alpha/features/baseline/glossary.feature","tests/core/unstable/engines/alpha/features/baseline/strict_canned_responses.feature","tests/core/unstable/engines/alpha/features/baseline/supervision.feature","tests/core/unstable/engines/alpha/features/baseline/tools.feature","tests/core/unstable/engines/alpha/features/user_stories/conversation.feature","tests/core/unstable/engines/alpha/test_agent_intention_proposer.py","tests/core/unstable/engines/alpha/test_baseline_scenarios.py","tests/core/unstable/engines/alpha/test_disambiguation_batch.py","tests/core/unstable/engines/alpha/test_guideline_matcher.py","tests/core/unstable/engines/alpha/test_journey_node_selection.py","tests/core/unstable/engines/alpha/test_previously_applied_actionable_batch.py","tests/core/unstable/engines/alpha/test_user_story_scenarios.py","tests/data/get_products_by_type_data.json","tests/e2e/conftest.py","tests/e2e/test_client_cli_via_api.py","tests/e2e/test_server_cli.py","tests/e2e/test_utilities.py","tests/modules/bank.py","tests/modules/mcp_parrot.py","tests/modules/tech_store.py","tests/sdk/conftest.py","tests/sdk/test_agents.py","tests/sdk/test_canned_responses.py","tests/sdk/test_current_entities.py","tests/sdk/test_customers.py","tests/sdk/test_dynamic_composition_mode.py","tests/sdk/test_glossary.py","tests/sdk/test_guidelines.py","tests/sdk/test_journeys.py","tests/sdk/test_labels.py","tests/sdk/test_planners.py","tests/sdk/test_retrievers.py","tests/sdk/test_sdk_validation.py","tests/sdk/test_server.py","tests/sdk/test_tools.py","tests/sdk/test_variables.py","tests/sdk/utils.py"],"Other — CLAUDE.md":["CLAUDE.md"],"Other — DCO.md":["DCO.md"],"Other — README.md":["README.md"],"Other — graphify-out":["graphify-out/GRAPH_REPORT.md","graphify-out/cost.json","graphify-out/graph.html","graphify-out/manifest.json"],"Other — transcripts":["graphify-out/transcripts/loading.txt"],"Other — llms.txt":["llms.txt"],"Other — mypy.ini":["mypy.ini"],"Other — pyproject.toml":["pyproject.toml"],"Other — pytest.ini":["pytest.ini"],"Other — pytest_stochastics.json":["pytest_stochastics.json"],"Other — ruff.toml":["ruff.toml"],"Other — ci":["scripts/ci/github_action_ubuntu_2404_free_space.sh"],"Other — fern":["scripts/fern/docs.yml","scripts/fern/fern.config.json","scripts/fern/generators.yml"],"Other — scripts":["scripts/generate_client_sdk.py","scripts/initialize_repo.py","scripts/install_packages.py","scripts/lint.py","scripts/publish.py","scripts/utils.py","scripts/version.py"],"Other — parlant":["src/parlant/api/chat/eslint.config.js","src/parlant/api/chat/package.json","src/parlant/api/chat/postcss.config.js","src/parlant/api/chat/public/fonts/ibm-plex-mono/static/OFL.txt","src/parlant/api/chat/public/fonts/ubuntu-mono/static/UFL.txt","src/parlant/api/chat/public/fonts/ubuntu-sans/README.txt","src/parlant/api/chat/public/fonts/ubuntu-sans/UFL.txt","src/parlant/api/chat/tailwind.config.js","src/parlant/api/chat/tsconfig.app.json","src/parlant/api/chat/tsconfig.app.tsbuildinfo","src/parlant/api/chat/tsconfig.json","src/parlant/api/chat/tsconfig.node.json","src/parlant/api/chat/tsconfig.node.tsbuildinfo","src/parlant/api/chat/vite.config.ts","src/parlant/core/version.py","src/parlant/py.typed"],"Other — tests":["tests/__init__.py","tests/conftest.py","tests/test_utilities.py","tests/tool_utilities.py"],"Other — adapters":["tests/adapters/db/test_chroma.py","tests/adapters/db/test_json_file.py","tests/adapters/db/test_mongodb.py","tests/adapters/db/test_snowflake_db.py","tests/adapters/nlp/test_azure_service.py","tests/adapters/nlp/test_litellm_service.py","tests/adapters/nlp/test_openrouter_service.py","tests/adapters/nlp/test_qwen_service.py","tests/adapters/nlp/test_zhipu_service.py","tests/adapters/vector_db/test_mongo_vector.py","tests/adapters/vector_db/test_qdrant.py","tests/adapters/vector_db/test_transient.py"],"Other — api":["tests/api/conftest.py","tests/api/test_agents.py","tests/api/test_app.py","tests/api/test_authorization.py","tests/api/test_canned_responses.py","tests/api/test_capabilities.py","tests/api/test_context_variables.py","tests/api/test_customers.py","tests/api/test_evaluations.py","tests/api/test_glossary.py","tests/api/test_guidelines.py","tests/api/test_journeys.py","tests/api/test_relationships.py","tests/api/test_services.py","tests/api/test_sessions.py","tests/api/test_tags.py","tests/api/test_websocket_logger.py"],"Other — core":["tests/core/common/engines/alpha/steps/agents.py","tests/core/common/engines/alpha/steps/canned_responses.py","tests/core/common/engines/alpha/steps/capabilities.py","tests/core/common/engines/alpha/steps/context_variables.py","tests/core/common/engines/alpha/steps/customers.py","tests/core/common/engines/alpha/steps/engines.py","tests/core/common/engines/alpha/steps/events.py","tests/core/common/engines/alpha/steps/guidelines.py","tests/core/common/engines/alpha/steps/journeys.py","tests/core/common/engines/alpha/steps/sessions.py","tests/core/common/engines/alpha/steps/tags.py","tests/core/common/engines/alpha/steps/terms.py","tests/core/common/engines/alpha/steps/tools.py","tests/core/common/engines/alpha/utils.py","tests/core/common/utils.py","tests/core/conftest.py","tests/core/stable/engines/alpha/features/baseline/capabilities.feature","tests/core/stable/engines/alpha/features/baseline/context_variables.feature","tests/core/stable/engines/alpha/features/baseline/conversation.feature","tests/core/stable/engines/alpha/features/baseline/errors.feature","tests/core/stable/engines/alpha/features/baseline/glossary.feature","tests/core/stable/engines/alpha/features/baseline/journeys.feature","tests/core/stable/engines/alpha/features/baseline/moderation.feature","tests/core/stable/engines/alpha/features/baseline/proactivity.feature","tests/core/stable/engines/alpha/features/baseline/relationships.feature","tests/core/stable/engines/alpha/features/baseline/strict_canned_responses.feature","tests/core/stable/engines/alpha/features/baseline/strict_canned_responses_capabilities.feature","tests/core/stable/engines/alpha/features/baseline/supervision.feature","tests/core/stable/engines/alpha/features/baseline/tools.feature","tests/core/stable/engines/alpha/features/baseline/triggered_utterances.feature","tests/core/stable/engines/alpha/features/user_stories/conversation.feature","tests/core/stable/engines/alpha/test_baseline_scenarios.py","tests/core/stable/engines/alpha/test_context_variable_loading.py","tests/core/stable/engines/alpha/test_disambiguation_batch.py","tests/core/stable/engines/alpha/test_generic_response_analysis.py","tests/core/stable/engines/alpha/test_guideline_actionable_batch.py","tests/core/stable/engines/alpha/test_guideline_low_criticality_batch.py","tests/core/stable/engines/alpha/test_guideline_matcher.py","tests/core/stable/engines/alpha/test_journey_node_selection.py","tests/core/stable/engines/alpha/test_mcp.py","tests/core/stable/engines/alpha/test_previously_applied_actionable_batch.py","tests/core/stable/engines/alpha/test_previously_applied_actionable_customer_dependent_batch.py","tests/core/stable/engines/alpha/test_relational_resolver.py","tests/core/stable/engines/alpha/test_tool_caller.py","tests/core/stable/engines/alpha/test_user_story_scenarios.py","tests/core/stable/nlp/test_embedding.py","tests/core/stable/nlp/test_generation.py","tests/core/stable/persistence/test_matches_filters.py","tests/core/stable/services/indexing/test_agent_intention_proposer.py","tests/core/stable/services/indexing/test_continuous_guideline_proposer.py","tests/core/stable/services/indexing/test_customer_dependent_action_detector.py","tests/core/stable/services/indexing/test_guideline_action_proposer.py","tests/core/stable/services/indexing/test_relative_action_step_proposer.py","tests/core/stable/services/indexing/test_tool_running_action_detector.py","tests/core/stable/services/tools/test_mcp_client.py","tests/core/stable/services/tools/test_openapi.py","tests/core/stable/services/tools/test_plugin_client.py","tests/core/stable/test_application.py","tests/core/stable/test_capability_vector_store.py","tests/core/stable/test_entity_cq.py","tests/core/stable/test_health_reporter.py","tests/core/stable/test_journey_guideline_projection.py","tests/core/stable/test_relationships.py","tests/core/test_cancellation_suppression_latch.py","tests/core/test_id_generator.py","tests/core/unstable/engines/alpha/features/baseline/conversation.feature","tests/core/unstable/engines/alpha/features/baseline/fluid_canned_responses.feature","tests/core/unstable/engines/alpha/features/baseline/glossary.feature","tests/core/unstable/engines/alpha/features/baseline/strict_canned_responses.feature","tests/core/unstable/engines/alpha/features/baseline/supervision.feature","tests/core/unstable/engines/alpha/features/baseline/tools.feature","tests/core/unstable/engines/alpha/features/user_stories/conversation.feature","tests/core/unstable/engines/alpha/test_agent_intention_proposer.py","tests/core/unstable/engines/alpha/test_baseline_scenarios.py","tests/core/unstable/engines/alpha/test_disambiguation_batch.py","tests/core/unstable/engines/alpha/test_guideline_matcher.py","tests/core/unstable/engines/alpha/test_journey_node_selection.py","tests/core/unstable/engines/alpha/test_previously_applied_actionable_batch.py","tests/core/unstable/engines/alpha/test_user_story_scenarios.py"],"Other — data":["tests/data/get_products_by_type_data.json"],"Other — e2e":["tests/e2e/conftest.py","tests/e2e/test_client_cli_via_api.py","tests/e2e/test_server_cli.py","tests/e2e/test_utilities.py"],"Other — modules":["tests/modules/bank.py","tests/modules/mcp_parrot.py","tests/modules/tech_store.py"],"Other — sdk":["tests/sdk/conftest.py","tests/sdk/test_agents.py","tests/sdk/test_canned_responses.py","tests/sdk/test_current_entities.py","tests/sdk/test_customers.py","tests/sdk/test_dynamic_composition_mode.py","tests/sdk/test_glossary.py","tests/sdk/test_guidelines.py","tests/sdk/test_journeys.py","tests/sdk/test_labels.py","tests/sdk/test_planners.py","tests/sdk/test_retrievers.py","tests/sdk/test_sdk_validation.py","tests/sdk/test_server.py","tests/sdk/test_tools.py","tests/sdk/test_variables.py","tests/sdk/utils.py"]},"moduleTree":[{"name":"Getting Started & Examples","slug":"getting-started-examples","files":["docs/quickstart/examples.md","docs/quickstart/installation.md","docs/quickstart/motivation.md","examples/healthcare.py","examples/travel_voice_agent.py"]},{"name":"Core Entities","slug":"core-entities","files":["docs/concepts/entities/agents.md","docs/concepts/entities/customers.md","src/parlant/api/agents.py","src/parlant/api/customers.py","src/parlant/api/tags.py","src/parlant/core/agents.py","src/parlant/core/customers.py","src/parlant/core/tags.py","src/parlant/core/app_modules/agents.py","src/parlant/core/app_modules/customers.py","src/parlant/core/app_modules/tags.py"]},{"name":"Messaging & Sessions","slug":"messaging-sessions","files":[],"children":[{"name":"Messaging & Sessions — concepts","slug":"messaging-sessions-concepts","files":["docs/concepts/sessions.md"]},{"name":"Messaging & Sessions — docs","slug":"messaging-sessions-docs","files":["docs/interactions.md"]},{"name":"Messaging & Sessions — parlant","slug":"messaging-sessions-parlant","files":["src/parlant/api/sessions.py","src/parlant/core/sessions.py","src/parlant/core/app_modules/sessions.py","src/parlant/core/emissions.py","src/parlant/core/emission/event_buffer.py","src/parlant/core/emission/event_publisher.py"]}]},{"name":"Behavioral Customization","slug":"behavioral-customization","files":[],"children":[{"name":"Behavioral Customization — concepts","slug":"behavioral-customization-concepts","files":["docs/concepts/customization/guidelines.md","docs/concepts/customization/glossary.md","docs/concepts/customization/relationships.md","docs/concepts/customization/canned-responses.md","docs/concepts/customization/variables.md","docs/concepts/customization/retrievers.md"]},{"name":"Behavioral Customization — parlant","slug":"behavioral-customization-parlant","files":["src/parlant/api/guidelines.py","src/parlant/api/glossary.py","src/parlant/api/relationships.py","src/parlant/api/canned_responses.py","src/parlant/api/context_variables.py","src/parlant/core/guidelines.py","src/parlant/core/glossary.py","src/parlant/core/relationships.py","src/parlant/core/canned_responses.py","src/parlant/core/context_variables.py","src/parlant/core/app_modules/guidelines.py","src/parlant/core/app_modules/glossary.py","src/parlant/core/app_modules/relationships.py","src/parlant/core/app_modules/canned_responses.py","src/parlant/core/app_modules/context_variables.py","src/parlant/core/guideline_tool_associations.py"]}]},{"name":"Journeys & State Management","slug":"journeys-state-management","files":["docs/concepts/customization/journeys.md","src/parlant/api/journeys.py","src/parlant/core/journeys.py","src/parlant/core/app_modules/journeys.py","src/parlant/core/journey_guideline_projection.py"]},{"name":"Tooling & Service Integration","slug":"tooling-service-integration","files":[],"children":[{"name":"Tooling & Service Integration — concepts","slug":"tooling-service-integration-concepts","files":["docs/concepts/customization/tools.md"]},{"name":"Tooling & Service Integration — parlant","slug":"tooling-service-integration-parlant","files":["src/parlant/api/services.py","src/parlant/api/capabilities.py","src/parlant/core/tools.py","src/parlant/core/capabilities.py","src/parlant/core/app_modules/capabilities.py","src/parlant/core/app_modules/services.py","src/parlant/core/services/tools/mcp_service.py","src/parlant/core/services/tools/openapi.py","src/parlant/core/services/tools/plugins.py","src/parlant/core/services/tools/service_registry.py"]}]},{"name":"AI Reasoning Engine","slug":"ai-reasoning-engine","files":[],"children":[{"name":"AI Reasoning Engine — production","slug":"ai-reasoning-engine-production","files":["docs/production/agentic-design.md"]},{"name":"AI Reasoning Engine — parlant","slug":"ai-reasoning-engine-parlant","files":["src/parlant/core/engines/alpha/engine.py","src/parlant/core/engines/alpha/engine_context.py","src/parlant/core/engines/alpha/entity_context.py","src/parlant/core/engines/alpha/hooks.py","src/parlant/core/engines/alpha/planners.py","src/parlant/core/engines/alpha/prompt_builder.py","src/parlant/core/engines/alpha/relational_resolver.py","src/parlant/core/engines/alpha/message_generator.py","src/parlant/core/engines/alpha/message_event_composer.py","src/parlant/core/engines/alpha/tool_event_generator.py","src/parlant/core/engines/alpha/canned_response_generator.py","src/parlant/core/engines/alpha/optimization_policy.py","src/parlant/core/engines/alpha/perceived_performance_policy.py","src/parlant/core/engines/alpha/utils.py","src/parlant/core/engines/alpha/planning/__init__.py","src/parlant/core/engines/alpha/guideline_matching/common.py","src/parlant/core/engines/alpha/guideline_matching/custom_guideline_matching_strategy.py","src/parlant/core/engines/alpha/guideline_matching/generic_guideline_matching_strategy_resolver.py","src/parlant/core/engines/alpha/guideline_matching/guideline_match.py","src/parlant/core/engines/alpha/guideline_matching/guideline_matcher.py","src/parlant/core/engines/alpha/guideline_matching/guideline_matching_context.py","src/parlant/core/engines/alpha/guideline_matching/generic/common.py","src/parlant/core/engines/alpha/guideline_matching/generic/disambiguation_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/generic_guideline_matching_strategy.py","src/parlant/core/engines/alpha/guideline_matching/generic/guideline_actionable_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/guideline_low_criticality_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/guideline_previously_applied_actionable_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/guideline_previously_applied_actionable_customer_dependent_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/observational_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/response_analysis_batch.py","src/parlant/core/engines/alpha/guideline_matching/generic/journey/journey_backtrack_check.py","src/parlant/core/engines/alpha/guideline_matching/generic/journey/journey_backtrack_node_selection.py","src/parlant/core/engines/alpha/guideline_matching/generic/journey/journey_next_step_selection.py","src/parlant/core/engines/alpha/guideline_matching/generic/journey/journey_node_selection_batch.py","src/parlant/core/engines/alpha/tool_calling/default_tool_call_batcher.py","src/parlant/core/engines/alpha/tool_calling/overlapping_tools_batch.py","src/parlant/core/engines/alpha/tool_calling/single_tool_batch.py","src/parlant/core/engines/alpha/tool_calling/tool_caller.py","src/parlant/core/engines/types.py","src/parlant/core/entity_cq.py","src/parlant/core/shots.py"]}]},{"name":"NLP & LLM Adapters","slug":"nlp-llm-adapters","files":[],"children":[{"name":"NLP & LLM Adapters — adapters","slug":"nlp-llm-adapters-adapters","files":["docs/adapters/nlp/azure.md","docs/adapters/nlp/ollama.md","docs/adapters/nlp/openrouter.md","docs/adapters/nlp/snowflake-cortex.md","docs/adapters/nlp/vertex.md"]},{"name":"NLP & LLM Adapters — advanced","slug":"nlp-llm-adapters-advanced","files":["docs/advanced/custom-llms.md"]},{"name":"NLP & LLM Adapters — parlant","slug":"nlp-llm-adapters-parlant","files":["src/parlant/adapters/nlp/anthropic_service.py","src/parlant/adapters/nlp/aws_service.py","src/parlant/adapters/nlp/azure_service.py","src/parlant/adapters/nlp/cerebras_service.py","src/parlant/adapters/nlp/common.py","src/parlant/adapters/nlp/deepseek_service.py","src/parlant/adapters/nlp/emcie_service.py","src/parlant/adapters/nlp/fireworks_service.py","src/parlant/adapters/nlp/gemini_service.py","src/parlant/adapters/nlp/hugging_face.py","src/parlant/adapters/nlp/lakera.py","src/parlant/adapters/nlp/litellm_service.py","src/parlant/adapters/nlp/mistral_service.py","src/parlant/adapters/nlp/modelscope_service.py","src/parlant/adapters/nlp/novita_service.py","src/parlant/adapters/nlp/ollama_service.py","src/parlant/adapters/nlp/openai_service.py","src/parlant/adapters/nlp/openrouter_service.py","src/parlant/adapters/nlp/qwen_service.py","src/parlant/adapters/nlp/snowflake_cortex_service.py","src/parlant/adapters/nlp/together_service.py","src/parlant/adapters/nlp/vertex_service.py","src/parlant/adapters/nlp/zhipu_service.py","src/parlant/core/nlp/embedding.py","src/parlant/core/nlp/generation.py","src/parlant/core/nlp/generation_info.py","src/parlant/core/nlp/moderation.py","src/parlant/core/nlp/policies.py","src/parlant/core/nlp/service.py","src/parlant/core/nlp/tokenization.py"]}]},{"name":"Persistence & Data Layer","slug":"persistence-data-layer","files":[],"children":[{"name":"Persistence & Data Layer — adapters","slug":"persistence-data-layer-adapters","files":["docs/adapters/persistence/snowflake.md","docs/adapters/vector_db/qdrant.md"]},{"name":"Persistence & Data Layer — parlant","slug":"persistence-data-layer-parlant","files":["src/parlant/adapters/db/json_file.py","src/parlant/adapters/db/mongo_db.py","src/parlant/adapters/db/snowflake_db.py","src/parlant/adapters/db/transient.py","src/parlant/adapters/vector_db/chroma.py","src/parlant/adapters/vector_db/mongo.py","src/parlant/adapters/vector_db/qdrant.py","src/parlant/adapters/vector_db/transient.py","src/parlant/core/persistence/common.py","src/parlant/core/persistence/data_collection.py","src/parlant/core/persistence/document_database.py","src/parlant/core/persistence/document_database_helper.py","src/parlant/core/persistence/vector_database.py","src/parlant/core/persistence/vector_database_helper.py"]}]},{"name":"Evaluation & Moderation","slug":"evaluation-moderation","files":[],"children":[{"name":"Evaluation & Moderation — advanced","slug":"evaluation-moderation-advanced","files":["docs/advanced/explainability.md"]},{"name":"Evaluation & Moderation — production","slug":"evaluation-moderation-production","files":["docs/production/input-moderation.md"]},{"name":"Evaluation & Moderation — parlant","slug":"evaluation-moderation-parlant","files":["src/parlant/api/evaluations.py","src/parlant/core/evaluations.py","src/parlant/core/app_modules/evaluations.py","src/parlant/core/services/indexing/behavioral_change_evaluation.py","src/parlant/core/services/indexing/common.py","src/parlant/core/services/indexing/customer_dependent_action_detector.py","src/parlant/core/services/indexing/guideline_action_proposer.py","src/parlant/core/services/indexing/guideline_agent_intention_proposer.py","src/parlant/core/services/indexing/guideline_continuous_proposer.py","src/parlant/core/services/indexing/journey_reachable_nodes_evaluation.py","src/parlant/core/services/indexing/relative_action_proposer.py","src/parlant/core/services/indexing/tool_running_action_detector.py"]}]},{"name":"Infrastructure & Observability","slug":"infrastructure-observability","files":[],"children":[{"name":"Infrastructure & Observability — production","slug":"infrastructure-observability-production","files":["docs/production/api-hardening.md"]},{"name":"Infrastructure & Observability — parlant","slug":"infrastructure-observability-parlant","files":["src/parlant/api/app.py","src/parlant/api/authorization.py","src/parlant/api/common.py","src/parlant/api/health.py","src/parlant/api/logs.py","src/parlant/core/application.py","src/parlant/core/async_utils.py","src/parlant/core/background_tasks.py","src/parlant/core/common.py","src/parlant/core/event_loop_monitor.py","src/parlant/core/loggers.py","src/parlant/core/meter.py","src/parlant/core/tracer.py","src/parlant/core/app_modules/common.py","src/parlant/core/health/__init__.py","src/parlant/core/health/engine_view.py","src/parlant/core/health/event_loop_view.py","src/parlant/core/health/nlp_view.py","src/parlant/core/health/reporter.py","src/parlant/adapters/loggers/opentelemetry.py","src/parlant/adapters/loggers/websocket.py","src/parlant/adapters/meter/opentelemetry.py","src/parlant/adapters/tracing/opentelemetry.py"]}]},{"name":"SDK & Integration","slug":"sdk-integration","files":[],"children":[{"name":"SDK & Integration — advanced","slug":"sdk-integration-advanced","files":["docs/advanced/contributing.md","docs/advanced/engine-extensions.md"]},{"name":"SDK & Integration — production","slug":"sdk-integration-production","files":["docs/production/custom-frontend.md","docs/production/human-handoff.md"]},{"name":"SDK & Integration — parlant","slug":"sdk-integration-parlant","files":["src/parlant/sdk.py"]}]},{"name":"Chat UI","slug":"chat-ui","files":["src/parlant/api/chat/components.json","src/parlant/api/chat/index.html","src/parlant/api/chat/manifest.webmanifest","src/parlant/api/chat/public/fonts/Inter/inter.css","src/parlant/api/chat/public/fonts/ibm-plex-mono/ibm-plex-mono.css","src/parlant/api/chat/public/fonts/ubuntu-mono/ubuntu_mono.css","src/parlant/api/chat/public/fonts/ubuntu-sans/ubuntu_sans.css","src/parlant/api/chat/setupTests.ts","src/parlant/api/chat/src/App.css","src/parlant/api/chat/src/App.tsx","src/parlant/api/chat/src/index.css","src/parlant/api/chat/src/main.tsx","src/parlant/api/chat/src/store.ts","src/parlant/api/chat/src/components/agents-list/agent-list.module.scss","src/parlant/api/chat/src/components/agents-list/agent-list.tsx","src/parlant/api/chat/src/components/avatar/avatar.tsx","src/parlant/api/chat/src/components/canned-response/canned-response.tsx","src/parlant/api/chat/src/components/canned-responses/canned-responses.tsx","src/parlant/api/chat/src/components/chat-header/chat-header.tsx","src/parlant/api/chat/src/components/chatbot/chatbot.tsx","src/parlant/api/chat/src/components/dark-mode-toggle/dark-mode-toggle.tsx","src/parlant/api/chat/src/components/error-boundary/error-boundary.tsx","src/parlant/api/chat/src/components/gradient-button/gradient-button.module.scss","src/parlant/api/chat/src/components/gradient-button/gradient-button.tsx","src/parlant/api/chat/src/components/header-wrapper/header-wrapper.tsx","src/parlant/api/chat/src/components/log-filters/log-filters.tsx","src/parlant/api/chat/src/components/markdown/markdown.tsx","src/parlant/api/chat/src/components/message-details/empty-state.tsx","src/parlant/api/chat/src/components/message-details/filter-tabs.tsx","src/parlant/api/chat/src/components/message-details/flag-message.tsx","src/parlant/api/chat/src/components/message-details/indexeddb-data.tsx","src/parlant/api/chat/src/components/message-details/message-details-header.tsx","src/parlant/api/chat/src/components/message-details/message-details.tsx","src/parlant/api/chat/src/components/message-details/message-log.tsx","src/parlant/api/chat/src/components/message-details/message-logs.tsx","src/parlant/api/chat/src/components/message/draft-bubble.tsx","src/parlant/api/chat/src/components/message/message-bubble.tsx","src/parlant/api/chat/src/components/message/message-relative-time.tsx","src/parlant/api/chat/src/components/message/message.module.scss","src/parlant/api/chat/src/components/message/message.tsx","src/parlant/api/chat/src/components/progress-logo/progress-logo.tsx","src/parlant/api/chat/src/components/session-list/session-list-item/session-list-item.module.scss","src/parlant/api/chat/src/components/session-list/session-list-item/session-list-item.tsx","src/parlant/api/chat/src/components/session-list/session-list.tsx","src/parlant/api/chat/src/components/session-view/date-header/date-header.tsx","src/parlant/api/chat/src/components/session-view/session-view-header/session-view-header.tsx","src/parlant/api/chat/src/components/session-view/session-view.module.scss","src/parlant/api/chat/src/components/session-view/session-view.tsx","src/parlant/api/chat/src/components/ui/button.tsx","src/parlant/api/chat/src/components/ui/checkbox.tsx","src/parlant/api/chat/src/components/ui/custom/copy-text.tsx","src/parlant/api/chat/src/components/ui/custom/line-no-div.tsx","src/parlant/api/chat/src/components/ui/custom/spacer.tsx","src/parlant/api/chat/src/components/ui/custom/tooltip.tsx","src/parlant/api/chat/src/components/ui/dialog.tsx","src/parlant/api/chat/src/components/ui/drawer.tsx","src/parlant/api/chat/src/components/ui/dropdown-menu.tsx","src/parlant/api/chat/src/components/ui/input.tsx","src/parlant/api/chat/src/components/ui/radio-group.tsx","src/parlant/api/chat/src/components/ui/resizable.tsx","src/parlant/api/chat/src/components/ui/select.tsx","src/parlant/api/chat/src/components/ui/sheet.tsx","src/parlant/api/chat/src/components/ui/skeleton.tsx","src/parlant/api/chat/src/components/ui/sonner.tsx","src/parlant/api/chat/src/components/ui/switch.tsx","src/parlant/api/chat/src/components/ui/textarea.tsx","src/parlant/api/chat/src/components/ui/tooltip.tsx","src/parlant/api/chat/src/components/virtual-scroll/virtual-scroll.tsx","src/parlant/api/chat/src/hooks/useDialog.tsx","src/parlant/api/chat/src/hooks/useFetch.tsx","src/parlant/api/chat/src/hooks/useLocalStorage.ts","src/parlant/api/chat/src/hooks/useQuestionDialog.tsx","src/parlant/api/chat/src/hooks/useWebSocket.ts","src/parlant/api/chat/src/lib/broadcast-channel.ts","src/parlant/api/chat/src/lib/utils.ts","src/parlant/api/chat/src/utils/api.ts","src/parlant/api/chat/src/utils/date.tsx","src/parlant/api/chat/src/utils/interfaces.tsx","src/parlant/api/chat/src/utils/logs.ts","src/parlant/api/chat/src/utils/methods.tsx","src/parlant/api/chat/src/utils/obj.tsx","src/parlant/api/chat/src/utils/sounds.ts"]},{"name":"Other","slug":"other","files":[],"children":[{"name":"Other — CLAUDE.md","slug":"other-claude-md","files":["CLAUDE.md"]},{"name":"Other — DCO.md","slug":"other-dco-md","files":["DCO.md"]},{"name":"Other — README.md","slug":"other-readme-md","files":["README.md"]},{"name":"Other — graphify-out","slug":"other-graphify-out","files":["graphify-out/GRAPH_REPORT.md","graphify-out/cost.json","graphify-out/graph.html","graphify-out/manifest.json"]},{"name":"Other — transcripts","slug":"other-transcripts","files":["graphify-out/transcripts/loading.txt"]},{"name":"Other — llms.txt","slug":"other-llms-txt","files":["llms.txt"]},{"name":"Other — mypy.ini","slug":"other-mypy-ini","files":["mypy.ini"]},{"name":"Other — pyproject.toml","slug":"other-pyproject-toml","files":["pyproject.toml"]},{"name":"Other — pytest.ini","slug":"other-pytest-ini","files":["pytest.ini"]},{"name":"Other — pytest_stochastics.json","slug":"other-pytest-stochastics-json","files":["pytest_stochastics.json"]},{"name":"Other — ruff.toml","slug":"other-ruff-toml","files":["ruff.toml"]},{"name":"Other — ci","slug":"other-ci","files":["scripts/ci/github_action_ubuntu_2404_free_space.sh"]},{"name":"Other — fern","slug":"other-fern","files":["scripts/fern/docs.yml","scripts/fern/fern.config.json","scripts/fern/generators.yml"]},{"name":"Other — scripts","slug":"other-scripts","files":["scripts/generate_client_sdk.py","scripts/initialize_repo.py","scripts/install_packages.py","scripts/lint.py","scripts/publish.py","scripts/utils.py","scripts/version.py"]},{"name":"Other — parlant","slug":"other-parlant","files":["src/parlant/api/chat/eslint.config.js","src/parlant/api/chat/package.json","src/parlant/api/chat/postcss.config.js","src/parlant/api/chat/public/fonts/ibm-plex-mono/static/OFL.txt","src/parlant/api/chat/public/fonts/ubuntu-mono/static/UFL.txt","src/parlant/api/chat/public/fonts/ubuntu-sans/README.txt","src/parlant/api/chat/public/fonts/ubuntu-sans/UFL.txt","src/parlant/api/chat/tailwind.config.js","src/parlant/api/chat/tsconfig.app.json","src/parlant/api/chat/tsconfig.app.tsbuildinfo","src/parlant/api/chat/tsconfig.json","src/parlant/api/chat/tsconfig.node.json","src/parlant/api/chat/tsconfig.node.tsbuildinfo","src/parlant/api/chat/vite.config.ts","src/parlant/core/version.py","src/parlant/py.typed"]},{"name":"Other — tests","slug":"other-tests","files":["tests/__init__.py","tests/conftest.py","tests/test_utilities.py","tests/tool_utilities.py"]},{"name":"Other — adapters","slug":"other-adapters","files":["tests/adapters/db/test_chroma.py","tests/adapters/db/test_json_file.py","tests/adapters/db/test_mongodb.py","tests/adapters/db/test_snowflake_db.py","tests/adapters/nlp/test_azure_service.py","tests/adapters/nlp/test_litellm_service.py","tests/adapters/nlp/test_openrouter_service.py","tests/adapters/nlp/test_qwen_service.py","tests/adapters/nlp/test_zhipu_service.py","tests/adapters/vector_db/test_mongo_vector.py","tests/adapters/vector_db/test_qdrant.py","tests/adapters/vector_db/test_transient.py"]},{"name":"Other — api","slug":"other-api","files":["tests/api/conftest.py","tests/api/test_agents.py","tests/api/test_app.py","tests/api/test_authorization.py","tests/api/test_canned_responses.py","tests/api/test_capabilities.py","tests/api/test_context_variables.py","tests/api/test_customers.py","tests/api/test_evaluations.py","tests/api/test_glossary.py","tests/api/test_guidelines.py","tests/api/test_journeys.py","tests/api/test_relationships.py","tests/api/test_services.py","tests/api/test_sessions.py","tests/api/test_tags.py","tests/api/test_websocket_logger.py"]},{"name":"Other — core","slug":"other-core","files":["tests/core/common/engines/alpha/steps/agents.py","tests/core/common/engines/alpha/steps/canned_responses.py","tests/core/common/engines/alpha/steps/capabilities.py","tests/core/common/engines/alpha/steps/context_variables.py","tests/core/common/engines/alpha/steps/customers.py","tests/core/common/engines/alpha/steps/engines.py","tests/core/common/engines/alpha/steps/events.py","tests/core/common/engines/alpha/steps/guidelines.py","tests/core/common/engines/alpha/steps/journeys.py","tests/core/common/engines/alpha/steps/sessions.py","tests/core/common/engines/alpha/steps/tags.py","tests/core/common/engines/alpha/steps/terms.py","tests/core/common/engines/alpha/steps/tools.py","tests/core/common/engines/alpha/utils.py","tests/core/common/utils.py","tests/core/conftest.py","tests/core/stable/engines/alpha/features/baseline/capabilities.feature","tests/core/stable/engines/alpha/features/baseline/context_variables.feature","tests/core/stable/engines/alpha/features/baseline/conversation.feature","tests/core/stable/engines/alpha/features/baseline/errors.feature","tests/core/stable/engines/alpha/features/baseline/glossary.feature","tests/core/stable/engines/alpha/features/baseline/journeys.feature","tests/core/stable/engines/alpha/features/baseline/moderation.feature","tests/core/stable/engines/alpha/features/baseline/proactivity.feature","tests/core/stable/engines/alpha/features/baseline/relationships.feature","tests/core/stable/engines/alpha/features/baseline/strict_canned_responses.feature","tests/core/stable/engines/alpha/features/baseline/strict_canned_responses_capabilities.feature","tests/core/stable/engines/alpha/features/baseline/supervision.feature","tests/core/stable/engines/alpha/features/baseline/tools.feature","tests/core/stable/engines/alpha/features/baseline/triggered_utterances.feature","tests/core/stable/engines/alpha/features/user_stories/conversation.feature","tests/core/stable/engines/alpha/test_baseline_scenarios.py","tests/core/stable/engines/alpha/test_context_variable_loading.py","tests/core/stable/engines/alpha/test_disambiguation_batch.py","tests/core/stable/engines/alpha/test_generic_response_analysis.py","tests/core/stable/engines/alpha/test_guideline_actionable_batch.py","tests/core/stable/engines/alpha/test_guideline_low_criticality_batch.py","tests/core/stable/engines/alpha/test_guideline_matcher.py","tests/core/stable/engines/alpha/test_journey_node_selection.py","tests/core/stable/engines/alpha/test_mcp.py","tests/core/stable/engines/alpha/test_previously_applied_actionable_batch.py","tests/core/stable/engines/alpha/test_previously_applied_actionable_customer_dependent_batch.py","tests/core/stable/engines/alpha/test_relational_resolver.py","tests/core/stable/engines/alpha/test_tool_caller.py","tests/core/stable/engines/alpha/test_user_story_scenarios.py","tests/core/stable/nlp/test_embedding.py","tests/core/stable/nlp/test_generation.py","tests/core/stable/persistence/test_matches_filters.py","tests/core/stable/services/indexing/test_agent_intention_proposer.py","tests/core/stable/services/indexing/test_continuous_guideline_proposer.py","tests/core/stable/services/indexing/test_customer_dependent_action_detector.py","tests/core/stable/services/indexing/test_guideline_action_proposer.py","tests/core/stable/services/indexing/test_relative_action_step_proposer.py","tests/core/stable/services/indexing/test_tool_running_action_detector.py","tests/core/stable/services/tools/test_mcp_client.py","tests/core/stable/services/tools/test_openapi.py","tests/core/stable/services/tools/test_plugin_client.py","tests/core/stable/test_application.py","tests/core/stable/test_capability_vector_store.py","tests/core/stable/test_entity_cq.py","tests/core/stable/test_health_reporter.py","tests/core/stable/test_journey_guideline_projection.py","tests/core/stable/test_relationships.py","tests/core/test_cancellation_suppression_latch.py","tests/core/test_id_generator.py","tests/core/unstable/engines/alpha/features/baseline/conversation.feature","tests/core/unstable/engines/alpha/features/baseline/fluid_canned_responses.feature","tests/core/unstable/engines/alpha/features/baseline/glossary.feature","tests/core/unstable/engines/alpha/features/baseline/strict_canned_responses.feature","tests/core/unstable/engines/alpha/features/baseline/supervision.feature","tests/core/unstable/engines/alpha/features/baseline/tools.feature","tests/core/unstable/engines/alpha/features/user_stories/conversation.feature","tests/core/unstable/engines/alpha/test_agent_intention_proposer.py","tests/core/unstable/engines/alpha/test_baseline_scenarios.py","tests/core/unstable/engines/alpha/test_disambiguation_batch.py","tests/core/unstable/engines/alpha/test_guideline_matcher.py","tests/core/unstable/engines/alpha/test_journey_node_selection.py","tests/core/unstable/engines/alpha/test_previously_applied_actionable_batch.py","tests/core/unstable/engines/alpha/test_user_story_scenarios.py"]},{"name":"Other — data","slug":"other-data","files":["tests/data/get_products_by_type_data.json"]},{"name":"Other — e2e","slug":"other-e2e","files":["tests/e2e/conftest.py","tests/e2e/test_client_cli_via_api.py","tests/e2e/test_server_cli.py","tests/e2e/test_utilities.py"]},{"name":"Other — modules","slug":"other-modules","files":["tests/modules/bank.py","tests/modules/mcp_parrot.py","tests/modules/tech_store.py"]},{"name":"Other — sdk","slug":"other-sdk","files":["tests/sdk/conftest.py","tests/sdk/test_agents.py","tests/sdk/test_canned_responses.py","tests/sdk/test_current_entities.py","tests/sdk/test_customers.py","tests/sdk/test_dynamic_composition_mode.py","tests/sdk/test_glossary.py","tests/sdk/test_guidelines.py","tests/sdk/test_journeys.py","tests/sdk/test_labels.py","tests/sdk/test_planners.py","tests/sdk/test_retrievers.py","tests/sdk/test_sdk_validation.py","tests/sdk/test_server.py","tests/sdk/test_tools.py","tests/sdk/test_variables.py","tests/sdk/utils.py"]}]}]}; | |
| (function() { | |
| var activePage = 'overview'; | |
| document.addEventListener('DOMContentLoaded', function() { | |
| mermaid.initialize({ startOnLoad: false, theme: 'neutral', securityLevel: 'loose' }); | |
| renderMeta(); | |
| renderNav(); | |
| document.getElementById('menu-toggle').addEventListener('click', function() { | |
| document.getElementById('sidebar').classList.toggle('open'); | |
| }); | |
| if (location.hash && location.hash.length > 1) { | |
| activePage = decodeURIComponent(location.hash.slice(1)); | |
| } | |
| navigateTo(activePage); | |
| }); | |
| function renderMeta() { | |
| if (!META) return; | |
| var el = document.getElementById('meta-info'); | |
| var parts = []; | |
| if (META.generatedAt) { | |
| parts.push(new Date(META.generatedAt).toLocaleDateString()); | |
| } | |
| if (META.model) parts.push(META.model); | |
| if (META.fromCommit) parts.push(META.fromCommit.slice(0, 8)); | |
| el.textContent = parts.join(' \u00b7 '); | |
| } | |
| function renderNav() { | |
| var container = document.getElementById('nav-tree'); | |
| var html = '<div class="nav-section">'; | |
| html += '<a class="nav-item overview" data-page="overview" href="#overview">Overview</a>'; | |
| html += '</div>'; | |
| if (TREE.length > 0) { | |
| html += '<div class="nav-group-label">Modules</div>'; | |
| html += buildNavTree(TREE); | |
| } | |
| container.innerHTML = html; | |
| container.addEventListener('click', function(e) { | |
| var target = e.target; | |
| while (target && !target.dataset.page) { target = target.parentElement; } | |
| if (target && target.dataset.page) { | |
| e.preventDefault(); | |
| navigateTo(target.dataset.page); | |
| } | |
| }); | |
| } | |
| function buildNavTree(nodes) { | |
| var html = ''; | |
| for (var i = 0; i < nodes.length; i++) { | |
| var node = nodes[i]; | |
| html += '<div class="nav-section">'; | |
| html += '<a class="nav-item" data-page="' + escH(node.slug) + '" href="#' + encodeURIComponent(node.slug) + '">' + escH(node.name) + '</a>'; | |
| if (node.children && node.children.length > 0) { | |
| html += '<div class="nav-children">' + buildNavTree(node.children) + '</div>'; | |
| } | |
| html += '</div>'; | |
| } | |
| return html; | |
| } | |
| function escH(s) { | |
| var d = document.createElement('div'); | |
| d.textContent = s; | |
| return d.innerHTML; | |
| } | |
| function navigateTo(page) { | |
| activePage = page; | |
| location.hash = encodeURIComponent(page); | |
| var items = document.querySelectorAll('.nav-item'); | |
| for (var i = 0; i < items.length; i++) { | |
| if (items[i].dataset.page === page) { | |
| items[i].classList.add('active'); | |
| } else { | |
| items[i].classList.remove('active'); | |
| } | |
| } | |
| var contentEl = document.getElementById('content'); | |
| var md = PAGES[page]; | |
| if (!md) { | |
| contentEl.innerHTML = '<div class="empty-state"><h2>Page not found</h2><p>' + escH(page) + '.md does not exist.</p></div>'; | |
| return; | |
| } | |
| contentEl.innerHTML = marked.parse(md); | |
| // Rewrite .md links to hash navigation | |
| var links = contentEl.querySelectorAll('a[href]'); | |
| for (var i = 0; i < links.length; i++) { | |
| var href = links[i].getAttribute('href'); | |
| if (href && href.endsWith('.md') && href.indexOf('://') === -1) { | |
| var slug = href.replace(/\.md$/, ''); | |
| links[i].setAttribute('href', '#' + encodeURIComponent(slug)); | |
| (function(s) { | |
| links[i].addEventListener('click', function(e) { | |
| e.preventDefault(); | |
| navigateTo(s); | |
| }); | |
| })(slug); | |
| } | |
| } | |
| // Convert mermaid code blocks into mermaid divs | |
| var mermaidBlocks = contentEl.querySelectorAll('pre code.language-mermaid'); | |
| for (var i = 0; i < mermaidBlocks.length; i++) { | |
| var pre = mermaidBlocks[i].parentElement; | |
| var div = document.createElement('div'); | |
| div.className = 'mermaid'; | |
| div.textContent = mermaidBlocks[i].textContent; | |
| pre.parentNode.replaceChild(div, pre); | |
| } | |
| try { mermaid.run({ querySelector: '.mermaid' }); } catch(e) {} | |
| window.scrollTo(0, 0); | |
| document.getElementById('sidebar').classList.remove('open'); | |
| } | |
| })(); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment