Showing preview only (7,533K chars total). Download the full file or copy to clipboard to get everything.
Repository: emcie-co/parlant
Branch: develop
Commit: d1299ad3b7d5
Files: 478
Total size: 7.1 MB
Directory structure:
gitextract_lshtm9pg/
├── .devcontainer/
│ ├── Dockerfile
│ └── devcontainer.json
├── .githooks/
│ ├── pre-commit
│ ├── pre-push
│ └── prepare-commit-msg
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug-report.md
│ │ └── feature-request.md
│ ├── dco.yml
│ └── workflows/
│ ├── ci-test.yml
│ ├── docker-publish.yml
│ └── lint.yml
├── .gitignore
├── CHANGELOG.md
├── CLAUDE.md
├── CONTRIBUTING.md
├── DCO.md
├── LICENSE
├── README.md
├── docs/
│ ├── adapters/
│ │ ├── nlp/
│ │ │ ├── azure.md
│ │ │ ├── ollama.md
│ │ │ ├── openrouter.md
│ │ │ ├── snowflake-cortex.md
│ │ │ └── vertex.md
│ │ ├── persistence/
│ │ │ └── snowflake.md
│ │ └── vector_db/
│ │ └── qdrant.md
│ ├── advanced/
│ │ ├── contributing.md
│ │ ├── custom-llms.md
│ │ ├── engine-extensions.md
│ │ └── explainability.md
│ ├── concepts/
│ │ ├── customization/
│ │ │ ├── canned-responses.md
│ │ │ ├── glossary.md
│ │ │ ├── guidelines.md
│ │ │ ├── journeys.md
│ │ │ ├── relationships.md
│ │ │ ├── retrievers.md
│ │ │ ├── tools.md
│ │ │ └── variables.md
│ │ ├── entities/
│ │ │ ├── agents.md
│ │ │ └── customers.md
│ │ └── sessions.md
│ ├── interactions.md
│ ├── production/
│ │ ├── agentic-design.md
│ │ ├── api-hardening.md
│ │ ├── custom-frontend.md
│ │ ├── human-handoff.md
│ │ └── input-moderation.md
│ └── quickstart/
│ ├── examples.md
│ ├── installation.md
│ └── motivation.md
├── examples/
│ ├── healthcare.py
│ └── travel_voice_agent.py
├── llms.txt
├── mypy.ini
├── pyproject.toml
├── pytest.ini
├── pytest_stochastics.json
├── ruff.toml
├── scripts/
│ ├── ci/
│ │ └── github_action_ubuntu_2404_free_space.sh
│ ├── fern/
│ │ ├── docs.yml
│ │ ├── fern.config.json
│ │ └── generators.yml
│ ├── generate_client_sdk.py
│ ├── initialize_repo.py
│ ├── install_packages.py
│ ├── lint.py
│ ├── publish.py
│ ├── utils.py
│ └── version.py
├── src/
│ └── parlant/
│ ├── adapters/
│ │ ├── db/
│ │ │ ├── json_file.py
│ │ │ ├── mongo_db.py
│ │ │ ├── snowflake_db.py
│ │ │ └── transient.py
│ │ ├── loggers/
│ │ │ ├── opentelemetry.py
│ │ │ └── websocket.py
│ │ ├── meter/
│ │ │ └── opentelemetry.py
│ │ ├── nlp/
│ │ │ ├── anthropic_service.py
│ │ │ ├── aws_service.py
│ │ │ ├── azure_service.py
│ │ │ ├── cerebras_service.py
│ │ │ ├── common.py
│ │ │ ├── deepseek_service.py
│ │ │ ├── emcie_service.py
│ │ │ ├── fireworks_service.py
│ │ │ ├── gemini_service.py
│ │ │ ├── glm_service.py
│ │ │ ├── hugging_face.py
│ │ │ ├── lakera.py
│ │ │ ├── litellm_service.py
│ │ │ ├── mistral_service.py
│ │ │ ├── modelscope_service.py
│ │ │ ├── ollama_service.py
│ │ │ ├── openai_service.py
│ │ │ ├── openrouter_service.py
│ │ │ ├── qwen_service.py
│ │ │ ├── snowflake_cortex_service.py
│ │ │ ├── together_service.py
│ │ │ ├── vertex_service.py
│ │ │ └── zhipu_service.py
│ │ ├── tracing/
│ │ │ └── opentelemetry.py
│ │ └── vector_db/
│ │ ├── chroma.py
│ │ ├── qdrant.py
│ │ └── transient.py
│ ├── api/
│ │ ├── agents.py
│ │ ├── app.py
│ │ ├── authorization.py
│ │ ├── canned_responses.py
│ │ ├── capabilities.py
│ │ ├── chat/
│ │ │ ├── .gitignore
│ │ │ ├── .prettierrc
│ │ │ ├── .vite/
│ │ │ │ └── deps_temp_0491001f/
│ │ │ │ └── package.json
│ │ │ ├── components.json
│ │ │ ├── dist/
│ │ │ │ ├── assets/
│ │ │ │ │ ├── index-BBAJ1vle.js
│ │ │ │ │ ├── index-BRVifGSy.css
│ │ │ │ │ └── manifest-BRNJYplA.webmanifest
│ │ │ │ ├── fonts/
│ │ │ │ │ ├── Inter/
│ │ │ │ │ │ └── inter.css
│ │ │ │ │ ├── ibm-plex-mono/
│ │ │ │ │ │ ├── ibm-plex-mono.css
│ │ │ │ │ │ └── static/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── ubuntu-mono/
│ │ │ │ │ │ ├── static/
│ │ │ │ │ │ │ └── UFL.txt
│ │ │ │ │ │ └── ubuntu_mono.css
│ │ │ │ │ └── ubuntu-sans/
│ │ │ │ │ ├── README.txt
│ │ │ │ │ ├── UFL.txt
│ │ │ │ │ └── ubuntu_sans.css
│ │ │ │ └── index.html
│ │ │ ├── eslint.config.js
│ │ │ ├── index.html
│ │ │ ├── manifest.webmanifest
│ │ │ ├── package.json
│ │ │ ├── postcss.config.js
│ │ │ ├── public/
│ │ │ │ └── fonts/
│ │ │ │ ├── Inter/
│ │ │ │ │ └── inter.css
│ │ │ │ ├── ibm-plex-mono/
│ │ │ │ │ ├── ibm-plex-mono.css
│ │ │ │ │ └── static/
│ │ │ │ │ └── OFL.txt
│ │ │ │ ├── ubuntu-mono/
│ │ │ │ │ ├── static/
│ │ │ │ │ │ └── UFL.txt
│ │ │ │ │ └── ubuntu_mono.css
│ │ │ │ └── ubuntu-sans/
│ │ │ │ ├── README.txt
│ │ │ │ ├── UFL.txt
│ │ │ │ └── ubuntu_sans.css
│ │ │ ├── setupTests.ts
│ │ │ ├── src/
│ │ │ │ ├── App.css
│ │ │ │ ├── App.tsx
│ │ │ │ ├── components/
│ │ │ │ │ ├── agents-list/
│ │ │ │ │ │ ├── agent-list.module.scss
│ │ │ │ │ │ └── agent-list.tsx
│ │ │ │ │ ├── avatar/
│ │ │ │ │ │ └── avatar.tsx
│ │ │ │ │ ├── canned-response/
│ │ │ │ │ │ └── canned-response.tsx
│ │ │ │ │ ├── canned-responses/
│ │ │ │ │ │ └── canned-responses.tsx
│ │ │ │ │ ├── chat-header/
│ │ │ │ │ │ └── chat-header.tsx
│ │ │ │ │ ├── chatbot/
│ │ │ │ │ │ └── chatbot.tsx
│ │ │ │ │ ├── dark-mode-toggle/
│ │ │ │ │ │ └── dark-mode-toggle.tsx
│ │ │ │ │ ├── error-boundary/
│ │ │ │ │ │ └── error-boundary.tsx
│ │ │ │ │ ├── gradient-button/
│ │ │ │ │ │ ├── gradient-button.module.scss
│ │ │ │ │ │ └── gradient-button.tsx
│ │ │ │ │ ├── header-wrapper/
│ │ │ │ │ │ └── header-wrapper.tsx
│ │ │ │ │ ├── log-filters/
│ │ │ │ │ │ └── log-filters.tsx
│ │ │ │ │ ├── markdown/
│ │ │ │ │ │ └── markdown.tsx
│ │ │ │ │ ├── message/
│ │ │ │ │ │ ├── draft-bubble.tsx
│ │ │ │ │ │ ├── message-bubble.tsx
│ │ │ │ │ │ ├── message-relative-time.tsx
│ │ │ │ │ │ ├── message.module.scss
│ │ │ │ │ │ └── message.tsx
│ │ │ │ │ ├── message-details/
│ │ │ │ │ │ ├── empty-state.tsx
│ │ │ │ │ │ ├── filter-tabs.tsx
│ │ │ │ │ │ ├── flag-message.tsx
│ │ │ │ │ │ ├── indexeddb-data.tsx
│ │ │ │ │ │ ├── message-details-header.tsx
│ │ │ │ │ │ ├── message-details.tsx
│ │ │ │ │ │ ├── message-log.tsx
│ │ │ │ │ │ └── message-logs.tsx
│ │ │ │ │ ├── progress-logo/
│ │ │ │ │ │ └── progress-logo.tsx
│ │ │ │ │ ├── session-list/
│ │ │ │ │ │ ├── session-list-item/
│ │ │ │ │ │ │ ├── session-list-item.module.scss
│ │ │ │ │ │ │ └── session-list-item.tsx
│ │ │ │ │ │ └── session-list.tsx
│ │ │ │ │ ├── session-view/
│ │ │ │ │ │ ├── date-header/
│ │ │ │ │ │ │ └── date-header.tsx
│ │ │ │ │ │ ├── session-view-header/
│ │ │ │ │ │ │ └── session-view-header.tsx
│ │ │ │ │ │ ├── session-view.module.scss
│ │ │ │ │ │ └── session-view.tsx
│ │ │ │ │ ├── ui/
│ │ │ │ │ │ ├── button.tsx
│ │ │ │ │ │ ├── checkbox.tsx
│ │ │ │ │ │ ├── custom/
│ │ │ │ │ │ │ ├── copy-text.tsx
│ │ │ │ │ │ │ ├── line-no-div.tsx
│ │ │ │ │ │ │ ├── spacer.tsx
│ │ │ │ │ │ │ └── tooltip.tsx
│ │ │ │ │ │ ├── dialog.tsx
│ │ │ │ │ │ ├── drawer.tsx
│ │ │ │ │ │ ├── dropdown-menu.tsx
│ │ │ │ │ │ ├── input.tsx
│ │ │ │ │ │ ├── radio-group.tsx
│ │ │ │ │ │ ├── resizable.tsx
│ │ │ │ │ │ ├── select.tsx
│ │ │ │ │ │ ├── sheet.tsx
│ │ │ │ │ │ ├── skeleton.tsx
│ │ │ │ │ │ ├── sonner.tsx
│ │ │ │ │ │ ├── switch.tsx
│ │ │ │ │ │ ├── textarea.tsx
│ │ │ │ │ │ └── tooltip.tsx
│ │ │ │ │ └── virtual-scroll/
│ │ │ │ │ └── virtual-scroll.tsx
│ │ │ │ ├── hooks/
│ │ │ │ │ ├── useDialog.tsx
│ │ │ │ │ ├── useFetch.tsx
│ │ │ │ │ ├── useLocalStorage.ts
│ │ │ │ │ ├── useQuestionDialog.tsx
│ │ │ │ │ └── useWebSocket.ts
│ │ │ │ ├── index.css
│ │ │ │ ├── lib/
│ │ │ │ │ ├── broadcast-channel.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── main.tsx
│ │ │ │ ├── store.ts
│ │ │ │ ├── utils/
│ │ │ │ │ ├── api.ts
│ │ │ │ │ ├── date.tsx
│ │ │ │ │ ├── interfaces.tsx
│ │ │ │ │ ├── logs.ts
│ │ │ │ │ ├── methods.tsx
│ │ │ │ │ ├── obj.tsx
│ │ │ │ │ └── sounds.ts
│ │ │ │ └── vite-env.d.ts
│ │ │ ├── tailwind.config.js
│ │ │ ├── tsconfig.app.json
│ │ │ ├── tsconfig.app.tsbuildinfo
│ │ │ ├── tsconfig.json
│ │ │ ├── tsconfig.node.json
│ │ │ ├── tsconfig.node.tsbuildinfo
│ │ │ └── vite.config.ts
│ │ ├── common.py
│ │ ├── context_variables.py
│ │ ├── customers.py
│ │ ├── evaluations.py
│ │ ├── glossary.py
│ │ ├── guidelines.py
│ │ ├── journeys.py
│ │ ├── logs.py
│ │ ├── relationships.py
│ │ ├── services.py
│ │ ├── sessions.py
│ │ └── tags.py
│ ├── bin/
│ │ ├── client.py
│ │ ├── prepare_migration.py
│ │ └── server.py
│ ├── core/
│ │ ├── agents.py
│ │ ├── app_modules/
│ │ │ ├── agents.py
│ │ │ ├── canned_responses.py
│ │ │ ├── capabilities.py
│ │ │ ├── common.py
│ │ │ ├── context_variables.py
│ │ │ ├── customers.py
│ │ │ ├── evaluations.py
│ │ │ ├── glossary.py
│ │ │ ├── guidelines.py
│ │ │ ├── journeys.py
│ │ │ ├── relationships.py
│ │ │ ├── services.py
│ │ │ ├── sessions.py
│ │ │ └── tags.py
│ │ ├── application.py
│ │ ├── async_utils.py
│ │ ├── background_tasks.py
│ │ ├── canned_responses.py
│ │ ├── capabilities.py
│ │ ├── common.py
│ │ ├── context_variables.py
│ │ ├── customers.py
│ │ ├── emission/
│ │ │ ├── event_buffer.py
│ │ │ └── event_publisher.py
│ │ ├── emissions.py
│ │ ├── engines/
│ │ │ ├── alpha/
│ │ │ │ ├── canned_response_generator.py
│ │ │ │ ├── engine.py
│ │ │ │ ├── engine_context.py
│ │ │ │ ├── entity_context.py
│ │ │ │ ├── guideline_matching/
│ │ │ │ │ ├── common.py
│ │ │ │ │ ├── custom_guideline_matching_strategy.py
│ │ │ │ │ ├── generic/
│ │ │ │ │ │ ├── common.py
│ │ │ │ │ │ ├── disambiguation_batch.py
│ │ │ │ │ │ ├── generic_guideline_matching_strategy.py
│ │ │ │ │ │ ├── guideline_actionable_batch.py
│ │ │ │ │ │ ├── guideline_low_criticality_batch.py
│ │ │ │ │ │ ├── guideline_previously_applied_actionable_batch.py
│ │ │ │ │ │ ├── guideline_previously_applied_actionable_customer_dependent_batch.py
│ │ │ │ │ │ ├── journey/
│ │ │ │ │ │ │ ├── journey_backtrack_check.py
│ │ │ │ │ │ │ ├── journey_backtrack_node_selection.py
│ │ │ │ │ │ │ ├── journey_next_step_selection.py
│ │ │ │ │ │ │ └── journey_node_selection_batch.py
│ │ │ │ │ │ ├── observational_batch.py
│ │ │ │ │ │ └── response_analysis_batch.py
│ │ │ │ │ ├── generic_guideline_matching_strategy_resolver.py
│ │ │ │ │ ├── guideline_match.py
│ │ │ │ │ ├── guideline_matcher.py
│ │ │ │ │ └── guideline_matching_context.py
│ │ │ │ ├── hooks.py
│ │ │ │ ├── message_event_composer.py
│ │ │ │ ├── message_generator.py
│ │ │ │ ├── optimization_policy.py
│ │ │ │ ├── perceived_performance_policy.py
│ │ │ │ ├── planners.py
│ │ │ │ ├── planning/
│ │ │ │ │ └── __init__.py
│ │ │ │ ├── prompt_builder.py
│ │ │ │ ├── relational_resolver.py
│ │ │ │ ├── tool_calling/
│ │ │ │ │ ├── default_tool_call_batcher.py
│ │ │ │ │ ├── overlapping_tools_batch.py
│ │ │ │ │ ├── single_tool_batch.py
│ │ │ │ │ └── tool_caller.py
│ │ │ │ ├── tool_event_generator.py
│ │ │ │ └── utils.py
│ │ │ └── types.py
│ │ ├── entity_cq.py
│ │ ├── evaluations.py
│ │ ├── glossary.py
│ │ ├── guideline_tool_associations.py
│ │ ├── guidelines.py
│ │ ├── journey_guideline_projection.py
│ │ ├── journeys.py
│ │ ├── loggers.py
│ │ ├── meter.py
│ │ ├── nlp/
│ │ │ ├── embedding.py
│ │ │ ├── generation.py
│ │ │ ├── generation_info.py
│ │ │ ├── moderation.py
│ │ │ ├── policies.py
│ │ │ ├── service.py
│ │ │ └── tokenization.py
│ │ ├── persistence/
│ │ │ ├── common.py
│ │ │ ├── data_collection.py
│ │ │ ├── document_database.py
│ │ │ ├── document_database_helper.py
│ │ │ ├── vector_database.py
│ │ │ └── vector_database_helper.py
│ │ ├── relationships.py
│ │ ├── services/
│ │ │ ├── indexing/
│ │ │ │ ├── behavioral_change_evaluation.py
│ │ │ │ ├── common.py
│ │ │ │ ├── customer_dependent_action_detector.py
│ │ │ │ ├── guideline_action_proposer.py
│ │ │ │ ├── guideline_agent_intention_proposer.py
│ │ │ │ ├── guideline_continuous_proposer.py
│ │ │ │ ├── journey_reachable_nodes_evaluation.py
│ │ │ │ ├── relative_action_proposer.py
│ │ │ │ └── tool_running_action_detector.py
│ │ │ └── tools/
│ │ │ ├── mcp_service.py
│ │ │ ├── openapi.py
│ │ │ ├── plugins.py
│ │ │ └── service_registry.py
│ │ ├── sessions.py
│ │ ├── shots.py
│ │ ├── tags.py
│ │ ├── tools.py
│ │ ├── tracer.py
│ │ └── version.py
│ ├── py.typed
│ └── sdk.py
└── tests/
├── __init__.py
├── adapters/
│ ├── db/
│ │ ├── test_chroma.py
│ │ ├── test_json_file.py
│ │ ├── test_mongodb.py
│ │ └── test_snowflake_db.py
│ ├── nlp/
│ │ ├── test_azure_service.py
│ │ ├── test_litellm_service.py
│ │ ├── test_openrouter_service.py
│ │ ├── test_qwen_service.py
│ │ └── test_zhipu_service.py
│ └── vector_db/
│ ├── test_qdrant.py
│ └── test_transient.py
├── api/
│ ├── conftest.py
│ ├── test_agents.py
│ ├── test_app.py
│ ├── test_authorization.py
│ ├── test_canned_responses.py
│ ├── test_capabilities.py
│ ├── test_context_variables.py
│ ├── test_customers.py
│ ├── test_evaluations.py
│ ├── test_glossary.py
│ ├── test_guidelines.py
│ ├── test_journeys.py
│ ├── test_relationships.py
│ ├── test_services.py
│ ├── test_sessions.py
│ ├── test_tags.py
│ └── test_websocket_logger.py
├── conftest.py
├── core/
│ ├── .gitkeep
│ ├── common/
│ │ ├── engines/
│ │ │ └── alpha/
│ │ │ ├── steps/
│ │ │ │ ├── agents.py
│ │ │ │ ├── canned_responses.py
│ │ │ │ ├── capabilities.py
│ │ │ │ ├── context_variables.py
│ │ │ │ ├── customers.py
│ │ │ │ ├── engines.py
│ │ │ │ ├── events.py
│ │ │ │ ├── guidelines.py
│ │ │ │ ├── journeys.py
│ │ │ │ ├── sessions.py
│ │ │ │ ├── tags.py
│ │ │ │ ├── terms.py
│ │ │ │ └── tools.py
│ │ │ └── utils.py
│ │ └── utils.py
│ ├── conftest.py
│ ├── stable/
│ │ ├── engines/
│ │ │ └── alpha/
│ │ │ ├── features/
│ │ │ │ ├── baseline/
│ │ │ │ │ ├── capabilities.feature
│ │ │ │ │ ├── context_variables.feature
│ │ │ │ │ ├── conversation.feature
│ │ │ │ │ ├── errors.feature
│ │ │ │ │ ├── glossary.feature
│ │ │ │ │ ├── journeys.feature
│ │ │ │ │ ├── moderation.feature
│ │ │ │ │ ├── proactivity.feature
│ │ │ │ │ ├── relationships.feature
│ │ │ │ │ ├── strict_canned_responses.feature
│ │ │ │ │ ├── strict_canned_responses_capabilities.feature
│ │ │ │ │ ├── supervision.feature
│ │ │ │ │ ├── tools.feature
│ │ │ │ │ └── triggered_utterances.feature
│ │ │ │ └── user_stories/
│ │ │ │ └── conversation.feature
│ │ │ ├── test_baseline_scenarios.py
│ │ │ ├── test_context_variable_loading.py
│ │ │ ├── test_disambiguation_batch.py
│ │ │ ├── test_generic_response_analysis.py
│ │ │ ├── test_guideline_actionable_batch.py
│ │ │ ├── test_guideline_low_criticality_batch.py
│ │ │ ├── test_guideline_matcher.py
│ │ │ ├── test_journey_node_selection.py
│ │ │ ├── test_mcp.py
│ │ │ ├── test_previously_applied_actionable_batch.py
│ │ │ ├── test_previously_applied_actionable_customer_dependent_batch.py
│ │ │ ├── test_relational_resolver.py
│ │ │ ├── test_tool_caller.py
│ │ │ └── test_user_story_scenarios.py
│ │ ├── nlp/
│ │ │ ├── test_embedding.py
│ │ │ └── test_generation.py
│ │ ├── persistence/
│ │ │ └── test_matches_filters.py
│ │ ├── services/
│ │ │ ├── indexing/
│ │ │ │ ├── test_agent_intention_proposer.py
│ │ │ │ ├── test_continuous_guideline_proposer.py
│ │ │ │ ├── test_customer_dependent_action_detector.py
│ │ │ │ ├── test_guideline_action_proposer.py
│ │ │ │ ├── test_relative_action_step_proposer.py
│ │ │ │ └── test_tool_running_action_detector.py
│ │ │ └── tools/
│ │ │ ├── test_openapi.py
│ │ │ └── test_plugin_client.py
│ │ ├── test_application.py
│ │ ├── test_capability_vector_store.py
│ │ ├── test_entity_cq.py
│ │ ├── test_journey_guideline_projection.py
│ │ └── test_relationships.py
│ ├── test_cancellation_suppression_latch.py
│ ├── test_id_generator.py
│ └── unstable/
│ └── engines/
│ └── alpha/
│ ├── features/
│ │ ├── baseline/
│ │ │ ├── conversation.feature
│ │ │ ├── fluid_canned_responses.feature
│ │ │ ├── glossary.feature
│ │ │ ├── strict_canned_responses.feature
│ │ │ ├── supervision.feature
│ │ │ └── tools.feature
│ │ └── user_stories/
│ │ └── conversation.feature
│ ├── test_agent_intention_proposer.py
│ ├── test_baseline_scenarios.py
│ ├── test_disambiguation_batch.py
│ ├── test_guideline_matcher.py
│ ├── test_journey_node_selection.py
│ ├── test_previously_applied_actionable_batch.py
│ └── test_user_story_scenarios.py
├── data/
│ └── get_products_by_type_data.json
├── e2e/
│ ├── conftest.py
│ ├── test_client_cli_via_api.py
│ ├── test_server_cli.py
│ └── test_utilities.py
├── modules/
│ ├── bank.py
│ ├── mcp_parrot.py
│ └── tech_store.py
├── sdk/
│ ├── conftest.py
│ ├── test_agents.py
│ ├── test_canned_responses.py
│ ├── test_current_entities.py
│ ├── test_customers.py
│ ├── test_dynamic_composition_mode.py
│ ├── test_glossary.py
│ ├── test_guidelines.py
│ ├── test_journeys.py
│ ├── test_labels.py
│ ├── test_planners.py
│ ├── test_retrievers.py
│ ├── test_sdk_validation.py
│ ├── test_server.py
│ ├── test_tools.py
│ ├── test_variables.py
│ └── utils.py
├── test_utilities.py
└── tool_utilities.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .devcontainer/Dockerfile
================================================
FROM mcr.microsoft.com/devcontainers/base:ubuntu-24.04
ARG DEBIAN_FRONTEND=noninteractive
ARG USER=vscode
RUN DEBIAN_FRONTEND=noninteractive \
&& apt-get update \
&& apt-get install -y build-essential --no-install-recommends make \
ca-certificates \
bash-completion \
git \
just \
libssl-dev \
zlib1g-dev \
libbz2-dev \
libreadline-dev \
libsqlite3-dev \
wget \
curl \
llvm \
libncurses5-dev \
xz-utils \
tk-dev \
libxml2-dev \
libxmlsec1-dev \
libffi-dev \
liblzma-dev
# Python and poetry installation
USER $USER
ARG HOME="/home/$USER"
ARG PYTHON_VERSION=3.10
ENV PYENV_ROOT="${HOME}/.pyenv"
ENV PATH="${PYENV_ROOT}/shims:${PYENV_ROOT}/bin:${HOME}/.local/bin:$PATH"
EXPOSE 8800
RUN echo "Configuring Python environment" \
&& curl https://pyenv.run | bash \
&& pyenv install ${PYTHON_VERSION} \
&& pyenv global ${PYTHON_VERSION} \
&& curl -LsSf https://astral.sh/uv/install.sh | sh \
&& pip install ruff semver toml
================================================
FILE: .devcontainer/devcontainer.json
================================================
{
"name": "uv-pyenv",
"build": {
"dockerfile": "Dockerfile"
},
// "features": {},
// 👇 Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// 👇 Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "(cd /workspaces/parlant* && git config --global --add safe.directory $PWD && python ./scripts/initialize_repo.py)",
// 👇 Configure tool-specific properties.
"customizations": {
"vscode": {
"extensions": [
"alexkrechik.cucumberautocomplete",
"charliermarsh.ruff",
"github.remotehub",
"github.vscode-github-actions",
"GitHub.vscode-pull-request-github",
"hbenl.vscode-test-explorer",
"matangover.mypy",
"ms-azuretools.vscode-docker",
"ms-python.debugpy",
"ms-python.python",
"ms-python.vscode-pylance",
"mutantdino.resourcemonitor",
"njpwerner.autodocstring",
"tamasfe.even-better-toml",
"streetsidesoftware.code-spell-checker"
]
}
},
// 👇 Features to add to the Dev Container. More info: https://containers.dev/implementors/features.
"features": {
"ghcr.io/devcontainers-extra/features/mypy:2": {
"version": "latest"
},
"node": {
"version": "lts",
"nodeGypDependencies": true
}
},
"mounts": [],
// 👇 Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
"containerEnv": {
"OPENAI_API_KEY": "${localEnv:OPENAI_API_KEY}"
},
"remoteEnv": {
"OPENAI_API_KEY": "${localEnv:OPENAI_API_KEY}"
}
}
================================================
FILE: .githooks/pre-commit
================================================
#!/bin/bash
ROOT=$(git rev-parse --show-toplevel)
cd $ROOT
python scripts/lint.py --ruff
================================================
FILE: .githooks/pre-push
================================================
#!/bin/bash
ROOT=$(git rev-parse --show-toplevel)
cd $ROOT
python scripts/lint.py --mypy --ruff
================================================
FILE: .githooks/prepare-commit-msg
================================================
#!/bin/bash
# A git commit hook that will automatically append a DCO signoff to the bottom
# of any commit message that does not have one. This append happens after the git
# default message is generated, but before the user is dropped into the commit
# message editor.
ROOT=$(git rev-parse --show-toplevel)
cd $ROOT
COMMIT_MESSAGE_FILE="$1"
AUTHOR=$(git var GIT_AUTHOR_IDENT)
SIGNOFF=$(echo "$AUTHOR" | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# Check for DCO signoff message. If one does not exist, append one and then warn
# the user that you did so.
if ! grep -qs "^$SIGNOFF" "$COMMIT_MESSAGE_FILE"; then
echo -e "\n$SIGNOFF" >> "$COMMIT_MESSAGE_FILE"
echo -e "Appended the following signoff to the end of the commit message:\n $SIGNOFF\n"
fi
================================================
FILE: .github/ISSUE_TEMPLATE/bug-report.md
================================================
---
name: Bug Report
about: Create a report to help us improve
title: "[Bug] <Replace this with a descriptive title>"
labels: bug
assignees: ''
---
# Description
A clear and concise description of what the bug is.
# How to Reproduce
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
# Expected Behavior
A clear and concise description of what you expected to happen.
# Environment
- OS: [e.g. iOS]
- Python version [e.g. 3.12]
- Parlant version [e.g. 1.5.1]
# Discussion
Add any other context or open questions about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature-request.md
================================================
---
name: Feature Request
about: Suggest an idea for this project
title: "[Enhancement] <Replace this with a descriptive title>"
labels: enhancement
assignees: ''
---
# Motivation
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
# Solution Proposal
A clear and concise description of what you want to happen.
# Discussion
Add any other context or open questions about the feature request here.
================================================
FILE: .github/dco.yml
================================================
allowRemediationCommits:
individual: true
require:
members: false
================================================
FILE: .github/workflows/ci-test.yml
================================================
name: Verify and Test
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "develop" ]
jobs:
build:
runs-on: ubuntu-24.04
strategy:
matrix:
python-version: ["3.10"]
steps:
- name: checkout branch commit
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install uv
run: pip install uv
- name: Initial Configs
run: |
git config --local core.hooksPath .githooks/
chmod +x .githooks/pre-commit .githooks/pre-push
- name: Install packages
run: python scripts/install_packages.py
- name: install just
uses: extractions/setup-just@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Test Parlant (deterministic)
if: always()
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: just test-deterministic
- name: Test Parlant (core-stable)
if: always()
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: just test-core-stable
- name: Test Parlant (core-unstable)
if: always()
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: just test-core-unstable
- name: test log artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: testresults
path: logs/*
================================================
FILE: .github/workflows/docker-publish.yml
================================================
name: Docker
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
on:
schedule:
- cron: '44 23 * * *'
push:
branches: [ "develop" ]
# Publish semver tags as releases.
tags: [ 'v*.*.*' ]
pull_request:
branches: [ "develop" ]
env:
# Use docker.io for Docker Hub if empty
REGISTRY: ghcr.io
# github.repository as <account>/<repo>
IMAGE_NAME: emcie-co/parlant
jobs:
build:
runs-on: ubuntu-24.04
permissions:
contents: read
packages: write
# This is used to complete the identity challenge
# with sigstore/fulcio when running outside of PRs.
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Install the cosign tool except on PR
# https://github.com/sigstore/cosign-installer
- name: Install cosign
if: github.event_name != 'pull_request'
uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 #v3.5.0
with:
cosign-release: 'v2.2.4'
# Set up BuildKit Docker container builder to be able to build
# multi-platform images and export cache
# https://github.com/docker/setup-buildx-action
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
# Login against a Docker registry except on PR
# https://github.com/docker/login-action
- name: Log into registry ${{ env.REGISTRY }}
if: github.event_name != 'pull_request'
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Extract metadata (tags, labels) for Docker
# https://github.com/docker/metadata-action
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@96383f45573cb7f253c731d3b3ab81c87ef81934 # v5.0.0
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=edge
# Remove unused packages and directories to free up space for a (possibly large) Docker build
- name: Cleanup disk space
run: |
chmod +x ./scripts/ci/github_action_ubuntu_2404_free_space.sh
./scripts/ci/github_action_ubuntu_2404_free_space.sh
# Build and push Docker image with Buildx (don't push on PR)
# https://github.com/docker/build-push-action
- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0
with:
context: .
file: ./Dockerfile
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# Sign the resulting Docker image digest except on PRs.
# This will only write to the public Rekor transparency log when the Docker
# repository is public to avoid leaking data. If you would like to publish
# transparency data even for private images, pass --force to cosign below.
# https://github.com/sigstore/cosign
- name: Sign the published Docker image
if: ${{ github.event_name != 'pull_request' }}
env:
# https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable
TAGS: ${{ steps.meta.outputs.tags }}
DIGEST: ${{ steps.build-and-push.outputs.digest }}
# This step uses the identity token to provision an ephemeral certificate
# against the sigstore community Fulcio instance.
run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST}
================================================
FILE: .github/workflows/lint.yml
================================================
name: Lint
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-24.04
strategy:
matrix:
python-version: ["3.10"]
steps:
- name: checkout branch commit
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install uv
run: pip install uv
- name: Initial Configs
run: |
git config --local core.hooksPath .githooks/
chmod +x .githooks/pre-commit .githooks/pre-push
- name: Install packages
run: python scripts/install_packages.py
continue-on-error: false
- name: Lint packages
run: python scripts/lint.py
continue-on-error: false
================================================
FILE: .gitignore
================================================
.env
.pytest_cache
.mypy_cache
.ruff_cache
__pycache__
.justfile
testresults**
tests/core/persistence/test_cache/*.json
data/*.json
cache/
.coverage
.DS_STORE
*~
.vscode
.venv
.cursor
logs
runtime-data
parlant-data
/dist/
scripts/sdks/
scripts/fern/openapi
fern.generate.log
schematic_generation_test_cache.json
test_timing.csv
================================================
FILE: CHANGELOG.md
================================================
# Changelog
All notable changes to Parlant will be documented here.
## [Unreleased]
### Changed
- Change tag dependency semantics from ALL to ANY: a dependency on a tag is now satisfied when at least one tagged member (guideline, observation, or journey) is active, rather than requiring all of them
### Fixed
- Fix `Variable.get_value()` returning `None` when called from a retriever, caused by retrievers starting before context variables were loaded
## [3.3.0] - 2025-03-15
### Added
- Add per-agent planners via `Server.create_agent(planner=...)`, allowing each agent to use a custom `Planner` implementation
- Accept `Tag` as a target in `depend_on()`, `exclude()`, and `prioritize_over()` on both `Guideline` and `Tag`, enabling relationships that target all guidelines sharing a custom tag
- Add `Tag.depend_on()`, `Tag.exclude()`, and `Tag.prioritize_over()` methods to the SDK, enabling tag-based dependency and priority relationships with guidelines and journeys
- Support custom TAG as source for DEPENDENCY relationships in the relational resolver
- Add `tags` parameter to `create_guideline`, `create_observation`, and `create_journey` on both `Agent` and `Journey`, allowing custom tags to be attached to entities at creation time
- Add `Tag.reevaluate_after()` method to the SDK, enabling tag-based reevaluation relationships with tools
- Add tag-based reevaluation support in the engine: when a tool fires, all guidelines carrying a tag that has a reevaluation relationship with that tool are now re-evaluated
- Add staged_events to GuidelineMatchingContext in SDK
- Add `priority` property to guidelines and journeys for priority-based filtering in the relational resolver
- Add transient guidelines (renamed from tool-provided guidelines), allowing tools to dynamically inject behavioral guidelines into the agent's context
- Add `Agent.utter()` to the SDK, enabling programmatic agent message generation with transient guidelines
- Add `Customer.update()` and `CustomerMetadata` to the SDK, allowing tools to update customer name and metadata
- Add `Session.update()`, `SessionMetadata`, and `SessionLabels` to the SDK, allowing tools to update session properties, metadata, and labels
- Add `customer`, `agent`, `mode`, and `title` properties to SDK `Session` class
- Add `Server.get_tag()` to the SDK, supporting lookup by either `id` or `name`
- Add name-based filtering to `TagStore.list_tags()` and the `GET /tags` API endpoint via an optional `name` query parameter
- Enforce tag name uniqueness in `TagStore`, raising an error when creating a tag with a duplicate name
### Changed
- Made extended thinking indicator optional in perceived performance policy
- Change `reevaluate_after()` on `Tag` and `Guideline` to accept multiple tools (`*tools`) and return `Sequence[Relationship]`
- Change `tags` field type from `Sequence[TagId]` to `Sequence[Tag]` on `Guideline`, `Journey`, `Capability`, `Term`, `Variable`, `Customer`, and `Agent` in the SDK
- Change `Tag.preamble()` to return a full `Tag` object instead of a `TagId`
- Upgrade MCP service and bump dependency versions to resolve security vulnerabilities
### Deprecated
- OpenAPI tool services are now deprecated; please migrate to SDK tool services
### Fixed
- Fix deadlock when sending a new message right after a preamble
- Fix transitive filtering in relational resolver for custom tag dependency targets (guidelines depending on a custom tag are now correctly deactivated when a tagged member is deprioritized)
- Fix SSE `read_event` endpoint stalling after first streaming chunk until full completion
- Fix response analysis logs not always reaching the integrated UI
- Fix guideline formatting in canned response and streaming modes when condition is absent
- Fix AzureService small text embedding dimension size
- Fix onnxruntime compatibility with Python 3.10 and transformers 5.x type changes
- Fix agent intention proposer prompt clarification
- Fix embedding LRU cache eviction corrupting the length index when entries share the same text length
- Fix LiteLLMEmbedder failing to resolve via lagom container when LITELLM_EMBEDDING_MODEL_NAME is set
- Fix non-consequential tool calls being rejected when optional parameters are missing
### Removed
- Remove stale `parlant-test` entry point and testing framework documentation from README
## [3.2.2] - 2025-02-18
### Added
- Added p.MATCH_ALWAYS, now the preferred alias to p.Guideline.MATCH_ALWAYS
- Added `logger` property to p.Server
### Changed
- Adjusted log levels of relational resolver to trace instead of debug
- Allow tool context parameter names to be all of 'context', 'ctx', and 'c'
### Fixed
- Fix completed streamed messages re-animating on page refresh
- Propagate `Server.current` context to tool functions in hosted plugin server
## [3.2.1] - 2026-02-17
### Added
- Add optional `dependencies` parameter to guideline, observation, and journey creation methods
- Add `exclude()` as an alias for `prioritize_over()` on guidelines and journeys
- Add `tools` parameter to `create_observation` methods
### Changed
- Deprecate `attach_tool()` in favor of `create_guideline()`/`create_observation()` with `tools` parameter
### Fixed
- Preserve draft message language during canned response recomposition
- Fix server hang when an exception occurs during setup
- Fix canned response field extraction to handle falsy values
## [3.2.0] - 2026-02-08
### Added
- Add labels to Guidelines, Journeys, JourneyNodes, and Sessions for categorization and filtering
- Add automatic session label propagation from matched entities (guidelines, observations, journeys)
- Add `track` parameter to guidelines to control "previously applied" tracking
- Support multiple targets in `prioritize_over()` and `depend_on()` methods
- Add `field_dependencies` to canned responses for explicit field availability requirements
- Add `attach_retriever()` to Guideline, Journey, and JourneyState for conditional data retrieval
- Add `on_match` and `on_message` hooks to journeys for lifecycle callbacks
- Add per-agent preamble configuration (custom examples and instructions)
- Add separate default greeting responses for first agent message in fluid mode
- Add streaming message output mode
- Allow specifying custom journey node ID
- Add matched guidelines/journey states to completion ready event
### Changed
- Make condition optional for SDK guidelines
- Tweak default preamble examples
- Soften log levels for relational guideline resolver
- Add activated/skipped logs to custom guideline matcher batches
### Fixed
- Fix websocket warning upon startup
- Fix agent intention proposer (guidelines were getting rewritten incorrectly)
- Fix multiple customer guideline matchers not working
- Fix bug with context variable access in SDK
## [3.1.0] - 2026-01-05
### Added
- Add .current property for Server, Agent, and Customer in SDK
- Add /healthz endpoint
- Add API for CRUD operations on session metadata
- Add EmcieService
- Add GLM service
- Add Mistral service
- Add OpenRouter service
- Add OpenTelemetry integration for Meter, Logger and Tracer
- Add Qdrant VectorDatabase adapter
- Add Snowflake Cortex service
- Add ability to configure and extend the FastAPI app object
- Add deferred retrievers
- Add dynamic composition mode
- Add follow-up canned responses
- Add guideline criticality level
- Add guideline on_match() hooks
- Add persistence option for context variable values (variable store)
- Added guideline descriptions
- Allow bailing out of canned response selection and utilize the draft directly, using a hook
- Allow controlling max tool result payload via environment variable
- Allow controlling perceived performance policy per agent
- Allow journey transitions from one tool state to another
- Allow specifying custom IDs when creating agents via SDK and API
- Allow specifying custom IDs when creating customers via SDK and API
- Allow specifying custom IDs when creating guidelines, journeys, and glossary terms via SDK and API
- Expose IoC container in server object
- Support adding custom canrep fields to matched guidelines and journey states
- Support code-based, custom guideline matchers
### Changed
- Changed default NLPService to EmcieService
- Improved efficiency of journey state matching when first state is a tool state
- Rename ContextualCorrelator to Tracer
- Rename LoadedContext to EngineContext
- Support proxy URL for LiteLLM
### Fixed
- Fix critical bug with cancellation during response analysis
- Fix critical similarity calculation error in TransientVectorDatabase
- Fix unnecessary extra evaluation of journeys and tools in some edge cases
- Improved Gemini Flash 2.5 output consistency by using function call trick instead of structured outputs
## [3.0.4] - 2025-11-18
### Fixed
- Fix bug where NanoDB query failed when no filters matched
- Extend tool insights across iterations
- Fix deprecated status.HTTP_422_UNPROCESSABLE_ENTITY to status.HTTP_422_UNPROCESSABLE_CONTENT
- Fix broken CLI by adding missing websocket-client dependency
- Added specific classes for embedder initialisation
- Make base url once in OllamaEmbedder
- Update dependencies for security, upgrade FastAPI, fix mypy in hugging_face.py
- Bump torch for fixing vulnerability
## [3.0.3] - 2025-10-23
### Fixed
- Fix installation issue in some environments, failing due to an older FastMCP version
- Bump versions of OpenTelemetry
- Made ChromaDB an extra package parlant[chroma]
- Update NPM dependencies for integrated UI
## [3.0.2] - 2025-08-27
### Added
- Added docs/\* and llms.txt
- Added Vertex NLP service
- Added Ollama NLP service
- Added LiteLLM support to the SDK
- Added Gemini support to the SDK
- Added Journey.create_observation() helper
- Added auth permission READ_AGENT_DESCRIPTION
- Added optional AWS_SESSION_TOKEN to BedrockService
- Support creating status events via the API
### Changed
- Moved tool call success log to DEBUG level
- Optimized canrep to not generate a draft in strict mode if no canrep candidates found
- Removed `acknowledged_event_offset` from status events
- Removed `last_known_event_offset` from `LoadedContext.interaction`
### Fixed
- Fixed presentation of missing API keys for built-in NLP services
- Improvements to canned response generation
- Fixed bug with null journey paths in some cases
- Fixed tiny bug with terminal nodes in journey node selection
- Fixed evaluations not showing properly after version upgrade
## [3.0.1] - 2025-08-16
### Changed
- Move tool call success log to DEBUG level
### Fixed
- Fix tool-based variable not enabling the associated tool on the server
- Fix authorization errors throwing 500 instead of 403
- Changed OpenAI LLM request operation level to TRACE to fix evaluation progress bars
## [3.0.0] - 2025-08-15
- Please see the announcement at https://parlant.io/blog/parlant-3-0-release
## [2.2.0] - 2025-05-20
### Added
- Add journeys
- Add of guideline properties evaluation
- Add automatic guideline action deduction when adding direct tool guidelines
- Added choices of invalid and missing tool parameters to tool insights
### Changed
- Make guideline action optional
## [2.1.2] - 2025-05-07
### Changed
- Remove interaction history from utterance recomposition prompt
- Use tool calls from the entire interaction for utterance field substitution
- Improve error handling and reporting with utterance rendering failures
### Fixed
- Always reason about utterance selection to improve performance
## [2.1.1] - 2025-04-30
### Fixed
- Fixed rendering relationships in CLI
- Fixed parlant client using old imports from python client SDK
## [2.1.0] - 2025-04-29
### Added
- ToolParameterOptions.choice_provider can now access ToolContext
- Added utterance/draft toggle in the integrated UI
- Added new guideline relationship: Dependency
- Added tool relationships and the OVERLAP relationship
- Added the 'overlap' property to tools. By default, tools will be assumed not to overlap with each other, simplifying their evaluation at runtime.
- Introduce ToolBatchers
- Introduce Journey
### Changed
- Improved tool calling efficiency by adjusting the prompt to the tool at hand
- Revised completion schema (ARQs) for tool calling
- Utterances now follow a 2-stage process: draft + select
- Changed guest customer name to Guest
### Fixed
- Fixed deprioritized guidelines always being skipped
- Fixed agent creation with tags
- Fixed client CLI exit status when encountering an error
- Fixed agent update
### Known Issues
- OpenAPI tool services sometimes run into issues due to a version update in aiopenapi3
## [2.0.0] - 2025-04-09
### Added
- Improved tool parameter flexibility: custom types, Pydantic models, and annotated ToolParameterOptions
- Allow returning a new (modified) container in modules using configure_module()
- Added Tool Insights with tool parameter options
- Added support for default values for tool parameters in tool calling
- Added WebSocket logger feature for streaming logs in real time
- Added a log viewer to the sandbox UI
- Added API and CLI for Utterances
- Added support for the --migrate CLI flag to enable seamless store version upgrades during server startup
- Added clear rate limit error logs for NLP adapters
- Added enabled/disabled flag for guidelines to facilitate experimentation without deletion
- Allow different schematic generators to adjust incoming prompts in a structured manner
- Added tags to context variables, guidelines, glossary and agents
- Added guideline matching strategies
- Added guideline relationships
- Added support for tool parameters choice provider using the tool context as argument
### Changed
- Made the message generator slightly more polite by default, following user feedback
- Allow only specifying guideline condition or action when updating guideline from CLI
- Renamed guideline proposer with guideline matcher
### Fixed
- Lowered likelihood of the agent hallucinating facts in fluid mode
- Lowered likelihood of the agent offering services that were not specifically mentioned by the business
## [1.6.2] - 2025-01-29
### Fixed
- Fix loading DeepSeek service during server boot
## [1.6.1] - 2025-01-20
### Fixed
- Fix ToolCaller not getting clear information on a parameter being optional
- Ensure ToolCaller only calls a tool if all required args were given
- Improve valid JSON generation likelihood in MessageEventGenerator
- Improve ToolCaller's ability to correctly run multiple tools at once
## [1.6.0] - 2025-01-19
### Added
- Add shot creation helper functions under Shot
- Add ContextEvaluation in MessageEventGenerator
- Add a log command under client CLI for streaming logs
- Add engine lifecycle hooks
### Changed
- Split vendor dependencies to extra packages to avoid reduce installation time
- Modified ToolCaller shot schema
- Disable coherence and connection checking by default in the CLI for now
### Fixed
- Improved GuidelineProposer's ability to handle compound actions
- Improved GuidelineProposer's ability to distinguish between a fulfilled and unfulfilled action
- Improved GuidelineProposer's ability to detect a previously applied guideline's application to new information
- Reduced likelihood of agent offering hallucinated services
- Fix ToolCaller false-negative argument validation from int to float
- Fix ToolCaller accuracy
- Fix ToolCaller making up argument values when it doesn't have them
- Fix some cases where the ToolCaller also calls a less-fitting tool
- Fix mistake in coherence checker few shots
- Fix markdown tables in sandbox UI
- Fix wrong import of RateLimitError
- Fix PluginServer validation for optional tool arguments when they're passed None
- Fix utterances sometimes not producing a message
## [1.5.1] - 2025-01-05
### Fixed
- Fix server CLI boot
## [1.5.1] - 2025-01-05
### Fixed
- Fix server CLI boot
## [1.5.0] - 2025-01-04
### Added
- Add DeepSeek provider support (via DeepSeekService)
### Changed
- Change default home dir from runtime-data to parlant-data
### Fixed
- Fix tool-calling test
- Fix HuggingFace model loading issues
## [1.4.3] - 2025-01-02
### Fixed
- Upgraded dependency "tiktoken" to 0.8.0 to fix installation errors on some environments
## [1.4.2] - 2024-12-31
### Fixed
- Fix race condition in JSONFileDocumentDatabase when deleting or updating documents
## [1.4.1] - 2024-12-31
### Changed
- Remove tool metadata from prompts - agents are now only aware of the data itself
### Fixed
- Fix tool calling in scenarios where a guideline has multiple tools where more than one should run
## [1.4.0] - 2024-12-31
### Added
- Support custom plugin data for PluginServer
- Allow specifying custom logger ID when creating loggers
- Add 'hosted' parameter to PluginServer, for running inside modules
### Fixed
- Fix the tool caller's few shots to include better rationales and arguments.
## [1.3.1] - 2024-12-27
### Changed
- Return event ID instead of trace ID from utterance API
- Improve and normalize entity update messages in client CLI
## [1.3.0] - 2024-12-26
### Added
- Add manual utterance requests
- Refactor few-shot examples and allow adding more examples from a module
- Allow tapping into the PluginServer FastAPI app to provide additional custom endpoints
- Support for union parameters ("T | None") in tool functions
### Changed
- Made all stores thread-safe with reader/writer locks
- Reverted GPT version for guideline connection proposer to 2024-08-06
- Changed definition of causal connection to take the source's when statement into account. The connection proposer now assumes the source's condition is true when examining if it entails other guideline.
### Fixed
- Fix 404 not being returned if a tool service isn't found
- Fix having direct calls to asyncio.gather() instead of safe_gather()
### Removed
- Removed connection kind (entails / suggests) from the guideline connection proposer and all places downstream. the connection_kind argument is no longer needed or supported for all guideline connections.
## [1.2.0] - 2024-12-19
### Added
- Expose deletion flag for events in Session API
### Changed
- Print traceback when reporting server boot errors
- Make cancelled operations issue a warning rather than an error
### Fixed
- Fixed tool calling with optional parameters
- Fixed sandbox UI issues with message regeneration and status icon
- Fixed case where guideline is applied due to condition being partially applied
### Removed
None
## [1.1.0] - 2024-12-18
### Added
- Customer selection in sandbox Chat UI
- Support tool calls with freshness rules for context variables
- Add support for loading external modules for changing engine behavior programmatically
- CachedSchematicGenerator to run the test suite more quickly
- TransientVectorDatabase to run the test suite more quickly
### Changed
- Changed model path for Chroma documents. You may need to delete your `runtime-data` dir.
### Fixed
- Improve handling of partially fulfilled guidelines
### Removed
None
================================================
FILE: CLAUDE.md
================================================
This is the main repo of Parlant (https://parlant.io).
Parlant is a Python based agent framework. Its core strengths:
1. It allows you to create compliant and controlled AI agents for customer-facing use cases
2. It provides many conversational management features out of the box
3. It's built for enterprise, large-scale use cases, where SLAs, stability and security are paramount
The repo's structure follows the Hexagonal Architecture (Ports and Adapters) approach.
- src/parlant
- core: Core framework code
- adapters: Implementations of interfaces using 3rd party tools
- api: REST API layer using FastAPI. Uses modules from core/
- tests: all tests for the project. Structure strives to mirror that which is under src/parlant.
General Coding Instructions:
- Always ensure you stick to Hexagonal Architecture patterns in line with how they're used in this codebase.
- Every time you add something, look for similar things in the codebase and ensure you follow the coding style.
- We use MyPy on strict mode. Every parameter needs to be type-annotated. Every function's result too.
- If you need to add a test for something, first say where you plan to add it and ask for confirmation.
- We follow TDD. When you make a change, first create a failing test. Once it fails, implement just enough so it passes.
- If you need to test classes/methods in sdk.py (or generally to test things that relate to engine behavior) make sure you inherit from SDKTest and understand how it works and how to use it.
- Test names should go "test*that*..." using clear names that explain the context, what is executed, and what is the expected result.
- You can run tests using pytest. Make sure you run "uv run pytest tests/path/to/test/file.py" while also specifying the test name that you need to run.
Always follow this plan when asked to code a feature or fix a bug:
1. Consider the codebase's structure
2. Describe your implementation plan, including:
a. What tests you will write (test names + files they would live in)
b. Why do you think the tests would initially fail
c. Where you would plan to implement the code that would make the tests pass
3. Ask for plan confirmation. If you get feedback, revise your plan and ask for confirmation again until you get it.
4. Implement the tests first. Ask for confirmation and code review.
5. Once tests are approved, once again suggest your implementation plan for making them pass, and get plan review until confirmation.
6. Once your implementation plan is confirmed, go ahead with implementing the code to pass them.
7. Make sure to format all of the files you changed using ruff (it is installed in the environment).
8. Run `uv run python scripts/lint.py --mypy --ruff` to ensure your code has no lint issues.
================================================
FILE: CONTRIBUTING.md
================================================
# DCO Sign Off
All commits must be signed off with the Developer Certificate of Origin ([DCO.md](DCO.md)).
This attests that you have the rights to submit your contribution under our project's license (Apache 2.0).
To sign off your commits:
1. Configure your Git client with your github account details:
```
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"
```
2. If you've configured git to use our hooks (`.githooks`), you are now ready. Otherwise, either:
1. use our `.githooks`:
```
git config set core.hookspath .githooks
```
**OR**
2. Add the `-s` flag when committing:
```
git commit -s -m "Your commit message"
```
### Or
* Add the sign-off manually with:
```
Signed-off-by: Your Name <your.email@example.com>
```
================================================
FILE: DCO.md
================================================
Developer Certificate of Origin
Version 1.1
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2025 Emcie Co Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
<div align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/emcie-co/parlant/blob/develop/docs/LogoTransparentLight.png?raw=true">
<img alt="Parlant" src="https://github.com/emcie-co/parlant/blob/develop/docs/LogoTransparentDark.png?raw=true" width=400 />
</picture>
### The conversational control layer for customer-facing AI agents
<p>
<a href="https://pypi.org/project/parlant/"><img alt="PyPI" src="https://img.shields.io/pypi/v/parlant?color=blue"></a>
<img alt="Python 3.10+" src="https://img.shields.io/badge/python-3.10+-blue">
<a href="https://opensource.org/licenses/Apache-2.0"><img alt="License" src="https://img.shields.io/badge/license-Apache%202.0-green"></a>
<a href="https://discord.gg/duxWqxKk6J"><img alt="Discord" src="https://img.shields.io/discord/1312378700993663007?color=7289da&logo=discord&logoColor=white"></a>
<img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/emcie-co/parlant?style=social">
</p>
<p>
<a href="https://www.parlant.io/" target="_blank">Website</a> •
<a href="https://www.parlant.io/docs/quickstart/installation" target="_blank">Quick Start</a> •
<a href="https://www.parlant.io/docs/quickstart/examples" target="_blank">Examples</a> •
<a href="https://discord.gg/duxWqxKk6J" target="_blank">Discord</a>
</p>
<p>
<a href="https://zdoc.app/de/emcie-co/parlant">Deutsch</a> |
<a href="https://zdoc.app/es/emcie-co/parlant">Español</a> |
<a href="https://zdoc.app/fr/emcie-co/parlant">français</a> |
<a href="https://zdoc.app/ja/emcie-co/parlant">日本語</a> |
<a href="https://zdoc.app/ko/emcie-co/parlant">한국어</a> |
<a href="https://zdoc.app/pt/emcie-co/parlant">Português</a> |
<a href="https://zdoc.app/ru/emcie-co/parlant">Русский</a> |
<a href="https://zdoc.app/zh/emcie-co/parlant">中文</a>
</p>
<a href="https://trendshift.io/repositories/12768" target="_blank">
<img src="https://trendshift.io/api/badge/repositories/12768" alt="Trending" style="width: 250px; height: 55px;" width="250" height="55"/>
</a>
</div>
**Parlant streamlines conversational context engineering for enterprise-grade B2C (business to consumer) and sensitive B2B interactions that need to be consistent, compliant, and on-brand.**
## Why Parlant?
Conversational context engineering is hard because real-world interactions are diverse, nuanced, and non-linear.
### ❌ The Problem: What you've probably tried and couldn't get to work at scale
**System prompts** work until production complexity kicks in. The more instructions you add to a prompt, the faster your agent stops paying attention to any of them.
**Routed graphs** solve the prompt-overload problem, but the more routing you add, the more fragile it becomes when faced with the chaos of natural interactions.
### 🔑 The Solution: Context engineering, optimized for conversational control
Parlant solves this with [context engineering](https://www.gartner.com/en/articles/context-engineering): getting the right context, no more and no less, into the prompt at the right time. You define your rules, knowledge, and tools once; the engine narrows the context in real-time to what's immediately relevant to the current turn.
<img alt="Parlant Demo" src="https://github.com/emcie-co/parlant/blob/develop/docs/demo.gif?raw=true" width="100%" />
## Getting started
```bash
pip install parlant
```
```python
import parlant.sdk as p
async with p.Server():
agent = await server.create_agent(
name="Customer Support",
description="Handles customer inquiries for an airline",
)
# Evaluate and call tools only under the right conditions
expert_customer = await agent.create_observation(
condition="customer uses financial terminology like DTI or amortization",
tools=[research_deep_answer],
)
# When the expert observation holds, always respond
# with depth. Set the guideline to automatically match
# whenever the observation it depends on holds...
expert_answers = await agent.create_guideline(
matcher=p.MATCH_ALWAYS,
action="respond with technical depth",
dependencies=[expert_customer],
)
beginner_answers = await agent.create_guideline(
condition="customer seems new to the topic",
action="simplify and use concrete examples",
)
# When both match, beginners wins. Neither expert-level
# tool-data nor instructions can enter the agent's context.
await beginner_answers.exclude(expert_customer)
```
Follow the **[5-minute quickstart](https://www.parlant.io/docs/quickstart/installation)** for a full walkthrough.
## Parlant at a glance
You define your agent's behavior in code (not prompts), and the engine dynamically narrows the context on each turn to only what's immediately relevant, so the LLM stays focused and your agent stays aligned.
```mermaid
graph TD
O[Observations] -->|Events| E[Contextual Matching Engine]
G[Guidelines] -->|Instructions| E
J["Journeys (SOPs)"] -->|Current Steps| E
R[Retrievers] -->|Domain Knowledge| E
GL[Glossary] -->|Domain Terms| E
V[Variables] -->|Memories| E
E -->|Tool Requests| T[Tool Caller]
T -.->|Results + Optional Extra Matching Iterations| E
T -->|**Key Result:**<br/>Focused Context Window| M[Message Generation]
```
Instead of sending a large system prompt followed by a raw conversation to the model, Parlant first assembles a focused context — matching only the instructions and tools relevant to each conversational turn — then generates a response from that narrowed context.
```mermaid
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#e8f5e9', 'primaryTextColor': '#1b5e20', 'primaryBorderColor': '#81c784', 'lineColor': '#66bb6a', 'secondaryColor': '#fff9e1', 'tertiaryColor': 'transparent'}}}%%
flowchart LR
A(User):::outputNode
subgraph Engine["Parlant Engine"]
direction LR
B["Match Guidelines and Resolve Journey States"]:::matchNode
C["Call Contextually-Associated Tools and Workflows"]:::toolNode
D["Generated Message"]:::composeNode
E["Canned Message"]:::cannedNode
end
A a@-->|💬 User Input| B
B b@--> C
C c@-->|Fluid Output Mode?| D
C d@-->|Strict Output Mode?| E
D e@-->|💬 Fluid Output| A
E f@-->|💬 Canned Output| A
a@{animate: true}
b@{animate: true}
c@{animate: true}
d@{animate: true}
e@{animate: true}
f@{animate: true}
linkStyle 2 stroke-width:2px
linkStyle 4 stroke-width:2px
linkStyle 3 stroke-width:2px,stroke:#3949AB
linkStyle 5 stroke-width:2px,stroke:#3949AB
classDef composeNode fill:#F9E9CB,stroke:#AB8139,stroke-width:2px,color:#7E5E1A,stroke-width:0
classDef cannedNode fill:#DFE3F9,stroke:#3949AB,stroke-width:2px,color:#1a237e,stroke-width:0
```
In this way, adding more rules makes the agent smarter, not more confused — because the engine filters context relevance, not the LLM.
## Is Parlant for you?
Parlant is built for teams that need their AI agent to behave reliably in front of real customers. It's a good fit if:
- You're building a **customer-facing agent** — support, sales, onboarding, advisory — where tone, accuracy, and compliance matter.
- You have **dozens or hundreds of behavioral rules** and your system prompt is buckling under the weight.
- You're in a **regulated or high-stakes domain** (finance, insurance, healthcare, telecom) where every response needs to be explainable and auditable.
**_Parlant is deployed in production at the most stringent organizations, including banks._**
> _Parlant isn't just a framework. It's a high-level software that solves the conversational modeling problem head-on._
> — **Sarthak Dalabehera**, Principal Engineer, Slice Bank
> _By far the most elegant conversational AI framework that I've come across._
> — **Vishal Ahuja**, Senior Lead, Applied AI, JPMorgan Chase
> _Parlant dramatically reduces the need for prompt engineering and complex flow control. Building agents becomes closer to domain modeling._
> — **Diogo Santiago**, AI Engineer, Orcale
## Features
- **[Guidelines](https://parlant.io/docs/concepts/customization/guidelines)** —
Behavioral rules as condition-action pairs; the engine matches only what's relevant per turn.
- **[Relationships](https://parlant.io/docs/concepts/customization/relationships)** —
Dependencies and exclusions between guidelines to keep the context narrow and focused.
- **[Journeys](https://parlant.io/docs/concepts/customization/journeys)** —
Multi-turn SOPs that adapt to how the customer actually interacts.
- **[Canned Responses](https://parlant.io/docs/concepts/customization/canned-responses)** —
Pre-approved response templates that eliminate hallucination at critical moments.
- **[Tools](https://parlant.io/docs/concepts/customization/tools)** —
External APIs and workflows, triggered only when their observation matches.
- **[Glossary](https://parlant.io/docs/concepts/customization/glossary)** —
Domain-specific vocabulary so the agent understands customer language.
- **[Explainability](https://parlant.io/docs/advanced/explainability)** —
Full OpenTelemetry tracing — every guideline match and decision is logged.
## [Guidelines](https://parlant.io/docs/concepts/customization/guidelines)
Behavioral rules as condition-action pairs: when the condition applies, the action kicks into context.
Instead of cramming all guidelines in a single prompt, the engine evaluates which ones apply on each conversational turn and only includes the relevant ones in the LLM's context.
This lets you define hundreds of guidelines without degrading adherence.
```python
await agent.create_guideline(
condition="customer uses financial terminology like DTI or amortization",
action="respond with technical depth — skip basic explanations",
)
```
## [Relationships](https://parlant.io/docs/concepts/customization/guidelines)
Relationships between elements help you keep the final context just right: narrow and focused.
**Exclusion** relationships keep certain guidelines out of the model's attention when conflicting ones are matched.
```python
for_experts = await agent.create_guideline(
condition="customer uses financial terminology",
action="respond with technical depth",
)
for_beginners = await agent.create_guideline(
condition="customer seems new to the topic",
action="simplify and use concrete examples",
)
# In conflicting reads of the customer, set which takes priority
await for_beginners.exclude(for_experts)
```
**Dependency** relationships ensure a guideline only activates when another one has set the stage, helping you create _topic-based guideline hierarchies._
```python
suspects_fraud = await agent.create_observation(
condition="customer suspects unauthorized transactions on their card",
)
await agent.create_guideline(
condition="customer wants to take action regarding the transaction",
action="ask whether they want to dispute the transaction or lock the card",
# Only activates when fraud suspicion has been established
dependencies=[suspects_fraud],
)
```
## [Journeys](https://parlant.io/docs/concepts/customization/journeys)
Multi-turn SOPs (Standard Operating Procedures). Define a flow for processes like booking, troubleshooting, or onboarding. The agent follows the flow but adapts — it can fast-forward states, revisit earlier ones, or adjust pace based on how the customer interacts.
```python
journey = await agent.create_journey(
title="Book Flight",
description="Guide the customer through flight booking",
conditions=["customer wants to book a flight"],
)
t0 = await journey.initial_state.transition_to(
# Instruction to follow while in this state (could be multiple turns)
chat_state="See if they're interested in last-minute deals",
)
# Branch A - not interested in deals
t1 = await t0.target.transition_to(
chat_state="Determine where they want to go and when",
condition="They aren't interested",
)
# Branch B - interested in deals
t2 = await t0.target.transition_to(
tool_state=load_latest_flight_deals,
condition="They are",
)
t3 = await t1.target.transition_to(
chat_state="List deals and see if they're interested",
)
```
## [Canned Responses](https://parlant.io/docs/concepts/customization/canned-responses)
At critical moments or conversational events, limit the agent to using only pre-approved response templates.
After running the matching sequence and drafting a message to the customer, the agent selects the template that best matches its generated draft instead of sending it directly, eliminating hallucination risk entirely and keeping wording exact to the letter.
```python
await agent.create_guideline(
condition="The customer discusses things unrelated to our business"
action="Tell them you can't help with that",
# Strict composition mode triggers when this guideline
# matches - the rest of the agent stays fluid
composition_mode=p.CompositionMode.STRICT,
canned_responses=[
await agent.create_canned_response(
"Sorry, but I can't help you with that."
)
],
priority=100, # Top priority, focuses the agent on this alone
)
```
## [Tools](https://parlant.io/docs/concepts/customization/tools)
Tools activate only when their observation matches; they don't sit in the context permanently. This prevents the false-positive invocations that plague traditional LLM tool setups.
```python
@p.tool
async def query_docs(context: p.ToolContext, user_query: str) -> p.ToolResult:
results = search_knowledge_base(user_query)
return p.ToolResult(results)
await agent.create_observation(
condition="customer asks about service features",
tools=[query_docs],
)
```
Tools can also feed custom values into canned response templates.
## [Glossary](https://parlant.io/docs/concepts/customization/glossary)
Domain-specific vocabulary for your agent. Map colloquial terms and synonyms to precise business definitions so the agent understands customer language.
```python
await agent.create_term(
name="Ocean View",
description="Room category with direct view of the Atlantic",
synonyms=["sea view", "rooms with a view to the Atlantic"],
)
```
## [Explainability](https://parlant.io/docs/advanced/explainability)
Every decision is traced with OpenTelemetry. Parlant ships out of the box with elaborate logs, metrics, and traces.
## Framework Integration
Parlant handles conversational governance; it doesn't replace your existing stack.
Use it alongside frameworks like LangGraph, Agno, LlamaIndex, or others for workflow automation and knowledge retrieval. Parlant takes over the behavioral control layer while your framework of choice handles the rest of your agent's processing logic.
Any external workflow or agent becomes a Parlant tool, triggered only when relevant:
```python
from my_workflows import refund_graph # a compiled LangGraph StateGraph
@p.tool
async def run_refund_workflow(
context: p.ToolContext,
order_id: str
) -> p.ToolResult:
result = await refund_graph.ainvoke({"order_id": order_id})
# Graph result can inject both data and instructions into the agent.
# Instructions are transformed to guidelines, and participate
# in contextual guideline resolution (including prioritizations)
return p.ToolResult(
data=result["data"],
# Inject dynamic guidelines from workflow result
guidelines=[
{"action": inst, "priority": 3} for inst in result["instructions"]
],
)
await agent.create_observation(
condition="customer wants to process a refund",
tools=[run_refund_workflow],
)
```
The same pattern works with LlamaIndex query engines, Agno agents, or any async Python function.
## LLM Agnostic
Parlant works with most LLM providers. The recommended ones are [Emcie](https://www.emcie.co) which delivers an ideal cost/quality value since it's built specifically for Parlant, but OpenAI and Anthropic deliver excellent quality outputs as well. You can also use any model and provider via LiteLLM, but they need to be good ones - off-the-shelf models which are too small tend to produce inconsistent results.
Generally, you can swap models without changing behavioral configuration.
## [Official React Chat Widget](https://github.com/emcie-co/parlant-chat-react)
Drop-in chat component to get a frontend running immediately.
## Learn more
- **[How Parlant ensures compliance](https://www.parlant.io/blog/how-parlant-guarantees-compliance)** — deep dive into the engine
- **[Parlant vs LangGraph](https://www.parlant.io/blog/parlant-vs-langgraph)** — when to use which
- **[Parlant vs DSPy](https://www.parlant.io/blog/parlant-vs-dspy)** — different tools for different problems
## Community
- **[Discord](https://discord.gg/duxWqxKk6J)** — ask questions, share what you're building
- **[GitHub Issues](https://github.com/emcie-co/parlant/issues)** — bug reports and feature requests
- **[Contact](https://parlant.io/contact)** — reach the engineering team directly
**If Parlant helps you build better agents, **[give it a star](https://github.com/emcie-co/parlant)** — it helps others find the project.**
## License
Apache 2.0 — free for commercial use.
---
<div align="center">
**[Try it now](https://www.parlant.io/docs/quickstart/installation)** • **[Join Discord](https://discord.gg/duxWqxKk6J)** • **[Read the docs](https://www.parlant.io/)**
Built by the team at **[Emcie](https://emcie.co)**
</div>
================================================
FILE: docs/adapters/nlp/azure.md
================================================
# Azure OpenAI Service Documentation
The Azure service provides integration with Azure OpenAI services, supporting both legacy API key authentication and modern Azure AD authentication. This integration enables Parlant to leverage Azure's enterprise-grade AI services while maintaining security best practices.
## Prerequisites
1. **Azure OpenAI Resource**: Create an Azure OpenAI resource in your Azure subscription
2. **Authentication Setup**: Choose between API key or Azure AD authentication
3. **Model Deployment**: Deploy required models in your Azure OpenAI resource
4. **Permissions**: Ensure proper IAM roles for Azure AD authentication
## Authentication Methods
### Development (Local Machine)
For local development, use Azure CLI authentication:
```bash
# Install Azure CLI if not already installed
# https://docs.microsoft.com/en-us/cli/azure/install-azure-cli
# Login to Azure
az login
# Set your endpoint
export AZURE_ENDPOINT="https://your-resource.openai.azure.com/"
```
### Production (Server Deployment)
For server deployment, **do NOT use `az login`**. Instead, use one of these methods:
#### Option 1: Service Principal (Recommended)
```bash
# Set environment variables
export AZURE_ENDPOINT="https://your-resource.openai.azure.com/"
export AZURE_CLIENT_ID="your-service-principal-client-id"
export AZURE_CLIENT_SECRET="your-service-principal-secret"
export AZURE_TENANT_ID="your-azure-tenant-id"
```
#### Option 2: Managed Identity (Azure Resources)
If running on Azure VMs, App Services, or other Azure resources:
```bash
# Only set the endpoint - authentication is automatic
export AZURE_ENDPOINT="https://your-resource.openai.azure.com/"
```
#### Option 3: Workload Identity (Kubernetes)
For Kubernetes deployments:
```bash
export AZURE_ENDPOINT="https://your-resource.openai.azure.com/"
export AZURE_CLIENT_ID="your-workload-identity-client-id"
export AZURE_TENANT_ID="your-azure-tenant-id"
export AZURE_FEDERATED_TOKEN_FILE="/var/run/secrets/azure/tokens/azure-identity-token"
```
## Environment Variables
### Required Variables
- `AZURE_ENDPOINT`: Your Azure OpenAI resource endpoint
### Optional Variables
- `AZURE_API_VERSION`: API version (default: "2024-08-01-preview")
- `AZURE_GENERATIVE_MODEL_NAME`: Model name (default: "gpt-4o")
- `AZURE_GENERATIVE_MODEL_WINDOW`: Context window size (default: 4096)
- `AZURE_EMBEDDING_MODEL_NAME`: Embedding model (default: "text-embedding-3-large")
- `AZURE_EMBEDDING_MODEL_DIMS`: Embedding dimensions (default: 3072)
- `AZURE_EMBEDDING_MODEL_WINDOW`: Embedding context window (default: 8192)
## Supported Models
The Azure service supports **any Azure OpenAI model** that is deployed and available in your Azure OpenAI resource. The models listed below are pre-configured defaults, but you can use any model by setting the appropriate environment variables.
### Pre-configured Generative Models
| Model Name | Description | Context Window | Use Case |
|------------|-------------|---------------|----------|
| `gpt-4o` | Most capable GPT-4 model (default) | 128K tokens | Complex reasoning, high accuracy |
| `gpt-4o-mini` | Faster, cost-effective GPT-4 | 128K tokens | Balanced performance and cost |
### Pre-configured Embedding Models
| Model Name | Dimensions | Context Window | Description |
|------------|------------|---------------|-------------|
| `text-embedding-3-large` | 3072 | 8192 | High-quality embeddings (default) |
| `text-embedding-3-small` | 3072 | 8192 | Efficient embeddings |
### Using Custom Models
You can use **any Azure OpenAI model** that is deployed in your Azure OpenAI resource:
```bash
# Use any generative model (examples - check your Azure resource for availability)
export AZURE_GENERATIVE_MODEL_NAME="gpt-35-turbo" # GPT-3.5 Turbo
export AZURE_GENERATIVE_MODEL_NAME="gpt-4" # GPT-4
export AZURE_GENERATIVE_MODEL_NAME="gpt-4-turbo" # GPT-4 Turbo
# Use any embedding model (examples - check your Azure resource for availability)
export AZURE_EMBEDDING_MODEL_NAME="text-embedding-ada-002" # Ada embeddings
export AZURE_EMBEDDING_MODEL_NAME="text-embedding-3-large" # Large embeddings
```
**Important**:
- Model availability depends on what you've deployed in your Azure OpenAI resource
- Not all models are available in all Azure regions
- Check your Azure OpenAI resource deployment to see which models are available
## Authentication Priority
The service follows this authentication priority:
1. **API Key** (highest priority - for backward compatibility)
2. **Azure AD** (fallback when no API key is present)
## Required Azure Permissions
For Azure AD authentication, ensure your identity has the following role on the Azure OpenAI resource:
- **Cognitive Services OpenAI User**: Required for accessing Azure OpenAI services
## Usage Example
```python
import parlant.sdk as p
from parlant.sdk import NLPServices
async with p.Server(nlp_service=NLPServices.azure) as server:
agent = await server.create_agent(
name="Healthcare Agent",
description="Is empathetic and calming to the patient.",
)
```
## Server Deployment Guide
### Setting Up Service Principal for Production
1. **Create Service Principal**:
```bash
# Login as admin user
az login
# Create service principal
az ad sp create-for-rbac --name "parlant-service-principal" --role "Cognitive Services OpenAI User" --scopes "/subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/YOUR_RESOURCE_GROUP/providers/Microsoft.CognitiveServices/accounts/YOUR_OPENAI_RESOURCE"
```
2. **Configure Environment Variables**:
```bash
export AZURE_ENDPOINT="https://your-resource.openai.azure.com/"
export AZURE_CLIENT_ID="appId-from-step-1"
export AZURE_CLIENT_SECRET="password-from-step-1"
export AZURE_TENANT_ID="tenant-from-step-1"
```
3. **Test Authentication**:
```bash
# Verify the service principal can access Azure OpenAI
python -c "
from parlant.adapters.nlp.azure_service import AzureService
error = AzureService.verify_environment()
print('Configuration OK' if error is None else f'Error: {error}')
"
```
### Configuration Tips
### Development Setup
```bash
export AZURE_ENDPOINT="https://my-resource.openai.azure.com/"
export AZURE_API_KEY="your-api-key"
export AZURE_GENERATIVE_MODEL_NAME="gpt-4o-mini"
```
### Production Setup (Azure AD)
```bash
export AZURE_ENDPOINT="https://my-resource.openai.azure.com/"
export AZURE_CLIENT_ID="your-client-id"
export AZURE_CLIENT_SECRET="your-client-secret"
export AZURE_TENANT_ID="your-tenant-id"
export AZURE_GENERATIVE_MODEL_NAME="gpt-4o"
```
## Troubleshooting
### Common Issues
1. **Authentication Failures**
```
Azure authentication is not properly configured.
```
**Solution**:
- For development: Run `az login` (only for local development)
- For production: Use service principal variables (NOT `az login`)
- Ensure "Cognitive Services OpenAI User" role is assigned
- Verify service principal has correct permissions
2. **Rate Limit Errors**
```
Azure API rate limit exceeded
```
**Solution**:
- Check Azure account balance and billing status
- Review API usage limits in Azure dashboard
- Consider upgrading service tier
3. **Model Access Denied**
```
Model not found or access denied
```
**Solution**:
- Verify model is deployed in your Azure OpenAI resource
- Check regional availability
- Ensure proper permissions
4. **Connection Errors**
```
Cannot connect to Azure OpenAI endpoint
```
**Solution**:
- Verify `AZURE_ENDPOINT` is correct
- Check network connectivity
- Ensure firewall allows Azure OpenAI traffic
## Available Model Classes
The service provides these pre-configured model classes for convenience, but supports any Azure OpenAI model:
### Pre-configured Classes
- `GPT_4o`: Most capable GPT-4 model (128K context) - **Default**
- `GPT_4o_Mini`: Faster, cost-effective GPT-4 (128K context)
- `AzureTextEmbedding3Large`: High-quality embeddings (3072 dimensions) - **Default**
- `AzureTextEmbedding3Small`: Efficient embeddings (3072 dimensions)
### Custom Model Classes
- `CustomAzureSchematicGenerator`: Uses any generative model via `AZURE_GENERATIVE_MODEL_NAME`
- `CustomAzureEmbedder`: Uses any embedding model via `AZURE_EMBEDDING_MODEL_NAME`
**The service automatically chooses the appropriate class based on your environment variables.**
### How Model Selection Works
The service uses this logic to select the appropriate model class:
```python
# Generative Model Selection
if AZURE_GENERATIVE_MODEL_NAME is set:
use CustomAzureSchematicGenerator # Any model you specify
else:
use GPT_4o # Default model
# Embedding Model Selection
if AZURE_EMBEDDING_MODEL_NAME is set:
use CustomAzureEmbedder # Any embedding model you specify
else:
use AzureTextEmbedding3Large # Default embedding model
```
This means you can use **any Azure OpenAI model** without code changes - just set the environment variables!
### Example: Using Different Models
```bash
# Use GPT-3.5 Turbo (if available in your region)
export AZURE_ENDPOINT="https://your-resource.openai.azure.com/"
export AZURE_GENERATIVE_MODEL_NAME="gpt-35-turbo"
export AZURE_EMBEDDING_MODEL_NAME="text-embedding-ada-002"
# Use GPT-4 Turbo (if available in your region)
export AZURE_GENERATIVE_MODEL_NAME="gpt-4-turbo"
export AZURE_EMBEDDING_MODEL_NAME="text-embedding-3-large"
# Use default models (GPT-4o and text-embedding-3-large)
export AZURE_ENDPOINT="https://your-resource.openai.azure.com/"
# No need to set AZURE_GENERATIVE_MODEL_NAME or AZURE_EMBEDDING_MODEL_NAME
```
## Security Notes
- **API Keys**: Store securely, rotate regularly
- **Azure AD**: Use managed identities in production
- **Network**: Ensure proper network security groups
- **Monitoring**: Monitor usage and access patterns
- **Compliance**: Follow organizational security policies
## Migration Guide
### From API Key to Azure AD
1. Set up Azure AD authentication using one of the supported methods
2. Remove the API key from your environment variables
3. Verify permissions - ensure your identity has "Cognitive Services OpenAI User" role
4. Test the configuration using `AzureService.verify_environment()`
### Backward Compatibility
The service maintains full backward compatibility:
- Existing API key configurations continue to work
- No changes required for existing deployments
- Gradual migration to Azure AD is supported
================================================
FILE: docs/adapters/nlp/ollama.md
================================================
# Ollama Service Documentation
The Ollama service provides local LLM capabilities for Parlant using [Ollama](https://ollama.ai/). This service supports both text generation and embeddings using various open-source models.
## Prerequisites
1. **Install Ollama**: Download and install from [ollama.ai](https://ollama.ai/)
2. **Start Ollama server**: Run `ollama serve` (usually starts automatically)
3. **Pull required models** (see [Recommended Models](#recommended-models) section)
## Environment Variables
Configure the Ollama service using these environment variables:
```bash
# Ollama server URL (default: http://localhost:11434)
export OLLAMA_BASE_URL="http://localhost:11434"
# Model size to use (default: 4b)
# Options: gemma3:1b, gemma3:4b, llama3.1:8b, gemma3:12b, gemma3:27b, llama3.1:70b, llama3.1:405b
export OLLAMA_MODEL="gemma3:4b"
# Embedding model (default: nomic-embed-text)
# Options: nomic-embed-text, mxbai-embed-large
export OLLAMA_EMBEDDING_MODEL="nomic-embed-text"
# API timeout in seconds (default: 300)
export OLLAMA_API_TIMEOUT="300"
```
### Example Configuration
```bash
# For development (fast, good balance)
export OLLAMA_MODEL="gemma3:4b"
export OLLAMA_EMBEDDING_MODEL="nomic-embed-text"
export OLLAMA_API_TIMEOUT="180"
# higher accuracy cloud
export OLLAMA_MODEL="gemma3:4b"
export OLLAMA_EMBEDDING_MODEL="nomic-embed-text"
export OLLAMA_API_TIMEOUT="600"
```
## Recommended Models
**⚠️ IMPORTANT**: Pull these models before running Parlant to avoid API timeouts during first use:
### Text Generation Models
```bash
# Recommended for most use cases (good balance of speed/accuracy)
ollama pull gemma3:4b-it-qat
# Fast but may struggle with complex schemas
ollama pull gemma3:1b
# embedding model required for creating embeddings
ollama pull nomic-embed-text
```
### Large Models (Cloud/High-end Hardware Only)
```bash
# Better reasoning capabilities
ollama pull llama3.1:8b
# High accuracy for complex tasks
ollama pull gemma3:12b
# Very high accuracy (requires more resources)
ollama pull gemma3:27b-it-qat
# ⚠️ WARNING: Requires 40GB+ GPU memory
ollama pull llama3.1:70b
# ⚠️ WARNING: Requires 200GB+ GPU memory (cloud-only)
ollama pull llama3.1:405b
```
### Embedding Models
To use custom embedding model set OLLAMA_EMBEDDING_MODEL environment value as required name
Note that this implementation is tested using nomic-embed-text
**⚠️ IMPORTANT**:
Support for using other embedding models has been added including a custom embedding model of your own choice
Ensure to set OLLAMA_EMBEDDING_VECTOR_SIZE which is compatible with your own embedding model before starting the server
Tested with `snowflake-arctic-embed` with vector size of 1024
It is not NECESSARY to put OLLAMA_EMBEDDING_VECTOR_SIZE if you are using the supported `nomic-embed-text`, `mxbai-embed-large` or `bge-m3`. The vector size defaults to 768, 1024 and 1024 respectively for these
```bash
# Alternative embedding model (512 dimensions)
ollama pull mxbai-embed-large:latest
```
## Model Recommendations by Use Case
| Model Size | Use Case | Memory Requirements | Performance |
|------------|----------|-------------------|-------------|
| `1b` | Quick testing, simple tasks | ~2GB | Fast but limited accuracy |
| `4b` | **Recommended for development** | ~4GB | Good balance of speed/accuracy |
| `8b` | complex reasoning | ~8GB | Better reasoning than Gemma |
| `12b` | High-accuracy tasks | ~12GB | High accuracy, slower |
| `27b` | Complex workloads | ~27GB | Very high accuracy |
| `70b` | Enterprise/cloud only | ~40GB+ | Excellent accuracy |
| `405b` | Research/cloud only | ~200GB+ | State-of-the-art |
## Usage Example
```python
import parlant.sdk as p
from parlant.sdk import NLPServices
async with p.Server(nlp_service=NLPServices.ollama) as server:
agent = await server.create_agent(
name="Healthcare Agent",
description="Is empathetic and calming to the patient.",
)
```
## Configuration Tips
### Development Setup
```bash
export OLLAMA_MODEL=gemma3:4b
export OLLAMA_API_TIMEOUT=180
```
### High-Performance Setup (Cloud)
```bash
export OLLAMA_MODEL=llama3.1:70b
export OLLAMA_API_TIMEOUT=300
```
### Custom / Other models
```bash
export OLLAMA_MODEL=llama3.2:3b
export OLLAMA_API_TIMEOUT=300
```
## Troubleshooting
### Common Issues
1. **Model Not Found Error**
```
Model gemma3:4b not found. Please pull it first with: ollama pull gemma3:4b
```
**Solution**: Run `ollama pull gemma3:4b-it-qat` before starting Parlant
2. **Connection Error**
```
Cannot connect to Ollama server at http://localhost:11434
```
**Solution**: Ensure Ollama is running with `ollama serve`
3. **Timeout Error**
```
Request timed out after 300s
```
**Solution**: Increase `OLLAMA_API_TIMEOUT` or use a smaller model
4. **Out of Memory**
```
CUDA out of memory
```
**Solution**: Use a smaller model size or increase GPU memory
### Performance Optimization
1. **Pre-pull models**: Always pull models before first use
2. **Adjust timeout**: Increase timeout for larger models
3. **Model selection**: Use smallest model that meets accuracy requirements
4. **GPU memory**: Monitor GPU usage and adjust model size accordingly
## Available Model Classes
The service provides these pre-configured model classes:
- `OllamaGemma3_1B`: Fast, basic accuracy
- `OllamaGemma3_4B`: **Recommended** - good balance
- `OllamaLlama31_8B`: Better reasoning
- `OllamaGemma3_12B`: High accuracy
- `OllamaGemma3_27B`: Very high accuracy
- `OllamaLlama31_70B`: Enterprise-grade (high memory)
- `OllamaLlama31_405B`: Research-grade (very high memory)
## Security Notes
- Ollama runs locally, so no data leaves your machine
- No API keys required
- Models are downloaded and cached locally
- Consider firewall rules if exposing Ollama server externally
================================================
FILE: docs/adapters/nlp/openrouter.md
================================================
# OpenRouter Service Documentation
The OpenRouter service provides access to **400+ AI models** through a single unified API, including GPT-4, Claude, Llama, Qwen, and many more. OpenRouter makes it easy to switch between different models for both text generation and embeddings without changing code.
## Prerequisites
1. **OpenRouter Account**: Sign up at [openrouter.ai](https://openrouter.ai)
2. **API Key**: Get your API key from the [OpenRouter dashboard](https://openrouter.ai/keys)
3. **Model Access**: Ensure you have access to the models you want to use
## Quick Start
### Basic Setup
```bash
# Set your OpenRouter API key (required)
export OPENROUTER_API_KEY="your-api-key-here"
# Optionally set default models
export OPENROUTER_MODEL="openai/gpt-4o-mini"
export OPENROUTER_EMBEDDER_MODEL="openai/text-embedding-3-large"
```
### Minimal Example
```python
import parlant.sdk as p
from parlant.sdk import NLPServices
async with p.Server(nlp_service=NLPServices.openrouter) as server:
agent = await server.create_agent(
name="AI Assistant",
description="A helpful assistant powered by OpenRouter.",
)
# 🎉 Ready to use at http://localhost:8800
```
## Configuration
All configuration is done via environment variables. Set the required and optional environment variables before running your application:
```bash
# Required: API Key
export OPENROUTER_API_KEY="your-api-key-here"
# Optional: LLM Configuration
export OPENROUTER_MODEL="openai/gpt-4o-mini"
export OPENROUTER_MAX_TOKENS="128000"
# Optional: Embedding Configuration
export OPENROUTER_EMBEDDER_MODEL="qwen/qwen3-embedding-8b"
export OPENROUTER_EMBEDDER_DIMENSIONS="4096" # Optional override
# Optional: Analytics
export OPENROUTER_HTTP_REFERER="https://myapp.com"
export OPENROUTER_SITE_NAME="My Application"
```
## Environment Variables Reference
### Required Variables
| Variable | Description | Example |
|----------|-------------|---------|
| `OPENROUTER_API_KEY` | Your OpenRouter API key | `sk-or-v1-...` |
### Optional Variables - LLM Configuration
| Variable | Description | Default | Example |
|----------|-------------|---------|---------|
| `OPENROUTER_MODEL` | LLM model name | `openai/gpt-4o` | `openai/gpt-4o-mini` |
| `OPENROUTER_MAX_TOKENS` | Max tokens limit | Auto-detected | `128000` |
### Optional Variables - Embedding Configuration
| Variable | Description | Default | Example |
|----------|-------------|---------|---------|
| `OPENROUTER_EMBEDDER_MODEL` | Embedding model name | `openai/text-embedding-3-large` | `qwen/qwen3-embedding-8b` |
| `OPENROUTER_EMBEDDER_DIMENSIONS` | Override embedding dimensions | Auto-detected | `4096` |
### Optional Variables - Analytics
| Variable | Description | Example |
|----------|-------------|---------|
| `OPENROUTER_HTTP_REFERER` | Your app's URL (for analytics) | `https://myapp.com` |
| `OPENROUTER_SITE_NAME` | Your app's name (for analytics) | `My Application` |
## Supported Models
OpenRouter supports **400+ models** from different providers. Models are automatically optimized with specialized configurations when available.
### Pre-configured LLM Models
These models have specialized configurations for optimal performance:
| Model | Provider | Context | Use Case |
|-------|----------|---------|----------|
| `openai/gpt-4o` | OpenAI | 128K | Default, best overall quality |
| `openai/gpt-4o-mini` | OpenAI | 128K | Cost-effective, fast |
| `anthropic/claude-3.5-sonnet` | Anthropic | 200K | Advanced reasoning, long context |
| `meta-llama/llama-3.3-70b-instruct` | Meta | 8K | Open-source option |
### Supported Embedding Models
The service supports multiple embedding models with automatic dimension detection:
| Model | Dimensions | Provider | Use Case |
|-------|------------|----------|----------|
| `openai/text-embedding-3-large` | 3072 | OpenAI | Default, high quality |
| `openai/text-embedding-3-small` | 1536 | OpenAI | Faster, smaller |
| `openai/text-embedding-ada-002` | 1536 | OpenAI | Legacy model |
| `qwen/qwen3-embedding-8b` | 4096 | Qwen | High dimension, multilingual |
| `qwen/qwen-embedding-v2` | 1536 | Qwen | Multilingual embeddings |
### Using Any OpenRouter Model
You can use **any model** that OpenRouter supports by setting the appropriate environment variables:
```bash
# LLM Models
export OPENROUTER_MODEL="google/gemini-pro-1.5"
# Embedding Models
export OPENROUTER_EMBEDDER_MODEL="qwen/qwen3-embedding-8b"
```
Check the [OpenRouter Models page](https://openrouter.ai/models) for the full list of available models.
## Usage Examples
### Example 1: Default Configuration
Use the default models (GPT-4o for LLM, text-embedding-3-large for embeddings):
```python
import parlant.sdk as p
from parlant.sdk import NLPServices
async with p.Server(nlp_service=NLPServices.openrouter) as server:
agent = await server.create_agent(
name="General Assistant",
description="A helpful AI assistant."
)
```
### Example 2: Custom LLM Model
Use Claude for text generation:
```bash
export OPENROUTER_MODEL="anthropic/claude-3.5-sonnet"
```
```python
async with p.Server(nlp_service=NLPServices.openrouter) as server:
agent = await server.create_agent(
name="Claude Assistant",
description="Powered by Claude."
)
```
### Example 3: Custom Embedder Model
Use a custom embedding model for better multilingual support:
```bash
export OPENROUTER_MODEL="openai/gpt-4o-mini"
export OPENROUTER_EMBEDDER_MODEL="qwen/qwen3-embedding-8b"
```
```python
async with p.Server(nlp_service=NLPServices.openrouter) as server:
agent = await server.create_agent(
name="Multilingual Assistant",
description="Supports multiple languages."
)
```
### Example 4: High-Performance Setup
Optimize for speed and quality:
```bash
export OPENROUTER_MODEL="openai/gpt-4o-mini"
export OPENROUTER_EMBEDDER_MODEL="openai/text-embedding-3-large"
export OPENROUTER_MAX_TOKENS="128000"
```
```python
async with p.Server(nlp_service=NLPServices.openrouter) as server:
agent = await server.create_agent(
name="High-Performance Agent",
description="Optimized for speed and accuracy."
)
```
### Example 5: Cost-Optimized Setup
Balance quality and cost:
```bash
export OPENROUTER_MODEL="openai/gpt-4o-mini"
export OPENROUTER_EMBEDDER_MODEL="openai/text-embedding-3-small"
```
```python
async with p.Server(nlp_service=NLPServices.openrouter) as server:
agent = await server.create_agent(
name="Cost-Optimized Agent",
description="Optimized for cost-effectiveness."
)
```
## Embedding Model Configuration
### Understanding Embedding Dimensions
Different embedding models produce vectors of different dimensions. The service automatically detects dimensions for known models, and can auto-detect from API responses for unknown models.
### Known Embedding Dimensions
The following models have pre-configured dimensions:
- `openai/text-embedding-3-large`: **3072** dimensions
- `openai/text-embedding-3-small`: **1536** dimensions
- `openai/text-embedding-ada-002`: **1536** dimensions
- `qwen/qwen3-embedding-8b`: **4096** dimensions
- `qwen/qwen-embedding-v2`: **1536** dimensions
### Auto-Detection
For unknown models, dimensions are automatically detected from the first API response and cached for subsequent use.
### Manual Dimension Override
If needed, you can manually specify dimensions via environment variable:
```bash
export OPENROUTER_EMBEDDER_DIMENSIONS="4096"
```
⚠️ **Important**: If you change embedder models or dimensions, you may need to clear your vector database cache to avoid dimension mismatch errors.
## Dynamic Model Selection
OpenRouter intelligently handles model selection and configuration:
### Automatic Generator Selection
Known models use specialized generators for optimal performance:
- `openai/gpt-4o` → `OpenRouterGPT4O`
- `openai/gpt-4o-mini` → `OpenRouterGPT4OMini`
- `anthropic/claude-3.5-sonnet` → `OpenRouterClaude35Sonnet`
- `meta-llama/llama-3.3-70b-instruct` → `OpenRouterLlama33_70B`
- Other models → Dynamic generator with auto-configured parameters
### Automatic Embedder Selection
Embedders are automatically configured based on the model name:
- Known models → Pre-configured dimensions
- Unknown models → Auto-detected dimensions from API response
- Dynamic embedder → Created with proper container resolution
## Advantages of OpenRouter
1. **Model Diversity**: Access to 400+ models from different providers
2. **Unified Embeddings**: Native support for embedding models via the same API
3. **Cost Flexibility**: Choose models based on price-performance needs
4. **Single API**: One integration for multiple providers
5. **Auto-Optimization**: Automatic configuration for known models
6. **Environment-Based Configuration**: All configuration via environment variables
7. **Analytics**: Built-in usage tracking through OpenRouter dashboard
## Troubleshooting
### Rate Limit Errors
**Error:**
```
OpenRouter API rate limit exceeded
```
**Solutions:**
- Check your OpenRouter account balance and billing status
- Review usage limits in the [OpenRouter dashboard](https://openrouter.ai/keys)
- Consider upgrading your plan for higher limits
- Try a different model with higher rate limits
- Wait a moment before retrying
### JSON Mode Not Supported
**Error:**
```
Model 'xyz' does not support JSON mode
```
**Solutions:**
- OpenRouter automatically falls back to prompting for JSON output
- Consider using a model that supports JSON mode:
- `openai/gpt-4o`
- `openai/gpt-4o-mini`
- `anthropic/claude-3.5-sonnet`
- The fallback still produces structured output reliably
### Dimension Mismatch Errors
**Error:**
```
ValueError: all the input array dimensions except for the concatenation axis must match exactly
```
**Solutions:**
- This occurs when switching embedder models with different dimensions
- Clear your vector database cache/embeddings
- Or delete the cached embeddings files in your `parlant-data` directory
- The embedder will create new embeddings with the correct dimensions
### Authentication Errors
**Error:**
```
OPENROUTER_API_KEY is not set
```
**Solutions:**
- Set the `OPENROUTER_API_KEY` environment variable
- Verify your API key in the [OpenRouter dashboard](https://openrouter.ai/keys)
- Ensure the key hasn't expired or been revoked
- Check for typos in the environment variable name
### Container Resolution Errors
**Error:**
```
Unable to construct dependency of type OpenRouterEmbedder
```
**Solutions:**
- This is automatically handled by the dynamic embedder class
- Ensure you're using the latest version of the code
- If the error persists, check that `embedder_model_name` is correctly set
## Cost Management
OpenRouter provides transparent pricing across models. Choose models based on your needs:
### Cost-Effective LLM Options
```python
# GPT-4o-mini - Good quality, lower cost
model_name="openai/gpt-4o-mini"
# Claude Haiku - Fast, affordable
model_name="anthropic/claude-3-haiku"
# Llama - Open source, very affordable
model_name="meta-llama/llama-3.3-70b-instruct"
```
### Cost-Effective Embedding Options
```python
# text-embedding-3-small - Smaller, faster, cheaper
embedder_model_name="openai/text-embedding-3-small"
# text-embedding-ada-002 - Legacy, very affordable
embedder_model_name="openai/text-embedding-ada-002"
```
### Premium Options
```python
# GPT-4o - Highest quality
model_name="openai/gpt-4o"
# text-embedding-3-large - Highest quality embeddings
embedder_model_name="openai/text-embedding-3-large"
```
Check [OpenRouter pricing](https://openrouter.ai/docs/pricing) for current rates.
## Model Selection Guide
### When to Use Each LLM Model
**GPT-4o** (`openai/gpt-4o`)
- Complex reasoning tasks
- Code generation and debugging
- Multi-step problem solving
- When accuracy is critical
- Best overall performance
**GPT-4o-mini** (`openai/gpt-4o-mini`)
- General purpose tasks
- High-volume applications
- Cost-sensitive use cases
- When 95% accuracy is sufficient
- Fast response times
**Claude** (`anthropic/claude-3.5-sonnet`)
- Long context tasks (200K tokens)
- Creative writing
- Detailed analysis
- When you need extended reasoning
- Complex document understanding
**Llama** (`meta-llama/llama-3.3-70b-instruct`)
- Open-source requirements
- Custom fine-tuning needs
- Privacy-sensitive applications
- Cost optimization
- Self-hosted deployments
### When to Use Each Embedding Model
**text-embedding-3-large** (`openai/text-embedding-3-large`)
- Default choice for most use cases
- High quality semantic search
- Best accuracy for retrieval
- Recommended for production
**text-embedding-3-small** (`openai/text-embedding-3-small`)
- Cost-sensitive applications
- Faster embedding generation
- Good quality for most tasks
- Large-scale deployments
**qwen3-embedding-8b** (`qwen/qwen3-embedding-8b`)
- Multilingual applications
- Higher dimensional space (4096)
- Better fine-grained distinctions
- When you need more embedding dimensions
## Best Practices
### 1. Start with Defaults
Begin with the default models (`gpt-4o` and `text-embedding-3-large`) for best balance of quality and performance.
### 2. Use Mini for Scale
Switch to `gpt-4o-mini` for high-volume operations where cost is a concern.
### 3. Match Embedder to Use Case
- Use `text-embedding-3-large` for quality-critical applications
- Use `text-embedding-3-small` for cost-sensitive deployments
- Use `qwen3-embedding-8b` for multilingual or high-dimensional needs
### 4. Set Max Tokens
Prevent runaway costs by setting appropriate `max_tokens` limits via environment variable:
```bash
export OPENROUTER_MAX_TOKENS="128000" # For long-context models
export OPENROUTER_MAX_TOKENS="8192" # For standard use cases
```
### 5. Monitor Costs
Regularly check the [OpenRouter dashboard](https://openrouter.ai/keys) to monitor usage and costs.
### 6. Use Analytics
Set `OPENROUTER_HTTP_REFERER` and `OPENROUTER_SITE_NAME` to track usage across different applications.
### 7. Clear Cache When Changing Models
If you switch embedder models, clear your vector database cache to avoid dimension mismatches.
### 8. Environment Variables for Production
Use environment variables for production deployments instead of hardcoding values:
```bash
# Production configuration
export OPENROUTER_API_KEY="sk-or-v1-..."
export OPENROUTER_MODEL="openai/gpt-4o-mini"
export OPENROUTER_EMBEDDER_MODEL="openai/text-embedding-3-large"
```
## Advanced Configuration
### Custom Dimensions for Unknown Models
If using an embedding model not in the known list, you can specify dimensions:
```bash
export OPENROUTER_EMBEDDER_MODEL="custom/embedding-model"
export OPENROUTER_EMBEDDER_DIMENSIONS="2048"
```
The service will also auto-detect dimensions from the first API response.
### Combining Multiple Configurations
All configuration is done via environment variables. Set multiple variables to configure different aspects:
```bash
# Set all configuration via environment variables
export OPENROUTER_MODEL="anthropic/claude-3.5-sonnet"
export OPENROUTER_MAX_TOKENS="200000"
export OPENROUTER_EMBEDDER_MODEL="openai/text-embedding-3-large"
```
## Additional Resources
- [OpenRouter Documentation](https://openrouter.ai/docs)
- [Available Models](https://openrouter.ai/models)
- [API Reference](https://openrouter.ai/docs/api-reference)
- [Pricing Information](https://openrouter.ai/docs/pricing)
- [Rate Limits](https://openrouter.ai/docs/api-reference/limits)
## Example: Complete Setup
Here's a complete example showing a production-ready setup:
```bash
# Set environment variables
export OPENROUTER_API_KEY="your-api-key-here"
export OPENROUTER_MODEL="openai/gpt-4o-mini"
export OPENROUTER_EMBEDDER_MODEL="openai/text-embedding-3-large"
export OPENROUTER_MAX_TOKENS="32768"
```
```python
import parlant.sdk as p
from parlant.sdk import NLPServices
@p.tool
async def get_weather(context: p.ToolContext, city: str) -> p.ToolResult:
# Your weather API logic here
return p.ToolResult(f"Sunny, 72°F in {city}")
async def main():
async with p.Server(nlp_service=NLPServices.openrouter) as server:
agent = await server.create_agent(
name="Weather Assistant",
description="Helps users check weather conditions."
)
await agent.create_guideline(
condition="User asks about weather",
action="Get weather information using the get_weather tool",
tools=[get_weather]
)
# 🎉 Ready at http://localhost:8800
if __name__ == "__main__":
import asyncio
asyncio.run(main())
```
This setup provides:
- ✅ Cost-effective LLM (`gpt-4o-mini`)
- ✅ High-quality embeddings (`text-embedding-3-large`)
- ✅ Reasonable token limit (32K)
- ✅ Tool integration
- ✅ Guideline-based behavior control
================================================
FILE: docs/adapters/nlp/snowflake-cortex.md
================================================
# Snowflake Cortex Adapter
Integrate [Snowflake Cortex REST APIs](https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-rest-api) for **chat/structured generation** and **embeddings** with Snowflake-hosted LLMs. The adapter talks directly to:
- `POST /api/v2/cortex/inference:complete` for chat/JSON output
- `POST /api/v2/cortex/inference:embed` for embeddings
## Requirements
### Authentication
See [Snowflake REST API authentication](https://docs.snowflake.com/en/developer-guide/snowflake-rest-api/authentication). PAT is recommended.
### Environment Variables
See [Cortex models](https://docs.snowflake.com/en/user-guide/snowflake-cortex/llm) for available model names.
```bash
export SNOWFLAKE_CORTEX_BASE_URL="https://<account>.snowflakecomputing.com"
export SNOWFLAKE_AUTH_TOKEN="<jwt-or-pat>"
export SNOWFLAKE_CORTEX_CHAT_MODEL="mistral-large2"
export SNOWFLAKE_CORTEX_EMBED_MODEL="e5-base-v2"
# Optional:
export SNOWFLAKE_CORTEX_MAX_TOKENS="8192"
```
## Usage Example
```python
import parlant.sdk as p
from parlant.sdk import NLPServices
@p.tool
async def get_weather(context: p.ToolContext, city: str) -> p.ToolResult:
# Your weather API logic here
return p.ToolResult(f"Sunny, 72°F in {city}")
@p.tool
async def get_datetime(context: p.ToolContext) -> p.ToolResult:
from datetime import datetime
return p.ToolResult(datetime.now())
async def main():
async with p.Server(nlp_service=NLPServices.snowflake) as server:
agent = await server.create_agent(
name="WeatherBot",
description="Helpful weather assistant"
)
# Have the agent's context be updated on every response (though
# update interval is customizable) using a context variable.
await agent.create_variable(name="current-datetime", tool=get_datetime)
# Control and guide agent behavior with natural language
await agent.create_guideline(
condition="User asks about weather",
action="Get current weather and provide a friendly response with suggestions",
tools=[get_weather]
)
# Add other (reliably enforced) behavioral modeling elements
# ...
# 🎉 Test playground ready at http://localhost:8800
# Integrate the official React widget into your app,
# or follow the tutorial to build your own frontend!
if __name__ == "__main__":
import asyncio
asyncio.run(main())
```
## Configuration Reference
| Variable | Required | Description |
|----------------------------------|----------|-------------|
| `SNOWFLAKE_CORTEX_BASE_URL` | ✅ | Base account URL (e.g., `https://<account>.snowflakecomputing.com`). |
| `SNOWFLAKE_AUTH_TOKEN` | ✅ | OAuth / Keypair JWT / PAT used in the `Authorization: Bearer` header. |
| `SNOWFLAKE_CORTEX_CHAT_MODEL` | ✅ | Chat model name. |
| `SNOWFLAKE_CORTEX_EMBED_MODEL` | ✅ | Embedding model name. |
| `SNOWFLAKE_CORTEX_MAX_TOKENS` | ❌ | Local upper bound for generation; does not override provider limits. |
## Notes on Privacy & Data Residency
The adapter allows apps to call Cortex directly in your Snowflake account, reducing the need to move data outside Snowflake for LLM tasks. Review Snowflake's REST guidance for regional availability and account setup.
================================================
FILE: docs/adapters/nlp/vertex.md
================================================
# Vertex AI Service Adapter Documentation
## Overview
The Vertex AI Service Adapter provides integration with Google Cloud's Vertex AI platform, supporting both Anthropic Claude models and Google Gemini models through their respective APIs. This adapter implements the Parlant NLP service interface for text generation, embeddings, and tokenization.
## Architecture
### Core Components
- **VertexAIService**: Main service class implementing the NLPService interface
- **VertexAIClaudeSchematicGenerator**: Generator for Claude models via Anthropic Vertex API
- **VertexAIGeminiSchematicGenerator**: Generator for Gemini models via Google Gen AI API
- **VertexAIEmbedder**: Text embedding service using Google's text-embedding-004 model
- **VertexAIEstimatingTokenizer**: Token counting for both Claude and Gemini models
## Configuration
### Environment Variables
```bash
# Required
VERTEX_AI_PROJECT_ID=your-gcp-project-id
VERTEX_AI_REGION=us-central1 # Put your region
VERTEX_AI_MODEL=claude-opus-4
```
### Authentication
The adapter uses Google Application Default Credentials (ADC):
```bash
# For local development
gcloud auth application-default login
# For production, use service account key or workload identity
```
## Supported Models
### Claude Models (via Anthropic Vertex API)
| Short Name | Full Model Name | Description |
|------------|-----------------|-------------|
| `claude-opus-4` | `claude-opus-4@20250514` | Most capable Claude model |
| `claude-sonnet-4` | `claude-sonnet-4@20250514` | Balanced performance and speed |
| `claude-sonnet-3.5` | `claude-3-5-sonnet-v2@20241022` | Previous generation Sonnet |
| `claude-haiku-3.5` | `claude-3-5-haiku@20241022` | Fastest Claude model |
### Gemini Models (via Google Gen AI API)
| Short Name | Full Model Name | Description |
|------------|-----------------|-------------|
| `gemini-2.5-flash` | `gemini-2.5-flash` | Latest fast Gemini model |
| `gemini-2.5-pro` | `gemini-2.5-pro` | Latest pro Gemini model |
| `gemini-2.0-flash` | `gemini-2.0-flash` | Previous generation flash |
| `gemini-1.5-flash` | `gemini-1.5-flash` | 1M token context |
| `gemini-1.5-pro` | `gemini-1.5-pro` | 2M token context |
## Usage
### Basic Setup
```python
import parlant.sdk import p
from parlant.sdk import NLPServices
async with p.Server(nlp_service=NLPServices.vertex) as server:
agent = await server.create_agent(
name="Healthcare Agent",
description="Is empathetic and calming to the patient.",
)
```
### Direct Service Usage
```python
from parlant.adapters.nlp.vertex_service import VertexAIService
from parlant.core.loggers import Logger
# Initialize service
logger = Logger()
service = VertexAIService(logger=logger)
# Get schematic generator
generator = await service.get_schematic_generator(YourSchemaClass)
# Generate content
result = await generator.generate(
prompt="Your prompt here",
hints={"temperature": 0.7, "max_tokens": 1000}
)
```
## API Reference
### VertexAIService
Main service class implementing the NLPService interface.
#### Constructor
```python
def __init__(self, logger: Logger) -> None
```
Initializes the service with environment variables:
- Reads `VERTEX_AI_PROJECT_ID`, `VERTEX_AI_REGION`, `VERTEX_AI_MODEL`
- Validates Application Default Credentials
- Sets up logging
#### Methods
##### get_schematic_generator
```python
async def get_schematic_generator(self, t: type[T]) -> SchematicGenerator[T]
```
Returns appropriate generator based on configured model:
- Claude models → VertexAIClaudeSchematicGenerator
- Gemini models → VertexAIGeminiSchematicGenerator
- Includes fallback logic for Claude Opus 4
##### get_embedder
```python
async def get_embedder(self) -> Embedder
```
Returns VertexTextEmbedding004 embedder instance.
##### get_moderation_service
```python
async def get_moderation_service(self) -> ModerationService
```
Returns NoModeration service (moderation not yet implemented).
### VertexAIClaudeSchematicGenerator
Schematic generator for Claude models via Anthropic Vertex API.
#### Supported Hints
- `temperature`: Controls randomness (0.0-1.0)
- `max_tokens`: Maximum output tokens
- `top_p`: Nucleus sampling parameter
- `top_k`: Top-k sampling parameter
#### Properties
- `id`: Returns `vertex-ai/{model_name}`
- `tokenizer`: Returns VertexAIEstimatingTokenizer instance
- `max_tokens`: Returns 200,000 (Claude context limit)
#### Methods
##### generate
```python
async def generate(
self,
prompt: str | PromptBuilder,
hints: Mapping[str, Any] = {},
) -> SchematicGenerationResult[T]
```
Generates structured content using Claude models with:
- JSON schema validation
- Retry policies for rate limits and errors
- Usage tracking
### VertexAIGeminiSchematicGenerator
Schematic generator for Gemini models via Google Gen AI API.
#### Supported Hints
- `temperature`: Controls randomness (0.0-1.0)
- `thinking_config`: Configuration for reasoning models
#### Properties
- `id`: Returns `vertex-ai/{model_name}`
- `tokenizer`: Returns VertexAIEstimatingTokenizer instance
- `max_tokens`: Returns 1M (Flash) or 2M (Pro) tokens
#### Methods
##### generate
```python
async def generate(
self,
prompt: str | PromptBuilder,
hints: Mapping[str, Any] = {},
) -> SchematicGenerationResult[T]
```
Generates structured content using Gemini models with:
- Native JSON schema support
- JSON parsing and validation
- Usage metadata tracking
### VertexAIEmbedder
Text embedding service using Google's text-embedding-004 model.
#### Properties
- `id`: Returns `vertex-ai/text-embedding-004`
- `dimensions`: Returns 768 (embedding dimensions)
- `max_tokens`: Returns 8,192 (input token limit)
#### Supported Hints
- `title`: Document title for better embeddings
- `task_type`: Embedding task type (default: "RETRIEVAL_DOCUMENT")
#### Methods
##### embed
```python
async def embed(
self,
texts: list[str],
hints: Mapping[str, Any] = {},
) -> EmbeddingResult
```
Generates embeddings for input texts with batch processing support.
### VertexAIEstimatingTokenizer
Token counting service supporting both Claude and Gemini models.
#### Methods
##### estimate_token_count
```python
async def estimate_token_count(self, prompt: str) -> int
```
Estimates token count using:
- tiktoken for Claude models
- Google Gen AI API for Gemini models
## Error Handling
### Authentication Errors
```python
class VertexAIAuthError(Exception):
"""Raised when there are authentication issues with Vertex AI."""
```
Common causes and solutions:
- Missing ADC: Run `gcloud auth application-default login`
- Insufficient permissions: Ensure "Vertex AI User" role
- Model not enabled: Check Vertex AI Model Garden
### Rate Limiting
The adapter implements comprehensive retry policies:
#### Claude Models
- Retries: APIConnectionError, APITimeoutError, RateLimitError, APIResponseValidationError
- Max attempts: 3 with exponential backoff (1s, 2s, 4s)
- Server errors: 2 attempts with longer delays (1s, 5s)
#### Gemini Models
- Retries: NotFound, TooManyRequests, ResourceExhausted
- Max attempts: 3 with exponential backoff (1s, 2s, 4s)
- Server errors: 2 attempts with longer delays (1s, 5s)
### Error Messages
The adapter provides detailed error messages for common issues:
#### Rate Limit Exceeded
```
Vertex AI rate limit exceeded. Possible reasons:
1. Your GCP project may have insufficient quota.
2. The model may not be enabled in Vertex AI Model Garden.
3. You might have exceeded the requests-per-minute limit.
Recommended actions:
- Check your Vertex AI quotas in the GCP Console.
- Ensure the model is enabled in Vertex AI Model Garden.
- Review IAM permissions for the service account.
- Visit: https://console.cloud.google.com/vertex-ai/model-garden
```
#### Permission Denied
```
Permission denied accessing Vertex AI. Ensure:
1. ADC is properly configured (run 'gcloud auth application-default login')
2. The service account has 'Vertex AI User' role
3. The {model_name} model is enabled in Vertex AI Model Garden
```
## Performance Considerations
### Token Limits
| Model Type | Context Limit | Recommended Usage |
|------------|---------------|-------------------|
| Claude Models | 200K tokens | Long documents, complex reasoning |
| Gemini Flash | 1M tokens | Large context processing |
| Gemini Pro | 2M tokens | Maximum context requirements |
## Best Practices
### Model Selection
1. **Claude Sonnet 3.5**: Best balance of performance and cost
2. **Claude Opus 4**: Maximum capability with fallback
3. **Gemini 2.5 Flash**: Fast processing with large context
4. **Gemini 2.5 Pro**: Complex reasoning tasks
### Configuration
```python
export VERTEX_AI_PROJECT_ID=your-project-id
export VERTEX_AI_REGION=us-central1
export VERTEX_AI_MODEL=claude-sonnet-3.5
```
### Error Handling
```python
from parlant.adapters.nlp.vertex_service import VertexAIAuthError
try:
service = VertexAIService(logger=logger)
generator = await service.get_schematic_generator(MySchema)
result = await generator.generate(prompt)
except VertexAIAuthError as e:
logger.error(f"Authentication failed: {e}")
# Handle auth setup
except Exception as e:
logger.error(f"Generation failed: {e}")
# Handle other errors
```
## Troubleshooting
### Common Issues
1. **Authentication Failures**
- Verify ADC setup: `gcloud auth application-default print-access-token`
- Check project permissions in GCP Console
- Ensure service account has required roles
2. **Model Access Denied**
- Enable models in Vertex AI Model Garden
- Check regional availability
- Verify billing account is active
3. **Rate Limiting**
- Monitor quota usage in GCP Console
- Implement application-level rate limiting
- Consider upgrading service tier
### Debugging
Check usage from the playground UI by inspecting on the generated message
## Migration Guide
### From Other Adapters
When migrating from other NLP adapters:
1. **Update Environment Variables**
```bash
# Remove old variables
unset OPENAI_API_KEY ANTHROPIC_API_KEY
# Set Vertex AI variables
export VERTEX_AI_PROJECT_ID=your-project-id
export VERTEX_AI_REGION=us-central1
export VERTEX_AI_MODEL=claude-opus-4
```
2. **Model Name Mapping**
- `gpt-4` → `claude-opus-4`
- `gpt-3.5-turbo` → `gemini-2.5-flash`
- `claude-3-sonnet` → `claude-opus-4`
## Contributing
### Adding New Models
1. **Determine Provider**: Check if model uses Anthropic or Google API
2. **Create Model Class**: Inherit from appropriate base generator
3. **Update Service**: Add model mapping in VertexAIService
4. **Add Tests**: Include integration tests for new model
5. **Update Documentation**: Add model to supported models table
### Code Style
- Follow existing patterns for error handling
- Include comprehensive logging
- Add type hints for all methods
- Document public APIs with docstrings
- Use retry policies for external API calls
## Prerequisites and Installation
### Installation
To use the Vertex AI Service Adapter with Parlant, you need to install the appropriate optional dependencies:
```bash
pip install "parlant[vertex]"
```
This installation includes support for both Claude and Gemini models through the Vertex AI platform.
### Important Model Deprecation Notice
⚠️ **Claude 3.5 Sonnet Models Deprecation**: Claude Sonnet 3.5 models (claude-3-5-sonnet-20240620 and claude-3-5-sonnet-20241022) will be retired on October 22, 2025. We recommend migrating to Claude Sonnet 4 (claude-sonnet-4-20250514) for improved performance and capabilities.
## Authentication Setup
Before using the adapter, ensure you have proper authentication configured:
```bash
# For local development
gcloud auth application-default login
# Verify authentication
gcloud auth application-default print-access-token
```
## Required Permissions
Ensure your service account or user has the following IAM roles:
- `Vertex AI User` - for accessing Vertex AI services
- `AI Platform User` - for model access (legacy role, may be needed for some models)
## License
Licensed under the Apache License, Version 2.0. See the source file header for full license text.
## Maintainer
Agam Dubey - hello.world.agam@gmail.com
================================================
FILE: docs/adapters/persistence/snowflake.md
================================================
# Snowflake Persistence Adapter
The Snowflake document adapter lets Parlant persist the long–lived parts of a
deployment—sessions, customers, and context variables—inside your Snowflake
account. That means you can run the server (for example inside Snowpark
Container Services), stop it, and later resume the exact same conversation
state.
This page walks through the required environment variables and shows how to
wire the stores into Snowflake when booting Parlant via the SDK.
## Requirements
1. Install the optional dependency (or otherwise provide
`snowflake-connector-python`):
```bash
pip install "parlant[snowflake]"
```
2. Set the credentials that `SnowflakeDocumentDatabase` consumes:
| Variable | Required | Description |
|-----------------------------|:--------:|-------------------------------------------------------------------------------------|
| `SNOWFLAKE_ACCOUNT` | ✅ | Account locator (e.g. `abc-xy123`). |
| `SNOWFLAKE_USER` | ✅ | Username that Parlant should authenticate as. |
| `SNOWFLAKE_PASSWORD` | ✅* | Password for password-based auth. Skip when using OAuth (see `SNOWFLAKE_TOKEN`). |
| `SNOWFLAKE_TOKEN` | ✅* | OAuth access token. When set, the adapter automatically switches to OAuth. |
| `SNOWFLAKE_WAREHOUSE` | ✅ | Warehouse to execute queries against. |
| `SNOWFLAKE_DATABASE` | ✅ | Database that will host the Parlant tables. |
| `SNOWFLAKE_SCHEMA` | ✅ | Schema inside the database. |
| `SNOWFLAKE_ROLE` | ➖ | Optional role override. |
> ✅* Provide **either** `SNOWFLAKE_PASSWORD` **or** `SNOWFLAKE_TOKEN`.
## SDK / Module Setup
Parlant’s SDK exposes a `configure_container` hook that lets you replace the
default persistence layer. The pattern below shows how to register
Snowflake-backed implementations of the three configurable stores:
- `SessionStore` → `SessionDocumentStore`
- `CustomerStore` → `CustomerDocumentStore`
- `ContextVariableStore` → `ContextVariableDocumentStore`
Each store receives its own table prefix (`PARLANT_SESSIONS_`,
`PARLANT_CUSTOMERS_`, `PARLANT_CONTEXT_VARIABLES_`) so their metadata never
collides. We also rebind `EventEmitterFactory`, so system events get written into
the same store.
```python
from contextlib import AsyncExitStack
import parlant.sdk as p
from parlant.adapters.db.snowflake_db import SnowflakeDocumentDatabase
from parlant.core.emission.event_publisher import EventPublisherFactory
EXIT_STACK = AsyncExitStack()
async def _make_session_store(container: p.Container) -> p.SessionStore:
database = await EXIT_STACK.enter_async_context(
SnowflakeDocumentDatabase(
logger=container[p.Logger],
table_prefix="PARLANT_SESSIONS_",
)
)
store = p.SessionDocumentStore(database=database, allow_migration=True)
return await EXIT_STACK.enter_async_context(store)
async def _make_customer_store(container: p.Container) -> p.CustomerStore:
database = await EXIT_STACK.enter_async_context(
SnowflakeDocumentDatabase(
logger=container[p.Logger],
table_prefix="PARLANT_CUSTOMERS_",
)
)
store = p.CustomerDocumentStore(
id_generator=container[p.IdGenerator],
database=database,
allow_migration=True,
)
return await EXIT_STACK.enter_async_context(store)
async def _make_variable_store(container: p.Container) -> p.ContextVariableStore:
database = await EXIT_STACK.enter_async_context(
SnowflakeDocumentDatabase(
logger=container[p.Logger],
table_prefix="PARLANT_CONTEXT_VARIABLES_",
)
)
store = p.ContextVariableDocumentStore(
id_generator=container[p.IdGenerator],
database=database,
allow_migration=True,
)
return await EXIT_STACK.enter_async_context(store)
async def configure_container(container: p.Container) -> p.Container:
container = container.clone()
session_store = await _make_session_store(container)
container[p.SessionDocumentStore] = session_store
container[p.SessionStore] = session_store
customer_store = await _make_customer_store(container)
container[p.CustomerDocumentStore] = customer_store
container[p.CustomerStore] = customer_store
variable_store = await _make_variable_store(container)
container[p.ContextVariableDocumentStore] = variable_store
container[p.ContextVariableStore] = variable_store
container[p.EventEmitterFactory] = EventPublisherFactory(
container[p.AgentStore],
session_store,
)
return container
async def shutdown_snowflake() -> None:
await EXIT_STACK.aclose()
```
### Using the SDK
```python
async def main() -> None:
try:
async with p.Server(
nlp_service=p.NLPServices.snowflake,
configure_container=configure_container,
) as server:
...
finally:
await shutdown_snowflake()
```
## What Gets Persisted?
Once the Snowflake stores are registered, Snowflake becomes the source of truth for:
- Sessions + events + inspections
- Customers + their tag associations
- Context variables + their values
Other stores (agents, guidelines, journeys, etc.) continue to use their default
backends. If you define them in code at startup, they will automatically be
recreated each time the server runs. For dynamic authoring flows you can follow
the same module approach to route additional stores into Snowflake.
================================================
FILE: docs/adapters/vector_db/qdrant.md
================================================
# Qdrant Vector Database
The Qdrant adapter provides persistent vector storage for Parlant using Qdrant's vector database. This replaces the default in-memory storage with production-ready persistence.
For general Parlant usage, see the [official documentation](https://www.parlant.io/docs/).
## Prerequisites
1. **Install Qdrant adapter**: `pip install parlant[qdrant]`
2. **Choose storage**: Local file system or Qdrant Cloud
## Quick Start
### Setup (Manual)
```python
import parlant.sdk as p
from pathlib import Path
from contextlib import AsyncExitStack
from parlant.adapters.vector_db.qdrant import QdrantDatabase
from parlant.core.nlp.embedding import EmbedderFactory, EmbeddingCache, Embedder
from parlant.core.loggers import Logger
from parlant.core.nlp.service import NLPService
from parlant.core.glossary import GlossaryVectorStore, GlossaryStore
from parlant.core.canned_responses import CannedResponseVectorStore, CannedResponseStore
from parlant.core.capabilities import CapabilityVectorStore, CapabilityStore
from parlant.core.journeys import JourneyVectorStore, JourneyStore
from parlant.adapters.db.transient import TransientDocumentDatabase
async def configure_container(container: p.Container) -> p.Container:
embedder_factory = EmbedderFactory(container)
async def get_embedder_type() -> type[Embedder]:
return type(await container[NLPService].get_embedder())
exit_stack = AsyncExitStack()
qdrant_db = await exit_stack.enter_async_context(
QdrantDatabase(
logger=container[Logger],
path=Path("./qdrant_data"),
embedder_factory=EmbedderFactory(container),
embedding_cache_provider=lambda: container[EmbeddingCache],
)
)
# For Qdrant Cloud, replace the above with:
# qdrant_db = await exit_stack.enter_async_context(
# QdrantDatabase(
# logger=container[Logger],
# url="https://your-cluster-id.us-east4-0.gcp.cloud.qdrant.io",
# api_key="your-api-key-here",
# embedder_factory=EmbedderFactory(container),
# embedding_cache_provider=lambda: container[EmbeddingCache],
# )
# )
# Configure stores using vector database
container[GlossaryStore] = await exit_stack.enter_async_context(
GlossaryVectorStore(
id_generator=container[p.IdGenerator],
vector_db=qdrant_db,
document_db=TransientDocumentDatabase(),
embedder_factory=embedder_factory,
embedder_type_provider=get_embedder_type,
) # type: ignore
)
container[CannedResponseStore] = await exit_stack.enter_async_context(
CannedResponseVectorStore(
id_generator=container[p.IdGenerator],
vector_db=qdrant_db,
document_db=TransientDocumentDatabase(),
embedder_factory=embedder_factory,
embedder_type_provider=get_embedder_type,
) # type: ignore
)
container[CapabilityStore] = await exit_stack.enter_async_context(
CapabilityVectorStore(
id_generator=container[p.IdGenerator],
vector_db=qdrant_db,
document_db=TransientDocumentDatabase(),
embedder_factory=embedder_factory,
embedder_type_provider=get_embedder_type,
) # type: ignore
)
container[JourneyStore] = await exit_stack.enter_async_context(
JourneyVectorStore(
id_generator=container[p.IdGenerator],
vector_db=qdrant_db,
document_db=TransientDocumentDatabase(),
embedder_factory=embedder_factory,
embedder_type_provider=get_embedder_type,
) # type: ignore
)
return container
async def main():
async with p.Server(configure_container=configure_container) as server:
agent = await server.create_agent(
name="My Agent",
description="Agent using Qdrant for persistent storage",
)
# Test: Create a term to verify Qdrant is working
term = await agent.create_term(
name="Example Term",
description="This is stored in Qdrant",
)
print(f"Created term: {term.name}")
# All vector operations now use Qdrant
```
## Verification
To verify Qdrant integration is working correctly:
### Check Collections
**Qdrant Cloud:** Collections appear in your Qdrant dashboard with names like:
- `glossary_OpenAITextEmbedding3Large`
- `glossary_unembedded`
- `capabilities_OpenAITextEmbedding3Large`
- `canned_responses_OpenAITextEmbedding3Large`
**Local Qdrant:** A folder is created at your specified path containing Qdrant database files.
### Confirm No Transient Storage
When Qdrant is properly configured:
- **No vector files** are created in the `parlant-data` folder
- Vector data is stored only in Qdrant (cloud or local)
- Data persists across server restarts
### Test Vector Search
Create terms and test persistence:
```python
term = await agent.create_term(
name="Test Term",
description="This should be stored in Qdrant",
)
# Then chat with agent about "test term" - it should understand via vector search
# Test persistence: close the server and run again
# The term should still be available after restart
```
---
## Common Issues
### Integration Not Working (Still Using Transient Storage)
**Symptoms:**
- No collections appear in Qdrant dashboard
- Vector data appears in `parlant-data` folder
- Data lost on server restart
**Solution:** Ensure all vector stores are properly configured with Qdrant in your `configure_container` function. Make sure you're using `AsyncExitStack` to properly manage the Qdrant database and vector stores lifecycle.
### Windows File Locks
On Windows, use `async with` context manager. The adapter automatically handles file lock retries.
### Collection Sync
Collections auto-sync when embedders or schemas change. Large collections may take time on first access.
### Embedder Changes
When changing embedder types, old embedded collections persist until manually deleted.
### Performance
Use Qdrant Cloud or server for production - local mode doesn't support payload indexes. You'll see a warning about this when using local Qdrant, which is expected and can be ignored.
---
## Troubleshooting
### Connection Issues
- **Local**: Check path exists and is writable
- **Remote**: Verify URL and API key
### Slow Performance
- Use embedding cache
- Use Qdrant Cloud/server for payload indexes
- Consider splitting large collections
### Data Not Persisting
- Check file path is correct and writable
- Verify connection settings for remote servers
- Test by closing the server and restarting—data should persist
---
## Requirements
- Python 3.8+
- `pip install parlant[qdrant]`
- Writable directory (for local storage) or Qdrant Cloud account
## Key Features
- **Persistent storage**: Replaces in-memory storage with production-ready persistence
- **Auto-sync**: Collections automatically sync when embedders or schemas change
- **Windows support**: Automatic file lock handling
================================================
FILE: docs/advanced/contributing.md
================================================
# Contributing to Parlant
We use the Linux-standard Developer Certificate of Origin ([DCO.md](https://github.com/emcie-co/parlant/blob/develop/DCO.md)), so that, by contributing, you confirm that you have the rights to submit your contribution under the Apache 2.0 license (i.e., the code you're contributing is truly yours to share with the project).
Please consult [CONTRIBUTING.md](https://github.com/emcie-co/parlant/blob/develop/CONTRIBUTING.md) for more details.
Want to start getting involved right now? Join us on [Discord](https://discord.gg/duxWqxKk6J) and let's discuss how you can help shape Parlant. We're excited to work with contributors directly while we set up our formal processes.
Otherwise, feel free to start a discussion or open an issue on [GitHub](https://github.com/emcie-co/parlant).
================================================
FILE: docs/advanced/custom-llms.md
================================================
# Custom NLP Models
Once you've understood the basic of setting up [engine extensions](https://parlant.io/docs/advanced/engine-extensions), you can integrate other NLP models into Parlant.
> **A Note on Custom Models**
>
> Parlant was optimized to work with the built-in LLMs, so using other models may require additional configuration and testing.
>
> In particular, please note that Parlant uses some complex output JSON schemas in its operation. This means that you either need a powerful model that can handle complex outputs, or, alternatively, that you use a smaller model (SLM) that has been fine-tuned on Parlant data specifically, using a larger model as a teacher.
>
> Using smaller models is actually a great way to reduce costs, latency—and sometimes even accuracy—in production environments.
## Understanding `NLPService`
Whether you want to use a different model from a supported built-in provider, or an entirely different provider, you can do so by creating a custom `NLPService` implementation.
An `NLPService` has 3 key components:
1. **Schematic Generators**: These are used to generate structured content based on prompts.
2. **Embedders**: These are used to create vector representations of text for semantic retrieval.
3. **Moderation Service**: This is used to filter out harmful or inappropriate user input in conversations.
> **Reference Example**
>
> You can take a look at the official [`OpenAIService`](https://github.com/emcie-co/parlant/blob/main/src/parlant/adapters/nlp/openai_service.py) for a production-ready reference implementation of an `NLPService`.
### Schematic Generation
Throughout the Parlant engine, you'll find references to `SchematicGenerator[T]` objects. These are objects that generate [Pydantic](https://docs.pydantic.dev/latest/) models using instructions in a provided prompt. Behind the scenes, they always use LLMs to generate JSON schemas that in turn are converted to Pydantic models.
All LLM requests in Parlant are actually made using these schematic generators, which means that, whatever model you use, it must be able to generate valid JSON schemas consistently. This is the only requirement for a model in Parlant.
Let's now look at a few important interfaces that you need to implement in your custom NLP service.
#### Estimating Tokenizers
The `EstimatingTokenizer` interface is used to estimate the number of tokens in a prompt. This is important for managing costs and rate limits when using LLM APIs. It's also used in embedding models, where Parlant needs to chunk the input text into smaller parts to fit within the model's context window.
The reason it's called "estimating" is because not all model APIs provide exact token counts.
```python
class EstimatingTokenizer(ABC):
"""An interface for estimating the token count of a prompt."""
@abstractmethod
async def estimate_token_count(self, prompt: str) -> int:
"""Estimate the number of tokens in the given prompt."""
...
```
For example, with `OpenAI`, you can implement this to use the `tiktoken` library to get accurate token counts for GPT models, or estimated token counts for other popular models.
#### Schematic Generators
Now let's look at the `SchematicGenerator[T]` interface itself, which is used to generate structured content based on a prompt.
Each generation result from a `SchematicGenerator[T]` contains not just the generated object, but also additional metadata about the generation process. Here's what it looks like:
```python
@dataclass(frozen=True)
class SchematicGenerationResult(Generic[T]):
content: T # The generated schematic content (a Pydantic model instance)
info: GenerationInfo # Metadata about the generation process
@dataclass(frozen=True)
class GenerationInfo:
schema_name: str # The name of the Pydantic schema used for the generated content
model: str # The name of the model used for generation
duration: float # Time taken for the generation in seconds
usage: UsageInfo # Token usage information
@dataclass(frozen=True)
class UsageInfo:
input_tokens: int
output_tokens: int
extra: Optional[Mapping[str, int]] = None # May contain metrics like cached input tokens
```
Now let's look at the `SchematicGenerator[T]` interface itself, which you'd need to implement for your custom model:
```python
class SchematicGenerator(ABC, Generic[T]):
"""An interface for generating structured content based on a prompt."""
@abstractmethod
async def generate(
self,
# The prompt (or PromptBuilder) containing instructions for the generation.
prompt: str | PromptBuilder,
# Hints are a good way to provide additional context or parameters for the generation,
# such as temperature, top P, logit bias, and things of that nature.
hints: Mapping[str, Any] = {},
) -> SchematicGenerationResult[T]:
"""Generate content based on the provided prompt and hints."""
# Implement this method to generate content using your own model.
...
@property
@abstractmethod
def id(self) -> str:
"""Return a unique identifier for the generator."""
# Normally, this would be the model name or ID used in the LLM API.
...
@property
@abstractmethod
def max_tokens(self) -> int:
"""Return the maximum number of tokens in the underlying model's context window."""
# Return the maximum number of tokens that can be processed by your model.
...
@property
@abstractmethod
def tokenizer(self) -> EstimatingTokenizer:
"""Return a tokenizer that approximates that of the underlying model."""
# This tokenizer should be able to estimate token counts for prompts for this model.
...
@cached_property
def schema(self) -> type[T]:
"""Return the schema type for the generated content.
This is useful for derived classes, allowing them to access the concrete
schema type for the current instance without needing to know the type parameter.
"""
# You don't need to implement this method - it's an inherited convenience method.
orig_class = getattr(self, "__orig_class__")
generic_args = get_args(orig_class)
return cast(type[T], generic_args[0])
```
> **Reference Example**
>
> You can take a look at the official [`OpenAIService`](https://github.com/emcie-co/parlant/blob/main/src/parlant/adapters/nlp/openai_service.py) for a production-ready reference implementation of an `SchematicGenerator[T]`.
### Embedding
In addition to generating structured content, Parlant also uses embedders to create vector representations of text. These are used for semantic retrieval where applicable throughout the response lifecycle.
#### Embedding Results
Every embedding operation returns an `EmbeddingResult`, which contains the vectors generated by the embedder:
```python
@dataclass(frozen=True)
class EmbeddingResult:
vectors: Sequence[Sequence[float]]
```
#### Embedders
Now let's look at the `Embedder` interface and how to implement it:
```python
class Embedder(ABC):
@abstractmethod
async def embed(
self,
texts: list[str],
hints: Mapping[str, Any] = {},
) -> EmbeddingResult:
# Generate embeddings for the given texts.
...
@property
@abstractmethod
def id(self) -> str:
# Return a unique identifier for the embedder - usually the model name or ID.
...
@property
@abstractmethod
def max_tokens(self) -> int:
# Return the maximum number of tokens in the model's context window.
...
@property
@abstractmethod
def tokenizer(self) -> EstimatingTokenizer:
# Return a tokenizer that approximates the model's token count for prompts.
...
@property
@abstractmethod
def dimensions(self) -> int:
# Return the dimensionality of the embedding space.
...
```
> **Reference Example**
>
> You can take a look at the official [`OpenAIService`](https://github.com/emcie-co/parlant/blob/main/src/parlant/adapters/nlp/openai_service.py) for a production-ready reference implementation of an `Embedder`.
### Moderation Services
Parlant includes a comprehensive content moderation system to filter harmful or inappropriate user input. The moderation service is the third key component of an `NLPService`, alongside schematic generators and embedders.
#### Understanding Moderation in Parlant
Parlant's moderation system provides content filtering capabilities that can detect and flag various types of harmful content before it reaches your AI agents. The engine can integrate with all stsandard moderation providers and can be configured with different levels of strictness.
#### Moderation Interface
All moderation services implement the `ModerationService` abstract base class:
```python
@dataclass(frozen=True)
class CustomerModerationContext:
"""Context for moderation check"""
session: Session # Session context for the message being checked
message: str # The content of the message to check
@dataclass(frozen=True)
class ModerationCheck:
"""Result of a moderation check."""
flagged: bool # Whether the content was flagged as inappropriate
tags: list[str] # Specific categories that were flagged
class ModerationService(ABC):
"""Abstract base class for content moderation services."""
@abstractmethod
async def moderate_customer(self, context: CustomerModerationContext) -> ModerationCheck:
"""Check content for policy violations and return moderation result."""
...
```
#### Moderation Tags
Parlant uses standardized moderation tags that map to common content policy categories:
```python
ModerationTag: TypeAlias = Literal[
"jailbreak", # Prompt injection attempts
"harassment", # Harassment or bullying content
"hate", # Hate speech or discrimination
"illicit", # Illegal activities or substances
"self-harm", # Self-harm or suicide content
"sexual", # Sexual or adult content
"violence", # Violence or graphic content
]
```
#### Implementing Custom Moderation Services
Here's how to create your own moderation service:
```python
import httpx
import parlant.sdk as p
class MyModerationService(p.ModerationService):
def __init__(self, api_key: str, logger: p.Logger):
self._api_key = api_key
self._logger = logger
self._client = httpx.AsyncClient()
async def moderate_customer(self, context: p.CustomerModerationContext) -> p.ModerationCheck:
"""Implement your moderation logic here."""
try:
# Example: Call your moderation API
response = await self._client.post(
"https://api.your-moderation-service.com/moderate",
json={"text": context.message},
headers={"Authorization": f"Bearer {self._api_key}"}
)
response.raise_for_status()
result = response.json()
# Map your service's response to Parlant's format
flagged = result.get("flagged", False)
categories = result.get("categories", [])
# Convert your categories to Parlant's standardized tags
tags = []
category_mapping = {
"toxic": "harassment",
"hate_speech": "hate",
"violence": "violence",
"sexual_content": "sexual",
"self_harm": "self-harm",
"illegal": "illicit",
"prompt_injection": "jailbreak",
}
for category in categories:
if category in category_mapping:
tags.append(category_mapping[category])
return p.ModerationCheck(
flagged=flagged,
tags=tags,
)
except Exception as e:
self._logger.error(f"Moderation check failed: {e}")
# Fail closed: return unflagged to allow content through
# Or fail open: return flagged to block content
return p.ModerationCheck(flagged=False, tags=[])
```
## Customizing Prompts
When you implement your own `SchematicGenerator[T]`, you can also customize the prompts it actually uses.
This is achieved via the `PromptBuilder` class. It's the same class used throughout the Parlant engine to build prompts for LLMs using consistent rules and formats, and it allows you to access and modify prompt templates.
One of the cool things you can do with it is to edit specific prompt sections right before you build the final prompt.
Let's look at an example of how we'd override the draft creation prompt of the `CannedResponseGenerator`.
```python
class MySchematicGenerator(p.SchematicGenerator[p.T]):
async def generate(
self,
prompt: str | p.PromptBuilder,
hints: Mapping[str, Any] = {},
) -> p.SchematicGenerationResult[T]:
def edit_draft_instructions(section: p.PromptSection) -> p.PromptSection:
# You can inspect the section's dynamically-passed properties
# to see what you can make use of in your modified template.
section.props
section.template = f"""
Write your custom instructions here ...
Pass in dynamic props where needed: {section.props}
"""
return section
prompt.edit_section(
name="canned-response-generator-draft-general-instructions",
editor_func=edit_draft_instructions,
)
# Call the parent class's generate method with the modified prompt
return await super().generate(prompt, hints)
```
You can modify any section used anywhere within Parlant. You can find these sections by looking at references to `PromptBuilder.add_section()` in the Parlant codebase.
## Implementing an `NLPService`
Now that you understand the key interfaces, you can implement your own `NLPService`. This is the easy part.
Here's what that would look like:
```python
class MyNLPService(p.NLPService):
def __init__(self, logger: p.Logger):
self.logger = logger
async def get_schematic_generator(self, t: type[p.T]) -> p.SchematicGenerator[p.T]:
# Return your custom schematic generator for the given type.
return MySchematicGenerator[p.T](
logger=self.logger, # Assuming you use a logger
)
async def get_embedder(self) -> p.Embedder:
return MyEmbedder(
logger=self.logger, # Assuming you use a logger
)
async def get_moderation_service(self) -> p.ModerationService:
# Return your custom moderation service implementation.
# If you don't need moderation, return NoModeration().
return MyModerationService(logger=self.logger)
```
## Injecting a Custom `NLPService`
Once you've implemented your custom `NLPService`, you can easily register it with your Parlant server.
You also get a reference to the dependency-injection container, from which you can access the system's logger and other services, as needed.
```python
def load_custom_nlp_service(container: p.Container) -> p.NLPService:
return MyNLPService(
logger=container[p.Logger]
)
```
Then, when you start your Parlant server, pass your loader function to the `nlp_service` parameter:
```python
async with p.Server(
nlp_service=load_custom_nlp_service,
) as server:
# Your code here
```
================================================
FILE: docs/advanced/engine-extensions.md
================================================
# Engine Extensions
Working with an external framework and adapting it to your needs isn’t always simple, especially when you need it to behave in ways its original design didn’t anticipate.
Modifying the framework’s source code is a treacherous path—not just because it requires deeper expertise, but also because it leads to divergences between your locally-modified version and upstream updates.
So how do you get a pre-built framework to work differently? The idea is to be able to run a system or software that includes your code customizations without breaking its fundamental assumptions.
The [Open/Closed Principle](https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle) states that software should be open for extension, but closed for modification, such that it can allow its behavior to be extended without modifying its source code. Parlant is carefully designed to abide by this principle, allowing you to achieve extreme extensibility by hooking into its structure.
With extensions, you are free to build exactly what you need without waiting for updates or modifying core engine components. This is a good time to remind you that you can join our [Discord](https://discord.gg/duxWqxKk6J) community to ask questions.
## Engine Hooks
Every time an agent needs to respond to a customer, the engine goes through a series of steps to generate the response. You can hook into these steps to modify the behavior of the engine. This is easily done by registering hook functions.
While there are many hooks you can utilize, here's a simple example that:
1. Overrides the entire engine's response generation process if we detect that the customer only greeted the agent.
1. Inspects the agent's message for compliance breaches (using a custom checker) before sending it to the customer.
```python
import asyncio
from typing import Any
import parlant.sdk as p
async def intercept_message_generation_with_greeting(
ctx: p.LoadedContext, payload: Any, exc: Exception | None
) -> p.EngineHookResult:
if await is_only_greeting(ctx.interaction.last_customer_message):
await ctx.session_event_emitter.emit_message_event(
trace_id=ctx.tracer.trace_id,
data="Hello! How can I help you today?",
)
return p.EngineHookResult.BAIL # Intercept the rest of the process
else:
return p.EngineHookResult.CALL_NEXT # Continue with the normal process
async def check_message_compliance(
ctx: p.LoadedContext, payload: Any, exc: Exception | None
) -> p.EngineHookResult:
generated_message = payload
if not await is_compliant(generated_message):
ctx.logger.warning(f"Prevented sending a non-compliant message: '{generated_message}'.")
return p.EngineHookResult.BAIL # Do not send this message
return p.EngineHookResult.CALL_NEXT # Continue with the normal process
async def configure_hooks(hooks: p.EngineHooks) -> p.EngineHooks:
hooks.on_acknowledged.append(intercept_message_generation_with_greeting)
hooks.on_message_generated.append(check_message_compliance)
return hooks
async def main():
async with p.Server(
configure_hooks=configure_hooks,
) as server:
# Your logic here
...
```
## Dependency Injection
In order to extend the engine without modifying its source code, Parlant uses a [dependency injection](https://en.wikipedia.org/wiki/Dependency_injection) system. This allows you to inject your own implementations of various components or even the processing engine itself (say, if you wanted to optimize the entire pipeline for particular use cases).
For simplicity, we'll take a look at some basic extension mechanics, as well as common use cases for extension.
However, if you need help with something that isn't covered here, please reach out to us on [Discord](https://discord.gg/duxWqxKk6J), [GitHub Discussions](https://github.com/emcie-co/parlant/discussions), or simply using the [Contact Page](https://parlant.io/contact) and we'll get back to you.
### Working with the Container
Let's see how to work with Parlant's dependency injection container. The container is a central place where all components are registered, and you can use it to retrieve or register your own components.
There are two things you might want to do with respect to the container:
1. **Register your own components**: You can add your own implementations of various components to the container, making them available for injection throughout the application.
1. **Adjust the behavior of existing components**: You can retrieve instances of components from the container, allowing you to use them in your own code.
#### Registering Components
Registering components lets you override nearly every aspect of how Parlant works. You can access the container during its registration phase by passing a `configure_container` hook to the server.
This hook accepts a baseline state of the container, and returns a modified version of it before the server starts.
```python
import asyncio
import parlant.sdk as p
async def configure_container(container: p.Container) -> p.Container:
# Register your own components here
# ...
return container
async def main():
async with p.Server(
configure_container=configure_container,
) as server:
# Your logic here
...
```
#### Adjusting Existing Components
If you want to adjust the behavior of built-in components, you can retrieve them from the container and modify their behavior. This is useful for debugging or extending existing functionality without replacing the entire component.
This hook is called `initialize_container`, and it allows you to modify components within the container after all of the classes have been registered and determined—but before the server actually starts to use them.
This hook accepts the final state of the container, and returns `None`, as the container is only provided for _accessing_ registered components.
```python
import asyncio
import parlant.sdk as p
async def initialize_container(container: p.Container) -> None:
# Register your own components here
# ...
return container
async def main():
async with p.Server(
configure_container=configure_container,
) as server:
# Your logic here
...
```
## Open for Extension
If you read or debug Parlant code, you'll come across many different types of components within the engine. Using the configuration and initialization hooks, you now know how to access them and extend, modify, or completely override their implementations as needed.
#### Common Use Cases for Extensions
1. Overriding the no-match behavior of canned responses. This is actually documented here: [Canned Responses](https://parlant.io/docs/concepts/customization/canned-responses#no-match-responses).
1. Wrapping any engine component to add logging, monitoring, or other cross-cutting concerns.
1. Overriding the way particular guidelines are evaluated. For example, if they are simple and you have enough data, you can evaluate them with custom-trained BERT models instead of going through an LLM.
1. Overriding the entire message generation component, allowing you to leverage Parlant's guideline matching and tool execution, but using your message generation logic.
But there's much more you can do. The engine is designed to be flexible and extensible, so you can adapt it to your specific needs without modifying the core codebase.
================================================
FILE: docs/advanced/explainability.md
================================================
# Enforcement & Explainability
Let's dive into how Parlant enforces the conversation model consistently and provides visibility into your agent's situational understanding and decision-making process.
In this section, you'll learn:
1. How _Attentive Reasoning Queries (ARQs)_ enforce the conversation model
1. How to use ARQ artifacts to troubleshoot and improve behavior
### Understanding Runtime Enforcement
During message generation, Parlant ensures guidelines are followed consistently in real-time conversations through our [Attentive Reasoning Queries](https://arxiv.org/abs/2503.03669#:~:text=We%20present%20Attentive%20Reasoning%20Queries%20%28ARQs%29%2C%20a%20novel,in%20Large%20Language%20Models%20through%20domain-specialized%20reasoning%20blueprints.) prompting method. Rather than simply adding guidelines to prompts and hoping for the best, Parlant employes explicit techniques to maximize the LLM's ability and likelihood to adhere to your guidelines.
Attentive Reasoning Queries (ARQs) are essentially structured reasoning blueprints built into prompts that guide LLMs through specific thinking patterns when making decisions or solving problems. Rather than hoping an AI agent naturally considers all important factors, ARQs explicitly outline reasoning steps for different domains—like having specialized mental checklists to go through.
What makes ARQs effective for behavioral enforcement is that they force attention on critical considerations that might otherwise be overlooked. The model must work through predetermined reasoning stages (like context assessment, solution exploration, critique, and decision formation), ensuring it consistently evaluates important constraints before taking action.

**Figure:** Illustration of ARQs (taken from the [research paper](https://arxiv.org/abs/2503.03669#:~:text=We%20present%20Attentive%20Reasoning%20Queries%20%28ARQs%29%2C%20a%20novel,in%20Large%20Language%20Models%20through%20domain-specialized%20reasoning%20blueprints.))
Besides increasing accuracy and conformance to instructions, this process creates, as a byproduct, transparent, auditable reasoning paths that help maintain alignment with desired behaviors.
ARQs are flexible enough to adapt to different contexts and risk levels, with reasoning blueprints that can be tailored to specific domains or regulatory requirements. While there's some computational overhead to this more deliberate thinking process, carefully designed ARQs can beat Chain-of-Thought reasoning in both accuracy and latency.
Parlant uses different sets of ARQs for each of its components (e.g., guideline matching, tool-calling, or message composition), and dynamically specializes the ARQs to the specific entity it's evaluating, whether it's a particular guideline, tool, or conversational context.
Here's an illustrated example from the `GuidelineMatcher`'s logs:
```json
{
"guideline_id": "fl00LGUyZX",
"condition": "the customer wants to return an item",
"condition_application_rationale": "The customer explicitly stated that they need to return a sweater that doesn't fit, indicating a desire to return an item.",
"condition_applies": true,
"action": "get the order number and item name and them help them return it",
"action_application_rationale": [
{
"action_segment": "Get the order number and item name",
"rationale": "I've yet to get the order number and item name from the customer."
},
{
"action_segment": "Help them return it",
"rationale": "I've yet to offer to help the customer in returning the item."
}
],
"applies_score": 9
}
```
### Explaining and Troubleshooting Agent Behavior
Message generation in Parlant goes through quite a lot of quality assurance. As mentioned above, ARQs produce artifacts that can help explain how the agent interpreted circumstances and instructions.
When you run into issues, you can inspect these artifacts to better understand why the agent responded the way it did, and whether it correctly interpreted your intentions.
Over time, this feedback loop helps you build more precise and effective sets of guidelines.

================================================
FILE: docs/concepts/customization/canned-responses.md
================================================
# Canned Responses
Canned responses provide you with precise control over your Parlant agent's responses.
The [concept of canned responses](https://en.wikipedia.org/wiki/Canned_response) comes from real-world contact centers, where they're widely used to ensure that agents communicate with customers in a consistent, accurate, and brand-aligned manner.
By restricting to a pre-defined and pre-approved set of responses, you ensure your agent communicates with a consistent tone, style, and accuracy, aligning perfectly with your brand voice and service protocols while **completely eliminating the risk of even subtle unwanted or hallucinated outputs**.
Canned responses function like a hand of cards: given a set of choices you provide to your agent, it selects the most appropriate "card" that best matches the required response based on the conversation context.


## A Practical Example
#### Without Canned Responses
Using LLM-generated (token-by-token) responses.
> **Customer:** Do you have it in stock?
>
> **Agent:** Yes, we've got this item in stock! Let me know if you need any help finding it.
#### With Canned Responses
```
# Draft message: "Yes, we've got this item in stock! Let me know if you need any help finding it."
#
# Available templates:
# - ...
# - "Hey, {{std.customer.name}}! What help do you need today?"
# - ...
# - "No, sorry, we've just sold the last ones. Would you like to see something similar?"
# - "Yep, we have it. Should I add it to your cart?"
# - ...
```
> **Customer:** Do you have it in stock?
>
> **Agent:** Yep, we have it. Should I add it to your cart?
## How Canned Responses Work
Under the hood, canned responses work in a 4-stage process:
1. The agent drafts a fluid message based on its current situational awareness (interaction, guidelines, tool results, etc.)
2. The engine retrieves the most relevant canned response templates, based on the draft message
3. The engine renders the candidate templates, using tool-provided field substitutions where applicable
4. Based on the draft message, the agent selects the most fitting canned response out of the provided candidates
```mermaid
flowchart LR
A[Draft Fluid Message] --> B[Retrieve Most Relevant Response Templates] --> C[Render Templates] --> D[Select Canned Response]
```
## Composition Modes
Parlant agents can use one of several **composition modes** in their responses. These composition modes offer varying levels of restriction on the agent's outputs, as well as the manner in which it uses your canned responses.
| Mode | Description | Use Cases |
|------|-------------|-----------|
| **Fluid** | The agent prioritizes selecting from canned responses if a good match can be found, but falls back to default message generation otherwise. | **(A)** Staying mostly fluid, but controlling specific situations and responses where applicable<br/>**(B)** Prototyping an agent, generating fluid recommendations for additional utterances as you go |
| **Composited** | The agent will only use the canned response candidates to alter the generated draft message so as to mimic the style of the retrieved candidates | Brand-sensitive use cases where tone of voice is important to maintain |
| **Strict** | The agent can only output responses from the provided ones. If no matching response exists, the agent will send a customizable no-match message. | High-risk settings that cannot afford even the most subtle and infrequent hallucinations |
> **Tip:**
> If you have a high-risk use case and are apprehensive about deploying GenAI agents to your customers, we recommend starting out with strict mode. Parlant is flexible and will allow you to easily transition to more fluid modes when you're ready. You will still maintain and utilize all other aspects of your conversation model as you switch between composition modes.
### Setting an Agent's Composition Mode
You just need to pass the right `composition_mode` when creating your agent:
```python
await server.create_agent(
name="My Agent",
description="An agent that uses canned responses",
composition_mode=p.CompositionMode.STRICT, # or FLUID or COMPOSITED
)
```
## Creating Canned Responses
Here's how you can create canned responses for your agent:
```python
await agent.create_canned_response(template=TEXT)
```
#### Journey-Scoped Responses
You can also add **journey-scoped** responses. These are responses that are only available when a specific journey is active. Scoping your canned responses to journeys is useful for narrowing down the set of responses to choose from, increasing the chances of choosing the desired response.
To do so, just call the `create_canned_response` method on a specific journey instance instead of the agent:
```python
await journey.create_canned_response(template=TEXT)
```
#### Preamble Responses
Parlant's employs multiple techniques to enhance the conversational user-experience by leveraging the principle of [perceived performance](https://en.wikipedia.org/wiki/Perceived_performance#:~:text=Perceived%20performance%2C%20in%20computer%20engineering%2C%20refers%20to%20how,The%20concept%20applies%20mainly%20to%20user%20acceptance%20aspects.). One of these techniques is the use of **preamble responses**.
Parlant agents often send preamble responses (such as _"Got it."_, _"Understood."_, or _"Let me look into that"_) to acknowledge the customer's input while it's working on generating a detailed, accurate response.
Normally, these preamble responses are automatically generated by the agent according to the context, but you can also create custom preamble responses for the agent to choose from.
To create a canned preamble response, just add the `preamble()` tag in your canned response creation:
```python
await agent.create_canned_response(
template="Sure thing.",
tags=[p.Tag.preamble()],
)
```
## Template Syntax
Canned responses are defined using **templates**. Templates are strings that can contain static text, as well as dynamic fields that will be substituted with actual values when the response is selected.
### Standard Fields
Use standard fields (using the `std.` prefix) to display dynamic information from the conversation context:
#### Available values
1. `std.customer.name`: String; The customer's name (or `Guest` for a non-registered [customer](https://parlant.io/docs/concepts/entities/customers))
2. `std.agent.name`: String; The agent's name
3. `std.variables.NAME`: Any; The content of a variable named `NAME`
4. `std.missing_params`: List of strings; Contains the names of missing tool parameters (if any) based on [Tool Insights](https://parlant.io/docs/concepts/customization/tools#tool-insights-and-parameter-options)
#### Example
```python
await agent.create_canned_response(
template="Hi {{std.customer.name}}, Yes, this product is available in stock."
)
```
### Generative Fields
If you refer to a field with a `generative.` prefix, the LLM will auto-infer and substitute the value based on its name and the surrounding context. This is a great way to introduce controlled, localized generation into strict templates.
#### Example
```python
await agent.create_canned_response(
template="Can I ask why you'd like to return {{generative.item_name}}?"
)
```
### Tool/Retriever-Based Fields
Canned responses can refer to fields coming from tool and retriever results. These fields must be specified in the `canned_response_fields` property of a `ToolResult` or a `RetrieverResult`.
This is one of the most useful field types as they can introduce truly dynamic data into your canned responses.
> **Warning: The Crucial Role of Fields in Avoiding Consequential Hallucinations**
>
> There's another great benefit to using tool-based fields in your canned responses. When retrieving candidate responses, the engine will also look at the `canned_response_fields` to determine relevance.
>
> Responses that refer to fields that aren't present in the context will never be selected, even if they're similar to the draft message. This is important, as it helps to ensure that the responses generated by the agent are grounded in the actual data available.
>
> For example, when using the strict composition mode, your agent could never output a message referring to a `{{successful_transaction.id}}` if the `successful_transaction` field was not provided by a successfully-run tool call. In other words, if you coordinate your responses and tools correctly, you can ensure your agent never hallucinates misleading responses about data or state.
#### Example
```python
@p.tool
def get_account_balance(context: p.ToolContext) -> p.ToolResult:
balance = 1234.5
return p.ToolResult(
# Note that you must still provide the result in the `data` field,
# as this is what will inform the agent when evaluating guidelines,
# calling tools, as well as when generating the draft message.
data={f"Account balance is {balance}"},
# Here you provide dynamic values specifically for template field substitution
canned_response_fields={"account_balance": balance},
)
```
And this is how your response template would refer to this field:
```python
await agent.create_canned_response(template="Your current balance is {{account_balance}}")
```
## Returning Full Responses from Tools
Tools can also return full canned responses for consideration. This is useful when you want to generate a complete response based on the tool's output, rather than just providing data for field substitution. It is usually particularly relevant for complex Q&A retrieval scenarios.
```python
@p.tool
def get_answer(context: p.ToolContext, question: str) -> p.ToolResult:
answer = "The answer to your question is...."
return p.ToolResult(
data=answer,
# Make the answer available as a complete canned response candidate
canned_responses=[answer],
)
```
## Optimizing Response Selection
Let's look at how you can ensure that your agent selects the right canned response.
#### Controlling the Draft Message
Because of how the selection process works, the first step to getting the right response delivered is to ensure that the draft message is generated as closely as possible to your desired response. You can achieve this using all of the standard control mechanisms, such as guidelines, journeys, tools, glossary terms, and agent description.
This means you'll need to keep a close eye on what drafts are being generated prior to response selection. You can inspect the generated draft message in the integrated UI to see what the agent wanted to say.

#### Ensuring the Right Candidates Are Retrieved
Next, you need to ensure that your desired response templates are retrieved by the engine as candidates for selection.
Sometimes, the response itself is close enough to the draft message to appear in the candidate list. But not always—especially if its template contains field substitutions which make semantic similarity comparisons harder.
For this, you can use **signals** when creating canned responses. Signals are a way to tell your agent, "This response is a good match for these drafts." Each signal is essentially a draft message example. When retrieving candidate responses, the engine will also look at these signals to find determine relevance, so that if a response has a signal that's really close to the draft message, it will be retrieved as a candidate even if the response itself is quite different in form.
Here's how you can add signals to your canned responses:
```python
await agent.create_canned_response(
template="Yes, we've got this item in stock! Let me know if you need any help finding it.",
signals=["We do have it in stock", "We do! Do you need help finding it?"],
)
```
## The Flexibility of Jinja2
Response templates integrate with the Jinja2 templating engine, enabling more dynamic formatting, substitution filters, as well as list processing. You can learn more advanced syntax on the [Jinja2 documentation site](https://jinja.palletsprojects.com/en/stable/).
#### Example
```python
@p.tool
def get_pizza_toppings(context: p.ToolContext) -> p.ToolResult:
toppings = ['olives', 'peppers', 'onions']
return p.ToolResult(
data={f"Toppings are {toppings}"},
canned_response_fields={"toppings": toppings},
)
```
```python
await agent.create_canned_response(
template="We have the following toppings {% for t in toppings %}\n- {{t}}{% endfor %}"
)
```
## No-Match Responses
When using strict composition mode, if the agent cannot find a suitable canned response for its draft, it will send a no-match response.
If you want to customize this response, there are two ways to do so:
1. Customizing the static no-match response
2. Using a custom no-match provider to dynamically generate the response according to the context
#### Static No-Match Response
This is the simplest way to customize the no-match response. You can set a static no-match response that will be used whenever the agent cannot find a suitable canned response.
```python
async def initialize_func(c: p.Container) -> None:
no_match_provider = c[p.BasicNoMatchResponseProvider]
no_match_provider.template = "My custom no-match response."
async with p.Server(
initialize_container=initialize_func,
) as server:
...
```
#### Custom No-Match Provider
If you need more flexibility, you can create a custom no-match response provider. This allows you to generate the no-match response dynamically based on the conversation context.
However, please note that `p.LoadedContext` (which gives you access to internal engine state) is subject to change in future releases, so keep in mind you may need to adjust your implementation accordingly at some point.
```python
class CustomNoMatchResponseProvider(p.NoMatchResponseProvider):
async def get_template(self, context: p.LoadedContext, draft: str | None) -> str:
# Generate a custom no-match response based on the provided context,
# such as the conversation history, draft message, guidelines, tool calls, etc.
template = "..."
return template
async def configure_func(c: p.Container) -> p.Container:
c[p.NoMatchResponseProvider] = CustomNoMatchResponseProvider()
async with p.Server(
configure_container=configure_func,
) as server:
...
```
================================================
FILE: docs/concepts/customization/glossary.md
================================================
# Glossary
The glossary is a fundamental part of shaping your agent's understanding of its domain. It's like your agent's professional dictionary: a set of terms specific to your business or service context.
### When to Use the Glossary
When you create an agent to handle specific tasks, it often needs to understand the unique vocabulary of your domain. For example, if your agent helps guests book rooms at the Boogie Nights hotel, it needs to know what "Boogie Nights" means in your context—in this case, that it's not just a movie title, but your hotel's name.
#### Creating Glossary Terms
Here's how to create a new glossary term:
```python
await agent.create_term(
name=TERM,
description=DESCRIPTION,
synonyms=[SYNONYM_1, SYNONYM_2, ...],
)
```
### Structure of Terms
Each glossary entry consists of three components:
> * **Term:** The word or phrase being defined
> * **Description:** What this term means in your specific context
> * **Synonyms:** Alternative ways users might refer to this term
For example:
```python
await agent.create_term(
name="Boogie Nights",
description="Our luxury beachfront hotel located in Miami",
synonyms=["BN Hotel", "The Boogie", "Boogie Hotel"],
)
```
### How Agents Use the Glossary
The glossary serves two crucial purposes in agent interactions.
First, it helps your agent understand customers better when they interact with it. When a guest says _"I'd like to stay at The Boogie,"_ the agent knows they're referring to your hotel.
Second, it helps the agent interpret your guidelines correctly. Consider the following configuration:
```python
await agent.create_guideline(
condition="the user asks about Ocean View rooms",
action="explain the Sunrise Package benefits",
)
await agent.create_term(
name="Ocean View",
description="Our premium rooms on floors 15-20 facing the Atlantic",
synonyms=["seaside rooms", "beach view"],
)
await agent.create_term(
name="Sunrise Package",
description="Complimentary breakfast and early check-in for Ocean View bookings",
synonyms=["morning special", "sunrise special"],
)
```
Here, both the condition as well as the action depend on the agent understanding what these terms mean.
If the Customer comes in and asks,
> **Customer:** I heard you have some rooms with a view to the Atlantic. What are those?
The agent can understand, based on the glossary term, that the condition _"the user asks about Ocean View rooms"_ is met, and it can then respond with the action _"explain the Sunrise Package benefits"_.
## Glossary vs Guidelines vs Agent Description
Each component serves a distinct purpose in shaping your agent's behavior:
1. The Glossary teaches your agent "what things are". For example, _"A Club Member is a guest who has stayed with us more than 5 times."_ You can have as many terms as you want.
1. Guidelines teach your agent "how to act in situations". For example, _"When speaking with Club Members, acknowledge their loyalty status."_ You can have as many guidelines as you want.
1. Agent Description provides overall context and personality. For example, _"You are a helpful hotel booking assistant for Boogie Nights."_ The agent's description is static and limited.
Think of it this way: the glossary builds your agent's vocabulary, guidelines shape its behavior, and the agent description sets its overall context, role, personality and tone.
## Glossary vs Tools
While both glossary terms and tools help your agent understand your domain, they serve fundamentally different purposes. The glossary provides static knowledge, while tools enable dynamic data access.
Consider a hotel booking scenario:
**Glossary Term:**
> * **Term:** Club Member
> * **Description:** A guest who has stayed with us more than 5 times
> * **Synonyms:** loyal guest, regular guest
**Tool:**
`check_member_status(user_id) # Returns current stay count and benefits`
The glossary term provides a consistent definition of what a Club Member is, while the tool can check a specific user's actual status in your database. Similarly:
**Glossary Term:**
> * **Term:** Ocean View Room
> * **Description:** Premium rooms on floors 15-20 facing the Atlantic
> * **Synonyms:** seaside room, beach view
**Tool:**
`check_room_availability(room_type, dates) # Returns current availability and rates`
The glossary helps your agent understand what an Ocean View Room is, while the tool provides real-time information about specific rooms' availability and pricing.
This separation between static knowledge (glossary) and dynamic data access (tools) helps create clear, maintainable agent implementations that can handle both general inquiries and specific, data-driven interactions.
================================================
FILE: docs/concepts/customization/guidelines.md
================================================
# Guidelines
Guidelines are a powerful customization feature. While they're quite simple in principle, there is a lot to say about them.
### What Are Guidelines?
Guidelines are the primary way to nudge the behavior of [agents](https://parlant.io/docs/concepts/entities/agents) in Parlant in a contextual and targeted manner.
They allow us to instruct how an agent should respond in specific situations, overriding its default behavior, thus ensuring that its behavior aligns with our expectations and business needs.
Guidelines allow us to shape an [agent](https://parlant.io/docs/concepts/entities/agents)'s behavior in two key scenarios:
1. When certain out-of-the-box responses don't meet our expectations
1. When we simply want to ensure consistent behavior across all interactions
> **Guidelines vs. Journeys**
>
> Journeys are the ideal way to provide a structured, step-by-step interaction flow, while guidelines are more about providing contextual nudges to the agent's behavior. Use journeys for complex interactions that require multiple steps, and guidelines for simpler, context-specific adjustments—as well as for simple, general tool-calling triggers that aren't necessarily within any particular journey.
#### Example
Suppose we have an agent that helps customers order products. By default, the agent's behavior might look like this:
> **User:** I'd like to order a new laptop.
>
> **Agent:** Sure, what are your preferences? (e.g., budget, operating system, screen size, use cases?)
But say we want to make our agent more personable by first having it ask simply whether they want Mac or Windows. We can add a guideline to ensure that this happens consistently, like so:
```python
await agent.create_guideline(
condition="The customer wants to buy a laptop",
action="First, determine whether they prefer Mac or Windows"
)
```
Resulting in a conversation like this:
> **User:** I'd like to order a new laptop.
>
> **Agent:** Sounds good. Would you prefer Mac or Windows?
> **Careful What You Wish For**
>
> Instructing an LLM is very similar to instructing a human, except that by default it has absolutely zero context of who is instructing it and the context in which the instruction is given. For this reason, when we provide guidelines, we must strive to be as clear and articulate as possible, so that the agent can follow them without ambiguity. More about this later in this page.
### The Structure of Guidelines
In Parlant, each guideline is composed of two parts: the **condition** and the **action**.
1. The **action** part describes what the guideline should accomplish. For example, "Offer a discount."
1. The **condition** is the part the specifies _when the action should take place_. For example, "It is a holiday".
```python
await agent.create_guideline(
condition="It is a holiday",
action="Offer a discount on the order"
)
```
When speaking informally about guidelines, we often describe them in _when/then_ form: When <CONDITION>, Then <ACTION>, or in this case, When it is a holiday, Then offer a discount.
> **Guideline Tracking**
>
> Once the action is accomplished in a session, Parlant will deactivate the guideline—unless it has reason to believe the action should re-apply due to a contextual shift (e.g., in the example above, if the customer starts another order).
### Using Tools
One of the foremost issues with most LLMs is their bias toward false-positives. Put simply, they are always looking to please, so they will tend to answer positively to most questions.
This becomes a huge problem when we want to ensure that an agent only performs certain actions when it has the right context or information.
For this reasons, Parlant allows us to associate [tools](https://parlant.io/docs/concepts/customization/tools) (essentially, functions) with guidelines, such that the agent would only consider calling a tool when a guideline's requisite condition is met within the interaction's current context.
Just as importantly, it also allows you to specify contextual information on *how* and *why* you want a particular tool to be called when certain circumstances hold. Here's an example:
```python
@p.tool
async def find_products_in_stock(context: p.ToolContext, query: str) -> p.ToolResult:
...
await agent.create_guideline(
condition="The customer asks about the newest laptops",
action="First recommend the latest Mac laptops",
# The guideline's action will ensure the following tool is
# called with the right query (e.g., "Latest Mac laptops")
tools=[find_products_in_stock],
)
```
## How Guidelines Work
To understand how guidelines work, we need to look briefly at Parlant's response processing pipeline.
When an agent receives a message, it goes through a response processing pipeline that involves several steps to ensure the response is aligned with the guidelines and expectations.
```mermaid
graph LR
Engine -->|Match guidelines| GuidelineMatcher
GuidelineMatcher -->|Call associated tools| ToolCaller
ToolCaller -->|Compose message| MessageComposer
MessageComposer -.->|Generated response| Engine
```
As the figure above suggests, guidelines are evaluated and matched *before* the agent composes its response.
> **Keep in Mind**
>
> This means that the agent needs to be able to evaluate and apply instructions and tool calls based on the interaction's context *before* generating the response. In other words, guidelines such as "Do X immediately after you've done Y" may not work as you expect.
### How Parlant Uses Guidelines
LLMs are a magnificent creation, built on the principle of [statistical attention](https://arxiv.org/abs/1706.03762) in text; yet, their attention span is painfully finite. When it comes to following instructions, they need help.
Behind the scenes, Parlant ensures that agent responses are aligned with expectations by dynamically managing the LLM's context to only include the relevant guidelines at each point.
```mermaid
%%{init: {'sequence': {'mirrorActors': false}}}%%
sequenceDiagram
participant Engine
participant GuidelineMatcher
participant MessageComposer
Engine ->> GuidelineMatcher: match guidelines
GuidelineMatcher -->> Engine: <guidelines>
Engine ->> MessageComposer: compose contextually guided message
MessageComposer -->> Engine: <guided message>
```
Before each response, Parlant only loads the guidelines that are relevant to the conversation's current state. This dynamic management keeps the LLM's "cognitive load" minimal, maximizing its attention and, consequently, the alignment of each response with expected behavior.
> Another important ability that Parlant employs to ensure alignment is supervising the agent's outputs before they reach the [customer](https://parlant.io/docs/concepts/entities/customers), to ensure to the utmost degree that guidelines were correctly adhered to. To achieve this, NLP researchers working on Parlant have devised an innovative prompting technique called **Attentive Reasoning Queries (ARQs)**. You're welcome to explore the research paper on [arxiv.org, Attentive Reasoning Queries: A Systematic Method for Optimizing Instruction-Following in Large Language Models](https://arxiv.org/abs/2503.03669#:~:text=We%20present%20Attentive%20Reasoning%20Queries%20%28ARQs%29%2C%20a%20novel,in%20Large%20Language%20Models%20through%20domain-specialized%20reasoning%20blueprints.).
### Managing Guidelines
Parlant is built to make guideline management as simple as possible.
Often, guidelines are added when business experts request behavioral changes in the agent. Developers can use Parlant to make those changes, iterating quickly and reliably, at the pace of the business experts they're working with.
Here's a practical example. When Sales requests: "The agent should first ask about the customer's needs and pain points before discussing our solution," implementing this feedback takes just a minute by adding the following:
```python
await agent.create_guideline(
condition="The customer has yet to specify their current pain points",
action="Seek to understand their pain points before talking about our solution"
)
```
Once added, Parlant takes care of the rest, automatically ensuring this new guideline is followed consistently across all relevant conversations, without degrading your agent's conformance to other guidelines.
### Formulating Guidelines
Think of an LLM as a highly knowledgeable stranger who's just walked into your business. They might have years of general experience, but they don't know your specific context, preferences, or way of doing things. Yet, this stranger is eager to help and will always try to—even when uncertain.
This is where guidelines come in. They're your way of channeling this endless enthusiasm and broad knowledge into focused, appropriate responses.
But specifying effective guidelines is a bit of an art—just like it is with people.
#### The Art of Guidance
Consider a customer service scenario. As a very naive example, we might be tempted to have:
**DON'T**
> * **Condition:** Customer is unhappy
> * **Action:** Make them feel better
While well-intentioned, this is an example of a guideline that is just too vague. The LLM might interpret this in countless ways, from offering discounts it can't actually provide to making jokes that might be inappropriate for your brand. Instead, consider:
**DO**
> * **Condition:** Customer expresses dissatisfaction with our service
> * **Action:** Acknowledge their frustration specifically, express sincere empathy, and ask for details about their experience so we can address it properly.
Notice how this guideline is both specific and bounded.
**DON'T**
> * **Condition:** Customer asks about products
> * **Action:** Recommend something they might like
**DO**
> * **Condition:** Customer asks for product recommendations without specifying preferences
> * **Action:** Ask about their specific needs, previous experience with similar products, and any particular features they're looking for before making recommendations
#### Finding the Right Balance
In principle, we're looking for guidelines that are "just right"—neither over nor under specified. Consider these iterations for a technical support agent:
**DON'T**
Too vague:
> * **Condition:** Customer has a technical problem
> * **Action:** Help them fix it
**DON'T**
Too rigid:
> * **Condition:** Customer reports an error message
> * **Action:** First ask for their operating system version, then their browser version, then their last system update date
**DO**
Just right:
> * **Condition:** Customer reports difficulty accessing our platform
> * **Action:** Express understanding of their situation, ask for key details about their setup (OS and browser), and check if they've tried some concrete troubleshooting steps
Remember, LLMs will usually take your guidance quite literally. If you tell your agent to "always suggest premium features," it might do so even when talking to a customer who's complaining about pricing. Always try to consider the broader context and potential edge cases when formulating your guidelines. It'll pay off in less changes and troubleshooting down the line.
**If in doubt, prefer to err on the side of vagueness.** The goal of Agentic Behavior Modeling isn't to script out every possible interaction but to provide clear, contextual guidance that shapes the LLM's natural generalization abilities into reliable, appropriate responses for your specific use case.
================================================
FILE: docs/concepts/customization/journeys.md
================================================
# Journeys
There are many use cases where you want your agent to follow a specific flow of conversation, such as booking a trip, troubleshooting an issue, or otherwise guiding a user through a conversational process in the intended manner.
In Parlant, this can be achieved easily and reliably using **Journeys**.
#### Journey Structure
Journeys have 4 important components:
1. **Title:** A short, descriptive name for the journey, to differentiate it from other journeys.
1. **Conditions:** These contextual queries determine when a journey should be active.
1. **Description:** This lets you describe the nature of the journey, including motivating or orientating notes, if needed.
1. **States & Transitions**: A state diagram that communicates to the agent what the ideal flow is.
> **Balancing Rigidity vs. Flexibility**
>
> In traditional conversational frameworks, flows are rigidly defined, with each state and transition being strictly followed to the letter.
>
> While this type of approach is easy to reason about and implement, it very often leads to frustrating user experiences when the agent is unable to adapt to the customer's interaction patterns. This "one-size-fits-all" approach doesn't account for the nuances of human conversation—leading to user disengagement and dissatisfaction, and ultimately resulting in an unused agent.
>
> Parlant implements a "lessons learned" approach, allowing agents to traverse the journey's states in a more natural way. They can choose to skip states, revisit previous states, or even jump ahead to later states in an adaptive manner.
>
> As such, journeys are not meant to be followed rigidly, but rather to serve as a guiding framework for the agent. The agent will strive to follow the flow as strictly as it can, while still maintaining an adaptive approach toward the customer's interaction patterns.
## A Worked Example
Consider the following example for a journey in a travel agent:
> * **Title:** Book Flight
> * **Conditions:** The customer requested to book a flight
> * **Description:** This journey guides the customer through the flight booking process.
```mermaid
%%{init: { "theme": "forest" }}%%
stateDiagram-v2
direction LR
state "Where to?" as A
state "Dates?" as B
state "Load destinations" as Ca
state "Suggest" as Cb
state "Confirm" as E
state "Book" as F
state "Provide ticket" as G
[*] --> A
A --> Ca: Don't know
Ca --> Cb
A --> B: Destination provided
Cb --> B: Destination selected
B --> E
E --> F: Yes
E --> [*]: No
F --> G
G --> [*]
style Ca fill:#ffeecc,stroke:#333,stroke-width:1px
style F fill:#ffeecc,stroke:#333,stroke-width:1px
```
This journey will be activated when the customer asks to book a flight. The agent will then strive to follow the flow while maintaining an adaptive approach at the pace of the customer, yet ensuring that all necessary information is collected.
#### Implementing the Journey
Before we learn more about how journeys work, let's look at how we would implement the journey above:
```python
async def create_book_flight_journey(agent: p.Agent):
journey = await agent.create_journey(
title="Book Flight",
conditions=["The customer requested to book a flight"],
description="This journey guides the customer through the flight booking process.",
)
t1 = await journey.initial_state.transition_to(chat_state="Ask if they have a destination in mind")
# Branch out based on the customer's response
t2 = await t1.target.transition_to(condition="They do", chat_state="Get dates of travel")
t3a = await t1.target.transition_to(condition="They don't", tool_state=load_popular_destinations)
t3b = await t3a.target.transition_to(chat_state="Recommend a destination")
# Merge back to the main path after choosing a destination.
# This is done by transitioning into an existing state node.
await t3b.target.transition_to(state=t2.target, condition="Destination selected")
t4 = await t2.target.transition_to(chat_state="Confirm details")
t5a = await t4.target.transition_to(tool_state=book_flight)
t5b = await t5a.target.transition_to(chat_state="Provide ticket details")
```
## States and Transitions
A journey is modeled after a state diagram, which is a directed graph in which each node represents a **state** and each edge represents a **transition** (which may be associated with a condition).
```mermaid
stateDiagram-v2
direction LR
state "CHAT STATE" as A
state "TOOL STATE" as B
state "CHAT STATE" as C
state "CHAT STATE" as D
state "FORK STATE" as E
state "CHAT STATE" as F
state "CHAT STATE" as G
[*] --> A: INITIAL
A --> B: CONDITIONAL
A --> C: CONDITIONAL
B --> D: DIRECT
C --> E: DIRECT
D --> E: DIRECT
E --> F: CONDITIONAL
E --> G: CONDITIONAL
F --> [*]: END
G --> [*]: END
style B fill:#ffeecc,stroke:#333,stroke-width:1px
```
#### States
1. **Chat States:** While in this state, the agent will chat with the customer while being guided by the state's action. The agent may spend multiple turns in this state, until it decides to transition to another state.
```python
t = await state.transition_to(chat_state=CONVERSATIONAL_INSTRUCTION)
```
2. **Tool States:** In this state, the agent will call an external tool to perform an action and load its result into the context. A tool state must be followed by a chat state, which will usually be used to present the tool's result to the customer.
```python
t = await state.transition_to(tool_state=TOOL)
```
```python
t = await state.transition_to(tool_state=TOOL, tool_instruction=OPTIONAL_HINT_ON_HOW_TO_USE_TOOL)
```
> **Transitioning from Tool to Chat**
>
> When transitioning from a tool state to a chat state, the agent will automatically load the tool's result into the context, so you can use it in the chat state's action. Note that a tool state cannot transition to another tool state; it must always be followed by a chat state.
>
> This is by design, as tool usage can incur noticeable latency in agentic applications. Instead of using sequential tool states, you should use a single tool state to perform all necessary actions, and then follow it with a chat state to present the results to the customer.
#### Transitions
1. **Direct Transitions:** These transitions should always be taken. They move the conversation forward without branching.
2. **Conditional Transitions:** These transitions are only taken if/when their associated condition is met.
```python
t = await state.transition_to(chat_state=CONVERSATIONAL_INSTRUCTION, condition=CONDITION)
```
```python
t = await state.transition_to(tool_state=TOOL, condition=CONDITION)
```
In most cases, you'd be using the `transition_to()` overload that takes a `chat_state` or `tool_state` argument, which will automatically create the transition's target state for you. However, you can also use the `transition_to()` overload that takes a `state` argument, which allows you to transition to an existing state node in the journey.
```python
t = await state.transition_to(state=EXISTING_STATE)
```
```python
t = await state.transition_to(state=EXISTING_STATE, condition=CONDITION)
```
> **Combining Conditional and Direct Transitions**
>
> If a state has a conditional transition to another state, it cannot also have a direct transition coming out of it. This is because the engine would not be able to logically determine which transition to take when the condition is met. The SDK enforces this rule.
#### Fork States
Journeys also support a special kind of state, called a **fork state**.
In this state, the agent will evaluate conditions and branch the conversation flow accordingly. While, strictly speaking, such branching can be modeled without fork states, they are sometimes a useful modeling tool for keeping the conversation flow clear, explicit, and organized.
```python
fork = await state.fork()
t1 = await fork.transition_to(chat_state=CONVERSATIONAL_INSTRUCTION, condition=CONDITION_1)
t2 = await fork.transition_to(chat_state=CONVERSATIONAL_INSTRUCTION, condition=CONDITION_2)
t3 = await fork.transition_to(tool_state=TOOL, condition=CONDITION_3)
```
> **Visualizing Your Journey**
>
> Building a state diagram in code can sometimes be a bit confusing. It's often useful to visualize the journey as you build it, to ensure that the flow is clear, logical, and as you intend. Here's how it's done:
>
> 1. Visit `http://localhost:8800/journeys` in your browser.
> 2. Copy the ID of the journey you want to visualize.
> 3. Visit `http://localhost:8800/journeys/<JOURNEY_ID>/mermaid` in your browser, replacing `<JOURNEY_ID>` with the ID you copied.
> 4. Copy the generated Mermaid diagram code.
> 5. Paste it into a [Mermaid live editor](https://mermaid.live/) to visualize the journey.
## Journey vs. Task Automation
If you look at how the engine works with journeys, it means that journeys should not be used to guide the model on how to automate tasks. Instead, journeys are used by the agent to self-orientate and guide the conversation flow according to your preferences.
This is a good time to recall the importance of separating **business logic** from **conversation logic**. The former is best handled by custom, [dedicated tools](https://parlant.io/docs/concepts/customization/tools) (which may or may not use LLMs internally), while the latter is best handled by the conversational engine.
#### Do's and Don'ts
**DON'T**
The following is ***not*** a valid journey, as it does not represent a conversation flow but rather a task automation flow.
```mermaid
stateDiagram-v2
direction LR
state "Find user ID" as A
state "Load personal preferences" as B
state "Send email" as C
[*] --> A
A --> B
B --> C: Email notifications enabled
B --> [*]: Email notifications disabled
style A fill:#ffeecc,stroke:#333,stroke-width:1px
style B fill:#ffeecc,stroke:#333,stroke-width:1px
style C fill:#ffeecc,stroke:#333,stroke-width:1px
```
**DO**
The following is a valid journey, as it represents a conversation protocol that guides the
gitextract_lshtm9pg/
├── .devcontainer/
│ ├── Dockerfile
│ └── devcontainer.json
├── .githooks/
│ ├── pre-commit
│ ├── pre-push
│ └── prepare-commit-msg
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug-report.md
│ │ └── feature-request.md
│ ├── dco.yml
│ └── workflows/
│ ├── ci-test.yml
│ ├── docker-publish.yml
│ └── lint.yml
├── .gitignore
├── CHANGELOG.md
├── CLAUDE.md
├── CONTRIBUTING.md
├── DCO.md
├── LICENSE
├── README.md
├── docs/
│ ├── adapters/
│ │ ├── nlp/
│ │ │ ├── azure.md
│ │ │ ├── ollama.md
│ │ │ ├── openrouter.md
│ │ │ ├── snowflake-cortex.md
│ │ │ └── vertex.md
│ │ ├── persistence/
│ │ │ └── snowflake.md
│ │ └── vector_db/
│ │ └── qdrant.md
│ ├── advanced/
│ │ ├── contributing.md
│ │ ├── custom-llms.md
│ │ ├── engine-extensions.md
│ │ └── explainability.md
│ ├── concepts/
│ │ ├── customization/
│ │ │ ├── canned-responses.md
│ │ │ ├── glossary.md
│ │ │ ├── guidelines.md
│ │ │ ├── journeys.md
│ │ │ ├── relationships.md
│ │ │ ├── retrievers.md
│ │ │ ├── tools.md
│ │ │ └── variables.md
│ │ ├── entities/
│ │ │ ├── agents.md
│ │ │ └── customers.md
│ │ └── sessions.md
│ ├── interactions.md
│ ├── production/
│ │ ├── agentic-design.md
│ │ ├── api-hardening.md
│ │ ├── custom-frontend.md
│ │ ├── human-handoff.md
│ │ └── input-moderation.md
│ └── quickstart/
│ ├── examples.md
│ ├── installation.md
│ └── motivation.md
├── examples/
│ ├── healthcare.py
│ └── travel_voice_agent.py
├── llms.txt
├── mypy.ini
├── pyproject.toml
├── pytest.ini
├── pytest_stochastics.json
├── ruff.toml
├── scripts/
│ ├── ci/
│ │ └── github_action_ubuntu_2404_free_space.sh
│ ├── fern/
│ │ ├── docs.yml
│ │ ├── fern.config.json
│ │ └── generators.yml
│ ├── generate_client_sdk.py
│ ├── initialize_repo.py
│ ├── install_packages.py
│ ├── lint.py
│ ├── publish.py
│ ├── utils.py
│ └── version.py
├── src/
│ └── parlant/
│ ├── adapters/
│ │ ├── db/
│ │ │ ├── json_file.py
│ │ │ ├── mongo_db.py
│ │ │ ├── snowflake_db.py
│ │ │ └── transient.py
│ │ ├── loggers/
│ │ │ ├── opentelemetry.py
│ │ │ └── websocket.py
│ │ ├── meter/
│ │ │ └── opentelemetry.py
│ │ ├── nlp/
│ │ │ ├── anthropic_service.py
│ │ │ ├── aws_service.py
│ │ │ ├── azure_service.py
│ │ │ ├── cerebras_service.py
│ │ │ ├── common.py
│ │ │ ├── deepseek_service.py
│ │ │ ├── emcie_service.py
│ │ │ ├── fireworks_service.py
│ │ │ ├── gemini_service.py
│ │ │ ├── glm_service.py
│ │ │ ├── hugging_face.py
│ │ │ ├── lakera.py
│ │ │ ├── litellm_service.py
│ │ │ ├── mistral_service.py
│ │ │ ├── modelscope_service.py
│ │ │ ├── ollama_service.py
│ │ │ ├── openai_service.py
│ │ │ ├── openrouter_service.py
│ │ │ ├── qwen_service.py
│ │ │ ├── snowflake_cortex_service.py
│ │ │ ├── together_service.py
│ │ │ ├── vertex_service.py
│ │ │ └── zhipu_service.py
│ │ ├── tracing/
│ │ │ └── opentelemetry.py
│ │ └── vector_db/
│ │ ├── chroma.py
│ │ ├── qdrant.py
│ │ └── transient.py
│ ├── api/
│ │ ├── agents.py
│ │ ├── app.py
│ │ ├── authorization.py
│ │ ├── canned_responses.py
│ │ ├── capabilities.py
│ │ ├── chat/
│ │ │ ├── .gitignore
│ │ │ ├── .prettierrc
│ │ │ ├── .vite/
│ │ │ │ └── deps_temp_0491001f/
│ │ │ │ └── package.json
│ │ │ ├── components.json
│ │ │ ├── dist/
│ │ │ │ ├── assets/
│ │ │ │ │ ├── index-BBAJ1vle.js
│ │ │ │ │ ├── index-BRVifGSy.css
│ │ │ │ │ └── manifest-BRNJYplA.webmanifest
│ │ │ │ ├── fonts/
│ │ │ │ │ ├── Inter/
│ │ │ │ │ │ └── inter.css
│ │ │ │ │ ├── ibm-plex-mono/
│ │ │ │ │ │ ├── ibm-plex-mono.css
│ │ │ │ │ │ └── static/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── ubuntu-mono/
│ │ │ │ │ │ ├── static/
│ │ │ │ │ │ │ └── UFL.txt
│ │ │ │ │ │ └── ubuntu_mono.css
│ │ │ │ │ └── ubuntu-sans/
│ │ │ │ │ ├── README.txt
│ │ │ │ │ ├── UFL.txt
│ │ │ │ │ └── ubuntu_sans.css
│ │ │ │ └── index.html
│ │ │ ├── eslint.config.js
│ │ │ ├── index.html
│ │ │ ├── manifest.webmanifest
│ │ │ ├── package.json
│ │ │ ├── postcss.config.js
│ │ │ ├── public/
│ │ │ │ └── fonts/
│ │ │ │ ├── Inter/
│ │ │ │ │ └── inter.css
│ │ │ │ ├── ibm-plex-mono/
│ │ │ │ │ ├── ibm-plex-mono.css
│ │ │ │ │ └── static/
│ │ │ │ │ └── OFL.txt
│ │ │ │ ├── ubuntu-mono/
│ │ │ │ │ ├── static/
│ │ │ │ │ │ └── UFL.txt
│ │ │ │ │ └── ubuntu_mono.css
│ │ │ │ └── ubuntu-sans/
│ │ │ │ ├── README.txt
│ │ │ │ ├── UFL.txt
│ │ │ │ └── ubuntu_sans.css
│ │ │ ├── setupTests.ts
│ │ │ ├── src/
│ │ │ │ ├── App.css
│ │ │ │ ├── App.tsx
│ │ │ │ ├── components/
│ │ │ │ │ ├── agents-list/
│ │ │ │ │ │ ├── agent-list.module.scss
│ │ │ │ │ │ └── agent-list.tsx
│ │ │ │ │ ├── avatar/
│ │ │ │ │ │ └── avatar.tsx
│ │ │ │ │ ├── canned-response/
│ │ │ │ │ │ └── canned-response.tsx
│ │ │ │ │ ├── canned-responses/
│ │ │ │ │ │ └── canned-responses.tsx
│ │ │ │ │ ├── chat-header/
│ │ │ │ │ │ └── chat-header.tsx
│ │ │ │ │ ├── chatbot/
│ │ │ │ │ │ └── chatbot.tsx
│ │ │ │ │ ├── dark-mode-toggle/
│ │ │ │ │ │ └── dark-mode-toggle.tsx
│ │ │ │ │ ├── error-boundary/
│ │ │ │ │ │ └── error-boundary.tsx
│ │ │ │ │ ├── gradient-button/
│ │ │ │ │ │ ├── gradient-button.module.scss
│ │ │ │ │ │ └── gradient-button.tsx
│ │ │ │ │ ├── header-wrapper/
│ │ │ │ │ │ └── header-wrapper.tsx
│ │ │ │ │ ├── log-filters/
│ │ │ │ │ │ └── log-filters.tsx
│ │ │ │ │ ├── markdown/
│ │ │ │ │ │ └── markdown.tsx
│ │ │ │ │ ├── message/
│ │ │ │ │ │ ├── draft-bubble.tsx
│ │ │ │ │ │ ├── message-bubble.tsx
│ │ │ │ │ │ ├── message-relative-time.tsx
│ │ │ │ │ │ ├── message.module.scss
│ │ │ │ │ │ └── message.tsx
│ │ │ │ │ ├── message-details/
│ │ │ │ │ │ ├── empty-state.tsx
│ │ │ │ │ │ ├── filter-tabs.tsx
│ │ │ │ │ │ ├── flag-message.tsx
│ │ │ │ │ │ ├── indexeddb-data.tsx
│ │ │ │ │ │ ├── message-details-header.tsx
│ │ │ │ │ │ ├── message-details.tsx
│ │ │ │ │ │ ├── message-log.tsx
│ │ │ │ │ │ └── message-logs.tsx
│ │ │ │ │ ├── progress-logo/
│ │ │ │ │ │ └── progress-logo.tsx
│ │ │ │ │ ├── session-list/
│ │ │ │ │ │ ├── session-list-item/
│ │ │ │ │ │ │ ├── session-list-item.module.scss
│ │ │ │ │ │ │ └── session-list-item.tsx
│ │ │ │ │ │ └── session-list.tsx
│ │ │ │ │ ├── session-view/
│ │ │ │ │ │ ├── date-header/
│ │ │ │ │ │ │ └── date-header.tsx
│ │ │ │ │ │ ├── session-view-header/
│ │ │ │ │ │ │ └── session-view-header.tsx
│ │ │ │ │ │ ├── session-view.module.scss
│ │ │ │ │ │ └── session-view.tsx
│ │ │ │ │ ├── ui/
│ │ │ │ │ │ ├── button.tsx
│ │ │ │ │ │ ├── checkbox.tsx
│ │ │ │ │ │ ├── custom/
│ │ │ │ │ │ │ ├── copy-text.tsx
│ │ │ │ │ │ │ ├── line-no-div.tsx
│ │ │ │ │ │ │ ├── spacer.tsx
│ │ │ │ │ │ │ └── tooltip.tsx
│ │ │ │ │ │ ├── dialog.tsx
│ │ │ │ │ │ ├── drawer.tsx
│ │ │ │ │ │ ├── dropdown-menu.tsx
│ │ │ │ │ │ ├── input.tsx
│ │ │ │ │ │ ├── radio-group.tsx
│ │ │ │ │ │ ├── resizable.tsx
│ │ │ │ │ │ ├── select.tsx
│ │ │ │ │ │ ├── sheet.tsx
│ │ │ │ │ │ ├── skeleton.tsx
│ │ │ │ │ │ ├── sonner.tsx
│ │ │ │ │ │ ├── switch.tsx
│ │ │ │ │ │ ├── textarea.tsx
│ │ │ │ │ │ └── tooltip.tsx
│ │ │ │ │ └── virtual-scroll/
│ │ │ │ │ └── virtual-scroll.tsx
│ │ │ │ ├── hooks/
│ │ │ │ │ ├── useDialog.tsx
│ │ │ │ │ ├── useFetch.tsx
│ │ │ │ │ ├── useLocalStorage.ts
│ │ │ │ │ ├── useQuestionDialog.tsx
│ │ │ │ │ └── useWebSocket.ts
│ │ │ │ ├── index.css
│ │ │ │ ├── lib/
│ │ │ │ │ ├── broadcast-channel.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── main.tsx
│ │ │ │ ├── store.ts
│ │ │ │ ├── utils/
│ │ │ │ │ ├── api.ts
│ │ │ │ │ ├── date.tsx
│ │ │ │ │ ├── interfaces.tsx
│ │ │ │ │ ├── logs.ts
│ │ │ │ │ ├── methods.tsx
│ │ │ │ │ ├── obj.tsx
│ │ │ │ │ └── sounds.ts
│ │ │ │ └── vite-env.d.ts
│ │ │ ├── tailwind.config.js
│ │ │ ├── tsconfig.app.json
│ │ │ ├── tsconfig.app.tsbuildinfo
│ │ │ ├── tsconfig.json
│ │ │ ├── tsconfig.node.json
│ │ │ ├── tsconfig.node.tsbuildinfo
│ │ │ └── vite.config.ts
│ │ ├── common.py
│ │ ├── context_variables.py
│ │ ├── customers.py
│ │ ├── evaluations.py
│ │ ├── glossary.py
│ │ ├── guidelines.py
│ │ ├── journeys.py
│ │ ├── logs.py
│ │ ├── relationships.py
│ │ ├── services.py
│ │ ├── sessions.py
│ │ └── tags.py
│ ├── bin/
│ │ ├── client.py
│ │ ├── prepare_migration.py
│ │ └── server.py
│ ├── core/
│ │ ├── agents.py
│ │ ├── app_modules/
│ │ │ ├── agents.py
│ │ │ ├── canned_responses.py
│ │ │ ├── capabilities.py
│ │ │ ├── common.py
│ │ │ ├── context_variables.py
│ │ │ ├── customers.py
│ │ │ ├── evaluations.py
│ │ │ ├── glossary.py
│ │ │ ├── guidelines.py
│ │ │ ├── journeys.py
│ │ │ ├── relationships.py
│ │ │ ├── services.py
│ │ │ ├── sessions.py
│ │ │ └── tags.py
│ │ ├── application.py
│ │ ├── async_utils.py
│ │ ├── background_tasks.py
│ │ ├── canned_responses.py
│ │ ├── capabilities.py
│ │ ├── common.py
│ │ ├── context_variables.py
│ │ ├── customers.py
│ │ ├── emission/
│ │ │ ├── event_buffer.py
│ │ │ └── event_publisher.py
│ │ ├── emissions.py
│ │ ├── engines/
│ │ │ ├── alpha/
│ │ │ │ ├── canned_response_generator.py
│ │ │ │ ├── engine.py
│ │ │ │ ├── engine_context.py
│ │ │ │ ├── entity_context.py
│ │ │ │ ├── guideline_matching/
│ │ │ │ │ ├── common.py
│ │ │ │ │ ├── custom_guideline_matching_strategy.py
│ │ │ │ │ ├── generic/
│ │ │ │ │ │ ├── common.py
│ │ │ │ │ │ ├── disambiguation_batch.py
│ │ │ │ │ │ ├── generic_guideline_matching_strategy.py
│ │ │ │ │ │ ├── guideline_actionable_batch.py
│ │ │ │ │ │ ├── guideline_low_criticality_batch.py
│ │ │ │ │ │ ├── guideline_previously_applied_actionable_batch.py
│ │ │ │ │ │ ├── guideline_previously_applied_actionable_customer_dependent_batch.py
│ │ │ │ │ │ ├── journey/
│ │ │ │ │ │ │ ├── journey_backtrack_check.py
│ │ │ │ │ │ │ ├── journey_backtrack_node_selection.py
│ │ │ │ │ │ │ ├── journey_next_step_selection.py
│ │ │ │ │ │ │ └── journey_node_selection_batch.py
│ │ │ │ │ │ ├── observational_batch.py
│ │ │ │ │ │ └── response_analysis_batch.py
│ │ │ │ │ ├── generic_guideline_matching_strategy_resolver.py
│ │ │ │ │ ├── guideline_match.py
│ │ │ │ │ ├── guideline_matcher.py
│ │ │ │ │ └── guideline_matching_context.py
│ │ │ │ ├── hooks.py
│ │ │ │ ├── message_event_composer.py
│ │ │ │ ├── message_generator.py
│ │ │ │ ├── optimization_policy.py
│ │ │ │ ├── perceived_performance_policy.py
│ │ │ │ ├── planners.py
│ │ │ │ ├── planning/
│ │ │ │ │ └── __init__.py
│ │ │ │ ├── prompt_builder.py
│ │ │ │ ├── relational_resolver.py
│ │ │ │ ├── tool_calling/
│ │ │ │ │ ├── default_tool_call_batcher.py
│ │ │ │ │ ├── overlapping_tools_batch.py
│ │ │ │ │ ├── single_tool_batch.py
│ │ │ │ │ └── tool_caller.py
│ │ │ │ ├── tool_event_generator.py
│ │ │ │ └── utils.py
│ │ │ └── types.py
│ │ ├── entity_cq.py
│ │ ├── evaluations.py
│ │ ├── glossary.py
│ │ ├── guideline_tool_associations.py
│ │ ├── guidelines.py
│ │ ├── journey_guideline_projection.py
│ │ ├── journeys.py
│ │ ├── loggers.py
│ │ ├── meter.py
│ │ ├── nlp/
│ │ │ ├── embedding.py
│ │ │ ├── generation.py
│ │ │ ├── generation_info.py
│ │ │ ├── moderation.py
│ │ │ ├── policies.py
│ │ │ ├── service.py
│ │ │ └── tokenization.py
│ │ ├── persistence/
│ │ │ ├── common.py
│ │ │ ├── data_collection.py
│ │ │ ├── document_database.py
│ │ │ ├── document_database_helper.py
│ │ │ ├── vector_database.py
│ │ │ └── vector_database_helper.py
│ │ ├── relationships.py
│ │ ├── services/
│ │ │ ├── indexing/
│ │ │ │ ├── behavioral_change_evaluation.py
│ │ │ │ ├── common.py
│ │ │ │ ├── customer_dependent_action_detector.py
│ │ │ │ ├── guideline_action_proposer.py
│ │ │ │ ├── guideline_agent_intention_proposer.py
│ │ │ │ ├── guideline_continuous_proposer.py
│ │ │ │ ├── journey_reachable_nodes_evaluation.py
│ │ │ │ ├── relative_action_proposer.py
│ │ │ │ └── tool_running_action_detector.py
│ │ │ └── tools/
│ │ │ ├── mcp_service.py
│ │ │ ├── openapi.py
│ │ │ ├── plugins.py
│ │ │ └── service_registry.py
│ │ ├── sessions.py
│ │ ├── shots.py
│ │ ├── tags.py
│ │ ├── tools.py
│ │ ├── tracer.py
│ │ └── version.py
│ ├── py.typed
│ └── sdk.py
└── tests/
├── __init__.py
├── adapters/
│ ├── db/
│ │ ├── test_chroma.py
│ │ ├── test_json_file.py
│ │ ├── test_mongodb.py
│ │ └── test_snowflake_db.py
│ ├── nlp/
│ │ ├── test_azure_service.py
│ │ ├── test_litellm_service.py
│ │ ├── test_openrouter_service.py
│ │ ├── test_qwen_service.py
│ │ └── test_zhipu_service.py
│ └── vector_db/
│ ├── test_qdrant.py
│ └── test_transient.py
├── api/
│ ├── conftest.py
│ ├── test_agents.py
│ ├── test_app.py
│ ├── test_authorization.py
│ ├── test_canned_responses.py
│ ├── test_capabilities.py
│ ├── test_context_variables.py
│ ├── test_customers.py
│ ├── test_evaluations.py
│ ├── test_glossary.py
│ ├── test_guidelines.py
│ ├── test_journeys.py
│ ├── test_relationships.py
│ ├── test_services.py
│ ├── test_sessions.py
│ ├── test_tags.py
│ └── test_websocket_logger.py
├── conftest.py
├── core/
│ ├── .gitkeep
│ ├── common/
│ │ ├── engines/
│ │ │ └── alpha/
│ │ │ ├── steps/
│ │ │ │ ├── agents.py
│ │ │ │ ├── canned_responses.py
│ │ │ │ ├── capabilities.py
│ │ │ │ ├── context_variables.py
│ │ │ │ ├── customers.py
│ │ │ │ ├── engines.py
│ │ │ │ ├── events.py
│ │ │ │ ├── guidelines.py
│ │ │ │ ├── journeys.py
│ │ │ │ ├── sessions.py
│ │ │ │ ├── tags.py
│ │ │ │ ├── terms.py
│ │ │ │ └── tools.py
│ │ │ └── utils.py
│ │ └── utils.py
│ ├── conftest.py
│ ├── stable/
│ │ ├── engines/
│ │ │ └── alpha/
│ │ │ ├── features/
│ │ │ │ ├── baseline/
│ │ │ │ │ ├── capabilities.feature
│ │ │ │ │ ├── context_variables.feature
│ │ │ │ │ ├── conversation.feature
│ │ │ │ │ ├── errors.feature
│ │ │ │ │ ├── glossary.feature
│ │ │ │ │ ├── journeys.feature
│ │ │ │ │ ├── moderation.feature
│ │ │ │ │ ├── proactivity.feature
│ │ │ │ │ ├── relationships.feature
│ │ │ │ │ ├── strict_canned_responses.feature
│ │ │ │ │ ├── strict_canned_responses_capabilities.feature
│ │ │ │ │ ├── supervision.feature
│ │ │ │ │ ├── tools.feature
│ │ │ │ │ └── triggered_utterances.feature
│ │ │ │ └── user_stories/
│ │ │ │ └── conversation.feature
│ │ │ ├── test_baseline_scenarios.py
│ │ │ ├── test_context_variable_loading.py
│ │ │ ├── test_disambiguation_batch.py
│ │ │ ├── test_generic_response_analysis.py
│ │ │ ├── test_guideline_actionable_batch.py
│ │ │ ├── test_guideline_low_criticality_batch.py
│ │ │ ├── test_guideline_matcher.py
│ │ │ ├── test_journey_node_selection.py
│ │ │ ├── test_mcp.py
│ │ │ ├── test_previously_applied_actionable_batch.py
│ │ │ ├── test_previously_applied_actionable_customer_dependent_batch.py
│ │ │ ├── test_relational_resolver.py
│ │ │ ├── test_tool_caller.py
│ │ │ └── test_user_story_scenarios.py
│ │ ├── nlp/
│ │ │ ├── test_embedding.py
│ │ │ └── test_generation.py
│ │ ├── persistence/
│ │ │ └── test_matches_filters.py
│ │ ├── services/
│ │ │ ├── indexing/
│ │ │ │ ├── test_agent_intention_proposer.py
│ │ │ │ ├── test_continuous_guideline_proposer.py
│ │ │ │ ├── test_customer_dependent_action_detector.py
│ │ │ │ ├── test_guideline_action_proposer.py
│ │ │ │ ├── test_relative_action_step_proposer.py
│ │ │ │ └── test_tool_running_action_detector.py
│ │ │ └── tools/
│ │ │ ├── test_openapi.py
│ │ │ └── test_plugin_client.py
│ │ ├── test_application.py
│ │ ├── test_capability_vector_store.py
│ │ ├── test_entity_cq.py
│ │ ├── test_journey_guideline_projection.py
│ │ └── test_relationships.py
│ ├── test_cancellation_suppression_latch.py
│ ├── test_id_generator.py
│ └── unstable/
│ └── engines/
│ └── alpha/
│ ├── features/
│ │ ├── baseline/
│ │ │ ├── conversation.feature
│ │ │ ├── fluid_canned_responses.feature
│ │ │ ├── glossary.feature
│ │ │ ├── strict_canned_responses.feature
│ │ │ ├── supervision.feature
│ │ │ └── tools.feature
│ │ └── user_stories/
│ │ └── conversation.feature
│ ├── test_agent_intention_proposer.py
│ ├── test_baseline_scenarios.py
│ ├── test_disambiguation_batch.py
│ ├── test_guideline_matcher.py
│ ├── test_journey_node_selection.py
│ ├── test_previously_applied_actionable_batch.py
│ └── test_user_story_scenarios.py
├── data/
│ └── get_products_by_type_data.json
├── e2e/
│ ├── conftest.py
│ ├── test_client_cli_via_api.py
│ ├── test_server_cli.py
│ └── test_utilities.py
├── modules/
│ ├── bank.py
│ ├── mcp_parrot.py
│ └── tech_store.py
├── sdk/
│ ├── conftest.py
│ ├── test_agents.py
│ ├── test_canned_responses.py
│ ├── test_current_entities.py
│ ├── test_customers.py
│ ├── test_dynamic_composition_mode.py
│ ├── test_glossary.py
│ ├── test_guidelines.py
│ ├── test_journeys.py
│ ├── test_labels.py
│ ├── test_planners.py
│ ├── test_retrievers.py
│ ├── test_sdk_validation.py
│ ├── test_server.py
│ ├── test_tools.py
│ ├── test_variables.py
│ └── utils.py
├── test_utilities.py
└── tool_utilities.py
Showing preview only (812K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (8451 symbols across 317 files)
FILE: examples/healthcare.py
function get_insurance_providers (line 9) | async def get_insurance_providers(context: p.ToolContext) -> p.ToolResult:
function get_upcoming_slots (line 14) | async def get_upcoming_slots(context: p.ToolContext) -> p.ToolResult:
function get_later_slots (line 20) | async def get_later_slots(context: p.ToolContext) -> p.ToolResult:
function schedule_appointment (line 26) | async def schedule_appointment(context: p.ToolContext, datetime: datetim...
function get_lab_results (line 32) | async def get_lab_results(context: p.ToolContext) -> p.ToolResult:
function add_domain_glossary (line 48) | async def add_domain_glossary(agent: p.Agent) -> None:
function create_scheduling_journey (line 69) | async def create_scheduling_journey(server: p.Server, agent: p.Agent) ->...
function create_lab_results_journey (line 129) | async def create_lab_results_journey(server: p.Server, agent: p.Agent) -...
function main (line 165) | async def main() -> None:
FILE: examples/travel_voice_agent.py
function get_available_destinations (line 9) | async def get_available_destinations(context: p.ToolContext) -> p.ToolRe...
function get_available_flights (line 21) | async def get_available_flights(context: p.ToolContext, destination: str...
function get_alternative_flights (line 33) | async def get_alternative_flights(context: p.ToolContext, destination: s...
function book_flight (line 44) | async def book_flight(context: p.ToolContext, flight_details: str) -> p....
function get_booking_status (line 53) | async def get_booking_status(context: p.ToolContext, confirmation_number...
function add_domain_glossary (line 71) | async def add_domain_glossary(agent: p.Agent) -> None:
function create_flight_booking_journey (line 99) | async def create_flight_booking_journey(server: p.Server, agent: p.Agent...
function create_booking_status_journey (line 167) | async def create_booking_status_journey(server: p.Server, agent: p.Agent...
function configure_container (line 211) | async def configure_container(container: p.Container) -> p.Container:
function main (line 216) | async def main() -> None:
FILE: scripts/generate_client_sdk.py
function replace_in_files (line 38) | def replace_in_files(rootdir: Path, search: str, replace: str) -> None:
FILE: scripts/initialize_repo.py
function install_packages (line 21) | def install_packages() -> None:
function install_hooks (line 25) | def install_hooks() -> None:
FILE: scripts/install_packages.py
function install_package (line 21) | def install_package(package: Package) -> None:
FILE: scripts/lint.py
function run_cmd_or_die (line 21) | def run_cmd_or_die(
function lint_package (line 35) | def lint_package(mypy: bool, ruff: bool, package: Package) -> None:
FILE: scripts/publish.py
function get_server_version (line 24) | def get_server_version() -> str:
function run_command (line 32) | def run_command(args: list[str]) -> None:
function publish_docker (line 49) | def publish_docker() -> None:
function publish_package (line 92) | def publish_package(package: Package) -> None:
FILE: scripts/utils.py
class Package (line 24) | class Package:
method run_cmd (line 31) | def run_cmd(self, cmd: str) -> tuple[int, str]:
function get_repo_root (line 36) | def get_repo_root() -> Path:
function get_packages (line 47) | def get_packages() -> list[Package]:
function for_each_package (line 61) | def for_each_package(
function die (line 78) | def die(message: str) -> NoReturn:
FILE: scripts/version.py
function get_project_file (line 27) | def get_project_file(package: Package) -> Path:
function get_current_version (line 31) | def get_current_version(package: Package) -> str:
function set_package_version (line 36) | def set_package_version(version: str, package: Package) -> None:
function update_version_variable_in_code (line 72) | def update_version_variable_in_code(version: str) -> None:
function tag_repo (line 88) | def tag_repo(version: str) -> None:
function get_current_server_version (line 96) | def get_current_server_version() -> str:
function update_version (line 101) | def update_version(
function there_are_pending_git_changes (line 134) | def there_are_pending_git_changes() -> bool:
function commit_version (line 141) | def commit_version(version: str) -> bool:
FILE: src/parlant/adapters/db/json_file.py
class JSONFileDocumentDatabase (line 47) | class JSONFileDocumentDatabase(DocumentDatabase):
method __init__ (line 48) | def __init__(
method flush (line 66) | async def flush(self) -> None:
method __aenter__ (line 70) | async def __aenter__(self) -> Self:
method __aexit__ (line 76) | async def __aexit__(
method _load_raw_data (line 86) | async def _load_raw_data(
method _save_data (line 96) | async def _save_data(
method load_documents_with_loader (line 111) | async def load_documents_with_loader(
method create_collection (line 146) | async def create_collection(
method get_collection (line 160) | async def get_collection(
method get_or_create_collection (line 181) | async def get_or_create_collection(
method delete_collection (line 209) | async def delete_collection(
method _flush_unlocked (line 219) | async def _flush_unlocked(self) -> None:
class JSONFileDocumentCollection (line 226) | class JSONFileDocumentCollection(DocumentCollection[TDocument]):
method __init__ (line 227) | def __init__(
method find (line 244) | async def find(
method _apply_sort (line 291) | def _apply_sort(
method _apply_field_sort (line 310) | def _apply_field_sort(
method _apply_cursor_filter (line 325) | def _apply_cursor_filter(
method find_one (line 362) | async def find_one(
method ensure_indexes (line 379) | async def ensure_indexes(
method insert_one (line 386) | async def insert_one(
method update_one (line 400) | async def update_one(
method delete_one (line 438) | async def delete_one(
FILE: src/parlant/adapters/db/mongo_db.py
class MongoDocumentDatabase (line 37) | class MongoDocumentDatabase(DocumentDatabase):
method __init__ (line 38) | def __init__(
method create_collection (line 52) | async def create_collection(
method get_collection (line 71) | async def get_collection(
method get_or_create_collection (line 129) | async def get_or_create_collection(
method delete_collection (line 137) | async def delete_collection(self, name: str) -> None:
method __aenter__ (line 143) | async def __aenter__(self) -> Self:
method __aexit__ (line 147) | async def __aexit__(
class MongoDocumentCollection (line 159) | class MongoDocumentCollection(DocumentCollection[TDocument]):
method __init__ (line 160) | def __init__(
method find (line 168) | async def find(
method _translate_sort (line 235) | def _translate_sort(
method find_one (line 244) | async def find_one(
method ensure_indexes (line 253) | async def ensure_indexes(
method insert_one (line 263) | async def insert_one(self, document: TDocument) -> InsertResult:
method update_one (line 267) | async def update_one(
method delete_one (line 282) | async def delete_one(self, filters: Where) -> DeleteResult[TDocument]:
FILE: src/parlant/adapters/db/snowflake_db.py
class SnowflakeAdapterError (line 54) | class SnowflakeAdapterError(Exception):
function _sanitize_identifier (line 61) | def _sanitize_identifier(raw: str) -> str:
function _stringify (line 72) | def _stringify(value: Any) -> Optional[str]:
function _load_connection_params_from_env (line 83) | def _load_connection_params_from_env() -> dict[str, Any]:
class SnowflakeDocumentDatabase (line 131) | class SnowflakeDocumentDatabase(DocumentDatabase):
method __init__ (line 132) | def __init__(
method __aenter__ (line 161) | async def __aenter__(self) -> Self:
method __aexit__ (line 165) | async def __aexit__(
method create_collection (line 177) | async def create_collection(
method get_collection (line 188) | async def get_collection(
method get_or_create_collection (line 200) | async def get_or_create_collection(
method delete_collection (line 208) | async def delete_collection(self, name: str) -> None:
method _get_or_create_initialized_collection (line 215) | async def _get_or_create_initialized_collection(
method load_documents_with_loader (line 265) | async def load_documents_with_loader(
method _execute (line 298) | async def _execute(
method _run_query (line 310) | def _run_query(
method _ensure_connection (line 337) | async def _ensure_connection(self) -> None:
method _import_connector (line 356) | def _import_connector(self) -> None:
method _table_identifier (line 376) | def _table_identifier(self, name: str) -> str:
method _failed_table_identifier (line 379) | def _failed_table_identifier(self, name: str) -> str:
class SnowflakeDocumentCollection (line 383) | class SnowflakeDocumentCollection(DocumentCollection[TDocument]):
method __init__ (line 390) | def __init__(
method find (line 405) | async def find(
method _apply_field_sort (line 463) | def _apply_field_sort(
method find_one (line 478) | async def find_one(
method ensure_indexes (line 496) | async def ensure_indexes(
method insert_one (line 502) | async def insert_one(self, document: TDocument) -> InsertResult:
method update_one (line 525) | async def update_one(
method delete_one (line 549) | async def delete_one(self, filters: Where) -> DeleteResult[TDocument]:
method _row_to_document (line 562) | def _row_to_document(self, row: Any) -> BaseDocument:
method _replace_document (line 573) | async def _replace_document(self, document: TDocument) -> None:
method _delete_documents (line 584) | async def _delete_documents(self, identifiers: Sequence[Any]) -> None:
method _persist_failed_documents (line 593) | async def _persist_failed_documents(self, documents: Sequence[BaseDocu...
method _serialize_document (line 612) | def _serialize_document(self, document: TDocument) -> MutableMapping[s...
function _build_where_clause (line 621) | def _build_where_clause(filters: Where, indexed_fields: set[str]) -> tup...
function _build_cursor_clause (line 633) | def _build_cursor_clause(
class _WhereTranslator (line 656) | class _WhereTranslator:
method __init__ (line 657) | def __init__(self, indexed_fields: set[str]) -> None:
method params (line 663) | def params(self) -> Mapping[str, Any]:
method render (line 666) | def render(self, filters: Where) -> str:
method _render (line 669) | def _render(self, filters: Where) -> str:
method _render_field (line 693) | def _render_field(self, field: str, condition: Any) -> str:
method _membership_clause (line 714) | def _membership_clause(self, field: str, operand: Any, *, negate: bool...
method _equality_clause (line 728) | def _equality_clause(self, field: str, operand: Any) -> str:
method _column_expr (line 733) | def _column_expr(self, field: str) -> tuple[str, bool]:
method _wrap_value (line 741) | def _wrap_value(self, placeholder: str, needs_variant: bool) -> str:
method _comparison_clause (line 744) | def _comparison_clause(self, field: str, operator: str, operand: Any) ...
method _add_param (line 757) | def _add_param(self, value: Any) -> str:
FILE: src/parlant/adapters/db/transient.py
class TransientDocumentDatabase (line 42) | class TransientDocumentDatabase(DocumentDatabase):
method __init__ (line 43) | def __init__(self) -> None:
method create_collection (line 47) | async def create_collection(
method get_collection (line 63) | async def get_collection(
method get_or_create_collection (line 74) | async def get_or_create_collection(
method delete_collection (line 92) | async def delete_collection(
class TransientDocumentCollection (line 102) | class TransientDocumentCollection(DocumentCollection[TDocument]):
method __init__ (line 103) | def __init__(
method find (line 114) | async def find(
method _apply_sort (line 160) | def _apply_sort(
method _apply_field_sort (line 179) | def _apply_field_sort(
method _apply_cursor_filter (line 194) | def _apply_cursor_filter(
method find_one (line 233) | async def find_one(
method ensure_indexes (line 249) | async def ensure_indexes(
method insert_one (line 256) | async def insert_one(
method update_one (line 267) | async def update_one(
method delete_one (line 302) | async def delete_one(
FILE: src/parlant/adapters/loggers/opentelemetry.py
class OpenTelemetryLogger (line 20) | class OpenTelemetryLogger(TracingLogger):
method __init__ (line 23) | def __init__(
method __aenter__ (line 38) | async def __aenter__(self) -> Self:
method __aexit__ (line 78) | async def __aexit__(
method set_level (line 90) | def set_level(self, log_level: LogLevel) -> None:
method _inject_structlog_processors (line 95) | def _inject_structlog_processors(self) -> None:
method trace (line 132) | def trace(self, message: str) -> None:
method debug (line 139) | def debug(self, message: str) -> None:
method info (line 143) | def info(self, message: str) -> None:
method warning (line 147) | def warning(self, message: str) -> None:
method error (line 151) | def error(self, message: str) -> None:
method critical (line 155) | def critical(self, message: str) -> None:
FILE: src/parlant/adapters/loggers/websocket.py
class WebSocketSubscription (line 29) | class WebSocketSubscription:
class WebSocketLogger (line 34) | class WebSocketLogger(TracingLogger):
method __init__ (line 35) | def __init__(
method _enqueue_message (line 48) | def _enqueue_message(self, timestamp: str, level: str, message: str) -...
method subscribe (line 61) | async def subscribe(self, web_socket: WebSocket) -> WebSocketSubscript...
method _timestamp (line 71) | def _timestamp(self) -> str:
method trace (line 75) | def trace(self, message: str) -> None:
method debug (line 79) | def debug(self, message: str) -> None:
method info (line 83) | def info(self, message: str) -> None:
method warning (line 87) | def warning(self, message: str) -> None:
method error (line 91) | def error(self, message: str) -> None:
method critical (line 95) | def critical(self, message: str) -> None:
method start (line 98) | async def start(self) -> None:
FILE: src/parlant/adapters/meter/opentelemetry.py
class OpenTelemetryCounter (line 28) | class OpenTelemetryCounter(Counter):
method __init__ (line 29) | def __init__(self, otel_counter: OTelCounter) -> None:
method increment (line 33) | async def increment(
class OpenTelemetryHistogram (line 41) | class OpenTelemetryHistogram(DurationHistogram):
method __init__ (line 42) | def __init__(self, otel_histogram: OTelHistogram) -> None:
method record (line 46) | async def record(
method measure (line 55) | async def measure(
class OpenTelemetryMeter (line 69) | class OpenTelemetryMeter(Meter):
method __init__ (line 70) | def __init__(self) -> None:
method __aenter__ (line 77) | async def __aenter__(self) -> Self:
method __aexit__ (line 113) | async def __aexit__(
method create_counter (line 125) | def create_counter(
method create_custom_histogram (line 138) | def create_custom_histogram(
method create_duration_histogram (line 153) | def create_duration_histogram(
FILE: src/parlant/adapters/nlp/anthropic_service.py
class AnthropicEstimatingTokenizer (line 63) | class AnthropicEstimatingTokenizer(EstimatingTokenizer):
method __init__ (line 64) | def __init__(self, client: AsyncAnthropic, model_name: str) -> None:
method estimate_token_count (line 69) | async def estimate_token_count(self, prompt: str) -> int:
class AnthropicAISchematicGenerator (line 78) | class AnthropicAISchematicGenerator(BaseSchematicGenerator[T]):
method __init__ (line 81) | def __init__(
method id (line 95) | def id(self) -> str:
method tokenizer (line 100) | def tokenizer(self) -> AnthropicEstimatingTokenizer:
method do_generate (line 117) | async def do_generate(
method _do_generate (line 125) | async def _do_generate(
class Claude_Sonnet_3_5 (line 205) | class Claude_Sonnet_3_5(AnthropicAISchematicGenerator[T]):
method __init__ (line 206) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 216) | def max_tokens(self) -> int:
class Claude_Sonnet_4 (line 220) | class Claude_Sonnet_4(AnthropicAISchematicGenerator[T]):
method __init__ (line 221) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 231) | def max_tokens(self) -> int:
class Claude_Opus_4_1 (line 235) | class Claude_Opus_4_1(AnthropicAISchematicGenerator[T]):
method __init__ (line 236) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 246) | def max_tokens(self) -> int:
class AnthropicService (line 250) | class AnthropicService(NLPService):
method verify_environment (line 252) | def verify_environment() -> str | None:
method __init__ (line 263) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method supports_streaming (line 272) | def supports_streaming(self) -> bool:
method get_streaming_text_generator (line 276) | async def get_streaming_text_generator(
method get_schematic_generator (line 282) | async def get_schematic_generator(
method get_embedder (line 294) | async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder:
method get_moderation_service (line 298) | async def get_moderation_service(self) -> ModerationService:
FILE: src/parlant/adapters/nlp/aws_service.py
class AnthropicBedrockEstimatingTokenizer (line 56) | class AnthropicBedrockEstimatingTokenizer(EstimatingTokenizer):
method __init__ (line 57) | def __init__(self) -> None:
method estimate_token_count (line 61) | async def estimate_token_count(self, prompt: str) -> int:
class AnthropicBedrockAISchematicGenerator (line 66) | class AnthropicBedrockAISchematicGenerator(BaseSchematicGenerator[T]):
method __init__ (line 69) | def __init__(
method id (line 89) | def id(self) -> str:
method tokenizer (line 94) | def tokenizer(self) -> AnthropicBedrockEstimatingTokenizer:
method do_generate (line 111) | async def do_generate(
method _do_generate (line 119) | async def _do_generate(
class Claude_Sonnet_3_5 (line 194) | class Claude_Sonnet_3_5(AnthropicBedrockAISchematicGenerator[T]):
method __init__ (line 195) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 205) | def max_tokens(self) -> int:
class BedrockService (line 209) | class BedrockService(NLPService):
method verify_environment (line 211) | def verify_environment() -> str | None:
method __init__ (line 226) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method supports_streaming (line 233) | def supports_streaming(self) -> bool:
method get_streaming_text_generator (line 237) | async def get_streaming_text_generator(
method get_schematic_generator (line 243) | async def get_schematic_generator(
method get_embedder (line 249) | async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder:
method get_moderation_service (line 253) | async def get_moderation_service(self) -> ModerationService:
FILE: src/parlant/adapters/nlp/azure_service.py
class AzureEstimatingTokenizer (line 58) | class AzureEstimatingTokenizer(EstimatingTokenizer):
method __init__ (line 59) | def __init__(self, model_name: str) -> None:
method estimate_token_count (line 63) | async def estimate_token_count(self, prompt: str) -> int:
class AzureSchematicGenerator (line 68) | class AzureSchematicGenerator(BaseSchematicGenerator[T]):
method __init__ (line 75) | def __init__(
method id (line 89) | def id(self) -> str:
method tokenizer (line 93) | def tokenizer(self) -> AzureEstimatingTokenizer:
method _list_arguments (line 96) | def _list_arguments(self, hints: Mapping[str, Any]) -> Mapping[str, Any]:
method do_generate (line 123) | async def do_generate(
method _do_generate (line 131) | async def _do_generate(
function create_azure_client (line 276) | def create_azure_client() -> AsyncAzureOpenAI:
class CustomAzureSchematicGenerator (line 331) | class CustomAzureSchematicGenerator(AzureSchematicGenerator[T]):
method __init__ (line 332) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 344) | def max_tokens(self) -> int:
class GPT_4o (line 348) | class GPT_4o(AzureSchematicGenerator[T]):
method __init__ (line 349) | def __init__(
method max_tokens (line 361) | def max_tokens(self) -> int:
class GPT_4o_Mini (line 365) | class GPT_4o_Mini(AzureSchematicGenerator[T]):
method __init__ (line 366) | def __init__(
method max_tokens (line 379) | def max_tokens(self) -> int:
class AzureEmbedder (line 383) | class AzureEmbedder(BaseEmbedder):
method __init__ (line 386) | def __init__(
method id (line 401) | def id(self) -> str:
method tokenizer (line 406) | def tokenizer(self) -> AzureEstimatingTokenizer:
method do_embed (line 410) | async def do_embed(
class CustomAzureEmbedder (line 441) | class CustomAzureEmbedder(AzureEmbedder):
method __init__ (line 442) | def __init__(
method max_tokens (line 459) | def max_tokens(self) -> int:
method dimensions (line 463) | def dimensions(self) -> int:
class AzureTextEmbedding3Large (line 467) | class AzureTextEmbedding3Large(AzureEmbedder):
method __init__ (line 468) | def __init__(
method max_tokens (line 485) | def max_tokens(self) -> int:
method dimensions (line 489) | def dimensions(self) -> int:
class AzureTextEmbedding3Small (line 493) | class AzureTextEmbedding3Small(AzureEmbedder):
method __init__ (line 494) | def __init__(
method max_tokens (line 510) | def max_tokens(self) -> int:
method dimensions (line 514) | def dimensions(self) -> int:
class AzureService (line 518) | class AzureService(NLPService):
method verify_environment (line 520) | def verify_environment() -> str | None:
method __init__ (line 638) | def __init__(
method supports_streaming (line 650) | def supports_streaming(self) -> bool:
method get_streaming_text_generator (line 654) | async def get_streaming_text_generator(
method get_schematic_generator (line 659) | async def get_schematic_generator(
method get_embedder (line 668) | async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder:
method get_moderation_service (line 673) | async def get_moderation_service(self) -> ModerationService:
FILE: src/parlant/adapters/nlp/cerebras_service.py
class LlamaEstimatingTokenizer (line 55) | class LlamaEstimatingTokenizer(EstimatingTokenizer):
method __init__ (line 56) | def __init__(self) -> None:
method estimate_token_count (line 60) | async def estimate_token_count(self, prompt: str) -> int:
class CerebrasSchematicGenerator (line 65) | class CerebrasSchematicGenerator(BaseSchematicGenerator[T]):
method __init__ (line 68) | def __init__(
method do_generate (line 92) | async def do_generate(
method _do_generate (line 100) | async def _do_generate(
class Llama3_3_8B (line 179) | class Llama3_3_8B(CerebrasSchematicGenerator[T]):
method __init__ (line 180) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method id (line 191) | def id(self) -> str:
method max_tokens (line 196) | def max_tokens(self) -> int:
method tokenizer (line 201) | def tokenizer(self) -> LlamaEstimatingTokenizer:
class Llama3_3_70B (line 205) | class Llama3_3_70B(CerebrasSchematicGenerator[T]):
method __init__ (line 206) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method id (line 218) | def id(self) -> str:
method tokenizer (line 223) | def tokenizer(self) -> LlamaEstimatingTokenizer:
method max_tokens (line 228) | def max_tokens(self) -> int:
class CerebrasService (line 232) | class CerebrasService(NLPService):
method verify_environment (line 234) | def verify_environment() -> str | None:
method __init__ (line 245) | def __init__(
method supports_streaming (line 258) | def supports_streaming(self) -> bool:
method get_streaming_text_generator (line 262) | async def get_streaming_text_generator(
method get_schematic_generator (line 268) | async def get_schematic_generator(
method get_embedder (line 274) | async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder:
method get_moderation_service (line 278) | async def get_moderation_service(self) -> ModerationService:
FILE: src/parlant/adapters/nlp/common.py
function normalize_json_output (line 19) | def normalize_json_output(raw_output: str) -> str:
function record_llm_metrics (line 41) | async def record_llm_metrics(
FILE: src/parlant/adapters/nlp/deepseek_service.py
class DeepSeekEstimatingTokenizer (line 63) | class DeepSeekEstimatingTokenizer(EstimatingTokenizer):
method __init__ (line 64) | def __init__(self, model_name: str) -> None:
method estimate_token_count (line 69) | async def estimate_token_count(self, prompt: str) -> int:
class DeepSeekSchematicGenerator (line 74) | class DeepSeekSchematicGenerator(BaseSchematicGenerator[T]):
method __init__ (line 78) | def __init__(
method id (line 96) | def id(self) -> str:
method tokenizer (line 101) | def tokenizer(self) -> DeepSeekEstimatingTokenizer:
method do_generate (line 119) | async def do_generate(
method _do_generate (line 127) | async def _do_generate(
class DeepSeek_Chat (line 205) | class DeepSeek_Chat(DeepSeekSchematicGenerator[T]):
method __init__ (line 206) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 211) | def max_tokens(self) -> int:
class DeepSeekService (line 215) | class DeepSeekService(NLPService):
method verify_environment (line 217) | def verify_environment() -> str | None:
method __init__ (line 228) | def __init__(
method supports_streaming (line 241) | def supports_streaming(self) -> bool:
method get_streaming_text_generator (line 245) | async def get_streaming_text_generator(
method get_schematic_generator (line 251) | async def get_schematic_generator(
method get_embedder (line 257) | async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder:
method get_moderation_service (line 261) | async def get_moderation_service(self) -> ModerationService:
FILE: src/parlant/adapters/nlp/emcie_service.py
class EmcieEstimatingTokenizer (line 85) | class EmcieEstimatingTokenizer(EstimatingTokenizer):
method __init__ (line 86) | def __init__(self) -> None:
method estimate_token_count (line 90) | async def estimate_token_count(self, prompt: str) -> int:
class EmcieAPIError (line 95) | class EmcieAPIError(Exception):
class InsufficientCreditsError (line 99) | class InsufficientCreditsError(EmcieAPIError):
class RateLimitError (line 103) | class RateLimitError(EmcieAPIError):
class UnauthorizedError (line 107) | class UnauthorizedError(EmcieAPIError):
class EmcieSchematicGenerator (line 111) | class EmcieSchematicGenerator(BaseSchematicGenerator[T]):
method __init__ (line 114) | def __init__(
method id (line 129) | def id(self) -> str:
method tokenizer (line 134) | def tokenizer(self) -> EmcieEstimatingTokenizer:
method do_generate (line 144) | async def do_generate(
method _do_generate (line 152) | async def _do_generate(
class Jackal (line 271) | class Jackal(EmcieSchematicGenerator[T]):
method __init__ (line 272) | def __init__(
method max_tokens (line 289) | def max_tokens(self) -> int:
class Bison (line 293) | class Bison(EmcieSchematicGenerator[T]):
method __init__ (line 294) | def __init__(
method max_tokens (line 311) | def max_tokens(self) -> int:
class EmcieStreamingTextGenerator (line 320) | class EmcieStreamingTextGenerator(BaseStreamingTextGenerator):
method __init__ (line 328) | def __init__(
method id (line 342) | def id(self) -> str:
method tokenizer (line 347) | def tokenizer(self) -> EmcieEstimatingTokenizer:
method do_generate (line 351) | async def do_generate(
class JackalStreaming (line 487) | class JackalStreaming(EmcieStreamingTextGenerator):
method __init__ (line 488) | def __init__(
class BisonStreaming (line 504) | class BisonStreaming(EmcieStreamingTextGenerator):
method __init__ (line 505) | def __init__(
class EmcieEmbedder (line 526) | class EmcieEmbedder(BaseEmbedder):
method __init__ (line 529) | def __init__(
method id (line 541) | def id(self) -> str:
method tokenizer (line 546) | def tokenizer(self) -> EmcieEstimatingTokenizer:
method do_embed (line 556) | async def do_embed(
class BisonEmbedding (line 613) | class BisonEmbedding(EmcieEmbedder):
method __init__ (line 614) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 624) | def max_tokens(self) -> int:
method dimensions (line 628) | def dimensions(self) -> int:
class JackalEmbedding (line 632) | class JackalEmbedding(EmcieEmbedder):
method __init__ (line 633) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 643) | def max_tokens(self) -> int:
method dimensions (line 647) | def dimensions(self) -> int:
class EmcieService (line 651) | class EmcieService(NLPService):
method verify_environment (line 653) | def verify_environment() -> str | None:
method __init__ (line 667) | def __init__(
method supports_streaming (line 689) | def supports_streaming(self) -> bool:
method get_streaming_text_generator (line 693) | async def get_streaming_text_generator(
method get_schematic_generator (line 713) | async def get_schematic_generator(
method get_embedder (line 735) | async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder:
method get_moderation_service (line 743) | async def get_moderation_service(self) -> ModerationService:
FILE: src/parlant/adapters/nlp/fireworks_service.py
class FireworksEstimatingTokenizer (line 63) | class FireworksEstimatingTokenizer(EstimatingTokenizer):
method __init__ (line 64) | def __init__(self, model_name: str) -> None:
method estimate_token_count (line 69) | async def estimate_token_count(self, prompt: str) -> int:
class FireworksSchematicGenerator (line 74) | class FireworksSchematicGenerator(BaseSchematicGenerator[T]):
method __init__ (line 77) | def __init__(
method id (line 91) | def id(self) -> str:
method tokenizer (line 96) | def tokenizer(self) -> FireworksEstimatingTokenizer:
method do_generate (line 111) | async def do_generate(
method _do_generate (line 119) | async def _do_generate(
class FireworksLlama3_1_8B (line 194) | class FireworksLlama3_1_8B(FireworksSchematicGenerator[T]):
method __init__ (line 195) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 205) | def max_tokens(self) -> int:
method tokenizer (line 210) | def tokenizer(self) -> FireworksEstimatingTokenizer:
class FireworksLlama3_1_70B (line 214) | class FireworksLlama3_1_70B(FireworksSchematicGenerator[T]):
method __init__ (line 215) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 225) | def max_tokens(self) -> int:
method tokenizer (line 230) | def tokenizer(self) -> FireworksEstimatingTokenizer:
class FireworksLlama3_1_405B (line 234) | class FireworksLlama3_1_405B(FireworksSchematicGenerator[T]):
method __init__ (line 240) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 250) | def max_tokens(self) -> int:
method tokenizer (line 255) | def tokenizer(self) -> FireworksEstimatingTokenizer:
class FireworksMythoMax (line 259) | class FireworksMythoMax(FireworksSchematicGenerator[T]):
method __init__ (line 260) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 270) | def max_tokens(self) -> int:
method tokenizer (line 275) | def tokenizer(self) -> FireworksEstimatingTokenizer:
class FireworksGemma2_9B (line 279) | class FireworksGemma2_9B(FireworksSchematicGenerator[T]):
method __init__ (line 280) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 290) | def max_tokens(self) -> int:
method tokenizer (line 295) | def tokenizer(self) -> FireworksEstimatingTokenizer:
class CustomFireworksSchematicGenerator (line 299) | class CustomFireworksSchematicGenerator(FireworksSchematicGenerator[T]):
method __init__ (line 302) | def __init__(self, model_name: str, logger: Logger, tracer: Tracer, me...
method max_tokens (line 312) | def max_tokens(self) -> int:
method tokenizer (line 317) | def tokenizer(self) -> FireworksEstimatingTokenizer:
class FireworksService (line 324) | class FireworksService(NLPService):
method verify_environment (line 326) | def verify_environment() -> str | None:
method __init__ (line 354) | def __init__(
method supports_streaming (line 373) | def supports_streaming(self) -> bool:
method get_streaming_text_generator (line 377) | async def get_streaming_text_generator(
method _get_specialized_generator_class (line 382) | def _get_specialized_generator_class(
method _log_model_warnings (line 399) | def _log_model_warnings(self, model_name: str) -> None:
method get_schematic_generator (line 408) | async def get_schematic_generator(
method get_embedder (line 434) | async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder:
method get_moderation_service (line 438) | async def get_moderation_service(self) -> ModerationService:
FILE: src/parlant/adapters/nlp/gemini_service.py
class GoogleEstimatingTokenizer (line 69) | class GoogleEstimatingTokenizer(EstimatingTokenizer):
method __init__ (line 70) | def __init__(self, client: google.genai.Client, model_name: str) -> None:
method estimate_token_count (line 75) | async def estimate_token_count(self, prompt: str) -> int:
class GeminiSchematicGenerator (line 88) | class GeminiSchematicGenerator(BaseSchematicGenerator[T]):
method __init__ (line 91) | def __init__(
method id (line 106) | def id(self) -> str:
method tokenizer (line 111) | def tokenizer(self) -> EstimatingTokenizer:
method do_generate (line 127) | async def do_generate(
method _do_generate (line 135) | async def _do_generate(
method _get_schema_function_declaration (line 230) | def _get_schema_function_declaration(self) -> google.genai.types.Funct...
class Gemini_2_0_Flash (line 258) | class Gemini_2_0_Flash(GeminiSchematicGenerator[T]):
method __init__ (line 259) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 269) | def max_tokens(self) -> int:
class Gemini_2_0_Flash_Lite (line 273) | class Gemini_2_0_Flash_Lite(GeminiSchematicGenerator[T]):
method __init__ (line 274) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 284) | def max_tokens(self) -> int:
class Gemini_2_5_Flash (line 288) | class Gemini_2_5_Flash(GeminiSchematicGenerator[T]):
method __init__ (line 289) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method generate (line 298) | async def generate(
method max_tokens (line 310) | def max_tokens(self) -> int:
class Gemini_2_5_Flash_Lite (line 314) | class Gemini_2_5_Flash_Lite(GeminiSchematicGenerator[T]):
method __init__ (line 315) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method generate (line 324) | async def generate(
method max_tokens (line 336) | def max_tokens(self) -> int:
class Gemini_2_5_Pro (line 340) | class Gemini_2_5_Pro(GeminiSchematicGenerator[T]):
method __init__ (line 341) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 351) | def max_tokens(self) -> int:
class GoogleEmbedder (line 355) | class GoogleEmbedder(BaseEmbedder):
method __init__ (line 358) | def __init__(self, model_name: str, logger: Logger, tracer: Tracer, me...
method id (line 366) | def id(self) -> str:
method tokenizer (line 371) | def tokenizer(self) -> GoogleEstimatingTokenizer:
method do_embed (line 387) | async def do_embed(
class GeminiTextEmbedding_001 (line 422) | class GeminiTextEmbedding_001(GoogleEmbedder):
method __init__ (line 423) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 433) | def max_tokens(self) -> int:
method dimensions (line 437) | def dimensions(self) -> int:
class GeminiService (line 441) | class GeminiService(NLPService):
method verify_environment (line 443) | def verify_environment() -> str | None:
method __init__ (line 454) | def __init__(
method supports_streaming (line 468) | def supports_streaming(self) -> bool:
method get_streaming_text_generator (line 472) | async def get_streaming_text_generator(
method get_schematic_generator (line 478) | async def get_schematic_generator(
method get_embedder (line 496) | async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder:
method get_moderation_service (line 500) | async def get_moderation_service(self) -> ModerationService:
function convert_type_annotation_to_gemini_compatible_schema (line 504) | def convert_type_annotation_to_gemini_compatible_schema(annotation: Any)...
function convert_model_to_gemini_compatible_schema (line 546) | def convert_model_to_gemini_compatible_schema(model_cls: type[DefaultBas...
FILE: src/parlant/adapters/nlp/glm_service.py
class GLMEstimatingTokenizer (line 75) | class GLMEstimatingTokenizer(EstimatingTokenizer):
method __init__ (line 76) | def __init__(self, model_name: str) -> None:
method estimate_token_count (line 81) | async def estimate_token_count(self, prompt: str) -> int:
class GLMEmbedder (line 86) | class GLMEmbedder(BaseEmbedder):
method __init__ (line 89) | def __init__(self, model_name: str, logger: Logger, tracer: Tracer, me...
method id (line 100) | def id(self) -> str:
method tokenizer (line 105) | def tokenizer(self) -> GLMEstimatingTokenizer:
method do_embed (line 123) | async def do_embed(
class GMLTextEmbedding_3 (line 143) | class GMLTextEmbedding_3(GLMEmbedder):
method __init__ (line 144) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 149) | def max_tokens(self) -> int:
method dimensions (line 153) | def dimensions(self) -> int:
class GLMSchematicGenerator (line 157) | class GLMSchematicGenerator(BaseSchematicGenerator[T]):
method __init__ (line 161) | def __init__(
method id (line 179) | def id(self) -> str:
method tokenizer (line 184) | def tokenizer(self) -> GLMEstimatingTokenizer:
method do_generate (line 202) | async def do_generate(
method _do_generate (line 210) | async def _do_generate(
class GLM_4_5 (line 286) | class GLM_4_5(GLMSchematicGenerator[T]):
method __init__ (line 287) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 292) | def max_tokens(self) -> int:
class GLMService (line 296) | class GLMService(NLPService):
method verify_environment (line 298) | def verify_environment() -> str | None:
method __init__ (line 309) | def __init__(
method supports_streaming (line 322) | def supports_streaming(self) -> bool:
method get_streaming_text_generator (line 326) | async def get_streaming_text_generator(
method get_schematic_generator (line 332) | async def get_schematic_generator(
method get_embedder (line 338) | async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder:
method get_moderation_service (line 342) | async def get_moderation_service(self) -> ModerationService:
FILE: src/parlant/adapters/nlp/hugging_face.py
function _model_temp_dir (line 45) | def _model_temp_dir() -> str:
function _create_tokenizer (line 49) | def _create_tokenizer(model_name: str) -> PreTrainedTokenizerBase:
function _get_device (line 66) | def _get_device() -> torch.device:
function _create_auto_model (line 82) | def _create_auto_model(model_name: str) -> PreTrainedModel:
class HuggingFaceEstimatingTokenizer (line 104) | class HuggingFaceEstimatingTokenizer(EstimatingTokenizer):
method __init__ (line 105) | def __init__(self, model_name: str) -> None:
method estimate_token_count (line 110) | async def estimate_token_count(self, prompt: str) -> int:
class HuggingFaceEmbedder (line 116) | class HuggingFaceEmbedder(BaseEmbedder):
method __init__ (line 117) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter, model...
method id (line 125) | def id(self) -> str:
method max_tokens (line 130) | def max_tokens(self) -> int:
method tokenizer (line 135) | def tokenizer(self) -> HuggingFaceEstimatingTokenizer:
method do_embed (line 152) | async def do_embed(
class JinaAIEmbedder (line 168) | class JinaAIEmbedder(HuggingFaceEmbedder):
method __init__ (line 169) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method dimensions (line 179) | def dimensions(self) -> int:
FILE: src/parlant/adapters/nlp/lakera.py
class LakeraGuard (line 30) | class LakeraGuard(BaseModerationService):
method __init__ (line 31) | def __init__(self, logger: Logger, meter: Meter) -> None:
method do_moderate (line 35) | async def do_moderate(self, context: CustomerModerationContext) -> Mod...
FILE: src/parlant/adapters/nlp/litellm_service.py
class LiteLLMEstimatingTokenizer (line 67) | class LiteLLMEstimatingTokenizer(EstimatingTokenizer):
method __init__ (line 68) | def __init__(self, model_name: str) -> None:
method estimate_token_count (line 73) | async def estimate_token_count(self, prompt: str) -> int:
class LiteLLMSchematicGenerator (line 78) | class LiteLLMSchematicGenerator(BaseSchematicGenerator[T]):
method __init__ (line 88) | def __init__(
method id (line 105) | def id(self) -> str:
method tokenizer (line 110) | def tokenizer(self) -> LiteLLMEstimatingTokenizer:
method do_generate (line 114) | async def do_generate(
class LiteLLM_Default (line 201) | class LiteLLM_Default(LiteLLMSchematicGenerator[T]):
method __init__ (line 202) | def __init__(
method max_tokens (line 215) | def max_tokens(self) -> int:
class LiteLLMEmbedder (line 221) | class LiteLLMEmbedder(BaseEmbedder):
method __init__ (line 224) | def __init__(
method id (line 239) | def id(self) -> str:
method tokenizer (line 244) | def tokenizer(self) -> LiteLLMEstimatingTokenizer:
method max_tokens (line 249) | def max_tokens(self) -> int:
method dimensions (line 254) | def dimensions(self) -> int:
method do_embed (line 258) | async def do_embed(
class LiteLLMService (line 276) | class LiteLLMService(NLPService):
method verify_environment (line 278) | def verify_environment() -> str | None:
method __init__ (line 291) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method supports_streaming (line 308) | def supports_streaming(self) -> bool:
method get_streaming_text_generator (line 312) | async def get_streaming_text_generator(
method get_schematic_generator (line 318) | async def get_schematic_generator(
method create_embedder (line 325) | def create_embedder(self) -> Embedder:
method get_embedder (line 337) | async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder:
method get_moderation_service (line 341) | async def get_moderation_service(self) -> ModerationService:
FILE: src/parlant/adapters/nlp/mistral_service.py
class MistralEstimatingTokenizer (line 84) | class MistralEstimatingTokenizer(EstimatingTokenizer):
method __init__ (line 85) | def __init__(self, model_name: str) -> None:
method estimate_token_count (line 91) | async def estimate_token_count(self, prompt: str) -> int:
class MistralSchematicGenerator (line 96) | class MistralSchematicGenerator(BaseSchematicGenerator[T]):
method __init__ (line 100) | def __init__(
method id (line 114) | def id(self) -> str:
method tokenizer (line 119) | def tokenizer(self) -> MistralEstimatingTokenizer:
method do_generate (line 135) | async def do_generate(
method _do_generate (line 143) | async def _do_generate(
class Mistral_Large_2411 (line 221) | class Mistral_Large_2411(MistralSchematicGenerator[T]):
method __init__ (line 222) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 227) | def max_tokens(self) -> int:
class Mistral_Medium_2508 (line 231) | class Mistral_Medium_2508(MistralSchematicGenerator[T]):
method __init__ (line 232) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 239) | def max_tokens(self) -> int:
class Mistral_Small_2506 (line 243) | class Mistral_Small_2506(MistralSchematicGenerator[T]):
method __init__ (line 244) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 249) | def max_tokens(self) -> int:
class MistralEmbedder (line 253) | class MistralEmbedder(BaseEmbedder):
method __init__ (line 254) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method id (line 261) | def id(self) -> str:
method tokenizer (line 266) | def tokenizer(self) -> MistralEstimatingTokenizer:
method max_tokens (line 271) | def max_tokens(self) -> int:
method dimensions (line 275) | def dimensions(self) -> int:
method do_embed (line 291) | async def do_embed(
class MistralModerationService (line 312) | class MistralModerationService(BaseModerationService):
method __init__ (line 313) | def __init__(self, logger: Logger, meter: Meter) -> None:
method do_moderate (line 320) | async def do_moderate(self, context: CustomerModerationContext) -> Mod...
class MistralService (line 368) | class MistralService(NLPService):
method verify_environment (line 370) | def verify_environment() -> str | None:
method __init__ (line 381) | def __init__(
method supports_streaming (line 394) | def supports_streaming(self) -> bool:
method get_streaming_text_generator (line 398) | async def get_streaming_text_generator(
method get_schematic_generator (line 404) | async def get_schematic_generator(
method get_embedder (line 416) | async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder:
method get_moderation_service (line 420) | async def get_moderation_service(self) -> ModerationService:
FILE: src/parlant/adapters/nlp/modelscope_service.py
class ModelScopeEstimatingTokenizer (line 64) | class ModelScopeEstimatingTokenizer(EstimatingTokenizer):
method __init__ (line 65) | def __init__(self, model_name: str) -> None:
method estimate_token_count (line 70) | async def estimate_token_count(self, prompt: str) -> int:
class ModelScopeSchematicGenerator (line 75) | class ModelScopeSchematicGenerator(BaseSchematicGenerator[T]):
method __init__ (line 79) | def __init__(
method id (line 97) | def id(self) -> str:
method tokenizer (line 102) | def tokenizer(self) -> ModelScopeEstimatingTokenizer:
method generate (line 120) | async def generate(
method _do_generate (line 128) | async def _do_generate(
class ModelScopeChat (line 200) | class ModelScopeChat(ModelScopeSchematicGenerator[T]):
method __init__ (line 201) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 207) | def max_tokens(self) -> int:
class ModelScopeService (line 211) | class ModelScopeService(NLPService):
method verify_environment (line 213) | def verify_environment() -> str | None:
method __init__ (line 228) | def __init__(
method supports_streaming (line 241) | def supports_streaming(self) -> bool:
method get_streaming_text_generator (line 245) | async def get_streaming_text_generator(
method get_schematic_generator (line 251) | async def get_schematic_generator(
method get_embedder (line 257) | async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder:
method get_moderation_service (line 261) | async def get_moderation_service(self) -> ModerationService:
FILE: src/parlant/adapters/nlp/ollama_service.py
class OllamaError (line 52) | class OllamaError(Exception):
class OllamaConnectionError (line 58) | class OllamaConnectionError(OllamaError):
class OllamaModelError (line 64) | class OllamaModelError(OllamaError):
class OllamaTimeoutError (line 70) | class OllamaTimeoutError(OllamaError):
class OllamaModelVerifier (line 76) | class OllamaModelVerifier:
method verify_models (line 80) | def verify_models(base_url: str, generation_model: str, embedding_mode...
class OllamaEstimatingTokenizer (line 137) | class OllamaEstimatingTokenizer(EstimatingTokenizer):
method __init__ (line 140) | def __init__(self, model_name: str):
method estimate_token_count (line 145) | async def estimate_token_count(self, prompt: str) -> int:
class OllamaSchematicGenerator (line 151) | class OllamaSchematicGenerator(BaseSchematicGenerator[T]):
method __init__ (line 156) | def __init__(
method id (line 175) | def id(self) -> str:
method tokenizer (line 180) | def tokenizer(self) -> EstimatingTokenizer:
method max_tokens (line 185) | def max_tokens(self) -> int:
method _create_options (line 199) | def _create_options(self, hints: Mapping[str, Any]) -> dict[str, Any]:
method do_generate (line 235) | async def do_generate(
method _do_generate (line 243) | async def _do_generate(
class OllamaGemma3_1B (line 353) | class OllamaGemma3_1B(OllamaSchematicGenerator[T]):
method __init__ (line 354) | def __init__(
class OllamaGemma3_4B (line 366) | class OllamaGemma3_4B(OllamaSchematicGenerator[T]):
method __init__ (line 367) | def __init__(
class OllamaGemma3_12B (line 379) | class OllamaGemma3_12B(OllamaSchematicGenerator[T]):
method __init__ (line 380) | def __init__(
class OllamaGemma3_27B (line 392) | class OllamaGemma3_27B(OllamaSchematicGenerator[T]):
method __init__ (line 393) | def __init__(
class OllamaLlama31_8B (line 405) | class OllamaLlama31_8B(OllamaSchematicGenerator[T]):
method __init__ (line 406) | def __init__(
class OllamaLlama31_70B (line 418) | class OllamaLlama31_70B(OllamaSchematicGenerator[T]):
method __init__ (line 425) | def __init__(
class OllamaLlama31_405B (line 437) | class OllamaLlama31_405B(OllamaSchematicGenerator[T]):
method __init__ (line 444) | def __init__(
class CustomOllamaSchematicGenerator (line 456) | class CustomOllamaSchematicGenerator(OllamaSchematicGenerator[T]):
method __init__ (line 459) | def __init__(
class OllamaEmbedder (line 476) | class OllamaEmbedder(BaseEmbedder):
method __init__ (line 481) | def __init__(self, model_name: str, logger: Logger, tracer: Tracer, me...
method id (line 490) | def id(self) -> str:
method tokenizer (line 495) | def tokenizer(self) -> EstimatingTokenizer:
method max_tokens (line 500) | def max_tokens(self) -> int:
method do_embed (line 513) | async def do_embed(
class OllamaNomicEmbedding (line 544) | class OllamaNomicEmbedding(OllamaEmbedder):
method __init__ (line 545) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 550) | def max_tokens(self) -> int:
method dimensions (line 554) | def dimensions(self) -> int:
class OllamaMxbiEmbeddingLarge (line 558) | class OllamaMxbiEmbeddingLarge(OllamaEmbedder):
method __init__ (line 559) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 564) | def max_tokens(self) -> int:
method dimensions (line 568) | def dimensions(self) -> int:
class OllamaBgeM3EmbeddingLarge (line 572) | class OllamaBgeM3EmbeddingLarge(OllamaEmbedder):
method __init__ (line 573) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 578) | def max_tokens(self) -> int:
method dimensions (line 582) | def dimensions(self) -> int:
class OllamaCustomEmbedding (line 586) | class OllamaCustomEmbedding(OllamaEmbedder):
method __init__ (line 587) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 594) | def max_tokens(self) -> int:
method dimensions (line 598) | def dimensions(self) -> int:
class OllamaService (line 602) | class OllamaService(NLPService):
method verify_environment (line 606) | def verify_environment() -> str | None:
method verify_models (line 633) | def verify_models() -> str | None:
method __init__ (line 647) | def __init__(
method supports_streaming (line 668) | def supports_streaming(self) -> bool:
method get_streaming_text_generator (line 672) | async def get_streaming_text_generator(
method _get_specialized_generator_class (line 677) | def _get_specialized_generator_class(
method _log_model_warnings (line 700) | def _log_model_warnings(self, model_name: str) -> None:
method get_schematic_generator (line 714) | async def get_schematic_generator(
method get_embedder (line 739) | async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder:
method get_moderation_service (line 750) | async def get_moderation_service(self) -> ModerationService:
FILE: src/parlant/adapters/nlp/openai_service.py
class OpenAIEstimatingTokenizer (line 100) | class OpenAIEstimatingTokenizer(EstimatingTokenizer):
method __init__ (line 101) | def __init__(self, model_name: str) -> None:
method estimate_token_count (line 112) | async def estimate_token_count(self, prompt: str) -> int:
class OpenAISchematicGenerator (line 117) | class OpenAISchematicGenerator(BaseSchematicGenerator[T]):
method __init__ (line 124) | def __init__(
method id (line 142) | def id(self) -> str:
method tokenizer (line 147) | def tokenizer(self) -> OpenAIEstimatingTokenizer:
method do_generate (line 165) | async def do_generate(
method _list_arguments (line 173) | def _list_arguments(self, hints: Mapping[str, Any]) -> Mapping[str, Any]:
method _do_generate (line 187) | async def _do_generate(
class GPT_4o (line 312) | class GPT_4o(OpenAISchematicGenerator[T]):
method __init__ (line 313) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 318) | def max_tokens(self) -> int:
class GPT_4o_24_08_06 (line 322) | class GPT_4o_24_08_06(OpenAISchematicGenerator[T]):
method __init__ (line 323) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 328) | def max_tokens(self) -> int:
class GPT_4_1 (line 332) | class GPT_4_1(OpenAISchematicGenerator[T]):
method __init__ (line 333) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 344) | def max_tokens(self) -> int:
class GPT_4o_Mini (line 348) | class GPT_4o_Mini(OpenAISchematicGenerator[T]):
method __init__ (line 349) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 355) | def max_tokens(self) -> int:
class GPT_4_1_Mini (line 359) | class GPT_4_1_Mini(OpenAISchematicGenerator[T]):
method __init__ (line 360) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 366) | def max_tokens(self) -> int:
class GPT_4_1_Nano (line 370) | class GPT_4_1_Nano(OpenAISchematicGenerator[T]):
method __init__ (line 371) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 377) | def max_tokens(self) -> int:
class GPT_5_1 (line 381) | class GPT_5_1(OpenAISchematicGenerator[T]):
method __init__ (line 382) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 388) | def max_tokens(self) -> int:
class GPT_5_Mini (line 392) | class GPT_5_Mini(OpenAISchematicGenerator[T]):
method __init__ (line 393) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 399) | def max_tokens(self) -> int:
class GPT_5_Nano (line 403) | class GPT_5_Nano(OpenAISchematicGenerator[T]):
method __init__ (line 404) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 410) | def max_tokens(self) -> int:
class OpenAIStreamingTextGenerator (line 426) | class OpenAIStreamingTextGenerator(BaseStreamingTextGenerator):
method __init__ (line 434) | def __init__(
method id (line 451) | def id(self) -> str:
method tokenizer (line 456) | def tokenizer(self) -> OpenAIEstimatingTokenizer:
method _list_arguments (line 459) | def _list_arguments(self, hints: Mapping[str, Any]) -> Mapping[str, Any]:
method do_generate (line 463) | async def do_generate(
class GPT_4_1_Streaming (line 551) | class GPT_4_1_Streaming(OpenAIStreamingTextGenerator):
method __init__ (line 552) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
class OpenAIEmbedder (line 567) | class OpenAIEmbedder(BaseEmbedder):
method __init__ (line 570) | def __init__(self, model_name: str, logger: Logger, tracer: Tracer, me...
method id (line 578) | def id(self) -> str:
method tokenizer (line 583) | def tokenizer(self) -> OpenAIEstimatingTokenizer:
method do_embed (line 601) | async def do_embed(
class OpenAITextEmbedding3Large (line 621) | class OpenAITextEmbedding3Large(OpenAIEmbedder):
method __init__ (line 622) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 629) | def max_tokens(self) -> int:
method dimensions (line 633) | def dimensions(self) -> int:
class OpenAITextEmbedding3Small (line 637) | class OpenAITextEmbedding3Small(OpenAIEmbedder):
method __init__ (line 638) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 645) | def max_tokens(self) -> int:
method dimensions (line 649) | def dimensions(self) -> int:
class OpenAIModerationService (line 653) | class OpenAIModerationService(BaseModerationService):
method __init__ (line 654) | def __init__(self, model_name: str, logger: Logger, meter: Meter) -> N...
method do_moderate (line 667) | async def do_moderate(self, context: CustomerModerationContext) -> Mod...
class OmniModeration (line 708) | class OmniModeration(OpenAIModerationService):
method __init__ (line 709) | def __init__(self, logger: Logger, meter: Meter) -> None:
class OpenAIService (line 713) | class OpenAIService(NLPService):
method verify_environment (line 715) | def verify_environment() -> str | None:
method __init__ (line 726) | def __init__(
method supports_streaming (line 740) | def supports_streaming(self) -> bool:
method get_streaming_text_generator (line 744) | async def get_streaming_text_generator(
method get_schematic_generator (line 750) | async def get_schematic_generator(
method get_embedder (line 802) | async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder:
method get_moderation_service (line 810) | async def get_moderation_service(self) -> ModerationService:
FILE: src/parlant/adapters/nlp/openrouter_service.py
class OpenRouterEmptyEmbeddingResponseError (line 76) | class OpenRouterEmptyEmbeddingResponseError(Exception):
class OpenRouterEstimatingTokenizer (line 80) | class OpenRouterEstimatingTokenizer(EstimatingTokenizer):
method __init__ (line 81) | def __init__(self, model_name: str) -> None:
method estimate_token_count (line 87) | async def estimate_token_count(self, prompt: str) -> int:
class OpenRouterSchematicGenerator (line 92) | class OpenRouterSchematicGenerator(BaseSchematicGenerator[T]):
method __init__ (line 95) | def __init__(
method id (line 122) | def id(self) -> str:
method tokenizer (line 127) | def tokenizer(self) -> OpenRouterEstimatingTokenizer:
method max_tokens (line 132) | def max_tokens(self) -> int:
method do_generate (line 152) | async def do_generate(
class OpenRouterGPT4O (line 314) | class OpenRouterGPT4O(OpenRouterSchematicGenerator[T]):
method __init__ (line 315) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 320) | def max_tokens(self) -> int:
class OpenRouterGPT4OMini (line 324) | class OpenRouterGPT4OMini(OpenRouterSchematicGenerator[T]):
method __init__ (line 325) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 330) | def max_tokens(self) -> int:
class OpenRouterClaude35Sonnet (line 334) | class OpenRouterClaude35Sonnet(OpenRouterSchematicGenerator[T]):
method __init__ (line 335) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 342) | def max_tokens(self) -> int:
class OpenRouterLlama33_70B (line 346) | class OpenRouterLlama33_70B(OpenRouterSchematicGenerator[T]):
method __init__ (line 347) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 357) | def max_tokens(self) -> int:
class OpenRouterEmbedder (line 361) | class OpenRouterEmbedder(BaseEmbedder):
method __init__ (line 373) | def __init__(self, model_name: str, logger: Logger, tracer: Tracer, me...
method id (line 394) | def id(self) -> str:
method tokenizer (line 399) | def tokenizer(self) -> OpenRouterEstimatingTokenizer:
method max_tokens (line 404) | def max_tokens(self) -> int:
method dimensions (line 410) | def dimensions(self) -> int:
method do_embed (line 444) | async def do_embed(
class OpenRouterTextEmbedding3Large (line 491) | class OpenRouterTextEmbedding3Large(OpenRouterEmbedder):
method __init__ (line 492) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 499) | def max_tokens(self) -> int:
method dimensions (line 504) | def dimensions(self) -> int:
class OpenRouterService (line 508) | class OpenRouterService(NLPService):
method verify_environment (line 510) | def verify_environment() -> str | None:
method __init__ (line 521) | def __init__(
method supports_streaming (line 554) | def supports_streaming(self) -> bool:
method get_streaming_text_generator (line 558) | async def get_streaming_text_generator(
method _get_specialized_generator_class (line 563) | def _get_specialized_generator_class(
method get_schematic_generator (line 632) | async def get_schematic_generator(
method get_embedder (line 639) | async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder:
method get_moderation_service (line 653) | async def get_moderation_service(self) -> ModerationService:
FILE: src/parlant/adapters/nlp/qwen_service.py
function get_qwen_base_url (line 81) | def get_qwen_base_url() -> str:
class QwenEstimatingTokenizer (line 98) | class QwenEstimatingTokenizer(EstimatingTokenizer):
method __init__ (line 99) | def __init__(self, model_name: str) -> None:
method estimate_token_count (line 104) | async def estimate_token_count(self, prompt: str) -> int:
class QwenEmbedder (line 109) | class QwenEmbedder(BaseEmbedder):
method __init__ (line 112) | def __init__(self, model_name: str, logger: Logger, tracer: Tracer, me...
method id (line 123) | def id(self) -> str:
method tokenizer (line 128) | def tokenizer(self) -> QwenEstimatingTokenizer:
method do_embed (line 146) | async def do_embed(
class QwenTextEmbedding_V4 (line 166) | class QwenTextEmbedding_V4(QwenEmbedder):
method __init__ (line 167) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 172) | def max_tokens(self) -> int:
method dimensions (line 176) | def dimensions(self) -> int:
class QwenSchematicGenerator (line 180) | class QwenSchematicGenerator(BaseSchematicGenerator[T]):
method __init__ (line 183) | def __init__(
method id (line 201) | def id(self) -> str:
method tokenizer (line 206) | def tokenizer(self) -> QwenEstimatingTokenizer:
method do_generate (line 224) | async def do_generate(
method _do_generate (line 232) | async def _do_generate(
class Qwen_MAX (line 306) | class Qwen_MAX(QwenSchematicGenerator[T]):
method __init__ (line 307) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 312) | def max_tokens(self) -> int:
class Qwen_Plus (line 316) | class Qwen_Plus(QwenSchematicGenerator[T]):
method __init__ (line 317) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 322) | def max_tokens(self) -> int:
class Qwen_2_5_72b (line 326) | class Qwen_2_5_72b(QwenSchematicGenerator[T]):
method __init__ (line 327) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 334) | def max_tokens(self) -> int:
class QwenService (line 338) | class QwenService(NLPService):
method verify_environment (line 340) | def verify_environment() -> str | None:
method __init__ (line 358) | def __init__(
method supports_streaming (line 373) | def supports_streaming(self) -> bool:
method get_streaming_text_generator (line 377) | async def get_streaming_text_generator(
method _get_specialized_generator_class (line 382) | def _get_specialized_generator_class(
method get_schematic_generator (line 402) | async def get_schematic_generator(
method get_embedder (line 410) | async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder:
method get_moderation_service (line 414) | async def get_moderation_service(self) -> ModerationService:
FILE: src/parlant/adapters/nlp/snowflake_cortex_service.py
class CortexEstimatingTokenizer (line 56) | class CortexEstimatingTokenizer(EstimatingTokenizer):
method __init__ (line 57) | def __init__(self, model_name: Optional[str] = None) -> None:
method estimate_token_count (line 65) | async def estimate_token_count(self, prompt: str) -> int:
class CortexSchematicGenerator (line 69) | class CortexSchematicGenerator(BaseSchematicGenerator[T]):
method __init__ (line 78) | def __init__(self, *, schema: type[T], logger: Logger, tracer: Tracer,...
method id (line 92) | def id(self) -> str:
method tokenizer (line 97) | def tokenizer(self) -> EstimatingTokenizer:
method max_tokens (line 102) | def max_tokens(self) -> int:
method _headers (line 105) | def _headers(self) -> dict[str, str]:
method do_generate (line 127) | async def do_generate(
method _do_generate (line 135) | async def _do_generate(
class CortexEmbedder (line 239) | class CortexEmbedder(BaseEmbedder):
method __init__ (line 248) | def __init__(self, *, logger: Logger, tracer: Tracer, meter: Meter) ->...
method id (line 261) | def id(self) -> str:
method tokenizer (line 266) | def tokenizer(self) -> EstimatingTokenizer:
method dimensions (line 271) | def dimensions(self) -> int:
method _infer_dims (line 275) | def _infer_dims(model_name: str) -> int:
method _headers (line 285) | def _headers(self) -> dict[str, str]:
method do_embed (line 307) | async def do_embed(
method max_tokens (line 337) | def max_tokens(self) -> int:
class SnowflakeCortexService (line 341) | class SnowflakeCortexService(NLPService):
method verify_environment (line 353) | def verify_environment() -> str | None:
method __init__ (line 369) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method supports_streaming (line 385) | def supports_streaming(self) -> bool:
method get_streaming_text_generator (line 389) | async def get_streaming_text_generator(
method get_schematic_generator (line 395) | async def get_schematic_generator(
method get_embedder (line 403) | async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder:
method get_moderation_service (line 407) | async def get_moderation_service(self) -> ModerationService:
FILE: src/parlant/adapters/nlp/together_service.py
class LlamaEstimatingTokenizer (line 69) | class LlamaEstimatingTokenizer(EstimatingTokenizer):
method __init__ (line 70) | def __init__(self) -> None:
method estimate_token_count (line 74) | async def estimate_token_count(self, prompt: str) -> int:
class TogetherAISchematicGenerator (line 79) | class TogetherAISchematicGenerator(BaseSchematicGenerator[T]):
method __init__ (line 82) | def __init__(
method id (line 96) | def id(self) -> str:
method tokenizer (line 101) | def tokenizer(self) -> LlamaEstimatingTokenizer:
method max_tokens (line 106) | def max_tokens(self) -> int:
method do_generate (line 124) | async def do_generate(
method _do_generate (line 132) | async def _do_generate(
class Llama3_1_8B (line 198) | class Llama3_1_8B(TogetherAISchematicGenerator[T]):
method __init__ (line 199) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
class Llama3_1_70B (line 208) | class Llama3_1_70B(TogetherAISchematicGenerator[T]):
method __init__ (line 209) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
class Llama3_1_405B (line 218) | class Llama3_1_405B(TogetherAISchematicGenerator[T]):
method __init__ (line 219) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
class Llama3_3_70B (line 228) | class Llama3_3_70B(TogetherAISchematicGenerator[T]):
method __init__ (line 229) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
class TogetherAIEmbedder (line 238) | class TogetherAIEmbedder(BaseEmbedder):
method __init__ (line 239) | def __init__(self, model_name: str, logger: Logger, tracer: Tracer, me...
method do_embed (line 258) | async def do_embed(
class M2Bert32K (line 278) | class M2Bert32K(TogetherAIEmbedder):
method __init__ (line 279) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method id (line 290) | def id(self) -> str:
method max_tokens (line 295) | def max_tokens(self) -> int:
method tokenizer (line 300) | def tokenizer(self) -> HuggingFaceEstimatingTokenizer:
method dimensions (line 305) | def dimensions(self) -> int:
class CustomTogetherAISchematicGenerator (line 309) | class CustomTogetherAISchematicGenerator(TogetherAISchematicGenerator[T]):
method __init__ (line 312) | def __init__(self, model_name: str, logger: Logger, tracer: Tracer, me...
class CustomTogetherAIEmbedder (line 321) | class CustomTogetherAIEmbedder(TogetherAIEmbedder):
method __init__ (line 324) | def __init__(self, model_name: str, logger: Logger, tracer: Tracer, me...
method id (line 331) | def id(self) -> str:
method max_tokens (line 336) | def max_tokens(self) -> int:
method tokenizer (line 341) | def tokenizer(self) -> HuggingFaceEstimatingTokenizer:
method dimensions (line 346) | def dimensions(self) -> int:
class TogetherService (line 350) | class TogetherService(NLPService):
method verify_environment (line 352) | def verify_environment() -> str | None:
method __init__ (line 379) | def __init__(
method supports_streaming (line 399) | def supports_streaming(self) -> bool:
method get_streaming_text_generator (line 403) | async def get_streaming_text_generator(
method _get_specialized_generator_class (line 408) | def _get_specialized_generator_class(
method get_schematic_generator (line 426) | async def get_schematic_generator(
method _get_specialized_embedder_class (line 443) | def _get_specialized_embedder_class(
method get_embedder (line 457) | async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder:
method get_moderation_service (line 473) | async def get_moderation_service(self) -> ModerationService:
FILE: src/parlant/adapters/nlp/vertex_service.py
class ModelProvider (line 72) | class ModelProvider(Enum):
class VertexAIAuthError (line 79) | class VertexAIAuthError(Exception):
class VertexAIEstimatingTokenizer (line 85) | class VertexAIEstimatingTokenizer(EstimatingTokenizer):
method __init__ (line 88) | def __init__(self, client: google.genai.Client, model_name: str):
method estimate_token_count (line 99) | async def estimate_token_count(self, prompt: str) -> int:
function get_model_provider (line 116) | def get_model_provider(model_name: str) -> ModelProvider:
class VertexAIClaudeSchematicGenerator (line 126) | class VertexAIClaudeSchematicGenerator(BaseSchematicGenerator[T]):
method __init__ (line 131) | def __init__(
method id (line 155) | def id(self) -> str:
method tokenizer (line 160) | def tokenizer(self) -> EstimatingTokenizer:
method max_tokens (line 165) | def max_tokens(self) -> int:
method do_generate (line 185) | async def do_generate(
method _do_generate (line 193) | async def _do_generate(
class VertexAIGeminiSchematicGenerator (line 278) | class VertexAIGeminiSchematicGenerator(BaseSchematicGenerator[T]):
method __init__ (line 283) | def __init__(
method id (line 302) | def id(self) -> str:
method tokenizer (line 307) | def tokenizer(self) -> EstimatingTokenizer:
method max_tokens (line 312) | def max_tokens(self) -> int:
method do_generate (line 333) | async def do_generate(
method _do_generate (line 341) | async def _do_generate(
class VertexClaudeOpus4 (line 439) | class VertexClaudeOpus4(VertexAIClaudeSchematicGenerator[T]):
method __init__ (line 440) | def __init__(
class VertexClaudeSonnet4 (line 453) | class VertexClaudeSonnet4(VertexAIClaudeSchematicGenerator[T]):
method __init__ (line 454) | def __init__(
class VertexClaudeSonnet35 (line 467) | class VertexClaudeSonnet35(VertexAIClaudeSchematicGenerator[T]):
method __init__ (line 468) | def __init__(
class VertexClaudeHaiku35 (line 481) | class VertexClaudeHaiku35(VertexAIClaudeSchematicGenerator[T]):
method __init__ (line 482) | def __init__(
class VertexGemini15Flash (line 495) | class VertexGemini15Flash(VertexAIGeminiSchematicGenerator[T]):
method __init__ (line 496) | def __init__(
class VertexGemini15Pro (line 509) | class VertexGemini15Pro(VertexAIGeminiSchematicGenerator[T]):
method __init__ (line 510) | def __init__(
class VertexGemini20Flash (line 523) | class VertexGemini20Flash(VertexAIGeminiSchematicGenerator[T]):
method __init__ (line 524) | def __init__(
class VertexGemini25Flash (line 537) | class VertexGemini25Flash(VertexAIGeminiSchematicGenerator[T]):
method __init__ (line 538) | def __init__(
method generate (line 551) | async def generate(
class VertexGemini25Pro (line 562) | class VertexGemini25Pro(VertexAIGeminiSchematicGenerator[T]):
method __init__ (line 563) | def __init__(
class VertexAIEmbedder (line 581) | class VertexAIEmbedder(BaseEmbedder):
method __init__ (line 586) | def __init__(
method id (line 611) | def id(self) -> str:
method tokenizer (line 616) | def tokenizer(self) -> EstimatingTokenizer:
method max_tokens (line 621) | def max_tokens(self) -> int:
method do_embed (line 638) | async def do_embed(
class VertexTextEmbedding004 (line 679) | class VertexTextEmbedding004(VertexAIEmbedder):
method __init__ (line 680) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method dimensions (line 685) | def dimensions(self) -> int:
class VertexAIService (line 689) | class VertexAIService(NLPService):
method verify_environment (line 708) | def verify_environment() -> str | None:
method validate_adc (line 733) | def validate_adc() -> str | None:
method __init__ (line 750) | def __init__(
method supports_streaming (line 773) | def supports_streaming(self) -> bool:
method get_streaming_text_generator (line 777) | async def get_streaming_text_generator(
method _normalize_model_name (line 782) | def _normalize_model_name(self, model_name: str) -> str:
method get_schematic_generator (line 793) | async def get_schematic_generator(
method get_embedder (line 907) | async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder:
method get_moderation_service (line 912) | async def get_moderation_service(self) -> ModerationService: # @Todo ...
FILE: src/parlant/adapters/nlp/zhipu_service.py
class ZhipuEstimatingTokenizer (line 85) | class ZhipuEstimatingTokenizer(EstimatingTokenizer):
method __init__ (line 88) | def __init__(self, model_name: str) -> None:
method estimate_token_count (line 99) | async def estimate_token_count(self, prompt: str) -> int:
class ZhipuSchematicGenerator (line 112) | class ZhipuSchematicGenerator(BaseSchematicGenerator[T]):
method __init__ (line 118) | def __init__(
method id (line 144) | def id(self) -> str:
method tokenizer (line 154) | def tokenizer(self) -> ZhipuEstimatingTokenizer:
method do_generate (line 176) | async def do_generate(
method _do_generate (line 193) | async def _do_generate(
class GLM_4_Plus (line 284) | class GLM_4_Plus(ZhipuSchematicGenerator[T]):
method __init__ (line 287) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 298) | def max_tokens(self) -> int:
class GLM_4_Flash (line 307) | class GLM_4_Flash(ZhipuSchematicGenerator[T]):
method __init__ (line 310) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 321) | def max_tokens(self) -> int:
class GLM_4_Air (line 330) | class GLM_4_Air(ZhipuSchematicGenerator[T]):
method __init__ (line 333) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 344) | def max_tokens(self) -> int:
class ZhipuEmbedder (line 353) | class ZhipuEmbedder(BaseEmbedder):
method __init__ (line 358) | def __init__(
method id (line 380) | def id(self) -> str:
method tokenizer (line 390) | def tokenizer(self) -> ZhipuEstimatingTokenizer:
method do_embed (line 412) | async def do_embed(
class Embedding_3 (line 449) | class Embedding_3(ZhipuEmbedder):
method __init__ (line 452) | def __init__(self, logger: Logger, tracer: Tracer, meter: Meter) -> None:
method max_tokens (line 463) | def max_tokens(self) -> int:
method dimensions (line 473) | def dimensions(self) -> int:
class ZhipuModerationService (line 482) | class ZhipuModerationService(BaseModerationService):
method __init__ (line 485) | def __init__(self, model_name: str, logger: Logger, meter: Meter) -> N...
method do_moderate (line 504) | async def do_moderate(self, context: CustomerModerationContext) -> Mod...
method _do_moderate (line 516) | async def _do_moderate(self, context: CustomerModerationContext) -> Mo...
class ZhipuService (line 569) | class ZhipuService(NLPService):
method verify_environment (line 573) | def verify_environment() -> str | None:
method __init__ (line 593) | def __init__(
method supports_streaming (line 612) | def supports_streaming(self) -> bool:
method get_streaming_text_generator (line 616) | async def get_streaming_text_generator(
method get_schematic_generator (line 622) | async def get_schematic_generator(
method get_embedder (line 641) | async def get_embedder(self, hints: EmbedderHints = {}) -> Embedder:
method get_moderation_service (line 650) | async def get_moderation_service(self) -> BaseModerationService:
FILE: src/parlant/adapters/tracing/opentelemetry.py
class OpenTelemetryTracer (line 39) | class OpenTelemetryTracer(Tracer):
method __init__ (line 40) | def __init__(self) -> None:
method __aenter__ (line 68) | async def __aenter__(self) -> Self:
method __aexit__ (line 113) | async def __aexit__(
method span (line 126) | def span(
method attributes (line 211) | def attributes(
method trace_id (line 231) | def trace_id(self) -> str:
method span_id (line 239) | def span_id(self) -> str:
method get_attribute (line 246) | def get_attribute(
method set_attribute (line 254) | def set_attribute(
method add_event (line 268) | def add_event(
method flush (line 278) | def flush(self) -> None:
FILE: src/parlant/adapters/vector_db/chroma.py
class ChromaDatabase (line 51) | class ChromaDatabase(VectorDatabase):
method __init__ (line 52) | def __init__(
method __aenter__ (line 70) | async def __aenter__(self) -> Self:
method __aexit__ (line 74) | async def __aexit__(
method format_collection_name (line 82) | def format_collection_name(
method _load_collection_documents (line 90) | async def _load_collection_documents(
method _index_collection (line 151) | async def _index_collection(
method create_collection (line 196) | async def create_collection(
method get_collection (line 235) | async def get_collection(
method get_or_create_collection (line 300) | async def get_or_create_collection(
method delete_collection (line 361) | async def delete_collection(
method upsert_metadata (line 373) | async def upsert_metadata(
method remove_metadata (line 410) | async def remove_metadata(
method read_metadata (line 434) | async def read_metadata(
class ChromaCollection (line 449) | class ChromaCollection(Generic[TDocument], BaseVectorCollection[TDocumen...
method __init__ (line 450) | def __init__(
method find (line 477) | async def find(
method find_one (line 490) | async def find_one(
method insert_one (line 503) | async def insert_one(
method update_one (line 549) | async def update_one(
method delete_one (line 665) | async def delete_one(
method do_find_similar_documents (line 704) | async def do_find_similar_documents(
FILE: src/parlant/adapters/vector_db/qdrant.py
function _retry_on_timeout_async (line 57) | async def _retry_on_timeout_async(
function _string_id_to_int (line 112) | def _string_id_to_int(doc_id: str) -> int:
function _extract_field_names_from_where (line 121) | def _extract_field_names_from_where(where: Where, field_names: set[str])...
function _convert_where_to_qdrant_filter (line 152) | def _convert_where_to_qdrant_filter(where: Where) -> Optional[Filter]:
class QdrantDatabase (line 229) | class QdrantDatabase(VectorDatabase):
method __init__ (line 230) | def __init__(
method __aenter__ (line 252) | async def __aenter__(self) -> Self:
method __aexit__ (line 283) | async def __aexit__(
method format_collection_name (line 320) | def format_collection_name(
method _ensure_payload_index (line 327) | def _ensure_payload_index(self, collection_name: str, field_name: str)...
method _load_collection_documents (line 354) | async def _load_collection_documents(
method _get_collection_version (line 432) | async def _get_collection_version(self, collection_name: str) -> int:
method _set_collection_version (line 442) | async def _set_collection_version(self, collection_name: str, version:...
method _index_collection (line 449) | async def _index_collection(
method create_collection (line 558) | async def create_collection(
method get_collection (line 618) | async def get_collection(
method get_or_create_collection (line 685) | async def get_or_create_collection(
method delete_collection (line 754) | async def delete_collection(
method upsert_metadata (line 772) | async def upsert_metadata(
method remove_metadata (line 831) | async def remove_metadata(
method read_metadata (line 869) | async def read_metadata(
class QdrantCollection (line 894) | class QdrantCollection(Generic[TDocument], BaseVectorCollection[TDocumen...
method __init__ (line 895) | def __init__(
method find (line 927) | async def find(
method find_one (line 972) | async def find_one(
method insert_one (line 1020) | async def insert_one(
method update_one (line 1096) | async def update_one(
method delete_one (line 1283) | async def delete_one(
method do_find_similar_documents (line 1350) | async def do_find_similar_documents(
FILE: src/parlant/adapters/vector_db/transient.py
function _null_basicConfig (line 33) | def _null_basicConfig(*args: Any, **kwargs: Any) -> None:
class _NullLogger (line 37) | class _NullLogger:
method info (line 38) | def info(self, *args: Any, **kwargs: Any) -> None:
method debug (line 41) | def debug(self, *args: Any, **kwargs: Any) -> None:
function _null_getLogger (line 45) | def _null_getLogger(*args: Any, **kwargs: Any) -> object:
class TransientVectorDatabase (line 79) | class TransientVectorDatabase(VectorDatabase):
method __init__ (line 80) | def __init__(
method create_collection (line 97) | async def create_collection(
method get_collection (line 123) | async def get_collection(
method get_or_create_collection (line 136) | async def get_or_create_collection(
method delete_collection (line 164) | async def delete_collection(
method upsert_metadata (line 174) | async def upsert_metadata(
method remove_metadata (line 182) | async def remove_metadata(
method read_metadata (line 189) | async def read_metadata(
class TransientVectorCollection (line 195) | class TransientVectorCollection(Generic[TDocument], BaseVectorCollection...
method __init__ (line 196) | def __init__(
method _build_filter_lambda (line 218) | def _build_filter_lambda(
method find (line 227) | async def find(
method find_one (line 241) | async def find_one(
method insert_one (line 252) | async def insert_one(
method update_one (line 282) | async def update_one(
method delete_one (line 341) | async def delete_one(
method _distance_from_similarity (line 360) | def _distance_from_similarity(similarity: float) -> float:
method do_find_similar_documents (line 363) | async def do_find_similar_documents(
FILE: src/parlant/api/agents.py
class AgentDTO (line 110) | class AgentDTO(
class AgentCreationParamsDTO (line 142) | class AgentCreationParamsDTO(
class AgentTagUpdateParamsDTO (line 192) | class AgentTagUpdateParamsDTO(
class AgentUpdateParamsDTO (line 204) | class AgentUpdateParamsDTO(
function create_router (line 223) | def create_router(
FILE: src/parlant/api/app.py
class AppWrapper (line 75) | class AppWrapper:
method __init__ (line 76) | def __init__(self, app: FastAPI) -> None:
method __call__ (line 79) | async def __call__(self, scope: Scope, receive: Receive, send: Send) -...
function _resolve_operation_id (line 94) | def _resolve_operation_id(request: Request) -> str | None:
function create_api_app (line 106) | async def create_api_app(
FILE: src/parlant/api/authorization.py
class Operation (line 32) | class Operation(Enum):
class AuthorizationException (line 130) | class AuthorizationException(Exception):
method __init__ (line 131) | def __init__(
class RateLimitExceededException (line 145) | class RateLimitExceededException(AuthorizationException):
method __init__ (line 146) | def __init__(self, request: Request, operation: Operation | None) -> N...
class AuthorizationPolicy (line 154) | class AuthorizationPolicy(ABC):
method configure_app (line 155) | async def configure_app(self, app: FastAPI) -> FastAPI:
method check_permission (line 159) | async def check_permission(self, request: Request, operation: Operatio...
method check_rate_limit (line 162) | async def check_rate_limit(self, request: Request, operation: Operatio...
method authorize (line 164) | async def authorize(self, request: Request, operation: Operation) -> N...
method name (line 173) | def name(self) -> str: ...
class DevelopmentAuthorizationPolicy (line 176) | class DevelopmentAuthorizationPolicy(AuthorizationPolicy):
method configure_app (line 177) | async def configure_app(self, app: FastAPI) -> FastAPI:
method check_rate_limit (line 190) | async def check_rate_limit(self, request: Request, operation: Operatio...
method check_permission (line 195) | async def check_permission(self, request: Request, operation: Operatio...
method name (line 201) | def name(self) -> str:
class RateLimiter (line 205) | class RateLimiter(ABC):
method check (line 207) | async def check(
class ProductionAuthorizationPolicy (line 214) | class ProductionAuthorizationPolicy(AuthorizationPolicy):
method __init__ (line 215) | def __init__(self) -> None:
method configure_app (line 237) | async def configure_app(self, app: FastAPI) -> FastAPI:
method name (line 256) | def name(self) -> str:
method check_permission (line 260) | async def check_permission(self, request: Request, operation: Operatio...
method check_rate_limit (line 273) | async def check_rate_limit(self, request: Request, operation: Operatio...
class BasicRateLimiter (line 279) | class BasicRateLimiter(RateLimiter):
method __init__ (line 280) | def __init__(
method check (line 292) | async def check(
method _build_key (line 302) | def _build_key(
method _get_client_ip (line 319) | def _get_client_ip(request: Request) -> str | None:
FILE: src/parlant/api/canned_responses.py
class CannedResponseFieldDTO (line 73) | class CannedResponseFieldDTO(
class CannedResponseDTO (line 181) | class CannedResponseDTO(
class CannedResponseCreationParamsDTO (line 209) | class CannedResponseCreationParamsDTO(
class CannedResponseTagUpdateParamsDTO (line 249) | class CannedResponseTagUpdateParamsDTO(
class CannedResponseMetadataUpdateParamsDTO (line 274) | class CannedResponseMetadataUpdateParamsDTO(
class CannedResponseUpdateParamsDTO (line 303) | class CannedResponseUpdateParamsDTO(
function _dto_to_canned_response_field (line 315) | def _dto_to_canned_response_field(dto: CannedResponseFieldDTO) -> Canned...
function _canned_response_field_to_dto (line 323) | def _canned_response_field_to_dto(
function create_router (line 339) | def create_router(
FILE: src/parlant/api/capabilities.py
class CapabilityDTO (line 81) | class CapabilityDTO(
class CapabilityCreationParamsDTO (line 96) | class CapabilityCreationParamsDTO(
class CapabilityTagUpdateParamsDTO (line 132) | class CapabilityTagUpdateParamsDTO(
class CapabilityUpdateParamsDTO (line 144) | class CapabilityUpdateParamsDTO(
function create_router (line 168) | def create_router(
FILE: src/parlant/api/chat/dist/assets/index-BBAJ1vle.js
function DM (line 1) | function DM(t,e){for(var n=0;n<e.length;n++){const r=e[n];if(typeof r!="...
function n (line 1) | function n(i){const s={};return i.integrity&&(s.integrity=i.integrity),i...
function r (line 1) | function r(i){if(i.ep)return;i.ep=!0;const s=n(i);fetch(i.href,s)}
function _s (line 1) | function _s(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.c...
function LM (line 9) | function LM(){if(nv)return Et;nv=1;var t=Symbol.for("react.element"),e=S...
function Dh (line 9) | function Dh(){return rv||(rv=1,ug.exports=LM()),ug.exports}
function PM (line 17) | function PM(){if(iv)return wu;iv=1;var t=Dh(),e=Symbol.for("react.elemen...
function FM (line 17) | function FM(){return sv||(sv=1,lg.exports=PM()),lg.exports}
function BM (line 25) | function BM(){return ov||(ov=1,(function(t){function e(j,W){var O=j.leng...
function UM (line 25) | function UM(){return av||(av=1,dg.exports=BM()),dg.exports}
function HM (line 33) | function HM(){if(lv)return Cr;lv=1;var t=Dh(),e=UM();function n(a){for(v...
function ZS (line 40) | function ZS(){if(uv)return cg.exports;uv=1;function t(){if(!(typeof __RE...
function zM (line 40) | function zM(){if(cv)return Qd;cv=1;var t=ZS();return Qd.createRoot=t.cre...
method constructor (line 40) | constructor(){this.subscribe=t=>(this.subscribers.push(t),()=>{let e=thi...
function oD (line 40) | function oD(t,{insertAt:e}={}){if(typeof document>"u")return;let n=docum...
function Zd (line 41) | function Zd(t){return t.label!==void 0}
function gi (line 41) | function gi(...t){return t.filter(Boolean).join(" ")}
function pD (line 41) | function pD(t){let[e,n]=t.split("-"),r=[];return e&&r.push(e),n&&r.push(...
function V (line 41) | function V(){var te,me,De;return O!=null&&O.loading?we.createElement("di...
function hv (line 41) | function hv(){if(typeof window>"u"||typeof document>"u")return"ltr";let ...
function gD (line 41) | function gD(t,e){let n={};return[t,e].forEach((r,i)=>{let s=i===1,o=s?"-...
function hg (line 41) | function hg(t,e,n=[],r=!1,i=!0,s=!0){const[o,l]=T.useState(null),[c,d]=T...
function t_ (line 41) | function t_(t){var e,n,r="";if(typeof t=="string"||typeof t=="number")r+...
function Al (line 41) | function Al(){for(var t,e,n=0,r="",i=arguments.length;n<i;n++)(t=argumen...
method get (line 41) | get(s){let o=n.get(s);if(o!==void 0)return o;if((o=r.get(s))!==void 0)re...
method set (line 41) | set(s,o){n.has(s)?n.set(s,o):i(s,o)}
function On (line 41) | function On(){let t=0,e,n,r="";for(;t<arguments.length;)(e=arguments[t++...
function ND (line 41) | function ND(t,...e){let n,r,i,s=o;function o(c){const d=e.reduce((f,p)=>...
function Rt (line 41) | function Rt(...t){return Xe(Al(t))}
function Lh (line 43) | function Lh(t,e,n){return new Promise((r,i)=>{const s=indexedDB.open(t,1...
function je (line 43) | function je(t,e,{checkForDefaultPrevented:n=!0}={}){return function(i){i...
function yv (line 43) | function yv(t,e){if(typeof t=="function")return t(e);t!=null&&(t.current...
function Ph (line 43) | function Ph(...t){return e=>{let n=!1;const r=t.map(i=>{const s=yv(i,e);...
function Pt (line 43) | function Pt(...t){return T.useCallback(Ph(...t),t)}
function JD (line 43) | function JD(t,e){const n=T.createContext(e),r=s=>{const{children:o,...l}...
function Cs (line 43) | function Cs(t,e=[]){let n=[];function r(s,o){const l=T.createContext(o),...
function eL (line 43) | function eL(...t){const e=t[0];if(t.length===1)return e;const n=()=>{con...
function Go (line 43) | function Go(t){const e=nL(t),n=T.forwardRef((r,i)=>{const{children:s,......
function nL (line 43) | function nL(t){const e=T.forwardRef((n,r)=>{const{children:i,...s}=n;if(...
function rL (line 43) | function rL(t){const e=({children:n})=>w.jsx(w.Fragment,{children:n});re...
function iL (line 43) | function iL(t){return T.isValidElement(t)&&typeof t.type=="function"&&"_...
function sL (line 43) | function sL(t,e){const n={...e};for(const r in e){const i=t[r],s=e[r];/^...
function oL (line 43) | function oL(t){let e=Object.getOwnPropertyDescriptor(t.props,"ref")?.get...
function u_ (line 43) | function u_(t,e){t&&Ac.flushSync(()=>t.dispatchEvent(e))}
function Yi (line 43) | function Yi(t){const e=T.useRef(t);return T.useEffect(()=>{e.current=t})...
function lL (line 43) | function lL(t,e=globalThis?.document){const n=Yi(t);T.useEffect(()=>{con...
function pL (line 43) | function pL(t,e=globalThis?.document){const n=Yi(t),r=T.useRef(!1),i=T.u...
function mL (line 43) | function mL(t,e=globalThis?.document){const n=Yi(t),r=T.useRef(!1);retur...
function vv (line 43) | function vv(){const t=new CustomEvent(k0);document.dispatchEvent(t)}
function d_ (line 43) | function d_(t,e,n,{discrete:r}){const i=n.originalEvent.target,s=new Cus...
function Gi (line 43) | function Gi(t){const[e,n]=T.useState(gL());return lr(()=>{n(r=>r??String...
function N0 (line 43) | function N0(t,e,n){return $r(t,uo(e,n))}
function ys (line 43) | function ys(t,e){return typeof t=="function"?t(e):t}
function xs (line 43) | function xs(t){return t.split("-")[0]}
function Nl (line 43) | function Nl(t){return t.split("-")[1]}
function tE (line 43) | function tE(t){return t==="x"?"y":"x"}
function nE (line 43) | function nE(t){return t==="y"?"height":"width"}
function Vi (line 43) | function Vi(t){return vL.has(xs(t))?"y":"x"}
function rE (line 43) | function rE(t){return tE(Vi(t))}
function wL (line 43) | function wL(t,e,n){n===void 0&&(n=!1);const r=Nl(t),i=rE(t),s=nE(i);let ...
function TL (line 43) | function TL(t){const e=Zf(t);return[R0(t),e,R0(e)]}
function R0 (line 43) | function R0(t){return t.replace(/start|end/g,e=>xL[e])}
function CL (line 43) | function CL(t,e,n){switch(t){case"top":case"bottom":return n?e?Tv:wv:e?w...
function AL (line 43) | function AL(t,e,n,r){const i=Nl(t);let s=CL(xs(t),n==="start",r);return ...
function Zf (line 43) | function Zf(t){return t.replace(/left|right|bottom|top/g,e=>yL[e])}
function kL (line 43) | function kL(t){return{top:0,right:0,bottom:0,left:0,...t}}
function f_ (line 43) | function f_(t){return typeof t!="number"?kL(t):{top:t,right:t,bottom:t,l...
function Jf (line 43) | function Jf(t){const{x:e,y:n,width:r,height:i}=t;return{width:r,height:i...
function Sv (line 43) | function Sv(t,e,n){let{reference:r,floating:i}=t;const s=Vi(e),o=rE(e),l...
function oc (line 43) | async function oc(t,e){var n;e===void 0&&(e={});const{x:r,y:i,platform:s...
method fn (line 43) | async fn(e){const{x:n,y:r,placement:i,rects:s,platform:o,elements:l,midd...
method fn (line 43) | async fn(e){var n,r;const{placement:i,middlewareData:s,rects:o,initialPl...
function _v (line 43) | function _v(t,e){return{top:t.top-e.height,right:t.right-e.width,bottom:...
function Cv (line 43) | function Cv(t){return EL.some(e=>t[e]>=0)}
method fn (line 43) | async fn(e){const{rects:n}=e,{strategy:r="referenceHidden",...i}=ys(t,e)...
function ML (line 43) | async function ML(t,e){const{placement:n,platform:r,elements:i}=t,s=awai...
method fn (line 43) | async fn(e){var n,r;const{x:i,y:s,placement:o,middlewareData:l}=e,c=awai...
method fn (line 43) | async fn(e){const{x:n,y:r,placement:i}=e,{mainAxis:s=!0,crossAxis:o=!1,l...
method fn (line 43) | fn(e){const{x:n,y:r,placement:i,rects:s,middlewareData:o}=e,{offset:l=0,...
method fn (line 43) | async fn(e){var n,r;const{placement:i,rects:s,platform:o,elements:l}=e,{...
function Fh (line 43) | function Fh(){return typeof window<"u"}
function Rl (line 43) | function Rl(t){return p_(t)?(t.nodeName||"").toLowerCase():"#document"}
function Vr (line 43) | function Vr(t){var e;return(t==null||(e=t.ownerDocument)==null?void 0:e....
function Qi (line 43) | function Qi(t){var e;return(e=(p_(t)?t.ownerDocument:t.document)||window...
function p_ (line 43) | function p_(t){return Fh()?t instanceof Node||t instanceof Vr(t).Node:!1}
function Ti (line 43) | function Ti(t){return Fh()?t instanceof Element||t instanceof Vr(t).Elem...
function qi (line 43) | function qi(t){return Fh()?t instanceof HTMLElement||t instanceof Vr(t)....
function Av (line 43) | function Av(t){return!Fh()||typeof ShadowRoot>"u"?!1:t instanceof Shadow...
function Nc (line 43) | function Nc(t){const{overflow:e,overflowX:n,overflowY:r,display:i}=Si(t)...
function HL (line 43) | function HL(t){return UL.has(Rl(t))}
function Bh (line 43) | function Bh(t){return zL.some(e=>{try{return t.matches(e)}catch{return!1...
function iE (line 43) | function iE(t){const e=sE(),n=Ti(t)?Si(t):t;return jL.some(r=>n[r]?n[r]!...
function VL (line 43) | function VL(t){let e=co(t);for(;qi(e)&&!pl(e);){if(iE(e))return e;if(Bh(...
function sE (line 43) | function sE(){return typeof CSS>"u"||!CSS.supports?!1:CSS.supports("-web...
function pl (line 43) | function pl(t){return GL.has(Rl(t))}
function Si (line 43) | function Si(t){return Vr(t).getComputedStyle(t)}
function Uh (line 43) | function Uh(t){return Ti(t)?{scrollLeft:t.scrollLeft,scrollTop:t.scrollT...
function co (line 43) | function co(t){if(Rl(t)==="html")return t;const e=t.assignedSlot||t.pare...
function m_ (line 43) | function m_(t){const e=co(t);return pl(e)?t.ownerDocument?t.ownerDocumen...
function ac (line 43) | function ac(t,e,n){var r;e===void 0&&(e=[]),n===void 0&&(n=!0);const i=m...
function I0 (line 43) | function I0(t){return t.parent&&Object.getPrototypeOf(t.parent)?t.frameE...
function g_ (line 43) | function g_(t){const e=Si(t);let n=parseFloat(e.width)||0,r=parseFloat(e...
function oE (line 43) | function oE(t){return Ti(t)?t:t.contextElement}
function rl (line 43) | function rl(t){const e=oE(t);if(!qi(e))return Ki(1);const n=e.getBoundin...
function b_ (line 43) | function b_(t){const e=Vr(t);return!sE()||!e.visualViewport?KL:{x:e.visu...
function YL (line 43) | function YL(t,e,n){return e===void 0&&(e=!1),!n||e&&n!==Vr(t)?!1:e}
function Ko (line 43) | function Ko(t,e,n,r){e===void 0&&(e=!1),n===void 0&&(n=!1);const i=t.get...
function aE (line 43) | function aE(t,e){const n=Uh(t).scrollLeft;return e?e.left+n:Ko(Qi(t)).le...
function E_ (line 43) | function E_(t,e,n){n===void 0&&(n=!1);const r=t.getBoundingClientRect(),...
function qL (line 43) | function qL(t){let{elements:e,rect:n,offsetParent:r,strategy:i}=t;const ...
function XL (line 43) | function XL(t){return Array.from(t.getClientRects())}
function QL (line 43) | function QL(t){const e=Qi(t),n=Uh(t),r=t.ownerDocument.body,i=$r(e.scrol...
function ZL (line 43) | function ZL(t,e){const n=Vr(t),r=Qi(t),i=n.visualViewport;let s=r.client...
function eP (line 43) | function eP(t,e){const n=Ko(t,!0,e==="fixed"),r=n.top+t.clientTop,i=n.le...
function kv (line 43) | function kv(t,e,n){let r;if(e==="viewport")r=ZL(t,n);else if(e==="docume...
function y_ (line 43) | function y_(t,e){const n=co(t);return n===e||!Ti(n)||pl(n)?!1:Si(n).posi...
function tP (line 43) | function tP(t,e){const n=e.get(t);if(n)return n;let r=ac(t,[],!1).filter...
function nP (line 43) | function nP(t){let{element:e,boundary:n,rootBoundary:r,strategy:i}=t;con...
function rP (line 43) | function rP(t){const{width:e,height:n}=g_(t);return{width:e,height:n}}
function iP (line 43) | function iP(t,e,n){const r=qi(e),i=Qi(e),s=n==="fixed",o=Ko(t,!0,s,e);le...
function mg (line 43) | function mg(t){return Si(t).position==="static"}
function Nv (line 43) | function Nv(t,e){if(!qi(t)||Si(t).position==="fixed")return null;if(e)re...
function x_ (line 43) | function x_(t,e){const n=Vr(t);if(Bh(t))return n;if(!qi(t)){let i=co(t);...
function oP (line 43) | function oP(t){return Si(t).direction==="rtl"}
function v_ (line 43) | function v_(t,e){return t.x===e.x&&t.y===e.y&&t.width===e.width&&t.heigh...
function lP (line 43) | function lP(t,e){let n=null,r;const i=Qi(t);function s(){var l;clearTime...
function uP (line 43) | function uP(t,e,n,r){r===void 0&&(r={});const{ancestorScroll:i=!0,ancest...
function eh (line 43) | function eh(t,e){if(t===e)return!0;if(typeof t!=typeof e)return!1;if(typ...
function w_ (line 43) | function w_(t){return typeof window>"u"?1:(t.ownerDocument.defaultView||...
function Iv (line 43) | function Iv(t,e){const n=w_(t);return Math.round(e*n)/n}
function gg (line 43) | function gg(t){const e=T.useRef(t);return Lf(()=>{e.current=t}),e}
function yP (line 43) | function yP(t){t===void 0&&(t={});const{placement:e="bottom",strategy:n=...
function e (line 43) | function e(n){return{}.hasOwnProperty.call(n,"current")}
method fn (line 43) | fn(n){const{element:r,padding:i}=typeof t=="function"?t(n):t;return r&&e...
function S_ (line 43) | function S_(t){const[e,n]=T.useState(void 0);return lr(()=>{if(t){n({wid...
function DP (line 43) | function DP(t){return t!==null}
method fn (line 43) | fn(e){const{placement:n,rects:r,middlewareData:i}=e,o=i.arrow?.centerOff...
function M_ (line 43) | function M_(t){const[e,n="center"]=t.split("-");return[e,n]}
function FP (line 43) | function FP(t,e){return T.useReducer((n,r)=>e[n][r]??n,t)}
function BP (line 43) | function BP(t){const[e,n]=T.useState(),r=T.useRef(null),i=T.useRef(t),s=...
function tf (line 43) | function tf(t){return t?.animationName||"none"}
function UP (line 43) | function UP(t){let e=Object.getOwnPropertyDescriptor(t.props,"ref")?.get...
function Yo (line 43) | function Yo({prop:t,defaultProp:e,onChange:n=()=>{},caller:r}){const[i,s...
function zP (line 43) | function zP({defaultProp:t,onChange:e}){const[n,r]=T.useState(t),i=T.use...
function jP (line 43) | function jP(t){return typeof t=="function"}
function t3 (line 43) | function t3(t,e){const n=Math.abs(e.top-t.y),r=Math.abs(e.bottom-t.y),i=...
function n3 (line 43) | function n3(t,e,n=5){const r=[];switch(e){case"top":r.push({x:t.x-n,y:t....
function r3 (line 43) | function r3(t){const{top:e,right:n,bottom:r,left:i}=t;return[{x:i,y:e},{...
function i3 (line 43) | function i3(t,e){const{x:n,y:r}=t;let i=!1;for(let s=0,o=e.length-1;s<e....
function s3 (line 43) | function s3(t){const e=t.slice();return e.sort((n,r)=>n.x<r.x?-1:n.x>r.x...
function o3 (line 43) | function o3(t){if(t.length<=1)return t.slice();const e=[];for(let r=0;r<...
function Xn (line 43) | function Xn({children:t,value:e,className:n,style:r={},side:i="bottom",a...
function mE (line 43) | function mE(t){const e=t+"CollectionProvider",[n,r]=Cs(e),[i,s]=n(e,{col...
function gE (line 43) | function gE(t){const e=T.useContext(p3);return t||e||"ltr"}
function bE (line 43) | function bE(){T.useEffect(()=>{const t=document.querySelectorAll("[data-...
function Dv (line 43) | function Dv(){const t=document.createElement("span");return t.setAttribu...
method pause (line 43) | pause(){this.paused=!0}
method resume (line 43) | resume(){this.paused=!1}
function g3 (line 43) | function g3(t,{select:e=!1}={}){const n=document.activeElement;for(const...
function b3 (line 43) | function b3(t){const e=G_(t),n=Pv(e,t),r=Pv(e.reverse(),t);return[n,r]}
function G_ (line 43) | function G_(t){const e=[],n=document.createTreeWalker(t,NodeFilter.SHOW_...
function Pv (line 43) | function Pv(t,e){for(const n of t)if(!E3(n,{upTo:e}))return n}
function E3 (line 43) | function E3(t,{upTo:e}){if(getComputedStyle(t).visibility==="hidden")ret...
function y3 (line 43) | function y3(t){return t instanceof HTMLInputElement&&"select"in t}
function Zs (line 43) | function Zs(t,{select:e=!1}={}){if(t&&t.focus){const n=document.activeEl...
function x3 (line 43) | function x3(){let t=[];return{add(e){const n=t[0];e!==n&&n?.pause(),t=Bv...
function Bv (line 43) | function Bv(t,e){const n=[...t],r=n.indexOf(e);return r!==-1&&n.splice(r...
function v3 (line 43) | function v3(t){return t.filter(e=>e.tagName!=="A")}
function N3 (line 43) | function N3(t,e){return e!=="rtl"?t:t==="ArrowLeft"?"ArrowRight":t==="Ar...
function R3 (line 43) | function R3(t,e,n){const r=N3(t.key,n);if(!(e==="vertical"&&["ArrowLeft"...
function Z_ (line 43) | function Z_(t,e=!1){const n=document.activeElement;for(const r of t)if(r...
function I3 (line 43) | function I3(t,e){return t.map((n,r)=>t[(e+r)%t.length])}
function eC (line 43) | function eC(t,e){var n={};for(var r in t)Object.prototype.hasOwnProperty...
function F3 (line 43) | function F3(t,e,n){if(n||arguments.length===2)for(var r=0,i=e.length,s;r...
function wg (line 43) | function wg(t,e){return typeof t=="function"?t(e):t&&(t.current=e),t}
function H3 (line 43) | function H3(t,e){var n=T.useState(function(){return{value:t,callback:e,f...
function j3 (line 43) | function j3(t,e){var n=H3(null,function(r){return t.forEach(function(i){...
function $3 (line 43) | function $3(t){return t}
function W3 (line 43) | function W3(t,e){e===void 0&&(e=$3);var n=[],r=!1,i={read:function(){if(...
function V3 (line 43) | function V3(t){t===void 0&&(t={});var e=W3(null);return e.options=ji({as...
function G3 (line 43) | function G3(t,e){return t.useMedium(e),tC}
function Y3 (line 43) | function Y3(){if(!document)return null;var t=document.createElement("sty...
function q3 (line 43) | function q3(t,e){t.styleSheet?t.styleSheet.cssText=e:t.appendChild(docum...
function X3 (line 43) | function X3(t){var e=document.head||document.getElementsByTagName("head"...
function g6 (line 83) | function g6(t){var e=T.useRef([]),n=T.useRef([0,0]),r=T.useRef(),i=T.use...
function b6 (line 83) | function b6(t){for(var e=null;t!==null;)t instanceof ShadowRoot&&(e=t.ho...
function NC (line 83) | function NC(t){return t?"open":"closed"}
function nh (line 83) | function nh(t){return t==="indeterminate"}
function _E (line 83) | function _E(t){return nh(t)?"indeterminate":t?"checked":"unchecked"}
function j6 (line 83) | function j6(t){const e=document.activeElement;for(const n of t)if(n===e|...
function $6 (line 83) | function $6(t,e){return t.map((n,r)=>t[(e+r)%t.length])}
function W6 (line 83) | function W6(t,e,n){const i=e.length>1&&Array.from(e).every(d=>d===e[0])?...
function V6 (line 83) | function V6(t,e){const{x:n,y:r}=t;let i=!1;for(let s=0,o=e.length-1;s<e....
function G6 (line 83) | function G6(t,e){if(!e)return!1;const n={x:t.clientX,y:t.clientY};return...
function cc (line 83) | function cc(t){return e=>e.pointerType==="mouse"?t(e):void 0}
function Y4 (line 168) | function Y4(t){const e=t.getBoundingClientRect();return window.innerWidt...
function OE (line 168) | function OE(t){return t?"open":"closed"}
method signal (line 172) | get signal(){return ie||(ie=new AbortController),ie.signal}
method setSelf (line 172) | get setSelf(){return(Bu?"production":void 0)!=="production"&&!_g(D)&&con...
function ki (line 172) | function ki(t,e){const n=`atom${++dF}`,r={toString(){return(UE?"producti...
function fF (line 172) | function fF(t){return t(this)}
function hF (line 172) | function hF(t,e,n){return e(this,typeof n=="function"?n(t(this)):n)}
function mF (line 172) | function mF(){return(UE?"production":void 0)!=="production"?pF():AA()}
function gF (line 172) | function gF(){return _u||(_u=mF(),(UE?"production":void 0)!=="production...
function kA (line 172) | function kA(t){return T.useContext(EF)||gF()}
function xF (line 172) | function xF(t,e){const{delay:n,unstable_promiseStatus:r=!we.use}={},i=kA...
function vF (line 172) | function vF(t,e){const n=kA();return T.useCallback((...i)=>{if((bF?"prod...
function lt (line 172) | function lt(t,e){return[xF(t),vF(t)]}
function BA (line 172) | function BA({text:t,textToCopy:e,preText:n,className:r,element:i}){e||(e...
function z0 (line 172) | function z0({session:t,isSelected:e,refetch:n,editingTitle:r,setEditingT...
function UA (line 172) | function UA({filterSessionVal:t}){const[e,n]=T.useState(null),[r]=lt(As)...
class HA (line 172) | class HA extends T.Component{constructor(e){super(e),this.state={hasErro...
method constructor (line 172) | constructor(e){super(e),this.state={hasError:!1}}
method getDerivedStateFromError (line 172) | static getDerivedStateFromError(){return{hasError:!0}}
method componentDidCatch (line 172) | componentDidCatch(e){this.setState({errorStack:e.stack})}
method render (line 172) | render(){return this.state.hasError?this.props.component||w.jsxs("div"...
function OF (line 172) | function OF(){if(tw)return Rg;tw=1;var t="SECRET_DO_NOT_PASS_THIS_OR_YOU...
function MF (line 172) | function MF(){if(nw)return Ig;nw=1;var t=OF();function e(){}function n()...
function DF (line 172) | function DF(){return rw||(rw=1,Ng.exports=MF()()),Ng.exports}
function PF (line 172) | function PF(){if(iw)return Og;iw=1;function t(l){return l&&typeof l=="ob...
function UF (line 172) | function UF(){if(sw)return Mg;sw=1;var t=typeof Element<"u",e=typeof Map...
function jF (line 176) | function jF(){if(ow)return Dg;ow=1;var t=Object.getOwnPropertySymbols,e=...
function t (line 176) | function t(e,n){for(var r=0;r<n.length;r++){var i=n[r];i.enumerable=i.en...
function s (line 176) | function s(){return YF(this,s),QF(this,i.apply(this,arguments))}
function mB (line 176) | function mB(t,e){return t.reduce((n,r)=>{let i=e(r);return i||(i=i?.toSt...
function cw (line 176) | function cw(t){const e=[],n=String(t||"");let r=n.indexOf(","),i=0,s=!1;...
function GA (line 176) | function GA(t,e){const n={};return(t[t.length-1]===""?[...t,""]:t).join(...
function dw (line 176) | function dw(t,e){return(yB.jsx?EB:bB).test(t)}
function vB (line 176) | function vB(t){return typeof t=="object"?t.type==="text"?fw(t.value):!1:...
function fw (line 176) | function fw(t){return t.replace(xB,"")===""}
method constructor (line 176) | constructor(e,n,r){this.normal=n,this.property=e,r&&(this.space=r)}
function KA (line 176) | function KA(t,e){const n={},r={};for(const i of t)Object.assign(n,i.prop...
function fc (line 176) | function fc(t){return t.toLowerCase()}
method constructor (line 176) | constructor(e,n){this.attribute=n,this.property=e}
function aa (line 176) | function aa(){return 2**++wB}
method constructor (line 176) | constructor(e,n,r,i){let s=-1;if(super(e,n),hw(this,"space",i),typeof r=...
function hw (line 176) | function hw(t,e,n){n&&(t[e]=n)}
function Ol (line 176) | function Ol(t){const e={},n={};for(const[r,i]of Object.entries(t.propert...
method transform (line 176) | transform(t,e){return e==="role"?e:"aria-"+e.slice(4).toLowerCase()}
function qA (line 176) | function qA(t,e){return e in t?t[e]:e}
function XA (line 176) | function XA(t,e){return qA(t,e.toLowerCase())}
method transform (line 176) | transform(t,e){return"xlink:"+e.slice(5).toLowerCase()}
method transform (line 176) | transform(t,e){return"xml:"+e.slice(3).toLowerCase()}
function $E (line 176) | function $E(t,e){const n=fc(e);let r=e,i=Mr;if(n in t.normal)return t.pr...
function kB (line 176) | function kB(t){return"-"+t.toLowerCase()}
function NB (line 176) | function NB(t){return t.charAt(1).toUpperCase()}
function mw (line 176) | function mw(t){const e=String(t||"").trim();return e?e.split(/[ \t\n\r\f...
function ek (line 176) | function ek(t){return t.join(" ").trim()}
function RB (line 176) | function RB(){if(gw)return Fg;gw=1;var t=/\/\*[^*]*\*+([^/*][^*]*\*+)*\/...
function IB (line 177) | function IB(){if(bw)return za;bw=1;var t=za&&za.__importDefault||functio...
function OB (line 177) | function OB(){if(Ew)return ku;Ew=1,Object.defineProperty(ku,"__esModule"...
function MB (line 177) | function MB(){if(yw)return Nu;yw=1;var t=Nu&&Nu.__importDefault||functio...
function tk (line 177) | function tk(t){return e;function e(n){const r=n&&n.position&&n.position[...
function PB (line 177) | function PB(t){const e=Ji(t),n=op(t);if(e&&n)return{start:e,end:n}}
function Gu (line 177) | function Gu(t){return!t||typeof t!="object"?"":"position"in t||"type"in ...
function Y0 (line 177) | function Y0(t){return vw(t&&t.line)+":"+vw(t&&t.column)}
function xw (line 177) | function xw(t){return Y0(t&&t.start)+"-"+Y0(t&&t.end)}
function vw (line 177) | function vw(t){return t&&typeof t=="number"?t:1}
class ur (line 177) | class ur extends Error{constructor(e,n,r){super(),typeof n=="string"&&(r...
method constructor (line 177) | constructor(e,n,r){super(),typeof n=="string"&&(r=n,n=void 0);let i=""...
function zB (line 177) | function zB(t,e){if(!e||e.Fragment===void 0)throw new TypeError("Expecte...
function rk (line 177) | function rk(t,e,n){if(e.type==="element")return jB(t,e,n);if(e.type==="m...
function jB (line 177) | function jB(t,e,n){const r=t.schema;let i=r;e.tagName.toLowerCase()==="s...
function $B (line 177) | function $B(t,e){if(e.data&&e.data.estree&&t.evaluater){const r=e.data.e...
function WB (line 177) | function WB(t,e){if(e.data&&e.data.estree&&t.evaluater)return t.evaluate...
function VB (line 177) | function VB(t,e,n){const r=t.schema;let i=r;e.name==="svg"&&r.space==="h...
function GB (line 177) | function GB(t,e,n){const r={};return VE(r,GE(t,e)),t.create(e,t.Fragment...
function KB (line 177) | function KB(t,e){return e.value}
function ik (line 177) | function ik(t,e,n,r){typeof n!="string"&&n!==t.Fragment&&t.passNode&&(e....
function VE (line 177) | function VE(t,e){if(e.length>0){const n=e.length>1?e:e[0];n&&(t.children...
function YB (line 177) | function YB(t,e,n){return r;function r(i,s,o,l){const d=Array.isArray(o....
function qB (line 177) | function qB(t,e){return n;function n(r,i,s,o){const l=Array.isArray(s.ch...
function XB (line 177) | function XB(t,e){const n={};let r,i;for(i in e.properties)if(i!=="childr...
function QB (line 177) | function QB(t,e){const n={};for(const r of e.attributes)if(r.type==="mdx...
function GE (line 177) | function GE(t,e){const n=[];let r=-1;const i=t.passKeys?new Map:FB;for(;...
function ZB (line 177) | function ZB(t,e,n){const r=$E(t.schema,e);if(!(n==null||typeof n=="numbe...
function JB (line 177) | function JB(t,e){try{return LB(e,{reactCompat:!0})}catch(n){if(t.ignoreI...
function sk (line 177) | function sk(t,e,n){let r;if(!n)r={type:"Literal",value:e};else if(e.incl...
function hc (line 177) | function hc(t,e){const n=new ur("Cannot handle MDX estrees without `crea...
function e5 (line 177) | function e5(t){const e={};let n;for(n in t)WE.call(t,n)&&(e[t5(n)]=t[n])...
function t5 (line 177) | function t5(t){let e=t.replace(BB,n5);return e.slice(0,3)==="ms-"&&(e="-...
function n5 (line 177) | function n5(t){return"-"+t.toLowerCase()}
function KE (line 177) | function KE(t,e){const n=r5,r=typeof n.includeImageAlt=="boolean"?n.incl...
function ok (line 177) | function ok(t,e,n){if(i5(t)){if("value"in t)return t.type==="html"&&!n?"...
function ww (line 177) | function ww(t,e,n){const r=[];let i=-1;for(;++i<t.length;)r[i]=ok(t[i],e...
function i5 (line 177) | function i5(t){return!!(t&&typeof t=="object")}
function YE (line 177) | function YE(t){const e="&"+t+";";Tw.innerHTML=e;const n=Tw.textContent;r...
function Gr (line 177) | function Gr(t,e,n,r){const i=t.length;let s=0,o;if(e<0?e=-e>i?0:i+e:e=e>...
function ti (line 177) | function ti(t,e){return t.length>0?(Gr(t,t.length,0,e),t):e}
function ak (line 177) | function ak(t){const e={};let n=-1;for(;++n<t.length;)s5(e,t[n]);return e}
function s5 (line 177) | function s5(t,e){let n;for(n in e){const i=(Sw.call(t,n)?t[n]:void 0)||(...
function o5 (line 177) | function o5(t,e){let n=-1;const r=[];for(;++n<e.length;)(e[n].add==="aft...
function lk (line 177) | function lk(t,e){const n=Number.parseInt(t,e);return n<9||n===11||n>13&&...
function vi (line 177) | function vi(t){return t.replace(/[\t\n\r ]+/g," ").replace(/^ | $/g,"")....
function uh (line 177) | function uh(t){return t!==null&&(t<32||t===127)}
function et (line 177) | function et(t){return t!==null&&t<-2}
function Kt (line 177) | function Kt(t){return t!==null&&(t<0||t===32)}
function St (line 177) | function St(t){return t===-2||t===-1||t===32}
function po (line 177) | function po(t){return e;function e(n){return n!==null&&n>-1&&t.test(Stri...
function Dl (line 177) | function Dl(t){const e=[];let n=-1,r=0,i=0;for(;++n<t.length;){const s=t...
function Nt (line 177) | function Nt(t,e,n,r){const i=r?r-1:Number.POSITIVE_INFINITY;let s=0;retu...
function d5 (line 177) | function d5(t){const e=t.attempt(this.parser.constructs.contentInitial,r...
function h5 (line 177) | function h5(t){const e=this,n=[];let r=0,i,s,o;return l;function l(k){if...
function p5 (line 177) | function p5(t,e,n){return Nt(t,t.attempt(this.parser.constructs.document...
function bl (line 177) | function bl(t){if(t===null||Kt(t)||Xo(t))return 1;if(ap(t))return 2}
function lp (line 177) | function lp(t,e,n){const r=[];let i=-1;for(;++i<t.length;){const s=t[i]....
function m5 (line 177) | function m5(t,e){let n=-1,r,i,s,o,l,c,d,f;for(;++n<t.length;)if(t[n][0]=...
function g5 (line 177) | function g5(t,e){const n=this.parser.constructs.attentionMarkers.null,r=...
function Cw (line 177) | function Cw(t,e){t.column+=e,t.offset+=e,t._bufferIndex+=e}
function E5 (line 177) | function E5(t,e,n){let r=0;return i;function i(g){return t.enter("autoli...
function y5 (line 177) | function y5(t,e,n){return r;function r(s){return St(s)?Nt(t,i,"linePrefi...
function x5 (line 177) | function x5(t,e,n){const r=this;return i;function i(o){if(o===62){const ...
function v5 (line 177) | function v5(t,e,n){const r=this;return i;function i(o){return St(o)?Nt(t...
function w5 (line 177) | function w5(t){t.exit("blockQuote")}
function T5 (line 177) | function T5(t,e,n){return r;function r(s){return t.enter("characterEscap...
function S5 (line 177) | function S5(t,e,n){const r=this;let i=0,s,o;return l;function l(p){retur...
function _5 (line 177) | function _5(t,e,n){const r=this,i={partial:!0,tokenize:F};let s=0,o=0,l;...
function C5 (line 177) | function C5(t,e,n){const r=this;return i;function i(o){return o===null?n...
function k5 (line 177) | function k5(t,e,n){const r=this;return i;function i(d){return t.enter("c...
function N5 (line 177) | function N5(t,e,n){const r=this;return i;function i(o){return r.parser.l...
function I5 (line 177) | function I5(t){let e=t.length-4,n=3,r,i;if((t[n][1].type==="lineEnding"|...
function O5 (line 177) | function O5(t){return t!==96||this.events[this.events.length-1][1].type=...
function M5 (line 177) | function M5(t,e,n){let r=0,i,s;return o;function o(p){return t.enter("co...
class D5 (line 177) | class D5{constructor(e){this.left=e?[...e]:[],this.right=[]}get(e){if(e<...
method constructor (line 177) | constructor(e){this.left=e?[...e]:[],this.right=[]}
method get (line 177) | get(e){if(e<0||e>=this.left.length+this.right.length)throw new RangeEr...
method length (line 177) | get length(){return this.left.length+this.right.length}
method shift (line 177) | shift(){return this.setCursor(0),this.right.pop()}
method slice (line 177) | slice(e,n){const r=n??Number.POSITIVE_INFINITY;return r<this.left.leng...
method splice (line 177) | splice(e,n,r){const i=n||0;this.setCursor(Math.trunc(e));const s=this....
method pop (line 177) | pop(){return this.setCursor(Number.POSITIVE_INFINITY),this.left.pop()}
method push (line 177) | push(e){this.setCursor(Number.POSITIVE_INFINITY),this.left.push(e)}
method pushMany (line 177) | pushMany(e){this.setCursor(Number.POSITIVE_INFINITY),Ru(this.left,e)}
method unshift (line 177) | unshift(e){this.setCursor(0),this.right.push(e)}
method unshiftMany (line 177) | unshiftMany(e){this.setCursor(0),Ru(this.right,e.reverse())}
method setCursor (line 177) | setCursor(e){if(!(e===this.left.length||e>this.left.length&&this.right...
function Ru (line 177) | function Ru(t,e){let n=0;if(e.length<1e4)t.push(...e);else for(;n<e.leng...
function fk (line 177) | function fk(t){const e={};let n=-1,r,i,s,o,l,c,d;const f=new D5(t);for(;...
function L5 (line 177) | function L5(t,e){const n=t.get(e)[1],r=t.get(e)[2];let i=e-1;const s=[];...
function B5 (line 177) | function B5(t){return fk(t),t}
function U5 (line 177) | function U5(t,e){let n;return r;function r(l){return t.enter("content"),...
function H5 (line 177) | function H5(t,e,n){const r=this;return i;function i(o){return t.exit("ch...
function hk (line 177) | function hk(t,e,n,r,i,s,o,l,c){const d=c||Number.POSITIVE_INFINITY;let f...
function pk (line 177) | function pk(t,e,n,r,i,s){const o=this;let l=0,c;return d;function d(g){r...
function mk (line 177) | function mk(t,e,n,r,i,s){let o;return l;function l(m){return m===34||m==...
function Ku (line 177) | function Ku(t,e){let n;return r;function r(i){return et(i)?(t.enter("lin...
function $5 (line 177) | function $5(t,e,n){const r=this;let i;return s;function s(g){return t.en...
function W5 (line 177) | function W5(t,e,n){return r;function r(l){return Kt(l)?Ku(t,i)(l):n(l)}f...
function G5 (line 177) | function G5(t,e,n){return r;function r(s){return t.enter("hardBreakEscap...
function Y5 (line 177) | function Y5(t,e){let n=t.length-2,r=3,i,s;return t[r][1].type==="whitesp...
function q5 (line 177) | function q5(t,e,n){let r=0;return i;function i(f){return t.enter("atxHea...
function e8 (line 177) | function e8(t){let e=t.length;for(;e--&&!(t[e][0]==="enter"&&t[e][1].typ...
function t8 (line 177) | function t8(t,e,n){const r=this;let i,s,o,l,c;return d;function d(R){ret...
function n8 (line 177) | function n8(t,e,n){const r=this;return i;function i(o){return et(o)?(t.e...
function r8 (line 177) | function r8(t,e,n){return r;function r(i){return t.enter("lineEnding"),t...
function s8 (line 177) | function s8(t,e,n){const r=this;let i,s,o;return l;function l(O){return ...
function u8 (line 177) | function u8(t){let e=-1;const n=[];for(;++e<t.length;){const r=t[e][1];i...
function c8 (line 177) | function c8(t,e){let n=t.length,r=0,i,s,o,l;for(;n--;)if(i=t[n][1],s){if...
function d8 (line 177) | function d8(t,e,n){const r=this;let i=r.events.length,s,o;for(;i--;)if((...
function f8 (line 177) | function f8(t,e,n){return r;function r(p){return t.enter("resource"),t.e...
function h8 (line 177) | function h8(t,e,n){const r=this;return i;function i(l){return pk.call(r,...
function p8 (line 177) | function p8(t,e,n){return r;function r(s){return t.enter("reference"),t....
function g8 (line 177) | function g8(t,e,n){const r=this;return i;function i(l){return t.enter("l...
function E8 (line 177) | function E8(t,e,n){const r=this;return i;function i(o){return t.enter("l...
function y8 (line 177) | function y8(t,e){return n;function n(r){return t.enter("lineEnding"),t.c...
function x8 (line 177) | function x8(t,e,n){let r=0,i;return s;function s(d){return t.enter("them...
function T8 (line 177) | function T8(t,e,n){const r=this,i=r.events[r.events.length-1];let s=i&&i...
function S8 (line 177) | function S8(t,e,n){const r=this;return r.containerState._closeFlow=void ...
function _8 (line 177) | function _8(t,e,n){const r=this;return Nt(t,i,"listItemIndent",r.contain...
function C8 (line 177) | function C8(t){t.exit(this.containerState.type)}
function A8 (line 177) | function A8(t,e,n){const r=this;return Nt(t,i,"listItemPrefixWhitespace"...
function k8 (line 177) | function k8(t,e){let n=t.length,r,i,s;for(;n--;)if(t[n][0]==="enter"){if...
function N8 (line 177) | function N8(t,e,n){const r=this;let i;return s;function s(d){let f=r.eve...
function I8 (line 177) | function I8(t){const e=this,n=t.attempt(Dc,r,t.attempt(this.parser.const...
function gk (line 177) | function gk(t){return{resolveAll:bk(t==="text"?L8:void 0),tokenize:e};fu...
function bk (line 177) | function bk(t){return e;function e(n,r){let i=-1,s;for(;++i<=n.length;)s...
function L8 (line 177) | function L8(t,e){let n=0;for(;++n<=t.length;)if((n===t.length||t[n][1].t...
function G8 (line 177) | function G8(t,e,n){let r={_bufferIndex:-1,_index:0,line:n&&n.line||1,col...
function K8 (line 177) | function K8(t,e){const n=e.start._index,r=e.start._bufferIndex,i=e.end._...
function Y8 (line 177) | function Y8(t,e){let n=-1;const r=[];let i;for(;++n<t.length;){const s=t...
function q8 (line 179) | function q8(t){const r={constructs:ak([V8,...(t||{}).extensions||[]]),co...
function X8 (line 179) | function X8(t){for(;!fk(t););return t}
function Q8 (line 179) | function Q8(){let t=1,e="",n=!0,r;return i;function i(s,o,l){const c=[];...
function J8 (line 179) | function J8(t){return t.replace(Z8,e9)}
function e9 (line 179) | function e9(t,e,n){if(e)return e;if(n.charCodeAt(0)===35){const i=n.char...
function t9 (line 179) | function t9(t,e,n){return typeof e!="string"&&(n=e,e=void 0),n9(n)(X8(q8...
function n9 (line 179) | function n9(t){const e={transforms:[],canContainEols:["emphasis","fragme...
function Qs (line 179) | function Qs(t){return{line:t.line,column:t.column,offset:t.offset}}
function yk (line 179) | function yk(t,e){let n=-1;for(;++n<e.length;){const r=e[n];Array.isArray...
function r9 (line 179) | function r9(t,e){let n;for(n in e)if(Ek.call(e,n))switch(n){case"canCont...
function Ow (line 179) | function Ow(t,e){throw t?new Error("Cannot close `"+t.type+"` ("+Gu({sta...
function i9 (line 179) | function i9(t){const e=this;e.parser=n;function n(r){return t9(r,{...e.d...
function s9 (line 179) | function s9(t,e){const n={type:"element",tagName:"blockquote",properties...
function o9 (line 179) | function o9(t,e){const n={type:"element",tagName:"br",properties:{},chil...
function a9 (line 180) | function a9(t,e){const n=e.value?e.value+`
function l9 (line 181) | function l9(t,e){const n={type:"element",tagName:"del",properties:{},chi...
function u9 (line 181) | function u9(t,e){const n={type:"element",tagName:"em",properties:{},chil...
function c9 (line 181) | function c9(t,e){const n=typeof t.options.clobberPrefix=="string"?t.opti...
function d9 (line 181) | function d9(t,e){const n={type:"element",tagName:"h"+e.depth,properties:...
function f9 (line 181) | function f9(t,e){if(t.options.allowDangerousHtml){const n={type:"raw",va...
function xk (line 181) | function xk(t,e){const n=e.referenceType;let r="]";if(n==="collapsed"?r+...
function h9 (line 181) | function h9(t,e){const n=String(e.identifier).toUpperCase(),r=t.definiti...
function p9 (line 181) | function p9(t,e){const n={src:Dl(e.url)};e.alt!==null&&e.alt!==void 0&&(...
function m9 (line 181) | function m9(t,e){const n={type:"text",value:e.value.replace(/\r?\n|\r/g,...
function g9 (line 181) | function g9(t,e){const n=String(e.identifier).toUpperCase(),r=t.definiti...
function b9 (line 181) | function b9(t,e){const n={href:Dl(e.url)};e.title!==null&&e.title!==void...
function E9 (line 181) | function E9(t,e,n){const r=t.all(e),i=n?y9(n):vk(e),s={},o=[];if(typeof ...
function y9 (line 183) | function y9(t){let e=!1;if(t.type==="list"){e=t.spread||!1;const n=t.chi...
function vk (line 183) | function vk(t){const e=t.spread;return e??t.children.length>1}
function x9 (line 183) | function x9(t,e){const n={},r=t.all(e);let i=-1;for(typeof e.start=="num...
function v9 (line 183) | function v9(t,e){const n={type:"element",tagName:"p",properties:{},child...
function w9 (line 183) | function w9(t,e){const n={type:"root",children:t.wrap(t.all(e))};return ...
function T9 (line 183) | function T9(t,e){const n={type:"element",tagName:"strong",properties:{},...
function S9 (line 183) | function S9(t,e){const n=t.all(e),r=n.shift(),i=[];if(r){const o={type:"...
function _9 (line 183) | function _9(t,e,n){const r=n?n.children:void 0,s=(r?r.indexOf(e):1)===0?...
function C9 (line 183) | function C9(t,e){const n={type:"element",tagName:"td",properties:{},chil...
function A9 (line 183) | function A9(t){const e=String(t),n=/\r?\n|\r/g;let r=n.exec(e),i=0;const...
function Lw (line 183) | function Lw(t,e,n){let r=0,i=t.length;if(e){let s=t.codePointAt(r);for(;...
function k9 (line 183) | function k9(t,e){const n={type:"text",value:A9(String(e.value))};return ...
function N9 (line 183) | function N9(t,e){const n={type:"element",tagName:"hr",properties:{},chil...
function lf (line 183) | function lf(){}
function L9 (line 183) | function L9(t,e){const n=[{type:"text",value:"↩"}];return e>1&&n.push({t...
function P9 (line 183) | function P9(t,e){return"Back to reference "+(t+1)+(e>1?"-"+e:"")}
function F9 (line 183) | function F9(t){const e=typeof t.options.clobberPrefix=="string"?t.option...
function B9 (line 185) | function B9(t){const e=[];let n=-1;for(;++n<t.length;)e[n]=Lc(t[n]);retu...
function U9 (line 185) | function U9(t){const e=t;return cp(n);function n(r){const i=r;let s;for(...
function H9 (line 185) | function H9(t){return cp(e);function e(n){return n&&n.type===t}}
function cp (line 185) | function cp(t){return e;function e(n,r,i){return!!(j9(n)&&t.call(this,n,...
function z9 (line 185) | function z9(){return!0}
function j9 (line 185) | function j9(t){return t!==null&&typeof t=="object"&&"type"in t}
function Ck (line 185) | function Ck(t,e,n,r){let i;typeof e=="function"&&typeof n!="function"?(r...
function V9 (line 185) | function V9(t){return Array.isArray(t)?t:typeof t=="number"?[$9,t]:t==nu...
function Pc (line 185) | function Pc(t,e,n,r){let i,s,o;typeof e=="function"&&typeof n!="function...
function K9 (line 185) | function K9(t,e){const n=e||G9,r=new Map,i=new Map,s=new Map,o={...R9,.....
function Y9 (line 185) | function Y9(t,e){t.position&&(e.position=PB(t))}
function q9 (line 185) | function q9(t,e){let n=e;if(t&&t.data){const r=t.data.hName,i=t.data.hCh...
function X9 (line 185) | function X9(t,e){const n=e.data||{},r="value"in e&&!(Z0.call(n,"hPropert...
function Q9 (line 185) | function Q9(t,e){const n=[];let r=-1;for(e&&n.push({type:"text",value:`
function Uw (line 188) | function Uw(t){let e=0,n=t.charCodeAt(e);for(;n===9||n===32;)e++,n=t.cha...
function Hw (line 188) | function Hw(t,e){const n=K9(t,e),r=n.one(t,void 0),i=F9(n),s=Array.isArr...
function Z9 (line 189) | function Z9(t,e){return t&&"run"in t?async function(n,r){const i=Hw(n,{f...
function zw (line 189) | function zw(t){if(t)throw t}
function J9 (line 189) | function J9(){if(jw)return zg;jw=1;var t=Object.prototype.hasOwnProperty...
function J0 (line 189) | function J0(t){if(typeof t!="object"||t===null)return!1;const e=Object.g...
function tU (line 189) | function tU(){const t=[],e={run:n,use:r};return e;function n(...i){let s...
function nU (line 189) | function nU(t,e){let n;return r;function r(...o){const l=t.length>o.leng...
function rU (line 189) | function rU(t,e){if(e!==void 0&&typeof e!="string")throw new TypeError('...
function iU (line 189) | function iU(t){if(Fc(t),t.length===0)return".";let e=-1,n=t.length,r;for...
function sU (line 189) | function sU(t){Fc(t);let e=t.length,n=-1,r=0,i=-1,s=0,o;for(;e--;){const...
function oU (line 189) | function oU(...t){let e=-1,n;for(;++e<t.length;)Fc(t[e]),t[e]&&(n=n===vo...
function aU (line 189) | function aU(t){Fc(t);const e=t.codePointAt(0)===47;let n=lU(t,!e);return...
function lU (line 189) | function lU(t,e){let n="",r=0,i=-1,s=0,o=-1,l,c;for(;++o<=t.length;){if(...
function Fc (line 189) | function Fc(t){if(typeof t!="string")throw new TypeError("Path must be a...
function cU (line 189) | function cU(){return"/"}
function eb (line 189) | function eb(t){return!!(t!==null&&typeof t=="object"&&"href"in t&&t.href...
function dU (line 189) | function dU(t){if(typeof t=="string")t=new URL(t);else if(!eb(t)){const ...
function fU (line 189) | function fU(t){if(t.hostname!==""){const r=new TypeError('File URL host ...
class Ak (line 189) | class Ak{constructor(e){let n;e?eb(e)?n={path:e}:typeof e=="string"||hU(...
method constructor (line 189) | constructor(e){let n;e?eb(e)?n={path:e}:typeof e=="string"||hU(e)?n={v...
method basename (line 189) | get basename(){return typeof this.path=="string"?Ui.basename(this.path...
method basename (line 189) | set basename(e){Vg(e,"basename"),Wg(e,"basename"),this.path=Ui.join(th...
method dirname (line 189) | get dirname(){return typeof this.path=="string"?Ui.dirname(this.path):...
method dirname (line 189) | set dirname(e){$w(this.basename,"dirname"),this.path=Ui.join(e||"",thi...
method extname (line 189) | get extname(){return typeof this.path=="string"?Ui.extname(this.path):...
method extname (line 189) | set extname(e){if(Wg(e,"extname"),$w(this.dirname,"extname"),e){if(e.c...
method path (line 189) | get path(){return this.history[this.history.length-1]}
method path (line 189) | set path(e){eb(e)&&(e=dU(e)),Vg(e,"path"),this.path!==e&&this.history....
method stem (line 189) | get stem(){return typeof this.path=="string"?Ui.basename(this.path,thi...
method stem (line 189) | set stem(e){Vg(e,"stem"),Wg(e,"stem"),this.path=Ui.join(this.dirname||...
method fail (line 189) | fail(e,n,r){const i=this.message(e,n,r);throw i.fatal=!0,i}
method info (line 189) | info(e,n,r){const i=this.message(e,n,r);return i.fatal=void 0,i}
method message (line 189) | message(e,n,r){const i=new ur(e,n,r);return this.path&&(i.name=this.pa...
method toString (line 189) | toString(e){return this.value===void 0?"":typeof this.value=="string"?...
function Wg (line 189) | function Wg(t,e){if(t&&t.includes(Ui.sep))throw new Error("`"+e+"` canno...
function Vg (line 189) | function Vg(t,e){if(!t)throw new Error("`"+e+"` cannot be empty")}
function $w (line 189) | function $w(t,e){if(!t)throw new Error("Setting `"+e+"` requires `path` ...
function hU (line 189) | function hU(t){return!!(t&&typeof t=="object"&&"byteLength"in t&&"byteOf...
class e1 (line 189) | class e1 extends pU{constructor(){super("copy"),this.Compiler=void 0,thi...
method constructor (line 189) | constructor(){super("copy"),this.Compiler=void 0,this.Parser=void 0,th...
method copy (line 189) | copy(){const e=new e1;let n=-1;for(;++n<this.attachers.length;){const ...
method data (line 189) | data(e,n){return typeof e=="string"?arguments.length===2?(Yg("data",th...
method freeze (line 189) | freeze(){if(this.frozen)return this;const e=this;for(;++this.freezeInd...
method parse (line 189) | parse(e){this.freeze();const n=cf(e),r=this.parser||this.Parser;return...
method process (line 189) | process(e,n){const r=this;return this.freeze(),Gg("process",this.parse...
method processSync (line 189) | processSync(e){let n=!1,r;return this.freeze(),Gg("processSync",this.p...
method run (line 189) | run(e,n,r){Ww(e),this.freeze();const i=this.transformers;return!r&&typ...
method runSync (line 189) | runSync(e,n){let r=!1,i;return this.run(e,n,s),Vw("runSync","run",r),i...
method stringify (line 189) | stringify(e,n){this.freeze();const r=cf(n),i=this.compiler||this.Compi...
method use (line 189) | use(e,...n){const r=this.attachers,i=this.namespace;if(Yg("use",this.f...
function Gg (line 189) | function Gg(t,e){if(typeof e!="function")throw new TypeError("Cannot `"+...
function Kg (line 189) | function Kg(t,e){if(typeof e!="function")throw new TypeError("Cannot `"+...
function Yg (line 189) | function Yg(t,e){if(e)throw new Error("Cannot call `"+t+"` on a frozen p...
function Ww (line 189) | function Ww(t){if(!J0(t)||typeof t.type!="string")throw new TypeError("E...
function Vw (line 189) | function Vw(t,e,n){if(!n)throw new Error("`"+t+"` finished async. Use `"...
function cf (line 189) | function cf(t){return bU(t)?t:new Ak(t)}
function bU (line 189) | function bU(t){return!!(t&&typeof t=="object"&&"message"in t&&"messages"...
function EU (line 189) | function EU(t){return typeof t=="string"||yU(t)}
function yU (line 189) | function yU(t){return!!(t&&typeof t=="object"&&"byteLength"in t&&"byteOf...
function TU (line 189) | function TU(t){const e=SU(t),n=_U(t);return CU(e.runSync(e.parse(n),n),t)}
function SU (line 189) | function SU(t){const e=t.rehypePlugins||Gw,n=t.remarkPlugins||Gw,r=t.rem...
function _U (line 189) | function _U(t){const e=t.children||"",n=new Ak;return typeof e=="string"...
function CU (line 189) | function CU(t,e){const n=e.allowedElements,r=e.allowElement,i=e.componen...
function AU (line 189) | function AU(t){const e=t.indexOf(":"),n=t.indexOf("?"),r=t.indexOf("#"),...
function Yw (line 189) | function Yw(t,e){const n=String(t);if(typeof e!="string")throw new TypeE...
function kU (line 189) | function kU(t){if(typeof t!="string")throw new TypeError("Expected a str...
function NU (line 189) | function NU(t,e,n){const i=Lc((n||{}).ignore||[]),s=RU(e);let o=-1;for(;...
function RU (line 189) | function RU(t){const e=[];if(!Array.isArray(t))throw new TypeError("Expe...
function IU (line 189) | function IU(t){return typeof t=="string"?new RegExp(kU(t),"g"):t}
function OU (line 189) | function OU(t){return typeof t=="function"?t:function(){return t}}
function MU (line 189) | function MU(){return{transforms:[HU],enter:{literalAutolink:LU,literalAu...
function DU (line 189) | function DU(){return{unsafe:[{character:"@",before:"[+\\-.\\w]",after:"[...
function LU (line 189) | function LU(t){this.enter({type:"link",title:null,url:"",children:[]},t)}
function Qg (line 189) | function Qg(t){this.config.enter.autolinkProtocol.call(this,t)}
function PU (line 189) | function PU(t){this.config.exit.autolinkProtocol.call(this,t)}
function FU (line 189) | function FU(t){this.config.exit.data.call(this,t);const e=this.stack[thi...
function BU (line 189) | function BU(t){this.config.exit.autolinkEmail.call(this,t)}
function UU (line 189) | function UU(t){this.exit(t)}
function HU (line 189) | function HU(t){NU(t,[[/(https?:\/\/|www(?=\.))([-.\w]+)([^ \t\r\n]*)/gi,...
function zU (line 189) | function zU(t,e,n,r,i){let s="";if(!kk(i)||(/^w/i.test(e)&&(n=e+n,e="",s...
function jU (line 189) | function jU(t,e,n,r){return!kk(r,!0)||/[-\d_]$/.test(n)?!1:{type:"link",...
function $U (line 189) | function $U(t){const e=t.split(".");return!(e.length<2||e[e.length-1]&&(...
function WU (line 189) | function WU(t){const e=/[!"&'),.:;<>?\]}]+$/.exec(t);if(!e)return[t,void...
function kk (line 189) | function kk(t,e){const n=t.input.charCodeAt(t.index-1);return(t.index===...
function VU (line 189) | function VU(){this.buffer()}
function GU (line 189) | function GU(t){this.enter({type:"footnoteReference",identifier:"",label:...
function KU (line 189) | function KU(){this.buffer()}
function YU (line 189) | function YU(t){this.enter({type:"footnoteDefinition",identifier:"",label...
function qU (line 189) | function qU(t){const e=this.resume(),n=this.stack[this.stack.length-1];n...
function XU (line 189) | function XU(t){this.exit(t)}
function QU (line 189) | function QU(t){const e=this.resume(),n=this.stack[this.stack.length-1];n...
function ZU (line 189) | function ZU(t){this.exit(t)}
function JU (line 189) | function JU(){return"["}
function Nk (line 189) | function Nk(t,e,n,r){const i=n.createTracker(r);let s=i.move("[^");const...
function eH (line 189) | function eH(){return{enter:{gfmFootnoteCallString:VU,gfmFootnoteCall:GU,...
function tH (line 189) | function tH(t){let e=!1;return t&&t.firstLineBlank&&(e=!0),{handlers:{fo...
function nH (line 190) | function nH(t,e,n){return e===0?t:Rk(t,e,n)}
function Rk (line 190) | function Rk(t,e,n){return(n?"":" ")+t}
function iH (line 190) | function iH(){return{canContainEols:["delete"],enter:{strikethrough:oH},...
function sH (line 190) | function sH(){return{unsafe:[{character:"~",inConstruct:"phrasing",notIn...
function oH (line 190) | function oH(t){this.enter({type:"delete",children:[]},t)}
function aH (line 190) | function aH(t){this.exit(t)}
function Ik (line 190) | function Ik(t,e,n,r){const i=n.createTracker(r),s=n.enter("strikethrough...
function lH (line 190) | function lH(){return"~"}
function uH (line 190) | function uH(t){return t.length}
function cH (line 190) | function cH(t,e){const n=e||{},r=(n.align||[]).concat(),i=n.stringLength...
function dH (line 191) | function dH(t){return t==null?"":String(t)}
function qw (line 191) | function qw(t){const e=typeof t=="string"?t.codePointAt(0):0;return e===...
function Ok (line 191) | function Ok(t,e){const n=e||{};function r(i,...s){let o=r.invalid;const ...
function fH (line 191) | function fH(t,e,n,r){const i=n.enter("blockquote"),s=n.createTracker(r);...
function hH (line 191) | function hH(t,e,n){return">"+(n?"":" ")+t}
function pH (line 191) | function pH(t,e){return Qw(t,e.inConstruct,!0)&&!Qw(t,e.notInConstruct,!1)}
function Qw (line 191) | function Qw(t,e,n){if(typeof e=="string"&&(e=[e]),!e||e.length===0)retur...
function Zw (line 191) | function Zw(t,e,n,r){let i=-1;for(;++i<n.unsafe.length;)if(n.unsafe[i].c...
function mH (line 193) | function mH(t,e){const n=String(t);let r=n.indexOf(e),i=r,s=0,o=0;if(typ...
function gH (line 193) | function gH(t,e){return!!(e.options.fences===!1&&t.value&&!t.lang&&/[^ \...
function bH (line 193) | function bH(t){const e=t.options.fence||"`";if(e!=="`"&&e!=="~")throw ne...
function EH (line 193) | function EH(t,e,n,r){const i=bH(n),s=t.value||"",o=i==="`"?"GraveAccent"...
function yH (line 196) | function yH(t,e,n){return(n?"":" ")+t}
function t1 (line 196) | function t1(t){const e=t.options.quote||'"';if(e!=='"'&&e!=="'")throw ne...
function xH (line 196) | function xH(t,e,n,r){const i=t1(n),s=i==='"'?"Quote":"Apostrophe",o=n.en...
function vH (line 197) | function vH(t){const e=t.options.emphasis||"*";if(e!=="*"&&e!=="_")throw...
function pc (line 197) | function pc(t){return"&#x"+t.toString(16).toUpperCase()+";"}
function dh (line 197) | function dh(t,e,n){const r=bl(t),i=bl(e);return r===void 0?i===void 0?n=...
function Mk (line 197) | function Mk(t,e,n,r){const i=vH(n),s=n.enter("emphasis"),o=n.createTrack...
function wH (line 197) | function wH(t,e,n){return n.options.emphasis||"*"}
function TH (line 197) | function TH(t,e){let n=!1;return Pc(t,function(r){if("value"in r&&/\r?\n...
function SH (line 197) | function SH(t,e,n,r){const i=Math.max(Math.min(6,t.depth||1),1),s=n.crea...
function Dk (line 202) | function Dk(t){return t.value||""}
function _H (line 202) | function _H(){return"<"}
function Lk (line 202) | function Lk(t,e,n,r){const i=t1(n),s=i==='"'?"Quote":"Apostrophe",o=n.en...
function CH (line 202) | function CH(){return"!"}
function Pk (line 202) | function Pk(t,e,n,r){const i=t.referenceType,s=n.enter("imageReference")...
function AH (line 202) | function AH(){return"!"}
function Fk (line 202) | function Fk(t,e,n){let r=t.value||"",i="`",s=-1;for(;new RegExp("(^|[^`]...
function kH (line 202) | function kH(){return"`"}
function Bk (line 202) | function Bk(t,e){const n=KE(t);return!!(!e.options.resourceLink&&t.url&&...
function Uk (line 202) | function Uk(t,e,n,r){const i=t1(n),s=i==='"'?"Quote":"Apostrophe",o=n.cr...
function NH (line 202) | function NH(t,e,n){return Bk(t,n)?"<":"["}
function Hk (line 202) | function Hk(t,e,n,r){const i=t.referenceType,s=n.enter("linkReference");...
function RH (line 202) | function RH(){return"["}
function n1 (line 202) | function n1(t){const e=t.options.bullet||"*";if(e!=="*"&&e!=="+"&&e!=="-...
function IH (line 202) | function IH(t){const e=n1(t),n=t.options.bulletOther;if(!n)return e==="*...
function OH (line 202) | function OH(t){const e=t.options.bulletOrdered||".";if(e!=="."&&e!==")")...
function zk (line 202) | function zk(t){const e=t.options.rule||"*";if(e!=="*"&&e!=="-"&&e!=="_")...
function MH (line 202) | function MH(t,e,n,r){const i=n.enter("list"),s=n.bulletCurrent;let o=t.o...
function DH (line 202) | function DH(t){const e=t.options.listItemIndent||"one";if(e!=="tab"&&e!=...
function LH (line 202) | function LH(t,e,n,r){const i=DH(n);let s=n.bulletCurrent||n1(n);e&&e.typ...
function PH (line 202) | function PH(t,e,n,r){const i=n.enter("paragraph"),s=n.enter("phrasing"),...
function BH (line 202) | function BH(t,e,n,r){return(t.children.some(function(o){return FH(o)})?n...
function UH (line 202) | function UH(t){const e=t.options.strong||"*";if(e!=="*"&&e!=="_")throw n...
function jk (line 202) | function jk(t,e,n,r){const i=UH(n),s=n.enter("strong"),o=n.createTracker...
function HH (line 202) | function HH(t,e,n){return n.options.strong||"*"}
function zH (line 202) | function zH(t,e,n,r){return n.safe(t.value,r)}
function jH (line 202) | function jH(t){const e=t.options.ruleRepetition||3;if(e<3)throw new Erro...
function $H (line 202) | function $H(t,e,n){const r=(zk(n)+(n.options.ruleSpaces?" ":"")).repeat(...
function WH (line 202) | function WH(){return{enter:{table:VH,tableData:Jw,tableHeader:Jw,tableRo...
function VH (line 202) | function VH(t){const e=t._align;this.enter({type:"table",align:e.map(fun...
function GH (line 202) | function GH(t){this.exit(t),this.data.inTable=void 0}
function KH (line 202) | function KH(t){this.enter({type:"tableRow",children:[]},t)}
function Zg (line 202) | function Zg(t){this.exit(t)}
function Jw (line 202) | function Jw(t){this.enter({type:"tableCell",children:[]},t)}
function YH (line 202) | function YH(t){let e=this.resume();this.data.inTable&&(e=e.replace(/\\([...
function qH (line 202) | function qH(t,e){return e==="|"?e:t}
function XH (line 202) | function XH(t){const e=t||{},n=e.tableCellPadding,r=e.tablePipeAlign,i=e...
function QH (line 204) | function QH(){return{exit:{taskListCheckValueChecked:eT,taskListCheckVal...
function ZH (line 204) | function ZH(){return{unsafe:[{atBreak:!0,character:"-",after:"[:|-]"}],h...
function eT (line 204) | function eT(t){const e=this.stack[this.stack.length-2];e.type,e.checked=...
function JH (line 204) | function JH(t){const e=this.stack[this.stack.length-2];if(e&&e.type==="l...
function ez (line 204) | function ez(t,e,n,r){const i=t.children[0],s=typeof t.checked=="boolean"...
function tz (line 204) | function tz(){return[MU(),eH(),iH(),WH(),QH()]}
function nz (line 204) | function nz(t){return{extensions:[DU(),tH(t),sH(),XH(t),ZH()]}}
function sz (line 204) | function sz(){return{text:es}}
function oz (line 204) | function oz(t,e,n){const r=this;let i,s;return o;function o(p){return!tb...
function az (line 204) | function az(t,e,n){const r=this;return i;function i(o){return o!==87&&o!...
function lz (line 204) | function lz(t,e,n){const r=this;let i="",s=!1;return o;function o(p){ret...
function uz (line 204) | function uz(t,e,n){let r=0;return i;function i(o){return(o===87||o===119...
function cz (line 204) | function cz(t,e,n){let r,i,s;return o;function o(d){return d===46||d===9...
function dz (line 204) | function dz(t,e){let n=0,r=0;return i;function i(o){return o===40?(n++,t...
function fz (line 204) | function fz(t,e,n){return r;function r(l){return l===33||l===34||l===39|...
function hz (line 204) | function hz(t,e,n){return r;function r(s){return t.consume(s),i}function...
function qk (line 204) | function qk(t){return t===null||t===40||t===42||t===95||t===91||t===93||...
function Xk (line 204) | function Xk(t){return!Er(t)}
function Qk (line 204) | function Qk(t){return!(t===47||tb(t))}
function tb (line 204) | function tb(t){return t===43||t===45||t===46||t===95||sr(t)}
function r1 (line 204) | function r1(t){let e=t.length,n=!1;for(;e--;){const r=t[e][1];if((r.type...
function mz (line 204) | function mz(){return{document:{91:{name:"gfmFootnoteDefinition",tokenize...
function gz (line 204) | function gz(t,e,n){const r=this;let i=r.events.length;const s=r.parser.g...
function bz (line 204) | function bz(t,e){let n=t.length;for(;n--;)if(t[n][1].type==="labelImage"...
function Ez (line 204) | function Ez(t,e,n){const r=this,i=r.parser.gfmFootnotes||(r.parser.gfmFo...
function yz (line 204) | function yz(t,e,n){const r=this,i=r.parser.gfmFootnotes||(r.parser.gfmFo...
function xz (line 204) | function xz(t,e,n){return t.check(Dc,e,t.attempt(pz,e,n))}
function vz (line 204) | function vz(t){t.exit("gfmFootnoteDefinition")}
function wz (line 204) | function wz(t,e,n){const r=this;return Nt(t,i,"gfmFootnoteDefinitionInde...
function Tz (line 204) | function Tz(t){let n=(t||{}).singleTilde;const r={name:"strikethrough",t...
class Sz (line 204) | class Sz{constructor(){this.map=[]}add(e,n,r){_z(this,e,n,r)}consume(e){...
method constructor (line 204) | constructor(){this.map=[]}
method add (line 204) | add(e,n,r){_z(this,e,n,r)}
method consume (line 204) | consume(e){if(this.map.sort(function(s,o){return s[0]-o[0]}),this.map....
function _z (line 204) | function _z(t,e,n,r){let i=0;if(!(n===0&&r.length===0)){for(;i<t.map.len...
function Cz (line 204) | function Cz(t,e){let n=!1;const r=[];for(;e<t.length;){const i=t[e];if(n...
function Az (line 204) | function Az(){return{flow:{null:{name:"table",tokenize:kz,resolveAll:Nz}}}}
function kz (line 204) | function kz(t,e,n){const r=this;let i=0,s=0,o;return l;function l(P){let...
function Nz (line 204) | function Nz(t,e){let n=-1,r=!0,i=0,s=[0,0,0,0],o=[0,0,0,0],l=!1,c=0,d,f,...
function df (line 204) | function df(t,e,n,r,i,s){const o=r===1?"tableHeader":r===2?"tableDelimit...
function tT (line 204) | function tT(t,e,n,r,i){const s=[],o=Va(e.events,n);i&&(i.end=Object.assi...
function Va (line 204) | function Va(t,e){const n=t[e],r=n[0]==="enter"?"start":"end";return n[1]...
function Iz (line 204) | function Iz(){return{text:{91:Rz}}}
function Oz (line 204) | function Oz(t,e,n){const r=this;return i;function i(c){return r.previous...
function Mz (line 204) | function Mz(t,e,n){return Nt(t,r,"whitespace");function r(i){return i===...
function Dz (line 204) | function Dz(t){return ak([sz(),mz(),Tz(t),Az(),Iz()])}
function Pz (line 204) | function Pz(t){const e=this,n=t||Lz,r=e.data(),i=r.micromarkExtensions||...
function Fz (line 204) | function Fz(t){const e=[];let n=-1;for(;++n<t.length;)e[n]=la(t[n]);retu...
function Bz (line 204) | function Bz(t){return i1(e);function e(n){return n.tagName===t}}
function i1 (line 204) | function i1(t){return e;function e(n,r,i){return!!(Hz(n)&&t.call(this,n,...
function Uz (line 204) | function Uz(t){return!!(t&&typeof t=="object"&&"type"in t&&t.type==="ele...
function Hz (line 204) | function Hz(t){return t!==null&&typeof t=="object"&&"type"in t&&"tagName...
function $z (line 204) | function $z(t,e){const n=e||{},r="children"in t?t.children:[],i=Zk(t),s=...
function Jk (line 205) | function Jk(t,e,n){return t.type==="element"?Wz(t,e,n):t.type==="text"?n...
function Wz (line 205) | function Wz(t,e,n){const r=tN(t,n),i=t.children||[];let s=-1,o=[];if(jz(...
function eN (line 206) | function eN(t,e){const n=String(t.value),r=[],i=[];let s=0;for(;s<=n.len...
function Vz (line 206) | function Vz(t){return[String(t.value)]}
function Gz (line 206) | function Gz(t,e,n){const r=[];let i=0,s;for(;i<t.length;){iT.lastIndex=i...
function tN (line 206) | function tN(t,e){if(t.type==="element"){const n=t.properties||{};switch(...
function Kz (line 206) | function Kz(t){return!!(t.properties||{}).hidden}
function Yz (line 206) | function Yz(t){return t.tagName==="td"||t.tagName==="th"}
function qz (line 206) | function qz(t){return t.tagName==="dialog"&&!(t.properties||{}).open}
function Xz (line 206) | function Xz(t){const e=t.regex,n=t.COMMENT("//","$",{contains:[{begin:/\...
function Qz (line 206) | function Qz(t){const e={type:["boolean","byte","word","String"],built_in...
function Zz (line 206) | function Zz(t){const e=t.regex,n={},r={begin:/\$\{/,end:/\}/,contains:["...
function Jz (line 206) | function Jz(t){const e=t.regex,n=t.COMMENT("//","$",{contains:[{begin:/\...
function e7 (line 206) | function e7(t){const e=t.regex,n=t.COMMENT("//","$",{contains:[{begin:/\...
function t7 (line 206) | function t7(t){const e=["bool","byte","char","decimal","delegate","doubl...
function c7 (line 206) | function c7(t){const e=t.regex,n=n7(t),r={begin:/-(webkit|moz|ms|o)-(?=[...
function d7 (line 206) | function d7(t){const e=t.regex;return{name:"Diff",aliases:["patch"],cont...
function f7 (line 206) | function f7(t){const s={keyword:["break","case","chan","const","continue...
function h7 (line 206) | function h7(t){const e=t.regex,n=/[_A-Za-z][_0-9A-Za-z]*/;return{name:"G...
function p7 (line 206) | function p7(t){const e=t.regex,n={className:"number",relevance:0,variant...
function nN (line 206) | function nN(t,e,n){return n===-1?"":t.replace(e,r=>nN(t,e,n-1))}
function m7 (line 206) | function m7(t){const e=t.regex,n="[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*",r=n+nN...
function x7 (line 206) | function x7(t){const e=t.regex,n=(j,{after:W})=>{const O="</"+j[0].slice...
function v7 (line 206) | function v7(t){const e={className:"attr",begin:/"(\\.|[^\\"\r\n])*"(?=\s...
function T7 (line 206) | function T7(t){const e={keyword:"abstract as val var vararg get set clas...
function I7 (line 207) | function I7(t){const e=S7(t),n=R7,r="and or not only",i="[\\w-]+",s="("+...
function O7 (line 207) | function O7(t){const e="\\[=*\\[",n="\\]=*\\]",r={begin:e,end:n,contains...
function M7 (line 207) | function M7(t){const e={className:"variable",variants:[{begin:"\\$\\("+t...
function D7 (line 207) | function D7(t){const e=t.regex,n={begin:/<\/?[A-Za-z_]/,end:">",subLangu...
function L7 (line 207) | function L7(t){const e={className:"built_in",begin:"\\b(AV|CA|CF|CG|CI|C...
function P7 (line 207) | function P7(t){const e=t.regex,n=["abs","accept","alarm","and","atan2","...
function F7 (line 207) | function F7(t){const e=t.regex,n=/(?![A-Za-z0-9])(?![$])/,r=e.concat(/[a...
function B7 (line 208) | function B7(t){return{name:"PHP template",subLanguage:"xml",contains:[{b...
function U7 (line 208) | function U7(t){return{name:"Plain text",aliases:["text","txt"],disableAu...
function H7 (line 208) | function H7(t){const e=t.regex,n=new RegExp("[\\p{XID_Start}_]\\p{XID_Co...
function z7 (line 208) | function z7(t){return{aliases:["pycon"],contains:[{className:"meta.promp...
function j7 (line 208) | function j7(t){const e=t.regex,n=/(?:(?:[a-zA-Z]|\.[._a-zA-Z])[._a-zA-Z0...
function $7 (line 208) | function $7(t){const e=t.regex,n="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|=...
function W7 (line 208) | function W7(t){const e=t.regex,n=/(r#)?/,r=e.concat(n,t.UNDERSCORE_IDENT...
function J7 (line 208) | function J7(t){const e=V7(t),n=Q7,r=X7,i="@[a-z-]+",s="and or not only",...
function ej (line 208) | function ej(t){return{name:"Shell Session",aliases:["console","shellsess...
function tj (line 208) | function tj(t){const e=t.regex,n=t.COMMENT("--","$"),r={scope:"string",v...
function lN (line 208) | function lN(t){return t?typeof t=="string"?t:t.source:null}
function Ou (line 208) | function Ou(t){return zt("(?=",t,")")}
function zt (line 208) | function zt(...t){return t.map(n=>lN(n)).join("")}
function nj (line 208) | function nj(t){const e=t[t.length-1];return typeof e=="object"&&e.constr...
function br (line 208) | function br(...t){return"("+(nj(t).capture?"":"?:")+t.map(r=>lN(r)).join...
function uj (line 208) | function uj(t){const e={match:/\s+/,relevance:0},n=t.COMMENT("/\\*","\\*...
function cj (line 208) | function cj(t){const e=t.regex,n=(j,{after:W})=>{const O="</"+j[0].slice...
function dj (line 208) | function dj(t){const e=t.regex,n=cj(t),r=hh,i=["any","void","number","bo...
function fj (line 208) | function fj(t){const e=t.regex,n={className:"string",begin:/"(""|[^/n])"...
function hj (line 208) | function hj(t){t.regex;const e=t.COMMENT(/\(;/,/;\)/);e.contains.push("s...
function pj (line 208) | function pj(t){const e=t.regex,n=e.concat(/[\p{L}_]/u,e.optional(/[\p{L}...
function mj (line 208) | function mj(t){const e="true false yes no null",n="[\\w#;/?:@&=+$,.~*'()...
function bj (line 208) | function bj(){if(fT)return t0;fT=1;function t(V){return V instanceof Map...
function vj (line 210) | function vj(t){const e=yj.newInstance();return t&&s(t),{highlight:n,high...
class wj (line 210) | class wj{constructor(e){this.options=e,this.root={type:"root",children:[...
method constructor (line 210) | constructor(e){this.options=e,this.root={type:"root",children:[],data:...
method addText (line 210) | addText(e){if(e==="")return;const n=this.stack[this.stack.length-1],r=...
method startScope (line 210) | startScope(e){this.openNode(String(e))}
method endScope (line 210) | endScope(){this.closeNode()}
method __addSublanguage (line 210) | __addSublanguage(e,n){const r=this.stack[this.stack.length-1],i=e.root...
method openNode (line 210) | openNode(e){const n=this,r=e.split(".").map(function(o,l){return l?o+"...
method closeNode (line 210) | closeNode(){this.stack.pop()}
method finalize (line 210) | finalize(){}
method toHTML (line 210) | toHTML(){return""}
function Sj (line 210) | function Sj(t){const e=t||Tj,n=e.aliases,r=e.detect||!1,i=e.languages||g...
function _j (line 210) | function _j(t){const e=t.properties.className;let n=-1;if(!Array.isArray...
function Cj (line 210) | function Cj(t,e){const n=t||"",r={};let i=0,s,o;for(;i<n.length;){pT.las...
function yN (line 210) | function yN(t,e,n){const r=n?Rj(n):void 0;function i(s,o,...l){let c;if(...
function Aj (line 210) | function Aj(t){if(t===null||typeof t!="object"||Array.isArray(t))return!...
function kj (line 210) | function kj(t,e,n,r){const i=$E(t,n);let s;if(r!=null){if(typeof r=="num...
function rb (line 210) | function rb(t,e){if(e!=null)if(typeof e=="number"||typeof e=="string")t....
function mT (line 210) | function mT(t,e,n){if(typeof n=="string"){if(t.number&&n&&!Number.isNaN(...
function Nj (line 210) | function Nj(t){const e=[];for(const[n,r]of Object.entries(t))e.push([n,r...
function Rj (line 210) | function Rj(t){const e=new Map;for(const n of t)e.set(n.toLowerCase(),n)...
function Dj (line 210) | function Dj(t){const e=String(t),n=[];return{toOffset:i,toPoint:r};funct...
function gT (line 210) | function gT(t,e){const n=t.indexOf("\r",e),r=t.indexOf(`
function Pj (line 211) | function Pj(t,e){const n=e||{};return o1({file:n.file||void 0,location:!...
function o1 (line 211) | function o1(t,e){let n;switch(e.nodeName){case"#comment":{const r=e;retu...
function vN (line 211) | function vN(t,e){let n=-1;const r=[];for(;++n<e.length;){const i=o1(t,e[...
function Fj (line 211) | function Fj(t,e){const n=t.schema;t.schema=e.namespaceURI===Ho.svg?Ml:sp...
function Uf (line 211) | function Uf(t,e,n){if("sourceCodeLocation"in e&&e.sourceCodeLocation&&t....
function Bj (line 211) | function Bj(t,e,n){const r=Za(n);if(e.type==="element"){const i=e.childr...
function Za (line 211) | function Za(t){const e=bT({line:t.startLine,column:t.startCol,offset:t.s...
function bT (line 211) | function bT(t){return t.line&&t.column?t:void 0}
class Bc (line 211) | class Bc{constructor(e,n,r){this.property=e,this.normal=n,r&&(this.space...
method constructor (line 211) | constructor(e,n,r){this.property=e,this.normal=n,r&&(this.space=r)}
function wN (line 211) | function wN(t,e){const n={},r={};let i=-1;for(;++i<t.length;)Object.assi...
function ib (line 211) | function ib(t){return t.toLowerCase()}
class ai (line 211) | class ai{constructor(e,n){this.property=e,this.attribute=n}}
method constructor (line 211) | constructor(e,n){this.property=e,this.attribute=n}
function ua (line 211) | function ua(){return 2**++Uj}
class a1 (line 211) | class a1 extends ai{constructor(e,n,r,i){let s=-1;if(super(e,n),ET(this,...
method constructor (line 211) | constructor(e,n,r,i){let s=-1;if(super(e,n),ET(this,"space",i),typeof ...
function ET (line 211) | function ET(t,e,n){n&&(t[e]=n)}
function Ll (line 211) | function Ll(t){const e={},n={};let r;for(r in t.properties)if(Hj.call(t....
method transform (line 211) | transform(t,e){return"xlink:"+e.slice(5).toLowerCase()}
method transform (line 211) | transform(t,e){return"xml:"+e.slice(3).toLowerCase()}
function CN (line 211) | function CN(t,e){return e in t?t[e]:e}
function AN (line 211) | function AN(t,e){return CN(t,e.toLowerCase())}
method transform (line 211) | transform(t,e){return e==="role"?e:"aria-"+e.slice(4).toLowerCase()}
function Vj (line 211) | function Vj(t,e){const n=ib(e);let r=e,i=ai;if(n in t.normal)return t.pr...
function Gj (line 211) | function Gj(t){return"-"+t.toLowerCase()}
function Kj (line 211) | function Kj(t){return t.charAt(1).toUpperCase()}
function Qj (line 211) | function Qj(t,e){const r=(e||qj).space;return IN(t,r==="svg"?RN:Yj)}
function Zj (line 211) | function Zj(t,e){const n={nodeName:"#document",mode:(t.data||{}).quirksM...
function Jj (line 211) | function Jj(t,e){const n={nodeName:"#document-fragment",childNodes:[]};r...
function e$ (line 211) | function e$(t){const e={nodeName:"#documentType",name:"html",publicId:""...
function t$ (line 211) | function t$(t){const e={nodeName:"#text",value:t.value,parentNode:null};...
function n$ (line 211) | function n$(t){const e={nodeName:"#comment",data:t.value,parentNode:null...
function r$ (line 211) | function r$(t,e){const n=e;let r=n;t.type==="element"&&t.tagName.toLower...
function i$ (line 211) | function i$(t,e,n){const r=Vj(t,e);if(n===!1||n===null||n===void 0||type...
function l1 (line 211) | function l1(t,e,n){let r=-1;const i=[];if(t)for(;++r<t.length;){const s=...
function Pl (line 211) | function Pl(t,e){const n=t.position;n&&n.start&&n.end&&(n.start.offset,n...
function ON (line 211) | function ON(t){return t>=55296&&t<=57343}
function a$ (line 211) | function a$(t){return t>=56320&&t<=57343}
function l$ (line 211) | function l$(t,e){return(t-55296)*1024+9216+e}
function MN (line 211) | function MN(t){return t!==32&&t!==10&&t!==13&&t!==9&&t!==12&&t>=1&&t<=31...
function DN (line 211) | function DN(t){return t>=64976&&t<=65007||o$.has(t)}
class c$ (line 211) | class c${constructor(e){this.handler=e,this.html="",this.pos=-1,this.las...
method constructor (line 211) | constructor(e){this.handler=e,this.html="",this.pos=-1,this.lastGapPos...
method col (line 211) | get col(){return this.pos-this.lineStartPos+ +(this.lastGapPos!==this....
method offset (line 211) | get offset(){return this.droppedBufferSize+this.pos}
method getError (line 211) | getError(e,n){const{line:r,col:i,offset:s}=this,o=i+n,l=s+n;return{cod...
method _err (line 211) | _err(e){this.handler.onParseError&&this.lastErrOffset!==this.offset&&(...
method _addGap (line 211) | _addGap(){this.gapStack.push(this.lastGapPos),this.lastGapPos=this.pos}
method _processSurrogate (line 211) | _processSurrogate(e){if(this.pos!==this.html.length-1){const n=this.ht...
method willDropParsedChunk (line 211) | willDropParsedChunk(){return this.pos>this.bufferWaterline}
method dropParsedChunk (line 211) | dropParsedChunk(){this.willDropParsedChunk()&&(this.html=this.html.sub...
method write (line 211) | write(e,n){this.html.length>0?this.html+=e:this.html=e,this.endOfChunk...
method insertHtmlAtCurrentPos (line 211) | insertHtmlAtCurrentPos(e){this.html=this.html.substring(0,this.pos+1)+...
method startsWith (line 211) | startsWith(e,n){if(this.pos+e.length>this.html.length)return this.endO...
method peek (line 211) | peek(e){const n=this.pos+e;if(n>=this.html.length)return this.endOfChu...
method advance (line 211) | advance(){if(this.pos++,this.isEol&&(this.isEol=!1,this.line++,this.li...
method _checkForProblematicCharacters (line 211) | _checkForProblematicCharacters(e){MN(e)?this._err(fe.controlCharacterI...
method retreat (line 211) | retreat(e){for(this.pos-=e;this.pos<this.lastGapPos;)this.lastGapPos=t...
function LN (line 211) | function LN(t,e){for(let n=t.attrs.length-1;n>=0;n--)if(t.attrs[n].name=...
function h$ (line 211) | function h$(t){var e;return t>=55296&&t<=57343||t>1114111?65533:(e=f$.ge...
function ob (line 211) | function ob(t){return t>=Wn.ZERO&&t<=Wn.NINE}
function m$ (line 211) | function m$(t){return t>=Wn.UPPER_A&&t<=Wn.UPPER_F||t>=Wn.LOWER_A&&t<=Wn...
function g$ (line 211) | function g$(t){return t>=Wn.UPPER_A&&t<=Wn.UPPER_Z||t>=Wn.LOWER_A&&t<=Wn...
function b$ (line 211) | function b$(t){return t===Wn.EQUALS||g$(t)}
class E$ (line 211) | class E${constructor(e,n,r){this.decodeTree=e,this.emitCodePoint=n,this....
method constructor (line 211) | constructor(e,n,r){this.decodeTree=e,this.emitCodePoint=n,this.errors=...
method startEntity (line 211) | startEntity(e){this.decodeMode=e,this.state=jn.EntityStart,this.result...
method write (line 211) | write(e,n){switch(this.state){case jn.EntityStart:return e.charCodeAt(...
method stateNumericStart (line 211) | stateNumericStart(e,n){return n>=e.length?-1:(e.charCodeAt(n)|p$)===Wn...
method addToNumericResult (line 211) | addToNumericResult(e,n,r,i){if(n!==r){const s=r-n;this.result=this.res...
method stateNumericHex (line 211) | stateNumericHex(e,n){const r=n;for(;n<e.length;){const i=e.charCodeAt(...
method stateNumericDecimal (line 211) | stateNumericDecimal(e,n){const r=n;for(;n<e.length;){const i=e.charCod...
method emitNumericEntity (line 211) | emitNumericEntity(e,n){var r;if(this.consumed<=n)return(r=this.errors)...
method stateNamedEntity (line 211) | stateNamedEntity(e,n){const{decodeTree:r}=this;let i=r[this.treeIndex]...
method emitNotTerminatedNamedEntity (line 211) | emitNotTerminatedNamedEntity(){var e;const{result:n,decodeTree:r}=this...
method emitNamedEntityData (line 211) | emitNamedEntityData(e,n,r){const{decodeTree:i}=this;return this.emitCo...
method end (line 211) | end(){var e;switch(this.state){case jn.NamedEntity:return this.result!...
function y$ (line 211) | function y$(t,e,n,r){const i=(e&ro.BRANCH_LENGTH)>>7,s=e&ro.JUMP_TABLE;i...
function Fl (line 211) | function Fl(t){var e;return(e=x$.get(t))!==null&&e!==void 0?e:E.UNKNOWN}
function w$ (line 211) | function w$(t){return t>=L.DIGIT_0&&t<=L.DIGIT_9}
function Uu (line 211) | function Uu(t){return t>=L.LATIN_CAPITAL_A&&t<=L.LATIN_CAPITAL_Z}
function T$ (line 211) | function T$(t){return t>=L.LATIN_SMALL_A&&t<=L.LATIN_SMALL_Z}
function Js (line 211) | function Js(t){return T$(t)||Uu(t)}
function xT (line 211) | function xT(t){return Js(t)||w$(t)}
function bf (line 211) | function bf(t){return t+32}
function PN (line 211) | function PN(t){return t===L.SPACE||t===L.LINE_FEED||t===L.TABULATION||t=...
function vT (line 211) | function vT(t){return PN(t)||t===L.SOLIDUS||t===L.GREATER_THAN_SIGN}
function S$ (line 211) | function S$(t){return t===L.NULL?fe.nullCharacterReference:t>1114111?fe....
class _$ (line 211) | class _${constructor(e,n){this.options=e,this.handler=n,this.paused=!1,t...
method constructor (line 211) | constructor(e,n){this.options=e,this.handler=n,this.paused=!1,this.inL...
method _err (line 211) | _err(e,n=0){var r,i;(i=(r=this.handler).onParseError)===null||i===void...
method getCurrentLocation (line 211) | getCurrentLocation(e){return this.options.sourceCodeLocationInfo?{star...
method _runParsingLoop (line 211) | _runParsingLoop(){if(!this.inLoop){for(this.inLoop=!0;this.active&&!th...
method pause (line 211) | pause(){this.paused=!0}
method resume (line 211) | resume(e){if(!this.paused)throw new Error("Parser was already resumed"...
method write (line 211) | write(e,n,r){this.active=!0,this.preprocessor.write(e,n),this._runPars...
method insertHtmlAtCurrentPos (line 211) | insertHtmlAtCurrentPos(e){this.active=!0,this.preprocessor.insertHtmlA...
method _ensureHibernation (line 211) | _ensureHibernation(){return this.preprocessor.endOfChunkHit?(this.prep...
method _consume (line 211) | _consume(){return this.consumedAfterSnapshot++,this.preprocessor.advan...
method _advanceBy (line 211) | _advanceBy(e){this.consumedAfterSnapshot+=e;for(let n=0;n<e;n++)this.p...
method _consumeSequenceIfMatch (line 211) | _consumeSequenceIfMatch(e,n){return this.preprocessor.startsWith(e,n)?...
method _createStartTagToken (line 211) | _createStartTagToken(){this.currentToken={type:yt.START_TAG,tagName:""...
method _createEndTagToken (line 211) | _createEndTagToken(){this.currentToken={type:yt.END_TAG,tagName:"",tag...
method _createCommentToken (line 211) | _createCommentToken(e){this.currentToken={type:yt.COMMENT,data:"",loca...
method _createDoctypeToken (line 211) | _createDoctypeToken(e){this.currentToken={type:yt.DOCTYPE,name:e,force...
method _createCharacterToken (line 211) | _createCharacterToken(e,n){this.currentCharacterToken={type:e,chars:n,...
method _createAttr (line 211) | _createAttr(e){this.currentAttr={name:e,value:""},this.currentLocation...
method _leaveAttrName (line 211) | _leaveAttrName(){var e,n;const r=this.currentToken;if(LN(r,this.curren...
method _leaveAttrValue (line 211) | _leaveAttrValue(){this.currentLocation&&(this.currentLocation.endLine=...
method prepareToken (line 211) | prepareToken(e){this._emitCurrentCharacterToken(e.location),this.curre...
method emitCurrentTagToken (line 211) | emitCurrentTagToken(){const e=this.currentToken;this.prepareToken(e),e...
method emitCurrentComment (line 211) | emitCurrentComment(e){this.prepareToken(e),this.handler.onComment(e),t...
method emitCurrentDoctype (line 211) | emitCurrentDoctype(e){this.prepareToken(e),this.handler.onDoctype(e),t...
method _emitCurrentCharacterToken (line 211) | _emitCurrentCharacterToken(e){if(this.currentCharacterToken){switch(e&...
method _emitEOFToken (line 211) | _emitEOFToken(){const e=this.getCurrentLocation(0);e&&(e.endLine=e.sta...
method _appendCharToCurrentCharacterToken (line 211) | _appendCharToCurrentCharacterToken(e,n){if(this.currentCharacterToken)...
method _emitCodePoint (line 211) | _emitCodePoint(e){const n=PN(e)?yt.WHITESPACE_CHARACTER:e===L.NULL?yt....
method _emitChars (line 211) | _emitChars(e){this._appendCharToCurrentCharacterToken(yt.CHARACTER,e)}
method _startCharacterReference (line 211) | _startCharacterReference(){this.returnState=this.state,this.state=B.CH...
method _isCharacterReferenceInAttribute (line 211) | _isCharacterReferenceInAttribute(){return this.returnState===B.ATTRIBU...
method _flushCodePointConsumedAsCharacterReference (line 211) | _flushCodePointConsumedAsCharacterReference(e){this._isCharacterRefere...
method _callState (line 211) | _callState(e){switch(this.state){case B.DATA:{this._stateData(e);break...
method _stateData (line 211) | _stateData(e){switch(e){case L.LESS_THAN_SIGN:{this.state=B.TAG_OPEN;b...
method _stateRcdata (line 211) | _stateRcdata(e){switch(e){case L.AMPERSAND:{this._startCharacterRefere...
method _stateRawtext (line 211) | _stateRawtext(e){switch(e){case L.LESS_THAN_SIGN:{this.state=B.RAWTEXT...
method _stateScriptData (line 211) | _stateScriptData(e){switch(e){case L.LESS_THAN_SIGN:{this.state=B.SCRI...
method _statePlaintext (line 211) | _statePlaintext(e){switch(e){case L.NULL:{this._err(fe.unexpectedNullC...
method _stateTagOpen (line 211) | _stateTagOpen(e){if(Js(e))this._createStartTagToken(),this.state=B.TAG...
method _stateEndTagOpen (line 211) | _stateEndTagOpen(e){if(Js(e))this._createEndTagToken(),this.state=B.TA...
method _stateTagName (line 211) | _stateTagName(e){const n=this.currentToken;switch(e){case L.SPACE:case...
method _stateRcdataLessThanSign (line 211) | _stateRcdataLessThanSign(e){e===L.SOLIDUS?this.state=B.RCDATA_END_TAG_...
method _stateRcdataEndTagOpen (line 211) | _stateRcdataEndTagOpen(e){Js(e)?(this.state=B.RCDATA_END_TAG_NAME,this...
method handleSpecialEndTag (line 211) | handleSpecialEndTag(e){if(!this.preprocessor.startsWith(this.lastStart...
method _stateRcdataEndTagName (line 211) | _stateRcdataEndTagName(e){this.handleSpecialEndTag(e)&&(this._emitChar...
method _stateRawtextLessThanSign (line 211) | _stateRawtextLessThanSign(e){e===L.SOLIDUS?this.state=B.RAWTEXT_END_TA...
method _stateRawtextEndTagOpen (line 211) | _stateRawtextEndTagOpen(e){Js(e)?(this.state=B.RAWTEXT_END_TAG_NAME,th...
method _stateRawtextEndTagName (line 211) | _stateRawtextEndTagName(e){this.handleSpecialEndTag(e)&&(this._emitCha...
method _stateScriptDataLessThanSign (line 211) | _stateScriptDataLessThanSign(e){switch(e){case L.SOLIDUS:{this.state=B...
method _stateScriptDataEndTagOpen (line 211) | _stateScriptDataEndTagOpen(e){Js(e)?(this.state=B.SCRIPT_DATA_END_TAG_...
method _stateScriptDataEndTagName (line 211) | _stateScriptDataEndTagName(e){this.handleSpecialEndTag(e)&&(this._emit...
method _stateScriptDataEscapeStart (line 211) | _stateScriptDataEscapeStart(e){e===L.HYPHEN_MINUS?(this.state=B.SCRIPT...
method _stateScriptDataEscapeStartDash (line 211) | _stateScriptDataEscapeStartDash(e){e===L.HYPHEN_MINUS?(this.state=B.SC...
method _stateScriptDataEscaped (line 211) | _stateScriptDataEscaped(e){switch(e){case L.HYPHEN_MINUS:{this.state=B...
method _stateScriptDataEscapedDash (line 211) | _stateScriptDataEscapedDash(e){switch(e){case L.HYPHEN_MINUS:{this.sta...
method _stateScriptDataEscapedDashDash (line 211) | _stateScriptDataEscapedDashDash(e){switch(e){case L.HYPHEN_MINUS:{this...
method _stateScriptDataEscapedLessThanSign (line 211) | _stateScriptDataEscapedLessThanSign(e){e===L.SOLIDUS?this.state=B.SCRI...
method _stateScriptDataEscapedEndTagOpen (line 211) | _stateScriptDataEscapedEndTagOpen(e){Js(e)?(this.state=B.SCRIPT_DATA_E...
method _stateScriptDataEscapedEndTagName (line 211) | _stateScriptDataEscapedEndTagName(e){this.handleSpecialEndTag(e)&&(thi...
method _stateScriptDataDoubleEscapeStart (line 211) | _stateScriptDataDoubleEscapeStart(e){if(this.preprocessor.startsWith(A...
method _stateScriptDataDoubleEscaped (line 211) | _stateScriptDataDoubleEscaped(e){switch(e){case L.HYPHEN_MINUS:{this.s...
method _stateScriptDataDoubleEscapedDash (line 211) | _stateScriptDataDoubleEscapedDash(e){switch(e){case L.HYPHEN_MINUS:{th...
method _stateScriptDataDoubleEscapedDashDash (line 211) | _stateScriptDataDoubleEscapedDashDash(e){switch(e){case L.HYPHEN_MINUS...
method _stateScriptDataDoubleEscapedLessThanSign (line 211) | _stateScriptDataDoubleEscapedLessThanSign(e){e===L.SOLIDUS?(this.state...
method _stateScriptDataDoubleEscapeEnd (line 211) | _stateScriptDataDoubleEscapeEnd(e){if(this.preprocessor.startsWith(Ar....
method _stateBeforeAttributeName (line 211) | _stateBeforeAttributeName(e){switch(e){case L.SPACE:case L.LINE_FEED:c...
method _stateAttributeName (line 211) | _stateAttributeName(e){switch(e){case L.SPACE:case L.LINE_FEED:case L....
method _stateAfterAttributeName (line 211) | _stateAfterAttributeName(e){switch(e){case L.SPACE:case L.LINE_FEED:ca...
method _stateBeforeAttributeValue (line 211) | _stateBeforeAttributeValue(e){switch(e){case L.SPACE:case L.LINE_FEED:...
method _stateAttributeValueDoubleQuoted (line 211) | _stateAttributeValueDoubleQuoted(e){switch(e){case L.QUOTATION_MARK:{t...
method _stateAttributeValueSingleQuoted (line 211) | _stateAttributeValueSingleQuoted(e){switch(e){case L.APOSTROPHE:{this....
method _stateAttributeValueUnquoted (line 211) | _stateAttributeValueUnquoted(e){switch(e){case L.SPACE:case L.LINE_FEE...
method _stateAfterAttributeValueQuoted (line 211) | _stateAfterAttributeValueQuoted(e){switch(e){case L.SPACE:case L.LINE_...
method _stateSelfClosingStartTag (line 211) | _stateSelfClosingStartTag(e){switch(e){case L.GREATER_THAN_SIGN:{const...
method _stateBogusComment (line 211) | _stateBogusComment(e){const n=this.currentToken;switch(e){case L.GREAT...
method _stateMarkupDeclarationOpen (line 211) | _stateMarkupDeclarationOpen(e){this._consumeSequenceIfMatch(Ar.DASH_DA...
method _stateCommentStart (line 211) | _stateCommentStart(e){switch(e){case L.HYPHEN_MINUS:{this.state=B.COMM...
method _stateCommentStartDash (line 211) | _stateCommentStartDash(e){const n=this.currentToken;switch(e){case L.H...
method _stateComment (line 211) | _stateComment(e){const n=this.currentToken;switch(e){case L.HYPHEN_MIN...
method _stateCommentLessThanSign (line 211) | _stateCommentLessThanSign(e){const n=this.currentToken;switch(e){case ...
method _stateCommentLessThanSignBang (line 211) | _stateCommentLessThanSignBang(e){e===L.HYPHEN_MINUS?this.state=B.COMME...
method _stateCommentLessThanSignBangDash (line 211) | _stateCommentLessThanSignBangDash(e){e===L.HYPHEN_MINUS?this.state=B.C...
method _stateCommentLessThanSignBangDashDash (line 211) | _stateCommentLessThanSignBangDashDash(e){e!==L.GREATER_THAN_SIGN&&e!==...
method _stateCommentEndDash (line 211) | _stateCommentEndDash(e){const n=this.currentToken;switch(e){case L.HYP...
method _stateCommentEnd (line 211) | _stateCommentEnd(e){const n=this.currentToken;switch(e){case L.GREATER...
method _stateCommentEndBang (line 211) | _stateCommentEndBang(e){const n=this.currentToken;switch(e){case L.HYP...
method _stateDoctype (line 211) | _stateDoctype(e){switch(e){case L.SPACE:case L.LINE_FEED:case L.TABULA...
method _stateBeforeDoctypeName (line 211) | _stateBeforeDoctypeName(e){if(Uu(e))this._createDoctypeToken(String.fr...
method _stateDoctypeName (line 211) | _stateDoctypeName(e){const n=this.currentToken;switch(e){case L.SPACE:...
method _stateAfterDoctypeName (line 211) | _stateAfterDoctypeName(e){const n=this.currentToken;switch(e){case L.S...
method _stateAfterDoctypePublicKeyword (line 211) | _stateAfterDoctypePublicKeyword(e){const n=this.currentToken;switch(e)...
method _stateBeforeDoctypePublicIdentifier (line 211) | _stateBeforeDoctypePublicIdentifier(e){const n=this.currentToken;switc...
method _stateDoctypePublicIdentifierDoubleQuoted (line 211) | _stateDoctypePublicIdentifierDoubleQuoted(e){const n=this.currentToken...
method _stateDoctypePublicIdentifierSingleQuoted (line 211) | _stateDoctypePublicIdentifierSingleQuoted(e){const n=this.currentToken...
method _stateAfterDoctypePublicIdentifier (line 211) | _stateAfterDoctypePublicIdentifier(e){const n=this.currentToken;switch...
method _stateBetweenDoctypePublicAndSystemIdentifiers (line 211) | _stateBetweenDoctypePublicAndSystemIdentifiers(e){const n=this.current...
method _stateAfterDoctypeSystemKeyword (line 211) | _stateAfterDoctypeSystemKeyword(e){const n=this.currentToken;switch(e)...
method _stateBeforeDoctypeSystemIdentifier (line 211) | _stateBeforeDoctypeSystemIdentifier(e){const n=this.currentToken;switc...
method _stateDoctypeSystemIdentifierDoubleQuoted (line 211) | _stateDoctypeSystemIdentifierDoubleQuoted(e){const n=this.currentToken...
method _stateDoctypeSystemIdentifierSingleQuoted (line 211) | _stateDoctypeSystemIdentifierSingleQuoted(e){const n=this.currentToken...
method _stateAfterDoctypeSystemIdentifier (line 211) | _stateAfterDoctypeSystemIdentifier(e){const n=this.currentToken;switch...
method _stateBogusDoctype (line 211) | _stateBogusDoctype(e){const n=this.currentToken;switch(e){case L.GREAT...
method _stateCdataSection (line 211) | _stateCdataSection(e){switch(e){case L.RIGHT_SQUARE_BRACKET:{this.stat...
method _stateCdataSectionBracket (line 211) | _stateCdataSectionBracket(e){e===L.RIGHT_SQUARE_BRACKET?this.state=B.C...
method _stateCdataSectionEnd (line 211) | _stateCdataSectionEnd(e){switch(e){case L.GREATER_THAN_SIGN:{this.stat...
method _stateCharacterReference (line 211) | _stateCharacterReference(){let e=this.entityDecoder.write(this.preproc...
method _stateAmbiguousAmpersand (line 211) | _stateAmbiguousAmpersand(e){xT(e)?this._flushCodePointConsumedAsCharac...
class O$ (line 211) | class O${get currentTmplContentOrNode(){return this._isInTemplate()?this...
method currentTmplContentOrNode (line 211) | get currentTmplContentOrNode(){return this._isInTemplate()?this.treeAd...
method constructor (line 211) | constructor(e,n,r){this.treeAdapter=n,this.handler=r,this.items=[],thi...
method _indexOf (line 211) | _indexOf(e){return this.items.lastIndexOf(e,this.stackTop)}
method _isInTemplate (line 211) | _isInTemplate(){return this.currentTagId===E.TEMPLATE&&this.treeAdapte...
method _updateCurrentElement (line 211) | _updateCurrentElement(){this.current=this.items[this.stackTop],this.cu...
method push (line 211) | push(e,n){this.stackTop++,this.items[this.stackTop]=e,this.current=e,t...
method pop (line 211) | pop(){const e=this.current;this.tmplCount>0&&this._isInTemplate()&&thi...
method replace (line 211) | replace(e,n){const r=this._indexOf(e);this.items[r]=n,r===this.stackTo...
method insertAfter (line 211) | insertAfter(e,n,r){const i=this._indexOf(e)+1;this.items.splice(i,0,n)...
method popUntilTagNamePopped (line 211) | popUntilTagNamePopped(e){let n=this.stackTop+1;do n=this.tagIDs.lastIn...
method shortenToLength (line 211) | shortenToLength(e){for(;this.stackTop>=e;){const n=this.current;this.t...
method popUntilElementPopped (line 211) | popUntilElementPopped(e){const n=this._indexOf(e);this.shortenToLength...
method popUntilPopped (line 211) | popUntilPopped(e,n){const r=this._indexOfTagNames(e,n);this.shortenToL...
method popUntilNumberedHeaderPopped (line 211) | popUntilNumberedHeaderPopped(){this.popUntilPopped(ab,be.HTML)}
method popUntilTableCellPopped (line 211) | popUntilTableCellPopped(){this.popUntilPopped(I$,be.HTML)}
method popAllUpToHtmlElement (line 211) | popAllUpToHtmlElement(){this.tmplCount=0,this.shortenToLength(1)}
method _indexOfTagNames (line 211) | _indexOfTagNames(e,n){for(let r=this.stackTop;r>=0;r--)if(e.has(this.t...
method clearBackTo (line 211) | clearBackTo(e,n){const r=this._indexOfTagNames(e,n);this.shortenToLeng...
method clearBackToTableContext (line 211) | clearBackToTableContext(){this.clearBackTo(R$,be.HTML)}
method clearBackToTableBodyContext (line 211) | clearBackToTableBodyContext(){this.clearBackTo(N$,be.HTML)}
method clearBackToTableRowContext (line 211) | clearBackToTableRowContext(){this.clearBackTo(k$,be.HTML)}
method remove (line 211) | remove(e){const n=this._indexOf(e);n>=0&&(n===this.stackTop?this.pop()...
method tryPeekProperlyNestedBodyElement (line 211) | tryPeekProperlyNestedBodyElement(){return this.stackTop>=1&&this.tagID...
method contains (line 211) | contains(e){return this._indexOf(e)>-1}
method getCommonAncestor (line 211) | getCommonAncestor(e){const n=this._indexOf(e)-1;return n>=0?this.items...
method isRootHtmlElementCurrent (line 211) | isRootHtmlElementCurrent(){return this.stackTop===0&&this.tagIDs[0]===...
method hasInDynamicScope (line 211) | hasInDynamicScope(e,n){for(let r=this.stackTop;r>=0;r--){const i=this....
method hasInScope (line 211) | hasInScope(e){return this.hasInDynamicScope(e,ph)}
method hasInListItemScope (line 211) | hasInListItemScope(e){return this.hasInDynamicScope(e,C$)}
method hasInButtonScope (line 211) | hasInButtonScope(e){return this.hasInDynamicScope(e,A$)}
method hasNumberedHeaderInScope (line 211) | hasNumberedHeaderInScope(){for(let e=this.stackTop;e>=0;e--){const n=t...
method hasInTableScope (line 211) | hasInTableScope(e){for(let n=this.stackTop;n>=0;n--)if(this.treeAdapte...
method hasTableBodyContextInTableScope (line 211) | hasTableBodyContextInTableScope(){for(let e=this.stackTop;e>=0;e--)if(...
method hasInSelectScope (line 211) | hasInSelectScope(e){for(let n=this.stackTop;n>=0;n--)if(this.treeAdapt...
method generateImpliedEndTags (line 211) | generateImpliedEndTags(){for(;this.currentTagId!==void 0&&FN.has(this....
method generateImpliedEndTagsThoroughly (line 211) | generateImpliedEndTagsThoroughly(){for(;this.currentTagId!==void 0&&wT...
method generateImpliedEndTagsWithExclusion (line 211) | generateImpliedEndTagsWithExclusion(e){for(;this.currentTagId!==void 0...
class M$ (line 211) | class M${constructor(e){this.treeAdapter=e,this.entries=[],this.bookmark...
method constructor (line 211) | constructor(e){this.treeAdapter=e,this.entries=[],this.bookmark=null}
method _getNoahArkConditionCandidates (line 211) | _getNoahArkConditionCandidates(e,n){const r=[],i=n.length,s=this.treeA...
method _ensureNoahArkCondition (line 211) | _ensureNoahArkCondition(e){if(this.entries.length<r0)return;const n=th...
method insertMarker (line 211) | insertMarker(){this.entries.unshift(_T)}
method pushElement (line 211) | pushElement(e,n){this._ensureNoahArkCondition(e),this.entries.unshift(...
method insertElementAfterBookmark (line 211) | insertElementAfterBookmark(e,n){const r=this.entries.indexOf(this.book...
method removeEntry (line 211) | removeEntry(e){const n=this.entries.indexOf(e);n!==-1&&this.entries.sp...
method clearToLastMarker (line 211) | clearToLastMarker(){const e=this.entries.indexOf(_T);e===-1?this.entri...
method getElementEntryInScopeWithTagName (line 211) | getElementEntryInScopeWithTagName(e){const n=this.entries.find(r=>r.ty...
method getElementEntry (line 211) | getElementEntry(e){return this.entries.find(n=>n.type===zi.Element&&n....
method createDocument (line 211) | createDocument(){return{nodeName:"#document",mode:ni.NO_QUIRKS,childNode...
method createDocumentFragment (line 211) | createDocumentFragment(){return{nodeName:"#document-fragment",childNodes...
method createElement (line 211) | createElement(t,e,n){return{nodeName:t,tagName:t,attrs:n,namespaceURI:e,...
method createCommentNode (line 211) | createCommentNode(t){return{nodeName:"#comment",data:t,parentNode:null}}
method createTextNode (line 211) | createTextNode(t){return{nodeName:"#text",value:t,parentNode:null}}
method appendChild (line 211) | appendChild(t,e){t.childNodes.push(e),e.parentNode=t}
method insertBefore (line 211) | insertBefore(t,e,n){const r=t.childNodes.indexOf(n);t.childNodes.splice(...
method setTemplateContent (line 211) | setTemplateContent(t,e){t.content=e}
method getTemplateContent (line 211) | getTemplateContent(t){return t.content}
method setDocumentType (line 211) | setDocumentType(t,e,n,r){const i=t.childNodes.find(s=>s.nodeName==="#doc...
method setDocumentMode (line 211) | setDocumentMode(t,e){t.mode=e}
method getDocumentMode (line 211) | getDocumentMode(t){return t.mode}
method detachNode (line 211) | detachNode(t){if(t.parentNode){const e=t.parentNode.childNodes.indexOf(t...
method insertText (line 211) | insertText(t,e){if(t.childNodes.length>0){const n=t.childNodes[t.childNo...
method insertTextBefore (line 211) | insertTextBefore(t,e,n){const r=t.childNodes[t.childNodes.indexOf(n)-1];...
method adoptAttributes (line 211) | adoptAttributes(t,e){const n=new Set(t.attrs.map(r=>r.name));for(let r=0...
method getFirstChild (line 211) | getFirstChild(t){return t.childNodes[0]}
method getChildNodes (line 211) | getChildNodes(t){return t.childNodes}
method getParentNode (line 211) | getParentNode(t){return t.parentNode}
method getAttrList (line 211) | getAttrList(t){return t.attrs}
method getTagName (line 211) | getTagName(t){return t.tagName}
method getNamespaceURI (line 211) | getNamespaceURI(t){return t.namespaceURI}
method getTextNodeContent (line 211) | getTextNodeContent(t){return t.value}
method getCommentNodeContent (line 211) | getCommentNodeContent(t){return t.data}
method getDocumentTypeNodeName (line 211) | getDocumentTypeNodeName(t){return t.name}
method getDocumentTypeNodePublicId (line 211) | getDocumentTypeNodePublicId(t){return t.publicId}
method getDocumentTypeNodeSystemId (line 211) | getDocumentTypeNodeSystemId(t){return t.systemId}
method isTextNode (line 211) | isTextNode(t){return t.nodeName==="#text"}
method isCommentNode (line 211) | isCommentNode(t){return t.nodeName==="#comment"}
method isDocumentTypeNode (line 211) | isDocumentTypeNode(t){return t.nodeName==="#documentType"}
method isElementNode (line 211) | isElementNode(t){return Object.prototype.hasOwnProperty.call(t,"tagName")}
method setNodeSourceCodeLocation (line 211) | setNodeSourceCodeLocation(t,e){t.sourceCodeLocation=e}
method getNodeSourceCodeLocation (line 211) | getNodeSourceCodeLocation(t){return t.sourceCodeLocation}
method updateNodeSourceCodeLocation (line 211) | updateNodeSourceCodeLocation(t,e){t.sourceCodeLocation={...t.sourceCodeL...
function CT (line 211) | function CT(t,e){return e.some(n=>t.startsWith(n))}
function U$ (line 211) | function U$(t){return t.name===BN&&t.publicId===null&&(t.systemId===null...
function H$ (line 211) | function H$(t){if(t.name!==BN)return ni.QUIRKS;const{systemId:e}=t;if(e&...
function K$ (line 211) | function K$(t){const e=t.tagID;return e===E.FONT&&t.attrs.some(({name:r}...
function zN (line 211) | function zN(t){for(let e=0;e<t.attrs.length;e++)if(t.attrs[e].name===z$)...
function jN (line 211) | function jN(t){for(let e=0;e<t.attrs.length;e++){const n=$$.get(t.attrs[...
function u1 (line 211) | function u1(t){for(let e=0;e<t.attrs.length;e++){const n=W$.get(t.attrs[...
function Y$ (line 211) | function Y$(t){const e=V$.get(t.tagName);e!=null&&(t.tagName=e,t.tagID=F...
function q$ (line 211) | function q$(t,e){return e===be.MATHML&&(t===E.MI||t===E.MO||t===E.MN||t=...
function X$ (line 211) | function X$(t,e,n){if(e===be.MATHML&&t===E.ANNOTATION_XML){for(let r=0;r...
function Q$ (line 211) | function Q$(t,e,n,r){return(!r||r===be.HTML)&&X$(t,e,n)||(!r||r===be.MAT...
class NT (line 211) | class NT{constructor(e,n,r=null,i=null){this.fragmentContext=r,this.scri...
method constructor (line 211) | constructor(e,n,r=null,i=null){this.fragmentContext=r,this.scriptHandl...
method parse (line 211) | static parse(e,n){const r=new this(n);return r.tokenizer.write(e,!0),r...
method getFragmentParser (line 211) | static getFragmentParser(e,n){const r={...kT,...n};e??(e=r.treeAdapter...
method getFragment (line 211) | getFragment(){const e=this.treeAdapter.getFirstChild(this.document),n=...
method _err (line 211) | _err(e,n,r){var i;if(!this.onParseError)return;const s=(i=e.location)!...
method onItemPush (line 211) | onItemPush(e,n,r){var i,s;(s=(i=this.treeAdapter).onItemPush)===null||...
method onItemPop (line 211) | onItemPop(e,n){var r,i;if(this.options.sourceCodeLocationInfo&&this._s...
method _setContextModes (line 211) | _setContextModes(e,n){const r=e===this.document||e&&this.treeAdapter.g...
method _switchToTextParsing (line 211) | _switchToTextParsing(e,n){this._insertElement(e,be.HTML),this.tokenize...
method switchToPlaintextParsing (line 211) | switchToPlaintextParsing(){this.insertionMode=$.TEXT,this.originalInse...
method _getAdjustedCurrentElement (line 211) | _getAdjustedCurrentElement(){return this.openElements.stackTop===0&&th...
method _findFormInFragmentContext (line 211) | _findFormInFragmentContext(){let e=this.fragmentContext;for(;e;){if(th...
method _initTokenizerForFragmentParsing (line 211) | _initTokenizerForFragmentParsing(){if(!(!this.fragmentContext||this.tr...
method _setDocumentType (line 211) | _setDocumentType(e){const n=e.name||"",r=e.publicId||"",i=e.systemId||...
method _attachElementToTree (line 211) | _attachElementToTree(e,n){if(this.options.sourceCodeLocationInfo){cons...
method _appendElement (line 211) | _appendElement(e,n){const r=this.treeAdapter.createElement(e.tagName,n...
method _insertElement (line 211) | _insertElement(e,n){const r=this.treeAdapter.createElement(e.tagName,n...
method _insertFakeElement (line 211) | _insertFakeElement(e,n){const r=this.treeAdapter.createElement(e,be.HT...
method _insertTemplate (line 211) | _insertTemplate(e){const n=this.treeAdapter.createElement(e.tagName,be...
method _insertFakeRootElement (line 211) | _insertFakeRootElement(){const e=this.treeAdapter.createElement(re.HTM...
method _appendCommentNode (line 211) | _appendCommentNode(e,n){const r=this.treeAdapter.createCommentNode(e.d...
method _insertCharacters (line 211) | _insertCharacters(e){let n,r;if(this._shouldFosterParentOnInsertion()?...
method _adoptNodes (line 211) | _adoptNodes(e,n){for(let r=this.treeAdapter.getFirstChild(e);r;r=this....
method _setEndLocation (line 211) | _setEndLocation(e,n){if(this.treeAdapter.getNodeSourceCodeLocation(e)&...
method shouldProcessStartTagTokenInForeignContent (line 211) | shouldProcessStartTagTokenInForeignContent(e){if(!this.currentNotInHTM...
method _processToken (line 211) | _processToken(e){switch(e.type){case yt.CHARACTER:{this.onCharacter(e)...
method _isIntegrationPoint (line 211) | _isIntegrationPoint(e,n,r){const i=this.treeAdapter.getNamespaceURI(n)...
method _reconstructActiveFormattingElements (line 211) | _reconstructActiveFormattingElements(){const e=this.activeFormattingEl...
method _closeTableCell (line 211) | _closeTableCell(){this.openElements.generateImpliedEndTags(),this.open...
method _closePElement (line 211) | _closePElement(){this.openElements.generateImpliedEndTagsWithExclusion...
method _resetInsertionMode (line 211) | _resetInsertionMode(){for(let e=this.openElements.stackTop;e>=0;e--)sw...
method _resetInsertionModeForSelect (line 211) | _resetInsertionModeForSelect(e){if(e>0)for(let n=e-1;n>0;n--){const r=...
method _isElementCausesFosterParenting (line 211) | _isElementCausesFosterParenting(e){return $N.has(e)}
method _shouldFosterParentOnInsertion (line 211) | _shouldFosterParentOnInsertion(){return this.fosterParentingEnabled&&t...
method _findFosterParentingLocation (line 211) | _findFosterParentingLocation(){for(let e=this.openElements.stackTop;e>...
method _fosterParentElement (line 211) | _fosterParentElement(e){const n=this._findFosterParentingLocation();n....
method _isSpecialElement (line 211) | _isSpecialElement(e,n){const r=this.treeAdapter.getNamespaceURI(e);ret...
method onCharacter (line 211) | onCharacter(e){if(this.skipNextNewLine=!1,this.tokenizer.inForeignNode...
method onNullCharacter (line 211) | onNullCharacter(e){if(this.skipNextNewLine=!1,this.tokenizer.inForeign...
method onComment (line 211) | onComment(e){if(this.skipNextNewLine=!1,this.currentNotInHTML){lb(this...
method onDoctype (line 211) | onDoctype(e){switch(this.skipNextNewLine=!1,this.insertionMode){case $...
method onStartTag (line 211) | onStartTag(e){this.skipNextNewLine=!1,this.currentToken=e,this._proces...
method _processStartTag (line 211) | _processStartTag(e){this.shouldProcessStartTagTokenInForeignContent(e)...
method _startTagOutsideForeignContent (line 211) | _startTagOutsideForeignContent(e){switch(this.insertionMode){case $.IN...
method onEndTag (line 211) | onEndTag(e){this.skipNextNewLine=!1,this.currentToken=e,this.currentNo...
method _endTagOutsideForeignContent (line 211) | _endTagOutsideForeignContent(e){switch(this.insertionMode){case $.INIT...
method onEof (line 211) | onEof(e){switch(this.insertionMode){case $.INITIAL:{Mu(this,e);break}c...
method onWhitespaceCharacter (line 211) | onWhitespaceCharacter(e){if(this.skipNextNewLine&&(this.skipNextNewLin...
function nW (line 211) | function nW(t,e){let n=t.activeFormattingElements.getElementEntryInScope...
function rW (line 211) | function rW(t,e){let n=null,r=t.openElements.stackTop;for(;r>=0;r--){con...
function iW (line 211) | function iW(t,e,n){let r=e,i=t.openElements.getCommonAncestor(e);for(let...
function sW (line 211) | function sW(t,e){const n=t.treeAdapter.getNamespaceURI(e.element),r=t.tr...
function oW (line 211) | function oW(t,e,n){const r=t.treeAdapter.getTagName(e),i=Fl(r);if(t._isE...
function aW (line 211) | function aW(t,e,n){const r=t.treeAdapter.getNamespaceURI(n.element),{tok...
function c1 (line 211) | function c1(t,e){for(let n=0;n<J$;n++){const r=nW(t,e);if(!r)break;const...
function lb (line 211) | function lb(t,e){t._appendCommentNode(e,t.openElements.currentTmplConten...
function lW (line 211) | function lW(t,e){t._appendCommentNode(e,t.openElements.items[0])}
function uW
Condensed preview — 478 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (7,782K chars).
[
{
"path": ".devcontainer/Dockerfile",
"chars": 1026,
"preview": "FROM mcr.microsoft.com/devcontainers/base:ubuntu-24.04\n\nARG DEBIAN_FRONTEND=noninteractive\nARG USER=vscode\n\nRUN DEBIAN_F"
},
{
"path": ".devcontainer/devcontainer.json",
"chars": 1666,
"preview": "{\n \"name\": \"uv-pyenv\",\n \"build\": {\n \"dockerfile\": \"Dockerfile\"\n },\n // \"features\": {},\n // 👇 Use 'forwardPorts' "
},
{
"path": ".githooks/pre-commit",
"chars": 90,
"preview": "#!/bin/bash\n\nROOT=$(git rev-parse --show-toplevel)\ncd $ROOT\npython scripts/lint.py --ruff\n"
},
{
"path": ".githooks/pre-push",
"chars": 98,
"preview": "#!/bin/bash\n\nROOT=$(git rev-parse --show-toplevel)\ncd $ROOT\npython scripts/lint.py --mypy --ruff\n\n"
},
{
"path": ".githooks/prepare-commit-msg",
"chars": 757,
"preview": "#!/bin/bash\n\n# A git commit hook that will automatically append a DCO signoff to the bottom\n# of any commit message that"
},
{
"path": ".github/ISSUE_TEMPLATE/bug-report.md",
"chars": 599,
"preview": "---\nname: Bug Report\nabout: Create a report to help us improve\ntitle: \"[Bug] <Replace this with a descriptive title>\"\nla"
},
{
"path": ".github/ISSUE_TEMPLATE/feature-request.md",
"chars": 442,
"preview": "---\nname: Feature Request\nabout: Suggest an idea for this project\ntitle: \"[Enhancement] <Replace this with a descriptive"
},
{
"path": ".github/dco.yml",
"chars": 70,
"preview": "allowRemediationCommits:\n individual: true\nrequire:\n members: false\n"
},
{
"path": ".github/workflows/ci-test.yml",
"chars": 1458,
"preview": "name: Verify and Test\n\non:\n push:\n branches: [ \"main\" ]\n pull_request:\n branches: [ \"develop\" ]\n\njobs:\n build:\n"
},
{
"path": ".github/workflows/docker-publish.yml",
"chars": 4041,
"preview": "name: Docker\n\n# This workflow uses actions that are not certified by GitHub.\n# They are provided by a third-party and ar"
},
{
"path": ".github/workflows/lint.yml",
"chars": 839,
"preview": "name: Lint\n\non:\n push:\n branches: [ \"main\" ]\n pull_request:\n branches: [ \"main\" ]\n\n\njobs:\n build:\n runs-on: "
},
{
"path": ".gitignore",
"chars": 328,
"preview": ".env\n.pytest_cache\n.mypy_cache\n.ruff_cache\n__pycache__\n.justfile\ntestresults**\ntests/core/persistence/test_cache/*.json\n"
},
{
"path": "CHANGELOG.md",
"chars": 19056,
"preview": "# Changelog\n\nAll notable changes to Parlant will be documented here.\n\n## [Unreleased]\n\n### Changed\n\n- Change tag depende"
},
{
"path": "CLAUDE.md",
"chars": 2772,
"preview": "This is the main repo of Parlant (https://parlant.io).\n\nParlant is a Python based agent framework. Its core strengths:\n\n"
},
{
"path": "CONTRIBUTING.md",
"chars": 846,
"preview": "# DCO Sign Off\n\nAll commits must be signed off with the Developer Certificate of Origin ([DCO.md](DCO.md)).\nThis attests"
},
{
"path": "DCO.md",
"chars": 1365,
"preview": "Developer Certificate of Origin\nVersion 1.1\n\nCopyright (C) 2004, 2006 The Linux Foundation and its contributors.\n\nEveryo"
},
{
"path": "LICENSE",
"chars": 11344,
"preview": "\n Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 17632,
"preview": "<div align=\"center\">\n\n<picture>\n <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/emcie-co/parla"
},
{
"path": "docs/adapters/nlp/azure.md",
"chars": 10485,
"preview": "# Azure OpenAI Service Documentation\n\nThe Azure service provides integration with Azure OpenAI services, supporting both"
},
{
"path": "docs/adapters/nlp/ollama.md",
"chars": 5854,
"preview": "# Ollama Service Documentation\n\nThe Ollama service provides local LLM capabilities for Parlant using [Ollama](https://ol"
},
{
"path": "docs/adapters/nlp/openrouter.md",
"chars": 16866,
"preview": "# OpenRouter Service Documentation\n\nThe OpenRouter service provides access to **400+ AI models** through a single unifie"
},
{
"path": "docs/adapters/nlp/snowflake-cortex.md",
"chars": 3359,
"preview": "# Snowflake Cortex Adapter\n\nIntegrate [Snowflake Cortex REST APIs](https://docs.snowflake.com/en/user-guide/snowflake-co"
},
{
"path": "docs/adapters/nlp/vertex.md",
"chars": 12278,
"preview": "# Vertex AI Service Adapter Documentation\n\n## Overview\n\nThe Vertex AI Service Adapter provides integration with Google C"
},
{
"path": "docs/adapters/persistence/snowflake.md",
"chars": 5980,
"preview": "# Snowflake Persistence Adapter\n\nThe Snowflake document adapter lets Parlant persist the long–lived parts of a\ndeploymen"
},
{
"path": "docs/adapters/vector_db/qdrant.md",
"chars": 7144,
"preview": "# Qdrant Vector Database\n\nThe Qdrant adapter provides persistent vector storage for Parlant using Qdrant's vector databa"
},
{
"path": "docs/advanced/contributing.md",
"chars": 814,
"preview": "# Contributing to Parlant\n\nWe use the Linux-standard Developer Certificate of Origin ([DCO.md](https://github.com/emcie-"
},
{
"path": "docs/advanced/custom-llms.md",
"chars": 15572,
"preview": "# Custom NLP Models\n\nOnce you've understood the basic of setting up [engine extensions](https://parlant.io/docs/advanced"
},
{
"path": "docs/advanced/engine-extensions.md",
"chars": 7483,
"preview": "# Engine Extensions\n\nWorking with an external framework and adapting it to your needs isn’t always simple, especially wh"
},
{
"path": "docs/advanced/explainability.md",
"chars": 4267,
"preview": "# Enforcement & Explainability\n\nLet's dive into how Parlant enforces the conversation model consistently and provides vi"
},
{
"path": "docs/concepts/customization/canned-responses.md",
"chars": 14597,
"preview": "# Canned Responses\n\nCanned responses provide you with precise control over your Parlant agent's responses.\n\nThe [concept"
},
{
"path": "docs/concepts/customization/glossary.md",
"chars": 4735,
"preview": "# Glossary\n\nThe glossary is a fundamental part of shaping your agent's understanding of its domain. It's like your agent"
},
{
"path": "docs/concepts/customization/guidelines.md",
"chars": 11539,
"preview": "# Guidelines\n\nGuidelines are a powerful customization feature. While they're quite simple in principle, there is a lot t"
},
{
"path": "docs/concepts/customization/journeys.md",
"chars": 15834,
"preview": "# Journeys\n\nThere are many use cases where you want your agent to follow a specific flow of conversation, such as bookin"
},
{
"path": "docs/concepts/customization/relationships.md",
"chars": 9257,
"preview": "# Relationships\n\nDefining how **guidelines** and **journeys** relate to each other is a powerful (and advanced) part of "
},
{
"path": "docs/concepts/customization/retrievers.md",
"chars": 5160,
"preview": "# Retrievers\n\nFor pragmatic reasons, Parlant distinguishes between two modes of data access; namely, tools and **retriev"
},
{
"path": "docs/concepts/customization/tools.md",
"chars": 21911,
"preview": "# Tools\n\nParlant provides a guided approach to tool usage, tightly integrated with its guidance system.\n\nParlant's tool-"
},
{
"path": "docs/concepts/customization/variables.md",
"chars": 5918,
"preview": "# Variables\n\nEvery customer is unique, and your agent may choose to treat them as such where appropriate.\n\nVariables enr"
},
{
"path": "docs/concepts/entities/agents.md",
"chars": 5689,
"preview": "# Agents\n\nIn Parlant, an agent is a customized AI personality that interacts with customers as a single, competent entit"
},
{
"path": "docs/concepts/entities/customers.md",
"chars": 5098,
"preview": "# Customers\n\nIn Parlant, a **customer** is a code word for anyone who interacts with an agent—regardless of the real nat"
},
{
"path": "docs/concepts/sessions.md",
"chars": 15323,
"preview": "# Sessions\n\nA session represents a continuous interaction between an [agent](https://parlant.io/docs/concepts/entities/a"
},
{
"path": "docs/interactions.md",
"chars": 5137,
"preview": "# Interaction Flow\n\n## Motivation\n\nThe first thing that's important to understand about the design of the Human/AI inter"
},
{
"path": "docs/production/agentic-design.md",
"chars": 20197,
"preview": "# Agentic Design Methodology\n\nBuilding AI agents takes a fundamental paradigm shift from traditional software developmen"
},
{
"path": "docs/production/api-hardening.md",
"chars": 9479,
"preview": "# API Hardening\n\nParlant provides a robust authorization and rate limiting system to protect your API from unauthorized "
},
{
"path": "docs/production/custom-frontend.md",
"chars": 15592,
"preview": "# Custom Frontend\n\nThe fastest way to integrate Parlant into your React application is using our official [`parlant-chat"
},
{
"path": "docs/production/human-handoff.md",
"chars": 12720,
"preview": "# Human Handoff\n\nHuman handoff is a crucial aspect of customer service automation, especially when using AI agents. It a"
},
{
"path": "docs/production/input-moderation.md",
"chars": 4148,
"preview": "# User-Input Moderation\n\nAdding content filtering to your AI agents helps achieve a more professional level of customer "
},
{
"path": "docs/quickstart/examples.md",
"chars": 16782,
"preview": "# Healthcare Agent Example\n\nThis page walks you through using Parlant to design and build a healthcare agent with two cu"
},
{
"path": "docs/quickstart/installation.md",
"chars": 6669,
"preview": "# Installation\n\n\n\n**Parlant** is an open-source **Agentic Behavior"
},
{
"path": "docs/quickstart/motivation.md",
"chars": 8734,
"preview": "# Motivation\n\nLet's say you downloaded some agent framework and built an AI agent—that's great! However, when you actual"
},
{
"path": "examples/healthcare.py",
"chars": 7287,
"preview": "# healthcare.py\n\nimport parlant.sdk as p\nimport asyncio\nfrom datetime import datetime\n\n\n@p.tool\nasync def get_insurance_"
},
{
"path": "examples/travel_voice_agent.py",
"chars": 9919,
"preview": "# travel_voice_agent.py\n\nimport parlant.sdk as p\nimport asyncio\nfrom datetime import datetime\n\n\n@p.tool\nasync def get_av"
},
{
"path": "llms.txt",
"chars": 13632,
"preview": "# Parlant\n\n> Open-source AI agent framework for building customer-facing conversational agents with ensured rule complia"
},
{
"path": "mypy.ini",
"chars": 216,
"preview": "[mypy]\nstrict = True\nnamespace_packages = True\nexplicit_package_bases = True\nwarn_unused_ignores = False\nmypy_path = src"
},
{
"path": "pyproject.toml",
"chars": 4393,
"preview": "[project]\nname = \"parlant\"\nversion = \"3.3.0\"\ndescription = \"\"\nreadme = \"README.md\"\nlicense = \"Apache-2.0\"\nauthors = [\n "
},
{
"path": "pytest.ini",
"chars": 357,
"preview": "[pytest]\nasyncio_mode = auto\nbdd_features_base_dir = tests/\nfilterwarnings =\n ignore::pytest.PytestDeprecationWarning"
},
{
"path": "pytest_stochastics.json",
"chars": 2438,
"preview": "{\n \"test_plan_list\": [\n {\n \"plan\": \"complete\",\n \"_comment\": \"utility plan equivalent to running all the ot"
},
{
"path": "ruff.toml",
"chars": 1548,
"preview": "# Exclude a variety of commonly ignored directories.\nexclude = [\n \".bzr\",\n \".direnv\",\n \".eggs\",\n \".git\",\n "
},
{
"path": "scripts/ci/github_action_ubuntu_2404_free_space.sh",
"chars": 1371,
"preview": "#!/bin/sh\n\n# Print initial disk space usage\ndf -h / | awk 'NR==2 {printf \"Before cleanup: %s used, %s free\\n\", $3, $4}'\n"
},
{
"path": "scripts/fern/docs.yml",
"chars": 169,
"preview": "instances:\n - url: https://docs.parlant.io\ntitle: Parlant | Documentation\nnavigation:\n - api: API Reference\ncolors:\n "
},
{
"path": "scripts/fern/fern.config.json",
"chars": 55,
"preview": "{\n \"organization\": \"parlant\",\n \"version\": \"0.61.22\"\n}"
},
{
"path": "scripts/fern/generators.yml",
"chars": 528,
"preview": "api:\n specs:\n - openapi: openapi/parlant.openapi.json\ndefault-group: local\ngroups:\n local:\n generators:\n - "
},
{
"path": "scripts/generate_client_sdk.py",
"chars": 4386,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "scripts/initialize_repo.py",
"chars": 940,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "scripts/install_packages.py",
"chars": 1131,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "scripts/lint.py",
"chars": 1457,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "scripts/publish.py",
"chars": 3099,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "scripts/utils.py",
"chars": 2020,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "scripts/version.py",
"chars": 5094,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/db/json_file.py",
"chars": 14754,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/db/mongo_db.py",
"chars": 10801,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/db/snowflake_db.py",
"chars": 25401,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/db/transient.py",
"chars": 9972,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/loggers/opentelemetry.py",
"chars": 5378,
"preview": "import os\nfrom typing import Any, MutableMapping\nimport structlog\nfrom types import TracebackType\nfrom typing_extensions"
},
{
"path": "src/parlant/adapters/loggers/websocket.py",
"chars": 4493,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/meter/opentelemetry.py",
"chars": 4861,
"preview": "from __future__ import annotations\nimport asyncio\nimport os\nfrom types import TracebackType\nfrom typing import AsyncGene"
},
{
"path": "src/parlant/adapters/nlp/anthropic_service.py",
"chars": 10177,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/nlp/aws_service.py",
"chars": 8682,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/nlp/azure_service.py",
"chars": 23601,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/nlp/cerebras_service.py",
"chars": 8958,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/nlp/common.py",
"chars": 2478,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/nlp/deepseek_service.py",
"chars": 8528,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/nlp/emcie_service.py",
"chars": 25782,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/nlp/fireworks_service.py",
"chars": 15506,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/nlp/gemini_service.py",
"chars": 20610,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/nlp/glm_service.py",
"chars": 10998,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/nlp/hugging_face.py",
"chars": 5438,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/nlp/lakera.py",
"chars": 3314,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/nlp/litellm_service.py",
"chars": 11255,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/nlp/mistral_service.py",
"chars": 14514,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/nlp/modelscope_service.py",
"chars": 8788,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/nlp/ollama_service.py",
"chars": 25861,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/nlp/openai_service.py",
"chars": 29350,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/nlp/openrouter_service.py",
"chars": 25021,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/nlp/qwen_service.py",
"chars": 13581,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/nlp/snowflake_cortex_service.py",
"chars": 13911,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/nlp/together_service.py",
"chars": 16009,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/nlp/vertex_service.py",
"chars": 31723,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/nlp/zhipu_service.py",
"chars": 21680,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/tracing/opentelemetry.py",
"chars": 9762,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/vector_db/chroma.py",
"chars": 26895,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/adapters/vector_db/qdrant.py",
"chars": 56834,
"preview": "# Copyright 2026 Emcie Co Ltd.\r\n#\r\n# Licensed under the Apache License, Version 2.0 (the \"License\");\r\n# you may not use "
},
{
"path": "src/parlant/adapters/vector_db/transient.py",
"chars": 12474,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\")\n# You may not use this"
},
{
"path": "src/parlant/api/agents.py",
"chars": 15600,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/api/app.py",
"chars": 11146,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/api/authorization.py",
"chars": 11306,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/api/canned_responses.py",
"chars": 17609,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/api/capabilities.py",
"chars": 11724,
"preview": "# Copyright 2026 Emcie Co Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use thi"
},
{
"path": "src/parlant/api/chat/.gitignore",
"chars": 248,
"preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist-ssr"
},
{
"path": "src/parlant/api/chat/.prettierrc",
"chars": 196,
"preview": "{\n\t\"singleQuote\": true,\n\t\"tabWidth\": 2,\n\t\"semi\": true,\n\t\"bracketSameLine\": true,\n\t\"arrowParens\": \"always\",\n\t\"bracketSpac"
},
{
"path": "src/parlant/api/chat/.vite/deps_temp_0491001f/package.json",
"chars": 23,
"preview": "{\n \"type\": \"module\"\n}\n"
},
{
"path": "src/parlant/api/chat/components.json",
"chars": 415,
"preview": "{\n \"$schema\": \"https://ui.shadcn.com/schema.json\",\n \"style\": \"default\",\n \"rsc\": false,\n \"tsx\": true,\n \"tailwind\": {"
},
{
"path": "src/parlant/api/chat/dist/assets/index-BBAJ1vle.js",
"chars": 1207848,
"preview": "function DM(t,e){for(var n=0;n<e.length;n++){const r=e[n];if(typeof r!=\"string\"&&!Array.isArray(r)){for(const i in r)if("
},
{
"path": "src/parlant/api/chat/dist/assets/index-BRVifGSy.css",
"chars": 68582,
"preview": "@import\"https://fonts.googleapis.com/css2?family=Ubuntu+Sans:ital,wght@0,100..800;1,100..800&display=swap\";#root{height:"
},
{
"path": "src/parlant/api/chat/dist/assets/manifest-BRNJYplA.webmanifest",
"chars": 295,
"preview": "{\n\t\"name\": \"Parlant\",\n\t\"short_name\": \"Parlant\",\n\t\"description\": \"Chatbot by Parlant\",\n\t\"start_url\": \"/\",\n\t\"display\": \"st"
},
{
"path": "src/parlant/api/chat/dist/fonts/Inter/inter.css",
"chars": 1379,
"preview": "@font-face {\n\tfont-family: 'Inter';\n\tfont-style: normal;\n\tfont-weight: 100;\n\tsrc: url('/fonts/Inter/static/Inter_28pt-Th"
},
{
"path": "src/parlant/api/chat/dist/fonts/ibm-plex-mono/ibm-plex-mono.css",
"chars": 1522,
"preview": "@font-face {\n\tfont-family: 'IBM Plex Mono';\n\tfont-style: normal;\n\tfont-weight: 100;\n\tsrc: url('/fonts/ibm-plex-mono/stat"
},
{
"path": "src/parlant/api/chat/dist/fonts/ibm-plex-mono/static/OFL.txt",
"chars": 4455,
"preview": "Copyright © 2017 IBM Corp. with Reserved Font Name \"Plex\"\r\n\r\nThis Font Software is licensed under the SIL Open Font Lice"
},
{
"path": "src/parlant/api/chat/dist/fonts/ubuntu-mono/static/UFL.txt",
"chars": 4769,
"preview": "-------------------------------\r\nUBUNTU FONT LICENCE Version 1.0\r\n-------------------------------\r\n\r\nPREAMBLE\r\nThis lice"
},
{
"path": "src/parlant/api/chat/dist/fonts/ubuntu-mono/ubuntu_mono.css",
"chars": 1479,
"preview": "@font-face {\n\tfont-family: 'Ubuntu Mono';\n\tfont-style: normal;\n\tfont-weight: 100;\n\tsrc: url('/fonts/ubuntu-mono/static/U"
},
{
"path": "src/parlant/api/chat/dist/fonts/ubuntu-sans/README.txt",
"chars": 4716,
"preview": "Ubuntu Sans Variable Font\n=========================\n\nThis download contains Ubuntu Sans as both variable fonts and stati"
},
{
"path": "src/parlant/api/chat/dist/fonts/ubuntu-sans/UFL.txt",
"chars": 4769,
"preview": "-------------------------------\r\nUBUNTU FONT LICENCE Version 1.0\r\n-------------------------------\r\n\r\nPREAMBLE\r\nThis lice"
},
{
"path": "src/parlant/api/chat/dist/fonts/ubuntu-sans/ubuntu_sans.css",
"chars": 1442,
"preview": "@font-face {\n font-family: 'Ubuntu Sans';\n font-style: normal;\n font-weight: 100;\n src: url('/fonts/ubuntu-s"
},
{
"path": "src/parlant/api/chat/dist/index.html",
"chars": 923,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"UTF-8\" />\n\t\t<link rel=\"icon\" type=\"image/svg+xml\" href=\"/chat/"
},
{
"path": "src/parlant/api/chat/eslint.config.js",
"chars": 733,
"preview": "import js from '@eslint/js';\nimport globals from 'globals';\nimport reactHooks from 'eslint-plugin-react-hooks';\nimport r"
},
{
"path": "src/parlant/api/chat/index.html",
"chars": 791,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"UTF-8\" />\n\t\t<link rel=\"icon\" type=\"image/svg+xml\" href=\"/logo-"
},
{
"path": "src/parlant/api/chat/manifest.webmanifest",
"chars": 295,
"preview": "{\n\t\"name\": \"Parlant\",\n\t\"short_name\": \"Parlant\",\n\t\"description\": \"Chatbot by Parlant\",\n\t\"start_url\": \"/\",\n\t\"display\": \"st"
},
{
"path": "src/parlant/api/chat/package.json",
"chars": 2239,
"preview": "{\n \"name\": \"chat\",\n \"private\": true,\n \"version\": \"0.0.0\",\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite\",\n \""
},
{
"path": "src/parlant/api/chat/postcss.config.js",
"chars": 80,
"preview": "export default {\n plugins: {\n tailwindcss: {},\n autoprefixer: {},\n },\n}\n"
},
{
"path": "src/parlant/api/chat/public/fonts/Inter/inter.css",
"chars": 1379,
"preview": "@font-face {\n\tfont-family: 'Inter';\n\tfont-style: normal;\n\tfont-weight: 100;\n\tsrc: url('/fonts/Inter/static/Inter_28pt-Th"
},
{
"path": "src/parlant/api/chat/public/fonts/ibm-plex-mono/ibm-plex-mono.css",
"chars": 1522,
"preview": "@font-face {\n\tfont-family: 'IBM Plex Mono';\n\tfont-style: normal;\n\tfont-weight: 100;\n\tsrc: url('/fonts/ibm-plex-mono/stat"
},
{
"path": "src/parlant/api/chat/public/fonts/ibm-plex-mono/static/OFL.txt",
"chars": 4455,
"preview": "Copyright © 2017 IBM Corp. with Reserved Font Name \"Plex\"\r\n\r\nThis Font Software is licensed under the SIL Open Font Lice"
},
{
"path": "src/parlant/api/chat/public/fonts/ubuntu-mono/static/UFL.txt",
"chars": 4769,
"preview": "-------------------------------\r\nUBUNTU FONT LICENCE Version 1.0\r\n-------------------------------\r\n\r\nPREAMBLE\r\nThis lice"
},
{
"path": "src/parlant/api/chat/public/fonts/ubuntu-mono/ubuntu_mono.css",
"chars": 1479,
"preview": "@font-face {\n\tfont-family: 'Ubuntu Mono';\n\tfont-style: normal;\n\tfont-weight: 100;\n\tsrc: url('/fonts/ubuntu-mono/static/U"
},
{
"path": "src/parlant/api/chat/public/fonts/ubuntu-sans/README.txt",
"chars": 4716,
"preview": "Ubuntu Sans Variable Font\n=========================\n\nThis download contains Ubuntu Sans as both variable fonts and stati"
},
{
"path": "src/parlant/api/chat/public/fonts/ubuntu-sans/UFL.txt",
"chars": 4769,
"preview": "-------------------------------\r\nUBUNTU FONT LICENCE Version 1.0\r\n-------------------------------\r\n\r\nPREAMBLE\r\nThis lice"
},
{
"path": "src/parlant/api/chat/public/fonts/ubuntu-sans/ubuntu_sans.css",
"chars": 1442,
"preview": "@font-face {\n font-family: 'Ubuntu Sans';\n font-style: normal;\n font-weight: 100;\n src: url('/fonts/ubuntu-s"
},
{
"path": "src/parlant/api/chat/setupTests.ts",
"chars": 42,
"preview": "import '@testing-library/jest-dom/vitest';"
},
{
"path": "src/parlant/api/chat/src/App.css",
"chars": 2115,
"preview": "#root {\n\theight: 100vh;\n\tmargin: auto;\n\tfont-family: 'Inter';\n}\n\nbody {\n\tpointer-events: all !important;\n}\n\n.fixed-scrol"
},
{
"path": "src/parlant/api/chat/src/App.tsx",
"chars": 488,
"preview": "import './App.css';\nimport Chatbot from './components/chatbot/chatbot';\nimport {useWebSocket} from './hooks/useWebSocket"
},
{
"path": "src/parlant/api/chat/src/components/agents-list/agent-list.module.scss",
"chars": 80,
"preview": ".select {\n padding: 0 !important;\n button {\n display: none;\n }\n}"
},
{
"path": "src/parlant/api/chat/src/components/agents-list/agent-list.tsx",
"chars": 3012,
"preview": "import {AgentInterface, CustomerInterface, SessionInterface} from '@/utils/interfaces';\nimport {ReactNode, useEffect} fr"
},
{
"path": "src/parlant/api/chat/src/components/avatar/avatar.tsx",
"chars": 4453,
"preview": "/* eslint-disable react-refresh/only-export-components */\nimport {AgentInterface, CustomerInterface} from '@/utils/inter"
},
{
"path": "src/parlant/api/chat/src/components/canned-response/canned-response.tsx",
"chars": 1716,
"preview": "import Tooltip from '../ui/custom/tooltip';\nimport {copy} from '@/lib/utils';\nimport {twMerge} from 'tailwind-merge';\n\n/"
},
{
"path": "src/parlant/api/chat/src/components/canned-responses/canned-responses.tsx",
"chars": 1461,
"preview": "import {useState} from 'react';\nimport {ClassNameValue, twMerge} from 'tailwind-merge';\nimport CannedResponse from '../c"
},
{
"path": "src/parlant/api/chat/src/components/chat-header/chat-header.tsx",
"chars": 4138,
"preview": "import {ReactNode, useEffect, useState} from 'react';\nimport Tooltip from '../ui/custom/tooltip';\nimport {spaceClick} fr"
},
{
"path": "src/parlant/api/chat/src/components/chatbot/chatbot.tsx",
"chars": 4404,
"preview": "/* eslint-disable react-refresh/only-export-components */\nimport {createContext, ReactElement, useEffect, useState} from"
},
{
"path": "src/parlant/api/chat/src/components/dark-mode-toggle/dark-mode-toggle.tsx",
"chars": 1052,
"preview": "import { ReactNode, useEffect, useState } from 'react';\n\nconst DarkModeToggle = (): ReactNode =>{\n const getInitialTh"
},
{
"path": "src/parlant/api/chat/src/components/error-boundary/error-boundary.tsx",
"chars": 1340,
"preview": "import {Component, ReactNode} from 'react';\n\ninterface Props {\n\tchildren: ReactNode;\n\tcomponent?: ReactNode;\n}\n\ninterfac"
},
{
"path": "src/parlant/api/chat/src/components/gradient-button/gradient-button.module.scss",
"chars": 481,
"preview": " .colorsButton {\n .children {\n color: white;\n border-radius: 6px;\n border: none;\n }\n &:hover, &"
},
{
"path": "src/parlant/api/chat/src/components/gradient-button/gradient-button.tsx",
"chars": 1023,
"preview": "import { spaceClick } from '@/utils/methods';\nimport styles from './gradient-button.module.scss';\nimport { ReactElement,"
},
{
"path": "src/parlant/api/chat/src/components/header-wrapper/header-wrapper.tsx",
"chars": 483,
"preview": "import {ReactNode} from 'react';\nimport {twMerge} from 'tailwind-merge';\n\nconst HeaderWrapper = ({children, className}: "
},
{
"path": "src/parlant/api/chat/src/components/log-filters/log-filters.tsx",
"chars": 14798,
"preview": "import {memo, ReactNode, useEffect, useRef, useState} from 'react';\nimport {Button} from '../ui/button';\nimport {Checkbo"
},
{
"path": "src/parlant/api/chat/src/components/markdown/markdown.tsx",
"chars": 936,
"preview": "/* eslint-disable @typescript-eslint/no-unused-vars */\nimport ReactMarkdown from 'react-markdown';\nimport remarkGfm from"
},
{
"path": "src/parlant/api/chat/src/components/message/draft-bubble.tsx",
"chars": 1337,
"preview": "import Markdown from '../markdown/markdown';\nimport {twMerge} from 'tailwind-merge';\nimport Tooltip from '../ui/custom/t"
},
{
"path": "src/parlant/api/chat/src/components/message/message-bubble.tsx",
"chars": 14002,
"preview": "/* eslint-disable react-hooks/exhaustive-deps */\nimport {useEffect, useRef, useState} from 'react';\nimport {twJoin, twMe"
},
{
"path": "src/parlant/api/chat/src/components/message/message-relative-time.tsx",
"chars": 2035,
"preview": "/* eslint-disable react-hooks/exhaustive-deps */\nimport {timeAgo} from '@/lib/utils';\nimport {EventInterface} from '@/ut"
},
{
"path": "src/parlant/api/chat/src/components/message/message.module.scss",
"chars": 899,
"preview": ".pendingVideo {\n\tclip-path: inset(1px 0.9px 0.5px 0.8px round 50%);\n}\n.markdown {\n\tcode {\n\t\twhite-space: break-spaces;\n\t"
},
{
"path": "src/parlant/api/chat/src/components/message/message.tsx",
"chars": 3572,
"preview": "/* eslint-disable react-hooks/exhaustive-deps */\nimport {ReactElement, useEffect, useRef, useState} from 'react';\nimport"
},
{
"path": "src/parlant/api/chat/src/components/message-details/empty-state.tsx",
"chars": 975,
"preview": "import {ClassNameValue, twMerge} from 'tailwind-merge';\n\ninterface Props {\n\ttitle: string;\n\tsubTitle?: string;\n\tclassNam"
},
{
"path": "src/parlant/api/chat/src/components/message-details/filter-tabs.tsx",
"chars": 4243,
"preview": "/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {twJoin, twMerge} from 'tailwind-merge';\nimport {Level, T"
},
{
"path": "src/parlant/api/chat/src/components/message-details/flag-message.tsx",
"chars": 2352,
"preview": "import {EventInterface} from '@/utils/interfaces';\nimport {Textarea} from '../ui/textarea';\nimport {Button} from '../ui/"
},
{
"path": "src/parlant/api/chat/src/components/message-details/indexeddb-data.tsx",
"chars": 1336,
"preview": "/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {clearIndexedDBData, getIndexedDBSize} from '@/utils/logs"
},
{
"path": "src/parlant/api/chat/src/components/message-details/message-details-header.tsx",
"chars": 3672,
"preview": "import {dialogAtom, sessionAtom} from '@/store';\nimport {EventInterface} from '@/utils/interfaces';\nimport {useAtom} fro"
},
{
"path": "src/parlant/api/chat/src/components/message-details/message-details.tsx",
"chars": 9558,
"preview": "/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable react-hooks/exhaustive-deps */\nimport {EventIn"
},
{
"path": "src/parlant/api/chat/src/components/message-details/message-log.tsx",
"chars": 2685,
"preview": "import {twJoin} from 'tailwind-merge';\nimport {X} from 'lucide-react';\nimport {copy} from '@/lib/utils';\nimport clsx fro"
},
{
"path": "src/parlant/api/chat/src/components/message-details/message-logs.tsx",
"chars": 1299,
"preview": "import {Log} from '@/utils/interfaces';\nimport MessageLog from './message-log';\n\ninterface Props {\n\tmessagesRef: React.R"
},
{
"path": "src/parlant/api/chat/src/components/progress-logo/progress-logo.tsx",
"chars": 1427,
"preview": "/* eslint-disable react-hooks/exhaustive-deps */\nimport React, {useEffect, useState} from 'react';\n\ninterface ProgressIm"
},
{
"path": "src/parlant/api/chat/src/components/session-list/session-list-item/session-list-item.module.scss",
"chars": 306,
"preview": ".editSession {\n\tposition: relative;\n\t&::before {\n\t\tcontent: '';\n\t\tposition: absolute;\n\t\ttop: 50%;\n\t\tleft: 50%;\n\t\tborder:"
},
{
"path": "src/parlant/api/chat/src/components/session-list/session-list-item/session-list-item.tsx",
"chars": 12426,
"preview": "import {Dispatch, ReactElement, SetStateAction, useEffect, useRef, useState} from 'react';\nimport {Input} from '../../ui"
},
{
"path": "src/parlant/api/chat/src/components/session-list/session-list.tsx",
"chars": 2855,
"preview": "import {ReactElement, useEffect, useState} from 'react';\nimport useFetch from '@/hooks/useFetch';\nimport Session from '."
},
{
"path": "src/parlant/api/chat/src/components/session-view/date-header/date-header.tsx",
"chars": 964,
"preview": "import {getDateStr} from '@/utils/date';\nimport {memo, ReactElement} from 'react';\nimport {twMerge} from 'tailwind-merge"
},
{
"path": "src/parlant/api/chat/src/components/session-view/session-view-header/session-view-header.tsx",
"chars": 1654,
"preview": "import Avatar from '@/components/avatar/avatar';\nimport HeaderWrapper from '@/components/header-wrapper/header-wrapper';"
},
{
"path": "src/parlant/api/chat/src/components/session-view/session-view.module.scss",
"chars": 0,
"preview": ""
},
{
"path": "src/parlant/api/chat/src/components/session-view/session-view.tsx",
"chars": 24588,
"preview": "/* eslint-disable react-hooks/exhaustive-deps */\nimport React, {ReactElement, useCallback, useEffect, useRef, useState} "
},
{
"path": "src/parlant/api/chat/src/components/ui/button.tsx",
"chars": 1941,
"preview": "import * as React from 'react';\nimport { Slot } from '@radix-ui/react-slot';\nimport { cva, type VariantProps } from 'cla"
},
{
"path": "src/parlant/api/chat/src/components/ui/checkbox.tsx",
"chars": 1026,
"preview": "import * as React from 'react';\nimport * as CheckboxPrimitive from '@radix-ui/react-checkbox';\nimport {Check} from 'luci"
},
{
"path": "src/parlant/api/chat/src/components/ui/custom/copy-text.tsx",
"chars": 1377,
"preview": "import {ReactNode} from 'react';\nimport {toast} from 'sonner';\nimport {twMerge} from 'tailwind-merge';\nimport {spaceClic"
},
{
"path": "src/parlant/api/chat/src/components/ui/custom/line-no-div.tsx",
"chars": 1885,
"preview": "import {useEffect, useRef} from 'react';\nimport {EditorView, lineNumbers} from '@codemirror/view';\nimport {EditorState} "
},
{
"path": "src/parlant/api/chat/src/components/ui/custom/spacer.tsx",
"chars": 168,
"preview": "import {memo, ReactElement} from 'react';\n\nconst Spacer = (): ReactElement => {\n\treturn <div className='w-[16px] min-w-["
},
{
"path": "src/parlant/api/chat/src/components/ui/custom/tooltip.tsx",
"chars": 1106,
"preview": "import {Tooltip as ShadcnTooltip, TooltipContent, TooltipProvider, TooltipTrigger} from '@/components/ui/tooltip';\nimpor"
},
{
"path": "src/parlant/api/chat/src/components/ui/dialog.tsx",
"chars": 3587,
"preview": "import * as React from 'react';\nimport * as DialogPrimitive from '@radix-ui/react-dialog';\nimport {X} from 'lucide-react"
},
{
"path": "src/parlant/api/chat/src/components/ui/drawer.tsx",
"chars": 2686,
"preview": "import * as React from 'react';\nimport {Drawer as DrawerPrimitive} from 'vaul';\n\nimport {cn} from '@/lib/utils';\n\nconst "
},
{
"path": "src/parlant/api/chat/src/components/ui/dropdown-menu.tsx",
"chars": 7035,
"preview": "import * as React from 'react';\nimport * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';\nimport {Check, C"
},
{
"path": "src/parlant/api/chat/src/components/ui/input.tsx",
"chars": 858,
"preview": "import * as React from 'react';\n\nimport {cn} from '@/lib/utils';\n\n// eslint-disable-next-line @typescript-eslint/no-empt"
},
{
"path": "src/parlant/api/chat/src/components/ui/radio-group.tsx",
"chars": 1384,
"preview": "import * as React from 'react';\nimport * as RadioGroupPrimitive from '@radix-ui/react-radio-group';\nimport {Circle} from"
},
{
"path": "src/parlant/api/chat/src/components/ui/resizable.tsx",
"chars": 1667,
"preview": "import * as ResizablePrimitive from 'react-resizable-panels';\n\nimport {cn} from '@/lib/utils';\n\nconst ResizablePanelGrou"
},
{
"path": "src/parlant/api/chat/src/components/ui/select.tsx",
"chars": 5637,
"preview": "import * as React from 'react';\nimport * as SelectPrimitive from '@radix-ui/react-select';\nimport { Check, ChevronDown, "
},
{
"path": "src/parlant/api/chat/src/components/ui/sheet.tsx",
"chars": 4290,
"preview": "import * as React from 'react';\nimport * as SheetPrimitive from '@radix-ui/react-dialog';\nimport { cva, type VariantProp"
},
{
"path": "src/parlant/api/chat/src/components/ui/skeleton.tsx",
"chars": 264,
"preview": "import { cn } from '@/lib/utils';\n\nfunction Skeleton({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) "
},
{
"path": "src/parlant/api/chat/src/components/ui/sonner.tsx",
"chars": 886,
"preview": "import { useTheme } from 'next-themes';\nimport { Toaster as Sonner } from 'sonner';\n\ntype ToasterProps = React.Component"
},
{
"path": "src/parlant/api/chat/src/components/ui/switch.tsx",
"chars": 1146,
"preview": "'use client';\n\nimport * as React from 'react';\nimport * as SwitchPrimitives from '@radix-ui/react-switch';\n\nimport { cn "
},
{
"path": "src/parlant/api/chat/src/components/ui/textarea.tsx",
"chars": 846,
"preview": "import * as React from 'react';\n\nimport { cn } from '@/lib/utils';\n\n// eslint-disable-next-line @typescript-eslint/no-em"
},
{
"path": "src/parlant/api/chat/src/components/ui/tooltip.tsx",
"chars": 1154,
"preview": "import * as React from 'react';\nimport * as TooltipPrimitive from '@radix-ui/react-tooltip';\n\nimport { cn } from '@/lib/"
},
{
"path": "src/parlant/api/chat/src/components/virtual-scroll/virtual-scroll.tsx",
"chars": 1681,
"preview": "import { useEffect, useRef, useState, ReactNode, ReactElement } from 'react';\n\ninterface VirtualScrollContainerProps {\n "
},
{
"path": "src/parlant/api/chat/src/hooks/useDialog.tsx",
"chars": 2515,
"preview": "import {useState, ReactNode} from 'react';\nimport {Dialog, DialogContent, DialogHeader, DialogPortal} from '@/components"
},
{
"path": "src/parlant/api/chat/src/hooks/useFetch.tsx",
"chars": 3290,
"preview": "import {BASE_URL} from '@/utils/api';\nimport {useState, useEffect, useCallback, useRef, ReactElement} from 'react';\nimpo"
},
{
"path": "src/parlant/api/chat/src/hooks/useLocalStorage.ts",
"chars": 1151,
"preview": "import {useEffect, useState} from 'react';\n\nconst LIMIT = 30;\n\nexport function useLocalStorage<T>(key: string, initialVa"
},
{
"path": "src/parlant/api/chat/src/hooks/useQuestionDialog.tsx",
"chars": 1672,
"preview": "import {Button} from '@/components/ui/button';\nimport {useAtom} from 'jotai';\nimport {dialogAtom} from '@/store';\nimport"
},
{
"path": "src/parlant/api/chat/src/hooks/useWebSocket.ts",
"chars": 2945,
"preview": "import {useEffect, useRef, useState, useCallback} from 'react';\n\ninterface WebSocketOptions {\n\tonMessage?: (message: str"
},
{
"path": "src/parlant/api/chat/src/index.css",
"chars": 1881,
"preview": "@import url('https://fonts.googleapis.com/css2?family=Ubuntu+Sans:ital,wght@0,100..800;1,100..800&display=swap');\n@impor"
}
]
// ... and 278 more files (download for full content)
About this extraction
This page contains the full source code of the emcie-co/parlant GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 478 files (7.1 MB), approximately 1.9M tokens, and a symbol index with 8451 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.